import type { MouseEvent } from 'react' import { CircularProgress, MenuItem } from '@mui/material' import { getLegendStore, selectAllGroupsCollapsed, selectGroupVisibility, selectHasGroups, selectLayersByGroup, selectOrderedGroups, useLegendId, useLegendStore, } from '../../stores' import { useLegendConfig } from '../../provider' import { useLegendGroupId, useLegendMenu } from '../contexts' import { runAsyncMenuAction } from '../run-async-menu-action' /** * Show only this group (hide all other layers). * * @experimental This API is new and may change in a future release. */ export function LegendShowOnlyGroup() { const id = useLegendId() const groupId = useLegendGroupId() const { labels } = useLegendConfig() if (groupId === null) return null const showOnly = () => { const state = getLegendStore(id).getState() for (const group of selectOrderedGroups(state)) { state.setGroupVisibility(group.id, group.id === groupId) } // Exclusive: the ungrouped layers hide too. for (const layer of selectLayersByGroup(state, undefined)) { state.setVisibility(layer.id, false) } } return {labels.showOnlyGroup} } /** * Show every layer (panel-level `Legend.PanelMenu` only). * * @experimental This API is new and may change in a future release. */ export function LegendShowAllGroups() { const id = useLegendId() const hasGroups = useLegendStore(id, selectHasGroups) const { labels } = useLegendConfig() if (!hasGroups) return null const showAll = () => { const state = getLegendStore(id).getState() for (const group of selectOrderedGroups(state)) { state.setGroupVisibility(group.id, true) } for (const layer of selectLayersByGroup(state, undefined)) { state.setVisibility(layer.id, true) } } return {labels.showAllGroups} } /** * Collapse / expand all groups (panel-level `Legend.PanelMenu` only). * * @experimental This API is new and may change in a future release. */ export function LegendCollapseAllGroups() { const id = useLegendId() const hasGroups = useLegendStore(id, selectHasGroups) const allCollapsed = useLegendStore(id, selectAllGroupsCollapsed) const { labels } = useLegendConfig() if (!hasGroups) return null const toggleAll = () => { const state = getLegendStore(id).getState() const collapsed = selectAllGroupsCollapsed(state) for (const group of selectOrderedGroups(state)) { state.setGroupCollapsed(group.id, !collapsed) } } return ( {allCollapsed ? labels.expandAllGroups : labels.collapseAllGroups} ) } export interface LegendZoomToGroupProps { /** Fit viewport to the group; may return a Promise for async menu feedback. */ onZoomTo: (groupId: string) => void | Promise } /** * Zoom-to-group menu item for `Legend.GroupMenu`. Self-hides when all members are hidden. * * @experimental This API is new and may change in a future release. */ export function LegendZoomToGroup({ onZoomTo }: LegendZoomToGroupProps) { const id = useLegendId() const groupId = useLegendGroupId() const menu = useLegendMenu() const hidden = useLegendStore( id, (s) => groupId !== null && selectGroupVisibility(s, groupId) === 'hidden', ) const { labels } = useLegendConfig() if (groupId === null || hidden) return null const busy = menu?.busy ?? false const handleClick = (e: MouseEvent) => { e.stopPropagation() if (!menu) return void runAsyncMenuAction(menu, () => onZoomTo(groupId)) } return ( {busy && } {busy ? labels.loading : labels.zoomToGroup} ) }