vintage-frames 0.15.0 → 0.16.0

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.
Files changed (47) hide show
  1. package/custom-elements.json +681 -65
  2. package/dist/chrome.d.ts +10 -1
  3. package/dist/chrome.js +8 -3
  4. package/dist/components/vf-desktop.d.ts +5 -2
  5. package/dist/components/vf-desktop.js +5 -5
  6. package/dist/components/vf-dialog.d.ts +7 -2
  7. package/dist/components/vf-dialog.js +27 -27
  8. package/dist/components/vf-menu-bar.js +9 -10
  9. package/dist/components/vf-menu-item.js +18 -13
  10. package/dist/components/vf-menu.d.ts +8 -3
  11. package/dist/components/vf-menu.js +85 -61
  12. package/dist/components/vf-number-field.d.ts +4 -0
  13. package/dist/components/vf-number-field.js +28 -25
  14. package/dist/components/vf-paragraph.d.ts +3 -1
  15. package/dist/components/vf-paragraph.js +7 -0
  16. package/dist/components/vf-scroll-area.d.ts +16 -1
  17. package/dist/components/vf-scroll-area.js +39 -29
  18. package/dist/components/vf-select.d.ts +5 -4
  19. package/dist/components/vf-select.js +26 -17
  20. package/dist/components/vf-text-field.d.ts +5 -5
  21. package/dist/components/vf-text-field.js +1 -1
  22. package/dist/components/vf-window.d.ts +22 -5
  23. package/dist/components/vf-window.js +113 -98
  24. package/dist/cursor.d.ts +8 -0
  25. package/dist/cursor.js +70 -73
  26. package/dist/index.d.ts +2 -1
  27. package/dist/modal-dialog.d.ts +20 -2
  28. package/dist/modal-dialog.js +63 -51
  29. package/dist/shell/catalog.d.ts +1 -1
  30. package/dist/shell/catalog.js +32 -18
  31. package/dist/shell/finder.d.ts +6 -1
  32. package/dist/shell/finder.js +182 -176
  33. package/dist/shell/index.d.ts +1 -1
  34. package/dist/shell/pure.d.ts +10 -0
  35. package/dist/shell/pure.js +4 -0
  36. package/dist/shell/shell.d.ts +16 -3
  37. package/dist/shell/shell.js +141 -126
  38. package/dist/shell/windows.d.ts +48 -10
  39. package/dist/shell/windows.js +142 -85
  40. package/dist/text-control.d.ts +24 -1
  41. package/dist/text-control.js +25 -4
  42. package/dist/top-layer.d.ts +13 -0
  43. package/dist/top-layer.js +16 -0
  44. package/docs/SPEC.md +23 -22
  45. package/editor/vscode.html-custom-data.json +21 -11
  46. package/editor/web-types.json +51 -23
  47. package/package.json +5 -1
@@ -2563,7 +2563,7 @@
2563
2563
  "declarations": [
2564
2564
  {
2565
2565
  "kind": "class",
2566
- "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the desktop pattern — the classic 50% dither by default, or any of\nthe standard patterns by name (`pattern`, System 7's General Controls\nsetting) — and manages the stacking order and `active` state of slotted\n`vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, synced in a task once\nany pointer gesture has ended), so tabbing walks the stack the way the eye\ndoes and Shift+Tab is its exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\nA slotted `vf-menu-bar` (or a free-standing `vf-menu`) sits on a tier\nabove both, so its dropped menus cover palettes and document windows\nalike; only the screen-corner mask is in front of it.\n\n**Deactivation.** On a real System 7 machine clicking the desktop clicked\nthe *Finder* — the frontmost application's windows lost their stripes.\nclearActive is that gesture's handler: it clears `active` from\nthe whole document tier, and **zero active windows is a legal state**,\nheld until a press or keyboard focus re-enters a document window (or a\nnew one is slotted, which activates it — opening a window brings its\napplication forward). The desktop never takes this decision itself: its\nfurniture is slotted light DOM (an icon layer, say), so only the page\nknows which of its children — or which presses on the bare dither — mean\n\"the Finder\", and it routes those through `clearActive()`. Left alone,\nthe classic always-one-active behavior is unchanged. activeWindow\nreads the current holder, and every change of holder — including to and\nfrom none — fires `vf-activate`.\n\n**Hidden windows.** A window with `hidden` — closed by a page that hides\nits windows rather than removing them, through `vf-window.hide()` or the\nattribute itself — never holds the active state. One slotted hidden waits\nto be shown; `bringToFront()` on one gives it its place in the stack and\nactivates nothing; the holder hiding hands the state to the topmost shown\ndocument window, or to none. A window shown into a tier where none is\nactive, unless the tier was deliberately deactivated, takes it.\nstackingOrder lists the windows as they stand, bottom-most first.\n\n**The work area.** A slotted `vf-menu-bar` along the top takes its band\noff the screen: workArea is what is left, and the gestures on the\nscreen stay in it — a window dragged up stops with its title bar under the\nbar, where it can still be grabbed, and an icon dropped, nudged or walked\non the desktop lands below the bar. `window-top` deepens the area for\nwindows alone (windowArea), for a page with a strip of its own\nunder the bar. A gesture asks for the box it is clamped into with\n`vf-placement-bounds-request` (bubbles, non-composed), the drag surface's\nhandshake, and the desktop answers for the hosts placed on its screen.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its four corners\nwith the classic corner mask.\n\n**`pattern`** names the desktop pattern — `gray-50` (the dither) by\ndefault, any of the 38 standard patterns (docs/PATTERNS.md), or sixteen\nhex digits stating a custom 8×8 pattern, as on `vf-container`. It is\npainted as the screen's own background: black ink on an opaque white\npaper, a repeating tile drawn at the display's resolution, 1-bit at every\ndensity and zoom (src/pattern-fill.ts).\n\n**The drag surface.** The Finder dragged an icon as a dotted outline drawn\non the *screen*, clipped at its edge and phase-locked to its raster, so\nthe screen hosts the layer that outline draws on: a full-bleed child of\nthe screen, `pointer-events: none` (never a hit for the page's\n`elementsFromPoint`), whose children paint one tier above the menu bar\nand under the corner mask — the layer itself is deliberately no stacking\ncontext, since a blend inside one would composite against nothing. An\nicon reaches it without an import, the menu-handshake idiom: on a drag's\nfirst step it dispatches `vf-drag-surface-request` (bubbles, non-composed,\n`detail.surface` null), and the nearest desktop on its light-DOM path\nfills the detail with the layer. A window asks the same way and draws\nthere with the same pen: its zoom rects when it opens from a rect\n(`vf-window.show({ from })`), its outline under an `outline-drag`. Not the\ntop layer: stable Safari cannot\nblend an element there against the page (src/cursor.ts), and a second\nkit entry in the top layer would need a re-promotion handshake.\n\nCustom properties:\n- `--vf-desktop-pattern` — a consumer's own tile art in place of the\n pattern (the kit's default is a 1-bit 50% checker, opaque\n black-on-white on a 30-system-px tile). Set, it wins over `pattern` and\n renders as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern (default\n `#808080`). The pattern's paper is opaque, so this only becomes visible\n when `--vf-desktop-pattern` is overridden with a tile that has\n transparent cells (or with `none`).",
2566
+ "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the desktop pattern — the classic 50% dither by default, or any of\nthe standard patterns by name (`pattern`, System 7's General Controls\nsetting) — and manages the stacking order and `active` state of slotted\n`vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. A press on a title bar with ⌘ held\nraises nothing, so a background window is dragged where it stands in the\nstack. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, synced in a task once\nany pointer gesture has ended), so tabbing walks the stack the way the eye\ndoes and Shift+Tab is its exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\nA slotted `vf-menu-bar` (or a free-standing `vf-menu`) sits on a tier\nabove both, so its dropped menus cover palettes and document windows\nalike; only the screen-corner mask is in front of it.\n\n**Deactivation.** On a real System 7 machine clicking the desktop clicked\nthe *Finder* — the frontmost application's windows lost their stripes.\nclearActive is that gesture's handler: it clears `active` from\nthe whole document tier, and **zero active windows is a legal state**,\nheld until a press or keyboard focus re-enters a document window (or a\nnew one is slotted, which activates it — opening a window brings its\napplication forward). The desktop never takes this decision itself: its\nfurniture is slotted light DOM (an icon layer, say), so only the page\nknows which of its children — or which presses on the bare dither — mean\n\"the Finder\", and it routes those through `clearActive()`. Left alone,\nthe classic always-one-active behavior is unchanged. activeWindow\nreads the current holder, and every change of holder — including to and\nfrom none — fires `vf-activate`.\n\n**Hidden windows.** A window with `hidden` — closed by a page that hides\nits windows rather than removing them, through `vf-window.hide()` or the\nattribute itself — never holds the active state. One slotted hidden waits\nto be shown; `bringToFront()` on one gives it its place in the stack and\nactivates nothing; the holder hiding hands the state to the topmost shown\ndocument window, or to none. A window shown into a tier where none is\nactive, unless the tier was deliberately deactivated, takes it.\nstackingOrder lists the windows as they stand, bottom-most first.\n\n**The work area.** A slotted `vf-menu-bar` along the top takes its band\noff the screen: workArea is what is left, and the gestures on the\nscreen stay in it — a window dragged up stops with its title bar under the\nbar, where it can still be grabbed, and an icon dropped, nudged or walked\non the desktop lands below the bar. `window-top` deepens the area for\nwindows alone (windowArea), for a page with a strip of its own\nunder the bar. A gesture asks for the box it is clamped into with\n`vf-placement-bounds-request` (bubbles, non-composed), the drag surface's\nhandshake, and the desktop answers for the hosts placed on its screen.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its four corners\nwith the classic corner mask.\n\n**`pattern`** names the desktop pattern — `gray-50` (the dither) by\ndefault, any of the 38 standard patterns (docs/PATTERNS.md), or sixteen\nhex digits stating a custom 8×8 pattern, as on `vf-container`. It is\npainted as the screen's own background: black ink on an opaque white\npaper, a repeating tile drawn at the display's resolution, 1-bit at every\ndensity and zoom (src/pattern-fill.ts).\n\n**The drag surface.** The Finder dragged an icon as a dotted outline drawn\non the *screen*, clipped at its edge and phase-locked to its raster, so\nthe screen hosts the layer that outline draws on: a full-bleed child of\nthe screen, `pointer-events: none` (never a hit for the page's\n`elementsFromPoint`), whose children paint one tier above the menu bar\nand under the corner mask — the layer itself is deliberately no stacking\ncontext, since a blend inside one would composite against nothing. An\nicon reaches it without an import, the menu-handshake idiom: on a drag's\nfirst step it dispatches `vf-drag-surface-request` (bubbles, non-composed,\n`detail.surface` null), and the nearest desktop on its light-DOM path\nfills the detail with the layer. A window asks the same way and draws\nthere with the same pen: its zoom rects when it opens from a rect\n(`vf-window.show({ from })`), its outline under an `outline-drag`. Not the\ntop layer: stable Safari cannot\nblend an element there against the page (src/cursor.ts), and a second\nkit entry in the top layer would need a re-promotion handshake.\n\nCustom properties:\n- `--vf-desktop-pattern` — a consumer's own tile art in place of the\n pattern (the kit's default is a 1-bit 50% checker, opaque\n black-on-white on a 30-system-px tile). Set, it wins over `pattern` and\n renders as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern (default\n `#808080`). The pattern's paper is opaque, so this only becomes visible\n when `--vf-desktop-pattern` is overridden with a tile that has\n transparent cells (or with `none`).",
2567
2567
  "name": "VfDesktop",
2568
2568
  "cssProperties": [
2569
2569
  {
@@ -2626,8 +2626,9 @@
2626
2626
  "text": "string | null | undefined"
2627
2627
  },
2628
2628
  "default": "'gray-50'",
2629
- "description": "The desktop pattern — System 7's General Controls setting. A library\npattern by name (`gray-50`, the classic dither, by default; `gray-75`,\n`bricks`, … — docs/PATTERNS.md) or sixteen hex digits stating a custom\n8×8 pattern, as on `vf-container`. Painted black on opaque white over\nthe whole screen, 1-bit at every density and zoom. A\n`--vf-desktop-pattern` token override still wins and renders the\nconsumer's tile as a placed grid; an unrecognized value warns once and\nkeeps the dither.",
2630
- "attribute": "pattern"
2629
+ "description": "The desktop pattern — System 7's General Controls setting. A library\npattern by name (`gray-50`, the classic dither, by default; `gray-75`,\n`bricks`, … — docs/PATTERNS.md) or sixteen hex digits stating a custom\n8×8 pattern, as on `vf-container`. Painted black on opaque white over\nthe whole screen, 1-bit at every density and zoom. A\n`--vf-desktop-pattern` token override still wins and renders the\nconsumer's tile as a placed grid; an unrecognized value warns once and\nkeeps the dither. Reflects, so a change can be observed on the\nattribute.",
2630
+ "attribute": "pattern",
2631
+ "reflects": true
2631
2632
  },
2632
2633
  {
2633
2634
  "kind": "field",
@@ -3298,7 +3299,7 @@
3298
3299
  "text": "string | null | undefined"
3299
3300
  },
3300
3301
  "default": "DEFAULT_PATTERN",
3301
- "description": "The desktop pattern — System 7's General Controls setting. A library\npattern by name (`gray-50`, the classic dither, by default; `gray-75`,\n`bricks`, … — docs/PATTERNS.md) or sixteen hex digits stating a custom\n8×8 pattern, as on `vf-container`. Painted black on opaque white over\nthe whole screen, 1-bit at every density and zoom. A\n`--vf-desktop-pattern` token override still wins and renders the\nconsumer's tile as a placed grid; an unrecognized value warns once and\nkeeps the dither.",
3302
+ "description": "The desktop pattern — System 7's General Controls setting. A library\npattern by name (`gray-50`, the classic dither, by default; `gray-75`,\n`bricks`, … — docs/PATTERNS.md) or sixteen hex digits stating a custom\n8×8 pattern, as on `vf-container`. Painted black on opaque white over\nthe whole screen, 1-bit at every density and zoom. A\n`--vf-desktop-pattern` token override still wins and renders the\nconsumer's tile as a placed grid; an unrecognized value warns once and\nkeeps the dither. Reflects, so a change can be observed on the\nattribute.",
3302
3303
  "fieldName": "pattern"
3303
3304
  },
3304
3305
  {
@@ -3494,7 +3495,7 @@
3494
3495
  "text": "boolean"
3495
3496
  },
3496
3497
  "default": "false",
3497
- "description": "Show the close box (left side of the title bar). Off by default — the\nbare movable-modal bar. Ignored with `frame=\"plain\"` (no bar). Clicking\nit closes the dialog and fires `vf-close` with `{ reason: 'close' }`.",
3498
+ "description": "Show the close box (left side of the title bar). Off by default — the\nbare movable-modal bar. Ignored with `frame=\"plain\"` (no bar). Clicking\nit closes the dialog and fires `vf-close` with `{ reason: 'close' }` and\nthe modifier keys held on the click, as `vf-window`'s close box does.",
3498
3499
  "attribute": "closable",
3499
3500
  "reflects": true
3500
3501
  },
