sugarcraft/candy-mouse

Self-contained Mark/Scan/Get mouse hit-testing (bubblezone pattern) plus ZoneClickTracker for press/release deduplication. No external Manager wiring needed.

Maintainers

Package info

github.com/sugarcraft/candy-mouse

Documentation

pkg:composer/sugarcraft/candy-mouse

Statistics

Installs: 5

Dependents: 6

Suggesters: 0

Stars: 0

Open Issues: 0

dev-master 2026-06-01 14:48 UTC

This package is not auto-updated.

Last update: 2026-06-02 12:39:01 UTC


README

Self-contained Mark/Scan/Get mouse hit-testing (bubblezone pattern) plus ZoneClickTracker for press/release deduplication. No external Manager wiring needed.

composer require sugarcraft/candy-mouse: dev-master

Role

Replaces the model where consumers wire candy-zone's Manager externally. Each consumer owns its own Scanner instance — click handling stays local, no shared global state.

Quickstart

use SugarCraft\Mouse\Mark;
use SugarCraft\Mouse\Scanner;
use SugarCraft\Mouse\ZoneClickTracker;
use SugarCraft\Mouse\MouseEvent;

// 1. Wrap interactive content with invisible zone markers.
$rendered = Mark::zone('btn-ok', '  OK  ')
              . Mark::zone('btn-cancel', 'Cancel');

// 2. Scan after rendering to populate the zone registry.
$scanner = Scanner::new()->scan($rendered);

// 3. Reverse-lookup on mouse events.
$zone = $scanner->hit($mouseX, $mouseY); // ?Zone

// 4. Deduplicate clicks so each press+release pair emits one click.
$tracker = new ZoneClickTracker();
$result = $tracker->track(new MouseEvent(5, 1, 0, MouseAction::Release));
if ($result !== null) {
    echo "Clicked zone: " . $result->zone->id;
}

Key classes

Class Role
Mark Wrap content with invisible Unicode sentinel markers
Scanner Parse sentinels; get(id) and hit(col, row) lookups
Zone Readonly bounding box (start/end col/row)
ZoneClickTracker Press+Release dedup per button
MouseEvent Immutable event (x, y, button, action enum)
MouseAction Press / Release / Drag / Scroll enum

Sentinel design

Sentinels use private-use codepoints U+E000 (open) and U+E001 (close) — they never collide with ANSI SGR sequences or regular text. Scanning strips them from output.

Coverage

codecov

Upstream

Inspired by lrstanley/bubblezone — the Mark/Scan/Get pattern mirrors bubblezone's API. ZoneClickTracker addresses bubblezone issue #10.