@orkestrel/test 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,28 @@ export declare const ACCESSIBLE_ROLES: readonly string[];
22
22
  */
23
23
  export declare function blendColor(front: Color, back: Color): Color;
24
24
 
25
+ /**
26
+ * Builds one unmounted element of a known tag, wearing the classes, text, and attributes asked for.
27
+ *
28
+ * @param tag - The HTML tag name, which fixes the returned element's exact type.
29
+ * @param options - The class list, the text, and the attributes to apply.
30
+ * @returns The built element, not yet in any document.
31
+ *
32
+ * @remarks
33
+ * The element is unmounted on purpose, so a fixture is assembled before the page ever sees it and a
34
+ * test decides where it goes. Nothing here resolves against the cascade: a built element computes no
35
+ * style and lays out no box until {@link mount} puts it in the document.
36
+ *
37
+ * The text is set as text rather than parsed as markup, so a `<` in it stays a `<`. Use
38
+ * {@link render} where the fixture is markup.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const button = build('button', { classes: 'primary', text: 'Save', attributes: { type: 'button' } })
43
+ * ```
44
+ */
45
+ export declare function build<K extends keyof HTMLElementTagNameMap>(tag: K, options?: ElementOptions): HTMLElementTagNameMap[K];
46
+
25
47
  /**
26
48
  * The page a browser paints an unstyled document onto.
27
49
  *
@@ -178,6 +200,51 @@ export declare function clickDisclosure(name: string): Promise<void>;
178
200
  */
179
201
  export declare type Color = readonly [red: number, green: number, blue: number, alpha: number];
180
202
 
203
+ /**
204
+ * Determines whether two colors render the same, within the rounding a browser does.
205
+ *
206
+ * @param first - A CSS color expression or an already-parsed color.
207
+ * @param second - A CSS color expression or an already-parsed color.
208
+ * @returns `true` when every channel and the alpha agree within the tolerance; `false` otherwise,
209
+ * including when either side names no readable color.
210
+ *
211
+ * @remarks
212
+ * Each string side is resolved through {@link rgba}, so a keyword, a token reference, and the
213
+ * `rgb()` the engine computes for either of them compare equal without a test converting anything
214
+ * first. A side that resolves to nothing makes the answer `false` rather than a throw, because this
215
+ * is a predicate.
216
+ *
217
+ * The tolerance is half a channel step on the 0–255 scale, and the alpha is scaled onto that same
218
+ * range before it is compared, so one number covers both. Half a step is what a composite of
219
+ * translucent layers and a `color-mix()` round trip actually drift by; anything a reader could see
220
+ * is further than that and reports unequal.
221
+ *
222
+ * @example
223
+ * ```ts
224
+ * colorEqual('rebeccapurple', 'rgb(102, 51, 153)') // true
225
+ * colorEqual('red', [0, 0, 255, 1]) // false
226
+ * ```
227
+ */
228
+ export declare function colorEqual(first: string | Color, second: string | Color): boolean;
229
+
230
+ /**
231
+ * Sets one field's value and commits it, the way typing and then leaving the field does.
232
+ *
233
+ * @param element - The input or textarea to write into.
234
+ * @param text - The value to set.
235
+ *
236
+ * @remarks
237
+ * The order is the browser's: {@link typeInput} first, so `input` is dispatched with the value
238
+ * already set, and one bubbling `change` after it. A component that reads the value from either
239
+ * event therefore reads `text` from both.
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * commitInput(requireValue(container.querySelector('input')), 'Ada')
244
+ * ```
245
+ */
246
+ export declare function commitInput(element: HTMLInputElement | HTMLTextAreaElement, text: string): void;
247
+
181
248
  /**
182
249
  * The roles whose accessible name is the text a reader can see inside them.
183
250
  *
@@ -226,6 +293,60 @@ export declare const CONTENT_ROLES: readonly string[];
226
293
  */
227
294
  export declare function contrast(element: Element, floor?: Color): number;
228
295
 