@@ -3561,7 +3562,15 @@
3561
3562
  "type": {
3562
3563
  "text": "void"
3563
3564
  }
3564
- }
3565
+ },
3566
+ "parameters": [
3567
+ {
3568
+ "name": "event",
3569
+ "type": {
3570
+ "text": "MouseEvent"
3571
+ }
3572
+ }
3573
+ ]
3565
3574
  },
3566
3575
  {
3567
3576
  "kind": "field",
@@ -3753,6 +3762,20 @@
3753
3762
  "module": "src/modal-dialog.ts"
3754
3763
  }
3755
3764
  },
3765
+ {
3766
+ "kind": "field",
3767
+ "name": "#closeKeys",
3768
+ "privacy": "private",
3769
+ "type": {
3770
+ "text": "VfCloseKeys | null"
3771
+ },
3772
+ "default": "null",
3773
+ "description": "The modifier keys a close box's click held, pending for the next native `close` event.",
3774
+ "inheritedFrom": {
3775
+ "name": "VfModalDialog",
3776
+ "module": "src/modal-dialog.ts"
3777
+ }
3778
+ },
3756
3779
  {
3757
3780
  "kind": "field",
3758
3781
  "name": "#onSubmit",
@@ -3823,10 +3846,10 @@
3823
3846
  "privacy": "private",
3824
3847
  "return": {
3825
3848
  "type": {
3826
- "text": "void"
3849
+ "text": "HTMLElement | null"
3827
3850
  }
3828
3851
  },
3829
- "description": "Hand focus to initialFocusTarget, right after `showModal()`'s own\nfocusing steps have run (so this is the last word, not a race).",
3852
+ "description": "Hand focus to initialFocusTarget, right after `showModal()`'s own\nfocusing steps have run (so this is the last word, not a race). Returns\nthe element focused, for `vf-show`.",
3830
3853
  "inheritedFrom": {
3831
3854
  "name": "VfModalDialog",
3832
3855
  "module": "src/modal-dialog.ts"
@@ -3922,6 +3945,29 @@
3922
3945
  "module": "src/modal-dialog.ts"
3923
3946
  }
3924
3947
  },
3948
+ {
3949
+ "kind": "method",
3950
+ "name": "closeFromBox",
3951
+ "privacy": "protected",
3952
+ "return": {
3953
+ "type": {
3954
+ "text": "void"
3955
+ }
3956
+ },
3957
+ "parameters": [
3958
+ {
3959
+ "name": "keys",
3960
+ "type": {
3961
+ "text": "VfCloseKeys"
3962
+ }
3963
+ }
3964
+ ],
3965
+ "description": "Close from a close box, its `vf-close` carrying the modifier keys held on the click.",
3966
+ "inheritedFrom": {
3967
+ "name": "VfModalDialog",
3968
+ "module": "src/modal-dialog.ts"
3969
+ }
3970
+ },
3925
3971
  {
3926
3972
  "kind": "method",
3927
3973
  "name": "#viewport",
@@ -4159,7 +4205,15 @@
4159
4205
  ],
