Level: atom. Inventory status: local-code.
Purpose
Provide the compact icon-only action used by map zoom, auxiliary controls and polygon tools. Use the general Button component for ordinary labelled actions; Map Control Button owns the verified 32 × 32 map treatment only.
Confirmed correction target
The resumed M-003 correction adds explicit Tooltip placement to the public API.
The Angular component disables its Tooltip while the control is active so a
mode action bar can occupy the same side without overlap. It also derives the
owned Tooltip appearance from theme: dark-map controls pass inverted, while
light-map controls pass default.
Anatomy
- Native icon-only button with one shared Icon glyph at 16 × 16.
- The standalone treatment has a level-1-base surface, secondary 1 px stroke,
8 px radius and dropdown shadow.
topandbottomshapes join the two zoom actions without exposing separate Plus/Minus component owners. - Zoom actions reuse the same control owner but join into Map Zoom:
zoom-inis the upper half andzoom-outis the lower half. - Tooltip text is supplied by the caller and is also the accessible name.
Actions and states
Supported actions are zoom-in, zoom-out, info, settings,
enter-fullscreen, exit-fullscreen, draw-polygon, edit-polygon and
delete-polygon.
Default, hover, active, focus-visible and disabled are runtime states. The
caller may mark a persistent toggle-like action as activated; this exposes
aria-pressed and the accent treatment. Disabled controls do not emit.
theme selects the verified light/dark control surface. It is independent of
the browser or application theme because the map's cartographic theme may be
changed locally. The same value controls the nested Tooltip appearance:
theme='dark' renders its overlay with a light background and dark text;
theme='light' keeps the default dark background and light text.
Behavior and accessibility
- Render a real
button type="button"; do not simulate an action on a frame or generic element. labelis required, non-empty and supplies botharia-labeland Tooltip text. The glyph remains decorative.tooltipPlacementpasses an explicit owned Tooltip placement. Map usesrightfor polygon tools, Map Zoom usesleft, and bottom-right auxiliary actions usetop.- The nested Tooltip receives
appearance='inverted'whentheme='dark'andappearance='default'whentheme='light'; this applies to hover and keyboard-focus opening alike. - Emit
triggeredwith the owned action only for an enabled user activation. Native keyboard activation, focus order and disabled behavior must remain intact. - The 32 × 32 hit target must not be reduced by its icon or focus treatment.
Token use
- Light surface:
--color-background-level-1-base; hover/pressed/disabled use the matching dropdown and level-1 semantic colors. - Dark surface and content use the owned inverted-button semantic tokens.
- Tooltip surface and text remain owned by Tooltip; Map Control Button selects
only its
defaultorinvertedappearance and does not duplicate those color values. - Icon:
--color-text-icon-primary; disabled uses the tertiary/inverted disabled content token; activated content uses the constant-white token. - Stroke and focus:
--color-stroke-secondary,--color-stroke-focused,--space-100. - Radius, dimensions and shadow:
--radius-s,--space-800,--shadow-dropdown. - Use exact shared glyph assets. Do not draw or approximate the map icons.
Storybook coverage target
Show light and dark controls with their Tooltips available on hover and focus.
The dark example must demonstrate the nested inverted Tooltip without
changing the control label, placement or interaction state.
Local component contract
This is the M-003 owned contract for component.map-control-button.
Public types
export type WblMapControlAction =
| 'zoom-in'
| 'zoom-out'
| 'info'
| 'settings'
| 'enter-fullscreen'
| 'exit-fullscreen'
| 'draw-polygon'
| 'edit-polygon'
| 'delete-polygon';
export type WblMapControlButtonShape = 'standalone' | 'top' | 'bottom';
export type WblMapTheme = 'light' | 'dark';
Class and selector
WblMapControlButtonComponent—wbl-map-control-button.
Inputs
action = input.required<WblMapControlAction>()label = input.required<string>()disabled = input(false)activated = input(false)theme = input<WblMapTheme>('light')shape = input<WblMapControlButtonShape>('standalone')tooltipPlacement = input<WblTooltipPlacement>('top')
theme also deterministically derives the nested Tooltip appearance; no
second public appearance input belongs to Map Control Button.
Models
- None.
Outputs
triggered = output<WblMapControlAction>()
Slots
- None. The action resolves to an exact shared Icon glyph.
Focused regression target
theme='light'passes Tooltipappearance='default'.theme='dark'passes Tooltipappearance='inverted'without changing its label, placement, disabled state or button accessibility semantics.
Local evidence target
- Code:
src/app/design-system/primitives/map-control-button/map-control-button.component.ts. - Focused test:
src/app/design-system/primitives/map-control-button/map-control-button.component.spec.ts. - Public export:
src/app/design-system/index.ts. - Storybook:
storybook/stories/map-control-button.stories.ts.
Figma evidence
- Map Button actions, node
10031:62538: Info, Settings, View full, View mini, Draw polygon, Edit and Delete. - Base control states, node
5767:184463: Default, Hover and Focus. - Plus states, node
5714:266383and Minus states, node5714:266394: Default, Hover, Focus and Disabled. - Cursor-hint Tooltip, node
14577:5540: 8 px block padding, 12 px inline padding, 8 px radius and description typography. This node verifies appearance and copy; the Map organism owns its cursor-relative lifecycle.
Exact-node metadata, design context and variable bindings were read on 2026-09-10. Published component keys were not returned by the available scoped Figma reads, so no assembly sidecar is claimed by this contract yet.
Documentation task
M-003 · GitLab issue ·
actor artem-mokin / GitLab 26942597 · agent Specs subagent ·
run/session 7a124ab4-0ecb-435c-9cb5-dd9df24c995e.