tray: Tray.placeSig analogue of placeCard for SIG SELECT exit; rename arc-in → fade-in — TDD
After all 3 gamers in a polarity room confirm TAKE SIG and the 12s countdown
expires, sig-select.js's room:polarity_room_done handler now plays the same
tray-open / fade-in / tray-close sequence the role-select uses, then
dismisses the sig overlay & shows the waiting msg ("Gravity settling…" /
"Levity appraising…") on Tray.placeSig's completion callback. Visual order:
sig stage → tray slides in → sig fades into the second tray cell → tray
slides out → table hex w. waiting msg. Cross-polarity events (other room
finishing while we're still in our overlay) are no-op as before.
- tray.js: new Tray.placeSig(sourceEl, onComplete). Mutates the SECOND
.tray-cell in place (sig slot), copies aria-label / data-energies /
data-operations / corner-rank + suit-icon markup from the source
.sig-stage-card, then runs the shared open → fade-in → close sequence.
Extracted _runFadeInSequence helper so placeCard + placeSig share the
same animation glue. reset() now also clears .tray-sig-card from cells.
- _tray.scss: .tray-sig-card.fade-in > .sig-stage-card animates via the
existing tray-role-fade-in keyframes.
- sig-select.js polarity_room_done handler: Tray.placeSig(stageCard,
_settle); _settle runs the existing _dismissSigOverlay + _showWaitingMsg.
Falls back to immediate dismiss when Tray is undefined (test environments
without the tray).
- arc-in → fade-in rename across tray.js, role-select.js, _tray.scss
(incl. @keyframes tray-role-arc-in → tray-role-fade-in), TraySpec.js
spec descriptions + assertions, & test_room_role_select.py docstrings.
The original "arc-in" name suggested a curved-path animation; the actual
behaviour is a 1s opacity fade, so fade-in is the accurate label.
- TraySpec: 10 new placeSig specs mirroring placeCard (second-cell mutation,
data + markup copy, tabIndex, fade-in class, animationend-triggered close,
onComplete callback, landscape parity, reset cleanup).
- SigSelectSpec: 3 new specs (Tray.placeSig called w. stageCard on own
polarity; not called on other polarity; overlay dismiss deferred to the
Tray.placeSig completion callback).
344 specs / 4 pending green; RoleSelectTrayTest FT still green.
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -120,7 +120,7 @@ var RoleSelect = (function () {
|
||||
}
|
||||
openFan();
|
||||
} else {
|
||||
// Animate the role card into the tray: open, arc-in, force-close.
|
||||
// Animate the role card into the tray: open, fade-in, force-close.
|
||||
// Any turn_changed that arrived while the fetch was in-flight is
|
||||
// queued in _pendingTurnChange and will run after onComplete.
|
||||
if (typeof Tray !== "undefined") {
|
||||
|
||||
@@ -529,8 +529,19 @@ var SigSelect = (function () {
|
||||
if (!overlay) return;
|
||||
if (e.detail.polarity !== userPolarity) return;
|
||||
var pendingPolarity = userPolarity === 'levity' ? 'gravity' : 'levity';
|
||||
_dismissSigOverlay();
|
||||
_showWaitingMsg(pendingPolarity);
|
||||
// Tray-place sequence first (visually anchors the sig stage's exit);
|
||||
// overlay dismissal + waiting msg run on Tray.placeSig's completion
|
||||
// callback so the user sees: stage card → tray slides in → sig fades
|
||||
// into the tray cell → tray slides out → table hex w. waiting msg.
|
||||
function _settle() {
|
||||
_dismissSigOverlay();
|
||||
_showWaitingMsg(pendingPolarity);
|
||||
}
|
||||
if (typeof Tray !== "undefined" && Tray.placeSig) {
|
||||
Tray.placeSig(stageCard, _settle);
|
||||
} else {
|
||||
_settle();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('room:pick_sky_available', function () {
|
||||
|
||||
@@ -243,18 +243,18 @@ var Tray = (function () {
|
||||
});
|
||||
}
|
||||
|
||||
// _arcIn — add .arc-in to cardEl, wait for animationend, remove it, call onComplete.
|
||||
function _arcIn(cardEl, onComplete) {
|
||||
cardEl.classList.add('arc-in');
|
||||
// _fadeIn — add .fade-in to cardEl, wait for animationend, remove it, call onComplete.
|
||||
function _fadeIn(cardEl, onComplete) {
|
||||
cardEl.classList.add('fade-in');
|
||||
cardEl.addEventListener('animationend', function handler() {
|
||||
cardEl.removeEventListener('animationend', handler);
|
||||
cardEl.classList.remove('arc-in');
|
||||
cardEl.classList.remove('fade-in');
|
||||
if (onComplete) onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
// placeCard(roleCode, onComplete) — mark the first tray cell with the role,
|
||||
// open the tray, arc-in the cell, then animated-close. Calls onComplete after
|
||||
// open the tray, fade-in the cell, then animated-close. Calls onComplete after
|
||||
// the close slide finishes (transitionend), with a fallback timeout in case
|
||||
// CSS transitions are disabled (e.g. test environments).
|
||||
// The grid always contains exactly 8 .tray-cell elements (from the template);
|
||||
@@ -276,8 +276,56 @@ var Tray = (function () {
|
||||
firstCell.appendChild(img);
|
||||
}
|
||||
|
||||
_runFadeInSequence(firstCell, onComplete);
|
||||
}
|
||||
|
||||
// placeSig(sourceEl, onComplete) — analogue of placeCard, applied to the
|
||||
// second tray cell. Copies the user's selected sig-stage-card data + inner
|
||||
// markup so the tray sig card renders identically to the page-load case
|
||||
// (room.html: <div class="sig-stage-card sea-sig-card" aria-label data-energies
|
||||
// data-operations><span class="fan-corner-rank">…</span><i class="fa-solid …"></i></div>).
|
||||
// The grid keeps exactly 8 .tray-cell elements; the second cell is mutated
|
||||
// in place rather than inserting a new element.
|
||||
function placeSig(sourceEl, onComplete) {
|
||||
if (!_grid) { if (onComplete) onComplete(); return; }
|
||||
var secondCell = _grid.children[1];
|
||||
if (!secondCell) { if (onComplete) onComplete(); return; }
|
||||
|
||||
secondCell.classList.add('tray-sig-card');
|
||||
secondCell.tabIndex = 0;
|
||||
secondCell.textContent = '';
|
||||
|
||||
var stage = document.createElement('div');
|
||||
stage.className = 'sig-stage-card sea-sig-card';
|
||||
if (sourceEl) {
|
||||
var aria = sourceEl.getAttribute && sourceEl.getAttribute('aria-label');
|
||||
if (aria) stage.setAttribute('aria-label', aria);
|
||||
if (sourceEl.dataset && sourceEl.dataset.energies) {
|
||||
stage.dataset.energies = sourceEl.dataset.energies;
|
||||
}
|
||||
if (sourceEl.dataset && sourceEl.dataset.operations) {
|
||||
stage.dataset.operations = sourceEl.dataset.operations;
|
||||
}
|
||||
// Carry over rank + suit-icon markup from the source. We copy
|
||||
// those two specific children rather than the whole innerHTML so
|
||||
// the source's larger fan-card-face-* / qualifier markup doesn't
|
||||
// leak into the tray card layout.
|
||||
var rank = sourceEl.querySelector && sourceEl.querySelector('.fan-corner-rank');
|
||||
if (rank) stage.appendChild(rank.cloneNode(true));
|
||||
var icon = sourceEl.querySelector && sourceEl.querySelector('i.fa-solid');
|
||||
if (icon) stage.appendChild(icon.cloneNode(true));
|
||||
}
|
||||
secondCell.appendChild(stage);
|
||||
|
||||
_runFadeInSequence(secondCell, onComplete);
|
||||
}
|
||||
|
||||
// Shared open → fade-in → close → onComplete sequence for placeCard /
|
||||
// placeSig. cardEl is the .tray-cell that just received the role / sig
|
||||
// class + content.
|
||||
function _runFadeInSequence(cardEl, onComplete) {
|
||||
open();
|
||||
_arcIn(firstCell, function () {
|
||||
_fadeIn(cardEl, function () {
|
||||
close();
|
||||
if (!onComplete) return;
|
||||
if (!_wrap) { onComplete(); return; }
|
||||
@@ -518,7 +566,7 @@ var Tray = (function () {
|
||||
// Clear any role-card state from tray cells (Jasmine afterEach)
|
||||
if (_grid) {
|
||||
_grid.querySelectorAll('.tray-cell').forEach(function (el) {
|
||||
el.classList.remove('tray-role-card', 'arc-in');
|
||||
el.classList.remove('tray-role-card', 'tray-sig-card', 'fade-in');
|
||||
el.removeAttribute('tabindex');
|
||||
el.textContent = '';
|
||||
delete el.dataset.role;
|
||||
@@ -543,6 +591,7 @@ var Tray = (function () {
|
||||
forceClose: forceClose,
|
||||
isOpen: isOpen,
|
||||
placeCard: placeCard,
|
||||
placeSig: placeSig,
|
||||
reset: reset,
|
||||
_testSetLandscape: function (v) { _landscapeOverride = v; },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user