4160
4206
  "events": [
4161
4207
  {
4162
- "description": "Dialog closed. Detail `{ reason: 'escape' | 'close' | 'outside', returnValue: string | null }` — `'outside'` only under `light-dismiss`.",
4208
+ "description": "Dialog opened, placed and given its initial focus. Detail `{ focus }`, the element focused: the moment to select a field's default text (`select()`) or measure copy that varies.",
4209
+ "name": "vf-show",
4210
+ "inheritedFrom": {
4211
+ "name": "VfModalDialog",
4212
+ "module": "src/modal-dialog.ts"
4213
+ }
4214
+ },
4215
+ {
4216
+ "description": "Dialog closed. Detail `{ reason: 'escape' | 'close' | 'outside', returnValue: string | null }` — `'outside'` only under `light-dismiss` — plus `altKey`, `shiftKey`, `metaKey` and `ctrlKey` when the close box closed it.",
4163
4217
  "name": "vf-close",
4164
4218
  "inheritedFrom": {
4165
4219
  "name": "VfModalDialog",
@@ -4192,7 +4246,7 @@
4192
4246
  "text": "boolean"
4193
4247
  },
4194
4248
  "default": "false",
4195
- "description": "Show the close box (left side of the title bar). Off by default — the\nbare movable-modal bar. Ignored with `frame=\"plain\"` (no bar). Clicking\nit closes the dialog and fires `vf-close` with `{ reason: 'close' }`.",
4249
+ "description": "Show the close box (left side of the title bar). Off by default — the\nbare movable-modal bar. Ignored with `frame=\"plain\"` (no bar). Clicking\nit closes the dialog and fires `vf-close` with `{ reason: 'close' }` and\nthe modifier keys held on the click, as `vf-window`'s close box does.",
4196
4250
  "fieldName": "closable"
4197
4251
  },
4198
4252
  {
@@ -9309,7 +9363,7 @@
9309
9363
  "name": ""
9310
9364
  },
9311
9365
  {
9312
- "description": "Replaces the `label` text in the bar — e.g. a `vf-img` apple icon for the Apple menu. Keep the `label` attribute set too: it stays the menu's accessible name (the bar item's `aria-label` and the panel's) when the visible title is an image.",
9366
+ "description": "Replaces the `label` text in the bar — e.g. a `vf-img` apple icon for the Apple menu. An icon (`vf-img`, `img`, `svg`, `picture` or `canvas`) is drawn in a 16×16 cell and placed for one: 6 system px into its plate, 6 short of the plate's end, on the plate's top row. Text keeps the text title's place. Keep the `label` attribute set too: it stays the menu's accessible name (the bar item's `aria-label` and the panel's) when the visible title is an image.",
9313
9367
  "name": "label"
9314
9368
  }
9315
9369
  ],
@@ -9386,6 +9440,21 @@
9386
9440
  },
9387
9441
  "privacy": "private"
9388
9442
  },
9443
+ {
9444
+ "kind": "field",
9445
+ "name": "_artTitle",
9446
+ "type": {
9447
+ "text": "boolean"
9448
+ },
9449
+ "privacy": "private",
9450
+ "default": "false",
9451
+ "description": "Whether the title is art — only images in the `label` slot — rather than text."
9452
+ },
9453
+ {
9454
+ "kind": "field",
9455
+ "name": "#onLabelSlotChange",
9456
+ "privacy": "private"
9457
+ },
9389
9458
  {
9390
9459
  "kind": "field",
9391
9460
  "name": "_assignedItems",
@@ -9966,6 +10035,48 @@
9966
10035
  }
9967
10036
  ]
9968
10037
  },
10038
+ {
10039
+ "kind": "method",
10040
+ "name": "#fit",
10041
+ "privacy": "private",
10042
+ "return": {
10043
+ "type": {
10044
+ "text": "string"
10045
+ }
10046
+ },
10047
+ "parameters": [
10048
+ {
10049
+ "name": "n",
10050
+ "type": {
10051
+ "text": "number"
10052
+ }
10053
+ }
10054
+ ],
10055
+ "description": "`n` clamped and rounded to the step's precision, as text."
10056
+ },
10057
+ {
10058
+ "kind": "method",
10059
+ "name": "committedText",
10060
+ "privacy": "protected",
10061
+ "return": {
10062
+ "type": {
10063
+ "text": "string"
10064
+ }
10065
+ },
10066
+ "parameters": [
10067
+ {
10068
+ "name": "raw",
10069
+ "type": {
10070
+ "text": "string"
10071
+ }
10072
+ }
10073
+ ],
10074
+ "description": "Typed text clamps and rounds when it is a number; otherwise it stays as typed.",
10075
+ "inheritedFrom": {
10076
+ "name": "VfTextControlBase",
10077
+ "module": "src/text-control.ts"
10078
+ }
10079
+ },
9969
10080
  {
9970
10081
  "kind": "method",
9971
10082
  "name": "#commit",
@@ -9983,7 +10094,7 @@
9983
10094
  }
9984
10095
  }
9985
10096
  ],
9986
- "description": "Clamp + round to the step's precision, store, and announce a change — but\nonly when the value actually changes, so autorepeat held against a bound\n(or a keyboard step already at min/max) doesn't fire a redundant\n`vf-change` on every 60ms tick."
10097
+ "description": "Step to `n`, clamped and rounded, and announce a change — but\nonly when the value actually changes, so autorepeat held against a bound\n(or a keyboard step already at min/max) doesn't fire a redundant\n`vf-change` on every 60ms tick."
9987
10098
  },
9988
10099
  {
9989
10100
  "kind": "method",
@@ -10005,8 +10116,8 @@
10005
10116
  },
10006
10117
  {
10007
10118
  "kind": "method",
10008
- "name": "#emit",
10009
- "privacy": "private",
10119
+ "name": "emitValue",
10120
+ "privacy": "protected",
10010
10121
  "return": {
10011
10122
  "type": {
10012
10123
  "text": "void"
@@ -10018,8 +10129,20 @@
10018
10129
  "type": {
10019
10130
  "text": "'vf-input' | 'vf-change'"
10020
10131
  }
10132
+ },
10133
+ {
10134
+ "name": "detail",
10135
+ "default": "{ value: this.value, valueAsNumber: this.#parse() }",
10136
+ "type": {
10137
+ "text": "Record<string, unknown>"
10138
+ }
10021
10139
  }
10022
- ]
10140
+ ],
10141
+ "description": "Every value event carries `valueAsNumber` too.",
10142
+ "inheritedFrom": {
10143
+ "name": "VfTextControlBase",
10144
+ "module": "src/text-control.ts"
10145
+ }
10023
10146
  },
10024
10147
  {
10025
10148
  "kind": "method",
@@ -10069,11 +10192,6 @@
10069
10192
  "name": "#onInput",
10070
10193
  "privacy": "private"
10071
10194
  },
10072
- {
10073
- "kind": "field",
10074
- "name": "#onChange",
10075
- "privacy": "private"
10076
- },
10077
10195
  {
10078
10196
  "kind": "field",
10079
10197
  "name": "top",
@@ -10318,6 +10436,48 @@
10318
10436
  "module": "src/text-control.ts"
10319
10437
  }
10320
10438
  },
10439
+ {
10440
+ "kind": "field",
10441
+ "name": "committed",
10442
+ "type": {
10443
+ "text": "string | null"
10444
+ },
10445
+ "privacy": "protected",
10446
+ "default": "null",
10447
+ "description": "The text as last committed: taken when the field gains focus, then at\neach commit. A commit that brings nothing new isn't announced, so the\nnative `change` that follows a Return commit, or a step, is not a second\none.",
10448
+ "inheritedFrom": {
10449
+ "name": "VfTextControlBase",
10450
+ "module": "src/text-control.ts"
10451
+ }
10452
+ },
10453
+ {
10454
+ "kind": "field",
10455
+ "name": "control",
10456
+ "type": {
10457
+ "text": "HTMLInputElement | HTMLTextAreaElement | null"
10458
+ },
10459
+ "privacy": "protected",
10460
+ "description": "The inner native control every field renders, tagged `vf-field`.",
10461
+ "readonly": true,
10462
+ "inheritedFrom": {
10463
+ "name": "VfTextControlBase",
10464
+ "module": "src/text-control.ts"
10465
+ }
10466
+ },
10467
+ {
10468
+ "kind": "method",
10469
+ "name": "select",
10470
+ "return": {
10471
+ "type": {
10472
+ "text": "void"
10473
+ }
10474
+ },
10475
+ "description": "Select all of the field's text, as a native field's `select()` does.",
10476
+ "inheritedFrom": {
10477
+ "name": "VfTextControlBase",
10478
+ "module": "src/text-control.ts"
10479
+ }
10480
+ },
10321
10481
  {
10322
10482
  "kind": "method",
10323
10483
  "name": "formResetCallback",
@@ -10372,7 +10532,7 @@
10372
10532
  },
