Skip to content

feat(dui/spinner)!: collapse to single library-owned rotation spinner#396

Merged
Faerkeren merged 1 commit into
mainfrom
dui/spinner-simplify
May 29, 2026
Merged

feat(dui/spinner)!: collapse to single library-owned rotation spinner#396
Faerkeren merged 1 commit into
mainfrom
dui/spinner-simplify

Conversation

@Faerkeren
Copy link
Copy Markdown
Contributor

Closes #395.

Summary

Replaces the configurable per-package spinner with a single, library-owned 8-frame rotation animation at 100 ms intervals. Packages declare only a placeholder <g id="..."> in their layout SVG and reference it via spinner: { node: ... } in the manifest; DeUX injects the canonical geometry (background tile + 8 radial bars) at frame-generation time.

Breaking changes

  • SpinnerSpec reduced to a single node field.
  • type, frames, interval_ms, and background_node are no longer accepted; manifests using them fail to load with a clear error.
  • SpinnerType enum, DEFAULT_SPINNER_FRAMES, DEFAULT_SPINNER_INTERVAL_MS, and the SpinnerFrames class are removed.
  • Frame generation is now a module-level get_frames(...) function backed by a process-wide LRU cache keyed by rendered SVG, placeholder id, size, image format, and background tile signature.

Migration

Before:

spinner:
  type: rotation
  node: spinner
  frames: 8
  interval_ms: 100
  background_node: spinner_background

After:

spinner:
  node: spinner

In the layout SVG, replace the inline spinner geometry with an empty placeholder:

<g id="spinner" transform="translate(60 47.5)"/>

The library-shipped IconKey.dui and PictureKey.dui packages have been migrated.

Validation

  • ruff check . — clean
  • mypy src/deux — clean
  • pytest tests/ --cov=deux --cov-fail-under=95 — 1979 passed, 1 skipped, coverage 95.66 %
  • deux.dui.spinner module coverage: 96 %

Files

  • src/deux/dui/schema.py: shrink SpinnerSpec to {node}, drop SpinnerType and default constants.
  • src/deux/dui/loader.py: reject legacy keys; drop CUSTOM / background validation.
  • src/deux/dui/spinner.py: full rewrite — canonical SVG constant + LRU get_frames.
  • src/deux/dui/svg_renderer.py: simplify _hide_spinner_node.
  • src/deux/dui/key.py, src/deux/dui/card.py: switch to get_frames, drop SpinnerFrames usage.
  • src/deux/dui/__init__.py: update exports.
  • src/deux/dui/packages/{IconKey,PictureKey}.dui: migrate to minimal placeholder form.
  • tests/test_spinner.py: rewritten for the new API.
  • tests/test_spinner_cache.py: new — LRU identity, eviction, key composition.
  • tests/test_busy_guard.py, tests/test_dui_svg_renderer.py: updated for new schema.
  • docs/guides/creating-dui-packages.md: collapsed spinner section.

The spinner is now a single, library-owned 8-frame rotation animation
at 100 ms intervals. Packages declare only a placeholder `<g id=...>`
in their layout SVG and reference it via `spinner: { node: ... }` in
the manifest; DeUX injects the canonical geometry (background tile +
8 radial bars) at frame-generation time.

BREAKING CHANGES
- `SpinnerSpec` reduced to a single `node` field. The fields `type`,
  `frames`, `interval_ms`, and `background_node` are gone.
- Manifests that include any of those legacy keys fail to load.
- `SpinnerType` enum, `DEFAULT_SPINNER_FRAMES`, and
  `DEFAULT_SPINNER_INTERVAL_MS` are removed.
- `SpinnerFrames` class is replaced by the module-level
  `get_frames(...)` function backed by a process-wide LRU cache keyed
  by rendered SVG, placeholder id, size, image format, and background
  tile signature.

Library-shipped `IconKey.dui` and `PictureKey.dui` packages have been
migrated to the new minimal form.

Refs #395
@Faerkeren Faerkeren merged commit 716f821 into main May 29, 2026
16 checks passed
@Faerkeren Faerkeren deleted the dui/spinner-simplify branch May 29, 2026 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Simplify spinner: single system-wide rotation spinner injected by the library

1 participant