import { type AdaptiveResolutionContext, type CircleSymbolDescriptor, type RenderMedium } from "@trackunit/react-map-adapter-shared"; import type { MapTheme } from "../../core/types"; import type { MarkerDomSize } from "../../markers/model/markerDomTypes"; /** * Tunables for {@link pickRenderMedium}. All optional — sensible defaults are * documented inline. */ export type PickRenderMediumOptions = Readonly<{ /** * If `markersInViewport` exceeds this, the helper returns `"symbol"` even * when selected/hovered promotion does not apply. Keeps DOM marker counts * bounded so layout cost stays low. * * @default 200 */ maxMarkersForDom?: number; /** * When `true`, the helper short-circuits to `"dom"` whenever a marker is * hovered or selected, so the rich DOM form is always available for * interaction even outside the density envelope. * * @default true */ domMediumOnInteraction?: boolean; }>; /** * Default heuristic for `AdaptiveRenderConfig.resolveMode` (ADR-0009). * * Returns `"dom"` when the marker is interacted with (hover/select) or when * the viewport is not over-dense; otherwise `"symbol"`. Pure — no React, no * allocation per call. * * Consumers use this directly: * * ```ts * resolveMode: (_item, ctx) => pickRenderMedium(ctx) * ``` * * Or tune thresholds: * * ```ts * resolveMode: (_item, ctx) => * pickRenderMedium(ctx, { maxMarkersForDom: 80 }) * ``` * * The library does not impose this heuristic — `resolveMode` always wins. The * helper is a documented starting point for the common case (Q6 of the * design grilling). */ export declare const pickRenderMedium: (ctx: AdaptiveResolutionContext, options?: PickRenderMediumOptions) => RenderMedium; /** * Single zoom→size step. The helper picks the breakpoint with the highest * `minZoom` that is still `<= ctx.zoom`. */ export type MarkerSizeBreakpoint = Readonly<{ /** Zoom at or above which this size applies. */ minZoom: number; /** Size to use once `ctx.zoom >= minZoom`. */ size: MarkerDomSize; }>; /** * Tunables for {@link pickMarkerSize}. */ export type PickMarkerSizeOptions = Readonly<{ /** * Zoom→size ladder, sorted ascending by `minZoom`. The last breakpoint with * `minZoom <= ctx.zoom` wins. If `ctx.zoom` is below every breakpoint, the * first breakpoint's `size` is returned (the smallest tier acts as the * floor). * * @default DEFAULT_MARKER_SIZE_BREAKPOINTS */ breakpoints?: ReadonlyArray; }>; /** * Five-tier zoom ladder matching the `MapMarker` `size` prop. The chosen * thresholds align with how the existing demos read at typical fleet zooms * (city → asset → street). */ export declare const DEFAULT_MARKER_SIZE_BREAKPOINTS: ReadonlyArray; /** * Default zoom→`MarkerDomSize` mapping for the DOM branch of an adaptive * `render`. * * Pure. Iterates the breakpoint ladder once and picks the largest `minZoom` * still satisfied by `ctx.zoom`. The breakpoint list must be sorted ascending * by `minZoom`; the helper does not sort defensively because it runs per * marker per frame. * * ```ts * * ``` * * Consumers can tune the ladder for denser or sparser maps: * * ```ts * pickMarkerSize(ctx, { * breakpoints: [ * { minZoom: 0, size: "xs" }, * { minZoom: 10, size: "md" }, * { minZoom: 14, size: "xl" }, * ], * }) * ``` */ export declare const pickMarkerSize: (ctx: AdaptiveResolutionContext, options?: PickMarkerSizeOptions) => MarkerDomSize; /** * Tunables for {@link pickSymbolDiameter}. The same ladder shape as * {@link pickMarkerSize} so `mode: "adaptive"` consumers can share one * options object across both branches. */ export type PickSymbolDiameterOptions = PickMarkerSizeOptions; /** * Symbol counterpart of {@link pickMarkerSize}: returns a `diameterPx` that * matches the `MapMarker` `circle` dimension at the same zoom-derived tier * (`MARKER_SIZE_MAP`). Use it inside the symbol arm of an adaptive `render` * so the WebGL/canvas dot is the same physical size as the DOM circle the * marker is about to morph into. * * ```ts * if (state.medium === "symbol") { * return { color, diameterPx: pickSymbolDiameter(ctx) }; * } * ``` * * Pure; defers entirely to {@link pickMarkerSize} for the tier decision. */ export declare const pickSymbolDiameter: (ctx: AdaptiveResolutionContext, options?: PickSymbolDiameterOptions) => number; /** * Width of the disc border drawn on DOM markers (Tailwind `border` = 1 px). * Shared by {@link pickSymbolDescriptor} so DOM and symbol layers stay in sync. */ export declare const MARKER_DISC_BORDER_WIDTH_PX = 1; /** * Full symbol descriptor for adaptive symbol markers. * * Symbol markers intentionally stay at the `xs` footprint to keep dense-map * rendering stable while zooming. We still compute `diameterPx` via * {@link pickSymbolDiameter} so the actual pixel value is sourced from the same * `MARKER_SIZE_MAP` as DOM markers. * * Also derives `borderColor` * from the same `color-mix()` formula used by `cvaMarkerIndicator` in CSS: * - **light**: darken the fill by 30% (mix with black) * - **dark**: lighten the fill by 50% (mix with white) * * Use this instead of the manual `{ color, diameterPx: pickSymbolDiameter(ctx) }` * when you want the symbol circle and the DOM disc to look identical: * * ```ts * if (state.medium === "symbol") { * return pickSymbolDescriptor(color, theme, sizingCtx); * } * ``` */ export declare const pickSymbolDescriptor: (color: string, theme: MapTheme, ctx: AdaptiveResolutionContext) => CircleSymbolDescriptor;