diff --git a/README.md b/README.md index f92b2175..73883ebe 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ npm run build # writes dist/ and regenerates index.html; the folder is wh The browser suite and the three example games need a machine with a GPU: ```bash -node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 1285 checks (GM_STEPS=20 for one step) +node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 1286 checks (GM_STEPS=20 for one step) # every tool signs in first – see the Accounts page node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs diff --git a/src/editor/debugHook.ts b/src/editor/debugHook.ts index 45d927f7..669e3d5b 100644 --- a/src/editor/debugHook.ts +++ b/src/editor/debugHook.ts @@ -210,6 +210,11 @@ export function installDebugHook(app: Application, state: EditorState, editor: E inspectorField: fieldOf, /** The inspector panel on screen – what tells whether a row of it can be clicked at all. */ inspectorRect: () => rectOf(inspector), + /** Where the focused widget sits on screen, or `null` – for checks on its focus border. */ + focusedRect: () => { + const widget = ui().focus.focused; + return widget ? rectOf(widget) : null; + }, inspectorInfo: () => inspector.debugInfo(), textColor, overlayTexts, diff --git a/src/ui/Theme.ts b/src/ui/Theme.ts index e37242f6..15270b92 100644 --- a/src/ui/Theme.ts +++ b/src/ui/Theme.ts @@ -12,7 +12,7 @@ export const Theme = { controlHeight: 24, padding: 8, gap: 4, - radius: 8, + radius: 2, fieldPadding: 4, checkboxSize: 16, scrollbarWidth: 4, diff --git a/src/ui/widgets/TextField.ts b/src/ui/widgets/TextField.ts index b2f48b38..98910d95 100644 --- a/src/ui/widgets/TextField.ts +++ b/src/ui/widgets/TextField.ts @@ -1,4 +1,4 @@ -import { CanvasTextMetrics, type FederatedPointerEvent, Graphics, Text } from 'pixi.js'; +import { CanvasTextMetrics, Container, type FederatedPointerEvent, Graphics, Text } from 'pixi.js'; import { pressCount } from '../clicks'; import { drawControlBox } from '../draw'; import type { TextEditTarget } from '../KeyboardBridge'; @@ -66,15 +66,12 @@ export class TextField extends Widget implements TextEditTarget { this.minWidth = options.width ?? 80; this.textNode = new Text({ text: value, style: textStyle(options.style ?? 'body') }); this.placeholderNode = new Text({ text: this.placeholder, style: textStyle('muted') }); - this.addChild( - this.bg, - this.selectionShape, - this.placeholderNode, - this.textNode, - this.caret, - this.clipShape, - ); - this.mask = this.clipShape; + // Only the contents are clipped: a mask on the whole field cut its border away along the + // straight edges and left it showing at the rounded corners alone. + const content = new Container(); + content.addChild(this.selectionShape, this.placeholderNode, this.textNode, this.caret); + content.mask = this.clipShape; + this.addChild(this.bg, content, this.clipShape); this.trackHover(); this.on('pointerdown', (e: FederatedPointerEvent) => this.handlePointerDown(e)); diff --git a/tools/e2e/02-inspector.mjs b/tools/e2e/02-inspector.mjs index c2c35d28..8fd9bc8a 100644 --- a/tools/e2e/02-inspector.mjs +++ b/tools/e2e/02-inspector.mjs @@ -63,6 +63,21 @@ export async function inspector(t) { await press('a', { ctrl: true }); await typeText('Renamed crate'); await shot('03-typing'); + // The focus border runs all the way round, not only through the rounded corners: the field's + // clip once took in its own border and cut the straight edges away. + const field = await json(`__gm.focusedRect()`); + const edges = field + ? await json( + `[[${field.x + field.w / 2}, ${field.y}], [${field.x + field.w / 2}, ${field.y + field.h - 1}],` + + ` [${field.x}, ${field.y + field.h / 2}], [${field.x + field.w - 1}, ${field.y + field.h / 2}]]` + + `.map(([x, y]) => __gm.pixelAt(Math.round(x), Math.round(y)))`, + ) + : []; + check( + 'the focused field is outlined along all four edges', + edges.length === 4 && edges.every((c) => c === '#4c8dff'), + JSON.stringify({ field, edges }), + ); await press('Enter'); check( 'typing + Enter renamed the object',