10373
10533
  {
10374
10534
  "kind": "method",
10375
- "name": "emitValue",
10535
+ "name": "handleInput",
10376
10536
  "privacy": "protected",
10377
10537
  "return": {
10378
10538
  "type": {
@@ -10381,20 +10541,36 @@
10381
10541
  },
10382
10542
  "parameters": [
10383
10543
  {
10384
- "name": "type",
10544
+ "name": "event",
10385
10545
  "type": {
10386
- "text": "'vf-input' | 'vf-change'"
10546
+ "text": "Event"
10387
10547
  }
10388
- },
10548
+ }
10549
+ ],
10550
+ "description": "Mirror the native control's value into `value` and announce a keystroke.",
10551
+ "inheritedFrom": {
10552
+ "name": "VfTextControlBase",
10553
+ "module": "src/text-control.ts"
10554
+ }
10555
+ },
10556
+ {
10557
+ "kind": "method",
10558
+ "name": "commit",
10559
+ "privacy": "protected",
10560
+ "return": {
10561
+ "type": {
10562
+ "text": "void"
10563
+ }
10564
+ },
10565
+ "parameters": [
10389
10566
  {
10390
- "name": "detail",
10391
- "default": "{ value: this.value }",
10567
+ "name": "raw",
10392
10568
  "type": {
10393
- "text": "Record<string, unknown>"
10569
+ "text": "string"
10394
10570
  }
10395
10571
  }
10396
10572
  ],
10397
- "description": "Dispatch a bubbling, composed value event (SPEC §4). Text fields use the\ndefault `{ value }` detail; `vf-number-field` passes an enriched detail that\nalso carries `valueAsNumber`.",
10573
+ "description": "Commit typed text: its committed form into `value`, announced unless it is what was last committed.",
10398
10574
  "inheritedFrom": {
10399
10575
  "name": "VfTextControlBase",
10400
10576
  "module": "src/text-control.ts"
@@ -10402,7 +10578,7 @@
10402
10578
  },
10403
10579
  {
10404
10580
  "kind": "method",
10405
- "name": "handleInput",
10581
+ "name": "handleChange",
10406
10582
  "privacy": "protected",
10407
10583
  "return": {
10408
10584
  "type": {
@@ -10417,7 +10593,7 @@
10417
10593
  }
10418
10594
  }
10419
10595
  ],
10420
- "description": "Mirror the native control's value into `value` and announce a keystroke.",
10596
+ "description": "The native control's commit.",
10421
10597
  "inheritedFrom": {
10422
10598
  "name": "VfTextControlBase",
10423
10599
  "module": "src/text-control.ts"
@@ -10425,7 +10601,7 @@
10425
10601
  },
10426
10602
  {
10427
10603
  "kind": "method",
10428
- "name": "handleChange",
10604
+ "name": "submitOnEnter",
10429
10605
  "privacy": "protected",
10430
10606
  "return": {
10431
10607
  "type": {
@@ -10436,11 +10612,11 @@
10436
10612
  {
10437
10613
  "name": "event",
10438
10614
  "type": {
10439
- "text": "Event"
10615
+ "text": "KeyboardEvent"
10440
10616
  }
10441
10617
  }
10442
10618
  ],
10443
- "description": "Mirror the native control's value into `value` and announce a commit.",
10619
+ "description": "A plain Return in a single-line field with a form: commit, then the\nform's implicit submission, the order a native input keeps (its `change`\ncomes before the submission). The keydown is cancelled, so an enclosing\nmodal does not route the same press to its default button as well.",
10444
10620
  "inheritedFrom": {
10445
10621
  "name": "VfTextControlBase",
10446
10622
  "module": "src/text-control.ts"
@@ -11498,7 +11674,7 @@
11498
11674
  "declarations": [
11499
11675
  {
11500
11676
  "kind": "class",
11501
- "description": "`<vf-paragraph>` — a paragraph of copy on the kit's body face and grid.\n\nThe installer's welcome text, a dialog's explanation, an article's prose:\nanything a page would otherwise set with a `<p>` and hope the leading landed\nsomewhere sensible. What it adds over that `<p>`:\n\n- the **Geneva body face** by default (`face=\"display\"` switches to\n the Chicago-style chrome face);\n- a **whole-system-pixel line box at the face's native pitch** —\n `--vf-paragraph-line-height`: 12px for the body face (Geneva 9's own\n strike line) and 16px under `face=\"display\"` (Chicago 12's — ascent 12 +\n descent 3 + leading 1, the pitch a real dialog wrapped its copy on).\n Whole pixels are the point of the component: line boxes are the single\n biggest source of off-grid layout, because a ratio resolves to whatever\n it resolves to (`1.65 × 17px = 28.05px`) and every line of prose nudges\n everything after it further off the device-pixel grid, smearing 1-bit\n borders and bitmap glyph stems (docs/SIZING.md rule 2). A\n whole-pixel line box accumulates whole offsets;\n- its own GridSnapController, so it holds its own origin\n wherever the page puts it;\n- a **declared box** when the layout wants one — `width`/`height` in whole\n system px (VfSized). In flow a paragraph takes its container's\n width, which is usually right; a *placed* one (`top`/`left`) shrink-wraps\n its longest line instead — a fractional glyph-run width, wrapped wherever\n the parent's edge happens to fall — so a DITL-style layout states the\n measure the copy wraps to, whole and on the grid.\n\nThe shadow root renders a real `<p>`, so the copy keeps paragraph semantics\nfor assistive tech, and — unlike the kit's chrome — the text is selectable.\nThere is no margin: per SPEC §2 a component adds nothing outside its own box,\nso paragraph spacing is the page's (a `gap` on the column, or a margin on the\nhost — kept a whole number of pixels, like everything else in the contract).",
11677
+ "description": "`<vf-paragraph>` — a paragraph of copy on the kit's body face and grid.\n\nThe installer's welcome text, a dialog's explanation, an article's prose:\nanything a page would otherwise set with a `<p>` and hope the leading landed\nsomewhere sensible. What it adds over that `<p>`:\n\n- the **Geneva body face** by default (`face=\"display\"` switches to\n the Chicago-style chrome face);\n- a **whole-system-pixel line box at the face's native pitch** —\n `--vf-paragraph-line-height`: 12px for the body face (Geneva 9's own\n strike line) and 16px under `face=\"display\"` (Chicago 12's — ascent 12 +\n descent 3 + leading 1, the pitch a real dialog wrapped its copy on).\n Whole pixels are the point of the component: line boxes are the single\n biggest source of off-grid layout, because a ratio resolves to whatever\n it resolves to (`1.65 × 17px = 28.05px`) and every line of prose nudges\n everything after it further off the device-pixel grid, smearing 1-bit\n borders and bitmap glyph stems (docs/SIZING.md rule 2). A\n whole-pixel line box accumulates whole offsets;\n- its own GridSnapController, so it holds its own origin\n wherever the page puts it;\n- a **declared box** when the layout wants one — `width`/`height` in whole\n system px (VfSized). In flow a paragraph takes its container's\n width, which is usually right; a *placed* one (`top`/`left`) shrink-wraps\n its longest line instead — a fractional glyph-run width, wrapped wherever\n the parent's edge happens to fall — so a DITL-style layout states the\n measure the copy wraps to, whole and on the grid.\n\nThe shadow root renders a real `<p>`, so the copy keeps paragraph semantics\nfor assistive tech, and — unlike the kit's chrome — the text is selectable,\nselected text inverting to the 1-bit highlight (`--vf-highlight` /\n`--vf-highlight-text`) as a field's does.\nThere is no margin: per SPEC §2 a component adds nothing outside its own box,\nso paragraph spacing is the page's (a `gap` on the column, or a margin on the\nhost — kept a whole number of pixels, like everything else in the contract).",
11502
11678
  "name": "VfParagraph",
11503
11679
  "cssProperties": [
11504
11680
  {
@@ -13397,7 +13573,7 @@
13397
13573
  "declarations": [
13398
13574
  {
13399
13575
  "kind": "class",
13400
- "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them,\nand corner reserves that cell on a single-axis rail too — the\nrail stops 15px short of the frame, for a grow box to land in.\n\nSize the host (width/height) from the outside; the viewport fills it.\nContent runs to the frame and the rails — the area adds no inset of its\nown; an inset is the content's (a `vf-stack pad`).\n\nThe scrolled plane sizes to its content — never narrower than the\nviewport, as wide as content that cannot wrap — so the rails follow a row\nthat grows sideways the way they follow copy that grows down, and a\n`slotchange` re-measures. A placed child moved through `top`/`left` is\nheard too: every such write is announced as `vf-placement-change`\n(src/position.ts), and the area re-measures on it — a drop, an arrow\nnudge, a page's own `icon.left = …`, with no code on the page. * measure covers a scroll range that changes with no box and no placement\nchanging (a transform).\n\nplacementAt converts a viewport point into the plane's own\nplacement coordinates, for a drop that lands in this area from elsewhere.",
13576
+ "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them,\nand corner reserves that cell on a single-axis rail too — the\nrail stops 15px short of the frame, for a grow box to land in.\n\nSize the host (width/height) from the outside; the viewport fills it.\nContent runs to the frame and the rails — the area adds no inset of its\nown; an inset is the content's (a `vf-stack pad`). `pattern` fills the\nscrolled plane with a 1-bit pattern, as on `vf-container`.\n\nThe scrolled plane sizes to its content — never narrower than the\nviewport, as wide as content that cannot wrap — so the rails follow a row\nthat grows sideways the way they follow copy that grows down, and a\n`slotchange` re-measures. A placed child moved through `top`/`left` is\nheard too: every such write is announced as `vf-placement-change`\n(src/position.ts), and the area re-measures on it — a drop, an arrow\nnudge, a page's own `icon.left = …`, with no code on the page. * measure covers a scroll range that changes with no box and no placement\nchanging (a transform).\n\nplacementAt converts a viewport point into the plane's own\nplacement coordinates, for a drop that lands in this area from elsewhere.",
13401
13577
  "name": "VfScrollArea",
13402
13578
  "cssProperties": [
13403
13579
  {
@@ -13469,6 +13645,35 @@
13469
13645
  "description": "Accessible name for the scrolling viewport, applied as its `aria-label`\n(an `aria-label` on the host would not reach into the shadow DOM). The\nviewport is keyboard-focusable while its content overflows, so without a\nname it is announced only as an anonymous scrollable group; setting\n`label` also promotes it to a named `role=\"region\"` landmark. While\n`label` is empty the viewport is a plain `group` when scrollable (an\nunnamed region is inert) and role-less when not.",
13470
13646
  "attribute": "label"
13471
13647
  },
13648
+ {
13649
+ "kind": "field",
13650
+ "name": "pattern",
13651
+ "type": {
13652
+ "text": "string | null | undefined"
13653
+ },
13654
+ "description": "A 1-bit fill for the scrolled plane, as on `vf-container`: a library\npattern by name (docs/PATTERNS.md) or sixteen hex digits. It fills the\nvisible area, runs on past the content, and scrolls with it, its phase\nanchored at the content's top-left. Unset, the plane stays white; an\nunrecognized value paints nothing and warns once.",
13655
+ "attribute": "pattern"
13656
+ },
13657
+ {
13658
+ "kind": "field",
13659
+ "name": "_pattern",
13660
+ "type": {
13661
+ "text": "Pattern | null"
13662
+ },
13663
+ "privacy": "private",
13664
+ "default": "null",
13665
+ "description": "`pattern`, resolved — what the fill paints; null paints nothing."
13666
+ },
13667
+ {
13668
+ "kind": "field",
13669
+ "name": "#warnedPattern",
13670
+ "privacy": "private",
13671
+ "type": {
13672
+ "text": "boolean"
13673
+ },
13674
+ "default": "false",
13675
+ "description": "One warning per element for an unrecognized `pattern`, not per render."
13676
+ },
13472
13677
  {
13473
13678
  "kind": "field",
13474
13679
  "name": "viewport",
@@ -13485,6 +13690,14 @@
13485
13690
  },
13486
13691
  "privacy": "private"
13487
13692
  },
13693
+ {
13694
+ "kind": "field",
13695
+ "name": "patternFill",
13696
+ "privacy": "private",
13697
+ "readonly": true,
13698
+ "default": "new PatternFillController(this, { getBox: () => this.content, getPattern: () => this._pattern, })",
13699
+ "description": "The pattern fill, painted on the scrolled plane (src/pattern-fill.ts)."
13700
+ },
13488
13701
  {
13489
13702
  "kind": "field",
13490
13703
  "name": "scrollState",
@@ -13671,6 +13884,14 @@
13671
13884
  "description": "Accessible name for the scrolling viewport, applied as its `aria-label`\n(an `aria-label` on the host would not reach into the shadow DOM). The\nviewport is keyboard-focusable while its content overflows, so without a\nname it is announced only as an anonymous scrollable group; setting\n`label` also promotes it to a named `role=\"region\"` landmark. While\n`label` is empty the viewport is a plain `group` when scrollable (an\nunnamed region is inert) and role-less when not.",
13672
13885
  "fieldName": "label"
13673
13886
  },
13887
+ {
13888
+ "name": "pattern",
13889
+ "type": {
13890
+ "text": "string | null | undefined"
13891
+ },
13892
+ "description": "A 1-bit fill for the scrolled plane, as on `vf-container`: a library\npattern by name (docs/PATTERNS.md) or sixteen hex digits. It fills the\nvisible area, runs on past the content, and scrolls with it, its phase\nanchored at the content's top-left. Unset, the plane stays white; an\nunrecognized value paints nothing and warns once.",
13893
+ "fieldName": "pattern"
13894
+ },
13674
13895
  {
13675
13896
  "name": "top",
13676
13897
  "type": {
@@ -13760,7 +13981,7 @@
13760
13981
  "declarations": [
13761
13982
  {
13762
13983
  "kind": "class",
13763
- "description": "`<vf-select>` — the classic System 7 popup menu control (\"Macintosh HD ▼\").\n\nChildren are `<vf-option>` elements in the default slot. The closed control\nis a white box with a 1px black border, the small 1px hard shadow, the\nselected option's label on the left and a solid black ▼ triangle on the\nright. The open panel uses the shared `.vf-panel` recipe and is positioned\n`position: fixed` (computed from `getBoundingClientRect()`) so it escapes\nclipping containers; when possible the currently-selected item opens\ndirectly over the control, like the real popup menu.\n\nPointer — two interaction styles are supported and disambiguated by the\ngesture itself, resolved at the first pointer release:\n - System 7 press-drag-release: press the pill (the list appears under the\n pointer), drag onto an item, release over it to pick — one continuous\n press. Releasing over the current item or off the list closes with no\n change.\n - Modern click-to-open: a quick in-place click (no drag, released within\n PRESS_HOLD_MS) leaves the list open; a second, independent click\n then picks an item.\nThe two share one opening trigger (pointerdown) and diverge only on how the\npress ends — whether the pointer travelled to another item, and (for an\nin-place release) whether it was a quick tap or a held press. The pull-down\nmenus drive themselves the same way, on the same threshold; that half lives\nin src/menu-press.ts, because one menu press may travel across a whole bar.\n\nA list too tall for the screen is **clipped**, never scrolled: the edge slot\nwith items beyond it shows a solid arrow instead of a row, which rolls the\nlist one row at a time while the pointer rests on it. The clamp is quantized\nto the pill lattice, so a clipped popup still opens with its selected row\nover the closed pill — and the panel keeps every slot the list asked for, so\na box that had to slide to fit the screen opens with *blank rows* at whichever\nend the list no longer reaches: the exact travel it will roll through, in\neither direction. See src/popup-overflow.ts.\n\n`size=\"small\"` sets the pill and its rows in the body face: a 12px pill\n(`--vf-popup-height-small`) over 10px rows, the baseline 8 rows down so the\nface's 2-row descenders end on the last content row. Its ▼ and scroll\narrows are the 9×5 `CARET_DOWN_SMALL` / `CARET_UP_SMALL`; the ✓ and the\nhorizontal insets are the regular pill's. Marks above a capital (É, Å, Ñ)\nreach past the 8 rows above the baseline and are clipped.\n\n`no-shadow` draws the closed pill without its 1px hard shadow, and the focus\nrule moves up the row the shadow took. The open list keeps its shadow.\n\nKeyboard: Space/Enter/ArrowDown open; while open ArrowUp/ArrowDown move the\nhighlight, Home/End jump, Enter/Space select, Escape cancels. Selecting an\nitem plays the classic inversion blink (~250 ms) before closing. Keyboard\nfocus is marked with the kit's 1px dashed rule under the closed pill\n(`vfFocusUnderline`) rather than a ring around it — keyboard only, which\nhere means the page's input modality rather than `:focus-visible` (the pill\ndrives its own focus, and Blink reads that as visible either way).\n\nForm-associated: submits `value` under `name`.",
13984
+ "description": "`<vf-select>` — the classic System 7 popup menu control (\"Macintosh HD ▼\").\n\nChildren are `<vf-option>` elements in the default slot. The closed control\nis a white box with a 1px black border, the small 1px hard shadow, the\nselected option's label on the left and a solid black ▼ triangle on the\nright. The open panel uses the shared `.vf-panel` recipe and is a manual\npopover in the top layer, positioned `position: fixed` (computed from\n`getBoundingClientRect()`), so it escapes clipping containers and paints\nover every window, palettes included; when possible the currently-selected\nitem opens directly over the control, like the real popup menu.\n\nPointer — two interaction styles are supported and disambiguated by the\ngesture itself, resolved at the first pointer release:\n - System 7 press-drag-release: press the pill (the list appears under the\n pointer), drag onto an item, release over it to pick — one continuous\n press. Releasing over the current item or off the list closes with no\n change.\n - Modern click-to-open: a quick in-place click (no drag, released within\n PRESS_HOLD_MS) leaves the list open; a second, independent click\n then picks an item.\nThe two share one opening trigger (pointerdown) and diverge only on how the\npress ends — whether the pointer travelled to another item, and (for an\nin-place release) whether it was a quick tap or a held press. The pull-down\nmenus drive themselves the same way, on the same threshold; that half lives\nin src/menu-press.ts, because one menu press may travel across a whole bar.\n\nA list too tall for the screen is **clipped**, never scrolled: the edge slot\nwith items beyond it shows a solid arrow instead of a row, which rolls the\nlist one row at a time while the pointer rests on it. The clamp is quantized\nto the pill lattice, so a clipped popup still opens with its selected row\nover the closed pill — and the panel keeps every slot the list asked for, so\na box that had to slide to fit the screen opens with *blank rows* at whichever\nend the list no longer reaches: the exact travel it will roll through, in\neither direction. See src/popup-overflow.ts.\n\n`size=\"small\"` sets the pill and its rows in the body face: a 12px pill\n(`--vf-popup-height-small`) over 10px rows, the baseline 8 rows down so the\nface's 2-row descenders end on the last content row. Its ▼ and scroll\narrows are the 9×5 `CARET_DOWN_SMALL` / `CARET_UP_SMALL`; the ✓ and the\nhorizontal insets are the regular pill's. Marks above a capital (É, Å, Ñ)\nreach past the 8 rows above the baseline and are clipped.\n\n`no-shadow` draws the closed pill without its 1px hard shadow, and the focus\nrule moves up the row the shadow took. The open list keeps its shadow.\n\nKeyboard: Space/Enter/ArrowDown open; while open ArrowUp/ArrowDown move the\nhighlight, Home/End jump, Enter/Space select, Escape cancels. Selecting an\nitem plays the classic inversion blink (~250 ms) before closing. Keyboard\nfocus is marked with the kit's 1px dashed rule under the closed pill\n(`vfFocusUnderline`) rather than a ring around it — keyboard only, which\nhere means the page's input modality rather than `:focus-visible` (the pill\ndrives its own focus, and Blink reads that as visible either way).\n\nForm-associated: submits `value` under `name`.",
13764
13985
  "name": "VfSelect",
13765
13986
  "cssProperties": [
13766
13987
  {
@@ -18265,29 +18486,71 @@
18265
18486
  }
18266
18487
  },
18267
18488
  {
18268
- "kind": "method",
18269
- "name": "formResetCallback",
18270
- "return": {
18271
- "type": {
18272
- "text": "void"
18273
- }
18489
+ "kind": "field",
18490
+ "name": "committed",
18491
+ "type": {
18492
+ "text": "string | null"
18274
18493
  },
18275
- "description": "Restores the initial value when the associated form resets.",
18494
+ "privacy": "protected",
18495
+ "default": "null",
18496
+ "description": "The text as last committed: taken when the field gains focus, then at\neach commit. A commit that brings nothing new isn't announced, so the\nnative `change` that follows a Return commit, or a step, is not a second\none.",
18276
18497
  "inheritedFrom": {
18277
18498
  "name": "VfTextControlBase",
18278
18499
  "module": "src/text-control.ts"
18279
18500
  }
18280
18501
  },
18281
18502
  {
18282
- "kind": "method",
18283
- "name": "isSubmitEnter",
18284
- "privacy": "protected",
18285
- "return": {
18286
- "type": {
18287
- "text": "boolean"
18288
- }
18503
+ "kind": "field",
18504
+ "name": "control",
18505
+ "type": {
18506
+ "text": "HTMLInputElement | HTMLTextAreaElement | null"
18289
18507
  },
18290
- "parameters": [
18508
+ "privacy": "protected",
18509
+ "description": "The inner native control every field renders, tagged `vf-field`.",
18510
+ "readonly": true,
18511
+ "inheritedFrom": {
18512
+ "name": "VfTextControlBase",
18513
+ "module": "src/text-control.ts"
18514
+ }
18515
+ },
18516
+ {
18517
+ "kind": "method",
18518
+ "name": "select",
18519
+ "return": {
18520
+ "type": {
18521
+ "text": "void"
18522
+ }
18523
+ },
18524
+ "description": "Select all of the field's text, as a native field's `select()` does.",
18525
+ "inheritedFrom": {
18526
+ "name": "VfTextControlBase",
18527
+ "module": "src/text-control.ts"
18528
+ }
18529
+ },
18530
+ {
18531
+ "kind": "method",
18532
+ "name": "formResetCallback",
18533
+ "return": {
18534
+ "type": {
18535
+ "text": "void"
18536
+ }
18537
+ },
18538
+ "description": "Restores the initial value when the associated form resets.",
18539
+ "inheritedFrom": {
18540
+ "name": "VfTextControlBase",
18541
+ "module": "src/text-control.ts"
18542
+ }
18543
+ },
18544
+ {
18545
+ "kind": "method",
18546
+ "name": "isSubmitEnter",
18547
+ "privacy": "protected",
18548
+ "return": {
18549
+ "type": {
18550
+ "text": "boolean"
18551
+ }
18552
+ },
18553
+ "parameters": [
18291
18554
  {
18292
18555
  "name": "event",
18293
18556
  "type": {
@@ -18346,6 +18609,52 @@
18346
18609
  "module": "src/text-control.ts"
18347
18610
  }
18348
18611
  },
18612
+ {
18613
+ "kind": "method",
18614
+ "name": "committedText",
18615
+ "privacy": "protected",
18616
+ "return": {
18617
+ "type": {
18618
+ "text": "string"
18619
+ }
18620
+ },
18621
+ "parameters": [
18622
+ {
18623
+ "name": "raw",
18624
+ "type": {
18625
+ "text": "string"
18626
+ }
18627
+ }
18628
+ ],
18629
+ "description": "The committed form of typed text: as typed here; `vf-number-field` clamps and rounds it.",
18630
+ "inheritedFrom": {
18631
+ "name": "VfTextControlBase",
18632
+ "module": "src/text-control.ts"
18633
+ }
18634
+ },
18635
+ {
18636
+ "kind": "method",
18637
+ "name": "commit",
18638
+ "privacy": "protected",
18639
+ "return": {
18640
+ "type": {
18641
+ "text": "void"
18642
+ }
18643
+ },
18644
+ "parameters": [
18645
+ {
18646
+ "name": "raw",
18647
+ "type": {
18648
+ "text": "string"
18649
+ }
18650
+ }
18651
+ ],
18652
+ "description": "Commit typed text: its committed form into `value`, announced unless it is what was last committed.",
18653
+ "inheritedFrom": {
18654
+ "name": "VfTextControlBase",
18655
+ "module": "src/text-control.ts"
18656
+ }
18657
+ },
18349
18658
  {
18350
18659
  "kind": "method",
18351
18660
  "name": "handleChange",
@@ -18363,7 +18672,30 @@
18363
18672
  }
18364
18673
  }
18365
18674
  ],
18366
- "description": "Mirror the native control's value into `value` and announce a commit.",
18675
+ "description": "The native control's commit.",
18676
+ "inheritedFrom": {
18677
+ "name": "VfTextControlBase",
18678
+ "module": "src/text-control.ts"
18679
+ }
18680
+ },
18681
+ {
18682
+ "kind": "method",
18683
+ "name": "submitOnEnter",
18684
+ "privacy": "protected",
18685
+ "return": {
18686
+ "type": {
18687
+ "text": "void"
18688
+ }
18689
+ },
18690
+ "parameters": [
18691
+ {
18692
+ "name": "event",
18693
+ "type": {
18694
+ "text": "KeyboardEvent"
18695
+ }
18696
+ }
18697
+ ],
18698
+ "description": "A plain Return in a single-line field with a form: commit, then the\nform's implicit submission, the order a native input keeps (its `change`\ncomes before the submission). The keydown is cancelled, so an enclosing\nmodal does not route the same press to its default button as well.",
18367
18699
  "inheritedFrom": {
18368
18700
  "name": "VfTextControlBase",
18369
18701
  "module": "src/text-control.ts"
@@ -19186,7 +19518,7 @@
19186
19518
  }
19187
19519
  }
19188
19520
  ],
19189
- "description": "Enter in a single-line field triggers the associated form's implicit\nsubmission. The native `<input>` is shadow-encapsulated, so its form owner\nis null and the browser won't do this itself. A press the form took is\ncancelled, so an enclosing modal does not route it again."
19521
+ "description": "Enter in a single-line field commits, then triggers the associated\nform's implicit submission. The native `<input>` is shadow-encapsulated,\nso its form owner is null and the browser won't do this itself."
19190
19522
  },
19191
19523
  {
19192
19524
  "kind": "field",
@@ -19416,6 +19748,48 @@
19416
19748
  "module": "src/text-control.ts"
19417
19749
  }
19418
19750
  },
19751
+ {
19752
+ "kind": "field",
19753
+ "name": "committed",
19754
+ "type": {
19755
+ "text": "string | null"
19756
+ },
19757
+ "privacy": "protected",
19758
+ "default": "null",
19759
+ "description": "The text as last committed: taken when the field gains focus, then at\neach commit. A commit that brings nothing new isn't announced, so the\nnative `change` that follows a Return commit, or a step, is not a second\none.",
19760
+ "inheritedFrom": {
19761
+ "name": "VfTextControlBase",
19762
+ "module": "src/text-control.ts"
19763
+ }
19764
+ },
19765
+ {
19766
+ "kind": "field",
19767
+ "name": "control",
19768
+ "type": {
19769
+ "text": "HTMLInputElement | HTMLTextAreaElement | null"
19770
+ },
19771
+ "privacy": "protected",
19772
+ "description": "The inner native control every field renders, tagged `vf-field`.",
19773
+ "readonly": true,
19774
+ "inheritedFrom": {
19775
+ "name": "VfTextControlBase",
19776
+ "module": "src/text-control.ts"
19777
+ }
19778
+ },
19779
+ {
19780
+ "kind": "method",
19781
+ "name": "select",
19782
+ "return": {
19783
+ "type": {
19784
+ "text": "void"
19785
+ }
19786
+ },
19787
+ "description": "Select all of the field's text, as a native field's `select()` does.",
19788
+ "inheritedFrom": {
19789
+ "name": "VfTextControlBase",
19790
+ "module": "src/text-control.ts"
19791
+ }
19792
+ },
19419
19793
  {
19420
19794
  "kind": "method",
19421
19795
  "name": "formResetCallback",
@@ -19521,6 +19895,52 @@
19521
19895
  "module": "src/text-control.ts"
19522
19896
  }
19523
19897
  },
19898
+ {
19899
+ "kind": "method",
19900
+ "name": "committedText",
19901
+ "privacy": "protected",
19902
+ "return": {
19903
+ "type": {
19904
+ "text": "string"
19905
+ }
19906
+ },
19907
+ "parameters": [
19908
+ {
19909
+ "name": "raw",
19910
+ "type": {
19911
+ "text": "string"
19912
+ }
19913
+ }
19914
+ ],
19915
+ "description": "The committed form of typed text: as typed here; `vf-number-field` clamps and rounds it.",
19916
+ "inheritedFrom": {
19917
+ "name": "VfTextControlBase",
19918
+ "module": "src/text-control.ts"
19919
+ }
19920
+ },
19921
+ {
19922
+ "kind": "method",
19923
+ "name": "commit",
19924
+ "privacy": "protected",
19925
+ "return": {
19926
+ "type": {
19927
+ "text": "void"
19928
+ }
19929
+ },
19930
+ "parameters": [
19931
+ {
19932
+ "name": "raw",
19933
+ "type": {
19934
+ "text": "string"
19935
+ }
19936
+ }
19937
+ ],
19938
+ "description": "Commit typed text: its committed form into `value`, announced unless it is what was last committed.",
19939
+ "inheritedFrom": {
19940
+ "name": "VfTextControlBase",
19941
+ "module": "src/text-control.ts"
19942
+ }
19943
+ },
19524
19944
  {
19525
19945
  "kind": "method",
19526
19946
  "name": "handleChange",
@@ -19538,7 +19958,30 @@
19538
19958
  }
19539
19959
  }
19540
19960
  ],
19541
- "description": "Mirror the native control's value into `value` and announce a commit.",
19961
+ "description": "The native control's commit.",
19962
+ "inheritedFrom": {
19963
+ "name": "VfTextControlBase",
19964
+ "module": "src/text-control.ts"
19965
+ }
19966
+ },
19967
+ {
19968
+ "kind": "method",
19969
+ "name": "submitOnEnter",
19970
+ "privacy": "protected",
19971
+ "return": {
19972
+ "type": {
19973
+ "text": "void"
19974
+ }
19975
+ },
19976
+ "parameters": [
19977
+ {
19978
+ "name": "event",
19979
+ "type": {
19980
+ "text": "KeyboardEvent"
19981
+ }
19982
+ }
19983
+ ],
19984
+ "description": "A plain Return in a single-line field with a form: commit, then the\nform's implicit submission, the order a native input keeps (its `change`\ncomes before the submission). The keydown is cancelled, so an enclosing\nmodal does not route the same press to its default button as well.",
19542
19985
  "inheritedFrom": {
19543
19986
  "name": "VfTextControlBase",
19544
19987
  "module": "src/text-control.ts"
@@ -20077,7 +20520,7 @@
20077
20520
  "name": "vf-input"
20078
20521
  },
20079
20522
  {
20080
- "description": "On commit (native `change`). `detail: { value: string }`.",
20523
+ "description": "On commit: the native `change`, leaving the field, or Return in a form, before its submission. `detail: { value: string }`.",
20081
20524
  "name": "vf-change"
20082
20525
  },
20083
20526
  {
@@ -20292,7 +20735,7 @@
20292
20735
  "declarations": [
20293
20736
  {
20294
20737
  "kind": "class",
20295
- "description": "`<vf-window>` — the System 7 desktop-window shell.\n\nStriped title bar with optional close box (left) and zoom box (right), a\nsolid-white frame with a hard offset shadow, an optional grow box for\nresizing, optional edge scroll rails (`scrollbars`), and the slim windoid\nchrome (`variant=\"utility\"`). The HIG's window archetypes are parameter\nrecipes over this shell rather than fixed anatomies — the component enables\nHIG compliance, it doesn't enforce it (see docs/LAYOUT.md \"Window archetypes\"):\nthe full document window is `closable zoomable movable resizable\nscrollbars=\"both\"`, a modeless dialog box is `closable movable`, a utility\nwindow is `variant=\"utility\" movable`. Place inside `<vf-desktop>` to get\nclick-to-front stacking and automatic `active` management (utility windows\nfloat above the document tier).\n\nEvery recipe also declares `width` AND `height` (VfSized), in whole\nsystem px — the art's own unit, so the window keeps its proportions to the\nchrome inside it at every display density (a CSS-px size stays put while\nthe components in it triple). A window is a fixed box in both axes, the way\nthe WIND resource carried it: left to layout it takes whatever its\ncontainer or content hands it, which is how a title bar ends up wider than\nthe screen or a dialog reflows as it moves — and a window that grows with\nits body is one the user can neither predict nor (via the grow box) own.\nContent taller than the declared box is clipped at the frame the way the\nclassic content region was; `scrollbars` lets the user reach the rest.\nUnset, the window still renders — normal block layout, as before — and\nsays so once in the console.\n\n**Opening from a rect.** show clears `hidden`, and given `from` — a\nbox in viewport CSS px, an icon's `cellRect()` or a button's rect — opens\nthe window from it: dotted rectangles grow from that box toward the\nwindow's frame, four on screen at a time, bunched at the box and opening\nout toward the window, drawn with the icon drag outline's XOR pen on the\ndesktop's drag surface; the window draws once they have drained, eighteen\nsteps later. Until then it matches `:state(opening)` and paints nothing —\nstill laid out, focusable and a hit target, so a page can place it, raise\nit and focus into it at once, and a press finishes the rects and lands on\nthe window. Under `prefers-reduced-motion`, with no `vf-desktop` on its\npath, or without `from`, the window shows at once.\n\n**Closing to a rect.** hide sets `hidden`, and given `to` closes\nthe window to it: the same rectangles run the other way, from where the\nframe was in toward the box, the window gone from the first step. A press\nfinishes them, and removing the window leaves them running. Under\n`prefers-reduced-motion`, with no `vf-desktop` on its path, or without\n`to`, the window hides at once. The window knows nothing about icons:\n`from` and `to` are any rect.\n\n**Dragging as an outline.** A `movable` window moves live under the\npointer. With `outline-drag` a press on the title bar draws a dotted\noutline around the window on the desktop's drag surface instead, with the\nsame pen; the drag moves the outline, held where the window can land, and\nthe window moves there on the release. Escape cancels.",
20738
+ "description": "`<vf-window>` — the System 7 desktop-window shell.\n\nStriped title bar with optional close box (left) and zoom box (right), a\nsolid-white frame with a hard offset shadow, an optional grow box for\nresizing, optional edge scroll rails (`scrollbars`), and the slim windoid\nchrome (`variant=\"utility\"`). The HIG's window archetypes are parameter\nrecipes over this shell rather than fixed anatomies — the component enables\nHIG compliance, it doesn't enforce it (see docs/LAYOUT.md \"Window archetypes\"):\nthe full document window is `closable zoomable movable resizable\nscrollbars=\"both\"`, a modeless dialog box is `closable movable`, a utility\nwindow is `variant=\"utility\" closable movable`. Place inside `<vf-desktop>` to get\nclick-to-front stacking and automatic `active` management (utility windows\nfloat above the document tier).\n\nEvery recipe also declares `width` AND `height` (VfSized), in whole\nsystem px — the art's own unit, so the window keeps its proportions to the\nchrome inside it at every display density (a CSS-px size stays put while\nthe components in it triple). A window is a fixed box in both axes, the way\nthe WIND resource carried it: left to layout it takes whatever its\ncontainer or content hands it, which is how a title bar ends up wider than\nthe screen or a dialog reflows as it moves — and a window that grows with\nits body is one the user can neither predict nor (via the grow box) own.\nContent taller than the declared box is clipped at the frame the way the\nclassic content region was; `scrollbars` lets the user reach the rest.\nUnset, the window still renders — normal block layout, as before — and\nsays so once in the console.\n\n**Opening from a rect.** show clears `hidden`, and given `from` — a\nbox in viewport CSS px, an icon's `cellRect()` or a button's rect — opens\nthe window from it: dotted rectangles grow from that box toward the\nwindow's frame, four on screen at a time, bunched at the box and opening\nout toward the window, drawn with the icon drag outline's XOR pen on the\ndesktop's drag surface; the window draws once they have drained, eighteen\nsteps later. Until then it matches `:state(opening)` and paints nothing —\nstill laid out, focusable and a hit target, so a page can place it, raise\nit and focus into it at once, and a press finishes the rects and lands on\nthe window. Under `prefers-reduced-motion`, with no `vf-desktop` on its\npath, or without `from`, the window shows at once.\n\n**Closing to a rect.** hide sets `hidden`, and given `to` closes\nthe window to it: the same rectangles run the other way, from where the\nframe was in toward the box, the window gone from the first step. A press\nfinishes them, and removing the window leaves them running. Under\n`prefers-reduced-motion`, with no `vf-desktop` on its path, or without\n`to`, the window hides at once. The window knows nothing about icons:\n`from` and `to` are any rect.\n\n**Dragging as an outline.** A `movable` window moves live under the\npointer. With `outline-drag` a press on the title bar draws a dotted\noutline around the window on the desktop's drag surface instead, with the\nsame pen; the drag moves the outline, held where the window can land, and\nthe window moves there on the release. Escape cancels.",
20296
20739
  "name": "VfWindow",
20297
20740
  "cssProperties": [
20298
20741
  {
@@ -20413,8 +20856,8 @@
20413
20856
  "type": {
20414
20857
  "text": "boolean"
20415
20858
  },
20416
- "default": "true",
20417
- "description": "Show the close box (left side of the title bar).",
20859
+ "default": "false",
20860
+ "description": "Show the close box (left side of the title bar). Off by default, like\nevery other boolean attribute, so markup can leave it out; the document\nwindow and the modeless dialog box recipes say `closable`.",
20418
20861
  "attribute": "closable",
20419
20862
  "reflects": true
20420
20863
  },
@@ -20526,6 +20969,35 @@
20526
20969
  "description": "The header's height in whole system px, rule included — the way every\nkit bar counts its rule (an 18px title bar is 17 + 1). Unset, the header\nis as tall as what is slotted into it, plus the rule. Only matters while\nthe `header` slot is populated.",
20527
20970
  "attribute": "header-height"
20528
20971
  },
20972
+ {
20973
+ "kind": "field",
20974
+ "name": "pattern",
20975
+ "type": {
20976
+ "text": "string | null | undefined"
20977
+ },
20978
+ "description": "A 1-bit fill for the body, as on `vf-container`: a library pattern by\nname (docs/PATTERNS.md) or sixteen hex digits, under the content and\nanchored at the content region's corner. Under `scrollbars` it fills the\nscrolled plane and scrolls with it (`vf-scroll-area`'s `pattern`). Unset,\nthe body stays white; an unrecognized value paints nothing and warns\nonce.",
20979
+ "attribute": "pattern"
20980
+ },
20981
+ {
20982
+ "kind": "field",
20983
+ "name": "_pattern",
20984
+ "type": {
20985
+ "text": "Pattern | null"
20986
+ },
20987
+ "privacy": "private",
20988
+ "default": "null",
20989
+ "description": "`pattern`, resolved — what the body's fill paints; null paints nothing."
20990
+ },
20991
+ {
20992
+ "kind": "field",
20993
+ "name": "#warnedPattern",
20994
+ "privacy": "private",
20995
+ "type": {
20996
+ "text": "boolean"
20997
+ },
20998
+ "default": "false",
20999
+ "description": "One warning per element for an unrecognized `pattern`, not per render."
21000
+ },
20529
21001
  {
20530
21002
  "kind": "field",
20531
21003
  "name": "_hasHeader",
@@ -20608,6 +21080,14 @@
20608
21080
  "default": "new RepeatTileController(this, { getBox: () => this.renderRoot?.querySelector<HTMLElement>('.vf-dots'), getArt: () => (this.variant === 'utility' && !this._dotsPattern ? DOTS : null), property: '--_vf-dots-tile', })",
20609
21081
  "description": "The kit dots: the utility bar's `.vf-dots` layer carries the repeating\ntile as `--_vf-dots-tile` (`vfDots`), whatever the window's width."
20610
21082
  },
21083
+ {
21084
+ "kind": "field",
21085
+ "name": "#bodyFill",
21086
+ "privacy": "private",
21087
+ "readonly": true,
21088
+ "default": "new PatternFillController(this, { getBox: () => this.body, getPattern: () => (this.scrollbars ? null : this._pattern), })",
21089
+ "description": "The body's pattern fill (src/pattern-fill.ts). Under `scrollbars` the\nbuilt-in scroll area paints it on its scrolled plane instead."
21090
+ },
20611
21091
  {
20612
21092
  "kind": "method",
20613
21093
  "name": "_dotsTexture",
@@ -21085,7 +21565,15 @@
21085
21565
  "type": {
21086
21566
  "text": "void"
21087
21567
  }
21088
- }
21568
+ },
21569
+ "parameters": [
21570
+ {
21571
+ "name": "event",
21572
+ "type": {
21573
+ "text": "MouseEvent"
21574
+ }
21575
+ }
21576
+ ]
21089
21577
  },
21090
21578
  {
21091
21579
  "kind": "method",
@@ -21236,7 +21724,7 @@
21236
21724
  ],
21237
21725
  "events": [
21238
21726
  {
21239
- "description": "Close box clicked. Detail `{ reason: 'close' }` (shape- compatible with vf-dialog's `vf-close`). The window does NOT remove itself; the consumer decides what closing means.",
21727
+ "description": "Close box clicked. Detail `{ reason: 'close', altKey, shiftKey, metaKey, ctrlKey }`, the modifier keys held on the click (shape-compatible with vf-dialog's `vf-close`), so an Option-click can mean more than a click. The window does NOT remove itself; the consumer decides what closing means.",
21240
21728
  "name": "vf-close"
21241
21729
  },
21242
21730
  {
@@ -21280,8 +21768,8 @@
21280
21768
  "type": {
21281
21769
  "text": "boolean"
21282
21770
  },
21283
- "default": "true",
21284
- "description": "Show the close box (left side of the title bar).",
21771
+ "default": "false",
21772
+ "description": "Show the close box (left side of the title bar). Off by default, like\nevery other boolean attribute, so markup can leave it out; the document\nwindow and the modeless dialog box recipes say `closable`.",
21285
21773
  "fieldName": "closable"
21286
21774
  },
21287
21775
  {
@@ -21368,6 +21856,14 @@
21368
21856
  "description": "The header's height in whole system px, rule included — the way every\nkit bar counts its rule (an 18px title bar is 17 + 1). Unset, the header\nis as tall as what is slotted into it, plus the rule. Only matters while\nthe `header` slot is populated.",
21369
21857
  "fieldName": "headerHeight"
21370
21858
  },
21859
+ {
21860
+ "name": "pattern",
21861
+ "type": {
21862
+ "text": "string | null | undefined"
21863
+ },
21864
+ "description": "A 1-bit fill for the body, as on `vf-container`: a library pattern by\nname (docs/PATTERNS.md) or sixteen hex digits, under the content and\nanchored at the content region's corner. Under `scrollbars` it fills the\nscrolled plane and scrolls with it (`vf-scroll-area`'s `pattern`). Unset,\nthe body stays white; an unrecognized value paints nothing and warns\nonce.",
21865
+ "fieldName": "pattern"
21866
+ },
21371
21867
  {
21372
21868
  "name": "width",
21373
21869
  "type": {
@@ -22563,6 +23059,36 @@
22563
23059
  "description": "Classes for the `.vf-field-well` wrapper every field renders around its\nnative control: the shared skin hook (`vfField`), the grid-snap target, and\nthe focus rule's own gate. Assembled here so the three fields state the\nwrapper once and can't drift on what turns the rule on.",
22564
23060
  "readonly": true
22565
23061
  },
23062
+ {
23063
+ "kind": "field",
23064
+ "name": "committed",
23065
+ "type": {
23066
+ "text": "string | null"
23067
+ },
23068
+ "privacy": "protected",
23069
+ "default": "null",
23070
+ "description": "The text as last committed: taken when the field gains focus, then at\neach commit. A commit that brings nothing new isn't announced, so the\nnative `change` that follows a Return commit, or a step, is not a second\none."
23071
+ },
23072
+ {
23073
+ "kind": "field",
23074
+ "name": "control",
23075
+ "type": {
23076
+ "text": "HTMLInputElement | HTMLTextAreaElement | null"
23077
+ },
23078
+ "privacy": "protected",
23079
+ "description": "The inner native control every field renders, tagged `vf-field`.",
23080
+ "readonly": true
23081
+ },
23082
+ {
23083
+ "kind": "method",
23084
+ "name": "select",
23085
+ "return": {
23086
+ "type": {
23087
+ "text": "void"
23088
+ }
23089
+ },
23090
+ "description": "Select all of the field's text, as a native field's `select()` does."
23091
+ },
22566
23092
  {
22567
23093
  "kind": "method",
22568
23094
  "name": "formResetCallback",
@@ -22648,6 +23174,44 @@
22648
23174
  ],
22649
23175
  "description": "Mirror the native control's value into `value` and announce a keystroke."
22650
23176
  },
23177
+ {
23178
+ "kind": "method",
23179
+ "name": "committedText",
23180
+ "privacy": "protected",
23181
+ "return": {
23182
+ "type": {
23183
+ "text": "string"
23184
+ }
23185
+ },
23186
+ "parameters": [
23187
+ {
23188
+ "name": "raw",
23189
+ "type": {
23190
+ "text": "string"
23191
+ }
23192
+ }
23193
+ ],
23194
+ "description": "The committed form of typed text: as typed here; `vf-number-field` clamps and rounds it."
23195
+ },
23196
+ {
23197
+ "kind": "method",
23198
+ "name": "commit",
23199
+ "privacy": "protected",
23200
+ "return": {
23201
+ "type": {
23202
+ "text": "void"
23203
+ }
23204
+ },
23205
+ "parameters": [
23206
+ {
23207
+ "name": "raw",
23208
+ "type": {
23209
+ "text": "string"
23210
+ }
23211
+ }
23212
+ ],
23213
+ "description": "Commit typed text: its committed form into `value`, announced unless it is what was last committed."
23214
+ },
22651
23215
  {
22652
23216
  "kind": "method",
22653
23217
  "name": "handleChange",
@@ -22665,7 +23229,26 @@
22665
23229
  }
22666
23230
  }
22667
23231
  ],
22668
- "description": "Mirror the native control's value into `value` and announce a commit."
23232
+ "description": "The native control's commit."
23233
+ },
23234
+ {
23235
+ "kind": "method",
23236
+ "name": "submitOnEnter",
23237
+ "privacy": "protected",
23238
+ "return": {
23239
+ "type": {
23240
+ "text": "void"
23241
+ }
23242
+ },
23243
+ "parameters": [
23244
+ {
23245
+ "name": "event",
23246
+ "type": {
23247
+ "text": "KeyboardEvent"
23248
+ }
23249
+ }
23250
+ ],
23251
+ "description": "A plain Return in a single-line field with a form: commit, then the\nform's implicit submission, the order a native input keeps (its `change`\ncomes before the submission). The keydown is cancelled, so an enclosing\nmodal does not route the same press to its default button as well."
22669
23252
  },
22670
23253
  {
22671
23254
  "kind": "field",
@@ -23678,6 +24261,16 @@
23678
24261
  "default": "null",
23679
24262
  "description": "The value `close(value)` gave, pending for the next native `close` event."
23680
24263
  },
24264
+ {
24265
+ "kind": "field",
24266
+ "name": "#closeKeys",
24267
+ "privacy": "private",
24268
+ "type": {
24269
+ "text": "VfCloseKeys | null"
24270
+ },
24271
+ "default": "null",
24272
+ "description": "The modifier keys a close box's click held, pending for the next native `close` event."
24273
+ },
23681
24274
  {
23682
24275
  "kind": "field",
23683
24276
  "name": "#onSubmit",
@@ -23728,10 +24321,10 @@
23728
24321
  "privacy": "private",
23729
24322
  "return": {
23730
24323
  "type": {
23731
- "text": "void"
24324
+ "text": "HTMLElement | null"
23732
24325
  }
23733
24326
  },
23734
- "description": "Hand focus to initialFocusTarget, right after `showModal()`'s own\nfocusing steps have run (so this is the last word, not a race)."
24327
+ "description": "Hand focus to initialFocusTarget, right after `showModal()`'s own\nfocusing steps have run (so this is the last word, not a race). Returns\nthe element focused, for `vf-show`."
23735
24328
  },
23736
24329
  {
23737
24330
  "kind": "field",
@@ -23795,6 +24388,25 @@
23795
24388
  ],
23796
24389
  "description": "Close the modal, with `returnValue` as its answer when one is given.\nFires `vf-close` with `{ reason: 'close', returnValue }`."
23797
24390
  },
24391
+ {
24392
+ "kind": "method",
24393
+ "name": "closeFromBox",
24394
+ "privacy": "protected",
24395
+ "return": {
24396
+ "type": {
24397
+ "text": "void"
24398
+ }
24399
+ },
24400
+ "parameters": [
24401
+ {
24402
+ "name": "keys",
24403
+ "type": {
24404
+ "text": "VfCloseKeys"
24405
+ }
24406
+ }
24407
+ ],
24408
+ "description": "Close from a close box, its `vf-close` carrying the modifier keys held on the click."
24409
+ },
23798
24410
  {
23799
24411
  "kind": "method",
23800
24412
  "name": "#viewport",
@@ -23975,6 +24587,10 @@
23975
24587
  }
23976
24588
  ],
23977
24589
  "events": [
24590
+ {
24591
+ "description": "The modal opened: it is in the top layer, placed, and its initial focus is set. `detail: { focus }`, the element focused. The page's moment to finish composing it — select a field's default text, measure copy that varies. Fired inside `show()` once the modal has rendered, else at its first render.",
24592
+ "name": "vf-show"
24593
+ },
23978
24594
  {
23979
24595
  "description": "The modal closed. `detail: { reason: 'escape' | 'close' | 'outside', returnValue: string | null }`.",
23980
24596
  "name": "vf-close"