@accelint/map-toolkit 2.0.0 → 3.0.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +8 -1
  3. package/catalog-info.yaml +9 -6
  4. package/dist/deckgl/base-map/index.d.ts +2 -2
  5. package/dist/deckgl/base-map/provider.d.ts +2 -2
  6. package/dist/deckgl/extensions/coffin-corner/coffin-corner-extension.d.ts +144 -0
  7. package/dist/deckgl/extensions/coffin-corner/coffin-corner-extension.js +535 -0
  8. package/dist/deckgl/extensions/coffin-corner/coffin-corner-extension.js.map +1 -0
  9. package/dist/deckgl/extensions/coffin-corner/index.d.ts +17 -0
  10. package/dist/deckgl/extensions/coffin-corner/index.js +19 -0
  11. package/dist/deckgl/extensions/coffin-corner/store.d.ts +96 -0
  12. package/dist/deckgl/extensions/coffin-corner/store.js +173 -0
  13. package/dist/deckgl/extensions/coffin-corner/store.js.map +1 -0
  14. package/dist/deckgl/extensions/coffin-corner/types.d.ts +76 -0
  15. package/dist/deckgl/extensions/coffin-corner/types.js +27 -0
  16. package/dist/deckgl/extensions/coffin-corner/types.js.map +1 -0
  17. package/dist/deckgl/extensions/coffin-corner/use-coffin-corner.d.ts +81 -0
  18. package/dist/deckgl/extensions/coffin-corner/use-coffin-corner.js +75 -0
  19. package/dist/deckgl/extensions/coffin-corner/use-coffin-corner.js.map +1 -0
  20. package/dist/deckgl/extensions/index.d.ts +15 -0
  21. package/dist/deckgl/extensions/index.js +16 -0
  22. package/dist/deckgl/index.d.ts +6 -1
  23. package/dist/deckgl/index.js +5 -1
  24. package/dist/deckgl/shapes/display-shape-layer/constants.js +6 -15
  25. package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -1
  26. package/dist/deckgl/shapes/display-shape-layer/index.d.ts +31 -15
  27. package/dist/deckgl/shapes/display-shape-layer/index.js +97 -78
  28. package/dist/deckgl/shapes/display-shape-layer/index.js.map +1 -1
  29. package/dist/deckgl/shapes/display-shape-layer/types.d.ts +8 -0
  30. package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js +3 -48
  31. package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js.map +1 -1
  32. package/dist/deckgl/shapes/display-shape-layer/utils/radius-label.js +53 -0
  33. package/dist/deckgl/shapes/display-shape-layer/utils/radius-label.js.map +1 -0
  34. package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +7 -3
  35. package/dist/deckgl/shapes/draw-shape-layer/index.js +7 -3
  36. package/dist/deckgl/shapes/draw-shape-layer/index.js.map +1 -1
  37. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +4 -2
  38. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -1
  39. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +3 -2
  40. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js.map +1 -1
  41. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +5 -2
  42. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js.map +1 -1
  43. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +5 -2
  44. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js.map +1 -1
  45. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +7 -2
  46. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js.map +1 -1
  47. package/dist/deckgl/shapes/draw-shape-layer/types.d.ts +2 -2
  48. package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +7 -4
  49. package/dist/deckgl/shapes/edit-shape-layer/index.js +22 -8
  50. package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
  51. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +3 -2
  52. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js.map +1 -1
  53. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +4 -2
  54. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
  55. package/dist/deckgl/shapes/edit-shape-layer/store.js +15 -4
  56. package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
  57. package/dist/deckgl/shapes/edit-shape-layer/types.d.ts +4 -2
  58. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.d.ts +1 -1
  59. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js +7 -3
  60. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js.map +1 -1
  61. package/dist/deckgl/shapes/index.d.ts +3 -2
  62. package/dist/deckgl/shapes/index.js +2 -1
  63. package/dist/deckgl/shapes/shared/constants.js +1 -1
  64. package/dist/deckgl/shapes/shared/types.d.ts +11 -4
  65. package/dist/deckgl/shapes/shared/types.js.map +1 -1
  66. package/dist/deckgl/shapes/shared/utils/duplicate-shape.d.ts +56 -0
  67. package/dist/deckgl/shapes/shared/utils/duplicate-shape.js +131 -0
  68. package/dist/deckgl/shapes/shared/utils/duplicate-shape.js.map +1 -0
  69. package/dist/deckgl/shapes/shared/utils/geometry-measurements.js.map +1 -1
  70. package/dist/deckgl/shapes/shared/utils/layer-config.js +10 -7
  71. package/dist/deckgl/shapes/shared/utils/layer-config.js.map +1 -1
  72. package/dist/deckgl/symbol-layer/fiber.d.ts +3 -1
  73. package/dist/deckgl/symbol-layer/fiber.js.map +1 -1
  74. package/dist/shared/units.d.ts +15 -56
  75. package/dist/shared/units.js +1 -52
  76. package/dist/shared/units.js.map +1 -1
  77. package/dist/viewport/index.d.ts +2 -3
  78. package/dist/viewport/index.js +1 -2
  79. package/dist/viewport/types.d.ts +8 -4
  80. package/dist/viewport/utils.d.ts +3 -3
  81. package/dist/viewport/utils.js +16 -8
  82. package/dist/viewport/utils.js.map +1 -1
  83. package/dist/viewport/viewport-size.d.ts +4 -3
  84. package/dist/viewport/viewport-size.js +2 -2
  85. package/dist/viewport/viewport-size.js.map +1 -1
  86. package/package.json +13 -6
  87. package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js +0 -50
  88. package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js.map +0 -1
