From 102e931ffae2cbaaf5c09eea52c66de9ceef1504 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Tue, 9 Jun 2026 16:43:08 +0100 Subject: [PATCH 01/16] Update redux state on layout change --- src/redux/slices/fileCacheSlice.ts | 12 ++++++- .../displayResponsive.tsx | 34 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/redux/slices/fileCacheSlice.ts b/src/redux/slices/fileCacheSlice.ts index 2243218..db209a2 100644 --- a/src/redux/slices/fileCacheSlice.ts +++ b/src/redux/slices/fileCacheSlice.ts @@ -110,6 +110,15 @@ const fileCacheSlice = createSlice({ }; } }); + }, + fileDisplayUpdateResponsiveLayout(state, action) { + const { file, displayId, responsiveLayouts } = action.payload; + + const fileDescription = state.fileCache[file]; + const display = findWidgetById([fileDescription], displayId); + + if (!display || display.type !== "displayResponsive") return; + display.responsiveLayouts = responsiveLayouts; } }, selectors: { @@ -121,7 +130,8 @@ export const { fileChanged, refreshFile, fileDisplaySetGridLayout, - fileDisplaySetResponsiveLayout + fileDisplaySetResponsiveLayout, + fileDisplayUpdateResponsiveLayout } = fileCacheSlice.actions; export default fileCacheSlice.reducer; diff --git a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx index 0468e59..057d91c 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx @@ -4,7 +4,8 @@ import React, { ReactNode, useEffect, useMemo, - useCallback + useCallback, + useRef } from "react"; import { ResponsiveLayouts, @@ -46,7 +47,10 @@ import { calculateDefaultLayoutWithHorizontalCompactor, sameKeys } from "./displayLayoutUtilities"; -import { fileDisplaySetResponsiveLayout } from "../../../redux/slices/fileCacheSlice"; +import { + fileDisplaySetResponsiveLayout, + fileDisplayUpdateResponsiveLayout +} from "../../../redux/slices/fileCacheSlice"; import log from "loglevel"; import { Dispatch } from "@reduxjs/toolkit"; @@ -88,6 +92,10 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { // can set macros by using the updateMacro function on the // context. const dispatch = useDispatch(); + + const isInteractingRef = useRef(false); + const shouldCommitRef = useRef(false); + const { width, containerRef, mounted } = useContainerWidth({ measureBeforeMount: false }); @@ -263,6 +271,18 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { enabled: gridCellResizeEnabled, handles: ["se"] }} + onLayoutChange={(layout, layouts) => { + if (!isInteractingRef.current && shouldCommitRef.current) { + dispatch( + fileDisplayUpdateResponsiveLayout({ + file: props.fileId, + displayId: props.id, + responsiveLayouts: layouts + }) + ); + shouldCommitRef.current = false; + } + }} onDragStart={( layout, oldItem, @@ -274,11 +294,21 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { if (element?.style != null && gridCellDragEnabled) { element.style.cursor = "grabbing"; } + isInteractingRef.current = true; }} onDragStop={(layout, oldItem, newItem, placeholder, e, element) => { if (element?.style != null && gridCellDragEnabled) { element.style.cursor = "grab"; } + isInteractingRef.current = false; + shouldCommitRef.current = true; + }} + onResizeStart={() => { + isInteractingRef.current = true; + }} + onResizeStop={() => { + isInteractingRef.current = false; + shouldCommitRef.current = true; }} style={{ ...style.colors, From e3d4027ff7d9f4932a409efefefc7468a6b96f85 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 10 Jun 2026 09:57:29 +0100 Subject: [PATCH 02/16] Add callback to dynamic page to return display and file id --- src/ui/hooks/useFile.test.tsx | 4 ++-- src/ui/hooks/useFile.tsx | 6 +++--- src/ui/widgets/DynamicPage/dynamicPage.tsx | 2 ++ src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx | 12 ++++++++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/ui/hooks/useFile.test.tsx b/src/ui/hooks/useFile.test.tsx index d5a214c..e7c0a55 100644 --- a/src/ui/hooks/useFile.test.tsx +++ b/src/ui/hooks/useFile.test.tsx @@ -52,8 +52,8 @@ describe("useFile", (): void => { const responseContent = JSON.stringify({ type: "shape", - id: "123", - fileId: "AShapeFilePath", + id: "EMPTY_WIDGET", + fileId: "EMPTY_WIDGET", position: newAbsolutePosition("0", "0", "0", "0") }); diff --git a/src/ui/hooks/useFile.tsx b/src/ui/hooks/useFile.tsx index 9916b04..a6f5c9e 100644 --- a/src/ui/hooks/useFile.tsx +++ b/src/ui/hooks/useFile.tsx @@ -16,10 +16,10 @@ import { parseOpi } from "../widgets/EmbeddedDisplay/opiParser"; import { Store } from "redux"; import { newAbsolutePosition } from "../../types/position"; -const EMPTY_WIDGET: WidgetDescription = { +export const EMPTY_WIDGET: WidgetDescription = { type: "shape", - id: "123", - fileId: "AShapeFilePath", + id: "EMPTY_WIDGET", + fileId: "EMPTY_WIDGET", position: newAbsolutePosition("0", "0", "0", "0") }; diff --git a/src/ui/widgets/DynamicPage/dynamicPage.tsx b/src/ui/widgets/DynamicPage/dynamicPage.tsx index d1c4beb..119e074 100644 --- a/src/ui/widgets/DynamicPage/dynamicPage.tsx +++ b/src/ui/widgets/DynamicPage/dynamicPage.tsx @@ -93,6 +93,7 @@ export const DynamicPageComponent = ( mjpgEndpoints={[props?.mjpgEndpoint, defaultMjpgEndpoint].filter( x => x != null )} + fileDetailsCallback={props?.fileDetailsCallback} />
x != null )} + fileDetailsCallback={props?.fileDetailsCallback} /> ); diff --git a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx index df364c8..ad3a47b 100644 --- a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx +++ b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx @@ -1,6 +1,6 @@ /* A component to load files directly. */ -import React, { useContext } from "react"; +import React, { useContext, useEffect } from "react"; import log from "loglevel"; import { errorWidget, widgetDescriptionToComponent } from "../createComponent"; @@ -27,7 +27,7 @@ import { useId } from "react-id-generator"; import { getOptionalValue, trimFromString } from "../utils"; import { Theme, ThemeProvider } from "@mui/material"; import { phoebusTheme } from "../../../phoebusTheme"; -import { useFile, File } from "../../hooks/useFile"; +import { useFile, File, EMPTY_WIDGET } from "../../hooks/useFile"; import { recursiveResolve } from "../../hooks/useMacros"; import { useRules } from "../../hooks/useRules"; @@ -41,6 +41,7 @@ const RESIZE_STRINGS = [ export interface EmbeddedDisplayPropsExtra { theme?: Theme; + fileDetailsCallback?: (fileId: string, id: string) => void; } const EmbeddedDisplayProps = { @@ -91,6 +92,13 @@ export const EmbeddedDisplay = ( embeddedDisplayMacroContext.macros ); + const fileDetailsCallback = props?.fileDetailsCallback; + useEffect(() => { + if (fileDetailsCallback && description !== EMPTY_WIDGET) { + fileDetailsCallback(description?.fileId, description?.id); + } + }, [fileDetailsCallback, description]); + let resize = resolvedProps.resize || "scroll-content"; // If number, convert back to string if (typeof resize === "number") resize = RESIZE_STRINGS[resize]; From 25e0359413bf92741d997d0e095dd84c91190c94 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 10 Jun 2026 11:01:08 +0100 Subject: [PATCH 03/16] Removing dependency on UUID. --- src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts | 3 +-- src/ui/widgets/Line/line.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts b/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts index bd77507..6c107c0 100644 --- a/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts +++ b/src/ui/widgets/EmbeddedDisplay/scripts/scriptExecutor.ts @@ -1,5 +1,4 @@ import log from "loglevel"; -import { v4 as uuidv4 } from "uuid"; import { ScriptResponse } from "./scriptTypes"; import { enqueueScript, executeAllScriptsInQueue } from "./scriptQueue"; @@ -172,7 +171,7 @@ const postScriptToIframe = ( } return new Promise((resolve, reject) => { - const id = uuidv4(); + const id = crypto.randomUUID(); let hasTimedOut = false; const cleanup = () => { diff --git a/src/ui/widgets/Line/line.tsx b/src/ui/widgets/Line/line.tsx index de18645..67db88b 100644 --- a/src/ui/widgets/Line/line.tsx +++ b/src/ui/widgets/Line/line.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { v4 as uuidv4 } from "uuid"; import { Widget } from "../widget"; import { PVWidgetPropType, PVComponent } from "../widgetProps"; import { @@ -73,7 +72,7 @@ export const LineComponent = (props: LineComponentProps): JSX.Element => { const transform = `rotation(${rotationAngle},0,0)`; // Each marker definition needs a unique ID or colours overlap - const uid = uuidv4(); + const uid = crypto.randomUUID(); // Create a marker if arrows set let arrowConfig = {}; From 4c1cec7cd7726c1aef7e71978b33282e8a521086 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 10 Jun 2026 11:01:40 +0100 Subject: [PATCH 04/16] Dropping UUID from package.json --- package-lock.json | 17 +---------------- package.json | 3 +-- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e22670..b258234 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,7 @@ "react-grid-layout": "^2.2.3", "react-plotly.js": "^2.6.0", "react-toastify": "^11.0.5", - "utf-8-validate": "^5.0.10", - "uuid": "^9.0.1" + "utf-8-validate": "^5.0.10" }, "devDependencies": { "@apollo/client": "^3.11.8", @@ -17563,20 +17562,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index e5f21d4..37a0dd6 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,7 @@ "react-grid-layout": "^2.2.3", "react-plotly.js": "^2.6.0", "react-toastify": "^11.0.5", - "utf-8-validate": "^5.0.10", - "uuid": "^9.0.1" + "utf-8-validate": "^5.0.10" }, "devDependencies": { "@apollo/client": "^3.11.8", From 5c6fc7e0faf14d34d016224111da612fe9eeabff Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Thu, 11 Jun 2026 16:08:35 +0100 Subject: [PATCH 05/16] Create a display instance cache in the FileCache slice, use it to store live widget props. --- package-lock.json | 10 + package.json | 1 + src/redux/slices/fileCacheSlice.test.ts | 14 +- src/redux/slices/fileCacheSlice.ts | 183 ++++++++++++++---- src/ui/hooks/useFile.tsx | 43 +++- .../displayGridLayout.tsx | 11 +- .../displayResponsive.test.tsx | 4 +- .../displayResponsive.tsx | 19 +- src/ui/widgets/DynamicPage/dynamicPage.tsx | 7 +- .../EmbeddedDisplay/embeddedDisplay.tsx | 20 +- src/ui/widgets/createComponent.tsx | 16 ++ src/ui/widgets/widgetProps.ts | 7 +- 12 files changed, 255 insertions(+), 80 deletions(-) diff --git a/package-lock.json b/package-lock.json index b258234..c99e08f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "react-grid-layout": "^2.2.3", "react-plotly.js": "^2.6.0", "react-toastify": "^11.0.5", + "safe-stable-stringify": "^2.5.0", "utf-8-validate": "^5.0.10" }, "devDependencies": { @@ -16097,6 +16098,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", diff --git a/package.json b/package.json index 37a0dd6..bd63d73 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "react-grid-layout": "^2.2.3", "react-plotly.js": "^2.6.0", "react-toastify": "^11.0.5", + "safe-stable-stringify": "^2.5.0", "utf-8-validate": "^5.0.10" }, "devDependencies": { diff --git a/src/redux/slices/fileCacheSlice.test.ts b/src/redux/slices/fileCacheSlice.test.ts index 100ec74..cbdf494 100644 --- a/src/redux/slices/fileCacheSlice.test.ts +++ b/src/redux/slices/fileCacheSlice.test.ts @@ -6,8 +6,8 @@ import fileCacheReducer, { FileCacheState, fileChanged, fileComparator, - fileDisplaySetGridLayout, - fileDisplaySetResponsiveLayout, + displayInstanceSetGridLayout, + displayInstanceSetResponsiveLayout, makeSelectWidgetPosition, refreshFile, selectFile @@ -46,7 +46,7 @@ describe("fileDisplaySetResponsiveLayout", () => { }; test("applies responsive layout and updates child positions", () => { - const action = fileDisplaySetResponsiveLayout({ + const action = displayInstanceSetResponsiveLayout({ file: "file.bob", displayId: "display1", responsiveLayouts: { lg: [] }, @@ -84,7 +84,7 @@ describe("fileDisplaySetResponsiveLayout", () => { } }; - const action = fileDisplaySetResponsiveLayout({ + const action = displayInstanceSetResponsiveLayout({ file: "file.bob", displayId: "display1", responsiveLayouts: {}, @@ -123,7 +123,7 @@ describe("fileDisplaySetGridLayout", () => { }; test("applies grid layout properties and normalises child positions", () => { - const action = fileDisplaySetGridLayout({ + const action = displayInstanceSetGridLayout({ file: "file.bob", displayId: "display1", gridLayout: [{ i: "child1", x: 0, y: 0, w: 2, h: 2 }], @@ -150,7 +150,7 @@ describe("fileDisplaySetGridLayout", () => { }); test("does nothing if display not found", () => { - const action = fileDisplaySetGridLayout({ + const action = displayInstanceSetGridLayout({ file: "file.bob", displayId: "missing", gridLayout: [], @@ -176,7 +176,7 @@ describe("fileDisplaySetGridLayout", () => { } }; - const action = fileDisplaySetGridLayout({ + const action = displayInstanceSetGridLayout({ file: "file.bob", displayId: "display1", gridLayout: [], diff --git a/src/redux/slices/fileCacheSlice.ts b/src/redux/slices/fileCacheSlice.ts index db209a2..49c483f 100644 --- a/src/redux/slices/fileCacheSlice.ts +++ b/src/redux/slices/fileCacheSlice.ts @@ -1,19 +1,53 @@ // fileCacheSlice.ts -import { createSlice, PayloadAction, createSelector } from "@reduxjs/toolkit"; -import { WidgetDescription } from "../../ui/widgets/createComponent"; +import { + createSlice, + PayloadAction, + createSelector, + current +} from "@reduxjs/toolkit"; +import { + injectFieldsIntoAllDescriptions, + WidgetDescription +} from "../../ui/widgets/createComponent"; import { findWidgetById } from "./storeUtils"; import { Position } from "../../types"; +import { MacroMap } from "../../types/macros"; +import stringify from "safe-stable-stringify"; export interface FileCache { - [fileName: string]: WidgetDescription; + [fileId: string]: WidgetDescription; +} + +export interface DisplayInstance { + description: WidgetDescription; + fileId: string; + macros: MacroMap; + hash: string; + uuid: string; // universally unique id +} + +export interface DisplayInstanceCache { + [uuid: string]: DisplayInstance; } export interface FileCacheState { + // The file cache should represent files loaded from the server, it should be immutable. fileCache: FileCache; + + // The display instance cache contains a instances of the displays, + // these have had some macros applied and are mutable representations of embedded displays. + displayInstanceCache: DisplayInstanceCache; + + // A combination of file path and macro set can be used to look-up the display instance uuid + displayInstanceIndex: { + [hash: string]: string; + }; } const initialState: FileCacheState = { - fileCache: {} + fileCache: {}, + displayInstanceCache: {}, + displayInstanceIndex: {} }; const fileCacheSlice = createSlice({ @@ -30,12 +64,21 @@ const fileCacheSlice = createSlice({ refreshFile(state, action: PayloadAction<{ file: string }>) { delete state.fileCache[action.payload.file]; + + Object.entries(state.displayInstanceCache).forEach(([uuid, inst]) => { + if (inst.fileId === action.payload.file) { + if (state.displayInstanceIndex[inst.hash] === uuid) { + delete state.displayInstanceIndex[inst.hash]; + } + delete state.displayInstanceCache[uuid]; + } + }); }, - fileDisplaySetGridLayout(state, action) { + displayInstanceSetGridLayout(state, action) { const { - file, - displayId, + embeddedDisplayUuid, + gridDisplayId, gridLayout, gridLayoutColumns, gridCellMargins, @@ -44,8 +87,11 @@ const fileCacheSlice = createSlice({ gridCellResizeEnabled } = action.payload; - const fileDescription = state.fileCache[file]; - const display = findWidgetById([fileDescription], displayId); + const displayInstance = state.displayInstanceCache[embeddedDisplayUuid]; + const display = findWidgetById( + [displayInstance.description], + gridDisplayId + ); if (!display || display.type !== "displayGridLayout") return; @@ -69,9 +115,9 @@ const fileCacheSlice = createSlice({ }); }, - fileDisplaySetResponsiveLayout(state, action) { + displayInstanceSetResponsiveLayout(state, action) { const { - file, + embeddedDisplayUuid, displayId, responsiveLayouts, responsiveColumns, @@ -82,8 +128,8 @@ const fileCacheSlice = createSlice({ gridCellResizeEnabled } = action.payload; - const fileDescription = state.fileCache[file]; - const display = findWidgetById([fileDescription], displayId); + const displayInstance = state.displayInstanceCache[embeddedDisplayUuid]; + const display = findWidgetById([displayInstance.description], displayId); if (!display || display.type !== "displayResponsive") return; @@ -111,38 +157,114 @@ const fileCacheSlice = createSlice({ } }); }, - fileDisplayUpdateResponsiveLayout(state, action) { - const { file, displayId, responsiveLayouts } = action.payload; - const fileDescription = state.fileCache[file]; - const display = findWidgetById([fileDescription], displayId); + displayInstanceUpdateResponsiveLayout(state, action) { + const { embeddedDisplayUuid, displayId, responsiveLayouts } = + action.payload; + + const displayInstance = state.displayInstanceCache[embeddedDisplayUuid]; + const display = findWidgetById([displayInstance.description], displayId); if (!display || display.type !== "displayResponsive") return; display.responsiveLayouts = responsiveLayouts; + }, + + createDisplayInstanceFromFile(state, action) { + const { file, macros } = action.payload; + const fileDescription = state.fileCache[file]; + + const hash = `${file}::${stringify(macros)}`; + + if ( + Object.values(state.displayInstanceCache).some( + inst => inst.hash === hash + ) + ) { + return; + } + + const uuid = crypto.randomUUID(); + const description = structuredClone(current(fileDescription)); + injectFieldsIntoAllDescriptions(description, { + embeddedDisplayUuid: uuid + }); + + state.displayInstanceCache[uuid] = { + description: description, + fileId: file, + macros: macros, + uuid, + hash + }; + + state.displayInstanceIndex[hash] = uuid; } }, selectors: { - selectFileCache: state => state.fileCache + selectFileCache: state => state.fileCache, + selectDisplayInstanceCache: state => state.displayInstanceCache, + selectDisplayInstanceIndex: state => state.displayInstanceIndex } }); export const { fileChanged, refreshFile, - fileDisplaySetGridLayout, - fileDisplaySetResponsiveLayout, - fileDisplayUpdateResponsiveLayout + displayInstanceSetGridLayout, + displayInstanceSetResponsiveLayout, + displayInstanceUpdateResponsiveLayout, + createDisplayInstanceFromFile } = fileCacheSlice.actions; export default fileCacheSlice.reducer; -export const { selectFileCache } = fileCacheSlice.selectors; +export const { + selectFileCache, + selectDisplayInstanceCache, + selectDisplayInstanceIndex +} = fileCacheSlice.selectors; export const selectFile = createSelector( [selectFileCache, (_state, fileId: string) => fileId], (fileCache, fileId) => fileCache[fileId] ); +export const selectDisplayInstance = createSelector( + [selectDisplayInstanceCache, (_state, uuid: string) => uuid], + (displayInstanceCache, uuid) => displayInstanceCache[uuid] +); + +export const selectDisplayInstanceByFileAndMacros = createSelector( + [ + selectDisplayInstanceIndex, + selectDisplayInstanceCache, + (_state, file: string) => file, + (_state, _file, macros: MacroMap) => macros + ], + (index, displayInstanceCache, file, macros) => { + const hash = `${file}::${stringify(macros)}`; + const id = index[hash]; + return id ? displayInstanceCache[id] : undefined; + } +); + +/** + * This selector factory provides an alternative means for a widget to get its + * position props. Generally the wrapper should manage position and the + * useContainerWidth hook should be used to get a measured width and height. + * But in some rare situations these props need be be known before first render + * and are not expected to change, for example through a react grid layout resize. + * @returns A new selector that gets the widget position properties + */ +export const makeSelectWidgetPosition = () => + createSelector( + [selectFile, (_state: any, _fileId: string, widgetId: string) => widgetId], + (file, widgetId) => + file + ? (findWidgetById([file], widgetId)?.position as Position | undefined) + : undefined + ); + export const fileComparator = ( before: WidgetDescription, after: WidgetDescription @@ -163,20 +285,3 @@ export const fileComparator = ( } return true; }; - -/** - * This selector factory provides an alternative means for a widget to get its - * position props. Generally the wrapper should manage position and the - * useContainerWidth hook should be used to get a measured width and height. - * But in some rare situations these props need be be known before first render - * and are not expected to change, for example through a react grid layout resize. - * @returns A new selector that gets the widget position properties - */ -export const makeSelectWidgetPosition = () => - createSelector( - [selectFile, (_state: any, _fileId: string, widgetId: string) => widgetId], - (file, widgetId) => - file - ? (findWidgetById([file], widgetId)?.position as Position | undefined) - : undefined - ); diff --git a/src/ui/hooks/useFile.tsx b/src/ui/hooks/useFile.tsx index a6f5c9e..ae922d1 100644 --- a/src/ui/hooks/useFile.tsx +++ b/src/ui/hooks/useFile.tsx @@ -3,7 +3,9 @@ import { fileChanged, refreshFile as refreshFileAction, selectFile, - fileComparator + fileComparator, + selectDisplayInstanceByFileAndMacros, + createDisplayInstanceFromFile } from "../../redux/slices/fileCacheSlice"; import { MacroMap } from "../../types/macros"; import { errorWidget, WidgetDescription } from "../widgets/createComponent"; @@ -16,6 +18,7 @@ import { parseOpi } from "../widgets/EmbeddedDisplay/opiParser"; import { Store } from "redux"; import { newAbsolutePosition } from "../../types/position"; +export const EMPTY_WIDGET_ID = "EMPTY_WIDGET"; export const EMPTY_WIDGET: WidgetDescription = { type: "shape", id: "EMPTY_WIDGET", @@ -80,10 +83,17 @@ async function fetchAndConvert( } } -export function useFile(file: File, macros?: MacroMap): WidgetDescription { +export function useFile( + file: File, + macros?: MacroMap +): [WidgetDescription, string] { const dispatch = useDispatch(); - const contents = useSelector( + const displayInstance = useSelector(state => + selectDisplayInstanceByFileAndMacros(state, file.path, macros ?? {}) + ); + + const fileContents = useSelector( (state): any => selectFile(state, file.path), fileComparator ); @@ -99,21 +109,42 @@ export function useFile(file: File, macros?: MacroMap): WidgetDescription { // Populate the file cache. if (isMounted) { dispatch(fileChanged({ file: file.path, contents: widgetDescription })); + dispatch( + createDisplayInstanceFromFile({ + file: file.path, + macros: macros ?? {} + }) + ); } }; - if (contents == null) { + if (fileContents == null && displayInstance == null) { fetchData(); + } else if (displayInstance == null) { + dispatch( + createDisplayInstanceFromFile({ file: file.path, macros: macros ?? {} }) + ); } + let isMounted = true; // Tidy up in case component is unmounted return () => { isMounted = false; }; - }, [file.path, file.defaultProtocol, contents, dispatch, macros]); + }, [ + file.path, + file.defaultProtocol, + fileContents, + dispatch, + macros, + displayInstance + ]); - return contents || EMPTY_WIDGET; + return [ + displayInstance?.description || EMPTY_WIDGET, + displayInstance?.uuid ?? "EMPTY_WIDGET" + ]; } export function refreshFile(store: Store, file: string): void { diff --git a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx index 130b40f..ea7932a 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx @@ -40,7 +40,7 @@ import { import { useStyle } from "../../hooks/useStyle"; import { calculateDefaultLayout, toNumber } from "./displayLayoutUtilities"; import { - fileDisplaySetGridLayout, + displayInstanceSetGridLayout, makeSelectWidgetPosition } from "../../../redux/slices/fileCacheSlice"; import { useDispatch, useSelector } from "react-redux"; @@ -76,6 +76,7 @@ export const DisplayGridLayoutComponent = ( props: InferWidgetProps & { id: string; fileId: string; + embeddedDisplayUuid: string; } ): JSX.Element => { // Macros specific to this display. Children of this component @@ -167,9 +168,9 @@ export const DisplayGridLayoutComponent = ( cellHeight ); dispatch( - fileDisplaySetGridLayout({ - file: props.fileId, - displayId: props.id, + displayInstanceSetGridLayout({ + embeddedDisplayUuid: props.embeddedDisplayUuid, + gridDisplayId: props.id, gridLayout: calculatedLayout, gridLayoutColumns: columns, gridCellMargins: cellMargins, @@ -180,7 +181,7 @@ export const DisplayGridLayoutComponent = ( ); }, [ dispatch, - props.fileId, + props.embeddedDisplayUuid, props.id, props.gridLayout, childrenArray, diff --git a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx index cb29364..3d9c84e 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx @@ -4,7 +4,7 @@ import { render, screen } from "@testing-library/react"; import "@testing-library/jest-dom"; import { DisplayResponsiveComponent } from "./displayResponsive"; -import { fileDisplaySetResponsiveLayout } from "../../../redux/slices/fileCacheSlice"; +import { displayInstanceSetResponsiveLayout } from "../../../redux/slices/fileCacheSlice"; import { calculateDefaultLayoutWithHorizontalCompactor } from "./displayLayoutUtilities"; let capturedLayouts: any; @@ -263,7 +263,7 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { const dispatchedArg = dispatchMock.mock.calls[0][0]; expect(dispatchedArg).toEqual( - fileDisplaySetResponsiveLayout( + displayInstanceSetResponsiveLayout( expect.objectContaining({ displayId: "display-1", file: "file-1", diff --git a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx index 057d91c..481bbde 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx @@ -48,8 +48,8 @@ import { sameKeys } from "./displayLayoutUtilities"; import { - fileDisplaySetResponsiveLayout, - fileDisplayUpdateResponsiveLayout + displayInstanceSetResponsiveLayout, + displayInstanceUpdateResponsiveLayout } from "../../../redux/slices/fileCacheSlice"; import log from "loglevel"; import { Dispatch } from "@reduxjs/toolkit"; @@ -84,6 +84,7 @@ const DisplayResponsiveProps = { type propsType = InferWidgetProps & { id: string; fileId: string; + embeddedDisplayUuid: string; }; // Display widget that uses react-grid-layout to provide a responsive drag and drop container @@ -200,7 +201,7 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { () => calculateLayout( props.id, - props.fileId, + props.embeddedDisplayUuid, props.responsiveLayouts as ResponsiveLayouts, areBreakpointsConsistent, breakpoints, @@ -214,7 +215,7 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { ), [ dispatch, - props.fileId, + props.embeddedDisplayUuid, props.id, props.responsiveLayouts, childrenArray, @@ -274,8 +275,8 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { onLayoutChange={(layout, layouts) => { if (!isInteractingRef.current && shouldCommitRef.current) { dispatch( - fileDisplayUpdateResponsiveLayout({ - file: props.fileId, + displayInstanceUpdateResponsiveLayout({ + embeddedDisplayUuid: props.embeddedDisplayUuid, displayId: props.id, responsiveLayouts: layouts }) @@ -337,7 +338,7 @@ registerWidget(DisplayResponsive, DisplayResponsiveWidgetProps, widgetName); const calculateLayout = ( id: string, - fileId: string, + embeddedDisplayUuid: string, responsiveLayouts: ResponsiveLayouts, areBreakpointsConsistent: boolean, breakpoints: Breakpoints, @@ -373,8 +374,8 @@ const calculateLayout = ( ); dispatch( - fileDisplaySetResponsiveLayout({ - file: fileId, + displayInstanceSetResponsiveLayout({ + embeddedDisplayUuid, displayId: id, responsiveLayouts: computedResponsiveLayouts, responsiveColumns: columns, diff --git a/src/ui/widgets/DynamicPage/dynamicPage.tsx b/src/ui/widgets/DynamicPage/dynamicPage.tsx index 119e074..f575ed1 100644 --- a/src/ui/widgets/DynamicPage/dynamicPage.tsx +++ b/src/ui/widgets/DynamicPage/dynamicPage.tsx @@ -93,7 +93,7 @@ export const DynamicPageComponent = ( mjpgEndpoints={[props?.mjpgEndpoint, defaultMjpgEndpoint].filter( x => x != null )} - fileDetailsCallback={props?.fileDetailsCallback} + widgetIdsCallback={props?.widgetIdsCallback} />
x != null )} - fileDetailsCallback={props?.fileDetailsCallback} + widgetIdsCallback={props?.widgetIdsCallback} /> ); @@ -156,7 +156,8 @@ const DynamicPageWidgetProps = { }; export const DynamicPageWidget = ( - props: InferWidgetProps + props: InferWidgetProps & + EmbeddedDisplayPropsExtra ): JSX.Element => ; registerWidget(DynamicPageWidget, DynamicPageWidgetProps, widgetName); diff --git a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx index ad3a47b..ecd259c 100644 --- a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx +++ b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.tsx @@ -41,7 +41,7 @@ const RESIZE_STRINGS = [ export interface EmbeddedDisplayPropsExtra { theme?: Theme; - fileDetailsCallback?: (fileId: string, id: string) => void; + widgetIdsCallback?: (embeddedDisplayUuid: string, id: string) => void; } const EmbeddedDisplayProps = { @@ -87,17 +87,22 @@ export const EmbeddedDisplay = ( ); const resolvedProps = useRules(macroProps); - const description = useFile( + const [description, embeddedDisplayUuid] = useFile( resolvedProps.file as File, embeddedDisplayMacroContext.macros ); - const fileDetailsCallback = props?.fileDetailsCallback; + const widgetIdsCallback = props?.widgetIdsCallback; useEffect(() => { - if (fileDetailsCallback && description !== EMPTY_WIDGET) { - fileDetailsCallback(description?.fileId, description?.id); + if (widgetIdsCallback && description.fileId !== EMPTY_WIDGET.fileId) { + widgetIdsCallback(embeddedDisplayUuid, description.id); } - }, [fileDetailsCallback, description]); + }, [ + widgetIdsCallback, + embeddedDisplayUuid, + description.fileId, + description.id + ]); let resize = resolvedProps.resize || "scroll-content"; // If number, convert back to string @@ -260,7 +265,8 @@ export const EmbeddedDisplay = ( component = widgetDescriptionToComponent( { type: "display", - id: `display_${crypto.randomUUID()}`, + id: `display_${embeddedDisplayUuid}`, + embeddedDisplayUuid: embeddedDisplayUuid, fileId: props?.file?.path, position: resolvedProps.position, backgroundColor: diff --git a/src/ui/widgets/createComponent.tsx b/src/ui/widgets/createComponent.tsx index a0a8b44..594eafe 100644 --- a/src/ui/widgets/createComponent.tsx +++ b/src/ui/widgets/createComponent.tsx @@ -117,3 +117,19 @@ export function widgetDescriptionToComponent( ); } + +/** + * Adds the specified fields to all nodes of the WidgetDescription tree in place + * @param node The current WidgetDescription instance + * @param fields The fields to add. + */ +export const injectFieldsIntoAllDescriptions = ( + node: WidgetDescription, + fields: Record +): void => { + Object.assign(node, fields); + + node?.children?.forEach(child => { + injectFieldsIntoAllDescriptions(child, fields); + }); +}; diff --git a/src/ui/widgets/widgetProps.ts b/src/ui/widgets/widgetProps.ts index 01af093..d4743f4 100644 --- a/src/ui/widgets/widgetProps.ts +++ b/src/ui/widgets/widgetProps.ts @@ -10,7 +10,8 @@ import { PvTypePropOpt, PVMetadataType, ScriptsPropOpt, - StringArrayPropOpt + StringArrayPropOpt, + FuncPropOpt } from "./propTypes"; import { GenericProp } from "../../types/props"; @@ -20,13 +21,15 @@ import { File } from "../hooks/useFile"; // Internal prop types object for properties which are not in a standard widget const BasicPropsType = { id: StringPropOpt, + embeddedDisplayUuid: StringPropOpt, rules: RulesPropOpt, scripts: ScriptsPropOpt, actions: ActionsPropType, tooltip: StringPropOpt, border: BorderPropOpt, visible: BoolPropOpt, - mjpgEndpoints: StringArrayPropOpt + mjpgEndpoints: StringArrayPropOpt, + widgetIdsCallback: FuncPropOpt }; const PositionPropsType = { From 19ecce77142744642775d83e57ec652d35406a7c Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Fri, 12 Jun 2026 16:30:36 +0100 Subject: [PATCH 06/16] Overhaul tests for embedded display, dynamic page and use file, add additional tests to fileCacheSlice --- src/redux/slices/fileCacheSlice.test.ts | 320 ++++++- src/redux/slices/fileCacheSlice.ts | 79 +- src/testResources.tsx | 12 +- src/ui/hooks/useFile.test.tsx | 252 +++-- src/ui/hooks/useFile.tsx | 3 +- .../displayResponsive.test.tsx | 3 +- .../widgets/DynamicPage/dynamicPage.test.tsx | 263 ++++-- .../EmbeddedDisplay/embeddedDisplay.test.tsx | 863 +++++++++++------- 8 files changed, 1273 insertions(+), 522 deletions(-) diff --git a/src/redux/slices/fileCacheSlice.test.ts b/src/redux/slices/fileCacheSlice.test.ts index cbdf494..6b95408 100644 --- a/src/redux/slices/fileCacheSlice.test.ts +++ b/src/redux/slices/fileCacheSlice.test.ts @@ -10,7 +10,11 @@ import fileCacheReducer, { displayInstanceSetResponsiveLayout, makeSelectWidgetPosition, refreshFile, - selectFile + selectFile, + createDisplayInstanceFromFile, + displayInstanceUpdateResponsiveLayout, + selectDisplayInstance, + selectDisplayInstanceByFileAndMacros } from "./fileCacheSlice"; const initialState: FileCacheState = { @@ -21,7 +25,22 @@ const initialState: FileCacheState = { type: "ellipse", position: newAbsolutePosition("0", "0", "0", "0") } - } + }, + displayInstanceCache: { + UUID1: { + fileId: "mySecondFile.bob", + macros: { a: "b" }, + hash: "", + uuid: "UUID1", + description: { + fileId: "mySecondFile.bob", + id: "123", + type: "ellipse", + position: newAbsolutePosition("0", "0", "0", "0") + } + } + }, + displayInstanceIndex: {} }; describe("fileDisplaySetResponsiveLayout", () => { @@ -31,6 +50,7 @@ describe("fileDisplaySetResponsiveLayout", () => { fileId: "file", children: [ { + fileId: "file", id: "child1", type: "shape", position: newAbsolutePosition("10", "10", "20", "20") @@ -42,12 +62,22 @@ describe("fileDisplaySetResponsiveLayout", () => { const initialState: FileCacheState = { fileCache: { "file.bob": baseDisplay as any - } + }, + displayInstanceCache: { + UUID1: { + fileId: "file.bob", + macros: { a: "b" }, + hash: "", + uuid: "UUID1", + description: baseDisplay + } + }, + displayInstanceIndex: {} }; test("applies responsive layout and updates child positions", () => { const action = displayInstanceSetResponsiveLayout({ - file: "file.bob", + embeddedDisplayUuid: "UUID1", displayId: "display1", responsiveLayouts: { lg: [] }, responsiveColumns: { lg: 12 }, @@ -59,7 +89,7 @@ describe("fileDisplaySetResponsiveLayout", () => { }); const state = fileCacheReducer(initialState, action); - const display = state.fileCache["file.bob"]; + const display = state.displayInstanceCache["UUID1"]?.description; expect(display.responsiveColumns.lg).toBe(12); expect(display.gridCellHeight).toBe(50); @@ -85,7 +115,7 @@ describe("fileDisplaySetResponsiveLayout", () => { }; const action = displayInstanceSetResponsiveLayout({ - file: "file.bob", + embeddedDisplayUuid: "file.bob", displayId: "display1", responsiveLayouts: {}, responsiveColumns: {}, @@ -110,22 +140,35 @@ describe("fileDisplaySetGridLayout", () => { { id: "child1", type: "shape", + fileId: "file", position: newAbsolutePosition("10", "10", "20", "20") } ], position: newAbsolutePosition("0", "0", "100", "100") }; + const baseDisplayInstance = { + uuid: "UUID1", + fileId: "mySecondFile.bob", + macros: { a: "b" }, + hash: "", + description: baseDisplay + }; + const initialState: FileCacheState = { fileCache: { "file.bob": baseDisplay as any - } + }, + displayInstanceCache: { + UUID1: baseDisplayInstance + }, + displayInstanceIndex: {} }; - test("applies grid layout properties and normalises child positions", () => { + it("applies grid layout properties and normalises child positions", () => { const action = displayInstanceSetGridLayout({ - file: "file.bob", - displayId: "display1", + embeddedDisplayUuid: "UUID1", + gridDisplayId: "display1", gridLayout: [{ i: "child1", x: 0, y: 0, w: 2, h: 2 }], gridLayoutColumns: 12, gridCellMargins: [5, 5], @@ -135,7 +178,7 @@ describe("fileDisplaySetGridLayout", () => { }); const state = fileCacheReducer(initialState, action); - const display = state.fileCache["file.bob"]; + const display = state.displayInstanceCache["UUID1"]?.description; expect(display.gridLayoutColumns).toBe(12); expect(display.gridCellHeight).toBe(30); @@ -149,10 +192,10 @@ describe("fileDisplaySetGridLayout", () => { }); }); - test("does nothing if display not found", () => { + it("does nothing if display not found", () => { const action = displayInstanceSetGridLayout({ - file: "file.bob", - displayId: "missing", + embeddedDisplayUuid: "UUID1", + gridDisplayId: "missing", gridLayout: [], gridLayoutColumns: 12, gridCellMargins: [0, 0], @@ -165,20 +208,27 @@ describe("fileDisplaySetGridLayout", () => { expect(state).toEqual(initialState); }); - test("does nothing if wrong display type", () => { + it("does nothing if wrong display type", () => { const badState: FileCacheState = { ...initialState, - fileCache: { - "file.bob": { - ...baseDisplay, - type: "shape" // wrong type - } as any + displayInstanceCache: { + ...initialState.displayInstanceCache, + UUID2: { + uuid: "UUID2", + fileId: "mySecondFile.bob", + macros: { a: "c" }, + hash: "", + description: { + ...baseDisplay, + type: "shape" + } + } } }; const action = displayInstanceSetGridLayout({ - file: "file.bob", - displayId: "display1", + embeddedDisplayUuid: "UUID2", + gridDisplayId: "display1", gridLayout: [], gridLayoutColumns: 12, gridCellMargins: [0, 0], @@ -190,6 +240,30 @@ describe("fileDisplaySetGridLayout", () => { const state = fileCacheReducer(badState, action); expect(state).toEqual(badState); }); + + it("does nothing if display instance missing", () => { + const state: FileCacheState = { + fileCache: {}, + displayInstanceCache: {}, + displayInstanceIndex: {} + }; + + const result = fileCacheReducer( + state, + displayInstanceSetGridLayout({ + embeddedDisplayUuid: "missing", + gridDisplayId: "id", + gridLayout: [], + gridLayoutColumns: 12, + gridCellMargins: [0, 0], + gridCellHeight: 10, + gridCellDragEnabled: true, + gridCellResizeEnabled: true + }) + ); + + expect(result).toEqual(state); + }); }); describe("FILE_CHANGED", (): void => { @@ -212,7 +286,7 @@ describe("FILE_CHANGED", (): void => { }); describe("REFRESH_FILE", (): void => { - test("csReducer deletes the file entry from fileCache", (): void => { + it("deletes the file entry from fileCache", (): void => { const fileName = "mySecondFile.bob"; const action: ReturnType = { type: "fileCache/refreshFile", @@ -222,6 +296,31 @@ describe("REFRESH_FILE", (): void => { const newState = fileCacheReducer(initialState, action); expect(newState.fileCache[fileName]).toBeUndefined(); }); + + it("removes display instances linked to the file", () => { + const state: FileCacheState = { + fileCache: { + "file.bob": {} as any + }, + displayInstanceCache: { + uuid1: { + uuid: "uuid1", + fileId: "file.bob", + macros: {}, + hash: "file.bob::{}", + description: {} as any + } + }, + displayInstanceIndex: { + "file.bob::{}": "uuid1" + } + }; + + const result = fileCacheReducer(state, refreshFile({ file: "file.bob" })); + + expect(result.displayInstanceCache).toEqual({}); + expect(result.displayInstanceIndex).toEqual({}); + }); }); describe("selectFile", (): void => { @@ -255,6 +354,40 @@ describe("selectFile", (): void => { }); }); +describe("selectDisplayInstance", () => { + it("selectDisplayInstance returns correct instance", () => { + const state = createRootStoreState(); + + state.fileCache.displayInstanceCache = { + uuid1: { uuid: "uuid1" } as any + }; + + expect(selectDisplayInstance(state, "uuid1")).toEqual({ + uuid: "uuid1" + }); + }); +}); + +describe("selectDisplayInstanceByFileAndMacros", () => { + it("selectDisplayInstanceByFileAndMacros resolves correctly", () => { + const hash = "file::{}"; + + const state = createRootStoreState(undefined, undefined, { + fileCache: {}, + displayInstanceCache: { + uuid1: { uuid: "uuid1" } as any + }, + displayInstanceIndex: { + [hash]: "uuid1" + } + }); + + const result = selectDisplayInstanceByFileAndMacros(state, "file", {}); + + expect(result).toEqual({ uuid: "uuid1" }); + }); +}); + describe("makeSelectWidgetPosition", () => { const position = newAbsolutePosition("1", "2", "3", "4"); @@ -274,7 +407,9 @@ describe("makeSelectWidgetPosition", () => { const state = createRootStoreState(undefined, undefined, { fileCache: { "file.bob": file as any - } + }, + displayInstanceCache: {}, + displayInstanceIndex: {} }); test("returns widget position when found", () => { @@ -356,3 +491,140 @@ describe("fileComparator", (): void => { expect(fileComparator(contents, { ...contents })).toBe(true); }); }); + +describe("createDisplayInstanceFromFile", () => { + it("creates a new display instance", () => { + const state: FileCacheState = { + fileCache: { + "file.bob": { + id: "root", + type: "display", + fileId: "file.bob", + position: newAbsolutePosition("0", "0", "0", "0") + } + }, + displayInstanceCache: {}, + displayInstanceIndex: {} + }; + + const action = createDisplayInstanceFromFile({ + file: "file.bob", + macros: { a: "b" } + }); + + const result = fileCacheReducer(state, action); + + const instances = Object.values(result.displayInstanceCache); + + expect(instances).toHaveLength(1); + expect(instances[0].fileId).toBe("file.bob"); + + const hash = "file.bob::" + JSON.stringify({ a: "b" }); + expect(result.displayInstanceIndex[hash]).toBeDefined(); + }); + + it("does not create duplicate display instances", () => { + const hash = "file.bob::" + JSON.stringify({}); + + const state: FileCacheState = { + fileCache: { + "file.bob": { + id: "root", + type: "display", + fileId: "file.bob", + position: newAbsolutePosition("0", "0", "0", "0") + } + }, + displayInstanceCache: { + uuid1: { + uuid: "uuid1", + fileId: "file.bob", + macros: {}, + hash, + description: {} as any + } + }, + displayInstanceIndex: { + [hash]: "uuid1" + } + }; + + const action = createDisplayInstanceFromFile({ + file: "file.bob", + macros: {} + }); + + const result = fileCacheReducer(state, action); + + expect(Object.keys(result.displayInstanceCache)).toHaveLength(1); + }); +}); + +describe("displayInstanceUpdateResponsiveLayout", () => { + it("updates responsiveLayouts on existing display", () => { + const state: FileCacheState = { + fileCache: {}, + displayInstanceCache: { + uuid1: { + uuid: "uuid1", + fileId: "file", + macros: {}, + hash: "", + description: { + id: "d", + type: "displayResponsive", + responsiveLayouts: {}, + children: [] + } as any + } + }, + displayInstanceIndex: {} + }; + + const layouts = { lg: [] }; + + const result = fileCacheReducer( + state, + displayInstanceUpdateResponsiveLayout({ + embeddedDisplayUuid: "uuid1", + displayId: "d", + responsiveLayouts: layouts + }) + ); + + expect( + result.displayInstanceCache.uuid1.description.responsiveLayouts + ).toEqual(layouts); + }); + + it("does nothing if display not found or wrong type", () => { + const state: FileCacheState = { + fileCache: {}, + displayInstanceCache: { + uuid1: { + uuid: "uuid1", + fileId: "file", + macros: {}, + hash: "", + description: { + id: "d", + type: "shape", // wrong type + children: [] + } as any + } + }, + displayInstanceIndex: {} + }; + + const result = fileCacheReducer( + state, + displayInstanceUpdateResponsiveLayout({ + embeddedDisplayUuid: "uuid1", + displayId: "d", + responsiveLayouts: { lg: [] } + }) + ); + + expect(result).toEqual(state); + }); +}); diff --git a/src/redux/slices/fileCacheSlice.ts b/src/redux/slices/fileCacheSlice.ts index 49c483f..cf8cefa 100644 --- a/src/redux/slices/fileCacheSlice.ts +++ b/src/redux/slices/fileCacheSlice.ts @@ -13,6 +13,7 @@ import { findWidgetById } from "./storeUtils"; import { Position } from "../../types"; import { MacroMap } from "../../types/macros"; import stringify from "safe-stable-stringify"; +import { Breakpoints, Layout, ResponsiveLayouts } from "react-grid-layout"; export interface FileCache { [fileId: string]: WidgetDescription; @@ -23,7 +24,7 @@ export interface DisplayInstance { fileId: string; macros: MacroMap; hash: string; - uuid: string; // universally unique id + uuid: string; // universally unique id for a display } export interface DisplayInstanceCache { @@ -75,7 +76,19 @@ const fileCacheSlice = createSlice({ }); }, - displayInstanceSetGridLayout(state, action) { + displayInstanceSetGridLayout( + state, + action: PayloadAction<{ + embeddedDisplayUuid: string; + gridDisplayId: string; + gridLayout: Layout; + gridLayoutColumns: number; + gridCellMargins: [number, number]; + gridCellHeight: number; + gridCellDragEnabled: boolean; + gridCellResizeEnabled: boolean; + }> + ) { const { embeddedDisplayUuid, gridDisplayId, @@ -87,7 +100,11 @@ const fileCacheSlice = createSlice({ gridCellResizeEnabled } = action.payload; - const displayInstance = state.displayInstanceCache[embeddedDisplayUuid]; + const displayInstance = state.displayInstanceCache?.[embeddedDisplayUuid]; + if (!displayInstance) { + return; + } + const display = findWidgetById( [displayInstance.description], gridDisplayId @@ -115,7 +132,20 @@ const fileCacheSlice = createSlice({ }); }, - displayInstanceSetResponsiveLayout(state, action) { + displayInstanceSetResponsiveLayout( + state, + action: PayloadAction<{ + embeddedDisplayUuid: string; + displayId: string; + responsiveLayouts: ResponsiveLayouts; + responsiveColumns: Breakpoints; + responsiveBreakpoints: Breakpoints; + gridCellMargins: [number, number]; + gridCellHeight: number; + gridCellDragEnabled: boolean; + gridCellResizeEnabled: boolean; + }> + ) { const { embeddedDisplayUuid, displayId, @@ -128,7 +158,9 @@ const fileCacheSlice = createSlice({ gridCellResizeEnabled } = action.payload; - const displayInstance = state.displayInstanceCache[embeddedDisplayUuid]; + const displayInstance = state.displayInstanceCache?.[embeddedDisplayUuid]; + if (!displayInstance) return; + const display = findWidgetById([displayInstance.description], displayId); if (!display || display.type !== "displayResponsive") return; @@ -158,7 +190,14 @@ const fileCacheSlice = createSlice({ }); }, - displayInstanceUpdateResponsiveLayout(state, action) { + displayInstanceUpdateResponsiveLayout( + state, + action: PayloadAction<{ + embeddedDisplayUuid: string; + displayId: string; + responsiveLayouts: ResponsiveLayouts; + }> + ) { const { embeddedDisplayUuid, displayId, responsiveLayouts } = action.payload; @@ -171,12 +210,12 @@ const fileCacheSlice = createSlice({ createDisplayInstanceFromFile(state, action) { const { file, macros } = action.payload; - const fileDescription = state.fileCache[file]; + const fileDescription = state.fileCache?.[file]; const hash = `${file}::${stringify(macros)}`; if ( - Object.values(state.displayInstanceCache).some( + Object.values(state?.displayInstanceCache ?? {}).some( inst => inst.hash === hash ) ) { @@ -189,15 +228,17 @@ const fileCacheSlice = createSlice({ embeddedDisplayUuid: uuid }); - state.displayInstanceCache[uuid] = { - description: description, - fileId: file, - macros: macros, - uuid, - hash - }; + if (state.displayInstanceCache) { + state.displayInstanceCache[uuid] = { + description: description, + fileId: file, + macros: macros, + uuid, + hash + }; - state.displayInstanceIndex[hash] = uuid; + state.displayInstanceIndex[hash] = uuid; + } } }, selectors: { @@ -231,7 +272,7 @@ export const selectFile = createSelector( export const selectDisplayInstance = createSelector( [selectDisplayInstanceCache, (_state, uuid: string) => uuid], - (displayInstanceCache, uuid) => displayInstanceCache[uuid] + (displayInstanceCache, uuid) => displayInstanceCache?.[uuid] ); export const selectDisplayInstanceByFileAndMacros = createSelector( @@ -243,8 +284,8 @@ export const selectDisplayInstanceByFileAndMacros = createSelector( ], (index, displayInstanceCache, file, macros) => { const hash = `${file}::${stringify(macros)}`; - const id = index[hash]; - return id ? displayInstanceCache[id] : undefined; + const id = index?.[hash]; + return id ? displayInstanceCache?.[id] : undefined; } ); diff --git a/src/testResources.tsx b/src/testResources.tsx index 7f4e365..4ec811e 100644 --- a/src/testResources.tsx +++ b/src/testResources.tsx @@ -83,7 +83,11 @@ export const createRootStoreState = ( ) => ({ cs: csState ?? initialCsState, notifications: notifications ?? initialNotificationsState, - fileCache: fileCache ?? ({} as FileCache) + fileCache: fileCache ?? { + fileCache: {} as FileCache, + displayInstanceCache: {}, + displayInstanceIndex: {} + } }); export const contextWrapperGenerator = ( @@ -111,7 +115,11 @@ export const contextWrapperGenerator = ( preloadedState: { ...initialRootStoreState, cs: { ...initialRootStoreState.cs, globalMacros: extendedGlobalMacros }, - fileCache: { fileCache: {} } + fileCache: { + fileCache: {}, + displayInstanceCache: {}, + displayInstanceIndex: {} + } } }); diff --git a/src/ui/hooks/useFile.test.tsx b/src/ui/hooks/useFile.test.tsx index e7c0a55..e052c23 100644 --- a/src/ui/hooks/useFile.test.tsx +++ b/src/ui/hooks/useFile.test.tsx @@ -1,53 +1,63 @@ import React from "react"; import { contextRender, createRootStoreState } from "../../testResources"; -import { CsState } from "../../redux/csState"; import { File, useFile } from "./useFile"; -import { vi } from "vitest"; -import { act, screen } from "@testing-library/react"; +import { Mock, vi } from "vitest"; +import { waitFor } from "@testing-library/react"; import { ensureWidgetsRegistered } from "../widgets"; import { newAbsolutePosition, PositionType } from "../../types/position"; import { ColorUtils } from "../../types/color"; +import { + createDisplayInstanceFromFile, + fileChanged +} from "../../redux/slices/fileCacheSlice"; +import { httpRequest } from "../../misc"; +import { useSelector } from "react-redux"; + ensureWidgetsRegistered(); -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace NodeJS { - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface Global {} - } -} +vi.mock("../../misc", () => ({ + httpRequest: vi.fn() +})); +const mockedHttpRequest = httpRequest as unknown as Mock; +const mockedUseSelector = useSelector as unknown as Mock; +const mockDispatch = vi.fn(); + +vi.mock("react-redux", async () => { + const actual = await vi.importActual("react-redux"); + return { + ...actual, + useDispatch: () => mockDispatch, + useSelector: vi.fn() + }; +}); -interface GlobalFetch extends NodeJS.Global { - fetch: any; -} -const globalWithFetch = global as GlobalFetch; +const parsedWidget = { + id: "1234", + type: "ellipse", + fileId: "test.json", + children: [], + position: { positionType: PositionType.RELATIVE } +}; const FileTester = (props: { file: File }): JSX.Element => { - const contents = useFile(props.file); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [contents, _] = useFile(props.file); return
contents: {JSON.stringify(contents)}
; }; -function getFileState(): CsState { - return { - valueCache: {}, - subscriptions: {}, - globalMacros: {}, - effectivePvNameMap: {}, - deviceCache: {}, - pvwsSettings: {} - }; -} - describe("useFile", (): void => { - it("returns empty widget if file not in cache", (): void => { - const initialState = getFileState(); + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("returns empty widget if file not in cache", () => { const { getByText } = contextRender( , {}, {}, - createRootStoreState(initialState) + createRootStoreState() ); const responseContent = JSON.stringify({ @@ -60,55 +70,153 @@ describe("useFile", (): void => { expect(getByText(`contents: ${responseContent}`)).toBeInTheDocument(); }); - it("returns contents if file in cache", async (): Promise => { - const mockSuccessResponse = JSON.stringify({ + it("returns widget if instance is in cache", async () => { + mockedUseSelector + .mockReturnValueOnce({ + description: parsedWidget, + uuid: "uuid-1" + }) + .mockReturnValueOnce(parsedWidget); + + const { getByText } = contextRender( + , + {}, + {}, + createRootStoreState() + ); + + await waitFor(() => { + const text = getByText(/contents:/).textContent || ""; + + expect(text).toContain('"id":"1234"'); + expect(text).toContain('"fileId":"test.json"'); + }); + }); + + it("does not fetch file if file in cache, dispatches to create new display instance and updates UI after instance is available", async () => { + const file = { + path: "test.json", + defaultProtocol: "ca", + macros: {} + }; + + mockedUseSelector + .mockReturnValueOnce(null) + .mockReturnValueOnce(parsedWidget); + + const { getByText, rerender } = contextRender( + , + {}, + {}, + createRootStoreState() + ); + + await waitFor(() => { + expect(mockDispatch).toHaveBeenCalled(); + }); + + expect(mockedHttpRequest).toHaveBeenCalledTimes(0); + + expect(mockDispatch).not.toHaveBeenCalledWith( + fileChanged({ + file: "test.json", + contents: expect.objectContaining({ + id: "1234" + }) + }) + ); + + expect(mockDispatch).toHaveBeenCalledWith( + createDisplayInstanceFromFile({ + file: "test.json", + macros: {} + }) + ); + + mockedUseSelector + .mockReturnValueOnce({ + description: parsedWidget, + uuid: "uuid-1" + }) + .mockReturnValueOnce(parsedWidget); + + // Re-render + rerender(); + + await waitFor(() => { + const text = getByText(/contents:/).textContent || ""; + + expect(text).toContain('"id":"1234"'); + expect(text).toContain('"fileId":"test.json"'); + }); + }); + + it("fetches file if not in cache, dispatches file contents and updates UI after data is available", async () => { + const file = { + path: "test.json", + defaultProtocol: "ca", + macros: {} + }; + + const mockResponse = JSON.stringify({ id: "1234", type: "ellipse", - backgroundColor: ColorUtils.GREEN, - position: undefined + backgroundColor: ColorUtils.GREEN }); - const mockJsonPromise = Promise.resolve(mockSuccessResponse); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockJsonPromise + + mockedHttpRequest.mockResolvedValue({ + text: () => Promise.resolve(mockResponse) }); - const mockFetch = (): Promise => mockFetchPromise; - vi.spyOn(globalWithFetch, "fetch").mockImplementation(mockFetch); - const initialState = getFileState(); - await act(async () => { - contextRender( - , - {}, - {}, - createRootStoreState(initialState) - ); + + mockedUseSelector.mockReturnValueOnce(null).mockReturnValueOnce(null); + + const { getByText, rerender } = contextRender( + , + {}, + {}, + createRootStoreState() + ); + + await waitFor(() => { + expect(mockDispatch).toHaveBeenCalled(); }); - const responseContent = JSON.stringify({ - type: "ellipse", - position: { - x: "", - y: "", - width: "", - height: "", - margin: "", - padding: "", - minWidth: "", - maxWidth: "", - minHeight: "", - positionType: PositionType.RELATIVE - }, - backgroundColor: { colorString: "rgba(0,128,0,1)" }, - id: "1234", - children: [], - precisionFromPv: true, - showUnits: true, - wrapWords: true, - fileId: "test.json" + expect(mockedHttpRequest).toHaveBeenCalledTimes(1); + expect(mockedHttpRequest).toHaveBeenCalledWith("test.json"); + + expect(mockDispatch).toHaveBeenCalledWith( + fileChanged({ + file: "test.json", + contents: expect.objectContaining({ + id: "1234" + }) + }) + ); + + expect(mockDispatch).toHaveBeenCalledWith( + createDisplayInstanceFromFile({ + file: "test.json", + macros: {} + }) + ); + + mockedUseSelector + .mockReturnValueOnce({ + description: parsedWidget, + uuid: "uuid-1" + }) + .mockReturnValueOnce(parsedWidget); + + // Re-render + rerender(); + + await waitFor(() => { + const text = getByText(/contents:/).textContent || ""; + + expect(text).toContain('"id":"1234"'); + expect(text).toContain('"fileId":"test.json"'); }); - expect( - screen.getByText(`contents: ${responseContent}`) - ).toBeInTheDocument(); }); }); diff --git a/src/ui/hooks/useFile.tsx b/src/ui/hooks/useFile.tsx index ae922d1..7b4fbc4 100644 --- a/src/ui/hooks/useFile.tsx +++ b/src/ui/hooks/useFile.tsx @@ -117,6 +117,7 @@ export function useFile( ); } }; + let isMounted = true; if (fileContents == null && displayInstance == null) { fetchData(); @@ -126,8 +127,6 @@ export function useFile( ); } - let isMounted = true; - // Tidy up in case component is unmounted return () => { isMounted = false; diff --git a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx index 3d9c84e..989cdbb 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx @@ -249,6 +249,7 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { { displayInstanceSetResponsiveLayout( expect.objectContaining({ displayId: "display-1", - file: "file-1", + embeddedDisplayUuid: "uuid1", responsiveLayouts: { lg: expect.any(Array) } diff --git a/src/ui/widgets/DynamicPage/dynamicPage.test.tsx b/src/ui/widgets/DynamicPage/dynamicPage.test.tsx index 5848570..b22ec50 100644 --- a/src/ui/widgets/DynamicPage/dynamicPage.test.tsx +++ b/src/ui/widgets/DynamicPage/dynamicPage.test.tsx @@ -1,76 +1,237 @@ import React from "react"; +import { render } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach, Mock } from "vitest"; -import { waitFor } from "@testing-library/react"; import { DynamicPageComponent } from "./dynamicPage"; -import { PageState } from "../../../misc/fileContext"; -import { contextRender } from "../../../testResources"; +import { FileContext } from "../../../misc/fileContext"; -import { ensureWidgetsRegistered } from ".."; -import { vi } from "vitest"; -import { createMockStyle } from "../../../test-utils/styleTestUtils"; -ensureWidgetsRegistered(); +import { useSelector } from "react-redux"; +import { Theme } from "react-toastify"; vi.mock("../../hooks/useStyle", () => ({ - useStyle: vi.fn(() => createMockStyle()) + useStyle: () => ({ + border: {}, + colors: {}, + font: {}, + other: {} + }) })); -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace NodeJS { - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface Global {} +const mockEmbeddedDisplay = vi.fn((props?: any) => ( +
+)); + +vi.mock("../EmbeddedDisplay/embeddedDisplay", () => ({ + EmbeddedDisplay: (props: any) => { + mockEmbeddedDisplay(props); + return
; + } +})); + +const mockActionButton = vi.fn((props?: any) => ( +
+)); + +vi.mock("../ActionButton/actionButton", () => ({ + ActionButton: (props: any) => { + mockActionButton(props); + return
; } -} +})); + +vi.mock("react-redux", () => ({ + useSelector: vi.fn() +})); + +const renderWithContext = (ui: React.ReactNode, pageState: any = {}) => { + return render( + + {ui} + + ); +}; + +const mockedUseSelector = useSelector as unknown as Mock; -interface GlobalFetch extends NodeJS.Global { - fetch: any; -} -const globalWithFetch = global as GlobalFetch; +const baseProps = { + location: "test-location", + position: { x: "0", y: "0", width: "100%", height: "100%" } +}; -beforeEach((): void => { - // Ensure the fetch() function mock is always cleared. - vi.spyOn(globalWithFetch, "fetch").mockClear(); +beforeEach(() => { + vi.clearAllMocks(); }); -describe("", (): void => { - it("shows placeholder if no page is loaded", () => { - const { queryByText } = contextRender( - , - {}, +describe("DynamicPageComponent (unit)", () => { + beforeEach(() => { + vi.clearAllMocks(); + mockedUseSelector.mockReset(); + }); + + it("renders message when no file is loaded", () => { + const { getByText } = renderWithContext( + , {} ); - expect(queryByText(/.*no file loaded/)).toBeInTheDocument(); + + expect( + getByText(/Dynamic page "test-location": no file loaded/i) + ).toBeInTheDocument(); }); - it("loads a page", async (): Promise => { - const mockSuccessResponse = - '{"type": "display", "position": "relative", "children": [ { "type": "label", "position": "relative", "text": "hello" } ] }'; - const mockJsonPromise = Promise.resolve(mockSuccessResponse); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockJsonPromise + it("renders EmbeddedDisplay when file exists", () => { + const file = { path: "file1", macros: {} }; + + renderWithContext(, { + "test-location": file }); - const mockFetch = (): Promise => mockFetchPromise; - vi.spyOn(globalWithFetch, "fetch").mockImplementation(mockFetch); - - const initialPageState: PageState = { - testlocation: { - path: "/json/test.json", - macros: {}, - defaultProtocol: "pva" - } - }; - const { queryByText } = contextRender( - , - initialPageState + + expect(mockEmbeddedDisplay).toHaveBeenCalled(); + }); + + it("renders close button by default", () => { + const file = { path: "file1", macros: {} }; + + const { getByTestId } = renderWithContext( + , + { "test-location": file } + ); + + expect(getByTestId("action-button")).toBeInTheDocument(); + }); + + it("does not render close button when showCloseButton is false", () => { + const file = { path: "file1", macros: {} }; + + const { queryByTestId } = renderWithContext( + , + { "test-location": file } + ); + + expect(queryByTestId("action-button")).toBeNull(); + }); + + it("passes correct props to EmbeddedDisplay (default branch)", () => { + const file = { path: "file1", macros: {} }; + + renderWithContext(, { + "test-location": file + }); + + const props = mockEmbeddedDisplay.mock.calls[0][0]; + + expect(props.file).toBe(file); + expect(props.scroll).toBe(true); + expect(props.scalingOrigin).toBe("0 0"); + }); + + it("passes full-size position when showCloseButton is false", () => { + const file = { path: "file1", macros: {} }; + + renderWithContext( + , + { "test-location": file } ); - expect(queryByText("hello")).not.toBeInTheDocument(); + const props = mockEmbeddedDisplay.mock.calls[0][0]; - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith("/json/test.json"); + expect(props.position.width).toBe("100%"); + expect(props.position.height).toBe("100%"); + }); + + it("defaults scroll to false", () => { + const file = { path: "file1", macros: {} }; + + renderWithContext(, { + "test-location": file + }); + + const props = mockEmbeddedDisplay.mock.calls[0][0]; + + expect(props.scroll).toBe(false); + }); + + it("passes mjpgEndpoints combining custom and default", () => { + const file = { path: "file1", macros: {} }; + + mockedUseSelector.mockReturnValue("default-endpoint"); + + renderWithContext( + , + { "test-location": file } + ); + + const props = mockEmbeddedDisplay.mock.calls[0][0]; + + expect(props.mjpgEndpoints).toEqual([ + "custom-endpoint", + "default-endpoint" + ]); + }); + + it("filters out undefined mjpgEndpoints", () => { + const file = { path: "file1", macros: {} }; + + mockedUseSelector.mockReturnValue("default-endpoint"); + mockedUseSelector.mockReturnValue(undefined); + + renderWithContext(, { + "test-location": file + }); - await waitFor((): void => { - expect(queryByText("hello")).toBeInTheDocument(); + const props = mockEmbeddedDisplay.mock.calls[0][0]; + + expect(props.mjpgEndpoints).toEqual([]); + }); + + it("passes widgetIdsCallback to EmbeddedDisplay", () => { + const file = { path: "file1", macros: {} }; + const callback = vi.fn(); + + renderWithContext( + , + { "test-location": file } + ); + + const props = mockEmbeddedDisplay.mock.calls[0][0]; + + expect(props.widgetIdsCallback).toBe(callback); + }); + + it("passes custom theme to EmbeddedDisplay", () => { + const file = { path: "file1", macros: {} }; + const customTheme = {}; + + renderWithContext( + , + { "test-location": file } + ); + + const props = mockEmbeddedDisplay.mock.calls[0][0]; + + expect(props.theme).toBe(customTheme); + }); + + it("wires ActionButton with correct CLOSE_PAGE payload", () => { + const file = { path: "file1", macros: {} }; + + renderWithContext(, { + "test-location": file }); + + const actionProps = mockActionButton.mock.calls[0][0]; + const action = actionProps.actions.actions[0]; + + expect(action.dynamicInfo.name).toBe("test-location"); + expect(action.dynamicInfo.location).toBe("test-location"); + expect(action.dynamicInfo.file).toBe(file); + expect(action.dynamicInfo.description).toBe("Close"); }); }); diff --git a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx index e8d4f64..8420cf2 100644 --- a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx +++ b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx @@ -1,418 +1,579 @@ import React from "react"; -import log from "loglevel"; +import { render } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; + import { EmbeddedDisplay } from "./embeddedDisplay"; -import { waitFor, screen } from "@testing-library/react"; -import { newRelativePosition } from "../../../types/position"; -import { contextRender } from "../../../testResources"; -import { ensureWidgetsRegistered } from ".."; -import { vi } from "vitest"; -import * as useRulesModule from "../../hooks/useRules"; +import { MacroContext } from "../../../types/macros"; -ensureWidgetsRegistered(); +import { useFile } from "../../hooks/useFile"; +import { BorderStyle, newRelativePosition } from "../../../types"; +import { newBorder } from "../../../types/border"; +import { newColor } from "../../../types/color"; -interface GlobalFetch extends NodeJS.Global { - fetch: any; -} -const globalWithFetch = global as GlobalFetch; +vi.mock("../../hooks/useFile", () => ({ + useFile: vi.fn(), + EMPTY_WIDGET: { fileId: "EMPTY" } +})); vi.mock("../../hooks/useRules", () => ({ - useRules: vi.fn() + useRules: vi.fn(x => x) })); -vi.mocked(useRulesModule.useRules).mockImplementation(props => props); -beforeEach((): void => { - // Ensure the fetch() function mock is always cleared. - vi.spyOn(globalWithFetch, "fetch").mockClear(); - vi.mocked(useRulesModule.useRules).mockClear(); -}); +vi.mock("../../hooks/useMacros", () => ({ + recursiveResolve: vi.fn(x => x) +})); + +const mockWidgetRenderer = vi.fn((config: any) => ( +
+)); +vi.mock("../createComponent", () => ({ + widgetDescriptionToComponent: (...args: any[]) => mockWidgetRenderer(args), + errorWidget: (msg: string) => ({ type: "error", message: msg }) +})); + +vi.mock("../GroupBox/groupBox", () => ({ + GroupBoxComponent: ({ children }: any) => ( +
{children}
+ ) +})); + +vi.mock("react-id-generator", () => ({ + useId: () => ["test-id"] +})); + +vi.mock("../utils", () => ({ + getOptionalValue: (v: any, d: any) => (v !== undefined ? v : d), + trimFromString: (s: string | number) => + typeof s === "string" ? parseInt(s) : s +})); -describe("", (): void => { - it.each([ - ["/TestFile.bob", "/TestFile.bob"], - ["https://a.com/b.bob", "https://a.com/b.bob"], - ["/json/TestFile.json", "/json/TestFile.json"], - ["https://a.com/b.json", "https://a.com/b.json"], - ["/TestFile.opi", "/TestFile.opi"], - ["https://a.com/b.opi", "https://a.com/b.opi"] - ] as [string, string][])( - "fetches a file from the server", - async (inputFile: string, resolvedFile: string): Promise => { - const mockSuccessResponse = {}; - const mockTextPromise = Promise.resolve(mockSuccessResponse); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockTextPromise - }); - vi.spyOn(globalWithFetch, "fetch").mockImplementation( - (): Promise => mockFetchPromise - ); - - const props = { - position: newRelativePosition(), - file: { - path: inputFile, - defaultProtocol: "ca", - macros: {} - } - }; - - // Suppress logging for expected error. - log.setLevel("error"); - const { queryByText } = contextRender(); - - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith(resolvedFile); - - await waitFor((): void => { - expect(vi.mocked(useRulesModule.useRules)).toHaveBeenCalledWith( - expect.objectContaining(props) - ); - - expect(queryByText(/Error parsing.*/)).toBeInTheDocument(); - }); - log.setLevel("info"); - } +vi.mock("../../../types/color", () => ({ + newColor: () => "color" +})); + +vi.mock("../../../types/border", () => ({ + newBorder: (style: any) => ({ style }), + BorderStyle: { Line: "line", GroupBox: "groupbox" } +})); + +const baseProps = { + position: newRelativePosition(), + file: { path: "file", macros: {}, defaultProtocol: "ca" } +}; + +const renderWithContext = (ui: React.ReactNode) => { + return render( + + {ui} + ); - it("returns an error label when embedding a widget only", async (): Promise => { - const mockSuccessResponse = ` - - Label - From .bob file - 30 - 10 - 140 - `; - const mockTextPromise = Promise.resolve(mockSuccessResponse); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockTextPromise - }); +}; - vi.spyOn(globalWithFetch, "fetch").mockImplementation( - (): Promise => mockFetchPromise - ); +beforeEach(() => { + vi.clearAllMocks(); +}); - // Suppress logging for expected error. - log.setLevel("error"); - const { queryByText } = contextRender( - , - {}, - {} +describe("EmbeddedDisplay (unit)", () => { + it("renders component from description", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "display", + position: {}, + children: [] + }, + "uuid" + ]); + + renderWithContext(); + + expect(mockWidgetRenderer).toHaveBeenCalled(); + }); + + it("calls widgetIdsCallback when description is loaded", () => { + const callback = vi.fn(); + + vi.mocked(useFile).mockReturnValue([ + { + id: "desc-id", + fileId: "file1", + type: "dummy", + position: {}, + children: [] + }, + "uuid-123" + ]); + + renderWithContext( + ); - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith("/TestFile1.bob"); + expect(callback).toHaveBeenCalledWith("uuid-123", "desc-id"); + }); - await waitFor((): void => - expect(queryByText(/Error parsing.*/)).toBeInTheDocument() + it("applies scroll-content resize correctly", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: {}, + children: [] + }, + "uuid" + ]); + + renderWithContext( + ); - log.setLevel("info"); + + // verify widgetDescriptionToComponent received overflow auto + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.overflow).toBe("auto"); }); - it("converts a display with child widget", async (): Promise => { - const mockSuccessResponse = ` - - - Display - 200 - 350 - - Label - From .bob file - 30 - 10 - 140 - - `; - const mockTextPromise = Promise.resolve(mockSuccessResponse); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockTextPromise - }); + it("enables autoZoom for size-content", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: {}, + children: [] + }, + "uuid" + ]); + + renderWithContext(); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.autoZoomToFit).toBe(true); + }); - vi.spyOn(globalWithFetch, "fetch").mockImplementation( - (): Promise => mockFetchPromise - ); + it("filters children by groupName", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: {}, + children: [ + { + id: "124", + fileId: "file124", + type: "groupbox", + name: "A", + position: {}, + children: [] + }, + { + id: "125", + fileId: "file125", + type: "groupbox", + name: "B", + position: {}, + children: [] + } + ] + }, + "uuid" + ]); + + renderWithContext(); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + + expect(args.children[0].children).toHaveLength(1); + expect(args.children[0].children[0].name).toBe("B"); + }); - const { queryByText } = contextRender( + it("resolves groupName using macros", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: {}, + children: [ + { + id: "123", + fileId: "file123", + type: "groupbox", + name: "$(GROUP)", + position: {}, + children: [] + } + ] + }, + "uuid" + ]); + + renderWithContext( , - {}, - {} + /> ); - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith("/TestFile2.bob"); + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.children[0].children).toHaveLength(1); + }); - await waitFor((): void => - expect(queryByText("From .bob file")).toBeInTheDocument() + it("handles nested embedded displays (no double scaling)", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: {}, + children: [ + { + id: "123", + fileId: "file123", + type: "embeddedDisplay", + position: {}, + children: [] + } + ] + }, + "uuid" + ]); + + renderWithContext( + ); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + + const child = args.children[0].children[0]; + expect(child.overrideAutoZoomToFitValue).toBe(false); + }); + + it("passes scaling factors when autoZoom is enabled", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: { width: "100px", height: "100px" }, + autoZoomToFit: true, + children: [] + }, + "uuid" + ]); + + renderWithContext(); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + + expect(args.scaling[0]).toBe("7.68"); + expect(args.scaling[1]).toBe("7.68"); }); - it("converts fetched children to JSON", async (): Promise => { - const mockSuccessResponse = - '{ "type": "display", "position": "relative", "children": [{ "type": "label", "position": "relative", "text": "Test" }] }'; - const mockJsonPromise = Promise.resolve(mockSuccessResponse); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockJsonPromise + it("wraps in GroupBox when border style is GroupBox", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: {}, + children: [] + }, + "uuid" + ]); + + const props = { + ...baseProps, + border: newBorder(BorderStyle.GroupBox, newColor("white"), 1) as any + }; + + const { getByTestId } = renderWithContext(); + + expect(getByTestId("groupbox")).toBeInTheDocument(); + }); + + it("renders error widget when rendering fails", () => { + const spy = vi.spyOn(console, "warn").mockImplementation(() => {}); + + mockWidgetRenderer.mockImplementationOnce(() => { + throw new Error("fail"); }); - vi.spyOn(globalWithFetch, "fetch").mockImplementation( - (): Promise => mockFetchPromise - ); + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: {}, + children: [] + }, + "uuid" + ]); - const { queryByText } = contextRender( - , - {}, - {} + renderWithContext(); + + expect(mockWidgetRenderer).toHaveBeenCalled(); + + spy.mockRestore(); + }); + + it("handles stretch-content with independent scaling", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "123", + fileId: "file123", + type: "dummy", + position: { width: "100px", height: "200px" }, + autoZoomToFit: true, + children: [] + }, + "uuid" + ]); + + renderWithContext( + ); - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith("/TestFile3.json"); + const args = mockWidgetRenderer.mock.calls[0][0][0]; - await waitFor((): void => expect(queryByText("Test")).toBeInTheDocument()); + expect(args.autoZoomToFit).toBe(true); + expect(args.overflow).toBe("visible"); + expect(args.scaling[0]).not.toBe(args.scaling[1]); // independent scaling }); - it("selects specific group from fetched children, when group is specified", async (): Promise => { - const mockSuccessResponse = { - type: "display", - name: "embedded_display", - position: "absolute", - x: 10, - y: 20, - width: 600, - height: 700, - children: [ - { - type: "groupbox", - name: "group_name_1", - position: "absolute", - x: 20, - y: 30, - width: 400, - height: 500, - children: [ - { - type: "label", - position: "relative", - text: "Test group 1" - } - ] - }, - { - type: "groupbox", - name: "group_name_2", - position: "absolute", - x: 220, - y: 230, - width: 240, - height: 250, - children: [ - { - type: "label", - position: "relative", - text: "Test group 2" - } - ] - } - ] - }; + it("sets overflow visible for size-widget", () => { + vi.mocked(useFile).mockReturnValue([ + { id: "1", fileId: "f1", type: "d", position: {}, children: [] }, + "uuid" + ]); - const mockJsonPromise = Promise.resolve( - JSON.stringify(mockSuccessResponse) - ); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockJsonPromise - }); + renderWithContext(); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.overflow).toBe("visible"); + expect(args.autoZoomToFit).not.toBe(true); + }); + + it("sets overflow hidden for crop-content", () => { + vi.mocked(useFile).mockReturnValue([ + { id: "1", fileId: "f1", type: "d", position: {}, children: [] }, + "uuid" + ]); + + renderWithContext(); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.overflow).toBe("hidden"); + }); - vi.spyOn(globalWithFetch, "fetch").mockImplementation( - (): Promise => mockFetchPromise + it("does not call widgetIdsCallback when EMPTY_WIDGET is returned", () => { + const callback = vi.fn(); + + vi.mocked(useFile).mockReturnValue([ + { + id: "ignored", + fileId: "EMPTY", + type: "dummy", + position: {}, + children: [] + }, + "uuid" + ]); + + renderWithContext( + ); - const { container, queryByText } = contextRender( - , - {}, - {} + expect(callback).not.toHaveBeenCalled(); + }); + + it("respects overrideAutoZoomToFitValue=false", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "1", + fileId: "f", + type: "d", + position: {}, + autoZoomToFit: true, + children: [] + }, + "uuid" + ]); + + renderWithContext( + ); - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith("/TestFile3.json"); + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.autoZoomToFit).toBe(false); + }); - await screen.findByText("Test group 2"); - // Second group should not be present - expect(queryByText("Test group 1")).not.toBeInTheDocument(); + it("falls back to description.autoZoomToFit when override undefined", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "1", + fileId: "f", + type: "d", + position: {}, + autoZoomToFit: true, + children: [] + }, + "uuid" + ]); + + renderWithContext(); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.autoZoomToFit).toBe(true); + }); - const display = container.querySelector(".display"); - expect(display).not.toBeNull(); + it("uses window size when position is missing", () => { + Object.defineProperty(window, "innerWidth", { + value: 800, + configurable: true + }); + Object.defineProperty(window, "innerHeight", { + value: 600, + configurable: true + }); - const innerDisplayWidgetWrapper = display?.firstElementChild; + vi.mocked(useFile).mockReturnValue([ + { + id: "1", + fileId: "f", + type: "d", + position: {}, + autoZoomToFit: true, + children: [] + }, + "uuid" + ]); - expect(innerDisplayWidgetWrapper).toHaveStyle("position: absolute"); + renderWithContext(); - // This should match the size of the selected group - expect(innerDisplayWidgetWrapper).not.toBeNull(); - expect(innerDisplayWidgetWrapper).toHaveStyle("top: 0px"); - expect(innerDisplayWidgetWrapper).toHaveStyle("left: 0px"); - expect(innerDisplayWidgetWrapper).toHaveStyle("height: 250px"); - expect(innerDisplayWidgetWrapper).toHaveStyle("width: 240px"); + const args = mockWidgetRenderer.mock.calls[0][0][0]; - const displayInner = display?.querySelector(".display"); - expect(displayInner).not.toBeNull(); - const groupBoxWidgetWrapper = displayInner?.firstChild; - expect(groupBoxWidgetWrapper).toHaveStyle("position: absolute"); - expect(groupBoxWidgetWrapper).toHaveStyle("height: 250px"); - expect(groupBoxWidgetWrapper).toHaveStyle("width: 240px"); - // Positioned at top left irrespective of specified coordinates - expect(groupBoxWidgetWrapper).toHaveStyle("top: 0"); - expect(groupBoxWidgetWrapper).toHaveStyle("left: 0"); + expect(args.scaling[0]).toBe("1"); + expect(args.scaling[1]).toBe("1"); }); - it("selects specific group from fetched children, when group is specified by macro name", async (): Promise => { - const mockSuccessResponse = { - type: "display", - name: "embedded_display", - position: "absolute", - x: 10, - y: 20, - width: 600, - height: 700, - children: [ - { - type: "groupbox", - name: "group_name_1", - position: "absolute", - x: 20, - y: 30, - width: 400, - height: 500, - children: [ - { - type: "label", - position: "relative", - text: "Test group 1" - } - ] - }, - { - type: "groupbox", - name: "$(MACRO_GROUP_NAME)", - position: "absolute", - x: 220, - y: 230, - width: 240, - height: 250, - children: [ - { - type: "label", - position: "relative", - text: "Test group 2" - } - ] - } - ] - }; + it("converts numeric resize to string enum", () => { + vi.mocked(useFile).mockReturnValue([ + { id: "1", fileId: "f", type: "d", position: {}, children: [] }, + "uuid" + ]); - const mockJsonPromise = Promise.resolve( - JSON.stringify(mockSuccessResponse) - ); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockJsonPromise - }); + renderWithContext(); - vi.spyOn(globalWithFetch, "fetch").mockImplementation( - (): Promise => mockFetchPromise - ); + const args = mockWidgetRenderer.mock.calls[0][0][0]; + // index 1 = "size-content" + expect(args.autoZoomToFit).toBe(true); + }); - const { queryByText } = contextRender( - , - {}, - {} + it("propagates scalingOrigin to child when not autoZoom", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "1", + fileId: "f", + type: "d", + position: { height: "100px", width: "100px" }, + autoZoomToFit: false, + children: [ + { + id: "child", + fileId: "cf", + type: "embeddedDisplay", + position: {}, + children: [] + } + ] + }, + "uuid" + ]); + + renderWithContext( + ); - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith("/TestFile3.json"); + const args = mockWidgetRenderer.mock.calls[0][0][0]; + const child = args.children[0].children[0]; - await waitFor((): void => { - expect(queryByText("Test group 2")).toBeInTheDocument(); - // Second group should not be present - expect(queryByText("Test group 1")).not.toBeInTheDocument(); - }); + expect(child.scalingOrigin).toBe("center"); }); - it("Applies macros to filename before loading the embedded display file", async (): Promise => { - const mockSuccessResponse = { - type: "display", - name: "embedded_display", - position: "absolute", - x: 10, - y: 20, - width: 600, - height: 700, - children: [] - }; + it("uses provided theme instead of default", () => { + const customTheme = {} as any; - const mockJsonPromise = Promise.resolve( - JSON.stringify(mockSuccessResponse) - ); - const mockFetchPromise = Promise.resolve({ - text: (): Promise => mockJsonPromise + vi.mocked(useFile).mockReturnValue([ + { id: "1", fileId: "f", type: "d", position: {}, children: [] }, + "uuid" + ]); + + renderWithContext(); + + // indirect check: component rendered successfully + expect(mockWidgetRenderer).toHaveBeenCalled(); + }); + + it("renders error widget when renderer throws", () => { + mockWidgetRenderer.mockImplementationOnce(() => { + throw new Error("boom"); }); - vi.spyOn(globalWithFetch, "fetch").mockImplementation( - (): Promise => mockFetchPromise - ); + vi.mocked(useFile).mockReturnValue([ + { id: "1", fileId: "f", type: "d", position: {}, children: [] }, + "uuid" + ]); - contextRender( - , - {}, - {} + renderWithContext(); + + const call = mockWidgetRenderer.mock.calls[1]; // second call = error fallback + expect(call[0][0].type).toBe("error"); + }); + + it("passes scalingOrigin to renderer", () => { + vi.mocked(useFile).mockReturnValue([ + { id: "1", fileId: "f", type: "d", position: {}, children: [] }, + "uuid" + ]); + + renderWithContext( + ); - expect(globalWithFetch.fetch).toHaveBeenCalledTimes(1); - expect(globalWithFetch.fetch).toHaveBeenCalledWith("aBobFile.bob"); + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.scalingOrigin).toBe("top-left"); + }); + + it("falls back to all children when groupName not found", () => { + vi.mocked(useFile).mockReturnValue([ + { + id: "1", + fileId: "f", + type: "d", + position: {}, + children: [ + { + id: "a", + fileId: "f", + type: "groupbox", + name: "A", + position: {}, + children: [] + } + ] + }, + "uuid" + ]); + + renderWithContext(); + + const args = mockWidgetRenderer.mock.calls[0][0][0]; + expect(args.children[0].children).toHaveLength(1); }); }); From c66f7b18a5fc3a2c3a0d427ae64c004e1c57dd78 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Fri, 12 Jun 2026 16:59:34 +0100 Subject: [PATCH 07/16] Post merge test fixes --- src/ui/hooks/useClassFile.test.tsx | 14 +++++++++++++- .../displayResponsive.test.tsx | 19 +++++++++++++++++-- .../widgets/DynamicPage/dynamicPage.test.tsx | 1 - .../EmbeddedDisplay/embeddedDisplay.test.tsx | 4 ++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/ui/hooks/useClassFile.test.tsx b/src/ui/hooks/useClassFile.test.tsx index 05d84e9..3132eb1 100644 --- a/src/ui/hooks/useClassFile.test.tsx +++ b/src/ui/hooks/useClassFile.test.tsx @@ -7,9 +7,21 @@ import { useClassFile } from "./useClassFile"; import { CsWebLibConfig } from "../../redux"; import { phoebusTheme } from "../../phoebusTheme"; import { createTheme } from "@mui/material"; -import { getFileState } from "./useFile.test"; +import { CsState } from "../../redux/csState"; + ensureWidgetsRegistered(); +function getFileState(): CsState { + return { + valueCache: {}, + subscriptions: {}, + globalMacros: {}, + effectivePvNameMap: {}, + deviceCache: {}, + pvwsSettings: {} + }; +} + const initialState: CsWebLibConfig = { storeMode: "DEV", PVWS_SOCKET: "", diff --git a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx index 989cdbb..feed863 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.test.tsx @@ -100,6 +100,7 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { @@ -119,7 +120,11 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { expect(() => render( - + ) @@ -142,6 +147,7 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { @@ -175,6 +181,7 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { @@ -203,6 +210,7 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { { { { it("uses fallback layout generator when layouts not specified", () => { render( - + ); @@ -335,6 +349,7 @@ describe("DisplayResponsiveComponent – high‑value behaviors", () => { ({ useStyle: () => ({ diff --git a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx index 8420cf2..b5e26d9 100644 --- a/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx +++ b/src/ui/widgets/EmbeddedDisplay/embeddedDisplay.test.tsx @@ -23,6 +23,10 @@ vi.mock("../../hooks/useMacros", () => ({ recursiveResolve: vi.fn(x => x) })); +vi.mock("../../hooks/useClassFile", () => ({ + useClassFile: vi.fn(theme => theme || {}) +})); + const mockWidgetRenderer = vi.fn((config: any) => (
)); From 6cc7783fb8812776a1c2e1c7b3f77c61cc18f2c4 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Fri, 12 Jun 2026 17:05:37 +0100 Subject: [PATCH 08/16] Lint fix --- src/ui/widgets/DynamicPage/dynamicPage.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/widgets/DynamicPage/dynamicPage.test.tsx b/src/ui/widgets/DynamicPage/dynamicPage.test.tsx index 47a60c8..18adbdd 100644 --- a/src/ui/widgets/DynamicPage/dynamicPage.test.tsx +++ b/src/ui/widgets/DynamicPage/dynamicPage.test.tsx @@ -6,6 +6,7 @@ import { DynamicPageComponent } from "./dynamicPage"; import { FileContext } from "../../../misc/fileContext"; import { useSelector } from "react-redux"; +import { Theme } from "@mui/material"; vi.mock("../../hooks/useStyle", () => ({ useStyle: () => ({ @@ -206,7 +207,7 @@ describe("DynamicPageComponent (unit)", () => { it("passes custom theme to EmbeddedDisplay", () => { const file = { path: "file1", macros: {} }; - const customTheme = {}; + const customTheme = {} as unknown as Theme; renderWithContext( , From f5611d9cb0c4c90c39e669d86399052a2997dffa Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Fri, 12 Jun 2026 17:36:05 +0100 Subject: [PATCH 09/16] Stop responsive screen clustering on the top left on initialisation. --- .../displayResponsive.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx index 481bbde..69ef518 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayResponsive.tsx @@ -98,7 +98,7 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { const shouldCommitRef = useRef(false); const { width, containerRef, mounted } = useContainerWidth({ - measureBeforeMount: false + measureBeforeMount: true }); const debouncedWidth = useDebouncedValue(width, 150); const gridCellDragEnabled = @@ -238,7 +238,7 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { breakpoints, cols: columns, layouts: initialLayouts, - width: 0 + width: 100 }); // Wrap the child components in a div keyed by the child id. The key MUST map to the i field of Layout item for the component. @@ -247,6 +247,18 @@ export const DisplayResponsiveComponent = (props: propsType): JSX.Element => { [childrenArray, gridCellDragEnabled] ); + const hasLayouts = useMemo(() => { + return ( + props.responsiveLayouts && + Object.keys(props.responsiveLayouts).length > 0 && + Object.values(props.responsiveLayouts).every( + layout => Array.isArray(layout) && layout.length > 0 + ) && + layouts && + Object.keys(layouts).length > 0 + ); + }, [props.responsiveLayouts, layouts]); + return (
{ style={extendedStyle} className="display-responsive-container" > - {mounted && props.responsiveLayouts && ( + {mounted && hasLayouts && ( Date: Wed, 17 Jun 2026 10:39:42 +0100 Subject: [PATCH 10/16] Switch makeSelectWidgetPosition to use the display instance cache --- src/redux/slices/fileCacheSlice.test.ts | 24 ++++++++++++------- src/redux/slices/fileCacheSlice.ts | 13 ++++++---- .../displayGridLayout.tsx | 2 +- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/redux/slices/fileCacheSlice.test.ts b/src/redux/slices/fileCacheSlice.test.ts index 6b95408..a013906 100644 --- a/src/redux/slices/fileCacheSlice.test.ts +++ b/src/redux/slices/fileCacheSlice.test.ts @@ -400,22 +400,30 @@ describe("makeSelectWidgetPosition", () => { id: "child1", type: "shape", position - } + } as Partial ] - }; + } as Partial; const state = createRootStoreState(undefined, undefined, { fileCache: { "file.bob": file as any }, - displayInstanceCache: {}, + displayInstanceCache: { + abcde1234: { + fileId: "file.bob", + uuid: "abcde1234", + hash: "", + macros: {}, + description: file as WidgetDescription + } + }, displayInstanceIndex: {} }); test("returns widget position when found", () => { const selector = makeSelectWidgetPosition(); - const result = selector(state, "file.bob", "child1"); + const result = selector(state, "abcde1234", "child1"); expect(result).toEqual(position); }); @@ -423,7 +431,7 @@ describe("makeSelectWidgetPosition", () => { test("returns undefined if widget not found", () => { const selector = makeSelectWidgetPosition(); - const result = selector(state, "file.bob", "missing"); + const result = selector(state, "abcde1234", "missing"); expect(result).toBeUndefined(); }); @@ -431,7 +439,7 @@ describe("makeSelectWidgetPosition", () => { test("returns undefined if file not found", () => { const selector = makeSelectWidgetPosition(); - const result = selector(state, "missing.bob", "child1"); + const result = selector(state, "XYZ0987", "child1"); expect(result).toBeUndefined(); }); @@ -439,8 +447,8 @@ describe("makeSelectWidgetPosition", () => { test("memoizes results (same inputs)", () => { const selector = makeSelectWidgetPosition(); - const result1 = selector(state, "file.bob", "child1"); - const result2 = selector(state, "file.bob", "child1"); + const result1 = selector(state, "abcde1234", "child1"); + const result2 = selector(state, "abcde1234", "child1"); expect(result1).toBe(result2); }); diff --git a/src/redux/slices/fileCacheSlice.ts b/src/redux/slices/fileCacheSlice.ts index cf8cefa..23a725a 100644 --- a/src/redux/slices/fileCacheSlice.ts +++ b/src/redux/slices/fileCacheSlice.ts @@ -299,10 +299,15 @@ export const selectDisplayInstanceByFileAndMacros = createSelector( */ export const makeSelectWidgetPosition = () => createSelector( - [selectFile, (_state: any, _fileId: string, widgetId: string) => widgetId], - (file, widgetId) => - file - ? (findWidgetById([file], widgetId)?.position as Position | undefined) + [ + selectDisplayInstance, + (_state: any, _uuId: string, widgetId: string) => widgetId + ], + (displayInstance, widgetId) => + displayInstance?.description + ? (findWidgetById([displayInstance.description], widgetId)?.position as + | Position + | undefined) : undefined ); diff --git a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx index ea7932a..69d5405 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx @@ -95,7 +95,7 @@ export const DisplayGridLayoutComponent = ( const selectWidgetPosition = useMemo(makeSelectWidgetPosition, []); const position = useSelector(state => - selectWidgetPosition(state, props.fileId, props.id) + selectWidgetPosition(state, props.embeddedDisplayUuid, props.id) ); const displayWidth = toNumber(position?.width, 1200); const cellHeight = Number(props.gridCellHeight ?? defaultRowHeight); From afc94eb38441c776d6dd593412c9cbb7672d0170 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 17 Jun 2026 10:49:09 +0100 Subject: [PATCH 11/16] Bump package version and upgrade Vite to resolve vulnerabilities --- package-lock.json | 1263 +++++++++++++++++++++++++++++++++------------ package.json | 6 +- 2 files changed, 932 insertions(+), 337 deletions(-) diff --git a/package-lock.json b/package-lock.json index c99e08f..662c380 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@diamondlightsource/cs-web-lib", - "version": "0.10.16", + "version": "0.10.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@diamondlightsource/cs-web-lib", - "version": "0.10.16", + "version": "0.10.17", "license": "ISC", "dependencies": { "@mui/icons-material": "^7.3.7", @@ -37,7 +37,7 @@ "@types/react-test-renderer": "^18.3.0", "@types/uuid": "^9.0.8", "@typescript-eslint/typescript-estree": "^8.13.0", - "@vitejs/plugin-react": "^4.7.0", + "@vitejs/plugin-react": "^6.0.2", "base64-js": "^1.5.1", "clipboard-copy": "^4.0.1", "d3": "^7.9.0", @@ -61,7 +61,7 @@ "rollup-preserve-directives": "^1.1.3", "tslib": "^2.8.1", "typescript": "^5.6.3", - "vite": "^7.2.2", + "vite": "^8.0.16", "vite-plugin-eslint": "^1.8.1", "vite-plugin-node-polyfills": "^0.26.0", "vitest": "^4.0.8", @@ -150,13 +150,13 @@ "license": "ISC" }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -165,9 +165,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", - "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -175,21 +175,21 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -262,14 +262,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -292,14 +292,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -396,9 +396,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "devOptional": true, "license": "MIT", "engines": { @@ -420,29 +420,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -525,9 +525,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "devOptional": true, "license": "MIT", "engines": { @@ -535,9 +535,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "devOptional": true, "license": "MIT", "engines": { @@ -545,9 +545,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -570,27 +570,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -1725,38 +1725,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-react-pure-annotations": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", @@ -2211,33 +2179,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -2245,14 +2213,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2393,6 +2361,40 @@ "node": ">=18" } }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", @@ -2546,9 +2548,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -2558,14 +2560,15 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -2575,14 +2578,15 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -2592,14 +2596,15 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -2609,14 +2614,15 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -2626,14 +2632,15 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -2643,14 +2650,15 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -2660,14 +2668,15 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -2677,14 +2686,15 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -2694,14 +2704,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -2711,14 +2722,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -2728,14 +2740,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -2745,14 +2758,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -2762,14 +2776,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -2779,14 +2794,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -2796,14 +2812,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -2813,14 +2830,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -2830,14 +2848,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -2847,14 +2866,15 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -2864,14 +2884,15 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -2881,14 +2902,15 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -2898,14 +2920,15 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -2915,14 +2938,15 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -2932,14 +2956,15 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -2949,14 +2974,15 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -2966,14 +2992,15 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -2983,6 +3010,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -3993,6 +4021,25 @@ } } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -4065,6 +4112,16 @@ "node": ">= 8" } }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@pkgr/core": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", @@ -4254,10 +4311,267 @@ } } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, @@ -4896,73 +5210,39 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/meta": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.5.tgz", - "integrity": "sha512-r+ohqxoyqeigFB0oFrQx/YEHIkOKqcKpCjvZkvZs7Tkv+IFco5MezAd2zd4rzK+0DfFgDP3KpJc7HqrYjvEjhg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@turf/helpers": "7.3.5", - "@types/geojson": "^7946.0.10", - "tslib": "^2.8.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, + "node_modules/@turf/meta": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.5.tgz", + "integrity": "sha512-r+ohqxoyqeigFB0oFrQx/YEHIkOKqcKpCjvZkvZs7Tkv+IFco5MezAd2zd4rzK+0DfFgDP3KpJc7HqrYjvEjhg==", "license": "MIT", + "peer": true, "dependencies": { - "@babel/types": "^7.0.0" + "@turf/helpers": "7.3.5", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "tslib": "^2.4.0" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } + "peer": true }, "node_modules/@types/chai": { "version": "5.2.3", @@ -6063,24 +6343,29 @@ "peer": true }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "@rolldown/pluginutils": "^1.0.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } } }, "node_modules/@vitest/expect": { @@ -8813,6 +9098,16 @@ "license": "MIT", "peer": true }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/diff-sequences": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", @@ -9351,12 +9646,14 @@ } }, "node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, "hasInstallScript": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -9364,32 +9661,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escalade": { @@ -10582,17 +10879,17 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -11431,9 +11728,9 @@ } }, "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -12415,10 +12712,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "peer": true, "dependencies": { @@ -12612,6 +12919,267 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -15162,16 +15730,6 @@ "license": "MIT", "peer": true }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-resizable": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.2.0.tgz", @@ -15809,6 +16367,40 @@ "dev": true, "license": "Unlicense" }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, "node_modules/rollup": { "version": "4.60.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", @@ -17003,9 +17595,9 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { @@ -17584,18 +18176,17 @@ } }, "node_modules/vite": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.3.tgz", - "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -17611,9 +18202,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -17626,13 +18218,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { "optional": true }, - "lightningcss": { + "jiti": { + "optional": true + }, + "less": { "optional": true }, "sass": { @@ -18138,9 +18733,9 @@ "peer": true }, "node_modules/ws": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", - "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index bd63d73..ecf3291 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@diamondlightsource/cs-web-lib", - "version": "0.10.16", + "version": "0.10.17", "description": "Control system web library", "main": "./dist/index.cjs", "scripts": { @@ -48,7 +48,7 @@ "@types/react-test-renderer": "^18.3.0", "@types/uuid": "^9.0.8", "@typescript-eslint/typescript-estree": "^8.13.0", - "@vitejs/plugin-react": "^4.7.0", + "@vitejs/plugin-react": "^6.0.2", "base64-js": "^1.5.1", "clipboard-copy": "^4.0.1", "d3": "^7.9.0", @@ -72,7 +72,7 @@ "rollup-preserve-directives": "^1.1.3", "tslib": "^2.8.1", "typescript": "^5.6.3", - "vite": "^7.2.2", + "vite": "^8.0.16", "vite-plugin-eslint": "^1.8.1", "vite-plugin-node-polyfills": "^0.26.0", "vitest": "^4.0.8", From 7e22296b4e1dcb4e17a0a61228198f630d512a7e Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 17 Jun 2026 10:58:25 +0100 Subject: [PATCH 12/16] Drop plotly dependency --- package-lock.json | 2486 +-------------------------------------------- package.json | 1 - 2 files changed, 41 insertions(+), 2446 deletions(-) diff --git a/package-lock.json b/package-lock.json index 662c380..0ea6de5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "bufferutil": "^4.0.8", "loglevel": "^1.9.2", "react-grid-layout": "^2.2.3", - "react-plotly.js": "^2.6.0", "react-toastify": "^11.0.5", "safe-stable-stringify": "^2.5.0", "utf-8-validate": "^5.0.10" @@ -2226,26 +2225,6 @@ "node": ">=6.9.0" } }, - "node_modules/@choojs/findup": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@choojs/findup/-/findup-0.2.1.tgz", - "integrity": "sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==", - "license": "MIT", - "peer": true, - "dependencies": { - "commander": "^2.15.1" - }, - "bin": { - "findup": "bin/findup.js" - } - }, - "node_modules/@choojs/findup/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true - }, "node_modules/@csstools/color-helpers": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", @@ -3262,122 +3241,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mapbox/geojson-rewind": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", - "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "license": "ISC", - "peer": true, - "dependencies": { - "get-stream": "^6.0.1", - "minimist": "^1.2.6" - }, - "bin": { - "geojson-rewind": "geojson-rewind" - } - }, - "node_modules/@mapbox/geojson-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz", - "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==", - "license": "ISC", - "peer": true - }, - "node_modules/@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@mapbox/mapbox-gl-supported": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz", - "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==", - "license": "BSD-3-Clause", - "peer": true, - "peerDependencies": { - "mapbox-gl": ">=0.32.1 <2.0.0" - } - }, - "node_modules/@mapbox/point-geometry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", - "license": "ISC", - "peer": true - }, - "node_modules/@mapbox/tiny-sdf": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz", - "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==", - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/@mapbox/unitbezier": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==", - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/@mapbox/vector-tile": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "@mapbox/point-geometry": "~0.1.0" - } - }, - "node_modules/@mapbox/whoots-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", - "license": "ISC", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", - "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", - "license": "ISC", - "peer": true, - "dependencies": { - "@mapbox/jsonlint-lines-primitives": "~2.0.2", - "@mapbox/unitbezier": "^0.0.1", - "json-stringify-pretty-compact": "^4.0.0", - "minimist": "^1.2.8", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "tinyqueue": "^3.0.0" - }, - "bin": { - "gl-style-format": "dist/gl-style-format.mjs", - "gl-style-migrate": "dist/gl-style-migrate.mjs", - "gl-style-validate": "dist/gl-style-validate.mjs" - } - }, - "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/@mapbox/unitbezier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", - "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/tinyqueue": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", - "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", - "license": "ISC", - "peer": true - }, "node_modules/@mui/core-downloads-tracker": { "version": "7.3.11", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.11.tgz", @@ -4135,146 +3998,6 @@ "url": "https://opencollective.com/pkgr" } }, - "node_modules/@plotly/d3": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/@plotly/d3/-/d3-3.8.2.tgz", - "integrity": "sha512-wvsNmh1GYjyJfyEBPKJLTMzgf2c2bEbSIL50lmqVUi+o1NHaLPi1Lb4v7VxXXJn043BhNyrxUrWI85Q+zmjOVA==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@plotly/d3-sankey": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@plotly/d3-sankey/-/d3-sankey-0.7.2.tgz", - "integrity": "sha512-2jdVos1N3mMp3QW0k2q1ph7Gd6j5PY1YihBrwpkFnKqO+cqtZq3AdEYUeSGXMeLsBDQYiqTVcihYfk8vr5tqhw==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "d3-array": "1", - "d3-collection": "1", - "d3-shape": "^1.2.0" - } - }, - "node_modules/@plotly/d3-sankey-circular": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@plotly/d3-sankey-circular/-/d3-sankey-circular-0.33.1.tgz", - "integrity": "sha512-FgBV1HEvCr3DV7RHhDsPXyryknucxtfnLwPtCKKxdolKyTFYoLX/ibEfX39iFYIL7DYbVeRtP43dbFcrHNE+KQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "d3-array": "^1.2.1", - "d3-collection": "^1.0.4", - "d3-shape": "^1.2.0", - "elementary-circuits-directed-graph": "^1.0.4" - } - }, - "node_modules/@plotly/d3-sankey-circular/node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@plotly/d3-sankey-circular/node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@plotly/d3-sankey-circular/node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/@plotly/d3-sankey/node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@plotly/d3-sankey/node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@plotly/d3-sankey/node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/@plotly/mapbox-gl": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/@plotly/mapbox-gl/-/mapbox-gl-1.13.4.tgz", - "integrity": "sha512-sR3/Pe5LqT/fhYgp4rT4aSFf1rTsxMbGiH6Hojc7PH36ny5Bn17iVFUjpzycafETURuFbLZUfjODO8LvSI+5zQ==", - "license": "SEE LICENSE IN LICENSE.txt", - "peer": true, - "dependencies": { - "@mapbox/geojson-rewind": "^0.5.2", - "@mapbox/geojson-types": "^1.0.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^1.5.0", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^1.1.1", - "@mapbox/unitbezier": "^0.0.0", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "csscolorparser": "~1.0.3", - "earcut": "^2.2.2", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.2.1", - "grid-index": "^1.1.0", - "murmurhash-js": "^1.0.0", - "pbf": "^3.2.1", - "potpack": "^1.0.1", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "supercluster": "^7.1.0", - "tinyqueue": "^2.0.3", - "vt-pbf": "^3.1.1" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/@plotly/point-cluster": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@plotly/point-cluster/-/point-cluster-3.1.9.tgz", - "integrity": "sha512-MwaI6g9scKf68Orpr1pHZ597pYx9uP8UEFXLPbsCmuw3a84obwz6pnMXGc90VhgDNeNiLEdlmuK7CPo+5PIxXw==", - "license": "MIT", - "peer": true, - "dependencies": { - "array-bounds": "^1.0.1", - "binary-search-bounds": "^2.0.4", - "clamp": "^1.0.1", - "defined": "^1.0.0", - "dtype": "^2.0.0", - "flatten-vertex-data": "^1.0.2", - "is-obj": "^1.0.1", - "math-log2": "^1.0.1", - "parse-rect": "^1.2.0", - "pick-by-alias": "^1.2.0" - } - }, - "node_modules/@plotly/regl": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@plotly/regl/-/regl-2.1.2.tgz", - "integrity": "sha512-Mdk+vUACbQvjd0m/1JJjOOafmkp/EpmHjISsopEz5Av44CBq7rPC05HHNbYGKVyNUF2zmEoBS/TT0pd0SPFFyw==", - "license": "MIT", - "peer": true - }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -5148,83 +4871,6 @@ } } }, - "node_modules/@turf/area": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@turf/area/-/area-7.3.5.tgz", - "integrity": "sha512-sSn80wPT7XfBIDN3vurCPxhk9W4U8ozS/XImSqeLN8qveTICOxzZkhsGDMp0CuncaN+plWut4a2TdNM7mzZB6Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "@turf/helpers": "7.3.5", - "@turf/meta": "7.3.5", - "@types/geojson": "^7946.0.10", - "tslib": "^2.8.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/bbox": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-7.3.5.tgz", - "integrity": "sha512-oG1ya/HtBjAIg4TimbWx+nOYPbY0bCvt82Bq8tm6sBw3qqtbOyRSfDz79Sq90TnH7DXJprJ1qnVGKNtZ6jemfw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@turf/helpers": "7.3.5", - "@turf/meta": "7.3.5", - "@types/geojson": "^7946.0.10", - "tslib": "^2.8.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/centroid": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-7.3.5.tgz", - "integrity": "sha512-hkWaqwGFdOn6Tf0EWfn2yn1XZ1FWE1h2C5ZWstDMu/FxYO5DB+YjlmOFPl4K6SmSOEgdV07eK2vDCyPeTHqKGA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@turf/helpers": "7.3.5", - "@turf/meta": "7.3.5", - "@types/geojson": "^7946.0.10", - "tslib": "^2.8.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/helpers": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.5.tgz", - "integrity": "sha512-E/NMGV5MwbjjP7AJXBtsanC3yY8N2MQ87IGdIgkB2ji5AtBpwnH4L3gEqpYN4RlCJJWbLbzO91BbKv2waUd0eg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/geojson": "^7946.0.10", - "tslib": "^2.8.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/meta": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.3.5.tgz", - "integrity": "sha512-r+ohqxoyqeigFB0oFrQx/YEHIkOKqcKpCjvZkvZs7Tkv+IFco5MezAd2zd4rzK+0DfFgDP3KpJc7HqrYjvEjhg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@turf/helpers": "7.3.5", - "@types/geojson": "^7946.0.10", - "tslib": "^2.8.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, "node_modules/@tybys/wasm-util": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", @@ -5568,18 +5214,9 @@ "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, "license": "MIT" }, - "node_modules/@types/geojson-vt": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", - "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/geojson": "*" - } - }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", @@ -5618,25 +5255,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/mapbox__point-geometry": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", - "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", - "license": "MIT", - "peer": true - }, - "node_modules/@types/mapbox__vector-tile": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", - "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/geojson": "*", - "@types/mapbox__point-geometry": "*", - "@types/pbf": "*" - } - }, "node_modules/@types/node": { "version": "22.19.19", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", @@ -5661,13 +5279,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/@types/pbf": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", - "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", - "license": "MIT", - "peer": true - }, "node_modules/@types/plotly.js": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-3.0.10.tgz", @@ -5758,16 +5369,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/supercluster": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", - "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/geojson": "*" - } - }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.9", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", @@ -6550,13 +6151,6 @@ "node": ">=8" } }, - "node_modules/abs-svg-path": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", - "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==", - "license": "MIT", - "peer": true - }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -6750,13 +6344,6 @@ "dequal": "^2.0.3" } }, - "node_modules/array-bounds": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-bounds/-/array-bounds-1.0.1.tgz", - "integrity": "sha512-8wdW3ZGk6UjMPJx/glyEt0sLzzwAE1bhToPsO1W2pbpR2gULyxe3BjSiuJFheP50T/GgODVPz2fuMUmIywt8cQ==", - "license": "MIT", - "peer": true - }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", @@ -6774,16 +6361,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-includes": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", @@ -6807,23 +6384,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-normalize": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array-normalize/-/array-normalize-1.1.4.tgz", - "integrity": "sha512-fCp0wKFLjvSPmCn4F5Tiw4M3lpMZoHlCjfcs7nNzuj3vqQQ1/a8cgB9DXcpDSn18c+coLnaW7rqfcYCvKbyJXg==", - "license": "MIT", - "peer": true, - "dependencies": { - "array-bounds": "^1.0.0" - } - }, - "node_modules/array-range": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-range/-/array-range-1.0.1.tgz", - "integrity": "sha512-shdaI1zT3CVNL2hnx9c0JMc0ZogGaxDs5e85akgHWKYa0yVbIyp06Ind3dVkTj/uuFrzaHBOyqFzo+VV6aXgtA==", - "license": "MIT", - "peer": true - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -7168,16 +6728,6 @@ "node": "18 || 20 || >=22" } }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -7219,38 +6769,6 @@ "dev": true, "license": "MIT" }, - "node_modules/binary-search-bounds": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", - "integrity": "sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==", - "license": "MIT", - "peer": true - }, - "node_modules/bit-twiddle": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz", - "integrity": "sha512-B9UhK0DKFZhoTFcfvAzhqsjStvGJp9vYWf3+6SNTtdSQnvIgfkHbgHrg/e4+TH71N2GDu8tpmCVoyfrL1d7ntA==", - "license": "MIT", - "peer": true - }, - "node_modules/bitmap-sdf": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/bitmap-sdf/-/bitmap-sdf-1.0.4.tgz", - "integrity": "sha512-1G3U4n5JE6RAiALMxu0p1XmeZkTeCwGKykzsLTCqVzfSDaN6S7fKnkIkfejogz+iwqBWc0UYAIKnKHNN7pSfDg==", - "license": "MIT", - "peer": true - }, - "node_modules/bl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", - "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, "node_modules/bn.js": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", @@ -7453,13 +6971,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT", - "peer": true - }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", @@ -7649,13 +7160,6 @@ "node": ">= 0.10" } }, - "node_modules/clamp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", - "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==", - "license": "MIT", - "peer": true - }, "node_modules/clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -7709,26 +7213,6 @@ "node": ">=6" } }, - "node_modules/color-alpha": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-alpha/-/color-alpha-1.1.3.tgz", - "integrity": "sha512-krPYBO1RSO5LH4AGb/b6z70O1Ip2o0F0+0cVFN5FN99jfQtZFT08rQyg+9oOBNJYAn3SRwJIFC8jUEOKz7PisA==", - "license": "MIT", - "peer": true, - "dependencies": { - "color-parse": "^1.4.1" - } - }, - "node_modules/color-alpha/node_modules/color-parse": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", - "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "^1.0.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7742,93 +7226,13 @@ "node": ">=7.0.0" } }, - "node_modules/color-id": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/color-id/-/color-id-1.1.0.tgz", - "integrity": "sha512-2iRtAn6dC/6/G7bBIo0uupVrIne1NsQJvJxZOBCzQOfk7jRq97feaDZ3RdzuHakRXXnHGNwglto3pqtRx1sX0g==", - "license": "MIT", - "peer": true, - "dependencies": { - "clamp": "^1.0.1" - } - }, "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, - "node_modules/color-normalize": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/color-normalize/-/color-normalize-1.5.0.tgz", - "integrity": "sha512-rUT/HDXMr6RFffrR53oX3HGWkDOP9goSAQGBkUaAYKjOE2JxozccdGyufageWDlInRAjm/jYPrf/Y38oa+7obw==", - "license": "MIT", - "peer": true, - "dependencies": { - "clamp": "^1.0.1", - "color-rgba": "^2.1.1", - "dtype": "^2.0.0" - } - }, - "node_modules/color-normalize/node_modules/color-parse": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", - "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "^1.0.0" - } - }, - "node_modules/color-normalize/node_modules/color-rgba": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-2.4.0.tgz", - "integrity": "sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "color-parse": "^1.4.2", - "color-space": "^2.0.0" - } - }, - "node_modules/color-parse": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-2.0.2.tgz", - "integrity": "sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==", - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "^2.0.0" - } - }, - "node_modules/color-parse/node_modules/color-name": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", - "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/color-rgba": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-3.0.0.tgz", - "integrity": "sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==", - "license": "MIT", - "peer": true, - "dependencies": { - "color-parse": "^2.0.0", - "color-space": "^2.0.0" - } - }, - "node_modules/color-space": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/color-space/-/color-space-2.3.2.tgz", - "integrity": "sha512-BcKnbOEsOarCwyoLstcoEztwT0IJxqqQkNwDuA3a65sICvvHL2yoeV13psoDFh5IuiOMnIOKdQDwB4Mk3BypiA==", - "license": "Unlicense", - "peer": true - }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -7873,22 +7277,6 @@ "dev": true, "license": "MIT" }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "node_modules/concat-with-sourcemaps": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", @@ -7968,6 +7356,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, "license": "MIT" }, "node_modules/cosmiconfig": { @@ -7997,13 +7386,6 @@ "node": ">= 6" } }, - "node_modules/country-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/country-regex/-/country-regex-1.1.0.tgz", - "integrity": "sha512-iSPlClZP8vX7MC3/u6s3lrDuoQyhQukh5LyABJ3hvfzbQ3Yyayd4fp04zjLnfi267B/B2FkumcWWgrbban7sSA==", - "license": "MIT", - "peer": true - }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", @@ -8114,59 +7496,6 @@ "postcss": "^8.0.9" } }, - "node_modules/css-font": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-font/-/css-font-1.2.0.tgz", - "integrity": "sha512-V4U4Wps4dPDACJ4WpgofJ2RT5Yqwe1lEH6wlOOaIxMi0gTjdIijsc5FmxQlZ7ZZyKQkkutqqvULOp07l9c7ssA==", - "license": "MIT", - "peer": true, - "dependencies": { - "css-font-size-keywords": "^1.0.0", - "css-font-stretch-keywords": "^1.0.1", - "css-font-style-keywords": "^1.0.1", - "css-font-weight-keywords": "^1.0.0", - "css-global-keywords": "^1.0.1", - "css-system-font-keywords": "^1.0.0", - "pick-by-alias": "^1.2.0", - "string-split-by": "^1.0.0", - "unquote": "^1.1.0" - } - }, - "node_modules/css-font-size-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz", - "integrity": "sha512-Q+svMDbMlelgCfH/RVDKtTDaf5021O486ZThQPIpahnIjUkMUslC+WuOQSWTgGSrNCH08Y7tYNEmmy0hkfMI8Q==", - "license": "MIT", - "peer": true - }, - "node_modules/css-font-stretch-keywords": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz", - "integrity": "sha512-KmugPO2BNqoyp9zmBIUGwt58UQSfyk1X5DbOlkb2pckDXFSAfjsD5wenb88fNrD6fvS+vu90a/tsPpb9vb0SLg==", - "license": "MIT", - "peer": true - }, - "node_modules/css-font-style-keywords": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz", - "integrity": "sha512-0Fn0aTpcDktnR1RzaBYorIxQily85M2KXRpzmxQPgh8pxUN9Fcn00I8u9I3grNr1QXVgCl9T5Imx0ZwKU973Vg==", - "license": "MIT", - "peer": true - }, - "node_modules/css-font-weight-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz", - "integrity": "sha512-5So8/NH+oDD+EzsnF4iaG4ZFHQ3vaViePkL1ZbZ5iC/KrsCY+WHq/lvOgrtmuOQ9pBBZ1ADGpaf+A4lj1Z9eYA==", - "license": "MIT", - "peer": true - }, - "node_modules/css-global-keywords": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-global-keywords/-/css-global-keywords-1.0.1.tgz", - "integrity": "sha512-X1xgQhkZ9n94WDwntqst5D/FKkmiU0GlJSFZSV3kLvyJ1WC5VeyoXDOuleUD+SIuH9C7W05is++0Woh0CGfKjQ==", - "license": "MIT", - "peer": true - }, "node_modules/css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -8184,13 +7513,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css-system-font-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz", - "integrity": "sha512-1umTtVd/fXS25ftfjB71eASCrYhilmEsvDEI6wG/QplnmlfmVM5HkZ/ZX46DT5K3eblFPgLUHt5BRCb0YXkSFA==", - "license": "MIT", - "peer": true - }, "node_modules/css-tree": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", @@ -8235,13 +7557,6 @@ "dev": true, "license": "MIT" }, - "node_modules/csscolorparser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", - "license": "MIT", - "peer": true - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -8391,20 +7706,6 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "license": "ISC", - "peer": true, - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/d3": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", @@ -8500,17 +7801,11 @@ "node": ">=12" } }, - "node_modules/d3-collection": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", - "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==", - "license": "BSD-3-Clause", - "peer": true - }, "node_modules/d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -8653,50 +7948,6 @@ "node": ">=12" } }, - "node_modules/d3-geo-projection": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.9.0.tgz", - "integrity": "sha512-ZULvK/zBn87of5rWAfFMc9mJOipeSo57O+BBitsKIXmU4rTVAnX1kSsJkE0R+TxY8pGNoM1nbyRRE7GYHhdOEQ==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "commander": "2", - "d3-array": "1", - "d3-geo": "^1.12.0", - "resolve": "^1.1.10" - }, - "bin": { - "geo2svg": "bin/geo2svg", - "geograticule": "bin/geograticule", - "geoproject": "bin/geoproject", - "geoquantize": "bin/geoquantize", - "geostitch": "bin/geostitch" - } - }, - "node_modules/d3-geo-projection/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true - }, - "node_modules/d3-geo-projection/node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/d3-geo-projection/node_modules/d3-geo": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", - "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "d3-array": "1" - } - }, "node_modules/d3-hierarchy": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", @@ -8711,6 +7962,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, "license": "ISC", "dependencies": { "d3-color": "1 - 3" @@ -9040,16 +8292,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delaunator": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", @@ -9091,13 +8333,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/detect-kerning": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-kerning/-/detect-kerning-2.1.2.tgz", - "integrity": "sha512-I3JIbrnKPAntNLl1I6TpSQQdQ4AutYzv/sKMFKbepawV/hlH0GmYKhUoOEMd4xqaUHT+Bm0f4127lh5qs1m1tw==", - "license": "MIT", - "peer": true - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -9263,27 +8498,6 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/draw-svg-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/draw-svg-path/-/draw-svg-path-1.0.0.tgz", - "integrity": "sha512-P8j3IHxcgRMcY6sDzr0QvJDLzBnJJqpTG33UZ2Pvp8rw0apCHhJCWqYprqrXjrgHnJ6tuhP1iTJSAodPDHxwkg==", - "license": "MIT", - "peer": true, - "dependencies": { - "abs-svg-path": "~0.1.1", - "normalize-svg-path": "~0.1.0" - } - }, - "node_modules/dtype": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dtype/-/dtype-2.0.0.tgz", - "integrity": "sha512-s2YVcLKdFGS0hpFqJaTwscsyt0E8nNFdmo73Ocd81xNPj4URI4rj6D60A+vFMIw7BXWlb4yRkEwfBqcZzPGiZg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -9299,33 +8513,6 @@ "node": ">= 0.4" } }, - "node_modules/dup": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz", - "integrity": "sha512-Bz5jxMMC0wgp23Zm15ip1x8IhYRqJvF3nFC0UInJUDkN1z4uNPk9jTnfCUJXbOGiQ1JbXLQsiV41Fb+HXcj5BA==", - "license": "MIT", - "peer": true - }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "license": "MIT", - "peer": true, - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", - "license": "ISC", - "peer": true - }, "node_modules/electron-to-chromium": { "version": "1.5.360", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.360.tgz", @@ -9333,16 +8520,6 @@ "dev": true, "license": "ISC" }, - "node_modules/elementary-circuits-directed-graph": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/elementary-circuits-directed-graph/-/elementary-circuits-directed-graph-1.3.1.tgz", - "integrity": "sha512-ZEiB5qkn2adYmpXGnJKkxT8uJHlW/mxmBpmeqawEHzPxh9HkLD4/1mFYX5l0On+f6rcPIt8/EWlRU2Vo3fX6dQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "strongly-connected-components": "^1.0.1" - } - }, "node_modules/elliptic": { "version": "6.6.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", @@ -9373,16 +8550,6 @@ "dev": true, "license": "MIT" }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "peer": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -9489,6 +8656,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9589,62 +8757,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "hasInstallScript": true, - "license": "ISC", - "peer": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "license": "MIT", - "peer": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "license": "ISC", - "peer": true, - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "license": "ISC", - "peer": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "node_modules/esbuild": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", @@ -9712,39 +8824,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", @@ -10448,22 +9527,6 @@ "node": "*" } }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "license": "ISC", - "peer": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -10497,20 +9560,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "peer": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", @@ -10541,6 +9590,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -10557,22 +9607,12 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "license": "MIT", - "peer": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -10584,6 +9624,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.x" @@ -10610,43 +9651,6 @@ "node": ">=12.0.0" } }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "license": "ISC", - "peer": true, - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/falafel": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.5.tgz", - "integrity": "sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "acorn": "^7.1.1", - "isarray": "^2.0.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/falafel/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -10698,16 +9702,6 @@ "node": ">= 6" } }, - "node_modules/fast-isnumeric": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-isnumeric/-/fast-isnumeric-1.1.4.tgz", - "integrity": "sha512-1mM8qOr2LYz8zGaUdmiqRDiuue00Dxjgcb1NQR7TnhLVh6sQyngP9xvLo7Sl7LZpP/sk5eb+bcyWXw530NTBZw==", - "license": "MIT", - "peer": true, - "dependencies": { - "is-string-blank": "^1.0.1" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -10832,36 +9826,6 @@ "license": "ISC", "peer": true }, - "node_modules/flatten-vertex-data": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz", - "integrity": "sha512-BvCBFK2NZqerFTdMDgqfHBwxYWnxeCkwONsw6PvBMcUXqo8U/KDWwmXhqx1x2kLIg7DqIsJfOaJFOmlua3Lxuw==", - "license": "MIT", - "peer": true, - "dependencies": { - "dtype": "^2.0.0" - } - }, - "node_modules/font-atlas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/font-atlas/-/font-atlas-2.1.0.tgz", - "integrity": "sha512-kP3AmvX+HJpW4w3d+PiPR2X6E1yvsBXt2yhuCw+yReO9F1WYhvZwx3c95DGZGwg9xYzDGrgJYa885xmVA+28Cg==", - "license": "MIT", - "peer": true, - "dependencies": { - "css-font": "^1.0.0" - } - }, - "node_modules/font-measure": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/font-measure/-/font-measure-1.2.2.tgz", - "integrity": "sha512-mRLEpdrWzKe9hbfaF3Qpr06TAjquuBVP5cHy4b3hyeNdjc9i0PO6HniGsX5vjL5OWv7+Bd++NiooNpT/s8BvIA==", - "license": "MIT", - "peer": true, - "dependencies": { - "css-font": "^1.2.0" - } - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -10895,17 +9859,6 @@ "node": ">= 6" } }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "license": "MIT", - "peer": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -10933,6 +9886,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10999,20 +9953,6 @@ "node": ">=6.9.0" } }, - "node_modules/geojson-vt": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", - "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==", - "license": "ISC", - "peer": true - }, - "node_modules/get-canvas-context": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-canvas-context/-/get-canvas-context-1.0.2.tgz", - "integrity": "sha512-LnpfLf/TNzr9zVOGiIY6aKCz8EKuXmlYNV7CM2pUjBa/B+c2I15tS7KLySep75+FuerJdmArvJLcsAXWEy2H0A==", - "license": "MIT", - "peer": true - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -11052,19 +9992,6 @@ "node": ">= 0.4" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-symbol-description": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", @@ -11083,62 +10010,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gl-mat4": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.2.0.tgz", - "integrity": "sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA==", - "license": "Zlib", - "peer": true - }, - "node_modules/gl-matrix": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", - "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", - "license": "MIT", - "peer": true - }, - "node_modules/gl-text": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/gl-text/-/gl-text-1.4.0.tgz", - "integrity": "sha512-o47+XBqLCj1efmuNyCHt7/UEJmB9l66ql7pnobD6p+sgmBUdzfMZXIF0zD2+KRfpd99DJN+QXdvTFAGCKCVSmQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "bit-twiddle": "^1.0.2", - "color-normalize": "^1.5.0", - "css-font": "^1.2.0", - "detect-kerning": "^2.1.2", - "es6-weak-map": "^2.0.3", - "flatten-vertex-data": "^1.0.2", - "font-atlas": "^2.1.0", - "font-measure": "^1.2.2", - "gl-util": "^3.1.2", - "is-plain-obj": "^1.1.0", - "object-assign": "^4.1.1", - "parse-rect": "^1.2.0", - "parse-unit": "^1.0.1", - "pick-by-alias": "^1.2.0", - "regl": "^2.0.0", - "to-px": "^1.0.1", - "typedarray-pool": "^1.1.0" - } - }, - "node_modules/gl-util": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/gl-util/-/gl-util-3.1.3.tgz", - "integrity": "sha512-dvRTggw5MSkJnCbh74jZzSoTOGnVYK+Bt+Ckqm39CVcl6+zSsxqWk4lr5NKhkqXHL6qvZAU9h17ZF8mIskY9mA==", - "license": "MIT", - "peer": true, - "dependencies": { - "is-browser": "^2.0.1", - "is-firefox": "^1.0.3", - "is-plain-obj": "^1.1.0", - "number-is-integer": "^1.0.1", - "object-assign": "^4.1.0", - "pick-by-alias": "^1.2.0", - "weak-map": "^1.0.5" - } - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -11210,47 +10081,6 @@ "node": "*" } }, - "node_modules/global-prefix": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", - "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", - "license": "MIT", - "peer": true, - "dependencies": { - "ini": "^4.1.3", - "kind-of": "^6.0.3", - "which": "^4.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/global-prefix/node_modules/isexe": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", - "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", - "license": "BlueOak-1.0.0", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", - "peer": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -11306,228 +10136,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glsl-inject-defines": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz", - "integrity": "sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A==", - "license": "MIT", - "peer": true, - "dependencies": { - "glsl-token-inject-block": "^1.0.0", - "glsl-token-string": "^1.0.1", - "glsl-tokenizer": "^2.0.2" - } - }, - "node_modules/glsl-resolve": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/glsl-resolve/-/glsl-resolve-0.0.1.tgz", - "integrity": "sha512-xxFNsfnhZTK9NBhzJjSBGX6IOqYpvBHxxmo+4vapiljyGNCY0Bekzn0firQkQrazK59c1hYxMDxYS8MDlhw4gA==", - "license": "MIT", - "peer": true, - "dependencies": { - "resolve": "^0.6.1", - "xtend": "^2.1.2" - } - }, - "node_modules/glsl-resolve/node_modules/resolve": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", - "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-resolve/node_modules/xtend": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.2.0.tgz", - "integrity": "sha512-SLt5uylT+4aoXxXuwtQp5ZnMMzhDb1Xkg4pEqc00WUJCQifPfV9Ub1VrNhp9kXkrjZD2I2Hl8WnjP37jzZLPZw==", - "peer": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/glsl-token-assignments": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/glsl-token-assignments/-/glsl-token-assignments-2.0.2.tgz", - "integrity": "sha512-OwXrxixCyHzzA0U2g4btSNAyB2Dx8XrztY5aVUCjRSh4/D0WoJn8Qdps7Xub3sz6zE73W3szLrmWtQ7QMpeHEQ==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-token-defines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/glsl-token-defines/-/glsl-token-defines-1.0.0.tgz", - "integrity": "sha512-Vb5QMVeLjmOwvvOJuPNg3vnRlffscq2/qvIuTpMzuO/7s5kT+63iL6Dfo2FYLWbzuiycWpbC0/KV0biqFwHxaQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "glsl-tokenizer": "^2.0.0" - } - }, - "node_modules/glsl-token-depth": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/glsl-token-depth/-/glsl-token-depth-1.1.2.tgz", - "integrity": "sha512-eQnIBLc7vFf8axF9aoi/xW37LSWd2hCQr/3sZui8aBJnksq9C7zMeUYHVJWMhFzXrBU7fgIqni4EhXVW4/krpg==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-token-descope": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glsl-token-descope/-/glsl-token-descope-1.0.2.tgz", - "integrity": "sha512-kS2PTWkvi/YOeicVjXGgX5j7+8N7e56srNDEHDTVZ1dcESmbmpmgrnpjPcjxJjMxh56mSXYoFdZqb90gXkGjQw==", - "license": "MIT", - "peer": true, - "dependencies": { - "glsl-token-assignments": "^2.0.0", - "glsl-token-depth": "^1.1.0", - "glsl-token-properties": "^1.0.0", - "glsl-token-scope": "^1.1.0" - } - }, - "node_modules/glsl-token-inject-block": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz", - "integrity": "sha512-q/m+ukdUBuHCOtLhSr0uFb/qYQr4/oKrPSdIK2C4TD+qLaJvqM9wfXIF/OOBjuSA3pUoYHurVRNao6LTVVUPWA==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-token-properties": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/glsl-token-properties/-/glsl-token-properties-1.0.1.tgz", - "integrity": "sha512-dSeW1cOIzbuUoYH0y+nxzwK9S9O3wsjttkq5ij9ZGw0OS41BirKJzzH48VLm8qLg+au6b0sINxGC0IrGwtQUcA==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-token-scope": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/glsl-token-scope/-/glsl-token-scope-1.1.2.tgz", - "integrity": "sha512-YKyOMk1B/tz9BwYUdfDoHvMIYTGtVv2vbDSLh94PT4+f87z21FVdou1KNKgF+nECBTo0fJ20dpm0B1vZB1Q03A==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-token-string": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/glsl-token-string/-/glsl-token-string-1.0.1.tgz", - "integrity": "sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-token-whitespace-trim": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/glsl-token-whitespace-trim/-/glsl-token-whitespace-trim-1.0.0.tgz", - "integrity": "sha512-ZJtsPut/aDaUdLUNtmBYhaCmhIjpKNg7IgZSfX5wFReMc2vnj8zok+gB/3Quqs0TsBSX/fGnqUUYZDqyuc2xLQ==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-tokenizer": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz", - "integrity": "sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==", - "license": "MIT", - "peer": true, - "dependencies": { - "through2": "^0.6.3" - } - }, - "node_modules/glsl-tokenizer/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-tokenizer/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/glsl-tokenizer/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "license": "MIT", - "peer": true - }, - "node_modules/glsl-tokenizer/node_modules/through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "node_modules/glslify": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glslify/-/glslify-7.1.1.tgz", - "integrity": "sha512-bud98CJ6kGZcP9Yxcsi7Iz647wuDz3oN+IZsjCRi5X1PI7t/xPKeL0mOwXJjo+CRZMqvq0CkSJiywCcY7kVYog==", - "license": "MIT", - "peer": true, - "dependencies": { - "bl": "^2.2.1", - "concat-stream": "^1.5.2", - "duplexify": "^3.4.5", - "falafel": "^2.1.0", - "from2": "^2.3.0", - "glsl-resolve": "0.0.1", - "glsl-token-whitespace-trim": "^1.0.0", - "glslify-bundle": "^5.0.0", - "glslify-deps": "^1.2.5", - "minimist": "^1.2.5", - "resolve": "^1.1.5", - "stack-trace": "0.0.9", - "static-eval": "^2.0.5", - "through2": "^2.0.1", - "xtend": "^4.0.0" - }, - "bin": { - "glslify": "bin.js" - } - }, - "node_modules/glslify-bundle": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glslify-bundle/-/glslify-bundle-5.1.1.tgz", - "integrity": "sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A==", - "license": "MIT", - "peer": true, - "dependencies": { - "glsl-inject-defines": "^1.0.1", - "glsl-token-defines": "^1.0.0", - "glsl-token-depth": "^1.1.1", - "glsl-token-descope": "^1.0.2", - "glsl-token-scope": "^1.1.1", - "glsl-token-string": "^1.0.1", - "glsl-token-whitespace-trim": "^1.0.0", - "glsl-tokenizer": "^2.0.2", - "murmurhash-js": "^1.0.0", - "shallow-copy": "0.0.1" - } - }, - "node_modules/glslify-deps": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/glslify-deps/-/glslify-deps-1.3.2.tgz", - "integrity": "sha512-7S7IkHWygJRjcawveXQjRXLO2FTjijPDYC7QfZyAQanY+yGLCFHYnPtsGT9bdyHiwPTw/5a1m1M9hamT2aBpag==", - "license": "ISC", - "peer": true, - "dependencies": { - "@choojs/findup": "^0.2.0", - "events": "^3.2.0", - "glsl-resolve": "0.0.1", - "glsl-tokenizer": "^2.0.0", - "graceful-fs": "^4.1.2", - "inherits": "^2.0.1", - "map-limit": "0.0.1", - "resolve": "^1.0.0" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -11541,13 +10149,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC", - "peer": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -11594,13 +10195,6 @@ "graphql": ">=0.11 <=16" } }, - "node_modules/grid-index": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", - "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", - "license": "ISC", - "peer": true - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -11624,26 +10218,6 @@ "node": ">=8" } }, - "node_modules/has-hover": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-hover/-/has-hover-1.0.1.tgz", - "integrity": "sha512-0G6w7LnlcpyDzpeGUTuT0CEw05+QlMuGVk1IHNAlHrGJITGodjZu3x8BNDUMfKJSZXNB2ZAclqc1bvrd+uUpfg==", - "license": "MIT", - "peer": true, - "dependencies": { - "is-browser": "^2.0.1" - } - }, - "node_modules/has-passive-events": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-passive-events/-/has-passive-events-1.0.0.tgz", - "integrity": "sha512-2vSj6IeIsgvsRMyeQ0JaCX5Q3lX4zMn5HpoVc7MEhQ6pv8Iq9rsXjsp+E5ZwaT7T0xhMT0KmU8gtt1EFVdbJiw==", - "license": "MIT", - "peer": true, - "dependencies": { - "is-browser": "^2.0.1" - } - }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -11731,6 +10305,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "devOptional": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -11858,6 +10433,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, "funding": [ { "type": "github", @@ -11985,18 +10561,9 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, "license": "ISC" }, - "node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "license": "ISC", - "peer": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -12117,13 +10684,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-browser/-/is-browser-2.1.0.tgz", - "integrity": "sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ==", - "license": "MIT", - "peer": true - }, "node_modules/is-builtin-module": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", @@ -12157,6 +10717,7 @@ "version": "2.16.2", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "devOptional": true, "license": "MIT", "dependencies": { "hasown": "^2.0.3" @@ -12223,33 +10784,10 @@ "call-bound": "^1.0.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-firefox": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-firefox/-/is-firefox-1.0.3.tgz", - "integrity": "sha512-6Q9ITjvWIm0Xdqv+5U12wgOKEM2KoBw4Y926m0OFkvlCxnbG94HKAsVz8w3fWcfAS5YA2fJORXX1dLrkprCCxA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-generator-function": { @@ -12298,13 +10836,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-mobile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-4.0.0.tgz", - "integrity": "sha512-mlcHZA84t1qLSuWkt2v0I2l61PYdyQDt4aG1mLIXF5FDMm4+haBCxCPYSr/uwqQNRk1MiTizn0ypEuRAOLRAew==", - "license": "MIT", - "peer": true - }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -12369,16 +10900,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -12390,16 +10911,6 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -12482,20 +10993,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-string-blank": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-string-blank/-/is-string-blank-1.0.1.tgz", - "integrity": "sha512-9H+ZBCVs3L9OYqv8nuUAzpcT9OTgMD1yAWrG7ihlnibdkbtB850heAmYWxHuXc4CHy4lKeK69tN+ny1K7gBIrw==", - "license": "MIT", - "peer": true - }, - "node_modules/is-svg-path": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-svg-path/-/is-svg-path-1.0.2.tgz", - "integrity": "sha512-Lj4vePmqpPR1ZnRctHv8ltSh1OrSxHkhUkd7wi+VQdcdP15/KvQFyk7LhNuM7ZW0EVbJz8kZLVmL9quLrfq4Kg==", - "license": "MIT", - "peer": true - }, "node_modules/is-symbol": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", @@ -12580,6 +11077,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -12820,13 +11318,6 @@ "license": "MIT", "peer": true }, - "node_modules/json-stringify-pretty-compact": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", - "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", - "license": "MIT", - "peer": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -12856,13 +11347,6 @@ "node": ">=4.0" } }, - "node_modules/kdbush": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz", - "integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==", - "license": "ISC", - "peer": true - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -12874,16 +11358,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -13255,6 +11729,7 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, "license": "MIT", "peer": true }, @@ -13328,161 +11803,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/map-limit": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/map-limit/-/map-limit-0.0.1.tgz", - "integrity": "sha512-pJpcfLPnIF/Sk3taPW21G/RQsEEirGaFpCW3oXRwH9dnFHPHNGjNyvh++rdmC2fNqEaTw2MhYJraoJWAHx8kEg==", - "license": "MIT", - "peer": true, - "dependencies": { - "once": "~1.3.0" - } - }, - "node_modules/map-limit/node_modules/once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==", - "license": "ISC", - "peer": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/mapbox-gl": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.13.3.tgz", - "integrity": "sha512-p8lJFEiqmEQlyv+DQxFAOG/XPWN0Wp7j/Psq93Zywz7qt9CcUKFYDBOoOEKzqe6gudHVJY8/Bhqw6VDpX2lSBg==", - "license": "SEE LICENSE IN LICENSE.txt", - "peer": true, - "dependencies": { - "@mapbox/geojson-rewind": "^0.5.2", - "@mapbox/geojson-types": "^1.0.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^1.5.0", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^1.1.1", - "@mapbox/unitbezier": "^0.0.0", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "csscolorparser": "~1.0.3", - "earcut": "^2.2.2", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.2.1", - "grid-index": "^1.1.0", - "murmurhash-js": "^1.0.0", - "pbf": "^3.2.1", - "potpack": "^1.0.1", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "supercluster": "^7.1.0", - "tinyqueue": "^2.0.3", - "vt-pbf": "^3.1.1" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/maplibre-gl": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", - "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "@mapbox/geojson-rewind": "^0.5.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^2.0.6", - "@mapbox/unitbezier": "^0.0.1", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "@maplibre/maplibre-gl-style-spec": "^20.3.1", - "@types/geojson": "^7946.0.14", - "@types/geojson-vt": "3.2.5", - "@types/mapbox__point-geometry": "^0.1.4", - "@types/mapbox__vector-tile": "^1.3.4", - "@types/pbf": "^3.0.5", - "@types/supercluster": "^7.1.3", - "earcut": "^3.0.0", - "geojson-vt": "^4.0.2", - "gl-matrix": "^3.4.3", - "global-prefix": "^4.0.0", - "kdbush": "^4.0.2", - "murmurhash-js": "^1.0.0", - "pbf": "^3.3.0", - "potpack": "^2.0.0", - "quickselect": "^3.0.0", - "supercluster": "^8.0.1", - "tinyqueue": "^3.0.0", - "vt-pbf": "^3.1.3" - }, - "engines": { - "node": ">=16.14.0", - "npm": ">=8.1.0" - }, - "funding": { - "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" - } - }, - "node_modules/maplibre-gl/node_modules/@mapbox/tiny-sdf": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz", - "integrity": "sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==", - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/maplibre-gl/node_modules/@mapbox/unitbezier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", - "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/maplibre-gl/node_modules/earcut": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", - "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", - "license": "ISC", - "peer": true - }, - "node_modules/maplibre-gl/node_modules/geojson-vt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.3.tgz", - "integrity": "sha512-jR1MwkLaZGa8Zftct9ZFruyWFrdl9ZyD2OliXNy9Qq5bBPeg5wHVpBQF9p5GjnicSDQqvBVpysxTPKmWdsfWMA==", - "license": "ISC", - "peer": true - }, - "node_modules/maplibre-gl/node_modules/potpack": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz", - "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==", - "license": "ISC", - "peer": true - }, - "node_modules/maplibre-gl/node_modules/quickselect": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", - "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", - "license": "ISC", - "peer": true - }, - "node_modules/maplibre-gl/node_modules/supercluster": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", - "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", - "license": "ISC", - "peer": true, - "dependencies": { - "kdbush": "^4.0.2" - } - }, - "node_modules/maplibre-gl/node_modules/tinyqueue": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", - "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", - "license": "ISC", - "peer": true - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -13493,16 +11813,6 @@ "node": ">= 0.4" } }, - "node_modules/math-log2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-log2/-/math-log2-1.0.1.tgz", - "integrity": "sha512-9W0yGtkaMAkf74XGYVy4Dqw3YUMnTNB2eeiw9aQbUl4A3KmuCEHTt2DgAB07ENzOYAjsYSAYufkAq0Zd+jU7zA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -13647,6 +11957,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13672,26 +11983,13 @@ "color-name": "^1.1.4" } }, - "node_modules/mouse-event-offset": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mouse-event-offset/-/mouse-event-offset-3.0.2.tgz", - "integrity": "sha512-s9sqOs5B1Ykox3Xo8b3Ss2IQju4UwlW6LSR+Q5FXWpprJ5fzMLefIIItr3PH8RwzfGy6gxs/4GAmiNuZScE25w==", - "license": "MIT", - "peer": true - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "devOptional": true, "license": "MIT" }, - "node_modules/murmurhash-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", - "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", - "license": "MIT", - "peer": true - }, "node_modules/nanoid": { "version": "3.3.12", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", @@ -13711,13 +12009,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/native-promise-only": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", - "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", - "license": "MIT", - "peer": true - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -13733,54 +12024,6 @@ "dev": true, "license": "MIT" }, - "node_modules/needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/needle/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "license": "ISC", - "peer": true - }, "node_modules/node-exports-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", @@ -13915,13 +12158,6 @@ "semver": "bin/semver" } }, - "node_modules/normalize-svg-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-0.1.0.tgz", - "integrity": "sha512-1/kmYej2iedi5+ROxkRESL/pI02pkg0OBnaR4hJkSIX6+ORzepwbuUXfrdZaPjysTsJInj0Rj5NuX027+dMBvA==", - "license": "MIT", - "peer": true - }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -13948,19 +12184,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/number-is-integer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-integer/-/number-is-integer-1.0.1.tgz", - "integrity": "sha512-Dq3iuiFBkrbmuQjGFFF3zckXNCQoSD37/SdSbgcBailUx6knDvDwb5CympBgcoWHy36sfS12u74MHYkXyHq6bg==", - "license": "MIT", - "peer": true, - "dependencies": { - "is-finite": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/nwsapi": { "version": "2.2.23", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", @@ -14122,6 +12345,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "license": "ISC", "peer": true, "dependencies": { @@ -14287,13 +12511,6 @@ "node": ">=6" } }, - "node_modules/parenthesis": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.8.tgz", - "integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==", - "license": "MIT", - "peer": true - }, "node_modules/parse-asn1": { "version": "5.1.9", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", @@ -14330,30 +12547,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-rect": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parse-rect/-/parse-rect-1.2.0.tgz", - "integrity": "sha512-4QZ6KYbnE6RTwg9E0HpLchUM9EZt6DnDxajFZZDSV4p/12ZJEvPO702DZpGvRYEPo00yKDys7jASi+/w7aO8LA==", - "license": "MIT", - "peer": true, - "dependencies": { - "pick-by-alias": "^1.2.0" - } - }, - "node_modules/parse-svg-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", - "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", - "license": "MIT", - "peer": true - }, - "node_modules/parse-unit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz", - "integrity": "sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg==", - "license": "MIT", - "peer": true - }, "node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -14410,6 +12603,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "devOptional": true, "license": "MIT" }, "node_modules/path-type": { @@ -14429,20 +12623,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pbf": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", - "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "ieee754": "^1.1.12", - "resolve-protobuf-schema": "^2.1.0" - }, - "bin": { - "pbf": "bin/pbf" - } - }, "node_modules/pbkdf2": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", @@ -14461,20 +12641,6 @@ "node": ">= 0.10" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "license": "MIT", - "peer": true - }, - "node_modules/pick-by-alias": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pick-by-alias/-/pick-by-alias-1.2.0.tgz", - "integrity": "sha512-ESj2+eBxhGrcA1azgHs7lARG5+5iLakc/6nlfbpjcLl00HuuUOIuORhYXN4D1HfvMSKuVtFQjAlnwi1JHEeDIw==", - "license": "MIT", - "peer": true - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -14516,148 +12682,11 @@ "license": "MIT", "dependencies": { "find-up": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/plotly.js": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-3.5.1.tgz", - "integrity": "sha512-rUzQ7Q46whi1aWT2JlvKE2dnryNORPrxyy66OGSMXgejK3XgD4ysD9SapMOI1RzzUJyX0KbfVDFcB9/DqOyH9Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "@plotly/d3": "3.8.2", - "@plotly/d3-sankey": "0.7.2", - "@plotly/d3-sankey-circular": "0.33.1", - "@plotly/mapbox-gl": "1.13.4", - "@plotly/regl": "^2.1.2", - "@turf/area": "^7.1.0", - "@turf/bbox": "^7.1.0", - "@turf/centroid": "^7.1.0", - "base64-arraybuffer": "^1.0.2", - "color-normalize": "1.5.0", - "color-rgba": "3.0.0", - "country-regex": "^1.1.0", - "d3-force": "^1.2.1", - "d3-format": "^1.4.5", - "d3-geo": "^1.12.1", - "d3-geo-projection": "^2.9.0", - "d3-hierarchy": "^1.1.9", - "d3-interpolate": "^3.0.1", - "d3-time": "^1.1.0", - "d3-time-format": "^2.2.3", - "fast-isnumeric": "^1.1.4", - "gl-mat4": "^1.2.0", - "gl-text": "^1.4.0", - "has-hover": "^1.0.1", - "has-passive-events": "^1.0.0", - "is-mobile": "^4.0.0", - "maplibre-gl": "^4.7.1", - "mouse-event-offset": "^3.0.2", - "native-promise-only": "^0.8.1", - "parse-svg-path": "^0.1.2", - "point-in-polygon": "^1.1.0", - "polybooljs": "^1.2.2", - "probe-image-size": "^7.2.3", - "regl-error2d": "^2.0.12", - "regl-line2d": "^3.1.3", - "regl-scatter2d": "^3.3.1", - "regl-splom": "^1.0.14", - "strongly-connected-components": "^1.0.1", - "svg-path-sdf": "^1.1.3", - "tinycolor2": "^1.4.2", - "topojson-client": "^3.1.0", - "webgl-context": "^2.2.0", - "world-calendars": "^1.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/plotly.js/node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/plotly.js/node_modules/d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/plotly.js/node_modules/d3-force": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", - "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - }, - "node_modules/plotly.js/node_modules/d3-format": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", - "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/plotly.js/node_modules/d3-geo": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", - "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "d3-array": "1" - } - }, - "node_modules/plotly.js/node_modules/d3-hierarchy": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", - "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/plotly.js/node_modules/d3-quadtree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", - "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/plotly.js/node_modules/d3-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", - "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/plotly.js/node_modules/d3-time-format": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", - "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "d3-time": "1" + }, + "engines": { + "node": ">=10" } }, - "node_modules/plotly.js/node_modules/d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", - "license": "BSD-3-Clause", - "peer": true - }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -14668,20 +12697,6 @@ "node": ">=4" } }, - "node_modules/point-in-polygon": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", - "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==", - "license": "MIT", - "peer": true - }, - "node_modules/polybooljs": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/polybooljs/-/polybooljs-1.2.2.tgz", - "integrity": "sha512-ziHW/02J0XuNuUtmidBc6GXE8YohYydp3DWPWXYsd7O721TjcmN+k6ezjdwkDqep+gnWnFY+yqZHvzElra2oCg==", - "license": "MIT", - "peer": true - }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -15325,13 +13340,6 @@ "dev": true, "license": "MIT" }, - "node_modules/potpack": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "license": "ISC", - "peer": true - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -15407,28 +13415,6 @@ "dev": true, "license": "MIT" }, - "node_modules/probe-image-size": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.3.0.tgz", - "integrity": "sha512-7CaDeBwiAbh6ohXsvLbAZhO7wzsZAmaevfxe39qvCwRh8LyaZfDlBGGLU1CCTgrTLtCOdwBBhjOrIHaIIimHfQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "lodash.merge": "^4.6.2", - "needle": "^2.5.2", - "stream-parser": "~0.3.1" - } - }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -15443,6 +13429,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, "license": "MIT" }, "node_modules/promise.series": { @@ -15472,13 +13459,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/protocol-buffers-schema": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz", - "integrity": "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==", - "license": "MIT", - "peer": true - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -15557,23 +13537,6 @@ ], "license": "MIT" }, - "node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", - "license": "ISC", - "peer": true - }, - "node_modules/raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "license": "MIT", - "peer": true, - "dependencies": { - "performance-now": "^2.1.0" - } - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -15684,19 +13647,6 @@ "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", "license": "MIT" }, - "node_modules/react-plotly.js": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-plotly.js/-/react-plotly.js-2.6.0.tgz", - "integrity": "sha512-g93xcyhAVCSt9kV1svqG1clAEdL6k3U+jjuSzfTV7owaSU9Go6Ph8bl25J+jKfKvIGAEYpe4qj++WHJuc9IaeA==", - "license": "MIT", - "dependencies": { - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "plotly.js": ">1.34.0", - "react": ">0.13.0" - } - }, "node_modules/react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", @@ -15964,6 +13914,7 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -15979,12 +13930,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, "license": "MIT" }, "node_modules/readable-stream/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, "license": "MIT" }, "node_modules/redent": { @@ -16150,85 +14103,6 @@ "jsesc": "bin/jsesc" } }, - "node_modules/regl": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.1.tgz", - "integrity": "sha512-+IOGrxl3FZ8ZM9ixCWQZzFRiRn7Rzn9bu3iFHwg/yz4tlOUQgbO4PHLgG+1ZT60zcIV8tief6Qrmyl8qcoJP0g==", - "license": "MIT", - "peer": true - }, - "node_modules/regl-error2d": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/regl-error2d/-/regl-error2d-2.0.12.tgz", - "integrity": "sha512-r7BUprZoPO9AbyqM5qlJesrSRkl+hZnVKWKsVp7YhOl/3RIpi4UDGASGJY0puQ96u5fBYw/OlqV24IGcgJ0McA==", - "license": "MIT", - "peer": true, - "dependencies": { - "array-bounds": "^1.0.1", - "color-normalize": "^1.5.0", - "flatten-vertex-data": "^1.0.2", - "object-assign": "^4.1.1", - "pick-by-alias": "^1.2.0", - "to-float32": "^1.1.0", - "update-diff": "^1.1.0" - } - }, - "node_modules/regl-line2d": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/regl-line2d/-/regl-line2d-3.1.3.tgz", - "integrity": "sha512-fkgzW+tTn4QUQLpFKsUIE0sgWdCmXAM3ctXcCgoGBZTSX5FE2A0M7aynz7nrZT5baaftLrk9te54B+MEq4QcSA==", - "license": "MIT", - "peer": true, - "dependencies": { - "array-bounds": "^1.0.1", - "array-find-index": "^1.0.2", - "array-normalize": "^1.1.4", - "color-normalize": "^1.5.0", - "earcut": "^2.1.5", - "es6-weak-map": "^2.0.3", - "flatten-vertex-data": "^1.0.2", - "object-assign": "^4.1.1", - "parse-rect": "^1.2.0", - "pick-by-alias": "^1.2.0", - "to-float32": "^1.1.0" - } - }, - "node_modules/regl-scatter2d": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/regl-scatter2d/-/regl-scatter2d-3.4.0.tgz", - "integrity": "sha512-DavKQlHsI+iHZuLgOL+yGkg+sPd94CS+7FCBWkcQ6s/TbaNfUsF9eN591fjjSWIoKrGNfb/SEGhsXR5lXjqZ2w==", - "license": "MIT", - "peer": true, - "dependencies": { - "@plotly/point-cluster": "^3.1.9", - "array-bounds": "^1.0.1", - "color-id": "^1.1.0", - "color-normalize": "^1.5.0", - "flatten-vertex-data": "^1.0.2", - "glslify": "^7.0.0", - "parse-rect": "^1.2.0", - "pick-by-alias": "^1.2.0", - "to-float32": "^1.1.0", - "update-diff": "^1.1.0" - } - }, - "node_modules/regl-splom": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/regl-splom/-/regl-splom-1.0.14.tgz", - "integrity": "sha512-OiLqjmPRYbd7kDlHC6/zDf6L8lxgDC65BhC8JirhP4ykrK4x22ZyS+BnY8EUinXKDeMgmpRwCvUmk7BK4Nweuw==", - "license": "MIT", - "peer": true, - "dependencies": { - "array-bounds": "^1.0.1", - "array-range": "^1.0.1", - "color-alpha": "^1.0.4", - "flatten-vertex-data": "^1.0.2", - "parse-rect": "^1.2.0", - "pick-by-alias": "^1.2.0", - "raf": "^3.4.1", - "regl-scatter2d": "^3.2.3" - } - }, "node_modules/rehackt": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.1.0.tgz", @@ -16264,6 +14138,7 @@ "version": "1.22.12", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "devOptional": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -16291,16 +14166,6 @@ "node": ">=4" } }, - "node_modules/resolve-protobuf-schema": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "protocol-buffers-schema": "^3.3.1" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -16606,6 +14471,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/safe-array-concat": { @@ -16632,6 +14498,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -16703,12 +14570,14 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, "license": "MIT" }, "node_modules/sax": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -16833,13 +14702,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shallow-copy": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", - "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", - "license": "MIT", - "peer": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -17022,15 +14884,6 @@ "dev": true, "license": "MIT" }, - "node_modules/stack-trace": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", - "integrity": "sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==", - "peer": true, - "engines": { - "node": "*" - } - }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -17038,16 +14891,6 @@ "dev": true, "license": "MIT" }, - "node_modules/static-eval": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", - "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", - "license": "MIT", - "peer": true, - "dependencies": { - "escodegen": "^2.1.0" - } - }, "node_modules/std-env": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", @@ -17123,44 +14966,11 @@ "node": ">= 6" } }, - "node_modules/stream-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", - "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "2" - } - }, - "node_modules/stream-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/stream-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true - }, - "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", - "license": "MIT", - "peer": true - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -17170,6 +14980,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, "license": "MIT" }, "node_modules/string-hash": { @@ -17186,16 +14997,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string-split-by": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz", - "integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==", - "license": "MIT", - "peer": true, - "dependencies": { - "parenthesis": "^3.1.5" - } - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -17360,13 +15161,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strongly-connected-components": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strongly-connected-components/-/strongly-connected-components-1.0.1.tgz", - "integrity": "sha512-i0TFx4wPcO0FwX+4RkLJi1MxmcTv90jNZgxMu9XRnMXMeFUY1VJlIoXpZunPUvUUqbCT1pg5PEkFqqpcaElNaA==", - "license": "MIT", - "peer": true - }, "node_modules/style-inject": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", @@ -17397,23 +15191,6 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "license": "MIT" }, - "node_modules/supercluster": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", - "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", - "license": "ISC", - "peer": true, - "dependencies": { - "kdbush": "^3.0.0" - } - }, - "node_modules/supercluster/node_modules/kdbush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", - "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==", - "license": "ISC", - "peer": true - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -17431,6 +15208,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -17439,50 +15217,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svg-arc-to-cubic-bezier": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", - "integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==", - "license": "ISC", - "peer": true - }, - "node_modules/svg-path-bounds": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/svg-path-bounds/-/svg-path-bounds-1.0.2.tgz", - "integrity": "sha512-H4/uAgLWrppIC0kHsb2/dWUYSmb4GE5UqH06uqWBcg6LBjX2fu0A8+JrO2/FJPZiSsNOKZAhyFFgsLTdYUvSqQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "abs-svg-path": "^0.1.1", - "is-svg-path": "^1.0.1", - "normalize-svg-path": "^1.0.0", - "parse-svg-path": "^0.1.2" - } - }, - "node_modules/svg-path-bounds/node_modules/normalize-svg-path": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz", - "integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==", - "license": "MIT", - "peer": true, - "dependencies": { - "svg-arc-to-cubic-bezier": "^3.0.0" - } - }, - "node_modules/svg-path-sdf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/svg-path-sdf/-/svg-path-sdf-1.1.3.tgz", - "integrity": "sha512-vJJjVq/R5lSr2KLfVXVAStktfcfa1pNFjFOgyJnzZFXlO/fDZ5DmM8FpnSKKzLPfEYTVeXuVBTHF296TpxuJVg==", - "license": "MIT", - "peer": true, - "dependencies": { - "bitmap-sdf": "^1.0.0", - "draw-svg-path": "^1.0.0", - "is-svg-path": "^1.0.1", - "parse-svg-path": "^0.1.2", - "svg-path-bounds": "^1.0.1" - } - }, "node_modules/svgo": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.2.tgz", @@ -17546,17 +15280,6 @@ "license": "MIT", "peer": true }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/timers-browserify": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", @@ -17577,13 +15300,6 @@ "dev": true, "license": "MIT" }, - "node_modules/tinycolor2": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", - "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", - "license": "MIT", - "peer": true - }, "node_modules/tinyexec": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", @@ -17611,13 +15327,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", - "license": "ISC", - "peer": true - }, "node_modules/tinyrainbow": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", @@ -17663,23 +15372,6 @@ "node": ">= 0.4" } }, - "node_modules/to-float32": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/to-float32/-/to-float32-1.1.0.tgz", - "integrity": "sha512-keDnAusn/vc+R3iEiSDw8TOF7gPiTLdK1ArvWtYbJQiVfmRg6i/CAvbKq3uIS0vWroAC7ZecN3DjQKw3aSklUg==", - "license": "MIT", - "peer": true - }, - "node_modules/to-px": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/to-px/-/to-px-1.1.0.tgz", - "integrity": "sha512-bfg3GLYrGoEzrGoE05TAL/Uw+H/qrf2ptr9V3W7U0lkjjyYnIfgxmVLUfhQ1hZpIQwin81uxhDjvUkDYsC0xWw==", - "license": "MIT", - "peer": true, - "dependencies": { - "parse-unit": "^1.0.1" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -17693,28 +15385,6 @@ "node": ">=8.0" } }, - "node_modules/topojson-client": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", - "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", - "license": "ISC", - "peer": true, - "dependencies": { - "commander": "2" - }, - "bin": { - "topo2geo": "bin/topo2geo", - "topomerge": "bin/topomerge", - "topoquantize": "bin/topoquantize" - } - }, - "node_modules/topojson-client/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true - }, "node_modules/tough-cookie": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", @@ -17797,6 +15467,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, "license": "0BSD" }, "node_modules/tsutils": { @@ -17829,13 +15500,6 @@ "dev": true, "license": "MIT" }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "license": "ISC", - "peer": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -17942,24 +15606,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "license": "MIT", - "peer": true - }, - "node_modules/typedarray-pool": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/typedarray-pool/-/typedarray-pool-1.2.0.tgz", - "integrity": "sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "bit-twiddle": "^1.0.0", - "dup": "^1.0.0" - } - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -18044,13 +15690,6 @@ "node": ">=4" } }, - "node_modules/unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==", - "license": "MIT", - "peer": true - }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -18082,13 +15721,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/update-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-diff/-/update-diff-1.1.0.tgz", - "integrity": "sha512-rCiBPiHxZwT4+sBhEbChzpO5hYHjm91kScWgdHf4Qeafs6Ba7MBl+d9GlGv72bcTZQO0sLmtQS1pHSWoCLtN/A==", - "license": "MIT", - "peer": true - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -18162,6 +15794,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, "license": "MIT" }, "node_modules/validate-npm-package-license": { @@ -18491,18 +16124,6 @@ "dev": true, "license": "MIT" }, - "node_modules/vt-pbf": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", - "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@mapbox/point-geometry": "0.1.0", - "@mapbox/vector-tile": "^1.3.1", - "pbf": "^3.2.1" - } - }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", @@ -18516,23 +16137,6 @@ "node": ">=18" } }, - "node_modules/weak-map": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.8.tgz", - "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==", - "license": "Apache-2.0", - "peer": true - }, - "node_modules/webgl-context": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/webgl-context/-/webgl-context-2.2.0.tgz", - "integrity": "sha512-q/fGIivtqTT7PEoF07axFIlHNk/XCPaYpq64btnepopSWvKNFkoORlQYgqDigBIuGA1ExnFd/GnSUnBNEPQY7Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "get-canvas-context": "^1.0.1" - } - }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -18715,20 +16319,11 @@ "node": ">=0.10.0" } }, - "node_modules/world-calendars": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.4.tgz", - "integrity": "sha512-VGRnLJS+xJmGDPodgJRnGIDwGu0s+Cr9V2HB3EzlDZ5n0qb8h5SJtGUEkjrphZYAglEiXZ6kiXdmk0H/h/uu/w==", - "license": "MIT", - "peer": true, - "dependencies": { - "object-assign": "^4.1.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC", "peer": true }, @@ -18788,6 +16383,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.4" diff --git a/package.json b/package.json index ecf3291..4568285 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "bufferutil": "^4.0.8", "loglevel": "^1.9.2", "react-grid-layout": "^2.2.3", - "react-plotly.js": "^2.6.0", "react-toastify": "^11.0.5", "safe-stable-stringify": "^2.5.0", "utf-8-validate": "^5.0.10" From af6f98a5319f34c48aecbf6ca9b2eb437565012b Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 17 Jun 2026 12:25:30 +0100 Subject: [PATCH 13/16] Ensure grid display changes are reflected in the file cache slice --- src/redux/slices/fileCacheSlice.test.ts | 107 +++++++++++++++++- src/redux/slices/fileCacheSlice.ts | 24 ++++ .../displayGridLayout.tsx | 29 ++++- 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/src/redux/slices/fileCacheSlice.test.ts b/src/redux/slices/fileCacheSlice.test.ts index a013906..3d15c6d 100644 --- a/src/redux/slices/fileCacheSlice.test.ts +++ b/src/redux/slices/fileCacheSlice.test.ts @@ -14,7 +14,8 @@ import fileCacheReducer, { createDisplayInstanceFromFile, displayInstanceUpdateResponsiveLayout, selectDisplayInstance, - selectDisplayInstanceByFileAndMacros + selectDisplayInstanceByFileAndMacros, + displayInstanceUpdateGridLayout } from "./fileCacheSlice"; const initialState: FileCacheState = { @@ -568,6 +569,110 @@ describe("createDisplayInstanceFromFile", () => { }); }); +describe("displayInstanceUpdateGridLayout", () => { + const baseDisplay = { + id: "display1", + type: "displayGridLayout", + fileId: "file", + gridLayout: [], + children: [] + }; + + const initialState: FileCacheState = { + fileCache: { + "file.bob": baseDisplay as any + }, + displayInstanceCache: { + UUID1: { + uuid: "UUID1", + fileId: "file.bob", + macros: {}, + hash: "", + description: baseDisplay + } + }, + displayInstanceIndex: {} + }; + + it("updates gridLayout on a valid display", () => { + const newLayout = [{ i: "a", x: 1, y: 2, w: 3, h: 4 }]; + + const result = fileCacheReducer( + initialState, + displayInstanceUpdateGridLayout({ + embeddedDisplayUuid: "UUID1", + gridDisplayId: "display1", + gridLayout: newLayout + }) + ); + + const display = result.displayInstanceCache["UUID1"].description; + + expect(display.gridLayout).toEqual(newLayout); + }); + + it("does nothing if display instance is missing", () => { + const state: FileCacheState = { + fileCache: {}, + displayInstanceCache: {}, + displayInstanceIndex: {} + }; + + const result = fileCacheReducer( + state, + displayInstanceUpdateGridLayout({ + embeddedDisplayUuid: "missing", + gridDisplayId: "display1", + gridLayout: [] + }) + ); + + expect(result).toEqual(state); + }); + + it("does nothing if display not found", () => { + const result = fileCacheReducer( + initialState, + displayInstanceUpdateGridLayout({ + embeddedDisplayUuid: "UUID1", + gridDisplayId: "missing", + gridLayout: [] + }) + ); + + expect(result).toEqual(initialState); + }); + + it("does nothing if display type is not displayGridLayout", () => { + const badState: FileCacheState = { + ...initialState, + displayInstanceCache: { + UUID1: { + uuid: "UUID1", + fileId: "file.bob", + macros: {}, + hash: "", + description: { + ...baseDisplay, + type: "shape" // wrong type + } + } + } + }; + + const result = fileCacheReducer( + badState, + displayInstanceUpdateGridLayout({ + embeddedDisplayUuid: "UUID1", + gridDisplayId: "display1", + gridLayout: [] + }) + ); + + expect(result).toEqual(badState); + }); +}); + describe("displayInstanceUpdateResponsiveLayout", () => { it("updates responsiveLayouts on existing display", () => { const state: FileCacheState = { diff --git a/src/redux/slices/fileCacheSlice.ts b/src/redux/slices/fileCacheSlice.ts index 23a725a..4c82c2c 100644 --- a/src/redux/slices/fileCacheSlice.ts +++ b/src/redux/slices/fileCacheSlice.ts @@ -131,6 +131,29 @@ const fileCacheSlice = createSlice({ } }); }, + displayInstanceUpdateGridLayout( + state, + action: PayloadAction<{ + embeddedDisplayUuid: string; + gridDisplayId: string; + gridLayout: Layout; + }> + ) { + const { embeddedDisplayUuid, gridDisplayId, gridLayout } = action.payload; + + const displayInstance = state.displayInstanceCache?.[embeddedDisplayUuid]; + if (!displayInstance) { + return; + } + + const display = findWidgetById( + [displayInstance.description], + gridDisplayId + ); + + if (!display || display.type !== "displayGridLayout") return; + display.gridLayout = gridLayout; + }, displayInstanceSetResponsiveLayout( state, @@ -253,6 +276,7 @@ export const { refreshFile, displayInstanceSetGridLayout, displayInstanceSetResponsiveLayout, + displayInstanceUpdateGridLayout, displayInstanceUpdateResponsiveLayout, createDisplayInstanceFromFile } = fileCacheSlice.actions; diff --git a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx index 69d5405..94eb4fd 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx @@ -3,7 +3,8 @@ import React, { useContext, ReactNode, useMemo, - useEffect + useEffect, + useRef } from "react"; import { Layout, @@ -41,6 +42,7 @@ import { useStyle } from "../../hooks/useStyle"; import { calculateDefaultLayout, toNumber } from "./displayLayoutUtilities"; import { displayInstanceSetGridLayout, + displayInstanceUpdateGridLayout, makeSelectWidgetPosition } from "../../../redux/slices/fileCacheSlice"; import { useDispatch, useSelector } from "react-redux"; @@ -83,6 +85,9 @@ export const DisplayGridLayoutComponent = ( // can set macros by using the updateMacro function on the // context. const dispatch = useDispatch(); + const isInteractingRef = useRef(false); + const shouldCommitRef = useRef(false); + const gridCellDragEnabled = props?.gridCellDragEnabled == null ? true : props?.gridCellDragEnabled; const gridCellResizeEnabled = @@ -239,6 +244,18 @@ export const DisplayGridLayoutComponent = ( }} resizeConfig={{ enabled: gridCellResizeEnabled, handles: ["se"] }} compactor={verticalCompactor} + onLayoutChange={layout => { + if (!isInteractingRef.current && shouldCommitRef.current) { + dispatch( + displayInstanceUpdateGridLayout({ + embeddedDisplayUuid: props.embeddedDisplayUuid, + gridDisplayId: props.id, + gridLayout: layout + }) + ); + shouldCommitRef.current = false; + } + }} onDragStart={( layout, oldItem, @@ -249,10 +266,20 @@ export const DisplayGridLayoutComponent = ( ) => { if (element?.style && gridCellDragEnabled) element.style.cursor = "grabbing"; + isInteractingRef.current = true; }} onDragStop={(layout, oldItem, newItem, placeholder, e, element) => { if (element?.style && gridCellDragEnabled) element.style.cursor = "grab"; + isInteractingRef.current = false; + shouldCommitRef.current = true; + }} + onResizeStart={() => { + isInteractingRef.current = true; + }} + onResizeStop={() => { + isInteractingRef.current = false; + shouldCommitRef.current = true; }} style={{ ...style.colors, From 129e25e1bc05f42e4d975cddda53642f02ba8e58 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 17 Jun 2026 12:40:51 +0100 Subject: [PATCH 14/16] Simplify use of the ReactGridLayout callbacks --- .../displayGridLayout.tsx | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx index 94eb4fd..d56c78c 100644 --- a/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx +++ b/src/ui/widgets/DisplayReactGridLayout/displayGridLayout.tsx @@ -3,8 +3,7 @@ import React, { useContext, ReactNode, useMemo, - useEffect, - useRef + useEffect } from "react"; import { Layout, @@ -85,9 +84,6 @@ export const DisplayGridLayoutComponent = ( // can set macros by using the updateMacro function on the // context. const dispatch = useDispatch(); - const isInteractingRef = useRef(false); - const shouldCommitRef = useRef(false); - const gridCellDragEnabled = props?.gridCellDragEnabled == null ? true : props?.gridCellDragEnabled; const gridCellResizeEnabled = @@ -244,18 +240,6 @@ export const DisplayGridLayoutComponent = ( }} resizeConfig={{ enabled: gridCellResizeEnabled, handles: ["se"] }} compactor={verticalCompactor} - onLayoutChange={layout => { - if (!isInteractingRef.current && shouldCommitRef.current) { - dispatch( - displayInstanceUpdateGridLayout({ - embeddedDisplayUuid: props.embeddedDisplayUuid, - gridDisplayId: props.id, - gridLayout: layout - }) - ); - shouldCommitRef.current = false; - } - }} onDragStart={( layout, oldItem, @@ -266,20 +250,26 @@ export const DisplayGridLayoutComponent = ( ) => { if (element?.style && gridCellDragEnabled) element.style.cursor = "grabbing"; - isInteractingRef.current = true; }} onDragStop={(layout, oldItem, newItem, placeholder, e, element) => { if (element?.style && gridCellDragEnabled) element.style.cursor = "grab"; - isInteractingRef.current = false; - shouldCommitRef.current = true; - }} - onResizeStart={() => { - isInteractingRef.current = true; + dispatch( + displayInstanceUpdateGridLayout({ + embeddedDisplayUuid: props.embeddedDisplayUuid, + gridDisplayId: props.id, + gridLayout: layout + }) + ); }} - onResizeStop={() => { - isInteractingRef.current = false; - shouldCommitRef.current = true; + onResizeStop={layout => { + dispatch( + displayInstanceUpdateGridLayout({ + embeddedDisplayUuid: props.embeddedDisplayUuid, + gridDisplayId: props.id, + gridLayout: layout + }) + ); }} style={{ ...style.colors, From 8aa04f6edcbf32e3448063a025789ad5d40c65e2 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Wed, 17 Jun 2026 16:17:01 +0100 Subject: [PATCH 15/16] Adding x-charts and material to the peer dependencies --- package-lock.json | 3 +++ package.json | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 0ea6de5..d642a2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,10 @@ "xml-js": "^1.6.11" }, "peerDependencies": { + "@mui/material": "^7.3.2", + "@mui/x-charts": "^9.3.0", "@types/react": "^18.3.1", + "d3": "^7.9.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-gauge-component": "^2.0.26", diff --git a/package.json b/package.json index 4568285..4d4c9b7 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,10 @@ "react-dom": "^18.3.1", "react-gauge-component": "^2.0.26", "react-redux": "^7.2.9", - "react-router": "^7.13.0" + "react-router": "^7.13.0", + "d3": "^7.9.0", + "@mui/material": "^7.3.2", + "@mui/x-charts": "^9.3.0" }, "module": "./dist/index.js", "types": "./dist/index.d.ts", From 6305bc81770067ff85710d59251a81a2f5791a98 Mon Sep 17 00:00:00 2001 From: Greg Harris Date: Thu, 18 Jun 2026 12:36:35 +0100 Subject: [PATCH 16/16] Fix for CI failing test --- src/ui/widgets/DropDown/dropDown.test.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/ui/widgets/DropDown/dropDown.test.tsx b/src/ui/widgets/DropDown/dropDown.test.tsx index f8a1e41..dd7033f 100644 --- a/src/ui/widgets/DropDown/dropDown.test.tsx +++ b/src/ui/widgets/DropDown/dropDown.test.tsx @@ -6,17 +6,6 @@ import { fireEvent, render, waitFor } from "@testing-library/react"; import { vi } from "vitest"; import { createMockStyle } from "../../../test-utils/styleTestUtils"; -vi.mock("../../hooks/useStyle", () => ({ - useStyle: vi.fn(() => ({ - color: "", - backgroundColor: "", - fontFamily: undefined, - fontSize: undefined, - fontStyle: undefined, - fontWeight: undefined - })) -})); - vi.mock("../../hooks/useStyle", () => ({ useStyle: vi.fn(() => createMockStyle()) }));