yukey

yk-button: the per-context contract moves onto the YkButton class doc

commit 7d6001756d2def6cd41f4f8ebff38c96d9e34190 · parent bdc1230fa7 · browse this tree
Ximianth, 2026-10-24 10:54:20 UTC

yk-button was converted before the rule the docs round settled on (a
contract lives on the most specific exported declaration; the header
keeps intent), so its header still held the dual-context contract, the
claim list, the activation-is-click story, and the activation feedback,
and its class doc pointed readers at the header -- which the .d.ts
doesn't carry.  All of it now lives on YkButton; the header keeps the
purpose and the norm pointer.

Wording is unchanged apart from backticks on attribute names and keys,
and two file names becoming links: the claim idiom to
MegacolumnKeyDetail, press-flash.ts to flashPress.
diff --git a/packages/yukey/src/yk-button.ts b/packages/yukey/src/yk-button.ts
index b46f6e7..ea4dd0c 100644
--- a/packages/yukey/src/yk-button.ts
+++ b/packages/yukey/src/yk-button.ts
@@ -1,51 +1,7 @@
 // yk-button: the button that makes the guidelines' keyboard norms structural.
 // Use it and the norms happen; there is nothing to remember per screen.
 // (The norms: docs/precepts-we-love-the-keyboard.md, "buttons always show their hotkey" and the megacolumn sections.
-// Each property's doc names the norm it carries.)
-//
-// Dual context, detected at connect time:
-//
-// - Inside a megacolumn row (a [data-mc-row] ancestor in the same shadow tree):
-//   renders non-focusable markup -- the container must stay the column's only tab stop,
-//   and non-focusable content also gives clicks their native behavior of focusing the container.
-//   Activation arrives as megacolumn-key events,
-//   heard on the row element so the button answers row-scoped keys even when the forward targeted the row's other control.
-//   The button claims keys: it preventDefaults the forwarded `megacolumn-key` event,
-//   so later listeners and the controller treat the key as handled
-//   (the claim idiom is megacolumn-controller.ts's; it is defined there).
-//   First claim wins, and a disabled button claims but declines to act.  What it claims:
-//   - Enter/Space at this button's own position: activate.
-//   - Its hotkey, only when hotkeyDirect: activate
-//     (via the column-scoped marking contract: data-mc-hotkey plus data-mc-hotkey-direct on the host).
-//     Without hotkeyDirect the button declines its own hotkey:
-//     that decline lets the controller resolve the marking as a focus move to this row,
-//     and Enter/Space then activate (see-before-commit).
-//   - x/Delete from any position, aux buttons only: activate (the removal norm).
-//   - i at this button's own position: yk-info.
-// - Standalone (no [data-mc-container] ancestor): a real native button;
-//   Tab reaches it, Enter/Space activate natively, the focus ring is the tokens'.
-//   Its hotkey and i answer only while it holds focus
-//   (a broader standalone hotkey scope is an app-level concern, not this component's).
-// - Inside a container but outside any row: fail closed (throws at connect).
-//   A native tab stop loose in a container would quietly fracture the single-tab-stop model,
-//   and the scan cannot see into this shadow root.
-//
-// Activation is a `click` event on this element in every context and by every trigger (mouse, Enter/Space, hotkey):
-// authors write one @click handler.
-// In row mode every host click is also claimed (preventDefault) as it passes:
-// the megacolumn controller synthesizes an Enter-equivalent megacolumn-key from unclaimed clicks on row controls
-// (its pointer-activation norm for plain rows),
-// and the claim tells it this widget already owns click-activation --
-// without it, a mouse click would activate twice, once natively and once synthesized.
-// Standalone clicks stay unclaimed: no controller listens,
-// and a native button's click default is not this component's to consume.
-//
-// Activation feedback: every successful activation flashes the pressed look for --yk-press-ms (press-flash.ts),
-// so keyboard triggers are as visible as a mouse press;
-// a pointer held down shows the same look for as long as it stays down.
-// Disabled buttons show neither: nothing happened, nothing must claim otherwise.
-// The yk-pressed/yk-held classes live on the host element, outside classMap's managed set,
-// so renders never clobber a flash in flight.
+// Each property's doc names the norm it carries; the YkButton class doc has the per-context contract.)
 
 import { css, html, LitElement, type TemplateResult } from "lit";
 import { customElement, property } from "lit/decorators.js";
