@accelint/map-toolkit 1.2.0 → 1.3.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.
- package/CHANGELOG.md +11 -0
- package/catalog-info.yaml +3 -3
- package/dist/camera/events.d.ts +45 -0
- package/dist/camera/events.js +45 -0
- package/dist/camera/events.js.map +1 -1
- package/dist/camera/store.d.ts +47 -0
- package/dist/camera/store.js +81 -0
- package/dist/camera/store.js.map +1 -1
- package/dist/camera/types.d.ts +81 -0
- package/dist/cursor-coordinates/constants.d.ts +8 -0
- package/dist/cursor-coordinates/constants.js +22 -0
- package/dist/cursor-coordinates/constants.js.map +1 -0
- package/dist/cursor-coordinates/store.d.ts +1 -0
- package/dist/cursor-coordinates/store.js +1 -0
- package/dist/cursor-coordinates/store.js.map +1 -1
- package/dist/cursor-coordinates/use-cursor-coordinates.d.ts +5 -0
- package/dist/cursor-coordinates/use-cursor-coordinates.js +23 -8
- package/dist/cursor-coordinates/use-cursor-coordinates.js.map +1 -1
- package/dist/deckgl/base-map/constants.d.ts +12 -0
- package/dist/deckgl/base-map/constants.js +12 -0
- package/dist/deckgl/base-map/constants.js.map +1 -1
- package/dist/deckgl/base-map/controls.d.ts +11 -1
- package/dist/deckgl/base-map/controls.js +5 -0
- package/dist/deckgl/base-map/controls.js.map +1 -1
- package/dist/deckgl/base-map/events.d.ts +30 -0
- package/dist/deckgl/base-map/events.js +30 -0
- package/dist/deckgl/base-map/events.js.map +1 -1
- package/dist/deckgl/base-map/index.d.ts +2 -2
- package/dist/deckgl/base-map/index.js +33 -3
- package/dist/deckgl/base-map/index.js.map +1 -1
- package/dist/deckgl/base-map/provider.d.ts +2 -2
- package/dist/deckgl/index.js +1 -1
- package/dist/deckgl/saved-viewports/index.d.ts +75 -0
- package/dist/deckgl/saved-viewports/index.js +58 -0
- package/dist/deckgl/saved-viewports/index.js.map +1 -1
- package/dist/deckgl/saved-viewports/storage.d.ts +51 -0
- package/dist/deckgl/saved-viewports/storage.js +64 -0
- package/dist/deckgl/saved-viewports/storage.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/constants.js +18 -6
- package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/fiber.d.ts +7 -0
- package/dist/deckgl/shapes/display-shape-layer/fiber.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js +61 -4
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.d.ts +22 -8
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.js +75 -4
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/constants.js +30 -0
- package/dist/deckgl/shapes/draw-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/fiber.js +36 -0
- package/dist/deckgl/shapes/draw-shape-layer/fiber.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +2 -2
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +32 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +37 -8
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +43 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +44 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +46 -3
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/index.js +37 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/index.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/store.js +50 -2
- package/dist/deckgl/shapes/draw-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js +138 -17
- package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/events.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/events.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +2 -2
- package/dist/deckgl/shapes/edit-shape-layer/index.js +14 -0
- package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js +56 -8
- package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +26 -4
- package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +28 -3
- package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/index.js +24 -0
- package/dist/deckgl/shapes/edit-shape-layer/modes/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js +33 -4
- package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js +21 -2
- package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js +35 -11
- package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/store.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js +12 -0
- package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js.map +1 -1
- package/dist/deckgl/shapes/shared/types.d.ts +3 -3
- package/dist/deckgl/shapes/shared/types.js +2 -2
- package/dist/deckgl/shapes/shared/types.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/geometry-measurements.js +3 -3
- package/dist/deckgl/shapes/shared/utils/geometry-measurements.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/pick-filtering.js +1 -1
- package/dist/deckgl/shapes/shared/utils/pick-filtering.js.map +1 -1
- package/dist/deckgl/symbol-layer/fiber.d.ts +18 -0
- package/dist/deckgl/symbol-layer/fiber.js.map +1 -1
- package/dist/deckgl/symbol-layer/index.d.ts +79 -1
- package/dist/deckgl/symbol-layer/index.js +72 -1
- package/dist/deckgl/symbol-layer/index.js.map +1 -1
- package/dist/deckgl/text-layer/character-sets.d.ts +30 -0
- package/dist/deckgl/text-layer/character-sets.js +26 -0
- package/dist/deckgl/text-layer/character-sets.js.map +1 -1
- package/dist/deckgl/text-layer/default-settings.d.ts +29 -0
- package/dist/deckgl/text-layer/default-settings.js +28 -0
- package/dist/deckgl/text-layer/default-settings.js.map +1 -1
- package/dist/deckgl/text-layer/index.d.ts +65 -0
- package/dist/deckgl/text-layer/index.js +56 -0
- package/dist/deckgl/text-layer/index.js.map +1 -1
- package/dist/map-cursor/events.d.ts +19 -0
- package/dist/map-cursor/events.js +19 -0
- package/dist/map-cursor/events.js.map +1 -1
- package/dist/map-cursor/store.d.ts +34 -2
- package/dist/map-cursor/store.js +44 -3
- package/dist/map-cursor/store.js.map +1 -1
- package/dist/map-mode/store.d.ts +43 -4
- package/dist/map-mode/store.js +56 -6
- package/dist/map-mode/store.js.map +1 -1
- package/dist/shared/create-map-store.d.ts +14 -0
- package/dist/shared/create-map-store.js +26 -2
- package/dist/shared/create-map-store.js.map +1 -1
- package/dist/shared/units.d.ts +24 -0
- package/dist/shared/units.js +24 -0
- package/dist/shared/units.js.map +1 -1
- package/dist/viewport/store.d.ts +1 -0
- package/dist/viewport/store.js +4 -0
- package/dist/viewport/store.js.map +1 -1
- package/package.json +3 -3
|
@@ -15,7 +15,16 @@ import { TextLayer as TextLayer$1, TextLayerProps as TextLayerProps$1 } from "@d
|
|
|
15
15
|
import { LiteralUnion } from "type-fest";
|
|
16
16
|
|
|
17
17
|
//#region src/deckgl/text-layer/index.d.ts
|
|
18
|
+
/**
|
|
19
|
+
* Props for TextLayer component.
|
|
20
|
+
* Extends Deck.gl's TextLayerProps with enhanced character set support.
|
|
21
|
+
*/
|
|
18
22
|
interface TextLayerProps<TData = unknown> extends TextLayerProps$1<TData> {
|
|
23
|
+
/**
|
|
24
|
+
* Character set to use for text rendering.
|
|
25
|
+
* Can be a predefined CHARACTER_SETS key or a custom string of characters.
|
|
26
|
+
* Defaults to CHARACTER_SETS.EXPANDED for international text support.
|
|
27
|
+
*/
|
|
19
28
|
characterSet?: LiteralUnion<CharacterSetsKeys, string>;
|
|
20
29
|
}
|
|
21
30
|
/**
|
|
@@ -30,6 +39,62 @@ interface TextLayerProps<TData = unknown> extends TextLayerProps$1<TData> {
|
|
|
30
39
|
* Can be used directly with Deck.gl or as a JSX element with React Fiber:
|
|
31
40
|
* - React Fiber: `<textLayer id="text" data={[...]} ... />`
|
|
32
41
|
* - Direct: `new TextLayer({ id: 'text', data: [...], ... })`
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* Direct Deck.gl usage:
|
|
45
|
+
* ```typescript
|
|
46
|
+
* import { Deck } from '@deck.gl/core';
|
|
47
|
+
* import { TextLayer } from '@accelint/map-toolkit/deckgl/text-layer';
|
|
48
|
+
*
|
|
49
|
+
* const layer = new TextLayer({
|
|
50
|
+
* id: 'text-labels',
|
|
51
|
+
* data: [
|
|
52
|
+
* { position: [-122.4, 37.74], text: 'San Francisco' },
|
|
53
|
+
* { position: [-118.2, 34.05], text: 'Los Angeles' },
|
|
54
|
+
* ],
|
|
55
|
+
* getText: d => d.text,
|
|
56
|
+
* getPosition: d => d.position,
|
|
57
|
+
* getSize: 14,
|
|
58
|
+
* fontWeight: 600,
|
|
59
|
+
* outlineWidth: 2,
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* new Deck({
|
|
63
|
+
* initialViewState: { longitude: -120, latitude: 36, zoom: 6 },
|
|
64
|
+
* controller: true,
|
|
65
|
+
* layers: [layer],
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* React Fiber usage:
|
|
71
|
+
* ```tsx
|
|
72
|
+
* import '@accelint/map-toolkit/deckgl/text-layer/fiber';
|
|
73
|
+
* import { BaseMap } from '@accelint/map-toolkit/deckgl';
|
|
74
|
+
* import { View } from '@deckgl-fiber-renderer/dom';
|
|
75
|
+
*
|
|
76
|
+
* function MapWithLabels() {
|
|
77
|
+
* const cities = [
|
|
78
|
+
* { position: [-122.4, 37.74], text: 'San Francisco' },
|
|
79
|
+
* { position: [-118.2, 34.05], text: 'Los Angeles' },
|
|
80
|
+
* ];
|
|
81
|
+
*
|
|
82
|
+
* return (
|
|
83
|
+
* <BaseMap id="map" className="w-full h-full">
|
|
84
|
+
* <View id="main" controller />
|
|
85
|
+
* <textLayer
|
|
86
|
+
* id="city-labels"
|
|
87
|
+
* data={cities}
|
|
88
|
+
* getText={d => d.text}
|
|
89
|
+
* getPosition={d => d.position}
|
|
90
|
+
* getSize={14}
|
|
91
|
+
* fontWeight={600}
|
|
92
|
+
* outlineWidth={2}
|
|
93
|
+
* />
|
|
94
|
+
* </BaseMap>
|
|
95
|
+
* );
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
33
98
|
*/
|
|
34
99
|
declare class TextLayer<TData = unknown> extends TextLayer$1<TData> {
|
|
35
100
|
static CHARACTER_SETS: Readonly<{
|
|
@@ -28,6 +28,62 @@ import { TextLayer as TextLayer$1 } from "@deck.gl/layers";
|
|
|
28
28
|
* Can be used directly with Deck.gl or as a JSX element with React Fiber:
|
|
29
29
|
* - React Fiber: `<textLayer id="text" data={[...]} ... />`
|
|
30
30
|
* - Direct: `new TextLayer({ id: 'text', data: [...], ... })`
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* Direct Deck.gl usage:
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { Deck } from '@deck.gl/core';
|
|
36
|
+
* import { TextLayer } from '@accelint/map-toolkit/deckgl/text-layer';
|
|
37
|
+
*
|
|
38
|
+
* const layer = new TextLayer({
|
|
39
|
+
* id: 'text-labels',
|
|
40
|
+
* data: [
|
|
41
|
+
* { position: [-122.4, 37.74], text: 'San Francisco' },
|
|
42
|
+
* { position: [-118.2, 34.05], text: 'Los Angeles' },
|
|
43
|
+
* ],
|
|
44
|
+
* getText: d => d.text,
|
|
45
|
+
* getPosition: d => d.position,
|
|
46
|
+
* getSize: 14,
|
|
47
|
+
* fontWeight: 600,
|
|
48
|
+
* outlineWidth: 2,
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* new Deck({
|
|
52
|
+
* initialViewState: { longitude: -120, latitude: 36, zoom: 6 },
|
|
53
|
+
* controller: true,
|
|
54
|
+
* layers: [layer],
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* React Fiber usage:
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import '@accelint/map-toolkit/deckgl/text-layer/fiber';
|
|
62
|
+
* import { BaseMap } from '@accelint/map-toolkit/deckgl';
|
|
63
|
+
* import { View } from '@deckgl-fiber-renderer/dom';
|
|
64
|
+
*
|
|
65
|
+
* function MapWithLabels() {
|
|
66
|
+
* const cities = [
|
|
67
|
+
* { position: [-122.4, 37.74], text: 'San Francisco' },
|
|
68
|
+
* { position: [-118.2, 34.05], text: 'Los Angeles' },
|
|
69
|
+
* ];
|
|
70
|
+
*
|
|
71
|
+
* return (
|
|
72
|
+
* <BaseMap id="map" className="w-full h-full">
|
|
73
|
+
* <View id="main" controller />
|
|
74
|
+
* <textLayer
|
|
75
|
+
* id="city-labels"
|
|
76
|
+
* data={cities}
|
|
77
|
+
* getText={d => d.text}
|
|
78
|
+
* getPosition={d => d.position}
|
|
79
|
+
* getSize={14}
|
|
80
|
+
* fontWeight={600}
|
|
81
|
+
* outlineWidth={2}
|
|
82
|
+
* />
|
|
83
|
+
* </BaseMap>
|
|
84
|
+
* );
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
31
87
|
*/
|
|
32
88
|
var TextLayer = class extends TextLayer$1 {
|
|
33
89
|
static CHARACTER_SETS = CHARACTER_SETS;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["DglTextLayer"],"sources":["../../../src/deckgl/text-layer/index.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n TextLayer as DglTextLayer,\n type TextLayerProps as DglTextLayerProps,\n} from '@deck.gl/layers';\nimport { CHARACTER_SETS, type CharacterSetsKeys } from './character-sets.js';\nimport { defaultSettings } from './default-settings.js';\nimport type { LiteralUnion } from 'type-fest';\n\nexport interface TextLayerProps<TData = unknown>\n extends DglTextLayerProps<TData> {\n
|
|
1
|
+
{"version":3,"file":"index.js","names":["DglTextLayer"],"sources":["../../../src/deckgl/text-layer/index.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n TextLayer as DglTextLayer,\n type TextLayerProps as DglTextLayerProps,\n} from '@deck.gl/layers';\nimport { CHARACTER_SETS, type CharacterSetsKeys } from './character-sets.js';\nimport { defaultSettings } from './default-settings.js';\nimport type { LiteralUnion } from 'type-fest';\n\n/**\n * Props for TextLayer component.\n * Extends Deck.gl's TextLayerProps with enhanced character set support.\n */\nexport interface TextLayerProps<TData = unknown>\n extends DglTextLayerProps<TData> {\n /**\n * Character set to use for text rendering.\n * Can be a predefined CHARACTER_SETS key or a custom string of characters.\n * Defaults to CHARACTER_SETS.EXPANDED for international text support.\n */\n characterSet?: LiteralUnion<CharacterSetsKeys, string>;\n}\n\n/**\n * A styled text layer that extends Deck.gl's TextLayer with enhanced styling capabilities.\n *\n * This layer provides:\n * - Customizable font styling (size, weight, family, line height)\n * - Text outline support\n * - Extended character set support\n * - Consistent styling based on design specifications\n *\n * Can be used directly with Deck.gl or as a JSX element with React Fiber:\n * - React Fiber: `<textLayer id=\"text\" data={[...]} ... />`\n * - Direct: `new TextLayer({ id: 'text', data: [...], ... })`\n *\n * @example\n * Direct Deck.gl usage:\n * ```typescript\n * import { Deck } from '@deck.gl/core';\n * import { TextLayer } from '@accelint/map-toolkit/deckgl/text-layer';\n *\n * const layer = new TextLayer({\n * id: 'text-labels',\n * data: [\n * { position: [-122.4, 37.74], text: 'San Francisco' },\n * { position: [-118.2, 34.05], text: 'Los Angeles' },\n * ],\n * getText: d => d.text,\n * getPosition: d => d.position,\n * getSize: 14,\n * fontWeight: 600,\n * outlineWidth: 2,\n * });\n *\n * new Deck({\n * initialViewState: { longitude: -120, latitude: 36, zoom: 6 },\n * controller: true,\n * layers: [layer],\n * });\n * ```\n *\n * @example\n * React Fiber usage:\n * ```tsx\n * import '@accelint/map-toolkit/deckgl/text-layer/fiber';\n * import { BaseMap } from '@accelint/map-toolkit/deckgl';\n * import { View } from '@deckgl-fiber-renderer/dom';\n *\n * function MapWithLabels() {\n * const cities = [\n * { position: [-122.4, 37.74], text: 'San Francisco' },\n * { position: [-118.2, 34.05], text: 'Los Angeles' },\n * ];\n *\n * return (\n * <BaseMap id=\"map\" className=\"w-full h-full\">\n * <View id=\"main\" controller />\n * <textLayer\n * id=\"city-labels\"\n * data={cities}\n * getText={d => d.text}\n * getPosition={d => d.position}\n * getSize={14}\n * fontWeight={600}\n * outlineWidth={2}\n * />\n * </BaseMap>\n * );\n * }\n * ```\n */\nexport class TextLayer<TData = unknown> extends DglTextLayer<TData> {\n static CHARACTER_SETS = CHARACTER_SETS;\n\n static override layerName = 'textLayer';\n\n constructor(props: TextLayerProps<TData>) {\n const {\n characterSet = CHARACTER_SETS.EXPANDED,\n fontSettings,\n ...rest\n } = props;\n\n super({\n // set opinionated defaults\n ...defaultSettings,\n\n // user props override defaults\n ...rest,\n\n // handle special characterSet logic\n characterSet:\n CHARACTER_SETS[characterSet as CharacterSetsKeys] ?? characterSet,\n\n fontSettings: {\n // merge fontSettings\n ...defaultSettings.fontSettings,\n\n // user props override defaults\n ...fontSettings,\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuGA,IAAa,YAAb,cAAgDA,YAAoB;CAClE,OAAO,iBAAiB;CAExB,OAAgB,YAAY;CAE5B,YAAY,OAA8B;EACxC,MAAM,EACJ,eAAe,eAAe,UAC9B,cACA,GAAG,SACD;AAEJ,QAAM;GAEJ,GAAG;GAGH,GAAG;GAGH,cACE,eAAe,iBAAsC;GAEvD,cAAc;IAEZ,GAAG,gBAAgB;IAGnB,GAAG;IACJ;GACF,CAAC"}
|
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Event keys for map cursor state changes.
|
|
4
4
|
* These events are used for communication between cursor stores and consumers.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { Broadcast } from '@accelint/bus';
|
|
9
|
+
* import { MapCursorEvents } from '@accelint/map-toolkit/map-cursor';
|
|
10
|
+
* import type { MapCursorEventType } from '@accelint/map-toolkit/map-cursor';
|
|
11
|
+
*
|
|
12
|
+
* const bus = Broadcast.getInstance<MapCursorEventType>();
|
|
13
|
+
*
|
|
14
|
+
* // Listen for cursor changes
|
|
15
|
+
* bus.on(MapCursorEvents.changed, (event) => {
|
|
16
|
+
* console.log('Cursor changed to:', event.payload.currentCursor);
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Listen for rejections
|
|
20
|
+
* bus.on(MapCursorEvents.rejected, (event) => {
|
|
21
|
+
* console.warn('Cursor change rejected:', event.payload.reason);
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
5
24
|
*/
|
|
6
25
|
declare const MapCursorEvents: {
|
|
7
26
|
/** Emitted when a component requests a cursor change */
|
|
@@ -15,6 +15,25 @@
|
|
|
15
15
|
/**
|
|
16
16
|
* Event keys for map cursor state changes.
|
|
17
17
|
* These events are used for communication between cursor stores and consumers.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { Broadcast } from '@accelint/bus';
|
|
22
|
+
* import { MapCursorEvents } from '@accelint/map-toolkit/map-cursor';
|
|
23
|
+
* import type { MapCursorEventType } from '@accelint/map-toolkit/map-cursor';
|
|
24
|
+
*
|
|
25
|
+
* const bus = Broadcast.getInstance<MapCursorEventType>();
|
|
26
|
+
*
|
|
27
|
+
* // Listen for cursor changes
|
|
28
|
+
* bus.on(MapCursorEvents.changed, (event) => {
|
|
29
|
+
* console.log('Cursor changed to:', event.payload.currentCursor);
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Listen for rejections
|
|
33
|
+
* bus.on(MapCursorEvents.rejected, (event) => {
|
|
34
|
+
* console.warn('Cursor change rejected:', event.payload.reason);
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
18
37
|
*/
|
|
19
38
|
const MapCursorEvents = {
|
|
20
39
|
changeRequest: "cursor:change-request",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":[],"sources":["../../src/map-cursor/events.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Event keys for map cursor state changes.\n * These events are used for communication between cursor stores and consumers.\n */\nexport const MapCursorEvents = {\n /** Emitted when a component requests a cursor change */\n changeRequest: 'cursor:change-request',\n /** Emitted when the cursor has been changed */\n changed: 'cursor:changed',\n /** Emitted when a cursor change request is rejected */\n rejected: 'cursor:rejected',\n} as const;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../src/map-cursor/events.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Event keys for map cursor state changes.\n * These events are used for communication between cursor stores and consumers.\n *\n * @example\n * ```typescript\n * import { Broadcast } from '@accelint/bus';\n * import { MapCursorEvents } from '@accelint/map-toolkit/map-cursor';\n * import type { MapCursorEventType } from '@accelint/map-toolkit/map-cursor';\n *\n * const bus = Broadcast.getInstance<MapCursorEventType>();\n *\n * // Listen for cursor changes\n * bus.on(MapCursorEvents.changed, (event) => {\n * console.log('Cursor changed to:', event.payload.currentCursor);\n * });\n *\n * // Listen for rejections\n * bus.on(MapCursorEvents.rejected, (event) => {\n * console.warn('Cursor change rejected:', event.payload.reason);\n * });\n * ```\n */\nexport const MapCursorEvents = {\n /** Emitted when a component requests a cursor change */\n changeRequest: 'cursor:change-request',\n /** Emitted when the cursor has been changed */\n changed: 'cursor:changed',\n /** Emitted when a cursor change request is rejected */\n rejected: 'cursor:rejected',\n} as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAa,kBAAkB;CAE7B,eAAe;CAEf,SAAS;CAET,UAAU;CACX"}
|
|
@@ -40,7 +40,21 @@ type CursorActions = {
|
|
|
40
40
|
*/
|
|
41
41
|
declare const cursorStore: MapStore<CursorState, CursorActions>;
|
|
42
42
|
/**
|
|
43
|
-
* Get effective cursor
|
|
43
|
+
* Get effective cursor value for a map instance.
|
|
44
|
+
*
|
|
45
|
+
* Computes the effective cursor from the current state by applying
|
|
46
|
+
* the priority system (mode owner > most recent > default).
|
|
47
|
+
*
|
|
48
|
+
* @param mapId - Unique identifier for the map instance
|
|
49
|
+
* @returns The effective cursor to display
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { getCursor } from '@accelint/map-toolkit/map-cursor';
|
|
54
|
+
*
|
|
55
|
+
* const currentCursor = getCursor(mapId);
|
|
56
|
+
* console.log('Current cursor:', currentCursor); // 'default', 'pointer', etc.
|
|
57
|
+
* ```
|
|
44
58
|
*/
|
|
45
59
|
declare function getCursor(mapId: UniqueId): CSSCursorType;
|
|
46
60
|
/**
|
|
@@ -53,10 +67,28 @@ declare function getCursor(mapId: UniqueId): CSSCursorType;
|
|
|
53
67
|
* - Better ergonomics for consumers
|
|
54
68
|
*
|
|
55
69
|
* This hook exists for internal composition (used by useMapCursor).
|
|
70
|
+
*
|
|
71
|
+
* @param mapId - Unique identifier for the map instance
|
|
72
|
+
* @returns The effective cursor to display
|
|
56
73
|
*/
|
|
57
74
|
declare function useCursor(mapId: UniqueId): CSSCursorType;
|
|
58
75
|
/**
|
|
59
|
-
* Clear cursor state
|
|
76
|
+
* Clear cursor state for a specific map instance.
|
|
77
|
+
*
|
|
78
|
+
* Removes all cursor ownership data and resets to default state.
|
|
79
|
+
* This is typically not needed as cleanup happens automatically.
|
|
80
|
+
* Use only in advanced scenarios where manual cleanup is required.
|
|
81
|
+
*
|
|
82
|
+
* @param mapId - Unique identifier for the map instance to clear
|
|
83
|
+
* @returns void
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* import { clearCursorState } from '@accelint/map-toolkit/map-cursor';
|
|
88
|
+
*
|
|
89
|
+
* // Manual cleanup when destroying a map
|
|
90
|
+
* clearCursorState(mapId);
|
|
91
|
+
* ```
|
|
60
92
|
*/
|
|
61
93
|
declare function clearCursorState(mapId: UniqueId): void;
|
|
62
94
|
//#endregion
|
package/dist/map-cursor/store.js
CHANGED
|
@@ -73,7 +73,16 @@ function isRegisteredOwner(mapId, owner) {
|
|
|
73
73
|
return isRegisteredModeOwnerFn?.(mapId, owner) ?? false;
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
* Calculate effective cursor based on priority
|
|
76
|
+
* Calculate effective cursor based on priority.
|
|
77
|
+
*
|
|
78
|
+
* Priority order:
|
|
79
|
+
* 1. Mode owner's cursor (if mode is owned)
|
|
80
|
+
* 2. Most recent cursor request (if owner still has entry)
|
|
81
|
+
* 3. Default cursor
|
|
82
|
+
*
|
|
83
|
+
* @param mapId - Unique identifier for the map instance
|
|
84
|
+
* @param state - Current cursor state
|
|
85
|
+
* @returns The effective cursor to display
|
|
77
86
|
*/
|
|
78
87
|
function getEffectiveCursor(mapId, state) {
|
|
79
88
|
const modeOwner = getModeOwner?.(mapId);
|
|
@@ -191,7 +200,21 @@ const cursorStore = createMapStore({
|
|
|
191
200
|
}
|
|
192
201
|
});
|
|
193
202
|
/**
|
|
194
|
-
* Get effective cursor
|
|
203
|
+
* Get effective cursor value for a map instance.
|
|
204
|
+
*
|
|
205
|
+
* Computes the effective cursor from the current state by applying
|
|
206
|
+
* the priority system (mode owner > most recent > default).
|
|
207
|
+
*
|
|
208
|
+
* @param mapId - Unique identifier for the map instance
|
|
209
|
+
* @returns The effective cursor to display
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```typescript
|
|
213
|
+
* import { getCursor } from '@accelint/map-toolkit/map-cursor';
|
|
214
|
+
*
|
|
215
|
+
* const currentCursor = getCursor(mapId);
|
|
216
|
+
* console.log('Current cursor:', currentCursor); // 'default', 'pointer', etc.
|
|
217
|
+
* ```
|
|
195
218
|
*/
|
|
196
219
|
function getCursor(mapId) {
|
|
197
220
|
return getEffectiveCursor(mapId, cursorStore.get(mapId));
|
|
@@ -206,12 +229,30 @@ function getCursor(mapId) {
|
|
|
206
229
|
* - Better ergonomics for consumers
|
|
207
230
|
*
|
|
208
231
|
* This hook exists for internal composition (used by useMapCursor).
|
|
232
|
+
*
|
|
233
|
+
* @param mapId - Unique identifier for the map instance
|
|
234
|
+
* @returns The effective cursor to display
|
|
209
235
|
*/
|
|
210
236
|
function useCursor(mapId) {
|
|
211
237
|
return cursorStore.useSelector(mapId, (state) => getEffectiveCursor(mapId, state));
|
|
212
238
|
}
|
|
213
239
|
/**
|
|
214
|
-
* Clear cursor state
|
|
240
|
+
* Clear cursor state for a specific map instance.
|
|
241
|
+
*
|
|
242
|
+
* Removes all cursor ownership data and resets to default state.
|
|
243
|
+
* This is typically not needed as cleanup happens automatically.
|
|
244
|
+
* Use only in advanced scenarios where manual cleanup is required.
|
|
245
|
+
*
|
|
246
|
+
* @param mapId - Unique identifier for the map instance to clear
|
|
247
|
+
* @returns void
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* import { clearCursorState } from '@accelint/map-toolkit/map-cursor';
|
|
252
|
+
*
|
|
253
|
+
* // Manual cleanup when destroying a map
|
|
254
|
+
* clearCursorState(mapId);
|
|
255
|
+
* ```
|
|
215
256
|
*/
|
|
216
257
|
function clearCursorState(mapId) {
|
|
217
258
|
cursorStore.clear(mapId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","names":["DEFAULT_CURSOR: CSSCursorType","getModeOwnerFn: ((mapId: UniqueId) => string | undefined) | null","isRegisteredModeOwnerFn:\n | ((mapId: UniqueId, owner: string) => boolean)\n | null","importPromise: Promise<void> | null","updates: Partial<CursorState>","newState: CursorState"],"sources":["../../src/map-cursor/store.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Map Cursor Store\n *\n * Manages cursor state with ownership-based priority.\n *\n * Priority order:\n * 1. Mode owner's cursor (if mode is owned)\n * 2. Most recent cursor request\n * 3. Default cursor\n *\n * @example\n * ```tsx\n * import { cursorStore } from '@accelint/map-toolkit/map-cursor';\n *\n * function MapContainer({ mapId }) {\n * const cursor = cursorStore.useSelector(mapId, (s) => getEffectiveCursor(mapId, s));\n * return <div style={{ cursor }}>...</div>;\n * }\n *\n * // Request cursor change from a layer:\n * cursorStore.actions(mapId).requestCursorChange('crosshair', 'draw-layer');\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { MapModeEvents } from '../map-mode/events';\nimport { createMapStore, mapDelete, mapSet } from '../shared/create-map-store';\nimport { MapCursorEvents } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { ModeChangedEvent } from '../map-mode/types';\nimport type { CSSCursorType, MapCursorEventType } from './types';\n\nconst DEFAULT_CURSOR: CSSCursorType = 'default';\n\n/**\n * State shape for map cursor\n */\ntype CursorState = {\n /** Map of owner -> cursor */\n cursorOwners: Map<string, CSSCursorType>;\n /** Current active cursor (for priority tracking) */\n currentCursor: CSSCursorType | null;\n /** Current cursor owner (for priority tracking) */\n currentOwner: string | null;\n};\n\n/**\n * Actions for cursor management\n */\ntype CursorActions = {\n /** Request a cursor change */\n requestCursorChange: (cursor: CSSCursorType, owner: string) => void;\n /** Clear cursor for an owner */\n clearCursor: (owner: string) => void;\n};\n\nconst cursorBus = Broadcast.getInstance<MapCursorEventType>();\nconst modeBus = Broadcast.getInstance<ModeChangedEvent>();\n\n/**\n * Lazy import to avoid circular dependency between cursor and mode stores.\n * The mode store doesn't depend on cursor store, but importing it synchronously\n * at module load time can cause initialization order issues.\n *\n * This pattern ensures the import is resolved before first use (bus listeners\n * are set up on first subscriber, not at module load time).\n */\nlet getModeOwnerFn: ((mapId: UniqueId) => string | undefined) | null = null;\nlet isRegisteredModeOwnerFn:\n | ((mapId: UniqueId, owner: string) => boolean)\n | null = null;\nlet importPromise: Promise<void> | null = null;\nlet importFailed = false;\n\nfunction ensureModeStoreImported(): void {\n if (getModeOwnerFn !== null || importFailed) {\n return;\n }\n if (importPromise === null) {\n importPromise = import('../map-mode/store')\n .then((mod) => {\n getModeOwnerFn = mod.getCurrentModeOwner;\n isRegisteredModeOwnerFn = mod.isRegisteredModeOwner;\n })\n .catch((error) => {\n importFailed = true;\n // Log error in development only - in production this is a silent fallback\n if (process.env.NODE_ENV !== 'production') {\n console.error('[MapCursor] Failed to import mode store:', error);\n }\n });\n }\n}\n\n// Start the import immediately so it's likely resolved by first use\nensureModeStoreImported();\n\nfunction getModeOwner(mapId: UniqueId): string | undefined {\n // getModeOwnerFn will be available by the time bus listeners are set up\n // (which happens on first React subscriber, not at module load)\n return getModeOwnerFn?.(mapId);\n}\n\nfunction isRegisteredOwner(mapId: UniqueId, owner: string): boolean {\n return isRegisteredModeOwnerFn?.(mapId, owner) ?? false;\n}\n\n/**\n * Calculate effective cursor based on priority\n */\nfunction getEffectiveCursor(\n mapId: UniqueId,\n state: CursorState,\n): CSSCursorType {\n // Priority 1: Mode owner's cursor\n const modeOwner = getModeOwner?.(mapId);\n if (modeOwner) {\n const modeOwnerCursor = state.cursorOwners.get(modeOwner);\n if (modeOwnerCursor) {\n return modeOwnerCursor;\n }\n }\n\n // Priority 2: Current cursor (if owner still has entry)\n if (state.currentCursor && state.currentOwner) {\n if (state.cursorOwners.has(state.currentOwner)) {\n return state.currentCursor;\n }\n }\n\n // Priority 3: Default\n return DEFAULT_CURSOR;\n}\n\n/**\n * Cursor store\n */\nexport const cursorStore = createMapStore<CursorState, CursorActions>({\n defaultState: {\n cursorOwners: new Map(),\n currentCursor: null,\n currentOwner: null,\n },\n\n actions: (mapId, { get, set }) => ({\n requestCursorChange: (cursor: CSSCursorType, owner: string) => {\n const trimmedCursor = cursor.trim() as CSSCursorType;\n const trimmedOwner = owner.trim();\n\n if (!trimmedCursor) {\n throw new Error('requestCursorChange requires non-empty cursor');\n }\n if (!trimmedOwner) {\n throw new Error('requestCursorChange requires non-empty owner');\n }\n\n cursorBus.emit(MapCursorEvents.changeRequest, {\n cursor: trimmedCursor,\n owner: trimmedOwner,\n id: mapId,\n });\n },\n\n clearCursor: (owner: string) => {\n const state = get();\n const hadCursor = state.cursorOwners.has(owner);\n\n if (hadCursor) {\n // Clear current tracking if this was the owner\n const updates: Partial<CursorState> = {\n cursorOwners: mapDelete(state.cursorOwners, owner),\n };\n if (state.currentOwner === owner) {\n updates.currentCursor = null;\n updates.currentOwner = null;\n }\n\n set(updates);\n }\n },\n }),\n\n bus: (mapId, { get, set }) => {\n // Handle cursor change requests\n const unsubRequest = cursorBus.on(\n MapCursorEvents.changeRequest,\n (event) => {\n const { cursor, owner: requestOwner, id } = event.payload;\n if (id !== mapId) {\n return;\n }\n\n const state = get();\n const previousCursor = getEffectiveCursor(mapId, state);\n\n // Skip if same cursor already stored for this owner\n if (state.cursorOwners.get(requestOwner) === cursor) {\n return;\n }\n\n // Create new Map for immutable update\n const newCursorOwners = mapSet(\n state.cursorOwners,\n requestOwner,\n cursor,\n );\n\n // Check ownership\n const currentModeOwner = getModeOwner?.(mapId);\n const isOwnerless = !currentModeOwner;\n const isCurrentModeOwner = requestOwner === currentModeOwner;\n const isAnyModeOwner = isRegisteredOwner(mapId, requestOwner);\n\n if (isOwnerless || isCurrentModeOwner) {\n // Accept: apply cursor with immutable update\n const newState: CursorState = {\n cursorOwners: newCursorOwners,\n currentCursor: cursor,\n currentOwner: requestOwner,\n };\n\n // Calculate new cursor with updated state\n const newCursor = getEffectiveCursor(mapId, newState);\n\n if (previousCursor !== newCursor) {\n set(newState);\n cursorBus.emit(MapCursorEvents.changed, {\n previousCursor,\n currentCursor: newCursor,\n owner: requestOwner,\n id: mapId,\n });\n } else {\n // Still need to update state even if cursor didn't change visually\n set(newState);\n }\n } else if (isAnyModeOwner) {\n // Store but don't apply: requester owns a different mode (pending or not current).\n // When their mode becomes active, getEffectiveCursor will find their cursor.\n set({ cursorOwners: newCursorOwners });\n\n cursorBus.emit(MapCursorEvents.rejected, {\n rejectedCursor: cursor,\n rejectedOwner: requestOwner,\n currentOwner: state.currentOwner || currentModeOwner || 'unknown',\n reason: 'not-current-owner',\n id: mapId,\n });\n } else {\n // Reject: don't store. Non-owners should only set cursor in default mode.\n cursorBus.emit(MapCursorEvents.rejected, {\n rejectedCursor: cursor,\n rejectedOwner: requestOwner,\n currentOwner: state.currentOwner || currentModeOwner || 'unknown',\n reason: 'not-owner',\n id: mapId,\n });\n }\n },\n );\n\n // Handle mode changes\n const unsubMode = modeBus.on(MapModeEvents.changed, (event) => {\n if (event.payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const previousCursor = getEffectiveCursor(mapId, state);\n\n // Clear current tracking on mode change with immutable update\n if (\n event.payload.currentMode === 'default' ||\n event.payload.previousMode !== event.payload.currentMode\n ) {\n set({\n currentCursor: null,\n currentOwner: null,\n });\n }\n\n // Defer check until new mode owner is registered\n queueMicrotask(() => {\n // Re-get state after microtask since it may have changed\n const currentState = get();\n const newCursor = getEffectiveCursor(mapId, currentState);\n if (previousCursor !== newCursor) {\n const newModeOwner = getModeOwner?.(mapId) || 'system';\n cursorBus.emit(MapCursorEvents.changed, {\n previousCursor,\n currentCursor: newCursor,\n owner: newModeOwner,\n id: mapId,\n });\n }\n });\n });\n\n return () => {\n unsubRequest();\n unsubMode();\n };\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get effective cursor (computed from state)\n */\nexport function getCursor(mapId: UniqueId): CSSCursorType {\n return getEffectiveCursor(mapId, cursorStore.get(mapId));\n}\n\n/**\n * Hook for effective cursor value.\n *\n * **Internal use only** - not exported from the public API.\n * Use `useMapCursor` instead, which provides:\n * - MapContext integration (auto-resolves mapId inside MapProvider)\n * - Actions (requestCursorChange, clearCursor)\n * - Better ergonomics for consumers\n *\n * This hook exists for internal composition (used by useMapCursor).\n */\nexport function useCursor(mapId: UniqueId): CSSCursorType {\n return cursorStore.useSelector(mapId, (state) =>\n getEffectiveCursor(mapId, state),\n );\n}\n\n/**\n * Clear cursor state\n */\nexport function clearCursorState(mapId: UniqueId): void {\n cursorStore.clear(mapId);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","names":["DEFAULT_CURSOR: CSSCursorType","getModeOwnerFn: ((mapId: UniqueId) => string | undefined) | null","isRegisteredModeOwnerFn:\n | ((mapId: UniqueId, owner: string) => boolean)\n | null","importPromise: Promise<void> | null","updates: Partial<CursorState>","newState: CursorState"],"sources":["../../src/map-cursor/store.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Map Cursor Store\n *\n * Manages cursor state with ownership-based priority.\n *\n * Priority order:\n * 1. Mode owner's cursor (if mode is owned)\n * 2. Most recent cursor request\n * 3. Default cursor\n *\n * @example\n * ```tsx\n * import { cursorStore } from '@accelint/map-toolkit/map-cursor';\n *\n * function MapContainer({ mapId }) {\n * const cursor = cursorStore.useSelector(mapId, (s) => getEffectiveCursor(mapId, s));\n * return <div style={{ cursor }}>...</div>;\n * }\n *\n * // Request cursor change from a layer:\n * cursorStore.actions(mapId).requestCursorChange('crosshair', 'draw-layer');\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { MapModeEvents } from '../map-mode/events';\nimport { createMapStore, mapDelete, mapSet } from '../shared/create-map-store';\nimport { MapCursorEvents } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { ModeChangedEvent } from '../map-mode/types';\nimport type { CSSCursorType, MapCursorEventType } from './types';\n\nconst DEFAULT_CURSOR: CSSCursorType = 'default';\n\n/**\n * State shape for map cursor\n */\ntype CursorState = {\n /** Map of owner -> cursor */\n cursorOwners: Map<string, CSSCursorType>;\n /** Current active cursor (for priority tracking) */\n currentCursor: CSSCursorType | null;\n /** Current cursor owner (for priority tracking) */\n currentOwner: string | null;\n};\n\n/**\n * Actions for cursor management\n */\ntype CursorActions = {\n /** Request a cursor change */\n requestCursorChange: (cursor: CSSCursorType, owner: string) => void;\n /** Clear cursor for an owner */\n clearCursor: (owner: string) => void;\n};\n\nconst cursorBus = Broadcast.getInstance<MapCursorEventType>();\nconst modeBus = Broadcast.getInstance<ModeChangedEvent>();\n\n/**\n * Lazy import to avoid circular dependency between cursor and mode stores.\n * The mode store doesn't depend on cursor store, but importing it synchronously\n * at module load time can cause initialization order issues.\n *\n * This pattern ensures the import is resolved before first use (bus listeners\n * are set up on first subscriber, not at module load time).\n */\nlet getModeOwnerFn: ((mapId: UniqueId) => string | undefined) | null = null;\nlet isRegisteredModeOwnerFn:\n | ((mapId: UniqueId, owner: string) => boolean)\n | null = null;\nlet importPromise: Promise<void> | null = null;\nlet importFailed = false;\n\nfunction ensureModeStoreImported(): void {\n if (getModeOwnerFn !== null || importFailed) {\n return;\n }\n if (importPromise === null) {\n importPromise = import('../map-mode/store')\n .then((mod) => {\n getModeOwnerFn = mod.getCurrentModeOwner;\n isRegisteredModeOwnerFn = mod.isRegisteredModeOwner;\n })\n .catch((error) => {\n importFailed = true;\n // Log error in development only - in production this is a silent fallback\n if (process.env.NODE_ENV !== 'production') {\n console.error('[MapCursor] Failed to import mode store:', error);\n }\n });\n }\n}\n\n// Start the import immediately so it's likely resolved by first use\nensureModeStoreImported();\n\nfunction getModeOwner(mapId: UniqueId): string | undefined {\n // getModeOwnerFn will be available by the time bus listeners are set up\n // (which happens on first React subscriber, not at module load)\n return getModeOwnerFn?.(mapId);\n}\n\nfunction isRegisteredOwner(mapId: UniqueId, owner: string): boolean {\n return isRegisteredModeOwnerFn?.(mapId, owner) ?? false;\n}\n\n/**\n * Calculate effective cursor based on priority.\n *\n * Priority order:\n * 1. Mode owner's cursor (if mode is owned)\n * 2. Most recent cursor request (if owner still has entry)\n * 3. Default cursor\n *\n * @param mapId - Unique identifier for the map instance\n * @param state - Current cursor state\n * @returns The effective cursor to display\n */\nfunction getEffectiveCursor(\n mapId: UniqueId,\n state: CursorState,\n): CSSCursorType {\n // Priority 1: Mode owner's cursor\n const modeOwner = getModeOwner?.(mapId);\n if (modeOwner) {\n const modeOwnerCursor = state.cursorOwners.get(modeOwner);\n if (modeOwnerCursor) {\n return modeOwnerCursor;\n }\n }\n\n // Priority 2: Current cursor (if owner still has entry)\n if (state.currentCursor && state.currentOwner) {\n if (state.cursorOwners.has(state.currentOwner)) {\n return state.currentCursor;\n }\n }\n\n // Priority 3: Default\n return DEFAULT_CURSOR;\n}\n\n/**\n * Cursor store\n */\nexport const cursorStore = createMapStore<CursorState, CursorActions>({\n defaultState: {\n cursorOwners: new Map(),\n currentCursor: null,\n currentOwner: null,\n },\n\n actions: (mapId, { get, set }) => ({\n requestCursorChange: (cursor: CSSCursorType, owner: string) => {\n const trimmedCursor = cursor.trim() as CSSCursorType;\n const trimmedOwner = owner.trim();\n\n if (!trimmedCursor) {\n throw new Error('requestCursorChange requires non-empty cursor');\n }\n if (!trimmedOwner) {\n throw new Error('requestCursorChange requires non-empty owner');\n }\n\n cursorBus.emit(MapCursorEvents.changeRequest, {\n cursor: trimmedCursor,\n owner: trimmedOwner,\n id: mapId,\n });\n },\n\n clearCursor: (owner: string) => {\n const state = get();\n const hadCursor = state.cursorOwners.has(owner);\n\n if (hadCursor) {\n // Clear current tracking if this was the owner\n const updates: Partial<CursorState> = {\n cursorOwners: mapDelete(state.cursorOwners, owner),\n };\n if (state.currentOwner === owner) {\n updates.currentCursor = null;\n updates.currentOwner = null;\n }\n\n set(updates);\n }\n },\n }),\n\n bus: (mapId, { get, set }) => {\n // Handle cursor change requests\n const unsubRequest = cursorBus.on(\n MapCursorEvents.changeRequest,\n (event) => {\n const { cursor, owner: requestOwner, id } = event.payload;\n if (id !== mapId) {\n return;\n }\n\n const state = get();\n const previousCursor = getEffectiveCursor(mapId, state);\n\n // Skip if same cursor already stored for this owner\n if (state.cursorOwners.get(requestOwner) === cursor) {\n return;\n }\n\n // Create new Map for immutable update\n const newCursorOwners = mapSet(\n state.cursorOwners,\n requestOwner,\n cursor,\n );\n\n // Check ownership\n const currentModeOwner = getModeOwner?.(mapId);\n const isOwnerless = !currentModeOwner;\n const isCurrentModeOwner = requestOwner === currentModeOwner;\n const isAnyModeOwner = isRegisteredOwner(mapId, requestOwner);\n\n if (isOwnerless || isCurrentModeOwner) {\n // Accept: apply cursor with immutable update\n const newState: CursorState = {\n cursorOwners: newCursorOwners,\n currentCursor: cursor,\n currentOwner: requestOwner,\n };\n\n // Calculate new cursor with updated state\n const newCursor = getEffectiveCursor(mapId, newState);\n\n if (previousCursor !== newCursor) {\n set(newState);\n cursorBus.emit(MapCursorEvents.changed, {\n previousCursor,\n currentCursor: newCursor,\n owner: requestOwner,\n id: mapId,\n });\n } else {\n // Still need to update state even if cursor didn't change visually\n set(newState);\n }\n } else if (isAnyModeOwner) {\n // Store but don't apply: requester owns a different mode (pending or not current).\n // When their mode becomes active, getEffectiveCursor will find their cursor.\n set({ cursorOwners: newCursorOwners });\n\n cursorBus.emit(MapCursorEvents.rejected, {\n rejectedCursor: cursor,\n rejectedOwner: requestOwner,\n currentOwner: state.currentOwner || currentModeOwner || 'unknown',\n reason: 'not-current-owner',\n id: mapId,\n });\n } else {\n // Reject: don't store. Non-owners should only set cursor in default mode.\n cursorBus.emit(MapCursorEvents.rejected, {\n rejectedCursor: cursor,\n rejectedOwner: requestOwner,\n currentOwner: state.currentOwner || currentModeOwner || 'unknown',\n reason: 'not-owner',\n id: mapId,\n });\n }\n },\n );\n\n // Handle mode changes\n const unsubMode = modeBus.on(MapModeEvents.changed, (event) => {\n if (event.payload.id !== mapId) {\n return;\n }\n\n const state = get();\n const previousCursor = getEffectiveCursor(mapId, state);\n\n // Clear current tracking on mode change with immutable update\n if (\n event.payload.currentMode === 'default' ||\n event.payload.previousMode !== event.payload.currentMode\n ) {\n set({\n currentCursor: null,\n currentOwner: null,\n });\n }\n\n // Defer check until new mode owner is registered\n queueMicrotask(() => {\n // Re-get state after microtask since it may have changed\n const currentState = get();\n const newCursor = getEffectiveCursor(mapId, currentState);\n if (previousCursor !== newCursor) {\n const newModeOwner = getModeOwner?.(mapId) || 'system';\n cursorBus.emit(MapCursorEvents.changed, {\n previousCursor,\n currentCursor: newCursor,\n owner: newModeOwner,\n id: mapId,\n });\n }\n });\n });\n\n return () => {\n unsubRequest();\n unsubMode();\n };\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get effective cursor value for a map instance.\n *\n * Computes the effective cursor from the current state by applying\n * the priority system (mode owner > most recent > default).\n *\n * @param mapId - Unique identifier for the map instance\n * @returns The effective cursor to display\n *\n * @example\n * ```typescript\n * import { getCursor } from '@accelint/map-toolkit/map-cursor';\n *\n * const currentCursor = getCursor(mapId);\n * console.log('Current cursor:', currentCursor); // 'default', 'pointer', etc.\n * ```\n */\nexport function getCursor(mapId: UniqueId): CSSCursorType {\n return getEffectiveCursor(mapId, cursorStore.get(mapId));\n}\n\n/**\n * Hook for effective cursor value.\n *\n * **Internal use only** - not exported from the public API.\n * Use `useMapCursor` instead, which provides:\n * - MapContext integration (auto-resolves mapId inside MapProvider)\n * - Actions (requestCursorChange, clearCursor)\n * - Better ergonomics for consumers\n *\n * This hook exists for internal composition (used by useMapCursor).\n *\n * @param mapId - Unique identifier for the map instance\n * @returns The effective cursor to display\n */\nexport function useCursor(mapId: UniqueId): CSSCursorType {\n return cursorStore.useSelector(mapId, (state) =>\n getEffectiveCursor(mapId, state),\n );\n}\n\n/**\n * Clear cursor state for a specific map instance.\n *\n * Removes all cursor ownership data and resets to default state.\n * This is typically not needed as cleanup happens automatically.\n * Use only in advanced scenarios where manual cleanup is required.\n *\n * @param mapId - Unique identifier for the map instance to clear\n * @returns void\n *\n * @example\n * ```typescript\n * import { clearCursorState } from '@accelint/map-toolkit/map-cursor';\n *\n * // Manual cleanup when destroying a map\n * clearCursorState(mapId);\n * ```\n */\nexport function clearCursorState(mapId: UniqueId): void {\n cursorStore.clear(mapId);\n}\n"],"mappings":"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"}
|
package/dist/map-mode/store.d.ts
CHANGED
|
@@ -43,26 +43,65 @@ type MapModeActions = {
|
|
|
43
43
|
*/
|
|
44
44
|
declare const modeStore: MapStore<MapModeState, MapModeActions>;
|
|
45
45
|
/**
|
|
46
|
-
* Get the current mode for a map instance
|
|
46
|
+
* Get the current mode for a map instance.
|
|
47
|
+
*
|
|
48
|
+
* @param mapId - Unique identifier for the map instance
|
|
49
|
+
* @returns The current active mode string
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { getMode } from '@accelint/map-toolkit/map-mode';
|
|
54
|
+
*
|
|
55
|
+
* const currentMode = getMode(mapId);
|
|
56
|
+
* console.log('Current mode:', currentMode); // 'default', 'drawing', etc.
|
|
57
|
+
* ```
|
|
47
58
|
*/
|
|
48
59
|
declare function getMode(mapId: UniqueId): string;
|
|
49
60
|
/**
|
|
50
|
-
* Hook for current mode value
|
|
61
|
+
* Hook for current mode value.
|
|
62
|
+
*
|
|
63
|
+
* **Internal use only** - not exported from the public API.
|
|
64
|
+
* Use `useMapMode` instead for better ergonomics and MapContext integration.
|
|
65
|
+
*
|
|
66
|
+
* @param mapId - Unique identifier for the map instance
|
|
67
|
+
* @returns The current active mode string
|
|
51
68
|
*/
|
|
52
69
|
declare function useMode(mapId: UniqueId): string;
|
|
53
70
|
/**
|
|
54
|
-
* Get the owner of the current mode for a given map instance
|
|
71
|
+
* Get the owner of the current mode for a given map instance.
|
|
72
|
+
*
|
|
55
73
|
* @internal - For internal map-toolkit use only
|
|
74
|
+
* @param instanceId - Unique identifier for the map instance
|
|
75
|
+
* @returns The owner ID of the current mode, or undefined if unowned
|
|
56
76
|
*/
|
|
57
77
|
declare function getCurrentModeOwner(instanceId: UniqueId): string | undefined;
|
|
58
78
|
/**
|
|
59
79
|
* Check if a given owner is registered as the owner of any mode.
|
|
60
80
|
* This includes both active mode owners and pending mode requests.
|
|
81
|
+
*
|
|
61
82
|
* @internal - For internal map-toolkit use only
|
|
83
|
+
* @param instanceId - Unique identifier for the map instance
|
|
84
|
+
* @param owner - The owner ID to check
|
|
85
|
+
* @returns True if the owner is registered for any mode
|
|
62
86
|
*/
|
|
63
87
|
declare function isRegisteredModeOwner(instanceId: UniqueId, owner: string): boolean;
|
|
64
88
|
/**
|
|
65
|
-
* Manually clear map mode state for a specific
|
|
89
|
+
* Manually clear map mode state for a specific map instance.
|
|
90
|
+
*
|
|
91
|
+
* Removes all mode ownership data, pending requests, and resets to default state.
|
|
92
|
+
* This is typically not needed as cleanup happens automatically.
|
|
93
|
+
* Use only in advanced scenarios where manual cleanup is required.
|
|
94
|
+
*
|
|
95
|
+
* @param instanceId - Unique identifier for the map instance to clear
|
|
96
|
+
* @returns void
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* import { clearMapModeState } from '@accelint/map-toolkit/map-mode';
|
|
101
|
+
*
|
|
102
|
+
* // Manual cleanup when destroying a map
|
|
103
|
+
* clearMapModeState(mapId);
|
|
104
|
+
* ```
|
|
66
105
|
*/
|
|
67
106
|
declare function clearMapModeState(instanceId: UniqueId): void;
|
|
68
107
|
//#endregion
|
package/dist/map-mode/store.js
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
import { createMapStore, mapClear, mapDelete, mapSet } from "../shared/create-map-store.js";
|
|
15
15
|
import { MapModeEvents } from "./events.js";
|
|
16
16
|
import { Broadcast } from "@accelint/bus";
|
|
17
|
-
import { uuid } from "@accelint/core";
|
|
18
17
|
import { getLogger } from "@accelint/logger";
|
|
18
|
+
import { uuid } from "@accelint/core";
|
|
19
19
|
|
|
20
20
|
//#region src/map-mode/store.ts
|
|
21
21
|
/**
|
|
@@ -53,7 +53,18 @@ const DEFAULT_MODE = "default";
|
|
|
53
53
|
*/
|
|
54
54
|
const mapModeBus = Broadcast.getInstance();
|
|
55
55
|
/**
|
|
56
|
-
* Determine if a mode change request should be auto-accepted without authorization
|
|
56
|
+
* Determine if a mode change request should be auto-accepted without authorization.
|
|
57
|
+
*
|
|
58
|
+
* Auto-accept conditions:
|
|
59
|
+
* - Owner returning to default mode
|
|
60
|
+
* - Owner switching between their own modes
|
|
61
|
+
* - No ownership conflicts exist
|
|
62
|
+
* - Entering an owned mode from default mode
|
|
63
|
+
*
|
|
64
|
+
* @param state - Current mode state
|
|
65
|
+
* @param desiredMode - The mode being requested
|
|
66
|
+
* @param requestOwner - The component requesting the mode change
|
|
67
|
+
* @returns True if the request should be auto-accepted
|
|
57
68
|
*/
|
|
58
69
|
function shouldAutoAcceptRequest(state, desiredMode, requestOwner) {
|
|
59
70
|
const currentModeOwner = state.modeOwners.get(state.mode);
|
|
@@ -222,20 +233,40 @@ const modeStore = createMapStore({
|
|
|
222
233
|
}
|
|
223
234
|
});
|
|
224
235
|
/**
|
|
225
|
-
* Get the current mode for a map instance
|
|
236
|
+
* Get the current mode for a map instance.
|
|
237
|
+
*
|
|
238
|
+
* @param mapId - Unique identifier for the map instance
|
|
239
|
+
* @returns The current active mode string
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* import { getMode } from '@accelint/map-toolkit/map-mode';
|
|
244
|
+
*
|
|
245
|
+
* const currentMode = getMode(mapId);
|
|
246
|
+
* console.log('Current mode:', currentMode); // 'default', 'drawing', etc.
|
|
247
|
+
* ```
|
|
226
248
|
*/
|
|
227
249
|
function getMode(mapId) {
|
|
228
250
|
return modeStore.get(mapId).mode;
|
|
229
251
|
}
|
|
230
252
|
/**
|
|
231
|
-
* Hook for current mode value
|
|
253
|
+
* Hook for current mode value.
|
|
254
|
+
*
|
|
255
|
+
* **Internal use only** - not exported from the public API.
|
|
256
|
+
* Use `useMapMode` instead for better ergonomics and MapContext integration.
|
|
257
|
+
*
|
|
258
|
+
* @param mapId - Unique identifier for the map instance
|
|
259
|
+
* @returns The current active mode string
|
|
232
260
|
*/
|
|
233
261
|
function useMode(mapId) {
|
|
234
262
|
return modeStore.useSelector(mapId, (state) => state.mode);
|
|
235
263
|
}
|
|
236
264
|
/**
|
|
237
|
-
* Get the owner of the current mode for a given map instance
|
|
265
|
+
* Get the owner of the current mode for a given map instance.
|
|
266
|
+
*
|
|
238
267
|
* @internal - For internal map-toolkit use only
|
|
268
|
+
* @param instanceId - Unique identifier for the map instance
|
|
269
|
+
* @returns The owner ID of the current mode, or undefined if unowned
|
|
239
270
|
*/
|
|
240
271
|
function getCurrentModeOwner(instanceId) {
|
|
241
272
|
const state = modeStore.get(instanceId);
|
|
@@ -244,7 +275,11 @@ function getCurrentModeOwner(instanceId) {
|
|
|
244
275
|
/**
|
|
245
276
|
* Check if a given owner is registered as the owner of any mode.
|
|
246
277
|
* This includes both active mode owners and pending mode requests.
|
|
278
|
+
*
|
|
247
279
|
* @internal - For internal map-toolkit use only
|
|
280
|
+
* @param instanceId - Unique identifier for the map instance
|
|
281
|
+
* @param owner - The owner ID to check
|
|
282
|
+
* @returns True if the owner is registered for any mode
|
|
248
283
|
*/
|
|
249
284
|
function isRegisteredModeOwner(instanceId, owner) {
|
|
250
285
|
const state = modeStore.get(instanceId);
|
|
@@ -253,7 +288,22 @@ function isRegisteredModeOwner(instanceId, owner) {
|
|
|
253
288
|
return false;
|
|
254
289
|
}
|
|
255
290
|
/**
|
|
256
|
-
* Manually clear map mode state for a specific
|
|
291
|
+
* Manually clear map mode state for a specific map instance.
|
|
292
|
+
*
|
|
293
|
+
* Removes all mode ownership data, pending requests, and resets to default state.
|
|
294
|
+
* This is typically not needed as cleanup happens automatically.
|
|
295
|
+
* Use only in advanced scenarios where manual cleanup is required.
|
|
296
|
+
*
|
|
297
|
+
* @param instanceId - Unique identifier for the map instance to clear
|
|
298
|
+
* @returns void
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```typescript
|
|
302
|
+
* import { clearMapModeState } from '@accelint/map-toolkit/map-mode';
|
|
303
|
+
*
|
|
304
|
+
* // Manual cleanup when destroying a map
|
|
305
|
+
* clearMapModeState(mapId);
|
|
306
|
+
* ```
|
|
257
307
|
*/
|
|
258
308
|
function clearMapModeState(instanceId) {
|
|
259
309
|
modeStore.clear(instanceId);
|