From 6044adf9ad8103c3fc2d1100dbd1676139cb2443 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Wed, 20 May 2026 23:49:38 +0200 Subject: [PATCH 01/49] core: use @reduxjs/toolkit where possible, replace createStructuredSelector Signed-off-by: Paul Golmann --- packages/core/src/js/lib/base/controller.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/core/src/js/lib/base/controller.ts b/packages/core/src/js/lib/base/controller.ts index ac57035c..c0055d7c 100644 --- a/packages/core/src/js/lib/base/controller.ts +++ b/packages/core/src/js/lib/base/controller.ts @@ -1,10 +1,4 @@ -import type { - AnyAction, - Observable, - Reducer, - Store, - Unsubscribe, -} from "@reduxjs/toolkit"; +import type {Observable, Reducer, Store, Unsubscribe} from "@reduxjs/toolkit"; import {compose} from "@reduxjs/toolkit"; import {EventEmitter} from "eventemitter3"; @@ -20,14 +14,14 @@ import type { export class BaseController extends EventEmitter - implements Store + implements Store { // TODO: Should we also implement: observe, getAndObserve and getAndSubscribe? readonly #name: string; #store: EnhancedStore | null = null; #selector: Selector | null = null; - #reducers: Array<(state: TState, action: AnyAction) => TState>; + #reducers: Array>; constructor(controllerName: string) { super(); @@ -36,7 +30,7 @@ export class BaseController this.#reducers = []; } - replaceReducer(_nextReducer: Reducer): void {} + replaceReducer(_nextReducer: Reducer): void {} [Symbol.observable](): Observable { throw new Error("Method not implemented."); @@ -222,7 +216,7 @@ export class BaseController // empty } - registerReducer(reducer: (state: TState, action: AnyAction) => TState) { + registerReducer(reducer: Reducer) { this.#reducers.push(reducer); } From 03645d7ae1277717be18f1f8d3c6143fcdce6fec Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Wed, 20 May 2026 23:50:19 +0200 Subject: [PATCH 02/49] vector-editor: use @reduxjs/toolkit where possible, replace createStructuredSelector Signed-off-by: Paul Golmann --- .../src/js/components/vector-editor/DeleteButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx b/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx index 189ae56a..616e9421 100644 --- a/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx +++ b/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx @@ -2,7 +2,7 @@ import type React from "react"; import {useMemo} from "react"; import {useDispatch, useSelector} from "react-redux"; -import {type UnknownAction, createSelector} from "@reduxjs/toolkit"; +import {createSelector} from "@reduxjs/toolkit"; import {batchActions} from "redux-batched-actions"; import {deselectAll} from "@mapsight/core/lib/feature-selections/actions"; @@ -53,7 +53,7 @@ function DeleteButton({ featureIds, ), deselectAll(editor.controllers.featureSelections!, "select"), - ]) as unknown as UnknownAction, + ]), ); }; From af20b0fa94883503540c335bac055d93473a1f3d Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 21 May 2026 00:06:07 +0200 Subject: [PATCH 03/49] ui: improve types, prefer @reduxjs/toolkit exports, remove use of createStructuredSelector Signed-off-by: Paul Golmann --- packages/ui/src/js/components/app.tsx | 4 +-- .../src/js/components/feature-list/index.jsx | 8 +++--- .../with-sticky-header.tsx | 26 ++++--------------- .../layer-switcher/LayerSwitcherContainer.tsx | 4 +-- .../src/js/components/layer-switcher/index.ts | 2 +- .../src/js/components/main-panel/context.tsx | 7 +++-- .../main-panel/list-toggle-button.jsx | 2 +- .../components/map-synced-interlay/index.ts | 4 +-- .../js/components/switcher/SwitcherEntry.tsx | 6 ++--- .../components/tag-switcher/TagSwitcher.tsx | 4 +-- .../tag-switcher/createTagSwitcherEntry.ts | 6 ++--- .../tag-switcher/createTagSwitcherHeader.ts | 4 +-- .../src/js/components/tag-switcher/index.ts | 4 +-- .../view-toggle-button/desktop-button.jsx | 2 +- .../js/components/view-toggle-button/index.ts | 8 +++--- .../view-toggle-button/mobile-button.tsx | 2 +- .../view-toggle-button/viewport-button.tsx | 2 +- packages/ui/src/js/index.ts | 3 +-- .../ui/src/js/plugins/browser/no-scroll.ts | 2 +- .../src/js/plugins/common/measure-distance.ts | 6 ++--- packages/ui/src/js/store/actions.ts | 4 +-- packages/ui/src/js/store/selectors.ts | 6 ++--- packages/ui/src/js/types.ts | 10 +++---- 23 files changed, 56 insertions(+), 70 deletions(-) diff --git a/packages/ui/src/js/components/app.tsx b/packages/ui/src/js/components/app.tsx index fa8ccb75..70611378 100644 --- a/packages/ui/src/js/components/app.tsx +++ b/packages/ui/src/js/components/app.tsx @@ -18,10 +18,10 @@ import { tagSwitcherShowSelector, timeFilterVisible, viewSelector, -} from "../store/selectors"; +} from "../store/selectors.ts"; import FeatureList from "./feature-list"; import VisibilityWrapper from "./helping/visibility-wrapper"; -import LayerSwitcher from "./layer-switcher/index"; +import LayerSwitcher from "./layer-switcher/index.ts"; import AdditionalContainer from "./layout/additional-container"; import AdditionalContent from "./layout/additional-container/content"; import Marginal from "./layout/additional-container/marginal"; diff --git a/packages/ui/src/js/components/feature-list/index.jsx b/packages/ui/src/js/components/feature-list/index.jsx index 9bd6f9ab..0580e24d 100644 --- a/packages/ui/src/js/components/feature-list/index.jsx +++ b/packages/ui/src/js/components/feature-list/index.jsx @@ -8,7 +8,7 @@ import { layerSwitcherConfigExternalSelector, listUiOptionsSelector, viewSelector, -} from "../../store/selectors"; +} from "../../store/selectors.ts"; import FeatureCycling from "../feature-list-cycling"; import FeatureSorter from "../feature-list-sorting"; @@ -17,8 +17,8 @@ import { APP_EVENT_SCROLL_TO_FEATURE_LIST, useAppChannelEventListener, } from "../helping/app-channel"; -import LayerSwitcher from "../layer-switcher/index"; -import TagSwitcher from "../tag-switcher/index"; +import LayerSwitcher from "../layer-switcher/index.ts"; +import TagSwitcher from "../tag-switcher/index.ts"; import {FeatureListContextProvider} from "./context"; @@ -31,7 +31,7 @@ import useFeatureListState from "./hooks/useFeatureListState"; import {useMakeHeaderSticky} from "./hooks/useMakeHeaderSticky"; import useRestoreDocumentScroll from "./hooks/useRestoreDocumentScroll"; import useSelectFeature from "./hooks/useSelectFeature"; -import Pagination from "./pagination"; +import Pagination from "./pagination.tsx"; export const DEFAULT_LIST_RENDER_AS = "ul"; diff --git a/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx b/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx index 3e6a45e2..3c37db68 100644 --- a/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx +++ b/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx @@ -1,34 +1,18 @@ -import type {ReactNode} from "react"; import {useSelector} from "react-redux"; import useStickyHeader from "../../hooks/useStickyHeader"; -import {featureSelectionInfoUiOptionsSelector} from "../../store/selectors"; -import type {MapsightUiFeature} from "../../types"; +import {featureSelectionInfoUiOptionsSelector} from "../../store/selectors.ts"; import Container from "./container"; const stopEventPropagation = (e) => e.stopPropagation(); -type WithStickyHeaderProps = { - header: ReactNode; - feature: MapsightUiFeature; - content: ReactNode; - close: ReactNode; - renderWrapper: (props: any) => ReactNode; -}; - -function WithStickyHeader({ - header, - content, - feature, - close, - renderWrapper, -}: WithStickyHeaderProps) { - const {stuckHeaderHeight} = useSelector( +function WithStickyHeader({header, content, feature, close, renderWrapper}) { + const {stuckHeaderSize} = useSelector( featureSelectionInfoUiOptionsSelector, ); const {isHeaderStuck, stickyHeaderRef, stickyScrollAreaRef, onScroll} = - useStickyHeader({ - stuckHeaderHeight, + useStickyHeader({ + stuckHeaderSize: stuckHeaderHeight, resetDeps: [feature.id], }); diff --git a/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx b/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx index a82d037f..c66353de 100644 --- a/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx +++ b/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx @@ -13,8 +13,8 @@ import type {MapState} from "@mapsight/core/lib/map/types"; import {translate} from "../../helpers/i18n"; import GroupedLayerSwitcher from "./GroupedLayerSwitcher"; -import LayerSwitcher from "./LayerSwitcher"; -import LayerSwitcherEntry from "./LayerSwitcherEntry"; +import LayerSwitcher from "./LayerSwitcher.ts"; +import LayerSwitcherEntry from "./LayerSwitcherEntry.ts"; // TODO das berechnen der LayerListen (abhängig von grouped und layerIdSelector) in einen Selector packen, // damit diese Berechnung nur bei Änderungen am store berechnet neu wird diff --git a/packages/ui/src/js/components/layer-switcher/index.ts b/packages/ui/src/js/components/layer-switcher/index.ts index d6eff631..4f254ccb 100644 --- a/packages/ui/src/js/components/layer-switcher/index.ts +++ b/packages/ui/src/js/components/layer-switcher/index.ts @@ -2,7 +2,7 @@ import {connect} from "react-redux"; import type {Selector} from "@mapsight/core/types"; -import {FEATURE_LIST} from "../../config/constants/controllers"; +import {FEATURE_LIST} from "../../config/constants/controllers.ts"; import type {RootStateSlice} from "../../store/selectors"; import {layerSwitcherConfigInternalSelector} from "../../store/selectors"; import type {LayerSwitcherConfigState} from "../../types"; diff --git a/packages/ui/src/js/components/main-panel/context.tsx b/packages/ui/src/js/components/main-panel/context.tsx index 8ff61d8b..9f74996f 100644 --- a/packages/ui/src/js/components/main-panel/context.tsx +++ b/packages/ui/src/js/components/main-panel/context.tsx @@ -2,8 +2,11 @@ import type {PropsWithChildren} from "react"; import {createContext, useContext, useMemo} from "react"; import {useSelector} from "react-redux"; -import {createMainPanelContentTypeSelector} from "../../store/selectors"; -import type {MainPanelContextOptions, MainPanelContextValue} from "../../types"; +import {createMainPanelContentTypeSelector} from "../../store/selectors.ts"; +import type { + MainPanelContextOptions, + MainPanelContextValue, +} from "../../types.ts"; const MainPanelContext = createContext({ showSelectionInfo: false, diff --git a/packages/ui/src/js/components/main-panel/list-toggle-button.jsx b/packages/ui/src/js/components/main-panel/list-toggle-button.jsx index e7793604..7f1d0daa 100644 --- a/packages/ui/src/js/components/main-panel/list-toggle-button.jsx +++ b/packages/ui/src/js/components/main-panel/list-toggle-button.jsx @@ -5,7 +5,7 @@ import {toggleUserPreferenceListVisible} from "../../store/actions"; import {userPreferenceListVisibleSelector} from "../../store/selectors"; -import {useMainPanelContext} from "./context"; +import {useMainPanelContext} from "./context.tsx"; function MainPanelListToggleButton() { const {collapsible, contentType} = useMainPanelContext(); diff --git a/packages/ui/src/js/components/map-synced-interlay/index.ts b/packages/ui/src/js/components/map-synced-interlay/index.ts index bd6c9d09..39ced392 100644 --- a/packages/ui/src/js/components/map-synced-interlay/index.ts +++ b/packages/ui/src/js/components/map-synced-interlay/index.ts @@ -4,8 +4,8 @@ import {mapSizeSelector} from "@mapsight/core/lib/map/selectors"; import type {MapState} from "@mapsight/core/lib/map/types"; import {MAP} from "../../config/constants/controllers"; -import type {RootStateSlice} from "../../store/selectors"; -import {viewSelector} from "../../store/selectors"; +import type {RootStateSlice} from "../../store/selectors.ts"; +import {viewSelector} from "../../store/selectors.ts"; import MapSyncedInterlay from "./map-synced-interlay"; export default connect((state: RootStateSlice) => ({ diff --git a/packages/ui/src/js/components/switcher/SwitcherEntry.tsx b/packages/ui/src/js/components/switcher/SwitcherEntry.tsx index f3b721e6..7f8ee37f 100644 --- a/packages/ui/src/js/components/switcher/SwitcherEntry.tsx +++ b/packages/ui/src/js/components/switcher/SwitcherEntry.tsx @@ -29,8 +29,8 @@ const mapStatusLabel = (status: string) => translate("ui.switcher.entry.label" + status); const determineDisplayStatus = ( - status?: FeatureSourceStatus, - active: boolean = false, + status: FeatureSourceStatus, + active: boolean, ): SwitcherEntryStatus => { if (!status || status === STATUS_OK) { return active ? STATUS_ACTIVE : STATUS_INACTIVE; @@ -51,7 +51,7 @@ export type SwitcherEntryProps = { active?: boolean; activeCheckbox?: boolean; activeText?: boolean; - status?: FeatureSourceStatus; + status: FeatureSourceStatus; locked?: boolean; }; diff --git a/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx b/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx index 502aecec..217b172e 100644 --- a/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx +++ b/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx @@ -2,8 +2,8 @@ import {memo, useMemo} from "react"; import {getDocumentLanguage} from "../../helpers/i18n"; import GroupedSwitcher from "../switcher/GroupedSwitcher"; -import createTagSwitcherEntry from "./createTagSwitcherEntry"; -import createTagSwitcherHeader from "./createTagSwitcherHeader"; +import createTagSwitcherEntry from "./createTagSwitcherEntry.ts"; +import createTagSwitcherHeader from "./createTagSwitcherHeader.ts"; function TagSwitcher({ groupedTagData, diff --git a/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts b/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts index 428e5827..ecd3fafa 100644 --- a/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts +++ b/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts @@ -1,8 +1,8 @@ import {connect} from "react-redux"; -import {setTagVisible} from "../../store/actions"; -import type {RootStateSlice} from "../../store/selectors"; -import {createTagVisibleSelector} from "../../store/selectors"; +import {setTagVisible} from "../../store/actions.ts"; +import type {RootStateSlice} from "../../store/selectors.ts"; +import {createTagVisibleSelector} from "../../store/selectors.ts"; import SwitcherEntry from "../switcher/SwitcherEntry"; export default function createTagSwitcherEntry( diff --git a/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts b/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts index 9c18ad70..0ca8e6f0 100644 --- a/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts +++ b/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts @@ -1,10 +1,10 @@ import {connect} from "react-redux"; -import {setTagGroupVisible} from "../../store/actions"; +import {setTagGroupVisible} from "../../store/actions.ts"; import { type RootStateSlice, createTagGroupVisibleSelector, -} from "../../store/selectors"; +} from "../../store/selectors.ts"; import SwitcherHeader from "../switcher/SwitcherHeader"; type Props = { diff --git a/packages/ui/src/js/components/tag-switcher/index.ts b/packages/ui/src/js/components/tag-switcher/index.ts index 1076b845..727edf12 100644 --- a/packages/ui/src/js/components/tag-switcher/index.ts +++ b/packages/ui/src/js/components/tag-switcher/index.ts @@ -1,12 +1,12 @@ import {connect} from "react-redux"; -import type {RootStateSlice} from "../../store/selectors"; +import type {RootStateSlice} from "../../store/selectors.ts"; import { tagSwitcherFeatureSourceIdSelector, tagSwitcherSortTags, tagSwitcherTagsSelector, tagSwitcherToggleableGroups, -} from "../../store/selectors"; +} from "../../store/selectors.ts"; import TagSwitcher from "./TagSwitcher"; export default connect((state: RootStateSlice) => ({ diff --git a/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx b/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx index b8522852..07286e90 100644 --- a/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx +++ b/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx @@ -1,4 +1,4 @@ -import ViewToggleButton from "./index"; +import ViewToggleButton from "./index.ts"; function DesktopViewToggleButton() { return ( diff --git a/packages/ui/src/js/components/view-toggle-button/index.ts b/packages/ui/src/js/components/view-toggle-button/index.ts index de024603..fd2b019c 100644 --- a/packages/ui/src/js/components/view-toggle-button/index.ts +++ b/packages/ui/src/js/components/view-toggle-button/index.ts @@ -2,17 +2,17 @@ import {connect} from "react-redux"; import {deselectAll} from "@mapsight/core/lib/feature-selections/actions"; -import type {View} from "../../config/constants/app"; +import type {View} from "../../config/constants/app.ts"; import {FEATURE_SELECTIONS} from "../../config/constants/controllers"; import {FEATURE_SELECTION_SELECT} from "../../config/feature/selections"; -import {setView} from "../../store/actions"; -import type {RootStateSlice} from "../../store/selectors"; +import {setView} from "../../store/actions.ts"; +import type {RootStateSlice} from "../../store/selectors.ts"; import { isMapOutOfViewportSelector, isViewMobile, viewSelector, viewToggleOptionsSelector, -} from "../../store/selectors"; +} from "../../store/selectors.ts"; import ViewToggleButton from "./view-toggle-button"; export default connect( diff --git a/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx b/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx index dd9bfe4f..8d9917b4 100644 --- a/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx +++ b/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx @@ -1,4 +1,4 @@ -import ViewToggleButton from "./index"; +import ViewToggleButton from "./index.ts"; function MobileViewToggleButton() { return ( diff --git a/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx b/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx index 8628b38e..5ce34be1 100644 --- a/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx +++ b/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx @@ -1,4 +1,4 @@ -import ViewToggleButton from "./index"; +import ViewToggleButton from "./index.ts"; function ViewportViewToggleButton() { return ( diff --git a/packages/ui/src/js/index.ts b/packages/ui/src/js/index.ts index 431912d9..2ff2da9a 100644 --- a/packages/ui/src/js/index.ts +++ b/packages/ui/src/js/index.ts @@ -1,6 +1,6 @@ import {applyMiddleware, compose} from "@reduxjs/toolkit"; import merge from "lodash/merge"; -import {thunk} from "redux-thunk"; +import thunk from "redux-thunk"; import {createMapsightStore} from "@mapsight/core"; import {layerIdsExternalSwitcherSelector} from "@mapsight/core/lib/map/selectors"; @@ -189,7 +189,6 @@ export function create( // store enhancer const uiStoreEnhancer = applyMiddleware(thunk); - // @ts-expect-error TODO context.storeEnhancer = context.createOptions.storeEnhancer ? compose(uiStoreEnhancer, context.createOptions.storeEnhancer) : uiStoreEnhancer; diff --git a/packages/ui/src/js/plugins/browser/no-scroll.ts b/packages/ui/src/js/plugins/browser/no-scroll.ts index 82e3c84d..7fd213e5 100644 --- a/packages/ui/src/js/plugins/browser/no-scroll.ts +++ b/packages/ui/src/js/plugins/browser/no-scroll.ts @@ -5,7 +5,7 @@ import {getAndObserveState} from "@mapsight/lib-redux/observe-state"; import {VIEW_FULLSCREEN, VIEW_MAP_ONLY} from "../../config/constants/app"; import type {RootStateSlice} from "../../store/selectors"; import {viewSelector} from "../../store/selectors"; -import type {PluginInstance} from "../../types"; +import type {PluginInstance} from "../../types.ts"; function onTouchMoveNoScroll(e: TouchEvent) { e.preventDefault(); diff --git a/packages/ui/src/js/plugins/common/measure-distance.ts b/packages/ui/src/js/plugins/common/measure-distance.ts index ae01331d..1b2985f7 100644 --- a/packages/ui/src/js/plugins/common/measure-distance.ts +++ b/packages/ui/src/js/plugins/common/measure-distance.ts @@ -1,3 +1,4 @@ +import type {Store} from "@reduxjs/toolkit"; import {createSelector} from "@reduxjs/toolkit"; import {mergeAll} from "@mapsight/core/lib/base/actions"; @@ -13,7 +14,6 @@ import { import type {Definition} from "@mapsight/core/ol-proxy"; import {di} from "@mapsight/core/ol-proxy"; import DrawInteraction from "@mapsight/core/ol-proxy/definitions/interaction/DrawInteraction"; -import type {EnhancedStore} from "@mapsight/core/types"; import {observeState} from "@mapsight/lib-redux/observe-state"; @@ -23,7 +23,7 @@ import { MAP, } from "../../config/constants/controllers"; import {getDictionary} from "../../helpers/i18n"; -import type {PluginInstance} from "../../types"; +import type {PluginInstance} from "../../types.ts"; export const createActivateAction = (mapController: string, name: string) => activateInteraction(mapController, `${name}_drawInteraction`); @@ -49,7 +49,7 @@ function setupDrawInteraction({ drawStyle, displayStyle, }: { - store: EnhancedStore; + store: Store; name: string; featureSourcesControllerName: string; featureSelectionsControllerName: string; diff --git a/packages/ui/src/js/store/actions.ts b/packages/ui/src/js/store/actions.ts index 99425236..b59581e1 100644 --- a/packages/ui/src/js/store/actions.ts +++ b/packages/ui/src/js/store/actions.ts @@ -26,7 +26,7 @@ import type { FullUiState, MapsightUiFeatureId, UiState, -} from "../types"; +} from "../types.ts"; import type {RootStateSlice} from "./selectors"; import {featureDetailsUrlSelector, regionsSelector} from "./selectors"; @@ -261,7 +261,7 @@ export function setMiniLegendLayer(layerId: string | null) { }; } -export const SET_VIEW_BREAKPOINTS = "SET_VIEW_BREAKPOI"; +export const SET_VIEW_BREAKPOINTS = "SET_VIEW_BREAKPOINTS"; export function setViewBreakpoints(value: FullUiState["viewBreakpoints"]) { return { diff --git a/packages/ui/src/js/store/selectors.ts b/packages/ui/src/js/store/selectors.ts index a3fdea57..09f48066 100644 --- a/packages/ui/src/js/store/selectors.ts +++ b/packages/ui/src/js/store/selectors.ts @@ -28,7 +28,7 @@ import type {MapState} from "@mapsight/core/lib/map/types"; import type {UserGeolocationState} from "@mapsight/core/lib/user-geolocation/selectors"; import type {State} from "@mapsight/core/types"; -import type {MapsightUiPlacesData} from "../components/feature-list-sorting/feature-list-sorting"; +import type {MapsightUiPlacesData} from "../components/feature-list-sorting/feature-list-sorting.tsx"; import type {View} from "../config/constants/app"; import { DETAILS_CONTENT_STATE_KEY, @@ -58,14 +58,14 @@ import type { MapsightUiFeature, RegionState, UiState, -} from "../types"; +} from "../types.ts"; import { FETCH_JSON_STATUS_ERROR, FETCH_JSON_STATUS_LOADING, FETCH_JSON_STATUS_SUCCESS, FETCH_TEXT_STATUS_ERROR, FETCH_TEXT_STATUS_SUCCESS, -} from "./actions"; +} from "./actions.ts"; type SEARCH_STATUS = | typeof SEARCH_STATUS_INACTIVE diff --git a/packages/ui/src/js/types.ts b/packages/ui/src/js/types.ts index 71397ce0..5f775296 100644 --- a/packages/ui/src/js/types.ts +++ b/packages/ui/src/js/types.ts @@ -15,12 +15,12 @@ import type {EnhancedStore, Feature, State} from "@mapsight/core/types"; import type {MapsightStyleFunction} from "@mapsight/lib-ol/style/styleFunction"; -import type {MapsightUiPlacesData} from "./components/feature-list-sorting/feature-list-sorting"; -import type {View} from "./config/constants/app"; -import type {TAG_FILTER, TIME_FILTER} from "./config/constants/controllers"; +import type {MapsightUiPlacesData} from "./components/feature-list-sorting/feature-list-sorting.tsx"; +import type {View} from "./config/constants/app.ts"; +import type {TAG_FILTER, TIME_FILTER} from "./config/constants/controllers.ts"; import type {MapsightUiComponents} from "./helpers/components"; -import type {FETCH_JSON_STATUS, FETCH_TEXT_STATUS} from "./store/actions"; -import type {RootStateSlice} from "./store/selectors"; +import type {FETCH_JSON_STATUS, FETCH_TEXT_STATUS} from "./store/actions.ts"; +import type {RootStateSlice} from "./store/selectors.ts"; // helper type https://stackoverflow.com/a/61132308 export type DeepPartial = T extends object From 677934823991118aa9795e646e35ab1529a99ba0 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 21 May 2026 00:06:22 +0200 Subject: [PATCH 04/49] update deps Signed-off-by: Paul Golmann --- pnpm-lock.yaml | 148 ++++++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 70 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27499f46..5d2ba18c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,8 @@ settings: catalogs: default: '@reduxjs/toolkit': - specifier: ^2.11.2 - version: 2.12.0 + specifier: ^1.9.7 + version: 1.9.7 '@types/jsdom': specifier: ^28.0.3 version: 28.0.3 @@ -52,17 +52,17 @@ catalogs: specifier: ^19.2.6 version: 19.2.6 react-redux: - specifier: ^9.2.0 - version: 9.3.0 + specifier: ^8.1.3 + version: 8.1.3 redux-batched-actions: specifier: ^0.5.0 version: 0.5.0 redux-thunk: - specifier: ^3.1.0 - version: 3.1.0 + specifier: ^2.4.2 + version: 2.4.2 reselect: - specifier: ^5.1.1 - version: 5.2.0 + specifier: ^4.1.8 + version: 4.1.8 tailwindcss: specifier: ^4.3.0 version: 4.3.0 @@ -193,7 +193,7 @@ importers: version: 19.2.6(react@19.2.6) reselect: specifier: 'catalog:' - version: 5.2.0 + version: 4.1.8 devDependencies: '@mapsight/vector-style-compiler': specifier: workspace:^ @@ -263,7 +263,7 @@ importers: version: 19.2.6(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + version: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) react-router: specifier: ^7.15.0 version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -272,7 +272,7 @@ importers: version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) reselect: specifier: 'catalog:' - version: 5.2.0 + version: 4.1.8 tailwindcss: specifier: 'catalog:' version: 4.3.0 @@ -318,7 +318,7 @@ importers: version: link:../../packages/traffic-style/dist '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -339,13 +339,13 @@ importers: version: 3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + version: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) react-tooltip: specifier: ^4.5.1 version: 4.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) redux-batched-actions: specifier: 'catalog:' - version: 0.5.0(redux@5.0.1) + version: 0.5.0(redux@4.2.1) redux-undo: specifier: ^1.1.0 version: 1.1.0 @@ -403,7 +403,7 @@ importers: version: link:../lib-redux '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) eventemitter3: specifier: ^5.0.4 version: 5.0.4 @@ -415,11 +415,11 @@ importers: version: 10.2.5 redux-batched-actions: specifier: 'catalog:' - version: 0.5.0(redux@5.0.1) + version: 0.5.0(redux@4.2.1) devDependencies: '@redux-devtools/extension': specifier: ^3.3.0 - version: 3.3.0(redux@5.0.1) + version: 3.3.0(redux@4.2.1) '@types/geojson': specifier: ^7946.0.16 version: 7946.0.16 @@ -492,7 +492,7 @@ importers: version: link:../lib-js '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) '@types/lodash': specifier: 'catalog:' version: 4.17.24 @@ -570,7 +570,7 @@ importers: version: link:../lib-redux '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) '@types/react-redux': specifier: 'catalog:' version: 7.1.34 @@ -612,13 +612,13 @@ importers: version: 8.3.0(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + version: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) redux-batched-actions: specifier: 'catalog:' - version: 0.5.0(redux@5.0.1) + version: 0.5.0(redux@4.2.1) redux-thunk: specifier: 'catalog:' - version: 3.1.0(redux@5.0.1) + version: 2.4.2(redux@4.2.1) devDependencies: '@types/lodash': specifier: 'catalog:' @@ -1358,11 +1358,11 @@ packages: peerDependencies: redux: ^3.1.0 || ^4.0.0 || ^5.0.0 - '@reduxjs/toolkit@2.12.0': - resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==} + '@reduxjs/toolkit@1.9.7': + resolution: {integrity: sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==} peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 || ^19 - react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + react: ^16.9.0 || ^17.0.0 || ^18 + react-redux: ^7.2.1 || ^8.0.2 peerDependenciesMeta: react: optional: true @@ -1473,9 +1473,6 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@standard-schema/utils@0.3.0': - resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} @@ -1707,8 +1704,8 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - '@types/use-sync-external-store@0.0.6': - resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/use-sync-external-store@0.0.3': + resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} '@typescript-eslint/eslint-plugin@8.59.4': resolution: {integrity: sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==} @@ -2933,8 +2930,8 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - immer@11.1.8: - resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==} + immer@9.0.21: + resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} immutable@4.3.8: resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==} @@ -3732,6 +3729,9 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} @@ -3746,15 +3746,24 @@ packages: peerDependencies: react: ^16 || ^17 || ^18 || ^19 - react-redux@9.3.0: - resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} + react-redux@8.1.3: + resolution: {integrity: sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==} peerDependencies: - '@types/react': ^18.2.25 || ^19 - react: ^18.0 || ^19 - redux: ^5.0.0 + '@types/react': ^16.8 || ^17.0 || ^18.0 + '@types/react-dom': ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + react-native: '>=0.59' + redux: ^4 || ^5.0.0-beta.0 peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true + react-dom: + optional: true + react-native: + optional: true redux: optional: true @@ -3819,10 +3828,10 @@ packages: peerDependencies: redux: '>=1.0.0' - redux-thunk@3.1.0: - resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + redux-thunk@2.4.2: + resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} peerDependencies: - redux: ^5.0.0 + redux: ^4 redux-undo@1.1.0: resolution: {integrity: sha512-zzLFh2qeF0MTIlzDhDLm9NtkfBqCllQJ3OCuIl5RKlG/ayHw6GUdIFdMhzMS9NnrnWdBX5u//ExMOHpfudGGOg==} @@ -3830,9 +3839,6 @@ packages: redux@4.2.1: resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} - redux@5.0.1: - resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} - reference-spec-reader@0.2.0: resolution: {integrity: sha512-q0mfCi5yZSSHXpCyxjgQeaORq3tvDsxDyzaadA/5+AbAUwRyRuuTh0aRQuE/vAOt/qzzxidJ5iDeu1cLHaNBlQ==} @@ -3864,8 +3870,8 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - reselect@5.2.0: - resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} + reselect@4.1.8: + resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -5249,23 +5255,21 @@ snapshots: dependencies: react: 19.2.6 - '@redux-devtools/extension@3.3.0(redux@5.0.1)': + '@redux-devtools/extension@3.3.0(redux@4.2.1)': dependencies: '@babel/runtime': 7.29.2 immutable: 4.3.8 - redux: 5.0.1 + redux: 4.2.1 - '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': + '@reduxjs/toolkit@1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6)': dependencies: - '@standard-schema/spec': 1.1.0 - '@standard-schema/utils': 0.3.0 - immer: 11.1.8 - redux: 5.0.1 - redux-thunk: 3.1.0(redux@5.0.1) - reselect: 5.2.0 + immer: 9.0.21 + redux: 4.2.1 + redux-thunk: 2.4.2(redux@4.2.1) + reselect: 4.1.8 optionalDependencies: react: 19.2.6 - react-redux: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + react-redux: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) '@rolldown/binding-android-arm64@1.0.1': optional: true @@ -5322,8 +5326,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@standard-schema/utils@0.3.0': {} - '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -5527,7 +5529,7 @@ snapshots: '@types/tough-cookie@4.0.5': {} - '@types/use-sync-external-store@0.0.6': {} + '@types/use-sync-external-store@0.0.3': {} '@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: @@ -6940,7 +6942,7 @@ snapshots: ignore@7.0.5: {} - immer@11.1.8: {} + immer@9.0.21: {} immutable@4.3.8: {} @@ -7707,6 +7709,8 @@ snapshots: react-is@16.13.1: {} + react-is@18.3.1: {} + react-lifecycles-compat@3.0.4: {} react-modal@3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6): @@ -7723,14 +7727,20 @@ snapshots: prop-types: 15.8.1 react: 19.2.6 - react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1): + react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1): dependencies: - '@types/use-sync-external-store': 0.0.6 + '@babel/runtime': 7.29.2 + '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.14) + '@types/use-sync-external-store': 0.0.3 + hoist-non-react-statics: 3.3.2 react: 19.2.6 + react-is: 18.3.1 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: '@types/react': 19.2.14 - redux: 5.0.1 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + react-dom: 19.2.6(react@19.2.6) + redux: 4.2.1 react-router-dom@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: @@ -7790,13 +7800,13 @@ snapshots: readdirp@5.0.0: {} - redux-batched-actions@0.5.0(redux@5.0.1): + redux-batched-actions@0.5.0(redux@4.2.1): dependencies: - redux: 5.0.1 + redux: 4.2.1 - redux-thunk@3.1.0(redux@5.0.1): + redux-thunk@2.4.2(redux@4.2.1): dependencies: - redux: 5.0.1 + redux: 4.2.1 redux-undo@1.1.0: {} @@ -7804,8 +7814,6 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 - redux@5.0.1: {} - reference-spec-reader@0.2.0: {} reflect.getprototypeof@1.0.10: @@ -7842,7 +7850,7 @@ snapshots: require-from-string@2.0.2: {} - reselect@5.2.0: {} + reselect@4.1.8: {} resolve-from@4.0.0: {} From 4d7d7c009c369e315dcc5aa7b0bb4548d3f5e62d Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Wed, 20 May 2026 12:06:28 +0200 Subject: [PATCH 05/49] Update redux (toolkit), cleanup types, cleanup code Bumps the rtk group with 5 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@reduxjs/toolkit](https://github.com/reduxjs/redux-toolkit) | `1.9.7` | `2.11.2` | | [react-redux](https://github.com/reduxjs/react-redux) | `8.1.3` | `9.2.0` | | [redux-thunk](https://github.com/reduxjs/redux-thunk) | `2.4.2` | `3.1.0` | | [redux](https://github.com/reduxjs/redux) | `4.2.1` | `5.0.1` | | [reselect](https://github.com/reduxjs/reselect) | `4.1.8` | `5.1.1` | Updates `@reduxjs/toolkit` from 1.9.7 to 2.11.2 - [Release notes](https://github.com/reduxjs/redux-toolkit/releases) - [Commits](https://github.com/reduxjs/redux-toolkit/compare/v1.9.7...v2.11.2) Updates `react-redux` from 8.1.3 to 9.2.0 - [Release notes](https://github.com/reduxjs/react-redux/releases) - [Changelog](https://github.com/reduxjs/react-redux/blob/master/CHANGELOG.md) - [Commits](https://github.com/reduxjs/react-redux/compare/v8.1.3...v9.2.0) Updates `redux-thunk` from 2.4.2 to 3.1.0 - [Release notes](https://github.com/reduxjs/redux-thunk/releases) - [Commits](https://github.com/reduxjs/redux-thunk/compare/v2.4.2...v3.1.0) Updates `redux` from 4.2.1 to 5.0.1 - [Release notes](https://github.com/reduxjs/redux/releases) - [Changelog](https://github.com/reduxjs/redux/blob/master/CHANGELOG.md) - [Commits](https://github.com/reduxjs/redux/compare/v4.2.1...v5.0.1) Updates `reselect` from 4.1.8 to 5.1.1 - [Release notes](https://github.com/reduxjs/reselect/releases) - [Changelog](https://github.com/reduxjs/reselect/blob/master/CHANGELOG.md) - [Commits](https://github.com/reduxjs/reselect/compare/v4.1.8...v5.1.1) --- updated-dependencies: - dependency-name: "@reduxjs/toolkit" dependency-version: 2.11.2 dependency-type: direct:production update-type: version-update:semver-major dependency-group: rtk - dependency-name: react-redux dependency-version: 9.2.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: rtk - dependency-name: redux dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: rtk - dependency-name: redux-thunk dependency-version: 3.1.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: rtk - dependency-name: reselect dependency-version: 5.1.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: rtk ... Signed-off-by: Paul Golmann --- packages/core/src/js/lib/base/controller.ts | 16 +- packages/ui/src/js/components/app.tsx | 4 +- .../src/js/components/feature-list/index.jsx | 8 +- .../with-sticky-header.tsx | 26 ++- .../layer-switcher/LayerSwitcherContainer.tsx | 4 +- .../src/js/components/layer-switcher/index.ts | 2 +- .../src/js/components/main-panel/context.tsx | 7 +- .../main-panel/list-toggle-button.jsx | 2 +- .../components/map-synced-interlay/index.ts | 4 +- .../js/components/switcher/SwitcherEntry.tsx | 8 +- .../components/tag-switcher/TagSwitcher.tsx | 4 +- .../tag-switcher/createTagSwitcherEntry.ts | 6 +- .../tag-switcher/createTagSwitcherHeader.ts | 4 +- .../src/js/components/tag-switcher/index.ts | 4 +- .../view-toggle-button/desktop-button.jsx | 2 +- .../js/components/view-toggle-button/index.ts | 8 +- .../view-toggle-button/mobile-button.tsx | 2 +- .../view-toggle-button/viewport-button.tsx | 2 +- packages/ui/src/js/index.ts | 3 +- .../ui/src/js/plugins/browser/no-scroll.ts | 2 +- .../src/js/plugins/common/measure-distance.ts | 6 +- packages/ui/src/js/store/actions.ts | 4 +- packages/ui/src/js/store/selectors.ts | 6 +- packages/ui/src/js/types.ts | 10 +- pnpm-lock.yaml | 148 +++++++++--------- 25 files changed, 152 insertions(+), 140 deletions(-) diff --git a/packages/core/src/js/lib/base/controller.ts b/packages/core/src/js/lib/base/controller.ts index c0055d7c..ac57035c 100644 --- a/packages/core/src/js/lib/base/controller.ts +++ b/packages/core/src/js/lib/base/controller.ts @@ -1,4 +1,10 @@ -import type {Observable, Reducer, Store, Unsubscribe} from "@reduxjs/toolkit"; +import type { + AnyAction, + Observable, + Reducer, + Store, + Unsubscribe, +} from "@reduxjs/toolkit"; import {compose} from "@reduxjs/toolkit"; import {EventEmitter} from "eventemitter3"; @@ -14,14 +20,14 @@ import type { export class BaseController extends EventEmitter - implements Store + implements Store { // TODO: Should we also implement: observe, getAndObserve and getAndSubscribe? readonly #name: string; #store: EnhancedStore | null = null; #selector: Selector | null = null; - #reducers: Array>; + #reducers: Array<(state: TState, action: AnyAction) => TState>; constructor(controllerName: string) { super(); @@ -30,7 +36,7 @@ export class BaseController this.#reducers = []; } - replaceReducer(_nextReducer: Reducer): void {} + replaceReducer(_nextReducer: Reducer): void {} [Symbol.observable](): Observable { throw new Error("Method not implemented."); @@ -216,7 +222,7 @@ export class BaseController // empty } - registerReducer(reducer: Reducer) { + registerReducer(reducer: (state: TState, action: AnyAction) => TState) { this.#reducers.push(reducer); } diff --git a/packages/ui/src/js/components/app.tsx b/packages/ui/src/js/components/app.tsx index 70611378..fa8ccb75 100644 --- a/packages/ui/src/js/components/app.tsx +++ b/packages/ui/src/js/components/app.tsx @@ -18,10 +18,10 @@ import { tagSwitcherShowSelector, timeFilterVisible, viewSelector, -} from "../store/selectors.ts"; +} from "../store/selectors"; import FeatureList from "./feature-list"; import VisibilityWrapper from "./helping/visibility-wrapper"; -import LayerSwitcher from "./layer-switcher/index.ts"; +import LayerSwitcher from "./layer-switcher/index"; import AdditionalContainer from "./layout/additional-container"; import AdditionalContent from "./layout/additional-container/content"; import Marginal from "./layout/additional-container/marginal"; diff --git a/packages/ui/src/js/components/feature-list/index.jsx b/packages/ui/src/js/components/feature-list/index.jsx index 0580e24d..9bd6f9ab 100644 --- a/packages/ui/src/js/components/feature-list/index.jsx +++ b/packages/ui/src/js/components/feature-list/index.jsx @@ -8,7 +8,7 @@ import { layerSwitcherConfigExternalSelector, listUiOptionsSelector, viewSelector, -} from "../../store/selectors.ts"; +} from "../../store/selectors"; import FeatureCycling from "../feature-list-cycling"; import FeatureSorter from "../feature-list-sorting"; @@ -17,8 +17,8 @@ import { APP_EVENT_SCROLL_TO_FEATURE_LIST, useAppChannelEventListener, } from "../helping/app-channel"; -import LayerSwitcher from "../layer-switcher/index.ts"; -import TagSwitcher from "../tag-switcher/index.ts"; +import LayerSwitcher from "../layer-switcher/index"; +import TagSwitcher from "../tag-switcher/index"; import {FeatureListContextProvider} from "./context"; @@ -31,7 +31,7 @@ import useFeatureListState from "./hooks/useFeatureListState"; import {useMakeHeaderSticky} from "./hooks/useMakeHeaderSticky"; import useRestoreDocumentScroll from "./hooks/useRestoreDocumentScroll"; import useSelectFeature from "./hooks/useSelectFeature"; -import Pagination from "./pagination.tsx"; +import Pagination from "./pagination"; export const DEFAULT_LIST_RENDER_AS = "ul"; diff --git a/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx b/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx index 3c37db68..3e6a45e2 100644 --- a/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx +++ b/packages/ui/src/js/components/feature-selection-info/with-sticky-header.tsx @@ -1,18 +1,34 @@ +import type {ReactNode} from "react"; import {useSelector} from "react-redux"; import useStickyHeader from "../../hooks/useStickyHeader"; -import {featureSelectionInfoUiOptionsSelector} from "../../store/selectors.ts"; +import {featureSelectionInfoUiOptionsSelector} from "../../store/selectors"; +import type {MapsightUiFeature} from "../../types"; import Container from "./container"; const stopEventPropagation = (e) => e.stopPropagation(); -function WithStickyHeader({header, content, feature, close, renderWrapper}) { - const {stuckHeaderSize} = useSelector( +type WithStickyHeaderProps = { + header: ReactNode; + feature: MapsightUiFeature; + content: ReactNode; + close: ReactNode; + renderWrapper: (props: any) => ReactNode; +}; + +function WithStickyHeader({ + header, + content, + feature, + close, + renderWrapper, +}: WithStickyHeaderProps) { + const {stuckHeaderHeight} = useSelector( featureSelectionInfoUiOptionsSelector, ); const {isHeaderStuck, stickyHeaderRef, stickyScrollAreaRef, onScroll} = - useStickyHeader({ - stuckHeaderSize: stuckHeaderHeight, + useStickyHeader({ + stuckHeaderHeight, resetDeps: [feature.id], }); diff --git a/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx b/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx index c66353de..a82d037f 100644 --- a/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx +++ b/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx @@ -13,8 +13,8 @@ import type {MapState} from "@mapsight/core/lib/map/types"; import {translate} from "../../helpers/i18n"; import GroupedLayerSwitcher from "./GroupedLayerSwitcher"; -import LayerSwitcher from "./LayerSwitcher.ts"; -import LayerSwitcherEntry from "./LayerSwitcherEntry.ts"; +import LayerSwitcher from "./LayerSwitcher"; +import LayerSwitcherEntry from "./LayerSwitcherEntry"; // TODO das berechnen der LayerListen (abhängig von grouped und layerIdSelector) in einen Selector packen, // damit diese Berechnung nur bei Änderungen am store berechnet neu wird diff --git a/packages/ui/src/js/components/layer-switcher/index.ts b/packages/ui/src/js/components/layer-switcher/index.ts index 4f254ccb..d6eff631 100644 --- a/packages/ui/src/js/components/layer-switcher/index.ts +++ b/packages/ui/src/js/components/layer-switcher/index.ts @@ -2,7 +2,7 @@ import {connect} from "react-redux"; import type {Selector} from "@mapsight/core/types"; -import {FEATURE_LIST} from "../../config/constants/controllers.ts"; +import {FEATURE_LIST} from "../../config/constants/controllers"; import type {RootStateSlice} from "../../store/selectors"; import {layerSwitcherConfigInternalSelector} from "../../store/selectors"; import type {LayerSwitcherConfigState} from "../../types"; diff --git a/packages/ui/src/js/components/main-panel/context.tsx b/packages/ui/src/js/components/main-panel/context.tsx index 9f74996f..8ff61d8b 100644 --- a/packages/ui/src/js/components/main-panel/context.tsx +++ b/packages/ui/src/js/components/main-panel/context.tsx @@ -2,11 +2,8 @@ import type {PropsWithChildren} from "react"; import {createContext, useContext, useMemo} from "react"; import {useSelector} from "react-redux"; -import {createMainPanelContentTypeSelector} from "../../store/selectors.ts"; -import type { - MainPanelContextOptions, - MainPanelContextValue, -} from "../../types.ts"; +import {createMainPanelContentTypeSelector} from "../../store/selectors"; +import type {MainPanelContextOptions, MainPanelContextValue} from "../../types"; const MainPanelContext = createContext({ showSelectionInfo: false, diff --git a/packages/ui/src/js/components/main-panel/list-toggle-button.jsx b/packages/ui/src/js/components/main-panel/list-toggle-button.jsx index 7f1d0daa..e7793604 100644 --- a/packages/ui/src/js/components/main-panel/list-toggle-button.jsx +++ b/packages/ui/src/js/components/main-panel/list-toggle-button.jsx @@ -5,7 +5,7 @@ import {toggleUserPreferenceListVisible} from "../../store/actions"; import {userPreferenceListVisibleSelector} from "../../store/selectors"; -import {useMainPanelContext} from "./context.tsx"; +import {useMainPanelContext} from "./context"; function MainPanelListToggleButton() { const {collapsible, contentType} = useMainPanelContext(); diff --git a/packages/ui/src/js/components/map-synced-interlay/index.ts b/packages/ui/src/js/components/map-synced-interlay/index.ts index 39ced392..bd6c9d09 100644 --- a/packages/ui/src/js/components/map-synced-interlay/index.ts +++ b/packages/ui/src/js/components/map-synced-interlay/index.ts @@ -4,8 +4,8 @@ import {mapSizeSelector} from "@mapsight/core/lib/map/selectors"; import type {MapState} from "@mapsight/core/lib/map/types"; import {MAP} from "../../config/constants/controllers"; -import type {RootStateSlice} from "../../store/selectors.ts"; -import {viewSelector} from "../../store/selectors.ts"; +import type {RootStateSlice} from "../../store/selectors"; +import {viewSelector} from "../../store/selectors"; import MapSyncedInterlay from "./map-synced-interlay"; export default connect((state: RootStateSlice) => ({ diff --git a/packages/ui/src/js/components/switcher/SwitcherEntry.tsx b/packages/ui/src/js/components/switcher/SwitcherEntry.tsx index 7f8ee37f..86b4c7af 100644 --- a/packages/ui/src/js/components/switcher/SwitcherEntry.tsx +++ b/packages/ui/src/js/components/switcher/SwitcherEntry.tsx @@ -29,14 +29,14 @@ const mapStatusLabel = (status: string) => translate("ui.switcher.entry.label" + status); const determineDisplayStatus = ( - status: FeatureSourceStatus, - active: boolean, + status?: FeatureSourceStatus, + active: boolean = false, ): SwitcherEntryStatus => { if (!status || status === STATUS_OK) { return active ? STATUS_ACTIVE : STATUS_INACTIVE; } - return status; + return status ?? STATUS_INACTIVE; }; export type SwitcherEntryProps = { @@ -51,7 +51,7 @@ export type SwitcherEntryProps = { active?: boolean; activeCheckbox?: boolean; activeText?: boolean; - status: FeatureSourceStatus; + status?: FeatureSourceStatus; locked?: boolean; }; diff --git a/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx b/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx index 217b172e..502aecec 100644 --- a/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx +++ b/packages/ui/src/js/components/tag-switcher/TagSwitcher.tsx @@ -2,8 +2,8 @@ import {memo, useMemo} from "react"; import {getDocumentLanguage} from "../../helpers/i18n"; import GroupedSwitcher from "../switcher/GroupedSwitcher"; -import createTagSwitcherEntry from "./createTagSwitcherEntry.ts"; -import createTagSwitcherHeader from "./createTagSwitcherHeader.ts"; +import createTagSwitcherEntry from "./createTagSwitcherEntry"; +import createTagSwitcherHeader from "./createTagSwitcherHeader"; function TagSwitcher({ groupedTagData, diff --git a/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts b/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts index ecd3fafa..428e5827 100644 --- a/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts +++ b/packages/ui/src/js/components/tag-switcher/createTagSwitcherEntry.ts @@ -1,8 +1,8 @@ import {connect} from "react-redux"; -import {setTagVisible} from "../../store/actions.ts"; -import type {RootStateSlice} from "../../store/selectors.ts"; -import {createTagVisibleSelector} from "../../store/selectors.ts"; +import {setTagVisible} from "../../store/actions"; +import type {RootStateSlice} from "../../store/selectors"; +import {createTagVisibleSelector} from "../../store/selectors"; import SwitcherEntry from "../switcher/SwitcherEntry"; export default function createTagSwitcherEntry( diff --git a/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts b/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts index 0ca8e6f0..9c18ad70 100644 --- a/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts +++ b/packages/ui/src/js/components/tag-switcher/createTagSwitcherHeader.ts @@ -1,10 +1,10 @@ import {connect} from "react-redux"; -import {setTagGroupVisible} from "../../store/actions.ts"; +import {setTagGroupVisible} from "../../store/actions"; import { type RootStateSlice, createTagGroupVisibleSelector, -} from "../../store/selectors.ts"; +} from "../../store/selectors"; import SwitcherHeader from "../switcher/SwitcherHeader"; type Props = { diff --git a/packages/ui/src/js/components/tag-switcher/index.ts b/packages/ui/src/js/components/tag-switcher/index.ts index 727edf12..1076b845 100644 --- a/packages/ui/src/js/components/tag-switcher/index.ts +++ b/packages/ui/src/js/components/tag-switcher/index.ts @@ -1,12 +1,12 @@ import {connect} from "react-redux"; -import type {RootStateSlice} from "../../store/selectors.ts"; +import type {RootStateSlice} from "../../store/selectors"; import { tagSwitcherFeatureSourceIdSelector, tagSwitcherSortTags, tagSwitcherTagsSelector, tagSwitcherToggleableGroups, -} from "../../store/selectors.ts"; +} from "../../store/selectors"; import TagSwitcher from "./TagSwitcher"; export default connect((state: RootStateSlice) => ({ diff --git a/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx b/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx index 07286e90..b8522852 100644 --- a/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx +++ b/packages/ui/src/js/components/view-toggle-button/desktop-button.jsx @@ -1,4 +1,4 @@ -import ViewToggleButton from "./index.ts"; +import ViewToggleButton from "./index"; function DesktopViewToggleButton() { return ( diff --git a/packages/ui/src/js/components/view-toggle-button/index.ts b/packages/ui/src/js/components/view-toggle-button/index.ts index fd2b019c..de024603 100644 --- a/packages/ui/src/js/components/view-toggle-button/index.ts +++ b/packages/ui/src/js/components/view-toggle-button/index.ts @@ -2,17 +2,17 @@ import {connect} from "react-redux"; import {deselectAll} from "@mapsight/core/lib/feature-selections/actions"; -import type {View} from "../../config/constants/app.ts"; +import type {View} from "../../config/constants/app"; import {FEATURE_SELECTIONS} from "../../config/constants/controllers"; import {FEATURE_SELECTION_SELECT} from "../../config/feature/selections"; -import {setView} from "../../store/actions.ts"; -import type {RootStateSlice} from "../../store/selectors.ts"; +import {setView} from "../../store/actions"; +import type {RootStateSlice} from "../../store/selectors"; import { isMapOutOfViewportSelector, isViewMobile, viewSelector, viewToggleOptionsSelector, -} from "../../store/selectors.ts"; +} from "../../store/selectors"; import ViewToggleButton from "./view-toggle-button"; export default connect( diff --git a/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx b/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx index 8d9917b4..dd9bfe4f 100644 --- a/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx +++ b/packages/ui/src/js/components/view-toggle-button/mobile-button.tsx @@ -1,4 +1,4 @@ -import ViewToggleButton from "./index.ts"; +import ViewToggleButton from "./index"; function MobileViewToggleButton() { return ( diff --git a/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx b/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx index 5ce34be1..8628b38e 100644 --- a/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx +++ b/packages/ui/src/js/components/view-toggle-button/viewport-button.tsx @@ -1,4 +1,4 @@ -import ViewToggleButton from "./index.ts"; +import ViewToggleButton from "./index"; function ViewportViewToggleButton() { return ( diff --git a/packages/ui/src/js/index.ts b/packages/ui/src/js/index.ts index 2ff2da9a..431912d9 100644 --- a/packages/ui/src/js/index.ts +++ b/packages/ui/src/js/index.ts @@ -1,6 +1,6 @@ import {applyMiddleware, compose} from "@reduxjs/toolkit"; import merge from "lodash/merge"; -import thunk from "redux-thunk"; +import {thunk} from "redux-thunk"; import {createMapsightStore} from "@mapsight/core"; import {layerIdsExternalSwitcherSelector} from "@mapsight/core/lib/map/selectors"; @@ -189,6 +189,7 @@ export function create( // store enhancer const uiStoreEnhancer = applyMiddleware(thunk); + // @ts-expect-error TODO context.storeEnhancer = context.createOptions.storeEnhancer ? compose(uiStoreEnhancer, context.createOptions.storeEnhancer) : uiStoreEnhancer; diff --git a/packages/ui/src/js/plugins/browser/no-scroll.ts b/packages/ui/src/js/plugins/browser/no-scroll.ts index 7fd213e5..82e3c84d 100644 --- a/packages/ui/src/js/plugins/browser/no-scroll.ts +++ b/packages/ui/src/js/plugins/browser/no-scroll.ts @@ -5,7 +5,7 @@ import {getAndObserveState} from "@mapsight/lib-redux/observe-state"; import {VIEW_FULLSCREEN, VIEW_MAP_ONLY} from "../../config/constants/app"; import type {RootStateSlice} from "../../store/selectors"; import {viewSelector} from "../../store/selectors"; -import type {PluginInstance} from "../../types.ts"; +import type {PluginInstance} from "../../types"; function onTouchMoveNoScroll(e: TouchEvent) { e.preventDefault(); diff --git a/packages/ui/src/js/plugins/common/measure-distance.ts b/packages/ui/src/js/plugins/common/measure-distance.ts index 1b2985f7..ae01331d 100644 --- a/packages/ui/src/js/plugins/common/measure-distance.ts +++ b/packages/ui/src/js/plugins/common/measure-distance.ts @@ -1,4 +1,3 @@ -import type {Store} from "@reduxjs/toolkit"; import {createSelector} from "@reduxjs/toolkit"; import {mergeAll} from "@mapsight/core/lib/base/actions"; @@ -14,6 +13,7 @@ import { import type {Definition} from "@mapsight/core/ol-proxy"; import {di} from "@mapsight/core/ol-proxy"; import DrawInteraction from "@mapsight/core/ol-proxy/definitions/interaction/DrawInteraction"; +import type {EnhancedStore} from "@mapsight/core/types"; import {observeState} from "@mapsight/lib-redux/observe-state"; @@ -23,7 +23,7 @@ import { MAP, } from "../../config/constants/controllers"; import {getDictionary} from "../../helpers/i18n"; -import type {PluginInstance} from "../../types.ts"; +import type {PluginInstance} from "../../types"; export const createActivateAction = (mapController: string, name: string) => activateInteraction(mapController, `${name}_drawInteraction`); @@ -49,7 +49,7 @@ function setupDrawInteraction({ drawStyle, displayStyle, }: { - store: Store; + store: EnhancedStore; name: string; featureSourcesControllerName: string; featureSelectionsControllerName: string; diff --git a/packages/ui/src/js/store/actions.ts b/packages/ui/src/js/store/actions.ts index b59581e1..99425236 100644 --- a/packages/ui/src/js/store/actions.ts +++ b/packages/ui/src/js/store/actions.ts @@ -26,7 +26,7 @@ import type { FullUiState, MapsightUiFeatureId, UiState, -} from "../types.ts"; +} from "../types"; import type {RootStateSlice} from "./selectors"; import {featureDetailsUrlSelector, regionsSelector} from "./selectors"; @@ -261,7 +261,7 @@ export function setMiniLegendLayer(layerId: string | null) { }; } -export const SET_VIEW_BREAKPOINTS = "SET_VIEW_BREAKPOINTS"; +export const SET_VIEW_BREAKPOINTS = "SET_VIEW_BREAKPOI"; export function setViewBreakpoints(value: FullUiState["viewBreakpoints"]) { return { diff --git a/packages/ui/src/js/store/selectors.ts b/packages/ui/src/js/store/selectors.ts index 09f48066..a3fdea57 100644 --- a/packages/ui/src/js/store/selectors.ts +++ b/packages/ui/src/js/store/selectors.ts @@ -28,7 +28,7 @@ import type {MapState} from "@mapsight/core/lib/map/types"; import type {UserGeolocationState} from "@mapsight/core/lib/user-geolocation/selectors"; import type {State} from "@mapsight/core/types"; -import type {MapsightUiPlacesData} from "../components/feature-list-sorting/feature-list-sorting.tsx"; +import type {MapsightUiPlacesData} from "../components/feature-list-sorting/feature-list-sorting"; import type {View} from "../config/constants/app"; import { DETAILS_CONTENT_STATE_KEY, @@ -58,14 +58,14 @@ import type { MapsightUiFeature, RegionState, UiState, -} from "../types.ts"; +} from "../types"; import { FETCH_JSON_STATUS_ERROR, FETCH_JSON_STATUS_LOADING, FETCH_JSON_STATUS_SUCCESS, FETCH_TEXT_STATUS_ERROR, FETCH_TEXT_STATUS_SUCCESS, -} from "./actions.ts"; +} from "./actions"; type SEARCH_STATUS = | typeof SEARCH_STATUS_INACTIVE diff --git a/packages/ui/src/js/types.ts b/packages/ui/src/js/types.ts index 5f775296..71397ce0 100644 --- a/packages/ui/src/js/types.ts +++ b/packages/ui/src/js/types.ts @@ -15,12 +15,12 @@ import type {EnhancedStore, Feature, State} from "@mapsight/core/types"; import type {MapsightStyleFunction} from "@mapsight/lib-ol/style/styleFunction"; -import type {MapsightUiPlacesData} from "./components/feature-list-sorting/feature-list-sorting.tsx"; -import type {View} from "./config/constants/app.ts"; -import type {TAG_FILTER, TIME_FILTER} from "./config/constants/controllers.ts"; +import type {MapsightUiPlacesData} from "./components/feature-list-sorting/feature-list-sorting"; +import type {View} from "./config/constants/app"; +import type {TAG_FILTER, TIME_FILTER} from "./config/constants/controllers"; import type {MapsightUiComponents} from "./helpers/components"; -import type {FETCH_JSON_STATUS, FETCH_TEXT_STATUS} from "./store/actions.ts"; -import type {RootStateSlice} from "./store/selectors.ts"; +import type {FETCH_JSON_STATUS, FETCH_TEXT_STATUS} from "./store/actions"; +import type {RootStateSlice} from "./store/selectors"; // helper type https://stackoverflow.com/a/61132308 export type DeepPartial = T extends object diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d2ba18c..27499f46 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,8 @@ settings: catalogs: default: '@reduxjs/toolkit': - specifier: ^1.9.7 - version: 1.9.7 + specifier: ^2.11.2 + version: 2.12.0 '@types/jsdom': specifier: ^28.0.3 version: 28.0.3 @@ -52,17 +52,17 @@ catalogs: specifier: ^19.2.6 version: 19.2.6 react-redux: - specifier: ^8.1.3 - version: 8.1.3 + specifier: ^9.2.0 + version: 9.3.0 redux-batched-actions: specifier: ^0.5.0 version: 0.5.0 redux-thunk: - specifier: ^2.4.2 - version: 2.4.2 + specifier: ^3.1.0 + version: 3.1.0 reselect: - specifier: ^4.1.8 - version: 4.1.8 + specifier: ^5.1.1 + version: 5.2.0 tailwindcss: specifier: ^4.3.0 version: 4.3.0 @@ -193,7 +193,7 @@ importers: version: 19.2.6(react@19.2.6) reselect: specifier: 'catalog:' - version: 4.1.8 + version: 5.2.0 devDependencies: '@mapsight/vector-style-compiler': specifier: workspace:^ @@ -263,7 +263,7 @@ importers: version: 19.2.6(react@19.2.6) react-redux: specifier: 'catalog:' - version: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) + version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) react-router: specifier: ^7.15.0 version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -272,7 +272,7 @@ importers: version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) reselect: specifier: 'catalog:' - version: 4.1.8 + version: 5.2.0 tailwindcss: specifier: 'catalog:' version: 4.3.0 @@ -318,7 +318,7 @@ importers: version: link:../../packages/traffic-style/dist '@reduxjs/toolkit': specifier: 'catalog:' - version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -339,13 +339,13 @@ importers: version: 3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-redux: specifier: 'catalog:' - version: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) + version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) react-tooltip: specifier: ^4.5.1 version: 4.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) redux-batched-actions: specifier: 'catalog:' - version: 0.5.0(redux@4.2.1) + version: 0.5.0(redux@5.0.1) redux-undo: specifier: ^1.1.0 version: 1.1.0 @@ -403,7 +403,7 @@ importers: version: link:../lib-redux '@reduxjs/toolkit': specifier: 'catalog:' - version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) eventemitter3: specifier: ^5.0.4 version: 5.0.4 @@ -415,11 +415,11 @@ importers: version: 10.2.5 redux-batched-actions: specifier: 'catalog:' - version: 0.5.0(redux@4.2.1) + version: 0.5.0(redux@5.0.1) devDependencies: '@redux-devtools/extension': specifier: ^3.3.0 - version: 3.3.0(redux@4.2.1) + version: 3.3.0(redux@5.0.1) '@types/geojson': specifier: ^7946.0.16 version: 7946.0.16 @@ -492,7 +492,7 @@ importers: version: link:../lib-js '@reduxjs/toolkit': specifier: 'catalog:' - version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@types/lodash': specifier: 'catalog:' version: 4.17.24 @@ -570,7 +570,7 @@ importers: version: link:../lib-redux '@reduxjs/toolkit': specifier: 'catalog:' - version: 1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@types/react-redux': specifier: 'catalog:' version: 7.1.34 @@ -612,13 +612,13 @@ importers: version: 8.3.0(react@19.2.6) react-redux: specifier: 'catalog:' - version: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) + version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) redux-batched-actions: specifier: 'catalog:' - version: 0.5.0(redux@4.2.1) + version: 0.5.0(redux@5.0.1) redux-thunk: specifier: 'catalog:' - version: 2.4.2(redux@4.2.1) + version: 3.1.0(redux@5.0.1) devDependencies: '@types/lodash': specifier: 'catalog:' @@ -1358,11 +1358,11 @@ packages: peerDependencies: redux: ^3.1.0 || ^4.0.0 || ^5.0.0 - '@reduxjs/toolkit@1.9.7': - resolution: {integrity: sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==} + '@reduxjs/toolkit@2.12.0': + resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==} peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 - react-redux: ^7.2.1 || ^8.0.2 + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 peerDependenciesMeta: react: optional: true @@ -1473,6 +1473,9 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} @@ -1704,8 +1707,8 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - '@types/use-sync-external-store@0.0.3': - resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} '@typescript-eslint/eslint-plugin@8.59.4': resolution: {integrity: sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==} @@ -2930,8 +2933,8 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - immer@9.0.21: - resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} + immer@11.1.8: + resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==} immutable@4.3.8: resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==} @@ -3729,9 +3732,6 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} @@ -3746,24 +3746,15 @@ packages: peerDependencies: react: ^16 || ^17 || ^18 || ^19 - react-redux@8.1.3: - resolution: {integrity: sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==} + react-redux@9.3.0: + resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} peerDependencies: - '@types/react': ^16.8 || ^17.0 || ^18.0 - '@types/react-dom': ^16.8 || ^17.0 || ^18.0 - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - react-native: '>=0.59' - redux: ^4 || ^5.0.0-beta.0 + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 peerDependenciesMeta: '@types/react': optional: true - '@types/react-dom': - optional: true - react-dom: - optional: true - react-native: - optional: true redux: optional: true @@ -3828,10 +3819,10 @@ packages: peerDependencies: redux: '>=1.0.0' - redux-thunk@2.4.2: - resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} peerDependencies: - redux: ^4 + redux: ^5.0.0 redux-undo@1.1.0: resolution: {integrity: sha512-zzLFh2qeF0MTIlzDhDLm9NtkfBqCllQJ3OCuIl5RKlG/ayHw6GUdIFdMhzMS9NnrnWdBX5u//ExMOHpfudGGOg==} @@ -3839,6 +3830,9 @@ packages: redux@4.2.1: resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + reference-spec-reader@0.2.0: resolution: {integrity: sha512-q0mfCi5yZSSHXpCyxjgQeaORq3tvDsxDyzaadA/5+AbAUwRyRuuTh0aRQuE/vAOt/qzzxidJ5iDeu1cLHaNBlQ==} @@ -3870,8 +3864,8 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - reselect@4.1.8: - resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -5255,21 +5249,23 @@ snapshots: dependencies: react: 19.2.6 - '@redux-devtools/extension@3.3.0(redux@4.2.1)': + '@redux-devtools/extension@3.3.0(redux@5.0.1)': dependencies: '@babel/runtime': 7.29.2 immutable: 4.3.8 - redux: 4.2.1 + redux: 5.0.1 - '@reduxjs/toolkit@1.9.7(react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1))(react@19.2.6)': + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': dependencies: - immer: 9.0.21 - redux: 4.2.1 - redux-thunk: 2.4.2(redux@4.2.1) - reselect: 4.1.8 + '@standard-schema/spec': 1.1.0 + '@standard-schema/utils': 0.3.0 + immer: 11.1.8 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.2.0 optionalDependencies: react: 19.2.6 - react-redux: 8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1) + react-redux: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) '@rolldown/binding-android-arm64@1.0.1': optional: true @@ -5326,6 +5322,8 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@standard-schema/utils@0.3.0': {} + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -5529,7 +5527,7 @@ snapshots: '@types/tough-cookie@4.0.5': {} - '@types/use-sync-external-store@0.0.3': {} + '@types/use-sync-external-store@0.0.6': {} '@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: @@ -6942,7 +6940,7 @@ snapshots: ignore@7.0.5: {} - immer@9.0.21: {} + immer@11.1.8: {} immutable@4.3.8: {} @@ -7709,8 +7707,6 @@ snapshots: react-is@16.13.1: {} - react-is@18.3.1: {} - react-lifecycles-compat@3.0.4: {} react-modal@3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6): @@ -7727,20 +7723,14 @@ snapshots: prop-types: 15.8.1 react: 19.2.6 - react-redux@8.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(redux@4.2.1): + react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1): dependencies: - '@babel/runtime': 7.29.2 - '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.14) - '@types/use-sync-external-store': 0.0.3 - hoist-non-react-statics: 3.3.2 + '@types/use-sync-external-store': 0.0.6 react: 19.2.6 - react-is: 18.3.1 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - react-dom: 19.2.6(react@19.2.6) - redux: 4.2.1 + redux: 5.0.1 react-router-dom@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: @@ -7800,13 +7790,13 @@ snapshots: readdirp@5.0.0: {} - redux-batched-actions@0.5.0(redux@4.2.1): + redux-batched-actions@0.5.0(redux@5.0.1): dependencies: - redux: 4.2.1 + redux: 5.0.1 - redux-thunk@2.4.2(redux@4.2.1): + redux-thunk@3.1.0(redux@5.0.1): dependencies: - redux: 4.2.1 + redux: 5.0.1 redux-undo@1.1.0: {} @@ -7814,6 +7804,8 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 + redux@5.0.1: {} + reference-spec-reader@0.2.0: {} reflect.getprototypeof@1.0.10: @@ -7850,7 +7842,7 @@ snapshots: require-from-string@2.0.2: {} - reselect@4.1.8: {} + reselect@5.2.0: {} resolve-from@4.0.0: {} From 91ccec20a2de00a66615d736e6a3d48e55f5abce Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 21 May 2026 12:48:56 +0200 Subject: [PATCH 06/49] Fix types Signed-off-by: Paul Golmann --- .../src/js/components/vector-editor/DeleteButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx b/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx index 616e9421..189ae56a 100644 --- a/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx +++ b/apps/vector-editor/src/js/components/vector-editor/DeleteButton.tsx @@ -2,7 +2,7 @@ import type React from "react"; import {useMemo} from "react"; import {useDispatch, useSelector} from "react-redux"; -import {createSelector} from "@reduxjs/toolkit"; +import {type UnknownAction, createSelector} from "@reduxjs/toolkit"; import {batchActions} from "redux-batched-actions"; import {deselectAll} from "@mapsight/core/lib/feature-selections/actions"; @@ -53,7 +53,7 @@ function DeleteButton({ featureIds, ), deselectAll(editor.controllers.featureSelections!, "select"), - ]), + ]) as unknown as UnknownAction, ); }; From 380adbf578dc203b8b0085994eb6e57f8232da45 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 21 May 2026 12:54:23 +0200 Subject: [PATCH 07/49] Cleanup Signed-off-by: Paul Golmann --- packages/ui/src/js/components/switcher/SwitcherEntry.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/js/components/switcher/SwitcherEntry.tsx b/packages/ui/src/js/components/switcher/SwitcherEntry.tsx index 86b4c7af..f3b721e6 100644 --- a/packages/ui/src/js/components/switcher/SwitcherEntry.tsx +++ b/packages/ui/src/js/components/switcher/SwitcherEntry.tsx @@ -36,7 +36,7 @@ const determineDisplayStatus = ( return active ? STATUS_ACTIVE : STATUS_INACTIVE; } - return status ?? STATUS_INACTIVE; + return status; }; export type SwitcherEntryProps = { From 62bd6460d2b1e6776481a6c6a59d8d78faf702bb Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Mon, 25 May 2026 13:24:25 +0200 Subject: [PATCH 08/49] fix split layer switcher not working Signed-off-by: Paul Golmann --- .../layer-switcher/LayerSwitcherContainer.tsx | 11 ++++++----- packages/ui/src/js/components/layer-switcher/index.ts | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx b/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx index a82d037f..27fd1d99 100644 --- a/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx +++ b/packages/ui/src/js/components/layer-switcher/LayerSwitcherContainer.tsx @@ -1,6 +1,7 @@ import type {ElementType} from "react"; import {memo, useCallback} from "react"; +import type {ActionPath} from "@mapsight/core/lib/base/actions"; import { layerIdsIntegratedSwitcherSelector, makeFeatureSourceFromLayerIdSelector, @@ -26,7 +27,7 @@ export type LayerSwitcherContainerProps = { onClose?: () => void; layerIdsSelector?: (state: MapState) => string[]; grouped?: boolean; - setFeatureSourceIdPath?: unknown; + setFeatureSourceIdPath?: ActionPath | null; }; function LayerSwitcherContainer({ @@ -35,12 +36,11 @@ function LayerSwitcherContainer({ onClose, layerIdsSelector = layerIdsIntegratedSwitcherSelector, grouped = false, - setFeatureSourceIdPath: _, + setFeatureSourceIdPath, ...attributes }: LayerSwitcherContainerProps) { const renderLayerEntry = useCallback( - (id) => ( - // TODO: memo comp instance & selectors + (id: string) => ( ), - [], + [setFeatureSourceIdPath], ); const Switcher = grouped ? GroupedLayerSwitcher : LayerSwitcher; diff --git a/packages/ui/src/js/components/layer-switcher/index.ts b/packages/ui/src/js/components/layer-switcher/index.ts index d6eff631..537f99ed 100644 --- a/packages/ui/src/js/components/layer-switcher/index.ts +++ b/packages/ui/src/js/components/layer-switcher/index.ts @@ -8,7 +8,7 @@ import {layerSwitcherConfigInternalSelector} from "../../store/selectors"; import type {LayerSwitcherConfigState} from "../../types"; import LayerSwitcherContainer from "./LayerSwitcherContainer"; -const TRUE_SET_FEATURE_SOURCE_PATH = [FEATURE_LIST, "featureSource"] as const; +const TRUE_SET_FEATURE_SOURCE_PATH = [FEATURE_LIST, "featureSource"]; type Props = { configSelector?: Selector; From 9325bffedadbbb8b63193e89c7f022877ba23e29 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Mon, 25 May 2026 13:24:46 +0200 Subject: [PATCH 09/49] add exports for embed Signed-off-by: Paul Golmann --- packages/ui/package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/ui/package.json b/packages/ui/package.json index 444721d2..cfaeafc3 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -54,6 +54,10 @@ "./config/*": { "types": "./dist/config/*.d.ts", "default": "./dist/config/*.js" + }, + "./embed/*": { + "types": "./dist/embed/*.d.ts", + "default": "./dist/embed/*.js" } }, "license": "UNLICENSED", From 9109a1c88a9c27c250f8abc3bb3733fd0f27ac74 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 15:13:06 +0200 Subject: [PATCH 10/49] ignore tsconfig.node.tsbuildinfo Signed-off-by: Paul Golmann --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b468d7f2..f99e4e01 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ node_modules/ /apps/*/tmp/ /packages/*/tmp/ .turbo/ +tsconfig.node.tsbuildinfo # built files that get distributed /apps/*/dist/ From 0c3b075a1909d1352488556d79fe415b2ca33b41 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 15:14:27 +0200 Subject: [PATCH 11/49] vsc: fix watch mode Signed-off-by: Paul Golmann --- apps/demo-vite/tsconfig.node.json | 5 +++++ packages/vector-style-compiler/package.json | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 apps/demo-vite/tsconfig.node.json diff --git a/apps/demo-vite/tsconfig.node.json b/apps/demo-vite/tsconfig.node.json new file mode 100644 index 00000000..50f90c8c --- /dev/null +++ b/apps/demo-vite/tsconfig.node.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../configs/tsconfig-vite-node.json", + "include": ["vite.config.ts", "../../configs/vite-workspace-dev.mts"] +} diff --git a/packages/vector-style-compiler/package.json b/packages/vector-style-compiler/package.json index 60ef6269..e21558e6 100644 --- a/packages/vector-style-compiler/package.json +++ b/packages/vector-style-compiler/package.json @@ -26,8 +26,8 @@ "pidusage": "catalog:", "playwright": "catalog:", "replace-in-file": "^8.4.0", - "sass": "^1.99.0", - "vite": "^8.0.13", + "sass": "^1.100.0", + "vite": "^8.0.14", "vitest": "catalog:" }, "exports": { @@ -64,7 +64,7 @@ "test": "vitest run", "typecheck": "tsc --noEmit", "update-readme": "node scripts/update-readme.mts", - "watch": "tsc --watch" + "watch": "tsc -p tsconfig.build.json --watch" }, "types": "./dist/index.d.ts" } From 0c7e9bdc99605cbdabc33076054888793d18975b Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 15:14:57 +0200 Subject: [PATCH 12/49] vsc: cleanup generated code (remove source map comment, remove invalid pure annotations) Signed-off-by: Paul Golmann --- packages/vector-style-compiler/src/js/template.ts | 3 +++ packages/vector-style-compiler/src/js/treeToProgram.ts | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/vector-style-compiler/src/js/template.ts b/packages/vector-style-compiler/src/js/template.ts index fc17548f..57a461d7 100644 --- a/packages/vector-style-compiler/src/js/template.ts +++ b/packages/vector-style-compiler/src/js/template.ts @@ -44,6 +44,9 @@ const defaultTemplate = ({__meta, program1, program2}: TemplateArgs) => { result = replaceTag(result, "program1", program1); result = replaceTag(result, "program2", program2); + // Remove any source map comments + result = result.replace(/\/\/# sourceMappingURL=.*\n/g, ""); + return result; }; diff --git a/packages/vector-style-compiler/src/js/treeToProgram.ts b/packages/vector-style-compiler/src/js/treeToProgram.ts index 664b6bb4..85a93885 100644 --- a/packages/vector-style-compiler/src/js/treeToProgram.ts +++ b/packages/vector-style-compiler/src/js/treeToProgram.ts @@ -68,14 +68,15 @@ function checkToExpression(check: Check, aliases?: Map) { case "geometryType": return `geometryType == ${check.value}`; case "value": { - let property = pathToExpression(check.target, check.path); + const realProperty = pathToExpression(check.target, check.path); + let property = realProperty; if (aliases) { if (aliases.has(property)) { - property = aliases.get(property)!; + property = aliases.get(property)! + `/* ${realProperty} */`; } else { const alias = aliasName(aliases.size + 1); aliases.set(property, alias); - property = alias; + property = `${alias}/* ${realProperty} */`; } } @@ -181,8 +182,7 @@ export default function treeToProgram( } const aliasesPrograms = Array.from(aliases.entries()).map( - ([expression, alias]) => - `const ${alias} = /* @__PURE__ */${expression};`, + ([expression, alias]) => `const ${alias} = ${expression};`, ); if (aliasesPrograms.length) { From 0d3ecdf28da49cf0565bf8b96cc6406c1e2c69b4 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 15:16:00 +0200 Subject: [PATCH 13/49] traffic-style: cleanup Signed-off-by: Paul Golmann --- packages/traffic-style/src/scss/features/_cluster.scss | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/traffic-style/src/scss/features/_cluster.scss b/packages/traffic-style/src/scss/features/_cluster.scss index b9201ba2..9ff82aeb 100644 --- a/packages/traffic-style/src/scss/features/_cluster.scss +++ b/packages/traffic-style/src/scss/features/_cluster.scss @@ -1,7 +1,4 @@ @use "../variables"; -@use "../mixins/icon-base"; -@use "../mixins/icon"; -@use "../mixins/auto-icon"; #features [cluster] { .clusterLabel { From 5f5e188eec3c8e04004402c8c210b3ceccc027fd Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 15:16:45 +0200 Subject: [PATCH 14/49] traffic-style: make default xsmall/small zoom levels for icons configurable Signed-off-by: Paul Golmann --- packages/traffic-style/src/scss/_variables.scss | 3 +++ packages/traffic-style/src/scss/features/_base.scss | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/traffic-style/src/scss/_variables.scss b/packages/traffic-style/src/scss/_variables.scss index 82513a51..10444215 100644 --- a/packages/traffic-style/src/scss/_variables.scss +++ b/packages/traffic-style/src/scss/_variables.scss @@ -1,3 +1,6 @@ +$MAPSIGHT_TRAFFIC_STYLE__FEATURES_BASE_ZOOM_SMALL: 11 !default; +$MAPSIGHT_TRAFFIC_STYLE__FEATURES_BASE_ZOOM_DEFAULT: 13 !default; + $MAPSIGHT_TRAFFIC_STYLE__FILL_COLOR: rgba(255, 0, 0, 0.46) !default; $MAPSIGHT_TRAFFIC_STYLE__STROKE_COLOR: rgba(224, 109, 208, 0.9) !default; diff --git a/packages/traffic-style/src/scss/features/_base.scss b/packages/traffic-style/src/scss/features/_base.scss index 9fd6651a..6c5bb5b8 100644 --- a/packages/traffic-style/src/scss/features/_base.scss +++ b/packages/traffic-style/src/scss/features/_base.scss @@ -10,15 +10,15 @@ @include icon-base.iconBase; @include auto-icon.autoIcon("default"); - [|js="env.zoom >= 1 && env.zoom <= 10"] + [|js="env.zoom < #{variables.$MAPSIGHT_TRAFFIC_STYLE__FEATURES_BASE_ZOOM_SMALL}"] :not([state="highlight"]) :not([state="select"]) { @include auto-icon.autoIcon("xsmall"); } - [|js="env.zoom >= 11 && env.zoom <= 12"] - :not([state="highlight"]) - :not([state="select"]) { + [|js="env.zoom >= #{variables.$MAPSIGHT_TRAFFIC_STYLE__FEATURES_BASE_ZOOM_SMALL} && env.zoom < #{variables.$MAPSIGHT_TRAFFIC_STYLE__FEATURES_BASE_ZOOM_DEFAULT}"] + :not([state="highlight"]) + :not([state="select"]) { @include auto-icon.autoIcon("small"); } From 65a01e4cca12f80555c9dc9acc854dcc24f4d2be Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:07:13 +0200 Subject: [PATCH 15/49] add documentation for Mapsight redux architecture Signed-off-by: Paul Golmann --- docs/MAPSIGHT_REDUX_ARCHITECTURE.md | 463 ++++++++++++++++++++++++++++ 1 file changed, 463 insertions(+) create mode 100644 docs/MAPSIGHT_REDUX_ARCHITECTURE.md diff --git a/docs/MAPSIGHT_REDUX_ARCHITECTURE.md b/docs/MAPSIGHT_REDUX_ARCHITECTURE.md new file mode 100644 index 00000000..7c944202 --- /dev/null +++ b/docs/MAPSIGHT_REDUX_ARCHITECTURE.md @@ -0,0 +1,463 @@ +# Mapsight Redux Architecture + +> **What this is:** A reference for how Mapsight’s GIS state layer works today — not a migration plan. +> For stabilization and gradual modernization, see [MAPSIGHT_REDUX_IMPROVEMENT_PLAN.md](./MAPSIGHT_REDUX_IMPROVEMENT_PLAN.md). + +--- + +## TL;DR + +Mapsight is not “Redux with a map component.” It is a **declarative GIS runtime**: + +1. The entire map (layers, view, controls, interactions, feature data) is described as **serializable JSON** in a single Redux store. +2. **Controllers** watch that JSON and sync it to real OpenLayers objects (and back). +3. **Path-based actions** (`set`, `merge`, `mergeAll`) let you mutate any part of the tree — including bulk CMS-driven reconfiguration without a page reload. +4. A **controlled / uncontrolled** distinction prevents infinite loops when OpenLayers reports zoom/pan back into Redux. + +React is a thin view layer on top. The core is usable without React. + +--- + +## Mental model + +Think of Redux state as the **target document** (like a VDOM for the map). Controllers are **reconcilers** that diff state against OpenLayers and apply changes. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Redux Store │ +│ ┌─────────┐ ┌─────────┐ ┌────────────────┐ ┌───────────────┐ │ +│ │ map │ │ list │ │ featureSources │ │ featureSelect…│ │ +│ │ (JSON) │ │ (JSON) │ │ (JSON) │ │ (JSON) │ │ +│ └────┬────┘ └─────────┘ └───────┬────────┘ └───────────────┘ │ +│ │ │ │ +│ ┌────┴────┐ ┌──────┴──────┐ │ +│ │ app │ (UI slice) │ projections │ …other controllers │ +│ └─────────┘ └─────────────┘ │ +└───────────────────────────────┬─────────────────────────────────┘ + │ + observeUncontrolled (state → OL) + controlled + async (OL → state) + │ + ▼ + ┌───────────────────────┐ + │ MapController │ + │ (+ mixin modules) │ + │ ol-proxy │ + └───────────┬───────────┘ + │ + ▼ + ┌───────────────────────┐ + │ OpenLayers │ + │ Map, Layers, View, │ + │ Controls, Sources │ + └───────────────────────┘ +``` + +--- + +## Store creation + +Entry point: `createMapsightStore()` in `packages/core/src/js/index.ts`. + +```typescript +createMapsightStore( + controllers, // { map: MapController, list: ListController, … } + appReducers, // optional extra slices, e.g. { app: mapsightUiAppReducer } + preLoadedState, // initial JSON tree (from preset / CMS / SSR) + appEnhancer, // e.g. redux-thunk for UI +); +``` + +What happens: + +1. **One reducer per controller** — `combineReducers` keys match controller names (`map`, `list`, `featureSources`, …). +2. **Path filtering** — each controller reducer is wrapped with `createFilteredReducerForPath`, so `meta.path[0]` routes actions to the right slice. +3. **Store enhancements** (applied in order): + - `enableAsyncDispatch` — queue actions flagged `MAPSIGHT_ASYNC_ACTION` (dispatch-during-dispatch workaround). + - `enableControlledDispatchAndObserve` — adds `observeUncontrolled` / `subscribeUncontrolled`. + - `batchDispatchMiddleware` — `redux-batched-actions` support. + - `createPrefixedAsyncActionMiddleware` — thunk-like functions flagged as async. +4. **Controller binding** — each controller gets `bindToStore(store)` then `init()` (wires OL listeners). + +The UI package (`@mapsight/ui`) calls this via `create()` in `packages/ui/src/js/index.ts`, supplying default controllers and the `app` reducer. + +--- + +## State shape (top-level slices) + +Default controller keys (`packages/ui/src/js/config/constants/controllers.ts`): + +| Slice key | Controller | Role | +| ------------------- | ----------------------------- | ------------------------------------------------ | +| `map` | `MapController` | Layers, view, controls, interactions, animations | +| `list` | `ListController` | List/query state (mostly path-driven) | +| `featureSources` | `FeatureSourcesController` | GeoJSON data, XHR loading, undo/redo | +| `featureSelections` | `FeatureSelectionsController` | Select / preselect / highlight | +| `tagFilter` | `FilterController` | Tag-based feature filtering | +| `timeFilter` | `FilterController` | Time-based filtering | +| `projections` | `ProjectionsController` | Proj4 definitions | +| `userGeolocation` | `UserGeolocationController` | Geolocation tracking | +| `app` | `mapsightUiAppReducer` | Layout, modals, fetch cache, list UI prefs | + +> **“Dynamic slices” clarification:** You can register multiple instances of the same controller class (e.g. `map` and `map2`) at store creation time. What is dynamic is the **keys inside** each slice (`layers.foo`, `layers.bar`). You cannot add a new top-level slice after the store exists without `injectReducer` (not used today). + +### Example: `map` slice (simplified) + +```typescript +{ + view: { center: […], zoom: 12, resolution: …, rotation: 0 }, + size: [width, height], + layers: { + "base-osm": { + type: "OSM", + options: { visible: true }, + metaData: { title: "…", isBaseLayer: true, group: "base" } + }, + "poi-layer": { + type: "Vector", + options: { + visible: true, + source: { type: "VectorFeatureSource", options: { featureSourceId: "pois" } } + } + } + }, + controls: { … }, + interactions: { … }, + visibleLayers: ["poi-layer", …] +} +``` + +Layer definitions use the **ol-proxy `Description`** shape: `{ type, options?, metaData? }`. Types map to registered OpenLayers constructors in the dependency injector (`packages/core/src/js/ol-proxy`). + +--- + +## Controllers + +`BaseController` (`packages/core/src/js/lib/base/controller.ts`) is the foundation. + +Each controller: + +- Owns **one top-level slice** of state (selected by `state[controllerName]`). +- Exposes `dispatch`, `getState`, `observeUncontrolled`, `getAndObserveUncontrolled`. +- Implements `reduce(state, action)` → runs registered reducers, then **`baseReducer`** (generic path mutations). +- Runs **`init()`** after all controllers are bound — this is where OL sync is wired up. + +### MapController composition + +`MapController` is built from **mixins** copied onto its prototype at module load: + +| Mixin | Responsibility | +| ------------------------- | ----------------------------------------------- | +| `WithMap` | Core `ol/Map`, view sync (center/zoom/rotation) | +| `WithLayers` | Layer create/update/destroy via ol-proxy | +| `WithControls` | OL controls | +| `WithInteractions` | Draw, select, etc. | +| `WithAnimations` | `animate`, fit-to-extent | +| `WithVisibleLayers` | Derived visible layer list | +| `WithSize` | Map container dimensions | +| `WithStyleFunction` | Vector styling | +| `WithFeatureInteractions` | Feature click/hover wiring | +| … | | + +Each mixin’s `init()` registers `getAndObserveUncontrolled` handlers that diff state and call `updateProxyObject`. + +`registerReducer()` allows domain-specific reducer logic inside a controller (e.g. `WithLayers` enforces “only one base layer visible”). + +--- + +## Path-based actions + +Generic mutation API in `packages/core/src/js/lib/base/actions.ts`: + +| Function | Effect | +| --------------------------- | ------------------------------ | +| `set(path, value)` | Replace value at path | +| `merge(path, value)` | Shallow-merge object at path | +| `addTo(path, element)` | Append to array at path | +| `removeFrom(path, element)` | Remove from array at path | +| `unset(path)` | `set(path, undefined)` | +| `setAll` / `mergeAll` / … | Batch variant over object keys | + +Paths are arrays: `["map", "layers", "foo", "options", "visible"]`. + +Actions use generic types: `MAPSIGHT_SET`, `MAPSIGHT_MERGE`, etc. The path lives in `action.meta.path`. + +### Path routing + +`createFilteredReducerForPath(reducer, "map", "path")`: + +- If `action.meta.path[0] === "map"` → strip first segment, pass to reducer. +- Otherwise → ignore (return previous state). + +This lets one action type work across all slices without slice-specific action creators. + +### Immutability + +`baseReducer` delegates to `packages/lib-redux/reducers/immutable-path`, which: + +1. Reads old value at path (`lodash/get`). +2. Applies inner reducer (`set`, `merge`, …). +3. Writes back via `deepChangeState` (clones parent chain, no mutation). + +--- + +## Action flags (meta) + +| Flag | Constant | Purpose | +| ---------- | ---------------------------- | ------------------------------------------------------------------------------------------------------ | +| Controlled | `MAPSIGHT_CONTROLLED_ACTION` | “This update came from OL, don’t sync back to OL.” Skipped by `observeUncontrolled`. | +| Async | `MAPSIGHT_ASYNC_ACTION` | Queue dispatch to avoid dispatch-during-dispatch. Often wraps thunks that dispatch controlled actions. | +| Quiet | `MAPSIGHT_QUIET_ACTION` | Hide from Redux DevTools (high-frequency updates like zoom). | + +Helpers: `controlled(action)`, `async(action)`, `quiet(action)` — recursively applied inside batched actions. + +--- + +## Controlled ↔ uncontrolled sync (the loop breaker) + +**Problem:** State drives OL, but OL events (pan, zoom) must update state. Without a guard, you get: state change → OL update → OL event → state change → … + +**Solution:** + +``` +User / CMS / React OpenLayers + │ │ + │ dispatch(set(…)) │ + │ (uncontrolled) │ + ├──────────────────────────────►│ observeUncontrolled handler + │ │ applies to OL + │ │ + │ │ view 'change:center' + │◄──────────────────────────────┤ + │ dispatch(controlled( │ + │ async(() => set(…)) │ + │ )) │ + │ (controlled — observers │ + │ do NOT fire) │ +``` + +Implementation: `enableControlledDispatchAndObserve` patches `store.dispatch` to remember if the last action was controlled, and only notifies `observeUncontrolled` listeners when it was not. + +**Typical OL → state path** (`WithMap.ts`): + +```typescript +view.on("change:center", () => { + this.dispatch( + async(() => { + this.dispatch(controlled(setViewCenter(name, view.getCenter()))); + }), + ); +}); +``` + +**Typical state → OL path** (`WithLayers.ts`): + +```typescript +this.getAndObserveUncontrolled( + (state) => state.layers, + (newDefs, oldDefs) => { + /* updateProxyObject per layer */ + }, +); +``` + +--- + +## ol-proxy + +`packages/core/src/js/ol-proxy/index.ts` bridges JSON definitions to OpenLayers instances. + +**`updateProxyObject({ oldObject, oldDefinition, newDefinition, adder, remover })`:** + +1. If `newDefinition` is null/undefined → call `remover` (destroy). +2. If type changed or options require reconstruction → create new OL object. +3. Otherwise → `setOptions` to patch existing object. + +The dependency injector (`di`) maps `type: "Vector"` → constructor, `optionMap`, `eventMap`. + +This is the same pattern React uses (declarative description → imperative DOM), but for OpenLayers. + +--- + +## Three action systems (know which to use) + +Mapsight has evolved three coexisting patterns: + +### 1. Path actions (preferred for declarative config) + +```typescript +import { set, merge, mergeAll } from "@mapsight/core/lib/base/actions"; + +mergeAll({ map: { layers: { … } }, featureSources: { … } }); +set(["map", "view", "zoom"], 14); +``` + +**Use for:** CMS JSON, presets, cross-slice bulk updates, anything that should be serializable. + +### 2. Domain actions (imperative GIS operations) + +```typescript +import {LOAD_FEATURE_SOURCE} from "@mapsight/core/lib/feature-sources/actions"; +import { + animate, + fitMapViewToLayerFeature, +} from "@mapsight/core/lib/map/actions"; +``` + +**Use for:** Operations with side effects, typed parameters, or reducer logic that does not fit a simple path set (feature loading, undo/redo, fit-to-feature). + +### 3. App UI actions (layout & chrome) + +```typescript +import {setListVisible, setView} from "@mapsight/ui/store/actions"; +``` + +**Use for:** Panel visibility, breakpoints, list pagination, JSON fetch cache. Lives in the `app` slice. _Candidates for eventual extraction out of GIS Redux._ + +--- + +## Declarative pages / MPA without reload + +The original design goal: load a JSON config and reset the entire application state. + +**Pattern:** + +```typescript +import {resetMapsightCore} from "@mapsight/ui/store/actions"; + +import {mergeAll} from "@mapsight/core/lib/base/actions"; + +// Full reset: clear selections + apply new config tree +store.dispatch(resetMapsightCore(newConfig)); + +// Partial reconfiguration (e.g. router module switch) +store.dispatch(mergeAll({map: moduleMapConfig, featureSources: moduleSources})); +``` + +Real example: Stadtplan router plugin dispatches `mergeAll(base)` on module change (`apps/example/src/js/presets/stadtplan.tsx`). + +**Initial state** is assembled in `create()`: + +```typescript +initialState = merge({}, baseMapsightConfig, {app: uiState}); +// optionally merged with reHydratedState from SSR +``` + +Plugins can further restore from localStorage via `mergeAll` after first render. + +--- + +## React integration + +Minimal by design: + +```tsx +// packages/ui/src/js/components/helping/app-context.tsx + + + +``` + +Components use standard `useSelector` / `useDispatch`. The heavy sync work happens in controllers, not in `useEffect` hooks. + +`create()` returns a `MapsightUiContext` with `store`, `render()`, plugins, and `controllers` — usable from non-React hosts (embed scripts, PHP pages). + +### SSR / hydration + +- Server renders with dehydrated state embedded in the DOM. +- Client `create()` merges `reHydratedState` into `initialState`. +- Plugins (e.g. localStorage) may defer `mergeAll` until after first render to avoid DOM mismatch. + +--- + +## Feature sources & selections (data layer) + +**FeatureSourcesController** is the most complex controller: + +- Loads GeoJSON via XHR (`LOAD_FEATURE_SOURCE` → `LOAD_FEATURE_SOURCE_SUCCESS`). +- Supports undo/redo history per source. +- Can bind external store selectors via `bindFeatureSourceToStore`. +- Mixes domain reducers with path-based `baseReducer`. + +**FeatureSelectionsController** manages select / preselect / highlight state, wired to list and map interactions. + +Layers reference feature data indirectly: + +```typescript +source: { + type: "VectorFeatureSource", + options: { featureSourceId: "pois", featureSourcesControllerName: "featureSources" } +} +``` + +--- + +## Plugins + +`@mapsight/ui` supports a plugin system with lifecycle hooks: + +| Phase | When | +| -------------- | ------------------------------------------------- | +| `afterInit` | Before store creation (can modify `initialState`) | +| `afterCreate` | After store exists (can subscribe, dispatch) | +| `beforeRender` | Can delay render (async data) | +| `afterRender` | Post-first-paint (e.g. localStorage restore) | + +Plugins receive `MapsightUiContext` and are the extension point for app-specific behavior without forking core. + +--- + +## Key files reference + +| Area | Path | +| ------------------- | --------------------------------------------------------------------- | +| Store factory | `packages/core/src/js/index.ts` | +| Path actions | `packages/core/src/js/lib/base/actions.ts` | +| Base reducer | `packages/core/src/js/lib/base/reducer.ts` | +| Base controller | `packages/core/src/js/lib/base/controller.ts` | +| Map controller | `packages/core/src/js/lib/map/controller.ts` | +| Map mixins | `packages/core/src/js/lib/map/lib/With*.ts` | +| ol-proxy | `packages/core/src/js/ol-proxy/index.ts` | +| Controlled observe | `packages/lib-redux/src/js/enable-controlled-dispatch-and-observe.ts` | +| Path filter | `packages/lib-redux/src/js/create-filtered-reducer-for-path.ts` | +| Immutable path | `packages/lib-redux/src/js/reducers/immutable-path/` | +| UI entry | `packages/ui/src/js/index.ts` | +| Default controllers | `packages/ui/src/js/controllers/defaults.ts` | +| App reducer | `packages/ui/src/js/store/reducers.ts` | +| Types (core) | `packages/core/src/js/types.ts` | +| Map state types | `packages/core/src/js/lib/map/types.ts` | + +--- + +## Glossary + +| Term | Meaning | +| ----------------------- | ----------------------------------------------------------------------- | +| **Controller** | Class owning one state slice + OL sync side effects | +| **Description** | JSON `{ type, options?, metaData? }` describing an OL object | +| **Path action** | Generic `MAPSIGHT_SET` etc. with `meta.path` | +| **Controlled action** | OL-originated update; observers skip it | +| **Uncontrolled action** | User/CMS/React update; observers apply to OL | +| **Preset** | App-specific function returning initial state JSON (e.g. `stadtplan()`) | +| **Mixin** | MapController capability module (`WithLayers`, …) | + +--- + +## What this architecture optimizes for + +✅ Serializable, CMS-driven map configuration +✅ Single store for time-travel debugging and SSR +✅ Framework-agnostic GIS core +✅ Multiple map/list instances via named controllers +✅ Bidirectional OL sync without feedback loops + +## What it does not optimize for + +❌ Strict TypeScript path safety (yet) +❌ Minimal Redux boilerplate +❌ Colocating UI state with React components +❌ Runtime-dynamic slice injection + +--- + +_Last updated: June 2026_ From 020a1a514b21b129a2f5b298d868941002d5465d Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:10:18 +0200 Subject: [PATCH 16/49] fix watch/dev process Signed-off-by: Paul Golmann --- apps/demo-next/package.json | 2 +- apps/demo-vite/package.json | 7 ++-- apps/demo-vite/tsconfig.json | 1 + apps/demo-vite/vite.config.ts | 32 ++++++++++++------ apps/vector-editor/package.json | 2 +- configs/eslint-config-base.mts | 1 + configs/tsconfig-vite-node.json | 12 +++++++ configs/vite-workspace-dev.mts | 50 +++++++++++++++++++++++++++++ packages/core/package.json | 2 +- packages/lib-js/package.json | 5 ++- packages/lib-redux/package.json | 5 ++- packages/traffic-style/package.json | 2 +- pnpm-workspace.yaml | 4 +-- 13 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 configs/tsconfig-vite-node.json create mode 100644 configs/vite-workspace-dev.mts diff --git a/apps/demo-next/package.json b/apps/demo-next/package.json index 6c16ff24..5cc96b54 100644 --- a/apps/demo-next/package.json +++ b/apps/demo-next/package.json @@ -24,7 +24,7 @@ "babel-plugin-react-compiler": "1.0.0", "eslint-config-next": "16.2.6", "postcss": "^8.5.14", - "sass": "^1.99.0", + "sass": "^1.100.0", "tailwindcss": "catalog:" }, "license": "UNLICENSED", diff --git a/apps/demo-vite/package.json b/apps/demo-vite/package.json index caa25890..8c9f8cd4 100644 --- a/apps/demo-vite/package.json +++ b/apps/demo-vite/package.json @@ -3,6 +3,7 @@ "description": "Mapsight Demo Vite", "version": "0.0.6", "private": true, + "type": "module", "dependencies": { "@mapsight/core": "workspace:^", "@mapsight/lib-js": "workspace:^", @@ -28,7 +29,7 @@ "@types/react": "catalog:", "@types/react-dom": "catalog:", "terser": "^5.47.1", - "vite": "^8.0.13" + "vite": "^8.0.14" }, "license": "UNLICENSED", "repository": { @@ -45,8 +46,10 @@ "copy:ui": "mkdirp public/img && cp -R node_modules/@mapsight/ui/dist/img/* public/img/", "dev": "npm-run-all --parallel build:mapsightStyle copy --sequential dev:app", "dev:app": "vite", + "dev:linked": "npm-run-all --parallel dev:packages dev", + "dev:packages": "turbo watch watch --filter=@mapsight/core --filter=@mapsight/ui --filter=@mapsight/lib-js --filter=@mapsight/lib-ol --filter=@mapsight/lib-redux", "lint": "eslint", "start": "vite preview", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.node.json" } } diff --git a/apps/demo-vite/tsconfig.json b/apps/demo-vite/tsconfig.json index e42fb59e..f8a15dc1 100644 --- a/apps/demo-vite/tsconfig.json +++ b/apps/demo-vite/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../configs/tsconfig-base-app.json", "include": ["src/**/*"], + "references": [{"path": "./tsconfig.node.json"}], "compilerOptions": { "types": ["@types/node"] } diff --git a/apps/demo-vite/vite.config.ts b/apps/demo-vite/vite.config.ts index bbd65b80..9984e1e2 100644 --- a/apps/demo-vite/vite.config.ts +++ b/apps/demo-vite/vite.config.ts @@ -3,9 +3,26 @@ import {join} from "node:path"; import tailwindcss from "@tailwindcss/vite"; import {defineConfig} from "vite"; -export default defineConfig({ +import { + createWorkspaceDevAliases, + workspacePackages, +} from "../../configs/vite-workspace-dev.mts"; + +export default defineConfig(({command}) => ({ root: "src", publicDir: "../public", + resolve: { + alias: [ + ...(command === "serve" ? createWorkspaceDevAliases() : []), + { + find: /~(.+)/, + replacement: join(process.cwd(), "node_modules/$1"), + }, + ], + }, + optimizeDeps: { + exclude: [...workspacePackages], + }, build: { outDir: "../dist", emptyOutDir: true, @@ -38,13 +55,10 @@ export default defineConfig({ }, }, }, - resolve: { - alias: [ - { - find: /~(.+)/, - replacement: join(process.cwd(), "node_modules/$1"), - }, - ], + server: { + watch: { + ignored: ["**/node_modules/**", "!**/node_modules/@mapsight/**"], + }, }, plugins: [tailwindcss()], css: { @@ -56,4 +70,4 @@ export default defineConfig({ }, }, }, -}); +})); diff --git a/apps/vector-editor/package.json b/apps/vector-editor/package.json index 0618dcb3..6010141e 100644 --- a/apps/vector-editor/package.json +++ b/apps/vector-editor/package.json @@ -35,7 +35,7 @@ "autoprefixer": "^10.5.0", "postcss-import": "^16.1.1", "postcss-nested": "^7.0.2", - "vite": "^8.0.13" + "vite": "^8.0.14" }, "license": "UNLICENSED", "repository": { diff --git a/configs/eslint-config-base.mts b/configs/eslint-config-base.mts index 9af7b058..4cf09d03 100644 --- a/configs/eslint-config-base.mts +++ b/configs/eslint-config-base.mts @@ -32,6 +32,7 @@ export default defineConfig([ "eslint.config.mts", "gulpfile.mts", "vite.config.ts", + "vite.config.mts", "prettier.config.mjs", "postcss.config.mts", ], diff --git a/configs/tsconfig-vite-node.json b/configs/tsconfig-vite-node.json new file mode 100644 index 00000000..1658c3b8 --- /dev/null +++ b/configs/tsconfig-vite-node.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./tsconfig-base.json", + "compilerOptions": { + "composite": true, + "noEmit": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"], + "lib": ["ES2024"] + } +} diff --git a/configs/vite-workspace-dev.mts b/configs/vite-workspace-dev.mts new file mode 100644 index 00000000..876ccd5c --- /dev/null +++ b/configs/vite-workspace-dev.mts @@ -0,0 +1,50 @@ +import path from "node:path"; +import {fileURLToPath} from "node:url"; + +export type WorkspaceDevAlias = { + find: string | RegExp; + replacement: string; +}; + +const configDir = path.dirname(fileURLToPath(import.meta.url)); +export const repoRoot = path.resolve(configDir, ".."); + +/** Workspace packages resolved from source during Vite dev (serve). */ +export const workspacePackages = [ + "@mapsight/core", + "@mapsight/ui", + "@mapsight/lib-js", + "@mapsight/lib-ol", + "@mapsight/lib-redux", +] as const; + +const packageSourceRoots = { + "@mapsight/core": path.join(repoRoot, "packages/core/src/js"), + "@mapsight/ui": path.join(repoRoot, "packages/ui/src/js"), + "@mapsight/lib-js": path.join(repoRoot, "packages/lib-js/src/js"), + "@mapsight/lib-ol": path.join(repoRoot, "packages/lib-ol/src/js"), + "@mapsight/lib-redux": path.join(repoRoot, "packages/lib-redux/src/js"), +} as const; + +/** + * Resolve workspace packages from TypeScript source in dev. + * + * - Skips the tsc → dist roundtrip for HMR on package changes. + * - `@/` maps to core source (@mapsight/core's tsconfig paths). Only core uses + * it today; ui can adopt `@mapsight/ui/...` package-style imports internally + * instead of adding a second `@/` alias. + */ +export function createWorkspaceDevAliases(): WorkspaceDevAlias[] { + const coreSourceRoot = packageSourceRoots["@mapsight/core"]; + + return [ + { + find: /^@\/(.*)$/, + replacement: path.join(coreSourceRoot, "$1"), + }, + ...workspacePackages.map((name) => ({ + find: name, + replacement: packageSourceRoots[name], + })), + ]; +} diff --git a/packages/core/package.json b/packages/core/package.json index 9405496b..c07870a3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -93,7 +93,7 @@ "typecheck": "tsc --noEmit", "watch": "run-s build:modules watch:build", "watch:build": "run-p watch:build:modules watch:build:paths", - "watch:build:modules": "tsc --watch", + "watch:build:modules": "tsc --watch --preserveWatchOutput", "watch:build:paths": "tsc-alias --watch" } } diff --git a/packages/lib-js/package.json b/packages/lib-js/package.json index 3a0b9f63..66674e92 100644 --- a/packages/lib-js/package.json +++ b/packages/lib-js/package.json @@ -27,8 +27,7 @@ "lint": "eslint", "test": "vitest run", "typecheck": "tsc --noEmit", - "watch": "run-p watch:*", - "watch:cjs": "pnpm run build:cjs --watch", - "watch:esm": "pnpm run build:esm --watch" + "watch": "run-s build watch:build", + "watch:build": "tsc --project tsconfig.build.json --outDir dist --watch" } } diff --git a/packages/lib-redux/package.json b/packages/lib-redux/package.json index 1aa481ed..d88dc809 100644 --- a/packages/lib-redux/package.json +++ b/packages/lib-redux/package.json @@ -43,8 +43,7 @@ "clean": "rimraf dist/*", "clean-build": "run-s clean build", "typecheck": "tsc --noEmit", - "watch": "run-p watch:*", - "watch:copy": "pnpm run build:copy --watch", - "watch:modules": "pnpm run build:modules --watch" + "watch": "run-s build:setup build:modules watch:build", + "watch:build": "tsc --watch" } } diff --git a/packages/traffic-style/package.json b/packages/traffic-style/package.json index c81ef471..0086051d 100644 --- a/packages/traffic-style/package.json +++ b/packages/traffic-style/package.json @@ -52,7 +52,7 @@ "clean": "rimraf tmp/* dist/*", "clean-build": "run-s clean build", "copy": "run-p copy:src copy:misc", - "copy:misc": "cp package.json README.md *.scss dist/", + "copy:misc": "rimraf dist/*.scss; cp package.json README.md *.scss dist/", "copy:src": "mkdirp dist/src; cp -r src/scss dist/src/", "lint": "eslint scripts", "typecheck": "tsc --noEmit", diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 59147055..7a0972ad 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,7 +12,7 @@ catalog: "@types/jsdom": "^28.0.3" "@types/lodash": "^4.17.24" "@types/node": "^24.12.4" - "@types/react": "^19.2.14" + "@types/react": "^19.2.15" "@types/react-dom": "^19.2.3" "@types/react-redux": "^7.1.34" "jsdom": "^29.1.1" @@ -23,7 +23,7 @@ catalog: "proj4": "^2.20.8" "react": "^19.2.6" "react-dom": "^19.2.6" - "react-redux": "^9.2.0" + "react-redux": "^9.3.0" "redux": "^5.0.1" "redux-batched-actions": "^0.5.0" "redux-thunk": "^3.1.0" From 24d222db90f8870e739130683f2c02542c2a5439 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:23:19 +0200 Subject: [PATCH 17/49] vsc: actually fix source map comment Signed-off-by: Paul Golmann --- packages/vector-style-compiler/package.json | 4 ++-- packages/vector-style-compiler/src/js/template.ts | 5 +++-- packages/vector-style-compiler/tsconfig.build.json | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/vector-style-compiler/package.json b/packages/vector-style-compiler/package.json index e21558e6..f3801346 100644 --- a/packages/vector-style-compiler/package.json +++ b/packages/vector-style-compiler/package.json @@ -52,7 +52,7 @@ }, "scripts": { "bench": "node __tests__/performance.engines.bench.ts", - "build": "run-s build:setup build:modules", + "build": "run-s build:setup build:modules copy:templates", "build:modules": "tsc -p tsconfig.build.json", "build:setup": "mkdirp dist", "clean": "rimraf dist", @@ -64,7 +64,7 @@ "test": "vitest run", "typecheck": "tsc --noEmit", "update-readme": "node scripts/update-readme.mts", - "watch": "tsc -p tsconfig.build.json --watch" + "watch": "run-s copy:templates \"tsc -p tsconfig.build.json --watch\"" }, "types": "./dist/index.d.ts" } diff --git a/packages/vector-style-compiler/src/js/template.ts b/packages/vector-style-compiler/src/js/template.ts index 57a461d7..e0f7c622 100644 --- a/packages/vector-style-compiler/src/js/template.ts +++ b/packages/vector-style-compiler/src/js/template.ts @@ -44,8 +44,9 @@ const defaultTemplate = ({__meta, program1, program2}: TemplateArgs) => { result = replaceTag(result, "program1", program1); result = replaceTag(result, "program2", program2); - // Remove any source map comments - result = result.replace(/\/\/# sourceMappingURL=.*\n/g, ""); + // Strip source map comments injected by tsc or other tooling. + result = result.replace(/\/\/# sourceMappingURL=[^\n]*/g, ""); + result = result.replace(/\/\*# sourceMappingURL=[^*]*\*\//g, ""); return result; }; diff --git a/packages/vector-style-compiler/tsconfig.build.json b/packages/vector-style-compiler/tsconfig.build.json index 2dae871e..ec52f276 100644 --- a/packages/vector-style-compiler/tsconfig.build.json +++ b/packages/vector-style-compiler/tsconfig.build.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "./tsconfig.json", "include": ["src/js/**/*"], + "exclude": ["src/js/template.source.js"], "compilerOptions": { "outDir": "dist", "rootDir": "src/js" From c2578dc5407559128e8be55912b693330be8c389 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:23:30 +0200 Subject: [PATCH 18/49] vsc: update test snapshot Signed-off-by: Paul Golmann --- .../__snapshots__/compiler.test.ts.snap | 188 +++++++++--------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/packages/vector-style-compiler/__tests__/__snapshots__/compiler.test.ts.snap b/packages/vector-style-compiler/__tests__/__snapshots__/compiler.test.ts.snap index d43d50a9..ff87213f 100644 --- a/packages/vector-style-compiler/__tests__/__snapshots__/compiler.test.ts.snap +++ b/packages/vector-style-compiler/__tests__/__snapshots__/compiler.test.ts.snap @@ -76,27 +76,27 @@ style: __vectorStyle_style,}, { - const $a = /* @__PURE__ */props['test']; - const $b = /* @__PURE__ */get(props, ['path', 'to', 'test']); - const $c = /* @__PURE__ */props['state']; - const $d = /* @__PURE__ */$c == 'someState'; - const $e = /* @__PURE__ */$c == 'anotherState'; - const $f = /* @__PURE__ */props['attr']; - const $g = /* @__PURE__ */$f == 'test'; - const $h = /* @__PURE__ */props['hasAttrTest']; - const $i = /* @__PURE__ */$h; - const $j = /* @__PURE__ */$f == 123; - const $k = /* @__PURE__ */$f == 456; - const $l = /* @__PURE__ */get(props, ['parking', 'capacity']); - const $m = /* @__PURE__ */$l == 'tests nested properites'; - const $n = /* @__PURE__ */env['zoom']; - const $o = /* @__PURE__ */$n == 2; - const $p = /* @__PURE__ */geometryType == 'Point'; - const $q = /* @__PURE__ */geometryType == 'LineString'; - const $r = /* @__PURE__ */geometryType == 'Polygon'; - const $s = /* @__PURE__ */23 > 42; - const $t = /* @__PURE__ */env.zoom >= 1 && env.zoom <= 10; - const $u = /* @__PURE__ */$f; + const $a = props['test']; + const $b = get(props, ['path', 'to', 'test']); + const $c = props['state']; + const $d = $c/* props['state'] */ == 'someState'; + const $e = $c/* props['state'] */ == 'anotherState'; + const $f = props['attr']; + const $g = $f/* props['attr'] */ == 'test'; + const $h = props['hasAttrTest']; + const $i = $h/* props['hasAttrTest'] */; + const $j = $f/* props['attr'] */ == 123; + const $k = $f/* props['attr'] */ == 456; + const $l = get(props, ['parking', 'capacity']); + const $m = $l/* get(props, ['parking', 'capacity']) */ == 'tests nested properites'; + const $n = env['zoom']; + const $o = $n/* env['zoom'] */ == 2; + const $p = geometryType == 'Point'; + const $q = geometryType == 'LineString'; + const $r = geometryType == 'Polygon'; + const $s = 23 > 42; + const $t = env.zoom >= 1 && env.zoom <= 10; + const $u = $f/* props['attr'] */; h(1); h('@' + createHash($a)); @@ -179,8 +179,8 @@ style: __vectorStyle_style,}, break; case 'features': { - const $a = /* @__PURE__ */props['attr']; - const $b = /* @__PURE__ */$a == 'test'; + const $a = props['attr']; + const $b = $a/* props['attr'] */ == 'test'; h(26); if ($b) { @@ -198,25 +198,25 @@ style: __vectorStyle_style,}, { - const $a = /* @__PURE__ */props['state']; - const $b = /* @__PURE__ */$a == 'someState'; - const $c = /* @__PURE__ */$a == 'anotherState'; - const $d = /* @__PURE__ */props['attr']; - const $e = /* @__PURE__ */$d == 'test'; - const $f = /* @__PURE__ */props['hasAttrTest']; - const $g = /* @__PURE__ */$f; - const $h = /* @__PURE__ */$d == 123; - const $i = /* @__PURE__ */$d == 456; - const $j = /* @__PURE__ */get(props, ['parking', 'capacity']); - const $k = /* @__PURE__ */$j == 'tests nested properites'; - const $l = /* @__PURE__ */env['zoom']; - const $m = /* @__PURE__ */$l == 2; - const $n = /* @__PURE__ */geometryType == 'Point'; - const $o = /* @__PURE__ */geometryType == 'LineString'; - const $p = /* @__PURE__ */geometryType == 'Polygon'; - const $q = /* @__PURE__ */23 > 42; - const $r = /* @__PURE__ */env.zoom >= 1 && env.zoom <= 10; - const $s = /* @__PURE__ */$d; + const $a = props['state']; + const $b = $a/* props['state'] */ == 'someState'; + const $c = $a/* props['state'] */ == 'anotherState'; + const $d = props['attr']; + const $e = $d/* props['attr'] */ == 'test'; + const $f = props['hasAttrTest']; + const $g = $f/* props['hasAttrTest'] */; + const $h = $d/* props['attr'] */ == 123; + const $i = $d/* props['attr'] */ == 456; + const $j = get(props, ['parking', 'capacity']); + const $k = $j/* get(props, ['parking', 'capacity']) */ == 'tests nested properites'; + const $l = env['zoom']; + const $m = $l/* env['zoom'] */ == 2; + const $n = geometryType == 'Point'; + const $o = geometryType == 'LineString'; + const $p = geometryType == 'Polygon'; + const $q = 23 > 42; + const $r = env.zoom >= 1 && env.zoom <= 10; + const $s = $d/* props['attr'] */; const _default = ( d.default ??= {}); @@ -384,8 +384,8 @@ style: __vectorStyle_style,}, break; case 'features': { - const $a = /* @__PURE__ */props['attr']; - const $b = /* @__PURE__ */$a == 'test'; + const $a = props['attr']; + const $b = $a/* props['attr'] */ == 'test'; const _default = ( d.default ??= {}); @@ -414,25 +414,25 @@ export default createCachedStyleFunction(styleOptions); exports[`parses and transforms full css to declaration program correctly 1`] = ` " { -const $a = /* @__PURE__ */props['state']; -const $b = /* @__PURE__ */$a == 'someState'; -const $c = /* @__PURE__ */$a == 'anotherState'; -const $d = /* @__PURE__ */props['attr']; -const $e = /* @__PURE__ */$d == 'test'; -const $f = /* @__PURE__ */props['hasAttrTest']; -const $g = /* @__PURE__ */$f; -const $h = /* @__PURE__ */$d == 123; -const $i = /* @__PURE__ */$d == 456; -const $j = /* @__PURE__ */get(props, ['parking', 'capacity']); -const $k = /* @__PURE__ */$j == 'tests nested properites'; -const $l = /* @__PURE__ */env['zoom']; -const $m = /* @__PURE__ */$l == 2; -const $n = /* @__PURE__ */geometryType == 'Point'; -const $o = /* @__PURE__ */geometryType == 'LineString'; -const $p = /* @__PURE__ */geometryType == 'Polygon'; -const $q = /* @__PURE__ */23 > 42; -const $r = /* @__PURE__ */env.zoom >= 1 && env.zoom <= 10; -const $s = /* @__PURE__ */$d; +const $a = props['state']; +const $b = $a/* props['state'] */ == 'someState'; +const $c = $a/* props['state'] */ == 'anotherState'; +const $d = props['attr']; +const $e = $d/* props['attr'] */ == 'test'; +const $f = props['hasAttrTest']; +const $g = $f/* props['hasAttrTest'] */; +const $h = $d/* props['attr'] */ == 123; +const $i = $d/* props['attr'] */ == 456; +const $j = get(props, ['parking', 'capacity']); +const $k = $j/* get(props, ['parking', 'capacity']) */ == 'tests nested properites'; +const $l = env['zoom']; +const $m = $l/* env['zoom'] */ == 2; +const $n = geometryType == 'Point'; +const $o = geometryType == 'LineString'; +const $p = geometryType == 'Polygon'; +const $q = 23 > 42; +const $r = env.zoom >= 1 && env.zoom <= 10; +const $s = $d/* props['attr'] */; const _default = ( d.default ??= {}); @@ -600,8 +600,8 @@ switch (style) { break; case 'features': { - const $a = /* @__PURE__ */props['attr']; - const $b = /* @__PURE__ */$a == 'test'; + const $a = props['attr']; + const $b = $a/* props['attr'] */ == 'test'; const _default = ( d.default ??= {}); @@ -623,27 +623,27 @@ switch (style) { exports[`parses and transforms full css to hash program correctly 1`] = ` " { -const $a = /* @__PURE__ */props['test']; -const $b = /* @__PURE__ */get(props, ['path', 'to', 'test']); -const $c = /* @__PURE__ */props['state']; -const $d = /* @__PURE__ */$c == 'someState'; -const $e = /* @__PURE__ */$c == 'anotherState'; -const $f = /* @__PURE__ */props['attr']; -const $g = /* @__PURE__ */$f == 'test'; -const $h = /* @__PURE__ */props['hasAttrTest']; -const $i = /* @__PURE__ */$h; -const $j = /* @__PURE__ */$f == 123; -const $k = /* @__PURE__ */$f == 456; -const $l = /* @__PURE__ */get(props, ['parking', 'capacity']); -const $m = /* @__PURE__ */$l == 'tests nested properites'; -const $n = /* @__PURE__ */env['zoom']; -const $o = /* @__PURE__ */$n == 2; -const $p = /* @__PURE__ */geometryType == 'Point'; -const $q = /* @__PURE__ */geometryType == 'LineString'; -const $r = /* @__PURE__ */geometryType == 'Polygon'; -const $s = /* @__PURE__ */23 > 42; -const $t = /* @__PURE__ */env.zoom >= 1 && env.zoom <= 10; -const $u = /* @__PURE__ */$f; +const $a = props['test']; +const $b = get(props, ['path', 'to', 'test']); +const $c = props['state']; +const $d = $c/* props['state'] */ == 'someState'; +const $e = $c/* props['state'] */ == 'anotherState'; +const $f = props['attr']; +const $g = $f/* props['attr'] */ == 'test'; +const $h = props['hasAttrTest']; +const $i = $h/* props['hasAttrTest'] */; +const $j = $f/* props['attr'] */ == 123; +const $k = $f/* props['attr'] */ == 456; +const $l = get(props, ['parking', 'capacity']); +const $m = $l/* get(props, ['parking', 'capacity']) */ == 'tests nested properites'; +const $n = env['zoom']; +const $o = $n/* env['zoom'] */ == 2; +const $p = geometryType == 'Point'; +const $q = geometryType == 'LineString'; +const $r = geometryType == 'Polygon'; +const $s = 23 > 42; +const $t = env.zoom >= 1 && env.zoom <= 10; +const $u = $f/* props['attr'] */; h(1); h('@' + createHash($a)); @@ -726,8 +726,8 @@ switch (style) { break; case 'features': { - const $a = /* @__PURE__ */props['attr']; - const $b = /* @__PURE__ */$a == 'test'; + const $a = props['attr']; + const $b = $a/* props['attr'] */ == 'test'; h(26); if ($b) { @@ -2760,9 +2760,9 @@ switch (style) { switch (state) { case 'myStateName': { - const $a = /* @__PURE__ */props['state']; - const $b = /* @__PURE__ */$a == selected; - const $c = /* @__PURE__ */geometryType == 'LineString'; + const $a = props['state']; + const $b = $a/* props['state'] */ == selected; + const $c = geometryType == 'LineString'; if ($b) { const _default = ( @@ -2792,9 +2792,9 @@ switch (style) { switch (state) { case 'myStateName': { - const $a = /* @__PURE__ */props['state']; - const $b = /* @__PURE__ */$a == selected; - const $c = /* @__PURE__ */geometryType == 'LineString'; + const $a = props['state']; + const $b = $a/* props['state'] */ == selected; + const $c = geometryType == 'LineString'; if ($b) { h(1); From 1654182bcb9ff0024446f38462afa6c08bdd8768 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:24:24 +0200 Subject: [PATCH 19/49] ui: use caching to optimize tag selector performance Signed-off-by: Paul Golmann --- packages/ui/src/js/store/selectors.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/js/store/selectors.ts b/packages/ui/src/js/store/selectors.ts index a3fdea57..a8fdc639 100644 --- a/packages/ui/src/js/store/selectors.ts +++ b/packages/ui/src/js/store/selectors.ts @@ -240,6 +240,12 @@ export const tagSwitcherFeatureSourceIdSelector = (state: RootStateSlice) => export const tagSwitcherFeatureSourcesControllerNameSelector = ( state: RootStateSlice, ) => state.app.tagSwitcher?.featureSourcesControllerName; + +let tagSwitcherTagsCachedKey: string | undefined; +let tagSwitcherTagsCachedSelector: ReturnType< + typeof createTagsWithCountFromFeatureSourceSelector +>; + export const tagSwitcherTagsSelector = (state: RootStateSlice) => { const controllerName = tagSwitcherFeatureSourcesControllerNameSelector(state); @@ -248,10 +254,17 @@ export const tagSwitcherTagsSelector = (state: RootStateSlice) => { return {}; } - return createTagsWithCountFromFeatureSourceSelector( - controllerName, - featureSourceId, - )(state); + const key = `${controllerName}:${featureSourceId}`; + if (key !== tagSwitcherTagsCachedKey) { + tagSwitcherTagsCachedKey = key; + tagSwitcherTagsCachedSelector = + createTagsWithCountFromFeatureSourceSelector( + controllerName, + featureSourceId, + ); + } + + return tagSwitcherTagsCachedSelector(state); }; export const viewToggleShowSelector = (state: RootStateSlice) => From 21b576dfba5789c9851b67ab4cb1c89410cecb19 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:24:51 +0200 Subject: [PATCH 20/49] lib-js: add shallowEqualRecords Signed-off-by: Paul Golmann --- .../src/js/object/shallowEqualRecords.spec.ts | 32 +++++++++++++++++++ .../src/js/object/shallowEqualRecords.ts | 19 +++++++++++ 2 files changed, 51 insertions(+) create mode 100644 packages/lib-js/src/js/object/shallowEqualRecords.spec.ts create mode 100644 packages/lib-js/src/js/object/shallowEqualRecords.ts diff --git a/packages/lib-js/src/js/object/shallowEqualRecords.spec.ts b/packages/lib-js/src/js/object/shallowEqualRecords.spec.ts new file mode 100644 index 00000000..fc473dae --- /dev/null +++ b/packages/lib-js/src/js/object/shallowEqualRecords.spec.ts @@ -0,0 +1,32 @@ +import {strictEqual} from "assert"; + +import {describe, it} from "vitest"; + +import shallowEqualRecords from "./shallowEqualRecords.ts"; + +describe("shallowEqualRecords", () => { + it("returns true for the same reference", () => { + const record = {a: "1", b: "2"}; + strictEqual(shallowEqualRecords(record, record), true); + }); + + it("returns true for equal values with different references", () => { + strictEqual( + shallowEqualRecords({a: "1", b: "2"}, {a: "1", b: "2"}), + true, + ); + }); + + it("returns false when values differ", () => { + strictEqual(shallowEqualRecords({a: "1"}, {a: "2"}), false); + }); + + it("returns false when keys differ", () => { + strictEqual(shallowEqualRecords({a: "1"}, {a: "1", b: "2"}), false); + }); + + it("returns false when one side is undefined", () => { + strictEqual(shallowEqualRecords({a: "1"}, undefined), false); + strictEqual(shallowEqualRecords(undefined, undefined), true); + }); +}); diff --git a/packages/lib-js/src/js/object/shallowEqualRecords.ts b/packages/lib-js/src/js/object/shallowEqualRecords.ts new file mode 100644 index 00000000..6d7f7593 --- /dev/null +++ b/packages/lib-js/src/js/object/shallowEqualRecords.ts @@ -0,0 +1,19 @@ +export default function shallowEqualRecords>( + a: T | undefined, + b: T | undefined, +): boolean { + if (a === b) { + return true; + } + if (!a || !b) { + return false; + } + + const keysA = Object.keys(a); + const keysB = Object.keys(b); + if (keysA.length !== keysB.length) { + return false; + } + + return keysA.every((key) => a[key] === b[key]); +} From 63541d97c025eef4d7b81a63143a79918c5f4ed7 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:25:50 +0200 Subject: [PATCH 21/49] core: feature sources - fix empty filter handling in selector Signed-off-by: Paul Golmann --- packages/core/src/js/lib/feature-sources/selectors.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/core/src/js/lib/feature-sources/selectors.ts b/packages/core/src/js/lib/feature-sources/selectors.ts index d8781f64..b3a9d21c 100644 --- a/packages/core/src/js/lib/feature-sources/selectors.ts +++ b/packages/core/src/js/lib/feature-sources/selectors.ts @@ -1,6 +1,8 @@ import type {Selector} from "@reduxjs/toolkit"; import {createSelector} from "@reduxjs/toolkit"; +import shallowEqualRecords from "@mapsight/lib-js/object/shallowEqualRecords"; + import type { FeatureSourceData, FeatureSourceState, @@ -119,6 +121,8 @@ type FilteredFeatureSourceSelectorCache = { state?: FeatureSourceState; }; +const EMPTY_FILTERS: Record = {}; + export function createFilteredFeatureSourceSelector( featureSourcesControllerName: string, featureSourceId: string, @@ -128,7 +132,8 @@ export function createFilteredFeatureSourceSelector( featureSourcesControllerName, featureSourceId, ); - let filtersSelector: Selector> = () => ({}); + let filtersSelector: Selector> = () => + EMPTY_FILTERS; // internal state holding const cache: FilteredFeatureSourceSelectorCache = {}; @@ -175,7 +180,7 @@ export function createFilteredFeatureSourceSelector( } const filters = filtersSelector(state); - if (filters !== cache.filters) { + if (!shallowEqualRecords(filters, cache.filters)) { cache.filters = filters; hasChanged = true; } From fff3209ff87a569d97ec9905bd40b5f7f8285586 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:26:13 +0200 Subject: [PATCH 22/49] ui: map wrapper: add back anchoring, remove memo Signed-off-by: Paul Golmann --- packages/ui/src/js/components/map-wrapper.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/js/components/map-wrapper.tsx b/packages/ui/src/js/components/map-wrapper.tsx index a909692d..73961653 100644 --- a/packages/ui/src/js/components/map-wrapper.tsx +++ b/packages/ui/src/js/components/map-wrapper.tsx @@ -1,5 +1,5 @@ import type {PropsWithChildren, RefCallback} from "react"; -import {memo, useCallback, useRef} from "react"; +import {useCallback, useRef} from "react"; import {useInView} from "react-intersection-observer"; import {useDispatch, useSelector, useStore} from "react-redux"; @@ -13,8 +13,10 @@ import { useAppChannelEventListener, } from "./helping/app-channel"; -function MapWrapper(props: PropsWithChildren) { - const {children} = props; +export default function MapWrapper( + props: PropsWithChildren<{anchor?: "right" | "bottom"}>, +) { + const {children, anchor} = props; const dispatch = useDispatch(); const mapWrapperRef = useRef(undefined); @@ -54,12 +56,9 @@ function MapWrapper(props: PropsWithChildren) { return (
{children}
); } - -export default memo(MapWrapper); From 6157995c718df874194907495cdd16f2a5197c3e Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:39:42 +0200 Subject: [PATCH 23/49] core: Use `quiet()` on noisy OL feedback actions Signed-off-by: Paul Golmann --- .../js/lib/map/lib/WithFeatureInteractions.ts | 27 ++++++++++++++--- packages/core/src/js/lib/map/lib/WithMap.ts | 30 ++++++++++++------- packages/core/src/js/lib/map/lib/WithSize.ts | 6 ++-- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts index 5a96d01b..50a550ba 100644 --- a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts +++ b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts @@ -6,6 +6,7 @@ import {batchActions} from "redux-batched-actions"; import {ensureNonNullable} from "@mapsight/lib-js/nonNullable"; +import {quiet} from "@/lib/base/actions"; import { deselect, select, @@ -66,6 +67,11 @@ const FEATURE_PROPERTY_NAME_SELECTABLE = "selectable"; // TODO: Keep default? const defaultFeatureSelectionsControllerName = "featureSelections"; +const HIGHLIGHT_SELECTION_ID = "highlight"; + +function quietIfHighlight(action: Action, selectionId: string) { + return selectionId === HIGHLIGHT_SELECTION_ID ? quiet(action) : action; +} // TODO: Support button_s_? // See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button @@ -332,7 +338,10 @@ function handleEvent( if (shouldBeAdded) { hasAdded = true; actions.push( - selectAction(featureSelectionsControllerName, s, f), + quietIfHighlight( + selectAction(featureSelectionsControllerName, s, f), + s, + ), ); } }); @@ -345,7 +354,12 @@ function handleEvent( // Determine if the cached feature selection is invalid by comparing with new selection const shouldBeRemoved = newSelections[s] !== f; if (shouldBeRemoved) { - actions.push(deselect(featureSelectionsControllerName, s, f)); + actions.push( + quietIfHighlight( + deselect(featureSelectionsControllerName, s, f), + s, + ), + ); } }); } @@ -366,7 +380,10 @@ function handleEvent( ) .forEach((f) => actions.push( - deselect(featureSelectionsControllerName, s, f), + quietIfHighlight( + deselect(featureSelectionsControllerName, s, f), + s, + ), ), ); }); @@ -383,7 +400,9 @@ function handleEvent( } if (!cache || newCursor !== cache.cursor) { - cursorAction = setMapCursor(mapController.getName(), newCursor); + cursorAction = quiet( + setMapCursor(mapController.getName(), newCursor), + ); } } diff --git a/packages/core/src/js/lib/map/lib/WithMap.ts b/packages/core/src/js/lib/map/lib/WithMap.ts index b6f43cb5..5ccd0d7e 100644 --- a/packages/core/src/js/lib/map/lib/WithMap.ts +++ b/packages/core/src/js/lib/map/lib/WithMap.ts @@ -8,7 +8,7 @@ import {di, setOptions, updateProxyObject} from "@/ol-proxy"; import Map from "@/ol-proxy/definitions/Map"; import View from "@/ol-proxy/definitions/View"; -import {async, controlled} from "../../base/actions"; +import {async, controlled, quiet} from "../../base/actions"; import {BaseController} from "../../base/controller"; import { setViewCenter, @@ -81,11 +81,13 @@ export default class WithMap extends BaseController { const resolution = view?.getResolution(); if (zoom && resolution) { this.dispatch( - controlled( - setViewZoomAndResolution( - name, - zoom, - resolution, + quiet( + controlled( + setViewZoomAndResolution( + name, + zoom, + resolution, + ), ), ), ); @@ -100,8 +102,10 @@ export default class WithMap extends BaseController { const center = view?.getCenter(); if (center) { this.dispatch( - controlled( - setViewCenter(name, center), + quiet( + controlled( + setViewCenter(name, center), + ), ), ); } @@ -115,8 +119,13 @@ export default class WithMap extends BaseController { const rotation = view?.getRotation(); if (rotation) { this.dispatch( - controlled( - setViewRotation(name, rotation), + quiet( + controlled( + setViewRotation( + name, + rotation, + ), + ), ), ); } @@ -158,7 +167,6 @@ export default class WithMap extends BaseController { ); this._map = map; - console.log("added map", this); //updateSizeOnTransitionEnd(map); //canvasSizeFixer(map); diff --git a/packages/core/src/js/lib/map/lib/WithSize.ts b/packages/core/src/js/lib/map/lib/WithSize.ts index 68b83e01..0866dd00 100644 --- a/packages/core/src/js/lib/map/lib/WithSize.ts +++ b/packages/core/src/js/lib/map/lib/WithSize.ts @@ -1,4 +1,4 @@ -import {async, controlled, set} from "../../base/actions"; +import {async, controlled, quiet, set} from "../../base/actions"; import WithMap from "./WithMap"; export default class WithSize extends WithMap { @@ -19,7 +19,9 @@ export default class WithSize extends WithMap { oldValue[0] !== newValue[0] || oldValue[1] !== newValue[1]) ) { - this.dispatch(controlled(async(set([name, "size"], newValue)))); + this.dispatch( + quiet(controlled(async(set([name, "size"], newValue)))), + ); } }); } From 438c714f5487ae274a4912a9941a092e85239ebe Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:40:53 +0200 Subject: [PATCH 24/49] tsconfig: fix vite node config (conflicting noEmit and composite options) Signed-off-by: Paul Golmann --- configs/tsconfig-vite-node.json | 1 - 1 file changed, 1 deletion(-) diff --git a/configs/tsconfig-vite-node.json b/configs/tsconfig-vite-node.json index 1658c3b8..a50f1c7a 100644 --- a/configs/tsconfig-vite-node.json +++ b/configs/tsconfig-vite-node.json @@ -3,7 +3,6 @@ "extends": "./tsconfig-base.json", "compilerOptions": { "composite": true, - "noEmit": true, "module": "ESNext", "moduleResolution": "Bundler", "types": ["node"], From b8cdee030321a3895119144e6337f528854271ea Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 16:46:32 +0200 Subject: [PATCH 25/49] docs: add guide for different action types Signed-off-by: Paul Golmann --- docs/MAPSIGHT_ACTION_GUIDE.md | 256 ++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 docs/MAPSIGHT_ACTION_GUIDE.md diff --git a/docs/MAPSIGHT_ACTION_GUIDE.md b/docs/MAPSIGHT_ACTION_GUIDE.md new file mode 100644 index 00000000..4653952f --- /dev/null +++ b/docs/MAPSIGHT_ACTION_GUIDE.md @@ -0,0 +1,256 @@ +# Mapsight Action API — Decision Guide + +> **Context:** [MAPSIGHT_REDUX_ARCHITECTURE.md](./MAPSIGHT_REDUX_ARCHITECTURE.md) explains how the store, controllers, and path routing work. This guide answers a narrower question: _which action API do I dispatch for a given task?_ + +Mapsight has three coexisting action systems. Pick the one that matches your intent — not whichever import is closest. + +--- + +## Quick reference + +| I want to… | Use | +| --------------------------- | ---------------------------------------------------------- | +| Apply CMS / preset JSON | `mergeAll`, `set`, `resetMapsightCore` | +| Switch entire view/module | `resetMapsightCore` | +| Animate map, fit to feature | Domain actions in `@mapsight/core/lib/map/actions` | +| Load GeoJSON | `LOAD_FEATURE_SOURCE` family (`load`, …) | +| Toggle list/panel/layout | `@mapsight/ui/store/actions` (`app` slice) | +| OL reported pan/zoom | Already handled in controllers — don't dispatch from React | + +--- + +## 1. Apply CMS / preset JSON + +**Use:** path actions from `@mapsight/core/lib/base/actions`, and `resetMapsightCore` when you also need to clear selections. + +- `set(path, value)` — replace a single value (layer visibility, one field). +- `merge(path, value)` — shallow-merge an object at a path. +- `mergeAll({ map: …, featureSources: … })` — batch several top-level slices at once. +- `resetMapsightCore(config)` — deselect all features, then `mergeAll(config)` (see §2). + +Paths are arrays routed by the first segment (`["map", "layers", id, …]`). + +### Good + +```typescript +import {mergeAll, set} from "@mapsight/core/lib/base/actions"; + +// Bulk preset fragment: layers + sources in one batch +store.dispatch( + mergeAll({ + map: {layers: moduleLayers, view: {zoom: 12}}, + featureSources: moduleSources, + }), +); + +// Single field tweak +store.dispatch(set(["map", "layers", "poi-layer", "options", "visible"], true)); +``` + +### Anti-pattern + +```typescript +// ❌ Don't hand-roll action objects — you lose path routing and batching +store.dispatch({ + type: "MAPSIGHT_MERGE", + value: {visible: true}, + meta: {path: ["map", "layers", "poi-layer", "options"]}, // easy to get wrong +}); +``` + +--- + +## 2. Switch entire view / module + +**Use:** `resetMapsightCore` from `@mapsight/ui/store/actions`. + +Module switches replace most GIS slices and must not leave ghost layers or selections from the previous module. `resetMapsightCore` clears highlight/preselect/select, then deep-merges the new config tree. + +When only a partial update is safe (e.g. restoring localStorage), `mergeAll` alone is fine — but module switches are not that case. + +### Good + +```typescript +import { + resetMapsightCore, + setTagFilterControl, +} from "@mapsight/ui/store/actions"; + +// Stadtplan router: full GIS reset on module change, then UI-only follow-up +const {app, ...base} = getConfigForCityMapModule(moduleId); +store.dispatch(resetMapsightCore(base)); +store.dispatch( + setTagFilterControl( + app.tagSwitcher.show, + "featureSources", + app.tagSwitcher.featureSourceId ?? "_", + ), +); +``` + +`base` should include a **complete** layer catalog for the target module. `mergeAll` deep-merges `map.layers`; omitted layer IDs survive from the previous module. + +### Anti-pattern + +```typescript +// ❌ mergeAll without clearing selections — features stay highlighted across modules +store.dispatch(mergeAll(getConfigForCityMapModule(moduleId))); + +// ❌ Replacing only map.layers — list, featureSources, filters can drift +store.dispatch(set(["map", "layers"], newLayers)); +``` + +--- + +## 3. Animate map, fit to feature + +**Use:** domain actions in `@mapsight/core/lib/map/actions` — `animate`, `fitMapViewToLayerFeature`, `fitMapViewToLayerSourceExtent`, `setLayerVisibility`, interaction helpers, etc. + +These run reducer/controller logic (animations, fit bounds, base-layer rules) that a raw `set(["map", "view", …])` bypasses. + +### Good + +```typescript +import {easeOut} from "ol/easing"; + +import { + animate, + fitMapViewToLayerFeature, +} from "@mapsight/core/lib/map/actions"; + +store.dispatch( + animate("map", { + duration: 1000, + easing: easeOut, + bounds: regionExtent, + nearest: true, + }), +); + +store.dispatch( + fitMapViewToLayerFeature("map", "poi-layer", featureId, {maxZoom: 16}), +); +``` + +### Anti-pattern + +```typescript +import {set} from "@mapsight/core/lib/base/actions"; + +// ❌ Writing view center/zoom directly — skips animation mixin and controlled sync +store.dispatch(set(["map", "view", "center"], clickedCoordinate)); +store.dispatch(set(["map", "view", "zoom"], 14)); +``` + +Use path `set` for **declarative config** (initial view in a preset). Use **domain actions** for **imperative map behavior** after the map is running. + +--- + +## 4. Load GeoJSON + +**Use:** the `LOAD_FEATURE_SOURCE` family from `@mapsight/core/lib/feature-sources/actions`. Prefer the `load()` thunk — it handles request IDs, cache, and success/error follow-ups. + +Related: `setData` for local/cached data, `addFeature` / `updateFeature` for edits (often wrapped in `controlled()`). + +### Good + +```typescript +import {load} from "@mapsight/core/lib/feature-sources/actions"; + +// XHR or local loader — controller picks strategy from featureSources[id].type +store.dispatch(load("featureSources", "pois", {forceRefresh: true})); +``` + +Feature source **config** (`type`, `url`, filters) still belongs in preset JSON via `mergeAll`. `load()` fetches or hydrates **data** into that config. + +### Anti-pattern + +```typescript +import {LOAD_FEATURE_SOURCE} from "@mapsight/core/lib/feature-sources/actions"; + +// ❌ Dispatching the raw constant — no loader, no cache, no requestId deduping +store.dispatch({ + type: LOAD_FEATURE_SOURCE, + id: "pois", + meta: {path: ["featureSources"]}, +}); +``` + +--- + +## 5. Toggle list / panel / layout + +**Use:** `@mapsight/ui/store/actions` — these update the `app` slice (`mapsightUiAppReducer`), not GIS controllers. + +Examples: `setListVisible`, `setView`, `setMapVisible`, `setListPage`, `fetchJson`, `setOverlayModalVisible`. + +**Phase 1 rule:** do not add new fields to `mapsightUiAppReducer` during the demo push. Prefer existing actions or local React state for new UI-only concerns. + +### Good + +```typescript +import {VIEW_MAP_ONLY} from "@mapsight/ui/config/constants/app"; +import {setListVisible, setView} from "@mapsight/ui/store/actions"; + +store.dispatch(setView(VIEW_MAP_ONLY)); +store.dispatch(setListVisible(false)); +``` + +### Anti-pattern + +```typescript +import {set} from "@mapsight/core/lib/base/actions"; + +// ❌ Layout flags don't live under map/list controllers +store.dispatch(set(["app", "listVisible"], false)); // bypasses app reducer cases + +// ❌ Don't put panel open/closed state into map JSON +store.dispatch(set(["map", "options", "listOpen"], true)); +``` + +--- + +## 6. OpenLayers pan / zoom feedback + +**Use:** nothing from application code. `WithMap` (and related mixins) listen to OL view events and dispatch `controlled(async(() => setViewCenter(…)))` back into Redux. + +User-driven pan/zoom must not re-enter through React components — that causes double updates, sync loops, and DevTools noise. + +### Good + +```typescript +// In a React component — read view state if needed, but don't write it on pan/zoom +const center = useSelector((state) => state.map?.view?.center); + +// To move the map intentionally, use domain actions (see §3) +store.dispatch(animate("map", {center: target, duration: 500})); +``` + +Controllers already mark high-frequency feedback with `quiet()` so DevTools stays usable. + +### Anti-pattern + +```typescript +import {setViewCenter} from "@mapsight/core/lib/map/actions"; + +// ❌ Never mirror OL view events from React / plugins +map.getView().on("change:center", () => { + store.dispatch(setViewCenter("map", map.getView().getCenter()!)); +}); + +// ❌ Don't use uncontrolled path sets for live view — fights the controller loop +store.dispatch(set(["map", "view", "center"], map.getView().getCenter())); +``` + +--- + +## Cheat sheet: imports + +| Package | Path | When | +| ---------------- | ----------------------------- | ------------------------------------------------- | +| `@mapsight/core` | `lib/base/actions` | `set`, `merge`, `mergeAll`, `controlled`, `quiet` | +| `@mapsight/core` | `lib/map/actions` | Animate, fit, layer visibility, interactions | +| `@mapsight/core` | `lib/feature-sources/actions` | `load`, feature CRUD, undo/redo | +| `@mapsight/ui` | `store/actions` | `resetMapsightCore`, layout, list UI, fetch cache | + +When in doubt: **serializable config → path actions; imperative GIS ops → domain actions; chrome/layout → UI actions.** From fe0bdb217d60dafc8f88f283cfa460ef12485758 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 17:08:04 +0200 Subject: [PATCH 26/49] eslint allow vitest.config.ts Signed-off-by: Paul Golmann --- configs/eslint-config-base.mts | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/eslint-config-base.mts b/configs/eslint-config-base.mts index 4cf09d03..6659f016 100644 --- a/configs/eslint-config-base.mts +++ b/configs/eslint-config-base.mts @@ -33,6 +33,7 @@ export default defineConfig([ "gulpfile.mts", "vite.config.ts", "vite.config.mts", + "vitest.config.ts", "prettier.config.mjs", "postcss.config.mts", ], From 9bf3625930dac48893ff1b31e10d9ee0ffbd97da Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 17:08:27 +0200 Subject: [PATCH 27/49] move zod to workspace catalog Signed-off-by: Paul Golmann --- packages/traffic-style/package.json | 2 +- pnpm-workspace.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/traffic-style/package.json b/packages/traffic-style/package.json index 0086051d..55352a4a 100644 --- a/packages/traffic-style/package.json +++ b/packages/traffic-style/package.json @@ -16,7 +16,7 @@ "sharp": "^0.34.5", "svgo": "^4.0.1", "vinyl": "^3.0.1", - "zod": "^4.4.3" + "zod": "catalog:" }, "devDependencies": { "@mapsight/vector-style-compiler": "workspace:^", diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7a0972ad..a0037695 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -31,6 +31,7 @@ catalog: "tailwindcss": "^4.3.0" "typescript": "^6.0.3" "vitest": "^4.1.6" + "zod": "^4.4.3" minimumReleaseAgeExclude: - postcss@8.5.10 overrides: From 50d3d39abd7cca916c02aa6dd305ea0812f0e191 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 18:10:48 +0200 Subject: [PATCH 28/49] implement zod schema validation for mapsight config (core) Signed-off-by: Paul Golmann --- packages/core/package.json | 15 ++- .../src/js/lib/feature-selections/schema.ts | 7 + .../core/src/js/lib/feature-sources/schema.ts | 22 +++ .../core/src/js/lib/feature-sources/types.ts | 11 +- packages/core/src/js/lib/filter/types.ts | 1 + packages/core/src/js/lib/helpers/index.ts | 2 + .../core/src/js/lib/helpers/isDevelopment.ts | 12 ++ packages/core/src/js/lib/helpers/schema.ts | 28 ++++ packages/core/src/js/lib/list/schema.ts | 10 ++ packages/core/src/js/lib/list/types.ts | 6 +- .../src/js/lib/map/lib/WithLayerOverlays.ts | 20 +-- .../core/src/js/lib/map/lib/WithLayers.ts | 20 ++- packages/core/src/js/lib/map/schema.ts | 40 ++++++ packages/core/src/js/lib/map/selectors.ts | 12 +- packages/core/src/js/lib/map/types.ts | 68 ++++------ .../core/src/js/lib/projections/schema.ts | 5 + .../src/js/lib/user-geolocation/schema.ts | 5 + packages/core/src/js/ol-proxy/index.ts | 2 +- .../__tests__/create-config-schema.test.ts | 125 ++++++++++++++++++ .../src/js/schema/create-config-schema.ts | 11 ++ packages/core/src/js/schema/index.ts | 2 + .../core/src/js/schema/validate-config.ts | 33 +++++ packages/core/vitest.config.ts | 17 +++ packages/ui/package.json | 7 +- .../config/__tests__/mapsight-config.test.ts | 80 +++++++++++ packages/ui/src/js/config/schema/index.ts | 34 +++++ packages/ui/src/js/config/schema/validate.ts | 12 ++ packages/ui/src/js/controllers/defaults.ts | 3 +- packages/ui/src/js/filters/tag-filter.ts | 17 +++ packages/ui/src/js/filters/time-filter.ts | 23 ++-- packages/ui/src/js/index.ts | 19 ++- packages/ui/src/js/store/actions.ts | 8 +- packages/ui/src/js/store/selectors.ts | 13 +- packages/ui/src/js/types.ts | 11 +- packages/ui/tsconfig.json | 1 + packages/ui/vitest.config.ts | 12 ++ 36 files changed, 609 insertions(+), 105 deletions(-) create mode 100644 packages/core/src/js/lib/feature-selections/schema.ts create mode 100644 packages/core/src/js/lib/feature-sources/schema.ts create mode 100644 packages/core/src/js/lib/helpers/isDevelopment.ts create mode 100644 packages/core/src/js/lib/helpers/schema.ts create mode 100644 packages/core/src/js/lib/list/schema.ts create mode 100644 packages/core/src/js/lib/map/schema.ts create mode 100644 packages/core/src/js/lib/projections/schema.ts create mode 100644 packages/core/src/js/lib/user-geolocation/schema.ts create mode 100644 packages/core/src/js/schema/__tests__/create-config-schema.test.ts create mode 100644 packages/core/src/js/schema/create-config-schema.ts create mode 100644 packages/core/src/js/schema/index.ts create mode 100644 packages/core/src/js/schema/validate-config.ts create mode 100644 packages/core/vitest.config.ts create mode 100644 packages/ui/src/js/config/__tests__/mapsight-config.test.ts create mode 100644 packages/ui/src/js/config/schema/index.ts create mode 100644 packages/ui/src/js/config/schema/validate.ts create mode 100644 packages/ui/vitest.config.ts diff --git a/packages/core/package.json b/packages/core/package.json index c07870a3..4fc4767a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -11,7 +11,8 @@ "eventemitter3": "^5.0.4", "lodash": "catalog:", "minimatch": "^10.2.5", - "redux-batched-actions": "catalog:" + "redux-batched-actions": "catalog:", + "zod": "catalog:" }, "devDependencies": { "@redux-devtools/extension": "^3.3.0", @@ -23,7 +24,8 @@ "ol": "catalog:", "proj4": "catalog:", "tsc-alias": "^1.8.17", - "typescript": "catalog:" + "typescript": "catalog:", + "vitest": "catalog:" }, "exports": { ".": { @@ -38,6 +40,10 @@ "types": "./dist/lib/*.d.ts", "import": "./dist/lib/*.js" }, + "./lib/*/schema": { + "types": "./dist/lib/*/schema.d.ts", + "import": "./dist/lib/*/schema.js" + }, "./lib/helpers": { "types": "./dist/lib/helpers/index.d.ts", "import": "./dist/lib/helpers/index.js" @@ -57,6 +63,10 @@ "./env/ssr-simulated-browser": { "types": "./dist/env/ssr-simulated-browser.d.ts", "import": "./dist/env/ssr-simulated-browser.js" + }, + "./schema": { + "types": "./dist/schema/index.d.ts", + "import": "./dist/schema/index.js" } }, "license": "UNLICENSED", @@ -90,6 +100,7 @@ "clean": "rimraf dist/*", "clean-build": "run-s clean build", "lint": "eslint", + "test": "vitest run", "typecheck": "tsc --noEmit", "watch": "run-s build:modules watch:build", "watch:build": "run-p watch:build:modules watch:build:paths", diff --git a/packages/core/src/js/lib/feature-selections/schema.ts b/packages/core/src/js/lib/feature-selections/schema.ts new file mode 100644 index 00000000..f2fad371 --- /dev/null +++ b/packages/core/src/js/lib/feature-selections/schema.ts @@ -0,0 +1,7 @@ +import {z} from "zod"; + +export const featureSelectionsConfigSchema = z.record(z.string(), z.unknown()); + +export type FeatureSelectionsConfig = z.infer< + typeof featureSelectionsConfigSchema +>; diff --git a/packages/core/src/js/lib/feature-sources/schema.ts b/packages/core/src/js/lib/feature-sources/schema.ts new file mode 100644 index 00000000..c43f60fa --- /dev/null +++ b/packages/core/src/js/lib/feature-sources/schema.ts @@ -0,0 +1,22 @@ +import {z} from "zod"; + +export const featureSourceTypeSchema = z.enum(["local", "xhr-json", "noop"]); + +export const featureSourceConfigSchema = z + .object({ + type: featureSourceTypeSchema, + url: z.string().optional(), + filters: z.array(z.string()).optional(), + doRefresh: z.boolean().optional(), + timer: z.number().optional(), + enableHistory: z.boolean().optional(), + }) + .strict(); + +export const featureSourcesConfigSchema = z.record( + z.string(), + featureSourceConfigSchema, +); + +export type FeatureSourceConfig = z.infer; +export type FeatureSourcesConfig = z.infer; diff --git a/packages/core/src/js/lib/feature-sources/types.ts b/packages/core/src/js/lib/feature-sources/types.ts index 4625c3a0..f9e513f1 100644 --- a/packages/core/src/js/lib/feature-sources/types.ts +++ b/packages/core/src/js/lib/feature-sources/types.ts @@ -1,6 +1,9 @@ import type {FeatureSourceDataHistory} from "@/lib/feature-sources/lib/history"; +import type {FeatureSourceConfig} from "@/lib/feature-sources/schema"; import type {Feature, FeatureId} from "@/types"; +export type {FeatureSourceConfig}; + export type FeatureSourceData = { type?: "FeatureCollection"; features?: Array; @@ -8,22 +11,16 @@ export type FeatureSourceData = { export type FeatureSourceType = FeatureSourceState["type"]; -export interface FeatureSourceState { - type: "local" | "xhr-json" | "noop"; +export interface FeatureSourceState extends FeatureSourceConfig { data: FeatureSourceData | null; // TODO: replace the full scan with something smarter (eg bisecting a sorted list) ids?: Array; - filters?: Array; error?: string; - url?: string; lastUpdate: number | null; lastActionType: string | null; isLoading?: boolean; requestId?: number; - doRefresh?: boolean; refreshPaused?: boolean; - timer?: number; - enableHistory?: boolean; dataHistory?: FeatureSourceDataHistory; } diff --git a/packages/core/src/js/lib/filter/types.ts b/packages/core/src/js/lib/filter/types.ts index a9ed69ac..79e2f613 100644 --- a/packages/core/src/js/lib/filter/types.ts +++ b/packages/core/src/js/lib/filter/types.ts @@ -1,5 +1,6 @@ import type {Feature} from "@/types"; +/** Runtime filter slice state; shape depends on the filter implementation. */ export type FilterState = unknown; export type FiltersState = Record; diff --git a/packages/core/src/js/lib/helpers/index.ts b/packages/core/src/js/lib/helpers/index.ts index 6e8d878e..802da83c 100644 --- a/packages/core/src/js/lib/helpers/index.ts +++ b/packages/core/src/js/lib/helpers/index.ts @@ -1,3 +1,5 @@ +export {isDevelopment} from "./isDevelopment"; + export const hasGeolocationSupport = (() => { // eslint-disable-next-line n/no-unsupported-features/node-builtins if (typeof window === "undefined" || !("geolocation" in navigator)) { diff --git a/packages/core/src/js/lib/helpers/isDevelopment.ts b/packages/core/src/js/lib/helpers/isDevelopment.ts new file mode 100644 index 00000000..282e0acf --- /dev/null +++ b/packages/core/src/js/lib/helpers/isDevelopment.ts @@ -0,0 +1,12 @@ +export function isDevelopment(): boolean { + if (typeof process !== "undefined" && process.env.NODE_ENV) { + return process.env.NODE_ENV === "development"; + } + + if (typeof import.meta !== "undefined") { + const env = (import.meta as ImportMeta & {env?: {DEV?: boolean}}).env; + return env?.DEV === true; + } + + return false; +} diff --git a/packages/core/src/js/lib/helpers/schema.ts b/packages/core/src/js/lib/helpers/schema.ts new file mode 100644 index 00000000..5a7d40e8 --- /dev/null +++ b/packages/core/src/js/lib/helpers/schema.ts @@ -0,0 +1,28 @@ +import {z} from "zod"; + +/** Recursive serializable JSON value used in ol-proxy options. */ +export type OptionValue = + | string + | boolean + | number + | ReadonlyArray + | Array + | Options + | undefined + | null; + +export type Options = {[k: string]: OptionValue}; + +export const optionValueSchema: z.ZodType = z.lazy(() => + z.union([ + z.string(), + z.boolean(), + z.number(), + z.null(), + z.undefined(), + z.array(optionValueSchema), + z.record(z.string(), optionValueSchema), + ]), +); + +export const optionsSchema = z.record(z.string(), optionValueSchema); diff --git a/packages/core/src/js/lib/list/schema.ts b/packages/core/src/js/lib/list/schema.ts new file mode 100644 index 00000000..9bc466b4 --- /dev/null +++ b/packages/core/src/js/lib/list/schema.ts @@ -0,0 +1,10 @@ +import {z} from "zod"; + +export const listConfigSchema = z.looseObject({ + featureSource: z.string().optional(), + visible: z.boolean().optional(), + featureSelectionHighlight: z.string().optional(), + featureSelectionSelect: z.string().optional(), +}); + +export type ListConfig = z.infer; diff --git a/packages/core/src/js/lib/list/types.ts b/packages/core/src/js/lib/list/types.ts index 87f897a8..7d745497 100644 --- a/packages/core/src/js/lib/list/types.ts +++ b/packages/core/src/js/lib/list/types.ts @@ -1,3 +1,3 @@ -export type ListState = { - featureSource?: string; -}; +import type {ListConfig} from "@/lib/list/schema"; + +export type ListState = ListConfig; diff --git a/packages/core/src/js/lib/map/lib/WithLayerOverlays.ts b/packages/core/src/js/lib/map/lib/WithLayerOverlays.ts index a785c43c..4c1c44c8 100644 --- a/packages/core/src/js/lib/map/lib/WithLayerOverlays.ts +++ b/packages/core/src/js/lib/map/lib/WithLayerOverlays.ts @@ -32,26 +32,28 @@ export default class WithLayerOverlays extends WithMap { const updateLayerOverlay = ( id: string, - newDefinition: LayerDefinition, - oldDefinitions: LayerDefinition, + newDefinition: LayerDefinition | undefined, + oldDefinitions: Record, ) => { const oldDefinition = oldDefinitions[id]; - newDefinition = newDefinition && { + const overlayDefinition = newDefinition && { zIndex: Z_INDEX_OVERLAY, ...newDefinition, }; // update overlay // TODO: make overlay optional? - const featureSelections = newDefinition?.options?.selections; + const featureSelections = overlayDefinition?.options?.selections; updateProxyObject({ di: di, oldObject: this._overlays[id], - oldDefinition: {...oldDefinition, type: LAYER_TYPE}, - newDefinition: featureSelections && { - ...newDefinition, - type: LAYER_TYPE, - }, + oldDefinition: oldDefinition + ? {...oldDefinition, type: LAYER_TYPE} + : undefined, + newDefinition: + featureSelections && overlayDefinition + ? {...overlayDefinition, type: LAYER_TYPE} + : undefined, remover: () => { this._overlays[id]?.setMap(null); delete this._overlays[id]; diff --git a/packages/core/src/js/lib/map/lib/WithLayers.ts b/packages/core/src/js/lib/map/lib/WithLayers.ts index 2137c72f..7ee2b0ef 100644 --- a/packages/core/src/js/lib/map/lib/WithLayers.ts +++ b/packages/core/src/js/lib/map/lib/WithLayers.ts @@ -9,6 +9,7 @@ import matchesPath from "@mapsight/lib-redux/matchesPath"; import reducers from "@mapsight/lib-redux/reducers/immutable-path"; import type {MapController} from "@/lib/map/controller"; +import type {LayerConfig} from "@/lib/map/schema"; import {di, updateProxyObject} from "@/ol-proxy/index"; import {ACTION_SET} from "../../base/reducer"; @@ -20,8 +21,7 @@ import WithAnimations from "./WithAnimations"; import proxyPassOpenLayersEventsToMapController from "./proxyPassOpenLayersEventsToMapController"; import {getGroupForLayer, tagLayer} from "./tagLayer"; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type LayerDefinition = any; // TODO: Implement types for definitions in redux and ol-proxy +export type LayerDefinition = LayerConfig; export const LAYER_GROUP_DEFAULT = "default"; @@ -62,8 +62,8 @@ export default class WithLayers extends WithAnimations { const updateLayer = ( id: string, - newDefinition: LayerDefinition, - oldDefinitions: LayerDefinition, + newDefinition: LayerDefinition | undefined, + oldDefinitions: Record, ) => { const oldDefinition = oldDefinitions[id]; @@ -72,7 +72,7 @@ export default class WithLayers extends WithAnimations { di: di, oldObject: this._layers[id], oldDefinition: oldDefinition, - newDefinition: newDefinition, + newDefinition, remover: (oldObject) => { const group = getGroupForLayer(oldObject) || LAYER_GROUP_DEFAULT; @@ -83,7 +83,15 @@ export default class WithLayers extends WithAnimations { delete this._groups[group]?.layers[id]; }, adder: (layer) => { - const group = newDefinition.group || LAYER_GROUP_DEFAULT; + if (!newDefinition) { + return; + } + + const group = + (typeof newDefinition.group === "string" + ? newDefinition.group + : newDefinition.metaData?.group) || + LAYER_GROUP_DEFAULT; const layerGroup = this.getOrCreateLayerGroup(group); this._layers[id] = layer; ensureNonNullable(this._groups[group]).layers[id] = layer; diff --git a/packages/core/src/js/lib/map/schema.ts b/packages/core/src/js/lib/map/schema.ts new file mode 100644 index 00000000..6485b145 --- /dev/null +++ b/packages/core/src/js/lib/map/schema.ts @@ -0,0 +1,40 @@ +import {z} from "zod"; + +import {optionsSchema} from "@/lib/helpers/schema"; + +export const layerMetaDataSchema = z.looseObject({ + title: z.string().optional(), + group: z.string().optional(), + isBaseLayer: z.boolean().optional(), + attribution: z.string().optional(), + legend: z.string().optional(), + miniLegend: z.string().optional(), + lockedInLayerSwitcher: z.boolean().optional(), + visibleInLayerSwitcher: z.boolean().optional(), + visibleInExternalLayerSwitcher: z.boolean().optional(), +}); + +export const descriptionSchema = z.looseObject({ + type: z.string(), + options: optionsSchema.optional(), + metaData: layerMetaDataSchema.optional(), +}); + +export const layerConfigSchema = descriptionSchema; + +export const mapConfigSchema = z + .looseObject({ + layers: z.record(z.string(), layerConfigSchema).optional(), + size: z.tuple([z.number(), z.number()]).optional(), + view: optionsSchema.optional(), + controls: optionsSchema.optional(), + interactions: optionsSchema.optional(), + visibleLayers: z.array(z.string()).optional(), + viewportAnchor: optionsSchema.optional(), + }) + .partial(); + +export type LayerMetaData = z.infer; +export type Description = z.infer; +export type LayerConfig = z.infer; +export type MapConfig = z.infer; diff --git a/packages/core/src/js/lib/map/selectors.ts b/packages/core/src/js/lib/map/selectors.ts index 9be49c9a..e6a6d86d 100644 --- a/packages/core/src/js/lib/map/selectors.ts +++ b/packages/core/src/js/lib/map/selectors.ts @@ -185,11 +185,15 @@ export const reduceToLayersWithMiniLegends = ( return Object.fromEntries(entries); }; -export const layersWithLegendsSelector: Selector = - createSelector(layersSelector, reduceToLayersWithLegends); +export const layersWithLegendsSelector: Selector< + MapState, + Record +> = createSelector(layersSelector, reduceToLayersWithLegends); -export const layersWithMiniLegendsSelector: Selector = - createSelector(layersSelector, reduceToLayersWithMiniLegends); +export const layersWithMiniLegendsSelector: Selector< + MapState, + Record +> = createSelector(layersSelector, reduceToLayersWithMiniLegends); export const visibleLayersWithLegendsSelector: Selector< MapState, diff --git a/packages/core/src/js/lib/map/types.ts b/packages/core/src/js/lib/map/types.ts index 29cbda19..167bf0e7 100644 --- a/packages/core/src/js/lib/map/types.ts +++ b/packages/core/src/js/lib/map/types.ts @@ -1,16 +1,11 @@ import type OlLayer from "ol/layer/Layer"; +import type {OptionValue, Options} from "@/lib/helpers/schema"; import type {VectorFeatureSource} from "@/lib/map/lib/VectorFeatureSource"; import type {ViewportAnchor} from "@/lib/map/lib/WithAnchoredViewport"; +import type {Description, LayerConfig, LayerMetaData} from "@/lib/map/schema"; -// TODO: find a better name? "TargetState"? -/** Describes the target state of an ol object (comparable to one entry in the vdom of react) */ -export type Description = { - type: string; - options?: Options; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - metaData?: any; // TODO: type the metadata -}; +export type {Description, LayerMetaData, OptionValue, Options}; export const isDescription = (value: unknown): value is Description => typeof value === "object" && @@ -18,47 +13,34 @@ export const isDescription = (value: unknown): value is Description => "type" in value && typeof value.type === "string"; -export type Options = {[k: string]: OptionValue}; - -// Needs to be serializable -export type OptionValue = - | string - | boolean - | number - | Array - | Options - | undefined - | null; - -export interface LayerMetaData { - title?: string; - group?: string; - isBaseLayer?: boolean; - attribution?: string; - legend?: string; - miniLegend?: string; - lockedInLayerSwitcher?: boolean; - visibleInLayerSwitcher?: boolean; - visibleInExternalLayerSwitcher?: boolean; -} +export type LayerOptions = { + visible?: boolean; + selections?: InteractionsSelections; + source?: LayerSourceState; +} & Options; -export interface LayerState { +/** Runtime layer state; `type` is required in config ingress (`LayerConfig`). */ +export type LayerState = Omit & { + type?: string; [key: string]: unknown; metaData?: LayerMetaData; - options?: { - visible?: boolean; - selections?: InteractionsSelections; - source?: LayerSourceState; - }; -} + options?: LayerOptions; +}; + +type VectorFeatureSourceOptions = { + featureSourceId?: string; + featureSourcesControllerName?: string; + featureSelectionsControllerName?: string; + keepFeaturesInViewOptions?: Options; + fitFeaturesInViewOptions?: Options; + clusterFeatures?: boolean; + clusterFeaturesOptions?: Options; + [key: string]: OptionValue; +}; type VectorFeatureSourceState = { type: "VectorFeatureSource"; - options: { - featureSourceId?: string; - featureSourcesControllerName?: string; - featureSelectionsControllerName?: string; - }; + options: VectorFeatureSourceOptions; }; export type LayerSourceState = VectorFeatureSourceState; // TODO: add other types diff --git a/packages/core/src/js/lib/projections/schema.ts b/packages/core/src/js/lib/projections/schema.ts new file mode 100644 index 00000000..e751f95c --- /dev/null +++ b/packages/core/src/js/lib/projections/schema.ts @@ -0,0 +1,5 @@ +import {z} from "zod"; + +export const projectionsConfigSchema = z.array(z.string()); + +export type ProjectionsConfig = z.infer; diff --git a/packages/core/src/js/lib/user-geolocation/schema.ts b/packages/core/src/js/lib/user-geolocation/schema.ts new file mode 100644 index 00000000..8d546f97 --- /dev/null +++ b/packages/core/src/js/lib/user-geolocation/schema.ts @@ -0,0 +1,5 @@ +import {z} from "zod"; + +export const userGeolocationConfigSchema = z.unknown(); + +export type UserGeolocationConfig = z.infer; diff --git a/packages/core/src/js/ol-proxy/index.ts b/packages/core/src/js/ol-proxy/index.ts index 22554515..65fedae4 100644 --- a/packages/core/src/js/ol-proxy/index.ts +++ b/packages/core/src/js/ol-proxy/index.ts @@ -396,7 +396,7 @@ export function updateProxyObject< // TODO: remove "old" prefix, there's only one object, no "old" nor "new" oldObject?: TObject; oldDefinition?: Description; - newDefinition: Description; + newDefinition?: Description; remover?: (object: TObject, parentObject?: TParentObject) => void; adder?: (object: TObject, parentObject?: TParentObject) => void; parentObject?: TParentObject; diff --git a/packages/core/src/js/schema/__tests__/create-config-schema.test.ts b/packages/core/src/js/schema/__tests__/create-config-schema.test.ts new file mode 100644 index 00000000..cc07fad7 --- /dev/null +++ b/packages/core/src/js/schema/__tests__/create-config-schema.test.ts @@ -0,0 +1,125 @@ +import {afterEach, describe, expect, it, vi} from "vitest"; +import {z} from "zod"; + +import {featureSourcesConfigSchema} from "@/lib/feature-sources/schema"; +import {listConfigSchema} from "@/lib/list/schema"; +import {layerConfigSchema} from "@/lib/map/schema"; +import { + createMapsightConfigSchema, + formatZodError, + validateConfig, +} from "@/schema"; + +const exampleConfigSchema = createMapsightConfigSchema({ + map: z.object({layers: z.record(z.string(), layerConfigSchema)}).partial(), + list: listConfigSchema, + featureSources: featureSourcesConfigSchema, +}); + +describe("createMapsightConfigSchema", () => { + it("parses a valid minimal preset", () => { + const result = exampleConfigSchema.safeParse({ + map: {layers: {x: {type: "OSM"}}}, + }); + expect(result.success).toBe(true); + }); + + it("fails when a layer is missing type", () => { + const result = exampleConfigSchema.safeParse({ + map: {layers: {x: {options: {}}}}, + }); + expect(result.success).toBe(false); + if (!result.success) { + expect(formatZodError(result.error)).toContain("type"); + } + }); + + it("parses feature source config without runtime fields", () => { + const result = exampleConfigSchema.safeParse({ + featureSources: { + pois: {type: "xhr-json", url: "/data/pois.json"}, + }, + }); + expect(result.success).toBe(true); + }); + + it("parses list config fields used by featureList()", () => { + const result = exampleConfigSchema.safeParse({ + list: { + featureSource: "pois", + visible: false, + featureSelectionHighlight: "highlight", + featureSelectionSelect: "select", + }, + }); + expect(result.success).toBe(true); + }); + + it("allows unknown top-level slices via catchall", () => { + const result = exampleConfigSchema.safeParse({ + map2: {layers: {x: {type: "OSM"}}}, + app: {view: "mobile"}, + }); + expect(result.success).toBe(true); + }); +}); + +describe("validateConfig", () => { + afterEach(() => { + vi.unstubAllGlobals(); + vi.restoreAllMocks(); + }); + + it("returns parsed data on success", () => { + const config = {map: {layers: {base: {type: "OSM"}}}}; + expect(validateConfig(exampleConfigSchema, config)).toEqual(config); + }); + + it("warns in development on invalid config", () => { + const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); + vi.stubGlobal("process", { + ...process, + env: {...process.env, NODE_ENV: "development"}, + }); + + const invalid = {map: {layers: {x: {options: {}}}}}; + const result = validateConfig(exampleConfigSchema, invalid, { + context: "test", + }); + + expect(warn).toHaveBeenCalledWith( + "[mapsight] Config validation failed:", + expect.stringContaining("[test]"), + ); + expect(result).toBe(invalid); + }); + + it("throws in production when strict is true", () => { + vi.stubGlobal("process", { + ...process, + env: {...process.env, NODE_ENV: "production"}, + }); + + expect(() => + validateConfig( + exampleConfigSchema, + {map: {layers: {x: {options: {}}}}}, + {strict: true}, + ), + ).toThrow(/type/); + }); + + it("passes through invalid config silently in production", () => { + const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); + vi.stubGlobal("process", { + ...process, + env: {...process.env, NODE_ENV: "production"}, + }); + + const invalid = {map: {layers: {x: {options: {}}}}}; + const result = validateConfig(exampleConfigSchema, invalid); + + expect(warn).not.toHaveBeenCalled(); + expect(result).toBe(invalid); + }); +}); diff --git a/packages/core/src/js/schema/create-config-schema.ts b/packages/core/src/js/schema/create-config-schema.ts new file mode 100644 index 00000000..ac94ad20 --- /dev/null +++ b/packages/core/src/js/schema/create-config-schema.ts @@ -0,0 +1,11 @@ +import {z} from "zod"; + +/** + * Compose a top-level config schema from per-slice schemas. + * Slice keys match controller names registered at store creation time. + */ +export function createMapsightConfigSchema< + TSliceSchemas extends Record, +>(sliceSchemas: TSliceSchemas) { + return z.object(sliceSchemas).partial().catchall(z.unknown()); +} diff --git a/packages/core/src/js/schema/index.ts b/packages/core/src/js/schema/index.ts new file mode 100644 index 00000000..511e0b3c --- /dev/null +++ b/packages/core/src/js/schema/index.ts @@ -0,0 +1,2 @@ +export {createMapsightConfigSchema} from "./create-config-schema"; +export {formatZodError, validateConfig} from "./validate-config"; diff --git a/packages/core/src/js/schema/validate-config.ts b/packages/core/src/js/schema/validate-config.ts new file mode 100644 index 00000000..78ae6477 --- /dev/null +++ b/packages/core/src/js/schema/validate-config.ts @@ -0,0 +1,33 @@ +import type {ZodError, ZodType, z} from "zod"; + +import {isDevelopment} from "@/lib/helpers/isDevelopment"; + +export function formatZodError(error: ZodError, context?: string): string { + const prefix = context ? `[${context}] ` : ""; + const messages = error.issues.map((issue) => { + const path = + issue.path.length > 0 ? issue.path.map(String).join(".") : "(root)"; + return `${path}: ${issue.message}`; + }); + return `${prefix}${messages.join("; ")}`; +} + +export function validateConfig( + schema: T, + config: unknown, + options?: {strict?: boolean; context?: string}, +): z.infer { + const result = schema.safeParse(config); + + if (!result.success) { + const msg = formatZodError(result.error, options?.context); + if (isDevelopment()) { + console.warn("[mapsight] Config validation failed:", msg); + } else if (options?.strict) { + throw new Error(msg); + } + return config as z.infer; + } + + return result.data; +} diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts new file mode 100644 index 00000000..1746638e --- /dev/null +++ b/packages/core/vitest.config.ts @@ -0,0 +1,17 @@ +import path from "node:path"; +import {fileURLToPath} from "node:url"; + +import {defineConfig} from "vitest/config"; + +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default defineConfig({ + resolve: { + alias: { + "@": path.resolve(dirname, "src/js"), + }, + }, + test: { + include: ["src/js/**/*.test.ts"], + }, +}); diff --git a/packages/ui/package.json b/packages/ui/package.json index cfaeafc3..bb8a88d3 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -24,7 +24,8 @@ "react-paginate": "^8.3.0", "react-redux": "catalog:", "redux-batched-actions": "catalog:", - "redux-thunk": "catalog:" + "redux-thunk": "catalog:", + "zod": "catalog:" }, "devDependencies": { "@types/lodash": "catalog:", @@ -34,7 +35,8 @@ "chokidar": "^5.0.0", "react": "catalog:", "react-dom": "catalog:", - "svgo": "^4.0.1" + "svgo": "^4.0.1", + "vitest": "catalog:" }, "exports": { "./*": { @@ -76,6 +78,7 @@ "clean": "rimraf dist/*", "clean-build": "run-s clean build", "lint": "eslint", + "test": "vitest run", "typecheck": "tsc --noEmit", "watch": "run-s build:modules watch:build", "watch:build": "run-p watch:build:*", diff --git a/packages/ui/src/js/config/__tests__/mapsight-config.test.ts b/packages/ui/src/js/config/__tests__/mapsight-config.test.ts new file mode 100644 index 00000000..5d9f9f70 --- /dev/null +++ b/packages/ui/src/js/config/__tests__/mapsight-config.test.ts @@ -0,0 +1,80 @@ +import {afterEach, describe, expect, it, vi} from "vitest"; + +import {mapsightConfigSchema} from "../schema"; +import {formatZodError, validateMapsightConfig} from "../schema/validate"; + +describe("mapsightConfigSchema", () => { + it("parses a valid minimal preset", () => { + const result = mapsightConfigSchema.safeParse({ + map: {layers: {x: {type: "OSM"}}}, + }); + expect(result.success).toBe(true); + }); + + it("fails when a layer is missing type", () => { + const result = mapsightConfigSchema.safeParse({ + map: {layers: {x: {options: {}}}}, + }); + expect(result.success).toBe(false); + if (!result.success) { + expect(formatZodError(result.error)).toContain("type"); + } + }); + + it("parses feature source config without runtime fields", () => { + const result = mapsightConfigSchema.safeParse({ + featureSources: { + pois: {type: "xhr-json", url: "/data/pois.json"}, + }, + }); + expect(result.success).toBe(true); + }); + + it("parses list config fields used by featureList()", () => { + const result = mapsightConfigSchema.safeParse({ + list: { + featureSource: "pois", + visible: false, + featureSelectionHighlight: "highlight", + featureSelectionSelect: "select", + }, + }); + expect(result.success).toBe(true); + }); + + it("allows app slice via catchall", () => { + const result = mapsightConfigSchema.safeParse({ + app: {view: "mobile"}, + }); + expect(result.success).toBe(true); + }); +}); + +describe("validateMapsightConfig", () => { + afterEach(() => { + vi.unstubAllGlobals(); + vi.restoreAllMocks(); + }); + + it("returns parsed data on success", () => { + const config = {map: {layers: {base: {type: "OSM"}}}}; + expect(validateMapsightConfig(config)).toEqual(config); + }); + + it("warns in development on invalid config", () => { + const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); + vi.stubGlobal("process", { + ...process, + env: {...process.env, NODE_ENV: "development"}, + }); + + const invalid = {map: {layers: {x: {options: {}}}}}; + const result = validateMapsightConfig(invalid, {context: "test"}); + + expect(warn).toHaveBeenCalledWith( + "[mapsight] Config validation failed:", + expect.stringContaining("[test]"), + ); + expect(result).toBe(invalid); + }); +}); diff --git a/packages/ui/src/js/config/schema/index.ts b/packages/ui/src/js/config/schema/index.ts new file mode 100644 index 00000000..88bf1b37 --- /dev/null +++ b/packages/ui/src/js/config/schema/index.ts @@ -0,0 +1,34 @@ +import type {z} from "zod"; + +import {featureSelectionsConfigSchema} from "@mapsight/core/lib/feature-selections/schema"; +import {featureSourcesConfigSchema} from "@mapsight/core/lib/feature-sources/schema"; +import {listConfigSchema} from "@mapsight/core/lib/list/schema"; +import {mapConfigSchema} from "@mapsight/core/lib/map/schema"; +import {projectionsConfigSchema} from "@mapsight/core/lib/projections/schema"; +import {userGeolocationConfigSchema} from "@mapsight/core/lib/user-geolocation/schema"; +import {createMapsightConfigSchema} from "@mapsight/core/schema"; + +import {tagFilterConfigSchema} from "../../filters/tag-filter"; +import {timeFilterConfigSchema} from "../../filters/time-filter"; +import * as c from "../constants/controllers"; + +export type MapsightConfig = z.infer; + +/** + * Per-slice config schemas for the default @mapsight/ui controller set. + * Slice keys match controller names registered at store creation time. + */ +export const mapsightConfigSchemas = { + [c.MAP]: mapConfigSchema, + [c.FEATURE_LIST]: listConfigSchema, + [c.FEATURE_SOURCES]: featureSourcesConfigSchema, + [c.FEATURE_SELECTIONS]: featureSelectionsConfigSchema, + [c.PROJECTIONS]: projectionsConfigSchema, + [c.TAG_FILTER]: tagFilterConfigSchema, + [c.TIME_FILTER]: timeFilterConfigSchema, + [c.USER_GEOLOCATION]: userGeolocationConfigSchema, +} satisfies Record; + +export const mapsightConfigSchema = createMapsightConfigSchema( + mapsightConfigSchemas, +); diff --git a/packages/ui/src/js/config/schema/validate.ts b/packages/ui/src/js/config/schema/validate.ts new file mode 100644 index 00000000..4e6b1ded --- /dev/null +++ b/packages/ui/src/js/config/schema/validate.ts @@ -0,0 +1,12 @@ +import {formatZodError, validateConfig} from "@mapsight/core/schema"; + +import {type MapsightConfig, mapsightConfigSchema} from "./index"; + +export {formatZodError}; + +export function validateMapsightConfig( + config: unknown, + options?: {strict?: boolean; context?: string}, +): Partial { + return validateConfig(mapsightConfigSchema, config, options); +} diff --git a/packages/ui/src/js/controllers/defaults.ts b/packages/ui/src/js/controllers/defaults.ts index d2301d62..47883b41 100644 --- a/packages/ui/src/js/controllers/defaults.ts +++ b/packages/ui/src/js/controllers/defaults.ts @@ -8,6 +8,7 @@ import {ProjectionsController} from "@mapsight/core/lib/projections/controller"; import {UserGeolocationController} from "@mapsight/core/lib/user-geolocation/controller"; import * as c from "../config/constants/controllers"; +import type {mapsightConfigSchemas} from "../config/schema"; import {createTagFilterFunction} from "../filters/tag-filter"; import timeFilter from "../filters/time-filter"; import type {MapsightUiContext} from "../types"; @@ -32,5 +33,5 @@ export function createDefaultControllers( [c.FEATURE_SELECTIONS]: new FeatureSelectionsController( c.FEATURE_SELECTIONS, ), - }; + } satisfies Record; } diff --git a/packages/ui/src/js/filters/tag-filter.ts b/packages/ui/src/js/filters/tag-filter.ts index 3a8386f7..d8c4dd89 100644 --- a/packages/ui/src/js/filters/tag-filter.ts +++ b/packages/ui/src/js/filters/tag-filter.ts @@ -1,9 +1,26 @@ +import {z} from "zod"; + import type {FilterFunction} from "@mapsight/core/lib/filter/types"; import getPath from "@mapsight/lib-js/object/getPath"; import type {MapsightUiFeature} from "../types"; +export const tagFilterConfigSchema = z.looseObject({ + featureSourceId: z.string().optional(), + visibleTags: z + .record( + z.string(), + z.record(z.string(), z.record(z.string(), z.boolean())), + ) + .optional(), + visibleTagGroups: z + .record(z.string(), z.record(z.string(), z.boolean())) + .optional(), +}); + +export type TagFilterState = z.infer; + type CacheEntry = { features: Array; filtered: Array; diff --git a/packages/ui/src/js/filters/time-filter.ts b/packages/ui/src/js/filters/time-filter.ts index edf6dcee..f0a6471b 100644 --- a/packages/ui/src/js/filters/time-filter.ts +++ b/packages/ui/src/js/filters/time-filter.ts @@ -1,17 +1,20 @@ +import {z} from "zod"; + import type {FilterFunction} from "@mapsight/core/lib/filter/types"; import {unreachable} from "@mapsight/lib-js/unreachable"; -type TimeFilterState = { - options?: { - /** from datetime in ISO 8601 (Y-m-d\TH:i:sP) */ - fromDate?: string; - /** to datetime in ISO 8601 (Y-m-d\TH:i:sP) */ - toDate?: string; - /** if set to true the filter will filter even if neither from nor to date are set. */ - allowEmpty?: boolean; - }; -}; +export const timeFilterConfigSchema = z.looseObject({ + options: z + .looseObject({ + fromDate: z.string().optional(), + toDate: z.string().optional(), + allowEmpty: z.boolean().optional(), + }) + .optional(), +}); + +export type TimeFilterState = z.infer; // TODO: document/collect magic property names export interface FeatureWithWhen { diff --git a/packages/ui/src/js/index.ts b/packages/ui/src/js/index.ts index 431912d9..4bf0d36f 100644 --- a/packages/ui/src/js/index.ts +++ b/packages/ui/src/js/index.ts @@ -3,8 +3,8 @@ import merge from "lodash/merge"; import {thunk} from "redux-thunk"; import {createMapsightStore} from "@mapsight/core"; +import {isDevelopment} from "@mapsight/core/lib/helpers"; import {layerIdsExternalSwitcherSelector} from "@mapsight/core/lib/map/selectors"; -import {type State} from "@mapsight/core/types"; import * as nonNull from "@mapsight/lib-js/nonNullable"; import type {MapsightStyleFunction} from "@mapsight/lib-ol/style/styleFunction"; @@ -12,6 +12,8 @@ import type {MapsightStyleFunction} from "@mapsight/lib-ol/style/styleFunction"; import {siteConfig} from "./config"; import {VIEW_MOBILE} from "./config/constants/app"; import * as c from "./config/constants/controllers"; +import type {MapsightConfig} from "./config/schema"; +import {validateMapsightConfig} from "./config/schema/validate"; import {createDefaultControllers} from "./controllers/defaults"; import uiReducers from "./store/reducers"; import type { @@ -144,15 +146,24 @@ const defaultCreateOptions: CreateOptions = { export function create( container: HTMLElement | null, styleFunction: MapsightStyleFunction, - baseMapsightConfig: Partial = {}, + baseMapsightConfig: Partial = {}, createOptions: CreateOptions = {}, ): MapsightUiContext { + const mergedCreateOptions = merge({}, defaultCreateOptions, createOptions); + const shouldValidate = + mergedCreateOptions.validateConfig ?? isDevelopment(); + const validatedBaseMapsightConfig = shouldValidate + ? validateMapsightConfig(baseMapsightConfig, { + context: "create()", + }) + : baseMapsightConfig; + const context: MapsightUiContext = { hasRendered: false, container: container, styleFunction: styleFunction, - baseMapsightConfig: baseMapsightConfig, - createOptions: merge({}, defaultCreateOptions, createOptions), + baseMapsightConfig: validatedBaseMapsightConfig, + createOptions: mergedCreateOptions, appChannelListeners: [], }; diff --git a/packages/ui/src/js/store/actions.ts b/packages/ui/src/js/store/actions.ts index 99425236..be40afc0 100644 --- a/packages/ui/src/js/store/actions.ts +++ b/packages/ui/src/js/store/actions.ts @@ -6,6 +6,7 @@ import {batchActions} from "redux-batched-actions"; import {mergeAll} from "@mapsight/core/lib/base/actions"; import {deselectAll} from "@mapsight/core/lib/feature-selections/actions"; +import {isDevelopment} from "@mapsight/core/lib/helpers"; import {animate as animateMap} from "@mapsight/core/lib/map/actions"; import type {ActionOrThunk, State, ThunkAction} from "@mapsight/core/types"; @@ -21,6 +22,7 @@ import { FEATURE_SELECTION_PRESELECT, FEATURE_SELECTION_SELECT, } from "../config/feature/selections"; +import {validateMapsightConfig} from "../config/schema/validate"; import type { FetchTextState, FullUiState, @@ -39,11 +41,15 @@ function ensureFullUrl(url: string) { } export function resetMapsightCore(config: Partial) { + const validatedConfig = isDevelopment() + ? validateMapsightConfig(config, {context: "resetMapsightCore"}) + : config; + return batchActions([ deselectAll(c.FEATURE_SELECTIONS, FEATURE_SELECTION_HIGHLIGHT), deselectAll(c.FEATURE_SELECTIONS, FEATURE_SELECTION_PRESELECT), deselectAll(c.FEATURE_SELECTIONS, FEATURE_SELECTION_SELECT), - mergeAll(config), + mergeAll(validatedConfig), ]); } diff --git a/packages/ui/src/js/store/selectors.ts b/packages/ui/src/js/store/selectors.ts index a8fdc639..06e092fb 100644 --- a/packages/ui/src/js/store/selectors.ts +++ b/packages/ui/src/js/store/selectors.ts @@ -49,6 +49,7 @@ import { FEATURE_SELECTION_PRESELECT, FEATURE_SELECTION_SELECT, } from "../config/feature/selections"; +import type {TagFilterState} from "../filters/tag-filter"; import type { FetchTextState, FullUiState, @@ -82,17 +83,7 @@ export const SEARCH_STATUS_ERROR = "error"; export type RootStateSlice = { app: UiState; - [TAG_FILTER]: { - featureSourceId: string; - visibleTags: { - [tagGroup: string]: { - [tag: string]: boolean; - }; - }; - visibleTagGroups: { - [tagGroup: string]: boolean; - }; - }; + [TAG_FILTER]: TagFilterState; }; export const viewSelector = (state: RootStateSlice) => state.app.view!; diff --git a/packages/ui/src/js/types.ts b/packages/ui/src/js/types.ts index 71397ce0..62763687 100644 --- a/packages/ui/src/js/types.ts +++ b/packages/ui/src/js/types.ts @@ -18,6 +18,7 @@ import type {MapsightStyleFunction} from "@mapsight/lib-ol/style/styleFunction"; import type {MapsightUiPlacesData} from "./components/feature-list-sorting/feature-list-sorting"; import type {View} from "./config/constants/app"; import type {TAG_FILTER, TIME_FILTER} from "./config/constants/controllers"; +import type {MapsightConfig} from "./config/schema"; import type {MapsightUiComponents} from "./helpers/components"; import type {FETCH_JSON_STATUS, FETCH_TEXT_STATUS} from "./store/actions"; import type {RootStateSlice} from "./store/selectors"; @@ -43,7 +44,7 @@ export type MapsightUiContext = { /** the mapsight core vector style function (see @mapsight/core) (available after init) */ styleFunction: MapsightStyleFunction; /** base mapsight config (available after init) TODO: document further */ - baseMapsightConfig: Partial; + baseMapsightConfig: Partial; /** options on how to create the mapsight app (available after init) */ createOptions: CreateOptions; /** array of app channel listener definitions (available after init) */ @@ -306,11 +307,16 @@ export type MapsightCoreAction = AnyAction & ThunkAction & BatchAction; +/** + * @deprecated Use `State` from `@mapsight/core/types` or `MapsightConfig` from + * `@mapsight/ui/schema` for config ingress. Kept for legacy app reducer typing. + */ export type MapsightCoreState = | string | number | Array | object; +/** @deprecated Prefer `Reducer` with a concrete slice type. */ export type MapsightCoreReducer< T extends MapsightCoreState = MapsightCoreState, U extends MapsightCoreAction = MapsightCoreAction, @@ -319,6 +325,9 @@ export type MapsightCoreReducer< export type MapsightUiAppReducer = MapsightCoreReducer; export type CreateOptions = { + /** Validate Mapsight config ingress in development (default: true in dev). */ + validateConfig?: boolean; + // store storeEnhancer?: StoreEnhancer; reducers?: { diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index 75ef3ba0..c66e0550 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../configs/tsconfig-base-tsx.json", "include": ["src/js/**/*"], + "exclude": ["src/js/**/*.test.ts"], "compilerOptions": { "outDir": "dist", "rootDir": "src/js", diff --git a/packages/ui/vitest.config.ts b/packages/ui/vitest.config.ts new file mode 100644 index 00000000..ce6c79ea --- /dev/null +++ b/packages/ui/vitest.config.ts @@ -0,0 +1,12 @@ +import path from "node:path"; +import {fileURLToPath} from "node:url"; + +import {defineConfig} from "vitest/config"; + +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default defineConfig({ + test: { + include: ["src/js/**/*.test.ts"], + }, +}); From 018c9942f1d09c02fa5e9338b03cff9a974550e7 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 20:22:43 +0200 Subject: [PATCH 29/49] type and schema optimizations Signed-off-by: Paul Golmann --- .../src/js/lib/map/__tests__/schema.test.ts | 93 +++++++++++++++++++ .../js/lib/map/lib/WithFeatureInteractions.ts | 27 ++++-- .../core/src/js/lib/map/lib/WithLayers.ts | 12 ++- packages/core/src/js/lib/map/schema.ts | 90 +++++++++++++++++- packages/core/src/js/lib/map/selectors.ts | 26 ++++-- packages/core/src/js/lib/map/types.ts | 77 ++++++++------- packages/core/src/js/mixins/EditorMixin.ts | 2 +- packages/core/src/js/ol-proxy/index.ts | 14 ++- .../src/js/config/map/featureInteractions.ts | 2 +- packages/ui/src/js/config/map/layers.ts | 10 +- 10 files changed, 285 insertions(+), 68 deletions(-) create mode 100644 packages/core/src/js/lib/map/__tests__/schema.test.ts diff --git a/packages/core/src/js/lib/map/__tests__/schema.test.ts b/packages/core/src/js/lib/map/__tests__/schema.test.ts new file mode 100644 index 00000000..6df3433f --- /dev/null +++ b/packages/core/src/js/lib/map/__tests__/schema.test.ts @@ -0,0 +1,93 @@ +import {describe, expect, it} from "vitest"; + +import { + layerConfigSchema, + mapConfigSchema, + vectorFeatureSourceStateSchema, +} from "@/lib/map/schema"; + +describe("map config schema", () => { + it("parses a vector feature layer with structured source options", () => { + const result = layerConfigSchema.safeParse({ + type: "VectorLayer", + options: { + visible: true, + source: { + type: "VectorFeatureSource", + options: { + featureSourceId: "pois", + clusterFeatures: true, + clusterFeaturesOptions: {distance: 40}, + }, + }, + selections: { + mousedown: "select", + mouseover: "highlight", + }, + }, + }); + expect(result.success).toBe(true); + }); + + it("parses tile and OSM source layers", () => { + expect( + layerConfigSchema.safeParse({ + type: "TileLayer", + options: { + source: { + type: "OsmSource", + options: {url: "https://tile.osm.org"}, + }, + }, + }).success, + ).toBe(true); + + expect( + layerConfigSchema.safeParse({ + type: "TileLayer", + options: { + source: { + type: "TileWMSSource", + options: {url: "/wms", params: {LAYERS: "foo"}}, + }, + }, + }).success, + ).toBe(true); + }); + + it("rejects VectorFeatureSource with wrong type literal", () => { + const result = vectorFeatureSourceStateSchema.safeParse({ + type: "VectorSource", + options: {}, + }); + expect(result.success).toBe(false); + }); + + it("parses stadtplan-style map config with cluster options", () => { + const result = mapConfigSchema.safeParse({ + layers: { + pois: { + type: "VectorLayer", + metaData: {title: "POIs", group: "Points"}, + options: { + source: { + type: "VectorFeatureSource", + options: { + featureSourceId: "pois", + keepFeaturesInViewOptions: { + padding: [20, 20, 20, 20], + }, + fitFeaturesInViewOptions: { + padding: [20, 20, 20, 20], + }, + clusterFeatures: true, + clusterFeaturesOptions: {distance: 40}, + }, + }, + }, + }, + }, + }); + expect(result.success).toBe(true); + }); +}); diff --git a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts index 50a550ba..87c0d5ee 100644 --- a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts +++ b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts @@ -16,7 +16,7 @@ import type {FeatureSelectionsState} from "@/lib/feature-selections/selectors"; import {getOlFeatureId} from "@/lib/helpers/ol"; import {typeSafeObjectKeys} from "@/lib/helpers/types"; import type {MapController} from "@/lib/map/controller"; -import type {InteractionName, MapState} from "@/lib/map/types"; +import type {MapState} from "@/lib/map/types"; import type {Action} from "@/types"; import {setMapCursor} from "../actions"; @@ -29,6 +29,14 @@ type MapEventEmitter = Pick< "getMap" | "getStore" | "getState" | "dispatch" | "getName" >; +export const FeatureInteractionNames = [ + "mousedown", + "mouseover", + "touch", +] as const; + +export type FeatureInteractionName = (typeof FeatureInteractionNames)[number]; + export type FeatureInteractionOptions = { cursor?: string; hitTolerance?: number; @@ -57,11 +65,14 @@ type AnyFeatureInteractionOptions = FeatureInteractionOptions & FeatureInteractionOverrides; export type FeatureInteraction = { - selection: InteractionName; + selection: FeatureInteractionName; options: AnyFeatureInteractionOptions; }; -export type FeatureInteractions = Record; +export type FeatureInteractions = Record< + FeatureInteractionName, + FeatureInteraction +>; const FEATURE_PROPERTY_NAME_SELECTABLE = "selectable"; @@ -147,9 +158,9 @@ const defaultFeatureInteractions = { function getSelectionId( layerId: string, - interactionName: InteractionName, + interactionName: FeatureInteractionName, state: MapState, -) { +): string { return makeLayerSelectionSelector(layerId, interactionName)(state); } @@ -225,7 +236,7 @@ type FeatureInteractionEventCache = { function handleEvent( mapController: MapEventEmitter, featureSelectionsControllerName: string, - interactionName: InteractionName, + interactionName: FeatureInteractionName, options: FeatureInteractionOptions = {}, cache: FeatureInteractionEventCache | null = null, event: MapBrowserEvent, @@ -455,7 +466,7 @@ export default class WithFeatureInteractions extends WithMap { } const handlers: Record< - InteractionName, + FeatureInteractionName, ReturnType > = { mouseover: null, @@ -466,7 +477,7 @@ export default class WithFeatureInteractions extends WithMap { this.getAndObserveUncontrolled( (state) => ({ featureInteractions: state.featureInteractions as Record< - InteractionName, + FeatureInteractionName, FeatureInteraction >, featureSelectionsControllerName: diff --git a/packages/core/src/js/lib/map/lib/WithLayers.ts b/packages/core/src/js/lib/map/lib/WithLayers.ts index 7ee2b0ef..74ff3f7c 100644 --- a/packages/core/src/js/lib/map/lib/WithLayers.ts +++ b/packages/core/src/js/lib/map/lib/WithLayers.ts @@ -9,8 +9,8 @@ import matchesPath from "@mapsight/lib-redux/matchesPath"; import reducers from "@mapsight/lib-redux/reducers/immutable-path"; import type {MapController} from "@/lib/map/controller"; -import type {LayerConfig} from "@/lib/map/schema"; -import {di, updateProxyObject} from "@/ol-proxy/index"; +import type {LayerState} from "@/lib/map/types"; +import {di, updateProxyObject} from "@/ol-proxy"; import {ACTION_SET} from "../../base/reducer"; import { @@ -21,7 +21,7 @@ import WithAnimations from "./WithAnimations"; import proxyPassOpenLayersEventsToMapController from "./proxyPassOpenLayersEventsToMapController"; import {getGroupForLayer, tagLayer} from "./tagLayer"; -export type LayerDefinition = LayerConfig; +export type LayerDefinition = LayerState; export const LAYER_GROUP_DEFAULT = "default"; @@ -97,6 +97,12 @@ export default class WithLayers extends WithAnimations { ensureNonNullable(this._groups[group]).layers[id] = layer; tagLayer(layer, this, id, group); layerGroup.getLayers().push(layer); + if (!newDefinition.type) { + console.error( + `Could not wire layer events for "${id}". Layer definition is missing type.`, + ); + return; + } proxyPassOpenLayersEventsToMapController( this as unknown as MapController, layer, diff --git a/packages/core/src/js/lib/map/schema.ts b/packages/core/src/js/lib/map/schema.ts index 6485b145..6b418745 100644 --- a/packages/core/src/js/lib/map/schema.ts +++ b/packages/core/src/js/lib/map/schema.ts @@ -1,6 +1,12 @@ import {z} from "zod"; -import {optionsSchema} from "@/lib/helpers/schema"; +import {type Options, optionsSchema} from "@/lib/helpers/schema"; +import {FeatureInteractionNames} from "@/lib/map/lib/WithFeatureInteractions"; + +export const interactionsSelectionsSchema = z.partialRecord( + z.enum(FeatureInteractionNames), + z.string(), +); export const layerMetaDataSchema = z.looseObject({ title: z.string().optional(), @@ -14,9 +20,55 @@ export const layerMetaDataSchema = z.looseObject({ visibleInExternalLayerSwitcher: z.boolean().optional(), }); +export const vectorFeatureSourceOptionsSchema = z.looseObject({ + featureSourceId: z.string().optional(), + featureSourcesControllerName: z.string().optional(), + featureSelectionsControllerName: z.string().optional(), + keepFeaturesInViewOptions: optionsSchema.optional(), + fitFeaturesInViewOptions: optionsSchema.optional(), + clusterFeatures: z.boolean().optional(), + clusterFeaturesOptions: optionsSchema.optional(), +}); + +export const vectorFeatureSourceStateSchema = z.looseObject({ + type: z.literal("VectorFeatureSource"), + options: vectorFeatureSourceOptionsSchema, +}); + +export const osmSourceStateSchema = z.looseObject({ + type: z.literal("OsmSource"), + options: z.looseObject({url: z.string().optional()}), +}); + +export const tileWmsSourceStateSchema = z.looseObject({ + type: z.literal("TileWMSSource"), + options: z.looseObject({ + projection: z.string().optional(), + url: z.string().optional(), + params: optionsSchema.optional(), + }), +}); + +/** Known ol-proxy source shapes plus a fallback for other source types. */ +export const layerSourceStateSchema = z.union([ + vectorFeatureSourceStateSchema, + osmSourceStateSchema, + tileWmsSourceStateSchema, + z.looseObject({ + type: z.string(), + options: optionsSchema.optional(), + }), +]); + +export const layerOptionsSchema = z.looseObject({ + visible: z.boolean().optional(), + selections: interactionsSelectionsSchema.optional(), + source: layerSourceStateSchema.optional(), +}); + export const descriptionSchema = z.looseObject({ type: z.string(), - options: optionsSchema.optional(), + options: layerOptionsSchema.optional(), metaData: layerMetaDataSchema.optional(), }); @@ -34,7 +86,35 @@ export const mapConfigSchema = z }) .partial(); +/** Loose-object schema output plus ol-proxy option bag. */ +type LooseOptions = z.infer & Options; + export type LayerMetaData = z.infer; -export type Description = z.infer; -export type LayerConfig = z.infer; -export type MapConfig = z.infer; +export type InteractionsSelections = z.infer< + typeof interactionsSelectionsSchema +>; +export type VectorFeatureSourceOptions = LooseOptions< + typeof vectorFeatureSourceOptionsSchema +>; +export type VectorFeatureSourceState = z.infer< + typeof vectorFeatureSourceStateSchema +> & { + options: VectorFeatureSourceOptions; +}; +export type LayerSourceState = z.infer; +export type LayerOptions = LooseOptions; + +type WithLayerOptions = Omit & { + options?: LayerOptions; +}; + +export type Description = WithLayerOptions< + Omit, "type" | "metaData"> +> & { + type: string; + metaData?: LayerMetaData; +}; +export type LayerConfig = Description; +export type MapConfig = Omit, "layers"> & { + layers?: Record; +}; diff --git a/packages/core/src/js/lib/map/selectors.ts b/packages/core/src/js/lib/map/selectors.ts index e6a6d86d..ed188bca 100644 --- a/packages/core/src/js/lib/map/selectors.ts +++ b/packages/core/src/js/lib/map/selectors.ts @@ -9,7 +9,9 @@ import type { FeatureSourceState, FeatureSourcesState, } from "@/lib/feature-sources/types"; -import type {InteractionName, LayerState, MapState} from "@/lib/map/types"; +import type {FeatureInteractionName} from "@/lib/map/lib/WithFeatureInteractions"; +import type {LayerState, MapState} from "@/lib/map/types"; +import {isVectorFeatureSource} from "@/lib/map/types"; import type {State} from "@/types"; /** @@ -24,7 +26,8 @@ export const makeLayerLockedInLayerSwitcherSelector = state.layers[id]?.metaData?.lockedInLayerSwitcher ?? false; export const makeLayerSelectionSelector = - (id: string, interactionName: InteractionName) => (state: MapState) => + (id: string, interactionName: FeatureInteractionName) => + (state: MapState) => state.layers[id]?.options?.selections?.[interactionName]; export const layerIdsIntegratedSwitcherSelector: Selector = @@ -57,13 +60,22 @@ export const makeLayerVisibleSelector = state.layers[layerId]?.options?.visible ?? false; export const makeFeatureSourceIdFromLayerIdSelector = - (layerId: string) => (state: MapState) => - state.layers[layerId]?.options?.source?.options?.featureSourceId; + (layerId: string) => (state: MapState) => { + const source = state.layers[layerId]?.options?.source; + if (!isVectorFeatureSource(source)) { + return undefined; + } + return source.options.featureSourceId; + }; export const makeFeatureSourceControllerNameFromLayerIdSelector = - (layerId: string) => (state: MapState) => - state.layers[layerId]?.options?.source?.options - ?.featureSourcesControllerName; + (layerId: string) => (state: MapState) => { + const source = state.layers[layerId]?.options?.source; + if (!isVectorFeatureSource(source)) { + return undefined; + } + return source.options.featureSourcesControllerName; + }; /** * create selector for featureState corresponding to the featureSource used by a layer diff --git a/packages/core/src/js/lib/map/types.ts b/packages/core/src/js/lib/map/types.ts index 167bf0e7..2c67e920 100644 --- a/packages/core/src/js/lib/map/types.ts +++ b/packages/core/src/js/lib/map/types.ts @@ -3,47 +3,58 @@ import type OlLayer from "ol/layer/Layer"; import type {OptionValue, Options} from "@/lib/helpers/schema"; import type {VectorFeatureSource} from "@/lib/map/lib/VectorFeatureSource"; import type {ViewportAnchor} from "@/lib/map/lib/WithAnchoredViewport"; -import type {Description, LayerConfig, LayerMetaData} from "@/lib/map/schema"; +import { + type Description, + type InteractionsSelections, + type LayerConfig, + type LayerMetaData, + type LayerOptions, + type LayerSourceState, + type VectorFeatureSourceOptions, + type VectorFeatureSourceState, + descriptionSchema, + vectorFeatureSourceStateSchema, +} from "@/lib/map/schema"; -export type {Description, LayerMetaData, OptionValue, Options}; +export type { + Description, + InteractionsSelections, + LayerMetaData, + LayerOptions, + LayerSourceState, + OptionValue, + Options, + VectorFeatureSourceOptions, + VectorFeatureSourceState, +}; export const isDescription = (value: unknown): value is Description => - typeof value === "object" && - value !== null && - "type" in value && - typeof value.type === "string"; + descriptionSchema.safeParse(value).success; -export type LayerOptions = { - visible?: boolean; - selections?: InteractionsSelections; - source?: LayerSourceState; -} & Options; +/** Runtime layer options; ol-proxy keys beyond the config schema remain valid. */ +export type RuntimeLayerOptions = LayerOptions; /** Runtime layer state; `type` is required in config ingress (`LayerConfig`). */ -export type LayerState = Omit & { +export type LayerState = Omit & { type?: string; - [key: string]: unknown; metaData?: LayerMetaData; - options?: LayerOptions; -}; + options?: RuntimeLayerOptions; +} & Record; -type VectorFeatureSourceOptions = { - featureSourceId?: string; - featureSourcesControllerName?: string; - featureSelectionsControllerName?: string; - keepFeaturesInViewOptions?: Options; - fitFeaturesInViewOptions?: Options; - clusterFeatures?: boolean; - clusterFeaturesOptions?: Options; - [key: string]: OptionValue; -}; +export const isVectorFeatureSource = ( + source: unknown, +): source is VectorFeatureSourceState => + vectorFeatureSourceStateSchema.safeParse(source).success; -type VectorFeatureSourceState = { - type: "VectorFeatureSource"; - options: VectorFeatureSourceOptions; -}; - -export type LayerSourceState = VectorFeatureSourceState; // TODO: add other types +export function getVectorFeatureSource( + layer: LayerState, +): VectorFeatureSourceState { + const source = layer.options?.source; + if (!isVectorFeatureSource(source)) { + throw new Error("Expected layer with VectorFeatureSource source"); + } + return source; +} export interface MapState { [key: string]: unknown; @@ -60,7 +71,3 @@ export type VectorFeatureSourceLayer = OlLayer; export interface LayerStyleProps {} export type LayerStyleState = string | LayerStyleProps; - -export type InteractionName = "mousedown" | "mouseover" | "touch"; - -export type InteractionsSelections = Record; diff --git a/packages/core/src/js/mixins/EditorMixin.ts b/packages/core/src/js/mixins/EditorMixin.ts index 35b34cdf..6abdd1a1 100644 --- a/packages/core/src/js/mixins/EditorMixin.ts +++ b/packages/core/src/js/mixins/EditorMixin.ts @@ -35,7 +35,7 @@ export const DEFAULT_SELECTIONS = { mousedown: "select", mouseover: "highlight", touch: "select", -}; +} satisfies InteractionsSelections; export const DEFAULT_CONTROLLER_NAMES = { map: "map", diff --git a/packages/core/src/js/ol-proxy/index.ts b/packages/core/src/js/ol-proxy/index.ts index 65fedae4..bf4630c9 100644 --- a/packages/core/src/js/ol-proxy/index.ts +++ b/packages/core/src/js/ol-proxy/index.ts @@ -1,6 +1,11 @@ import isEqual from "lodash/isEqual"; -import type {Description, OptionValue, Options} from "@/lib/map/types"; +import type { + Description, + LayerState, + OptionValue, + Options, +} from "@/lib/map/types"; import {isDescription} from "@/lib/map/types"; import DependencyManager from "./DependencyManager"; @@ -8,6 +13,9 @@ import DependencyManager from "./DependencyManager"; export {isDescription} from "@/lib/map/types"; export type {Description} from "@/lib/map/types"; +/** Config ingress or runtime layer definition accepted by ol-proxy. */ +export type LayerProxyDefinition = Description | LayerState; + // TODO: use symbols? export const OPTION_SET = "__set__"; export const OPTION_COLLECTION = "__collection__"; @@ -395,8 +403,8 @@ export function updateProxyObject< di: DependencyManager; // TODO: remove "old" prefix, there's only one object, no "old" nor "new" oldObject?: TObject; - oldDefinition?: Description; - newDefinition?: Description; + oldDefinition?: LayerProxyDefinition; + newDefinition?: LayerProxyDefinition; remover?: (object: TObject, parentObject?: TParentObject) => void; adder?: (object: TObject, parentObject?: TParentObject) => void; parentObject?: TParentObject; diff --git a/packages/ui/src/js/config/map/featureInteractions.ts b/packages/ui/src/js/config/map/featureInteractions.ts index 35448155..c53c21ec 100644 --- a/packages/ui/src/js/config/map/featureInteractions.ts +++ b/packages/ui/src/js/config/map/featureInteractions.ts @@ -49,5 +49,5 @@ export default function createFeatureInteractions({ hitTolerance: hitTolerance, }, }, - }; + } satisfies FeatureInteractions; } diff --git a/packages/ui/src/js/config/map/layers.ts b/packages/ui/src/js/config/map/layers.ts index 21de0957..a8a5ba89 100644 --- a/packages/ui/src/js/config/map/layers.ts +++ b/packages/ui/src/js/config/map/layers.ts @@ -4,7 +4,7 @@ import type { Description, LayerMetaData, OptionValue, - Options, + VectorFeatureSourceOptions, } from "@mapsight/core/lib/map/types"; import type {MapsightStyleFunctionEnv} from "@mapsight/lib-ol/style/styleFunction"; @@ -21,7 +21,7 @@ export function features( interactive = false, _metaData: LayerMetaData = {}, style: string | MapsightStyleFunctionEnv = "features", - sourceOptions?: Options, + sourceOptions?: Partial, ): Description { return { type: "VectorLayer", @@ -55,11 +55,11 @@ export function features( } export function interactiveFeatures( - featureSourceId, + featureSourceId: string, visible = false, _metaData = {}, style: string | MapsightStyleFunctionEnv = "features", - sourceOptions?: Options, + sourceOptions?: Partial, ) { return features( featureSourceId, @@ -76,7 +76,7 @@ export function userGeolocation( visible = false, _metaData: LayerMetaData = {}, style: string | MapsightStyleFunctionEnv = "userGeolocation", - sourceOptions?: Options, + sourceOptions?: Partial, ) { const base = features( featureSourceId, From 9876ae2772e5974dbd2974404781faf6c55fd359 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 20:30:43 +0200 Subject: [PATCH 30/49] quiet down ol-proxy unless dev/debug Signed-off-by: Paul Golmann --- packages/core/src/js/ol-proxy/index.ts | 29 +++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/core/src/js/ol-proxy/index.ts b/packages/core/src/js/ol-proxy/index.ts index bf4630c9..b8db1791 100644 --- a/packages/core/src/js/ol-proxy/index.ts +++ b/packages/core/src/js/ol-proxy/index.ts @@ -1,5 +1,6 @@ import isEqual from "lodash/isEqual"; +import {isDevelopment} from "@/lib/helpers/isDevelopment"; import type { Description, LayerState, @@ -10,6 +11,28 @@ import {isDescription} from "@/lib/map/types"; import DependencyManager from "./DependencyManager"; +function isMapsightDebugEnabled(): boolean { + if (typeof process !== "undefined" && process.env.MAPSIGHT_DEBUG) { + const flag = process.env.MAPSIGHT_DEBUG; + return flag !== "0" && flag !== "false"; + } + + if (typeof import.meta !== "undefined") { + const flag = ( + import.meta as ImportMeta & {env?: {MAPSIGHT_DEBUG?: string}} + ).env?.MAPSIGHT_DEBUG; + return flag != null && flag !== "" && flag !== "0" && flag !== "false"; + } + + return false; +} + +function olProxyDebug(...args: Parameters) { + if (isDevelopment() || isMapsightDebugEnabled()) { + console.debug(...args); + } +} + export {isDescription} from "@/lib/map/types"; export type {Description} from "@/lib/map/types"; @@ -345,7 +368,7 @@ function hasSomeOptionChanged( const hasChanged = !isEqual(newOptions[key], oldOptions[key]); if (hasChanged) { - console.debug("ol-proxy: v UPDATE triggered by", key); + olProxyDebug("ol-proxy: v UPDATE triggered by", key); } return hasChanged; @@ -458,7 +481,7 @@ export function updateProxyObject< adder, parentObject, ); - console.debug( + olProxyDebug( "ol-proxy: CREATE", creationReason === "new" ? "new" @@ -490,7 +513,7 @@ export function updateProxyObject< ))) && object ) { - console.debug("ol-proxy: UPDATE", type); + olProxyDebug("ol-proxy: UPDATE", type); setOptions( object, oldOptions, From e0d0cf92eded0a69714160a11dde9d596c499004 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 21:25:26 +0200 Subject: [PATCH 31/49] feat(core): combined feature sources Signed-off-by: Paul Golmann --- packages/core/package.json | 8 + .../__tests__/combined.test.ts | 192 ++++++++++++++++++ .../src/js/lib/feature-sources/actions.ts | 19 +- .../src/js/lib/feature-sources/controller.ts | 108 +++++++++- .../js/lib/feature-sources/lib/combined.ts | 57 ++++++ .../loaders/combined-loader.ts | 28 +++ .../core/src/js/lib/feature-sources/schema.ts | 8 +- 7 files changed, 416 insertions(+), 4 deletions(-) create mode 100644 packages/core/src/js/lib/feature-sources/__tests__/combined.test.ts create mode 100644 packages/core/src/js/lib/feature-sources/lib/combined.ts create mode 100644 packages/core/src/js/lib/feature-sources/loaders/combined-loader.ts diff --git a/packages/core/package.json b/packages/core/package.json index 4fc4767a..cb233479 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -40,6 +40,14 @@ "types": "./dist/lib/*.d.ts", "import": "./dist/lib/*.js" }, + "./lib/*/*": { + "types": "./dist/lib/*/*.d.ts", + "import": "./dist/lib/*/*.js" + }, + "./lib/*/lib/*": { + "types": "./dist/lib/*/lib/*.d.ts", + "import": "./dist/lib/*/lib/*.js" + }, "./lib/*/schema": { "types": "./dist/lib/*/schema.d.ts", "import": "./dist/lib/*/schema.js" diff --git a/packages/core/src/js/lib/feature-sources/__tests__/combined.test.ts b/packages/core/src/js/lib/feature-sources/__tests__/combined.test.ts new file mode 100644 index 00000000..4b783212 --- /dev/null +++ b/packages/core/src/js/lib/feature-sources/__tests__/combined.test.ts @@ -0,0 +1,192 @@ +import {describe, expect, it} from "vitest"; + +import { + combineFeatureSources, + createCombinedFeatureSourceSelector, +} from "@/lib/feature-sources/lib/combined"; + +describe("combineFeatureSources", () => { + it("merges features from member sources", () => { + const result = combineFeatureSources( + { + a: { + type: "xhr-json", + data: { + type: "FeatureCollection", + features: [ + { + id: "a1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + ], + }, + lastUpdate: null, + lastActionType: null, + }, + b: { + type: "xhr-json", + data: { + type: "FeatureCollection", + features: [ + { + id: "b1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + ], + }, + lastUpdate: null, + lastActionType: null, + }, + }, + ["a", "b"], + ); + + expect(result.features).toEqual([ + { + id: "a1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + { + id: "b1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + ]); + }); + + it("returns an empty collection for an empty member list", () => { + const result = combineFeatureSources({}, []); + + expect(result).toEqual({ + type: "FeatureCollection", + features: [], + }); + }); + + it("skips errored or empty member sources", () => { + const result = combineFeatureSources( + { + a: { + type: "xhr-json", + error: "failed", + data: { + type: "FeatureCollection", + features: [ + { + id: "a1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + ], + }, + lastUpdate: null, + lastActionType: null, + }, + b: { + type: "xhr-json", + data: null, + lastUpdate: null, + lastActionType: null, + }, + }, + ["a", "b"], + ); + + expect(result.features).toEqual([]); + }); +}); + +describe("createCombinedFeatureSourceSelector", () => { + it("reads member sources from the configured controller", () => { + const selector = createCombinedFeatureSourceSelector( + ["a", "b"], + "featureSources", + ); + const result = selector({ + featureSources: { + a: { + type: "xhr-json", + data: { + type: "FeatureCollection", + features: [ + { + id: "a1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + ], + }, + lastUpdate: null, + lastActionType: null, + }, + b: { + type: "xhr-json", + data: { + type: "FeatureCollection", + features: [ + { + id: "b1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + ], + }, + lastUpdate: null, + lastActionType: null, + }, + }, + }); + + expect(result.data.features).toEqual([ + { + id: "a1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + { + id: "b1", + properties: {}, + type: "Feature", + geometry: { + type: "Point", + coordinates: [10, 10], + }, + }, + ]); + }); +}); diff --git a/packages/core/src/js/lib/feature-sources/actions.ts b/packages/core/src/js/lib/feature-sources/actions.ts index 0a8bcfc6..168acce4 100644 --- a/packages/core/src/js/lib/feature-sources/actions.ts +++ b/packages/core/src/js/lib/feature-sources/actions.ts @@ -1,4 +1,5 @@ import {async, controlled, withPath} from "@/lib/base/actions"; +import * as combined from "@/lib/feature-sources/loaders/combined-loader"; import * as local from "@/lib/feature-sources/loaders/local-state-loader"; import type {LocalStateLoaderOptions} from "@/lib/feature-sources/loaders/local-state-loader"; import * as noop from "@/lib/feature-sources/loaders/noop-loader"; @@ -17,6 +18,8 @@ function getLoader(type: FeatureSourceType) { return local; case "xhr-json": return xhrJson; + case "combined": + return combined; default: return noop; } @@ -343,7 +346,13 @@ export const load = ( ); return Promise.all([ - loadWithCache(currentState, getState, id, options).then( + loadWithCache( + currentState, + getState, + id, + controllerName, + options, + ).then( function handleLoadResolved(data) { dispatch(loadSuccess(controllerName, id, data)); }, @@ -415,6 +424,7 @@ async function loadWithCache( state: FeatureSourceState, getState: () => unknown, id: string, + controllerName: string, options: LoadOptions = {}, ) { const { @@ -434,5 +444,10 @@ async function loadWithCache( return Promise.resolve(state.data); } - return getLoader(state.type).load(state, loaderOptions, id, getState); + return getLoader(state.type).load( + state, + {...loaderOptions, controllerName}, + id, + getState, + ); } diff --git a/packages/core/src/js/lib/feature-sources/controller.ts b/packages/core/src/js/lib/feature-sources/controller.ts index f1288060..ab4e1559 100644 --- a/packages/core/src/js/lib/feature-sources/controller.ts +++ b/packages/core/src/js/lib/feature-sources/controller.ts @@ -1,7 +1,10 @@ import isEqual from "lodash/isEqual"; import {ensureNonNullable} from "@mapsight/lib-js/nonNullable"; -import {observeState} from "@mapsight/lib-redux/observe-state"; +import { + getAndObserveState, + observeState, +} from "@mapsight/lib-redux/observe-state"; import {async} from "@/lib/base/actions"; import {BaseController} from "@/lib/base/controller"; @@ -26,6 +29,10 @@ import { PAUSE_FEATURE_SOURCE_REFRESH_UNTIL_NEXT_LOAD, setDataOrError, } from "@/lib/feature-sources/actions"; +import { + createCombinedFeatureSourceSelector, + getCombinedFeatureSourceBindings, +} from "@/lib/feature-sources/lib/combined"; import { nextDataHistory, redoChange, @@ -97,7 +104,106 @@ function reduceUncontrolledFeatureSourceChanges( const emptyFeaturesArray: Array = []; +type CombinedFeatureSourceBinding = { + featureSourceNames: string[]; + unsubscribe: () => void; +}; + export class FeatureSourcesController extends BaseController { + #combinedFeatureSourceBindings = new Map< + string, + CombinedFeatureSourceBinding + >(); + + override init() { + const store = this.getStore(); + if (!store) { + return; + } + + this.syncCombinedFeatureSourceBindings(); + + const controllerName = this.getName(); + observeState( + store, + (state) => + getCombinedFeatureSourceBindings( + state[controllerName] as FeatureSourcesState, + ), + () => this.syncCombinedFeatureSourceBindings(), + isEqual, + ); + } + + syncCombinedFeatureSourceBindings() { + const sources = this.getState() as FeatureSourcesState; + const activeIds = new Set(); + + for (const [id, source] of Object.entries(sources)) { + if (source.type !== "combined") { + continue; + } + + const featureSourceNames = source.featureSourceNames ?? []; + activeIds.add(id); + const existing = this.#combinedFeatureSourceBindings.get(id); + if ( + existing && + isEqual(existing.featureSourceNames, featureSourceNames) + ) { + continue; + } + + existing?.unsubscribe(); + this.#combinedFeatureSourceBindings.set(id, { + featureSourceNames, + unsubscribe: this.bindCombinedFeatureSource(id, source), + }); + } + + for (const [id, binding] of this.#combinedFeatureSourceBindings) { + if (!activeIds.has(id)) { + binding.unsubscribe(); + this.#combinedFeatureSourceBindings.delete(id); + } + } + } + + bindCombinedFeatureSource( + featureSourceId: string, + source: FeatureSourceState, + ) { + const controllerName = this.getName(); + const store = this.getStore(); + if (!store) { + console.error( + "Can't bind combined feature source: store is not set", + ); + return () => undefined; + } + + const selector = createCombinedFeatureSourceSelector( + source.featureSourceNames ?? [], + controllerName, + ); + + return getAndObserveState( + store, + selector, + ({data, error}) => { + this.dispatch( + async( + setDataOrError(controllerName, featureSourceId, { + data, + error, + }), + ), + ); + }, + isEqual, + ); + } + bindFeatureSourceToStore( featureSourceId: string, selector: (state: State) => FeatureSourceState, diff --git a/packages/core/src/js/lib/feature-sources/lib/combined.ts b/packages/core/src/js/lib/feature-sources/lib/combined.ts new file mode 100644 index 00000000..c164af54 --- /dev/null +++ b/packages/core/src/js/lib/feature-sources/lib/combined.ts @@ -0,0 +1,57 @@ +import type { + FeatureSourceData, + FeatureSourcesState, +} from "@/lib/feature-sources/types"; +import type {State} from "@/types"; + +/** Merges features from the named feature sources that have loaded data. */ +export function combineFeatureSources( + featureSourcesState: FeatureSourcesState | undefined, + featureSourceNames: string[], +): FeatureSourceData { + let combinedFeatures: FeatureSourceData["features"] = []; + + for (const id of featureSourceNames) { + const source = featureSourcesState?.[id]; + if (!source?.error && source?.data) { + combinedFeatures = [ + ...combinedFeatures, + ...(source.data.features ?? []), + ]; + } + } + + return { + type: "FeatureCollection", + features: combinedFeatures, + }; +} + +export function createCombinedFeatureSourceSelector( + featureSourceNames: string[], + featureSourcesControllerName: string, +) { + return function combinedFeatureSourceSelector(state: State) { + const featureSourcesState = state[featureSourcesControllerName] as + | FeatureSourcesState + | undefined; + + return { + error: null, + data: combineFeatureSources( + featureSourcesState, + featureSourceNames, + ) satisfies FeatureSourceData, + }; + }; +} + +export function getCombinedFeatureSourceBindings( + featureSources: FeatureSourcesState = {}, +) { + return Object.fromEntries( + Object.entries(featureSources) + .filter(([, source]) => source.type === "combined") + .map(([id, source]) => [id, source.featureSourceNames ?? []]), + ); +} diff --git a/packages/core/src/js/lib/feature-sources/loaders/combined-loader.ts b/packages/core/src/js/lib/feature-sources/loaders/combined-loader.ts new file mode 100644 index 00000000..65eb270b --- /dev/null +++ b/packages/core/src/js/lib/feature-sources/loaders/combined-loader.ts @@ -0,0 +1,28 @@ +import {combineFeatureSources} from "@/lib/feature-sources/lib/combined"; +import type { + FeatureSourceData, + FeatureSourceState, + FeatureSourcesState, +} from "@/lib/feature-sources/types"; +import type {State} from "@/types"; + +type CombinedLoaderOptions = { + controllerName?: string; +}; + +export function load( + state: FeatureSourceState, + options: CombinedLoaderOptions = {}, + _id: string, + getState: () => unknown, +): Promise { + const controllerName = options.controllerName ?? "featureSources"; + const featureSourcesState = (getState() as State)[controllerName] as + | FeatureSourcesState + | undefined; + const featureSourceNames = state.featureSourceNames ?? []; + + return Promise.resolve( + combineFeatureSources(featureSourcesState, featureSourceNames), + ); +} diff --git a/packages/core/src/js/lib/feature-sources/schema.ts b/packages/core/src/js/lib/feature-sources/schema.ts index c43f60fa..f4f607d2 100644 --- a/packages/core/src/js/lib/feature-sources/schema.ts +++ b/packages/core/src/js/lib/feature-sources/schema.ts @@ -1,11 +1,17 @@ import {z} from "zod"; -export const featureSourceTypeSchema = z.enum(["local", "xhr-json", "noop"]); +export const featureSourceTypeSchema = z.enum([ + "local", + "xhr-json", + "noop", + "combined", +]); export const featureSourceConfigSchema = z .object({ type: featureSourceTypeSchema, url: z.string().optional(), + featureSourceNames: z.array(z.string()).optional(), filters: z.array(z.string()).optional(), doRefresh: z.boolean().optional(), timer: z.number().optional(), From 451914847f82172599168dccb69a290f485519db Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 22:21:07 +0200 Subject: [PATCH 32/49] traffic-style: fix copy script Signed-off-by: Paul Golmann --- packages/traffic-style/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/traffic-style/package.json b/packages/traffic-style/package.json index 55352a4a..58e180c7 100644 --- a/packages/traffic-style/package.json +++ b/packages/traffic-style/package.json @@ -52,7 +52,7 @@ "clean": "rimraf tmp/* dist/*", "clean-build": "run-s clean build", "copy": "run-p copy:src copy:misc", - "copy:misc": "rimraf dist/*.scss; cp package.json README.md *.scss dist/", + "copy:misc": "cp package.json README.md base.scss full.scss dist/", "copy:src": "mkdirp dist/src; cp -r src/scss dist/src/", "lint": "eslint scripts", "typecheck": "tsc --noEmit", From 21da5a6f069b88f7fc3d0a7c8329d4add63c01e4 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 22:22:53 +0200 Subject: [PATCH 33/49] ui: add combined visible layer plugin to fill a feature source with visible features Signed-off-by: Paul Golmann --- .changeset/combined-layer-feature-source.md | 6 + .../hooks/useAutoloadFeatureSource.ts | 26 ++-- packages/ui/src/js/config/feature/sources.ts | 33 ++++- packages/ui/src/js/config/map/layers.ts | 4 +- .../plugins/common/combined-visible-layers.ts | 132 ++++++++++++++++++ 5 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 .changeset/combined-layer-feature-source.md create mode 100644 packages/ui/src/js/plugins/common/combined-visible-layers.ts diff --git a/.changeset/combined-layer-feature-source.md b/.changeset/combined-layer-feature-source.md new file mode 100644 index 00000000..8554b82f --- /dev/null +++ b/.changeset/combined-layer-feature-source.md @@ -0,0 +1,6 @@ +--- +"@mapsight/core": minor +"@mapsight/ui": minor +--- + +Add combined feature sources that merge features from multiple member sources, and a `combinedVisibleLayers` plugin that keeps a combined source in sync with whichever member map layers are currently visible. diff --git a/packages/ui/src/js/components/feature-list/hooks/useAutoloadFeatureSource.ts b/packages/ui/src/js/components/feature-list/hooks/useAutoloadFeatureSource.ts index 71a94310..ba149231 100644 --- a/packages/ui/src/js/components/feature-list/hooks/useAutoloadFeatureSource.ts +++ b/packages/ui/src/js/components/feature-list/hooks/useAutoloadFeatureSource.ts @@ -1,10 +1,11 @@ import {useEffect} from "react"; -import {useDispatch} from "react-redux"; +import {useDispatch, useSelector} from "react-redux"; -import type {AnyAction} from "@reduxjs/toolkit"; +import type {ThunkDispatch} from "redux-thunk"; import {async} from "@mapsight/core/lib/base/actions"; import {load} from "@mapsight/core/lib/feature-sources/actions"; +import type {Action, State} from "@mapsight/core/types"; import {FEATURE_SOURCES} from "../../../config/constants/controllers"; @@ -12,14 +13,19 @@ export default function useAutoloadFeatureSource( enabled = false, featureSourceId?: string, ) { - const dispatch = useDispatch(); + const dispatch = useDispatch>(); + const needsLoad = useSelector((state: State) => { + if (!featureSourceId) { + return false; + } + + const featureSource = state[FEATURE_SOURCES]?.[featureSourceId]; + return !featureSource?.data && !featureSource?.isLoading; + }); + useEffect(() => { - if (enabled && featureSourceId) { - dispatch( - async( - load(FEATURE_SOURCES, featureSourceId), - ) as unknown as AnyAction, - ); + if (enabled && featureSourceId && needsLoad) { + dispatch(async(load(FEATURE_SOURCES, featureSourceId))); } - }, [enabled, featureSourceId, dispatch]); + }, [enabled, featureSourceId, needsLoad, dispatch]); } diff --git a/packages/ui/src/js/config/feature/sources.ts b/packages/ui/src/js/config/feature/sources.ts index cfc7d36e..235ef53b 100644 --- a/packages/ui/src/js/config/feature/sources.ts +++ b/packages/ui/src/js/config/feature/sources.ts @@ -1,4 +1,10 @@ -import type {FeatureSourceState} from "@mapsight/core/lib/feature-sources/types"; +import type { + FeatureSourceConfig, + FeatureSourceState, +} from "@mapsight/core/lib/feature-sources/types"; + +type FeatureSourceDefinition = FeatureSourceConfig & + Pick; export {TIME_FILTER, TAG_FILTER} from "../constants/controllers"; @@ -8,7 +14,7 @@ export {TIME_FILTER, TAG_FILTER} from "../constants/controllers"; * * @returns config for a plain feature source */ -export function plain(): FeatureSourceState { +export function plain(): FeatureSourceDefinition { return { type: "noop" as const, data: null, @@ -23,7 +29,7 @@ export function plain(): FeatureSourceState { * @param url url to fetch data from * @returns config for a xhr json feature source */ -export function xhrJson(url: string): FeatureSourceState { +export function xhrJson(url: string): FeatureSourceDefinition { return { type: "xhr-json" as const, url: url, @@ -45,7 +51,7 @@ export function xhrJson(url: string): FeatureSourceState { export function xhrJsonRefreshing( url: string, timer: number, -): FeatureSourceState { +): FeatureSourceDefinition { return { type: "xhr-json" as const, url: url, @@ -66,12 +72,25 @@ export function xhrJsonRefreshing( * @param filterName name of filter to add to the filter collection. The feature filter will be applied when using the appropriate feature source selectors. * @returns extended definition of feature source */ -export function withFilter( - featureSource: Partial, +export function withFilter>( + featureSource: T, filterName: string, -): Partial { +): T & Pick { return { ...featureSource, filters: [...(featureSource.filters || []), filterName], }; } + +/** Creates a feature source config that aggregates member feature sources. */ +export function combinedFeatureSource( + featureSourceNames: string[] = [], +): FeatureSourceDefinition { + return { + type: "combined", + featureSourceNames, + data: null, + lastUpdate: null, + lastActionType: null, + }; +} diff --git a/packages/ui/src/js/config/map/layers.ts b/packages/ui/src/js/config/map/layers.ts index a8a5ba89..01503296 100644 --- a/packages/ui/src/js/config/map/layers.ts +++ b/packages/ui/src/js/config/map/layers.ts @@ -77,7 +77,7 @@ export function userGeolocation( _metaData: LayerMetaData = {}, style: string | MapsightStyleFunctionEnv = "userGeolocation", sourceOptions?: Partial, -) { +): Description { const base = features( featureSourceId, visible, @@ -95,7 +95,7 @@ export function userGeolocation( updateWhileInteracting: true, renderBuffer: 400, }, - }; + } as Description; } export function osm(url: string, visible = false, _metaData = {}) { diff --git a/packages/ui/src/js/plugins/common/combined-visible-layers.ts b/packages/ui/src/js/plugins/common/combined-visible-layers.ts new file mode 100644 index 00000000..22b2e549 --- /dev/null +++ b/packages/ui/src/js/plugins/common/combined-visible-layers.ts @@ -0,0 +1,132 @@ +import isEqual from "lodash/isEqual"; + +import {mergeAll} from "@mapsight/core/lib/base/actions"; +import type {EnhancedStore, State} from "@mapsight/core/types"; + +import {observeState} from "@mapsight/lib-redux/observe-state"; + +import {FEATURE_SOURCES, MAP} from "../../config/constants/controllers"; +import type {PluginInstance} from "../../types"; + +export type VisibleLayerMembers = string[] | Record; + +type VisibleLayerMember = { + featureSourceName: string; + layerName: string; +}; + +type MapLayersState = { + layers?: Record; +}; + +export type CombinedVisibleLayersBinding = { + combinedFeatureSourceId: string; + members?: VisibleLayerMembers; + getMembers?: () => VisibleLayerMembers; + mapControllerName?: string; + featureSourcesControllerName?: string; +}; + +/** + * Keeps a combined feature source in sync with the visible subset of its + * configured member layers. + */ +export default function createCombinedVisibleLayersPlugin( + options: CombinedVisibleLayersBinding, +): PluginInstance { + return { + afterCreate(context) { + if (!context.store) { + return; + } + + const store: EnhancedStore = context.store; + const mapControllerName = options.mapControllerName ?? MAP; + const featureSourcesControllerName = + options.featureSourcesControllerName ?? FEATURE_SOURCES; + const combinedFeatureSourceId = options.combinedFeatureSourceId; + const getMembers = () => + options.getMembers?.() ?? options.members ?? []; + + function syncVisibleMembers() { + const visibleFeatureSourceNames = getVisibleFeatureSourceNames( + store.getState(), + getMembers(), + mapControllerName, + ); + + store.dispatch( + mergeAll({ + [featureSourcesControllerName]: { + [combinedFeatureSourceId]: { + featureSourceNames: visibleFeatureSourceNames, + }, + }, + }), + ); + } + + observeState( + store, + (state) => + createVisibleLayerMembersObserverState( + getMembers(), + mapControllerName, + )(state), + syncVisibleMembers, + isEqual, + ); + + syncVisibleMembers(); + }, + }; +} + +function normalizeVisibleLayerMembers( + members: VisibleLayerMembers, +): VisibleLayerMember[] { + if (Array.isArray(members)) { + return members.map((featureSourceName) => ({ + featureSourceName, + layerName: featureSourceName, + })); + } + + return Object.entries(members).map(([featureSourceName, layerName]) => ({ + featureSourceName, + layerName, + })); +} + +function getVisibleFeatureSourceNames( + state: State, + members: VisibleLayerMembers, + mapControllerName: string, +): string[] { + const mapState = state[mapControllerName] as MapLayersState | undefined; + + return normalizeVisibleLayerMembers(members) + .filter( + ({layerName}) => mapState?.layers?.[layerName]?.options?.visible, + ) + .map(({featureSourceName}) => featureSourceName); +} + +function createVisibleLayerMembersObserverState( + members: VisibleLayerMembers, + mapControllerName: string, +) { + const normalizedMembers = normalizeVisibleLayerMembers(members); + + return (state: State) => { + const mapState = state[mapControllerName] as MapLayersState | undefined; + + return { + members: normalizedMembers, + visibility: normalizedMembers.map( + ({layerName}) => + mapState?.layers?.[layerName]?.options?.visible, + ), + }; + }; +} From d120e7fba9406ae824281b5c8ed7c6b6dc5ef910 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 22:23:40 +0200 Subject: [PATCH 34/49] core: fix some type issues Signed-off-by: Paul Golmann --- packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts | 2 +- packages/core/src/js/lib/map/schema.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts index 87c0d5ee..312c7d8a 100644 --- a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts +++ b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts @@ -160,7 +160,7 @@ function getSelectionId( layerId: string, interactionName: FeatureInteractionName, state: MapState, -): string { +): string | undefined { return makeLayerSelectionSelector(layerId, interactionName)(state); } diff --git a/packages/core/src/js/lib/map/schema.ts b/packages/core/src/js/lib/map/schema.ts index 6b418745..5e7109e6 100644 --- a/packages/core/src/js/lib/map/schema.ts +++ b/packages/core/src/js/lib/map/schema.ts @@ -102,7 +102,11 @@ export type VectorFeatureSourceState = z.infer< options: VectorFeatureSourceOptions; }; export type LayerSourceState = z.infer; -export type LayerOptions = LooseOptions; +export type LayerOptions = { + visible?: boolean; + selections?: InteractionsSelections; + source?: LayerSourceState; +} & Omit; type WithLayerOptions = Omit & { options?: LayerOptions; From 718d15adeb700c9d96471914a300e1cdda1a41dd Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 22:31:22 +0200 Subject: [PATCH 35/49] add demo for combined list Signed-off-by: Paul Golmann --- apps/demo-next/package.json | 2 + .../public/combined-list/cafes.geojson | 47 ++++++ .../public/combined-list/parks.geojson | 47 ++++++ .../combined-list/MapsightCombinedListUi.tsx | 64 ++++++++ apps/demo-next/src/app/combined-list/page.tsx | 5 + apps/demo-next/src/app/ui/MapsightAppUi.tsx | 3 + apps/demo-vite/package.json | 2 + apps/demo-vite/src/combined-list/client.tsx | 23 +++ .../src/combined-list/data/cafes.geojson | 47 ++++++ .../src/combined-list/data/parks.geojson | 47 ++++++ apps/demo-vite/src/combined-list/index.html | 16 ++ apps/demo-vite/src/combined-list/shared.tsx | 11 ++ apps/demo-vite/src/full/shared.tsx | 11 +- apps/demo-vite/src/index.html | 1 + apps/demo-vite/vite.config.ts | 3 + configs/vite-workspace-dev.mts | 2 + packages/demo-shared/data/cafes.geojson | 47 ++++++ packages/demo-shared/data/parks.geojson | 47 ++++++ packages/demo-shared/package.json | 30 ++++ packages/demo-shared/src/combined-list.ts | 152 ++++++++++++++++++ packages/demo-shared/tsconfig.build.json | 12 ++ packages/demo-shared/tsconfig.json | 5 + 22 files changed, 620 insertions(+), 4 deletions(-) create mode 100644 apps/demo-next/public/combined-list/cafes.geojson create mode 100644 apps/demo-next/public/combined-list/parks.geojson create mode 100644 apps/demo-next/src/app/combined-list/MapsightCombinedListUi.tsx create mode 100644 apps/demo-next/src/app/combined-list/page.tsx create mode 100644 apps/demo-vite/src/combined-list/client.tsx create mode 100644 apps/demo-vite/src/combined-list/data/cafes.geojson create mode 100644 apps/demo-vite/src/combined-list/data/parks.geojson create mode 100644 apps/demo-vite/src/combined-list/index.html create mode 100644 apps/demo-vite/src/combined-list/shared.tsx create mode 100644 packages/demo-shared/data/cafes.geojson create mode 100644 packages/demo-shared/data/parks.geojson create mode 100644 packages/demo-shared/package.json create mode 100644 packages/demo-shared/src/combined-list.ts create mode 100644 packages/demo-shared/tsconfig.build.json create mode 100644 packages/demo-shared/tsconfig.json diff --git a/apps/demo-next/package.json b/apps/demo-next/package.json index 5cc96b54..a7cae770 100644 --- a/apps/demo-next/package.json +++ b/apps/demo-next/package.json @@ -5,6 +5,7 @@ "private": true, "dependencies": { "@mapsight/core": "workspace:^", + "@mapsight/demo-shared": "workspace:^", "@mapsight/lib-js": "workspace:^", "@mapsight/lib-ol": "workspace:^", "@mapsight/traffic-style": "workspace:^", @@ -38,6 +39,7 @@ "clean": "rimraf dist .next src/generated public/img/mapsight*", "clean-build": "run-s clean build", "copy": "run-p copy:*", + "copy:demo-data": "mkdirp public/combined-list && cp ../../packages/demo-shared/data/*.geojson public/combined-list/", "copy:traffic-style": "mkdirp public/img && cp -R node_modules/@mapsight/traffic-style/img/* public/img/", "copy:ui": "mkdirp public/img && cp -R node_modules/@mapsight/ui/dist/img/* public/img/", "dev": "npm-run-all --parallel build:mapsightStyle copy --sequential dev:app", diff --git a/apps/demo-next/public/combined-list/cafes.geojson b/apps/demo-next/public/combined-list/cafes.geojson new file mode 100644 index 00000000..0be69d0b --- /dev/null +++ b/apps/demo-next/public/combined-list/cafes.geojson @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "demo-cafe-corner", + "geometry": { + "type": "Point", + "coordinates": [10.5214, 52.2661] + }, + "properties": { + "id": "demo-cafe-corner", + "name": "Corner Cafe", + "listInformation": "Coffee and pastries", + "description": "

Cozy neighborhood cafe with outdoor seating.

" + } + }, + { + "type": "Feature", + "id": "demo-cafe-market", + "geometry": { + "type": "Point", + "coordinates": [10.5278, 52.2635] + }, + "properties": { + "id": "demo-cafe-market", + "name": "Market Square Bistro", + "listInformation": "Lunch menu and espresso bar", + "description": "

Busy spot next to the weekly market.

" + } + }, + { + "type": "Feature", + "id": "demo-cafe-garden", + "geometry": { + "type": "Point", + "coordinates": [10.5159, 52.2697] + }, + "properties": { + "id": "demo-cafe-garden", + "name": "Garden Terrace", + "listInformation": "Brunch and herbal tea", + "description": "

Relaxed cafe behind a courtyard garden.

" + } + } + ] +} diff --git a/apps/demo-next/public/combined-list/parks.geojson b/apps/demo-next/public/combined-list/parks.geojson new file mode 100644 index 00000000..93a99dd0 --- /dev/null +++ b/apps/demo-next/public/combined-list/parks.geojson @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "demo-park-riverside", + "geometry": { + "type": "Point", + "coordinates": [10.5182, 52.2684] + }, + "properties": { + "id": "demo-park-riverside", + "name": "Riverside Park", + "listInformation": "Green space along the river", + "description": "

Quiet park with walking paths and picnic areas.

" + } + }, + { + "type": "Feature", + "id": "demo-park-central", + "geometry": { + "type": "Point", + "coordinates": [10.5251, 52.2648] + }, + "properties": { + "id": "demo-park-central", + "name": "Central Gardens", + "listInformation": "Formal gardens in the city center", + "description": "

Shaded benches and seasonal flower beds.

" + } + }, + { + "type": "Feature", + "id": "demo-park-hilltop", + "geometry": { + "type": "Point", + "coordinates": [10.5316, 52.2612] + }, + "properties": { + "id": "demo-park-hilltop", + "name": "Hilltop Lookout", + "listInformation": "Small park with a viewpoint", + "description": "

Panoramic views over the old town.

" + } + } + ] +} diff --git a/apps/demo-next/src/app/combined-list/MapsightCombinedListUi.tsx b/apps/demo-next/src/app/combined-list/MapsightCombinedListUi.tsx new file mode 100644 index 00000000..39e2f23d --- /dev/null +++ b/apps/demo-next/src/app/combined-list/MapsightCombinedListUi.tsx @@ -0,0 +1,64 @@ +"use client"; + +import {useMemo} from "react"; + +import {createCombinedListDemo} from "@mapsight/demo-shared/combined-list"; +import App from "@mapsight/ui/components/app"; +import Instance from "@mapsight/ui/components/instance"; +import createDefaultBrowserPlugins from "@mapsight/ui/plugins/browser-defaults"; +import createLangPlugin from "@mapsight/ui/plugins/common/lang"; +import createDefaultServerPlugins from "@mapsight/ui/plugins/server-defaults"; +import type {CreateOptions, PluginDefinition} from "@mapsight/ui/types"; + +import styleFunction from "@/generated/mapsight-vector-styles/demo"; + +export default function MapsightCombinedListUi() { + const isClient = + typeof window !== "undefined" && typeof document !== "undefined"; + + const {baseMapsightConfig, createOptions: combinedListOptions} = useMemo( + () => + createCombinedListDemo({ + parks: "/combined-list/parks.geojson", + cafes: "/combined-list/cafes.geojson", + }), + [], + ); + + const createOptions = useMemo( + () => ({ + lang: "en", + imagesUrl: "/img/", + plugins: [ + ["lang", createLangPlugin()], + ...(combinedListOptions.plugins || []), + ...(isClient + ? createDefaultBrowserPlugins() + : createDefaultServerPlugins()), + ] as PluginDefinition[], + uiState: combinedListOptions.uiState, + }), + [isClient, combinedListOptions], + ); + + return ( +
+

+ ← Single-source demo +

+

Combined list demo

+

+ Toggle Parks and Cafes in the + layer switcher. The list shows features from all currently + visible layers. +

+ + + +
+ ); +} diff --git a/apps/demo-next/src/app/combined-list/page.tsx b/apps/demo-next/src/app/combined-list/page.tsx new file mode 100644 index 00000000..bc13dda7 --- /dev/null +++ b/apps/demo-next/src/app/combined-list/page.tsx @@ -0,0 +1,5 @@ +import MapsightCombinedListUi from "@/app/combined-list/MapsightCombinedListUi"; + +export default function CombinedListPage() { + return ; +} diff --git a/apps/demo-next/src/app/ui/MapsightAppUi.tsx b/apps/demo-next/src/app/ui/MapsightAppUi.tsx index 2048855c..9b06806a 100644 --- a/apps/demo-next/src/app/ui/MapsightAppUi.tsx +++ b/apps/demo-next/src/app/ui/MapsightAppUi.tsx @@ -154,6 +154,9 @@ export default function MapsightAppUi() { return (
+

+ Combined list demo → +

Mapsight Map

+ + , +); diff --git a/apps/demo-vite/src/combined-list/data/cafes.geojson b/apps/demo-vite/src/combined-list/data/cafes.geojson new file mode 100644 index 00000000..0be69d0b --- /dev/null +++ b/apps/demo-vite/src/combined-list/data/cafes.geojson @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "demo-cafe-corner", + "geometry": { + "type": "Point", + "coordinates": [10.5214, 52.2661] + }, + "properties": { + "id": "demo-cafe-corner", + "name": "Corner Cafe", + "listInformation": "Coffee and pastries", + "description": "

Cozy neighborhood cafe with outdoor seating.

" + } + }, + { + "type": "Feature", + "id": "demo-cafe-market", + "geometry": { + "type": "Point", + "coordinates": [10.5278, 52.2635] + }, + "properties": { + "id": "demo-cafe-market", + "name": "Market Square Bistro", + "listInformation": "Lunch menu and espresso bar", + "description": "

Busy spot next to the weekly market.

" + } + }, + { + "type": "Feature", + "id": "demo-cafe-garden", + "geometry": { + "type": "Point", + "coordinates": [10.5159, 52.2697] + }, + "properties": { + "id": "demo-cafe-garden", + "name": "Garden Terrace", + "listInformation": "Brunch and herbal tea", + "description": "

Relaxed cafe behind a courtyard garden.

" + } + } + ] +} diff --git a/apps/demo-vite/src/combined-list/data/parks.geojson b/apps/demo-vite/src/combined-list/data/parks.geojson new file mode 100644 index 00000000..93a99dd0 --- /dev/null +++ b/apps/demo-vite/src/combined-list/data/parks.geojson @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "demo-park-riverside", + "geometry": { + "type": "Point", + "coordinates": [10.5182, 52.2684] + }, + "properties": { + "id": "demo-park-riverside", + "name": "Riverside Park", + "listInformation": "Green space along the river", + "description": "

Quiet park with walking paths and picnic areas.

" + } + }, + { + "type": "Feature", + "id": "demo-park-central", + "geometry": { + "type": "Point", + "coordinates": [10.5251, 52.2648] + }, + "properties": { + "id": "demo-park-central", + "name": "Central Gardens", + "listInformation": "Formal gardens in the city center", + "description": "

Shaded benches and seasonal flower beds.

" + } + }, + { + "type": "Feature", + "id": "demo-park-hilltop", + "geometry": { + "type": "Point", + "coordinates": [10.5316, 52.2612] + }, + "properties": { + "id": "demo-park-hilltop", + "name": "Hilltop Lookout", + "listInformation": "Small park with a viewpoint", + "description": "

Panoramic views over the old town.

" + } + } + ] +} diff --git a/apps/demo-vite/src/combined-list/index.html b/apps/demo-vite/src/combined-list/index.html new file mode 100644 index 00000000..304cfe12 --- /dev/null +++ b/apps/demo-vite/src/combined-list/index.html @@ -0,0 +1,16 @@ + +Mapsight combined list demo + + + +← Index + +

Combined list demo

+

+ Toggle Parks and Cafes in the layer switcher. + The list shows features from all currently visible layers. +

+ +
+ + diff --git a/apps/demo-vite/src/combined-list/shared.tsx b/apps/demo-vite/src/combined-list/shared.tsx new file mode 100644 index 00000000..ad1e7456 --- /dev/null +++ b/apps/demo-vite/src/combined-list/shared.tsx @@ -0,0 +1,11 @@ +import {createCombinedListDemo} from "@mapsight/demo-shared/combined-list"; + +export {default as styleFunction} from "../generated/mapsight-vector-styles/demo"; + +const parksUrl = new URL("./data/parks.geojson", import.meta.url).toString(); +const cafesUrl = new URL("./data/cafes.geojson", import.meta.url).toString(); + +export const {baseMapsightConfig, createOptions} = createCombinedListDemo({ + parks: parksUrl, + cafes: cafesUrl, +}); diff --git a/apps/demo-vite/src/full/shared.tsx b/apps/demo-vite/src/full/shared.tsx index 6d55c9e1..45d06709 100644 --- a/apps/demo-vite/src/full/shared.tsx +++ b/apps/demo-vite/src/full/shared.tsx @@ -45,10 +45,13 @@ const clusterFeaturesOptions = { }; function withClustering(layer: LayerDefinition): LayerDefinition { - Object.assign(layer.options.source.options, { - clusterFeatures: true, - clusterFeaturesOptions: clusterFeaturesOptions, - }); + const source = layer.options?.source; + if (source?.type === "VectorFeatureSource" && source.options) { + Object.assign(source.options, { + clusterFeatures: true, + clusterFeaturesOptions: clusterFeaturesOptions, + }); + } return layer; } diff --git a/apps/demo-vite/src/index.html b/apps/demo-vite/src/index.html index 01fb55a4..4bcc2901 100644 --- a/apps/demo-vite/src/index.html +++ b/apps/demo-vite/src/index.html @@ -10,4 +10,5 @@

Mapsight UI Index

  • Full
  • Custom
  • With Router
  • +
  • Combined list
  • diff --git a/apps/demo-vite/vite.config.ts b/apps/demo-vite/vite.config.ts index 9984e1e2..c8e41822 100644 --- a/apps/demo-vite/vite.config.ts +++ b/apps/demo-vite/vite.config.ts @@ -22,6 +22,8 @@ export default defineConfig(({command}) => ({ }, optimizeDeps: { exclude: [...workspacePackages], + // build.rolldownOptions.input paths are relative to `root`; dep scan resolves from cwd. + entries: ["**/*.html"], }, build: { outDir: "../dist", @@ -34,6 +36,7 @@ export default defineConfig(({command}) => ({ "simple-map.html", "router/index.html", "full/index.html", + "combined-list/index.html", ], output: { codeSplitting: { diff --git a/configs/vite-workspace-dev.mts b/configs/vite-workspace-dev.mts index 876ccd5c..edfb879d 100644 --- a/configs/vite-workspace-dev.mts +++ b/configs/vite-workspace-dev.mts @@ -12,6 +12,7 @@ export const repoRoot = path.resolve(configDir, ".."); /** Workspace packages resolved from source during Vite dev (serve). */ export const workspacePackages = [ "@mapsight/core", + "@mapsight/demo-shared", "@mapsight/ui", "@mapsight/lib-js", "@mapsight/lib-ol", @@ -20,6 +21,7 @@ export const workspacePackages = [ const packageSourceRoots = { "@mapsight/core": path.join(repoRoot, "packages/core/src/js"), + "@mapsight/demo-shared": path.join(repoRoot, "packages/demo-shared/src"), "@mapsight/ui": path.join(repoRoot, "packages/ui/src/js"), "@mapsight/lib-js": path.join(repoRoot, "packages/lib-js/src/js"), "@mapsight/lib-ol": path.join(repoRoot, "packages/lib-ol/src/js"), diff --git a/packages/demo-shared/data/cafes.geojson b/packages/demo-shared/data/cafes.geojson new file mode 100644 index 00000000..0be69d0b --- /dev/null +++ b/packages/demo-shared/data/cafes.geojson @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "demo-cafe-corner", + "geometry": { + "type": "Point", + "coordinates": [10.5214, 52.2661] + }, + "properties": { + "id": "demo-cafe-corner", + "name": "Corner Cafe", + "listInformation": "Coffee and pastries", + "description": "

    Cozy neighborhood cafe with outdoor seating.

    " + } + }, + { + "type": "Feature", + "id": "demo-cafe-market", + "geometry": { + "type": "Point", + "coordinates": [10.5278, 52.2635] + }, + "properties": { + "id": "demo-cafe-market", + "name": "Market Square Bistro", + "listInformation": "Lunch menu and espresso bar", + "description": "

    Busy spot next to the weekly market.

    " + } + }, + { + "type": "Feature", + "id": "demo-cafe-garden", + "geometry": { + "type": "Point", + "coordinates": [10.5159, 52.2697] + }, + "properties": { + "id": "demo-cafe-garden", + "name": "Garden Terrace", + "listInformation": "Brunch and herbal tea", + "description": "

    Relaxed cafe behind a courtyard garden.

    " + } + } + ] +} diff --git a/packages/demo-shared/data/parks.geojson b/packages/demo-shared/data/parks.geojson new file mode 100644 index 00000000..93a99dd0 --- /dev/null +++ b/packages/demo-shared/data/parks.geojson @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "demo-park-riverside", + "geometry": { + "type": "Point", + "coordinates": [10.5182, 52.2684] + }, + "properties": { + "id": "demo-park-riverside", + "name": "Riverside Park", + "listInformation": "Green space along the river", + "description": "

    Quiet park with walking paths and picnic areas.

    " + } + }, + { + "type": "Feature", + "id": "demo-park-central", + "geometry": { + "type": "Point", + "coordinates": [10.5251, 52.2648] + }, + "properties": { + "id": "demo-park-central", + "name": "Central Gardens", + "listInformation": "Formal gardens in the city center", + "description": "

    Shaded benches and seasonal flower beds.

    " + } + }, + { + "type": "Feature", + "id": "demo-park-hilltop", + "geometry": { + "type": "Point", + "coordinates": [10.5316, 52.2612] + }, + "properties": { + "id": "demo-park-hilltop", + "name": "Hilltop Lookout", + "listInformation": "Small park with a viewpoint", + "description": "

    Panoramic views over the old town.

    " + } + } + ] +} diff --git a/packages/demo-shared/package.json b/packages/demo-shared/package.json new file mode 100644 index 00000000..01883824 --- /dev/null +++ b/packages/demo-shared/package.json @@ -0,0 +1,30 @@ +{ + "name": "@mapsight/demo-shared", + "description": "Shared Mapsight demo configurations", + "version": "0.0.1", + "private": true, + "type": "module", + "dependencies": { + "@mapsight/ui": "workspace:^" + }, + "devDependencies": { + "@types/react": "catalog:", + "typescript": "catalog:" + }, + "exports": { + "./*": { + "types": "./dist/*.d.ts", + "default": "./dist/*.js" + } + }, + "license": "UNLICENSED", + "repository": { + "url": "https://github.com/open-mapsight/mapsight" + }, + "scripts": { + "build": "tsc --project tsconfig.build.json --outDir dist", + "clean": "rm -rf dist", + "clean-build": "run-s clean build", + "typecheck": "tsc --noEmit" + } +} diff --git a/packages/demo-shared/src/combined-list.ts b/packages/demo-shared/src/combined-list.ts new file mode 100644 index 00000000..74c1e8d0 --- /dev/null +++ b/packages/demo-shared/src/combined-list.ts @@ -0,0 +1,152 @@ +import * as config from "@mapsight/ui/config"; +import { + TAG_FILTER, + combinedFeatureSource, + withFilter, + xhrJson, +} from "@mapsight/ui/config/feature/sources"; +import { + interactiveFeatures, + metaData, + osm, +} from "@mapsight/ui/config/map/layers"; +import createCombinedVisibleLayersPlugin from "@mapsight/ui/plugins/common/combined-visible-layers"; +import type {CreateOptions} from "@mapsight/ui/types"; + +/** Feature source and layer id for the parks demo layer. */ +export const PARKS_LAYER_ID = "parks"; + +/** Feature source and layer id for the cafes demo layer. */ +export const CAFES_LAYER_ID = "cafes"; + +/** Combined list feature source id (aggregates visible member layers). */ +export const LIST_COMBINED_FEATURE_SOURCE_ID = "listCombined"; + +/** Member layers that feed the combined list when visible. */ +export const LIST_MEMBER_LAYER_IDS = [PARKS_LAYER_ID, CAFES_LAYER_ID] as const; + +export type CombinedListDemoUrls = { + parks: string; + cafes: string; +}; + +const DEMO_MAP_CENTER = config.mapViewCenter(1171479, 6848253); +const DEMO_MAP_EXTENT = config.mapViewExtent( + 1097392, + 6789091, + 1240635, + 6895797, +); + +/** + * Demo config: two feature layers with a list backed by a combined feature + * source. The combinedVisibleLayers plugin keeps the list in sync with which + * member layers are currently visible in the layer switcher. + */ +export function createCombinedListDemo(urls: CombinedListDemoUrls): { + baseMapsightConfig: object; + createOptions: CreateOptions; +} { + const baseMapsightConfig = { + ...config.map( + { + osm: osm( + "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + true, + metaData( + "OSM", + '© OpenStreetMap contributors', + true, + false, + true, + "Base map", + ), + ), + [PARKS_LAYER_ID]: interactiveFeatures( + PARKS_LAYER_ID, + true, + metaData( + "Parks", + null, + true, + true, + false, + "Points of interest", + ), + { + style: "features", + mapsightIconId: "sportanlage", + }, + ), + [CAFES_LAYER_ID]: interactiveFeatures( + CAFES_LAYER_ID, + true, + metaData( + "Cafes", + null, + true, + true, + false, + "Points of interest", + ), + { + style: "features", + mapsightIconId: "marker", + }, + ), + }, + config.mapView(DEMO_MAP_CENTER, DEMO_MAP_EXTENT, 14, 10, 18), + ), + ...config.features({ + [PARKS_LAYER_ID]: xhrJson(urls.parks), + [CAFES_LAYER_ID]: xhrJson(urls.cafes), + [LIST_COMBINED_FEATURE_SOURCE_ID]: withFilter( + combinedFeatureSource(), + TAG_FILTER, + ), + }), + ...config.featureList(LIST_COMBINED_FEATURE_SOURCE_ID, true), + }; + + const createOptions: CreateOptions = { + plugins: [ + [ + "combinedVisibleLayers", + createCombinedVisibleLayersPlugin({ + combinedFeatureSourceId: LIST_COMBINED_FEATURE_SOURCE_ID, + members: [...LIST_MEMBER_LAYER_IDS], + }), + ], + ], + uiState: { + map: { + show: true, + }, + list: { + show: true, + selectOnClick: "mainAndIcon", + selectionBehavior: { + desktop: "scrollToMap", + mobile: "showInMapOnlyView", + }, + filterControl: true, + sortControl: true, + }, + layerSwitcher: { + show: { + internal: true, + external: true, + }, + internal: { + grouped: true, + }, + external: { + grouped: true, + setFeatureSourceId: true, + }, + }, + }, + }; + + return {baseMapsightConfig, createOptions}; +} diff --git a/packages/demo-shared/tsconfig.build.json b/packages/demo-shared/tsconfig.build.json new file mode 100644 index 00000000..ec1c9105 --- /dev/null +++ b/packages/demo-shared/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "declarationMap": true, + "isolatedDeclarations": false, + "rootDir": "src" + }, + "exclude": ["**/*.test.ts"] +} diff --git a/packages/demo-shared/tsconfig.json b/packages/demo-shared/tsconfig.json new file mode 100644 index 00000000..abcf0311 --- /dev/null +++ b/packages/demo-shared/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../configs/tsconfig-base-tsx.json", + "include": ["src/**/*"] +} From 0e8dcb7456b1e05e35befb3774e3fe1e274e9e65 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 22:32:06 +0200 Subject: [PATCH 36/49] docs: add section about batched actions Signed-off-by: Paul Golmann --- docs/MAPSIGHT_REDUX_ARCHITECTURE.md | 50 ++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/docs/MAPSIGHT_REDUX_ARCHITECTURE.md b/docs/MAPSIGHT_REDUX_ARCHITECTURE.md index 7c944202..169865dc 100644 --- a/docs/MAPSIGHT_REDUX_ARCHITECTURE.md +++ b/docs/MAPSIGHT_REDUX_ARCHITECTURE.md @@ -209,7 +209,7 @@ This lets one action type work across all slices without slice-specific action c | Async | `MAPSIGHT_ASYNC_ACTION` | Queue dispatch to avoid dispatch-during-dispatch. Often wraps thunks that dispatch controlled actions. | | Quiet | `MAPSIGHT_QUIET_ACTION` | Hide from Redux DevTools (high-frequency updates like zoom). | -Helpers: `controlled(action)`, `async(action)`, `quiet(action)` — recursively applied inside batched actions. +Helpers: `controlled(action)`, `async(action)`, `quiet(action)` — recursively applied inside batched actions. See [Batched actions caveat](#batched-actions-caveat-redux-batched-actions) below for why that recursion matters. --- @@ -261,6 +261,54 @@ this.getAndObserveUncontrolled( ); ``` +### Batched actions caveat (`redux-batched-actions`) + +Mapsight batches related dispatches with `batchActions()` from `redux-batched-actions`. The +`batchDispatchMiddleware` does **not** treat a batch as one atomic dispatch — it unwraps the +wrapper and calls `store.dispatch` once per child action. + +`enableControlledDispatchAndObserve` mirrors that: it sets a `wasControlled` flag on **each** +`dispatch` call, based only on whether **that** action carries +`meta.MAPSIGHT_CONTROLLED_ACTION`. After every dispatch (including each child inside a batch), +the store subscription runs and `observeUncontrolled` listeners fire when `wasControlled` is +false. + +**Implication:** marking only the outer batch wrapper as controlled is not enough. If children +are dispatched without the flag, observers treat them as uncontrolled and may sync state back +to OpenLayers — reintroducing the feedback loop the controlled flag exists to prevent. + +**What Mapsight does:** `controlled()` (and `quiet()`) recurse into batched payloads and apply +the flag to every child: + +```typescript +// packages/core/src/js/lib/base/actions.ts +export function controlled(action: Action) { + action.meta = action.meta || {}; + action.meta[CONTROLLED_ACTION_FLAG] = true; + + if (isBatchedAction(action)) { + action.payload = action.payload.map((batchedAction) => + controlled(batchedAction), + ); + } + + return action; +} +``` + +So `dispatch(controlled(batchActions([setA, setB])))` results in two child dispatches, each +individually flagged — observers stay quiet for the whole batch. + +**Contributor checklist:** + +| Do | Don't | +| -------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| Use `controlled(batchActions([…]))` or `controlled()` per child | Hand-roll `{ meta: { batch: true }, payload: […] }` without recursing | +| Copy the recurse pattern when adding new meta-flag helpers | Assume the outer batch wrapper propagates flags to children | +| Use `flattenActions()` when inspecting batch contents (DevTools, watchers) | Rely on the wrapper action alone for controlled / quiet semantics | + +See also: `packages/lib-redux/src/js/flatten-actions.ts` (deep flatten for nested batches). + --- ## ol-proxy From c7a3ce646da4781b1567405734ecfd6657c469f0 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 23:07:29 +0200 Subject: [PATCH 37/49] core: extract feature interaction names into separate file Signed-off-by: Paul Golmann --- .../src/js/lib/map/lib/WithFeatureInteractions.ts | 14 ++++++-------- .../src/js/lib/map/lib/featureInteractionNames.ts | 7 +++++++ packages/core/src/js/lib/map/schema.ts | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 packages/core/src/js/lib/map/lib/featureInteractionNames.ts diff --git a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts index 312c7d8a..9204b0d4 100644 --- a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts +++ b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts @@ -22,21 +22,19 @@ import type {Action} from "@/types"; import {setMapCursor} from "../actions"; import {makeLayerSelectionSelector} from "../selectors"; import WithMap from "./WithMap"; +import { + type FeatureInteractionName, + FeatureInteractionNames, +} from "./featureInteractionNames"; import {getIdForLayer} from "./tagLayer"; +export {FeatureInteractionNames, type FeatureInteractionName}; + type MapEventEmitter = Pick< MapController, "getMap" | "getStore" | "getState" | "dispatch" | "getName" >; -export const FeatureInteractionNames = [ - "mousedown", - "mouseover", - "touch", -] as const; - -export type FeatureInteractionName = (typeof FeatureInteractionNames)[number]; - export type FeatureInteractionOptions = { cursor?: string; hitTolerance?: number; diff --git a/packages/core/src/js/lib/map/lib/featureInteractionNames.ts b/packages/core/src/js/lib/map/lib/featureInteractionNames.ts new file mode 100644 index 00000000..b67528e1 --- /dev/null +++ b/packages/core/src/js/lib/map/lib/featureInteractionNames.ts @@ -0,0 +1,7 @@ +export const FeatureInteractionNames = [ + "mousedown", + "mouseover", + "touch", +] as const; + +export type FeatureInteractionName = (typeof FeatureInteractionNames)[number]; diff --git a/packages/core/src/js/lib/map/schema.ts b/packages/core/src/js/lib/map/schema.ts index 5e7109e6..9a4fbb4d 100644 --- a/packages/core/src/js/lib/map/schema.ts +++ b/packages/core/src/js/lib/map/schema.ts @@ -1,7 +1,7 @@ import {z} from "zod"; import {type Options, optionsSchema} from "@/lib/helpers/schema"; -import {FeatureInteractionNames} from "@/lib/map/lib/WithFeatureInteractions"; +import {FeatureInteractionNames} from "@/lib/map/lib/featureInteractionNames"; export const interactionsSelectionsSchema = z.partialRecord( z.enum(FeatureInteractionNames), From 4e5c8465c1adbb015fa61ae534191676ceab6b60 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 23:13:26 +0200 Subject: [PATCH 38/49] properly exclude tests and cleanup what files are published to npm Signed-off-by: Paul Golmann --- packages/core/.npmignore | 8 ++++---- packages/core/package.json | 3 +++ packages/core/tsconfig.json | 1 + packages/lib-js/.npmignore | 7 +++---- packages/lib-js/package.json | 3 +++ packages/lib-js/tsconfig.build.json | 7 ++++++- packages/lib-ol/.npmignore | 7 +++---- packages/lib-ol/package.json | 3 +++ packages/lib-ol/tsconfig.json | 1 + packages/lib-redux/.npmignore | 7 +++---- packages/lib-redux/package.json | 3 +++ packages/lib-redux/tsconfig.json | 1 + packages/traffic-style/.npmignore | 5 +++-- packages/traffic-style/tsconfig.json | 1 + packages/ui/.npmignore | 7 +++---- packages/ui/package.json | 3 +++ packages/ui/tsconfig.json | 2 +- packages/vector-style-compiler/.npmignore | 7 +++---- packages/vector-style-compiler/package.json | 4 ++++ packages/vector-style-compiler/tsconfig.build.json | 2 +- 20 files changed, 53 insertions(+), 29 deletions(-) diff --git a/packages/core/.npmignore b/packages/core/.npmignore index cf06fbb4..515699ab 100644 --- a/packages/core/.npmignore +++ b/packages/core/.npmignore @@ -1,4 +1,4 @@ -* - -!/dist/**/* -!/src/**/* +# Publish surface is package.json "files" (dist only). +# Exclude test output if it ever lands in dist. +**/__tests__/** +**/*.test.* diff --git a/packages/core/package.json b/packages/core/package.json index cb233479..b1726053 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -77,6 +77,9 @@ "import": "./dist/schema/index.js" } }, + "files": [ + "dist" + ], "license": "UNLICENSED", "peerDependencies": { "@redux-devtools/extension": "^3.3.0", diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 0c106d71..5e1a7157 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../configs/tsconfig-base.json", "include": ["src/js/**/*"], + "exclude": ["**/__tests__/**", "**/*.test.ts", "src/js/test/**"], "compilerOptions": { "outDir": "dist", "rootDir": "src/js", diff --git a/packages/lib-js/.npmignore b/packages/lib-js/.npmignore index cf06fbb4..3af222d6 100644 --- a/packages/lib-js/.npmignore +++ b/packages/lib-js/.npmignore @@ -1,4 +1,3 @@ -* - -!/dist/**/* -!/src/**/* +# Publish surface is package.json "files" (dist only). +**/__tests__/** +**/*.test.* diff --git a/packages/lib-js/package.json b/packages/lib-js/package.json index 66674e92..5e0a6e27 100644 --- a/packages/lib-js/package.json +++ b/packages/lib-js/package.json @@ -16,6 +16,9 @@ "import": "./dist/*.js" } }, + "files": [ + "dist" + ], "license": "UNLICENSED", "repository": { "url": "https://github.com/open-mapsight/mapsight" diff --git a/packages/lib-js/tsconfig.build.json b/packages/lib-js/tsconfig.build.json index 6636332a..a8a6123f 100644 --- a/packages/lib-js/tsconfig.build.json +++ b/packages/lib-js/tsconfig.build.json @@ -1,6 +1,11 @@ { "extends": "./tsconfig.json", - "exclude": ["scripts/**/*", "**/*.spec.ts", "**/*.test.ts"], + "exclude": [ + "scripts/**/*", + "**/__tests__/**", + "**/*.spec.ts", + "**/*.test.ts" + ], "include": ["src/js/**/*"], "compilerOptions": { "rootDir": "src/js", diff --git a/packages/lib-ol/.npmignore b/packages/lib-ol/.npmignore index cf06fbb4..3af222d6 100644 --- a/packages/lib-ol/.npmignore +++ b/packages/lib-ol/.npmignore @@ -1,4 +1,3 @@ -* - -!/dist/**/* -!/src/**/* +# Publish surface is package.json "files" (dist only). +**/__tests__/** +**/*.test.* diff --git a/packages/lib-ol/package.json b/packages/lib-ol/package.json index 1372bea8..b9deeaf4 100644 --- a/packages/lib-ol/package.json +++ b/packages/lib-ol/package.json @@ -18,6 +18,9 @@ "default": "./dist/*.js" } }, + "files": [ + "dist" + ], "license": "UNLICENSED", "main": "index.js", "peerDependencies": { diff --git a/packages/lib-ol/tsconfig.json b/packages/lib-ol/tsconfig.json index b04e2126..79f25a45 100644 --- a/packages/lib-ol/tsconfig.json +++ b/packages/lib-ol/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../configs/tsconfig-base.json", "include": ["src/js/**/*"], + "exclude": ["**/__tests__/**", "**/*.test.ts"], "compilerOptions": { "outDir": "dist", "rootDir": "src/js" diff --git a/packages/lib-redux/.npmignore b/packages/lib-redux/.npmignore index cf06fbb4..3af222d6 100644 --- a/packages/lib-redux/.npmignore +++ b/packages/lib-redux/.npmignore @@ -1,4 +1,3 @@ -* - -!/dist/**/* -!/src/**/* +# Publish surface is package.json "files" (dist only). +**/__tests__/** +**/*.test.* diff --git a/packages/lib-redux/package.json b/packages/lib-redux/package.json index d88dc809..373354d7 100644 --- a/packages/lib-redux/package.json +++ b/packages/lib-redux/package.json @@ -30,6 +30,9 @@ "import": "./dist/reducers/immutable-path/index.js" } }, + "files": [ + "dist" + ], "license": "UNLICENSED", "main": "index.js", "repository": { diff --git a/packages/lib-redux/tsconfig.json b/packages/lib-redux/tsconfig.json index b04e2126..79f25a45 100644 --- a/packages/lib-redux/tsconfig.json +++ b/packages/lib-redux/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../configs/tsconfig-base.json", "include": ["src/js/**/*"], + "exclude": ["**/__tests__/**", "**/*.test.ts"], "compilerOptions": { "outDir": "dist", "rootDir": "src/js" diff --git a/packages/traffic-style/.npmignore b/packages/traffic-style/.npmignore index aa36c10c..12f2c61b 100644 --- a/packages/traffic-style/.npmignore +++ b/packages/traffic-style/.npmignore @@ -1,2 +1,3 @@ -* -!/dist/**/* +# Published via publishConfig.directory (dist as package root). +**/__tests__/** +**/*.test.* diff --git a/packages/traffic-style/tsconfig.json b/packages/traffic-style/tsconfig.json index eb4bf538..8f79b87d 100644 --- a/packages/traffic-style/tsconfig.json +++ b/packages/traffic-style/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../configs/tsconfig-base.json", "include": ["scripts/**/*"], + "exclude": ["**/__tests__/**", "**/*.test.ts"], "compilerOptions": { "outDir": "dist/scripts", "rootDir": "scripts", diff --git a/packages/ui/.npmignore b/packages/ui/.npmignore index cf06fbb4..3af222d6 100644 --- a/packages/ui/.npmignore +++ b/packages/ui/.npmignore @@ -1,4 +1,3 @@ -* - -!/dist/**/* -!/src/**/* +# Publish surface is package.json "files" (dist only). +**/__tests__/** +**/*.test.* diff --git a/packages/ui/package.json b/packages/ui/package.json index bb8a88d3..690a70b7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -62,6 +62,9 @@ "default": "./dist/embed/*.js" } }, + "files": [ + "dist" + ], "license": "UNLICENSED", "peerDependencies": { "react": "catalog:", diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index c66e0550..6d32a0a2 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../configs/tsconfig-base-tsx.json", "include": ["src/js/**/*"], - "exclude": ["src/js/**/*.test.ts"], + "exclude": ["src/js/**/*.test.ts", "src/js/**/__tests__/**"], "compilerOptions": { "outDir": "dist", "rootDir": "src/js", diff --git a/packages/vector-style-compiler/.npmignore b/packages/vector-style-compiler/.npmignore index bccb2fb6..dbc98882 100644 --- a/packages/vector-style-compiler/.npmignore +++ b/packages/vector-style-compiler/.npmignore @@ -1,4 +1,3 @@ -* -!/bin/* -!/dist/**/* -!/src/**/* +# Publish surface is package.json "files" (dist + bin). +**/__tests__/** +**/*.test.* diff --git a/packages/vector-style-compiler/package.json b/packages/vector-style-compiler/package.json index f3801346..365ba687 100644 --- a/packages/vector-style-compiler/package.json +++ b/packages/vector-style-compiler/package.json @@ -40,6 +40,10 @@ "default": "./dist/*.js" } }, + "files": [ + "dist", + "bin" + ], "license": "UNLICENSED", "main": "./dist/index.js", "peerDependencies": { diff --git a/packages/vector-style-compiler/tsconfig.build.json b/packages/vector-style-compiler/tsconfig.build.json index ec52f276..82a24d62 100644 --- a/packages/vector-style-compiler/tsconfig.build.json +++ b/packages/vector-style-compiler/tsconfig.build.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "./tsconfig.json", "include": ["src/js/**/*"], - "exclude": ["src/js/template.source.js"], + "exclude": ["src/js/template.source.js", "**/__tests__/**", "**/*.test.ts"], "compilerOptions": { "outDir": "dist", "rootDir": "src/js" From 21dc106068cabcc58852330c980ac673e4eb964e Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 23:38:14 +0200 Subject: [PATCH 39/49] core: add testing for feature hightlight interactions (vitest and playwright e2e) Signed-off-by: Paul Golmann --- .gitignore | 5 + packages/core/e2e/highlight.spec.ts | 123 ++++++++ packages/core/e2e/index.html | 24 ++ packages/core/e2e/main.ts | 50 ++++ packages/core/e2e/vite.config.ts | 20 ++ packages/core/package.json | 6 + packages/core/playwright.config.ts | 20 ++ .../lib/map/__tests__/highlight-hover.test.ts | 104 +++++++ .../src/js/test/create-highlight-test-map.ts | 268 ++++++++++++++++++ .../src/js/test/inject-default-ol-proxy.ts | 34 +++ packages/core/src/js/test/setup-dom.ts | 59 ++++ packages/core/vitest.config.ts | 4 + pnpm-workspace.yaml | 4 + 13 files changed, 721 insertions(+) create mode 100644 packages/core/e2e/highlight.spec.ts create mode 100644 packages/core/e2e/index.html create mode 100644 packages/core/e2e/main.ts create mode 100644 packages/core/e2e/vite.config.ts create mode 100644 packages/core/playwright.config.ts create mode 100644 packages/core/src/js/lib/map/__tests__/highlight-hover.test.ts create mode 100644 packages/core/src/js/test/create-highlight-test-map.ts create mode 100644 packages/core/src/js/test/inject-default-ol-proxy.ts create mode 100644 packages/core/src/js/test/setup-dom.ts diff --git a/.gitignore b/.gitignore index f99e4e01..91fbac8e 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,11 @@ tsconfig.node.tsbuildinfo # local files *.local +# Test runners (Playwright, etc.) +test-results/ +playwright-report/ +blob-report/ + # Logs logs *.log diff --git a/packages/core/e2e/highlight.spec.ts b/packages/core/e2e/highlight.spec.ts new file mode 100644 index 00000000..ffda5110 --- /dev/null +++ b/packages/core/e2e/highlight.spec.ts @@ -0,0 +1,123 @@ +import {expect, test} from "@playwright/test"; + +const HIGHLIGHT_TEST_FEATURE_ID = "poi-1"; + +type ClientPoint = {x: number; y: number}; + +async function waitForHighlightTest(page: import("@playwright/test").Page) { + await page.goto("/"); + await page.waitForFunction( + () => window.__mapsightHighlightTest?.ready === true, + ); + return page.evaluate(() => ({ + center: window.__mapsightHighlightTest!.centerClientPosition(), + empty: window.__mapsightHighlightTest!.emptyClientPosition(), + })); +} + +async function getHighlightFeatures(page: import("@playwright/test").Page) { + return page.evaluate(() => + window.__mapsightHighlightTest!.getHighlightFeatures(), + ); +} + +function lerp(a: number, b: number, t: number) { + return a + (b - a) * t; +} + +function lerpPoint(from: ClientPoint, to: ClientPoint, t: number): ClientPoint { + return { + x: lerp(from.x, to.x, t), + y: lerp(from.y, to.y, t), + }; +} + +/** Move along a polyline with many intermediate pointer events (Playwright mouse). */ +async function mouseMovePath( + page: import("@playwright/test").Page, + points: Array, + stepsPerSegment = 8, +) { + for (let i = 1; i < points.length; i++) { + const from = points[i - 1]!; + const to = points[i]!; + for (let step = 1; step <= stepsPerSegment; step++) { + const t = step / stepsPerSegment; + const point = lerpPoint(from, to, t); + await page.mouse.move(point.x, point.y); + } + } +} + +test.describe("highlight on mouseover (core e2e)", () => { + test("clears highlight in redux when the pointer leaves the feature (simple two-move)", async ({ + page, + }) => { + const {center} = await waitForHighlightTest(page); + + await page.mouse.move(center.x, center.y); + await expect + .poll(() => getHighlightFeatures(page)) + .toEqual([HIGHLIGHT_TEST_FEATURE_ID]); + + await page.mouse.move(center.x - 180, center.y - 180); + await expect.poll(() => getHighlightFeatures(page)).toEqual([]); + }); + + test("clears highlight after a second pointermove off the feature", async ({ + page, + }) => { + const {center, empty} = await waitForHighlightTest(page); + + await page.mouse.move(center.x, center.y); + await expect + .poll(() => getHighlightFeatures(page)) + .toEqual([HIGHLIGHT_TEST_FEATURE_ID]); + + // Two moves off the feature while still outside hit tolerance. + await page.mouse.move(empty.x, empty.y); + await page.mouse.move(empty.x + 2, empty.y + 2); + await page.waitForTimeout(25); + await expect.poll(() => getHighlightFeatures(page)).toEqual([]); + }); + + test("clears highlight after many incremental moves onto and off the feature", async ({ + page, + }) => { + const {center, empty} = await waitForHighlightTest(page); + + for (let run = 0; run < 30; run++) { + await mouseMovePath(page, [empty, center], 12); + await page.waitForTimeout(25); + expect(await getHighlightFeatures(page)).toEqual([ + HIGHLIGHT_TEST_FEATURE_ID, + ]); + + await mouseMovePath(page, [center, empty], 12); + await page.waitForTimeout(25); + expect(await getHighlightFeatures(page)).toEqual([]); + } + }); + + test("clears highlight after jittery moves around the feature edge", async ({ + page, + }) => { + const {center, empty} = await waitForHighlightTest(page); + + // Oscillate near the feature center (within/outside default hitTolerance). + const edgeOffsets = [ + -12, -8, -4, 0, 4, 8, 12, 8, 4, 0, -4, -8, -16, -24, + ]; + + for (let run = 0; run < 20; run++) { + for (const offset of edgeOffsets) { + await page.mouse.move(center.x + offset, center.y + offset); + await page.waitForTimeout(5); + } + + await page.mouse.move(empty.x, empty.y); + await page.waitForTimeout(25); + expect(await getHighlightFeatures(page)).toEqual([]); + } + }); +}); diff --git a/packages/core/e2e/index.html b/packages/core/e2e/index.html new file mode 100644 index 00000000..7ae75bcb --- /dev/null +++ b/packages/core/e2e/index.html @@ -0,0 +1,24 @@ + + + + + + Mapsight Core E2E + + + +
    + + + diff --git a/packages/core/e2e/main.ts b/packages/core/e2e/main.ts new file mode 100644 index 00000000..92566695 --- /dev/null +++ b/packages/core/e2e/main.ts @@ -0,0 +1,50 @@ +import "@/test/inject-default-ol-proxy"; + +import { + centerPixel, + createHighlightTestMap, + getHighlightFeatures, +} from "@/test/create-highlight-test-map"; + +const mountTarget = document.querySelector("#map"); +if (!mountTarget) { + throw new Error("Map target element #map was not found"); +} + +const {store, map} = createHighlightTestMap({ + stubHits: false, + mountTarget: mountTarget as HTMLDivElement, +}); + +map.renderSync(); + +declare global { + interface Window { + __mapsightHighlightTest?: { + ready: boolean; + getHighlightFeatures: () => string[]; + centerClientPosition: () => {x: number; y: number}; + emptyClientPosition: () => {x: number; y: number}; + }; + } +} + +function clientPositionForMapPixel(pixel: [number, number]) { + const element = map.getTargetElement(); + if (!element) { + throw new Error("Map target element is not set"); + } + const rect = element.getBoundingClientRect(); + return { + x: rect.left + pixel[0], + y: rect.top + pixel[1], + }; +} + +window.__mapsightHighlightTest = { + ready: true, + getHighlightFeatures: () => getHighlightFeatures(store), + centerClientPosition: () => clientPositionForMapPixel(centerPixel(map)), + /** Top-left corner — well outside the point feature and hit tolerance. */ + emptyClientPosition: () => clientPositionForMapPixel([8, 8]), +}; diff --git a/packages/core/e2e/vite.config.ts b/packages/core/e2e/vite.config.ts new file mode 100644 index 00000000..239d10ef --- /dev/null +++ b/packages/core/e2e/vite.config.ts @@ -0,0 +1,20 @@ +import path from "node:path"; +import {fileURLToPath} from "node:url"; + +import {defineConfig} from "vite"; + +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default defineConfig({ + root: dirname, + resolve: { + alias: { + "@": path.resolve(dirname, "../src/js"), + }, + }, + server: { + host: "127.0.0.1", + port: 5173, + strictPort: true, + }, +}); diff --git a/packages/core/package.json b/packages/core/package.json index b1726053..41f480e0 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -15,16 +15,20 @@ "zod": "catalog:" }, "devDependencies": { + "@playwright/test": "catalog:", "@redux-devtools/extension": "^3.3.0", "@types/geojson": "^7946.0.16", "@types/jsdom": "catalog:", "@types/lodash": "catalog:", "@types/node": "catalog:", + "canvas": "catalog:", "jsdom": "catalog:", "ol": "catalog:", + "playwright": "catalog:", "proj4": "catalog:", "tsc-alias": "^1.8.17", "typescript": "catalog:", + "vite": "^8.0.14", "vitest": "catalog:" }, "exports": { @@ -112,6 +116,8 @@ "clean-build": "run-s clean build", "lint": "eslint", "test": "vitest run", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui", "typecheck": "tsc --noEmit", "watch": "run-s build:modules watch:build", "watch:build": "run-p watch:build:modules watch:build:paths", diff --git a/packages/core/playwright.config.ts b/packages/core/playwright.config.ts new file mode 100644 index 00000000..80d486ab --- /dev/null +++ b/packages/core/playwright.config.ts @@ -0,0 +1,20 @@ +import {defineConfig} from "@playwright/test"; + +export default defineConfig({ + testDir: "./e2e", + fullyParallel: true, + forbidOnly: Boolean(process.env.CI), + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: "list", + use: { + baseURL: "http://127.0.0.1:5173", + trace: "on-first-retry", + }, + webServer: { + command: + "node ./node_modules/vite/bin/vite.js --config e2e/vite.config.ts", + url: "http://127.0.0.1:5173", + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/packages/core/src/js/lib/map/__tests__/highlight-hover.test.ts b/packages/core/src/js/lib/map/__tests__/highlight-hover.test.ts new file mode 100644 index 00000000..0cc0a6e1 --- /dev/null +++ b/packages/core/src/js/lib/map/__tests__/highlight-hover.test.ts @@ -0,0 +1,104 @@ +import {describe, expect, it, vi} from "vitest"; + +import { + HIGHLIGHT_TEST_FEATURE_ID, + centerPixel, + createHighlightTestMap, + dispatchPointerMoveAtPixel, + getHighlightFeatures, +} from "@/test/create-highlight-test-map"; + +const HOVER_DISPATCH_DELAY_MS = 10; + +async function flushHoverDispatch() { + await vi.advanceTimersByTimeAsync(HOVER_DISPATCH_DELAY_MS + 5); +} + +describe("highlight on mouseover", () => { + it("selects and deselects highlight in redux when pointer leaves the feature", async () => { + vi.useFakeTimers(); + + let hitMode: "feature" | "empty" = "empty"; + const {store, map} = createHighlightTestMap({ + getHitMode: () => hitMode, + }); + const pixel = centerPixel(map); + + hitMode = "feature"; + dispatchPointerMoveAtPixel(map, pixel); + await flushHoverDispatch(); + expect(getHighlightFeatures(store)).toEqual([ + HIGHLIGHT_TEST_FEATURE_ID, + ]); + + hitMode = "empty"; + dispatchPointerMoveAtPixel(map, pixel); + await flushHoverDispatch(); + expect(getHighlightFeatures(store)).toEqual([]); + + vi.useRealTimers(); + }); + + it("clears highlight after a second pointermove off the feature", async () => { + vi.useFakeTimers(); + + let hitMode: "feature" | "empty" = "feature"; + const {store, map} = createHighlightTestMap({ + getHitMode: () => hitMode, + }); + const pixel = centerPixel(map); + const emptyPixel: [number, number] = [8, 8]; + + hitMode = "feature"; + dispatchPointerMoveAtPixel(map, pixel); + await flushHoverDispatch(); + expect(getHighlightFeatures(store)).toEqual([ + HIGHLIGHT_TEST_FEATURE_ID, + ]); + + hitMode = "empty"; + dispatchPointerMoveAtPixel(map, emptyPixel); + dispatchPointerMoveAtPixel(map, emptyPixel); + await flushHoverDispatch(); + expect(getHighlightFeatures(store)).toEqual([]); + + vi.useRealTimers(); + }); + + it("keeps highlight when pointer re-enters before a brief miss deselect would fire", async () => { + vi.useFakeTimers(); + + let hitMode: "feature" | "empty" = "feature"; + const {store, map} = createHighlightTestMap({ + getHitMode: () => hitMode, + }); + const pixel = centerPixel(map); + + // Hover feature — select scheduled for t+10ms. + dispatchPointerMoveAtPixel(map, pixel); + + // Brief miss (e.g. hit tolerance gap) — deselect scheduled for t+12ms. + hitMode = "empty"; + await vi.advanceTimersByTimeAsync(2); + dispatchPointerMoveAtPixel(map, pixel); + + // Back on feature before deselect runs — select scheduled for t+15ms. + hitMode = "feature"; + await vi.advanceTimersByTimeAsync(3); + dispatchPointerMoveAtPixel(map, pixel); + + // Re-entry select fires (earlier scheduled actions were cancelled). + await vi.advanceTimersByTimeAsync(10); + expect(getHighlightFeatures(store)).toEqual([ + HIGHLIGHT_TEST_FEATURE_ID, + ]); + + // Brief-miss deselect was cancelled when pointer re-entered the feature. + await vi.advanceTimersByTimeAsync(5); + expect(getHighlightFeatures(store)).toEqual([ + HIGHLIGHT_TEST_FEATURE_ID, + ]); + + vi.useRealTimers(); + }); +}); diff --git a/packages/core/src/js/test/create-highlight-test-map.ts b/packages/core/src/js/test/create-highlight-test-map.ts new file mode 100644 index 00000000..ba734fba --- /dev/null +++ b/packages/core/src/js/test/create-highlight-test-map.ts @@ -0,0 +1,268 @@ +import Feature from "ol/Feature"; +import type OlMap from "ol/Map"; +import MapBrowserEvent from "ol/MapBrowserEvent"; +import Point from "ol/geom/Point"; +import type BaseLayer from "ol/layer/Base"; +import CircleStyle from "ol/style/Circle"; +import Fill from "ol/style/Fill"; +import Style from "ol/style/Style"; + +import {createMapsightStore} from "@/index"; +import {FeatureSelectionsController} from "@/lib/feature-selections/controller"; +import {setData} from "@/lib/feature-sources/actions"; +import {FeatureSourcesController} from "@/lib/feature-sources/controller"; +import {MapController} from "@/lib/map/controller"; +import {getIdForLayer} from "@/lib/map/lib/tagLayer"; +import {ProjectionsController} from "@/lib/projections/controller"; +import type {EnhancedStore} from "@/types"; + +export const HIGHLIGHT_TEST_FEATURE_ID = "poi-1"; +export const HIGHLIGHT_TEST_COORD = [0, 0] as [number, number]; +export const HIGHLIGHT_TEST_MAP_SIZE: [number, number] = [400, 400]; + +export type HighlightTestMapContext = { + store: EnhancedStore; + mapController: MapController; + map: OlMap; + feature: Feature; + layer: BaseLayer; + target: HTMLDivElement; +}; + +type HitMode = "feature" | "empty"; + +export type CreateHighlightTestMapOptions = { + /** Stub OL hit detection (fast, deterministic). Default: true in vitest. */ + stubHits?: boolean; + getHitMode?: () => HitMode; + /** Mount target; creates and appends a div when omitted. */ + mountTarget?: HTMLElement; +}; + +/** + * Minimal mapsight runtime for hover/highlight integration tests. + * In Node/vitest, hit detection is stubbed by default — use Playwright for real OL hits. + */ +export function createHighlightTestMap( + options: CreateHighlightTestMapOptions = {}, +): HighlightTestMapContext { + const { + stubHits = typeof process !== "undefined" && + process.env.VITEST === "true", + getHitMode = () => "empty", + mountTarget, + } = options; + + const mapController = new MapController("map"); + mapController.setStyleFunction(() => [ + new Style({ + image: new CircleStyle({ + radius: 8, + fill: new Fill({color: "red"}), + }), + }), + ]); + + const controllers = { + projections: new ProjectionsController("projections"), + map: mapController, + featureSources: new FeatureSourcesController("featureSources"), + featureSelections: new FeatureSelectionsController("featureSelections"), + }; + + const initialState = { + map: { + view: { + center: HIGHLIGHT_TEST_COORD, + zoom: 10, + minZoom: 0, + maxZoom: 20, + }, + size: HIGHLIGHT_TEST_MAP_SIZE, + layers: { + pois: { + type: "VectorLayer", + options: { + visible: true, + style: "features", + source: { + type: "VectorFeatureSource", + options: { + featureSourceId: "pois", + featureSourcesControllerName: "featureSources", + featureSelectionsControllerName: + "featureSelections", + canCluster: false, + canAnimate: false, + }, + }, + selections: { + mouseover: "highlight", + }, + }, + }, + }, + featureInteractions: { + mouseover: { + selection: "mouseover", + options: { + main: true, + auxiliary: false, + secondary: false, + fourth: false, + fifth: false, + cursor: "pointer", + deselectUncontrolled: null, + hitTolerance: 5, + }, + }, + mousedown: { + selection: "mousedown", + options: { + main: true, + auxiliary: false, + secondary: false, + fourth: false, + fifth: false, + deselectUncontrolled: null, + hitTolerance: 5, + }, + }, + touch: { + selection: "touch", + options: { + deselectUncontrolled: null, + hitTolerance: 5, + }, + }, + }, + }, + featureSelections: { + highlight: {max: 1, features: []}, + }, + featureSources: { + pois: { + type: "local", + data: null, + lastUpdate: null, + lastActionType: null, + }, + }, + }; + + const store = createMapsightStore(controllers, {}, initialState); + + const target = mountTarget ?? document.createElement("div"); + if (!mountTarget) { + target.style.width = `${HIGHLIGHT_TEST_MAP_SIZE[0]}px`; + target.style.height = `${HIGHLIGHT_TEST_MAP_SIZE[1]}px`; + document.body.appendChild(target); + } + mapController.mount(target); + + const map = mapController.getMap(); + if (!map) { + throw new Error("Map was not created"); + } + + map.setSize(HIGHLIGHT_TEST_MAP_SIZE); + + const layer = findLayerById(map, "pois"); + + let feature: Feature; + if (stubHits) { + feature = new Feature({ + geometry: new Point(HIGHLIGHT_TEST_COORD), + }); + feature.setId(HIGHLIGHT_TEST_FEATURE_ID); + stubFeatureHitDetection(map, layer, feature, getHitMode); + } else { + store.dispatch( + setData("featureSources", "pois", { + type: "FeatureCollection", + features: [ + { + id: HIGHLIGHT_TEST_FEATURE_ID, + type: "Feature", + properties: {}, + geometry: { + type: "Point", + coordinates: HIGHLIGHT_TEST_COORD, + }, + }, + ], + }), + ); + map.renderSync(); + const source = ( + layer as {getSource: () => {getFeatures: () => Array}} + ).getSource(); + const loadedFeature = source + .getFeatures() + .find((f) => String(f.getId()) === HIGHLIGHT_TEST_FEATURE_ID); + if (!loadedFeature) { + throw new Error( + "Test feature was not loaded into the vector source", + ); + } + feature = loadedFeature; + } + + return {store, mapController, map, feature, layer, target}; +} + +export function centerPixel(map: OlMap): [number, number] { + const size = map.getSize(); + if (!size) { + throw new Error("Map size is not set"); + } + return [size[0] / 2, size[1] / 2]; +} + +export function dispatchPointerMoveAtPixel( + map: OlMap, + pixel: [number, number], +) { + const [x, y] = pixel; + const originalEvent = new MouseEvent("mousemove", { + clientX: x, + clientY: y, + bubbles: true, + }); + const event = new MapBrowserEvent("pointermove", map, originalEvent, false); + event.pixel = pixel; + map.dispatchEvent(event); +} + +export function stubFeatureHitDetection( + map: OlMap, + layer: BaseLayer, + feature: Feature, + getHitMode: () => HitMode, +) { + map.forEachFeatureAtPixel = (pixel, callback, options) => { + if (getHitMode() === "feature") { + return callback(feature, layer, pixel); + } + return undefined; + }; +} + +export function getHighlightFeatures(store: EnhancedStore): string[] { + return store.getState().featureSelections?.highlight?.features ?? []; +} + +function findLayerById(map: OlMap, layerId: string) { + for (const layer of map.getLayers().getArray()) { + if ("getLayers" in layer && typeof layer.getLayers === "function") { + for (const child of layer.getLayers().getArray()) { + if (getIdForLayer(child) === layerId) { + return child; + } + } + } else if (getIdForLayer(layer) === layerId) { + return layer; + } + } + throw new Error(`Layer ${layerId} was not found on the map`); +} diff --git a/packages/core/src/js/test/inject-default-ol-proxy.ts b/packages/core/src/js/test/inject-default-ol-proxy.ts new file mode 100644 index 00000000..c03d5749 --- /dev/null +++ b/packages/core/src/js/test/inject-default-ol-proxy.ts @@ -0,0 +1,34 @@ +import {di} from "@/ol-proxy"; +import GeoJSONFormat from "@/ol-proxy/definitions/format/GeoJSONFormat"; +import DoubleClickZoomInteraction from "@/ol-proxy/definitions/interaction/DoubleClickZoomInteraction"; +import DragPanInteraction from "@/ol-proxy/definitions/interaction/DragPanInteraction"; +import KeyboardPanInteraction from "@/ol-proxy/definitions/interaction/KeyboardPanInteraction"; +import KeyboardZoomInteraction from "@/ol-proxy/definitions/interaction/KeyboardZoomInteraction"; +import MouseWheelZoomInteraction from "@/ol-proxy/definitions/interaction/MouseWheelZoomInteraction"; +import PinchZoomInteraction from "@/ol-proxy/definitions/interaction/PinchZoomInteraction"; +import SelectInteraction from "@/ol-proxy/definitions/interaction/SelectInteraction"; +import TileLayer from "@/ol-proxy/definitions/layer/TileLayer"; +import VectorLayer from "@/ol-proxy/definitions/layer/VectorLayer"; +import VectorOverlayLayer from "@/ol-proxy/definitions/layer/VectorOverlayLayer"; +import OSMSource from "@/ol-proxy/definitions/source/OsmSource"; +import TileWMSSource from "@/ol-proxy/definitions/source/TileWMSSource"; +import VectorFeatureSource from "@/ol-proxy/definitions/source/VectorFeatureSource"; +import VectorSource from "@/ol-proxy/definitions/source/VectorSource"; + +di.injectDefinitions([ + TileLayer, + VectorLayer, + VectorOverlayLayer, + VectorSource, + TileWMSSource, + OSMSource, + VectorFeatureSource, + GeoJSONFormat, + SelectInteraction, + DragPanInteraction, + DoubleClickZoomInteraction, + PinchZoomInteraction, + MouseWheelZoomInteraction, + KeyboardPanInteraction, + KeyboardZoomInteraction, +]); diff --git a/packages/core/src/js/test/setup-dom.ts b/packages/core/src/js/test/setup-dom.ts new file mode 100644 index 00000000..548d66a8 --- /dev/null +++ b/packages/core/src/js/test/setup-dom.ts @@ -0,0 +1,59 @@ +import {Canvas, Image as CanvasImage} from "canvas"; + +import { + document, + requestAnimationFrame, + window, +} from "@/env/ssr-simulated-browser"; + +globalThis.window = window as Window & typeof globalThis; +globalThis.document = document; +globalThis.requestAnimationFrame = requestAnimationFrame; +globalThis.HTMLElement = window.HTMLElement; +globalThis.MouseEvent = window.MouseEvent; +globalThis.getComputedStyle = window.getComputedStyle; + +class ResizeObserverStub { + observe() {} + unobserve() {} + disconnect() {} +} + +globalThis.ResizeObserver = + ResizeObserverStub as unknown as typeof ResizeObserver; + +if (!globalThis.ShadowRoot) { + globalThis.ShadowRoot = class {} as typeof ShadowRoot; +} + +if (!globalThis.CanvasPattern) { + globalThis.CanvasPattern = class {} as typeof CanvasPattern; +} + +// node-canvas backing store for OpenLayers vector rendering in Node tests / SSR prep. +globalThis.Image = CanvasImage as unknown as typeof Image; + +const canvasProto = window.HTMLCanvasElement.prototype; +canvasProto.getContext = function getContext( + type: string, + attributes?: CanvasRenderingContext2DSettings, +) { + if (type === "2d") { + const width = Number(this.width) || 300; + const height = Number(this.height) || 150; + const nodeCanvas = new Canvas(width, height); + const context = nodeCanvas.getContext("2d", attributes); + if (!context) { + return null; + } + + // Keep the jsdom element dimensions in sync with the backing canvas. + Object.defineProperty(context, "canvas", { + get: () => this, + }); + + return context as unknown as CanvasRenderingContext2D; + } + + return null; +} as typeof canvasProto.getContext; diff --git a/packages/core/vitest.config.ts b/packages/core/vitest.config.ts index 1746638e..df5da8b5 100644 --- a/packages/core/vitest.config.ts +++ b/packages/core/vitest.config.ts @@ -13,5 +13,9 @@ export default defineConfig({ }, test: { include: ["src/js/**/*.test.ts"], + setupFiles: [ + "src/js/test/setup-dom.ts", + "src/js/test/inject-default-ol-proxy.ts", + ], }, }); diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a0037695..12dabc2d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,12 +4,16 @@ packages: - "apps/*" allowBuilds: '@parcel/watcher': true + canvas: true + esbuild: true fsevents: true unrs-resolver: true sharp: true catalog: "@reduxjs/toolkit": "^2.11.2" + "@playwright/test": "^1.60.0" "@types/jsdom": "^28.0.3" + "canvas": "^3.1.0" "@types/lodash": "^4.17.24" "@types/node": "^24.12.4" "@types/react": "^19.2.15" From 53bb5f779e13ac89d303a50207137e0a5ba3fc71 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 23:40:38 +0200 Subject: [PATCH 40/49] core: add compare function to BaseController.getAndObserveUncontrolled Signed-off-by: Paul Golmann --- packages/core/src/js/lib/base/controller.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/core/src/js/lib/base/controller.ts b/packages/core/src/js/lib/base/controller.ts index ac57035c..7d42c793 100644 --- a/packages/core/src/js/lib/base/controller.ts +++ b/packages/core/src/js/lib/base/controller.ts @@ -109,11 +109,13 @@ export class BaseController * * @param selector observe selector * @param handler observe handler + * @param compare optional custom equality function * @returns unsubscribe function */ getAndObserveUncontrolled( selector: Selector, handler: ObserveHandler, + compare?: (previousValue: TValue, newValue: TValue) => boolean, ) { const store = this.getStore(); if (!store) { @@ -127,6 +129,7 @@ export class BaseController const unsubscribe = store.observeUncontrolled( composedSelector, boundHandler as ObserveHandler, + compare ? (a, b) => compare(a as TValue, b as TValue) : undefined, ); boundHandler(composedSelector(store.getState())); return unsubscribe; From f64b7179519eb7e187c88762aad2fc3a46ed2888 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Tue, 9 Jun 2026 23:41:10 +0200 Subject: [PATCH 41/49] core: fix feature highlight race conditions Signed-off-by: Paul Golmann --- .../js/lib/map/lib/WithFeatureInteractions.ts | 103 ++++++++++++++---- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts index 9204b0d4..0026d8a1 100644 --- a/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts +++ b/packages/core/src/js/lib/map/lib/WithFeatureInteractions.ts @@ -1,6 +1,7 @@ import type Feature from "ol/Feature"; import forEach from "lodash/forEach"; +import isEqual from "lodash/isEqual"; import type {MapBrowserEvent} from "ol"; import {batchActions} from "redux-batched-actions"; @@ -78,6 +79,19 @@ const FEATURE_PROPERTY_NAME_SELECTABLE = "selectable"; const defaultFeatureSelectionsControllerName = "featureSelections"; const HIGHLIGHT_SELECTION_ID = "highlight"; +/** See {@link createHandler} — matches `enableAsyncDispatch` deferral timing elsewhere. */ +const FEATURE_INTERACTION_DISPATCH_DELAY_MS = 10; + +type PendingInteractionDispatch = { + actions: Array; + cursorAction: Action | null; +}; + +type HandleEventResult = { + cache: FeatureInteractionEventCache | null; + pendingDispatch: PendingInteractionDispatch | null; +}; + function quietIfHighlight(action: Action, selectionId: string) { return selectionId === HIGHLIGHT_SELECTION_ID ? quiet(action) : action; } @@ -226,10 +240,10 @@ type FeatureInteractionEventCache = { * @param [options.selectExclusively=true] set to false to keep uncontrolled selections * @param [options.removeUncontrolled=false] set to true to remove selections when they were not done through this interaction handler * @param [options.hitTolerance=5] pixel tolerance when determining hit features - * @param cache previous cache object controlled by parent + * @param cache hover state used to diff the next hit; see {@link createHandler} * @param event openlayers event object * - * @returns {FeatureInteractionEventCache|null} new cache object to be kept by parent + * @returns computed hover state and any redux actions to dispatch (may be deferred) */ function handleEvent( mapController: MapEventEmitter, @@ -238,21 +252,21 @@ function handleEvent( options: FeatureInteractionOptions = {}, cache: FeatureInteractionEventCache | null = null, event: MapBrowserEvent, -): FeatureInteractionEventCache | null { +): HandleEventResult { if (!interactionName) { - return cache; + return {cache, pendingDispatch: null}; } // TODO: Move code accessing ._map to the controller? const map = mapController.getMap(); if (!map) { - return cache; + return {cache, pendingDispatch: null}; } // TODO: Allow interaction during animation for some event types? const view = map.getView(); if (!view || view.getAnimating() || view.getInteracting()) { - return cache; + return {cache, pendingDispatch: null}; } if (event.originalEvent) { @@ -260,7 +274,7 @@ function handleEvent( const appliedOptions = overrideOptionsForEvent(options, originalEvent); if (appliedOptions === false) { - return cache; + return {cache, pendingDispatch: null}; } } @@ -399,7 +413,7 @@ function handleEvent( } if (!actions.length) { - return cache; + return {cache, pendingDispatch: null}; } let cursorAction: Action | null = null; @@ -415,22 +429,47 @@ function handleEvent( } } - // TODO: Check and document why we delay using setTimeout! - setTimeout(function () { - if (cursorAction) { - mapController.dispatch(cursorAction); - } + return { + cache: {selections: newSelections, cursor: newCursor}, + pendingDispatch: {actions, cursorAction}, + }; +} - if (actions.length === 1) { - mapController.dispatch(ensureNonNullable(actions[0])); - } else { - mapController.dispatch(batchActions(actions)); - } - }, 10); +function dispatchInteractionActions( + mapController: MapEventEmitter, + pendingDispatch: PendingInteractionDispatch, +) { + if (pendingDispatch.cursorAction) { + mapController.dispatch(pendingDispatch.cursorAction); + } - return {selections: newSelections, cursor: newCursor}; + if (pendingDispatch.actions.length === 1) { + mapController.dispatch(ensureNonNullable(pendingDispatch.actions[0])); + } else { + mapController.dispatch(batchActions(pendingDispatch.actions)); + } } +/** + * Returns an OL event handler that maps pointer hits to feature-selection actions. + * + * **Deferred dispatch.** Selection actions are not dispatched synchronously inside the + * OL event handler. Each new event cancels any pending dispatch and schedules a fresh + * one after {@link FEATURE_INTERACTION_DISPATCH_DELAY_MS}. That serves two purposes: + * + * 1. **Hover coalescing** — rapid `pointermove` across hit-tolerance edges (see default + * `hitTolerance: 5`) would otherwise select/deselect on every pixel. A short window + * lets a brief miss be cancelled when the pointer re-enters the feature. + * 2. **Defer out of the OL stack** — dispatching immediately would run selection + * observers (style / `FeatureSelectionConnector`) during `pointermove`. This mirrors + * the motivation for `async()` elsewhere, but hover needs cancel-on-new-event, not + * the action queue that `enableAsyncDispatch` provides. + * + * **Cache update.** When a dispatch is pending, in-memory `cache` is not updated until + * the timeout fires. Otherwise a follow-up move off the feature can cancel the pending + * deselect while `cache` is already empty, leaving highlight stuck in redux (see + * `highlight-hover.test.ts` / `e2e/highlight.spec.ts`). + */ function createHandler( mapController: MapEventEmitter, featureSelectionsControllerName: string, @@ -441,8 +480,19 @@ function createHandler( } let cache: FeatureInteractionEventCache | null = null; + let pendingDispatchTimeout: ReturnType | null = null; + + const clearPendingDispatch = () => { + if (pendingDispatchTimeout !== null) { + clearTimeout(pendingDispatchTimeout); + pendingDispatchTimeout = null; + } + }; + return function interactionHandler(event: MapBrowserEvent) { - cache = handleEvent( + clearPendingDispatch(); + + const {cache: nextCache, pendingDispatch} = handleEvent( mapController, featureSelectionsControllerName, options.selection, @@ -450,6 +500,16 @@ function createHandler( cache, event, ); + + if (pendingDispatch) { + pendingDispatchTimeout = setTimeout(() => { + pendingDispatchTimeout = null; + cache = nextCache; + dispatchInteractionActions(mapController, pendingDispatch); + }, FEATURE_INTERACTION_DISPATCH_DELAY_MS); + } else { + cache = nextCache; + } }; } @@ -505,6 +565,7 @@ export default class WithFeatureInteractions extends WithMap { ), }); }, + isEqual, ); map.on("pointermove", function onPointerMove(e) { From 5595b932791e0a561171df3ae1cad9a2fad754a0 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Wed, 10 Jun 2026 20:31:44 +0200 Subject: [PATCH 42/49] vsc: fix nested functions Signed-off-by: Paul Golmann --- .../__tests__/mapValue.test.ts | 9 ++ .../src/js/helpers/Replacer.ts | 82 ++++++++++++++++--- 2 files changed, 80 insertions(+), 11 deletions(-) diff --git a/packages/vector-style-compiler/__tests__/mapValue.test.ts b/packages/vector-style-compiler/__tests__/mapValue.test.ts index 9937b0ab..017427f7 100644 --- a/packages/vector-style-compiler/__tests__/mapValue.test.ts +++ b/packages/vector-style-compiler/__tests__/mapValue.test.ts @@ -45,4 +45,13 @@ it("mapValue", () => { }, value: "'' + (props['test'] + get(env, ['to', 'test'])) + ''", }); + expect( + mapValue('calc(mapsightRuntimeIcon(attr(mapsightIconId), "default"))'), + ).toStrictEqual({ + __meta: { + stylePropExpressions: ["props['mapsightIconId']"], + styleProps: ["mapsightIconId"], + }, + value: "'' + (mapsightRuntimeIcon(props['mapsightIconId'], \"default\")) + ''", + }); }); diff --git a/packages/vector-style-compiler/src/js/helpers/Replacer.ts b/packages/vector-style-compiler/src/js/helpers/Replacer.ts index 8c89ad08..a0b79ad9 100644 --- a/packages/vector-style-compiler/src/js/helpers/Replacer.ts +++ b/packages/vector-style-compiler/src/js/helpers/Replacer.ts @@ -1,5 +1,3 @@ -const RE_FUNCTION_PARAMETER = "([^\\)]*?)"; -const RE_DOUBLE_QUOTES_IN_PARIS_ONLY = '(?:(?:[^"]*"){2})*[^"]*$'; const TAG_DELIMITER = "%%%"; export type ReplacerFn = ( @@ -8,6 +6,46 @@ export type ReplacerFn = ( replacer: Replacer, ) => string; +function findBalancedParameterEnd( + value: string, + openParenIndex: number, +): number { + let depth = 0; + let inString = false; + let stringChar = ""; + + for (let i = openParenIndex; i < value.length; i++) { + const char = value[i]!; + + if (inString) { + if (char === stringChar && value[i - 1] !== "\\") { + inString = false; + } + continue; + } + + if (char === `"` || char === `'`) { + inString = true; + stringChar = char; + continue; + } + + if (char === "(") { + depth += 1; + continue; + } + + if (char === ")") { + depth -= 1; + if (depth === 0) { + return i; + } + } + } + + return -1; +} + export default class Replacer { private replacementCounter: number = 0; private replacements: Array<{tag: string; replacement: string}> = []; @@ -20,19 +58,41 @@ export default class Replacer { } addFunction(functionName: string, replacer: ReplacerFn) { - const regex = new RegExp( - `(${functionName}\\(${RE_FUNCTION_PARAMETER}\\))(?=${RE_DOUBLE_QUOTES_IN_PARIS_ONLY})`, - "ig", - ); - const fn = (value: string): string => - value.replace(regex, (match, _, parameter) => { + const fn = (value: string): string => { + const pattern = new RegExp(`\\b${functionName}\\(`, "ig"); + let result = ""; + let cursor = 0; + let match: RegExpExecArray | null; + + while ((match = pattern.exec(value)) !== null) { + const openParenIndex = match.index + match[0].length - 1; + const closeParenIndex = findBalancedParameterEnd( + value, + openParenIndex, + ); + + if (closeParenIndex === -1) { + continue; + } + + result += value.slice(cursor, match.index); + const fullMatch = value.slice(match.index, closeParenIndex + 1); + const parameter = value.slice( + openParenIndex + 1, + closeParenIndex, + ); const tag = TAG_DELIMITER + this.replacementCounter++ + TAG_DELIMITER; - const replacement = replacer(match, parameter as string, this); + const replacement = replacer(fullMatch, parameter, this); this.replacements.push({tag, replacement}); + result += tag; + cursor = closeParenIndex + 1; + pattern.lastIndex = cursor; + } + + return result + value.slice(cursor); + }; - return tag; - }); this.functions.push(fn); } From 7312aebc29d8a7f9f36f8391f8a3add53d750938 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Wed, 10 Jun 2026 20:32:18 +0200 Subject: [PATCH 43/49] vsc: fix missing style tree state assignment Signed-off-by: Paul Golmann --- packages/vector-style-compiler/src/js/rulesToTree.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vector-style-compiler/src/js/rulesToTree.ts b/packages/vector-style-compiler/src/js/rulesToTree.ts index 41f24667..f6ecff59 100644 --- a/packages/vector-style-compiler/src/js/rulesToTree.ts +++ b/packages/vector-style-compiler/src/js/rulesToTree.ts @@ -62,6 +62,7 @@ export default function rulesToTree(rules: Rules["rules"]) { declarations: rule.declarations, stylePropExpressions: rule.__meta.stylePropExpressions, }); + styleTree[state] = stateTree; return; } stateTree.stylePropExpressions = ( From 2c6d287ac44010c581147d12e18edf432b1fa461 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Wed, 10 Jun 2026 20:34:02 +0200 Subject: [PATCH 44/49] feat: composable runtime icons Replace pre-baked per-variant SVGs in traffic-style with pictogram templates composed at build time and rasterized at runtime. Add mapsightIconId parsing, color variants, and LRU-cached async loading. Wire async icons into the style pipeline via volatile cache keys in lib-ol and vector-style-compiler, and expose useMapsightIcon plus a runtime icon style plugin in ui. Signed-off-by: Paul Golmann --- .changeset/composable-runtime-icons.md | 8 + .../src/js/style/createCachedStyleFunction.ts | 87 +- .../lib-ol/src/js/style/styleFeatureScope.ts | 27 + packages/traffic-style/.gitignore | 1 + packages/traffic-style/README.md | 169 +++- .../traffic-style/docs/CUSTOMIZING_SCSS.md | 217 +++++ .../traffic-style/docs/CUSTOM_ICON_BUILDS.md | 170 ++++ packages/traffic-style/docs/DEVELOPMENT.md | 83 ++ packages/traffic-style/docs/ICON_CATALOG.md | 96 +++ .../traffic-style/docs/ICON_INTEGRATION.md | 139 +++ packages/traffic-style/docs/RUNTIME_ICONS.md | 399 +++++++++ packages/traffic-style/eslint.config.mts | 6 +- packages/traffic-style/package.json | 71 +- .../scripts/dev/build-composable-icons.ts | 55 ++ .../scripts/{ => dev}/create-meta-json.ts | 23 + .../scripts/{ => dev}/create-overview-md.ts | 0 .../scripts/dev/import-fontawesome.ts | 137 +++ .../scripts/dev/import-pictograms.test.ts | 55 ++ .../scripts/dev/import-pictograms.ts | 126 +++ .../scripts/dev/write-dist-package.json.ts | 48 ++ .../scripts/lib/composable-icons.test.ts | 44 + .../scripts/lib/composable-icons.ts | 228 +++++ packages/traffic-style/scripts/lib/meta.ts | 15 + .../scripts/lib/pictogram-packs.ts | 58 ++ .../scripts/traffic-composable-icons.ts | 149 ++++ .../scripts/traffic-icon-sprite.ts | 10 +- .../traffic-style/src/icons/0-default.svg | 8 - packages/traffic-style/src/icons/0-plain.svg | 8 - packages/traffic-style/src/icons/0-small.svg | 8 - .../traffic-style/src/icons/1-default.svg | 8 - packages/traffic-style/src/icons/1-plain.svg | 8 - packages/traffic-style/src/icons/1-small.svg | 8 - .../traffic-style/src/icons/2-default.svg | 8 - packages/traffic-style/src/icons/2-plain.svg | 8 - packages/traffic-style/src/icons/2-small.svg | 8 - .../traffic-style/src/icons/3-default.svg | 8 - packages/traffic-style/src/icons/3-plain.svg | 8 - packages/traffic-style/src/icons/3-small.svg | 8 - .../traffic-style/src/icons/4-default.svg | 8 - packages/traffic-style/src/icons/4-plain.svg | 8 - packages/traffic-style/src/icons/4-small.svg | 8 - .../traffic-style/src/icons/5-default.svg | 8 - packages/traffic-style/src/icons/5-plain.svg | 8 - packages/traffic-style/src/icons/5-small.svg | 8 - .../traffic-style/src/icons/6-default.svg | 8 - packages/traffic-style/src/icons/6-plain.svg | 8 - packages/traffic-style/src/icons/6-small.svg | 8 - .../traffic-style/src/icons/7-default.svg | 8 - packages/traffic-style/src/icons/7-plain.svg | 8 - packages/traffic-style/src/icons/7-small.svg | 8 - .../traffic-style/src/icons/8-default.svg | 8 - packages/traffic-style/src/icons/8-plain.svg | 8 - packages/traffic-style/src/icons/8-small.svg | 8 - .../traffic-style/src/icons/9-default.svg | 8 - packages/traffic-style/src/icons/9-plain.svg | 8 - packages/traffic-style/src/icons/9-small.svg | 8 - .../traffic-style/src/icons/a-default.svg | 8 - packages/traffic-style/src/icons/a-plain.svg | 8 - packages/traffic-style/src/icons/a-small.svg | 8 - .../src/icons/abfall_recycling-default.svg | 12 - .../src/icons/abfall_recycling-plain.svg | 12 - .../traffic-style/src/icons/b-default.svg | 8 - packages/traffic-style/src/icons/b-plain.svg | 8 - packages/traffic-style/src/icons/b-small.svg | 8 - .../traffic-style/src/icons/bike-default.svg | 14 - .../traffic-style/src/icons/bike-plain.svg | 14 - .../traffic-style/src/icons/bike-small.svg | 3 - .../traffic-style/src/icons/bike-xsmall.svg | 3 - .../src/icons/bilbiothek_archiv-default.svg | 8 - .../src/icons/bilbiothek_archiv-plain.svg | 8 - .../src/icons/bildung-allgemein-default.svg | 7 - .../src/icons/bildung-allgemein-plain.svg | 7 - .../src/icons/bildung-ausbildung-default.svg | 12 - .../src/icons/bildung-ausbildung-plain.svg | 12 - .../src/icons/bildung-grundschule-default.svg | 14 - .../src/icons/bildung-grundschule-plain.svg | 14 - .../src/icons/bildung-kind-default.svg | 9 - .../src/icons/bildung-kind-plain.svg | 9 - .../src/icons/bildung-senior-default.svg | 18 - .../src/icons/bildung-senior-plain.svg | 18 - .../icons/bildung-weiterbildung-default.svg | 15 - .../src/icons/bildung-weiterbildung-plain.svg | 15 - .../icons/bildung-weiterfuehrend-default.svg | 17 - .../icons/bildung-weiterfuehrend-plain.svg | 17 - .../traffic-style/src/icons/bundr-default.svg | 13 - .../traffic-style/src/icons/bundr-plain.svg | 13 - .../traffic-style/src/icons/c-default.svg | 8 - packages/traffic-style/src/icons/c-plain.svg | 8 - packages/traffic-style/src/icons/c-small.svg | 8 - .../src/icons/charging-station-default.svg | 13 - .../src/icons/charging-station-plain.svg | 13 - .../traffic-style/src/icons/d-default.svg | 8 - packages/traffic-style/src/icons/d-plain.svg | 8 - packages/traffic-style/src/icons/d-small.svg | 8 - .../traffic-style/src/icons/db-default.svg | 7 - packages/traffic-style/src/icons/db-plain.svg | 7 - .../traffic-style/src/icons/dot-plain.svg | 6 - .../traffic-style/src/icons/e-default.svg | 8 - packages/traffic-style/src/icons/e-plain.svg | 8 - packages/traffic-style/src/icons/e-small.svg | 8 - .../traffic-style/src/icons/f-default.svg | 8 - packages/traffic-style/src/icons/f-plain.svg | 8 - packages/traffic-style/src/icons/f-small.svg | 8 - .../src/icons/faehre-default.svg | 7 - .../traffic-style/src/icons/faehre-plain.svg | 7 - .../src/icons/flughafen-default.svg | 7 - .../src/icons/flughafen-plain.svg | 7 - .../src/icons/forschung-default.svg | 7 - .../src/icons/forschung-plain.svg | 7 - .../src/icons/friedhof-default.svg | 7 - .../src/icons/friedhof-plain.svg | 7 - .../traffic-style/src/icons/g-default.svg | 8 - packages/traffic-style/src/icons/g-plain.svg | 8 - packages/traffic-style/src/icons/g-small.svg | 8 - .../src/icons/gewerbe-default.svg | 7 - .../traffic-style/src/icons/gewerbe-plain.svg | 7 - .../traffic-style/src/icons/h-default.svg | 8 - packages/traffic-style/src/icons/h-plain.svg | 8 - packages/traffic-style/src/icons/h-small.svg | 8 - .../src/icons/haltestelle-default.svg | 7 - .../src/icons/haltestelle-plain.svg | 7 - .../src/icons/hochschule-default.svg | 13 - .../src/icons/hochschule-plain.svg | 13 - .../traffic-style/src/icons/hotel-default.svg | 7 - .../traffic-style/src/icons/hotel-plain.svg | 7 - .../traffic-style/src/icons/i-default.svg | 8 - packages/traffic-style/src/icons/i-plain.svg | 8 - packages/traffic-style/src/icons/i-small.svg | 8 - .../traffic-style/src/icons/info-default.svg | 7 - .../traffic-style/src/icons/info-plain.svg | 7 - .../traffic-style/src/icons/j-default.svg | 8 - packages/traffic-style/src/icons/j-plain.svg | 8 - packages/traffic-style/src/icons/j-small.svg | 8 - .../traffic-style/src/icons/k-default.svg | 8 - packages/traffic-style/src/icons/k-plain.svg | 8 - packages/traffic-style/src/icons/k-small.svg | 8 - .../traffic-style/src/icons/kita-default.svg | 7 - .../traffic-style/src/icons/kita-plain.svg | 7 - .../src/icons/krankenhaus_klinik-default.svg | 7 - .../src/icons/krankenhaus_klinik-plain.svg | 7 - .../traffic-style/src/icons/l-default.svg | 8 - packages/traffic-style/src/icons/l-plain.svg | 8 - packages/traffic-style/src/icons/l-small.svg | 8 - .../traffic-style/src/icons/m-default.svg | 8 - packages/traffic-style/src/icons/m-plain.svg | 8 - packages/traffic-style/src/icons/m-small.svg | 8 - .../src/icons/marker-default.svg | 6 - .../traffic-style/src/icons/marker-plain.svg | 6 - .../src/icons/museum-default.svg | 7 - .../traffic-style/src/icons/museum-plain.svg | 7 - .../traffic-style/src/icons/n-default.svg | 8 - packages/traffic-style/src/icons/n-plain.svg | 8 - packages/traffic-style/src/icons/n-small.svg | 8 - .../traffic-style/src/icons/o-default.svg | 8 - packages/traffic-style/src/icons/o-plain.svg | 8 - packages/traffic-style/src/icons/o-small.svg | 8 - .../traffic-style/src/icons/ort-default.svg | 12 - .../traffic-style/src/icons/ort-plain.svg | 12 - .../traffic-style/src/icons/p-default.svg | 8 - packages/traffic-style/src/icons/p-plain.svg | 8 - packages/traffic-style/src/icons/p-small.svg | 8 - .../src/icons/parkanlage-default.svg | 7 - .../src/icons/parkanlage-plain.svg | 7 - .../traffic-style/src/icons/q-default.svg | 8 - packages/traffic-style/src/icons/q-plain.svg | 8 - packages/traffic-style/src/icons/q-small.svg | 8 - .../traffic-style/src/icons/r-default.svg | 8 - packages/traffic-style/src/icons/r-plain.svg | 8 - packages/traffic-style/src/icons/r-small.svg | 8 - .../src/icons/religion-default.svg | 7 - .../src/icons/religion-plain.svg | 7 - .../traffic-style/src/icons/s-default.svg | 8 - packages/traffic-style/src/icons/s-plain.svg | 8 - packages/traffic-style/src/icons/s-small.svg | 8 - .../src/icons/schule-default.svg | 20 - .../traffic-style/src/icons/schule-plain.svg | 20 - .../src/icons/sehenswuerdigkeit-default.svg | 9 - .../src/icons/sehenswuerdigkeit-plain.svg | 9 - .../traffic-style/src/icons/sport-default.svg | 10 - .../traffic-style/src/icons/sport-plain.svg | 10 - .../src/icons/sportanlage-default.svg | 7 - .../src/icons/sportanlage-plain.svg | 7 - .../traffic-style/src/icons/t-default.svg | 8 - packages/traffic-style/src/icons/t-plain.svg | 8 - packages/traffic-style/src/icons/t-small.svg | 8 - .../traffic-style/src/icons/taxi-default.svg | 7 - .../traffic-style/src/icons/taxi-plain.svg | 7 - .../src/icons/theater-default.svg | 10 - .../traffic-style/src/icons/theater-plain.svg | 10 - .../traffic-style/src/icons/u-default.svg | 8 - packages/traffic-style/src/icons/u-plain.svg | 8 - packages/traffic-style/src/icons/u-small.svg | 8 - .../traffic-style/src/icons/v-default.svg | 8 - packages/traffic-style/src/icons/v-plain.svg | 8 - packages/traffic-style/src/icons/v-small.svg | 8 - .../traffic-style/src/icons/w-default.svg | 8 - packages/traffic-style/src/icons/w-plain.svg | 8 - packages/traffic-style/src/icons/w-small.svg | 8 - .../traffic-style/src/icons/x-default.svg | 8 - packages/traffic-style/src/icons/x-plain.svg | 8 - packages/traffic-style/src/icons/x-small.svg | 8 - .../traffic-style/src/icons/y-default.svg | 8 - packages/traffic-style/src/icons/y-plain.svg | 8 - packages/traffic-style/src/icons/y-small.svg | 8 - .../traffic-style/src/icons/z-default.svg | 8 - packages/traffic-style/src/icons/z-plain.svg | 8 - packages/traffic-style/src/icons/z-small.svg | 8 - packages/traffic-style/src/lib/icon-meta.ts | 29 + .../traffic-style/src/lib/icon/compose.d.ts | 4 + .../src/lib/icon/compose.d.ts.map | 1 + .../traffic-style/src/lib/icon/compose.js | 74 ++ .../traffic-style/src/lib/icon/compose.js.map | 1 + .../src/lib/icon/compose.test.ts | 56 ++ .../traffic-style/src/lib/icon/compose.ts | 104 +++ .../traffic-style/src/lib/icon/contrast.d.ts | 6 + .../src/lib/icon/contrast.d.ts.map | 1 + .../traffic-style/src/lib/icon/contrast.js | 53 ++ .../src/lib/icon/contrast.js.map | 1 + .../traffic-style/src/lib/icon/contrast.ts | 61 ++ .../traffic-style/src/lib/icon/icon-id.d.ts | 21 + .../src/lib/icon/icon-id.d.ts.map | 1 + .../traffic-style/src/lib/icon/icon-id.js | 112 +++ .../traffic-style/src/lib/icon/icon-id.js.map | 1 + .../src/lib/icon/icon-id.test.ts | 78 ++ .../traffic-style/src/lib/icon/icon-id.ts | 155 ++++ packages/traffic-style/src/lib/icon/index.ts | 11 + .../traffic-style/src/lib/icon/rasterize.d.ts | 17 + .../src/lib/icon/rasterize.d.ts.map | 1 + .../traffic-style/src/lib/icon/rasterize.js | 52 ++ .../src/lib/icon/rasterize.js.map | 1 + .../src/lib/icon/rasterize.test.ts | 14 + .../traffic-style/src/lib/icon/rasterize.ts | 62 ++ packages/traffic-style/src/lib/icon/render.ts | 38 + .../traffic-style/src/lib/icon/resolve.d.ts | 10 + .../src/lib/icon/resolve.d.ts.map | 1 + .../traffic-style/src/lib/icon/resolve.js | 16 + .../traffic-style/src/lib/icon/resolve.js.map | 1 + .../traffic-style/src/lib/icon/resolve.ts | 26 + .../traffic-style/src/lib/icon/templates.d.ts | 22 + .../src/lib/icon/templates.d.ts.map | 1 + .../traffic-style/src/lib/icon/templates.js | 68 ++ .../src/lib/icon/templates.js.map | 1 + .../traffic-style/src/lib/icon/templates.ts | 101 +++ .../src/lib/pictograms/fontawesome.ts | 11 + .../src/lib/pictograms/index.d.ts | 18 + .../src/lib/pictograms/index.d.ts.map | 1 + .../traffic-style/src/lib/pictograms/index.js | 28 + .../src/lib/pictograms/index.js.map | 1 + .../traffic-style/src/lib/pictograms/index.ts | 19 + .../src/lib/pictograms/registry.test.ts | 41 + .../src/lib/pictograms/registry.ts | 38 + .../traffic-style/src/lib/pictograms/types.ts | 18 + .../traffic-style/src/lib/runtime/cache.ts | 109 +++ .../src/lib/runtime/icon-key.test.ts | 14 + .../traffic-style/src/lib/runtime/icon-key.ts | 7 + .../src/lib/runtime/icon-load.test.ts | 16 + .../src/lib/runtime/icon-load.ts | 19 + .../src/lib/runtime/icon-style.test.ts | 281 +++++++ .../src/lib/runtime/icon-style.ts | 145 ++++ .../traffic-style/src/lib/runtime/index.ts | 10 + .../traffic-style/src/lib/runtime/prewarm.ts | 46 + .../src/lib/runtime/runtime-dev.ts | 21 + packages/traffic-style/src/meta.json | 795 ++++++++++++++---- .../src/pictograms/abfall_recycling.svg | 1 + .../traffic-style/src/pictograms/bike.svg | 1 + .../src/pictograms/bilbiothek_archiv.svg | 1 + .../src/pictograms/bildung-allgemein.svg | 1 + .../src/pictograms/bildung-ausbildung.svg | 1 + .../src/pictograms/bildung-grundschule.svg | 1 + .../src/pictograms/bildung-kind.svg | 1 + .../src/pictograms/bildung-senior.svg | 1 + .../src/pictograms/bildung-weiterbildung.svg | 1 + .../src/pictograms/bildung-weiterfuehrend.svg | 1 + .../traffic-style/src/pictograms/bundr.svg | 1 + .../src/pictograms/charging-station.svg | 4 + packages/traffic-style/src/pictograms/db.svg | 1 + packages/traffic-style/src/pictograms/dot.svg | 1 + .../traffic-style/src/pictograms/faehre.svg | 4 + .../src/pictograms/flughafen.svg | 1 + .../src/pictograms/forschung.svg | 1 + .../traffic-style/src/pictograms/friedhof.svg | 1 + .../traffic-style/src/pictograms/gewerbe.svg | 1 + .../src/pictograms/haltestelle.svg | 1 + .../src/pictograms/hochschule.svg | 1 + .../traffic-style/src/pictograms/hotel.svg | 1 + .../traffic-style/src/pictograms/info.svg | 1 + .../traffic-style/src/pictograms/kita.svg | 1 + .../src/pictograms/krankenhaus_klinik.svg | 1 + .../traffic-style/src/pictograms/marker.svg | 1 + .../traffic-style/src/pictograms/museum.svg | 1 + packages/traffic-style/src/pictograms/ort.svg | 1 + .../src/pictograms/parkanlage.svg | 1 + .../traffic-style/src/pictograms/religion.svg | 1 + .../traffic-style/src/pictograms/schule.svg | 1 + .../src/pictograms/sehenswuerdigkeit.svg | 1 + .../traffic-style/src/pictograms/sport.svg | 1 + .../src/pictograms/sportanlage.svg | 1 + .../traffic-style/src/pictograms/taxi.svg | 1 + .../traffic-style/src/pictograms/theater.svg | 1 + .../traffic-style/src/scss/_variables.scss | 3 + .../src/scss/features/_base.scss | 53 +- .../src/scss/mixins/_auto-icon.scss | 7 + packages/traffic-style/src/tsconfig.json | 5 + packages/traffic-style/tsconfig.lib.json | 15 + packages/traffic-style/tsconfig.scripts.json | 15 + packages/traffic-style/vitest.config.ts | 13 + packages/ui/package.json | 1 + .../js/components/feature-list-item/icon.jsx | 35 - .../js/components/feature-list-item/icon.tsx | 80 ++ packages/ui/src/js/hooks/use-mapsight-icon.ts | 72 ++ packages/ui/src/js/hooks/useMapsightIcon.ts | 77 ++ .../ui/src/js/plugins/browser-defaults.ts | 6 + .../js/plugins/common/runtime-icon-style.ts | 86 ++ packages/vector-style-compiler/README.md | 30 +- .../__snapshots__/compiler.test.ts.snap | 75 ++ .../volatileHashCompile.test.ts.snap | 17 + .../__tests__/compiler.test.ts | 6 + .../__tests__/helperImports.test.ts | 15 + .../__tests__/mapValue.test.ts | 9 + .../__tests__/runtimeIconCompile.test.ts | 47 ++ .../__tests__/volatileCalcHelpers.test.ts | 19 + .../__tests__/volatileHashCompile.test.ts | 59 ++ .../src/js/cssToRules.ts | 4 + .../src/js/cssToRules/mapRule.ts | 6 + .../src/js/cssToRules/mapValue.ts | 31 +- .../helpers/createHelperImportsFromProgram.ts | 15 + .../src/js/helpers/volatileCalcHelpers.ts | 5 + .../vector-style-compiler/src/js/index.ts | 4 + .../src/js/rulesToTree.ts | 7 + .../src/js/template.source.js | 18 +- .../vector-style-compiler/src/js/template.ts | 18 +- .../src/js/treeToProgram.ts | 10 + 332 files changed, 5867 insertions(+), 1863 deletions(-) create mode 100644 .changeset/composable-runtime-icons.md create mode 100644 packages/lib-ol/src/js/style/styleFeatureScope.ts create mode 100644 packages/traffic-style/docs/CUSTOMIZING_SCSS.md create mode 100644 packages/traffic-style/docs/CUSTOM_ICON_BUILDS.md create mode 100644 packages/traffic-style/docs/DEVELOPMENT.md create mode 100644 packages/traffic-style/docs/ICON_CATALOG.md create mode 100644 packages/traffic-style/docs/ICON_INTEGRATION.md create mode 100644 packages/traffic-style/docs/RUNTIME_ICONS.md create mode 100644 packages/traffic-style/scripts/dev/build-composable-icons.ts rename packages/traffic-style/scripts/{ => dev}/create-meta-json.ts (85%) rename packages/traffic-style/scripts/{ => dev}/create-overview-md.ts (100%) create mode 100644 packages/traffic-style/scripts/dev/import-fontawesome.ts create mode 100644 packages/traffic-style/scripts/dev/import-pictograms.test.ts create mode 100644 packages/traffic-style/scripts/dev/import-pictograms.ts create mode 100644 packages/traffic-style/scripts/dev/write-dist-package.json.ts create mode 100644 packages/traffic-style/scripts/lib/composable-icons.test.ts create mode 100644 packages/traffic-style/scripts/lib/composable-icons.ts create mode 100644 packages/traffic-style/scripts/lib/pictogram-packs.ts create mode 100644 packages/traffic-style/scripts/traffic-composable-icons.ts delete mode 100644 packages/traffic-style/src/icons/0-default.svg delete mode 100644 packages/traffic-style/src/icons/0-plain.svg delete mode 100644 packages/traffic-style/src/icons/0-small.svg delete mode 100644 packages/traffic-style/src/icons/1-default.svg delete mode 100644 packages/traffic-style/src/icons/1-plain.svg delete mode 100644 packages/traffic-style/src/icons/1-small.svg delete mode 100644 packages/traffic-style/src/icons/2-default.svg delete mode 100644 packages/traffic-style/src/icons/2-plain.svg delete mode 100644 packages/traffic-style/src/icons/2-small.svg delete mode 100644 packages/traffic-style/src/icons/3-default.svg delete mode 100644 packages/traffic-style/src/icons/3-plain.svg delete mode 100644 packages/traffic-style/src/icons/3-small.svg delete mode 100644 packages/traffic-style/src/icons/4-default.svg delete mode 100644 packages/traffic-style/src/icons/4-plain.svg delete mode 100644 packages/traffic-style/src/icons/4-small.svg delete mode 100644 packages/traffic-style/src/icons/5-default.svg delete mode 100644 packages/traffic-style/src/icons/5-plain.svg delete mode 100644 packages/traffic-style/src/icons/5-small.svg delete mode 100644 packages/traffic-style/src/icons/6-default.svg delete mode 100644 packages/traffic-style/src/icons/6-plain.svg delete mode 100644 packages/traffic-style/src/icons/6-small.svg delete mode 100644 packages/traffic-style/src/icons/7-default.svg delete mode 100644 packages/traffic-style/src/icons/7-plain.svg delete mode 100644 packages/traffic-style/src/icons/7-small.svg delete mode 100644 packages/traffic-style/src/icons/8-default.svg delete mode 100644 packages/traffic-style/src/icons/8-plain.svg delete mode 100644 packages/traffic-style/src/icons/8-small.svg delete mode 100644 packages/traffic-style/src/icons/9-default.svg delete mode 100644 packages/traffic-style/src/icons/9-plain.svg delete mode 100644 packages/traffic-style/src/icons/9-small.svg delete mode 100644 packages/traffic-style/src/icons/a-default.svg delete mode 100644 packages/traffic-style/src/icons/a-plain.svg delete mode 100644 packages/traffic-style/src/icons/a-small.svg delete mode 100644 packages/traffic-style/src/icons/abfall_recycling-default.svg delete mode 100644 packages/traffic-style/src/icons/abfall_recycling-plain.svg delete mode 100644 packages/traffic-style/src/icons/b-default.svg delete mode 100644 packages/traffic-style/src/icons/b-plain.svg delete mode 100644 packages/traffic-style/src/icons/b-small.svg delete mode 100644 packages/traffic-style/src/icons/bike-default.svg delete mode 100644 packages/traffic-style/src/icons/bike-plain.svg delete mode 100644 packages/traffic-style/src/icons/bike-small.svg delete mode 100644 packages/traffic-style/src/icons/bike-xsmall.svg delete mode 100644 packages/traffic-style/src/icons/bilbiothek_archiv-default.svg delete mode 100644 packages/traffic-style/src/icons/bilbiothek_archiv-plain.svg delete mode 100644 packages/traffic-style/src/icons/bildung-allgemein-default.svg delete mode 100644 packages/traffic-style/src/icons/bildung-allgemein-plain.svg delete mode 100644 packages/traffic-style/src/icons/bildung-ausbildung-default.svg delete mode 100644 packages/traffic-style/src/icons/bildung-ausbildung-plain.svg delete mode 100644 packages/traffic-style/src/icons/bildung-grundschule-default.svg delete mode 100644 packages/traffic-style/src/icons/bildung-grundschule-plain.svg delete mode 100644 packages/traffic-style/src/icons/bildung-kind-default.svg delete mode 100644 packages/traffic-style/src/icons/bildung-kind-plain.svg delete mode 100644 packages/traffic-style/src/icons/bildung-senior-default.svg delete mode 100644 packages/traffic-style/src/icons/bildung-senior-plain.svg delete mode 100644 packages/traffic-style/src/icons/bildung-weiterbildung-default.svg delete mode 100644 packages/traffic-style/src/icons/bildung-weiterbildung-plain.svg delete mode 100644 packages/traffic-style/src/icons/bildung-weiterfuehrend-default.svg delete mode 100644 packages/traffic-style/src/icons/bildung-weiterfuehrend-plain.svg delete mode 100644 packages/traffic-style/src/icons/bundr-default.svg delete mode 100644 packages/traffic-style/src/icons/bundr-plain.svg delete mode 100644 packages/traffic-style/src/icons/c-default.svg delete mode 100644 packages/traffic-style/src/icons/c-plain.svg delete mode 100644 packages/traffic-style/src/icons/c-small.svg delete mode 100644 packages/traffic-style/src/icons/charging-station-default.svg delete mode 100644 packages/traffic-style/src/icons/charging-station-plain.svg delete mode 100644 packages/traffic-style/src/icons/d-default.svg delete mode 100644 packages/traffic-style/src/icons/d-plain.svg delete mode 100644 packages/traffic-style/src/icons/d-small.svg delete mode 100644 packages/traffic-style/src/icons/db-default.svg delete mode 100644 packages/traffic-style/src/icons/db-plain.svg delete mode 100644 packages/traffic-style/src/icons/dot-plain.svg delete mode 100644 packages/traffic-style/src/icons/e-default.svg delete mode 100644 packages/traffic-style/src/icons/e-plain.svg delete mode 100644 packages/traffic-style/src/icons/e-small.svg delete mode 100644 packages/traffic-style/src/icons/f-default.svg delete mode 100644 packages/traffic-style/src/icons/f-plain.svg delete mode 100644 packages/traffic-style/src/icons/f-small.svg delete mode 100644 packages/traffic-style/src/icons/faehre-default.svg delete mode 100644 packages/traffic-style/src/icons/faehre-plain.svg delete mode 100644 packages/traffic-style/src/icons/flughafen-default.svg delete mode 100644 packages/traffic-style/src/icons/flughafen-plain.svg delete mode 100644 packages/traffic-style/src/icons/forschung-default.svg delete mode 100644 packages/traffic-style/src/icons/forschung-plain.svg delete mode 100644 packages/traffic-style/src/icons/friedhof-default.svg delete mode 100644 packages/traffic-style/src/icons/friedhof-plain.svg delete mode 100644 packages/traffic-style/src/icons/g-default.svg delete mode 100644 packages/traffic-style/src/icons/g-plain.svg delete mode 100644 packages/traffic-style/src/icons/g-small.svg delete mode 100644 packages/traffic-style/src/icons/gewerbe-default.svg delete mode 100644 packages/traffic-style/src/icons/gewerbe-plain.svg delete mode 100644 packages/traffic-style/src/icons/h-default.svg delete mode 100644 packages/traffic-style/src/icons/h-plain.svg delete mode 100644 packages/traffic-style/src/icons/h-small.svg delete mode 100644 packages/traffic-style/src/icons/haltestelle-default.svg delete mode 100644 packages/traffic-style/src/icons/haltestelle-plain.svg delete mode 100644 packages/traffic-style/src/icons/hochschule-default.svg delete mode 100644 packages/traffic-style/src/icons/hochschule-plain.svg delete mode 100644 packages/traffic-style/src/icons/hotel-default.svg delete mode 100644 packages/traffic-style/src/icons/hotel-plain.svg delete mode 100644 packages/traffic-style/src/icons/i-default.svg delete mode 100644 packages/traffic-style/src/icons/i-plain.svg delete mode 100644 packages/traffic-style/src/icons/i-small.svg delete mode 100644 packages/traffic-style/src/icons/info-default.svg delete mode 100644 packages/traffic-style/src/icons/info-plain.svg delete mode 100644 packages/traffic-style/src/icons/j-default.svg delete mode 100644 packages/traffic-style/src/icons/j-plain.svg delete mode 100644 packages/traffic-style/src/icons/j-small.svg delete mode 100644 packages/traffic-style/src/icons/k-default.svg delete mode 100644 packages/traffic-style/src/icons/k-plain.svg delete mode 100644 packages/traffic-style/src/icons/k-small.svg delete mode 100644 packages/traffic-style/src/icons/kita-default.svg delete mode 100644 packages/traffic-style/src/icons/kita-plain.svg delete mode 100644 packages/traffic-style/src/icons/krankenhaus_klinik-default.svg delete mode 100644 packages/traffic-style/src/icons/krankenhaus_klinik-plain.svg delete mode 100644 packages/traffic-style/src/icons/l-default.svg delete mode 100644 packages/traffic-style/src/icons/l-plain.svg delete mode 100644 packages/traffic-style/src/icons/l-small.svg delete mode 100644 packages/traffic-style/src/icons/m-default.svg delete mode 100644 packages/traffic-style/src/icons/m-plain.svg delete mode 100644 packages/traffic-style/src/icons/m-small.svg delete mode 100644 packages/traffic-style/src/icons/marker-default.svg delete mode 100644 packages/traffic-style/src/icons/marker-plain.svg delete mode 100644 packages/traffic-style/src/icons/museum-default.svg delete mode 100644 packages/traffic-style/src/icons/museum-plain.svg delete mode 100644 packages/traffic-style/src/icons/n-default.svg delete mode 100644 packages/traffic-style/src/icons/n-plain.svg delete mode 100644 packages/traffic-style/src/icons/n-small.svg delete mode 100644 packages/traffic-style/src/icons/o-default.svg delete mode 100644 packages/traffic-style/src/icons/o-plain.svg delete mode 100644 packages/traffic-style/src/icons/o-small.svg delete mode 100644 packages/traffic-style/src/icons/ort-default.svg delete mode 100644 packages/traffic-style/src/icons/ort-plain.svg delete mode 100644 packages/traffic-style/src/icons/p-default.svg delete mode 100644 packages/traffic-style/src/icons/p-plain.svg delete mode 100644 packages/traffic-style/src/icons/p-small.svg delete mode 100644 packages/traffic-style/src/icons/parkanlage-default.svg delete mode 100644 packages/traffic-style/src/icons/parkanlage-plain.svg delete mode 100644 packages/traffic-style/src/icons/q-default.svg delete mode 100644 packages/traffic-style/src/icons/q-plain.svg delete mode 100644 packages/traffic-style/src/icons/q-small.svg delete mode 100644 packages/traffic-style/src/icons/r-default.svg delete mode 100644 packages/traffic-style/src/icons/r-plain.svg delete mode 100644 packages/traffic-style/src/icons/r-small.svg delete mode 100644 packages/traffic-style/src/icons/religion-default.svg delete mode 100644 packages/traffic-style/src/icons/religion-plain.svg delete mode 100644 packages/traffic-style/src/icons/s-default.svg delete mode 100644 packages/traffic-style/src/icons/s-plain.svg delete mode 100644 packages/traffic-style/src/icons/s-small.svg delete mode 100644 packages/traffic-style/src/icons/schule-default.svg delete mode 100644 packages/traffic-style/src/icons/schule-plain.svg delete mode 100644 packages/traffic-style/src/icons/sehenswuerdigkeit-default.svg delete mode 100644 packages/traffic-style/src/icons/sehenswuerdigkeit-plain.svg delete mode 100644 packages/traffic-style/src/icons/sport-default.svg delete mode 100644 packages/traffic-style/src/icons/sport-plain.svg delete mode 100644 packages/traffic-style/src/icons/sportanlage-default.svg delete mode 100644 packages/traffic-style/src/icons/sportanlage-plain.svg delete mode 100644 packages/traffic-style/src/icons/t-default.svg delete mode 100644 packages/traffic-style/src/icons/t-plain.svg delete mode 100644 packages/traffic-style/src/icons/t-small.svg delete mode 100644 packages/traffic-style/src/icons/taxi-default.svg delete mode 100644 packages/traffic-style/src/icons/taxi-plain.svg delete mode 100644 packages/traffic-style/src/icons/theater-default.svg delete mode 100644 packages/traffic-style/src/icons/theater-plain.svg delete mode 100644 packages/traffic-style/src/icons/u-default.svg delete mode 100644 packages/traffic-style/src/icons/u-plain.svg delete mode 100644 packages/traffic-style/src/icons/u-small.svg delete mode 100644 packages/traffic-style/src/icons/v-default.svg delete mode 100644 packages/traffic-style/src/icons/v-plain.svg delete mode 100644 packages/traffic-style/src/icons/v-small.svg delete mode 100644 packages/traffic-style/src/icons/w-default.svg delete mode 100644 packages/traffic-style/src/icons/w-plain.svg delete mode 100644 packages/traffic-style/src/icons/w-small.svg delete mode 100644 packages/traffic-style/src/icons/x-default.svg delete mode 100644 packages/traffic-style/src/icons/x-plain.svg delete mode 100644 packages/traffic-style/src/icons/x-small.svg delete mode 100644 packages/traffic-style/src/icons/y-default.svg delete mode 100644 packages/traffic-style/src/icons/y-plain.svg delete mode 100644 packages/traffic-style/src/icons/y-small.svg delete mode 100644 packages/traffic-style/src/icons/z-default.svg delete mode 100644 packages/traffic-style/src/icons/z-plain.svg delete mode 100644 packages/traffic-style/src/icons/z-small.svg create mode 100644 packages/traffic-style/src/lib/icon-meta.ts create mode 100644 packages/traffic-style/src/lib/icon/compose.d.ts create mode 100644 packages/traffic-style/src/lib/icon/compose.d.ts.map create mode 100644 packages/traffic-style/src/lib/icon/compose.js create mode 100644 packages/traffic-style/src/lib/icon/compose.js.map create mode 100644 packages/traffic-style/src/lib/icon/compose.test.ts create mode 100644 packages/traffic-style/src/lib/icon/compose.ts create mode 100644 packages/traffic-style/src/lib/icon/contrast.d.ts create mode 100644 packages/traffic-style/src/lib/icon/contrast.d.ts.map create mode 100644 packages/traffic-style/src/lib/icon/contrast.js create mode 100644 packages/traffic-style/src/lib/icon/contrast.js.map create mode 100644 packages/traffic-style/src/lib/icon/contrast.ts create mode 100644 packages/traffic-style/src/lib/icon/icon-id.d.ts create mode 100644 packages/traffic-style/src/lib/icon/icon-id.d.ts.map create mode 100644 packages/traffic-style/src/lib/icon/icon-id.js create mode 100644 packages/traffic-style/src/lib/icon/icon-id.js.map create mode 100644 packages/traffic-style/src/lib/icon/icon-id.test.ts create mode 100644 packages/traffic-style/src/lib/icon/icon-id.ts create mode 100644 packages/traffic-style/src/lib/icon/index.ts create mode 100644 packages/traffic-style/src/lib/icon/rasterize.d.ts create mode 100644 packages/traffic-style/src/lib/icon/rasterize.d.ts.map create mode 100644 packages/traffic-style/src/lib/icon/rasterize.js create mode 100644 packages/traffic-style/src/lib/icon/rasterize.js.map create mode 100644 packages/traffic-style/src/lib/icon/rasterize.test.ts create mode 100644 packages/traffic-style/src/lib/icon/rasterize.ts create mode 100644 packages/traffic-style/src/lib/icon/render.ts create mode 100644 packages/traffic-style/src/lib/icon/resolve.d.ts create mode 100644 packages/traffic-style/src/lib/icon/resolve.d.ts.map create mode 100644 packages/traffic-style/src/lib/icon/resolve.js create mode 100644 packages/traffic-style/src/lib/icon/resolve.js.map create mode 100644 packages/traffic-style/src/lib/icon/resolve.ts create mode 100644 packages/traffic-style/src/lib/icon/templates.d.ts create mode 100644 packages/traffic-style/src/lib/icon/templates.d.ts.map create mode 100644 packages/traffic-style/src/lib/icon/templates.js create mode 100644 packages/traffic-style/src/lib/icon/templates.js.map create mode 100644 packages/traffic-style/src/lib/icon/templates.ts create mode 100644 packages/traffic-style/src/lib/pictograms/fontawesome.ts create mode 100644 packages/traffic-style/src/lib/pictograms/index.d.ts create mode 100644 packages/traffic-style/src/lib/pictograms/index.d.ts.map create mode 100644 packages/traffic-style/src/lib/pictograms/index.js create mode 100644 packages/traffic-style/src/lib/pictograms/index.js.map create mode 100644 packages/traffic-style/src/lib/pictograms/index.ts create mode 100644 packages/traffic-style/src/lib/pictograms/registry.test.ts create mode 100644 packages/traffic-style/src/lib/pictograms/registry.ts create mode 100644 packages/traffic-style/src/lib/pictograms/types.ts create mode 100644 packages/traffic-style/src/lib/runtime/cache.ts create mode 100644 packages/traffic-style/src/lib/runtime/icon-key.test.ts create mode 100644 packages/traffic-style/src/lib/runtime/icon-key.ts create mode 100644 packages/traffic-style/src/lib/runtime/icon-load.test.ts create mode 100644 packages/traffic-style/src/lib/runtime/icon-load.ts create mode 100644 packages/traffic-style/src/lib/runtime/icon-style.test.ts create mode 100644 packages/traffic-style/src/lib/runtime/icon-style.ts create mode 100644 packages/traffic-style/src/lib/runtime/index.ts create mode 100644 packages/traffic-style/src/lib/runtime/prewarm.ts create mode 100644 packages/traffic-style/src/lib/runtime/runtime-dev.ts create mode 100644 packages/traffic-style/src/pictograms/abfall_recycling.svg create mode 100644 packages/traffic-style/src/pictograms/bike.svg create mode 100644 packages/traffic-style/src/pictograms/bilbiothek_archiv.svg create mode 100644 packages/traffic-style/src/pictograms/bildung-allgemein.svg create mode 100644 packages/traffic-style/src/pictograms/bildung-ausbildung.svg create mode 100644 packages/traffic-style/src/pictograms/bildung-grundschule.svg create mode 100644 packages/traffic-style/src/pictograms/bildung-kind.svg create mode 100644 packages/traffic-style/src/pictograms/bildung-senior.svg create mode 100644 packages/traffic-style/src/pictograms/bildung-weiterbildung.svg create mode 100644 packages/traffic-style/src/pictograms/bildung-weiterfuehrend.svg create mode 100644 packages/traffic-style/src/pictograms/bundr.svg create mode 100644 packages/traffic-style/src/pictograms/charging-station.svg create mode 100644 packages/traffic-style/src/pictograms/db.svg create mode 100644 packages/traffic-style/src/pictograms/dot.svg create mode 100644 packages/traffic-style/src/pictograms/faehre.svg create mode 100644 packages/traffic-style/src/pictograms/flughafen.svg create mode 100644 packages/traffic-style/src/pictograms/forschung.svg create mode 100644 packages/traffic-style/src/pictograms/friedhof.svg create mode 100644 packages/traffic-style/src/pictograms/gewerbe.svg create mode 100644 packages/traffic-style/src/pictograms/haltestelle.svg create mode 100644 packages/traffic-style/src/pictograms/hochschule.svg create mode 100644 packages/traffic-style/src/pictograms/hotel.svg create mode 100644 packages/traffic-style/src/pictograms/info.svg create mode 100644 packages/traffic-style/src/pictograms/kita.svg create mode 100644 packages/traffic-style/src/pictograms/krankenhaus_klinik.svg create mode 100644 packages/traffic-style/src/pictograms/marker.svg create mode 100644 packages/traffic-style/src/pictograms/museum.svg create mode 100644 packages/traffic-style/src/pictograms/ort.svg create mode 100644 packages/traffic-style/src/pictograms/parkanlage.svg create mode 100644 packages/traffic-style/src/pictograms/religion.svg create mode 100644 packages/traffic-style/src/pictograms/schule.svg create mode 100644 packages/traffic-style/src/pictograms/sehenswuerdigkeit.svg create mode 100644 packages/traffic-style/src/pictograms/sport.svg create mode 100644 packages/traffic-style/src/pictograms/sportanlage.svg create mode 100644 packages/traffic-style/src/pictograms/taxi.svg create mode 100644 packages/traffic-style/src/pictograms/theater.svg create mode 100644 packages/traffic-style/src/tsconfig.json create mode 100644 packages/traffic-style/tsconfig.lib.json create mode 100644 packages/traffic-style/tsconfig.scripts.json create mode 100644 packages/traffic-style/vitest.config.ts delete mode 100644 packages/ui/src/js/components/feature-list-item/icon.jsx create mode 100644 packages/ui/src/js/components/feature-list-item/icon.tsx create mode 100644 packages/ui/src/js/hooks/use-mapsight-icon.ts create mode 100644 packages/ui/src/js/hooks/useMapsightIcon.ts create mode 100644 packages/ui/src/js/plugins/common/runtime-icon-style.ts create mode 100644 packages/vector-style-compiler/__tests__/__snapshots__/volatileHashCompile.test.ts.snap create mode 100644 packages/vector-style-compiler/__tests__/helperImports.test.ts create mode 100644 packages/vector-style-compiler/__tests__/runtimeIconCompile.test.ts create mode 100644 packages/vector-style-compiler/__tests__/volatileCalcHelpers.test.ts create mode 100644 packages/vector-style-compiler/__tests__/volatileHashCompile.test.ts create mode 100644 packages/vector-style-compiler/src/js/helpers/createHelperImportsFromProgram.ts create mode 100644 packages/vector-style-compiler/src/js/helpers/volatileCalcHelpers.ts diff --git a/.changeset/composable-runtime-icons.md b/.changeset/composable-runtime-icons.md new file mode 100644 index 00000000..1386587f --- /dev/null +++ b/.changeset/composable-runtime-icons.md @@ -0,0 +1,8 @@ +--- +"@mapsight/traffic-style": minor +"@mapsight/lib-ol": minor +"@mapsight/vector-style-compiler": minor +"@mapsight/ui": minor +--- + +Add composable runtime icons: pictogram-based templates and `mapsightIconId` parsing in traffic-style, async rasterization with volatile style-cache invalidation in lib-ol and vector-style-compiler, plus `useMapsightIcon` and a runtime icon style plugin in ui. diff --git a/packages/lib-ol/src/js/style/createCachedStyleFunction.ts b/packages/lib-ol/src/js/style/createCachedStyleFunction.ts index ce53c668..8f002ee6 100644 --- a/packages/lib-ol/src/js/style/createCachedStyleFunction.ts +++ b/packages/lib-ol/src/js/style/createCachedStyleFunction.ts @@ -1,5 +1,5 @@ -import type {Type as GeometryType} from "ol/geom/Geometry"; import type Geometry from "ol/geom/Geometry"; +import type {Type as GeometryType} from "ol/geom/Geometry"; import type GeometryCollection from "ol/geom/GeometryCollection"; import LRUCache from "ol/structs/LRUCache"; import type Style from "ol/style/Style"; @@ -11,6 +11,7 @@ import deriveGeometriesFromBase from "../geometry/deriveGeometriesFromBase.ts"; import type {GroupedRootStyleDeclaration} from "../index.ts"; import declarationToGeometry from "./declarationToGeometry.ts"; import declarationToStyle from "./declarationToStyle.ts"; +import {enterStyleFeatureScope} from "./styleFeatureScope.ts"; import type { MapsightStyleFunction, MapsightStyleFunctionEnv, @@ -69,6 +70,12 @@ export type StyleFunctionOptions = { geometryType: GeometryType, styleName: string, ) => unknown; // Using GroupedRootStyleDeclaration here breaks tsc, probably because the object is too big/complex + volatileHashFunction?: ( + env: MapsightStyleFunctionEnv, + props: MapsightStyleFunctionProps, + geometryType: GeometryType, + styleName: string, + ) => string; allowedProps?: Array | false; allowedStyles?: Array | false; cacheLevel1Size?: number; @@ -83,6 +90,7 @@ export type StyleFunctionOptions = { * @param [metricsCollector] optional callback receiving per-invocation runtime metrics (hash timing, cache hit/miss, and declaration/style timings) * @param declarationHashFunction style declaration hash function * @param declarationFunction style declaration function + * @param [volatileHashFunction] optional volatile hash function for values that should trigger a cache miss when changed, even if the declaration hash is the same (e.g. for time-based styling) * @param [allowedProps=false] list of props allowed, false = all allowed * @param [allowedStyles=false] list of styles allowed, false = all allowed * @param [cacheLevel1Size=100] size of first level cache that caches feature geometry styles based on feature and environment state @@ -96,6 +104,7 @@ export default function createCachedStyleFunction({ metricsCollector, declarationHashFunction, declarationFunction, + volatileHashFunction, allowedProps = false, allowedStyles = false, cacheLevel1Size = DEFAULT_CACHE_LEVEL_1_SIZE, @@ -110,6 +119,24 @@ export default function createCachedStyleFunction({ const cacheLevel2 = new LRUCache(cacheLevel2Size); // the second level cache caches style objects based on the rules that apply and the environment state const cacheLevel3 = new LRUCache - -← Index - -

    Mapsight UI Simple map

    - -
    - - diff --git a/apps/demo-vite/src/simple-map.tsx b/apps/demo-vite/src/simple-map.tsx deleted file mode 100644 index 73a9c88b..00000000 --- a/apps/demo-vite/src/simple-map.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import {createRoot} from "react-dom/client"; - -import Instance from "@mapsight/ui/components/instance"; -import Map from "@mapsight/ui/components/map"; -import MapWrapper from "@mapsight/ui/components/map-wrapper"; -import {map, mapView, mapViewCenter, mapViewExtent} from "@mapsight/ui/config"; -import {metaData, osm} from "@mapsight/ui/config/map/layers"; -import createDefaultPlugins from "@mapsight/ui/plugins/browser-defaults"; - -const bmc = { - ...map( - { - osm: osm( - "https://tile.openstreetmap.org/{z}/{x}/{y}.png", - true, - metaData( - "OSM", - '© OpenStreetMap-Mitwirkende-Mitwirkende', - true, - false, - true, - "Karte", - ), - ), - }, - mapView( - mapViewCenter(1171479, 6848253), // x, y ^= 52.2653825, 10.523575 (lat, lon) - mapViewExtent(1097392, 6789091, 1240635, 6895797), // minx, miny, maxx, maxy http://bboxfinder.com/#51.938934,9.858041,52.526000,11.144814 - 14, // z - 10, // minZoom - 18, // maxZoom - ), - ), -}; - -const createOptions = { - plugins: createDefaultPlugins(), - uiState: { - map: { - show: true, - }, - }, -}; - -const noopStyleFunction = () => []; - -const root = createRoot(document.querySelector("#root")!); -root.render( - - - - - , -); diff --git a/apps/demo-vite/.gitignore b/apps/showcase/.gitignore similarity index 100% rename from apps/demo-vite/.gitignore rename to apps/showcase/.gitignore diff --git a/apps/demo-vite/eslint.config.mts b/apps/showcase/eslint.config.mts similarity index 91% rename from apps/demo-vite/eslint.config.mts rename to apps/showcase/eslint.config.mts index 150b5ff0..a8506303 100644 --- a/apps/demo-vite/eslint.config.mts +++ b/apps/showcase/eslint.config.mts @@ -5,7 +5,7 @@ import baseConfig from "../../configs/eslint-config-base-app.mts"; export default defineConfig([ baseConfig, { - ignores: ["src/generated/**/*"], + ignores: ["src/generated/**/*", "vite.config.ts"], }, { name: "todos", diff --git a/apps/demo-vite/package.json b/apps/showcase/package.json similarity index 75% rename from apps/demo-vite/package.json rename to apps/showcase/package.json index 9b65960a..4d9ad11d 100644 --- a/apps/demo-vite/package.json +++ b/apps/showcase/package.json @@ -1,12 +1,11 @@ { - "name": "@mapsight/demo-vite", - "description": "Mapsight Demo Vite", - "version": "0.0.6", + "name": "@mapsight/showcase", + "description": "Mapsight ecosystem showcase — UI demo, icon catalog, and package overview", + "version": "0.1.0", "private": true, "type": "module", "dependencies": { "@mapsight/core": "workspace:^", - "@mapsight/demo-shared": "workspace:^", "@mapsight/lib-js": "workspace:^", "@mapsight/lib-ol": "workspace:^", "@mapsight/lib-redux": "workspace:^", @@ -18,7 +17,6 @@ "react": "catalog:", "react-dom": "catalog:", "react-redux": "catalog:", - "react-router": "^7.15.0", "react-router-dom": "^7.15.0", "reselect": "catalog:", "tailwindcss": "catalog:" @@ -29,7 +27,11 @@ "@types/node": "catalog:", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "mkdirp": "^3.0.1", + "npm-run-all": "^4.1.5", + "rimraf": "^6.1.3", "terser": "^5.47.1", + "typescript": "catalog:", "vite": "^8.0.14" }, "license": "UNLICENSED", @@ -39,11 +41,12 @@ "scripts": { "build": "npm-run-all --parallel build:mapsightStyle copy --sequential build:app", "build:app": "vite build --mode production --minify terser", - "build:mapsightStyle": "vector-style-compiler src/vector-styles/demo.scss --output src/generated/mapsight-vector-styles --name demo", + "build:mapsightStyle": "npm-run-all build:mapsightStyle:*", + "build:mapsightStyle:demo": "vector-style-compiler src/vector-styles/demo.scss --output src/generated/mapsight-vector-styles --name demo", + "build:mapsightStyle:icons": "vector-style-compiler src/vector-styles/icon-demo.scss --output src/generated/mapsight-vector-styles --name icon-demo", "clean": "rimraf dist node_modules/.vite src/generated public/img/mapsight*", "clean-build": "run-s clean build", "copy": "run-p copy:*", - "copy:demo-data": "mkdirp src/combined-list/data && cp ../../packages/demo-shared/data/*.geojson src/combined-list/data/", "copy:traffic-style": "mkdirp public/img && cp -R node_modules/@mapsight/traffic-style/img/* public/img/", "copy:ui": "mkdirp public/img && cp -R node_modules/@mapsight/ui/dist/img/* public/img/", "dev": "npm-run-all --parallel build:mapsightStyle copy --sequential dev:app", diff --git a/apps/demo-vite/public/img/.keep b/apps/showcase/public/img/.keep similarity index 100% rename from apps/demo-vite/public/img/.keep rename to apps/showcase/public/img/.keep diff --git a/apps/showcase/src/app.tsx b/apps/showcase/src/app.tsx new file mode 100644 index 00000000..6b0168cc --- /dev/null +++ b/apps/showcase/src/app.tsx @@ -0,0 +1,38 @@ +import {BrowserRouter, Navigate, Route, Routes} from "react-router-dom"; + +import {CatalogPage} from "./icons/catalog-page.tsx"; +import {EditorPage} from "./icons/editor-page.tsx"; +import {ShowcaseLayout} from "./layout/showcase-layout.tsx"; +import {LandingPage} from "./pages/landing-page.tsx"; +import {CombinedListPage} from "./pages/ui-demos/combined-list-page.tsx"; +import {CustomPage} from "./pages/ui-demos/custom-page.tsx"; +import {FullPage} from "./pages/ui-demos/full-page.tsx"; +import {RouterPage} from "./pages/ui-demos/router-page.tsx"; +import {SimpleMapPage} from "./pages/ui-demos/simple-map-page.tsx"; + +export function App() { + return ( + + + }> + } /> + } + /> + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + + + ); +} diff --git a/packages/demo-shared/src/combined-list.ts b/apps/showcase/src/combined-list/create-combined-list-demo.ts similarity index 100% rename from packages/demo-shared/src/combined-list.ts rename to apps/showcase/src/combined-list/create-combined-list-demo.ts diff --git a/apps/showcase/src/combined-list/shared.tsx b/apps/showcase/src/combined-list/shared.tsx new file mode 100644 index 00000000..74694483 --- /dev/null +++ b/apps/showcase/src/combined-list/shared.tsx @@ -0,0 +1,11 @@ +import {createCombinedListDemo} from "./create-combined-list-demo.ts"; + +export {default as styleFunction} from "../generated/mapsight-vector-styles/demo"; + +const parksUrl = new URL("../data/parks.geojson", import.meta.url).toString(); +const cafesUrl = new URL("../data/cafes.geojson", import.meta.url).toString(); + +export const {baseMapsightConfig, createOptions} = createCombinedListDemo({ + parks: parksUrl, + cafes: cafesUrl, +}); diff --git a/apps/demo-next/public/combined-list/cafes.geojson b/apps/showcase/src/data/cafes.geojson similarity index 100% rename from apps/demo-next/public/combined-list/cafes.geojson rename to apps/showcase/src/data/cafes.geojson diff --git a/apps/demo-vite/src/data.geojson b/apps/showcase/src/data/demo.geojson similarity index 100% rename from apps/demo-vite/src/data.geojson rename to apps/showcase/src/data/demo.geojson diff --git a/apps/demo-next/public/combined-list/parks.geojson b/apps/showcase/src/data/parks.geojson similarity index 100% rename from apps/demo-next/public/combined-list/parks.geojson rename to apps/showcase/src/data/parks.geojson diff --git a/apps/demo-vite/src/features/native-fullscreen/plugin.ts b/apps/showcase/src/features/native-fullscreen/plugin.ts similarity index 100% rename from apps/demo-vite/src/features/native-fullscreen/plugin.ts rename to apps/showcase/src/features/native-fullscreen/plugin.ts diff --git a/apps/showcase/src/global.css b/apps/showcase/src/global.css new file mode 100644 index 00000000..d049b7d3 --- /dev/null +++ b/apps/showcase/src/global.css @@ -0,0 +1,264 @@ +@import "tailwindcss"; + +html, +body, +#root { + height: 100%; +} + +body { + margin: 0; + background: #fff; + color: #15202b; + font-family: + Inter, + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + sans-serif; + line-height: 1.5; +} + +.showcase { + display: flex; + flex-direction: column; + height: 100%; + background: #fff; +} + +.showcase__header { + border-bottom: 1px solid #d8dee6; + background: #fff; +} + +.showcase__header-inner, +.showcase__subnav-inner { + padding-left: 1.25rem; + padding-right: 1.25rem; +} + +.showcase__header-inner { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding-top: 0.65rem; + padding-bottom: 0.65rem; +} + +.showcase__brand { + display: flex; + align-items: baseline; + gap: 0.5rem; +} + +.showcase__tagline { + font-size: 0.85rem; + color: #64748b; +} + +.showcase__nav ul { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + margin: 0; + padding: 0; + list-style: none; +} + +.showcase__nav-link { + display: inline-block; + padding: 0.35rem 0.75rem; + border-radius: 999px; + font-size: 0.9rem; + font-weight: 600; + color: #334155; + text-decoration: none; +} + +.showcase__nav-link:hover { + background: #f1f5f9; +} + +.showcase__nav-link.is-active { + background: #dbeafe; + color: #1d4ed8; +} + +.showcase__main { + flex: 1; + min-height: 0; + background: #fff; +} + +.showcase__main--embed { + overflow: auto; +} + +.showcase__main--icon-editor { + overflow: hidden; +} + +.showcase__subnav { + border-bottom: 1px solid #d8dee6; + background: #fff; +} + +.showcase__subnav-inner { + padding-top: 0.45rem; + padding-bottom: 0.45rem; +} + +.showcase__subnav ul { + display: flex; + flex-wrap: wrap; + gap: 0.35rem; + margin: 0; + padding: 0; + list-style: none; +} + +.showcase__subnav-link { + display: inline-block; + padding: 0.3rem 0.65rem; + border-radius: 8px; + font-size: 0.85rem; + font-weight: 600; + color: #475569; + text-decoration: none; +} + +.showcase__subnav-link:hover { + background: #f1f5f9; +} + +.showcase__subnav-link.is-active { + background: #eff6ff; + color: #1d4ed8; + box-shadow: inset 0 0 0 1px #bfdbfe; +} + +.ui-demo-embed { + height: 100%; + padding: 1.25rem; + overflow: auto; + box-sizing: border-box; +} + +.ui-demo-embed__frame { + width: 100%; + max-width: 880px; + height: 100%; + min-height: 520px; + margin: 0 auto; +} + +.ui-demo { + height: 100%; + min-height: 0; +} + +.ui-demo-router-nav { + border-bottom: 1px solid #d8dee6; + background: #fff; +} + +.ui-demo-router-nav ul { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + margin: 0; + padding: 0.5rem 0.75rem; + list-style: none; +} + +.ui-demo-router-nav__link { + display: inline-block; + padding: 0.25rem 0.65rem; + border-radius: 6px; + font-size: 0.9rem; + color: #334155; + text-decoration: none; +} + +.ui-demo-router-nav__link:hover { + background: #f1f5f9; +} + +.ui-demo-router-content { + padding: 0.5rem 0.75rem; + background: #fff; + border-bottom: 1px solid #e2e8f0; + font-size: 0.95rem; +} + +.landing { + height: 100%; + overflow: auto; +} + +.landing__inner { + width: 100%; + max-width: 72rem; + margin: 0 auto; + padding: 2rem 1.25rem 3rem; +} + +.landing__hero { + margin-bottom: 2rem; +} + +.landing__hero h1 { + margin: 0 0 0.5rem; + font-size: 2rem; +} + +.landing__hero p { + margin: 0; + color: #5b6773; + font-size: 1.05rem; + max-width: 42rem; +} + +.landing__grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); + gap: 1rem; +} + +.landing__card { + display: grid; + gap: 0.5rem; + padding: 1.25rem; + border: 1px solid #d8dee6; + border-radius: 12px; + background: #fff; + color: inherit; + text-decoration: none; + transition: + border-color 0.15s, + box-shadow 0.15s; +} + +.landing__card:hover { + border-color: #93c5fd; + box-shadow: 0 4px 16px rgb(37 99 235 / 8%); +} + +.landing__card h2 { + margin: 0; + font-size: 1.1rem; +} + +.landing__card p { + margin: 0; + color: #5b6773; + font-size: 0.95rem; +} + +.landing__card-link { + font-size: 0.9rem; + font-weight: 600; + color: #2563eb; +} diff --git a/apps/showcase/src/icons/catalog-grid.tsx b/apps/showcase/src/icons/catalog-grid.tsx new file mode 100644 index 00000000..9e1f38db --- /dev/null +++ b/apps/showcase/src/icons/catalog-grid.tsx @@ -0,0 +1,149 @@ +import type {ReactNode} from "react"; + +import {useMapsightIcon} from "@mapsight/ui/hooks/useMapsightIcon"; + +import type {CatalogSectionKind} from "./catalog-sections.ts"; + +function prebuiltIconSrc(id: string): string { + return `/img/mapsight-icons-svg/${id}-default.svg`; +} + +export function CatalogGrid({ + ids, + kind, + activeId = "", + onSelect, + showLabels = false, +}: { + ids: string[]; + kind: CatalogSectionKind; + activeId?: string; + onSelect?: (id: string) => void; + showLabels?: boolean; +}) { + return ( +
    + {ids.map((id) => ( + + ))} +
    + ); +} + +function CatalogGridItem({ + id, + kind, + active, + onSelect, + interactive, +}: { + id: string; + kind: CatalogSectionKind; + active: boolean; + onSelect?: (id: string) => void; + interactive: boolean; +}) { + if (kind === "prebuilt") { + return ( + + + + ); + } + + return ( + + ); +} + +function RuntimeCatalogGridItem({ + id, + active, + onSelect, + interactive, +}: { + id: string; + active: boolean; + onSelect?: (id: string) => void; + interactive: boolean; +}) { + const {src, bitmap, loading} = useMapsightIcon(id); + + return ( + + {src ? ( + + ) : ( + + {loading ? "…" : ""} + + )} + + ); +} + +function CatalogGridItemShell({ + id, + active, + onSelect, + interactive, + children, +}: { + id: string; + active: boolean; + onSelect?: (id: string) => void; + interactive: boolean; + children: ReactNode; +}) { + const className = `catalog-grid-item${active ? " is-active" : ""}`; + + if (!interactive) { + return ( +
    + {children} + {id} +
    + ); + } + + return ( + + ); +} diff --git a/apps/showcase/src/icons/catalog-page.tsx b/apps/showcase/src/icons/catalog-page.tsx new file mode 100644 index 00000000..d2b346fd --- /dev/null +++ b/apps/showcase/src/icons/catalog-page.tsx @@ -0,0 +1,36 @@ +import {CatalogGrid} from "./catalog-grid.tsx"; +import {catalogIconCount, catalogSections} from "./catalog-sections.ts"; + +export function CatalogPage() { + return ( +
    +
    +
    +

    Icon catalog

    +

    + {catalogIconCount} icons across prebuilt traffic + sprites, traffic-style pictograms, and Font Awesome + pictograms. +

    +
    +
    + + {catalogSections.map((section) => ( +
    +

    + {section.title}{" "} + + ({section.ids.length}) + +

    +

    {section.description}

    + +
    + ))} +
    + ); +} diff --git a/apps/showcase/src/icons/catalog-sections.ts b/apps/showcase/src/icons/catalog-sections.ts new file mode 100644 index 00000000..08f9517a --- /dev/null +++ b/apps/showcase/src/icons/catalog-sections.ts @@ -0,0 +1,48 @@ +import {listSpriteIconIds} from "@mapsight/traffic-style/icon-meta"; +import {listPictogramIdsBySource} from "@mapsight/traffic-style/runtime-dev"; + +export type CatalogSectionKind = "prebuilt" | "runtime"; + +export type CatalogSection = { + id: string; + title: string; + description: string; + kind: CatalogSectionKind; + ids: string[]; +}; + +const prebuiltIds = listSpriteIconIds(); +const trafficStyleIds = listPictogramIdsBySource("traffic-style"); +const fontAwesomeIds = listPictogramIdsBySource("fontawesome"); + +export const catalogSections: CatalogSection[] = [ + { + id: "prebuilt", + title: "Prebuilt", + description: + "Pixel-perfect traffic icons from the sprite sheet — not composed at runtime.", + kind: "prebuilt", + ids: prebuiltIds, + }, + { + id: "traffic-style", + title: "Traffic-style pictograms", + description: + "Glyph-only POI pictograms composed at runtime with backgrounds and variants.", + kind: "runtime", + ids: trafficStyleIds, + }, + { + id: "fontawesome", + title: "Font Awesome pictograms", + description: + "Imported Font Awesome glyphs composed at runtime with the same POI templates.", + kind: "runtime", + ids: fontAwesomeIds, + }, +]; + +export const catalogIconCount = catalogSections.reduce( + (total, section) => total + section.ids.length, + 0, +); diff --git a/apps/showcase/src/icons/demo-features.ts b/apps/showcase/src/icons/demo-features.ts new file mode 100644 index 00000000..bfed4287 --- /dev/null +++ b/apps/showcase/src/icons/demo-features.ts @@ -0,0 +1,85 @@ +import {formatMapsightIcon} from "@mapsight/traffic-style/runtime-dev"; + +export type DemoIconKind = "sprite" | "runtime-default" | "runtime-colored"; + +export type DemoMapFeature = { + id: string; + title: string; + kind: DemoIconKind; + coordinates: [number, number]; + mapsightIconId: string; +}; + +export const demoMapFeatures: DemoMapFeature[] = [ + { + id: "stau", + title: "Stau", + kind: "sprite", + coordinates: [10.512, 52.268], + mapsightIconId: "stau", + }, + { + id: "ampel", + title: "Ampel", + kind: "sprite", + coordinates: [10.518, 52.266], + mapsightIconId: "ampel", + }, + { + id: "baustelle", + title: "Baustelle", + kind: "sprite", + coordinates: [10.524, 52.264], + mapsightIconId: "baustelle", + }, + { + id: "museum-default-id", + title: "Museum", + kind: "runtime-default", + coordinates: [10.53, 52.269], + mapsightIconId: "museum", + }, + { + id: "charging-default", + title: "Charging station", + kind: "runtime-default", + coordinates: [10.536, 52.267], + mapsightIconId: "charging-station", + }, + { + id: "library-default", + title: "Library", + kind: "runtime-default", + coordinates: [10.528, 52.262], + mapsightIconId: "bilbiothek_archiv", + }, + { + id: "museum-colored", + title: "Museum", + kind: "runtime-colored", + coordinates: [10.522, 52.271], + mapsightIconId: "museum/#be123c", + }, + { + id: "charging-colored", + title: "Charging station", + kind: "runtime-colored", + coordinates: [10.534, 52.263], + mapsightIconId: "charging-station/#059669/#ffffff", + }, + { + id: "school-colored", + title: "School", + kind: "runtime-colored", + coordinates: [10.526, 52.259], + mapsightIconId: "fa-school/#1d4ed8/#ffffff", + }, +]; + +export const demoIconKindLabels: Record = { + sprite: "Sprite sheet", + "runtime-default": "Runtime (default colors)", + "runtime-colored": "Runtime (custom colors)", +}; + +export {formatMapsightIcon}; diff --git a/apps/showcase/src/icons/editor-page.tsx b/apps/showcase/src/icons/editor-page.tsx new file mode 100644 index 00000000..b33f5ce1 --- /dev/null +++ b/apps/showcase/src/icons/editor-page.tsx @@ -0,0 +1,284 @@ +import {useEffect, useMemo, useState} from "react"; +import {useDispatch} from "react-redux"; +import {useSearchParams} from "react-router-dom"; + +import { + buildCatalogTargets, + defaultIconCache, + listPictogramIds, + parseMapsightIcon, + pickContrastForeground, + prewarmCatalog, +} from "@mapsight/traffic-style/runtime-dev"; +import Instance from "@mapsight/ui/components/instance"; +import Map from "@mapsight/ui/components/map"; +import MapWrapper from "@mapsight/ui/components/map-wrapper"; +import {FEATURE_SOURCES} from "@mapsight/ui/config/constants/controllers"; + +import {updateFeatureProperty} from "@mapsight/core/lib/feature-sources/actions"; + +import { + ICON_BACKGROUND_PALETTE, + ICON_FOREGROUND_PALETTE, +} from "./icon-color-palette.ts"; +import {IconColorPicker} from "./icon-color-picker.tsx"; +import {IconPreview} from "./icon-preview.tsx"; +import { + DEFAULT_ICON_BACKGROUND, + EDITOR_PREVIEW_FEATURE_ID, + buildMapsightIcon, + createBaseMapsightConfig, + createOptions, + formatEditorPreviewFeatureJson, + styleFunction, +} from "./map-config.ts"; + +const pictogramIds = listPictogramIds(); + +type IconContentMode = "pictogram" | "label"; + +export function EditorPage() { + const [searchParams] = useSearchParams(); + const plainMap = searchParams.get("plainMap") === "1"; + const baseMapsightConfig = useMemo( + () => createBaseMapsightConfig({plainMap}), + [plainMap], + ); + + return ( + + + + ); +} + +function EditorPageContent({plainMap}: {plainMap: boolean}) { + const dispatch = useDispatch(); + const [contentMode, setContentMode] = + useState("pictogram"); + const [pictogram, setPictogram] = useState(pictogramIds[0] ?? "fa-marker"); + const [label, setLabel] = useState(""); + const [background, setBackground] = useState(DEFAULT_ICON_BACKGROUND); + const [foregroundOverride, setForegroundOverride] = useState( + null, + ); + const [stats, setStats] = useState(defaultIconCache.getStats()); + const [prewarmed, setPrewarmed] = useState(null); + + const foregroundIsAuto = foregroundOverride === null; + const resolvedForeground = + foregroundOverride ?? pickContrastForeground(background); + + const mapsightIconId = useMemo( + () => + buildMapsightIcon({ + pictogram: contentMode === "pictogram" ? pictogram : "", + label: contentMode === "label" ? label : "", + background, + foregroundOverride, + }), + [contentMode, pictogram, label, background, foregroundOverride], + ); + + const previewSpec = useMemo( + () => parseMapsightIcon(mapsightIconId), + [mapsightIconId], + ); + + const editorFeatureJson = useMemo( + () => formatEditorPreviewFeatureJson(mapsightIconId), + [mapsightIconId], + ); + + useEffect(() => { + dispatch( + updateFeatureProperty( + FEATURE_SOURCES, + "data", + EDITOR_PREVIEW_FEATURE_ID, + "mapsightIconId", + mapsightIconId, + undefined, + ), + ); + }, [dispatch, mapsightIconId]); + + useEffect(() => { + const timer = window.setInterval(() => { + setStats(defaultIconCache.getStats()); + }, 400); + return () => window.clearInterval(timer); + }, []); + + useEffect(() => { + const idle = window.requestIdleCallback?.( + () => { + void prewarmCatalog( + defaultIconCache, + buildCatalogTargets({variants: ["default", "plain"]}), + ).then((count) => setPrewarmed(count)); + }, + {timeout: 2000}, + ); + return () => { + if (idle) { + window.cancelIdleCallback(idle); + } + }; + }, []); + + return ( +
    + + +
    + + + +
    +
    + ); +} diff --git a/apps/showcase/src/icons/icon-color-palette.ts b/apps/showcase/src/icons/icon-color-palette.ts new file mode 100644 index 00000000..42de7599 --- /dev/null +++ b/apps/showcase/src/icons/icon-color-palette.ts @@ -0,0 +1,23 @@ +export const ICON_BACKGROUND_PALETTE = [ + "#ffffff", + "#e2e8f0", + "#fecdd3", + "#ddd6fe", + "#bfdbfe", + "#99f6e4", + "#bbf7d0", + "#fef08a", + "#be123c", + "#059669", + "#1d4ed8", + "#035799", +] as const; + +export const ICON_FOREGROUND_PALETTE = [ + "#000000", + "#333333", + "#666666", + "#999999", + "#cccccc", + "#ffffff", +] as const; diff --git a/apps/showcase/src/icons/icon-color-picker.tsx b/apps/showcase/src/icons/icon-color-picker.tsx new file mode 100644 index 00000000..12bb64b7 --- /dev/null +++ b/apps/showcase/src/icons/icon-color-picker.tsx @@ -0,0 +1,162 @@ +import {type ReactNode, useId, useState} from "react"; + +function normalizeHex(value: string): string | null { + const trimmed = value.trim().toLowerCase(); + + if (/^#[0-9a-f]{6}$/.test(trimmed)) { + return trimmed; + } + + const shortMatch = trimmed.match(/^#?([0-9a-f])([0-9a-f])([0-9a-f])$/); + if (shortMatch) { + const [, red, green, blue] = shortMatch; + return `#${red}${red}${green}${green}${blue}${blue}`; + } + + const bareMatch = trimmed.match(/^([0-9a-f]{6})$/); + if (bareMatch) { + return `#${bareMatch[1]}`; + } + + return null; +} + +function colorsMatch(left: string, right: string): boolean { + return normalizeHex(left) === normalizeHex(right); +} + +function HexColorInput({ + id, + labelText, + value, + onChange, +}: { + id: string; + labelText: string; + value: string; + onChange: (color: string) => void; +}) { + const [hexInput, setHexInput] = useState(value); + + const commitHexInput = (rawValue: string) => { + setHexInput(rawValue); + const normalized = normalizeHex(rawValue); + if (normalized) { + onChange(normalized); + } + }; + + return ( + commitHexInput(event.target.value)} + onBlur={(event) => { + const normalized = normalizeHex(event.target.value); + setHexInput(normalized ?? value); + }} + spellCheck={false} + aria-label={`${labelText} hex value`} + /> + ); +} + +export function IconColorPicker({ + id, + label, + value, + palette, + onChange, + onReset, + resetDisabled = false, + note, +}: { + id: string; + label: ReactNode; + value: string; + palette: readonly string[]; + onChange: (color: string) => void; + onReset?: () => void; + resetDisabled?: boolean; + note?: ReactNode; +}) { + const paletteId = useId(); + const labelText = typeof label === "string" ? label : id; + + return ( +
    +
    + + {onReset ? ( + + ) : null} +
    + +
    +
    + + +
    + +
    + {palette.map((color) => { + const selected = colorsMatch(color, value); + + return ( + + ); + })} +
    +
    + + {note ? {note} : null} +
    + ); +} diff --git a/apps/showcase/src/icons/icon-preview.tsx b/apps/showcase/src/icons/icon-preview.tsx new file mode 100644 index 00000000..1adca4ea --- /dev/null +++ b/apps/showcase/src/icons/icon-preview.tsx @@ -0,0 +1,51 @@ +import { + type IconSpec, + type IconVariant, + formatMapsightIcon, +} from "@mapsight/traffic-style/runtime-dev"; +import {useMapsightIcon} from "@mapsight/ui/hooks/useMapsightIcon"; + +const VARIANTS: IconVariant[] = ["default", "small", "xsmall", "plain"]; + +export function IconPreview({spec}: {spec: IconSpec}) { + return ( +
    + {VARIANTS.map((variant) => ( + + ))} +
    + ); +} + +function VariantPreview({ + mapsightIconId, + variant, + label, +}: { + mapsightIconId: string; + variant: IconVariant; + label: string; +}) { + const {src, bitmap, loading} = useMapsightIcon(mapsightIconId, variant); + + return ( +
    + {src ? ( + + ) : ( +
    {loading ? "…" : ""}
    + )} + {label} +
    + ); +} diff --git a/apps/showcase/src/icons/map-config.ts b/apps/showcase/src/icons/map-config.ts new file mode 100644 index 00000000..3da157ea --- /dev/null +++ b/apps/showcase/src/icons/map-config.ts @@ -0,0 +1,176 @@ +import * as config from "@mapsight/ui/config"; +import {FEATURE_SOURCES} from "@mapsight/ui/config/constants/controllers"; +import {plain} from "@mapsight/ui/config/feature/sources"; +import { + interactiveFeatures, + metaData, + osm, +} from "@mapsight/ui/config/map/layers"; +import createDefaultPlugins from "@mapsight/ui/plugins/browser-defaults"; +import type {CreateOptions, PluginDefinition} from "@mapsight/ui/types"; + +import {load} from "@mapsight/core/lib/feature-sources/actions"; + +import {demoMapFeatures, formatMapsightIcon} from "./demo-features.ts"; + +export {default as styleFunction} from "../generated/mapsight-vector-styles/icon-demo"; + +const MAP_CENTER_PROJECTED = [1171479, 6848253] as const; +const MAP_CENTER_GEOJSON: [number, number] = [10.523575, 52.2653825]; + +const center = config.mapViewCenter( + MAP_CENTER_PROJECTED[0], + MAP_CENTER_PROJECTED[1], +); +const extent = config.mapViewExtent(1097392, 6789091, 1240635, 6895797); + +export const EDITOR_PREVIEW_FEATURE_ID = "editor-preview"; +export const EDITOR_PREVIEW_COORDINATES = MAP_CENTER_GEOJSON; + +export function buildEditorPreviewFeature(mapsightIconId: string) { + return { + type: "Feature" as const, + id: EDITOR_PREVIEW_FEATURE_ID, + properties: { + title: "Editor preview", + mapsightIconId, + }, + geometry: { + type: "Point" as const, + coordinates: EDITOR_PREVIEW_COORDINATES, + }, + }; +} + +export function formatEditorPreviewFeatureJson(mapsightIconId: string): string { + const [lon, lat] = EDITOR_PREVIEW_COORDINATES; + + return `{ + "type": "Feature", + "properties": { + "mapsightIconId": ${JSON.stringify(mapsightIconId)} + }, + "geometry": { + "type": "Point", + "coordinates": [${lon}, ${lat}] + } +}`; +} + +function buildDemoFeatures() { + return demoMapFeatures.map((item) => ({ + type: "Feature" as const, + id: item.id, + properties: { + title: item.title, + mapsightIconId: item.mapsightIconId, + }, + geometry: { + type: "Point" as const, + coordinates: item.coordinates, + }, + })); +} + +export function createBaseMapsightConfig(options: {plainMap?: boolean} = {}) { + const features = [...buildDemoFeatures(), buildEditorPreviewFeature("")]; + const dataLayer = interactiveFeatures( + "data", + true, + metaData("Runtime icons", null, true, true, false, "Demo"), + "features", + ); + const mapView = config.mapView(center, extent, 14, 10, 18); + const featureSources = config.features({ + data: { + ...plain(), + data: { + type: "FeatureCollection", + features, + }, + lastUpdate: Date.now(), + lastActionType: null, + }, + }); + + if (options.plainMap) { + return { + ...config.map({data: dataLayer}, mapView), + ...featureSources, + }; + } + + return { + ...config.map( + { + osm: osm( + "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + true, + metaData( + "OSM", + '© OpenStreetMap', + true, + false, + true, + "Karte", + ), + ), + data: dataLayer, + }, + mapView, + ), + ...featureSources, + }; +} + +const loadDemoFeaturesPlugin: PluginDefinition = [ + "loadDemoFeatures", + { + afterInit(context) { + context.store?.dispatch(load(FEATURE_SOURCES, "data")); + }, + }, +]; + +export const createOptions: CreateOptions = { + plugins: [...createDefaultPlugins(), loadDemoFeaturesPlugin], + uiState: { + map: { + show: true, + }, + }, +}; + +export const DEFAULT_ICON_BACKGROUND = "#ffffff"; + +export function buildMapsightIcon(input: { + pictogram: string; + label: string; + background: string; + foregroundOverride: string | null; +}): string { + const hasPictogram = Boolean(input.pictogram); + const hasLabel = Boolean(input.label.trim()); + const usesDefaultBackground = input.background === DEFAULT_ICON_BACKGROUND; + const hasExplicitForeground = input.foregroundOverride !== null; + + if (usesDefaultBackground && !hasExplicitForeground) { + return formatMapsightIcon({ + pictogram: hasPictogram ? input.pictogram : undefined, + label: hasLabel ? input.label : undefined, + }); + } + + const colors: {background: string; foreground?: string} = { + background: input.background, + }; + if (input.foregroundOverride !== null) { + colors.foreground = input.foregroundOverride; + } + + return formatMapsightIcon({ + pictogram: hasPictogram ? input.pictogram : undefined, + label: hasLabel ? input.label : undefined, + colors, + }); +} diff --git a/apps/showcase/src/icons/styles.css b/apps/showcase/src/icons/styles.css new file mode 100644 index 00000000..2648a34e --- /dev/null +++ b/apps/showcase/src/icons/styles.css @@ -0,0 +1,537 @@ +:root { + color-scheme: light; + font-family: + Inter, + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + sans-serif; + line-height: 1.5; +} + +* { + box-sizing: border-box; +} + +.icon-route { + height: 100%; + overflow: hidden; +} + +.icon-route--editor { + min-height: 0; +} + +.icon-route--editor.app { + height: 100%; +} + +.icon-route--catalog { + overflow: auto; +} + +button, +input, +select { + font: inherit; +} + +.app { + display: grid; + grid-template-columns: 400px 1fr; + height: 100%; + overflow: hidden; +} + +.panel { + height: 100%; + padding: 1rem 1.25rem 2rem; + background: #fff; + border-right: 1px solid #d8dee6; + overflow-y: auto; + overscroll-behavior: contain; +} + +.panel h1 { + margin: 0 0 0.25rem; + font-size: 1.35rem; +} + +.panel h2 { + margin: 1.5rem 0 0; + font-size: 1rem; +} + +.panel p { + margin: 0 0 1rem; + color: #5b6773; +} + +.field { + display: grid; + gap: 0.35rem; + margin-bottom: 0.85rem; +} + +.field label, +.field__label { + font-size: 0.85rem; + font-weight: 600; +} + +.field__hint { + font-weight: 500; + color: #64748b; +} + +.field__note { + font-size: 0.75rem; + color: #64748b; +} + +.mode-toggle { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + padding: 0.2rem; + border: 1px solid #c7d0db; + border-radius: 8px; + background: #f8fafc; +} + +.mode-toggle__btn { + padding: 0.45rem 0.55rem; + border: 0; + border-radius: 6px; + background: transparent; + font-size: 0.85rem; + font-weight: 600; + color: #5b6773; + cursor: pointer; + transition: + background-color 0.15s, + color 0.15s, + box-shadow 0.15s; +} + +.mode-toggle__btn:hover:not(.is-active) { + color: #1f2937; +} + +.mode-toggle__btn.is-active { + background: #fff; + color: #111827; + box-shadow: 0 1px 2px rgb(15 23 42 / 0.08); +} + +.field input, +.field select { + padding: 0.45rem 0.55rem; + border: 1px solid #c7d0db; + border-radius: 8px; + background: #fff; +} + +.color-row { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 0.85rem; +} + +.color-picker-field { + margin-bottom: 0; + min-width: 0; +} + +.color-picker__control { + display: grid; + gap: 0.45rem; + min-width: 0; +} + +.color-picker__value-row { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + align-items: center; + gap: 0.45rem; + min-width: 0; +} + +.color-picker__preview-wrap { + position: relative; + display: block; + width: 2rem; + height: 2rem; + flex-shrink: 0; + cursor: pointer; +} + +.color-picker__preview { + display: block; + width: 100%; + height: 100%; + border: 1px solid #c7d0db; + border-radius: 7px; + pointer-events: none; +} + +.color-picker__native { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + padding: 0; + border: 0; + opacity: 0; + cursor: pointer; +} + +.color-picker__hex { + min-width: 0; + width: 100%; + padding: 0.35rem 0.5rem; + border: 1px solid #c7d0db; + border-radius: 8px; + background: #fff; + font-family: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + font-size: 0.78rem; + color: #1e293b; +} + +.color-picker__palette { + display: flex; + align-items: center; + gap: 0.3rem; + min-width: 0; + padding: 0.3rem 0.4rem; + border: 1px solid #c7d0db; + border-radius: 8px; + background: #fff; +} + +.color-picker__swatch { + position: relative; + flex: 1 1 0; + min-width: 0; + height: 1.35rem; + padding: 0; + border: 1px solid rgb(15 23 42 / 0.1); + border-radius: 5px; + cursor: pointer; +} + +.color-picker__swatch:hover { + border-color: rgb(15 23 42 / 0.22); +} + +.color-picker__swatch.is-selected { + border-color: #2563eb; + box-shadow: 0 0 0 1px #2563eb; +} + +.color-picker__swatch-label { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.field__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; +} + +.reset-btn { + padding: 0; + border: 0; + background: none; + font-size: 0.75rem; + font-weight: 600; + color: #2563eb; + cursor: pointer; +} + +.reset-btn:hover:not(:disabled) { + text-decoration: underline; +} + +.reset-btn:disabled { + color: #94a3b8; + cursor: default; +} + +.output-card { + margin-top: 1rem; + padding: 0.7rem 0.75rem; + border: 1px solid #bfdbfe; + border-radius: 10px; + background: #f8fbff; + font-size: 0.8rem; +} + +.output-card__header, +.output-card__subheader { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 0.5rem; +} + +.output-card__subheader { + margin-top: 0.7rem; +} + +.output-card strong { + font-size: 0.8rem; +} + +.output-card__hint { + font-size: 0.68rem; + font-weight: 500; + color: #64748b; +} + +.id-output { + margin-top: 0.4rem; + padding: 0.5rem 0.6rem; + border: 1px solid #93c5fd; + border-radius: 8px; + background: #fff; + font-family: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + font-size: 0.82rem; + font-weight: 700; + line-height: 1.3; + color: #0f172a; + word-break: break-all; +} + +.id-output__empty { + font-size: 0.75rem; + font-weight: 500; + color: #64748b; +} + +.geojson-output { + margin: 0.4rem 0 0; + padding: 0.5rem 0.6rem; + overflow: auto; + border: 1px solid #d8dee6; + border-radius: 8px; + background: #fff; + font-family: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + font-size: 0.68rem; + line-height: 1.35; + color: #1e293b; + white-space: pre; +} + +.preview-card { + margin-top: 1rem; + padding: 1rem; + border: 1px solid #d8dee6; + border-radius: 12px; + background: #fff; +} + +.preview-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 0.75rem; + margin-top: 0.75rem; +} + +.preview-item { + display: grid; + justify-items: center; + gap: 0.35rem; + padding: 0.5rem; + border-radius: 8px; + background: #fff; + border: 1px solid #e5ebf1; +} + +.preview-item span { + font-size: 0.7rem; + color: #5b6773; +} + +.stats { + margin-top: 1rem; + padding: 0.75rem 0.9rem; + border-radius: 8px; + border: 1px solid #dbeafe; + background: #fff; + font-size: 0.85rem; +} + +.catalog-page { + height: 100%; + overflow-y: auto; + padding: 1.25rem 1.25rem 2rem; +} + +.catalog-page__header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1.25rem; +} + +.catalog-page__header h1 { + margin: 0 0 0.35rem; + font-size: 1.5rem; +} + +.catalog-page__header p { + margin: 0; + color: #5b6773; +} + +.catalog-section { + margin-top: 2rem; +} + +.catalog-section h2 { + margin: 0 0 0.35rem; + font-size: 1.1rem; +} + +.catalog-section__count { + font-weight: 500; + color: #64748b; +} + +.catalog-section p { + margin: 0; + color: #5b6773; + font-size: 0.9rem; +} + +.catalog-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); + gap: 0.6rem; + margin-top: 0.75rem; +} + +.catalog-grid--page { + grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); + gap: 0.75rem; +} + +.catalog-grid--page .catalog-grid-item { + padding: 0.9rem 0.45rem 0.7rem; +} + +.catalog-grid--page .catalog-grid-item img, +.catalog-grid--page .catalog-grid-item__placeholder { + width: 48px; + height: 48px; +} + +.catalog-grid-item { + display: grid; + justify-items: center; + gap: 0.35rem; + padding: 0.7rem 0.35rem 0.55rem; + border-radius: 10px; + background: #fff; + border: 1px solid #e5ebf1; + cursor: pointer; + transition: + border-color 0.15s, + box-shadow 0.15s; +} + +.catalog-grid-item:hover, +.catalog-grid-item.is-active { + border-color: #3b82f6; + box-shadow: 0 0 0 1px #3b82f6; + background: #fff; +} + +.catalog-grid-item span { + font-size: 0.68rem; + text-align: center; + color: #5b6773; + word-break: break-word; + line-height: 1.2; +} + +.catalog-grid-item__placeholder { + display: grid; + place-items: center; + width: 40px; + height: 40px; + color: #94a3b8; +} + +.map-pane { + position: relative; + height: 100%; + overflow: hidden; +} + +.icon-route--editor .map-pane { + display: flex; + flex-direction: column; + min-height: 0; +} + +.icon-route--editor .ms3-map-wrapper { + flex: 1; + height: 100%; + max-height: none; + min-height: 0; +} + +.icon-route--plain-map .ms3-map-wrapper, +.icon-route--plain-map .ol-viewport { + background: #d4d4d4; +} + +.map-loading { + display: grid; + place-items: center; + height: 100%; + color: #5b6773; +} + +@media (max-width: 960px) { + html, + body, + #root { + overflow: auto; + } + + .app { + grid-template-columns: 1fr; + height: auto; + overflow: visible; + } + + .panel { + height: auto; + max-height: none; + overflow: visible; + } + + .map-pane { + height: 60vh; + min-height: 360px; + } +} diff --git a/apps/showcase/src/index.html b/apps/showcase/src/index.html new file mode 100644 index 00000000..66f9dbaf --- /dev/null +++ b/apps/showcase/src/index.html @@ -0,0 +1,15 @@ + + + + + + Mapsight Showcase + + + + + +
    + + + diff --git a/apps/showcase/src/layout/demo-nav.tsx b/apps/showcase/src/layout/demo-nav.tsx new file mode 100644 index 00000000..255dd928 --- /dev/null +++ b/apps/showcase/src/layout/demo-nav.tsx @@ -0,0 +1,13 @@ +import {ShowcaseSubnav} from "./showcase-subnav.tsx"; + +export const demoItems = [ + {to: "/ui/combined-list", label: "Combined list"}, + {to: "/ui/simple-map", label: "Simple map"}, + {to: "/ui/full", label: "Full"}, + {to: "/ui/custom", label: "Custom"}, + {to: "/ui/router", label: "Router", end: false}, +] as const; + +export function DemoNav() { + return ; +} diff --git a/apps/showcase/src/layout/icons-nav.tsx b/apps/showcase/src/layout/icons-nav.tsx new file mode 100644 index 00000000..694ecfa6 --- /dev/null +++ b/apps/showcase/src/layout/icons-nav.tsx @@ -0,0 +1,10 @@ +import {ShowcaseSubnav} from "./showcase-subnav.tsx"; + +export const iconItems = [ + {to: "/icons", label: "Editor"}, + {to: "/icons/catalog", label: "Catalog"}, +] as const; + +export function IconsNav() { + return ; +} diff --git a/apps/showcase/src/layout/showcase-layout.tsx b/apps/showcase/src/layout/showcase-layout.tsx new file mode 100644 index 00000000..da75c144 --- /dev/null +++ b/apps/showcase/src/layout/showcase-layout.tsx @@ -0,0 +1,62 @@ +import {NavLink, Outlet, useLocation} from "react-router-dom"; + +import {DemoNav} from "./demo-nav.tsx"; +import {IconsNav} from "./icons-nav.tsx"; + +const navItems = [ + {to: "/", label: "Home", end: true}, + {to: "/ui/combined-list", label: "Demos", end: false}, + {to: "/icons", label: "Icons", end: false}, +] as const; + +export function ShowcaseLayout() { + const location = useLocation(); + const showDemoNav = location.pathname.startsWith("/ui"); + const showIconsNav = location.pathname.startsWith("/icons"); + const isIconEditor = location.pathname === "/icons"; + + const mainClassName = [ + "showcase__main", + showDemoNav ? "showcase__main--embed" : "", + isIconEditor ? "showcase__main--icon-editor" : "", + ] + .filter(Boolean) + .join(" "); + + return ( +
    +
    +
    +
    + Mapsight + Showcase +
    + +
    +
    + {showDemoNav ? : null} + {showIconsNav ? : null} +
    + +
    +
    + ); +} diff --git a/apps/showcase/src/layout/showcase-subnav.tsx b/apps/showcase/src/layout/showcase-subnav.tsx new file mode 100644 index 00000000..a2c1d0bf --- /dev/null +++ b/apps/showcase/src/layout/showcase-subnav.tsx @@ -0,0 +1,39 @@ +import {NavLink} from "react-router-dom"; + +export type SubnavItem = { + to: string; + label: string; + end?: boolean; +}; + +export function ShowcaseSubnav({ + label, + items, +}: { + label: string; + items: readonly SubnavItem[]; +}) { + return ( + + ); +} diff --git a/apps/showcase/src/main.tsx b/apps/showcase/src/main.tsx new file mode 100644 index 00000000..c9f5d4e6 --- /dev/null +++ b/apps/showcase/src/main.tsx @@ -0,0 +1,12 @@ +import "@mapsight/traffic-style/pictograms-fontawesome"; + +import {StrictMode} from "react"; +import {createRoot} from "react-dom/client"; + +import {App} from "./app.tsx"; + +createRoot(document.querySelector("#root")!).render( + + + , +); diff --git a/apps/demo-vite/src/msui.scss b/apps/showcase/src/msui.scss similarity index 98% rename from apps/demo-vite/src/msui.scss rename to apps/showcase/src/msui.scss index fd9227a8..e396ef5e 100644 --- a/apps/demo-vite/src/msui.scss +++ b/apps/showcase/src/msui.scss @@ -17,11 +17,6 @@ html { font-size: 0.825em; } -body { - max-width: 800px; - margin: 0 auto; -} - .ms3-list__info, .ms3-feature-details-content { line-height: 1.5; diff --git a/apps/showcase/src/pages/landing-page.tsx b/apps/showcase/src/pages/landing-page.tsx new file mode 100644 index 00000000..0af3fab3 --- /dev/null +++ b/apps/showcase/src/pages/landing-page.tsx @@ -0,0 +1,47 @@ +import {Link} from "react-router-dom"; + +const sections = [ + { + to: "/ui/combined-list", + title: "Demos", + description: + "Mapsight UI examples — combined list, simple map, full layout, custom overlays, and router integration.", + }, + { + to: "/icons", + title: "Icons", + description: + "Runtime icon editor and catalog — compose pictograms on a map or browse prebuilt sprites and Font Awesome glyphs.", + }, +] as const; + +export function LandingPage() { + return ( +
    +
    +
    +

    Mapsight ecosystem showcase

    +

    + Interactive demos for the modular Mapsight packages — UI + components, traffic-style icons, and runtime + composition. +

    +
    + +
    + {sections.map((section) => ( + +

    {section.title}

    +

    {section.description}

    + Open → + + ))} +
    +
    +
    + ); +} diff --git a/apps/showcase/src/pages/ui-demos/combined-list-page.tsx b/apps/showcase/src/pages/ui-demos/combined-list-page.tsx new file mode 100644 index 00000000..74defcea --- /dev/null +++ b/apps/showcase/src/pages/ui-demos/combined-list-page.tsx @@ -0,0 +1,20 @@ +import App from "@mapsight/ui/components/app"; + +import { + baseMapsightConfig, + createOptions, + styleFunction, +} from "../../combined-list/shared.tsx"; +import {UiDemoShell} from "./ui-demo-shell.tsx"; + +export function CombinedListPage() { + return ( + + + + ); +} diff --git a/apps/demo-vite/src/custom.tsx b/apps/showcase/src/pages/ui-demos/custom-page.tsx similarity index 81% rename from apps/demo-vite/src/custom.tsx rename to apps/showcase/src/pages/ui-demos/custom-page.tsx index ba1eeb3b..81cfacb9 100644 --- a/apps/demo-vite/src/custom.tsx +++ b/apps/showcase/src/pages/ui-demos/custom-page.tsx @@ -1,9 +1,7 @@ import type {ReactNode} from "react"; import {useReducer} from "react"; -import {createRoot} from "react-dom/client"; import App from "@mapsight/ui/components/app"; -import Instance from "@mapsight/ui/components/instance"; import MeasureDistanceButton from "@mapsight/ui/components/map-overlay/measure-distance-button"; import SharePositionLinkButton from "@mapsight/ui/components/map-overlay/share-position-link-button"; import * as config from "@mapsight/ui/config"; @@ -20,12 +18,12 @@ import createShareLinkPlugin from "@mapsight/ui/plugins/browser/share-position-l import createMeasureDistancePlugin from "@mapsight/ui/plugins/common/measure-distance"; import type {CreateOptions} from "@mapsight/ui/types"; -import createNativeFullscreenPlugin from "./features/native-fullscreen/plugin"; -import styleFunction from "./generated/mapsight-vector-styles/demo.js"; +import createNativeFullscreenPlugin from "../../features/native-fullscreen/plugin.ts"; +import styleFunction from "../../generated/mapsight-vector-styles/demo.js"; +import {demoGeoJsonUrl} from "../../ui-demos/demo-geojson.ts"; +import {UiDemoShell} from "./ui-demo-shell.tsx"; -// test - -const bmc = { +const baseMapsightConfig = { ...config.map( { osm: osm( @@ -71,15 +69,15 @@ const bmc = { ), }, config.mapView( - config.mapViewCenter(1171479, 6848253), // x, y ^= 52.2653825, 10.523575 (lat, lon) - config.mapViewExtent(1097392, 6789091, 1240635, 6895797), // minx, miny, maxx, maxy http://bboxfinder.com/#51.938934,9.858041,52.526000,11.144814 - 14, // z - 10, // minZoom - 18, // maxZoom + config.mapViewCenter(1171479, 6848253), + config.mapViewExtent(1097392, 6789091, 1240635, 6895797), + 14, + 10, + 18, ), ), ...config.features({ - data: xhrJson(new URL("data.geojson", import.meta.url).toString()), + data: xhrJson(demoGeoJsonUrl), userGeolocation: plain(), searchResult: plain(), }), @@ -166,13 +164,15 @@ const createOptions: CreateOptions = { }, }; -const root = createRoot(document.querySelector("#root")!); -root.render( - - - , -); +export function CustomPage() { + return ( + + + + ); +} diff --git a/apps/showcase/src/pages/ui-demos/full-page.tsx b/apps/showcase/src/pages/ui-demos/full-page.tsx new file mode 100644 index 00000000..a3bcdd70 --- /dev/null +++ b/apps/showcase/src/pages/ui-demos/full-page.tsx @@ -0,0 +1,20 @@ +import App from "@mapsight/ui/components/app"; + +import { + baseMapsightConfig, + createOptions, + styleFunction, +} from "../../ui-demos/full-config.tsx"; +import {UiDemoShell} from "./ui-demo-shell.tsx"; + +export function FullPage() { + return ( + + + + ); +} diff --git a/apps/showcase/src/pages/ui-demos/router-page.tsx b/apps/showcase/src/pages/ui-demos/router-page.tsx new file mode 100644 index 00000000..991f1827 --- /dev/null +++ b/apps/showcase/src/pages/ui-demos/router-page.tsx @@ -0,0 +1,66 @@ +import {Link, Route, Routes} from "react-router-dom"; + +import App from "@mapsight/ui/components/app"; + +import { + baseMapsightConfig, + createOptions, + styleFunction, +} from "../../ui-demos/router-config.tsx"; +import {UiDemoShell} from "./ui-demo-shell.tsx"; + +function RoutedApp() { + return ; +} + +export function RouterPage() { + return ( + + + +
    + + Home} /> + Beispiel 1} /> + Beispiel 2} /> + +
    + + + } /> + +
    + ); +} diff --git a/apps/showcase/src/pages/ui-demos/simple-map-page.tsx b/apps/showcase/src/pages/ui-demos/simple-map-page.tsx new file mode 100644 index 00000000..48fed058 --- /dev/null +++ b/apps/showcase/src/pages/ui-demos/simple-map-page.tsx @@ -0,0 +1,24 @@ +import Map from "@mapsight/ui/components/map"; +import MapWrapper from "@mapsight/ui/components/map-wrapper"; + +import { + baseMapsightConfig, + createOptions, + noopStyleFunction, +} from "../../ui-demos/simple-map-config.ts"; +import {UiDemoShell} from "./ui-demo-shell.tsx"; + +export function SimpleMapPage() { + return ( + + + + + + ); +} diff --git a/apps/showcase/src/pages/ui-demos/ui-demo-shell.tsx b/apps/showcase/src/pages/ui-demos/ui-demo-shell.tsx new file mode 100644 index 00000000..ff7ca324 --- /dev/null +++ b/apps/showcase/src/pages/ui-demos/ui-demo-shell.tsx @@ -0,0 +1,49 @@ +import type {ReactNode} from "react"; + +import Instance from "@mapsight/ui/components/instance"; +import createDefaultPlugins from "@mapsight/ui/plugins/browser-defaults"; +import type {CreateOptions} from "@mapsight/ui/types"; + +import type {State} from "@mapsight/core/types"; + +type StyleFunction = Parameters[0]["styleFunction"]; + +export function UiDemoShell({ + baseMapsightConfig, + createOptions, + styleFunction, + mergeDefaultPlugins = true, + children, +}: { + baseMapsightConfig: Partial; + createOptions: CreateOptions; + styleFunction: StyleFunction; + mergeDefaultPlugins?: boolean; + children: ReactNode; +}) { + const resolvedOptions = mergeDefaultPlugins + ? { + ...createOptions, + plugins: [ + ...createDefaultPlugins(), + ...(createOptions.plugins ?? []), + ], + } + : createOptions; + + return ( +
    +
    +
    + + {children} + +
    +
    +
    + ); +} diff --git a/apps/showcase/src/ui-demos/demo-geojson.ts b/apps/showcase/src/ui-demos/demo-geojson.ts new file mode 100644 index 00000000..0792d993 --- /dev/null +++ b/apps/showcase/src/ui-demos/demo-geojson.ts @@ -0,0 +1,4 @@ +export const demoGeoJsonUrl = new URL( + "../data/demo.geojson", + import.meta.url, +).toString(); diff --git a/apps/demo-vite/src/full/shared.tsx b/apps/showcase/src/ui-demos/full-config.tsx similarity index 89% rename from apps/demo-vite/src/full/shared.tsx rename to apps/showcase/src/ui-demos/full-config.tsx index 45d06709..645614db 100644 --- a/apps/demo-vite/src/full/shared.tsx +++ b/apps/showcase/src/ui-demos/full-config.tsx @@ -25,7 +25,8 @@ import type {LayerDefinition} from "@mapsight/core/lib/map/lib/WithLayers"; import {DEFAULT_OPTIONS as FIT_FEATURE_DEFAULT_OPTIONS} from "@mapsight/lib-ol/map/fitToFeature"; -import createNativeFullscreenPlugin from "../features/native-fullscreen/plugin"; +import createNativeFullscreenPlugin from "../features/native-fullscreen/plugin.ts"; +import {demoGeoJsonUrl} from "./demo-geojson.ts"; export {default as styleFunction} from "../generated/mapsight-vector-styles/demo"; @@ -107,18 +108,15 @@ export const baseMapsightConfig = { ), }, config.mapView( - config.mapViewCenter(1171479, 6848253), // x, y ^= 52.2653825, 10.523575 (lat, lon) - config.mapViewExtent(1097392, 6789091, 1240635, 6895797), // minx, miny, maxx, maxy http://bboxfinder.com/#51.938934,9.858041,52.526000,11.144814 - 14, // z - 10, // minZoom - 18, // maxZoom + config.mapViewCenter(1171479, 6848253), + config.mapViewExtent(1097392, 6789091, 1240635, 6895797), + 14, + 10, + 18, ), ), ...config.features({ - data: withFilter( - xhrJson(new URL("../data.geojson", import.meta.url).toString()), - TAG_FILTER, - ), + data: withFilter(xhrJson(demoGeoJsonUrl), TAG_FILTER), userGeolocation: plain(), searchResult: plain(), }), @@ -131,7 +129,7 @@ export const createOptions: CreateOptions = { ["measureDistance", createMeasureDistancePlugin()], ["nativeFullscreen", createNativeFullscreenPlugin()], ], - imagesUrl: "/public/img/", + imagesUrl: "/img/", components: { MapOverlayTopLeft: () => ( diff --git a/apps/demo-vite/src/router/router.tsx b/apps/showcase/src/ui-demos/router-config.tsx similarity index 59% rename from apps/demo-vite/src/router/router.tsx rename to apps/showcase/src/ui-demos/router-config.tsx index 3f5a48cb..3ea71622 100644 --- a/apps/demo-vite/src/router/router.tsx +++ b/apps/showcase/src/ui-demos/router-config.tsx @@ -1,8 +1,5 @@ import {Fragment} from "react"; -import {createRoot} from "react-dom/client"; -import {BrowserRouter, Link, Route, Routes} from "react-router-dom"; -import Instance from "@mapsight/ui/components/instance"; import RegionSelector from "@mapsight/ui/components/map-overlay/region-selector"; import SearchOverlay from "@mapsight/ui/components/map-overlay/search-overlay"; import SharePositionLinkButton from "@mapsight/ui/components/map-overlay/share-position-link-button"; @@ -18,10 +15,11 @@ import createDefaultPlugins from "@mapsight/ui/plugins/browser-defaults"; import createShareLinkPlugin from "@mapsight/ui/plugins/browser/share-position-link"; import type {CreateOptions} from "@mapsight/ui/types"; -import styleFunction from "../generated/mapsight-vector-styles/demo"; -import RoutedApp from "./components/RoutedApp"; +import {demoGeoJsonUrl} from "./demo-geojson.ts"; -const bmc = { +export {default as styleFunction} from "../generated/mapsight-vector-styles/demo"; + +export const baseMapsightConfig = { ...config.map( { osm: osm( @@ -67,27 +65,27 @@ const bmc = { ), }, config.mapView( - config.mapViewCenter(1171479, 6848253), // x, y ^= 52.2653825, 10.523575 (lat, lon) - config.mapViewExtent(1097392, 6789091, 1240635, 6895797), // minx, miny, maxx, maxy http://bboxfinder.com/#51.938934,9.858041,52.526000,11.144814 - 14, // z - 10, // minZoom - 18, // maxZoom + config.mapViewCenter(1171479, 6848253), + config.mapViewExtent(1097392, 6789091, 1240635, 6895797), + 14, + 10, + 18, ), ), ...config.features({ - data: xhrJson(new URL("../data.geojson", import.meta.url).toString()), + data: xhrJson(demoGeoJsonUrl), userGeolocation: plain(), searchResult: plain(), }), ...config.featureList("data", true), }; -const createOptions: CreateOptions = { +export const createOptions: CreateOptions = { plugins: [ ...createDefaultPlugins(), ["shareLink", createShareLinkPlugin()], ], - imagesUrl: "/public/img/", + imagesUrl: "/img/", components: { MapOverlayTopLeft: function CustomMapOverlayTopLeft() { return ( @@ -126,39 +124,3 @@ const createOptions: CreateOptions = { }, }, }; - -const root = createRoot(document.querySelector("#root")!); -root.render( - - - - - - Home} /> - Beispiel 1} /> - Beispiel 2} /> - - - - } /> - - - , -); diff --git a/apps/showcase/src/ui-demos/simple-map-config.ts b/apps/showcase/src/ui-demos/simple-map-config.ts new file mode 100644 index 00000000..b57d1820 --- /dev/null +++ b/apps/showcase/src/ui-demos/simple-map-config.ts @@ -0,0 +1,41 @@ +import {map, mapView, mapViewCenter, mapViewExtent} from "@mapsight/ui/config"; +import {metaData, osm} from "@mapsight/ui/config/map/layers"; +import createDefaultPlugins from "@mapsight/ui/plugins/browser-defaults"; +import type {CreateOptions} from "@mapsight/ui/types"; + +export const baseMapsightConfig = { + ...map( + { + osm: osm( + "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + true, + metaData( + "OSM", + '© OpenStreetMap-Mitwirkende-Mitwirkende', + true, + false, + true, + "Karte", + ), + ), + }, + mapView( + mapViewCenter(1171479, 6848253), + mapViewExtent(1097392, 6789091, 1240635, 6895797), + 14, + 10, + 18, + ), + ), +}; + +export const createOptions: CreateOptions = { + plugins: createDefaultPlugins(), + uiState: { + map: { + show: true, + }, + }, +}; + +export const noopStyleFunction = () => []; diff --git a/apps/demo-vite/src/vector-styles/demo.scss b/apps/showcase/src/vector-styles/demo.scss similarity index 100% rename from apps/demo-vite/src/vector-styles/demo.scss rename to apps/showcase/src/vector-styles/demo.scss diff --git a/apps/showcase/src/vector-styles/icon-demo.scss b/apps/showcase/src/vector-styles/icon-demo.scss new file mode 100644 index 00000000..aca73133 --- /dev/null +++ b/apps/showcase/src/vector-styles/icon-demo.scss @@ -0,0 +1,9 @@ +@use "@mapsight/traffic-style/mapsight-traffic-style-icon-sprite-2x" as sprite; + +@use "@mapsight/traffic-style/src/scss/variables" as variables with ( + $MAPSIGHT_TRAFFIC_STYLE__IMAGE_PATH: "/img/", + $MAPSIGHT_TRAFFIC_STYLE__SPRITE_PATH: "/img/mapsight-traffic-style-icon-sprite-2x.png?v=2023-08-07-16-00", + $MAPSIGHT_TRAFFIC_STYLE__ICONS: sprite.$mapsight-traffic-style-icon-sprite-2x, +); + +@use "@mapsight/traffic-style/src/scss/features/base"; diff --git a/apps/demo-vite/tsconfig.json b/apps/showcase/tsconfig.json similarity index 100% rename from apps/demo-vite/tsconfig.json rename to apps/showcase/tsconfig.json diff --git a/apps/demo-vite/tsconfig.node.json b/apps/showcase/tsconfig.node.json similarity index 100% rename from apps/demo-vite/tsconfig.node.json rename to apps/showcase/tsconfig.node.json diff --git a/apps/demo-vite/vite.config.ts b/apps/showcase/vite.config.ts similarity index 81% rename from apps/demo-vite/vite.config.ts rename to apps/showcase/vite.config.ts index c8e41822..9dcd05e6 100644 --- a/apps/demo-vite/vite.config.ts +++ b/apps/showcase/vite.config.ts @@ -21,8 +21,12 @@ export default defineConfig(({command}) => ({ ], }, optimizeDeps: { - exclude: [...workspacePackages], - // build.rolldownOptions.input paths are relative to `root`; dep scan resolves from cwd. + exclude: [ + ...workspacePackages, + "@mapsight/traffic-style/runtime", + "@mapsight/traffic-style/runtime-dev", + "@mapsight/traffic-style/icon-style", + ], entries: ["**/*.html"], }, build: { @@ -30,14 +34,7 @@ export default defineConfig(({command}) => ({ emptyOutDir: true, license: true, rolldownOptions: { - input: [ - "index.html", - "custom.html", - "simple-map.html", - "router/index.html", - "full/index.html", - "combined-list/index.html", - ], + input: ["index.html"], output: { codeSplitting: { groups: [ diff --git a/configs/vite-workspace-dev.mts b/configs/vite-workspace-dev.mts index edfb879d..876ccd5c 100644 --- a/configs/vite-workspace-dev.mts +++ b/configs/vite-workspace-dev.mts @@ -12,7 +12,6 @@ export const repoRoot = path.resolve(configDir, ".."); /** Workspace packages resolved from source during Vite dev (serve). */ export const workspacePackages = [ "@mapsight/core", - "@mapsight/demo-shared", "@mapsight/ui", "@mapsight/lib-js", "@mapsight/lib-ol", @@ -21,7 +20,6 @@ export const workspacePackages = [ const packageSourceRoots = { "@mapsight/core": path.join(repoRoot, "packages/core/src/js"), - "@mapsight/demo-shared": path.join(repoRoot, "packages/demo-shared/src"), "@mapsight/ui": path.join(repoRoot, "packages/ui/src/js"), "@mapsight/lib-js": path.join(repoRoot, "packages/lib-js/src/js"), "@mapsight/lib-ol": path.join(repoRoot, "packages/lib-ol/src/js"), diff --git a/packages/demo-shared/data/cafes.geojson b/packages/demo-shared/data/cafes.geojson deleted file mode 100644 index 0be69d0b..00000000 --- a/packages/demo-shared/data/cafes.geojson +++ /dev/null @@ -1,47 +0,0 @@ -{ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "id": "demo-cafe-corner", - "geometry": { - "type": "Point", - "coordinates": [10.5214, 52.2661] - }, - "properties": { - "id": "demo-cafe-corner", - "name": "Corner Cafe", - "listInformation": "Coffee and pastries", - "description": "

    Cozy neighborhood cafe with outdoor seating.

    " - } - }, - { - "type": "Feature", - "id": "demo-cafe-market", - "geometry": { - "type": "Point", - "coordinates": [10.5278, 52.2635] - }, - "properties": { - "id": "demo-cafe-market", - "name": "Market Square Bistro", - "listInformation": "Lunch menu and espresso bar", - "description": "

    Busy spot next to the weekly market.

    " - } - }, - { - "type": "Feature", - "id": "demo-cafe-garden", - "geometry": { - "type": "Point", - "coordinates": [10.5159, 52.2697] - }, - "properties": { - "id": "demo-cafe-garden", - "name": "Garden Terrace", - "listInformation": "Brunch and herbal tea", - "description": "

    Relaxed cafe behind a courtyard garden.

    " - } - } - ] -} diff --git a/packages/demo-shared/data/parks.geojson b/packages/demo-shared/data/parks.geojson deleted file mode 100644 index 93a99dd0..00000000 --- a/packages/demo-shared/data/parks.geojson +++ /dev/null @@ -1,47 +0,0 @@ -{ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "id": "demo-park-riverside", - "geometry": { - "type": "Point", - "coordinates": [10.5182, 52.2684] - }, - "properties": { - "id": "demo-park-riverside", - "name": "Riverside Park", - "listInformation": "Green space along the river", - "description": "

    Quiet park with walking paths and picnic areas.

    " - } - }, - { - "type": "Feature", - "id": "demo-park-central", - "geometry": { - "type": "Point", - "coordinates": [10.5251, 52.2648] - }, - "properties": { - "id": "demo-park-central", - "name": "Central Gardens", - "listInformation": "Formal gardens in the city center", - "description": "

    Shaded benches and seasonal flower beds.

    " - } - }, - { - "type": "Feature", - "id": "demo-park-hilltop", - "geometry": { - "type": "Point", - "coordinates": [10.5316, 52.2612] - }, - "properties": { - "id": "demo-park-hilltop", - "name": "Hilltop Lookout", - "listInformation": "Small park with a viewpoint", - "description": "

    Panoramic views over the old town.

    " - } - } - ] -} diff --git a/packages/demo-shared/package.json b/packages/demo-shared/package.json deleted file mode 100644 index 01883824..00000000 --- a/packages/demo-shared/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@mapsight/demo-shared", - "description": "Shared Mapsight demo configurations", - "version": "0.0.1", - "private": true, - "type": "module", - "dependencies": { - "@mapsight/ui": "workspace:^" - }, - "devDependencies": { - "@types/react": "catalog:", - "typescript": "catalog:" - }, - "exports": { - "./*": { - "types": "./dist/*.d.ts", - "default": "./dist/*.js" - } - }, - "license": "UNLICENSED", - "repository": { - "url": "https://github.com/open-mapsight/mapsight" - }, - "scripts": { - "build": "tsc --project tsconfig.build.json --outDir dist", - "clean": "rm -rf dist", - "clean-build": "run-s clean build", - "typecheck": "tsc --noEmit" - } -} diff --git a/packages/demo-shared/tsconfig.build.json b/packages/demo-shared/tsconfig.build.json deleted file mode 100644 index ec1c9105..00000000 --- a/packages/demo-shared/tsconfig.build.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "./tsconfig.json", - "compilerOptions": { - "noEmit": false, - "declaration": true, - "declarationMap": true, - "isolatedDeclarations": false, - "rootDir": "src" - }, - "exclude": ["**/*.test.ts"] -} diff --git a/packages/demo-shared/tsconfig.json b/packages/demo-shared/tsconfig.json deleted file mode 100644 index abcf0311..00000000 --- a/packages/demo-shared/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "../../configs/tsconfig-base-tsx.json", - "include": ["src/**/*"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27499f46..db9b99dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,9 @@ settings: catalogs: default: + '@playwright/test': + specifier: ^1.60.0 + version: 1.60.0 '@reduxjs/toolkit': specifier: ^2.11.2 version: 2.12.0 @@ -19,14 +22,17 @@ catalogs: specifier: ^24.12.4 version: 24.12.4 '@types/react': - specifier: ^19.2.14 - version: 19.2.14 + specifier: ^19.2.15 + version: 19.2.15 '@types/react-dom': specifier: ^19.2.3 version: 19.2.3 '@types/react-redux': specifier: ^7.1.34 version: 7.1.34 + canvas: + specifier: ^3.1.0 + version: 3.2.3 jsdom: specifier: ^29.1.1 version: 29.1.1 @@ -52,7 +58,7 @@ catalogs: specifier: ^19.2.6 version: 19.2.6 react-redux: - specifier: ^9.2.0 + specifier: ^9.3.0 version: 9.3.0 redux-batched-actions: specifier: ^0.5.0 @@ -72,6 +78,9 @@ catalogs: vitest: specifier: ^4.1.6 version: 4.1.6 + zod: + specifier: ^4.4.3 + version: 4.4.3 overrides: postcss@<8.5.10: ^8.5.10 @@ -162,6 +171,115 @@ importers: specifier: ^8.59.4 version: 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + apps/braunschweig: + dependencies: + '@mapsight/core': + specifier: workspace:^ + version: link:../../packages/core + '@mapsight/lib-js': + specifier: workspace:^ + version: link:../../packages/lib-js + '@mapsight/lib-ol': + specifier: workspace:^ + version: link:../../packages/lib-ol + '@mapsight/lib-redux': + specifier: workspace:^ + version: link:../../packages/lib-redux + '@mapsight/traffic-style': + specifier: workspace:^ + version: link:../../packages/traffic-style/dist + '@mapsight/ui': + specifier: workspace:^ + version: link:../../packages/ui + '@tanstack/react-router': + specifier: ^1.170.8 + version: 1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tanstack/react-router-devtools': + specifier: ^1.167.0 + version: 1.167.0(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.171.6)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + breakpoint-sass: + specifier: ^3.0.0 + version: 3.0.0(sass@1.100.0) + hint.css: + specifier: ^3.0.0 + version: 3.0.0 + lodash: + specifier: 'catalog:' + version: 4.18.1 + ol: + specifier: 'catalog:' + version: 10.9.0 + proj4: + specifier: 'catalog:' + version: 2.20.8 + react: + specifier: 'catalog:' + version: 19.2.6 + react-dom: + specifier: 'catalog:' + version: 19.2.6(react@19.2.6) + react-modal: + specifier: ^3.16.3 + version: 3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-redux: + specifier: 'catalog:' + version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) + devDependencies: + '@mapsight/vector-style-compiler': + specifier: workspace:^ + version: link:../../packages/vector-style-compiler + '@tailwindcss/vite': + specifier: ^4.3.0 + version: 4.3.0(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + '@tanstack/router-plugin': + specifier: ^1.168.11 + version: 1.168.11(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + '@types/geojson': + specifier: ^7946.0.16 + version: 7946.0.16 + '@types/lodash': + specifier: 'catalog:' + version: 4.17.24 + '@types/node': + specifier: 'catalog:' + version: 24.12.4 + '@types/react': + specifier: 'catalog:' + version: 19.2.15 + '@types/react-dom': + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.15) + '@types/react-modal': + specifier: ^3.16.3 + version: 3.16.3 + '@vitejs/plugin-react': + specifier: ^6.0.2 + version: 6.0.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + npm-run-all: + specifier: ^4.1.5 + version: 4.1.5 + sass: + specifier: ^1.100.0 + version: 1.100.0 + tailwindcss: + specifier: 'catalog:' + version: 4.3.0 + tinyglobby: + specifier: ^0.2.16 + version: 0.2.16 + typescript: + specifier: 'catalog:' + version: 6.0.3 + undici: + specifier: ^7.25.0 + version: 7.25.0 + vite: + specifier: ^8.0.14 + version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + vite-plugin-handlebars: + specifier: ^2.0.3 + version: 2.0.3(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + apps/demo-next: dependencies: '@mapsight/core': @@ -181,7 +299,7 @@ importers: version: link:../../packages/ui next: specifier: ^16.2.6 - version: 16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.99.0) + version: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.100.0) ol: specifier: 'catalog:' version: 10.9.0 @@ -206,10 +324,10 @@ importers: version: 24.12.4 '@types/react': specifier: 'catalog:' - version: 19.2.14 + version: 19.2.15 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.14) + version: 19.2.3(@types/react@19.2.15) babel-plugin-react-compiler: specifier: 1.0.0 version: 1.0.0 @@ -220,13 +338,13 @@ importers: specifier: ^8.5.14 version: 8.5.14 sass: - specifier: ^1.99.0 - version: 1.99.0 + specifier: ^1.100.0 + version: 1.100.0 tailwindcss: specifier: 'catalog:' version: 4.3.0 - apps/demo-vite: + apps/showcase: dependencies: '@mapsight/core': specifier: workspace:^ @@ -248,7 +366,7 @@ importers: version: link:../../packages/ui breakpoint-sass: specifier: ^3.0.0 - version: 3.0.0(sass@1.99.0) + version: 3.0.0(sass@1.100.0) lodash: specifier: 'catalog:' version: 4.18.1 @@ -263,10 +381,7 @@ importers: version: 19.2.6(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) - react-router: - specifier: ^7.15.0 - version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) react-router-dom: specifier: ^7.15.0 version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -282,22 +397,34 @@ importers: version: link:../../packages/vector-style-compiler '@tailwindcss/vite': specifier: ^4.3.0 - version: 4.3.0(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.3.0(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) '@types/node': specifier: 'catalog:' version: 24.12.4 '@types/react': specifier: 'catalog:' - version: 19.2.14 + version: 19.2.15 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.14) + version: 19.2.3(@types/react@19.2.15) + mkdirp: + specifier: ^3.0.1 + version: 3.0.1 + npm-run-all: + specifier: ^4.1.5 + version: 4.1.5 + rimraf: + specifier: ^6.1.3 + version: 6.1.3 terser: specifier: ^5.47.1 version: 5.47.1 + typescript: + specifier: 'catalog:' + version: 6.0.3 vite: - specifier: ^8.0.13 - version: 8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + specifier: ^8.0.14 + version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) apps/vector-editor: dependencies: @@ -318,7 +445,7 @@ importers: version: link:../../packages/traffic-style/dist '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -339,7 +466,7 @@ importers: version: 3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) react-tooltip: specifier: ^4.5.1 version: 4.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -367,10 +494,10 @@ importers: version: 3.5.6 '@types/react': specifier: 'catalog:' - version: 19.2.14 + version: 19.2.15 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.14) + version: 19.2.3(@types/react@19.2.15) '@types/react-modal': specifier: ^3.16.3 version: 3.16.3 @@ -379,16 +506,16 @@ importers: version: 7.1.34 autoprefixer: specifier: ^10.5.0 - version: 10.5.0(postcss@8.5.14) + version: 10.5.0(postcss@8.5.15) postcss-import: specifier: ^16.1.1 - version: 16.1.1(postcss@8.5.14) + version: 16.1.1(postcss@8.5.15) postcss-nested: specifier: ^7.0.2 - version: 7.0.2(postcss@8.5.14) + version: 7.0.2(postcss@8.5.15) vite: - specifier: ^8.0.13 - version: 8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + specifier: ^8.0.14 + version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) packages/core: dependencies: @@ -403,7 +530,7 @@ importers: version: link:../lib-redux '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) eventemitter3: specifier: ^5.0.4 version: 5.0.4 @@ -416,7 +543,13 @@ importers: redux-batched-actions: specifier: 'catalog:' version: 0.5.0(redux@5.0.1) + zod: + specifier: 'catalog:' + version: 4.4.3 devDependencies: + '@playwright/test': + specifier: 'catalog:' + version: 1.60.0 '@redux-devtools/extension': specifier: ^3.3.0 version: 3.3.0(redux@5.0.1) @@ -432,12 +565,18 @@ importers: '@types/node': specifier: 'catalog:' version: 24.12.4 + canvas: + specifier: 'catalog:' + version: 3.2.3 jsdom: specifier: 'catalog:' - version: 29.1.1 + version: 29.1.1(canvas@3.2.3) ol: specifier: 'catalog:' version: 10.9.0 + playwright: + specifier: 'catalog:' + version: 1.60.0 proj4: specifier: 'catalog:' version: 2.20.8 @@ -447,6 +586,86 @@ importers: typescript: specifier: 'catalog:' version: 6.0.3 + vite: + specifier: ^8.0.14 + version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + vitest: + specifier: 'catalog:' + version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + + packages/count-aggregator-api: + dependencies: + '@zodios/core': + specifier: ^10.9.6 + version: 10.9.6(axios@1.17.0)(zod@4.4.3) + zod: + specifier: 'catalog:' + version: 4.4.3 + devDependencies: + npm-run-all: + specifier: ^4.1.5 + version: 4.1.5 + openapi-zod-client: + specifier: ^1.18.3 + version: 1.18.3(react@19.2.6) + rimraf: + specifier: ^6.1.3 + version: 6.1.3 + typescript: + specifier: 'catalog:' + version: 6.0.3 + vitest: + specifier: 'catalog:' + version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + + packages/count-aggregator-ui: + dependencies: + clsx: + specifier: ^2.1.1 + version: 2.1.1 + flatpickr: + specifier: ^4.6.13 + version: 4.6.13 + react-flatpickr: + specifier: ^4.0.11 + version: 4.0.11(react@19.2.6) + recharts: + specifier: ^2.15.4 + version: 2.15.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + tailwind-merge: + specifier: ^3.3.1 + version: 3.6.0 + devDependencies: + '@tanstack/react-query': + specifier: ^5.90.5 + version: 5.101.0(react@19.2.6) + '@types/react': + specifier: 'catalog:' + version: 19.2.15 + '@types/react-dom': + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.15) + '@types/react-flatpickr': + specifier: ^3.8.11 + version: 3.8.11 + axios: + specifier: ^1.16.1 + version: 1.17.0 + react: + specifier: 'catalog:' + version: 19.2.6 + react-dom: + specifier: 'catalog:' + version: 19.2.6(react@19.2.6) + react-select: + specifier: ^5.10.2 + version: 5.10.2(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + typescript: + specifier: 'catalog:' + version: 6.0.3 + vitest: + specifier: 'catalog:' + version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) packages/lib-js: devDependencies: @@ -464,7 +683,7 @@ importers: version: 4.1.5 vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1)(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) packages/lib-ol: dependencies: @@ -492,7 +711,7 @@ importers: version: link:../lib-js '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@types/lodash': specifier: 'catalog:' version: 4.17.24 @@ -506,6 +725,9 @@ importers: packages/traffic-style: dependencies: + '@fortawesome/free-solid-svg-icons': + specifier: ^6.7.2 + version: 6.7.2 '@mapsight/lib-ol': specifier: workspace:^ version: link:../lib-ol @@ -515,12 +737,18 @@ importers: fs-extra: specifier: ^11.3.5 version: 11.3.5 + lru-cache: + specifier: ^11.2.2 + version: 11.4.0 merge-stream: specifier: ^2.0.0 version: 2.0.0 ol: specifier: 'catalog:' version: 10.9.0 + react: + specifier: 'catalog:' + version: 19.2.6 sharp: specifier: ^0.34.5 version: 0.34.5 @@ -531,7 +759,7 @@ importers: specifier: ^3.0.1 version: 3.0.1 zod: - specifier: ^4.4.3 + specifier: 'catalog:' version: 4.4.3 devDependencies: '@mapsight/vector-style-compiler': @@ -551,7 +779,7 @@ importers: version: 2.0.0 vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1)(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) publishDirectory: dist packages/ui: @@ -568,27 +796,30 @@ importers: '@mapsight/lib-redux': specifier: workspace:^ version: link:../lib-redux + '@mapsight/traffic-style': + specifier: workspace:^ + version: link:../traffic-style/dist '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@types/react-redux': specifier: 'catalog:' version: 7.1.34 breakpoint-sass: specifier: ^3.0.0 - version: 3.0.0(sass@1.99.0) + version: 3.0.0(sass@1.100.0) flatpickr: specifier: ^4.6.13 version: 4.6.13 focus-trap-react: specifier: ^12.0.1 - version: 12.0.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 12.0.1(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) hint.css: specifier: ^3.0.0 version: 3.0.0 jsdom: specifier: 'catalog:' - version: 29.1.1 + version: 29.1.1(canvas@3.2.3) lodash: specifier: 'catalog:' version: 4.18.1 @@ -612,23 +843,26 @@ importers: version: 8.3.0(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) redux-batched-actions: specifier: 'catalog:' version: 0.5.0(redux@5.0.1) redux-thunk: specifier: 'catalog:' version: 3.1.0(redux@5.0.1) + zod: + specifier: 'catalog:' + version: 4.4.3 devDependencies: '@types/lodash': specifier: 'catalog:' version: 4.17.24 '@types/react': specifier: 'catalog:' - version: 19.2.14 + version: 19.2.15 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.14) + version: 19.2.3(@types/react@19.2.15) '@types/react-modal': specifier: ^3.16.3 version: 3.16.3 @@ -644,6 +878,9 @@ importers: svgo: specifier: ^4.0.1 version: 4.0.1 + vitest: + specifier: 'catalog:' + version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) packages/vector-style-compiler: dependencies: @@ -703,14 +940,14 @@ importers: specifier: ^8.4.0 version: 8.4.0 sass: - specifier: ^1.99.0 - version: 1.99.0 + specifier: ^1.100.0 + version: 1.100.0 vite: - specifier: ^8.0.13 - version: 8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + specifier: ^8.0.14 + version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1)(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) packages: @@ -718,6 +955,22 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@apidevtools/json-schema-ref-parser@11.7.2': + resolution: {integrity: sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==} + engines: {node: '>= 16'} + + '@apidevtools/openapi-schemas@2.1.0': + resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==} + engines: {node: '>=10'} + + '@apidevtools/swagger-methods@3.0.2': + resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} + + '@apidevtools/swagger-parser@10.1.1': + resolution: {integrity: sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==} + peerDependencies: + openapi-types: '>=7' + '@asamuzakjp/css-color@5.1.11': resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -767,6 +1020,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -788,6 +1045,18 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.29.2': resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} @@ -908,6 +1177,47 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -955,6 +1265,23 @@ packages: '@noble/hashes': optional: true + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@fortawesome/fontawesome-common-types@6.7.2': + resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==} + engines: {node: '>=6'} + + '@fortawesome/free-solid-svg-icons@6.7.2': + resolution: {integrity: sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==} + engines: {node: '>=6'} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -1165,6 +1492,12 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@liuli-util/fs-extra@0.1.0': + resolution: {integrity: sha512-eaAyDyMGT23QuRGbITVY3SOJff3G9ekAAyGqB9joAnTBmqvFN+9a1FazOdO70G6IUqgpKV451eBHYSRcOJ/FNQ==} + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -1251,8 +1584,8 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@oxc-project/types@0.130.0': - resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} + '@oxc-project/types@0.132.0': + resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} '@package-json/types@0.0.12': resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==} @@ -1348,6 +1681,11 @@ packages: '@petamoriken/float16@3.9.3': resolution: {integrity: sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==} + '@playwright/test@1.60.0': + resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==} + engines: {node: '>=18'} + hasBin: true + '@react-types/shared@3.34.0': resolution: {integrity: sha512-gp6xo/s2lX54AlTjOiqwDnxA7UW79BNvI9dB9pr3LZTzRKCd1ZA+ZbgKw/ReIiWuvvVw/8QFJpnqeeFyLocMcQ==} peerDependencies: @@ -1369,97 +1707,97 @@ packages: react-redux: optional: true - '@rolldown/binding-android-arm64@1.0.1': - resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} + '@rolldown/binding-android-arm64@1.0.2': + resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.1': - resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==} + '@rolldown/binding-darwin-arm64@1.0.2': + resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.1': - resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==} + '@rolldown/binding-darwin-x64@1.0.2': + resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.1': - resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==} + '@rolldown/binding-freebsd-x64@1.0.2': + resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.1': - resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.1': - resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==} + '@rolldown/binding-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.1': - resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==} + '@rolldown/binding-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.1': - resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==} + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.1': - resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.2': + resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.1': - resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==} + '@rolldown/binding-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.1': - resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==} + '@rolldown/binding-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.1': - resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==} + '@rolldown/binding-openharmony-arm64@1.0.2': + resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.1': - resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==} + '@rolldown/binding-wasm32-wasi@1.0.2': + resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.1': - resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==} + '@rolldown/binding-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.1': - resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==} + '@rolldown/binding-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1579,6 +1917,93 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 + '@tanstack/history@1.162.0': + resolution: {integrity: sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==} + engines: {node: '>=20.19'} + + '@tanstack/query-core@5.101.0': + resolution: {integrity: sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==} + + '@tanstack/react-query@5.101.0': + resolution: {integrity: sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/react-router-devtools@1.167.0': + resolution: {integrity: sha512-nGw095EG7IHx0h5NtlEmzf6vcCTaFNPWdTSuDKazajhN0ct/v/TkekJ9J6KYUCeV1a8/2ZmToc58M+0rrOyn7w==} + engines: {node: '>=20.19'} + peerDependencies: + '@tanstack/react-router': ^1.170.0 + '@tanstack/router-core': ^1.170.0 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + '@tanstack/router-core': + optional: true + + '@tanstack/react-router@1.170.8': + resolution: {integrity: sha512-Qw2ju6jjnIsMpuW+VrnHZWHuugqs592PWsnI56sG28qNhg14CgRLahOcNajfuJR9P4MxKGP94WVzmFKSYUz/ig==} + engines: {node: '>=20.19'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-store@0.9.3': + resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/router-core@1.171.6': + resolution: {integrity: sha512-Ol6DQ+j6rf/rPVELIzo8LHwOQV2KL+zry3b+39kL/GKrt7YId52WJRAFMzuseY4XceSW+PU7sG/Cc1QkwJr0hg==} + engines: {node: '>=20.19'} + + '@tanstack/router-devtools-core@1.168.0': + resolution: {integrity: sha512-wQoQhlBK7nlZgqzaqdYXKWNTpdHdsaREdaPhFZVH0/Ador+F+eM3/NF2i3f2LPeS0GgKraZUQXe1Q/1+KHyEYg==} + engines: {node: '>=20.19'} + peerDependencies: + '@tanstack/router-core': ^1.170.0 + csstype: ^3.0.10 + peerDependenciesMeta: + csstype: + optional: true + + '@tanstack/router-generator@1.167.10': + resolution: {integrity: sha512-CjbjWRSo6djLU/C7ncb9IbKUcf4IwpdqhLGngkwKkXaVFXGxEAafA/uhvOCv/UEUVR7NI3tJqqQmxYXGcJPbjw==} + engines: {node: '>=20.19'} + + '@tanstack/router-plugin@1.168.11': + resolution: {integrity: sha512-b2eom/8xCWL/OiWxKub8kYsr8p+kvmB/eXwYGqCWG8vilcJo+eQCSyp54nKt0AZ5k/ET1+eINc+4mwL3bVeAgg==} + engines: {node: '>=20.19'} + peerDependencies: + '@rsbuild/core': '>=1.0.2 || ^2.0.0' + '@tanstack/react-router': ^1.170.8 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' + vite-plugin-solid: ^2.11.10 || ^3.0.0-0 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-utils@1.162.1': + resolution: {integrity: sha512-62layyTGmclHDQS/eidwKRfN1hhCKwViG7iEBcVmL0MXgcAB3OOucWCEcDDGd9Cu11H6b4QQ5oOo47MWIqwz0A==} + engines: {node: '>=20.19'} + + '@tanstack/store@0.9.3': + resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} + + '@tanstack/virtual-file-routes@1.162.0': + resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} + engines: {node: '>=20.19'} + '@trivago/prettier-plugin-sort-imports@6.0.2': resolution: {integrity: sha512-3DgfkukFyC/sE/VuYjaUUWoFfuVjPK55vOFDsxD56XXynFMCZDYFogH2l/hDfOsQAm1myoU/1xByJ3tWqtulXA==} engines: {node: '>= 20'} @@ -1637,6 +2062,33 @@ packages: '@types/css@0.0.38': resolution: {integrity: sha512-FsAy4pBnrJb8qdKmIyDy582o4Xt8pHwpCwYRmIvXw4dslA7C4436oOM+8XNnMEsV/LSculbFNaZsBZmycDjARw==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -1649,6 +2101,9 @@ packages: '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/fs-extra@9.0.13': + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} @@ -1684,6 +2139,9 @@ packages: '@types/node@24.12.4': resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/pidusage@2.0.5': resolution: {integrity: sha512-MIiyZI4/MK9UGUXWt0jJcCZhVw7YdhBuTOuqP/BjuLDLZ2PmmViMIQgZiWxtaMicQfAz/kMrZ5T7PKxFSkTeUA==} @@ -1695,14 +2153,22 @@ packages: peerDependencies: '@types/react': ^19.2.0 + '@types/react-flatpickr@3.8.11': + resolution: {integrity: sha512-wXGyGRpUjiGknioxWzWJdNvF2XxKw5lAI7H64Iv7w4iL+1iT7QvAzrigz5FkW4lTg9IJOww6t7g21FzsrmRV6A==} + '@types/react-modal@3.16.3': resolution: {integrity: sha512-xXuGavyEGaFQDgBv4UVm8/ZsG+qxeQ7f77yNrW3n+1J6XAstUy5rYHeIHPh1KzsGc6IkCIdu6lQ2xWzu1jBTLg==} '@types/react-redux@7.1.34': resolution: {integrity: sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==} - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' + + '@types/react@19.2.15': + resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -1889,6 +2355,19 @@ packages: cpu: [x64] os: [win32] + '@vitejs/plugin-react@6.0.2': + resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@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 + '@vitest/expect@4.1.6': resolution: {integrity: sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==} @@ -1921,6 +2400,12 @@ packages: '@zarrita/storage@0.2.0': resolution: {integrity: sha512-855ZXqtnds7spnT8vNvD+MXa3QExP1m2GqShe8yt7uZXHnQLgJHgkpVwFjE1B0KDDRO0ki09hmk6OboTaIfPsQ==} + '@zodios/core@10.9.6': + resolution: {integrity: sha512-aH4rOdb3AcezN7ws8vDgBfGboZMk2JGGzEq/DtW65MhnRxyTGRuLJRWVQ/2KxDgWvV2F5oTkAS+5pnjKbl0n+A==} + peerDependencies: + axios: ^0.x || ^1.0.0 + zod: ^3.x + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1931,9 +2416,24 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -1962,6 +2462,10 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + ansis@4.3.0: + resolution: {integrity: sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==} + engines: {node: '>=14'} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -2027,6 +2531,9 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atob@2.1.2: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} engines: {node: '>= 4.5.0'} @@ -2047,6 +2554,9 @@ packages: resolution: {integrity: sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==} engines: {node: '>=4'} + axios@1.17.0: + resolution: {integrity: sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -2059,6 +2569,13 @@ packages: react-native-b4a: optional: true + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + babel-plugin-react-compiler@1.0.0: resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} @@ -2077,6 +2594,9 @@ packages: bare-abort-controller: optional: true + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.10.29: resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} engines: {node: '>=6.0.0'} @@ -2093,6 +2613,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2123,6 +2646,13 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2135,6 +2665,9 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} + call-me-maybe@1.0.2: + resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2142,6 +2675,10 @@ packages: caniuse-lite@1.0.30001792: resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} + canvas@3.2.3: + resolution: {integrity: sha512-PzE5nJZPz72YUAfo8oTp0u3fqqY7IzlTubneAihqDYAUcBk7ryeCmBbdJBEdaH0bptSOe2VT2Zwcb3UaFyaSWw==} + engines: {node: ^18.12.0 || >= 20.9.0} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -2165,14 +2702,13 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - chokidar@5.0.0: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -2209,6 +2745,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2227,13 +2767,23 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@3.1.1: + resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie@1.1.1: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + cpx2@8.0.2: resolution: {integrity: sha512-exLFEIh8XgWthEtrEq8hs+S6jxM5ZHpjQnRH6D7VU+2uAYS3amLSVOUSuirfx3HeN7WBCq+xFygHpt7l+gQtUA==} engines: {node: ^20.0.0 || >=22.0.0, npm: '>=10'} @@ -2277,6 +2827,50 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -2320,6 +2914,9 @@ packages: supports-color: optional: true + decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -2327,6 +2924,14 @@ packages: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -2338,6 +2943,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -2346,6 +2955,10 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2354,6 +2967,9 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -2383,10 +2999,17 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + enhanced-resolve@5.21.5: resolution: {integrity: sha512-mLCNbrQli11K1ySUmuNt4ZUB3OpGIDq4q2vTBTf5cL2lpsRjI9QKqSD0ndjW8FyvcW/Jj46gMe9syyHAsvMa/A==} engines: {node: '>=10.13.0'} + enhanced-resolve@5.22.0: + resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==} + engines: {node: '>=10.13.0'} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -2429,6 +3052,10 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} @@ -2647,6 +3274,12 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eval-estree-expression@3.0.1: + resolution: {integrity: sha512-zTLKGbiVdQYp4rQkSoXPibrFf5ZoPn6jzExegRLEQ13F+FSxu5iLgaRH6hlDs2kWSUa6vp8yD20cdJi0me6pEw==} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -2656,6 +3289,10 @@ packages: exenv@1.2.2: resolution: {integrity: sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} @@ -2666,6 +3303,10 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-equals@5.4.0: + resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} + engines: {node: '>=6.0.0'} + fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} @@ -2683,6 +3324,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -2709,6 +3353,9 @@ packages: find-index@0.1.1: resolution: {integrity: sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==} + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -2738,13 +3385,33 @@ packages: focus-trap@8.2.0: resolution: {integrity: sha512-CaBdQ9P4fa/yCA6pDf/3aJd8bf9IOG5QGK21/E+86o2V4V8kzXaR4A9E6tNR7KkkS1+T5ZIU1tJDBDLwsucz9g==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + fs-extra@11.3.5: resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} engines: {node: '>=14.14'} @@ -2812,6 +3479,9 @@ packages: get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2855,6 +3525,11 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + goober@2.1.19: + resolution: {integrity: sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==} + peerDependencies: + csstype: ^3.0.10 + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -2862,6 +3537,11 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} + engines: {node: '>=0.4.7'} + hasBin: true + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -2912,6 +3592,10 @@ packages: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + human-id@4.1.3: resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} hasBin: true @@ -2925,6 +3609,9 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -2953,10 +3640,17 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -3085,6 +3779,10 @@ packages: isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isbot@5.1.40: + resolution: {integrity: sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==} + engines: {node: '>=18'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3130,9 +3828,15 @@ packages: json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -3251,6 +3955,9 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lint-staged@17.0.5: resolution: {integrity: sha512-d12yC+/e8RhBjZtaxZn71FyrgU/P5e+uAPifhCLwdosQZP/zamSdKRWDC30ocVIbzDKiFG1McHc/LUgB92GIPw==} engines: {node: '>=22.22.1'} @@ -3315,6 +4022,9 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -3333,10 +4043,22 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -3355,6 +4077,9 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} @@ -3376,6 +4101,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -3384,6 +4112,9 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + next@16.2.6: resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} engines: {node: '>=20.9.0'} @@ -3408,6 +4139,10 @@ packages: nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + node-abi@3.92.0: + resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} + engines: {node: '>=10'} + node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -3474,10 +4209,23 @@ packages: ol@10.9.0: resolution: {integrity: sha512-svbbgVQUmEHaKpLQ8kRySojs59Brvgl2zYIrqG9eQNXGfsbi55rQasZIDpwpQzDL6OlzrUb0H4hQaiX9wDoGmA==} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@7.0.0: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + + openapi-zod-client@1.18.3: + resolution: {integrity: sha512-10vYK7xo1yyZfcoRvYNGIsDeej1CG9k63u8dkjbGBlr+NHZMy2Iy2h9s11UWNKdj6XMDWbNOPp5gIy8YdpgPtQ==} + hasBin: true + + openapi3-ts@3.1.0: + resolution: {integrity: sha512-1qKTvCCVoV0rkwUh1zq5o8QyghmwYPuhdvtjv1rFjuOnJToXhQyF8eGjNETQ8QmGjr9Jz/tkAKLITIl2s7dw3A==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3544,12 +4292,28 @@ packages: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + parse-statements@1.0.11: resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} parse5@8.0.1: resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + pastable@2.2.1: + resolution: {integrity: sha512-K4ClMxRKpgN4sXj6VIPPrvor/TMp2yPNCGtfhvV106C73SwefQ3FuegURsH7AQHpqu0WwbvKXRl1HQxF6qax9w==} + engines: {node: '>=14.x'} + peerDependencies: + react: '>=17' + xstate: '>=4.32.1' + peerDependenciesMeta: + react: + optional: true + xstate: + optional: true + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -3662,6 +4426,16 @@ packages: resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. + hasBin: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3685,6 +4459,13 @@ packages: protocol-buffers-schema@3.6.1: resolution: {integrity: sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -3709,6 +4490,10 @@ packages: rbush@4.0.1: resolution: {integrity: sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + react-aria@3.48.0: resolution: {integrity: sha512-jQjd4rBEIMqecBaAKYJbVGK6EqIHLa5znVQ7jwFyK5vCyljoj6KhgtiahmcIPsG5vG5vEDLw+ba+bEWn6A2P4w==} peerDependencies: @@ -3720,6 +4505,11 @@ packages: peerDependencies: react: ^19.2.6 + react-flatpickr@4.0.11: + resolution: {integrity: sha512-S0TAu8eUeJgN8lZ0Efi41WGPM/tPPUvrveXQ8CAUO60+7TTrF5Ehyv8fvPVagKCqJahY7hXYERM7XfH2hSAWdg==} + peerDependencies: + react: '>= 16 <= 19' + react-intersection-observer@10.0.3: resolution: {integrity: sha512-luICLMbs0zxTO/70Zy7K5jOXkABPEVSAF8T3FdZUlctsrIaPLmx8TZe2SSA+CY2HGWfz2INyNTnp82pxNNsShA==} peerDependencies: @@ -3732,6 +4522,9 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} @@ -3775,6 +4568,18 @@ packages: react-dom: optional: true + react-select@5.10.2: + resolution: {integrity: sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-smooth@4.0.4: + resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-stately@3.46.0: resolution: {integrity: sha512-OdxhWvHgs2L4OJGIs7hnuTr5WjjMM6enhNEAMRqiekhF8+ITvA2LRwNftOZwcogaoCslGYq5S2VQTQwnm0GbCA==} peerDependencies: @@ -3787,6 +4592,12 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + react@19.2.6: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} @@ -3802,18 +4613,29 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - readdirp@5.0.0: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} + recharts-scale@0.4.5: + resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} + + recharts@2.15.4: + resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} + engines: {node: '>=14'} + deprecated: 1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + redux-batched-actions@0.5.0: resolution: {integrity: sha512-6orZWyCnIQXMGY4DUGM0oj0L7oYnwTACsfsru/J7r94RM3P9eS7SORGpr3LCeRCMoIMQcpfKZ7X4NdyFHBS8Eg==} peerDependencies: @@ -3907,8 +4729,8 @@ packages: engines: {node: 20 || >=22} hasBin: true - rolldown@1.0.1: - resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==} + rolldown@1.0.2: + resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3933,9 +4755,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.99.0: - resolution: {integrity: sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==} - engines: {node: '>=14.0.0'} + sass@1.100.0: + resolution: {integrity: sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==} + engines: {node: '>=20.19.0'} hasBin: true sax@1.6.0: @@ -3962,6 +4784,16 @@ packages: engines: {node: '>=10'} hasBin: true + seroval-plugins@1.5.4: + resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.5.4: + resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} + engines: {node: '>=10'} + set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -4001,6 +4833,10 @@ packages: resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} + shell-quote@1.8.4: + resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.1: resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} @@ -4024,6 +4860,12 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -4047,6 +4889,10 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -4128,6 +4974,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -4140,6 +4989,10 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4157,6 +5010,9 @@ packages: babel-plugin-macros: optional: true + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + subarg@1.0.0: resolution: {integrity: sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==} @@ -4228,13 +5084,26 @@ packages: tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + tailwindcss@4.3.0: resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + tanu@0.1.13: + resolution: {integrity: sha512-UbRmX7ccZ4wMVOY/Uw+7ji4VOkEYSYJG1+I4qzbnn4qh/jtvVbrm6BFnF12NQQ4+jGv21wKmjb1iFyUSVnBWcQ==} + tapable@2.3.3: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + teex@1.0.1: resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} @@ -4250,6 +5119,9 @@ packages: text-decoder@1.2.7: resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -4290,6 +5162,12 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-pattern@5.9.0: + resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} + + ts-toolbelt@9.6.0: + resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} + tsc-alias@1.8.17: resolution: {integrity: sha512-EIduCZHqbNwPm8BZYfq1aD7BQ697A4h6uSGMOFQfYGoQwfrYFTKwYfy9Bv42YxHkduVBcn9Zx0DkX111DKskyg==} engines: {node: '>=16.20.2'} @@ -4301,6 +5179,9 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + turbo@2.9.14: resolution: {integrity: sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==} hasBin: true @@ -4309,6 +5190,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -4332,11 +5217,21 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -4359,6 +5254,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + unrs-resolver@1.12.2: resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} @@ -4375,6 +5274,15 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -4391,12 +5299,20 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + victory-vendor@36.9.2: + resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vinyl@3.0.1: resolution: {integrity: sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA==} engines: {node: '>=10.13.0'} - vite@8.0.13: - resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==} + vite-plugin-handlebars@2.0.3: + resolution: {integrity: sha512-LnzLfYtmHfK66R5M3yL/2EAYmsZh+/0SrlBStRPJYhww0pBDQBDzDgxmxHl9JV2UHZ/21uOx5+kPPZiEp2gMCQ==} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + vite@8.0.14: + resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4493,6 +5409,9 @@ packages: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-mimetype@5.0.0: resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} @@ -4501,6 +5420,10 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whence@2.1.0: + resolution: {integrity: sha512-4UBPMg5mng5KLzdliVQdQ4fJwCdIMXkE8CkoDmGKRy5r8pV9xq+nVgf/sKXpmNEIOtFp7m7v2bFdb7JoLvh+Hg==} + engines: {node: '>=14'} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -4538,6 +5461,9 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + wrap-ansi@10.0.0: resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} engines: {node: '>=20'} @@ -4546,6 +5472,9 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -4563,6 +5492,10 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} + engines: {node: '>= 6'} + yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} @@ -4589,6 +5522,9 @@ packages: peerDependencies: zod: ^3.25.0 || ^4.0.0 + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} @@ -4599,6 +5535,27 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@apidevtools/json-schema-ref-parser@11.7.2': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + + '@apidevtools/openapi-schemas@2.1.0': {} + + '@apidevtools/swagger-methods@3.0.2': {} + + '@apidevtools/swagger-parser@10.1.1(openapi-types@12.1.3)': + dependencies: + '@apidevtools/json-schema-ref-parser': 11.7.2 + '@apidevtools/openapi-schemas': 2.1.0 + '@apidevtools/swagger-methods': 3.0.2 + '@jsdevtools/ono': 7.1.3 + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + call-me-maybe: 1.0.2 + openapi-types: 12.1.3 + '@asamuzakjp/css-color@5.1.11': dependencies: '@asamuzakjp/generational-cache': 1.0.1 @@ -4681,6 +5638,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-plugin-utils@7.28.6': {} + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} @@ -4696,6 +5655,16 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/runtime@7.29.2': {} '@babel/template@7.28.6': @@ -4908,6 +5877,70 @@ snapshots: tslib: 2.8.1 optional: true + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.28.6 + '@babel/runtime': 7.29.2 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.2.15)(react@19.2.6)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.15 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.6)': + dependencies: + react: 19.2.6 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': dependencies: eslint: 9.39.4(jiti@2.7.0) @@ -4956,6 +5989,23 @@ snapshots: '@exodus/bytes@1.15.0': {} + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/utils@0.2.11': {} + + '@fortawesome/fontawesome-common-types@6.7.2': {} + + '@fortawesome/free-solid-svg-icons@6.7.2': + dependencies: + '@fortawesome/fontawesome-common-types': 6.7.2 + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -5111,6 +6161,13 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@jsdevtools/ono@7.1.3': {} + + '@liuli-util/fs-extra@0.1.0': + dependencies: + '@types/fs-extra': 9.0.13 + fs-extra: 10.1.0 + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.29.2 @@ -5178,7 +6235,7 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@oxc-project/types@0.130.0': {} + '@oxc-project/types@0.132.0': {} '@package-json/types@0.0.12': {} @@ -5245,6 +6302,10 @@ snapshots: '@petamoriken/float16@3.9.3': {} + '@playwright/test@1.60.0': + dependencies: + playwright: 1.60.0 + '@react-types/shared@3.34.0(react@19.2.6)': dependencies: react: 19.2.6 @@ -5255,7 +6316,7 @@ snapshots: immutable: 4.3.8 redux: 5.0.1 - '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 @@ -5265,55 +6326,55 @@ snapshots: reselect: 5.2.0 optionalDependencies: react: 19.2.6 - react-redux: 9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + react-redux: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) - '@rolldown/binding-android-arm64@1.0.1': + '@rolldown/binding-android-arm64@1.0.2': optional: true - '@rolldown/binding-darwin-arm64@1.0.1': + '@rolldown/binding-darwin-arm64@1.0.2': optional: true - '@rolldown/binding-darwin-x64@1.0.1': + '@rolldown/binding-darwin-x64@1.0.2': optional: true - '@rolldown/binding-freebsd-x64@1.0.1': + '@rolldown/binding-freebsd-x64@1.0.2': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.1': + '@rolldown/binding-linux-arm64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.1': + '@rolldown/binding-linux-arm64-musl@1.0.2': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.1': + '@rolldown/binding-linux-ppc64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.1': + '@rolldown/binding-linux-s390x-gnu@1.0.2': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.1': + '@rolldown/binding-linux-x64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-x64-musl@1.0.1': + '@rolldown/binding-linux-x64-musl@1.0.2': optional: true - '@rolldown/binding-openharmony-arm64@1.0.1': + '@rolldown/binding-openharmony-arm64@1.0.2': optional: true - '@rolldown/binding-wasm32-wasi@1.0.1': + '@rolldown/binding-wasm32-wasi@1.0.2': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.1': + '@rolldown/binding-win32-arm64-msvc@1.0.2': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.1': + '@rolldown/binding-win32-x64-msvc@1.0.2': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -5335,7 +6396,7 @@ snapshots: '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.21.5 + enhanced-resolve: 5.22.0 jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 @@ -5401,12 +6462,115 @@ snapshots: postcss: 8.5.14 tailwindcss: 4.3.0 - '@tailwindcss/vite@4.3.0(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.0(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 tailwindcss: 4.3.0 - vite: 8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + + '@tanstack/history@1.162.0': {} + + '@tanstack/query-core@5.101.0': {} + + '@tanstack/react-query@5.101.0(react@19.2.6)': + dependencies: + '@tanstack/query-core': 5.101.0 + react: 19.2.6 + + '@tanstack/react-router-devtools@1.167.0(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.171.6)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@tanstack/react-router': 1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tanstack/router-devtools-core': 1.168.0(@tanstack/router-core@1.171.6)(csstype@3.2.3) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@tanstack/router-core': 1.171.6 + transitivePeerDependencies: + - csstype + + '@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@tanstack/history': 1.162.0 + '@tanstack/react-store': 0.9.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tanstack/router-core': 1.171.6 + isbot: 5.1.40 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@tanstack/react-store@0.9.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@tanstack/store': 0.9.3 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + use-sync-external-store: 1.6.0(react@19.2.6) + + '@tanstack/router-core@1.171.6': + dependencies: + '@tanstack/history': 1.162.0 + cookie-es: 3.1.1 + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) + + '@tanstack/router-devtools-core@1.168.0(@tanstack/router-core@1.171.6)(csstype@3.2.3)': + dependencies: + '@tanstack/router-core': 1.171.6 + clsx: 2.1.1 + goober: 2.1.19(csstype@3.2.3) + optionalDependencies: + csstype: 3.2.3 + + '@tanstack/router-generator@1.167.10': + dependencies: + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.171.6 + '@tanstack/router-utils': 1.162.1 + '@tanstack/virtual-file-routes': 1.162.0 + jiti: 2.7.0 + magic-string: 0.30.21 + prettier: 3.8.3 + zod: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.168.11(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.171.6 + '@tanstack/router-generator': 1.167.10 + '@tanstack/router-utils': 1.162.1 + '@tanstack/virtual-file-routes': 1.162.0 + chokidar: 5.0.0 + unplugin: 3.0.0 + zod: 4.4.3 + optionalDependencies: + '@tanstack/react-router': 1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + transitivePeerDependencies: + - supports-color + + '@tanstack/router-utils@1.162.1': + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + ansis: 4.3.0 + babel-dead-code-elimination: 1.0.12 + diff: 8.0.4 + pathe: 2.0.3 + tinyglobby: 0.2.16 + transitivePeerDependencies: + - supports-color + + '@tanstack/store@0.9.3': {} + + '@tanstack/virtual-file-routes@1.162.0': {} '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3)': dependencies: @@ -5452,6 +6616,30 @@ snapshots: '@types/css@0.0.38': {} + '@types/d3-array@3.2.2': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + '@types/deep-eql@4.0.2': {} '@types/eslint-plugin-jsx-a11y@6.10.1(jiti@2.7.0)': @@ -5468,11 +6656,15 @@ snapshots: '@types/jsonfile': 6.1.4 '@types/node': 24.12.4 + '@types/fs-extra@9.0.13': + dependencies: + '@types/node': 24.12.4 + '@types/geojson@7946.0.16': {} - '@types/hoist-non-react-statics@3.3.7(@types/react@19.2.14)': + '@types/hoist-non-react-statics@3.3.7(@types/react@19.2.15)': dependencies: - '@types/react': 19.2.14 + '@types/react': 19.2.15 hoist-non-react-statics: 3.3.2 '@types/jsdom@28.0.3': @@ -5502,26 +6694,37 @@ snapshots: dependencies: undici-types: 7.16.0 + '@types/parse-json@4.0.2': {} + '@types/pidusage@2.0.5': {} '@types/rbush@4.0.0': {} - '@types/react-dom@19.2.3(@types/react@19.2.14)': + '@types/react-dom@19.2.3(@types/react@19.2.15)': + dependencies: + '@types/react': 19.2.15 + + '@types/react-flatpickr@3.8.11': dependencies: - '@types/react': 19.2.14 + '@types/react': 19.2.15 + flatpickr: 4.6.13 '@types/react-modal@3.16.3': dependencies: - '@types/react': 19.2.14 + '@types/react': 19.2.15 '@types/react-redux@7.1.34': dependencies: - '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.14) - '@types/react': 19.2.14 + '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.15) + '@types/react': 19.2.15 hoist-non-react-statics: 3.3.2 redux: 4.2.1 - '@types/react@19.2.14': + '@types/react-transition-group@4.4.12(@types/react@19.2.15)': + dependencies: + '@types/react': 19.2.15 + + '@types/react@19.2.15': dependencies: csstype: 3.2.3 @@ -5690,6 +6893,13 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true + '@vitejs/plugin-react@6.0.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + optionalDependencies: + babel-plugin-react-compiler: 1.0.0 + '@vitest/expect@4.1.6': dependencies: '@standard-schema/spec': 1.1.0 @@ -5699,13 +6909,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.6(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0))': + '@vitest/mocker@4.1.6(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) '@vitest/pretty-format@4.1.6': dependencies: @@ -5736,12 +6946,32 @@ snapshots: reference-spec-reader: 0.2.0 unzipit: 2.0.0 + '@zodios/core@10.9.6(axios@1.17.0)(zod@3.25.76)': + dependencies: + axios: 1.17.0 + zod: 3.25.76 + + '@zodios/core@10.9.6(axios@1.17.0)(zod@4.4.3)': + dependencies: + axios: 1.17.0 + zod: 4.4.3 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 acorn@8.16.0: {} + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ajv-draft-04@1.0.0(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -5749,6 +6979,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-colors@4.1.3: {} ansi-escapes@7.3.0: @@ -5769,6 +7006,8 @@ snapshots: ansi-styles@6.2.3: {} + ansis@4.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -5820,7 +7059,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 es-shim-unscopables: 1.1.0 array.prototype.flat@1.3.3: @@ -5861,15 +7100,17 @@ snapshots: async-function@1.0.0: {} + asynckit@0.4.0: {} + atob@2.1.2: {} - autoprefixer@10.5.0(postcss@8.5.14): + autoprefixer@10.5.0(postcss@8.5.15): dependencies: browserslist: 4.28.2 caniuse-lite: 1.0.30001792 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.14 + postcss: 8.5.15 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -5878,9 +7119,34 @@ snapshots: axe-core@4.11.4: {} + axios@1.17.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.5 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + axobject-query@4.1.0: {} - b4a@1.8.1: {} + b4a@1.8.1: {} + + babel-dead-code-elimination@1.0.12: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.3 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.29.2 + cosmiconfig: 7.1.0 + resolve: 1.22.12 babel-plugin-react-compiler@1.0.0: dependencies: @@ -5892,6 +7158,8 @@ snapshots: bare-events@2.8.2: {} + base64-js@1.5.1: {} + baseline-browser-mapping@2.10.29: {} better-path-resolve@1.0.0: @@ -5904,6 +7172,12 @@ snapshots: binary-extensions@2.3.0: {} + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + boolbase@1.0.0: {} brace-expansion@1.1.14: @@ -5923,9 +7197,9 @@ snapshots: dependencies: fill-range: 7.1.1 - breakpoint-sass@3.0.0(sass@1.99.0): + breakpoint-sass@3.0.0(sass@1.100.0): dependencies: - sass: 1.99.0 + sass: 1.100.0 browserslist@4.28.2: dependencies: @@ -5937,6 +7211,13 @@ snapshots: buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -5954,10 +7235,17 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 + call-me-maybe@1.0.2: {} + callsites@3.1.0: {} caniuse-lite@1.0.30001792: {} + canvas@3.2.3: + dependencies: + node-addon-api: 7.1.1 + prebuild-install: 7.1.3 + chai@6.2.2: {} chalk@2.4.2: @@ -5987,14 +7275,12 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - chokidar@5.0.0: dependencies: readdirp: 5.0.0 + chownr@1.1.4: {} + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -6028,6 +7314,10 @@ snapshots: color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@11.1.0: {} commander@2.20.3: {} @@ -6038,10 +7328,22 @@ snapshots: concat-map@0.0.1: {} + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} + cookie-es@3.1.1: {} + cookie@1.1.1: {} + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.3 + cpx2@8.0.2: dependencies: debounce: 3.0.0 @@ -6102,6 +7404,44 @@ snapshots: csstype@3.2.3: {} + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-ease@3.0.1: {} + + d3-format@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + damerau-levenshtein@1.0.8: {} data-urls@7.0.0: @@ -6141,10 +7481,18 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js-light@2.5.1: {} + decimal.js@10.6.0: {} decode-uri-component@0.2.2: {} + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + deep-is@0.1.4: {} define-data-property@1.1.4: @@ -6159,10 +7507,14 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + detect-indent@6.1.0: {} detect-libc@2.1.2: {} + diff@8.0.4: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -6171,6 +7523,11 @@ snapshots: dependencies: esutils: 2.0.3 + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.29.2 + csstype: 3.2.3 + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -6203,11 +7560,20 @@ snapshots: emoji-regex@9.2.2: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + enhanced-resolve@5.21.5: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 + enhanced-resolve@5.22.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 @@ -6235,7 +7601,7 @@ snapshots: data-view-byte-offset: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 function.prototype.name: 1.1.8 @@ -6309,6 +7675,10 @@ snapshots: dependencies: es-errors: 1.3.0 + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + es-set-tostringtag@2.1.0: dependencies: es-errors: 1.3.0 @@ -6658,6 +8028,10 @@ snapshots: esutils@2.0.3: {} + eval-estree-expression@3.0.1: {} + + eventemitter3@4.0.7: {} + eventemitter3@5.0.4: {} events-universal@1.0.1: @@ -6668,12 +8042,16 @@ snapshots: exenv@1.2.2: {} + expand-template@2.0.3: {} + expect-type@1.3.0: {} extendable-error@0.1.7: {} fast-deep-equal@3.1.3: {} + fast-equals@5.4.0: {} + fast-fifo@1.3.2: {} fast-glob@3.3.1: @@ -6696,6 +8074,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-uri@3.1.2: {} + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -6716,6 +8096,8 @@ snapshots: find-index@0.1.1: {} + find-root@1.1.0: {} + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -6735,10 +8117,10 @@ snapshots: flatted@3.4.2: {} - focus-trap-react@12.0.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + focus-trap-react@12.0.1(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@types/react': 19.2.15 + '@types/react-dom': 19.2.3(@types/react@19.2.15) focus-trap: 8.2.0 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) @@ -6748,12 +8130,30 @@ snapshots: dependencies: tabbable: 6.4.0 + follow-redirects@1.16.0: {} + for-each@0.3.5: dependencies: is-callable: 1.2.7 + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.3 + mime-types: 2.1.35 + fraction.js@5.3.4: {} + fs-constants@1.0.0: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + fs-extra@11.3.5: dependencies: graceful-fs: 4.2.11 @@ -6815,7 +8215,7 @@ snapshots: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 @@ -6826,7 +8226,7 @@ snapshots: get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-symbol-description@1.1.0: dependencies: @@ -6838,6 +8238,8 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + github-from-package@0.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -6880,10 +8282,23 @@ snapshots: globrex@0.1.2: {} + goober@2.1.19(csstype@3.2.3): + dependencies: + csstype: 3.2.3 + gopd@1.2.0: {} graceful-fs@4.2.11: {} + handlebars@4.7.9: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + has-bigints@1.1.0: {} has-flag@3.0.0: {} @@ -6928,6 +8343,13 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + human-id@4.1.3: {} husky@9.1.7: {} @@ -6936,6 +8358,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.5: {} @@ -6955,12 +8379,16 @@ snapshots: inherits@2.0.4: {} + ini@1.3.8: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.3 side-channel: 1.1.0 + internmap@2.0.3: {} + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.9 @@ -7093,12 +8521,14 @@ snapshots: isarray@2.0.5: {} + isbot@5.1.40: {} + isexe@2.0.0: {} iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 get-proto: 1.0.1 has-symbols: 1.1.0 @@ -7119,7 +8549,7 @@ snapshots: dependencies: argparse: 2.0.1 - jsdom@29.1.1: + jsdom@29.1.1(canvas@3.2.3): dependencies: '@asamuzakjp/css-color': 5.1.11 '@asamuzakjp/dom-selector': 7.1.1 @@ -7142,6 +8572,8 @@ snapshots: whatwg-mimetype: 5.0.0 whatwg-url: 16.0.1 xml-name-validator: 5.0.0 + optionalDependencies: + canvas: 3.2.3 transitivePeerDependencies: - '@noble/hashes' @@ -7151,8 +8583,12 @@ snapshots: json-parse-better-errors@1.0.2: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@1.0.2: @@ -7246,6 +8682,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + lines-and-columns@1.2.4: {} + lint-staged@17.0.5: dependencies: listr2: 10.2.1 @@ -7318,6 +8756,8 @@ snapshots: mdn-data@2.27.1: {} + memoize-one@6.0.0: {} + memorystream@0.3.1: {} merge-stream@2.0.0: {} @@ -7331,8 +8771,16 @@ snapshots: braces: 3.0.3 picomatch: 2.3.2 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mimic-function@5.0.1: {} + mimic-response@3.1.0: {} + minimatch@10.2.5: dependencies: brace-expansion: 5.0.6 @@ -7349,6 +8797,8 @@ snapshots: minipass@7.1.3: {} + mkdirp-classic@0.5.3: {} + mkdirp@3.0.1: {} mri@1.2.0: {} @@ -7359,11 +8809,15 @@ snapshots: nanoid@3.3.12: {} + napi-build-utils@2.0.0: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} - next@16.2.6(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.99.0): + neo-async@2.6.2: {} + + next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.100.0): dependencies: '@next/env': 16.2.6 '@swc/helpers': 0.5.15 @@ -7382,8 +8836,9 @@ snapshots: '@next/swc-linux-x64-musl': 16.2.6 '@next/swc-win32-arm64-msvc': 16.2.6 '@next/swc-win32-x64-msvc': 16.2.6 + '@playwright/test': 1.60.0 babel-plugin-react-compiler: 1.0.0 - sass: 1.99.0 + sass: 1.100.0 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' @@ -7391,8 +8846,11 @@ snapshots: nice-try@1.0.5: {} - node-addon-api@7.1.1: - optional: true + node-abi@3.92.0: + dependencies: + semver: 7.8.0 + + node-addon-api@7.1.1: {} node-exports-info@1.6.0: dependencies: @@ -7421,7 +8879,7 @@ snapshots: minimatch: 3.1.5 pidtree: 0.3.1 read-pkg: 3.0.0 - shell-quote: 1.8.3 + shell-quote: 1.8.4 string.prototype.padend: 3.1.6 nth-check@2.1.1: @@ -7443,7 +8901,7 @@ snapshots: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 has-symbols: 1.1.0 object-keys: 1.1.1 @@ -7485,10 +8943,42 @@ snapshots: rbush: 4.0.1 zarrita: 0.7.3 + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@7.0.0: dependencies: mimic-function: 5.0.1 + openapi-types@12.1.3: {} + + openapi-zod-client@1.18.3(react@19.2.6): + dependencies: + '@apidevtools/swagger-parser': 10.1.1(openapi-types@12.1.3) + '@liuli-util/fs-extra': 0.1.0 + '@zodios/core': 10.9.6(axios@1.17.0)(zod@3.25.76) + axios: 1.17.0 + cac: 6.7.14 + handlebars: 4.7.9 + openapi-types: 12.1.3 + openapi3-ts: 3.1.0 + pastable: 2.2.1(react@19.2.6) + prettier: 2.8.8 + tanu: 0.1.13 + ts-pattern: 5.9.0 + whence: 2.1.0 + zod: 3.25.76 + transitivePeerDependencies: + - debug + - react + - supports-color + - xstate + + openapi3-ts@3.1.0: + dependencies: + yaml: 2.9.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -7555,12 +9045,29 @@ snapshots: error-ex: 1.3.4 json-parse-better-errors: 1.0.2 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + parse-statements@1.0.11: {} parse5@8.0.1: dependencies: entities: 8.0.0 + pastable@2.2.1(react@19.2.6): + dependencies: + '@babel/core': 7.29.0 + ts-toolbelt: 9.6.0 + type-fest: 3.13.1 + optionalDependencies: + react: 19.2.6 + transitivePeerDependencies: + - supports-color + path-exists@4.0.0: {} path-key@2.0.1: {} @@ -7620,16 +9127,16 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-import@16.1.1(postcss@8.5.14): + postcss-import@16.1.1(postcss@8.5.15): dependencies: - postcss: 8.5.14 + postcss: 8.5.15 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.12 - postcss-nested@7.0.2(postcss@8.5.14): + postcss-nested@7.0.2(postcss@8.5.15): dependencies: - postcss: 8.5.14 + postcss: 8.5.15 postcss-selector-parser: 7.1.1 postcss-selector-parser@7.1.1: @@ -7645,6 +9152,27 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.92.0 + pump: 3.0.4 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + prelude-ls@1.2.1: {} prettier@2.8.8: {} @@ -7664,6 +9192,13 @@ snapshots: protocol-buffers-schema@3.6.1: {} + proxy-from-env@2.1.0: {} + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode@2.3.1: {} quansync@0.2.11: {} @@ -7680,6 +9215,13 @@ snapshots: dependencies: quickselect: 3.0.0 + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + react-aria@3.48.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@internationalized/date': 3.12.1 @@ -7699,6 +9241,11 @@ snapshots: react: 19.2.6 scheduler: 0.27.0 + react-flatpickr@4.0.11(react@19.2.6): + dependencies: + flatpickr: 4.6.13 + react: 19.2.6 + react-intersection-observer@10.0.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: react: 19.2.6 @@ -7707,6 +9254,8 @@ snapshots: react-is@16.13.1: {} + react-is@18.3.1: {} + react-lifecycles-compat@3.0.4: {} react-modal@3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6): @@ -7723,13 +9272,13 @@ snapshots: prop-types: 15.8.1 react: 19.2.6 - react-redux@9.3.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1): + react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.6 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@types/react': 19.2.14 + '@types/react': 19.2.15 redux: 5.0.1 react-router-dom@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): @@ -7746,6 +9295,31 @@ snapshots: optionalDependencies: react-dom: 19.2.6(react@19.2.6) + react-select@5.10.2(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/cache': 11.14.0 + '@emotion/react': 11.14.0(@types/react@19.2.15)(react@19.2.6) + '@floating-ui/dom': 1.7.6 + '@types/react-transition-group': 4.4.12(@types/react@19.2.15) + memoize-one: 6.0.0 + prop-types: 15.8.1 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-transition-group: 4.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.15)(react@19.2.6) + transitivePeerDependencies: + - '@types/react' + - supports-color + + react-smooth@4.0.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + fast-equals: 5.4.0 + prop-types: 15.8.1 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-transition-group: 4.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-stately@3.46.0(react@19.2.6): dependencies: '@internationalized/date': 3.12.1 @@ -7763,6 +9337,15 @@ snapshots: react-dom: 19.2.6(react@19.2.6) uuid: 7.0.3 + react-transition-group@4.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + '@babel/runtime': 7.29.2 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react@19.2.6: {} read-cache@1.0.0: @@ -7782,14 +9365,35 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readdirp@3.6.0: dependencies: picomatch: 2.3.2 - readdirp@4.1.2: {} - readdirp@5.0.0: {} + recharts-scale@0.4.5: + dependencies: + decimal.js-light: 2.5.1 + + recharts@2.15.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + clsx: 2.1.1 + eventemitter3: 4.0.7 + lodash: 4.18.1 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-is: 18.3.1 + react-smooth: 4.0.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.3 + victory-vendor: 36.9.2 + redux-batched-actions@0.5.0(redux@5.0.1): dependencies: redux: 5.0.1 @@ -7814,7 +9418,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 get-proto: 1.0.1 which-builtin-type: 1.2.1 @@ -7884,26 +9488,26 @@ snapshots: glob: 13.0.6 package-json-from-dist: 1.0.1 - rolldown@1.0.1: + rolldown@1.0.2: dependencies: - '@oxc-project/types': 0.130.0 + '@oxc-project/types': 0.132.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.1 - '@rolldown/binding-darwin-arm64': 1.0.1 - '@rolldown/binding-darwin-x64': 1.0.1 - '@rolldown/binding-freebsd-x64': 1.0.1 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.1 - '@rolldown/binding-linux-arm64-gnu': 1.0.1 - '@rolldown/binding-linux-arm64-musl': 1.0.1 - '@rolldown/binding-linux-ppc64-gnu': 1.0.1 - '@rolldown/binding-linux-s390x-gnu': 1.0.1 - '@rolldown/binding-linux-x64-gnu': 1.0.1 - '@rolldown/binding-linux-x64-musl': 1.0.1 - '@rolldown/binding-openharmony-arm64': 1.0.1 - '@rolldown/binding-wasm32-wasi': 1.0.1 - '@rolldown/binding-win32-arm64-msvc': 1.0.1 - '@rolldown/binding-win32-x64-msvc': 1.0.1 + '@rolldown/binding-android-arm64': 1.0.2 + '@rolldown/binding-darwin-arm64': 1.0.2 + '@rolldown/binding-darwin-x64': 1.0.2 + '@rolldown/binding-freebsd-x64': 1.0.2 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 + '@rolldown/binding-linux-arm64-gnu': 1.0.2 + '@rolldown/binding-linux-arm64-musl': 1.0.2 + '@rolldown/binding-linux-ppc64-gnu': 1.0.2 + '@rolldown/binding-linux-s390x-gnu': 1.0.2 + '@rolldown/binding-linux-x64-gnu': 1.0.2 + '@rolldown/binding-linux-x64-musl': 1.0.2 + '@rolldown/binding-openharmony-arm64': 1.0.2 + '@rolldown/binding-wasm32-wasi': 1.0.2 + '@rolldown/binding-win32-arm64-msvc': 1.0.2 + '@rolldown/binding-win32-x64-msvc': 1.0.2 run-parallel@1.2.0: dependencies: @@ -7932,9 +9536,9 @@ snapshots: safer-buffer@2.1.2: {} - sass@1.99.0: + sass@1.100.0: dependencies: - chokidar: 4.0.3 + chokidar: 5.0.0 immutable: 5.1.5 source-map-js: 1.2.1 optionalDependencies: @@ -7954,6 +9558,12 @@ snapshots: semver@7.8.0: {} + seroval-plugins@1.5.4(seroval@1.5.4): + dependencies: + seroval: 1.5.4 + + seroval@1.5.4: {} + set-cookie-parser@2.7.2: {} set-function-length@1.2.2: @@ -7976,7 +9586,7 @@ snapshots: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 sharp@0.34.5: dependencies: @@ -8023,6 +9633,8 @@ snapshots: shell-quote@1.8.3: {} + shell-quote@1.8.4: {} + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 @@ -8055,6 +9667,14 @@ snapshots: signal-exit@4.1.0: {} + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + slash@3.0.0: {} slice-ansi@7.1.2: @@ -8079,6 +9699,8 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map@0.5.7: {} + source-map@0.6.1: {} spawndamnit@3.0.1: @@ -8164,7 +9786,7 @@ snapshots: call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 string.prototype.repeat@1.0.0: dependencies: @@ -8178,7 +9800,7 @@ snapshots: define-data-property: 1.1.4 define-properties: 1.2.1 es-abstract: 1.24.2 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 has-property-descriptors: 1.0.2 string.prototype.trimend@1.0.9: @@ -8186,13 +9808,17 @@ snapshots: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.9 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 strip-ansi@6.0.1: dependencies: @@ -8204,6 +9830,8 @@ snapshots: strip-bom@3.0.0: {} + strip-json-comments@2.0.1: {} + strip-json-comments@3.1.1: {} styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.6): @@ -8213,6 +9841,8 @@ snapshots: optionalDependencies: '@babel/core': 7.29.0 + stylis@4.2.0: {} + subarg@1.0.0: dependencies: minimist: 1.2.8 @@ -8276,10 +9906,32 @@ snapshots: tabbable@6.4.0: {} + tailwind-merge@3.6.0: {} + tailwindcss@4.3.0: {} + tanu@0.1.13: + dependencies: + tslib: 2.8.1 + typescript: 4.9.5 + tapable@2.3.3: {} + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + teex@1.0.1: dependencies: streamx: 2.25.0 @@ -8302,6 +9954,8 @@ snapshots: transitivePeerDependencies: - react-native-b4a + tiny-invariant@1.3.3: {} + tinybench@2.9.0: {} tinyexec@1.1.2: {} @@ -8335,6 +9989,10 @@ snapshots: dependencies: typescript: 6.0.3 + ts-pattern@5.9.0: {} + + ts-toolbelt@9.6.0: {} + tsc-alias@1.8.17: dependencies: chokidar: 3.6.0 @@ -8354,6 +10012,10 @@ snapshots: tslib@2.8.1: {} + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + turbo@2.9.14: optionalDependencies: '@turbo/darwin-64': 2.9.14 @@ -8367,6 +10029,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@3.13.1: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -8411,8 +10075,13 @@ snapshots: transitivePeerDependencies: - supports-color + typescript@4.9.5: {} + typescript@6.0.3: {} + uglify-js@3.19.3: + optional: true + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -8430,6 +10099,12 @@ snapshots: universalify@2.0.1: {} + unplugin@3.0.0: + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.4 + webpack-virtual-modules: 0.6.2 + unrs-resolver@1.12.2: dependencies: napi-postinstall: 0.3.4 @@ -8469,6 +10144,12 @@ snapshots: dependencies: punycode: 2.3.1 + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.15)(react@19.2.6): + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.15 + use-sync-external-store@1.6.0(react@19.2.6): dependencies: react: 19.2.6 @@ -8482,6 +10163,23 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + victory-vendor@36.9.2: + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + vinyl@3.0.1: dependencies: clone: 2.1.2 @@ -8492,25 +10190,30 @@ snapshots: - bare-abort-controller - react-native-b4a - vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0): + vite-plugin-handlebars@2.0.3(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)): + dependencies: + handlebars: 4.7.9 + vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + + vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.14 - rolldown: 1.0.1 + postcss: 8.5.15 + rolldown: 1.0.2 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 24.12.4 fsevents: 2.3.3 jiti: 2.7.0 - sass: 1.99.0 + sass: 1.100.0 terser: 5.47.1 yaml: 2.9.0 - vitest@4.1.6(@types/node@24.12.4)(jsdom@29.1.1)(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)): + vitest@4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.6 - '@vitest/mocker': 4.1.6(vite@8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)) + '@vitest/mocker': 4.1.6(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.6 '@vitest/runner': 4.1.6 '@vitest/snapshot': 4.1.6 @@ -8527,11 +10230,11 @@ snapshots: tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.13(@types/node@24.12.4)(jiti@2.7.0)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.12.4 - jsdom: 29.1.1 + jsdom: 29.1.1(canvas@3.2.3) transitivePeerDependencies: - msw @@ -8547,6 +10250,8 @@ snapshots: webidl-conversions@8.0.1: {} + webpack-virtual-modules@0.6.2: {} + whatwg-mimetype@5.0.0: {} whatwg-url@16.0.1: @@ -8557,6 +10262,11 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + whence@2.1.0: + dependencies: + '@babel/parser': 7.29.3 + eval-estree-expression: 3.0.1 + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -8615,6 +10325,8 @@ snapshots: word-wrap@1.2.5: {} + wordwrap@1.0.0: {} + wrap-ansi@10.0.0: dependencies: ansi-styles: 6.2.3 @@ -8627,6 +10339,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.2.0 + wrappy@1.0.2: {} + xml-name-validator@5.0.0: {} xml-utils@1.10.2: {} @@ -8637,8 +10351,9 @@ snapshots: yallist@3.1.1: {} - yaml@2.9.0: - optional: true + yaml@1.10.3: {} + + yaml@2.9.0: {} yargs-parser@22.0.0: {} @@ -8662,6 +10377,8 @@ snapshots: dependencies: zod: 4.4.3 + zod@3.25.76: {} + zod@4.4.3: {} zstddec@0.2.0: {} From 66519f7a6c1bcd0feee78dd3a3101eef9012469f Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 11 Jun 2026 15:44:11 +0200 Subject: [PATCH 46/49] update changesets Signed-off-by: Paul Golmann --- .changeset/composable-runtime-icons.md | 2 +- .changeset/config-schema-validation.md | 6 ++++++ .changeset/embed-exports.md | 5 +++++ .changeset/empty-years-sleep.md | 8 ++++++++ .changeset/feature-interaction-fixes.md | 5 +++++ .changeset/shallow-equal-records.md | 5 +++++ .changeset/vsc-compiler-fixes.md | 5 +++++ 7 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 .changeset/config-schema-validation.md create mode 100644 .changeset/embed-exports.md create mode 100644 .changeset/empty-years-sleep.md create mode 100644 .changeset/feature-interaction-fixes.md create mode 100644 .changeset/shallow-equal-records.md create mode 100644 .changeset/vsc-compiler-fixes.md diff --git a/.changeset/composable-runtime-icons.md b/.changeset/composable-runtime-icons.md index 1386587f..fcd8f9c7 100644 --- a/.changeset/composable-runtime-icons.md +++ b/.changeset/composable-runtime-icons.md @@ -5,4 +5,4 @@ "@mapsight/ui": minor --- -Add composable runtime icons: pictogram-based templates and `mapsightIconId` parsing in traffic-style, async rasterization with volatile style-cache invalidation in lib-ol and vector-style-compiler, plus `useMapsightIcon` and a runtime icon style plugin in ui. +Add composable runtime icons: pictogram-based templates and `mapsightIconId` parsing in traffic-style (with configurable default xsmall/small icon zoom levels), async rasterization with volatile style-cache invalidation in lib-ol and vector-style-compiler, plus `useMapsightIcon` and a runtime icon style plugin in ui. diff --git a/.changeset/config-schema-validation.md b/.changeset/config-schema-validation.md new file mode 100644 index 00000000..78318d83 --- /dev/null +++ b/.changeset/config-schema-validation.md @@ -0,0 +1,6 @@ +--- +"@mapsight/core": minor +"@mapsight/ui": minor +--- + +Add Zod-based Mapsight config validation: core exports `createMapsightConfigSchema`, `validateConfig`, and per-domain schemas for map, layers, feature sources, and filters; ui validates config on startup (warn in development, optional strict mode in production). diff --git a/.changeset/embed-exports.md b/.changeset/embed-exports.md new file mode 100644 index 00000000..cde6cef9 --- /dev/null +++ b/.changeset/embed-exports.md @@ -0,0 +1,5 @@ +--- +"@mapsight/ui": patch +--- + +Add `@mapsight/ui/embed/*` package exports for embed entry points. diff --git a/.changeset/empty-years-sleep.md b/.changeset/empty-years-sleep.md new file mode 100644 index 00000000..c21777a0 --- /dev/null +++ b/.changeset/empty-years-sleep.md @@ -0,0 +1,8 @@ +--- +"@mapsight/vector-editor": minor +"@mapsight/lib-redux": minor +"@mapsight/core": minor +"@mapsight/ui": minor +--- + +Migrate to Redux Toolkit 2, Redux 5, react-redux 9, and reselect 5; replace `createStructuredSelector` usage, prefer `@reduxjs/toolkit` exports, and update the vector-editor browser renderer to React 18 `createRoot`. diff --git a/.changeset/feature-interaction-fixes.md b/.changeset/feature-interaction-fixes.md new file mode 100644 index 00000000..daac29fe --- /dev/null +++ b/.changeset/feature-interaction-fixes.md @@ -0,0 +1,5 @@ +--- +"@mapsight/core": patch +--- + +Fix feature highlight race conditions, export `FeatureInteractionNames`, add optional `compare` to `BaseController.getAndObserveUncontrolled`, and mark noisy OpenLayers feedback dispatches with `quiet()`. diff --git a/.changeset/shallow-equal-records.md b/.changeset/shallow-equal-records.md new file mode 100644 index 00000000..b5ed1ac5 --- /dev/null +++ b/.changeset/shallow-equal-records.md @@ -0,0 +1,5 @@ +--- +"@mapsight/lib-js": patch +--- + +Add `shallowEqualRecords` utility for shallow comparison of string-keyed records. diff --git a/.changeset/vsc-compiler-fixes.md b/.changeset/vsc-compiler-fixes.md new file mode 100644 index 00000000..cc011b06 --- /dev/null +++ b/.changeset/vsc-compiler-fixes.md @@ -0,0 +1,5 @@ +--- +"@mapsight/vector-style-compiler": patch +--- + +Fix nested function codegen and style-tree state assignment in compiled output. From 67972a518f883292509e919d88cfd8f2e819c28e Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 11 Jun 2026 15:51:55 +0200 Subject: [PATCH 47/49] update deps Signed-off-by: Paul Golmann --- package.json | 12 +- pnpm-lock.yaml | 2561 +++++++++++-------------------------------- pnpm-workspace.yaml | 2 +- 3 files changed, 676 insertions(+), 1899 deletions(-) diff --git a/package.json b/package.json index f2cdca52..213ede39 100644 --- a/package.json +++ b/package.json @@ -10,25 +10,25 @@ "@types/node": "catalog:", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", - "eslint-import-resolver-typescript": "^4.4.4", + "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-import-x": "^4.16.2", "eslint-plugin-jsx-a11y": "^6.10.2", - "eslint-plugin-n": "^18.0.1", + "eslint-plugin-n": "^18.1.0", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.1.1", "globals": "^17.6.0", "husky": "^9.1.7", "jiti": "^2.7.0", - "lint-staged": "^17.0.5", + "lint-staged": "^17.0.7", "mkdirp": "^3.0.1", "npm-run-all": "^4.1.5", "playwright": "catalog:", - "prettier": "^3.8.3", + "prettier": "^3.8.4", "rimraf": "^6.1.3", "syncpack": "^15.3.1", - "turbo": "^2.9.14", + "turbo": "^2.9.17", "typescript": "catalog:", - "typescript-eslint": "^8.59.4" + "typescript-eslint": "^8.61.0" }, "engines": { "node": "^24.15.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db9b99dc..52f7d040 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,11 +19,11 @@ catalogs: specifier: ^4.17.24 version: 4.17.24 '@types/node': - specifier: ^24.12.4 - version: 24.12.4 + specifier: ^24.13.1 + version: 24.13.1 '@types/react': specifier: ^19.2.15 - version: 19.2.15 + version: 19.2.17 '@types/react-dom': specifier: ^19.2.3 version: 19.2.3 @@ -91,13 +91,13 @@ importers: devDependencies: '@changesets/cli': specifier: ^2.31.0 - version: 2.31.0(@types/node@24.12.4) + version: 2.31.0(@types/node@24.13.1) '@eslint/js': specifier: ^9.39.4 version: 9.39.4 '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.2 - version: 6.0.2(prettier@3.8.3) + version: 6.0.2(prettier@3.8.4) '@types/eslint-plugin-jsx-a11y': specifier: ^6.10.1 version: 6.10.1(jiti@2.7.0) @@ -106,7 +106,7 @@ importers: version: 7946.0.16 '@types/node': specifier: 'catalog:' - version: 24.12.4 + version: 24.13.1 eslint: specifier: ^9.39.4 version: 9.39.4(jiti@2.7.0) @@ -114,17 +114,17 @@ importers: specifier: ^10.1.8 version: 10.1.8(eslint@9.39.4(jiti@2.7.0)) eslint-import-resolver-typescript: - specifier: ^4.4.4 - version: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + specifier: ^4.4.5 + version: 4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-import-x: specifier: ^4.16.2 - version: 4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)) + version: 4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-jsx-a11y: specifier: ^6.10.2 version: 6.10.2(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-n: - specifier: ^18.0.1 - version: 18.0.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + specifier: ^18.1.0 + version: 18.1.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) eslint-plugin-react: specifier: ^7.37.5 version: 7.37.5(eslint@9.39.4(jiti@2.7.0)) @@ -141,8 +141,8 @@ importers: specifier: ^2.7.0 version: 2.7.0 lint-staged: - specifier: ^17.0.5 - version: 17.0.5 + specifier: ^17.0.7 + version: 17.0.7 mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -153,8 +153,8 @@ importers: specifier: 'catalog:' version: 1.60.0 prettier: - specifier: ^3.8.3 - version: 3.8.3 + specifier: ^3.8.4 + version: 3.8.4 rimraf: specifier: ^6.1.3 version: 6.1.3 @@ -162,123 +162,14 @@ importers: specifier: ^15.3.1 version: 15.3.1 turbo: - specifier: ^2.9.14 - version: 2.9.14 + specifier: ^2.9.17 + version: 2.9.17 typescript: specifier: 'catalog:' version: 6.0.3 typescript-eslint: - specifier: ^8.59.4 - version: 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - - apps/braunschweig: - dependencies: - '@mapsight/core': - specifier: workspace:^ - version: link:../../packages/core - '@mapsight/lib-js': - specifier: workspace:^ - version: link:../../packages/lib-js - '@mapsight/lib-ol': - specifier: workspace:^ - version: link:../../packages/lib-ol - '@mapsight/lib-redux': - specifier: workspace:^ - version: link:../../packages/lib-redux - '@mapsight/traffic-style': - specifier: workspace:^ - version: link:../../packages/traffic-style/dist - '@mapsight/ui': - specifier: workspace:^ - version: link:../../packages/ui - '@tanstack/react-router': - specifier: ^1.170.8 - version: 1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tanstack/react-router-devtools': - specifier: ^1.167.0 - version: 1.167.0(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.171.6)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - breakpoint-sass: - specifier: ^3.0.0 - version: 3.0.0(sass@1.100.0) - hint.css: - specifier: ^3.0.0 - version: 3.0.0 - lodash: - specifier: 'catalog:' - version: 4.18.1 - ol: - specifier: 'catalog:' - version: 10.9.0 - proj4: - specifier: 'catalog:' - version: 2.20.8 - react: - specifier: 'catalog:' - version: 19.2.6 - react-dom: - specifier: 'catalog:' - version: 19.2.6(react@19.2.6) - react-modal: - specifier: ^3.16.3 - version: 3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-redux: - specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) - devDependencies: - '@mapsight/vector-style-compiler': - specifier: workspace:^ - version: link:../../packages/vector-style-compiler - '@tailwindcss/vite': - specifier: ^4.3.0 - version: 4.3.0(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) - '@tanstack/router-plugin': - specifier: ^1.168.11 - version: 1.168.11(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) - '@types/geojson': - specifier: ^7946.0.16 - version: 7946.0.16 - '@types/lodash': - specifier: 'catalog:' - version: 4.17.24 - '@types/node': - specifier: 'catalog:' - version: 24.12.4 - '@types/react': - specifier: 'catalog:' - version: 19.2.15 - '@types/react-dom': - specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.15) - '@types/react-modal': - specifier: ^3.16.3 - version: 3.16.3 - '@vitejs/plugin-react': - specifier: ^6.0.2 - version: 6.0.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) - npm-run-all: - specifier: ^4.1.5 - version: 4.1.5 - sass: - specifier: ^1.100.0 - version: 1.100.0 - tailwindcss: - specifier: 'catalog:' - version: 4.3.0 - tinyglobby: - specifier: ^0.2.16 - version: 0.2.16 - typescript: - specifier: 'catalog:' - version: 6.0.3 - undici: - specifier: ^7.25.0 - version: 7.25.0 - vite: - specifier: ^8.0.14 - version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) - vite-plugin-handlebars: - specifier: ^2.0.3 - version: 2.0.3(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + specifier: ^8.61.0 + version: 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) apps/demo-next: dependencies: @@ -299,7 +190,7 @@ importers: version: link:../../packages/ui next: specifier: ^16.2.6 - version: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.100.0) + version: 16.2.6(@babel/core@7.29.7)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.100.0) ol: specifier: 'catalog:' version: 10.9.0 @@ -321,19 +212,19 @@ importers: version: 4.3.0 '@types/node': specifier: 'catalog:' - version: 24.12.4 + version: 24.13.1 '@types/react': specifier: 'catalog:' - version: 19.2.15 + version: 19.2.17 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.15) + version: 19.2.3(@types/react@19.2.17) babel-plugin-react-compiler: specifier: 1.0.0 version: 1.0.0 eslint-config-next: specifier: 16.2.6 - version: 16.2.6(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + version: 16.2.6(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) postcss: specifier: ^8.5.14 version: 8.5.14 @@ -381,10 +272,10 @@ importers: version: 19.2.6(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) + version: 9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1) react-router-dom: specifier: ^7.15.0 - version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) reselect: specifier: 'catalog:' version: 5.2.0 @@ -397,16 +288,16 @@ importers: version: link:../../packages/vector-style-compiler '@tailwindcss/vite': specifier: ^4.3.0 - version: 4.3.0(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.3.0(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) '@types/node': specifier: 'catalog:' - version: 24.12.4 + version: 24.13.1 '@types/react': specifier: 'catalog:' - version: 19.2.15 + version: 19.2.17 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.15) + version: 19.2.3(@types/react@19.2.17) mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -418,13 +309,13 @@ importers: version: 6.1.3 terser: specifier: ^5.47.1 - version: 5.47.1 + version: 5.48.0 typescript: specifier: 'catalog:' version: 6.0.3 vite: specifier: ^8.0.14 - version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + version: 8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) apps/vector-editor: dependencies: @@ -445,7 +336,7 @@ importers: version: link:../../packages/traffic-style/dist '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1))(react@19.2.6) date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -466,7 +357,7 @@ importers: version: 3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) + version: 9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1) react-tooltip: specifier: ^4.5.1 version: 4.5.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -494,10 +385,10 @@ importers: version: 3.5.6 '@types/react': specifier: 'catalog:' - version: 19.2.15 + version: 19.2.17 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.15) + version: 19.2.3(@types/react@19.2.17) '@types/react-modal': specifier: ^3.16.3 version: 3.16.3 @@ -515,7 +406,7 @@ importers: version: 7.0.2(postcss@8.5.15) vite: specifier: ^8.0.14 - version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + version: 8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) packages/core: dependencies: @@ -530,7 +421,7 @@ importers: version: link:../lib-redux '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1))(react@19.2.6) eventemitter3: specifier: ^5.0.4 version: 5.0.4 @@ -564,7 +455,7 @@ importers: version: 4.17.24 '@types/node': specifier: 'catalog:' - version: 24.12.4 + version: 24.13.1 canvas: specifier: 'catalog:' version: 3.2.3 @@ -588,90 +479,16 @@ importers: version: 6.0.3 vite: specifier: ^8.0.14 - version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) - vitest: - specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) - - packages/count-aggregator-api: - dependencies: - '@zodios/core': - specifier: ^10.9.6 - version: 10.9.6(axios@1.17.0)(zod@4.4.3) - zod: - specifier: 'catalog:' - version: 4.4.3 - devDependencies: - npm-run-all: - specifier: ^4.1.5 - version: 4.1.5 - openapi-zod-client: - specifier: ^1.18.3 - version: 1.18.3(react@19.2.6) - rimraf: - specifier: ^6.1.3 - version: 6.1.3 - typescript: - specifier: 'catalog:' - version: 6.0.3 - vitest: - specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) - - packages/count-aggregator-ui: - dependencies: - clsx: - specifier: ^2.1.1 - version: 2.1.1 - flatpickr: - specifier: ^4.6.13 - version: 4.6.13 - react-flatpickr: - specifier: ^4.0.11 - version: 4.0.11(react@19.2.6) - recharts: - specifier: ^2.15.4 - version: 2.15.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - tailwind-merge: - specifier: ^3.3.1 - version: 3.6.0 - devDependencies: - '@tanstack/react-query': - specifier: ^5.90.5 - version: 5.101.0(react@19.2.6) - '@types/react': - specifier: 'catalog:' - version: 19.2.15 - '@types/react-dom': - specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.15) - '@types/react-flatpickr': - specifier: ^3.8.11 - version: 3.8.11 - axios: - specifier: ^1.16.1 - version: 1.17.0 - react: - specifier: 'catalog:' - version: 19.2.6 - react-dom: - specifier: 'catalog:' - version: 19.2.6(react@19.2.6) - react-select: - specifier: ^5.10.2 - version: 5.10.2(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - typescript: - specifier: 'catalog:' - version: 6.0.3 + version: 8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@24.13.1)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) packages/lib-js: devDependencies: '@changesets/cli': specifier: ^2.31.0 - version: 2.31.0(@types/node@24.12.4) + version: 2.31.0(@types/node@25.9.2) '@types/modernizr': specifier: ^3.5.6 version: 3.5.6 @@ -683,7 +500,7 @@ importers: version: 4.1.5 vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.9.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) packages/lib-ol: dependencies: @@ -711,7 +528,7 @@ importers: version: link:../lib-js '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@types/lodash': specifier: 'catalog:' version: 4.17.24 @@ -773,13 +590,13 @@ importers: version: 2.0.0 '@types/node': specifier: 'catalog:' - version: 24.12.4 + version: 24.13.1 markdown-table: specifier: ^2.0.0 version: 2.0.0 vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@24.13.1)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) publishDirectory: dist packages/ui: @@ -801,7 +618,7 @@ importers: version: link:../traffic-style/dist '@reduxjs/toolkit': specifier: 'catalog:' - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@types/react-redux': specifier: 'catalog:' version: 7.1.34 @@ -813,7 +630,7 @@ importers: version: 4.6.13 focus-trap-react: specifier: ^12.0.1 - version: 12.0.1(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 12.0.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) hint.css: specifier: ^3.0.0 version: 3.0.0 @@ -843,7 +660,7 @@ importers: version: 8.3.0(react@19.2.6) react-redux: specifier: 'catalog:' - version: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) + version: 9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1) redux-batched-actions: specifier: 'catalog:' version: 0.5.0(redux@5.0.1) @@ -859,10 +676,10 @@ importers: version: 4.17.24 '@types/react': specifier: 'catalog:' - version: 19.2.15 + version: 19.2.17 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.15) + version: 19.2.3(@types/react@19.2.17) '@types/react-modal': specifier: ^3.16.3 version: 3.16.3 @@ -880,7 +697,7 @@ importers: version: 4.0.1 vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.9.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) packages/vector-style-compiler: dependencies: @@ -895,7 +712,7 @@ importers: version: 4.17.24 '@types/node': specifier: 'catalog:' - version: 24.12.4 + version: 24.13.1 css: specifier: ^3.0.0 version: 3.0.0 @@ -944,10 +761,10 @@ importers: version: 1.100.0 vite: specifier: ^8.0.14 - version: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + version: 8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) vitest: specifier: 'catalog:' - version: 4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + version: 4.1.6(@types/node@24.13.1)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) packages: @@ -955,22 +772,6 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@apidevtools/json-schema-ref-parser@11.7.2': - resolution: {integrity: sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==} - engines: {node: '>= 16'} - - '@apidevtools/openapi-schemas@2.1.0': - resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==} - engines: {node: '>=10'} - - '@apidevtools/swagger-methods@3.0.2': - resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} - - '@apidevtools/swagger-parser@10.1.1': - resolution: {integrity: sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==} - peerDependencies: - openapi-types: '>=7' - '@asamuzakjp/css-color@5.1.11': resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -986,93 +787,93 @@ packages: '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.3': - resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.28.6': - resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true '@babel/runtime@7.29.2': resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} engines: {node: '>=6.9.0'} '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + '@bramus/specificity@2.4.2': resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true @@ -1177,47 +978,6 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@emotion/babel-plugin@11.13.5': - resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} - - '@emotion/cache@11.14.0': - resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} - - '@emotion/hash@0.9.2': - resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - - '@emotion/memoize@0.9.0': - resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - - '@emotion/react@11.14.0': - resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} - peerDependencies: - '@types/react': '*' - react: '>=16.8.0' - peerDependenciesMeta: - '@types/react': - optional: true - - '@emotion/serialize@1.3.3': - resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} - - '@emotion/sheet@1.4.0': - resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} - - '@emotion/unitless@0.10.0': - resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} - - '@emotion/use-insertion-effect-with-fallbacks@1.2.0': - resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} - peerDependencies: - react: '>=16.8.0' - - '@emotion/utils@1.4.2': - resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} - - '@emotion/weak-memoize@0.4.0': - resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1265,15 +1025,6 @@ packages: '@noble/hashes': optional: true - '@floating-ui/core@1.7.5': - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - - '@floating-ui/dom@1.7.6': - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - - '@floating-ui/utils@0.2.11': - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@fortawesome/fontawesome-common-types@6.7.2': resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==} engines: {node: '>=6'} @@ -1492,12 +1243,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@jsdevtools/ono@7.1.3': - resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} - - '@liuli-util/fs-extra@0.1.0': - resolution: {integrity: sha512-eaAyDyMGT23QuRGbITVY3SOJff3G9ekAAyGqB9joAnTBmqvFN+9a1FazOdO70G6IUqgpKV451eBHYSRcOJ/FNQ==} - '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -1510,6 +1255,12 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@next/env@16.2.6': resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} @@ -1584,8 +1335,8 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@oxc-project/types@0.132.0': - resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} '@package-json/types@0.0.12': resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==} @@ -1707,97 +1458,97 @@ packages: react-redux: optional: true - '@rolldown/binding-android-arm64@1.0.2': - resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.2': - resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.2': - resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.2': - resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.2': - resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.2': - resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.2': - resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.2': - resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.2': - resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.2': - resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.2': - resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.2': - resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.2': - resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.2': - resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.2': - resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1917,93 +1668,6 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/history@1.162.0': - resolution: {integrity: sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==} - engines: {node: '>=20.19'} - - '@tanstack/query-core@5.101.0': - resolution: {integrity: sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==} - - '@tanstack/react-query@5.101.0': - resolution: {integrity: sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg==} - peerDependencies: - react: ^18 || ^19 - - '@tanstack/react-router-devtools@1.167.0': - resolution: {integrity: sha512-nGw095EG7IHx0h5NtlEmzf6vcCTaFNPWdTSuDKazajhN0ct/v/TkekJ9J6KYUCeV1a8/2ZmToc58M+0rrOyn7w==} - engines: {node: '>=20.19'} - peerDependencies: - '@tanstack/react-router': ^1.170.0 - '@tanstack/router-core': ^1.170.0 - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - peerDependenciesMeta: - '@tanstack/router-core': - optional: true - - '@tanstack/react-router@1.170.8': - resolution: {integrity: sha512-Qw2ju6jjnIsMpuW+VrnHZWHuugqs592PWsnI56sG28qNhg14CgRLahOcNajfuJR9P4MxKGP94WVzmFKSYUz/ig==} - engines: {node: '>=20.19'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - - '@tanstack/react-store@0.9.3': - resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - '@tanstack/router-core@1.171.6': - resolution: {integrity: sha512-Ol6DQ+j6rf/rPVELIzo8LHwOQV2KL+zry3b+39kL/GKrt7YId52WJRAFMzuseY4XceSW+PU7sG/Cc1QkwJr0hg==} - engines: {node: '>=20.19'} - - '@tanstack/router-devtools-core@1.168.0': - resolution: {integrity: sha512-wQoQhlBK7nlZgqzaqdYXKWNTpdHdsaREdaPhFZVH0/Ador+F+eM3/NF2i3f2LPeS0GgKraZUQXe1Q/1+KHyEYg==} - engines: {node: '>=20.19'} - peerDependencies: - '@tanstack/router-core': ^1.170.0 - csstype: ^3.0.10 - peerDependenciesMeta: - csstype: - optional: true - - '@tanstack/router-generator@1.167.10': - resolution: {integrity: sha512-CjbjWRSo6djLU/C7ncb9IbKUcf4IwpdqhLGngkwKkXaVFXGxEAafA/uhvOCv/UEUVR7NI3tJqqQmxYXGcJPbjw==} - engines: {node: '>=20.19'} - - '@tanstack/router-plugin@1.168.11': - resolution: {integrity: sha512-b2eom/8xCWL/OiWxKub8kYsr8p+kvmB/eXwYGqCWG8vilcJo+eQCSyp54nKt0AZ5k/ET1+eINc+4mwL3bVeAgg==} - engines: {node: '>=20.19'} - peerDependencies: - '@rsbuild/core': '>=1.0.2 || ^2.0.0' - '@tanstack/react-router': ^1.170.8 - vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' - vite-plugin-solid: ^2.11.10 || ^3.0.0-0 - webpack: '>=5.92.0' - peerDependenciesMeta: - '@rsbuild/core': - optional: true - '@tanstack/react-router': - optional: true - vite: - optional: true - vite-plugin-solid: - optional: true - webpack: - optional: true - - '@tanstack/router-utils@1.162.1': - resolution: {integrity: sha512-62layyTGmclHDQS/eidwKRfN1hhCKwViG7iEBcVmL0MXgcAB3OOucWCEcDDGd9Cu11H6b4QQ5oOo47MWIqwz0A==} - engines: {node: '>=20.19'} - - '@tanstack/store@0.9.3': - resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} - - '@tanstack/virtual-file-routes@1.162.0': - resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} - engines: {node: '>=20.19'} - '@trivago/prettier-plugin-sort-imports@6.0.2': resolution: {integrity: sha512-3DgfkukFyC/sE/VuYjaUUWoFfuVjPK55vOFDsxD56XXynFMCZDYFogH2l/hDfOsQAm1myoU/1xByJ3tWqtulXA==} engines: {node: '>= 20'} @@ -2023,33 +1687,33 @@ packages: svelte: optional: true - '@turbo/darwin-64@2.9.14': - resolution: {integrity: sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==} + '@turbo/darwin-64@2.9.17': + resolution: {integrity: sha512-io5jn5RDeU+9YV78rWhwG++HD/OZ/Lxg1sg93+jDGKQNP3UDxY6RX2dmarbCILhNxNuAM8FH3WgGMY9E96Mf8w==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.14': - resolution: {integrity: sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw==} + '@turbo/darwin-arm64@2.9.17': + resolution: {integrity: sha512-83YZTYmN2sxFWf2LTMOwqbOvR3qZMa/TSFwnB6BHVBbIWyoPPe+TAdSTd8KevEx8ml8KkycJ/9A70DFVReyUww==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.14': - resolution: {integrity: sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA==} + '@turbo/linux-64@2.9.17': + resolution: {integrity: sha512-teKfwJg0zSC+C2ZSOsX3VnAJGVgcN+pgKNmnGWzcpXQ9eIkAQtYP+getrQ2f1Tw/ePudnreQhq8tVP8S73Vy6Q==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.9.14': - resolution: {integrity: sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g==} + '@turbo/linux-arm64@2.9.17': + resolution: {integrity: sha512-mqO36x2CNtJ9CCbEf5xOqH662tVSc1wB0mxh7dopBpgXg0fEifdzwX0IEAUW1WUAaNH986L7iEUUgw3HNqUWgg==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.9.14': - resolution: {integrity: sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A==} + '@turbo/windows-64@2.9.17': + resolution: {integrity: sha512-jbyoNePufyMoSSrvVr+/mglcjmya/MOgoIrSHPr67iZ1VFgrlMQXHXtptR2lR48gi+86b1XBvsviJZ9A7zrydg==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.14': - resolution: {integrity: sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g==} + '@turbo/windows-arm64@2.9.17': + resolution: {integrity: sha512-+ql0wYc99Y2AMvyHCcC/P+xtyV4nz522L+C9HDnyi7ryHXBGM+ZjBP28M7SLBGMDImgpN8sk2szpgbvreMeXVA==} cpu: [arm64] os: [win32] @@ -2062,33 +1726,6 @@ packages: '@types/css@0.0.38': resolution: {integrity: sha512-FsAy4pBnrJb8qdKmIyDy582o4Xt8pHwpCwYRmIvXw4dslA7C4436oOM+8XNnMEsV/LSculbFNaZsBZmycDjARw==} - '@types/d3-array@3.2.2': - resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} - - '@types/d3-color@3.1.3': - resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} - - '@types/d3-ease@3.0.2': - resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} - - '@types/d3-interpolate@3.0.4': - resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} - - '@types/d3-path@3.1.1': - resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} - - '@types/d3-scale@4.0.9': - resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} - - '@types/d3-shape@3.1.8': - resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} - - '@types/d3-time@3.0.4': - resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} - - '@types/d3-timer@3.0.2': - resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -2101,9 +1738,6 @@ packages: '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - '@types/fs-extra@9.0.13': - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} - '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} @@ -2136,11 +1770,11 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@24.12.4': - resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} + '@types/node@24.13.1': + resolution: {integrity: sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==} - '@types/parse-json@4.0.2': - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/node@25.9.2': + resolution: {integrity: sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==} '@types/pidusage@2.0.5': resolution: {integrity: sha512-MIiyZI4/MK9UGUXWt0jJcCZhVw7YdhBuTOuqP/BjuLDLZ2PmmViMIQgZiWxtaMicQfAz/kMrZ5T7PKxFSkTeUA==} @@ -2153,22 +1787,17 @@ packages: peerDependencies: '@types/react': ^19.2.0 - '@types/react-flatpickr@3.8.11': - resolution: {integrity: sha512-wXGyGRpUjiGknioxWzWJdNvF2XxKw5lAI7H64Iv7w4iL+1iT7QvAzrigz5FkW4lTg9IJOww6t7g21FzsrmRV6A==} - '@types/react-modal@3.16.3': resolution: {integrity: sha512-xXuGavyEGaFQDgBv4UVm8/ZsG+qxeQ7f77yNrW3n+1J6XAstUy5rYHeIHPh1KzsGc6IkCIdu6lQ2xWzu1jBTLg==} '@types/react-redux@7.1.34': resolution: {integrity: sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==} - '@types/react-transition-group@4.4.12': - resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} - peerDependencies: - '@types/react': '*' + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@types/react@19.2.15': - resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -2176,63 +1805,63 @@ packages: '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} - '@typescript-eslint/eslint-plugin@8.59.4': - resolution: {integrity: sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==} + '@typescript-eslint/eslint-plugin@8.61.0': + resolution: {integrity: sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.59.4 + '@typescript-eslint/parser': ^8.61.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.59.4': - resolution: {integrity: sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==} + '@typescript-eslint/parser@8.61.0': + resolution: {integrity: sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.59.4': - resolution: {integrity: sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==} + '@typescript-eslint/project-service@8.61.0': + resolution: {integrity: sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.59.4': - resolution: {integrity: sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==} + '@typescript-eslint/scope-manager@8.61.0': + resolution: {integrity: sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.59.4': - resolution: {integrity: sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==} + '@typescript-eslint/tsconfig-utils@8.61.0': + resolution: {integrity: sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.59.4': - resolution: {integrity: sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==} + '@typescript-eslint/type-utils@8.61.0': + resolution: {integrity: sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.59.4': - resolution: {integrity: sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==} + '@typescript-eslint/types@8.61.0': + resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.59.4': - resolution: {integrity: sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==} + '@typescript-eslint/typescript-estree@8.61.0': + resolution: {integrity: sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.59.4': - resolution: {integrity: sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==} + '@typescript-eslint/utils@8.61.0': + resolution: {integrity: sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.59.4': - resolution: {integrity: sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==} + '@typescript-eslint/visitor-keys@8.61.0': + resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.12.2': @@ -2355,19 +1984,6 @@ packages: cpu: [x64] os: [win32] - '@vitejs/plugin-react@6.0.2': - resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@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 - '@vitest/expect@4.1.6': resolution: {integrity: sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==} @@ -2400,12 +2016,6 @@ packages: '@zarrita/storage@0.2.0': resolution: {integrity: sha512-855ZXqtnds7spnT8vNvD+MXa3QExP1m2GqShe8yt7uZXHnQLgJHgkpVwFjE1B0KDDRO0ki09hmk6OboTaIfPsQ==} - '@zodios/core@10.9.6': - resolution: {integrity: sha512-aH4rOdb3AcezN7ws8vDgBfGboZMk2JGGzEq/DtW65MhnRxyTGRuLJRWVQ/2KxDgWvV2F5oTkAS+5pnjKbl0n+A==} - peerDependencies: - axios: ^0.x || ^1.0.0 - zod: ^3.x - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2416,24 +2026,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - ajv-draft-04@1.0.0: - resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} - peerDependencies: - ajv: ^8.5.0 - peerDependenciesMeta: - ajv: - optional: true - ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -2462,10 +2057,6 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansis@4.3.0: - resolution: {integrity: sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==} - engines: {node: '>=14'} - anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -2531,9 +2122,6 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - atob@2.1.2: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} engines: {node: '>= 4.5.0'} @@ -2550,13 +2138,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.11.4: - resolution: {integrity: sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==} + axe-core@4.12.1: + resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} engines: {node: '>=4'} - axios@1.17.0: - resolution: {integrity: sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==} - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -2569,13 +2154,6 @@ packages: react-native-b4a: optional: true - babel-dead-code-elimination@1.0.12: - resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} - - babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} - babel-plugin-react-compiler@1.0.0: resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} @@ -2619,11 +2197,11 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} - brace-expansion@2.1.0: - resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + brace-expansion@2.1.1: + resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} brace-expansion@5.0.6: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} @@ -2649,10 +2227,6 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2665,9 +2239,6 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - call-me-maybe@1.0.2: - resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2745,10 +2316,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2760,30 +2327,20 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} - comment-parser@1.4.6: - resolution: {integrity: sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==} + comment-parser@1.4.7: + resolution: {integrity: sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==} engines: {node: '>= 12.0.0'} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-es@3.1.1: - resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} - cookie@1.1.1: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} - cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} - cpx2@8.0.2: resolution: {integrity: sha512-exLFEIh8XgWthEtrEq8hs+S6jxM5ZHpjQnRH6D7VU+2uAYS3amLSVOUSuirfx3HeN7WBCq+xFygHpt7l+gQtUA==} engines: {node: ^20.0.0 || >=22.0.0, npm: '>=10'} @@ -2827,64 +2384,20 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} - d3-format@3.1.2: - resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} - engines: {node: '>=12'} - - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - - d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} - engines: {node: '>=12'} - - d3-time-format@4.1.0: - resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} - engines: {node: '>=12'} - - d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} - engines: {node: '>=12'} - - d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} - engines: {node: '>=12'} - - damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - - data-urls@7.0.0: - resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} data-view-byte-offset@1.0.1: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} @@ -2914,9 +2427,6 @@ packages: supports-color: optional: true - decimal.js-light@2.5.1: - resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} - decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -2943,10 +2453,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -2955,10 +2461,6 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - diff@8.0.4: - resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} - engines: {node: '>=0.3.1'} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2967,9 +2469,6 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} - dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -3002,12 +2501,8 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.21.5: - resolution: {integrity: sha512-mLCNbrQli11K1ySUmuNt4ZUB3OpGIDq4q2vTBTf5cL2lpsRjI9QKqSD0ndjW8FyvcW/Jj46gMe9syyHAsvMa/A==} - engines: {node: '>=10.13.0'} - - enhanced-resolve@5.22.0: - resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==} + enhanced-resolve@5.23.0: + resolution: {integrity: sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==} engines: {node: '>=10.13.0'} enquirer@2.4.1: @@ -3041,17 +2536,13 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.3.2: - resolution: {integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==} + es-iterator-helpers@1.3.3: + resolution: {integrity: sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==} engines: {node: '>= 0.4'} es-module-lexer@2.1.0: resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} @@ -3126,8 +2617,8 @@ packages: eslint-plugin-import-x: optional: true - eslint-import-resolver-typescript@4.4.4: - resolution: {integrity: sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==} + eslint-import-resolver-typescript@4.4.5: + resolution: {integrity: sha512-nbE5XLph6TLtGYcu/U6e6ZVXyKBhbDWK5cLGk76eJ7NdZpwf1P9EFkpt1Z01mNZNrrilsAYWKH6zUkL4reoXbw==} engines: {node: ^16.17.0 || >=18.6.0} peerDependencies: eslint: '*' @@ -3195,8 +2686,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - eslint-plugin-n@18.0.1: - resolution: {integrity: sha512-q3ARhk+eZRc7myR0KHx+R3/GJeOHF+Ir6PK95Pu2tEX8Sl/4BIpmmVLva2kPrjC2gCmn6WHlHm+3yeo6Rxhycw==} + eslint-plugin-n@18.1.0: + resolution: {integrity: sha512-hkUm9EtnFV2h2fE16jNVUfCVUqvPzI7fGLsFdun5lFt/pbmf2kCgDx6ymi9rx+NCUSggBmurJCZOfG20JBs/kg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: eslint: '>=8.57.1' @@ -3274,12 +2765,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - eval-estree-expression@3.0.1: - resolution: {integrity: sha512-zTLKGbiVdQYp4rQkSoXPibrFf5ZoPn6jzExegRLEQ13F+FSxu5iLgaRH6hlDs2kWSUa6vp8yD20cdJi0me6pEw==} - - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -3303,10 +2788,6 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-equals@5.4.0: - resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} - engines: {node: '>=6.0.0'} - fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} @@ -3324,9 +2805,6 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -3353,9 +2831,6 @@ packages: find-index@0.1.1: resolution: {integrity: sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==} - find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -3385,33 +2860,16 @@ packages: focus-trap@8.2.0: resolution: {integrity: sha512-CaBdQ9P4fa/yCA6pDf/3aJd8bf9IOG5QGK21/E+86o2V4V8kzXaR4A9E6tNR7KkkS1+T5ZIU1tJDBDLwsucz9g==} - follow-redirects@1.16.0: - resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - fs-extra@11.3.5: resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} engines: {node: '>=14.14'} @@ -3525,11 +2983,6 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - goober@2.1.19: - resolution: {integrity: sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==} - peerDependencies: - csstype: ^3.0.10 - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -3537,11 +2990,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - handlebars@4.7.9: - resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} - engines: {node: '>=0.4.7'} - hasBin: true - has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -3569,8 +3017,8 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} hermes-estree@0.25.1: @@ -3592,12 +3040,8 @@ packages: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - - human-id@4.1.3: - resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + human-id@4.2.0: + resolution: {integrity: sha512-K3GbkIWqyvvlpfhBPlbEvD97TtqBpAYA4kt+cn2lD2x2HuohzZCibcA2nOlnJT6exqvJLggoB5nv2dNf192nEA==} hasBin: true husky@9.1.7: @@ -3647,10 +3091,6 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -3779,10 +3219,6 @@ packages: isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isbot@5.1.40: - resolution: {integrity: sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==} - engines: {node: '>=18'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3804,8 +3240,8 @@ packages: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} hasBin: true jsdom@29.1.1: @@ -3828,15 +3264,9 @@ packages: json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -3955,11 +3385,8 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - lint-staged@17.0.5: - resolution: {integrity: sha512-d12yC+/e8RhBjZtaxZn71FyrgU/P5e+uAPifhCLwdosQZP/zamSdKRWDC30ocVIbzDKiFG1McHc/LUgB92GIPw==} + lint-staged@17.0.7: + resolution: {integrity: sha512-JrSobt+tW3rH8IOMi8tDZd3foorM5yPEkLD/V2NxobgHrFfHWGee4MOLVuZeScgxftEwbHrPHIFA/ZL+nUJeuA==} engines: {node: '>=22.22.1'} hasBin: true @@ -4003,6 +3430,10 @@ packages: resolution: {integrity: sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==} engines: {node: 20 || >=22} + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4022,9 +3453,6 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -4043,14 +3471,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -4112,9 +3532,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - next@16.2.6: resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} engines: {node: '>=20.9.0'} @@ -4216,16 +3633,6 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} - openapi-types@12.1.3: - resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} - - openapi-zod-client@1.18.3: - resolution: {integrity: sha512-10vYK7xo1yyZfcoRvYNGIsDeej1CG9k63u8dkjbGBlr+NHZMy2Iy2h9s11UWNKdj6XMDWbNOPp5gIy8YdpgPtQ==} - hasBin: true - - openapi3-ts@3.1.0: - resolution: {integrity: sha512-1qKTvCCVoV0rkwUh1zq5o8QyghmwYPuhdvtjv1rFjuOnJToXhQyF8eGjNETQ8QmGjr9Jz/tkAKLITIl2s7dw3A==} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -4292,28 +3699,12 @@ packages: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - parse-statements@1.0.11: resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} parse5@8.0.1: resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} - pastable@2.2.1: - resolution: {integrity: sha512-K4ClMxRKpgN4sXj6VIPPrvor/TMp2yPNCGtfhvV106C73SwefQ3FuegURsH7AQHpqu0WwbvKXRl1HQxF6qax9w==} - engines: {node: '>=14.x'} - peerDependencies: - react: '>=17' - xstate: '>=4.32.1' - peerDependenciesMeta: - react: - optional: true - xstate: - optional: true - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -4445,8 +3836,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} engines: {node: '>=14'} hasBin: true @@ -4459,10 +3850,6 @@ packages: protocol-buffers-schema@3.6.1: resolution: {integrity: sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==} - proxy-from-env@2.1.0: - resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} - engines: {node: '>=10'} - pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -4505,11 +3892,6 @@ packages: peerDependencies: react: ^19.2.6 - react-flatpickr@4.0.11: - resolution: {integrity: sha512-S0TAu8eUeJgN8lZ0Efi41WGPM/tPPUvrveXQ8CAUO60+7TTrF5Ehyv8fvPVagKCqJahY7hXYERM7XfH2hSAWdg==} - peerDependencies: - react: '>= 16 <= 19' - react-intersection-observer@10.0.3: resolution: {integrity: sha512-luICLMbs0zxTO/70Zy7K5jOXkABPEVSAF8T3FdZUlctsrIaPLmx8TZe2SSA+CY2HGWfz2INyNTnp82pxNNsShA==} peerDependencies: @@ -4522,9 +3904,6 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} @@ -4551,15 +3930,15 @@ packages: redux: optional: true - react-router-dom@7.15.0: - resolution: {integrity: sha512-VcrVg64Fo8nwBvDscajG8gRTLIuTC6N50nb22l2HOOV4PTOHgoGp8mUjy9wLiHYoYTSYI36tUnXZgasSRFZorQ==} + react-router-dom@7.17.0: + resolution: {integrity: sha512-fyU2yjGups/hE6Xz0I5ZYbVL8Gx29eCjgpHaRaTaVU+OOAdfRX05KsvyRm0GO8YQwOkhpU3MurW1jyMUJn+zSw==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.15.0: - resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==} + react-router@7.17.0: + resolution: {integrity: sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -4568,18 +3947,6 @@ packages: react-dom: optional: true - react-select@5.10.2: - resolution: {integrity: sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - react-smooth@4.0.4: - resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-stately@3.46.0: resolution: {integrity: sha512-OdxhWvHgs2L4OJGIs7hnuTr5WjjMM6enhNEAMRqiekhF8+ITvA2LRwNftOZwcogaoCslGYq5S2VQTQwnm0GbCA==} peerDependencies: @@ -4592,12 +3959,6 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' - react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' - react@19.2.6: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} @@ -4625,17 +3986,6 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} - recharts-scale@0.4.5: - resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} - - recharts@2.15.4: - resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} - engines: {node: '>=14'} - deprecated: 1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - redux-batched-actions@0.5.0: resolution: {integrity: sha512-6orZWyCnIQXMGY4DUGM0oj0L7oYnwTACsfsru/J7r94RM3P9eS7SORGpr3LCeRCMoIMQcpfKZ7X4NdyFHBS8Eg==} peerDependencies: @@ -4729,8 +4079,8 @@ packages: engines: {node: 20 || >=22} hasBin: true - rolldown@1.0.2: - resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -4784,15 +4134,10 @@ packages: engines: {node: '>=10'} hasBin: true - seroval-plugins@1.5.4: - resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} - engines: {node: '>=10'} - peerDependencies: - seroval: ^1.0 - - seroval@1.5.4: - resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} engines: {node: '>=10'} + hasBin: true set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -4849,8 +4194,8 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} siginfo@2.0.0: @@ -4889,10 +4234,6 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -4962,8 +4303,12 @@ packages: string.prototype.repeat@1.0.0: resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} engines: {node: '>= 0.4'} string.prototype.trimend@1.0.9: @@ -5010,9 +4355,6 @@ packages: babel-plugin-macros: optional: true - stylis@4.2.0: - resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - subarg@1.0.0: resolution: {integrity: sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==} @@ -5084,15 +4426,9 @@ packages: tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - tailwind-merge@3.6.0: - resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} - tailwindcss@4.3.0: resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} - tanu@0.1.13: - resolution: {integrity: sha512-UbRmX7ccZ4wMVOY/Uw+7ji4VOkEYSYJG1+I4qzbnn4qh/jtvVbrm6BFnF12NQQ4+jGv21wKmjb1iFyUSVnBWcQ==} - tapable@2.3.3: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} @@ -5111,17 +4447,14 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} - terser@5.47.1: - resolution: {integrity: sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==} + terser@5.48.0: + resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==} engines: {node: '>=10'} hasBin: true text-decoder@1.2.7: resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -5129,10 +4462,18 @@ packages: resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} @@ -5162,12 +4503,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-pattern@5.9.0: - resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} - - ts-toolbelt@9.6.0: - resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} - tsc-alias@1.8.17: resolution: {integrity: sha512-EIduCZHqbNwPm8BZYfq1aD7BQ697A4h6uSGMOFQfYGoQwfrYFTKwYfy9Bv42YxHkduVBcn9Zx0DkX111DKskyg==} engines: {node: '>=16.20.2'} @@ -5182,18 +4517,14 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo@2.9.14: - resolution: {integrity: sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==} + turbo@2.9.17: + resolution: {integrity: sha512-91Q3KxfHJn7esFu2Ic6j9pkvQqWjncQCOp7r1gCKChRSb/+T/yIjsavAmbGLmFRKAzSjmWW/FMrcknmJ4hEOPA==} hasBin: true type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} - typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -5206,38 +4537,31 @@ packages: resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} engines: {node: '>= 0.4'} - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} - typescript-eslint@8.59.4: - resolution: {integrity: sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==} + typescript-eslint@8.61.0: + resolution: {integrity: sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true - uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} - hasBin: true - unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} undici-types@7.25.0: resolution: {integrity: sha512-AXNgS1Byr27fTI+2bsPEkV9CxkT8H6xNyRI68b3TatlZo3RkzlqQBLL+w7SmGPVpokjHbcuNVQUWE7FRTg+LRA==} @@ -5254,10 +4578,6 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - unplugin@3.0.0: - resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} - engines: {node: ^20.19.0 || >=22.12.0} - unrs-resolver@1.12.2: resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} @@ -5274,15 +4594,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-isomorphic-layout-effect@1.2.1: - resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -5299,20 +4610,12 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - victory-vendor@36.9.2: - resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} - vinyl@3.0.1: resolution: {integrity: sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA==} engines: {node: '>=10.13.0'} - vite-plugin-handlebars@2.0.3: - resolution: {integrity: sha512-LnzLfYtmHfK66R5M3yL/2EAYmsZh+/0SrlBStRPJYhww0pBDQBDzDgxmxHl9JV2UHZ/21uOx5+kPPZiEp2gMCQ==} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - - vite@8.0.14: - resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -5409,9 +4712,6 @@ packages: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} - webpack-virtual-modules@0.6.2: - resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - whatwg-mimetype@5.0.0: resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} @@ -5420,10 +4720,6 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - whence@2.1.0: - resolution: {integrity: sha512-4UBPMg5mng5KLzdliVQdQ4fJwCdIMXkE8CkoDmGKRy5r8pV9xq+nVgf/sKXpmNEIOtFp7m7v2bFdb7JoLvh+Hg==} - engines: {node: '>=14'} - which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -5436,8 +4732,8 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + which-typed-array@1.1.22: + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} engines: {node: '>= 0.4'} which@1.3.1: @@ -5461,9 +4757,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - wrap-ansi@10.0.0: resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} engines: {node: '>=20'} @@ -5492,10 +4785,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@1.10.3: - resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} - engines: {node: '>= 6'} - yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} @@ -5522,9 +4811,6 @@ packages: peerDependencies: zod: ^3.25.0 || ^4.0.0 - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} @@ -5535,27 +4821,6 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@apidevtools/json-schema-ref-parser@11.7.2': - dependencies: - '@jsdevtools/ono': 7.1.3 - '@types/json-schema': 7.0.15 - js-yaml: 4.1.1 - - '@apidevtools/openapi-schemas@2.1.0': {} - - '@apidevtools/swagger-methods@3.0.2': {} - - '@apidevtools/swagger-parser@10.1.1(openapi-types@12.1.3)': - dependencies: - '@apidevtools/json-schema-ref-parser': 11.7.2 - '@apidevtools/openapi-schemas': 2.1.0 - '@apidevtools/swagger-methods': 3.0.2 - '@jsdevtools/ono': 7.1.3 - ajv: 8.20.0 - ajv-draft-04: 1.0.0(ajv@8.20.0) - call-me-maybe: 1.0.2 - openapi-types: 12.1.3 - '@asamuzakjp/css-color@5.1.11': dependencies: '@asamuzakjp/generational-cache': 1.0.1 @@ -5576,25 +4841,25 @@ snapshots: '@asamuzakjp/nwsapi@2.3.9': {} - '@babel/code-frame@7.29.0': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.3': {} + '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.0': + '@babel/core@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@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/core@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.4.3 @@ -5604,83 +4869,77 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.1': + '@babel/generator@7.29.7': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.28.6': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/parser@7.29.3': - dependencies: - '@babel/types': 7.29.0 + '@babel/helper-validator-option@7.29.7': {} - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/helpers@7.29.7': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/parser@7.29.7': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.7 '@babel/runtime@7.29.2': {} - '@babel/template@7.28.6': + '@babel/runtime@7.29.7': {} + + '@babel/template@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@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.4.3 transitivePeerDependencies: - supports-color @@ -5690,6 +4949,11 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@bramus/specificity@2.4.2': dependencies: css-tree: 3.2.1 @@ -5708,7 +4972,7 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.8.0 + semver: 7.8.4 '@changesets/assemble-release-plan@6.0.10': dependencies: @@ -5717,13 +4981,13 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 - semver: 7.8.0 + semver: 7.8.4 '@changesets/changelog-git@0.2.1': dependencies: '@changesets/types': 6.1.0 - '@changesets/cli@2.31.0(@types/node@24.12.4)': + '@changesets/cli@2.31.0(@types/node@24.13.1)': dependencies: '@changesets/apply-release-plan': 7.1.1 '@changesets/assemble-release-plan': 6.0.10 @@ -5739,7 +5003,7 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.3(@types/node@24.12.4) + '@inquirer/external-editor': 1.0.3(@types/node@24.13.1) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 enquirer: 2.4.1 @@ -5748,7 +5012,38 @@ snapshots: package-manager-detector: 0.2.11 picocolors: 1.1.1 resolve-from: 5.0.0 - semver: 7.8.0 + semver: 7.8.4 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/cli@2.31.0(@types/node@25.9.2)': + dependencies: + '@changesets/apply-release-plan': 7.1.1 + '@changesets/assemble-release-plan': 6.0.10 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.4 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.4 + '@changesets/get-release-plan': 4.0.16 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@25.9.2) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.8.4 spawndamnit: 3.0.1 term-size: 2.2.1 transitivePeerDependencies: @@ -5774,7 +5069,7 @@ snapshots: '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.8.0 + semver: 7.8.4 '@changesets/get-release-plan@4.0.16': dependencies: @@ -5802,7 +5097,7 @@ snapshots: '@changesets/parse@0.4.3': dependencies: '@changesets/types': 6.1.0 - js-yaml: 4.1.1 + js-yaml: 4.2.0 '@changesets/pre@2.0.2': dependencies: @@ -5834,7 +5129,7 @@ snapshots: dependencies: '@changesets/types': 6.1.0 fs-extra: 7.0.1 - human-id: 4.1.3 + human-id: 4.2.0 prettier: 2.8.8 '@csstools/color-helpers@6.0.2': {} @@ -5877,70 +5172,6 @@ snapshots: tslib: 2.8.1 optional: true - '@emotion/babel-plugin@11.13.5': - dependencies: - '@babel/helper-module-imports': 7.28.6 - '@babel/runtime': 7.29.2 - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/serialize': 1.3.3 - babel-plugin-macros: 3.1.0 - convert-source-map: 1.9.0 - escape-string-regexp: 4.0.0 - find-root: 1.1.0 - source-map: 0.5.7 - stylis: 4.2.0 - transitivePeerDependencies: - - supports-color - - '@emotion/cache@11.14.0': - dependencies: - '@emotion/memoize': 0.9.0 - '@emotion/sheet': 1.4.0 - '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.4.0 - stylis: 4.2.0 - - '@emotion/hash@0.9.2': {} - - '@emotion/memoize@0.9.0': {} - - '@emotion/react@11.14.0(@types/react@19.2.15)(react@19.2.6)': - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/babel-plugin': 11.13.5 - '@emotion/cache': 11.14.0 - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) - '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.4.0 - hoist-non-react-statics: 3.3.2 - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - transitivePeerDependencies: - - supports-color - - '@emotion/serialize@1.3.3': - dependencies: - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/unitless': 0.10.0 - '@emotion/utils': 1.4.2 - csstype: 3.2.3 - - '@emotion/sheet@1.4.0': {} - - '@emotion/unitless@0.10.0': {} - - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.6)': - dependencies: - react: 19.2.6 - - '@emotion/utils@1.4.2': {} - - '@emotion/weak-memoize@0.4.0': {} - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': dependencies: eslint: 9.39.4(jiti@2.7.0) @@ -5972,7 +5203,7 @@ snapshots: globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.1 + js-yaml: 4.2.0 minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -5989,17 +5220,6 @@ snapshots: '@exodus/bytes@1.15.0': {} - '@floating-ui/core@1.7.5': - dependencies: - '@floating-ui/utils': 0.2.11 - - '@floating-ui/dom@1.7.6': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - - '@floating-ui/utils@0.2.11': {} - '@fortawesome/fontawesome-common-types@6.7.2': {} '@fortawesome/free-solid-svg-icons@6.7.2': @@ -6118,12 +5338,19 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@inquirer/external-editor@1.0.3(@types/node@24.12.4)': + '@inquirer/external-editor@1.0.3(@types/node@24.13.1)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 24.13.1 + + '@inquirer/external-editor@1.0.3(@types/node@25.9.2)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 24.12.4 + '@types/node': 25.9.2 '@internationalized/date@3.12.1': dependencies: @@ -6161,23 +5388,16 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@jsdevtools/ono@7.1.3': {} - - '@liuli-util/fs-extra@0.1.0': - dependencies: - '@types/fs-extra': 9.0.13 - fs-extra: 10.1.0 - '@manypkg/find-root@1.1.0': dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 '@manypkg/get-packages@1.1.3': dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -6191,6 +5411,13 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + '@next/env@16.2.6': {} '@next/eslint-plugin-next@16.2.6': @@ -6235,7 +5462,7 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@oxc-project/types@0.132.0': {} + '@oxc-project/types@0.133.0': {} '@package-json/types@0.0.12': {} @@ -6316,7 +5543,7 @@ snapshots: immutable: 4.3.8 redux: 5.0.1 - '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 @@ -6326,55 +5553,55 @@ snapshots: reselect: 5.2.0 optionalDependencies: react: 19.2.6 - react-redux: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) + react-redux: 9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1) - '@rolldown/binding-android-arm64@1.0.2': + '@rolldown/binding-android-arm64@1.0.3': optional: true - '@rolldown/binding-darwin-arm64@1.0.2': + '@rolldown/binding-darwin-arm64@1.0.3': optional: true - '@rolldown/binding-darwin-x64@1.0.2': + '@rolldown/binding-darwin-x64@1.0.3': optional: true - '@rolldown/binding-freebsd-x64@1.0.2': + '@rolldown/binding-freebsd-x64@1.0.3': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.2': + '@rolldown/binding-linux-arm64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.2': + '@rolldown/binding-linux-arm64-musl@1.0.3': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.2': + '@rolldown/binding-linux-ppc64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.2': + '@rolldown/binding-linux-s390x-gnu@1.0.3': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.2': + '@rolldown/binding-linux-x64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-x64-musl@1.0.2': + '@rolldown/binding-linux-x64-musl@1.0.3': optional: true - '@rolldown/binding-openharmony-arm64@1.0.2': + '@rolldown/binding-openharmony-arm64@1.0.3': optional: true - '@rolldown/binding-wasm32-wasi@1.0.2': + '@rolldown/binding-wasm32-wasi@1.0.3': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.2': + '@rolldown/binding-win32-arm64-msvc@1.0.3': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.2': + '@rolldown/binding-win32-x64-msvc@1.0.3': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -6396,7 +5623,7 @@ snapshots: '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.22.0 + enhanced-resolve: 5.23.0 jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 @@ -6462,146 +5689,43 @@ snapshots: postcss: 8.5.14 tailwindcss: 4.3.0 - '@tailwindcss/vite@4.3.0(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.0(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 tailwindcss: 4.3.0 - vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + vite: 8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) - '@tanstack/history@1.162.0': {} - - '@tanstack/query-core@5.101.0': {} - - '@tanstack/react-query@5.101.0(react@19.2.6)': - dependencies: - '@tanstack/query-core': 5.101.0 - react: 19.2.6 - - '@tanstack/react-router-devtools@1.167.0(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.171.6)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@tanstack/react-router': 1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tanstack/router-devtools-core': 1.168.0(@tanstack/router-core@1.171.6)(csstype@3.2.3) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@tanstack/router-core': 1.171.6 - transitivePeerDependencies: - - csstype - - '@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@tanstack/history': 1.162.0 - '@tanstack/react-store': 0.9.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tanstack/router-core': 1.171.6 - isbot: 5.1.40 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - - '@tanstack/react-store@0.9.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@tanstack/store': 0.9.3 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - use-sync-external-store: 1.6.0(react@19.2.6) - - '@tanstack/router-core@1.171.6': - dependencies: - '@tanstack/history': 1.162.0 - cookie-es: 3.1.1 - seroval: 1.5.4 - seroval-plugins: 1.5.4(seroval@1.5.4) - - '@tanstack/router-devtools-core@1.168.0(@tanstack/router-core@1.171.6)(csstype@3.2.3)': - dependencies: - '@tanstack/router-core': 1.171.6 - clsx: 2.1.1 - goober: 2.1.19(csstype@3.2.3) - optionalDependencies: - csstype: 3.2.3 - - '@tanstack/router-generator@1.167.10': + '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.4)': dependencies: - '@babel/types': 7.29.0 - '@tanstack/router-core': 1.171.6 - '@tanstack/router-utils': 1.162.1 - '@tanstack/virtual-file-routes': 1.162.0 - jiti: 2.7.0 - magic-string: 0.30.21 - prettier: 3.8.3 - zod: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@tanstack/router-plugin@1.168.11(@tanstack/react-router@1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@tanstack/router-core': 1.171.6 - '@tanstack/router-generator': 1.167.10 - '@tanstack/router-utils': 1.162.1 - '@tanstack/virtual-file-routes': 1.162.0 - chokidar: 5.0.0 - unplugin: 3.0.0 - zod: 4.4.3 - optionalDependencies: - '@tanstack/react-router': 1.170.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) - transitivePeerDependencies: - - supports-color - - '@tanstack/router-utils@1.162.1': - dependencies: - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - ansis: 4.3.0 - babel-dead-code-elimination: 1.0.12 - diff: 8.0.4 - pathe: 2.0.3 - tinyglobby: 0.2.16 - transitivePeerDependencies: - - supports-color - - '@tanstack/store@0.9.3': {} - - '@tanstack/virtual-file-routes@1.162.0': {} - - '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3)': - dependencies: - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 javascript-natural-sort: 0.7.1 lodash-es: 4.18.1 minimatch: 9.0.9 parse-imports-exports: 0.2.4 - prettier: 3.8.3 + prettier: 3.8.4 transitivePeerDependencies: - supports-color - '@turbo/darwin-64@2.9.14': + '@turbo/darwin-64@2.9.17': optional: true - '@turbo/darwin-arm64@2.9.14': + '@turbo/darwin-arm64@2.9.17': optional: true - '@turbo/linux-64@2.9.14': + '@turbo/linux-64@2.9.17': optional: true - '@turbo/linux-arm64@2.9.14': + '@turbo/linux-arm64@2.9.17': optional: true - '@turbo/windows-64@2.9.14': + '@turbo/windows-64@2.9.17': optional: true - '@turbo/windows-arm64@2.9.14': + '@turbo/windows-arm64@2.9.17': optional: true '@tybys/wasm-util@0.10.2': @@ -6616,30 +5740,6 @@ snapshots: '@types/css@0.0.38': {} - '@types/d3-array@3.2.2': {} - - '@types/d3-color@3.1.3': {} - - '@types/d3-ease@3.0.2': {} - - '@types/d3-interpolate@3.0.4': - dependencies: - '@types/d3-color': 3.1.3 - - '@types/d3-path@3.1.1': {} - - '@types/d3-scale@4.0.9': - dependencies: - '@types/d3-time': 3.0.4 - - '@types/d3-shape@3.1.8': - dependencies: - '@types/d3-path': 3.1.1 - - '@types/d3-time@3.0.4': {} - - '@types/d3-timer@3.0.2': {} - '@types/deep-eql@4.0.2': {} '@types/eslint-plugin-jsx-a11y@6.10.1(jiti@2.7.0)': @@ -6654,22 +5754,18 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 24.12.4 - - '@types/fs-extra@9.0.13': - dependencies: - '@types/node': 24.12.4 + '@types/node': 25.9.2 '@types/geojson@7946.0.16': {} - '@types/hoist-non-react-statics@3.3.7(@types/react@19.2.15)': + '@types/hoist-non-react-statics@3.3.7(@types/react@19.2.14)': dependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.14 hoist-non-react-statics: 3.3.2 '@types/jsdom@28.0.3': dependencies: - '@types/node': 24.12.4 + '@types/node': 25.9.2 '@types/tough-cookie': 4.0.5 parse5: 8.0.1 undici-types: 7.25.0 @@ -6680,7 +5776,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 24.12.4 + '@types/node': 25.9.2 '@types/lodash@4.17.24': {} @@ -6690,41 +5786,38 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@24.12.4': + '@types/node@24.13.1': dependencies: - undici-types: 7.16.0 + undici-types: 7.18.2 - '@types/parse-json@4.0.2': {} + '@types/node@25.9.2': + dependencies: + undici-types: 7.24.6 '@types/pidusage@2.0.5': {} '@types/rbush@4.0.0': {} - '@types/react-dom@19.2.3(@types/react@19.2.15)': + '@types/react-dom@19.2.3(@types/react@19.2.17)': dependencies: - '@types/react': 19.2.15 - - '@types/react-flatpickr@3.8.11': - dependencies: - '@types/react': 19.2.15 - flatpickr: 4.6.13 + '@types/react': 19.2.17 '@types/react-modal@3.16.3': dependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.14 '@types/react-redux@7.1.34': dependencies: - '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.15) - '@types/react': 19.2.15 + '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.14) + '@types/react': 19.2.14 hoist-non-react-statics: 3.3.2 redux: 4.2.1 - '@types/react-transition-group@4.4.12(@types/react@19.2.15)': + '@types/react@19.2.14': dependencies: - '@types/react': 19.2.15 + csstype: 3.2.3 - '@types/react@19.2.15': + '@types/react@19.2.17': dependencies: csstype: 3.2.3 @@ -6732,14 +5825,14 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} - '@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.59.4 - '@typescript-eslint/type-utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.59.4 + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/type-utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.61.0 eslint: 9.39.4(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 @@ -6748,41 +5841,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.59.4 - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.59.4 + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.61.0 debug: 4.4.3 eslint: 9.39.4(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.4(typescript@6.0.3)': + '@typescript-eslint/project-service@8.61.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3) - '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 debug: 4.4.3 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.59.4': + '@typescript-eslint/scope-manager@8.61.0': dependencies: - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/visitor-keys': 8.59.4 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 - '@typescript-eslint/tsconfig-utils@8.59.4(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.61.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) - '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 eslint: 9.39.4(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@6.0.3) @@ -6790,37 +5883,37 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.59.4': {} + '@typescript-eslint/types@8.61.0': {} - '@typescript-eslint/typescript-estree@8.59.4(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.61.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.59.4(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3) - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/visitor-keys': 8.59.4 + '@typescript-eslint/project-service': 8.61.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.8.0 - tinyglobby: 0.2.16 + semver: 7.8.4 + tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.59.4 - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) eslint: 9.39.4(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.59.4': + '@typescript-eslint/visitor-keys@8.61.0': dependencies: - '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/types': 8.61.0 eslint-visitor-keys: 5.0.1 '@unrs/resolver-binding-android-arm-eabi@1.12.2': @@ -6881,7 +5974,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': @@ -6893,13 +5986,6 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true - '@vitejs/plugin-react@6.0.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': - dependencies: - '@rolldown/pluginutils': 1.0.1 - vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) - optionalDependencies: - babel-plugin-react-compiler: 1.0.0 - '@vitest/expect@4.1.6': dependencies: '@standard-schema/spec': 1.1.0 @@ -6909,13 +5995,21 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.6(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0))': + '@vitest/mocker@4.1.6(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))': + dependencies: + '@vitest/spy': 4.1.6 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) + + '@vitest/mocker@4.1.6(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + vite: 8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.6': dependencies: @@ -6946,32 +6040,12 @@ snapshots: reference-spec-reader: 0.2.0 unzipit: 2.0.0 - '@zodios/core@10.9.6(axios@1.17.0)(zod@3.25.76)': - dependencies: - axios: 1.17.0 - zod: 3.25.76 - - '@zodios/core@10.9.6(axios@1.17.0)(zod@4.4.3)': - dependencies: - axios: 1.17.0 - zod: 4.4.3 - acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 acorn@8.16.0: {} - agent-base@6.0.2: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - ajv-draft-04@1.0.0(ajv@8.20.0): - optionalDependencies: - ajv: 8.20.0 - ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -6979,13 +6053,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.20.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - ansi-colors@4.1.3: {} ansi-escapes@7.3.0: @@ -7006,8 +6073,6 @@ snapshots: ansi-styles@6.2.3: {} - ansis@4.3.0: {} - anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -7036,7 +6101,7 @@ snapshots: call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.2 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 is-string: 1.1.1 math-intrinsics: 1.1.0 @@ -7049,7 +6114,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 es-shim-unscopables: 1.1.0 array.prototype.findlastindex@1.2.6: @@ -7100,8 +6165,6 @@ snapshots: async-function@1.0.0: {} - asynckit@0.4.0: {} - atob@2.1.2: {} autoprefixer@10.5.0(postcss@8.5.15): @@ -7117,37 +6180,12 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axe-core@4.11.4: {} - - axios@1.17.0: - dependencies: - follow-redirects: 1.16.0 - form-data: 4.0.5 - https-proxy-agent: 5.0.1 - proxy-from-env: 2.1.0 - transitivePeerDependencies: - - debug - - supports-color + axe-core@4.12.1: {} axobject-query@4.1.0: {} b4a@1.8.1: {} - babel-dead-code-elimination@1.0.12: - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-macros@3.1.0: - dependencies: - '@babel/runtime': 7.29.2 - cosmiconfig: 7.1.0 - resolve: 1.22.12 - babel-plugin-react-compiler@1.0.0: dependencies: '@babel/types': 7.29.0 @@ -7180,12 +6218,12 @@ snapshots: boolbase@1.0.0: {} - brace-expansion@1.1.14: + brace-expansion@1.1.15: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.1.0: + brace-expansion@2.1.1: dependencies: balanced-match: 1.0.2 @@ -7216,8 +6254,6 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - cac@6.7.14: {} - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -7235,8 +6271,6 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - call-me-maybe@1.0.2: {} - callsites@3.1.0: {} caniuse-lite@1.0.30001792: {} @@ -7314,36 +6348,20 @@ snapshots: color-name@1.1.4: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - commander@11.1.0: {} commander@2.20.3: {} commander@9.5.0: {} - comment-parser@1.4.6: {} + comment-parser@1.4.7: {} concat-map@0.0.1: {} - convert-source-map@1.9.0: {} - convert-source-map@2.0.0: {} - cookie-es@3.1.1: {} - cookie@1.1.1: {} - cosmiconfig@7.1.0: - dependencies: - '@types/parse-json': 4.0.2 - import-fresh: 3.3.1 - parse-json: 5.2.0 - path-type: 4.0.0 - yaml: 1.10.3 - cpx2@8.0.2: dependencies: debounce: 3.0.0 @@ -7404,44 +6422,6 @@ snapshots: csstype@3.2.3: {} - d3-array@3.2.4: - dependencies: - internmap: 2.0.3 - - d3-color@3.1.0: {} - - d3-ease@3.0.1: {} - - d3-format@3.1.2: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-path@3.1.0: {} - - d3-scale@4.0.2: - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.2 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - - d3-shape@3.2.0: - dependencies: - d3-path: 3.1.0 - - d3-time-format@4.1.0: - dependencies: - d3-time: 3.1.0 - - d3-time@3.1.0: - dependencies: - d3-array: 3.2.4 - - d3-timer@3.0.1: {} - damerau-levenshtein@1.0.8: {} data-urls@7.0.0: @@ -7481,8 +6461,6 @@ snapshots: dependencies: ms: 2.1.3 - decimal.js-light@2.5.1: {} - decimal.js@10.6.0: {} decode-uri-component@0.2.2: {} @@ -7507,14 +6485,10 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - delayed-stream@1.0.0: {} - detect-indent@6.1.0: {} detect-libc@2.1.2: {} - diff@8.0.4: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -7523,11 +6497,6 @@ snapshots: dependencies: esutils: 2.0.3 - dom-helpers@5.2.1: - dependencies: - '@babel/runtime': 7.29.2 - csstype: 3.2.3 - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -7564,12 +6533,7 @@ snapshots: dependencies: once: 1.4.0 - enhanced-resolve@5.21.5: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.3 - - enhanced-resolve@5.22.0: + enhanced-resolve@5.23.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 @@ -7613,7 +6577,7 @@ snapshots: has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.3 + hasown: 2.0.4 internal-slot: 1.1.0 is-array-buffer: 3.0.5 is-callable: 1.2.7 @@ -7636,21 +6600,21 @@ snapshots: safe-regex-test: 1.1.0 set-proto: 1.0.0 stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.3 typed-array-byte-length: 1.0.3 typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 + typed-array-length: 1.0.8 unbox-primitive: 1.1.0 - which-typed-array: 1.1.20 + which-typed-array: 1.1.22 es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-iterator-helpers@1.3.2: + es-iterator-helpers@1.3.3: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -7671,10 +6635,6 @@ snapshots: es-module-lexer@2.1.0: {} - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -7684,11 +6644,11 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.3 + hasown: 2.0.4 es-shim-unscopables@1.1.0: dependencies: - hasown: 2.0.3 + hasown: 2.0.4 es-to-primitive@1.3.0: dependencies: @@ -7705,20 +6665,20 @@ snapshots: eslint-compat-utils@0.5.1(eslint@9.39.4(jiti@2.7.0)): dependencies: eslint: 9.39.4(jiti@2.7.0) - semver: 7.8.0 + semver: 7.8.4 - eslint-config-next@16.2.6(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): + eslint-config-next@16.2.6(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): dependencies: '@next/eslint-plugin-next': 16.2.6 eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) globals: 16.4.0 - typescript-eslint: 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + typescript-eslint: 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: @@ -7746,7 +6706,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -7754,15 +6714,15 @@ snapshots: get-tsconfig: 4.14.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 - tinyglobby: 0.2.16 + tinyglobby: 0.2.17 unrs-resolver: 1.12.2 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): + eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): dependencies: debug: 4.4.3 eslint: 9.39.4(jiti@2.7.0) @@ -7770,33 +6730,33 @@ snapshots: get-tsconfig: 4.14.0 is-bun-module: 2.0.0 stable-hash-x: 0.2.0 - tinyglobby: 0.2.16 + tinyglobby: 0.2.17 unrs-resolver: 1.12.2 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4(jiti@2.7.0)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.5)(eslint@9.39.4(jiti@2.7.0)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color optional: true @@ -7808,26 +6768,26 @@ snapshots: eslint: 9.39.4(jiti@2.7.0) eslint-compat-utils: 0.5.1(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)): + eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)): dependencies: '@package-json/types': 0.0.12 - '@typescript-eslint/types': 8.59.4 - comment-parser: 1.4.6 + '@typescript-eslint/types': 8.61.0 + comment-parser: 1.4.7 debug: 4.4.3 eslint: 9.39.4(jiti@2.7.0) eslint-import-context: 0.1.9(unrs-resolver@1.12.2) is-glob: 4.0.3 minimatch: 10.2.5 - semver: 7.8.0 + semver: 7.8.4 stable-hash-x: 0.2.0 unrs-resolver: 1.12.2 optionalDependencies: - '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -7838,8 +6798,8 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) - hasown: 2.0.3 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 minimatch: 3.1.5 @@ -7850,13 +6810,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4(jiti@2.7.0)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.5)(eslint@9.39.4(jiti@2.7.0)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -7867,8 +6827,8 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4(jiti@2.7.0)) - hasown: 2.0.3 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.5)(eslint@9.39.4(jiti@2.7.0)) + hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 minimatch: 3.1.5 @@ -7879,7 +6839,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -7892,12 +6852,12 @@ snapshots: array-includes: 3.1.9 array.prototype.flatmap: 1.3.3 ast-types-flow: 0.0.8 - axe-core: 4.11.4 + axe-core: 4.12.1 axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 eslint: 9.39.4(jiti@2.7.0) - hasown: 2.0.3 + hasown: 2.0.4 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 minimatch: 3.1.5 @@ -7905,24 +6865,24 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-n@18.0.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): + eslint-plugin-n@18.1.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - enhanced-resolve: 5.21.5 + enhanced-resolve: 5.23.0 eslint: 9.39.4(jiti@2.7.0) eslint-plugin-es-x: 7.8.0(eslint@9.39.4(jiti@2.7.0)) get-tsconfig: 4.14.0 globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 - semver: 7.8.0 + semver: 7.8.4 optionalDependencies: typescript: 6.0.3 eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 eslint: 9.39.4(jiti@2.7.0) hermes-parser: 0.25.1 zod: 4.4.3 @@ -7937,10 +6897,10 @@ snapshots: array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.3.2 + es-iterator-helpers: 1.3.3 eslint: 9.39.4(jiti@2.7.0) estraverse: 5.3.0 - hasown: 2.0.3 + hasown: 2.0.4 jsx-ast-utils: 3.3.5 minimatch: 3.1.5 object.entries: 1.1.9 @@ -8028,10 +6988,6 @@ snapshots: esutils@2.0.3: {} - eval-estree-expression@3.0.1: {} - - eventemitter3@4.0.7: {} - eventemitter3@5.0.4: {} events-universal@1.0.1: @@ -8050,8 +7006,6 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-equals@5.4.0: {} - fast-fifo@1.3.2: {} fast-glob@3.3.1: @@ -8074,8 +7028,6 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.1.2: {} - fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -8096,8 +7048,6 @@ snapshots: find-index@0.1.1: {} - find-root@1.1.0: {} - find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -8117,10 +7067,10 @@ snapshots: flatted@3.4.2: {} - focus-trap-react@12.0.1(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + focus-trap-react@12.0.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) focus-trap: 8.2.0 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) @@ -8130,30 +7080,14 @@ snapshots: dependencies: tabbable: 6.4.0 - follow-redirects@1.16.0: {} - for-each@0.3.5: dependencies: is-callable: 1.2.7 - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.3 - mime-types: 2.1.35 - fraction.js@5.3.4: {} fs-constants@1.0.0: {} - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.1 - universalify: 2.0.1 - fs-extra@11.3.5: dependencies: graceful-fs: 4.2.11 @@ -8186,7 +7120,7 @@ snapshots: call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 - hasown: 2.0.3 + hasown: 2.0.4 is-callable: 1.2.7 functions-have-names@1.2.3: {} @@ -8220,7 +7154,7 @@ snapshots: get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.3 + hasown: 2.0.4 math-intrinsics: 1.1.0 get-proto@1.0.1: @@ -8282,23 +7216,10 @@ snapshots: globrex@0.1.2: {} - goober@2.1.19(csstype@3.2.3): - dependencies: - csstype: 3.2.3 - gopd@1.2.0: {} graceful-fs@4.2.11: {} - handlebars@4.7.9: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.3 - has-bigints@1.1.0: {} has-flag@3.0.0: {} @@ -8319,7 +7240,7 @@ snapshots: dependencies: has-symbols: 1.1.0 - hasown@2.0.3: + hasown@2.0.4: dependencies: function-bind: 1.1.2 @@ -8343,14 +7264,7 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - human-id@4.1.3: {} + human-id@4.2.0: {} husky@9.1.7: {} @@ -8384,10 +7298,8 @@ snapshots: internal-slot@1.1.0: dependencies: es-errors: 1.3.0 - hasown: 2.0.3 - side-channel: 1.1.0 - - internmap@2.0.3: {} + hasown: 2.0.4 + side-channel: 1.1.1 is-array-buffer@3.0.5: dependencies: @@ -8420,13 +7332,13 @@ snapshots: is-bun-module@2.0.0: dependencies: - semver: 7.8.0 + semver: 7.8.4 is-callable@1.2.7: {} is-core-module@2.16.2: dependencies: - hasown: 2.0.3 + hasown: 2.0.4 is-data-view@1.0.2: dependencies: @@ -8479,7 +7391,7 @@ snapshots: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 - hasown: 2.0.3 + hasown: 2.0.4 is-set@2.0.3: {} @@ -8504,7 +7416,7 @@ snapshots: is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.20 + which-typed-array: 1.1.22 is-weakmap@2.0.2: {} @@ -8521,8 +7433,6 @@ snapshots: isarray@2.0.5: {} - isbot@5.1.40: {} - isexe@2.0.0: {} iterator.prototype@1.1.5: @@ -8545,7 +7455,7 @@ snapshots: argparse: 1.0.10 esprima: 4.0.1 - js-yaml@4.1.1: + js-yaml@4.2.0: dependencies: argparse: 2.0.1 @@ -8583,12 +7493,8 @@ snapshots: json-parse-better-errors@1.0.2: {} - json-parse-even-better-errors@2.3.1: {} - json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} json5@1.0.2: @@ -8682,14 +7588,12 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - lines-and-columns@1.2.4: {} - - lint-staged@17.0.5: + lint-staged@17.0.7: dependencies: listr2: 10.2.1 picomatch: 4.0.4 string-argv: 0.3.2 - tinyexec: 1.1.2 + tinyexec: 1.2.4 optionalDependencies: yaml: 2.9.0 @@ -8738,6 +7642,8 @@ snapshots: lru-cache@11.4.0: {} + lru-cache@11.5.1: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -8756,8 +7662,6 @@ snapshots: mdn-data@2.27.1: {} - memoize-one@6.0.0: {} - memorystream@0.3.1: {} merge-stream@2.0.0: {} @@ -8771,12 +7675,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.2 - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - mimic-function@5.0.1: {} mimic-response@3.1.0: {} @@ -8787,11 +7685,11 @@ snapshots: minimatch@3.1.5: dependencies: - brace-expansion: 1.1.14 + brace-expansion: 1.1.15 minimatch@9.0.9: dependencies: - brace-expansion: 2.1.0 + brace-expansion: 2.1.1 minimist@1.2.8: {} @@ -8815,9 +7713,7 @@ snapshots: natural-compare@1.4.0: {} - neo-async@2.6.2: {} - - next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.100.0): + next@16.2.6(@babel/core@7.29.7)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.100.0): dependencies: '@next/env': 16.2.6 '@swc/helpers': 0.5.15 @@ -8826,7 +7722,7 @@ snapshots: postcss: 8.5.14 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.6) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.6) optionalDependencies: '@next/swc-darwin-arm64': 16.2.6 '@next/swc-darwin-x64': 16.2.6 @@ -8848,7 +7744,7 @@ snapshots: node-abi@3.92.0: dependencies: - semver: 7.8.0 + semver: 7.8.4 node-addon-api@7.1.1: {} @@ -8910,14 +7806,14 @@ snapshots: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 object.fromentries@2.0.8: dependencies: call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 object.groupby@1.0.3: dependencies: @@ -8930,7 +7826,7 @@ snapshots: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 obug@2.1.1: {} @@ -8951,34 +7847,6 @@ snapshots: dependencies: mimic-function: 5.0.1 - openapi-types@12.1.3: {} - - openapi-zod-client@1.18.3(react@19.2.6): - dependencies: - '@apidevtools/swagger-parser': 10.1.1(openapi-types@12.1.3) - '@liuli-util/fs-extra': 0.1.0 - '@zodios/core': 10.9.6(axios@1.17.0)(zod@3.25.76) - axios: 1.17.0 - cac: 6.7.14 - handlebars: 4.7.9 - openapi-types: 12.1.3 - openapi3-ts: 3.1.0 - pastable: 2.2.1(react@19.2.6) - prettier: 2.8.8 - tanu: 0.1.13 - ts-pattern: 5.9.0 - whence: 2.1.0 - zod: 3.25.76 - transitivePeerDependencies: - - debug - - react - - supports-color - - xstate - - openapi3-ts@3.1.0: - dependencies: - yaml: 2.9.0 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -9045,29 +7913,12 @@ snapshots: error-ex: 1.3.4 json-parse-better-errors: 1.0.2 - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.29.0 - error-ex: 1.3.4 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - parse-statements@1.0.11: {} parse5@8.0.1: dependencies: entities: 8.0.0 - pastable@2.2.1(react@19.2.6): - dependencies: - '@babel/core': 7.29.0 - ts-toolbelt: 9.6.0 - type-fest: 3.13.1 - optionalDependencies: - react: 19.2.6 - transitivePeerDependencies: - - supports-color - path-exists@4.0.0: {} path-key@2.0.1: {} @@ -9078,7 +7929,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.4.0 + lru-cache: 11.5.1 minipass: 7.1.3 path-type@3.0.0: @@ -9177,7 +8028,7 @@ snapshots: prettier@2.8.8: {} - prettier@3.8.3: {} + prettier@3.8.4: {} proj4@2.20.8: dependencies: @@ -9192,8 +8043,6 @@ snapshots: protocol-buffers-schema@3.6.1: {} - proxy-from-env@2.1.0: {} - pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -9241,11 +8090,6 @@ snapshots: react: 19.2.6 scheduler: 0.27.0 - react-flatpickr@4.0.11(react@19.2.6): - dependencies: - flatpickr: 4.6.13 - react: 19.2.6 - react-intersection-observer@10.0.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: react: 19.2.6 @@ -9254,8 +8098,6 @@ snapshots: react-is@16.13.1: {} - react-is@18.3.1: {} - react-lifecycles-compat@3.0.4: {} react-modal@3.16.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6): @@ -9272,22 +8114,22 @@ snapshots: prop-types: 15.8.1 react: 19.2.6 - react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1): + react-redux@9.3.0(@types/react@19.2.17)(react@19.2.6)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.6 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.17 redux: 5.0.1 - react-router-dom@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router-dom@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.1.1 react: 19.2.6 @@ -9295,31 +8137,6 @@ snapshots: optionalDependencies: react-dom: 19.2.6(react@19.2.6) - react-select@5.10.2(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.2.15)(react@19.2.6) - '@floating-ui/dom': 1.7.6 - '@types/react-transition-group': 4.4.12(@types/react@19.2.15) - memoize-one: 6.0.0 - prop-types: 15.8.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-transition-group: 4.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.15)(react@19.2.6) - transitivePeerDependencies: - - '@types/react' - - supports-color - - react-smooth@4.0.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - fast-equals: 5.4.0 - prop-types: 15.8.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-transition-group: 4.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-stately@3.46.0(react@19.2.6): dependencies: '@internationalized/date': 3.12.1 @@ -9337,15 +8154,6 @@ snapshots: react-dom: 19.2.6(react@19.2.6) uuid: 7.0.3 - react-transition-group@4.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - '@babel/runtime': 7.29.2 - dom-helpers: 5.2.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react@19.2.6: {} read-cache@1.0.0: @@ -9377,23 +8185,6 @@ snapshots: readdirp@5.0.0: {} - recharts-scale@0.4.5: - dependencies: - decimal.js-light: 2.5.1 - - recharts@2.15.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - clsx: 2.1.1 - eventemitter3: 4.0.7 - lodash: 4.18.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-is: 18.3.1 - react-smooth: 4.0.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - recharts-scale: 0.4.5 - tiny-invariant: 1.3.3 - victory-vendor: 36.9.2 - redux-batched-actions@0.5.0(redux@5.0.1): dependencies: redux: 5.0.1 @@ -9488,26 +8279,26 @@ snapshots: glob: 13.0.6 package-json-from-dist: 1.0.1 - rolldown@1.0.2: + rolldown@1.0.3: dependencies: - '@oxc-project/types': 0.132.0 + '@oxc-project/types': 0.133.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.2 - '@rolldown/binding-darwin-arm64': 1.0.2 - '@rolldown/binding-darwin-x64': 1.0.2 - '@rolldown/binding-freebsd-x64': 1.0.2 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 - '@rolldown/binding-linux-arm64-gnu': 1.0.2 - '@rolldown/binding-linux-arm64-musl': 1.0.2 - '@rolldown/binding-linux-ppc64-gnu': 1.0.2 - '@rolldown/binding-linux-s390x-gnu': 1.0.2 - '@rolldown/binding-linux-x64-gnu': 1.0.2 - '@rolldown/binding-linux-x64-musl': 1.0.2 - '@rolldown/binding-openharmony-arm64': 1.0.2 - '@rolldown/binding-wasm32-wasi': 1.0.2 - '@rolldown/binding-win32-arm64-msvc': 1.0.2 - '@rolldown/binding-win32-x64-msvc': 1.0.2 + '@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 run-parallel@1.2.0: dependencies: @@ -9558,11 +8349,7 @@ snapshots: semver@7.8.0: {} - seroval-plugins@1.5.4(seroval@1.5.4): - dependencies: - seroval: 1.5.4 - - seroval@1.5.4: {} + semver@7.8.4: {} set-cookie-parser@2.7.2: {} @@ -9655,7 +8442,7 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.0: + side-channel@1.1.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -9699,8 +8486,6 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 - source-map@0.5.7: {} - source-map@0.6.1: {} spawndamnit@3.0.1: @@ -9772,14 +8557,14 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 gopd: 1.2.0 has-symbols: 1.1.0 internal-slot: 1.1.0 regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.1.0 + side-channel: 1.1.1 string.prototype.padend@3.1.6: dependencies: @@ -9793,7 +8578,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 - string.prototype.trim@1.2.10: + string.prototype.trim@1.2.11: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -9802,6 +8587,14 @@ snapshots: es-abstract: 1.24.2 es-object-atoms: 1.1.2 has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 + + string.prototype.trimend@1.0.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 string.prototype.trimend@1.0.9: dependencies: @@ -9834,14 +8627,12 @@ snapshots: strip-json-comments@3.1.1: {} - styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.6): + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.6): dependencies: client-only: 0.0.1 react: 19.2.6 optionalDependencies: - '@babel/core': 7.29.0 - - stylis@4.2.0: {} + '@babel/core': 7.29.7 subarg@1.0.0: dependencies: @@ -9906,15 +8697,8 @@ snapshots: tabbable@6.4.0: {} - tailwind-merge@3.6.0: {} - tailwindcss@4.3.0: {} - tanu@0.1.13: - dependencies: - tslib: 2.8.1 - typescript: 4.9.5 - tapable@2.3.3: {} tar-fs@2.1.4: @@ -9941,7 +8725,7 @@ snapshots: term-size@2.2.1: {} - terser@5.47.1: + terser@5.48.0: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.16.0 @@ -9954,17 +8738,22 @@ snapshots: transitivePeerDependencies: - react-native-b4a - tiny-invariant@1.3.3: {} - tinybench@2.9.0: {} tinyexec@1.1.2: {} + tinyexec@1.2.4: {} + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tinyrainbow@3.1.0: {} tldts-core@7.0.30: {} @@ -9989,10 +8778,6 @@ snapshots: dependencies: typescript: 6.0.3 - ts-pattern@5.9.0: {} - - ts-toolbelt@9.6.0: {} - tsc-alias@1.8.17: dependencies: chokidar: 3.6.0 @@ -10016,21 +8801,19 @@ snapshots: dependencies: safe-buffer: 5.2.1 - turbo@2.9.14: + turbo@2.9.17: optionalDependencies: - '@turbo/darwin-64': 2.9.14 - '@turbo/darwin-arm64': 2.9.14 - '@turbo/linux-64': 2.9.14 - '@turbo/linux-arm64': 2.9.14 - '@turbo/windows-64': 2.9.14 - '@turbo/windows-arm64': 2.9.14 + '@turbo/darwin-64': 2.9.17 + '@turbo/darwin-arm64': 2.9.17 + '@turbo/linux-64': 2.9.17 + '@turbo/linux-arm64': 2.9.17 + '@turbo/windows-64': 2.9.17 + '@turbo/windows-arm64': 2.9.17 type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - type-fest@3.13.1: {} - typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -10055,7 +8838,7 @@ snapshots: is-typed-array: 1.1.15 reflect.getprototypeof: 1.0.10 - typed-array-length@1.0.7: + typed-array-length@1.0.8: dependencies: call-bind: 1.0.9 for-each: 0.3.5 @@ -10064,24 +8847,19 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): + typescript-eslint@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) - '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/eslint-plugin': 8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) eslint: 9.39.4(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - typescript@4.9.5: {} - typescript@6.0.3: {} - uglify-js@3.19.3: - optional: true - unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -10089,7 +8867,9 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.16.0: {} + undici-types@7.18.2: {} + + undici-types@7.24.6: {} undici-types@7.25.0: {} @@ -10099,12 +8879,6 @@ snapshots: universalify@2.0.1: {} - unplugin@3.0.0: - dependencies: - '@jridgewell/remapping': 2.3.5 - picomatch: 4.0.4 - webpack-virtual-modules: 0.6.2 - unrs-resolver@1.12.2: dependencies: napi-postinstall: 0.3.4 @@ -10144,12 +8918,6 @@ snapshots: dependencies: punycode: 2.3.1 - use-isomorphic-layout-effect@1.2.1(@types/react@19.2.15)(react@19.2.6): - dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - use-sync-external-store@1.6.0(react@19.2.6): dependencies: react: 19.2.6 @@ -10163,23 +8931,6 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - victory-vendor@36.9.2: - dependencies: - '@types/d3-array': 3.2.2 - '@types/d3-ease': 3.0.2 - '@types/d3-interpolate': 3.0.4 - '@types/d3-scale': 4.0.9 - '@types/d3-shape': 3.1.8 - '@types/d3-time': 3.0.4 - '@types/d3-timer': 3.0.2 - d3-array: 3.2.4 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-scale: 4.0.2 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-timer: 3.0.1 - vinyl@3.0.1: dependencies: clone: 2.1.2 @@ -10190,30 +8941,40 @@ snapshots: - bare-abort-controller - react-native-b4a - vite-plugin-handlebars@2.0.3(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)): + vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0): dependencies: - handlebars: 4.7.9 - vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.1 + fsevents: 2.3.3 + jiti: 2.7.0 + sass: 1.100.0 + terser: 5.48.0 + yaml: 2.9.0 - vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0): + vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 postcss: 8.5.15 - rolldown: 1.0.2 - tinyglobby: 0.2.16 + rolldown: 1.0.3 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 24.12.4 + '@types/node': 25.9.2 fsevents: 2.3.3 jiti: 2.7.0 sass: 1.100.0 - terser: 5.47.1 + terser: 5.48.0 yaml: 2.9.0 - vitest@4.1.6(@types/node@24.12.4)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)): + vitest@4.1.6(@types/node@24.13.1)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.6 - '@vitest/mocker': 4.1.6(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0)) + '@vitest/mocker': 4.1.6(vite@8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.6 '@vitest/runner': 4.1.6 '@vitest/snapshot': 4.1.6 @@ -10230,10 +8991,38 @@ snapshots: tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.14(@types/node@24.12.4)(jiti@2.7.0)(sass@1.100.0)(terser@5.47.1)(yaml@2.9.0) + vite: 8.0.16(@types/node@24.13.1)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.12.4 + '@types/node': 24.13.1 + jsdom: 29.1.1(canvas@3.2.3) + transitivePeerDependencies: + - msw + + vitest@4.1.6(@types/node@25.9.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)): + dependencies: + '@vitest/expect': 4.1.6 + '@vitest/mocker': 4.1.6(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.6 + '@vitest/runner': 4.1.6 + '@vitest/snapshot': 4.1.6 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 8.0.16(@types/node@25.9.2)(jiti@2.7.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.9.2 jsdom: 29.1.1(canvas@3.2.3) transitivePeerDependencies: - msw @@ -10250,8 +9039,6 @@ snapshots: webidl-conversions@8.0.1: {} - webpack-virtual-modules@0.6.2: {} - whatwg-mimetype@5.0.0: {} whatwg-url@16.0.1: @@ -10262,11 +9049,6 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - whence@2.1.0: - dependencies: - '@babel/parser': 7.29.3 - eval-estree-expression: 3.0.1 - which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -10289,7 +9071,7 @@ snapshots: isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.20 + which-typed-array: 1.1.22 which-collection@1.0.2: dependencies: @@ -10298,7 +9080,7 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 - which-typed-array@1.1.20: + which-typed-array@1.1.22: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.9 @@ -10325,8 +9107,6 @@ snapshots: word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - wrap-ansi@10.0.0: dependencies: ansi-styles: 6.2.3 @@ -10351,9 +9131,8 @@ snapshots: yallist@3.1.1: {} - yaml@1.10.3: {} - - yaml@2.9.0: {} + yaml@2.9.0: + optional: true yargs-parser@22.0.0: {} @@ -10377,8 +9156,6 @@ snapshots: dependencies: zod: 4.4.3 - zod@3.25.76: {} - zod@4.4.3: {} zstddec@0.2.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 12dabc2d..ec5f9b69 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -15,7 +15,7 @@ catalog: "@types/jsdom": "^28.0.3" "canvas": "^3.1.0" "@types/lodash": "^4.17.24" - "@types/node": "^24.12.4" + "@types/node": "^24.13.1" "@types/react": "^19.2.15" "@types/react-dom": "^19.2.3" "@types/react-redux": "^7.1.34" From 270595ec6787759854de1a0ad4e7b1a2afc0c444 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 11 Jun 2026 16:17:44 +0200 Subject: [PATCH 48/49] cleanup after refactoring Signed-off-by: Paul Golmann --- packages/core/eslint.config.mts | 8 ++ packages/core/src/js/mixins/EditorMixin.ts | 4 +- packages/traffic-style/eslint.config.mts | 2 +- .../scripts/dev/build-composable-icons.ts | 2 +- .../scripts/dev/import-pictograms.ts | 2 +- .../scripts/dev/write-dist-package.json.ts | 9 +- .../scripts/lib/composable-icons.ts | 3 +- .../scripts/traffic-composable-icons.ts | 2 +- .../traffic-style/src/lib/icon/compose.d.ts | 4 - .../src/lib/icon/compose.d.ts.map | 1 - .../traffic-style/src/lib/icon/compose.js | 74 ------------ .../traffic-style/src/lib/icon/compose.js.map | 1 - .../traffic-style/src/lib/icon/contrast.d.ts | 6 - .../src/lib/icon/contrast.d.ts.map | 1 - .../traffic-style/src/lib/icon/contrast.js | 53 --------- .../src/lib/icon/contrast.js.map | 1 - .../traffic-style/src/lib/icon/icon-id.d.ts | 21 ---- .../src/lib/icon/icon-id.d.ts.map | 1 - .../traffic-style/src/lib/icon/icon-id.js | 112 ------------------ .../traffic-style/src/lib/icon/icon-id.js.map | 1 - .../traffic-style/src/lib/icon/rasterize.d.ts | 17 --- .../src/lib/icon/rasterize.d.ts.map | 1 - .../traffic-style/src/lib/icon/rasterize.js | 52 -------- .../src/lib/icon/rasterize.js.map | 1 - .../traffic-style/src/lib/icon/resolve.d.ts | 10 -- .../src/lib/icon/resolve.d.ts.map | 1 - .../traffic-style/src/lib/icon/resolve.js | 16 --- .../traffic-style/src/lib/icon/resolve.js.map | 1 - .../traffic-style/src/lib/icon/templates.d.ts | 22 ---- .../src/lib/icon/templates.d.ts.map | 1 - .../traffic-style/src/lib/icon/templates.js | 68 ----------- .../src/lib/icon/templates.js.map | 1 - .../src/lib/pictograms/index.d.ts | 18 --- .../src/lib/pictograms/index.d.ts.map | 1 - .../traffic-style/src/lib/pictograms/index.js | 28 ----- .../src/lib/pictograms/index.js.map | 1 - .../traffic-style/src/lib/runtime/index.ts | 1 + packages/ui/eslint.config.mts | 3 + .../js/components/feature-list-item/icon.tsx | 8 +- packages/ui/src/js/hooks/use-mapsight-icon.ts | 72 ----------- packages/ui/vitest.config.ts | 5 - .../__tests__/helperImports.test.ts | 2 +- 42 files changed, 28 insertions(+), 610 deletions(-) delete mode 100644 packages/traffic-style/src/lib/icon/compose.d.ts delete mode 100644 packages/traffic-style/src/lib/icon/compose.d.ts.map delete mode 100644 packages/traffic-style/src/lib/icon/compose.js delete mode 100644 packages/traffic-style/src/lib/icon/compose.js.map delete mode 100644 packages/traffic-style/src/lib/icon/contrast.d.ts delete mode 100644 packages/traffic-style/src/lib/icon/contrast.d.ts.map delete mode 100644 packages/traffic-style/src/lib/icon/contrast.js delete mode 100644 packages/traffic-style/src/lib/icon/contrast.js.map delete mode 100644 packages/traffic-style/src/lib/icon/icon-id.d.ts delete mode 100644 packages/traffic-style/src/lib/icon/icon-id.d.ts.map delete mode 100644 packages/traffic-style/src/lib/icon/icon-id.js delete mode 100644 packages/traffic-style/src/lib/icon/icon-id.js.map delete mode 100644 packages/traffic-style/src/lib/icon/rasterize.d.ts delete mode 100644 packages/traffic-style/src/lib/icon/rasterize.d.ts.map delete mode 100644 packages/traffic-style/src/lib/icon/rasterize.js delete mode 100644 packages/traffic-style/src/lib/icon/rasterize.js.map delete mode 100644 packages/traffic-style/src/lib/icon/resolve.d.ts delete mode 100644 packages/traffic-style/src/lib/icon/resolve.d.ts.map delete mode 100644 packages/traffic-style/src/lib/icon/resolve.js delete mode 100644 packages/traffic-style/src/lib/icon/resolve.js.map delete mode 100644 packages/traffic-style/src/lib/icon/templates.d.ts delete mode 100644 packages/traffic-style/src/lib/icon/templates.d.ts.map delete mode 100644 packages/traffic-style/src/lib/icon/templates.js delete mode 100644 packages/traffic-style/src/lib/icon/templates.js.map delete mode 100644 packages/traffic-style/src/lib/pictograms/index.d.ts delete mode 100644 packages/traffic-style/src/lib/pictograms/index.d.ts.map delete mode 100644 packages/traffic-style/src/lib/pictograms/index.js delete mode 100644 packages/traffic-style/src/lib/pictograms/index.js.map delete mode 100644 packages/ui/src/js/hooks/use-mapsight-icon.ts diff --git a/packages/core/eslint.config.mts b/packages/core/eslint.config.mts index e5c1ba03..84b83370 100644 --- a/packages/core/eslint.config.mts +++ b/packages/core/eslint.config.mts @@ -4,6 +4,14 @@ import baseConfig from "../../configs/eslint-config-base.mts"; export default defineConfig([ baseConfig, + { + ignores: [ + "e2e/**", + "playwright.config.ts", + "**/*.test.ts", + "src/js/test/**", + ], + }, { name: "todos", rules: { diff --git a/packages/core/src/js/mixins/EditorMixin.ts b/packages/core/src/js/mixins/EditorMixin.ts index 6abdd1a1..54b1a2e9 100644 --- a/packages/core/src/js/mixins/EditorMixin.ts +++ b/packages/core/src/js/mixins/EditorMixin.ts @@ -171,9 +171,7 @@ export default class EditorMixin extends Mixin { setInteractionSelections( ensureNonNullable(this.controllers.map), ensureNonNullable(this.ids.layer), - (status - ? this.getSelections() - : {}) as InteractionsSelections, + status ? this.getSelections() : {}, ), set: (options: Partial = {}) => { const { diff --git a/packages/traffic-style/eslint.config.mts b/packages/traffic-style/eslint.config.mts index 9cd73d96..7a2f97a0 100644 --- a/packages/traffic-style/eslint.config.mts +++ b/packages/traffic-style/eslint.config.mts @@ -5,7 +5,7 @@ import baseConfig from "../../configs/eslint-config-base.mts"; export default defineConfig([ baseConfig, { - ignores: ["scripts/**/*.test.ts"], + ignores: ["scripts/**/*.test.ts", "src/lib/**/*.test.ts"], }, { files: ["scripts/**/*.ts"], diff --git a/packages/traffic-style/scripts/dev/build-composable-icons.ts b/packages/traffic-style/scripts/dev/build-composable-icons.ts index 1c92929c..70e8d8d1 100644 --- a/packages/traffic-style/scripts/dev/build-composable-icons.ts +++ b/packages/traffic-style/scripts/dev/build-composable-icons.ts @@ -51,5 +51,5 @@ async function main(): Promise { main().catch((error: unknown) => { console.error(error); - process.exit(1); + process.exitCode = 1; }); diff --git a/packages/traffic-style/scripts/dev/import-pictograms.ts b/packages/traffic-style/scripts/dev/import-pictograms.ts index d36be926..fcbcf511 100644 --- a/packages/traffic-style/scripts/dev/import-pictograms.ts +++ b/packages/traffic-style/scripts/dev/import-pictograms.ts @@ -121,6 +121,6 @@ const isMain = if (isMain) { main().catch((error: unknown) => { console.error(error); - process.exit(1); + process.exitCode = 1; }); } diff --git a/packages/traffic-style/scripts/dev/write-dist-package.json.ts b/packages/traffic-style/scripts/dev/write-dist-package.json.ts index 120f4dbe..5f1b3a21 100644 --- a/packages/traffic-style/scripts/dev/write-dist-package.json.ts +++ b/packages/traffic-style/scripts/dev/write-dist-package.json.ts @@ -19,7 +19,12 @@ async function main() { const raw = await readFile(sourcePath, "utf8"); const pkg = JSON.parse(raw) as PackageJson; - const {scripts, devDependencies, publishConfig, ...distPkg} = pkg; + const { + scripts: _scripts, + devDependencies: _devDependencies, + publishConfig: _publishConfig, + ...distPkg + } = pkg; if ( distPkg.imports && @@ -44,5 +49,5 @@ async function main() { main().catch((error: unknown) => { console.error(error); - process.exit(1); + process.exitCode = 1; }); diff --git a/packages/traffic-style/scripts/lib/composable-icons.ts b/packages/traffic-style/scripts/lib/composable-icons.ts index 78769f82..b1da0e8c 100644 --- a/packages/traffic-style/scripts/lib/composable-icons.ts +++ b/packages/traffic-style/scripts/lib/composable-icons.ts @@ -1,5 +1,4 @@ -import {mkdir, writeFile} from "node:fs/promises"; -import {readFile} from "node:fs/promises"; +import {mkdir, readFile, writeFile} from "node:fs/promises"; import path from "node:path"; import {composeSvg} from "#icon/compose.js"; diff --git a/packages/traffic-style/scripts/traffic-composable-icons.ts b/packages/traffic-style/scripts/traffic-composable-icons.ts index 4a81caa7..5e58475c 100644 --- a/packages/traffic-style/scripts/traffic-composable-icons.ts +++ b/packages/traffic-style/scripts/traffic-composable-icons.ts @@ -144,6 +144,6 @@ const isMain = if (isMain) { main().catch((error: unknown) => { console.error(error); - process.exit(1); + process.exitCode = 1; }); } diff --git a/packages/traffic-style/src/lib/icon/compose.d.ts b/packages/traffic-style/src/lib/icon/compose.d.ts deleted file mode 100644 index 4b4991f5..00000000 --- a/packages/traffic-style/src/lib/icon/compose.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type {IconSpec} from "./icon-id.ts"; - -export declare function composeSvg(spec: IconSpec): string; -//# sourceMappingURL=compose.d.ts.map diff --git a/packages/traffic-style/src/lib/icon/compose.d.ts.map b/packages/traffic-style/src/lib/icon/compose.d.ts.map deleted file mode 100644 index 580ea971..00000000 --- a/packages/traffic-style/src/lib/icon/compose.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["compose.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAC;AA2E3C,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CA0BjD"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/compose.js b/packages/traffic-style/src/lib/icon/compose.js deleted file mode 100644 index cc1585b6..00000000 --- a/packages/traffic-style/src/lib/icon/compose.js +++ /dev/null @@ -1,74 +0,0 @@ -import {getPictogram} from "../pictograms/index.js"; -import {resolveSpec} from "./resolve.js"; -import {getTemplate} from "./templates.js"; - -const DEFAULT_PICTOGRAM_PADDING = 0.05; -const FONT_AWESOME_PICTOGRAM_PADDING = 0.1; -function parseViewBox(viewBox) { - const parts = viewBox.split(/\s+/).map(Number); - return { - x: parts[0] ?? 0, - y: parts[1] ?? 0, - width: parts[2] ?? 0, - height: parts[3] ?? 0, - }; -} -function pictogramPadding(pictogram) { - return ( - pictogram.padding ?? - (pictogram.source === "fontawesome" - ? FONT_AWESOME_PICTOGRAM_PADDING - : DEFAULT_PICTOGRAM_PADDING) - ); -} -function insetSlot(slot, padding) { - const inset = slot.size * padding; - return { - x: slot.x + inset, - y: slot.y + inset, - size: slot.size - inset * 2, - }; -} -function renderPictogram(pictogram, slot, color) { - const paddedSlot = insetSlot(slot, pictogramPadding(pictogram)); - const {x, y, width, height} = parseViewBox(pictogram.viewBox); - if (width <= 0 || height <= 0) { - return ""; - } - const scale = Math.min(paddedSlot.size / width, paddedSlot.size / height); - const scaledWidth = width * scale; - const scaledHeight = height * scale; - const translateX = paddedSlot.x + (paddedSlot.size - scaledWidth) / 2; - const translateY = paddedSlot.y + (paddedSlot.size - scaledHeight) / 2; - return `${pictogram.markup}`; -} -function renderLabel(label, anchor, fontSize, foreground, background) { - const text = label.slice(0, 2).toUpperCase(); - const strokeWidth = Math.max(2, fontSize * 0.32); - return `${text}`; -} -export function composeSvg(spec) { - const resolved = resolveSpec(spec); - const template = getTemplate(resolved.variant); - const hasPictogram = Boolean(resolved.pictogram); - const hasLabel = Boolean(resolved.label?.trim()); - let inner = template.renderBackground(resolved.colors); - if (hasPictogram && resolved.pictogram) { - const pictogram = getPictogram(resolved.pictogram); - inner += renderPictogram( - pictogram, - template.contentSlot, - resolved.colors.foreground, - ); - } else if (hasLabel && resolved.label) { - inner += renderLabel( - resolved.label, - template.textAnchor, - template.fontSize, - resolved.colors.foreground, - resolved.colors.background, - ); - } - return `${inner}`; -} -//# sourceMappingURL=compose.js.map diff --git a/packages/traffic-style/src/lib/icon/compose.js.map b/packages/traffic-style/src/lib/icon/compose.js.map deleted file mode 100644 index 294fed15..00000000 --- a/packages/traffic-style/src/lib/icon/compose.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"compose.js","sourceRoot":"","sources":["compose.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,YAAY,EAAC,MAAM,wBAAwB,CAAC;AAE9E,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAE3C,MAAM,yBAAyB,GAAG,IAAI,CAAC;AACvC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAE3C,SAAS,YAAY,CAAC,OAAe;IAMpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO;QACN,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAChB,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACpB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;KACrB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,SAA8B;IACvD,OAAO,CACN,SAAS,CAAC,OAAO;QACjB,CAAC,SAAS,CAAC,MAAM,KAAK,aAAa;YAClC,CAAC,CAAC,8BAA8B;YAChC,CAAC,CAAC,yBAAyB,CAAC,CAC7B,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CACjB,IAA0C,EAC1C,OAAe;IAEf,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;IAClC,OAAO;QACN,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,KAAK;QACjB,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,KAAK,GAAG,CAAC;KAC3B,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CACvB,SAA8B,EAC9B,IAA0C,EAC1C,KAAa;IAEb,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;IAChE,MAAM,EAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAC,GAAG,YAAY,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9D,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,KAAK,EAAE,UAAU,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IAC1E,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,CAAC;IAClC,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC;IACpC,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAEvE,OAAO,2BAA2B,UAAU,IAAI,UAAU,WAAW,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,KAAK,KAAK,SAAS,CAAC,MAAM,MAAM,CAAC;AAChJ,CAAC;AAED,SAAS,WAAW,CACnB,KAAa,EACb,MAA8B,EAC9B,QAAgB,EAChB,UAAkB,EAClB,UAAkB;IAElB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC,CAAC;IACjD,OAAO,YAAY,MAAM,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,WAAW,UAAU,aAAa,UAAU,mBAAmB,WAAW,qFAAqF,QAAQ,4CAA4C,IAAI,SAAS,CAAC;AAC7Q,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAc;IACxC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjD,IAAI,KAAK,GAAG,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEvD,IAAI,YAAY,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACnD,KAAK,IAAI,eAAe,CACvB,SAAS,EACT,QAAQ,CAAC,WAAW,EACpB,QAAQ,CAAC,MAAM,CAAC,UAAU,CAC1B,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QACvC,KAAK,IAAI,WAAW,CACnB,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,QAAQ,EACjB,QAAQ,CAAC,MAAM,CAAC,UAAU,EAC1B,QAAQ,CAAC,MAAM,CAAC,UAAU,CAC1B,CAAC;IACH,CAAC;IAED,OAAO,6FAA6F,QAAQ,CAAC,KAAK,aAAa,QAAQ,CAAC,MAAM,cAAc,QAAQ,CAAC,OAAO,wCAAwC,KAAK,YAAY,CAAC;AACvO,CAAC"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/contrast.d.ts b/packages/traffic-style/src/lib/icon/contrast.d.ts deleted file mode 100644 index 86838275..00000000 --- a/packages/traffic-style/src/lib/icon/contrast.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export declare function relativeLuminance(color: string): number | null; -/** Pick #000 or #fff whichever contrasts better with the background. */ -export declare function pickContrastForeground( - background: string, -): "#000000" | "#ffffff"; -//# sourceMappingURL=contrast.d.ts.map diff --git a/packages/traffic-style/src/lib/icon/contrast.d.ts.map b/packages/traffic-style/src/lib/icon/contrast.d.ts.map deleted file mode 100644 index f33576ca..00000000 --- a/packages/traffic-style/src/lib/icon/contrast.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"contrast.d.ts","sourceRoot":"","sources":["contrast.ts"],"names":[],"mappings":"AAwBA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW9D;AAMD,wEAAwE;AACxE,wBAAgB,sBAAsB,CACrC,UAAU,EAAE,MAAM,GAChB,SAAS,GAAG,SAAS,CAgBvB"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/contrast.js b/packages/traffic-style/src/lib/icon/contrast.js deleted file mode 100644 index e5a444e3..00000000 --- a/packages/traffic-style/src/lib/icon/contrast.js +++ /dev/null @@ -1,53 +0,0 @@ -function hexToRgb(hex) { - const normalized = hex.trim().replace(/^#/, ""); - if (normalized.length === 3) { - return { - r: Number.parseInt(normalized[0] + normalized[0], 16), - g: Number.parseInt(normalized[1] + normalized[1], 16), - b: Number.parseInt(normalized[2] + normalized[2], 16), - }; - } - if (normalized.length === 6) { - return { - r: Number.parseInt(normalized.slice(0, 2), 16), - g: Number.parseInt(normalized.slice(2, 4), 16), - b: Number.parseInt(normalized.slice(4, 6), 16), - }; - } - return null; -} -function srgbChannel(channel) { - const value = channel / 255; - return value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4; -} -export function relativeLuminance(color) { - const rgb = hexToRgb(color); - if (!rgb) { - return null; - } - return ( - 0.2126 * srgbChannel(rgb.r) + - 0.7152 * srgbChannel(rgb.g) + - 0.0722 * srgbChannel(rgb.b) - ); -} -function contrastRatio(lighter, darker) { - return (lighter + 0.05) / (darker + 0.05); -} -/** Pick #000 or #fff whichever contrasts better with the background. */ -export function pickContrastForeground(background) { - const backgroundLuminance = relativeLuminance(background); - if (backgroundLuminance == null) { - return "#000000"; - } - const contrastWithBlack = contrastRatio( - Math.max(backgroundLuminance, 0), - Math.min(backgroundLuminance, 0), - ); - const contrastWithWhite = contrastRatio( - Math.max(backgroundLuminance, 1), - Math.min(backgroundLuminance, 1), - ); - return contrastWithWhite >= contrastWithBlack ? "#ffffff" : "#000000"; -} -//# sourceMappingURL=contrast.js.map diff --git a/packages/traffic-style/src/lib/icon/contrast.js.map b/packages/traffic-style/src/lib/icon/contrast.js.map deleted file mode 100644 index a2bd6f32..00000000 --- a/packages/traffic-style/src/lib/icon/contrast.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"contrast.js","sourceRoot":"","sources":["contrast.ts"],"names":[],"mappings":"AAAA,SAAS,QAAQ,CAAC,GAAW;IAC5B,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAChD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO;YACN,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,GAAG,UAAU,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;YACvD,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,GAAG,UAAU,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;YACvD,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,GAAG,UAAU,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;SACvD,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO;YACN,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9C,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9C,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;SAC9C,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,OAAe;IACnC,MAAM,KAAK,GAAG,OAAO,GAAG,GAAG,CAAC;IAC5B,OAAO,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,CACN,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAC3B,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,OAAe,EAAE,MAAc;IACrD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,sBAAsB,CACrC,UAAkB;IAElB,MAAM,mBAAmB,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC1D,IAAI,mBAAmB,IAAI,IAAI,EAAE,CAAC;QACjC,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,MAAM,iBAAiB,GAAG,aAAa,CACtC,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAChC,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAChC,CAAC;IACF,MAAM,iBAAiB,GAAG,aAAa,CACtC,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAChC,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAChC,CAAC;IAEF,OAAO,iBAAiB,IAAI,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/icon-id.d.ts b/packages/traffic-style/src/lib/icon/icon-id.d.ts deleted file mode 100644 index d33fe8b3..00000000 --- a/packages/traffic-style/src/lib/icon/icon-id.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type IconVariant = "default" | "small" | "xsmall" | "plain"; -export type IconColors = { - background?: string; - foreground?: string; -}; -export type IconSpec = { - variant?: IconVariant; - pictogram?: string; - label?: string; - colors?: IconColors; -}; -/** Parse a compact `mapsightIconId` value into an IconSpec. */ -export declare function parseMapsightIcon(value: string): IconSpec | null; -/** Serialize an IconSpec to the compact `mapsightIconId` form. */ -export declare function formatMapsightIcon(spec: IconSpec): string; -/** Resolve a compact id + variant to the internal render spec. */ -export declare function resolveMapsightIconSpec( - mapsightIconId: string, - variant?: IconVariant, -): IconSpec | null; -//# sourceMappingURL=icon-id.d.ts.map diff --git a/packages/traffic-style/src/lib/icon/icon-id.d.ts.map b/packages/traffic-style/src/lib/icon/icon-id.d.ts.map deleted file mode 100644 index 1722ac44..00000000 --- a/packages/traffic-style/src/lib/icon/icon-id.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"icon-id.d.ts","sourceRoot":"","sources":["icon-id.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEnE,MAAM,MAAM,UAAU,GAAG;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACtB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,CAAC;CACpB,CAAC;AAqDF,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA0BhE;AAED,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAsCzD;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CACtC,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,WAAW,GACnB,QAAQ,GAAG,IAAI,CAWjB"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/icon-id.js b/packages/traffic-style/src/lib/icon/icon-id.js deleted file mode 100644 index dd52e9f5..00000000 --- a/packages/traffic-style/src/lib/icon/icon-id.js +++ /dev/null @@ -1,112 +0,0 @@ -import {hasPictogram} from "../pictograms/index.js"; -import {pickContrastForeground} from "./contrast.js"; -import {resolveSpec} from "./resolve.js"; - -const DEFAULT_RUNTIME_ICON = "marker"; -const COLOR_SEGMENT = /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i; -const LETTER_OR_NUMBER_ID = /^[0-9a-z]$/; -const COMPACT_LABEL_ID = /^[0-9a-zA-Z]{1,2}$/; -function normalizeColorSegment(value) { - if (!value) { - return undefined; - } - const trimmed = value.trim(); - return COLOR_SEGMENT.test(trimmed) ? trimmed : undefined; -} -function specFromIconIdSegment(iconId, options = {}) { - const base = {...options}; - if (hasPictogram(iconId)) { - return {...base, pictogram: iconId}; - } - if (LETTER_OR_NUMBER_ID.test(iconId)) { - const label = /^\d$/.test(iconId) ? iconId : iconId.toUpperCase(); - return {...base, label}; - } - if (COMPACT_LABEL_ID.test(iconId)) { - return {...base, label: iconId.toUpperCase()}; - } - return {...base, pictogram: iconId}; -} -function withDefaultPictogramFallback(spec) { - if (spec.label || !spec.pictogram || hasPictogram(spec.pictogram)) { - return spec; - } - const fallback = parseMapsightIcon(DEFAULT_RUNTIME_ICON); - if (!fallback?.pictogram) { - return spec; - } - return { - ...fallback, - colors: spec.colors ?? fallback.colors, - }; -} -/** Parse a compact `mapsightIconId` value into an IconSpec. */ -export function parseMapsightIcon(value) { - const trimmed = value.trim(); - if (!trimmed) { - return null; - } - const [iconIdPart, backgroundPart, foregroundPart] = trimmed.split("/"); - const iconId = iconIdPart?.trim(); - if (!iconId) { - return null; - } - const background = normalizeColorSegment(backgroundPart); - const explicitForeground = normalizeColorSegment(foregroundPart); - const colors = {}; - if (background) { - colors.background = background; - colors.foreground = - explicitForeground ?? pickContrastForeground(background); - } - return specFromIconIdSegment( - iconId, - Object.keys(colors).length > 0 ? {colors} : {}, - ); -} -/** Serialize an IconSpec to the compact `mapsightIconId` form. */ -export function formatMapsightIcon(spec) { - const iconId = - spec.pictogram ?? - spec.label?.slice(0, 2).toUpperCase() ?? - spec.label?.trim(); - if (!iconId) { - return ""; - } - const background = spec.colors?.background; - const foreground = spec.colors?.foreground; - const resolved = resolveSpec({ - pictogram: spec.pictogram, - label: spec.label, - colors: spec.colors, - }); - if ( - resolved.colors.background === resolveSpec({}).colors.background && - resolved.colors.foreground === resolveSpec({}).colors.foreground - ) { - return iconId; - } - if (!background) { - return iconId; - } - if (!foreground) { - return `${iconId}/${background}`; - } - const autoForeground = pickContrastForeground(background); - if (foreground.toLowerCase() === autoForeground.toLowerCase()) { - return `${iconId}/${background}`; - } - return `${iconId}/${background}/${foreground}`; -} -/** Resolve a compact id + variant to the internal render spec. */ -export function resolveMapsightIconSpec(mapsightIconId, variant) { - const trimmed = mapsightIconId.trim(); - if (!trimmed) { - return null; - } - const spec = withDefaultPictogramFallback( - parseMapsightIcon(trimmed) ?? {pictogram: trimmed}, - ); - return variant ? {...spec, variant} : spec; -} -//# sourceMappingURL=icon-id.js.map diff --git a/packages/traffic-style/src/lib/icon/icon-id.js.map b/packages/traffic-style/src/lib/icon/icon-id.js.map deleted file mode 100644 index c5cb187d..00000000 --- a/packages/traffic-style/src/lib/icon/icon-id.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"icon-id.js","sourceRoot":"","sources":["icon-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAC,sBAAsB,EAAC,MAAM,eAAe,CAAC;AACrD,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAgBzC,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AACtC,MAAM,aAAa,GAAG,iCAAiC,CAAC;AACxD,MAAM,mBAAmB,GAAG,YAAY,CAAC;AACzC,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AAE9C,SAAS,qBAAqB,CAAC,KAAyB;IACvD,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,SAAS,qBAAqB,CAC7B,MAAc,EACd,UAAgD,EAAE;IAElD,MAAM,IAAI,GAAa,EAAC,GAAG,OAAO,EAAC,CAAC;IAEpC,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAC,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,EAAC,CAAC;IACrC,CAAC;IAED,IAAI,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAClE,OAAO,EAAC,GAAG,IAAI,EAAE,KAAK,EAAC,CAAC;IACzB,CAAC;IAED,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACnC,OAAO,EAAC,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,EAAC,CAAC;IAC/C,CAAC;IAED,OAAO,EAAC,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,EAAC,CAAC;AACrC,CAAC;AAED,SAAS,4BAA4B,CAAC,IAAc;IACnD,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACnE,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;IACzD,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO;QACN,GAAG,QAAQ;QACX,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;KACtC,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,UAAU,EAAE,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,UAAU,GAAG,qBAAqB,CAAC,cAAc,CAAC,CAAC;IACzD,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,cAAc,CAAC,CAAC;IACjE,MAAM,MAAM,GAAe,EAAE,CAAC;IAE9B,IAAI,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;QAC/B,MAAM,CAAC,UAAU;YAChB,kBAAkB,IAAI,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,qBAAqB,CAC3B,MAAM,EACN,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAC,MAAM,EAAC,CAAC,CAAC,CAAC,EAAE,CAC9C,CAAC;AACH,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,kBAAkB,CAAC,IAAc;IAChD,MAAM,MAAM,GACX,IAAI,CAAC,SAAS;QACd,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE;QACrC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACpB,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;IAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC;QAC5B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;KACnB,CAAC,CAAC;IAEH,IACC,QAAQ,CAAC,MAAM,CAAC,UAAU,KAAK,WAAW,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU;QAChE,QAAQ,CAAC,MAAM,CAAC,UAAU,KAAK,WAAW,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,EAC/D,CAAC;QACF,OAAO,MAAM,CAAC;IACf,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,MAAM,CAAC;IACf,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,cAAc,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAC1D,IAAI,UAAU,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/D,OAAO,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;IAClC,CAAC;IAED,OAAO,GAAG,MAAM,IAAI,UAAU,IAAI,UAAU,EAAE,CAAC;AAChD,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB,CACtC,cAAsB,EACtB,OAAqB;IAErB,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;IACtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,IAAI,GAAG,4BAA4B,CACxC,iBAAiB,CAAC,OAAO,CAAC,IAAI,EAAC,SAAS,EAAE,OAAO,EAAC,CAClD,CAAC;IAEF,OAAO,OAAO,CAAC,CAAC,CAAC,EAAC,GAAG,IAAI,EAAE,OAAO,EAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,CAAC"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/rasterize.d.ts b/packages/traffic-style/src/lib/icon/rasterize.d.ts deleted file mode 100644 index fe2945c7..00000000 --- a/packages/traffic-style/src/lib/icon/rasterize.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** Rasterize the SVG at the target pixel size so vectors stay crisp (not upscaled). */ -export declare function prepareSvgForRasterization( - svg: string, - pixelWidth: number, - pixelHeight: number, -): string; -export declare function rasterizeSvg( - svg: string, - logicalWidth: number, - logicalHeight: number, - pixelRatio?: number, -): Promise<{ - dataUrl: string; - width: number; - height: number; -}>; -//# sourceMappingURL=rasterize.d.ts.map diff --git a/packages/traffic-style/src/lib/icon/rasterize.d.ts.map b/packages/traffic-style/src/lib/icon/rasterize.d.ts.map deleted file mode 100644 index 713ffa6c..00000000 --- a/packages/traffic-style/src/lib/icon/rasterize.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"rasterize.d.ts","sourceRoot":"","sources":["rasterize.ts"],"names":[],"mappings":"AASA,uFAAuF;AACvF,wBAAgB,0BAA0B,CACzC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACjB,MAAM,CAUR;AAED,wBAAsB,YAAY,CACjC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,SAAI,GACZ,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAAC,CA8B3D"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/rasterize.js b/packages/traffic-style/src/lib/icon/rasterize.js deleted file mode 100644 index feb14467..00000000 --- a/packages/traffic-style/src/lib/icon/rasterize.js +++ /dev/null @@ -1,52 +0,0 @@ -function loadImage(url) { - return new Promise((resolve, reject) => { - const image = new Image(); - image.onload = () => resolve(image); - image.onerror = () => reject(new Error("Failed to rasterize SVG icon")); - image.src = url; - }); -} -/** Rasterize the SVG at the target pixel size so vectors stay crisp (not upscaled). */ -export function prepareSvgForRasterization(svg, pixelWidth, pixelHeight) { - return svg.replace(/]*)?>/, (_match, attrs = "") => { - const cleaned = attrs - .replace(/\swidth="[^"]*"/g, "") - .replace(/\sheight="[^"]*"/g, ""); - return ``; - }); -} -export async function rasterizeSvg( - svg, - logicalWidth, - logicalHeight, - pixelRatio = 1, -) { - if (typeof document === "undefined") { - throw new Error("rasterizeSvg requires a browser DOM environment"); - } - const width = Math.round(logicalWidth * pixelRatio); - const height = Math.round(logicalHeight * pixelRatio); - const rasterSvg = prepareSvgForRasterization(svg, width, height); - const blob = new Blob([rasterSvg], {type: "image/svg+xml;charset=utf-8"}); - const url = URL.createObjectURL(blob); - try { - const image = await loadImage(url); - const canvas = document.createElement("canvas"); - canvas.width = width; - canvas.height = height; - const context = canvas.getContext("2d"); - if (!context) { - throw new Error("Canvas 2D context unavailable"); - } - context.imageSmoothingEnabled = false; - context.drawImage(image, 0, 0, width, height); - return { - dataUrl: canvas.toDataURL("image/png"), - width, - height, - }; - } finally { - URL.revokeObjectURL(url); - } -} -//# sourceMappingURL=rasterize.js.map diff --git a/packages/traffic-style/src/lib/icon/rasterize.js.map b/packages/traffic-style/src/lib/icon/rasterize.js.map deleted file mode 100644 index 2012be0b..00000000 --- a/packages/traffic-style/src/lib/icon/rasterize.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"rasterize.js","sourceRoot":"","sources":["rasterize.ts"],"names":[],"mappings":"AAAA,SAAS,SAAS,CAAC,GAAW;IAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAC1B,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpC,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;QACxE,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,0BAA0B,CACzC,GAAW,EACX,UAAkB,EAClB,WAAmB;IAEnB,OAAO,GAAG,CAAC,OAAO,CACjB,iBAAiB,EACjB,CAAC,MAAc,EAAE,QAAgB,EAAE,EAAE,EAAE;QACtC,MAAM,OAAO,GAAG,KAAK;aACnB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;aAC/B,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACnC,OAAO,OAAO,OAAO,WAAW,UAAU,aAAa,WAAW,IAAI,CAAC;IACxE,CAAC,CACD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,GAAW,EACX,YAAoB,EACpB,aAAqB,EACrB,UAAU,GAAG,CAAC;IAEd,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,UAAU,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,UAAU,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,0BAA0B,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAC,IAAI,EAAE,6BAA6B,EAAC,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,CAAC,qBAAqB,GAAG,KAAK,CAAC;QACtC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC9C,OAAO;YACN,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC;YACtC,KAAK;YACL,MAAM;SACN,CAAC;IACH,CAAC;YAAS,CAAC;QACV,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;AACF,CAAC"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/resolve.d.ts b/packages/traffic-style/src/lib/icon/resolve.d.ts deleted file mode 100644 index 3ab52cdf..00000000 --- a/packages/traffic-style/src/lib/icon/resolve.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type {IconColors, IconSpec} from "./icon-id.ts"; - -export type RequiredIconColors = Required; -export type ResolvedIconSpec = Required> & - IconSpec & { - colors: RequiredIconColors; - }; -export declare const RUNTIME_ICON_PIXEL_RATIO = 2; -export declare function resolveSpec(spec: IconSpec): ResolvedIconSpec; -//# sourceMappingURL=resolve.d.ts.map diff --git a/packages/traffic-style/src/lib/icon/resolve.d.ts.map b/packages/traffic-style/src/lib/icon/resolve.d.ts.map deleted file mode 100644 index 3e46036a..00000000 --- a/packages/traffic-style/src/lib/icon/resolve.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAE,QAAQ,EAAC,MAAM,cAAc,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAEtD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,GACjE,QAAQ,GAAG;IACV,MAAM,EAAE,kBAAkB,CAAC;CAC3B,CAAC;AAOH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,gBAAgB,CAS5D"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/resolve.js b/packages/traffic-style/src/lib/icon/resolve.js deleted file mode 100644 index d0d9573f..00000000 --- a/packages/traffic-style/src/lib/icon/resolve.js +++ /dev/null @@ -1,16 +0,0 @@ -const DEFAULT_COLORS = { - background: "#ffffff", - foreground: "#000000", -}; -export const RUNTIME_ICON_PIXEL_RATIO = 2; -export function resolveSpec(spec) { - return { - ...spec, - variant: spec.variant ?? "default", - colors: { - ...DEFAULT_COLORS, - ...spec.colors, - }, - }; -} -//# sourceMappingURL=resolve.js.map diff --git a/packages/traffic-style/src/lib/icon/resolve.js.map b/packages/traffic-style/src/lib/icon/resolve.js.map deleted file mode 100644 index df13dc1a..00000000 --- a/packages/traffic-style/src/lib/icon/resolve.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"resolve.js","sourceRoot":"","sources":["resolve.ts"],"names":[],"mappings":"AASA,MAAM,cAAc,GAAuB;IAC1C,UAAU,EAAE,SAAS;IACrB,UAAU,EAAE,SAAS;CACrB,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C,MAAM,UAAU,WAAW,CAAC,IAAc;IACzC,OAAO;QACN,GAAG,IAAI;QACP,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,SAAS;QAClC,MAAM,EAAE;YACP,GAAG,cAAc;YACjB,GAAG,IAAI,CAAC,MAAM;SACd;KACD,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/templates.d.ts b/packages/traffic-style/src/lib/icon/templates.d.ts deleted file mode 100644 index ae932942..00000000 --- a/packages/traffic-style/src/lib/icon/templates.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type {IconVariant} from "./icon-id.ts"; -import type {RequiredIconColors} from "./resolve.ts"; - -export type ContentSlot = { - x: number; - y: number; - size: number; -}; -export type TemplateDefinition = { - width: number; - height: number; - viewBox: string; - contentSlot: ContentSlot; - textAnchor: { - x: number; - y: number; - }; - fontSize: number; - renderBackground: (colors: RequiredIconColors) => string; -}; -export declare function getTemplate(variant: IconVariant): TemplateDefinition; -//# sourceMappingURL=templates.d.ts.map diff --git a/packages/traffic-style/src/lib/icon/templates.d.ts.map b/packages/traffic-style/src/lib/icon/templates.d.ts.map deleted file mode 100644 index f58e2527..00000000 --- a/packages/traffic-style/src/lib/icon/templates.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,MAAM,CAAC;CACzD,CAAC;AA6EF,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,kBAAkB,CAMpE"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/icon/templates.js b/packages/traffic-style/src/lib/icon/templates.js deleted file mode 100644 index fff6d82a..00000000 --- a/packages/traffic-style/src/lib/icon/templates.js +++ /dev/null @@ -1,68 +0,0 @@ -function renderSquareBackground(colors, rx, rect, plain) { - const {x, y, size} = rect; - if (plain) { - return ``; - } - return ( - `` + - `` - ); -} -function renderCircleBackground(colors, cx, cy, r) { - return ``; -} -const poiTemplates = { - default: { - width: 40, - height: 40, - viewBox: "0 0 40 40", - contentSlot: {x: 9, y: 9, size: 22}, - textAnchor: {x: 20, y: 26}, - fontSize: 18, - renderBackground: (colors) => - renderSquareBackground( - colors, - 4, - {x: 7.5, y: 7.5, size: 25}, - false, - ), - }, - small: { - width: 28, - height: 28, - viewBox: "0 0 28 28", - contentSlot: {x: 7.5, y: 7.5, size: 13}, - textAnchor: {x: 14, y: 18}, - fontSize: 11, - renderBackground: (colors) => - renderCircleBackground(colors, 14, 14, 8.5), - }, - xsmall: { - width: 22, - height: 22, - viewBox: "0 0 22 22", - contentSlot: {x: 6.5, y: 6.5, size: 9}, - textAnchor: {x: 11, y: 14.5}, - fontSize: 8, - renderBackground: (colors) => - renderCircleBackground(colors, 11, 11, 6.5), - }, - plain: { - width: 34, - height: 34, - viewBox: "0 0 34 34", - contentSlot: {x: 7, y: 7, size: 20}, - textAnchor: {x: 17, y: 22}, - fontSize: 14, - renderBackground: (colors) => - renderSquareBackground(colors, 3, {x: 5.5, y: 5.5, size: 23}, true), - }, -}; -export function getTemplate(variant) { - const definition = poiTemplates[variant]; - if (!definition) { - throw new Error(`Unknown icon variant: ${variant}`); - } - return definition; -} -//# sourceMappingURL=templates.js.map diff --git a/packages/traffic-style/src/lib/icon/templates.js.map b/packages/traffic-style/src/lib/icon/templates.js.map deleted file mode 100644 index 0858cd90..00000000 --- a/packages/traffic-style/src/lib/icon/templates.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"templates.js","sourceRoot":"","sources":["templates.ts"],"names":[],"mappings":"AAmBA,SAAS,sBAAsB,CAC9B,MAA0B,EAC1B,EAAU,EACV,IAA0C,EAC1C,KAAc;IAEd,MAAM,EAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAC,GAAG,IAAI,CAAC;IAE1B,IAAI,KAAK,EAAE,CAAC;QACX,OAAO,YAAY,CAAC,QAAQ,CAAC,YAAY,IAAI,aAAa,IAAI,SAAS,EAAE,WAAW,MAAM,CAAC,UAAU,yCAAyC,CAAC;IAChJ,CAAC;IAED,OAAO,CACN,YAAY,CAAC,QAAQ,CAAC,YAAY,IAAI,aAAa,IAAI,SAAS,EAAE,WAAW,MAAM,CAAC,UAAU,uCAAuC;QACrI,YAAY,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,GAAG,YAAY,IAAI,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,WAAW,MAAM,CAAC,UAAU,uCAAuC,CAC5K,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAC9B,MAA0B,EAC1B,EAAU,EACV,EAAU,EACV,CAAS;IAET,OAAO,eAAe,EAAE,SAAS,EAAE,QAAQ,CAAC,WAAW,MAAM,CAAC,UAAU,uCAAuC,CAAC;AACjH,CAAC;AAED,MAAM,YAAY,GAA4C;IAC7D,OAAO,EAAE;QACR,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,EAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAC;QACnC,UAAU,EAAE,EAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAC;QAC1B,QAAQ,EAAE,EAAE;QACZ,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC5B,sBAAsB,CACrB,MAAM,EACN,CAAC,EACD,EAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAC,EAC1B,KAAK,CACL;KACF;IACD,KAAK,EAAE;QACN,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,EAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAC;QACvC,UAAU,EAAE,EAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAC;QAC1B,QAAQ,EAAE,EAAE;QACZ,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC5B,sBAAsB,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;KAC5C;IACD,MAAM,EAAE;QACP,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,EAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAC;QACtC,UAAU,EAAE,EAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAC;QAC5B,QAAQ,EAAE,CAAC;QACX,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC5B,sBAAsB,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;KAC5C;IACD,KAAK,EAAE;QACN,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,EAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAC;QACnC,UAAU,EAAE,EAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAC;QAC1B,QAAQ,EAAE,EAAE;QACZ,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC5B,sBAAsB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAC,EAAE,IAAI,CAAC;KACpE;CACD,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,OAAoB;IAC/C,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,UAAU,CAAC;AACnB,CAAC"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/pictograms/index.d.ts b/packages/traffic-style/src/lib/pictograms/index.d.ts deleted file mode 100644 index 4184d7b5..00000000 --- a/packages/traffic-style/src/lib/pictograms/index.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -export type PictogramDefinition = { - id: string; - label?: Record; - /** SVG viewBox — supports "minX minY width height" for non-normalized glyphs. */ - viewBox: string; - markup: string; - source: "traffic-style" | "fontawesome"; - /** Extra inset inside the content slot (0–0.4). */ - padding?: number; -}; -export declare const pictograms: PictogramDefinition[]; -export declare function getPictogram(id: string): PictogramDefinition; -export declare function hasPictogram(id: string): boolean; -export declare function listPictogramIds(): string[]; -export declare function listPictogramIdsBySource( - source: PictogramDefinition["source"], -): string[]; -//# sourceMappingURL=index.d.ts.map diff --git a/packages/traffic-style/src/lib/pictograms/index.d.ts.map b/packages/traffic-style/src/lib/pictograms/index.d.ts.map deleted file mode 100644 index 5b29fea6..00000000 --- a/packages/traffic-style/src/lib/pictograms/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,mBAAmB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,GAAG,aAAa,CAAC;IACxC,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AASF,eAAO,MAAM,UAAU,uBAAqB,CAAC;AAE7C,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,mBAAmB,CAM5D;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GACnC,MAAM,EAAE,CAKV"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/pictograms/index.js b/packages/traffic-style/src/lib/pictograms/index.js deleted file mode 100644 index 71060853..00000000 --- a/packages/traffic-style/src/lib/pictograms/index.js +++ /dev/null @@ -1,28 +0,0 @@ -import {fontAwesomePictograms} from "../../generated/pictograms/fontawesome.js"; -import {trafficStylePictograms} from "../../generated/pictograms/traffic-style.js"; - -const byId = new Map(); -for (const pictogram of [...trafficStylePictograms, ...fontAwesomePictograms]) { - byId.set(pictogram.id, pictogram); -} -export const pictograms = [...byId.values()]; -export function getPictogram(id) { - const pictogram = byId.get(id); - if (!pictogram) { - throw new Error(`Unknown pictogram: ${id}`); - } - return pictogram; -} -export function hasPictogram(id) { - return byId.has(id); -} -export function listPictogramIds() { - return [...byId.keys()].sort(); -} -export function listPictogramIdsBySource(source) { - return pictograms - .filter((pictogram) => pictogram.source === source) - .map((pictogram) => pictogram.id) - .sort(); -} -//# sourceMappingURL=index.js.map diff --git a/packages/traffic-style/src/lib/pictograms/index.js.map b/packages/traffic-style/src/lib/pictograms/index.js.map deleted file mode 100644 index 303b8296..00000000 --- a/packages/traffic-style/src/lib/pictograms/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AAcrF,MAAM,IAAI,GAAG,IAAI,GAAG,EAA+B,CAAC;AAEpD,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,sBAAsB,EAAE,GAAG,qBAAqB,CAAC,EAAE,CAAC;IAC/E,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAE7C,MAAM,UAAU,YAAY,CAAC,EAAU;IACtC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAU;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC/B,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,wBAAwB,CACvC,MAAqC;IAErC,OAAO,UAAU;SACf,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC;SAClD,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;SAChC,IAAI,EAAE,CAAC;AACV,CAAC"} \ No newline at end of file diff --git a/packages/traffic-style/src/lib/runtime/index.ts b/packages/traffic-style/src/lib/runtime/index.ts index 835f1573..32a94abb 100644 --- a/packages/traffic-style/src/lib/runtime/index.ts +++ b/packages/traffic-style/src/lib/runtime/index.ts @@ -6,5 +6,6 @@ export { addRuntimeIconMapRenderCallback, mapsightRuntimeIcon, bindRuntimeIconStyleFeatureScope, + onRuntimeIconChange, setRuntimeIconMapRenderCallback, } from "./icon-style.ts"; diff --git a/packages/ui/eslint.config.mts b/packages/ui/eslint.config.mts index 5377b08b..a5dfcc0b 100644 --- a/packages/ui/eslint.config.mts +++ b/packages/ui/eslint.config.mts @@ -4,6 +4,9 @@ import baseConfig from "../../configs/eslint-config-base-react.mts"; export default defineConfig([ baseConfig, + { + ignores: ["**/*.test.ts"], + }, { name: "todos", rules: { diff --git a/packages/ui/src/js/components/feature-list-item/icon.tsx b/packages/ui/src/js/components/feature-list-item/icon.tsx index 6264a4b4..42778d75 100644 --- a/packages/ui/src/js/components/feature-list-item/icon.tsx +++ b/packages/ui/src/js/components/feature-list-item/icon.tsx @@ -2,10 +2,9 @@ import type {ElementType} from "react"; import {memo} from "react"; import {isComposableIcon} from "@mapsight/traffic-style/icon-meta"; -import {iconSpecFromMapsightIconId} from "@mapsight/traffic-style/runtime"; import {siteConfig} from "../../config"; -import {useMapsightIcon} from "../../hooks/use-mapsight-icon"; +import {useMapsightIcon} from "../../hooks/useMapsightIcon"; function SpriteMapsightIcon({id}: {id: string}) { const iconFileName = `${id}-plain.png`; @@ -18,10 +17,7 @@ function SpriteMapsightIcon({id}: {id: string}) { } function ComposableMapsightIcon({id}: {id: string}) { - const {src, error} = useMapsightIcon({ - ...iconSpecFromMapsightIconId(id), - variant: "plain", - }); + const {src, error} = useMapsightIcon(id, "plain"); if (error) { return ; diff --git a/packages/ui/src/js/hooks/use-mapsight-icon.ts b/packages/ui/src/js/hooks/use-mapsight-icon.ts deleted file mode 100644 index 5e68aa20..00000000 --- a/packages/ui/src/js/hooks/use-mapsight-icon.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {useEffect, useState} from "react"; - -import { - type IconBitmap, - type IconCache, - type IconSpec, - defaultIconCache, - hashSpec, -} from "@mapsight/traffic-style/runtime"; - -export function useMapsightIcon( - spec: IconSpec, - cache: IconCache = defaultIconCache, -): { - src: string | null; - bitmap: IconBitmap | null; - loading: boolean; - error: Error | null; -} { - const key = hashSpec(spec); - const [bitmap, setBitmap] = useState( - () => cache.getCached(spec) ?? null, - ); - const [loading, setLoading] = useState(() => cache.getCached(spec) == null); - const [error, setError] = useState(null); - - useEffect(() => { - let cancelled = false; - const cached = cache.getCached(spec); - if (cached) { - setBitmap(cached); - setLoading(false); - setError(null); - return; - } - - setBitmap(null); - setLoading(true); - setError(null); - - void cache - .get(spec) - .then((result) => { - if (!cancelled) { - setBitmap(result); - setLoading(false); - } - }) - .catch((cause: unknown) => { - if (!cancelled) { - setError( - cause instanceof Error - ? cause - : new Error(String(cause)), - ); - setLoading(false); - } - }); - - return () => { - cancelled = true; - }; - // `key` is derived from spec content; do not depend on `spec` object identity. - }, [cache, key]); - - return { - src: bitmap?.dataUrl ?? null, - bitmap, - loading, - error, - }; -} diff --git a/packages/ui/vitest.config.ts b/packages/ui/vitest.config.ts index ce6c79ea..d5bafbce 100644 --- a/packages/ui/vitest.config.ts +++ b/packages/ui/vitest.config.ts @@ -1,10 +1,5 @@ -import path from "node:path"; -import {fileURLToPath} from "node:url"; - import {defineConfig} from "vitest/config"; -const dirname = path.dirname(fileURLToPath(import.meta.url)); - export default defineConfig({ test: { include: ["src/js/**/*.test.ts"], diff --git a/packages/vector-style-compiler/__tests__/helperImports.test.ts b/packages/vector-style-compiler/__tests__/helperImports.test.ts index 8d77cca7..24fa1517 100644 --- a/packages/vector-style-compiler/__tests__/helperImports.test.ts +++ b/packages/vector-style-compiler/__tests__/helperImports.test.ts @@ -6,7 +6,7 @@ describe("createHelperImportsFromProgram", () => { it("imports runtime icon helpers when referenced in compiled programs", () => { const imports = createHelperImportsFromProgram( `if (props['mapsightIconId']) { - d.icon.src = { value: '' + (mapsightRuntimeIcon(props['mapsightIconId'], \"default\")) + '' }; + d.icon.src = { value: '' + (mapsightRuntimeIcon(props['mapsightIconId'], "default")) + '' }; }`, ); expect(imports).toContain("mapsightRuntimeIcon"); From eeb6355768405b885cd0f0b4f63244027cf863c4 Mon Sep 17 00:00:00 2001 From: Paul Golmann Date: Thu, 11 Jun 2026 16:25:55 +0200 Subject: [PATCH 49/49] add pre-push hook to prevent pushing private branches to remotes other than private Signed-off-by: Paul Golmann --- .husky/pre-push | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 .husky/pre-push diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 00000000..715e9d45 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,44 @@ +#!/usr/bin/env sh + +remote="$1" + +# Block pushing private/* branches to any remote except "private". +if [ "$remote" != "private" ]; then + blocked="" + + while read -r local_ref local_sha remote_ref remote_sha; do + [ -z "$local_ref" ] && continue + + # Allow deleting private branches from non-private remotes (cleanup after accidents). + if [ "$local_sha" = "0000000000000000000000000000000000000000" ]; then + continue + fi + + local_branch="${local_ref#refs/heads/}" + remote_branch="${remote_ref#refs/heads/}" + + case "$local_branch" in + private/*) + blocked="${blocked} + - ${local_branch}" + ;; + esac + + case "$remote_branch" in + private/*) + if ! printf '%s' "$blocked" | grep -Fq " - ${remote_branch}"; then + blocked="${blocked} + - ${remote_branch}" + fi + ;; + esac + done + + if [ -n "$blocked" ]; then + echo "error: refusing to push private branches to remote '$remote'." + echo "Use the private remote instead, for example:" + echo " git push private " + printf 'Blocked branch(es):%s\n' "$blocked" + exit 1 + fi +fi