@@ -0,0 +1,96 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { MapStore } from "../../../shared/create-map-store.js";
14
+ import { EntityId } from "./types.js";
15
+ import { UniqueId } from "@accelint/core";
16
+
17
+ //#region src/deckgl/extensions/coffin-corner/store.d.ts
18
+ /** Extracts an entity ID from a picked data item. */
19
+ type GetEntityId = (item: any) => EntityId;
20
+ /**
21
+ * State for coffin corner selection and hover.
22
+ */
23
+ type CoffinCornerState = {
24
+ /** Currently selected entity ID, or undefined if nothing is selected. */
25
+ selectedId: EntityId | undefined;
26
+ /** Currently hovered entity ID, or undefined if nothing is hovered. */
27
+ hoveredId: EntityId | undefined;
28
+ /** deck.gl layer ID used to filter map bus events to only this layer's interactions. */
29
+ layerId: string | undefined;
30
+ /** Accessor to extract an entity ID from a picked data item. */
31
+ getEntityId: GetEntityId;
32
+ };
33
+ /**
34
+ * Actions for coffin corner interactions.
35
+ */
36
+ type CoffinCornerActions = {
37
+ /** Select an entity by ID (emits domain event). Pass undefined to deselect. */
38
+ setSelectedId: (id: EntityId | undefined) => void;
39
+ /** Clear the current selection (emits deselect domain event). */
40
+ deselect: () => void;
41
+ /** Set the deck.gl layer ID used to filter map bus events. */
42
+ setLayerId: (layerId: string) => void;
43
+ /** Override the entity ID accessor for picked data items. */
44
+ setGetEntityId: (fn: GetEntityId) => void;
45
+ };
46
+ /**
47
+ * Coffin corner store - manages selection and hover state per map instance.
48
+ *
49
+ * Subscribes to map bus events for click/hover interactions and translates
50
+ * them into coffin corner domain events. The hook only needs to pass the
51
+ * layer ID — all subscription management lives here.
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * const { state, setSelectedId, deselect } = coffinCornerStore.use(mapId);
56
+ * ```
57
+ */
58
+ declare const coffinCornerStore: MapStore<CoffinCornerState, CoffinCornerActions>;
59
+ /**
60
+ * Get selected entity ID imperatively (non-reactive).
61
+ *
62
+ * @param mapId - The map instance to query.
63
+ * @returns The selected entity ID, or undefined if nothing is selected.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const selectedId = getSelectedEntityId(mapId);
68
+ * ```
69
+ */
70
+ declare function getSelectedEntityId(mapId: UniqueId): EntityId | undefined;
71
+ /**
72
+ * Get hovered entity ID imperatively (non-reactive).
73
+ *
74
+ * @param mapId - The map instance to query.
75
+ * @returns The hovered entity ID, or undefined if nothing is hovered.
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const hoveredId = getHoveredEntityId(mapId);
80
+ * ```
81
+ */
82
+ declare function getHoveredEntityId(mapId: UniqueId): EntityId | undefined;
83
+ /**
84
+ * Clear selection state (for tests/cleanup).
85
+ *
86
+ * @param mapId - The map instance to clear selection for.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * clearSelection(mapId);
91
+ * ```
92
+ */
93
+ declare function clearSelection(mapId: UniqueId): void;
94
+ //#endregion
95
+ export { clearSelection, coffinCornerStore, getHoveredEntityId, getSelectedEntityId };
96
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1,173 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ 'use client';
15
+
16
+ import { createMapStore } from "../../../shared/create-map-store.js";
17
+ import { MapEvents } from "../../base-map/events.js";
18
+ import { CoffinCornerEvents } from "./types.js";
19
+ import { Broadcast } from "@accelint/bus";
20
+
21
+ //#region src/deckgl/extensions/coffin-corner/store.ts
22
+ /** Default accessor — assumes the data item has an `id` property. */
23
+ const defaultGetEntityId = (item) => item.id;
24
+ const coffinCornerEventBus = Broadcast.getInstance();
25
+ const mapEventBus = Broadcast.getInstance();
26
+ /**
27
+ * Coffin corner store - manages selection and hover state per map instance.
28
+ *
29
+ * Subscribes to map bus events for click/hover interactions and translates
30
+ * them into coffin corner domain events. The hook only needs to pass the
31
+ * layer ID — all subscription management lives here.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * const { state, setSelectedId, deselect } = coffinCornerStore.use(mapId);
36
+ * ```
37
+ */
38
+ const coffinCornerStore = createMapStore({
39
+ defaultState: {
40
+ selectedId: void 0,
41
+ hoveredId: void 0,
42
+ layerId: void 0,
43
+ getEntityId: defaultGetEntityId
44
+ },
45
+ actions: (mapId, { get, set }) => ({
46
+ setSelectedId: (id) => {
47
+ const currentId = get().selectedId;
48
+ if (id == null && currentId != null) {
49
+ coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {
50
+ mapId,
51
+ selectedId: void 0
52
+ });
53
+ return;
54
+ }
55
+ if (id != null && currentId !== id) {
56
+ coffinCornerEventBus.emit(CoffinCornerEvents.SELECTED, {
57
+ selectedId: id,
58
+ mapId
59
+ });
60
+ return;
61
+ }
62
+ },
63
+ deselect: () => {
64
+ coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {
65
+ mapId,
66
+ selectedId: void 0
67
+ });
68
+ },
69
+ setLayerId: (layerId) => {
70
+ if (get().layerId !== layerId) set({ layerId });
71
+ },
72
+ setGetEntityId: (fn) => {
73
+ if (get().getEntityId !== fn) set({ getEntityId: fn });
74
+ }
75
+ }),
76
+ bus: (mapId, { get, set }) => {
77
+ const onSelected = coffinCornerEventBus.on(CoffinCornerEvents.SELECTED, (event) => {
78
+ if (event.payload.mapId !== mapId) return;
79
+ if (get().selectedId !== event.payload.selectedId) set({ selectedId: event.payload.selectedId });
80
+ });
81
+ const onDeselected = coffinCornerEventBus.on(CoffinCornerEvents.DESELECTED, (event) => {
82
+ if (event.payload.mapId !== mapId) return;
83
+ if (get().selectedId !== void 0) set({ selectedId: void 0 });
84
+ });
85
+ const onHovered = coffinCornerEventBus.on(CoffinCornerEvents.HOVERED, (event) => {
86
+ if (event.payload.mapId !== mapId) return;
87
+ if (get().hoveredId !== event.payload.hoveredId) set({ hoveredId: event.payload.hoveredId });
88
+ });
89
+ const onClick = mapEventBus.on(MapEvents.click, (event) => {
90
+ if (event.payload.id !== mapId) return;
91
+ const { info } = event.payload;
92
+ const { layerId, selectedId, getEntityId: getId } = get();
93
+ if (info.layerId === layerId && info.object) {
94
+ const entityId = getId(info.object);
95
+ if (selectedId === entityId) coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {
96
+ mapId,
97
+ selectedId: void 0
98
+ });
99
+ else coffinCornerEventBus.emit(CoffinCornerEvents.SELECTED, {
100
+ selectedId: entityId,
101
+ mapId
102
+ });
103
+ return;
104
+ }
105
+ if (info.index === -1 && selectedId !== void 0) coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {
106
+ mapId,
107
+ selectedId: void 0
108
+ });
109
+ });
110
+ const onHover = mapEventBus.on(MapEvents.hover, (event) => {
111
+ if (event.payload.id !== mapId) return;
112
+ const { info } = event.payload;
113
+ const { layerId, getEntityId: getId, hoveredId: currentHoveredId } = get();
114
+ const hoveredId = info.layerId === layerId && info.object ? getId(info.object) : void 0;
115
+ if (currentHoveredId !== hoveredId) coffinCornerEventBus.emit(CoffinCornerEvents.HOVERED, {
116
+ hoveredId,
117
+ mapId
118
+ });
119
+ });
120
+ return () => {
121
+ onSelected();
122
+ onDeselected();
123
+ onHovered();
124
+ onClick();
125
+ onHover();
126
+ };
127
+ }
128
+ });
129
+ /**
130
+ * Get selected entity ID imperatively (non-reactive).
131
+ *
132
+ * @param mapId - The map instance to query.
133
+ * @returns The selected entity ID, or undefined if nothing is selected.
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * const selectedId = getSelectedEntityId(mapId);
138
+ * ```
139
+ */
140
+ function getSelectedEntityId(mapId) {
141
+ return coffinCornerStore.get(mapId).selectedId;
142
+ }
143
+ /**
144
+ * Get hovered entity ID imperatively (non-reactive).
145
+ *
146
+ * @param mapId - The map instance to query.
147
+ * @returns The hovered entity ID, or undefined if nothing is hovered.
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const hoveredId = getHoveredEntityId(mapId);
152
+ * ```
153
+ */
154
+ function getHoveredEntityId(mapId) {
155
+ return coffinCornerStore.get(mapId).hoveredId;
156
+ }
157
+ /**
158
+ * Clear selection state (for tests/cleanup).
159
+ *
160
+ * @param mapId - The map instance to clear selection for.
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * clearSelection(mapId);
165
+ * ```
166
+ */
167
+ function clearSelection(mapId) {
168
+ coffinCornerStore.clear(mapId);
169
+ }
170
+
171
+ //#endregion
172
+ export { clearSelection, coffinCornerStore, getHoveredEntityId, getSelectedEntityId };
173
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","names":["defaultGetEntityId: GetEntityId"],"sources":["../../../../src/deckgl/extensions/coffin-corner/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'use client';\n\nimport { Broadcast } from '@accelint/bus';\nimport { createMapStore } from '@/shared/create-map-store';\nimport { MapEvents } from '../../base-map/events';\nimport { CoffinCornerEvents } from './types';\nimport type { UniqueId } from '@accelint/core';\nimport type {\n MapClickEvent,\n MapEventType,\n MapHoverEvent,\n} from '../../base-map/types';\nimport type { CoffinCornerEvent, EntityId } from './types';\n\n/** Extracts an entity ID from a picked data item. */\n// biome-ignore lint/suspicious/noExplicitAny: Data type is unknown at store level.\ntype GetEntityId = (item: any) => EntityId;\n\n/** Default accessor — assumes the data item has an `id` property. */\n// biome-ignore lint/suspicious/noExplicitAny: Data type is unknown at store level.\nconst defaultGetEntityId: GetEntityId = (item: any) => item.id as EntityId;\n\n/**\n * State for coffin corner selection and hover.\n */\ntype CoffinCornerState = {\n /** Currently selected entity ID, or undefined if nothing is selected. */\n selectedId: EntityId | undefined;\n /** Currently hovered entity ID, or undefined if nothing is hovered. */\n hoveredId: EntityId | undefined;\n /** deck.gl layer ID used to filter map bus events to only this layer's interactions. */\n layerId: string | undefined;\n /** Accessor to extract an entity ID from a picked data item. */\n getEntityId: GetEntityId;\n};\n\n/**\n * Actions for coffin corner interactions.\n */\ntype CoffinCornerActions = {\n /** Select an entity by ID (emits domain event). Pass undefined to deselect. */\n setSelectedId: (id: EntityId | undefined) => void;\n /** Clear the current selection (emits deselect domain event). */\n deselect: () => void;\n /** Set the deck.gl layer ID used to filter map bus events. */\n setLayerId: (layerId: string) => void;\n /** Override the entity ID accessor for picked data items. */\n setGetEntityId: (fn: GetEntityId) => void;\n};\n\nconst coffinCornerEventBus = Broadcast.getInstance<CoffinCornerEvent>();\nconst mapEventBus = Broadcast.getInstance<MapEventType>();\n\n/**\n * Coffin corner store - manages selection and hover state per map instance.\n *\n * Subscribes to map bus events for click/hover interactions and translates\n * them into coffin corner domain events. The hook only needs to pass the\n * layer ID — all subscription management lives here.\n *\n * @example\n * ```tsx\n * const { state, setSelectedId, deselect } = coffinCornerStore.use(mapId);\n * ```\n */\nexport const coffinCornerStore = createMapStore<\n CoffinCornerState,\n CoffinCornerActions\n>({\n defaultState: {\n selectedId: undefined,\n hoveredId: undefined,\n layerId: undefined,\n getEntityId: defaultGetEntityId,\n },\n\n // Actions emit domain events rather than calling set() directly.\n // The bus subscriptions below translate events → state, ensuring\n // all state changes are observable by external subscribers.\n actions: (mapId, { get, set }) => ({\n setSelectedId: (id: EntityId | undefined) => {\n const currentId = get().selectedId;\n\n if (id == null && currentId != null) {\n coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {\n mapId,\n selectedId: undefined,\n });\n\n return;\n }\n\n if (id != null && currentId !== id) {\n coffinCornerEventBus.emit(CoffinCornerEvents.SELECTED, {\n selectedId: id,\n mapId,\n });\n\n return;\n }\n },\n\n deselect: () => {\n coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {\n mapId,\n selectedId: undefined,\n });\n },\n\n setLayerId: (layerId: string) => {\n if (get().layerId !== layerId) {\n set({ layerId });\n }\n },\n\n setGetEntityId: (fn: GetEntityId) => {\n if (get().getEntityId !== fn) {\n set({ getEntityId: fn });\n }\n },\n }),\n\n bus: (mapId, { get, set }) => {\n // Domain events → state\n const onSelected = coffinCornerEventBus.on(\n CoffinCornerEvents.SELECTED,\n (event) => {\n if (event.payload.mapId !== mapId) {\n return;\n }\n\n if (get().selectedId !== event.payload.selectedId) {\n set({ selectedId: event.payload.selectedId });\n }\n },\n );\n\n const onDeselected = coffinCornerEventBus.on(\n CoffinCornerEvents.DESELECTED,\n (event) => {\n if (event.payload.mapId !== mapId) {\n return;\n }\n\n if (get().selectedId !== undefined) {\n set({ selectedId: undefined });\n }\n },\n );\n\n const onHovered = coffinCornerEventBus.on(\n CoffinCornerEvents.HOVERED,\n (event) => {\n if (event.payload.mapId !== mapId) {\n return;\n }\n if (get().hoveredId !== event.payload.hoveredId) {\n set({ hoveredId: event.payload.hoveredId });\n }\n },\n );\n\n // Map clicks → domain events\n const onClick = mapEventBus.on(MapEvents.click, (event: MapClickEvent) => {\n if (event.payload.id !== mapId) {\n return;\n }\n\n const { info } = event.payload;\n const { layerId, selectedId, getEntityId: getId } = get();\n\n if (info.layerId === layerId && info.object) {\n const entityId = getId(info.object);\n\n if (selectedId === entityId) {\n coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {\n mapId,\n selectedId: undefined,\n });\n } else {\n coffinCornerEventBus.emit(CoffinCornerEvents.SELECTED, {\n selectedId: entityId,\n mapId,\n });\n }\n\n return;\n }\n\n if (info.index === -1 && selectedId !== undefined) {\n coffinCornerEventBus.emit(CoffinCornerEvents.DESELECTED, {\n mapId,\n selectedId: undefined,\n });\n }\n });\n\n // Map hovers → domain events\n const onHover = mapEventBus.on(MapEvents.hover, (event: MapHoverEvent) => {\n if (event.payload.id !== mapId) {\n return;\n }\n\n const { info } = event.payload;\n const {\n layerId,\n getEntityId: getId,\n hoveredId: currentHoveredId,\n } = get();\n\n const hoveredId =\n info.layerId === layerId && info.object\n ? getId(info.object)\n : undefined;\n\n if (currentHoveredId !== hoveredId) {\n coffinCornerEventBus.emit(CoffinCornerEvents.HOVERED, {\n hoveredId,\n mapId,\n });\n }\n });\n\n return () => {\n onSelected();\n onDeselected();\n onHovered();\n onClick();\n onHover();\n };\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get selected entity ID imperatively (non-reactive).\n *\n * @param mapId - The map instance to query.\n * @returns The selected entity ID, or undefined if nothing is selected.\n *\n * @example\n * ```typescript\n * const selectedId = getSelectedEntityId(mapId);\n * ```\n */\nexport function getSelectedEntityId(mapId: UniqueId): EntityId | undefined {\n return coffinCornerStore.get(mapId).selectedId;\n}\n\n/**\n * Get hovered entity ID imperatively (non-reactive).\n *\n * @param mapId - The map instance to query.\n * @returns The hovered entity ID, or undefined if nothing is hovered.\n *\n * @example\n * ```typescript\n * const hoveredId = getHoveredEntityId(mapId);\n * ```\n */\nexport function getHoveredEntityId(mapId: UniqueId): EntityId | undefined {\n return coffinCornerStore.get(mapId).hoveredId;\n}\n\n/**\n * Clear selection state (for tests/cleanup).\n *\n * @param mapId - The map instance to clear selection for.\n *\n * @example\n * ```typescript\n * clearSelection(mapId);\n * ```\n */\nexport function clearSelection(mapId: UniqueId): void {\n coffinCornerStore.clear(mapId);\n}\n"],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { Payload } from "@accelint/bus";
14
+ import { UniqueId } from "@accelint/core";
15
+ import { Rgba255Tuple } from "@accelint/predicates";
16
+
17
+ //#region src/deckgl/extensions/coffin-corner/types.d.ts
18
+ /**
19
+ * Props added by the CoffinCornerExtension.
20
+ *
21
+ * @template TLayerProps - The host layer's props type to intersect with.
22
+ */
23
+ type CoffinCornerExtensionProps<TLayerProps = unknown> = {
24
+ /** The currently selected entity ID. */
25
+ selectedEntityId?: EntityId;
26
+ /** The currently hovered entity ID. */
27
+ hoveredEntityId?: EntityId;
28
+ /**
29
+ * RGBA color (0-255) for the selected-state bracket fill.
30
+ * Alpha modulates the bracket opacity.
31
+ * @default [57, 183, 250, 255] (#39B7FA, fully opaque)
32
+ */
33
+ selectedCoffinCornerColor?: Rgba255Tuple;
34
+ /**
35
+ * Accessor to extract an entity ID from a data item. Matched against
36
+ * `selectedEntityId` and `hoveredEntityId` to drive the shader state.
37
+ * @default (item) => item.id
38
+ */
39
+ getEntityId?: (item: any) => EntityId;
40
+ } & TLayerProps;
41
+ /**
42
+ * Event type constants for coffin corner interactions.
43
+ * Used as keys with the Broadcast event bus.
44
+ */
45
+ declare const CoffinCornerEvents: {
46
+ /** Emitted when an entity is selected (click on a new entity). */
47
+ readonly SELECTED: "coffin-corner:selected";
48
+ /** Emitted when the current selection is cleared. */
49
+ readonly DESELECTED: "coffin-corner:deselected";
50
+ /** Emitted when the hovered entity changes. */
51
+ readonly HOVERED: "coffin-corner:hovered";
52
+ };
53
+ /** String literal union of all coffin corner event type keys. */
54
+ type CoffinCornerEventType = (typeof CoffinCornerEvents)[keyof typeof CoffinCornerEvents];
55
+ /** Unique identifier for an entity managed by the coffin corner extension. */
56
+ type EntityId = string | number;
57
+ /** Payload emitted when an entity is selected. Contains the selected ID and map instance. */
58
+ type CoffinCornerSelectedEvent = Payload<typeof CoffinCornerEvents.SELECTED, {
59
+ selectedId: EntityId;
60
+ mapId: UniqueId;
61
+ }>;
62
+ /** Payload emitted when selection is cleared. */
63
+ type CoffinCornerDeselectedEvent = Payload<typeof CoffinCornerEvents.DESELECTED, {
64
+ mapId: UniqueId;
65
+ selectedId: undefined;
66
+ }>;
67
+ /** Payload emitted when the hovered entity changes. `hoveredId` is undefined when hover ends. */
68
+ type CoffinCornerHoveredEvent = Payload<typeof CoffinCornerEvents.HOVERED, {
69
+ hoveredId?: EntityId;
70
+ mapId: UniqueId;
71
+ }>;
72
+ /** Union of all coffin corner event payloads for type-safe bus subscription. */
73
+ type CoffinCornerEvent = CoffinCornerSelectedEvent | CoffinCornerDeselectedEvent | CoffinCornerHoveredEvent;
74
+ //#endregion
75
+ export { CoffinCornerDeselectedEvent, CoffinCornerEvent, CoffinCornerEventType, CoffinCornerEvents, CoffinCornerExtensionProps, CoffinCornerHoveredEvent, CoffinCornerSelectedEvent, EntityId };
76
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ //#region src/deckgl/extensions/coffin-corner/types.ts
15
+ /**
16
+ * Event type constants for coffin corner interactions.
17
+ * Used as keys with the Broadcast event bus.
18
+ */
19
+ const CoffinCornerEvents = {
20
+ SELECTED: "coffin-corner:selected",
21
+ DESELECTED: "coffin-corner:deselected",
22
+ HOVERED: "coffin-corner:hovered"
23
+ };
24
+
25
+ //#endregion
26
+ export { CoffinCornerEvents };
27
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../src/deckgl/extensions/coffin-corner/types.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 type { Payload } from '@accelint/bus';\nimport type { UniqueId } from '@accelint/core';\nimport type { Rgba255Tuple } from '@accelint/predicates';\n\n/**\n * Props added by the CoffinCornerExtension.\n *\n * @template TLayerProps - The host layer's props type to intersect with.\n */\nexport type CoffinCornerExtensionProps<TLayerProps = unknown> = {\n /** The currently selected entity ID. */\n selectedEntityId?: EntityId;\n /** The currently hovered entity ID. */\n hoveredEntityId?: EntityId;\n /**\n * RGBA color (0-255) for the selected-state bracket fill.\n * Alpha modulates the bracket opacity.\n * @default [57, 183, 250, 255] (#39B7FA, fully opaque)\n */\n selectedCoffinCornerColor?: Rgba255Tuple;\n /**\n * Accessor to extract an entity ID from a data item. Matched against\n * `selectedEntityId` and `hoveredEntityId` to drive the shader state.\n * @default (item) => item.id\n */\n // biome-ignore lint/suspicious/noExplicitAny: Data type is unknown at extension level.\n getEntityId?: (item: any) => EntityId;\n} & TLayerProps;\n\n/**\n * Event type constants for coffin corner interactions.\n * Used as keys with the Broadcast event bus.\n */\nexport const CoffinCornerEvents = {\n /** Emitted when an entity is selected (click on a new entity). */\n SELECTED: 'coffin-corner:selected',\n /** Emitted when the current selection is cleared. */\n DESELECTED: 'coffin-corner:deselected',\n /** Emitted when the hovered entity changes. */\n HOVERED: 'coffin-corner:hovered',\n} as const;\n\n/** String literal union of all coffin corner event type keys. */\nexport type CoffinCornerEventType =\n (typeof CoffinCornerEvents)[keyof typeof CoffinCornerEvents];\n\n/** Unique identifier for an entity managed by the coffin corner extension. */\nexport type EntityId = string | number;\n\n/** Payload emitted when an entity is selected. Contains the selected ID and map instance. */\nexport type CoffinCornerSelectedEvent = Payload<\n typeof CoffinCornerEvents.SELECTED,\n { selectedId: EntityId; mapId: UniqueId }\n>;\n\n/** Payload emitted when selection is cleared. */\nexport type CoffinCornerDeselectedEvent = Payload<\n typeof CoffinCornerEvents.DESELECTED,\n { mapId: UniqueId; selectedId: undefined }\n>;\n\n/** Payload emitted when the hovered entity changes. `hoveredId` is undefined when hover ends. */\nexport type CoffinCornerHoveredEvent = Payload<\n typeof CoffinCornerEvents.HOVERED,\n { hoveredId?: EntityId; mapId: UniqueId }\n>;\n\n/** Union of all coffin corner event payloads for type-safe bus subscription. */\nexport type CoffinCornerEvent =\n | CoffinCornerSelectedEvent\n | CoffinCornerDeselectedEvent\n | CoffinCornerHoveredEvent;\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6CA,MAAa,qBAAqB;CAEhC,UAAU;CAEV,YAAY;CAEZ,SAAS;CACV"}
@@ -0,0 +1,81 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { EntityId } from "./types.js";
14
+ import { UniqueId } from "@accelint/core";
15
+
16
+ //#region src/deckgl/extensions/coffin-corner/use-coffin-corner.d.ts
17
+ /**
18
+ * Return type for useCoffinCorner hook
19
+ */
20
+ type UseCoffinCornerReturn = {
21
+ /** Currently selected entity ID, or undefined if nothing selected */
22
+ selectedId: EntityId | undefined;
23
+ /** Currently hovered entity ID, or undefined if nothing hovered */
24
+ hoveredId: EntityId | undefined;
25
+ /** Set the selected entity ID */
26
+ setSelectedId: (id: EntityId | undefined) => void;
27
+ /** Clear the current selection */
28
+ deselect: () => void;
29
+ };
30
+ /**
31
+ * Options for the useCoffinCorner hook.
32
+ */
33
+ type UseCoffinCornerOptions = {
34
+ /**
35
+ * Accessor to extract an entity ID from a picked data item.
36
+ * Must match the `getEntityId` prop passed to the CoffinCornerExtension.
37
+ * Should be a stable reference (module-level or `useCallback`) to avoid unnecessary store updates on every render.
38
+ * @default (item) => item.id
39
+ */
40
+ getEntityId?: (item: any) => EntityId;
41
+ };
42
+ /**
43
+ * Hook to manage coffin corner entity selection state.
44
+ *
45
+ * Automatically subscribes to map bus events for the given map and layer,
46
+ * so you don't need onClick/onHover callbacks on the layer.
47
+ *
48
+ * @param mapId - The BaseMap instance ID
49
+ * @param layerId - The deck.gl layer ID to listen for interactions on
50
+ * @param options - Optional configuration for entity ID extraction
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * import { useCoffinCorner } from '@accelint/map-toolkit/deckgl/extensions/coffin-corner';
55
+ *
56
+ * function MapWithIcons({ mapId }) {
57
+ * const { selectedId, hoveredId } = useCoffinCorner(mapId, 'base-icons');
58
+ *
59
+ * return (
60
+ * <iconLayer
61
+ * id="base-icons"
62
+ * pickable
63
+ * extensions={[coffinCornerExtension]}
64
+ * selectedEntityId={selectedId}
65
+ * hoveredEntityId={hoveredId}
66
+ * />
67
+ * );
68
+ * }
69
+ * ```
70
+ *
71
+ * @example Custom entity ID accessor
72
+ * ```tsx
73
+ * const { selectedId, hoveredId } = useCoffinCorner(mapId, 'geojson-icons', {
74
+ * getEntityId: (d) => d.properties?.shapeId,
75
+ * });
76
+ * ```
77
+ */
78
+ declare function useCoffinCorner(mapId: UniqueId, layerId: string, options?: UseCoffinCornerOptions): UseCoffinCornerReturn;
79
+ //#endregion
80
+ export { UseCoffinCornerOptions, UseCoffinCornerReturn, useCoffinCorner };
81
+ //# sourceMappingURL=use-coffin-corner.d.ts.map
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ 'use client';
15
+
16
+ import { coffinCornerStore } from "./store.js";
17
+ import { useEffect } from "react";
18
+
19
+ //#region src/deckgl/extensions/coffin-corner/use-coffin-corner.ts
20
+ /**
21
+ * Hook to manage coffin corner entity selection state.
22
+ *
23
+ * Automatically subscribes to map bus events for the given map and layer,
24
+ * so you don't need onClick/onHover callbacks on the layer.
25
+ *
26
+ * @param mapId - The BaseMap instance ID
27
+ * @param layerId - The deck.gl layer ID to listen for interactions on
28
+ * @param options - Optional configuration for entity ID extraction
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * import { useCoffinCorner } from '@accelint/map-toolkit/deckgl/extensions/coffin-corner';
33
+ *
34
+ * function MapWithIcons({ mapId }) {
35
+ * const { selectedId, hoveredId } = useCoffinCorner(mapId, 'base-icons');
36
+ *
37
+ * return (
38
+ * <iconLayer
39
+ * id="base-icons"
40
+ * pickable
41
+ * extensions={[coffinCornerExtension]}
42
+ * selectedEntityId={selectedId}
43
+ * hoveredEntityId={hoveredId}
44
+ * />
45
+ * );
46
+ * }
47
+ * ```
48
+ *
49
+ * @example Custom entity ID accessor
50
+ * ```tsx
51
+ * const { selectedId, hoveredId } = useCoffinCorner(mapId, 'geojson-icons', {
52
+ * getEntityId: (d) => d.properties?.shapeId,
53
+ * });
54
+ * ```
55
+ */
56
+ function useCoffinCorner(mapId, layerId, options) {
57
+ const { state, setSelectedId, deselect, setLayerId, setGetEntityId } = coffinCornerStore.use(mapId);
58
+ useEffect(() => {
59
+ setLayerId(layerId);
60
+ }, [setLayerId, layerId]);
61
+ const getEntityId = options?.getEntityId;
62
+ useEffect(() => {
63
+ if (getEntityId) setGetEntityId(getEntityId);
64
+ }, [setGetEntityId, getEntityId]);
65
+ return {
66
+ selectedId: state.selectedId,
67
+ hoveredId: state.hoveredId,
68
+ setSelectedId,
69
+ deselect
70
+ };
71
+ }
72
+
73
+ //#endregion
74
+ export { useCoffinCorner };
75
+ //# sourceMappingURL=use-coffin-corner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-coffin-corner.js","names":[],"sources":["../../../../src/deckgl/extensions/coffin-corner/use-coffin-corner.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'use client';\n\nimport { useEffect } from 'react';\nimport { coffinCornerStore } from './store';\nimport type { UniqueId } from '@accelint/core';\nimport type { EntityId } from './types';\n\n/**\n * Return type for useCoffinCorner hook\n */\nexport type UseCoffinCornerReturn = {\n /** Currently selected entity ID, or undefined if nothing selected */\n selectedId: EntityId | undefined;\n /** Currently hovered entity ID, or undefined if nothing hovered */\n hoveredId: EntityId | undefined;\n /** Set the selected entity ID */\n setSelectedId: (id: EntityId | undefined) => void;\n /** Clear the current selection */\n deselect: () => void;\n};\n\n/**\n * Options for the useCoffinCorner hook.\n */\nexport type UseCoffinCornerOptions = {\n /**\n * Accessor to extract an entity ID from a picked data item.\n * Must match the `getEntityId` prop passed to the CoffinCornerExtension.\n * Should be a stable reference (module-level or `useCallback`) to avoid unnecessary store updates on every render.\n * @default (item) => item.id\n */\n // biome-ignore lint/suspicious/noExplicitAny: Data type is unknown at hook level.\n getEntityId?: (item: any) => EntityId;\n};\n\n/**\n * Hook to manage coffin corner entity selection state.\n *\n * Automatically subscribes to map bus events for the given map and layer,\n * so you don't need onClick/onHover callbacks on the layer.\n *\n * @param mapId - The BaseMap instance ID\n * @param layerId - The deck.gl layer ID to listen for interactions on\n * @param options - Optional configuration for entity ID extraction\n *\n * @example\n * ```tsx\n * import { useCoffinCorner } from '@accelint/map-toolkit/deckgl/extensions/coffin-corner';\n *\n * function MapWithIcons({ mapId }) {\n * const { selectedId, hoveredId } = useCoffinCorner(mapId, 'base-icons');\n *\n * return (\n * <iconLayer\n * id=\"base-icons\"\n * pickable\n * extensions={[coffinCornerExtension]}\n * selectedEntityId={selectedId}\n * hoveredEntityId={hoveredId}\n * />\n * );\n * }\n * ```\n *\n * @example Custom entity ID accessor\n * ```tsx\n * const { selectedId, hoveredId } = useCoffinCorner(mapId, 'geojson-icons', {\n * getEntityId: (d) => d.properties?.shapeId,\n * });\n * ```\n */\nexport function useCoffinCorner(\n mapId: UniqueId,\n layerId: string,\n options?: UseCoffinCornerOptions,\n): UseCoffinCornerReturn {\n const { state, setSelectedId, deselect, setLayerId, setGetEntityId } =\n coffinCornerStore.use(mapId);\n\n // Unlike a CompositeLayer, CoffinCornerExtension is a shader-only plugin\n // with no picking handlers. The store must filter raw map bus events by\n // layerId to know which clicks/hovers belong to this extension's layer.\n useEffect(() => {\n setLayerId(layerId);\n }, [setLayerId, layerId]);\n\n const getEntityId = options?.getEntityId;\n\n useEffect(() => {\n if (getEntityId) {\n setGetEntityId(getEntityId);\n }\n }, [setGetEntityId, getEntityId]);\n\n return {\n selectedId: state.selectedId,\n hoveredId: state.hoveredId,\n setSelectedId,\n deselect,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmFA,SAAgB,gBACd,OACA,SACA,SACuB;CACvB,MAAM,EAAE,OAAO,eAAe,UAAU,YAAY,mBAClD,kBAAkB,IAAI,MAAM;AAK9B,iBAAgB;AACd,aAAW,QAAQ;IAClB,CAAC,YAAY,QAAQ,CAAC;CAEzB,MAAM,cAAc,SAAS;AAE7B,iBAAgB;AACd,MAAI,YACF,gBAAe,YAAY;IAE5B,CAAC,gBAAgB,YAAY,CAAC;AAEjC,QAAO;EACL,YAAY,MAAM;EAClB,WAAW,MAAM;EACjB;EACA;EACD"}
@@ -0,0 +1,15 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { CoffinCornerExtensionProps } from "./coffin-corner/types.js";
14
+ import { CoffinCornerExtension } from "./coffin-corner/coffin-corner-extension.js";
15
+ export { CoffinCornerExtension, type CoffinCornerExtensionProps };
@@ -0,0 +1,16 @@
1
+ /*
2
+ * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at https://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ import { CoffinCornerExtension } from "./coffin-corner/coffin-corner-extension.js";
15
+
16
+ export { CoffinCornerExtension };
@@ -14,6 +14,11 @@ import { MapEvents, MapEventsNamespace } from "./base-map/events.js";
14
14
  import { BaseMapProps, MapClickEvent, MapClickPayload, MapControlPayload, MapDisablePanEvent, MapDisableZoomEvent, MapEnablePanEvent, MapEnableZoomEvent, MapEventType, MapHoverEvent, MapHoverPayload } from "./base-map/types.js";
15
15
  import { DARK_BASE_MAP_STYLE, LIGHT_BASE_MAP_STYLE, PARAMETERS } from "./base-map/constants.js";
16
16
  import { BaseMap } from "./base-map/index.js";
17
+ import { CoffinCornerDeselectedEvent, CoffinCornerEvent, CoffinCornerEventType, CoffinCornerEvents, CoffinCornerExtensionProps, CoffinCornerHoveredEvent, CoffinCornerSelectedEvent, EntityId } from "./extensions/coffin-corner/types.js";
18
+ import { CoffinCornerExtension } from "./extensions/coffin-corner/coffin-corner-extension.js";
19
+ import { clearSelection, coffinCornerStore, getHoveredEntityId, getSelectedEntityId } from "./extensions/coffin-corner/store.js";
20
+ import { UseCoffinCornerReturn, useCoffinCorner } from "./extensions/coffin-corner/use-coffin-corner.js";
21
+ import "./extensions/coffin-corner/index.js";
17
22
  import { SavedViewportOptions, createSavedViewport } from "./saved-viewports/index.js";
18
23
  import { CircleProperties, CircleRadius, EllipseProperties, Shape, ShapeFeature, ShapeFeatureProperties, ShapeFeatureType, ShapeId, StyleProperties, StyledFeature, StyledFeatureProperties } from "./shapes/shared/types.js";
19
24
  import { DisplayShapeLayerProps } from "./shapes/display-shape-layer/types.js";
@@ -22,4 +27,4 @@ import { DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_STYLE_PROPERTIES, LINE_PATTERNS, L
22
27
  import { ShapeEventType, ShapeEvents } from "./shapes/shared/events.js";
23
28
  import "./shapes/index.js";
24
29
  import { SymbolLayer, SymbolLayerProps } from "./symbol-layer/index.js";
25
- export { BaseMap, type BaseMapProps, type CircleProperties, type CircleRadius, DARK_BASE_MAP_STYLE, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_STYLE_PROPERTIES, DisplayShapeLayer, type DisplayShapeLayerProps, type EllipseProperties, LIGHT_BASE_MAP_STYLE, LINE_PATTERNS, LINE_WIDTHS, type MapClickEvent, type MapClickPayload, type MapControlPayload, type MapDisablePanEvent, type MapDisableZoomEvent, type MapEnablePanEvent, type MapEnableZoomEvent, type MapEventType, MapEvents, MapEventsNamespace, type MapHoverEvent, type MapHoverPayload, PARAMETERS, SHAPE_LAYER_IDS, type SavedViewportOptions, type Shape, type ShapeEventType, ShapeEvents, type ShapeFeature, type ShapeFeatureProperties, ShapeFeatureType, type ShapeId, type StyleProperties, type StyledFeature, type StyledFeatureProperties, SymbolLayer, type SymbolLayerProps, createSavedViewport };
30
+ export { BaseMap, type BaseMapProps, type CircleProperties, type CircleRadius, type CoffinCornerDeselectedEvent, type CoffinCornerEvent, type CoffinCornerEventType, CoffinCornerEvents, CoffinCornerExtension, type CoffinCornerExtensionProps, type CoffinCornerHoveredEvent, type CoffinCornerSelectedEvent, DARK_BASE_MAP_STYLE, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_STYLE_PROPERTIES, DisplayShapeLayer, type DisplayShapeLayerProps, type EllipseProperties, type EntityId, LIGHT_BASE_MAP_STYLE, LINE_PATTERNS, LINE_WIDTHS, type MapClickEvent, type MapClickPayload, type MapControlPayload, type MapDisablePanEvent, type MapDisableZoomEvent, type MapEnablePanEvent, type MapEnableZoomEvent, type MapEventType, MapEvents, MapEventsNamespace, type MapHoverEvent, type MapHoverPayload, PARAMETERS, SHAPE_LAYER_IDS, type SavedViewportOptions, type Shape, type ShapeEventType, ShapeEvents, type ShapeFeature, type ShapeFeatureProperties, ShapeFeatureType, type ShapeId, type StyleProperties, type StyledFeature, type StyledFeatureProperties, SymbolLayer, type SymbolLayerProps, type UseCoffinCornerReturn, clearSelection, coffinCornerStore, createSavedViewport, getHoveredEntityId, getSelectedEntityId, useCoffinCorner };
@@ -17,8 +17,12 @@ import { ShapeFeatureType } from "./shapes/shared/types.js";
17
17
  import { DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_STYLE_PROPERTIES, LINE_PATTERNS, LINE_WIDTHS, SHAPE_LAYER_IDS } from "./shapes/shared/constants.js";
18
18
  import { DARK_BASE_MAP_STYLE, LIGHT_BASE_MAP_STYLE, PARAMETERS } from "./base-map/constants.js";
19
19
  import { BaseMap } from "./base-map/index.js";
20
+ import { CoffinCornerExtension } from "./extensions/coffin-corner/coffin-corner-extension.js";
21
+ import { CoffinCornerEvents } from "./extensions/coffin-corner/types.js";
22
+ import { clearSelection, coffinCornerStore, getHoveredEntityId, getSelectedEntityId } from "./extensions/coffin-corner/store.js";
23
+ import { useCoffinCorner } from "./extensions/coffin-corner/use-coffin-corner.js";
20
24
  import { createSavedViewport } from "./saved-viewports/index.js";
21
25
  import { DisplayShapeLayer } from "./shapes/display-shape-layer/index.js";
22
26
  import { SymbolLayer } from "./symbol-layer/index.js";
23
27
 
24
- export { BaseMap, DARK_BASE_MAP_STYLE, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_STYLE_PROPERTIES, DisplayShapeLayer, LIGHT_BASE_MAP_STYLE, LINE_PATTERNS, LINE_WIDTHS, MapEvents, MapEventsNamespace, PARAMETERS, SHAPE_LAYER_IDS, ShapeEvents, ShapeFeatureType, SymbolLayer, createSavedViewport };
28
+ export { BaseMap, CoffinCornerEvents, CoffinCornerExtension, DARK_BASE_MAP_STYLE, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_STYLE_PROPERTIES, DisplayShapeLayer, LIGHT_BASE_MAP_STYLE, LINE_PATTERNS, LINE_WIDTHS, MapEvents, MapEventsNamespace, PARAMETERS, SHAPE_LAYER_IDS, ShapeEvents, ShapeFeatureType, SymbolLayer, clearSelection, coffinCornerStore, createSavedViewport, getHoveredEntityId, getSelectedEntityId, useCoffinCorner };