296
+ /**
297
+ * Creates one console channel that records every call it receives and hands that call on unchanged.
298
+ *
299
+ * @param name - The channel's name, which prefixes each line it records.
300
+ * @param output - The list each call is recorded into, appended to in place.
301
+ * @param forward - The channel every call is passed on to after it is recorded.
302
+ * @returns A channel carrying the console's own call signature.
303
+ *
304
+ * @remarks
305
+ * One call becomes one line. Every argument of that call is put through `String` and joined with a
306
+ * space, so a call carrying several values reads as the one line the page printed rather than as
307
+ * several entries.
308
+ *
309
+ * Nothing is swallowed. The record happens first and `forward` receives the arguments it would have
310
+ * received, so a page recorded through this prints exactly what it printed without it. The list
311
+ * belongs to the caller, so a channel writes into whatever it was handed and holds no state of its
312
+ * own. {@link createJournal} builds one channel per console method over one list.
313
+ *
314
+ * @example
315
+ * ```ts
316
+ * const output: string[] = []
317
+ * console.log = createChannel('log', output, console.log)
318
+ * ```
319
+ */
320
+ export declare function createChannel(name: string, output: string[], forward: (...data: unknown[]) => void): (...data: unknown[]) => void;
321
+
322
+ /**
323
+ * Creates one real drag event carrying a live data transfer, ready to dispatch.
324
+ *
325
+ * @param name - The event type, such as `dragstart`.
326
+ * @param options - Any `DragEventInit` member, each one overriding the default beneath it.
327
+ * @returns A real `DragEvent` of that type.
328
+ *
329
+ * @remarks
330
+ * A drag event with no `dataTransfer` is the shape that makes a drop handler fail in a test and work
331
+ * in a browser, so one is allocated. Pass your own to seed it: a `dataTransfer` given in `options`
332
+ * replaces the allocated one, which is how a drop is driven with the payload the drag was supposed
333
+ * to carry.
334
+ *
335
+ * The platform declares the `dataTransfer` member on the constructed event as nullable, so calling
336
+ * code still narrows it even though this always supplies one.
337
+ *
338
+ * `bubbles` and `cancelable` are set, because a drop handler that never prevents the default event
339
+ * is a drop the browser handles itself.
340
+ *
341
+ * @example
342
+ * ```ts
343
+ * const started = createDragEvent('dragstart')
344
+ * started.dataTransfer?.setData('text/plain', 'row-3')
345
+ * element.dispatchEvent(started)
346
+ * ```
347
+ */
348
+ export declare function createDragEvent(name: string, options?: DragEventInit): DragEvent;
349
+
229
350
  /**
230
351
  * Creates the journal one scenario records its steps and the page's own output into.
231
352
  *
@@ -252,6 +373,30 @@ export declare function contrast(element: Element, floor?: Color): number;
252
373
  */
253
374
  export declare function createJournal(): JournalInterface;
254
375
 
376
+ /**
377
+ * Creates one real pointer event, ready to dispatch.
378
+ *
379
+ * @param name - The event type, such as `pointerdown`.
380
+ * @param options - Any `PointerEventInit` member, each one overriding the default beneath it.
381
+ * @returns A real `PointerEvent` of that type.
382
+ *
383
+ * @remarks
384
+ * The defaults are what a browser's own pointer event carries and a hand-built one does not:
385
+ * `bubbles` and `cancelable` are set, so a delegated listener hears it and a handler can prevent it,
386
+ * and `pointerId`, `pointerType`, and `isPrimary` describe a single primary mouse, so a component
387
+ * that branches on the pointer kind takes the branch a mouse takes. Override any of them by naming
388
+ * it; a touch is `{ pointerType: 'touch' }` and nothing else has to be restated.
389
+ *
390
+ * The event is real rather than a shaped object, so `instanceof PointerEvent` holds and the
391
+ * coordinate and modifier members a handler reads are the ones the platform defines.
392
+ *
393
+ * @example
394
+ * ```ts
395
+ * element.dispatchEvent(createPointerEvent('pointerdown', { clientX: 10, clientY: 20 }))
396
+ * ```
397
+ */
398
+ export declare function createPointerEvent(name: string, options?: PointerEventInit): PointerEvent;
399
+
255
400
  /**
256
401
  * Creates the capture portfolio one run places its screenshots through.
257
402
  *
@@ -333,6 +478,24 @@ export declare function describeFocus(element: Element): string;
333
478
  */
