Skip to content

refactor(timing): extract after()/TimerHandle into SwiflowTiming with a host ManualTimers arm#255

Merged
zzal merged 1 commit into
mainfrom
refactor/swiflow-timing
Jul 19, 2026
Merged

refactor(timing): extract after()/TimerHandle into SwiflowTiming with a host ManualTimers arm#255
zzal merged 1 commit into
mainfrom
refactor/swiflow-timing

Conversation

@zzal

@zzal zzal commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Part-1 modularization-audit fix (finding 2).

Problem. SwiflowUI's only use of SwiflowDOM was Toast's auto-dismiss timer — a view library depending on the render backend for a 101-line utility. Worse, the timer was gated on canImport(JavaScriptKit) (true on host), so a host harness mounting ToastView walked straight into JSObject.global.setTimeout! and trapped; auto-dismiss and its WCAG pause were demo-verified only.

Change.

  • New leaf target SwiflowTiming owning after()/TimerHandle, split on arch(wasm32) per the repo rule. The wasm arm keeps the JSOneshotClosure implementation verbatim (same release contract); the host arm queues into ManualTimers — a public, test-driven queue (advance(by:), reset(), pendingCount) mirroring the ManualClock pattern.
  • SwiflowDOM re-exports the module (@_exported), so app code that imports SwiflowDOM (e.g. GridBoard) compiles unchanged.
  • SwiflowUI now depends on SwiflowTiming instead of SwiflowDOM; Toast's #if canImport timer gates are gone.
  • New ToastTimerTests (serialized suite owning the ManualTimers seam): countdown arms on mount and dismisses exactly once; hover pause re-arms the FULL duration on leave (WCAG 2.2.1); focusin/focusout pause; the countdown stays paused while either hold remains.

Verification. Whole-package swift test: 1901 tests, 351 suites, green. SwiflowUIDemo and GridBoard wasm builds pass locally (CI skips examples); GridBoard exercises the re-export path.

🤖 Generated with Claude Code

… a host ManualTimers arm

SwiflowUI's only SwiflowDOM use was Toast's auto-dismiss timer, which
pulled the whole renderer into the UI library's dependency closure and —
gated on canImport(JavaScriptKit), true on host — trapped at
JSObject.global.setTimeout the moment a host harness mounted a
ToastView. The new leaf target splits on arch(wasm32): the wasm arm
keeps the JSOneshotClosure implementation verbatim, the host arm queues
into ManualTimers for tests to advance. SwiflowDOM re-exports the
module, so app code importing SwiflowDOM is source-compatible.

ToastView's dismiss countdown and WCAG 2.2.1 hover/focus pause-resume
are now covered by host tests (ToastTimerTests) instead of being
demo-verified.

Whole-package swift test: 1901 tests green. SwiflowUIDemo + GridBoard
wasm builds verified locally (CI skips examples).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 Bundle size

Artifact Baseline This PR Δ
App.wasm 5.06 MB 5.23 MB +3.46%
App.wasm (gzip) 1.80 MB 1.87 MB +3.57%
JS runtime 54.5 KB 54.5 KB +0.00%
JS runtime (gzip) 11.3 KB 11.3 KB +0.00%
Total (gzip) 1.81 MB 1.88 MB +3.55%

✅ Within budget (≤5% growth allowed).

Baseline: Swift 6.3, WASM SDK 6.3-RELEASE, measured 2026-06-18.

@zzal
zzal merged commit 52a4f34 into main Jul 19, 2026
6 checks passed
@zzal
zzal deleted the refactor/swiflow-timing branch July 19, 2026 21:11
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.

1 participant