@12-apps/ui 6.99.0 → 6.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  RegionMap
3
- } from "../../../../chunk-AYDVNXGR.js";
3
+ } from "../../../../chunk-LCKUEYU2.js";
4
4
  import "../../../../chunk-NWUMGE6T.js";
5
5
  import "../../../../chunk-BRZKOUEL.js";
6
6
  import "../../../../chunk-PBRCKHN3.js";
7
- import "../../../../chunk-3V5V44UP.js";
7
+ import "../../../../chunk-YHFLI2FD.js";
8
8
  import "../../../../chunk-J3AWGTJY.js";
9
- import "../../../../chunk-DRYBA76G.js";
9
+ import "../../../../chunk-7XVT4RME.js";
10
10
  import "../../../../chunk-KAZWBDIH.js";
11
11
  import "../../../../chunk-MNJZPJ5S.js";
12
12
  import "../../../../chunk-PUFA7FQ7.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  RegionMapDrawing
3
- } from "../../../../chunk-3V5V44UP.js";
3
+ } from "../../../../chunk-YHFLI2FD.js";
4
4
  import "../../../../chunk-J3AWGTJY.js";
5
- import "../../../../chunk-DRYBA76G.js";
5
+ import "../../../../chunk-7XVT4RME.js";
6
6
  import "../../../../chunk-MNJZPJ5S.js";
7
7
  import "../../../../chunk-YKCAJ2TN.js";
8
8
  import "../../../../chunk-PZ5AY32C.js";
@@ -8,7 +8,7 @@ import {
8
8
  ScaleBar,
9
9
  latLngAt,
10
10
  scaleMetres
11
- } from "../../../../chunk-DRYBA76G.js";
11
+ } from "../../../../chunk-7XVT4RME.js";
12
12
  import "../../../../chunk-MNJZPJ5S.js";
13
13
  import "../../../../chunk-YKCAJ2TN.js";
14
14
  import "../../../../chunk-PZ5AY32C.js";
@@ -119,16 +119,16 @@ import "../../../chunk-CB6DTWD5.js";
119
119
  import "../../../chunk-WGKLBVDZ.js";
120
120
  import {
121
121
  RegionMap
122
- } from "../../../chunk-AYDVNXGR.js";
122
+ } from "../../../chunk-LCKUEYU2.js";
123
123
  import "../../../chunk-NWUMGE6T.js";
124
124
  import "../../../chunk-BRZKOUEL.js";
125
125
  import "../../../chunk-PBRCKHN3.js";
126
- import "../../../chunk-3V5V44UP.js";
126
+ import "../../../chunk-YHFLI2FD.js";
127
127
  import "../../../chunk-J3AWGTJY.js";
128
128
  import {
129
129
  latLngAt,
130
130
  scaleMetres
131
- } from "../../../chunk-DRYBA76G.js";
131
+ } from "../../../chunk-7XVT4RME.js";
132
132
  import {
133
133
  boundsOfRings,
134
134
  regionMapView
@@ -559,16 +559,16 @@ import "../../chunk-CB6DTWD5.js";
559
559
  import "../../chunk-WGKLBVDZ.js";
560
560
  import {
561
561
  RegionMap
562
- } from "../../chunk-AYDVNXGR.js";
562
+ } from "../../chunk-LCKUEYU2.js";
563
563
  import "../../chunk-NWUMGE6T.js";
564
564
  import "../../chunk-BRZKOUEL.js";
565
565
  import "../../chunk-PBRCKHN3.js";
566
- import "../../chunk-3V5V44UP.js";
566
+ import "../../chunk-YHFLI2FD.js";
567
567
  import "../../chunk-J3AWGTJY.js";
