Stop the table resizing under the thumb that is reaching for it
Two things moved the felt, and neither of them was the felt's business. The raise pad. It is 57px taller than the row it replaces, and the table was sized against it — so pressing Raise shrank the whole thing, re-ran the ten-candidate width search, redrew every seat at a different size, and undid all of it when the dealer pressed Raise to. Measured, five players nine-handed: 1280x900 felt 738x532 -> 669x481, pucks 120 -> 109, worst seat moved 73px 360x640 felt 283x329 -> 283x279, pucks 44 -> 48, worst seat moved 50px 390x844 felt 309x463 -> 309x451, worst seat moved 11px Every raise, all night, at the one moment the dealer is reading the felt to decide what to type. A phone held sideways already scored 0px: the rail is a column down the side, and its height never was the table's business. So the felt is sized against the bar at rest and the pad floats up over the bottom of it, which is what a transient surface is supposed to do — the context it is over stays where it was. --actionBarHeight is untouched and still says what is really covering the window, because that is what the toast has to clear. And the status row. It wraps, and flex settles its line breaks before it decides what to shrink, so a name too long for the room left beside the clock and the undo pill did not give way — it pushed them onto a third line. That is 22px off a felt underneath a bar fixed to the bottom. Measured at 360x640 mid-street: "Dee · $600 behind" left the table 283x329 and "Christopher · $1,200 behind" made it 283x310, with every seat moving 24px between one player and the next. Whose turn it was decided how big the table was. An earlier round saw this and reserved two lines for the row; three is what it takes. Reserving three would spend the 22px on every table for the sake of some of them. So the actor, the clock and the undo pill get a line of their own that cannot wrap, and the name shrinks into it — with the stack held out of the shrink, because a number read wrong is a worse failure than a name read short. The row is 66px whoever is acting. It claims that line only when there is somebody on it. Claiming it unconditionally cost one in the state that can least afford it — a board running out has nobody to act, so the row is the undo pill alone, and it used to sit up beside "All-in — running out the board". The pill gives width back to the name on a phone: 10rem is 160px, and at 360 it took half the row, leaving "Christopher" cut to 23px of its 75. A media query, not `min(10rem, 34%)` — that was tried, and a percentage against a row sized to its own contents chases itself: the sweep caught the pill drawn 38px wide at ten viewports. Verified by walking a hand at five viewports: one felt size, one puck width, and not one seat moving, across a raise pad opened and shut and a full street of action. 1003 unit tests. 320 layout audits across 13 viewports with a mouse and a thumb, and this is the first round in a while with nothing in them — the chip behind seat 11 on the twelve-handed Galaxy S8, which master has carried for rounds, clears too. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -3200,12 +3200,98 @@ body.hasActionBar #holdemApp {
|
||||
font-size: var(--fs-sm);
|
||||
}
|
||||
|
||||
.actionWho {
|
||||
/* Who is being waited on, and what they have behind.
|
||||
|
||||
It already said `text-overflow: ellipsis`, and the ellipsis never once appeared. A
|
||||
flex item's `min-width` is `auto`, which means "never smaller than your own content",
|
||||
so instead of giving way this pushed the clock and the undo pill onto a third line —
|
||||
and the row is in a bar fixed to the bottom, so a third line comes straight off the
|
||||
felt. Measured at 360x640 mid-street: "Dee · $600 behind" left the bar 151px tall,
|
||||
"Christopher · $1,200 behind" made it 173, and the table resized between one player
|
||||
and the next. Whose turn it was decided how big the felt was.
|
||||
|
||||
`min-width: 0` is what lets the ellipsis do the job it was already written for. What
|
||||
gives way is the name — see .actionWhoName. */
|
||||
/* The second line of the status block, and it is a line because it is written as one.
|
||||
|
||||
`flex: 1 1 100%` is what makes it take a line of its own inside a wrapping parent —
|
||||
which is the whole point. Flex settles its line breaks before it decides what to
|
||||
shrink, so a long name in the wrapping row did not give way, it pushed the clock and
|
||||
the undo pill onto a third line. Here the three of them are on a row that can shrink
|
||||
instead of a row that can wrap. */
|
||||
.actionActing {
|
||||
/* Only what it holds, when all it holds is the undo pill. Claiming a line
|
||||
unconditionally cost one in the state that can least afford it: while a board is
|
||||
running out there is nobody to act, so this row is the pill alone — it used to sit
|
||||
up beside "All-in — running out the board" and now it wanted a line of its own.
|
||||
That is 22px off the felt on the twelve-handed 360x640 table where the pucks are
|
||||
already at their 44px floor, and the sweep caught it as a seat's "ALL IN" going
|
||||
back under the blind badge next door. */
|
||||
flex: 0 1 auto;
|
||||
display: flex;
|
||||
/* The one that matters. Left wrapping, this row reproduced the fault it was made to
|
||||
fix one level down: the undo pill is a fixed 9rem, so a long name pushed it onto a
|
||||
line of its own and the block went back to being 84px for some players and 66 for
|
||||
others. Not wrapping is what forces the shrink, and the shrink is what the name
|
||||
is set up to absorb. */
|
||||
flex-wrap: nowrap;
|
||||
align-items: baseline;
|
||||
gap: var(--sp-1) var(--sp-2);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* And a line of its own the moment there is somebody being waited on, which is the case
|
||||
this row exists for — the name, what they have behind, the clock, and the way back.
|
||||
`flex: 1 1 100%` is what takes the line; nowrap above is what makes the name give way
|
||||
inside it instead of pushing the pill onto another one. */
|
||||
.actionActing:has(.actionWho) {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
/* On a phone the pill gives some of its width back to the name beside it.
|
||||
10rem is 160px, and at 360px the acting row has 319 to spend: the pill took half, the
|
||||
clock took 50, and what was left over went to the player being waited on — measured,
|
||||
"Christopher" was cut to 23px of its 75, which reads "Ch…". A third of the row is
|
||||
enough for a safety net when the other thing on the line is the question the dealer is
|
||||
actually answering.
|
||||
|
||||
Still one width at a time, which is the property that matters: the pill names the last
|
||||
action, so its label changes on every tap, and it must not resize under a thumb.
|
||||
A media query keeps that true. `min(10rem, 34%)` does not — the percentage resolves
|
||||
against this row, the row is sized to its contents, and the two chase each other: the
|
||||
sweep caught the pill drawn 38px wide at ten viewports. */
|
||||
@media (max-width: 480px) {
|
||||
.actionUndo {
|
||||
width: 7rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pushed to the far end of its own line, where it was before — the difference is that
|
||||
it is now the end of a line this block chose rather than wherever the text ran out. */
|
||||
.actionActing .actionUndo {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.actionWho {
|
||||
color: var(--text-muted);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* The half that shrinks. */
|
||||
.actionWhoName {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* And the half that doesn't. The same rule the seat pucks keep: a number read wrong is
|
||||
a worse failure than a name read short, so the stack keeps every digit and the name
|
||||
is what loses characters. */
|
||||
.actionWhoStack {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
/* Stopwatch, not a shot clock: it colours up as a prompt to the dealer, and does
|
||||
@@ -5248,6 +5334,13 @@ body.hasActionBar #toastHost {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* The rail is 190px wide, so its acting row is a stack rather than a line — every
|
||||
one of these readings is on its own line here regardless, and squeezing a name
|
||||
into a fifth of the column would be shrinking to fit a row that isn't there. */
|
||||
.actionActing {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.actionUndo {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,13 @@ const ActionBar = {
|
||||
// What is under the felt is the bar in one layout and the two links in the
|
||||
// other. Either way it is the same question — how much of the bottom is
|
||||
// already spoken for — so it is the same argument.
|
||||
this.publishFeltRoom(rail ? this.roomBelowFelt() : height);
|
||||
//
|
||||
// Except that the felt is asked a slightly different question from everything
|
||||
// else that reads --actionBarHeight. The toast and the scroll padding want to
|
||||
// know what is covering the bottom of the window *right now*; the table wants
|
||||
// to know how big to be, and being a different size for the few seconds a pad
|
||||
// is open over it is not an answer, it is a jolt. See restingBarHeight.
|
||||
this.publishFeltRoom(rail ? this.roomBelowFelt() : this.restingBarHeight(height));
|
||||
};
|
||||
|
||||
// Kept so anything that moves the table without touching the bar can ask for
|
||||
@@ -58,6 +64,42 @@ const ActionBar = {
|
||||
publish();
|
||||
},
|
||||
|
||||
// How tall the bar is when it is only a bar.
|
||||
//
|
||||
// The raise pad is 57px taller than the row it replaces, and the felt was sized
|
||||
// against it. Measured with five players nine-handed, pressing Raise:
|
||||
//
|
||||
// 1280x900 felt 738x532 -> 669x481, pucks 120 -> 109, worst seat moved 73px
|
||||
// 360x640 felt 283x329 -> 283x279, pucks 44 -> 48, worst seat moved 50px
|
||||
// 390x844 felt 309x463 -> 309x451, worst seat moved 11px
|
||||
//
|
||||
// The whole table jumped, re-ran the ten-candidate width search, redrew at a
|
||||
// different size — and then undid all of it when the dealer pressed Raise to. Every
|
||||
// raise, all night, at the one moment they are reading the felt to decide what to
|
||||
// type. A phone held sideways already did the right thing here and scored 0px: the
|
||||
// rail is a column down the side, so its height never was the table's business.
|
||||
//
|
||||
// A pad over the bar is a transient surface, and the thing a transient surface must
|
||||
// not do is take the context away from underneath itself. So the felt is sized
|
||||
// against the bar the thumb is coming back to, and the pad grows up over the bottom
|
||||
// of the felt for as long as it is open.
|
||||
//
|
||||
// Only the felt's question is answered this way. --actionBarHeight stays what it has
|
||||
// always been — what is actually covering the bottom of the window — because that is
|
||||
// what the toast has to clear and what the page has to scroll past.
|
||||
//
|
||||
// The remembered height goes stale if the window changes size while the pad is open,
|
||||
// which on a phone means turning it over mid-raise. The next publish after the pad
|
||||
// closes is a measurement, so it puts itself right; a stale felt for the seconds in
|
||||
// between is the same trade being made everywhere else here.
|
||||
restingBarHeight(measured) {
|
||||
if (!this.raiseOpen) {
|
||||
this.barHeightAtRest = measured;
|
||||
return measured;
|
||||
}
|
||||
return this.barHeightAtRest === undefined ? measured : this.barHeightAtRest;
|
||||
},
|
||||
|
||||
// Is the bar a rail down the side rather than a bar across the bottom?
|
||||
//
|
||||
// Asked of the stylesheet rather than answered again here. The layout is chosen by
|
||||
@@ -336,20 +378,59 @@ const ActionBar = {
|
||||
row.appendChild(runout);
|
||||
}
|
||||
|
||||
// The second line of this block, held as a line rather than left to whatever the
|
||||
// wrapping happens to produce.
|
||||
//
|
||||
// The row wraps, and flex decides its line breaks before it decides what to
|
||||
// shrink — so a name too long for the space left beside the clock and the undo
|
||||
// pill did not give way, it pushed them onto a third line. That is 22px, and the
|
||||
// bar is fixed to the bottom, so it came off the felt: measured at 360x640
|
||||
// mid-street, "Dee · $600 behind" left the table 283x329 and "Christopher ·
|
||||
// $1,200 behind" made it 283x310, with every seat moving 24px between one player
|
||||
// and the next. Whose turn it was decided how big the table was.
|
||||
//
|
||||
// On its own line the three of them are a row that can shrink instead of a row
|
||||
// that can wrap, and the block is two lines whoever is acting.
|
||||
const acting = document.createElement("div");
|
||||
acting.className = "actionActing";
|
||||
|
||||
const index = this.state.actingSeatIndex;
|
||||
if (index !== null && index !== undefined && !Betting.isHandOver(this.state)) {
|
||||
const player = this.state.seats[index];
|
||||
// Two spans rather than one sentence, because only one half of it is
|
||||
// allowed to give way. This row wraps, and a name long enough to push the
|
||||
// clock and the undo pill onto a third line takes 22px off the felt — so
|
||||
// whose turn it is decided how big the table was. Measured at 360x640:
|
||||
// "Dee · $600 behind" left the bar 151px tall and "Christopher · $1,200
|
||||
// behind" made it 173, and the felt resized between one player and the next.
|
||||
//
|
||||
// So the name shrinks and the number does not. A name cut to "Christophe…"
|
||||
// is still the player the dealer is looking at; a stack cut to "$1,2…" is a
|
||||
// figure they would have to go and find somewhere else.
|
||||
const who = document.createElement("span");
|
||||
who.className = "actionWho";
|
||||
who.textContent = `${HoldemState.displayName(player, index)} · ${Money.format(Betting.stackOf(this.state, player))} behind`;
|
||||
row.appendChild(who);
|
||||
|
||||
const whoName = document.createElement("span");
|
||||
whoName.className = "actionWhoName";
|
||||
whoName.textContent = HoldemState.displayName(player, index);
|
||||
// The whole of it, for the one name on the narrowest phone that still has to
|
||||
// give up a few characters. Same arrangement the seat pucks have.
|
||||
whoName.title = whoName.textContent;
|
||||
who.appendChild(whoName);
|
||||
|
||||
const whoStack = document.createElement("span");
|
||||
whoStack.className = "actionWhoStack";
|
||||
whoStack.textContent = ` · ${Money.format(Betting.stackOf(this.state, player))} behind`;
|
||||
who.appendChild(whoStack);
|
||||
|
||||
acting.appendChild(who);
|
||||
|
||||
const tank = document.createElement("span");
|
||||
tank.className = "actionTank";
|
||||
tank.id = "actionTank";
|
||||
tank.title = "How long this player has been thinking";
|
||||
tank.textContent = "0:00";
|
||||
row.appendChild(tank);
|
||||
acting.appendChild(tank);
|
||||
|
||||
// Rendered every time and shown by the tick once the wait is long enough
|
||||
// to be worth it, so a clock never costs a re-render at the moment the
|
||||
@@ -375,7 +456,7 @@ const ActionBar = {
|
||||
clock.title = `${this.CLOCK_THINK_S} seconds, then a ${this.CLOCK_COUNTDOWN_S}-second countdown`;
|
||||
clock.addEventListener("click", () => this.callClock());
|
||||
}
|
||||
row.appendChild(clock);
|
||||
acting.appendChild(clock);
|
||||
}
|
||||
|
||||
// A standing control rather than a toast per action: a dealer taps this bar
|
||||
@@ -410,9 +491,12 @@ const ActionBar = {
|
||||
key.textContent = this.KEY_HINTS.actionUndo;
|
||||
undo.appendChild(key);
|
||||
undo.addEventListener("click", () => this.hooks.undoLast());
|
||||
row.appendChild(undo);
|
||||
acting.appendChild(undo);
|
||||
}
|
||||
|
||||
// Nothing to act on and nothing to take back — no second line at all.
|
||||
if (acting.childElementCount) row.appendChild(acting);
|
||||
|
||||
return row;
|
||||
},
|
||||
|
||||
|
||||
@@ -156,9 +156,19 @@ describe("controls that must not resize under a thumb", () => {
|
||||
test("the undo pill has a fixed width, not a content width", () => {
|
||||
// It names the last action, so its label changes on every tap. Measured across
|
||||
// one hand before this: 148, 110, 109, 108, 109, 110, 120.
|
||||
const rule = css.match(/\.actionUndo\s*\{[^}]*\}/);
|
||||
assert.ok(rule, ".actionUndo rule not found");
|
||||
assert.match(rule[0], /width:\s*[0-9.]+rem/);
|
||||
//
|
||||
// A length at every breakpoint, never a percentage: `min(10rem, 34%)` was tried
|
||||
// and the percentage resolves against the row it sits in, which is sized to its
|
||||
// own contents — the two chase each other, and the sweep caught the pill drawn
|
||||
// 38px wide at ten viewports. A phone gets a narrower one through a media query
|
||||
// instead, which is still one width at a time.
|
||||
const rules = [...css.matchAll(/\.actionUndo\s*\{([^}]*)\}/g)].map(m => m[1]);
|
||||
assert.ok(rules.length, ".actionUndo rule not found");
|
||||
rules.filter(body => /(?<![\w-])width:/.test(body)).forEach(body =>
|
||||
assert.match(body, /(?<![\w-])width:\s*([0-9.]+rem|100%)/,
|
||||
"a content width would let the pill resize under the dealer's thumb"));
|
||||
assert.ok(rules.some(body => /(?<![\w-])width:\s*[0-9.]+rem/.test(body)),
|
||||
"the pill should still state a fixed width somewhere");
|
||||
});
|
||||
|
||||
test("and its label is the part that ellipsizes", () => {
|
||||
|
||||
@@ -15,6 +15,8 @@ const { ActionBar, Render } = require("./load");
|
||||
|
||||
const CSS = fs.readFileSync(
|
||||
path.join(__dirname, "..", "..", "JoshHeaps.Net", "wwwroot", "css", "casino", "holdem.css"), "utf8");
|
||||
const CSS_JS = fs.readFileSync(
|
||||
path.join(__dirname, "..", "..", "JoshHeaps.Net", "wwwroot", "js", "casino", "holdem", "actionBar.js"), "utf8");
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -160,6 +162,138 @@ describe("the button seat's name", () => {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("the table is sized against the bar, not against a pad over it", () => {
|
||||
// The raise pad is 57px taller than the row it replaces, and the felt was sized
|
||||
// against it. Measured with five players nine-handed, pressing Raise:
|
||||
//
|
||||
// 1280x900 felt 738x532 -> 669x481, pucks 120 -> 109, worst seat moved 73px
|
||||
// 360x640 felt 283x329 -> 283x279, pucks 44 -> 48, worst seat moved 50px
|
||||
//
|
||||
// The whole table jumped, re-ran the ten-candidate width search, and undid all of it
|
||||
// when the dealer pressed Raise to. Every raise, all night, at the one moment they
|
||||
// are reading the felt to decide what to type.
|
||||
//
|
||||
// A phone held sideways already scored 0px, because the rail is a column down the
|
||||
// side and its height never was the table's business. This is the upright layout
|
||||
// being held to what the sideways one already does.
|
||||
test.afterEach(() => { ActionBar.raiseOpen = false; delete ActionBar.barHeightAtRest; });
|
||||
|
||||
test("a closed bar is measured, and remembered", () => {
|
||||
ActionBar.raiseOpen = false;
|
||||
assert.equal(ActionBar.restingBarHeight(151), 151);
|
||||
assert.equal(ActionBar.barHeightAtRest, 151);
|
||||
});
|
||||
|
||||
test("and an open pad gets the height the bar had before it opened", () => {
|
||||
ActionBar.raiseOpen = false;
|
||||
ActionBar.restingBarHeight(151);
|
||||
ActionBar.raiseOpen = true;
|
||||
assert.equal(ActionBar.restingBarHeight(208), 151,
|
||||
"the felt would resize under the dealer's thumb mid-raise");
|
||||
});
|
||||
|
||||
test("and gets it back the moment the pad closes", () => {
|
||||
ActionBar.raiseOpen = false;
|
||||
ActionBar.restingBarHeight(151);
|
||||
ActionBar.raiseOpen = true;
|
||||
ActionBar.restingBarHeight(208);
|
||||
ActionBar.raiseOpen = false;
|
||||
assert.equal(ActionBar.restingBarHeight(172), 172,
|
||||
"a bar that really did grow — a side pot to show — still takes its room");
|
||||
});
|
||||
|
||||
test("a pad open before anything was ever measured takes what it can see", () => {
|
||||
// Nothing has been remembered yet, so the measurement is the only answer there
|
||||
// is. Better a felt sized for the pad than one sized for undefined.
|
||||
ActionBar.raiseOpen = true;
|
||||
delete ActionBar.barHeightAtRest;
|
||||
assert.equal(ActionBar.restingBarHeight(208), 208);
|
||||
});
|
||||
|
||||
test("the bar that is actually covering the window is still reported honestly", () => {
|
||||
// Only the felt's question is answered from the resting height. The toast has to
|
||||
// clear whatever is really there, and so does the page's scroll padding, so
|
||||
// --actionBarHeight stays a measurement.
|
||||
const publish = CSS_JS.slice(CSS_JS.indexOf("const publish = () => {"));
|
||||
const body = publish.slice(0, publish.indexOf("};"));
|
||||
assert.match(body, /--actionBarHeight[^\n]*Math\.round\(height\)/,
|
||||
"--actionBarHeight should still be the measured height");
|
||||
assert.match(body, /publishFeltRoom\(.*restingBarHeight\(height\)/,
|
||||
"the felt should be the one asking for the resting height");
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("the status block is the same number of lines whoever is acting", () => {
|
||||
// The bar is fixed to the bottom, so a line added to this block comes straight off
|
||||
// the felt. The block wraps, and flex settles its line breaks before it decides what
|
||||
// to shrink — so a name too long for the space left beside the clock and the undo
|
||||
// pill did not give way, it pushed them onto a third line.
|
||||
//
|
||||
// Measured at 360x640 mid-street: "Dee · $600 behind" left the table 283x329 and
|
||||
// "Christopher · $1,200 behind" made it 283x310, with every seat moving 24px between
|
||||
// one player and the next. Whose turn it was decided how big the table was.
|
||||
const acting = CSS.match(/\.actionActing \{([^}]*)\}/);
|
||||
const who = CSS.match(/\n\.actionWho \{([^}]*)\}/);
|
||||
const name = CSS.match(/\.actionWhoName \{([^}]*)\}/);
|
||||
const stack = CSS.match(/\.actionWhoStack \{([^}]*)\}/);
|
||||
|
||||
test("the acting row takes a line of its own, once there is somebody on it", () => {
|
||||
assert.ok(acting, ".actionActing rule not found");
|
||||
assert.match(acting[1], /flex:\s*0 1 auto/,
|
||||
"the pill on its own should not claim a line");
|
||||
const withActor = CSS.match(/\.actionActing:has\(\.actionWho\) \{([^}]*)\}/);
|
||||
assert.ok(withActor, "nothing gives the acting row its own line");
|
||||
assert.match(withActor[1], /flex:\s*1 1 100%/,
|
||||
"without a full basis it shares whatever line the wrap left it");
|
||||
});
|
||||
|
||||
test("and only then — a run-out has nobody to act and cannot spare the line", () => {
|
||||
// While a board is running out there is nobody to act, so this row is the undo
|
||||
// pill alone. Claiming a line for it is 22px off the felt on the twelve-handed
|
||||
// 360x640 table where the pucks are already at their 44px floor, and the sweep
|
||||
// caught that as a seat's "ALL IN" going back under the blind badge next door.
|
||||
assert.doesNotMatch(acting[1], /flex:\s*1 1 100%/);
|
||||
});
|
||||
|
||||
test("and it shrinks rather than wrapping", () => {
|
||||
// Left wrapping, this row reproduced the fault one level down: the undo pill is
|
||||
// a fixed width, so a long name pushed it onto a line of its own and the block
|
||||
// was 84px for some players and 66 for others.
|
||||
assert.match(acting[1], /flex-wrap:\s*nowrap/);
|
||||
});
|
||||
|
||||
test("the name is what gives way", () => {
|
||||
// `min-width` on a flex item defaults to `auto` — "never smaller than your own
|
||||
// content" — which is why the ellipsis this was written with never once appeared.
|
||||
assert.ok(who && name, "the actor should be a name and an amount, not one string");
|
||||
assert.match(who[1], /min-width:\s*0/);
|
||||
assert.match(name[1], /min-width:\s*0/);
|
||||
assert.match(name[1], /text-overflow:\s*ellipsis/);
|
||||
});
|
||||
|
||||
test("and the stack is what does not", () => {
|
||||
// The same rule the seat pucks keep: a number read wrong is a worse failure than
|
||||
// a name read short, so the stack keeps every digit.
|
||||
assert.ok(stack, ".actionWhoStack rule not found");
|
||||
assert.match(stack[1], /flex:\s*none/);
|
||||
});
|
||||
|
||||
test("except in the rail, which is a column and has no line to shrink into", () => {
|
||||
// 190px wide: every one of these readings is on its own line there regardless,
|
||||
// and squeezing a name into a fifth of the column would be shrinking to fit a
|
||||
// row that isn't there.
|
||||
const rules = [...CSS.matchAll(/\.actionActing \{([^}]*)\}/g)].map(m => m[1]);
|
||||
assert.equal(rules.length, 2,
|
||||
"one rule for the bar and one for the rail — no more, no fewer");
|
||||
assert.ok(rules.some(body => /flex-wrap:\s*wrap\s*;/.test(body)),
|
||||
"the rail should say what it wants instead");
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("how much of the bottom is spoken for", () => {
|
||||
// feltRoomFor asks one question — what is under the felt — and gets two different
|
||||
// answers depending on the layout. Under the bar it is the bar. Under the rail it is
|
||||
|
||||
Reference in New Issue
Block a user