334
479
  export declare function describeTree(element: Element): string;
335
480
 
481
+ /**
482
+ * Options for one built element.
483
+ *
484
+ * @remarks
485
+ * `classes` is written the way a `class` attribute is written — one space-separated string — so a
486
+ * fixture reads as the markup it stands in for. `attributes` is set name by name after the class
487
+ * list and the text, so an `attributes` entry named `class` wins over `classes` rather than merging
488
+ * with it.
489
+ */
490
+ export declare interface ElementOptions {
491
+ /** The class list, space-separated, exactly as a `class` attribute writes it. */
492
+ readonly classes?: string;
493
+ /** The text the element carries, set as text rather than parsed as markup. */
494
+ readonly text?: string;
495
+ /** Every attribute to set, keyed by attribute name. */
496
+ readonly attributes?: Readonly<Record<string, string>>;
497
+ }
498
+
336
499
  /**
337
500
  * Expands a capture registry across every variant into the filenames a complete portfolio holds.
338
501
  *
@@ -407,6 +570,49 @@ export declare const FIELD_ROLES: Readonly<Record<string, string>>;
407
570
  */
408
571
  export declare function fillAccessible(name: string, text: string): Promise<void>;
409
572
 
573
+ /**
574
+ * Finds the animation the cascade declares under one name.
575
+ *
576
+ * @param name - The exact `@keyframes` name.
577
+ * @returns The first matching rule in {@link readRules} order, or `undefined` when the cascade
578
+ * declares no animation under that name.
579
+ *
580
+ * @remarks
581
+ * The name is matched exactly, which is where this parts from {@link findRule}: a selector is
582
+ * compound and a fragment of one is a useful question, and an animation name is one atom that either
583
+ * is or is not the one an `animation` declaration references.
584
+ *
585
+ * @example
586
+ * ```ts
587
+ * findKeyframes('fade')?.cssRules.length
588
+ * ```
589
+ */
590
+ export declare function findKeyframes(name: string): CSSKeyframesRule | undefined;
591
+
592
+ /**
593
+ * Finds the first style rule in the cascade whose selector carries a fragment.
594
+ *
595
+ * @param selector - The selector fragment to look for, matched as a substring of the whole selector
596
+ * text.
597
+ * @returns The first matching rule in {@link readRules} order, or `undefined` when no rule carries
598
+ * the fragment.
599
+ *
600
+ * @remarks
601
+ * This proves a declaration exists in the cascade at all, which is a different question from what an
602
+ * element resolves to: {@link style} reads the winner, and a rule this finds may be overridden by
603
+ * another. Assert on this where the subject is the stylesheet, and on `style` where the subject is
604
+ * the rendered result.
605
+ *
606
+ * The match is a substring, so `findRule('.card')` finds `.card`, `.card:hover`, and
607
+ * `.panel > .card` alike. Pass more of the selector to narrow it.
608
+ *
609
+ * @example
610
+ * ```ts
611
+ * findRule('.card')?.style.getPropertyValue('padding')
612
+ * ```
613
+ */
614
+ export declare function findRule(selector: string): CSSStyleRule | undefined;
615
+
410
616
  /**
411
617
  * What sequential keyboard navigation can reach, before disabled and unrendered elements go.
412
618
  *
@@ -608,6 +814,35 @@ export declare function measureContrast(front: Color, back: Color): number;
608
814
  */
609
815
  export declare function measureLuminance(color: Color): number;
610
816
 