@@ -61,8 +17,49 @@ import { dispatchYkInfo } from "./yk-info.js";
  * and one `click` event for every trigger.
  * Hit targets from `--yk-hit-min-h`/`--yk-hit-min-w`.
  *
- * Standalone it is a native button;
- * inside a megacolumn row it is a non-focusable row control (the file header lists which keys it claims in that mode).
+ * Dual context, detected at connect time:
+ *
+ * - Inside a megacolumn row (a `[data-mc-row]` ancestor in the same shadow tree):
+ *   renders non-focusable markup -- the container must stay the column's only tab stop,
+ *   and non-focusable content also gives clicks their native behavior of focusing the container.
+ *   Activation arrives as megacolumn-key events,
+ *   heard on the row element so the button answers row-scoped keys even when the forward targeted the row's other control.
+ *   The button claims keys: it preventDefaults the forwarded `megacolumn-key` event,
+ *   so later listeners and the controller treat the key as handled
+ *   (the claim idiom is defined on {@link MegacolumnKeyDetail}).
+ *   First claim wins, and a disabled button claims but declines to act.  What it claims:
+ *   - Enter/Space at this button's own position: activate.
+ *   - Its hotkey, only when {@link hotkeyDirect}: activate
+ *     (via the column-scoped marking contract: `data-mc-hotkey` plus `data-mc-hotkey-direct` on the host).
+ *     Without hotkeyDirect the button declines its own hotkey:
+ *     that decline lets the controller resolve the marking as a focus move to this row,
+ *     and Enter/Space then activate (see-before-commit).
+ *   - x/Delete from any position, aux buttons only: activate (the removal norm).
+ *   - `i` at this button's own position: yk-info.
+ * - Standalone (no `[data-mc-container]` ancestor): a real native button;
+ *   Tab reaches it, Enter/Space activate natively, the focus ring is the tokens'.
+ *   Its hotkey and `i` answer only while it holds focus
+ *   (a broader standalone hotkey scope is an app-level concern, not this component's).
+ * - Inside a container but outside any row: fail closed (throws at connect).
+ *   A native tab stop loose in a container would quietly fracture the single-tab-stop model,
+ *   and the scan cannot see into this shadow root.
+ *
+ * Activation is a `click` event on this element in every context and by every trigger (mouse, Enter/Space, hotkey):
+ * authors write one @click handler.
+ * In row mode every host click is also claimed (preventDefault) as it passes:
+ * the megacolumn controller synthesizes an Enter-equivalent megacolumn-key from unclaimed clicks on row controls
+ * (its pointer-activation norm for plain rows),
+ * and the claim tells it this widget already owns click-activation --
+ * without it, a mouse click would activate twice, once natively and once synthesized.
+ * Standalone clicks stay unclaimed: no controller listens,
+ * and a native button's click default is not this component's to consume.
+ *
+ * Activation feedback: every successful activation flashes the pressed look for `--yk-press-ms` (see {@link flashPress}),
+ * so keyboard triggers are as visible as a mouse press;
+ * a pointer held down shows the same look for as long as it stays down.
+ * Disabled buttons show neither: nothing happened, nothing must claim otherwise.
+ * The `yk-pressed`/`yk-held` classes live on the host element, outside classMap's managed set,
+ * so renders never clobber a flash in flight.
  */
 @customElement("yk-button")
 export class YkButton extends LitElement {
@@ -136,7 +133,7 @@ export class YkButton extends LitElement {
 			color: inherit;
 		}
 		/* activation feedback: the same look for held-under-a-pointer and for the
-		   post-activation flash (see the file header) */
+		   post-activation flash (see the class doc) */
 		:host(.yk-held) .btn,
 		:host(.yk-pressed) .btn {
 			background: var(--yk-wash-pressed);
@@ -304,7 +301,7 @@ export class YkButton extends LitElement {
 		this.#releaseHold();
 	}
 
-	/** #onMegacolumnKey answers forwarded keys in row mode; the file header has the table of which keys it claims. */
+	/** #onMegacolumnKey answers forwarded keys in row mode; the {@link YkButton} class doc has the list of which keys it claims. */
 	#onMegacolumnKey = (e: Event): void => {
 		if (e.defaultPrevented) return; // someone earlier in the row claimed it
 		const { key, position } = (e as CustomEvent<MegacolumnKeyDetail>).detail;