# Map Control Button

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. `top` and `bottom` shapes 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-in`
  is the upper half and `zoom-out` is 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.
- `label` is required, non-empty and supplies both `aria-label` and Tooltip
  text. The glyph remains decorative.
- `tooltipPlacement` passes an explicit owned Tooltip placement. Map uses
  `right` for polygon tools, Map Zoom uses `left`, and bottom-right auxiliary
  actions use `top`.
- The nested Tooltip receives `appearance='inverted'` when `theme='dark'` and
  `appearance='default'` when `theme='light'`; this applies to hover and
  keyboard-focus opening alike.
- Emit `triggered` with 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 `default` or `inverted` appearance 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

```ts
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 Tooltip `appearance='default'`.
- `theme='dark'` passes Tooltip `appearance='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`](https://www.figma.com/design/EO9tuCsqwuHL8cZ4Eb2psR/?node-id=10031-62538): Info, Settings, View full, View mini, Draw polygon, Edit and Delete.
- [Base control states, node `5767:184463`](https://www.figma.com/design/EO9tuCsqwuHL8cZ4Eb2psR/?node-id=5767-184463): Default, Hover and Focus.
- [Plus states, node `5714:266383`](https://www.figma.com/design/EO9tuCsqwuHL8cZ4Eb2psR/?node-id=5714-266383) and [Minus states, node `5714:266394`](https://www.figma.com/design/EO9tuCsqwuHL8cZ4Eb2psR/?node-id=5714-266394): Default, Hover, Focus and Disabled.
- [Cursor-hint Tooltip, node `14577:5540`](https://www.figma.com/design/EO9tuCsqwuHL8cZ4Eb2psR/?node-id=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](https://gitlab.com/polozovdaniel/logistics-2/-/work_items/39) ·
actor `artem-mokin` / GitLab `26942597` · agent `Specs subagent` ·
run/session `7a124ab4-0ecb-435c-9cb5-dd9df24c995e`.