817
+ /**
818
+ * Puts one element into the document and hands it straight back.
819
+ *
820
+ * @param element - The element to attach.
821
+ * @returns The same element, now appended to `document.body`.
822
+ *
823
+ * @remarks
824
+ * What this buys is the composition, not the attachment: the `append` method returns `void`, and
825
+ * this hands the element back, so it fits where an expression is expected. The {@link render} helper
826
+ * returns its fixture through it, and the {@link rgba} helper probes through `mount(build('span'))`.
827
+ * A bare `append` call breaks each of those call sites.
828
+ *
829
+ * Being connected is what the attachment then buys: `getComputedStyle` resolves against the shipped
830
+ * cascade, custom properties inherit from `:root`, and the element lays out a real box. A detached
831
+ * element answers each of those questions with the initial value instead, which reads as a styling
832
+ * defect rather than as a detached node.
833
+ *
834
+ * Taking it back out belongs to the consumer's teardown, because this records nothing: a browser
835
+ * test file shares one page, so a fixture left behind is the next test's resolver ambiguity. Build a
836
+ * recorded container in a setup module and remove it from an `afterEach` hook.
837
+ *
838
+ * @example
839
+ * ```ts
840
+ * const panel = mount(build('div', { classes: 'surface' }))
841
+ * panel.remove()
842
+ * ```
843
+ */
844
+ export declare function mount<T extends Element>(element: T): T;
845
+
611
846
  /**
612
847
  * Parses one computed CSS color value into straight sRGB channels.
613
848
  *
@@ -630,6 +865,31 @@ export declare function measureLuminance(color: Color): number;
630
865
  */
631
866
  export declare function parseColor(value: string): Color | undefined;
632
867
 
868
+ /**
869
+ * Reads one resolved CSS length as a number of pixels.
870
+ *
871
+ * @param element - The element whose resolved style to inspect.
872
+ * @param property - The CSS property name, registered or custom.
873
+ * @returns The leading numeric part of the resolved value, and `0` when it carries none.
874
+ *
875
+ * @remarks
876
+ * A resolved length is text with a unit — `'12px'` — so this reads the number in front of the unit
877
+ * and discards the rest. The unit is not checked: the resolved value of a length is in pixels in
878
+ * every case a browser hands back, and a property that resolves to something else is the caller's
879
+ * mistake rather than this reader's.
880
+ *
881
+ * An unparsable value reads as `0` rather than as absence, because every caller of this is measuring
882
+ * and `'auto'`, `'none'`, and `''` each contribute no pixels to what a reader sees. Where the
883
+ * distinction matters, read the text with {@link style} instead.
884
+ *
885
+ * @example
886
+ * ```ts
887
+ * pixels(button, 'padding-left') // 12
888
+ * pixels(button, 'width') // 0 when the width resolves to `auto`
889
+ * ```
890
+ */
891
+ export declare function pixels(element: Element, property: string): number;
892
+
633
893
  /** The registry of capture states one run places, and the files it wrote placing them. */
