@oicl/openbridge-webcomponents 2.0.0-next.170 → 2.0.0-next.171

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 (54) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +870 -441
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +1333 -392
  4. package/dist/ar/poi/poi-aton.d.ts +1 -0
  5. package/dist/ar/poi/poi-aton.d.ts.map +1 -1
  6. package/dist/ar/poi/poi-aton.js +1 -0
  7. package/dist/ar/poi/poi-aton.js.map +1 -1
  8. package/dist/ar/poi/poi-base.d.ts +39 -5
  9. package/dist/ar/poi/poi-base.d.ts.map +1 -1
  10. package/dist/ar/poi/poi-base.js +108 -37
  11. package/dist/ar/poi/poi-base.js.map +1 -1
  12. package/dist/ar/poi/poi-data.d.ts +1 -0
  13. package/dist/ar/poi/poi-data.d.ts.map +1 -1
  14. package/dist/ar/poi/poi-data.js +1 -0
  15. package/dist/ar/poi/poi-data.js.map +1 -1
  16. package/dist/ar/poi/poi-vessel.d.ts +1 -0
  17. package/dist/ar/poi/poi-vessel.d.ts.map +1 -1
  18. package/dist/ar/poi/poi-vessel.js +1 -0
  19. package/dist/ar/poi/poi-vessel.js.map +1 -1
  20. package/dist/ar/poi/poi.d.ts +4 -12
  21. package/dist/ar/poi/poi.d.ts.map +1 -1
  22. package/dist/ar/poi/poi.js +6 -72
  23. package/dist/ar/poi/poi.js.map +1 -1
  24. package/dist/ar/poi-button/poi-button.d.ts +6 -2
  25. package/dist/ar/poi-button/poi-button.d.ts.map +1 -1
  26. package/dist/ar/poi-button/poi-button.js +10 -1
  27. package/dist/ar/poi-button/poi-button.js.map +1 -1
  28. package/dist/ar/poi-card/poi-card.d.ts +12 -1
  29. package/dist/ar/poi-card/poi-card.d.ts.map +1 -1
  30. package/dist/ar/poi-card/poi-card.js +4 -1
  31. package/dist/ar/poi-card/poi-card.js.map +1 -1
  32. package/dist/ar/poi-controller/poi-controller.d.ts +45 -1
  33. package/dist/ar/poi-controller/poi-controller.d.ts.map +1 -1
  34. package/dist/ar/poi-controller/poi-controller.js +72 -14
  35. package/dist/ar/poi-controller/poi-controller.js.map +1 -1
  36. package/dist/ar/poi-group/poi-group.d.ts +28 -5
  37. package/dist/ar/poi-group/poi-group.d.ts.map +1 -1
  38. package/dist/ar/poi-group/poi-group.js +50 -7
  39. package/dist/ar/poi-group/poi-group.js.map +1 -1
  40. package/dist/ar/poi-layer/poi-layer.css.js +69 -18
  41. package/dist/ar/poi-layer/poi-layer.css.js.map +1 -1
  42. package/dist/ar/poi-layer/poi-layer.d.ts +64 -5
  43. package/dist/ar/poi-layer/poi-layer.d.ts.map +1 -1
  44. package/dist/ar/poi-layer/poi-layer.js +173 -39
  45. package/dist/ar/poi-layer/poi-layer.js.map +1 -1
  46. package/dist/ar/poi-layer-stack/poi-layer-stack.d.ts +82 -7
  47. package/dist/ar/poi-layer-stack/poi-layer-stack.d.ts.map +1 -1
  48. package/dist/ar/poi-layer-stack/poi-layer-stack.js +172 -100
  49. package/dist/ar/poi-layer-stack/poi-layer-stack.js.map +1 -1
  50. package/dist/ar/poi-projection/poi-projection.d.ts +88 -0
  51. package/dist/ar/poi-projection/poi-projection.d.ts.map +1 -0
  52. package/dist/ar/poi-projection/poi-projection.js +90 -0
  53. package/dist/ar/poi-projection/poi-projection.js.map +1 -0
  54. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"poi-controller.js","names":[],"sources":["../../../src/ar/poi-controller/poi-controller.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, queryAssignedElements, state} from 'lit/decorators.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './poi-controller.css?inline';\nimport '../poi-layer-stack/poi-layer-stack.js';\nimport {ObcPoiLayer} from '../poi-layer/poi-layer.js';\nimport {ObcPoiData} from '../poi/poi-data.js';\nimport {resolvePoiButtonTypeFromBoxSize} from '../poi-button/poi-button.js';\n\nexport type PoiDetection = {\n x: number;\n y: number;\n box_width?: number;\n box_height?: number;\n id?: string;\n confidence?: number;\n class?: string;\n class_id?: number;\n heading?: number;\n direction?: number;\n};\n\nexport type PoiKeyFn = (det: PoiDetection, index: number) => string;\n\nexport type PoiFrame = {\n frame?: number;\n timestamp?: number;\n detections: PoiDetection[];\n};\n\nexport enum PoiFitMode {\n Contain = 'contain',\n Cover = 'cover',\n}\n\n/**\n * `<obc-poi-controller>` — Maps detection data onto POI markers over a video or image.\n *\n * Takes detection coordinates in media pixel space (e.g. x,y in a 1920x1080 frame),\n * projects them to screen space using the media's rendered size and fit mode, and\n * creates/updates `obc-poi-data` targets inside a layer stack.\n *\n * ## Quick Start\n *\n * The media slot accepts a `<video>` (live stream, HLS, file) or `<img>` element.\n *\n * ```html\n * <obc-poi-controller fit=\"cover\">\n * <video slot=\"media\" src=\"stream.mp4\" autoplay muted></video>\n * <obc-poi-layer-stack slot=\"stack\" selection-mode=\"multi\">\n * <obc-poi-layer is-selected></obc-poi-layer>\n * <obc-poi-layer data-controller-layer=\"background\"></obc-poi-layer>\n * </obc-poi-layer-stack>\n * </obc-poi-controller>\n * ```\n *\n * Then set detections from your data source (WebSocket, API, etc.):\n *\n * ```js\n * const controller = document.querySelector('obc-poi-controller');\n * controller.detections = [\n * { id: 'track-1', x: 400, y: 800, box_width: 50, box_height: 40, heading: -15 },\n * { id: 'track-2', x: 900, y: 750, box_width: 35, box_height: 30, heading: 45 },\n * ];\n * ```\n *\n * ## Framework Usage\n *\n * **Lit:**\n * ```html\n * <obc-poi-controller .detections=${detections} fit=\"cover\">\n * ```\n *\n * **Vue:**\n * ```html\n * <obc-poi-controller :detections=\"detections\" fit=\"cover\">\n * ```\n *\n * **Svelte:**\n * ```html\n * <obc-poi-controller detections={detections} fit=\"cover\">\n * ```\n *\n * **React 18** (needs ref for array props):\n * ```tsx\n * const ref = useRef(null);\n * useEffect(() => { ref.current.detections = detections; }, [detections]);\n * <obc-poi-controller ref={ref} fit=\"cover\">\n * ```\n *\n * **React 19+** (native custom element support):\n * ```tsx\n * <obc-poi-controller detections={detections} fit=\"cover\">\n * ```\n *\n * ## Coordinate Model\n *\n * Detection `x` and `y` are in **media pixel space** (e.g. 0-1920 for a 1920x1080 video).\n * The controller projects them to screen space using the `fit` mode (`contain` or `cover`)\n * and the media element's rendered dimensions.\n *\n * The Y coordinate maps to the line length from the layer's top edge down to the\n * detection point. The button sits at the top of the layer; the line extends downward.\n *\n * ## Detection Data\n *\n * Each detection can include:\n * - `x`, `y` (required) — position in media pixel space\n * - `id` — stable identity key (prevents marker churn when array order changes)\n * - `box_width`, `box_height` — bounding box size; determines button type (regular vs enhanced)\n * - `heading` or `direction` — rotation angle for the icon arrow (degrees)\n * - `confidence` — filtered by `confidenceMin`\n * - `class` — filtered by `classFilter`\n *\n * ## Layer Setup\n *\n * The stack needs at least two layers:\n * 1. A **selected layer** (`is-selected`) — targets jump here when clicked\n * 2. A **background layer** (`data-controller-layer=\"background\"`) — where the controller places targets\n *\n * If no `data-controller-layer=\"background\"` is set, the controller uses the first non-selected layer.\n *\n * ## Selection\n *\n * Clicking a target moves it to the selected layer with a FLIP animation.\n * The controller does not interfere with selected targets — it only manages\n * targets in the background layer. The layer-stack owns selection state.\n *\n * ## CSS Custom Properties\n *\n * - `--obc-poi-controller-stack-top` (default `15%`) — vertical position of the stack\n * - `--obc-poi-controller-stack-height` (default `50%`) — height of the stack\n * - `--obc-poi-controller-stack-gap` (default `8px`) — gap between layers\n *\n * @slot media - Video or image element. Sets the projection source dimensions.\n * @slot stack - `obc-poi-layer-stack` containing the layers for target placement.\n * @experimental\n */\n@customElement('obc-poi-controller')\nexport class ObcPoiController extends LitElement {\n @property({type: String}) fit: PoiFitMode = PoiFitMode.Contain;\n @property({type: Array}) frames: PoiFrame[] | null = null;\n @property({type: Array}) detections: PoiDetection[] | null = null;\n @property({type: Number}) frameIndex: number | null = null;\n @property({type: Number}) confidenceMin: number | null = null;\n @property({type: Array}) classFilter: string[] | null = null;\n @property({attribute: false})\n keyFn: PoiKeyFn | null = null;\n\n @state() private mediaWidth = 0;\n @state() private mediaHeight = 0;\n @state() private renderWidth = 0;\n @state() private renderHeight = 0;\n\n @queryAssignedElements({slot: 'media', flatten: true})\n private mediaElements!: HTMLElement[];\n @queryAssignedElements({slot: 'stack', flatten: true})\n private stackElements!: HTMLElement[];\n\n private resizeObserver?: ResizeObserver;\n private layerResizeObserver?: ResizeObserver;\n private syncRaf = 0;\n private handleMediaSlotChange = () => this.setupMediaObservers();\n private handleStackSlotChange = () => {\n this.currentLayer = null;\n this.setupLayerObserver();\n this.scheduleSync();\n };\n private controllerTargets = new Map<string, ObcPoiData>();\n private currentMedia: HTMLVideoElement | HTMLImageElement | null = null;\n private currentLayer: ObcPoiLayer | null = null;\n private mediaHandlers = {\n loadedmetadata: () => {\n if (this.currentMedia) this.updateMediaMetrics(this.currentMedia);\n },\n timeupdate: () => this.requestUpdate(),\n seeked: () => this.requestUpdate(),\n load: () => {\n if (this.currentMedia) this.updateMediaMetrics(this.currentMedia);\n },\n };\n\n override firstUpdated() {\n this.setupMediaObservers();\n const slot = this.shadowRoot?.querySelector('slot[name=\"media\"]');\n slot?.addEventListener('slotchange', this.handleMediaSlotChange);\n const stackSlot = this.shadowRoot?.querySelector('slot[name=\"stack\"]');\n stackSlot?.addEventListener('slotchange', this.handleStackSlotChange);\n }\n\n override updated(changed: PropertyValues) {\n if (\n changed.has('detections') ||\n changed.has('frames') ||\n changed.has('frameIndex') ||\n changed.has('fit') ||\n changed.has('confidenceMin') ||\n changed.has('classFilter') ||\n changed.has('mediaWidth') ||\n changed.has('mediaHeight') ||\n changed.has('renderWidth') ||\n changed.has('renderHeight')\n ) {\n this.scheduleSync();\n }\n }\n\n private scheduleSync() {\n if (this.syncRaf) return;\n this.syncRaf = requestAnimationFrame(() => {\n this.syncRaf = 0;\n this.syncTargetsToCustomStack();\n });\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n if (this.syncRaf) {\n cancelAnimationFrame(this.syncRaf);\n this.syncRaf = 0;\n }\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n this.layerResizeObserver?.disconnect();\n this.layerResizeObserver = undefined;\n this.currentLayer = null;\n this.detachMediaListeners();\n this.controllerTargets.clear();\n const slot = this.shadowRoot?.querySelector('slot[name=\"media\"]');\n slot?.removeEventListener('slotchange', this.handleMediaSlotChange);\n const stackSlot = this.shadowRoot?.querySelector('slot[name=\"stack\"]');\n stackSlot?.removeEventListener('slotchange', this.handleStackSlotChange);\n }\n\n private setupLayerObserver() {\n const layer = this.resolveTargetLayer();\n if (layer === this.currentLayer) return;\n\n this.layerResizeObserver?.disconnect();\n this.layerResizeObserver = undefined;\n this.currentLayer = layer;\n\n if (!layer) return;\n\n this.layerResizeObserver = new ResizeObserver(() => {\n this.scheduleSync();\n });\n this.layerResizeObserver.observe(layer);\n }\n\n private resolveTargetLayer(): ObcPoiLayer | null {\n const stack = this.getStackElement();\n if (!stack) return null;\n\n const explicitLayer = stack.querySelector<ObcPoiLayer>(\n 'obc-poi-layer[data-controller-layer=\"background\"]'\n );\n if (explicitLayer) return explicitLayer;\n\n const layers = Array.from(\n stack.querySelectorAll<ObcPoiLayer>('obc-poi-layer')\n );\n const isSelectedLayer = (candidate: ObcPoiLayer): boolean =>\n candidate.isSelected === true;\n return (\n layers.find((candidate) => !isSelectedLayer(candidate)) ??\n layers[layers.length - 1] ??\n null\n );\n }\n\n private setupMediaObservers() {\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n\n const media = this.getMediaElement();\n if (!media) return;\n\n if (this.currentMedia && this.currentMedia !== media) {\n this.detachMediaListeners();\n }\n this.currentMedia = media;\n\n this.updateMediaMetrics(media);\n\n if (media instanceof HTMLVideoElement) {\n media.addEventListener(\n 'loadedmetadata',\n this.mediaHandlers.loadedmetadata\n );\n media.addEventListener('timeupdate', this.mediaHandlers.timeupdate);\n media.addEventListener('seeked', this.mediaHandlers.seeked);\n } else if (media instanceof HTMLImageElement) {\n if (!media.complete) {\n media.addEventListener('load', this.mediaHandlers.load);\n }\n }\n\n this.resizeObserver = new ResizeObserver(() => {\n this.updateMediaMetrics(media);\n });\n this.resizeObserver.observe(media);\n }\n\n private detachMediaListeners() {\n if (!this.currentMedia) return;\n if (this.currentMedia instanceof HTMLVideoElement) {\n this.currentMedia.removeEventListener(\n 'loadedmetadata',\n this.mediaHandlers.loadedmetadata\n );\n this.currentMedia.removeEventListener(\n 'timeupdate',\n this.mediaHandlers.timeupdate\n );\n this.currentMedia.removeEventListener(\n 'seeked',\n this.mediaHandlers.seeked\n );\n } else if (this.currentMedia instanceof HTMLImageElement) {\n this.currentMedia.removeEventListener('load', this.mediaHandlers.load);\n }\n this.currentMedia = null;\n }\n\n private getMediaElement(): HTMLVideoElement | HTMLImageElement | null {\n const el = this.mediaElements?.[0];\n if (el instanceof HTMLVideoElement || el instanceof HTMLImageElement) {\n return el;\n }\n return null;\n }\n\n private getStackElement(): HTMLElement | null {\n const el = this.stackElements?.[0];\n if (el instanceof HTMLElement) return el;\n return null;\n }\n\n private updateMediaMetrics(media: HTMLVideoElement | HTMLImageElement) {\n const rect = media.getBoundingClientRect();\n this.renderWidth = rect.width;\n this.renderHeight = rect.height;\n\n if (media instanceof HTMLVideoElement) {\n this.mediaWidth = media.videoWidth || this.mediaWidth;\n this.mediaHeight = media.videoHeight || this.mediaHeight;\n } else {\n this.mediaWidth = media.naturalWidth || this.mediaWidth;\n this.mediaHeight = media.naturalHeight || this.mediaHeight;\n }\n }\n\n private getActiveDetections(): PoiDetection[] {\n if (Array.isArray(this.detections)) {\n return this.filterDetections(this.detections);\n }\n if (!Array.isArray(this.frames) || this.frames.length === 0) return [];\n\n const frame = this.pickFrame();\n if (!frame) return [];\n return this.filterDetections(frame.detections ?? []);\n }\n\n private filterDetections(detections: PoiDetection[]) {\n let filtered = detections;\n if (this.confidenceMin !== null && this.confidenceMin !== undefined) {\n filtered = filtered.filter(\n (det) =>\n det.confidence === undefined || det.confidence >= this.confidenceMin!\n );\n }\n if (Array.isArray(this.classFilter) && this.classFilter.length > 0) {\n filtered = filtered.filter(\n (det) =>\n det.class !== undefined && this.classFilter!.includes(det.class)\n );\n }\n return filtered;\n }\n\n private pickFrame(): PoiFrame | null {\n const frames = this.frames ?? [];\n if (frames.length === 0) return null;\n const media = this.getMediaElement();\n\n if (this.frameIndex !== null && this.frameIndex !== undefined) {\n return frames[this.frameIndex] ?? frames[frames.length - 1] ?? null;\n }\n\n if (media instanceof HTMLVideoElement) {\n const time = media.currentTime;\n let best = frames[0] ?? null;\n let bestDelta = Number.POSITIVE_INFINITY;\n for (const frame of frames) {\n if (typeof frame.timestamp !== 'number') continue;\n const delta = Math.abs(frame.timestamp - time);\n if (delta < bestDelta) {\n best = frame;\n bestDelta = delta;\n }\n }\n return best;\n }\n\n return frames[0] ?? null;\n }\n\n private mapDetection(\n det: PoiDetection\n ): {x: number; y: number; scale: number} | null {\n if (\n !Number.isFinite(this.mediaWidth) ||\n !Number.isFinite(this.mediaHeight) ||\n !Number.isFinite(this.renderWidth) ||\n !Number.isFinite(this.renderHeight) ||\n this.mediaWidth === 0 ||\n this.mediaHeight === 0 ||\n this.renderWidth === 0 ||\n this.renderHeight === 0\n ) {\n return null;\n }\n\n const scale =\n this.fit === PoiFitMode.Cover\n ? Math.max(\n this.renderWidth / this.mediaWidth,\n this.renderHeight / this.mediaHeight\n )\n : Math.min(\n this.renderWidth / this.mediaWidth,\n this.renderHeight / this.mediaHeight\n );\n\n const contentWidth = this.mediaWidth * scale;\n const contentHeight = this.mediaHeight * scale;\n const offsetX = (this.renderWidth - contentWidth) / 2;\n const offsetY = (this.renderHeight - contentHeight) / 2;\n\n return {\n x: offsetX + det.x * scale,\n y: offsetY + det.y * scale,\n scale,\n };\n }\n\n private syncTargetsToCustomStack() {\n const clearTargets = () => {\n if (this.controllerTargets.size === 0) {\n return;\n }\n this.controllerTargets.forEach((target) => target.remove());\n this.controllerTargets.clear();\n };\n\n if (!this.currentLayer || !this.currentLayer.isConnected) {\n this.setupLayerObserver();\n }\n const layer = this.currentLayer;\n if (!layer) {\n clearTargets();\n return;\n }\n\n const controllerRect = this.getBoundingClientRect();\n const layerRect = layer.getBoundingClientRect();\n const layerBottomInController = layerRect.bottom - controllerRect.top;\n\n const active = this.getActiveDetections();\n const activeKeys = new Set<string>();\n\n active.forEach((det, index) => {\n const mapped = this.mapDetection(det);\n if (!mapped) return;\n const key =\n det.id ?? (this.keyFn ? this.keyFn(det, index) : `index:${index}`);\n activeKeys.add(key);\n\n let target = this.controllerTargets.get(key);\n if (!target) {\n target = document.createElement('obc-poi-data') as ObcPoiData;\n target.dataset.controller = '1';\n target.dataset.detectionIndex = String(index);\n target.fixedTarget = false;\n this.controllerTargets.set(key, target);\n }\n\n // Append to background layer unless layer-stack moved it elsewhere\n if (!target.isConnected || target.parentElement === null) {\n layer.appendChild(target);\n }\n\n target.dataset.detectionIndex = String(index);\n target.x = mapped.x;\n target.y = Math.max(0, mapped.y - layerBottomInController);\n\n const boxWidth =\n typeof det.box_width === 'number' && Number.isFinite(det.box_width)\n ? det.box_width * mapped.scale\n : null;\n const boxHeight =\n typeof det.box_height === 'number' && Number.isFinite(det.box_height)\n ? det.box_height * mapped.scale\n : null;\n target.boxWidth = boxWidth;\n target.boxHeight = boxHeight;\n target.buttonType = resolvePoiButtonTypeFromBoxSize(boxWidth, boxHeight);\n\n const heading = det.heading ?? det.direction;\n if (typeof heading === 'number' && Number.isFinite(heading)) {\n target.relativeDirection = heading;\n }\n });\n\n Array.from(this.controllerTargets.entries()).forEach(([key, target]) => {\n if (!activeKeys.has(key)) {\n target.remove();\n this.controllerTargets.delete(key);\n }\n });\n }\n\n override render() {\n return html`\n <div class=\"wrapper\">\n <div class=\"media\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"overlay\">\n <slot name=\"stack\"></slot>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-poi-controller': ObcPoiController;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"poi-controller.js","names":[],"sources":["../../../src/ar/poi-controller/poi-controller.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, queryAssignedElements, state} from 'lit/decorators.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './poi-controller.css?inline';\nimport '../poi-layer-stack/poi-layer-stack.js';\nimport {ObcPoiLayer} from '../poi-layer/poi-layer.js';\nimport '../poi/poi-data.js';\nimport '../poi/poi-vessel.js';\nimport '../poi/poi-aton.js';\nimport {\n PoiBase,\n X_FILTER_CUTOFF_HZ,\n Y_FILTER_CUTOFF_HZ,\n} from '../poi/poi-base.js';\nimport {ObcPoiState} from '../poi/poi.js';\nimport {\n ObcPoiButtonDataItem,\n resolvePoiButtonTypeFromBoxSize,\n} from '../poi-button/poi-button.js';\nimport {\n MediaFit,\n computeMediaProjection,\n type MediaProjection,\n projectPoint,\n} from '../poi-projection/poi-projection.js';\n\nexport enum PoiDetectionVariant {\n Data = 'data',\n Vessel = 'vessel',\n Aton = 'aton',\n}\n\nconst DETECTION_VARIANT_TAGS: Record<PoiDetectionVariant, string> = {\n [PoiDetectionVariant.Data]: 'obc-poi-data',\n [PoiDetectionVariant.Vessel]: 'obc-poi-vessel',\n [PoiDetectionVariant.Aton]: 'obc-poi-aton',\n};\n\nexport type PoiDetection = {\n x: number;\n y: number;\n box_width?: number;\n box_height?: number;\n id?: string;\n confidence?: number;\n class?: string;\n class_id?: number;\n heading?: number;\n direction?: number;\n /** POI variant rendered for this detection (default `data`). */\n variant?: PoiDetectionVariant;\n /** Custom-element tag rendered as the POI's icon child (e.g. an `obi-*` icon). */\n icon?: string;\n /** Alert state applied to the target. */\n state?: ObcPoiState;\n /** Data rows shown in the target's expanded button. */\n data?: ObcPoiButtonDataItem[];\n};\n\nexport type PoiKeyFn = (det: PoiDetection, index: number) => string;\n\nexport type PoiFrame = {\n frame?: number;\n timestamp?: number;\n detections: PoiDetection[];\n};\n\nexport enum PoiFitMode {\n Contain = 'contain',\n Cover = 'cover',\n}\n\n/**\n * Attribute consumers set on a child `obc-poi-layer` to tell the\n * controller which layer receives its detection-driven targets.\n */\nexport const POI_CONTROLLER_LAYER_ATTR = 'data-controller-layer';\n\n/** `data-controller-layer` value marking the background/target layer. */\nexport const POI_CONTROLLER_BACKGROUND_LAYER = 'background';\n\n/**\n * `<obc-poi-controller>` — Maps detection data onto POI markers over a video or image.\n *\n * Takes detection coordinates in media pixel space (e.g. x,y in a 1920x1080 frame),\n * projects them to screen space using the media's rendered size and fit mode, and\n * creates/updates POI targets inside a layer stack (`obc-poi-data` by default;\n * `obc-poi-vessel`/`obc-poi-aton` via each detection's `variant`, with optional\n * per-detection `icon`, `state`, and `data`).\n *\n * ## Quick Start\n *\n * The media slot accepts a `<video>` (live stream, HLS, file) or `<img>` element.\n *\n * ```html\n * <obc-poi-controller fit=\"cover\">\n * <video slot=\"media\" src=\"stream.mp4\" autoplay muted></video>\n * <obc-poi-layer-stack slot=\"stack\" selection-mode=\"multi\">\n * <obc-poi-layer is-selected></obc-poi-layer>\n * <obc-poi-layer data-controller-layer=\"background\"></obc-poi-layer>\n * </obc-poi-layer-stack>\n * </obc-poi-controller>\n * ```\n *\n * Then set detections from your data source (WebSocket, API, etc.):\n *\n * ```js\n * const controller = document.querySelector('obc-poi-controller');\n * controller.detections = [\n * { id: 'track-1', x: 400, y: 800, box_width: 50, box_height: 40, heading: -15 },\n * { id: 'track-2', x: 900, y: 750, box_width: 35, box_height: 30, heading: 45 },\n * ];\n * ```\n *\n * ## Framework Usage\n *\n * **Lit:**\n * ```html\n * <obc-poi-controller .detections=${detections} fit=\"cover\">\n * ```\n *\n * **Vue:**\n * ```html\n * <obc-poi-controller :detections=\"detections\" fit=\"cover\">\n * ```\n *\n * **Svelte:**\n * ```html\n * <obc-poi-controller detections={detections} fit=\"cover\">\n * ```\n *\n * **React 18** (needs ref for array props):\n * ```tsx\n * const ref = useRef(null);\n * useEffect(() => { ref.current.detections = detections; }, [detections]);\n * <obc-poi-controller ref={ref} fit=\"cover\">\n * ```\n *\n * **React 19+** (native custom element support):\n * ```tsx\n * <obc-poi-controller detections={detections} fit=\"cover\">\n * ```\n *\n * ## Framework Notes\n *\n * Both paths are safe for declarative renderers (React, Vue, Lit): the\n * `detections` API creates and owns the resulting `obc-poi-data` elements,\n * and manually slotted POI children are never moved, re-parented, or\n * modified structurally by the library — selection is rendered by CSS\n * projection and auto-grouping happens inside the layer's shadow root via\n * slot assignment. Frameworks can manage POI children as ordinary\n * framework-owned elements.\n *\n * ## Coordinate Model\n *\n * Detection `x` and `y` are in **media pixel space** (e.g. 0-1920 for a 1920x1080 video).\n * The controller projects them to screen space using the `fit` mode (`contain` or `cover`)\n * and the media element's rendered dimensions.\n *\n * The Y coordinate maps to the line length from the layer's top edge down to the\n * detection point. The button sits at the top of the layer; the line extends downward.\n *\n * ## Detection Data\n *\n * Each detection can include:\n * - `x`, `y` (required) — position in media pixel space\n * - `id` — stable identity key (prevents marker churn when array order changes)\n * - `box_width`, `box_height` — bounding box size; determines button type (regular vs enhanced)\n * - `heading` or `direction` — rotation angle for the icon arrow (degrees)\n * - `confidence` — filtered by `confidenceMin`\n * - `class` — filtered by `classFilter`\n *\n * ## Layer Setup\n *\n * The stack needs at least two layers:\n * 1. A **selected layer** (`is-selected`) — targets jump here when clicked\n * 2. A **background layer** (`data-controller-layer=\"background\"`) — where the controller places targets\n *\n * If no `data-controller-layer=\"background\"` is set, the controller uses the first non-selected layer.\n *\n * ## Selection\n *\n * Clicking a target moves it to the selected layer with a FLIP animation.\n * The controller does not interfere with selected targets — it only manages\n * targets in the background layer. The layer-stack owns selection state.\n *\n * ## CSS Custom Properties\n *\n * - `--obc-poi-controller-stack-top` (default `15%`) — vertical position of the stack\n * - `--obc-poi-controller-stack-height` (default `50%`) — height of the stack\n * - `--obc-poi-controller-stack-gap` (default `8px`) — gap between layers\n *\n * @property xFilterCutoffHz - Forwarded to every controller-owned target's `xFilterCutoffHz`; `null` leaves the targets on their default.\n * @property yFilterCutoffHz - Forwarded to every controller-owned target's `yFilterCutoffHz`; `null` leaves the targets on their default.\n * @slot media - Video or image element. Sets the projection source dimensions.\n * @slot stack - `obc-poi-layer-stack` containing the layers for target placement.\n * @experimental\n */\n@customElement('obc-poi-controller')\nexport class ObcPoiController extends LitElement {\n @property({type: String}) fit: PoiFitMode = PoiFitMode.Contain;\n @property({type: Array}) frames: PoiFrame[] | null = null;\n @property({type: Array}) detections: PoiDetection[] | null = null;\n @property({type: Number}) frameIndex: number | null = null;\n @property({type: Number}) confidenceMin: number | null = null;\n @property({type: Array}) classFilter: string[] | null = null;\n @property({attribute: false})\n keyFn: PoiKeyFn | null = null;\n @property({type: Number, attribute: 'x-filter-cutoff-hz'})\n xFilterCutoffHz: number | null = null;\n @property({type: Number, attribute: 'y-filter-cutoff-hz'})\n yFilterCutoffHz: number | null = null;\n\n @state() private mediaWidth = 0;\n @state() private mediaHeight = 0;\n @state() private renderWidth = 0;\n @state() private renderHeight = 0;\n\n @queryAssignedElements({slot: 'media', flatten: true})\n private mediaElements!: HTMLElement[];\n @queryAssignedElements({slot: 'stack', flatten: true})\n private stackElements!: HTMLElement[];\n\n private resizeObserver?: ResizeObserver;\n private layerResizeObserver?: ResizeObserver;\n private syncRaf = 0;\n private handleMediaSlotChange = () => this.setupMediaObservers();\n private handleStackSlotChange = () => {\n this.currentLayer = null;\n this.setupLayerObserver();\n this.scheduleSync();\n };\n private controllerTargets = new Map<string, PoiBase>();\n private currentMedia: HTMLVideoElement | HTMLImageElement | null = null;\n private currentLayer: ObcPoiLayer | null = null;\n private mediaHandlers = {\n loadedmetadata: () => {\n if (this.currentMedia) this.updateMediaMetrics(this.currentMedia);\n },\n timeupdate: () => this.requestUpdate(),\n seeked: () => this.requestUpdate(),\n load: () => {\n if (this.currentMedia) this.updateMediaMetrics(this.currentMedia);\n },\n };\n\n override firstUpdated() {\n this.setupMediaObservers();\n const slot = this.shadowRoot?.querySelector('slot[name=\"media\"]');\n slot?.addEventListener('slotchange', this.handleMediaSlotChange);\n const stackSlot = this.shadowRoot?.querySelector('slot[name=\"stack\"]');\n stackSlot?.addEventListener('slotchange', this.handleStackSlotChange);\n }\n\n override updated(changed: PropertyValues) {\n if (\n changed.has('detections') ||\n changed.has('frames') ||\n changed.has('frameIndex') ||\n changed.has('fit') ||\n changed.has('confidenceMin') ||\n changed.has('classFilter') ||\n changed.has('mediaWidth') ||\n changed.has('mediaHeight') ||\n changed.has('renderWidth') ||\n changed.has('renderHeight')\n ) {\n this.scheduleSync();\n }\n }\n\n private scheduleSync() {\n if (this.syncRaf) return;\n this.syncRaf = requestAnimationFrame(() => {\n this.syncRaf = 0;\n this.syncTargetsToCustomStack();\n });\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n if (this.syncRaf) {\n cancelAnimationFrame(this.syncRaf);\n this.syncRaf = 0;\n }\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n this.layerResizeObserver?.disconnect();\n this.layerResizeObserver = undefined;\n this.currentLayer = null;\n this.detachMediaListeners();\n this.controllerTargets.clear();\n const slot = this.shadowRoot?.querySelector('slot[name=\"media\"]');\n slot?.removeEventListener('slotchange', this.handleMediaSlotChange);\n const stackSlot = this.shadowRoot?.querySelector('slot[name=\"stack\"]');\n stackSlot?.removeEventListener('slotchange', this.handleStackSlotChange);\n }\n\n private setupLayerObserver() {\n const layer = this.resolveTargetLayer();\n if (layer === this.currentLayer) return;\n\n this.layerResizeObserver?.disconnect();\n this.layerResizeObserver = undefined;\n this.currentLayer = layer;\n\n if (!layer) return;\n\n this.layerResizeObserver = new ResizeObserver(() => {\n this.scheduleSync();\n });\n this.layerResizeObserver.observe(layer);\n }\n\n private resolveTargetLayer(): ObcPoiLayer | null {\n const stack = this.getStackElement();\n if (!stack) return null;\n\n const explicitLayer = stack.querySelector<ObcPoiLayer>(\n `obc-poi-layer[${POI_CONTROLLER_LAYER_ATTR}=\"${POI_CONTROLLER_BACKGROUND_LAYER}\"]`\n );\n if (explicitLayer) return explicitLayer;\n\n const layers = Array.from(\n stack.querySelectorAll<ObcPoiLayer>('obc-poi-layer')\n );\n const isSelectedLayer = (candidate: ObcPoiLayer): boolean =>\n candidate.isSelected === true;\n return (\n layers.find((candidate) => !isSelectedLayer(candidate)) ??\n layers[layers.length - 1] ??\n null\n );\n }\n\n private setupMediaObservers() {\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n\n const media = this.getMediaElement();\n if (!media) return;\n\n if (this.currentMedia && this.currentMedia !== media) {\n this.detachMediaListeners();\n }\n this.currentMedia = media;\n\n this.updateMediaMetrics(media);\n\n if (media instanceof HTMLVideoElement) {\n media.addEventListener(\n 'loadedmetadata',\n this.mediaHandlers.loadedmetadata\n );\n media.addEventListener('timeupdate', this.mediaHandlers.timeupdate);\n media.addEventListener('seeked', this.mediaHandlers.seeked);\n } else if (media instanceof HTMLImageElement) {\n if (!media.complete) {\n media.addEventListener('load', this.mediaHandlers.load);\n }\n }\n\n this.resizeObserver = new ResizeObserver(() => {\n this.updateMediaMetrics(media);\n });\n this.resizeObserver.observe(media);\n }\n\n private detachMediaListeners() {\n if (!this.currentMedia) return;\n if (this.currentMedia instanceof HTMLVideoElement) {\n this.currentMedia.removeEventListener(\n 'loadedmetadata',\n this.mediaHandlers.loadedmetadata\n );\n this.currentMedia.removeEventListener(\n 'timeupdate',\n this.mediaHandlers.timeupdate\n );\n this.currentMedia.removeEventListener(\n 'seeked',\n this.mediaHandlers.seeked\n );\n } else if (this.currentMedia instanceof HTMLImageElement) {\n this.currentMedia.removeEventListener('load', this.mediaHandlers.load);\n }\n this.currentMedia = null;\n }\n\n private getMediaElement(): HTMLVideoElement | HTMLImageElement | null {\n const el = this.mediaElements?.[0];\n if (el instanceof HTMLVideoElement || el instanceof HTMLImageElement) {\n return el;\n }\n return null;\n }\n\n private getStackElement(): HTMLElement | null {\n const el = this.stackElements?.[0];\n if (el instanceof HTMLElement) return el;\n return null;\n }\n\n private updateMediaMetrics(media: HTMLVideoElement | HTMLImageElement) {\n const rect = media.getBoundingClientRect();\n this.renderWidth = rect.width;\n this.renderHeight = rect.height;\n\n if (media instanceof HTMLVideoElement) {\n this.mediaWidth = media.videoWidth || this.mediaWidth;\n this.mediaHeight = media.videoHeight || this.mediaHeight;\n } else {\n this.mediaWidth = media.naturalWidth || this.mediaWidth;\n this.mediaHeight = media.naturalHeight || this.mediaHeight;\n }\n }\n\n private getActiveDetections(): PoiDetection[] {\n if (Array.isArray(this.detections)) {\n return this.filterDetections(this.detections);\n }\n if (!Array.isArray(this.frames) || this.frames.length === 0) return [];\n\n const frame = this.pickFrame();\n if (!frame) return [];\n return this.filterDetections(frame.detections ?? []);\n }\n\n private filterDetections(detections: PoiDetection[]) {\n let filtered = detections;\n if (this.confidenceMin !== null && this.confidenceMin !== undefined) {\n filtered = filtered.filter(\n (det) =>\n det.confidence === undefined || det.confidence >= this.confidenceMin!\n );\n }\n if (Array.isArray(this.classFilter) && this.classFilter.length > 0) {\n filtered = filtered.filter(\n (det) =>\n det.class !== undefined && this.classFilter!.includes(det.class)\n );\n }\n return filtered;\n }\n\n private pickFrame(): PoiFrame | null {\n const frames = this.frames ?? [];\n if (frames.length === 0) return null;\n const media = this.getMediaElement();\n\n if (this.frameIndex !== null && this.frameIndex !== undefined) {\n return frames[this.frameIndex] ?? frames[frames.length - 1] ?? null;\n }\n\n if (media instanceof HTMLVideoElement) {\n const time = media.currentTime;\n let best = frames[0] ?? null;\n let bestDelta = Number.POSITIVE_INFINITY;\n for (const frame of frames) {\n if (typeof frame.timestamp !== 'number') continue;\n const delta = Math.abs(frame.timestamp - time);\n if (delta < bestDelta) {\n best = frame;\n bestDelta = delta;\n }\n }\n return best;\n }\n\n return frames[0] ?? null;\n }\n\n private computeCurrentProjection(): MediaProjection | null {\n return computeMediaProjection({\n mediaWidth: this.mediaWidth,\n mediaHeight: this.mediaHeight,\n renderWidth: this.renderWidth,\n renderHeight: this.renderHeight,\n fit: this.fit === PoiFitMode.Cover ? MediaFit.Cover : MediaFit.Contain,\n });\n }\n\n private mapDetection(\n det: PoiDetection,\n projection: MediaProjection | null = this.computeCurrentProjection()\n ): {x: number; y: number; scale: number} | null {\n if (!projection) return null;\n\n const point = projectPoint(projection, det.x, det.y);\n return {x: point.x, y: point.y, scale: projection.scale};\n }\n\n private syncTargetsToCustomStack() {\n const clearTargets = () => {\n if (this.controllerTargets.size === 0) {\n return;\n }\n this.controllerTargets.forEach((target) => target.remove());\n this.controllerTargets.clear();\n };\n\n if (!this.currentLayer || !this.currentLayer.isConnected) {\n this.setupLayerObserver();\n }\n const layer = this.currentLayer;\n if (!layer) {\n clearTargets();\n return;\n }\n\n const controllerRect = this.getBoundingClientRect();\n const layerRect = layer.getBoundingClientRect();\n const layerBottomInController = layerRect.bottom - controllerRect.top;\n\n const active = this.getActiveDetections();\n const activeKeys = new Set<string>();\n const projection = this.computeCurrentProjection();\n\n active.forEach((det, index) => {\n const mapped = this.mapDetection(det, projection);\n if (!mapped) return;\n const key =\n det.id ?? (this.keyFn ? this.keyFn(det, index) : `index:${index}`);\n activeKeys.add(key);\n\n const variant = det.variant ?? PoiDetectionVariant.Data;\n const tag = DETECTION_VARIANT_TAGS[variant];\n\n let target = this.controllerTargets.get(key);\n if (target && target.tagName.toLowerCase() !== tag) {\n target.remove();\n this.controllerTargets.delete(key);\n target = undefined;\n }\n if (!target) {\n target = document.createElement(tag) as PoiBase;\n target.dataset.controller = '1';\n target.dataset.detectionIndex = String(index);\n target.fixedTarget = false;\n this.controllerTargets.set(key, target);\n }\n\n const iconTag = det.icon?.toLowerCase() ?? null;\n const currentIcon = target.firstElementChild;\n if (iconTag) {\n if (currentIcon?.tagName.toLowerCase() !== iconTag) {\n currentIcon?.remove();\n target.appendChild(document.createElement(iconTag));\n }\n } else if (currentIcon) {\n currentIcon.remove();\n }\n\n // Append to background layer unless layer-stack moved it elsewhere\n if (!target.isConnected || target.parentElement === null) {\n layer.appendChild(target);\n }\n\n target.dataset.detectionIndex = String(index);\n target.x = mapped.x;\n target.y = Math.max(0, mapped.y - layerBottomInController);\n\n const boxWidth =\n typeof det.box_width === 'number' && Number.isFinite(det.box_width)\n ? det.box_width * mapped.scale\n : null;\n const boxHeight =\n typeof det.box_height === 'number' && Number.isFinite(det.box_height)\n ? det.box_height * mapped.scale\n : null;\n target.boxWidth = boxWidth;\n target.boxHeight = boxHeight;\n target.buttonType = resolvePoiButtonTypeFromBoxSize(boxWidth, boxHeight);\n\n const heading = det.heading ?? det.direction;\n if (typeof heading === 'number' && Number.isFinite(heading)) {\n target.relativeDirection = heading;\n }\n\n target.state = det.state ?? ObcPoiState.Enabled;\n target.data = det.data ?? [];\n target.xFilterCutoffHz = this.xFilterCutoffHz ?? X_FILTER_CUTOFF_HZ;\n target.yFilterCutoffHz = this.yFilterCutoffHz ?? Y_FILTER_CUTOFF_HZ;\n });\n\n Array.from(this.controllerTargets.entries()).forEach(([key, target]) => {\n if (!activeKeys.has(key)) {\n target.remove();\n this.controllerTargets.delete(key);\n }\n });\n }\n\n override render() {\n return html`\n <div class=\"wrapper\">\n <div class=\"media\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"overlay\">\n <slot name=\"stack\"></slot>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-poi-controller': ObcPoiController;\n }\n}\n"],"mappings":"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"}
@@ -15,14 +15,14 @@ export type ExpandEvent = CustomEvent<{
15
15
  * - Front-target handling: Keeps one front target visually prioritized while collapsing other targets into overlap state.
16
16
  * - Backdrop interaction: Shows a backdrop while expanded and collapses on backdrop click.
17
17
  * - Dynamic ordering: `internalSwapping` enables reordering while expanded based on current horizontal positions.
18
- * - Vertical placement: `positionVertical` sets the wrapper/group top offset used for collapsed positioning.
18
+ * - Vertical placement: `positionVertical` (attribute `position-vertical`) sets the wrapper/group top offset used for collapsed positioning.
19
19
  *
20
20
  * ### Usage Guidelines
21
21
  * - Slot only `obc-poi-data` items that should behave as one grouped target set.
22
22
  * - Control expand/collapse via the `expand` property, or let the built-in wrapper button toggle expansion.
23
23
  * - Use the `expand` event detail to synchronize nearby standalone targets (for example, set outside targets to overlapped while this group is open).
24
- * - Treat `collapsing` as component-managed runtime state unless you have a specific orchestration need.
25
- * - **TODO(designer):** Confirm whether external consumers should set `collapsing` directly, or if it should remain fully internal.
24
+ * - Treat `collapsing` as orchestration state: it is set by the group itself and by coordinating containers such as `obc-poi-layer-stack` during collapse animations. Do not set it directly.
25
+ * - `internalSwapping` is usually set via `obc-poi-layer`'s `internal-swapping` attribute, which forwards it to auto-created groups; set it directly only on manually managed groups.
26
26
  *
27
27
  * ### Slots
28
28
  * | Slot | Renders When... | Purpose |
@@ -32,6 +32,7 @@ export type ExpandEvent = CustomEvent<{
32
32
  * ### Events
33
33
  * - `expand` - Fired when expand state changes. Detail: `{ expand: boolean }`.
34
34
  * - `collapse-finished` - Fired when the collapse animation has fully completed.
35
+ * - `obc-poi-group-target-released` - Fired after `releaseTarget()` returns a target to the group's parent context: re-parented for consumer-managed groups, re-assigned to the layer's main slot for layer-created auto groups. Detail: `{ target: Poi }`.
35
36
  *
36
37
  * ### Best Practices
37
38
  * - Keep grouped targets positioned consistently so wrapper bounds and front-target selection remain stable.
@@ -40,23 +41,31 @@ export type ExpandEvent = CustomEvent<{
40
41
  *
41
42
  * ### Example
42
43
  * ```html
43
- * <obc-poi-group positionVertical="240px">
44
+ * <obc-poi-group position-vertical="240px">
44
45
  * <obc-poi-data x="300" button-y="240" y="240"></obc-poi-data>
45
46
  * <obc-poi-data x="320" button-y="240" y="240"></obc-poi-data>
46
47
  * <obc-poi-data x="340" button-y="240" y="240"></obc-poi-data>
47
48
  * </obc-poi-group>
48
49
  * ```
49
50
  *
51
+ * @property collapsing - Collapse-animation state. Set by the group itself and by coordinating
52
+ * containers such as `obc-poi-layer-stack` during collapse orchestration;
53
+ * do not set it directly.
54
+ * @property internalSwapping - Reorders expanded targets when their horizontal positions cross. Usually
55
+ * set via `obc-poi-layer`'s `internal-swapping` attribute, which forwards it
56
+ * to auto-created groups; set it directly only on manually managed groups.
50
57
  * @slot - Default slot for grouped `obc-poi-data` targets.
51
58
  * @fires {CustomEvent<{expand:boolean}>} expand - Fired when the group expand state changes.
52
59
  * @fires {CustomEvent<void>} collapse-finished - Fired after collapse animation completes.
53
- * @fires {CustomEvent<{target: Poi}>} obc-poi-group-target-released - Fired after a target leaves the group and has been re-inserted before it in the parent. Bubbles and is composed.
60
+ * @fires {CustomEvent<{target: Poi}>} obc-poi-group-target-released - Fired after `releaseTarget()` returns a target to the group's parent context (re-parented for consumer-managed groups, re-assigned for auto groups) — immediately when the group is collapsed, or once the collapse animation completes. Bubbles and is composed.
54
61
  * @experimental
55
62
  */
56
63
  export declare class ObcPoiGroup extends LitElement {
57
64
  expand: boolean;
65
+ /** Collapse-animation state. Set by the group itself and by coordinating containers such as `obc-poi-layer-stack` during collapse orchestration; do not set it directly. */
58
66
  collapsing: boolean;
59
67
  positionVertical: string;
68
+ /** Reorders expanded targets when their horizontal positions cross. Usually set via `obc-poi-layer`'s `internal-swapping` attribute, which forwards it to auto-created groups; set it directly only on manually managed groups. */
60
69
  internalSwapping: boolean;
61
70
  private wrapperOffsetX;
62
71
  private wrapperWidth;
@@ -83,6 +92,20 @@ export declare class ObcPoiGroup extends LitElement {
83
92
  render(): import('lit-html').TemplateResult<1>;
84
93
  updatePosition(): void;
85
94
  private onSlotChange;
95
+ /**
96
+ * Membership check that works for both light-DOM children (manual groups)
97
+ * and slot-assigned members (layer-created auto groups, where the member
98
+ * stays in the consumer's light DOM and is assigned into this group's
99
+ * member slot).
100
+ */
101
+ private isMember;
102
+ private getMemberSlot;
103
+ /**
104
+ * Paint the front child on top. For light-DOM members this reorders the
105
+ * children; for slot-assigned members it re-assigns the member slot, which
106
+ * changes flattened-tree order without touching the consumer's DOM.
107
+ */
108
+ private bringChildToFront;
86
109
  private ensureFrontChildOnTop;
87
110
  onClick(): void;
88
111
  releaseTarget(target: Poi): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"poi-group.d.ts","sourceRoot":"","sources":["../../../src/ar/poi-group/poi-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAkB,MAAM,KAAK,CAAC;AAKhE,OAAO,EAAC,GAAG,EAAQ,MAAM,eAAe,CAAC;AAoBzC,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC,CAAC,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBACa,WAAY,SAAQ,UAAU;IACd,MAAM,UAAS;IACf,UAAU,UAAS;IACpB,gBAAgB,SAAS;IAEnD,gBAAgB,UAAS;IAChB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,gBAAgB,CAAS;IAG1C,SAAS,EAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAE/B,OAAO,CAAC,mBAAmB,CAAa;IACxC,OAAO,CAAC,yBAAyB,CAA0B;IAC3D,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,gBAAgB,CAQV;IACd,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,wBAAwB,CAAsB;IACtD,OAAO,CAAC,qBAAqB,CAIb;;IAOP,YAAY,CAAC,kBAAkB,EAAE,cAAc;IAW/C,iBAAiB;IAKjB,oBAAoB;IAkBpB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAWzC,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAYrD,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAK1B,MAAM;IA6Bf,cAAc,IAAI,IAAI;IAuDtB,OAAO,CAAC,YAAY,CAYlB;IAEF,OAAO,CAAC,qBAAqB;IAO7B,OAAO,IAAI,IAAI;IAQR,aAAa,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IA+BnD,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IA4B1C,OAAO,CAAC,yBAAyB;IAiDjC,OAAO,CAAC,qBAAqB,CAA8C;IAE3E,qBAAqB,CAAC,cAAc,UAAQ,GAAG,IAAI;IAOnD,OAAO,CAAC,gBAAgB;IA6DxB,OAAO,CAAC,qBAAqB;IAoD7B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,aAAa;IAuCrB,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,kBAAkB,CAAgD;IAC1E,OAAO,CAAC,eAAe,CAAa;IAEpC,OAAO,CAAC,qBAAqB;IAoG7B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,uBAAuB;IA0B/B,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,qBAAqB;IAmD7B,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,WAAW,CAAC;KAC9B;CACF"}
1
+ {"version":3,"file":"poi-group.d.ts","sourceRoot":"","sources":["../../../src/ar/poi-group/poi-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAkB,MAAM,KAAK,CAAC;AAKhE,OAAO,EAAC,GAAG,EAAQ,MAAM,eAAe,CAAC;AAoBzC,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC,CAAC,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,qBACa,WAAY,SAAQ,UAAU;IACd,MAAM,UAAS;IACf,UAAU,UAAS;IAE9C,gBAAgB,SAAS;IAEzB,gBAAgB,UAAS;IAChB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,gBAAgB,CAAS;IAG1C,SAAS,EAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAE/B,OAAO,CAAC,mBAAmB,CAAa;IACxC,OAAO,CAAC,yBAAyB,CAA0B;IAC3D,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,gBAAgB,CAQV;IACd,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,wBAAwB,CAAsB;IACtD,OAAO,CAAC,qBAAqB,CAIb;;IAOP,YAAY,CAAC,kBAAkB,EAAE,cAAc;IAW/C,iBAAiB;IAKjB,oBAAoB;IAkBpB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAWzC,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAYrD,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAK1B,MAAM;IA6Bf,cAAc,IAAI,IAAI;IAuDtB,OAAO,CAAC,YAAY,CAYlB;IAEF;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,aAAa;IAMrB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,qBAAqB;IAO7B,OAAO,IAAI,IAAI;IAQR,aAAa,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IA+BnD,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IA4B1C,OAAO,CAAC,yBAAyB;IAiDjC,OAAO,CAAC,qBAAqB,CAA8C;IAE3E,qBAAqB,CAAC,cAAc,UAAQ,GAAG,IAAI;IAOnD,OAAO,CAAC,gBAAgB;IA6DxB,OAAO,CAAC,qBAAqB;IAoD7B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,aAAa;IAuCrB,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,kBAAkB,CAAgD;IAC1E,OAAO,CAAC,eAAe,CAAa;IAEpC,OAAO,CAAC,qBAAqB;IAoG7B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,uBAAuB;IA0B/B,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,qBAAqB;IA+E7B,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,WAAW,CAAC;KAC9B;CACF"}
@@ -151,9 +151,36 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
151
151
  this.wrapperHasValues = false;
152
152
  }
153
153
  }
154
+ /**
155
+ * Membership check that works for both light-DOM children (manual groups)
156
+ * and slot-assigned members (layer-created auto groups, where the member
157
+ * stays in the consumer's light DOM and is assigned into this group's
158
+ * member slot).
159
+ */
160
+ isMember(child) {
161
+ return child.parentElement === this || child.assignedSlot?.parentElement === this;
162
+ }
163
+ getMemberSlot() {
164
+ return this.querySelector(":scope > slot.auto-group-members");
165
+ }
166
+ /**
167
+ * Paint the front child on top. For light-DOM members this reorders the
168
+ * children; for slot-assigned members it re-assigns the member slot, which
169
+ * changes flattened-tree order without touching the consumer's DOM.
170
+ */
171
+ bringChildToFront(frontChild) {
172
+ const memberSlot = this.getMemberSlot();
173
+ if (memberSlot && frontChild.assignedSlot === memberSlot) {
174
+ const members = memberSlot.assignedElements();
175
+ if (members[members.length - 1] === frontChild) return;
176
+ memberSlot.assign(...members.filter((el) => el !== frontChild), frontChild);
177
+ return;
178
+ }
179
+ if (frontChild.parentElement === this) this.appendChild(frontChild);
180
+ }
154
181
  ensureFrontChildOnTop() {
155
182
  const frontChild = this.getFrontChild();
156
- if (frontChild && this.lastElementChild !== frontChild) this.appendChild(frontChild);
183
+ if (frontChild && this.lastElementChild !== frontChild) this.bringChildToFront(frontChild);
157
184
  }
158
185
  onClick() {
159
186
  if (this.expand) return;
@@ -162,7 +189,7 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
162
189
  this.expand = true;
163
190
  }
164
191
  releaseTarget(target) {
165
- if (target.parentElement !== this) return Promise.resolve(false);
192
+ if (!this.isMember(target)) return Promise.resolve(false);
166
193
  if (this.pendingReleasedTarget) {
167
194
  if (this.pendingReleasedTarget.target === target) return this.pendingReleasedTarget.promise;
168
195
  return Promise.resolve(false);
@@ -195,7 +222,7 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
195
222
  if (this.topOffsetProgress > 0) this.wrapperVisible = false;
196
223
  this.lockedExpandedCenter = null;
197
224
  }
198
- if (!expand && frontChild) this.appendChild(frontChild);
225
+ if (!expand && frontChild) this.bringChildToFront(frontChild);
199
226
  this.animateTopOffset(expand ? 1 : 0);
200
227
  }
201
228
  calculateTopOffsetTargets(preserveCenter = false) {
@@ -310,7 +337,7 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
310
337
  const visualExpanded = this.collapsing ? false : progress > .5;
311
338
  const touchAreaExpanded = progress > .5;
312
339
  this.topOffsetTargets.forEach((config, child) => {
313
- if (child.parentElement !== this) {
340
+ if (!this.isMember(child)) {
314
341
  this.topOffsetTargets.delete(child);
315
342
  this.collapseDeltas.delete(child);
316
343
  this.lastAppliedOffsets.delete(child);
@@ -438,7 +465,7 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
438
465
  }
439
466
  this.lastTargetOrder = orderedTargets;
440
467
  targets.forEach((child) => {
441
- if (child.parentElement !== this) {
468
+ if (!this.isMember(child)) {
442
469
  this.topOffsetTargets.delete(child);
443
470
  this.lastAppliedOffsets.delete(child);
444
471
  return;
@@ -496,7 +523,7 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
496
523
  pending.resolve(released);
497
524
  }
498
525
  releaseTargetToParent(target) {
499
- if (target.parentElement !== this) return false;
526
+ if (!this.isMember(target)) return false;
500
527
  target.setRuntimeHorizontalOffsets?.(0, 0);
501
528
  if (!target.setRuntimeHorizontalOffsets) {
502
529
  target.buttonOffsetX = 0;
@@ -518,6 +545,19 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
518
545
  target.style.removeProperty("--obc-poi-group-overlap-height");
519
546
  target.style.removeProperty("--obc-poi-group-overlap-shift");
520
547
  clearPoiVisualState(target);
548
+ const memberSlot = this.getMemberSlot();
549
+ if (memberSlot && target.assignedSlot === memberSlot) {
550
+ memberSlot.assign(...memberSlot.assignedElements().filter((el) => el !== target));
551
+ const root = this.getRootNode();
552
+ (root instanceof ShadowRoot ? root.host : null)?.releaseAssignedTarget?.(target);
553
+ this.updatePosition();
554
+ this.dispatchEvent(new CustomEvent("obc-poi-group-target-released", {
555
+ detail: { target },
556
+ bubbles: true,
557
+ composed: true
558
+ }));
559
+ return true;
560
+ }
521
561
  const parent = this.parentElement;
522
562
  if (!parent) return false;
523
563
  parent.insertBefore(target, this);
@@ -536,7 +576,10 @@ var ObcPoiGroup = class ObcPoiGroup extends LitElement {
536
576
  };
537
577
  __decorate([property({ type: Boolean })], ObcPoiGroup.prototype, "expand", void 0);
538
578
  __decorate([property({ type: Boolean })], ObcPoiGroup.prototype, "collapsing", void 0);
539
- __decorate([property({ type: String })], ObcPoiGroup.prototype, "positionVertical", void 0);
579
+ __decorate([property({
580
+ type: String,
581
+ attribute: "position-vertical"
582
+ })], ObcPoiGroup.prototype, "positionVertical", void 0);
540
583
  __decorate([property({
541
584
  type: Boolean,
542
585
  attribute: "internal-swapping"
@@ -1 +1 @@
1
- {"version":3,"file":"poi-group.js","names":[],"sources":["../../../src/ar/poi-group/poi-group.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, queryAssignedElements, state} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport componentStyle from './poi-group.css?inline';\nimport {PoiDataValue, PoiDataVisualRectPreference} from '../poi/poi-data.js';\nimport {Poi, isPoi} from '../poi/poi.js';\nimport {ObcPoiButtonType} from '../poi-button/poi-button.js';\nimport {customElement} from '../../decorator.js';\nimport {AnimationManager, easeInOutQuad, frameLerp} from './animation-utils.js';\nimport {getEffectivePoiX} from '../poi/poi-position.js';\nimport {\n getCssVarAsNumber,\n getTouchTargetSize,\n getVisualTargetSize,\n} from '../poi/poi-css-vars.js';\nimport {\n applyPoiVisualState,\n clearPoiVisualState,\n} from '../poi/poi-visual-state.js';\n\nconst POI_GROUP_SPACING_VAR = '--obc-poi-group-expanded-spacing';\nconst TOP_OFFSET_ANIMATION_MS_VAR = '--obc-poi-group-top-offset-animation-ms';\nconst TOP_OFFSET_ANIMATION_DELAY_MS_VAR =\n '--obc-poi-group-top-offset-animation-delay-ms';\n\nexport type ExpandEvent = CustomEvent<{expand: boolean}>;\n\n/**\n * `<obc-poi-group>` - A POI cluster component that collapses overlapping targets into one trigger and expands them into a spread list.\n *\n * This component wraps multiple `obc-poi-data` elements and manages their collapsed/expanded presentation as a single interactive unit.\n * Use it when nearby targets should be presented as one grouped control until the user expands the group.\n *\n * ### Features\n * - Expand/collapse state: Controlled by `expand`; collapse animation state is exposed through `collapsing`.\n * - Automatic wrapper sizing: Computes collapsed wrapper width/height from slotted target button bounds.\n * - Front-target handling: Keeps one front target visually prioritized while collapsing other targets into overlap state.\n * - Backdrop interaction: Shows a backdrop while expanded and collapses on backdrop click.\n * - Dynamic ordering: `internalSwapping` enables reordering while expanded based on current horizontal positions.\n * - Vertical placement: `positionVertical` sets the wrapper/group top offset used for collapsed positioning.\n *\n * ### Usage Guidelines\n * - Slot only `obc-poi-data` items that should behave as one grouped target set.\n * - Control expand/collapse via the `expand` property, or let the built-in wrapper button toggle expansion.\n * - Use the `expand` event detail to synchronize nearby standalone targets (for example, set outside targets to overlapped while this group is open).\n * - Treat `collapsing` as component-managed runtime state unless you have a specific orchestration need.\n * - **TODO(designer):** Confirm whether external consumers should set `collapsing` directly, or if it should remain fully internal.\n *\n * ### Slots\n * | Slot | Renders When... | Purpose |\n * | --- | --- | --- |\n * | default | Always | Contains grouped `obc-poi-data` targets managed by this component. |\n *\n * ### Events\n * - `expand` - Fired when expand state changes. Detail: `{ expand: boolean }`.\n * - `collapse-finished` - Fired when the collapse animation has fully completed.\n *\n * ### Best Practices\n * - Keep grouped targets positioned consistently so wrapper bounds and front-target selection remain stable.\n * - Prefer one `obc-poi-group` per overlap cluster rather than nesting groups.\n * - Use `internalSwapping` only when live target crossing should reorder expanded items.\n *\n * ### Example\n * ```html\n * <obc-poi-group positionVertical=\"240px\">\n * <obc-poi-data x=\"300\" button-y=\"240\" y=\"240\"></obc-poi-data>\n * <obc-poi-data x=\"320\" button-y=\"240\" y=\"240\"></obc-poi-data>\n * <obc-poi-data x=\"340\" button-y=\"240\" y=\"240\"></obc-poi-data>\n * </obc-poi-group>\n * ```\n *\n * @slot - Default slot for grouped `obc-poi-data` targets.\n * @fires {CustomEvent<{expand:boolean}>} expand - Fired when the group expand state changes.\n * @fires {CustomEvent<void>} collapse-finished - Fired after collapse animation completes.\n * @fires {CustomEvent<{target: Poi}>} obc-poi-group-target-released - Fired after a target leaves the group and has been re-inserted before it in the parent. Bubbles and is composed.\n * @experimental\n */\n@customElement('obc-poi-group')\nexport class ObcPoiGroup extends LitElement {\n @property({type: Boolean}) expand = false;\n @property({type: Boolean}) collapsing = false;\n @property({type: String}) positionVertical = '0px';\n @property({type: Boolean, attribute: 'internal-swapping'})\n internalSwapping = false;\n @state() private wrapperOffsetX = '0px';\n @state() private wrapperWidth = '48px';\n @state() private wrapperVisible = false;\n @state() private wrapperHeight = '48px';\n @state() private wrapperHasValues = false;\n\n @queryAssignedElements({flatten: true})\n _children!: Array<HTMLElement>;\n\n private boundUpdatePosition: () => void;\n private topOffsetAnimationManager = new AnimationManager();\n private topOffsetProgress = 0;\n private slotChangeRaf = 0;\n private topOffsetTargets: Map<\n Poi,\n {\n originalX: number;\n expandedOffset: number;\n currentExpandedOffset: number;\n originalLeft: number;\n }\n > = new Map();\n private lockedExpandedCenter: number | null = null;\n private collapseDeltas: Map<Poi, number> = new Map();\n private topOffsetAnimationTarget: 0 | 1 | null = null;\n private pendingReleasedTarget: {\n target: Poi;\n promise: Promise<boolean>;\n resolve: (released: boolean) => void;\n } | null = null;\n\n constructor() {\n super();\n this.boundUpdatePosition = this.updatePosition.bind(this);\n }\n\n override firstUpdated(_changedProperties: PropertyValues) {\n super.firstUpdated(_changedProperties);\n this.updatePosition();\n this.syncFrontChild();\n const slot = this.shadowRoot?.querySelector('slot');\n slot?.addEventListener('slotchange', this.onSlotChange);\n if (!this.expand) {\n this.wrapperVisible = true;\n }\n }\n\n override connectedCallback() {\n super.connectedCallback();\n window.addEventListener('resize', this.boundUpdatePosition);\n }\n\n override disconnectedCallback() {\n const slot = this.shadowRoot?.querySelector('slot');\n slot?.removeEventListener('slotchange', this.onSlotChange);\n window.removeEventListener('resize', this.boundUpdatePosition);\n this.stopExpandedObserver();\n if (this.slotChangeRaf) {\n cancelAnimationFrame(this.slotChangeRaf);\n this.slotChangeRaf = 0;\n }\n this.topOffsetAnimationManager.cancel();\n if (this.topOffsetDelayTimeout) {\n clearTimeout(this.topOffsetDelayTimeout);\n this.topOffsetDelayTimeout = null;\n }\n this.resolvePendingRelease(false);\n super.disconnectedCallback();\n }\n\n override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has('expand')) {\n if (this.collapsing && this.expand) {\n this.expand = false;\n return;\n }\n this.setExpandedChildren(this.expand);\n }\n }\n\n override willUpdate(changedProperties: PropertyValues) {\n super.willUpdate(changedProperties);\n // Prevent a one-frame wrapper flash when collapse starts.\n if (\n changedProperties.has('expand') &&\n !this.expand &&\n this.topOffsetProgress > 0\n ) {\n this.wrapperVisible = false;\n }\n }\n\n onBackdropClick(event: Event): void {\n event.stopPropagation();\n this.expand = false;\n }\n\n override render() {\n return html`\n ${\n this.expand\n ? html`<div @click=${this.onBackdropClick} class=\"backdrop\"></div>`\n : null\n }\n <slot></slot>\n ${\n !this.expand && this.wrapperVisible\n ? html`<button\n @click=${this.onClick}\n class=${classMap({\n wrapper: true,\n 'with-values': this.wrapperHasValues,\n })}\n style=\"left: 0; top: ${this.positionVertical}; width: ${\n this.wrapperWidth\n }; height: ${this.wrapperHeight}; --obc-poi-group-wrapper-x: ${\n this.wrapperOffsetX\n };\"\n >\n <div class=\"visible-wrapper\"></div>\n </button>`\n : null\n }\n `;\n }\n\n updatePosition(): void {\n if (this.expand || this.collapsing) {\n return;\n }\n\n let left = Number.MAX_VALUE;\n let right = -Number.MAX_VALUE;\n let maxHeight = 0;\n let hasValueTargets = false;\n\n this._children.forEach((element) => {\n if (isPoi(element)) {\n const anchorRect = this.getTargetButtonRect(\n element,\n PoiDataVisualRectPreference.Anchor\n );\n const sizeRect = this.getTargetButtonRect(\n element,\n PoiDataVisualRectPreference.Group\n );\n left = Math.min(left, anchorRect.left);\n right = Math.max(right, anchorRect.right);\n maxHeight = Math.max(maxHeight, sizeRect.height || 0);\n if (Array.isArray(element.data) && element.data.length > 0) {\n hasValueTargets = true;\n }\n return;\n }\n\n const boundingBox = element.getBoundingClientRect();\n left = Math.min(left, boundingBox.left);\n right = Math.max(right, boundingBox.right);\n maxHeight = Math.max(maxHeight, boundingBox.height || 0);\n });\n\n if (left !== Number.MAX_VALUE && right !== -Number.MAX_VALUE) {\n const rootDim = this.getBoundingClientRect();\n const targetLeftPx = left - rootDim.left;\n const targetRightPx = right - rootDim.left;\n const targetWidth = Math.max(0, targetRightPx - targetLeftPx);\n this.wrapperOffsetX = `${targetLeftPx}px`;\n this.wrapperWidth = `${targetWidth}px`;\n const normalizedHeight = Number.isFinite(maxHeight)\n ? Math.max(48, Math.round(maxHeight))\n : 48;\n this.wrapperHeight = `${normalizedHeight}px`;\n this.wrapperHasValues = hasValueTargets;\n } else {\n this.wrapperOffsetX = '0px';\n this.wrapperWidth = '48px';\n this.wrapperHeight = '48px';\n this.wrapperHasValues = false;\n }\n }\n\n private onSlotChange = () => {\n if (this.slotChangeRaf) {\n cancelAnimationFrame(this.slotChangeRaf);\n }\n this.slotChangeRaf = requestAnimationFrame(() => {\n this.slotChangeRaf = 0;\n this.updatePosition();\n if (!this.expand) {\n this.ensureFrontChildOnTop();\n this.syncFrontChild();\n }\n });\n };\n\n private ensureFrontChildOnTop() {\n const frontChild = this.getFrontChild();\n if (frontChild && this.lastElementChild !== frontChild) {\n this.appendChild(frontChild);\n }\n }\n\n onClick(): void {\n if (this.expand) return;\n if (this.hasAttribute('data-exiting')) return;\n const hasTargets = this._children.some((child) => isPoi(child));\n if (!hasTargets) return;\n this.expand = true;\n }\n\n public releaseTarget(target: Poi): Promise<boolean> {\n if (target.parentElement !== this) {\n return Promise.resolve(false);\n }\n\n if (this.pendingReleasedTarget) {\n if (this.pendingReleasedTarget.target === target) {\n return this.pendingReleasedTarget.promise;\n }\n return Promise.resolve(false);\n }\n\n if (!this.expand && !this.collapsing) {\n this.releaseTargetToParent(target);\n return Promise.resolve(true);\n }\n\n let resolveRelease!: (released: boolean) => void;\n const promise = new Promise<boolean>((resolve) => {\n resolveRelease = resolve;\n });\n\n this.pendingReleasedTarget = {\n target,\n promise,\n resolve: resolveRelease,\n };\n this.expand = false;\n return promise;\n }\n\n setExpandedChildren(expand: boolean): void {\n this.dispatchEvent(\n new CustomEvent('expand', {\n detail: {expand: this.expand},\n bubbles: true,\n composed: true,\n })\n );\n const frontChild = this.getFrontChild();\n\n if (expand) {\n this.calculateTopOffsetTargets();\n }\n\n if (!expand) {\n if (this.topOffsetProgress > 0) {\n this.wrapperVisible = false;\n }\n this.lockedExpandedCenter = null;\n }\n\n if (!expand && frontChild) {\n this.appendChild(frontChild);\n }\n\n this.animateTopOffset(expand ? 1 : 0);\n }\n\n private calculateTopOffsetTargets(preserveCenter = false) {\n this.topOffsetTargets.clear();\n\n const targets = this._children.filter((child): child is Poi =>\n isPoi(child)\n );\n\n if (targets.length === 0) return;\n\n const positions = targets.map((child) => {\n const rect = this.getTargetButtonRect(child);\n const currentLeft = this.getCurrentLeft(child);\n return {\n child,\n currentLeft,\n centerX: currentLeft + rect.width / 2,\n width: rect.width,\n };\n });\n positions.sort((a, b) => a.currentLeft - b.currentLeft);\n\n const leftMost = positions[0].centerX;\n const rightMost = positions[positions.length - 1].centerX;\n const computedCenter = (leftMost + rightMost) / 2;\n const groupCenter =\n preserveCenter && this.lockedExpandedCenter !== null\n ? this.lockedExpandedCenter\n : computedCenter;\n if (!preserveCenter) {\n this.lockedExpandedCenter = groupCenter;\n }\n\n const spacing = this.getExpandedSpacing();\n const totalWidth = (positions.length - 1) * spacing;\n const startX = groupCenter - totalWidth / 2;\n\n positions.forEach((pos, index) => {\n const targetX = startX + index * spacing;\n const expandedOffset = targetX - pos.centerX;\n const originalLeft = pos.currentLeft;\n this.topOffsetTargets.set(pos.child, {\n originalX: pos.centerX,\n expandedOffset,\n currentExpandedOffset: expandedOffset,\n originalLeft,\n });\n });\n }\n\n private topOffsetDelayTimeout: ReturnType<typeof setTimeout> | null = null;\n\n refreshExpandedLayout(preserveCenter = false): void {\n if (!this.expand) return;\n this.calculateTopOffsetTargets(preserveCenter);\n this.applyTopOffsetState(this.topOffsetProgress, this.getFrontChild());\n this.scheduleExpandedOffsets();\n }\n\n private animateTopOffset(targetProgress: number) {\n const normalizedTarget = targetProgress === 1 ? 1 : 0;\n const hasPendingOrRunningAnimation =\n this.topOffsetAnimationManager.isRunning() ||\n this.topOffsetDelayTimeout !== null;\n if (\n hasPendingOrRunningAnimation &&\n this.topOffsetAnimationTarget === normalizedTarget\n ) {\n return;\n }\n if (\n !hasPendingOrRunningAnimation &&\n Math.abs(this.topOffsetProgress - normalizedTarget) < 0.001\n ) {\n return;\n }\n\n this.topOffsetAnimationTarget = normalizedTarget;\n this.topOffsetAnimationManager.cancel();\n if (this.topOffsetDelayTimeout) {\n clearTimeout(this.topOffsetDelayTimeout);\n this.topOffsetDelayTimeout = null;\n }\n\n if (targetProgress === 0 && this.topOffsetProgress > 0) {\n this.collapsing = true;\n } else {\n this.collapsing = false;\n }\n\n const frontChild = this.getFrontChild();\n const isCollapsing = targetProgress === 0 && this.topOffsetProgress > 0;\n if (isCollapsing) {\n this.collapseDeltas.clear();\n this.topOffsetTargets.forEach((config, child) => {\n const currentLeft = this.getCurrentLeft(child);\n const delta = currentLeft - config.originalLeft;\n this.collapseDeltas.set(child, delta);\n });\n const delayMs = getCssVarAsNumber(\n this,\n TOP_OFFSET_ANIMATION_DELAY_MS_VAR,\n 0\n );\n if (delayMs > 0) {\n this.topOffsetDelayTimeout = setTimeout(() => {\n this.topOffsetDelayTimeout = null;\n this.runTopOffsetAnimation(targetProgress, frontChild);\n }, delayMs);\n } else {\n this.runTopOffsetAnimation(targetProgress, frontChild);\n }\n } else {\n if (targetProgress === 1) {\n this.collapseDeltas.clear();\n }\n this.runTopOffsetAnimation(targetProgress, frontChild);\n }\n }\n\n private runTopOffsetAnimation(\n targetProgress: number,\n frontChild: Poi | null\n ) {\n const duration = getCssVarAsNumber(this, TOP_OFFSET_ANIMATION_MS_VAR, 100);\n\n this.topOffsetAnimationManager.start(\n targetProgress,\n this.topOffsetProgress,\n {\n duration,\n onUpdate: (progress) => {\n this.topOffsetProgress = progress;\n\n if (targetProgress === 1) {\n this.updateExpandedOffsets(true);\n }\n\n this.applyTopOffsetState(progress, frontChild);\n },\n onComplete: () => {\n this.topOffsetAnimationTarget = null;\n if (targetProgress === 0) {\n this.collapsing = false;\n this.releasePendingTarget();\n this.dispatchEvent(\n new CustomEvent('collapse-finished', {\n bubbles: true,\n composed: true,\n })\n );\n this.updatePosition();\n this.wrapperVisible = true;\n this.stopExpandedObserver();\n this.collapseDeltas.clear();\n this.lastTargetOrder = [];\n this.lastAppliedOffsets.clear();\n }\n if (targetProgress === 1) {\n this.startExpandedObserver();\n this.scheduleExpandedOffsets();\n }\n },\n onError: (error) => {\n console.error('[poi-group] Error in top offset animation:', error);\n this.topOffsetAnimationTarget = null;\n this.collapsing = false;\n this.resolvePendingRelease(false);\n },\n }\n );\n }\n private applyTopOffsetState(progress: number, frontChild: Poi | null) {\n const eased = easeInOutQuad(progress);\n const frontHeight = frontChild\n ? this.getTargetButtonRect(frontChild).height\n : null;\n\n const visualExpanded = this.collapsing ? false : progress > 0.5;\n const touchAreaExpanded = progress > 0.5;\n\n this.topOffsetTargets.forEach((config, child) => {\n if (child.parentElement !== this) {\n this.topOffsetTargets.delete(child);\n this.collapseDeltas.delete(child);\n this.lastAppliedOffsets.delete(child);\n return;\n }\n const isCollapsing = this.collapseDeltas.size > 0;\n let delta: number;\n if (isCollapsing) {\n delta = this.collapseDeltas.get(child) ?? 0;\n } else {\n const currentLeft = this.getCurrentLeft(child);\n delta = currentLeft - config.originalLeft;\n }\n\n const buttonOffsetX = (config.currentExpandedOffset - delta) * eased;\n child.setRuntimeHorizontalOffsets?.(buttonOffsetX, child.targetOffsetX);\n if (!child.setRuntimeHorizontalOffsets) {\n child.buttonOffsetX = buttonOffsetX;\n }\n\n if (child !== frontChild) {\n const isOverlap = !visualExpanded;\n const nextValue = this.resolveTargetValue(child, isOverlap);\n child.value = nextValue;\n if (nextValue === PoiDataValue.Overlapped) {\n applyPoiVisualState(\n child,\n true,\n getVisualTargetSize(\n this,\n child.buttonType === ObcPoiButtonType.Enhanced,\n true\n )\n );\n } else {\n clearPoiVisualState(child);\n }\n this.setOverlappedDataHeight(\n child,\n nextValue === PoiDataValue.Overlapped,\n frontHeight\n );\n } else {\n child.value = this.resolveTargetValue(child, false);\n clearPoiVisualState(child);\n this.setOverlappedDataHeight(child, false, frontHeight);\n }\n\n if (touchAreaExpanded) {\n const touchTarget = `${getTouchTargetSize(this)}px`;\n child.style.width = touchTarget;\n child.style.minWidth = touchTarget;\n child.style.height = touchTarget;\n } else {\n child.style.width = 'unset';\n child.style.minWidth = 'unset';\n child.style.height = 'unset';\n }\n });\n }\n\n private getFrontChild(): Poi | null {\n const targets = this._children.filter((child): child is Poi =>\n isPoi(child)\n );\n\n if (targets.length === 0) return null;\n\n let front: Poi | null = null;\n let maxHeight = Number.NEGATIVE_INFINITY;\n const frontByAttr = targets.find((child) =>\n child.hasAttribute('data-front')\n );\n const epsilon = 0.001;\n\n for (const child of targets) {\n const yValue =\n typeof child.y === 'number' && Number.isFinite(child.y)\n ? child.y\n : Number.parseFloat(child.getAttribute('y') ?? '');\n if (Number.isNaN(yValue)) continue;\n\n if (yValue > maxHeight + epsilon) {\n maxHeight = yValue;\n front = child;\n continue;\n }\n\n if (\n Math.abs(yValue - maxHeight) <= epsilon &&\n frontByAttr &&\n child === frontByAttr\n ) {\n front = child;\n }\n }\n\n return front ?? targets[0] ?? null;\n }\n\n private syncFrontChild() {\n const front = this.getFrontChild();\n const frontHeight = front ? this.getTargetButtonRect(front).height : null;\n this._children.forEach((child) => {\n if (!isPoi(child)) return;\n const isOverlap = !this.expand && (!front || child !== front);\n const nextValue = this.resolveTargetValue(child, isOverlap);\n child.value = nextValue;\n if (nextValue === PoiDataValue.Overlapped) {\n applyPoiVisualState(\n child,\n true,\n getVisualTargetSize(\n this,\n child.buttonType === ObcPoiButtonType.Enhanced,\n true\n )\n );\n } else {\n clearPoiVisualState(child);\n }\n if (front && child === front) {\n child.setAttribute('data-front', 'true');\n } else {\n child.removeAttribute('data-front');\n }\n this.setOverlappedDataHeight(\n child,\n nextValue === PoiDataValue.Overlapped,\n frontHeight\n );\n });\n }\n\n private expandedLoopRunning = false;\n\n private startExpandedObserver() {\n if (this.expandedLoopRunning) return;\n this.expandedLoopRunning = true;\n this.runExpandedLoop();\n }\n\n private runExpandedLoop() {\n if (!this.expandedLoopRunning || !this.expand) {\n this.expandedLoopRunning = false;\n return;\n }\n try {\n this.updateExpandedOffsets();\n requestAnimationFrame(() => this.runExpandedLoop());\n } catch (error) {\n console.error('[poi-group] Error in expanded loop:', error);\n this.expandedLoopRunning = false;\n }\n }\n\n private stopExpandedObserver() {\n this.expandedLoopRunning = false;\n this.lastAppliedOffsets.clear();\n this.lastTargetOrder = [];\n }\n\n private scheduleExpandedOffsets() {\n if (!this.expand) return;\n this.updateExpandedOffsets();\n }\n\n private lastAppliedOffsets: Map<Poi, {buttonOffsetX: number}> = new Map();\n private lastTargetOrder: Poi[] = [];\n\n private updateExpandedOffsets(snap: boolean = false) {\n if (!this.expand) return;\n\n const targets = this._children.filter((child): child is Poi =>\n isPoi(child)\n );\n\n const sortedByCurrentPosition = [...targets]\n .map((child) => {\n const currentLeft = this.getCurrentLeft(child);\n return {child, currentLeft};\n })\n .sort((a, b) => a.currentLeft - b.currentLeft)\n .map((item) => item.child);\n\n const orderedTargets = this.internalSwapping\n ? sortedByCurrentPosition\n : this.lastTargetOrder.length > 0\n ? this.lastTargetOrder\n : sortedByCurrentPosition;\n\n const orderChanged =\n this.lastTargetOrder.length !== orderedTargets.length ||\n orderedTargets.some(\n (child, index) => this.lastTargetOrder[index] !== child\n );\n\n if (\n this.internalSwapping &&\n orderChanged &&\n this.lastTargetOrder.length > 0\n ) {\n const spacing = this.getExpandedSpacing();\n const totalWidth = (orderedTargets.length - 1) * spacing;\n\n const groupCenter =\n this.lockedExpandedCenter ??\n (() => {\n const positions = orderedTargets.map((child) => {\n return this.getCurrentLeft(child);\n });\n const leftMost = Math.min(...positions);\n const rightMost = Math.max(...positions);\n return (leftMost + rightMost) / 2;\n })();\n if (this.lockedExpandedCenter === null) {\n this.lockedExpandedCenter = groupCenter;\n }\n const startX = groupCenter - totalWidth / 2;\n\n orderedTargets.forEach((child, index) => {\n const config = this.topOffsetTargets.get(child);\n if (!config) return;\n\n const targetX = startX + index * spacing;\n const newExpandedOffset = targetX - config.originalX;\n\n config.expandedOffset = newExpandedOffset;\n });\n }\n\n this.lastTargetOrder = orderedTargets;\n\n targets.forEach((child) => {\n if (child.parentElement !== this) {\n this.topOffsetTargets.delete(child);\n this.lastAppliedOffsets.delete(child);\n return;\n }\n const config = this.topOffsetTargets.get(child);\n if (!config) return;\n\n const currentLeft = this.getCurrentLeft(child);\n const delta = currentLeft - config.originalLeft;\n\n if (snap) {\n config.currentExpandedOffset = config.expandedOffset;\n } else {\n config.currentExpandedOffset = frameLerp(\n config.currentExpandedOffset,\n config.expandedOffset,\n 0.1\n );\n }\n\n const buttonOffsetX = config.currentExpandedOffset - delta;\n\n const last = this.lastAppliedOffsets.get(child);\n if (last && last.buttonOffsetX === buttonOffsetX) {\n return;\n }\n\n this.lastAppliedOffsets.set(child, {buttonOffsetX});\n child.setRuntimeHorizontalOffsets?.(buttonOffsetX, child.targetOffsetX);\n if (!child.setRuntimeHorizontalOffsets) {\n child.buttonOffsetX = buttonOffsetX;\n }\n });\n }\n\n private getCurrentLeft(element: HTMLElement): number {\n const computedLeft = getEffectivePoiX(element);\n const targetOffsetX =\n typeof (element as Poi).targetOffsetX === 'number' &&\n Number.isFinite((element as Poi).targetOffsetX)\n ? (element as Poi).targetOffsetX\n : 0;\n return computedLeft + targetOffsetX;\n }\n\n private getTargetButtonRect(\n target: Poi,\n preference: PoiDataVisualRectPreference = PoiDataVisualRectPreference.Group\n ): DOMRect {\n return target.getVisualRect(preference);\n }\n\n private getExpandedSpacing(): number {\n const baseSpacing = getCssVarAsNumber(this, POI_GROUP_SPACING_VAR, 50);\n return this.wrapperHasValues ? baseSpacing + 2 : baseSpacing;\n }\n\n private setOverlappedDataHeight(\n target: Poi,\n overlap: boolean,\n frontHeight: number | null\n ) {\n const dataLength = Array.isArray(target.data) ? target.data.length : 0;\n if (\n !overlap ||\n dataLength === 0 ||\n frontHeight === null ||\n !Number.isFinite(frontHeight)\n ) {\n target.style.removeProperty('--obc-poi-group-overlap-height');\n target.style.removeProperty('--obc-poi-group-overlap-shift');\n return;\n }\n\n const adjustedHeight = Math.max(0, frontHeight * 0.95);\n const shift = Math.max(0, frontHeight - adjustedHeight);\n target.style.setProperty(\n '--obc-poi-group-overlap-height',\n `${adjustedHeight}px`\n );\n target.style.setProperty('--obc-poi-group-overlap-shift', `${shift}px`);\n }\n\n private resolveTargetValue(target: Poi, overlap: boolean): PoiDataValue {\n if (overlap) {\n return PoiDataValue.Overlapped;\n }\n if (target.selected) {\n return PoiDataValue.Checked;\n }\n return PoiDataValue.Unchecked;\n }\n\n private releasePendingTarget() {\n const pending = this.pendingReleasedTarget;\n if (!pending) {\n return;\n }\n\n const released = this.releaseTargetToParent(pending.target);\n this.resolvePendingRelease(released);\n }\n\n private resolvePendingRelease(released: boolean) {\n const pending = this.pendingReleasedTarget;\n if (!pending) {\n return;\n }\n\n this.pendingReleasedTarget = null;\n pending.resolve(released);\n }\n\n private releaseTargetToParent(target: Poi): boolean {\n if (target.parentElement !== this) {\n return false;\n }\n\n target.setRuntimeHorizontalOffsets?.(0, 0);\n if (!target.setRuntimeHorizontalOffsets) {\n target.buttonOffsetX = 0;\n target.targetOffsetX = 0;\n }\n target.removeAttribute('data-grouped');\n target.removeAttribute('data-joined-expanded');\n target.removeAttribute('data-pregrouped');\n target.removeAttribute('data-behind');\n target.removeAttribute('data-front');\n target.removeAttribute('data-front-exit');\n target.removeAttribute('data-exiting');\n target.removeAttribute('data-exit-lock');\n target.style.removeProperty('position');\n target.style.removeProperty('width');\n target.style.removeProperty('min-width');\n target.style.removeProperty('height');\n target.style.removeProperty('transform');\n target.style.removeProperty('--obc-poi-group-overlap-height');\n target.style.removeProperty('--obc-poi-group-overlap-shift');\n clearPoiVisualState(target);\n\n const parent = this.parentElement;\n if (!parent) {\n return false;\n }\n\n parent.insertBefore(target, this);\n this.updatePosition();\n\n const groupParent = parent as HTMLElement & {\n requestGroupingUpdate?: () => void;\n };\n groupParent.requestGroupingUpdate?.();\n\n this.dispatchEvent(\n new CustomEvent<{target: Poi}>('obc-poi-group-target-released', {\n detail: {target},\n bubbles: true,\n composed: true,\n })\n );\n\n return true;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-poi-group': ObcPoiGroup;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"poi-group.js","names":[],"sources":["../../../src/ar/poi-group/poi-group.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, queryAssignedElements, state} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport componentStyle from './poi-group.css?inline';\nimport {PoiDataValue, PoiDataVisualRectPreference} from '../poi/poi-data.js';\nimport {Poi, isPoi} from '../poi/poi.js';\nimport {ObcPoiButtonType} from '../poi-button/poi-button.js';\nimport {customElement} from '../../decorator.js';\nimport {AnimationManager, easeInOutQuad, frameLerp} from './animation-utils.js';\nimport {getEffectivePoiX} from '../poi/poi-position.js';\nimport {\n getCssVarAsNumber,\n getTouchTargetSize,\n getVisualTargetSize,\n} from '../poi/poi-css-vars.js';\nimport {\n applyPoiVisualState,\n clearPoiVisualState,\n} from '../poi/poi-visual-state.js';\n\nconst POI_GROUP_SPACING_VAR = '--obc-poi-group-expanded-spacing';\nconst TOP_OFFSET_ANIMATION_MS_VAR = '--obc-poi-group-top-offset-animation-ms';\nconst TOP_OFFSET_ANIMATION_DELAY_MS_VAR =\n '--obc-poi-group-top-offset-animation-delay-ms';\n\nexport type ExpandEvent = CustomEvent<{expand: boolean}>;\n\n/**\n * `<obc-poi-group>` - A POI cluster component that collapses overlapping targets into one trigger and expands them into a spread list.\n *\n * This component wraps multiple `obc-poi-data` elements and manages their collapsed/expanded presentation as a single interactive unit.\n * Use it when nearby targets should be presented as one grouped control until the user expands the group.\n *\n * ### Features\n * - Expand/collapse state: Controlled by `expand`; collapse animation state is exposed through `collapsing`.\n * - Automatic wrapper sizing: Computes collapsed wrapper width/height from slotted target button bounds.\n * - Front-target handling: Keeps one front target visually prioritized while collapsing other targets into overlap state.\n * - Backdrop interaction: Shows a backdrop while expanded and collapses on backdrop click.\n * - Dynamic ordering: `internalSwapping` enables reordering while expanded based on current horizontal positions.\n * - Vertical placement: `positionVertical` (attribute `position-vertical`) sets the wrapper/group top offset used for collapsed positioning.\n *\n * ### Usage Guidelines\n * - Slot only `obc-poi-data` items that should behave as one grouped target set.\n * - Control expand/collapse via the `expand` property, or let the built-in wrapper button toggle expansion.\n * - Use the `expand` event detail to synchronize nearby standalone targets (for example, set outside targets to overlapped while this group is open).\n * - Treat `collapsing` as orchestration state: it is set by the group itself and by coordinating containers such as `obc-poi-layer-stack` during collapse animations. Do not set it directly.\n * - `internalSwapping` is usually set via `obc-poi-layer`'s `internal-swapping` attribute, which forwards it to auto-created groups; set it directly only on manually managed groups.\n *\n * ### Slots\n * | Slot | Renders When... | Purpose |\n * | --- | --- | --- |\n * | default | Always | Contains grouped `obc-poi-data` targets managed by this component. |\n *\n * ### Events\n * - `expand` - Fired when expand state changes. Detail: `{ expand: boolean }`.\n * - `collapse-finished` - Fired when the collapse animation has fully completed.\n * - `obc-poi-group-target-released` - Fired after `releaseTarget()` returns a target to the group's parent context: re-parented for consumer-managed groups, re-assigned to the layer's main slot for layer-created auto groups. Detail: `{ target: Poi }`.\n *\n * ### Best Practices\n * - Keep grouped targets positioned consistently so wrapper bounds and front-target selection remain stable.\n * - Prefer one `obc-poi-group` per overlap cluster rather than nesting groups.\n * - Use `internalSwapping` only when live target crossing should reorder expanded items.\n *\n * ### Example\n * ```html\n * <obc-poi-group position-vertical=\"240px\">\n * <obc-poi-data x=\"300\" button-y=\"240\" y=\"240\"></obc-poi-data>\n * <obc-poi-data x=\"320\" button-y=\"240\" y=\"240\"></obc-poi-data>\n * <obc-poi-data x=\"340\" button-y=\"240\" y=\"240\"></obc-poi-data>\n * </obc-poi-group>\n * ```\n *\n * @property collapsing - Collapse-animation state. Set by the group itself and by coordinating\n * containers such as `obc-poi-layer-stack` during collapse orchestration;\n * do not set it directly.\n * @property internalSwapping - Reorders expanded targets when their horizontal positions cross. Usually\n * set via `obc-poi-layer`'s `internal-swapping` attribute, which forwards it\n * to auto-created groups; set it directly only on manually managed groups.\n * @slot - Default slot for grouped `obc-poi-data` targets.\n * @fires {CustomEvent<{expand:boolean}>} expand - Fired when the group expand state changes.\n * @fires {CustomEvent<void>} collapse-finished - Fired after collapse animation completes.\n * @fires {CustomEvent<{target: Poi}>} obc-poi-group-target-released - Fired after `releaseTarget()` returns a target to the group's parent context (re-parented for consumer-managed groups, re-assigned for auto groups) — immediately when the group is collapsed, or once the collapse animation completes. Bubbles and is composed.\n * @experimental\n */\n@customElement('obc-poi-group')\nexport class ObcPoiGroup extends LitElement {\n @property({type: Boolean}) expand = false;\n @property({type: Boolean}) collapsing = false;\n @property({type: String, attribute: 'position-vertical'})\n positionVertical = '0px';\n @property({type: Boolean, attribute: 'internal-swapping'})\n internalSwapping = false;\n @state() private wrapperOffsetX = '0px';\n @state() private wrapperWidth = '48px';\n @state() private wrapperVisible = false;\n @state() private wrapperHeight = '48px';\n @state() private wrapperHasValues = false;\n\n @queryAssignedElements({flatten: true})\n _children!: Array<HTMLElement>;\n\n private boundUpdatePosition: () => void;\n private topOffsetAnimationManager = new AnimationManager();\n private topOffsetProgress = 0;\n private slotChangeRaf = 0;\n private topOffsetTargets: Map<\n Poi,\n {\n originalX: number;\n expandedOffset: number;\n currentExpandedOffset: number;\n originalLeft: number;\n }\n > = new Map();\n private lockedExpandedCenter: number | null = null;\n private collapseDeltas: Map<Poi, number> = new Map();\n private topOffsetAnimationTarget: 0 | 1 | null = null;\n private pendingReleasedTarget: {\n target: Poi;\n promise: Promise<boolean>;\n resolve: (released: boolean) => void;\n } | null = null;\n\n constructor() {\n super();\n this.boundUpdatePosition = this.updatePosition.bind(this);\n }\n\n override firstUpdated(_changedProperties: PropertyValues) {\n super.firstUpdated(_changedProperties);\n this.updatePosition();\n this.syncFrontChild();\n const slot = this.shadowRoot?.querySelector('slot');\n slot?.addEventListener('slotchange', this.onSlotChange);\n if (!this.expand) {\n this.wrapperVisible = true;\n }\n }\n\n override connectedCallback() {\n super.connectedCallback();\n window.addEventListener('resize', this.boundUpdatePosition);\n }\n\n override disconnectedCallback() {\n const slot = this.shadowRoot?.querySelector('slot');\n slot?.removeEventListener('slotchange', this.onSlotChange);\n window.removeEventListener('resize', this.boundUpdatePosition);\n this.stopExpandedObserver();\n if (this.slotChangeRaf) {\n cancelAnimationFrame(this.slotChangeRaf);\n this.slotChangeRaf = 0;\n }\n this.topOffsetAnimationManager.cancel();\n if (this.topOffsetDelayTimeout) {\n clearTimeout(this.topOffsetDelayTimeout);\n this.topOffsetDelayTimeout = null;\n }\n this.resolvePendingRelease(false);\n super.disconnectedCallback();\n }\n\n override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has('expand')) {\n if (this.collapsing && this.expand) {\n this.expand = false;\n return;\n }\n this.setExpandedChildren(this.expand);\n }\n }\n\n override willUpdate(changedProperties: PropertyValues) {\n super.willUpdate(changedProperties);\n // Prevent a one-frame wrapper flash when collapse starts.\n if (\n changedProperties.has('expand') &&\n !this.expand &&\n this.topOffsetProgress > 0\n ) {\n this.wrapperVisible = false;\n }\n }\n\n onBackdropClick(event: Event): void {\n event.stopPropagation();\n this.expand = false;\n }\n\n override render() {\n return html`\n ${\n this.expand\n ? html`<div @click=${this.onBackdropClick} class=\"backdrop\"></div>`\n : null\n }\n <slot></slot>\n ${\n !this.expand && this.wrapperVisible\n ? html`<button\n @click=${this.onClick}\n class=${classMap({\n wrapper: true,\n 'with-values': this.wrapperHasValues,\n })}\n style=\"left: 0; top: ${this.positionVertical}; width: ${\n this.wrapperWidth\n }; height: ${this.wrapperHeight}; --obc-poi-group-wrapper-x: ${\n this.wrapperOffsetX\n };\"\n >\n <div class=\"visible-wrapper\"></div>\n </button>`\n : null\n }\n `;\n }\n\n updatePosition(): void {\n if (this.expand || this.collapsing) {\n return;\n }\n\n let left = Number.MAX_VALUE;\n let right = -Number.MAX_VALUE;\n let maxHeight = 0;\n let hasValueTargets = false;\n\n this._children.forEach((element) => {\n if (isPoi(element)) {\n const anchorRect = this.getTargetButtonRect(\n element,\n PoiDataVisualRectPreference.Anchor\n );\n const sizeRect = this.getTargetButtonRect(\n element,\n PoiDataVisualRectPreference.Group\n );\n left = Math.min(left, anchorRect.left);\n right = Math.max(right, anchorRect.right);\n maxHeight = Math.max(maxHeight, sizeRect.height || 0);\n if (Array.isArray(element.data) && element.data.length > 0) {\n hasValueTargets = true;\n }\n return;\n }\n\n const boundingBox = element.getBoundingClientRect();\n left = Math.min(left, boundingBox.left);\n right = Math.max(right, boundingBox.right);\n maxHeight = Math.max(maxHeight, boundingBox.height || 0);\n });\n\n if (left !== Number.MAX_VALUE && right !== -Number.MAX_VALUE) {\n const rootDim = this.getBoundingClientRect();\n const targetLeftPx = left - rootDim.left;\n const targetRightPx = right - rootDim.left;\n const targetWidth = Math.max(0, targetRightPx - targetLeftPx);\n this.wrapperOffsetX = `${targetLeftPx}px`;\n this.wrapperWidth = `${targetWidth}px`;\n const normalizedHeight = Number.isFinite(maxHeight)\n ? Math.max(48, Math.round(maxHeight))\n : 48;\n this.wrapperHeight = `${normalizedHeight}px`;\n this.wrapperHasValues = hasValueTargets;\n } else {\n this.wrapperOffsetX = '0px';\n this.wrapperWidth = '48px';\n this.wrapperHeight = '48px';\n this.wrapperHasValues = false;\n }\n }\n\n private onSlotChange = () => {\n if (this.slotChangeRaf) {\n cancelAnimationFrame(this.slotChangeRaf);\n }\n this.slotChangeRaf = requestAnimationFrame(() => {\n this.slotChangeRaf = 0;\n this.updatePosition();\n if (!this.expand) {\n this.ensureFrontChildOnTop();\n this.syncFrontChild();\n }\n });\n };\n\n /**\n * Membership check that works for both light-DOM children (manual groups)\n * and slot-assigned members (layer-created auto groups, where the member\n * stays in the consumer's light DOM and is assigned into this group's\n * member slot).\n */\n private isMember(child: HTMLElement): boolean {\n return (\n child.parentElement === this || child.assignedSlot?.parentElement === this\n );\n }\n\n private getMemberSlot(): HTMLSlotElement | null {\n return this.querySelector(\n ':scope > slot.auto-group-members'\n ) as HTMLSlotElement | null;\n }\n\n /**\n * Paint the front child on top. For light-DOM members this reorders the\n * children; for slot-assigned members it re-assigns the member slot, which\n * changes flattened-tree order without touching the consumer's DOM.\n */\n private bringChildToFront(frontChild: Poi) {\n const memberSlot = this.getMemberSlot();\n if (memberSlot && frontChild.assignedSlot === memberSlot) {\n const members = memberSlot.assignedElements();\n if (members[members.length - 1] === frontChild) return;\n memberSlot.assign(\n ...members.filter((el) => el !== frontChild),\n frontChild\n );\n return;\n }\n if (frontChild.parentElement === this) {\n this.appendChild(frontChild);\n }\n }\n\n private ensureFrontChildOnTop() {\n const frontChild = this.getFrontChild();\n if (frontChild && this.lastElementChild !== frontChild) {\n this.bringChildToFront(frontChild);\n }\n }\n\n onClick(): void {\n if (this.expand) return;\n if (this.hasAttribute('data-exiting')) return;\n const hasTargets = this._children.some((child) => isPoi(child));\n if (!hasTargets) return;\n this.expand = true;\n }\n\n public releaseTarget(target: Poi): Promise<boolean> {\n if (!this.isMember(target)) {\n return Promise.resolve(false);\n }\n\n if (this.pendingReleasedTarget) {\n if (this.pendingReleasedTarget.target === target) {\n return this.pendingReleasedTarget.promise;\n }\n return Promise.resolve(false);\n }\n\n if (!this.expand && !this.collapsing) {\n this.releaseTargetToParent(target);\n return Promise.resolve(true);\n }\n\n let resolveRelease!: (released: boolean) => void;\n const promise = new Promise<boolean>((resolve) => {\n resolveRelease = resolve;\n });\n\n this.pendingReleasedTarget = {\n target,\n promise,\n resolve: resolveRelease,\n };\n this.expand = false;\n return promise;\n }\n\n setExpandedChildren(expand: boolean): void {\n this.dispatchEvent(\n new CustomEvent('expand', {\n detail: {expand: this.expand},\n bubbles: true,\n composed: true,\n })\n );\n const frontChild = this.getFrontChild();\n\n if (expand) {\n this.calculateTopOffsetTargets();\n }\n\n if (!expand) {\n if (this.topOffsetProgress > 0) {\n this.wrapperVisible = false;\n }\n this.lockedExpandedCenter = null;\n }\n\n if (!expand && frontChild) {\n this.bringChildToFront(frontChild);\n }\n\n this.animateTopOffset(expand ? 1 : 0);\n }\n\n private calculateTopOffsetTargets(preserveCenter = false) {\n this.topOffsetTargets.clear();\n\n const targets = this._children.filter((child): child is Poi =>\n isPoi(child)\n );\n\n if (targets.length === 0) return;\n\n const positions = targets.map((child) => {\n const rect = this.getTargetButtonRect(child);\n const currentLeft = this.getCurrentLeft(child);\n return {\n child,\n currentLeft,\n centerX: currentLeft + rect.width / 2,\n width: rect.width,\n };\n });\n positions.sort((a, b) => a.currentLeft - b.currentLeft);\n\n const leftMost = positions[0].centerX;\n const rightMost = positions[positions.length - 1].centerX;\n const computedCenter = (leftMost + rightMost) / 2;\n const groupCenter =\n preserveCenter && this.lockedExpandedCenter !== null\n ? this.lockedExpandedCenter\n : computedCenter;\n if (!preserveCenter) {\n this.lockedExpandedCenter = groupCenter;\n }\n\n const spacing = this.getExpandedSpacing();\n const totalWidth = (positions.length - 1) * spacing;\n const startX = groupCenter - totalWidth / 2;\n\n positions.forEach((pos, index) => {\n const targetX = startX + index * spacing;\n const expandedOffset = targetX - pos.centerX;\n const originalLeft = pos.currentLeft;\n this.topOffsetTargets.set(pos.child, {\n originalX: pos.centerX,\n expandedOffset,\n currentExpandedOffset: expandedOffset,\n originalLeft,\n });\n });\n }\n\n private topOffsetDelayTimeout: ReturnType<typeof setTimeout> | null = null;\n\n refreshExpandedLayout(preserveCenter = false): void {\n if (!this.expand) return;\n this.calculateTopOffsetTargets(preserveCenter);\n this.applyTopOffsetState(this.topOffsetProgress, this.getFrontChild());\n this.scheduleExpandedOffsets();\n }\n\n private animateTopOffset(targetProgress: number) {\n const normalizedTarget = targetProgress === 1 ? 1 : 0;\n const hasPendingOrRunningAnimation =\n this.topOffsetAnimationManager.isRunning() ||\n this.topOffsetDelayTimeout !== null;\n if (\n hasPendingOrRunningAnimation &&\n this.topOffsetAnimationTarget === normalizedTarget\n ) {\n return;\n }\n if (\n !hasPendingOrRunningAnimation &&\n Math.abs(this.topOffsetProgress - normalizedTarget) < 0.001\n ) {\n return;\n }\n\n this.topOffsetAnimationTarget = normalizedTarget;\n this.topOffsetAnimationManager.cancel();\n if (this.topOffsetDelayTimeout) {\n clearTimeout(this.topOffsetDelayTimeout);\n this.topOffsetDelayTimeout = null;\n }\n\n if (targetProgress === 0 && this.topOffsetProgress > 0) {\n this.collapsing = true;\n } else {\n this.collapsing = false;\n }\n\n const frontChild = this.getFrontChild();\n const isCollapsing = targetProgress === 0 && this.topOffsetProgress > 0;\n if (isCollapsing) {\n this.collapseDeltas.clear();\n this.topOffsetTargets.forEach((config, child) => {\n const currentLeft = this.getCurrentLeft(child);\n const delta = currentLeft - config.originalLeft;\n this.collapseDeltas.set(child, delta);\n });\n const delayMs = getCssVarAsNumber(\n this,\n TOP_OFFSET_ANIMATION_DELAY_MS_VAR,\n 0\n );\n if (delayMs > 0) {\n this.topOffsetDelayTimeout = setTimeout(() => {\n this.topOffsetDelayTimeout = null;\n this.runTopOffsetAnimation(targetProgress, frontChild);\n }, delayMs);\n } else {\n this.runTopOffsetAnimation(targetProgress, frontChild);\n }\n } else {\n if (targetProgress === 1) {\n this.collapseDeltas.clear();\n }\n this.runTopOffsetAnimation(targetProgress, frontChild);\n }\n }\n\n private runTopOffsetAnimation(\n targetProgress: number,\n frontChild: Poi | null\n ) {\n const duration = getCssVarAsNumber(this, TOP_OFFSET_ANIMATION_MS_VAR, 100);\n\n this.topOffsetAnimationManager.start(\n targetProgress,\n this.topOffsetProgress,\n {\n duration,\n onUpdate: (progress) => {\n this.topOffsetProgress = progress;\n\n if (targetProgress === 1) {\n this.updateExpandedOffsets(true);\n }\n\n this.applyTopOffsetState(progress, frontChild);\n },\n onComplete: () => {\n this.topOffsetAnimationTarget = null;\n if (targetProgress === 0) {\n this.collapsing = false;\n this.releasePendingTarget();\n this.dispatchEvent(\n new CustomEvent('collapse-finished', {\n bubbles: true,\n composed: true,\n })\n );\n this.updatePosition();\n this.wrapperVisible = true;\n this.stopExpandedObserver();\n this.collapseDeltas.clear();\n this.lastTargetOrder = [];\n this.lastAppliedOffsets.clear();\n }\n if (targetProgress === 1) {\n this.startExpandedObserver();\n this.scheduleExpandedOffsets();\n }\n },\n onError: (error) => {\n console.error('[poi-group] Error in top offset animation:', error);\n this.topOffsetAnimationTarget = null;\n this.collapsing = false;\n this.resolvePendingRelease(false);\n },\n }\n );\n }\n private applyTopOffsetState(progress: number, frontChild: Poi | null) {\n const eased = easeInOutQuad(progress);\n const frontHeight = frontChild\n ? this.getTargetButtonRect(frontChild).height\n : null;\n\n const visualExpanded = this.collapsing ? false : progress > 0.5;\n const touchAreaExpanded = progress > 0.5;\n\n this.topOffsetTargets.forEach((config, child) => {\n if (!this.isMember(child)) {\n this.topOffsetTargets.delete(child);\n this.collapseDeltas.delete(child);\n this.lastAppliedOffsets.delete(child);\n return;\n }\n const isCollapsing = this.collapseDeltas.size > 0;\n let delta: number;\n if (isCollapsing) {\n delta = this.collapseDeltas.get(child) ?? 0;\n } else {\n const currentLeft = this.getCurrentLeft(child);\n delta = currentLeft - config.originalLeft;\n }\n\n const buttonOffsetX = (config.currentExpandedOffset - delta) * eased;\n child.setRuntimeHorizontalOffsets?.(buttonOffsetX, child.targetOffsetX);\n if (!child.setRuntimeHorizontalOffsets) {\n child.buttonOffsetX = buttonOffsetX;\n }\n\n if (child !== frontChild) {\n const isOverlap = !visualExpanded;\n const nextValue = this.resolveTargetValue(child, isOverlap);\n child.value = nextValue;\n if (nextValue === PoiDataValue.Overlapped) {\n applyPoiVisualState(\n child,\n true,\n getVisualTargetSize(\n this,\n child.buttonType === ObcPoiButtonType.Enhanced,\n true\n )\n );\n } else {\n clearPoiVisualState(child);\n }\n this.setOverlappedDataHeight(\n child,\n nextValue === PoiDataValue.Overlapped,\n frontHeight\n );\n } else {\n child.value = this.resolveTargetValue(child, false);\n clearPoiVisualState(child);\n this.setOverlappedDataHeight(child, false, frontHeight);\n }\n\n if (touchAreaExpanded) {\n const touchTarget = `${getTouchTargetSize(this)}px`;\n child.style.width = touchTarget;\n child.style.minWidth = touchTarget;\n child.style.height = touchTarget;\n } else {\n child.style.width = 'unset';\n child.style.minWidth = 'unset';\n child.style.height = 'unset';\n }\n });\n }\n\n private getFrontChild(): Poi | null {\n const targets = this._children.filter((child): child is Poi =>\n isPoi(child)\n );\n\n if (targets.length === 0) return null;\n\n let front: Poi | null = null;\n let maxHeight = Number.NEGATIVE_INFINITY;\n const frontByAttr = targets.find((child) =>\n child.hasAttribute('data-front')\n );\n const epsilon = 0.001;\n\n for (const child of targets) {\n const yValue =\n typeof child.y === 'number' && Number.isFinite(child.y)\n ? child.y\n : Number.parseFloat(child.getAttribute('y') ?? '');\n if (Number.isNaN(yValue)) continue;\n\n if (yValue > maxHeight + epsilon) {\n maxHeight = yValue;\n front = child;\n continue;\n }\n\n if (\n Math.abs(yValue - maxHeight) <= epsilon &&\n frontByAttr &&\n child === frontByAttr\n ) {\n front = child;\n }\n }\n\n return front ?? targets[0] ?? null;\n }\n\n private syncFrontChild() {\n const front = this.getFrontChild();\n const frontHeight = front ? this.getTargetButtonRect(front).height : null;\n this._children.forEach((child) => {\n if (!isPoi(child)) return;\n const isOverlap = !this.expand && (!front || child !== front);\n const nextValue = this.resolveTargetValue(child, isOverlap);\n child.value = nextValue;\n if (nextValue === PoiDataValue.Overlapped) {\n applyPoiVisualState(\n child,\n true,\n getVisualTargetSize(\n this,\n child.buttonType === ObcPoiButtonType.Enhanced,\n true\n )\n );\n } else {\n clearPoiVisualState(child);\n }\n if (front && child === front) {\n child.setAttribute('data-front', 'true');\n } else {\n child.removeAttribute('data-front');\n }\n this.setOverlappedDataHeight(\n child,\n nextValue === PoiDataValue.Overlapped,\n frontHeight\n );\n });\n }\n\n private expandedLoopRunning = false;\n\n private startExpandedObserver() {\n if (this.expandedLoopRunning) return;\n this.expandedLoopRunning = true;\n this.runExpandedLoop();\n }\n\n private runExpandedLoop() {\n if (!this.expandedLoopRunning || !this.expand) {\n this.expandedLoopRunning = false;\n return;\n }\n try {\n this.updateExpandedOffsets();\n requestAnimationFrame(() => this.runExpandedLoop());\n } catch (error) {\n console.error('[poi-group] Error in expanded loop:', error);\n this.expandedLoopRunning = false;\n }\n }\n\n private stopExpandedObserver() {\n this.expandedLoopRunning = false;\n this.lastAppliedOffsets.clear();\n this.lastTargetOrder = [];\n }\n\n private scheduleExpandedOffsets() {\n if (!this.expand) return;\n this.updateExpandedOffsets();\n }\n\n private lastAppliedOffsets: Map<Poi, {buttonOffsetX: number}> = new Map();\n private lastTargetOrder: Poi[] = [];\n\n private updateExpandedOffsets(snap: boolean = false) {\n if (!this.expand) return;\n\n const targets = this._children.filter((child): child is Poi =>\n isPoi(child)\n );\n\n const sortedByCurrentPosition = [...targets]\n .map((child) => {\n const currentLeft = this.getCurrentLeft(child);\n return {child, currentLeft};\n })\n .sort((a, b) => a.currentLeft - b.currentLeft)\n .map((item) => item.child);\n\n const orderedTargets = this.internalSwapping\n ? sortedByCurrentPosition\n : this.lastTargetOrder.length > 0\n ? this.lastTargetOrder\n : sortedByCurrentPosition;\n\n const orderChanged =\n this.lastTargetOrder.length !== orderedTargets.length ||\n orderedTargets.some(\n (child, index) => this.lastTargetOrder[index] !== child\n );\n\n if (\n this.internalSwapping &&\n orderChanged &&\n this.lastTargetOrder.length > 0\n ) {\n const spacing = this.getExpandedSpacing();\n const totalWidth = (orderedTargets.length - 1) * spacing;\n\n const groupCenter =\n this.lockedExpandedCenter ??\n (() => {\n const positions = orderedTargets.map((child) => {\n return this.getCurrentLeft(child);\n });\n const leftMost = Math.min(...positions);\n const rightMost = Math.max(...positions);\n return (leftMost + rightMost) / 2;\n })();\n if (this.lockedExpandedCenter === null) {\n this.lockedExpandedCenter = groupCenter;\n }\n const startX = groupCenter - totalWidth / 2;\n\n orderedTargets.forEach((child, index) => {\n const config = this.topOffsetTargets.get(child);\n if (!config) return;\n\n const targetX = startX + index * spacing;\n const newExpandedOffset = targetX - config.originalX;\n\n config.expandedOffset = newExpandedOffset;\n });\n }\n\n this.lastTargetOrder = orderedTargets;\n\n targets.forEach((child) => {\n if (!this.isMember(child)) {\n this.topOffsetTargets.delete(child);\n this.lastAppliedOffsets.delete(child);\n return;\n }\n const config = this.topOffsetTargets.get(child);\n if (!config) return;\n\n const currentLeft = this.getCurrentLeft(child);\n const delta = currentLeft - config.originalLeft;\n\n if (snap) {\n config.currentExpandedOffset = config.expandedOffset;\n } else {\n config.currentExpandedOffset = frameLerp(\n config.currentExpandedOffset,\n config.expandedOffset,\n 0.1\n );\n }\n\n const buttonOffsetX = config.currentExpandedOffset - delta;\n\n const last = this.lastAppliedOffsets.get(child);\n if (last && last.buttonOffsetX === buttonOffsetX) {\n return;\n }\n\n this.lastAppliedOffsets.set(child, {buttonOffsetX});\n child.setRuntimeHorizontalOffsets?.(buttonOffsetX, child.targetOffsetX);\n if (!child.setRuntimeHorizontalOffsets) {\n child.buttonOffsetX = buttonOffsetX;\n }\n });\n }\n\n private getCurrentLeft(element: HTMLElement): number {\n const computedLeft = getEffectivePoiX(element);\n const targetOffsetX =\n typeof (element as Poi).targetOffsetX === 'number' &&\n Number.isFinite((element as Poi).targetOffsetX)\n ? (element as Poi).targetOffsetX\n : 0;\n return computedLeft + targetOffsetX;\n }\n\n private getTargetButtonRect(\n target: Poi,\n preference: PoiDataVisualRectPreference = PoiDataVisualRectPreference.Group\n ): DOMRect {\n return target.getVisualRect(preference);\n }\n\n private getExpandedSpacing(): number {\n const baseSpacing = getCssVarAsNumber(this, POI_GROUP_SPACING_VAR, 50);\n return this.wrapperHasValues ? baseSpacing + 2 : baseSpacing;\n }\n\n private setOverlappedDataHeight(\n target: Poi,\n overlap: boolean,\n frontHeight: number | null\n ) {\n const dataLength = Array.isArray(target.data) ? target.data.length : 0;\n if (\n !overlap ||\n dataLength === 0 ||\n frontHeight === null ||\n !Number.isFinite(frontHeight)\n ) {\n target.style.removeProperty('--obc-poi-group-overlap-height');\n target.style.removeProperty('--obc-poi-group-overlap-shift');\n return;\n }\n\n const adjustedHeight = Math.max(0, frontHeight * 0.95);\n const shift = Math.max(0, frontHeight - adjustedHeight);\n target.style.setProperty(\n '--obc-poi-group-overlap-height',\n `${adjustedHeight}px`\n );\n target.style.setProperty('--obc-poi-group-overlap-shift', `${shift}px`);\n }\n\n private resolveTargetValue(target: Poi, overlap: boolean): PoiDataValue {\n if (overlap) {\n return PoiDataValue.Overlapped;\n }\n if (target.selected) {\n return PoiDataValue.Checked;\n }\n return PoiDataValue.Unchecked;\n }\n\n private releasePendingTarget() {\n const pending = this.pendingReleasedTarget;\n if (!pending) {\n return;\n }\n\n const released = this.releaseTargetToParent(pending.target);\n this.resolvePendingRelease(released);\n }\n\n private resolvePendingRelease(released: boolean) {\n const pending = this.pendingReleasedTarget;\n if (!pending) {\n return;\n }\n\n this.pendingReleasedTarget = null;\n pending.resolve(released);\n }\n\n private releaseTargetToParent(target: Poi): boolean {\n if (!this.isMember(target)) {\n return false;\n }\n\n target.setRuntimeHorizontalOffsets?.(0, 0);\n if (!target.setRuntimeHorizontalOffsets) {\n target.buttonOffsetX = 0;\n target.targetOffsetX = 0;\n }\n target.removeAttribute('data-grouped');\n target.removeAttribute('data-joined-expanded');\n target.removeAttribute('data-pregrouped');\n target.removeAttribute('data-behind');\n target.removeAttribute('data-front');\n target.removeAttribute('data-front-exit');\n target.removeAttribute('data-exiting');\n target.removeAttribute('data-exit-lock');\n target.style.removeProperty('position');\n target.style.removeProperty('width');\n target.style.removeProperty('min-width');\n target.style.removeProperty('height');\n target.style.removeProperty('transform');\n target.style.removeProperty('--obc-poi-group-overlap-height');\n target.style.removeProperty('--obc-poi-group-overlap-shift');\n clearPoiVisualState(target);\n\n const memberSlot = this.getMemberSlot();\n if (memberSlot && target.assignedSlot === memberSlot) {\n // Slot-assigned member (layer-created auto group): the target already\n // lives in the consumer's light DOM — only the assignment changes. The\n // host layer immediately re-assigns it to its main slot.\n memberSlot.assign(\n ...memberSlot.assignedElements().filter((el) => el !== target)\n );\n const root = this.getRootNode();\n const host =\n root instanceof ShadowRoot\n ? (root.host as HTMLElement & {\n releaseAssignedTarget?: (target: Poi) => void;\n })\n : null;\n host?.releaseAssignedTarget?.(target);\n this.updatePosition();\n\n this.dispatchEvent(\n new CustomEvent<{target: Poi}>('obc-poi-group-target-released', {\n detail: {target},\n bubbles: true,\n composed: true,\n })\n );\n return true;\n }\n\n const parent = this.parentElement;\n if (!parent) {\n return false;\n }\n\n parent.insertBefore(target, this);\n this.updatePosition();\n\n const groupParent = parent as HTMLElement & {\n requestGroupingUpdate?: () => void;\n };\n groupParent.requestGroupingUpdate?.();\n\n this.dispatchEvent(\n new CustomEvent<{target: Poi}>('obc-poi-group-target-released', {\n detail: {target},\n bubbles: true,\n composed: true,\n })\n );\n\n return true;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-poi-group': ObcPoiGroup;\n }\n}\n"],"mappings":"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"}