diff --git a/src/common/TrackLabButtonOptions.ts b/src/common/TrackLabButtonOptions.ts index 02dbfa1..a605c9d 100644 --- a/src/common/TrackLabButtonOptions.ts +++ b/src/common/TrackLabButtonOptions.ts @@ -4,22 +4,28 @@ * Shared flat button appearance for the sim. Rectangular and round push buttons * default to SceneryStack's 3-D appearance; pass these options (or spread them * into nested button options) for a flat look everywhere. + * + * Template-owned toolkit: each sim uses only some of these, so every export is tagged + * `@public` to tell dead-code checkers (knip) that an unused one is not dead code. */ import type { PlayPauseStepButtonGroupOptions, TimeControlNodeOptions } from "scenerystack/scenery-phet"; import { ButtonNode, type ComboBoxOptions } from "scenerystack/sun"; import TrackLabColors from "../TrackLabColors.js"; +/** @public */ export const FLAT_BUTTON_APPEARANCE_OPTIONS = { buttonAppearanceStrategy: ButtonNode.FlatAppearanceStrategy, } as const; -/** Text on flat push buttons and combo-box items (always on a light control surface). */ +/** Text on flat push buttons and combo-box items (always on a light control surface). @public */ export const LIGHT_SURFACE_TEXT_FILL = TrackLabColors.controlSurfaceTextColorProperty; /** * Combo-box chrome for panels. Item labels must use {@link LIGHT_SURFACE_TEXT_FILL}, not * {@link TrackLabColors.textColorProperty} — that color is for labels on the dark panel fill. + * + * @public */ export const SIM_COMBO_BOX_OPTIONS = { buttonFill: TrackLabColors.controlSurfaceColorProperty, @@ -28,13 +34,13 @@ export const SIM_COMBO_BOX_OPTIONS = { listStroke: TrackLabColors.panelBorderColorProperty, } satisfies Pick; -/** Options for RectangularPushButton and NumberControl arrow buttons. */ -export const FLAT_RECTANGULAR_BUTTON_OPTIONS = FLAT_BUTTON_APPEARANCE_OPTIONS; +/** Options for RectangularPushButton and NumberControl arrow buttons. @public */ +export const FLAT_RECTANGULAR_BUTTON_OPTIONS = { ...FLAT_BUTTON_APPEARANCE_OPTIONS } as const; -/** Options for ResetAllButton (extends RoundPushButton). */ -export const FLAT_RESET_ALL_BUTTON_OPTIONS = FLAT_BUTTON_APPEARANCE_OPTIONS; +/** Options for ResetAllButton (extends RoundPushButton). @public */ +export const FLAT_RESET_ALL_BUTTON_OPTIONS = { ...FLAT_BUTTON_APPEARANCE_OPTIONS } as const; -/** Nested options for TimeControlNode play / pause / step round buttons. */ +/** Nested options for TimeControlNode play / pause / step round buttons. @public */ export const FLAT_PLAY_PAUSE_STEP_BUTTON_OPTIONS = { playPauseButtonOptions: FLAT_BUTTON_APPEARANCE_OPTIONS, stepForwardButtonOptions: FLAT_BUTTON_APPEARANCE_OPTIONS, @@ -44,6 +50,8 @@ export const FLAT_PLAY_PAUSE_STEP_BUTTON_OPTIONS = { /** * Speed radio labels for TimeControlNode. SceneryStack Text defaults to black, which * is low-contrast on the sim's dark Default-mode panels. + * + * @public */ export const TIME_CONTROL_SPEED_RADIO_OPTIONS = { speedRadioButtonGroupOptions: { diff --git a/tests/fuzz/fuzz.spec.ts b/tests/fuzz/fuzz.spec.ts index db20e4a..c358093 100644 --- a/tests/fuzz/fuzz.spec.ts +++ b/tests/fuzz/fuzz.spec.ts @@ -94,7 +94,7 @@ async function runFuzz(page: Page, fuzzUrl: string): Promise { await page.waitForTimeout(waitTime); elapsed += waitTime; try { - await page.evaluate(() => window.document.hasFocus); + await page.evaluate(() => window.document.hasFocus()); } catch { break; } diff --git a/tests/helpers/memoryLeak.ts b/tests/helpers/memoryLeak.ts index f086253..03a8b64 100644 --- a/tests/helpers/memoryLeak.ts +++ b/tests/helpers/memoryLeak.ts @@ -13,6 +13,7 @@ import { describe, expect, it } from "vitest"; +/** @public */ export type DisposableObject = { dispose(): void }; export type DisposalCase = { @@ -34,6 +35,8 @@ export type DisposalCase = { * avoids the WeakRef macrotask-liveness pin. Without refs the loop always runs all * passes, which on a slow gc() can exceed the Vitest testTimeout — pass refs when * you have them. + * + * @public */ export async function forceGC(earlyExitRefs?: WeakRef | readonly WeakRef[]): Promise { const refs = earlyExitRefs === undefined ? [] : Array.isArray(earlyExitRefs) ? earlyExitRefs : [earlyExitRefs]; @@ -49,7 +52,7 @@ export async function forceGC(earlyExitRefs?: WeakRef | readonly WeakRef } } -/** Create, dispose, and return a WeakRef to the disposed instance. */ +/** Create, dispose, and return a WeakRef to the disposed instance. @public */ export function createAndDispose(create: () => DisposableObject): WeakRef { const instance = create(); const ref = new WeakRef(instance); diff --git a/tests/setup.ts b/tests/setup.ts index 4eca38e..30072ca 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -167,6 +167,8 @@ if (typeof globalThis.Worker === "undefined") { // its real type is a large overload union (widened further by @webgpu/types), // and a spread argument cannot be applied to an overload union. type LooseGetContext = (this: HTMLCanvasElement, contextId: string, ...args: unknown[]) => unknown; +// Detached on purpose: it is only ever invoked as `origGetContext.call(this, …)` below. +// oxlint-disable-next-line typescript/unbound-method const origGetContext = HTMLCanvasElement.prototype.getContext as unknown as LooseGetContext; HTMLCanvasElement.prototype.getContext = function (this: HTMLCanvasElement, contextId: string, ...args: unknown[]) { if (contextId === "2d") {