634
894
  export declare interface PortfolioInterface {
635
895
  /** The name of the variant this run renders. */
@@ -715,12 +975,24 @@ export declare function readBackdrop(element: Element, floor: Color): Color;
715
975
  /**
716
976
  * Collects every class token the stylesheets loaded into this document actually define.
717
977
  *
718
- * @returns The set of class names reachable in the shipped cascade.
978
+ * @returns The set of class names reachable in the shipped cascade, in {@link readRules} order.
719
979
  *
720
980
  * @remarks
721
981
  * The set is what an authored-class conformance check measures against, so a class no loaded
722
982
  * stylesheet defines — an invented utility, a misspelled framework name — is absent from it.
723
983
  *
984
+ * The tokens come from the {@link readRules} walk, which decides both the membership and the
985
+ * insertion order this reader reports, and each answer is a deliberate difference from 0.0.8. A
986
+ * class declared inside a grouping rule — a media query, a supports block, a layer, a nested style
987
+ * rule — counts as defined, because a class the cascade defines under a condition is still one the
988
+ * cascade defines; 0.0.8 read the top-level rules alone. Insertion order is breadth-first, so a
989
+ * top-level class lands before a class declared inside an earlier grouping rule; 0.0.8 popped a
990
+ * stack and inserted the deepest rule first. Iterate the set where the order is the subject, and
991
+ * read `has` where membership is.
992
+ *
993
+ * `@keyframes` children are outside that walk, so an animation's own rules define no token here.
994
+ * Reach the animation itself through {@link findKeyframes}.
995
+ *
724
996
  * @example
725
997
  * ```ts
726
998
  * readCascade().has('card')
@@ -905,6 +1177,35 @@ export declare function readRole(element: Element): string | undefined;
905
1177
  */
906
1178
  export declare function readRows(root: ParentNode, selector: string): readonly string[];
907
1179
 
1180
+ /**
1181
+ * Collects every rule the stylesheets loaded into this document hold, nested grouping rules
1182
+ * included.
1183
+ *
1184
+ * @returns Every rule reachable in the shipped cascade: each sheet's own rules in sheet order, then
1185
+ * the rules nested inside them, level by level.
1186
+ *
1187
+ * @remarks
1188
+ * The walk is iterative and reads the list it is still appending to, which is what expands a media
1189
+ * query, a supports block, a layer, and a nested style rule without recursion. Expanding by level
1190
+ * rather than by depth is why a top-level rule is always met before a rule nested inside an earlier
1191
+ * one; {@link findRule} returns the first match in exactly this order.
1192
+ *
1193
+ * The descent reaches a `CSSGroupingRule` and nothing else, and a `@keyframes` rule is not one. The
1194
+ * `@keyframes` rule itself is collected wherever it sits, and the keyframe rules inside it are not;
1195
+ * {@link findKeyframes} is the door to those.
1196
+ *
1197
+ * A stylesheet the document cannot read — a cross-origin sheet with no CORS grant — throws from its
1198
+ * own `cssRules` getter, and that sheet is skipped rather than ending the walk. What a page loaded
1199
+ * from another origin declares is unreadable to every caller here, so the alternative is a helper
1200
+ * that works until a test page adds a font or an analytics stylesheet.
1201
+ *
1202
+ * @example
1203
+ * ```ts
1204
+ * readRules().filter((rule) => rule instanceof CSSKeyframesRule)
1205
+ * ```
1206
+ */
1207
+ export declare function readRules(): readonly CSSRule[];
1208
+
908
1209
  /**
909
1210
  * Reads the states one element is announced in.
910
1211
  *
@@ -984,19 +1285,57 @@ export declare function readValue(role: string, name: string): string;
984
1285
  export declare function releasePane(): void;
985
1286
 
986
1287
  /**
987
- * Renders trusted fixture markup into a container attached to the document.
1288
+ * Deletes one IndexedDB database and reports what the request actually did.
1289
+ *
1290
+ * @param name - The database name to delete.
1291
+ * @returns A promise resolving after the deletion completes.
1292
+ * @throws Thrown when the request errors, and when an open connection blocks it.
1293
+ *
1294
+ * @remarks
1295
+ * Deleting a database that was never created succeeds, so this is safe to call from a teardown hook
1296
+ * that runs whether or not the test reached the code that opens one.
1297
+ *
1298
+ * A block is a rejection rather than a wait. `blocked` fires when another connection is still open,
1299
+ * and a suite that swallowed it would leave the next test reading the previous test's records
1300
+ * through a database that reports itself deleted. The connection holding it open is the caller's to
1301
+ * close, so the block is handed back rather than absorbed.
1302
+ *
1303
+ * @example
1304
+ * ```ts
1305
+ * afterEach(() => removeDatabase('ledger'))
1306
+ * ```
1307
+ */
1308
+ export declare function removeDatabase(name: string): Promise<void>;
1309
+
1310
+ /**
1311
+ * Renders one fixture into the document, from trusted markup or from a tag and its classes.
1312
+ *
1313
+ * @param first - The fixture markup, or the HTML tag name when `second` is present.
1314
+ * @param second - The class list when `first` supplies the tag name.
1315
+ * @returns The attached container for the markup form, and the attached element itself for the tag
1316
+ * form.
1317
+ *
1318
+ * @remarks
1319
+ * The class list is required in the tag form, which is what keeps the two forms apart: a
1320
+ * one-argument call is always markup. A tag with no classes is `mount(build(tag))`.
988
1321
  *
989
- * @param markup - The fixture markup to render.
990
- * @returns The attached container.
1322
+ * The markup form parses `first` into a fresh container and returns that container, so the fixture's
1323
+ * own nodes are its children. The tag form returns the element itself, typed as exactly that tag.
1324
+ * Both attach to `document.body` and neither records anything, so removal is the caller's, exactly
1325
+ * as it is for {@link mount}.
991
1326
  *
992
1327
  * @example
993
1328
  * ```ts
994
1329
  * const container = render('<button type="button">Save</button>')
1330
+ * const panel = render('section', 'surface muted')
995
1331
  * container.remove()
1332
+ * panel.remove()
996
1333
  * ```
997
1334
  */
998
1335
  export declare function render(markup: string): HTMLDivElement;
999
1336
 
1337
+ export declare function render<K extends keyof HTMLElementTagNameMap>(tag: K, classes: string): HTMLElementTagNameMap[K];
1338
+
1000
1339
  /**
1001
1340
  * Resolves one visible, focus-reachable interactive element by its exact accessible name. A
1002
1341
  * wholly-off-viewport target is scrolled into view before reachability is measured.
@@ -1054,6 +1393,57 @@ export declare function resolveAccessible(role: string, name: string): HTMLEleme
1054
1393
  */
1055
1394
  export declare function resolveRendered(first: string, second?: string): HTMLElement;
1056
1395
 
1396
+ /**
1397
+ * Resolves any CSS color expression to straight sRGB channels, by asking the browser.
1398
+ *
1399
+ * @param value - Any value the `color` property accepts: a keyword, a hex triple, a `var()`
1400
+ * reference, a `color-mix()`, or an already-computed `rgb()`.
1401
+ * @returns The resolved color's channels, or `undefined` when the CSSOM refuses the value or the
1402
+ * computed result names no color {@link parseColor} speaks.
1403
+ *
1404
+ * @remarks
1405
+ * This is the live half of the pair {@link parseColor} opens. `parseColor` reads text and speaks
1406
+ * only the computed syntaxes a cascade hands back; this stages a probe element, hands it to the real
1407
+ * cascade, and reads back what the engine computed — which is the only way a keyword, a hex triple,
1408
+ * or a `var()` reference becomes channels at all. The read itself goes through `parseColor`, so both
1409
+ * halves agree on what a computed value means.
1410
+ *
1411
+ * The probe is mounted, because an unmounted element inherits nothing and a `var()` reference to a
1412
+ * token declared on `:root` would resolve to the initial value instead. It is removed in a `finally`,
1413
+ * so a value that throws on the way through leaves no node behind.
1414
+ *
1415
+ * Refusal is the CSSOM's: an expression it will not parse leaves the probe's inline `color` empty
1416
+ * and this returns `undefined`. A `var()` naming an undeclared custom property is not refused,
1417
+ * because the cascade accepts it and computes the inherited color, so a test that means to catch a
1418
+ * missing token asserts on {@link token} rather than on this.
1419
+ *
1420
+ * @example
1421
+ * ```ts
1422
+ * rgba('rebeccapurple') // [102, 51, 153, 1]
1423
+ * rgba('not-a-color') // undefined
1424
+ * ```
1425
+ */
1426
+ export declare function rgba(value: string): Color | undefined;
1427
+
1428
+ /**
1429
+ * Reads one custom property from the document element.
1430
+ *
1431
+ * @param name - The custom property name, with or without its leading dashes.
1432
+ * @returns The resolved value, trimmed; an empty string when the document declares no such property.
1433
+ *
1434
+ * @remarks
1435
+ * This is {@link token} against `document.documentElement`, which is where a theme declares its
1436
+ * tokens and where a `[data-theme]` switch retunes them. It exists as its own name because that
1437
+ * element is the one a token question is nearly always about, and naming it at every call site
1438
+ * buries the question.
1439
+ *
1440
+ * @example
1441
+ * ```ts
1442
+ * rootToken('surface')
1443
+ * ```
1444
+ */
1445
+ export declare function rootToken(name: string): string;
1446
+
1057
1447
  /**
1058
1448
  * Sets the tester's viewport and renders the runner's pane at the size that viewport claims.
1059
1449
  *
@@ -1099,8 +1489,13 @@ export declare function stagePane(width: number, height: number): Promise<void>;
1099
1489
  * Reads one resolved CSS property from a real browser element.
1100
1490
  *
1101
1491
  * @param element - The element whose resolved style to inspect.
1102
- * @param property - The CSS property name.
1103
- * @returns The browser's resolved property value.
1492
+ * @param property - The CSS property name, registered or custom.
1493
+ * @returns The browser's resolved property value, trimmed; an empty string when the element resolves
1494
+ * none.
1495
+ *
1496
+ * @remarks
1497
+ * The value is trimmed, so what comes back is the value and never the whitespace around it. Internal
1498
+ * whitespace is kept: `--shadow: 0 0 2px` reads back with its spaces.
1104
1499
  *
1105
1500
  * @example
1106
1501
  * ```ts
@@ -1109,6 +1504,32 @@ export declare function stagePane(width: number, height: number): Promise<void>;
1109
1504
  */
1110
1505
  export declare function style(element: Element, property: string): string;
1111
1506
 
1507
+ /**
1508
+ * Reads one custom property from an element's resolved style.
1509
+ *
1510
+ * @param element - The element whose resolved style to inspect.
1511
+ * @param name - The custom property name, with or without its leading dashes.
1512
+ * @returns The resolved value, trimmed; an empty string when the element inherits no such property.
1513
+ *
1514
+ * @remarks
1515
+ * The dashes are optional because a token is spoken about both ways — `--surface` in a stylesheet
1516
+ * and `surface` in prose — and a reader that accepted only one spelling would turn that into a silent
1517
+ * empty string. An absent token reads as `''`, which is what the CSSOM returns and is
1518
+ * indistinguishable from a token declared empty; assert on the value you expect rather than on
1519
+ * presence.
1520
+ *
1521
+ * Resolution is inheritance, so a token declared on `:root` reads from any mounted descendant and
1522
+ * from an unmounted element reads as `''`. Use {@link rootToken} where the declaration is the
1523
+ * document's.
1524
+ *
1525
+ * @example
1526
+ * ```ts
1527
+ * token(panel, 'surface') // '#ffffff'
1528
+ * token(panel, '--surface') // '#ffffff'
1529
+ * ```
1530
+ */
1531
+ export declare function token(element: Element, name: string): string;
1532
+
1112
1533
  /**
1113
1534
  * Reaches a named control only through natural forward Tab traversal from the current focus.
1114
1535
  *
@@ -1137,6 +1558,31 @@ export declare function traverseAccessible(name: string): Promise<HTMLElement>;
1137
1558
  */
1138
1559
  export declare function typeAccessible(name: string, text: string): Promise<void>;
1139
1560
 
1561
+ /**
1562
+ * Sets one field's value and announces it the way typing into the field does.
1563
+ *
1564
+ * @param element - The input or textarea to write into.
1565
+ * @param text - The value to set.
1566
+ *
1567
+ * @remarks
1568
+ * This is the synthetic pair of {@link typeAccessible}, for a component that listens for `input` and
1569
+ * a test that has the element already. It sets the value in one write and dispatches one bubbling
1570
+ * `input` event, so a delegated listener on an ancestor hears it. It sends no keystrokes, so a
1571
+ * component reading `key`, composition, or selection sees nothing. The dispatched event is a plain
1572
+ * `Event`, never an `InputEvent`, so a component reading `inputType` or testing
1573
+ * `instanceof InputEvent` sees neither. Drive a component that reads any of those through
1574
+ * `typeAccessible` instead.
1575
+ *
1576
+ * No `change` event follows. Use {@link commitInput} where the component waits for the field to be
1577
+ * committed.
1578
+ *
1579
+ * @example
1580
+ * ```ts
1581
+ * typeInput(requireValue(container.querySelector('input')), 'Ada')
1582
+ * ```
1583
+ */
1584
+ export declare function typeInput(element: HTMLInputElement | HTMLTextAreaElement, text: string): void;
1585
+
1140
1586
  /**
1141
1587
  * Waits for one animation frame to settle pending browser paint work.
1142
1588
  *