568
568
  import {
569
569
  latLngAt,
570
570
  scaleMetres
571
- } from "../../chunk-DRYBA76G.js";
571
+ } from "../../chunk-7XVT4RME.js";
572
572
  import {
573
573
  boundsOfRings,
574
574
  regionMapView
@@ -266,7 +266,7 @@ function ScaleBar({
266
266
  "aria-hidden": true,
267
267
  sx: { position: "absolute", left: 0, right: 0, bottom: rem(theme, 10), pointerEvents: "none", zIndex: 1 },
268
268
  children: [
269
- /* @__PURE__ */ jsx(Box, { component: "span", sx: { display: "block", ml: rem(theme, 10), fontSize: rem(theme, 11), color: "text.secondary" }, children: copy.scale(metres) }),
269
+ /* @__PURE__ */ jsx(Box, { component: "span", sx: { display: "block", ml: rem(theme, 10), fontSize: rem(theme, 12), color: "text.secondary" }, children: copy.scale(metres) }),
270
270
  /* @__PURE__ */ jsx(
271
271
  Box,
272
272
  {
@@ -290,4 +290,4 @@ export {
290
290
  scaleMetres,
291
291
  ScaleBar
292
292
  };
293
- //# sourceMappingURL=chunk-DRYBA76G.js.map
293
+ //# sourceMappingURL=chunk-7XVT4RME.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/data-display/RegionMap/RegionMapPin.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport { alpha, type Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { rem } from '../../../tokens/relative';\n\nimport { METRES_PER_DEGREE, type PlaneBox, type PlanePoint, type Projection } from './RegionMap.helpers';\nimport type { RegionMapModel } from './RegionMap.hooks';\nimport type { RegionMapCenter, RegionMapCopy, RegionMapDot, RegionMapGhost, RegionMapPin } from './RegionMap.types';\n\n/**\n * The movable centre of a `RegionMap` (`pin`, `ghost`, `dots`): a pin the\n * viewer drags with a mouse or one finger, or focuses and nudges with the\n * arrow keys, while the VIEW stays where `center` put it — so the areas never\n * slide under a dragging finger. The circles follow the pin; a dashed ring\n * and dot stay at `ghost`; `dots` are small points (filled or hollow).\n *\n * The pin is HTML over the drawing, at its point by percent like the labels,\n * carrying `data-region-pin` so a host that zooms the drawing's layers can\n * move it with them. Its moves are reported, never applied: the host passes\n * the new point back.\n */\n\n/** The movable centre and what is drawn with it, as the drawing receives it. */\nexport interface Moving {\n center: RegionMapCenter;\n pin?: RegionMapPin;\n ghost?: RegionMapGhost;\n dots?: readonly RegionMapDot[];\n copy: RegionMapCopy;\n}\n\ntype DrawnModel = Pick<RegionMapModel, 'projection' | 'radii'> & { view: PlaneBox };\n\n/**\n * What the movable centre draws inside the SVG: the circles around the pin\n * (else `fallback`, the centre's own circles), the ghost, and the dots.\n */\nexport function PinShapes({ model, moving, testId, theme, fallback }: { model: DrawnModel; moving: Moving | undefined; testId: string; theme: Theme; fallback: React.ReactNode }): React.JSX.Element {\n const { projection, view } = model;\n if (!moving || !projection) return <>{fallback}</>;\n const pinAt = moving.pin ? projection.project([moving.pin.at.latitude, moving.pin.at.longitude]) : null;\n return (\n <>\n {pinAt ? <PinCircles at={pinAt} radii={model.radii} theme={theme} /> : fallback}\n {pinAt && moving.ghost ? <GhostShapes ghost={moving.ghost} pinAt={pinAt} projection={projection} view={view} testId={testId} theme={theme} /> : null}\n {moving.dots ? <Dots dots={moving.dots} projection={projection} view={view} testId={testId} theme={theme} /> : null}\n </>\n );\n}\n\n/** What the movable centre draws over the SVG, in HTML: the pin and the scale bar. */\nexport function PinOverlay({\n model,\n moving,\n svgRef,\n testId,\n theme,\n}: {\n model: DrawnModel;\n moving: Moving | undefined;\n svgRef: React.RefObject<SVGSVGElement | null>;\n testId: string;\n theme: Theme;\n}): React.JSX.Element | null {\n if (!moving || !model.projection) return null;\n return (\n <>\n {moving.pin ? <PinMarker pin={moving.pin} center={moving.center} projection={model.projection} view={model.view} svgRef={svgRef} testId={testId} theme={theme} /> : null}\n <ScaleBar view={model.view} copy={moving.copy} svgRef={svgRef} testId={testId} theme={theme} />\n </>\n );\n}\n\n/** The flat projection's inverse around `center` — it is linear. */\nexport function latLngAt(center: RegionMapCenter, point: PlanePoint): RegionMapCenter {\n const kx = METRES_PER_DEGREE * Math.cos((center.latitude * Math.PI) / 180);\n return { latitude: center.latitude - point.y / METRES_PER_DEGREE, longitude: center.longitude + point.x / kx };\n}\n\n/** A point of the plane as fractions of the view (0..1 across, 0..1 down). */\nfunction fractionOf(view: PlaneBox, point: PlanePoint): { x: number; y: number } {\n return { x: (point.x - view.minX) / view.spanX, y: (point.y - view.minY) / view.spanY };\n}\n\n/** Keep a fraction inside the view, a hair in from its edge (the mock's clamp). */\nconst clampFraction = (value: number): number => Math.min(0.995, Math.max(0.005, value));\n\n/** A plane point kept inside the view by the same clamp a drag gets. */\nfunction clampToView(view: PlaneBox, point: PlanePoint): PlanePoint {\n const at = fractionOf(view, point);\n return { x: view.minX + clampFraction(at.x) * view.spanX, y: view.minY + clampFraction(at.y) * view.spanY };\n}\n\n/** Arrow keys, as metres east and north per press. */\nconst ARROWS: Record<string, [number, number]> = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, 1], ArrowDown: [0, -1] };\n\n/** One arrow key: 50 m unless the host says otherwise. */\nconst DEFAULT_STEP_METRES = 50;\n\ninterface PinLayerProps {\n pin: RegionMapPin;\n center: RegionMapCenter;\n projection: Projection;\n view: PlaneBox;\n /** The drawing's SVG, whose on-screen box maps a pointer to the plane (zoomed or not). */\n svgRef: React.RefObject<SVGSVGElement | null>;\n testId: string;\n theme: Theme;\n}\n\n/** The draggable pin, as HTML over the drawing. */\nexport function PinMarker({ pin, center, projection, view, svgRef, testId, theme }: PinLayerProps): React.JSX.Element {\n const ref = React.useRef<HTMLDivElement>(null);\n const live = React.useRef({ pin, center, view });\n live.current = { pin, center, view };\n usePinDrag(ref, svgRef, live);\n const at = fractionOf(view, projection.project([pin.at.latitude, pin.at.longitude]));\n const onKeyDown = (event: React.KeyboardEvent): void => {\n const arrow = ARROWS[event.key];\n if (!arrow || pin.disabled) return;\n event.preventDefault();\n const step = pin.stepMetres ?? DEFAULT_STEP_METRES;\n const plane = projection.project([pin.at.latitude, pin.at.longitude]);\n const next = latLngAt(center, clampToView(view, { x: plane.x + arrow[0] * step, y: plane.y - arrow[1] * step }));\n pin.onMove?.(next);\n pin.onDrop(next);\n };\n return (\n <Box\n ref={ref}\n role=\"button\"\n tabIndex={pin.disabled ? -1 : 0}\n aria-label={pin.ariaLabel}\n aria-disabled={pin.disabled || undefined}\n onKeyDown={onKeyDown}\n data-testid={`${testId}-pin`}\n data-region-pin=\"\"\n style={{ left: `${(at.x * 100).toFixed(3)}%`, top: `${(at.y * 100).toFixed(3)}%` }}\n sx={{\n position: 'absolute',\n transform: 'translate(-50%, -100%)',\n width: rem(theme, 44),\n height: rem(theme, 48),\n display: 'flex',\n alignItems: 'flex-end',\n justifyContent: 'center',\n cursor: pin.disabled ? 'default' : 'grab',\n touchAction: 'none',\n zIndex: 2,\n borderRadius: 1,\n '&:focus-visible': { outline: `${rem(theme, 2)} solid`, outlineColor: 'primary.main', outlineOffset: rem(theme, 2) },\n }}\n >\n <Box component=\"svg\" viewBox=\"0 0 32 42\" aria-hidden=\"true\" sx={{ width: rem(theme, 32), height: rem(theme, 42) }}>\n <path\n d=\"M16 41C16 41 3 25 3 15.5A13 13 0 1 1 29 15.5C29 25 16 41 16 41Z\"\n fill={theme.palette.primary.main}\n stroke={theme.palette.background.paper}\n strokeWidth={2}\n />\n <circle cx=\"16\" cy=\"15.5\" r=\"5\" fill={theme.palette.background.paper} />\n </Box>\n <Box\n component=\"span\"\n aria-hidden\n sx={{\n position: 'absolute',\n left: '88%',\n top: 0,\n px: 0.75,\n borderRadius: 0.5,\n border: 1,\n borderColor: 'divider',\n bgcolor: 'background.paper',\n color: 'text.primary',\n fontSize: rem(theme, 12),\n fontWeight: 600,\n whiteSpace: 'nowrap',\n pointerEvents: 'none',\n }}\n >\n {pin.label}\n </Box>\n </Box>\n );\n}\n\n/**\n * The pointer drag: native listeners on the pin, so a host's own listeners on\n * the drawing (a pan, a tap) never see the press; captured, so a finger that\n * leaves the pin keeps dragging it; clamped inside the view.\n */\nfunction usePinDrag(\n ref: React.RefObject<HTMLDivElement | null>,\n svgRef: React.RefObject<SVGSVGElement | null>,\n live: React.RefObject<{ pin: RegionMapPin; center: RegionMapCenter; view: PlaneBox }>,\n): void {\n React.useEffect(() => {\n const element = ref.current;\n if (!element) return undefined;\n let dragging: number | null = null;\n // Where the last move put the pin: a cancelled gesture (a browser may\n // report 0,0 for it) rests there rather than jumping to the corner.\n let last: RegionMapCenter | null = null;\n const pointAt = (event: PointerEvent): RegionMapCenter | null => {\n const box = svgRef.current?.getBoundingClientRect();\n if (!box || box.width === 0 || box.height === 0) return null;\n const { view, center } = live.current;\n if (!Number.isFinite(event.clientX) || !Number.isFinite(event.clientY)) return null;\n const fx = clampFraction((event.clientX - box.left) / box.width);\n const fy = clampFraction((event.clientY - box.top) / box.height);\n return latLngAt(center, { x: view.minX + fx * view.spanX, y: view.minY + fy * view.spanY });\n };\n const down = (event: PointerEvent): void => {\n event.stopPropagation();\n if (live.current.pin.disabled) return;\n event.preventDefault();\n dragging = event.pointerId;\n last = null;\n element.setPointerCapture?.(event.pointerId);\n };\n const move = (event: PointerEvent): void => {\n if (dragging !== event.pointerId) return;\n event.stopPropagation();\n const at = pointAt(event);\n if (!at) return;\n last = at;\n live.current.pin.onMove?.(at);\n };\n const up = (event: PointerEvent): void => {\n if (dragging !== event.pointerId) return;\n event.stopPropagation();\n dragging = null;\n const at = event.type === 'pointercancel' ? last : (pointAt(event) ?? last);\n if (at) live.current.pin.onDrop(at);\n };\n // A click that ends a drag is the drag's, not a tap on the area under it.\n const click = (event: MouseEvent): void => event.stopPropagation();\n element.addEventListener('pointerdown', down);\n element.addEventListener('pointermove', move);\n element.addEventListener('pointerup', up);\n element.addEventListener('pointercancel', up);\n element.addEventListener('click', click);\n return () => {\n element.removeEventListener('pointerdown', down);\n element.removeEventListener('pointermove', move);\n element.removeEventListener('pointerup', up);\n element.removeEventListener('pointercancel', up);\n element.removeEventListener('click', click);\n };\n }, [ref, svgRef, live]);\n}\n\n/** The circles around the pin: solid in the primary colour, faintly filled. */\nexport function PinCircles({ at, radii, theme }: { at: PlanePoint; radii: readonly number[]; theme: Theme }): React.JSX.Element {\n return (\n <>\n {radii.map((radius) => (\n <circle\n key={radius}\n cx={at.x}\n cy={at.y}\n r={radius}\n fill={alpha(theme.palette.primary.main, 0.06)}\n stroke={theme.palette.primary.main}\n strokeWidth={2.25}\n vectorEffect=\"non-scaling-stroke\"\n pointerEvents=\"none\"\n />\n ))}\n </>\n );\n}\n\n/** Where the circles stood: a dashed ring and dot at `ghost`, and a dashed line from it to the pin. */\nexport function GhostShapes({\n ghost,\n pinAt,\n projection,\n view,\n testId,\n theme,\n}: {\n ghost: RegionMapGhost;\n pinAt: PlanePoint;\n projection: Projection;\n view: PlaneBox;\n testId: string;\n theme: Theme;\n}): React.JSX.Element {\n const at = projection.project([ghost.at.latitude, ghost.at.longitude]);\n const stroke = theme.palette.text.secondary;\n const common = { fill: 'none', stroke, vectorEffect: 'non-scaling-stroke', pointerEvents: 'none' } as const;\n return (\n <g data-testid={`${testId}-ghost`}>\n <circle cx={at.x} cy={at.y} r={ghost.radiusMetres} strokeWidth={1.5} strokeDasharray=\"6 5\" {...common} />\n <line x1={at.x} y1={at.y} x2={pinAt.x} y2={pinAt.y} strokeWidth={1.5} strokeDasharray=\"4 4\" {...common} />\n <circle cx={at.x} cy={at.y} r={view.spanX / 110} strokeWidth={2} strokeDasharray=\"3 2\" {...common} fill={alpha(theme.palette.background.paper, 0.7)} />\n </g>\n );\n}\n\n/** The dots: filled with the ink, or hollow (paper with an ink ring). */\nexport function Dots({ dots, projection, view, testId, theme }: { dots: readonly RegionMapDot[]; projection: Projection; view: PlaneBox; testId: string; theme: Theme }): React.JSX.Element {\n return (\n <g data-testid={`${testId}-dots`}>\n {dots.map((dot) => {\n const at = projection.project([dot.at.latitude, dot.at.longitude]);\n return (\n <circle\n key={dot.id}\n cx={at.x}\n cy={at.y}\n r={view.spanX / 150}\n fill={dot.filled ? theme.palette.text.primary : theme.palette.background.paper}\n stroke={theme.palette.text.primary}\n strokeWidth={2}\n vectorEffect=\"non-scaling-stroke\"\n pointerEvents=\"none\"\n data-filled={dot.filled ? 'true' : 'false'}\n />\n );\n })}\n </g>\n );\n}\n\n/** Nice lengths a scale bar may take, in metres. */\nconst SCALE_STEPS = [50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000];\n\n/** The longest nice length that fits in a quarter of the drawing's width. */\nexport function scaleMetres(view: PlaneBox): number {\n const quarter = view.spanX / 4;\n return SCALE_STEPS.filter((step) => step <= quarter).at(-1) ?? SCALE_STEPS[0]!;\n}\n\n/**\n * A scale bar, bottom-left, when the host gives `copy.scale`. It reads what is\n * on screen: a host that zooms the drawing's layers (a CSS scale on the SVG)\n * shows fewer metres per pixel, so after every render the bar compares the\n * SVG's drawn width with its laid-out width — both off the SVG itself — and\n * spans the drawing's own width, so its share of it is a share of the view.\n */\nexport function ScaleBar({\n view,\n copy,\n svgRef,\n testId,\n theme,\n}: {\n view: PlaneBox;\n copy: RegionMapCopy;\n svgRef: React.RefObject<SVGSVGElement | null>;\n testId: string;\n theme: Theme;\n}): React.JSX.Element | null {\n // What the drawing shows on screen: its laid-out width, and its width as\n // drawn (a host's CSS scale on the SVG), both read off the SVG itself.\n const [screen, setScreen] = React.useState({ laidOut: 0, drawn: 0 });\n const wanted = copy.scale !== undefined;\n React.useLayoutEffect(() => {\n if (!wanted) return;\n const svg = svgRef.current;\n const next = { laidOut: svg?.clientWidth ?? 0, drawn: svg?.getBoundingClientRect().width ?? 0 };\n if (next.laidOut !== screen.laidOut || Math.abs(next.drawn - screen.drawn) > 0.5) setScreen(next);\n });\n if (!copy.scale) return null;\n const zoom = screen.laidOut > 0 && screen.drawn > 0 ? screen.drawn / screen.laidOut : 1;\n const metres = scaleMetres({ ...view, spanX: view.spanX / zoom });\n // The bar's share of the drawing's width: metres on screen over the metres the width shows.\n const share = (metres * zoom) / view.spanX;\n return (\n <Box\n data-testid={`${testId}-scale`}\n aria-hidden\n sx={{ position: 'absolute', left: 0, right: 0, bottom: rem(theme, 10), pointerEvents: 'none', zIndex: 1 }}\n >\n <Box component=\"span\" sx={{ display: 'block', ml: rem(theme, 10), fontSize: rem(theme, 11), color: 'text.secondary' }}>\n {copy.scale(metres)}\n </Box>\n <Box\n component=\"span\"\n sx={{ display: 'block', height: rem(theme, 4), ml: rem(theme, 10), width: `${(share * 100).toFixed(2)}%`, borderStyle: 'solid', borderWidth: `0 ${rem(theme, 1.5)} ${rem(theme, 1.5)}`, borderColor: 'text.secondary' }}\n />\n </Box>\n );\n}\n"],"mappings":";;;;;;;;AAAA,OAAO,SAAS;AAChB,SAAS,aAAyB;AAClC,OAAO,WAAW;AAsCmB,wBAGjC,YAHiC;AAF9B,SAAS,UAAU,EAAE,OAAO,QAAQ,QAAQ,OAAO,SAAS,GAAkI;AACnM,QAAM,EAAE,YAAY,KAAK,IAAI;AAC7B,MAAI,CAAC,UAAU,CAAC,WAAY,QAAO,gCAAG,oBAAS;AAC/C,QAAM,QAAQ,OAAO,MAAM,WAAW,QAAQ,CAAC,OAAO,IAAI,GAAG,UAAU,OAAO,IAAI,GAAG,SAAS,CAAC,IAAI;AACnG,SACE,iCACG;AAAA,YAAQ,oBAAC,cAAW,IAAI,OAAO,OAAO,MAAM,OAAO,OAAc,IAAK;AAAA,IACtE,SAAS,OAAO,QAAQ,oBAAC,eAAY,OAAO,OAAO,OAAO,OAAc,YAAwB,MAAY,QAAgB,OAAc,IAAK;AAAA,IAC/I,OAAO,OAAO,oBAAC,QAAK,MAAM,OAAO,MAAM,YAAwB,MAAY,QAAgB,OAAc,IAAK;AAAA,KACjH;AAEJ;AAGO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAM6B;AAC3B,MAAI,CAAC,UAAU,CAAC,MAAM,WAAY,QAAO;AACzC,SACE,iCACG;AAAA,WAAO,MAAM,oBAAC,aAAU,KAAK,OAAO,KAAK,QAAQ,OAAO,QAAQ,YAAY,MAAM,YAAY,MAAM,MAAM,MAAM,QAAgB,QAAgB,OAAc,IAAK;AAAA,IACpK,oBAAC,YAAS,MAAM,MAAM,MAAM,MAAM,OAAO,MAAM,QAAgB,QAAgB,OAAc;AAAA,KAC/F;AAEJ;AAGO,SAAS,SAAS,QAAyB,OAAoC;AACpF,QAAM,KAAK,oBAAoB,KAAK,IAAK,OAAO,WAAW,KAAK,KAAM,GAAG;AACzE,SAAO,EAAE,UAAU,OAAO,WAAW,MAAM,IAAI,mBAAmB,WAAW,OAAO,YAAY,MAAM,IAAI,GAAG;AAC/G;AAGA,SAAS,WAAW,MAAgB,OAA6C;AAC/E,SAAO,EAAE,IAAI,MAAM,IAAI,KAAK,QAAQ,KAAK,OAAO,IAAI,MAAM,IAAI,KAAK,QAAQ,KAAK,MAAM;AACxF;AAGA,IAAM,gBAAgB,CAAC,UAA0B,KAAK,IAAI,OAAO,KAAK,IAAI,MAAO,KAAK,CAAC;AAGvF,SAAS,YAAY,MAAgB,OAA+B;AAClE,QAAM,KAAK,WAAW,MAAM,KAAK;AACjC,SAAO,EAAE,GAAG,KAAK,OAAO,cAAc,GAAG,CAAC,IAAI,KAAK,OAAO,GAAG,KAAK,OAAO,cAAc,GAAG,CAAC,IAAI,KAAK,MAAM;AAC5G;AAGA,IAAM,SAA2C,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE;AAG/H,IAAM,sBAAsB;AAcrB,SAAS,UAAU,EAAE,KAAK,QAAQ,YAAY,MAAM,QAAQ,QAAQ,MAAM,GAAqC;AACpH,QAAM,MAAM,MAAM,OAAuB,IAAI;AAC7C,QAAM,OAAO,MAAM,OAAO,EAAE,KAAK,QAAQ,KAAK,CAAC;AAC/C,OAAK,UAAU,EAAE,KAAK,QAAQ,KAAK;AACnC,aAAW,KAAK,QAAQ,IAAI;AAC5B,QAAM,KAAK,WAAW,MAAM,WAAW,QAAQ,CAAC,IAAI,GAAG,UAAU,IAAI,GAAG,SAAS,CAAC,CAAC;AACnF,QAAM,YAAY,CAAC,UAAqC;AACtD,UAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,QAAI,CAAC,SAAS,IAAI,SAAU;AAC5B,UAAM,eAAe;AACrB,UAAM,OAAO,IAAI,cAAc;AAC/B,UAAM,QAAQ,WAAW,QAAQ,CAAC,IAAI,GAAG,UAAU,IAAI,GAAG,SAAS,CAAC;AACpE,UAAM,OAAO,SAAS,QAAQ,YAAY,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,IAAI,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC;AAC/G,QAAI,SAAS,IAAI;AACjB,QAAI,OAAO,IAAI;AAAA,EACjB;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,MAAK;AAAA,MACL,UAAU,IAAI,WAAW,KAAK;AAAA,MAC9B,cAAY,IAAI;AAAA,MAChB,iBAAe,IAAI,YAAY;AAAA,MAC/B;AAAA,MACA,eAAa,GAAG,MAAM;AAAA,MACtB,mBAAgB;AAAA,MAChB,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,KAAK,KAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,IAAI;AAAA,MACjF,IAAI;AAAA,QACF,UAAU;AAAA,QACV,WAAW;AAAA,QACX,OAAO,IAAI,OAAO,EAAE;AAAA,QACpB,QAAQ,IAAI,OAAO,EAAE;AAAA,QACrB,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,QAAQ,IAAI,WAAW,YAAY;AAAA,QACnC,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,mBAAmB,EAAE,SAAS,GAAG,IAAI,OAAO,CAAC,CAAC,UAAU,cAAc,gBAAgB,eAAe,IAAI,OAAO,CAAC,EAAE;AAAA,MACrH;AAAA,MAEA;AAAA,6BAAC,OAAI,WAAU,OAAM,SAAQ,aAAY,eAAY,QAAO,IAAI,EAAE,OAAO,IAAI,OAAO,EAAE,GAAG,QAAQ,IAAI,OAAO,EAAE,EAAE,GAC9G;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,GAAE;AAAA,cACF,MAAM,MAAM,QAAQ,QAAQ;AAAA,cAC5B,QAAQ,MAAM,QAAQ,WAAW;AAAA,cACjC,aAAa;AAAA;AAAA,UACf;AAAA,UACA,oBAAC,YAAO,IAAG,MAAK,IAAG,QAAO,GAAE,KAAI,MAAM,MAAM,QAAQ,WAAW,OAAO;AAAA,WACxE;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,eAAW;AAAA,YACX,IAAI;AAAA,cACF,UAAU;AAAA,cACV,MAAM;AAAA,cACN,KAAK;AAAA,cACL,IAAI;AAAA,cACJ,cAAc;AAAA,cACd,QAAQ;AAAA,cACR,aAAa;AAAA,cACb,SAAS;AAAA,cACT,OAAO;AAAA,cACP,UAAU,IAAI,OAAO,EAAE;AAAA,cACvB,YAAY;AAAA,cACZ,YAAY;AAAA,cACZ,eAAe;AAAA,YACjB;AAAA,YAEC,cAAI;AAAA;AAAA,QACP;AAAA;AAAA;AAAA,EACF;AAEJ;AAOA,SAAS,WACP,KACA,QACA,MACM;AACN,QAAM,UAAU,MAAM;AACpB,UAAM,UAAU,IAAI;AACpB,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI,WAA0B;AAG9B,QAAI,OAA+B;AACnC,UAAM,UAAU,CAAC,UAAgD;AAC/D,YAAM,MAAM,OAAO,SAAS,sBAAsB;AAClD,UAAI,CAAC,OAAO,IAAI,UAAU,KAAK,IAAI,WAAW,EAAG,QAAO;AACxD,YAAM,EAAE,MAAM,OAAO,IAAI,KAAK;AAC9B,UAAI,CAAC,OAAO,SAAS,MAAM,OAAO,KAAK,CAAC,OAAO,SAAS,MAAM,OAAO,EAAG,QAAO;AAC/E,YAAM,KAAK,eAAe,MAAM,UAAU,IAAI,QAAQ,IAAI,KAAK;AAC/D,YAAM,KAAK,eAAe,MAAM,UAAU,IAAI,OAAO,IAAI,MAAM;AAC/D,aAAO,SAAS,QAAQ,EAAE,GAAG,KAAK,OAAO,KAAK,KAAK,OAAO,GAAG,KAAK,OAAO,KAAK,KAAK,MAAM,CAAC;AAAA,IAC5F;AACA,UAAM,OAAO,CAAC,UAA8B;AAC1C,YAAM,gBAAgB;AACtB,UAAI,KAAK,QAAQ,IAAI,SAAU;AAC/B,YAAM,eAAe;AACrB,iBAAW,MAAM;AACjB,aAAO;AACP,cAAQ,oBAAoB,MAAM,SAAS;AAAA,IAC7C;AACA,UAAM,OAAO,CAAC,UAA8B;AAC1C,UAAI,aAAa,MAAM,UAAW;AAClC,YAAM,gBAAgB;AACtB,YAAM,KAAK,QAAQ,KAAK;AACxB,UAAI,CAAC,GAAI;AACT,aAAO;AACP,WAAK,QAAQ,IAAI,SAAS,EAAE;AAAA,IAC9B;AACA,UAAM,KAAK,CAAC,UAA8B;AACxC,UAAI,aAAa,MAAM,UAAW;AAClC,YAAM,gBAAgB;AACtB,iBAAW;AACX,YAAM,KAAK,MAAM,SAAS,kBAAkB,OAAQ,QAAQ,KAAK,KAAK;AACtE,UAAI,GAAI,MAAK,QAAQ,IAAI,OAAO,EAAE;AAAA,IACpC;AAEA,UAAM,QAAQ,CAAC,UAA4B,MAAM,gBAAgB;AACjE,YAAQ,iBAAiB,eAAe,IAAI;AAC5C,YAAQ,iBAAiB,eAAe,IAAI;AAC5C,YAAQ,iBAAiB,aAAa,EAAE;AACxC,YAAQ,iBAAiB,iBAAiB,EAAE;AAC5C,YAAQ,iBAAiB,SAAS,KAAK;AACvC,WAAO,MAAM;AACX,cAAQ,oBAAoB,eAAe,IAAI;AAC/C,cAAQ,oBAAoB,eAAe,IAAI;AAC/C,cAAQ,oBAAoB,aAAa,EAAE;AAC3C,cAAQ,oBAAoB,iBAAiB,EAAE;AAC/C,cAAQ,oBAAoB,SAAS,KAAK;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC;AACxB;AAGO,SAAS,WAAW,EAAE,IAAI,OAAO,MAAM,GAAkF;AAC9H,SACE,gCACG,gBAAM,IAAI,CAAC,WACV;AAAA,IAAC;AAAA;AAAA,MAEC,IAAI,GAAG;AAAA,MACP,IAAI,GAAG;AAAA,MACP,GAAG;AAAA,MACH,MAAM,MAAM,MAAM,QAAQ,QAAQ,MAAM,IAAI;AAAA,MAC5C,QAAQ,MAAM,QAAQ,QAAQ;AAAA,MAC9B,aAAa;AAAA,MACb,cAAa;AAAA,MACb,eAAc;AAAA;AAAA,IART;AAAA,EASP,CACD,GACH;AAEJ;AAGO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOsB;AACpB,QAAM,KAAK,WAAW,QAAQ,CAAC,MAAM,GAAG,UAAU,MAAM,GAAG,SAAS,CAAC;AACrE,QAAM,SAAS,MAAM,QAAQ,KAAK;AAClC,QAAM,SAAS,EAAE,MAAM,QAAQ,QAAQ,cAAc,sBAAsB,eAAe,OAAO;AACjG,SACE,qBAAC,OAAE,eAAa,GAAG,MAAM,UACvB;AAAA,wBAAC,YAAO,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,MAAM,cAAc,aAAa,KAAK,iBAAgB,OAAO,GAAG,QAAQ;AAAA,IACvG,oBAAC,UAAK,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,aAAa,KAAK,iBAAgB,OAAO,GAAG,QAAQ;AAAA,IACxG,oBAAC,YAAO,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,KAAK,QAAQ,KAAK,aAAa,GAAG,iBAAgB,OAAO,GAAG,QAAQ,MAAM,MAAM,MAAM,QAAQ,WAAW,OAAO,GAAG,GAAG;AAAA,KACvJ;AAEJ;AAGO,SAAS,KAAK,EAAE,MAAM,YAAY,MAAM,QAAQ,MAAM,GAA+H;AAC1L,SACE,oBAAC,OAAE,eAAa,GAAG,MAAM,SACtB,eAAK,IAAI,CAAC,QAAQ;AACjB,UAAM,KAAK,WAAW,QAAQ,CAAC,IAAI,GAAG,UAAU,IAAI,GAAG,SAAS,CAAC;AACjE,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,IAAI,GAAG;AAAA,QACP,IAAI,GAAG;AAAA,QACP,GAAG,KAAK,QAAQ;AAAA,QAChB,MAAM,IAAI,SAAS,MAAM,QAAQ,KAAK,UAAU,MAAM,QAAQ,WAAW;AAAA,QACzE,QAAQ,MAAM,QAAQ,KAAK;AAAA,QAC3B,aAAa;AAAA,QACb,cAAa;AAAA,QACb,eAAc;AAAA,QACd,eAAa,IAAI,SAAS,SAAS;AAAA;AAAA,MAT9B,IAAI;AAAA,IAUX;AAAA,EAEJ,CAAC,GACH;AAEJ;AAGA,IAAM,cAAc,CAAC,IAAI,KAAK,KAAK,KAAK,KAAM,KAAM,KAAM,KAAO,KAAO,GAAK;AAGtE,SAAS,YAAY,MAAwB;AAClD,QAAM,UAAU,KAAK,QAAQ;AAC7B,SAAO,YAAY,OAAO,CAAC,SAAS,QAAQ,OAAO,EAAE,GAAG,EAAE,KAAK,YAAY,CAAC;AAC9E;AASO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAM6B;AAG3B,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,EAAE,SAAS,GAAG,OAAO,EAAE,CAAC;AACnE,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,gBAAgB,MAAM;AAC1B,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,OAAO;AACnB,UAAM,OAAO,EAAE,SAAS,KAAK,eAAe,GAAG,OAAO,KAAK,sBAAsB,EAAE,SAAS,EAAE;AAC9F,QAAI,KAAK,YAAY,OAAO,WAAW,KAAK,IAAI,KAAK,QAAQ,OAAO,KAAK,IAAI,IAAK,WAAU,IAAI;AAAA,EAClG,CAAC;AACD,MAAI,CAAC,KAAK,MAAO,QAAO;AACxB,QAAM,OAAO,OAAO,UAAU,KAAK,OAAO,QAAQ,IAAI,OAAO,QAAQ,OAAO,UAAU;AACtF,QAAM,SAAS,YAAY,EAAE,GAAG,MAAM,OAAO,KAAK,QAAQ,KAAK,CAAC;AAEhE,QAAM,QAAS,SAAS,OAAQ,KAAK;AACrC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAa,GAAG,MAAM;AAAA,MACtB,eAAW;AAAA,MACX,IAAI,EAAE,UAAU,YAAY,MAAM,GAAG,OAAO,GAAG,QAAQ,IAAI,OAAO,EAAE,GAAG,eAAe,QAAQ,QAAQ,EAAE;AAAA,MAExG;AAAA,4BAAC,OAAI,WAAU,QAAO,IAAI,EAAE,SAAS,SAAS,IAAI,IAAI,OAAO,EAAE,GAAG,UAAU,IAAI,OAAO,EAAE,GAAG,OAAO,iBAAiB,GACjH,eAAK,MAAM,MAAM,GACpB;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,IAAI,EAAE,SAAS,SAAS,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,OAAO,EAAE,GAAG,OAAO,IAAI,QAAQ,KAAK,QAAQ,CAAC,CAAC,KAAK,aAAa,SAAS,aAAa,KAAK,IAAI,OAAO,GAAG,CAAC,IAAI,IAAI,OAAO,GAAG,CAAC,IAAI,aAAa,iBAAiB;AAAA;AAAA,QACxN;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/components/data-display/RegionMap/RegionMapPin.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport { alpha, type Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { rem } from '../../../tokens/relative';\n\nimport { METRES_PER_DEGREE, type PlaneBox, type PlanePoint, type Projection } from './RegionMap.helpers';\nimport type { RegionMapModel } from './RegionMap.hooks';\nimport type { RegionMapCenter, RegionMapCopy, RegionMapDot, RegionMapGhost, RegionMapPin } from './RegionMap.types';\n\n/**\n * The movable centre of a `RegionMap` (`pin`, `ghost`, `dots`): a pin the\n * viewer drags with a mouse or one finger, or focuses and nudges with the\n * arrow keys, while the VIEW stays where `center` put it — so the areas never\n * slide under a dragging finger. The circles follow the pin; a dashed ring\n * and dot stay at `ghost`; `dots` are small points (filled or hollow).\n *\n * The pin is HTML over the drawing, at its point by percent like the labels,\n * carrying `data-region-pin` so a host that zooms the drawing's layers can\n * move it with them. Its moves are reported, never applied: the host passes\n * the new point back.\n */\n\n/** The movable centre and what is drawn with it, as the drawing receives it. */\nexport interface Moving {\n center: RegionMapCenter;\n pin?: RegionMapPin;\n ghost?: RegionMapGhost;\n dots?: readonly RegionMapDot[];\n copy: RegionMapCopy;\n}\n\ntype DrawnModel = Pick<RegionMapModel, 'projection' | 'radii'> & { view: PlaneBox };\n\n/**\n * What the movable centre draws inside the SVG: the circles around the pin\n * (else `fallback`, the centre's own circles), the ghost, and the dots.\n */\nexport function PinShapes({ model, moving, testId, theme, fallback }: { model: DrawnModel; moving: Moving | undefined; testId: string; theme: Theme; fallback: React.ReactNode }): React.JSX.Element {\n const { projection, view } = model;\n if (!moving || !projection) return <>{fallback}</>;\n const pinAt = moving.pin ? projection.project([moving.pin.at.latitude, moving.pin.at.longitude]) : null;\n return (\n <>\n {pinAt ? <PinCircles at={pinAt} radii={model.radii} theme={theme} /> : fallback}\n {pinAt && moving.ghost ? <GhostShapes ghost={moving.ghost} pinAt={pinAt} projection={projection} view={view} testId={testId} theme={theme} /> : null}\n {moving.dots ? <Dots dots={moving.dots} projection={projection} view={view} testId={testId} theme={theme} /> : null}\n </>\n );\n}\n\n/** What the movable centre draws over the SVG, in HTML: the pin and the scale bar. */\nexport function PinOverlay({\n model,\n moving,\n svgRef,\n testId,\n theme,\n}: {\n model: DrawnModel;\n moving: Moving | undefined;\n svgRef: React.RefObject<SVGSVGElement | null>;\n testId: string;\n theme: Theme;\n}): React.JSX.Element | null {\n if (!moving || !model.projection) return null;\n return (\n <>\n {moving.pin ? <PinMarker pin={moving.pin} center={moving.center} projection={model.projection} view={model.view} svgRef={svgRef} testId={testId} theme={theme} /> : null}\n <ScaleBar view={model.view} copy={moving.copy} svgRef={svgRef} testId={testId} theme={theme} />\n </>\n );\n}\n\n/** The flat projection's inverse around `center` — it is linear. */\nexport function latLngAt(center: RegionMapCenter, point: PlanePoint): RegionMapCenter {\n const kx = METRES_PER_DEGREE * Math.cos((center.latitude * Math.PI) / 180);\n return { latitude: center.latitude - point.y / METRES_PER_DEGREE, longitude: center.longitude + point.x / kx };\n}\n\n/** A point of the plane as fractions of the view (0..1 across, 0..1 down). */\nfunction fractionOf(view: PlaneBox, point: PlanePoint): { x: number; y: number } {\n return { x: (point.x - view.minX) / view.spanX, y: (point.y - view.minY) / view.spanY };\n}\n\n/** Keep a fraction inside the view, a hair in from its edge (the mock's clamp). */\nconst clampFraction = (value: number): number => Math.min(0.995, Math.max(0.005, value));\n\n/** A plane point kept inside the view by the same clamp a drag gets. */\nfunction clampToView(view: PlaneBox, point: PlanePoint): PlanePoint {\n const at = fractionOf(view, point);\n return { x: view.minX + clampFraction(at.x) * view.spanX, y: view.minY + clampFraction(at.y) * view.spanY };\n}\n\n/** Arrow keys, as metres east and north per press. */\nconst ARROWS: Record<string, [number, number]> = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, 1], ArrowDown: [0, -1] };\n\n/** One arrow key: 50 m unless the host says otherwise. */\nconst DEFAULT_STEP_METRES = 50;\n\ninterface PinLayerProps {\n pin: RegionMapPin;\n center: RegionMapCenter;\n projection: Projection;\n view: PlaneBox;\n /** The drawing's SVG, whose on-screen box maps a pointer to the plane (zoomed or not). */\n svgRef: React.RefObject<SVGSVGElement | null>;\n testId: string;\n theme: Theme;\n}\n\n/** The draggable pin, as HTML over the drawing. */\nexport function PinMarker({ pin, center, projection, view, svgRef, testId, theme }: PinLayerProps): React.JSX.Element {\n const ref = React.useRef<HTMLDivElement>(null);\n const live = React.useRef({ pin, center, view });\n live.current = { pin, center, view };\n usePinDrag(ref, svgRef, live);\n const at = fractionOf(view, projection.project([pin.at.latitude, pin.at.longitude]));\n const onKeyDown = (event: React.KeyboardEvent): void => {\n const arrow = ARROWS[event.key];\n if (!arrow || pin.disabled) return;\n event.preventDefault();\n const step = pin.stepMetres ?? DEFAULT_STEP_METRES;\n const plane = projection.project([pin.at.latitude, pin.at.longitude]);\n const next = latLngAt(center, clampToView(view, { x: plane.x + arrow[0] * step, y: plane.y - arrow[1] * step }));\n pin.onMove?.(next);\n pin.onDrop(next);\n };\n return (\n <Box\n ref={ref}\n role=\"button\"\n tabIndex={pin.disabled ? -1 : 0}\n aria-label={pin.ariaLabel}\n aria-disabled={pin.disabled || undefined}\n onKeyDown={onKeyDown}\n data-testid={`${testId}-pin`}\n data-region-pin=\"\"\n style={{ left: `${(at.x * 100).toFixed(3)}%`, top: `${(at.y * 100).toFixed(3)}%` }}\n sx={{\n position: 'absolute',\n transform: 'translate(-50%, -100%)',\n width: rem(theme, 44),\n height: rem(theme, 48),\n display: 'flex',\n alignItems: 'flex-end',\n justifyContent: 'center',\n cursor: pin.disabled ? 'default' : 'grab',\n touchAction: 'none',\n zIndex: 2,\n borderRadius: 1,\n '&:focus-visible': { outline: `${rem(theme, 2)} solid`, outlineColor: 'primary.main', outlineOffset: rem(theme, 2) },\n }}\n >\n <Box component=\"svg\" viewBox=\"0 0 32 42\" aria-hidden=\"true\" sx={{ width: rem(theme, 32), height: rem(theme, 42) }}>\n <path\n d=\"M16 41C16 41 3 25 3 15.5A13 13 0 1 1 29 15.5C29 25 16 41 16 41Z\"\n fill={theme.palette.primary.main}\n stroke={theme.palette.background.paper}\n strokeWidth={2}\n />\n <circle cx=\"16\" cy=\"15.5\" r=\"5\" fill={theme.palette.background.paper} />\n </Box>\n <Box\n component=\"span\"\n aria-hidden\n sx={{\n position: 'absolute',\n left: '88%',\n top: 0,\n px: 0.75,\n borderRadius: 0.5,\n border: 1,\n borderColor: 'divider',\n bgcolor: 'background.paper',\n color: 'text.primary',\n fontSize: rem(theme, 12),\n fontWeight: 600,\n whiteSpace: 'nowrap',\n pointerEvents: 'none',\n }}\n >\n {pin.label}\n </Box>\n </Box>\n );\n}\n\n/**\n * The pointer drag: native listeners on the pin, so a host's own listeners on\n * the drawing (a pan, a tap) never see the press; captured, so a finger that\n * leaves the pin keeps dragging it; clamped inside the view.\n */\nfunction usePinDrag(\n ref: React.RefObject<HTMLDivElement | null>,\n svgRef: React.RefObject<SVGSVGElement | null>,\n live: React.RefObject<{ pin: RegionMapPin; center: RegionMapCenter; view: PlaneBox }>,\n): void {\n React.useEffect(() => {\n const element = ref.current;\n if (!element) return undefined;\n let dragging: number | null = null;\n // Where the last move put the pin: a cancelled gesture (a browser may\n // report 0,0 for it) rests there rather than jumping to the corner.\n let last: RegionMapCenter | null = null;\n const pointAt = (event: PointerEvent): RegionMapCenter | null => {\n const box = svgRef.current?.getBoundingClientRect();\n if (!box || box.width === 0 || box.height === 0) return null;\n const { view, center } = live.current;\n if (!Number.isFinite(event.clientX) || !Number.isFinite(event.clientY)) return null;\n const fx = clampFraction((event.clientX - box.left) / box.width);\n const fy = clampFraction((event.clientY - box.top) / box.height);\n return latLngAt(center, { x: view.minX + fx * view.spanX, y: view.minY + fy * view.spanY });\n };\n const down = (event: PointerEvent): void => {\n event.stopPropagation();\n if (live.current.pin.disabled) return;\n event.preventDefault();\n dragging = event.pointerId;\n last = null;\n element.setPointerCapture?.(event.pointerId);\n };\n const move = (event: PointerEvent): void => {\n if (dragging !== event.pointerId) return;\n event.stopPropagation();\n const at = pointAt(event);\n if (!at) return;\n last = at;\n live.current.pin.onMove?.(at);\n };\n const up = (event: PointerEvent): void => {\n if (dragging !== event.pointerId) return;\n event.stopPropagation();\n dragging = null;\n const at = event.type === 'pointercancel' ? last : (pointAt(event) ?? last);\n if (at) live.current.pin.onDrop(at);\n };\n // A click that ends a drag is the drag's, not a tap on the area under it.\n const click = (event: MouseEvent): void => event.stopPropagation();\n element.addEventListener('pointerdown', down);\n element.addEventListener('pointermove', move);\n element.addEventListener('pointerup', up);\n element.addEventListener('pointercancel', up);\n element.addEventListener('click', click);\n return () => {\n element.removeEventListener('pointerdown', down);\n element.removeEventListener('pointermove', move);\n element.removeEventListener('pointerup', up);\n element.removeEventListener('pointercancel', up);\n element.removeEventListener('click', click);\n };\n }, [ref, svgRef, live]);\n}\n\n/** The circles around the pin: solid in the primary colour, faintly filled. */\nexport function PinCircles({ at, radii, theme }: { at: PlanePoint; radii: readonly number[]; theme: Theme }): React.JSX.Element {\n return (\n <>\n {radii.map((radius) => (\n <circle\n key={radius}\n cx={at.x}\n cy={at.y}\n r={radius}\n fill={alpha(theme.palette.primary.main, 0.06)}\n stroke={theme.palette.primary.main}\n strokeWidth={2.25}\n vectorEffect=\"non-scaling-stroke\"\n pointerEvents=\"none\"\n />\n ))}\n </>\n );\n}\n\n/** Where the circles stood: a dashed ring and dot at `ghost`, and a dashed line from it to the pin. */\nexport function GhostShapes({\n ghost,\n pinAt,\n projection,\n view,\n testId,\n theme,\n}: {\n ghost: RegionMapGhost;\n pinAt: PlanePoint;\n projection: Projection;\n view: PlaneBox;\n testId: string;\n theme: Theme;\n}): React.JSX.Element {\n const at = projection.project([ghost.at.latitude, ghost.at.longitude]);\n const stroke = theme.palette.text.secondary;\n const common = { fill: 'none', stroke, vectorEffect: 'non-scaling-stroke', pointerEvents: 'none' } as const;\n return (\n <g data-testid={`${testId}-ghost`}>\n <circle cx={at.x} cy={at.y} r={ghost.radiusMetres} strokeWidth={1.5} strokeDasharray=\"6 5\" {...common} />\n <line x1={at.x} y1={at.y} x2={pinAt.x} y2={pinAt.y} strokeWidth={1.5} strokeDasharray=\"4 4\" {...common} />\n <circle cx={at.x} cy={at.y} r={view.spanX / 110} strokeWidth={2} strokeDasharray=\"3 2\" {...common} fill={alpha(theme.palette.background.paper, 0.7)} />\n </g>\n );\n}\n\n/** The dots: filled with the ink, or hollow (paper with an ink ring). */\nexport function Dots({ dots, projection, view, testId, theme }: { dots: readonly RegionMapDot[]; projection: Projection; view: PlaneBox; testId: string; theme: Theme }): React.JSX.Element {\n return (\n <g data-testid={`${testId}-dots`}>\n {dots.map((dot) => {\n const at = projection.project([dot.at.latitude, dot.at.longitude]);\n return (\n <circle\n key={dot.id}\n cx={at.x}\n cy={at.y}\n r={view.spanX / 150}\n fill={dot.filled ? theme.palette.text.primary : theme.palette.background.paper}\n stroke={theme.palette.text.primary}\n strokeWidth={2}\n vectorEffect=\"non-scaling-stroke\"\n pointerEvents=\"none\"\n data-filled={dot.filled ? 'true' : 'false'}\n />\n );\n })}\n </g>\n );\n}\n\n/** Nice lengths a scale bar may take, in metres. */\nconst SCALE_STEPS = [50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000];\n\n/** The longest nice length that fits in a quarter of the drawing's width. */\nexport function scaleMetres(view: PlaneBox): number {\n const quarter = view.spanX / 4;\n return SCALE_STEPS.filter((step) => step <= quarter).at(-1) ?? SCALE_STEPS[0]!;\n}\n\n/**\n * A scale bar, bottom-left, when the host gives `copy.scale`. It reads what is\n * on screen: a host that zooms the drawing's layers (a CSS scale on the SVG)\n * shows fewer metres per pixel, so after every render the bar compares the\n * SVG's drawn width with its laid-out width — both off the SVG itself — and\n * spans the drawing's own width, so its share of it is a share of the view.\n */\nexport function ScaleBar({\n view,\n copy,\n svgRef,\n testId,\n theme,\n}: {\n view: PlaneBox;\n copy: RegionMapCopy;\n svgRef: React.RefObject<SVGSVGElement | null>;\n testId: string;\n theme: Theme;\n}): React.JSX.Element | null {\n // What the drawing shows on screen: its laid-out width, and its width as\n // drawn (a host's CSS scale on the SVG), both read off the SVG itself.\n const [screen, setScreen] = React.useState({ laidOut: 0, drawn: 0 });\n const wanted = copy.scale !== undefined;\n React.useLayoutEffect(() => {\n if (!wanted) return;\n const svg = svgRef.current;\n const next = { laidOut: svg?.clientWidth ?? 0, drawn: svg?.getBoundingClientRect().width ?? 0 };\n if (next.laidOut !== screen.laidOut || Math.abs(next.drawn - screen.drawn) > 0.5) setScreen(next);\n });\n if (!copy.scale) return null;\n const zoom = screen.laidOut > 0 && screen.drawn > 0 ? screen.drawn / screen.laidOut : 1;\n const metres = scaleMetres({ ...view, spanX: view.spanX / zoom });\n // The bar's share of the drawing's width: metres on screen over the metres the width shows.\n const share = (metres * zoom) / view.spanX;\n return (\n <Box\n data-testid={`${testId}-scale`}\n aria-hidden\n sx={{ position: 'absolute', left: 0, right: 0, bottom: rem(theme, 10), pointerEvents: 'none', zIndex: 1 }}\n >\n <Box component=\"span\" sx={{ display: 'block', ml: rem(theme, 10), fontSize: rem(theme, 12), color: 'text.secondary' }}>\n {copy.scale(metres)}\n </Box>\n <Box\n component=\"span\"\n sx={{ display: 'block', height: rem(theme, 4), ml: rem(theme, 10), width: `${(share * 100).toFixed(2)}%`, borderStyle: 'solid', borderWidth: `0 ${rem(theme, 1.5)} ${rem(theme, 1.5)}`, borderColor: 'text.secondary' }}\n />\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-PBRCKHN3.js";
10
10
  import {
11
11
  RegionMapDrawing
12
- } from "./chunk-3V5V44UP.js";
12
+ } from "./chunk-YHFLI2FD.js";
13
13
 
14
14
  // src/components/data-display/RegionMap/RegionMap.tsx
15
15
  import Box from "@mui/material/Box/index.js";
@@ -84,4 +84,4 @@ function RegionMap({
84
84
  export {
85
85
  RegionMap
86
86
  };
87
- //# sourceMappingURL=chunk-AYDVNXGR.js.map
87
+ //# sourceMappingURL=chunk-LCKUEYU2.js.map
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  PinOverlay,
7
7
  PinShapes
8
- } from "./chunk-DRYBA76G.js";
8
+ } from "./chunk-7XVT4RME.js";
9
9
  import {
10
10
  labelPosition
11
11
  } from "./chunk-MNJZPJ5S.js";
@@ -254,4 +254,4 @@ function AreaLabel({
254
254
  export {
255
255
  RegionMapDrawing
256
256
  };
257
- //# sourceMappingURL=chunk-3V5V44UP.js.map
257
+ //# sourceMappingURL=chunk-YHFLI2FD.js.map
@@ -1,16 +1,16 @@
1
1
  import "../chunk-WGKLBVDZ.js";
2
2
  import {
3
3
  RegionMap
4
- } from "../chunk-AYDVNXGR.js";
4
+ } from "../chunk-LCKUEYU2.js";
5
5
  import "../chunk-NWUMGE6T.js";
6
6
  import "../chunk-BRZKOUEL.js";
7
7
  import "../chunk-PBRCKHN3.js";
8
- import "../chunk-3V5V44UP.js";
8
+ import "../chunk-YHFLI2FD.js";
9
9
  import "../chunk-J3AWGTJY.js";
10
10
  import {
11
11
  latLngAt,
12
12
  scaleMetres
13
- } from "../chunk-DRYBA76G.js";
13
+ } from "../chunk-7XVT4RME.js";
14
14
  import {
15
15
  boundsOfRings,
16
16
  regionMapView
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "6.99.0",
3
+ "version": "6.100.0",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@10.34.5",
6
6
  "type": "module",
@@ -376,7 +376,7 @@ export function ScaleBar({
376
376
  aria-hidden
377
377
  sx={{ position: 'absolute', left: 0, right: 0, bottom: rem(theme, 10), pointerEvents: 'none', zIndex: 1 }}
378
378
  >
379
- <Box component="span" sx={{ display: 'block', ml: rem(theme, 10), fontSize: rem(theme, 11), color: 'text.secondary' }}>
379
+ <Box component="span" sx={{ display: 'block', ml: rem(theme, 10), fontSize: rem(theme, 12), color: 'text.secondary' }}>
380
380
  {copy.scale(metres)}
381
381
  </Box>
382
382
  <Box