vintage-frames 0.1.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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/custom-elements.json +19807 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js +9 -0
  5. package/dist/chrome.d.ts +73 -0
  6. package/dist/chrome.js +94 -0
  7. package/dist/components/vf-button-group.d.ts +50 -0
  8. package/dist/components/vf-button-group.js +68 -0
  9. package/dist/components/vf-button.d.ts +169 -0
  10. package/dist/components/vf-button.js +234 -0
  11. package/dist/components/vf-checkbox.d.ts +60 -0
  12. package/dist/components/vf-checkbox.js +135 -0
  13. package/dist/components/vf-container.d.ts +95 -0
  14. package/dist/components/vf-container.js +86 -0
  15. package/dist/components/vf-desktop.d.ts +243 -0
  16. package/dist/components/vf-desktop.js +310 -0
  17. package/dist/components/vf-dialog.d.ts +105 -0
  18. package/dist/components/vf-dialog.js +280 -0
  19. package/dist/components/vf-fieldset.d.ts +34 -0
  20. package/dist/components/vf-fieldset.js +76 -0
  21. package/dist/components/vf-grid.d.ts +124 -0
  22. package/dist/components/vf-grid.js +133 -0
  23. package/dist/components/vf-icon.d.ts +356 -0
  24. package/dist/components/vf-icon.js +507 -0
  25. package/dist/components/vf-img.d.ts +63 -0
  26. package/dist/components/vf-img.js +65 -0
  27. package/dist/components/vf-label.d.ts +117 -0
  28. package/dist/components/vf-label.js +151 -0
  29. package/dist/components/vf-list-item.d.ts +48 -0
  30. package/dist/components/vf-list-item.js +98 -0
  31. package/dist/components/vf-list.d.ts +77 -0
  32. package/dist/components/vf-list.js +256 -0
  33. package/dist/components/vf-menu-bar.d.ts +64 -0
  34. package/dist/components/vf-menu-bar.js +236 -0
  35. package/dist/components/vf-menu-item.d.ts +91 -0
  36. package/dist/components/vf-menu-item.js +252 -0
  37. package/dist/components/vf-menu.d.ts +95 -0
  38. package/dist/components/vf-menu.js +346 -0
  39. package/dist/components/vf-number-field.d.ts +60 -0
  40. package/dist/components/vf-number-field.js +248 -0
  41. package/dist/components/vf-option.d.ts +49 -0
  42. package/dist/components/vf-option.js +119 -0
  43. package/dist/components/vf-paragraph.d.ts +73 -0
  44. package/dist/components/vf-paragraph.js +66 -0
  45. package/dist/components/vf-progress-bar.d.ts +69 -0
  46. package/dist/components/vf-progress-bar.js +272 -0
  47. package/dist/components/vf-radio-group.d.ts +109 -0
  48. package/dist/components/vf-radio-group.js +105 -0
  49. package/dist/components/vf-radio.d.ts +59 -0
  50. package/dist/components/vf-radio.js +135 -0
  51. package/dist/components/vf-scroll-area.d.ts +75 -0
  52. package/dist/components/vf-scroll-area.js +124 -0
  53. package/dist/components/vf-select.d.ts +334 -0
  54. package/dist/components/vf-select.js +658 -0
  55. package/dist/components/vf-separator.d.ts +38 -0
  56. package/dist/components/vf-separator.js +55 -0
  57. package/dist/components/vf-slider.d.ts +80 -0
  58. package/dist/components/vf-slider.js +255 -0
  59. package/dist/components/vf-stack.d.ts +188 -0
  60. package/dist/components/vf-stack.js +168 -0
  61. package/dist/components/vf-swatch.d.ts +98 -0
  62. package/dist/components/vf-swatch.js +201 -0
  63. package/dist/components/vf-text-area.d.ts +77 -0
  64. package/dist/components/vf-text-area.js +121 -0
  65. package/dist/components/vf-text-field.d.ts +53 -0
  66. package/dist/components/vf-text-field.js +79 -0
  67. package/dist/components/vf-window.d.ts +157 -0
  68. package/dist/components/vf-window.js +377 -0
  69. package/dist/cursor-art.d.ts +37 -0
  70. package/dist/cursor-art.js +41 -0
  71. package/dist/cursor.d.ts +49 -0
  72. package/dist/cursor.js +171 -0
  73. package/dist/define.d.ts +45 -0
  74. package/dist/define.js +15 -0
  75. package/dist/document-listeners.d.ts +62 -0
  76. package/dist/document-listeners.js +29 -0
  77. package/dist/drag.d.ts +49 -0
  78. package/dist/drag.js +30 -0
  79. package/dist/events.d.ts +79 -0
  80. package/dist/events.js +25 -0
  81. package/dist/focus-modality.d.ts +94 -0
  82. package/dist/focus-modality.js +56 -0
  83. package/dist/form-control.d.ts +247 -0
  84. package/dist/form-control.js +127 -0
  85. package/dist/glyphs.d.ts +117 -0
  86. package/dist/glyphs.js +100 -0
  87. package/dist/grid-snap.d.ts +73 -0
  88. package/dist/grid-snap.js +135 -0
  89. package/dist/index.d.ts +145 -0
  90. package/dist/index.js +71 -0
  91. package/dist/menu-press.d.ts +60 -0
  92. package/dist/menu-press.js +97 -0
  93. package/dist/modal-dialog.d.ts +148 -0
  94. package/dist/modal-dialog.js +155 -0
  95. package/dist/motion.d.ts +72 -0
  96. package/dist/motion.js +22 -0
  97. package/dist/number.d.ts +24 -0
  98. package/dist/number.js +12 -0
  99. package/dist/open-art.d.ts +40 -0
  100. package/dist/open-art.js +35 -0
  101. package/dist/pixel-frame.d.ts +102 -0
  102. package/dist/pixel-frame.js +77 -0
  103. package/dist/popup-overflow.d.ts +157 -0
  104. package/dist/popup-overflow.js +45 -0
  105. package/dist/position.d.ts +187 -0
  106. package/dist/position.js +74 -0
  107. package/dist/scale.d.ts +259 -0
  108. package/dist/scale.js +133 -0
  109. package/dist/scroll-rail.d.ts +112 -0
  110. package/dist/scroll-rail.js +194 -0
  111. package/dist/scroll-state.d.ts +113 -0
  112. package/dist/scroll-state.js +55 -0
  113. package/dist/size.d.ts +47 -0
  114. package/dist/size.js +30 -0
  115. package/dist/styles/base.d.ts +38 -0
  116. package/dist/styles/body-font.d.ts +7 -0
  117. package/dist/styles/body-font.js +9 -0
  118. package/dist/styles/display-font.d.ts +7 -0
  119. package/dist/styles/display-font.js +9 -0
  120. package/dist/styles/recipes/body-face.d.ts +14 -0
  121. package/dist/styles/recipes/body-face.js +6 -0
  122. package/dist/styles/recipes/display-face.d.ts +23 -0
  123. package/dist/styles/recipes/display-face.js +10 -0
  124. package/dist/styles/recipes/field.d.ts +20 -0
  125. package/dist/styles/recipes/field.js +68 -0
  126. package/dist/styles/recipes/focus.d.ts +76 -0
  127. package/dist/styles/recipes/focus.js +39 -0
  128. package/dist/styles/recipes/host.d.ts +5 -0
  129. package/dist/styles/recipes/host.js +62 -0
  130. package/dist/styles/recipes/pattern.d.ts +80 -0
  131. package/dist/styles/recipes/pattern.js +82 -0
  132. package/dist/styles/recipes/scroll-rail.d.ts +69 -0
  133. package/dist/styles/recipes/scroll-rail.js +222 -0
  134. package/dist/styles/recipes/shadow.d.ts +13 -0
  135. package/dist/styles/recipes/shadow.js +5 -0
  136. package/dist/styles/recipes/static-text.d.ts +24 -0
  137. package/dist/styles/recipes/static-text.js +17 -0
  138. package/dist/styles/recipes/surface.d.ts +28 -0
  139. package/dist/styles/recipes/surface.js +27 -0
  140. package/dist/styles/recipes/tile.d.ts +122 -0
  141. package/dist/styles/recipes/tile.js +40 -0
  142. package/dist/styles/recipes/title-bar.d.ts +49 -0
  143. package/dist/styles/recipes/title-bar.js +134 -0
  144. package/dist/styles/recipes/toggle.d.ts +10 -0
  145. package/dist/styles/recipes/toggle.js +20 -0
  146. package/dist/styles/register-embedded-font.d.ts +64 -0
  147. package/dist/styles/register-embedded-font.js +30 -0
  148. package/dist/text-control.d.ts +131 -0
  149. package/dist/text-control.js +83 -0
  150. package/dist/tile-grid.d.ts +111 -0
  151. package/dist/tile-grid.js +53 -0
  152. package/dist/toggle-control.d.ts +60 -0
  153. package/dist/toggle-control.js +41 -0
  154. package/dist/track-width.d.ts +42 -0
  155. package/dist/track-width.js +30 -0
  156. package/dist/type-ahead.d.ts +35 -0
  157. package/dist/type-ahead.js +20 -0
  158. package/dist/zoom.d.ts +204 -0
  159. package/dist/zoom.js +105 -0
  160. package/docs/SPEC.md +2471 -0
  161. package/editor/vscode.html-custom-data.json +1320 -0
  162. package/editor/web-types.json +3237 -0
  163. package/package.json +118 -0
@@ -0,0 +1,9 @@
1
+ //#region \0@oxc-project+runtime@0.143.0/helpers/esm/decorate.js
2
+ function e(e, t, n, r) {
3
+ var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
4
+ if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
5
+ else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
6
+ return i > 3 && a && Object.defineProperty(t, n, a), a;
7
+ }
8
+ //#endregion
9
+ export { e as default };
@@ -0,0 +1,73 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import type { ReactiveController, ReactiveControllerHost } from 'lit';
3
+ import type { DragController } from './drag.js';
4
+ export declare const chromeTitleBar: (drag: DragController, content: unknown, textureClass?: "vf-stripes" | "vf-dots", texture?: unknown) => TemplateResult;
5
+ /**
6
+ * Holds the flex-centered `.vf-title` patch on the placement lattice.
7
+ *
8
+ * The bar centers the patch as `(bar − patch) / 2`, and the patch's width
9
+ * follows the heading's text run — so whenever the two widths' parities
10
+ * differ the patch lands half a system px off the grid, which a 3:1 display
11
+ * renders as title ink one device px off (both the glyph rows against the
12
+ * close box's, and the patch edge cutting a stripe to a hairline). No static
13
+ * rule can fix a parity that depends on the string, so this controller
14
+ * measures the centered offset after each render and cancels the fraction
15
+ * with `--vf-title-dx` on the host, which the recipe applies as a relative
16
+ * `left` on the patch (through layout, not transform — a fractional
17
+ * transform leaves a composite-time fringe; see grid-snap.ts).
18
+ *
19
+ * The offset lands on the placement lattice ({@link systemPxQuantum} system
20
+ * px — whole CSS px at dpr 2, where engines re-quantize sub-CSS-px paint per
21
+ * box), the same lattice drags and dialog centering land on, so bar origin
22
+ * plus offset stays on it absolutely. The ideal position is derived in whole
23
+ * system px rather than snapped from the measured one: both widths are whole
24
+ * system px by construction (bitmap advances plus whole-px padding, in a
25
+ * whole-px bar), so rounding the measured widths recovers exact integers —
26
+ * the 1/64-CSS-px rect noise sits near an integer, never near a tie — and
27
+ * the centered lattice point follows by integer arithmetic, the exact-half
28
+ * parity case going left as QuickDraw's `div 2` did. A consumer-swapped
29
+ * vector face breaks the whole-px premise, but the rounded widths still put
30
+ * the patch on the lattice within half a step of true center, which is all
31
+ * ungridded ink needs.
32
+ *
33
+ * Re-measures after every host render (heading, size and scale changes all
34
+ * re-render) and on any resize of the bar or patch — which is also how a
35
+ * late-registering 'VF Display' lands: the swap re-measures the text run and
36
+ * resizes the patch. A missing or boxless patch (the plain dialog frame, the
37
+ * utility windoid's display:none title) resets the correction.
38
+ */
39
+ export declare class TitleCenterController implements ReactiveController {
40
+ private readonly host;
41
+ /** Our current correction, in CSS px. */
42
+ private applied;
43
+ /** Exactly what we last wrote, to detect an externally rewritten style. */
44
+ private written;
45
+ private frame;
46
+ private resizes?;
47
+ constructor(host: ReactiveControllerHost & HTMLElement);
48
+ hostConnected(): void;
49
+ hostDisconnected(): void;
50
+ hostUpdated(): void;
51
+ /** Coalesce to one measurement per frame, after layout settles. */
52
+ private schedule;
53
+ private center;
54
+ /** Drop the correction: delete the variable and forget everything. */
55
+ private reset;
56
+ }
57
+ /**
58
+ * Widget label, qualified by the window/dialog title when there is one —
59
+ * several windows are open at once by design, so a bare "Close" repeated
60
+ * across the desktop leaves an AT user no way to tell which window a button
61
+ * belongs to.
62
+ */
63
+ export declare const widgetLabel: (action: string, heading: string) => string;
64
+ /**
65
+ * The close box (left of the bar) and zoom box (right of the bar), shared by
66
+ * `vf-window` and a `closable` `vf-dialog`. Byte-identical markup for the same
67
+ * reason as {@link chromeTitleBar}: the widgets must match by construction,
68
+ * not by copies staying in sync. Skinned by `vfWindowWidgets` (styles/base.ts);
69
+ * drag delegates must keep ignoring pointerdowns on `.box` so a press on a
70
+ * widget never starts a bar drag.
71
+ */
72
+ export declare const closeBox: (label: string, onClick: () => void) => TemplateResult;
73
+ export declare const zoomBox: (label: string, onClick: () => void) => TemplateResult;
package/dist/chrome.js ADDED
@@ -0,0 +1,94 @@
1
+ import { truePixelRatio as e } from "./zoom.js";
2
+ import { effectiveScale as t, sysLength as n, systemPxQuantum as r } from "./scale.js";
3
+ import { html as i } from "lit";
4
+ //#region src/chrome.ts
5
+ var a = i`${[
6
+ 0,
7
+ 2,
8
+ 4,
9
+ 6,
10
+ 8,
11
+ 10
12
+ ].map((e) => i`<span style="top:${n(e)}"></span>`)}<svg
13
+ viewBox="0 0 2 12"
14
+ preserveAspectRatio="none"
15
+ shape-rendering="crispEdges"
16
+ aria-hidden="true"
17
+ >
18
+ <rect x="0" y="0" width="2" height="1"></rect>
19
+ <rect x="0" y="2" width="2" height="1"></rect>
20
+ <rect x="0" y="4" width="2" height="1"></rect>
21
+ <rect x="0" y="6" width="2" height="1"></rect>
22
+ <rect x="0" y="8" width="2" height="1"></rect>
23
+ <rect x="0" y="10" width="2" height="1"></rect>
24
+ </svg>`, o = (e, t, n = "vf-stripes", r) => i`
25
+ <div
26
+ class="vf-title-bar"
27
+ part="title-bar"
28
+ @pointerdown=${e.onPointerDown}
29
+ @pointermove=${e.onPointerMove}
30
+ @pointerup=${e.onPointerUp}
31
+ @pointercancel=${e.onPointerUp}
32
+ >
33
+ <div class=${r ? `${n} vf-tile-grid` : n}>
34
+ ${r ?? (n === "vf-stripes" ? a : null)}
35
+ </div>
36
+ ${t}
37
+ </div>
38
+ `, s = .05, c = 1 / 64, l = class {
39
+ constructor(e) {
40
+ this.host = e, this.applied = 0, this.written = "", this.frame = 0, e.addController(this);
41
+ }
42
+ hostConnected() {
43
+ typeof ResizeObserver < "u" && (this.resizes ??= new ResizeObserver(() => this.schedule())), this.schedule();
44
+ }
45
+ hostDisconnected() {
46
+ this.resizes?.disconnect(), this.frame && cancelAnimationFrame(this.frame), this.frame = 0;
47
+ }
48
+ hostUpdated() {
49
+ this.schedule();
50
+ }
51
+ schedule() {
52
+ this.frame || typeof window > "u" || (this.frame = requestAnimationFrame(() => {
53
+ this.frame = 0, this.center();
54
+ }));
55
+ }
56
+ center() {
57
+ let n = this.host.shadowRoot, i = n?.querySelector(".vf-title-bar"), a = n?.querySelector(".vf-title");
58
+ if (!i || !a) {
59
+ this.reset();
60
+ return;
61
+ }
62
+ this.resizes?.observe(i), this.resizes?.observe(a);
63
+ let o = a.getBoundingClientRect();
64
+ if (!o.width) {
65
+ this.reset();
66
+ return;
67
+ }
68
+ let l = this.host.style;
69
+ l.getPropertyValue("--vf-title-dx") !== this.written && (this.applied = 0, this.written = "");
70
+ let u = i.getBoundingClientRect(), d = o.left - u.left - this.applied, f = t(this.host), p = Math.round(o.width / f), m = Math.round(u.width / f), h = r(this.host), g = Math.ceil((m - p - h) / (2 * h)) * h * f, _ = Math.round((g - d) / c) * c, v = e() || 1;
71
+ Math.abs(_ - this.applied) * v < s || (this.applied = _, this.written = `${_}px`, l.setProperty("--vf-title-dx", this.written));
72
+ }
73
+ reset() {
74
+ this.written &&= (this.host.style.removeProperty("--vf-title-dx"), this.applied = 0, "");
75
+ }
76
+ }, u = (e, t) => t ? `${e} ${t}` : e, d = (e, t) => i`
77
+ <button
78
+ type="button"
79
+ class="box close vf-focus"
80
+ part="close-box"
81
+ aria-label=${e}
82
+ @click=${t}
83
+ ></button>
84
+ `, f = (e, t) => i`
85
+ <button
86
+ type="button"
87
+ class="box zoom vf-focus"
88
+ part="zoom-box"
89
+ aria-label=${e}
90
+ @click=${t}
91
+ ></button>
92
+ `;
93
+ //#endregion
94
+ export { l as TitleCenterController, o as chromeTitleBar, d as closeBox, u as widgetLabel, f as zoomBox };
@@ -0,0 +1,50 @@
1
+ import { LitElement } from 'lit';
2
+ declare const VfButtonGroup_base: (new (...args: any[]) => import("../position.js").VfPositionedInterface) & typeof LitElement;
3
+ /**
4
+ * Lays out a set of `vf-button`s the way a System 7 dialog does: a tidy row
5
+ * (or column) with a consistent gap, every button sharing the width of the
6
+ * widest, and all their *faces* on one line.
7
+ *
8
+ * Two wrinkles make an ad-hoc flex row get this subtly wrong, and the group
9
+ * fixes both:
10
+ *
11
+ * - **Face alignment.** A `variant="default"` button reserves room for its
12
+ * ring with a {@link RING_INSET}px margin, so in a row aligned by any edge
13
+ * its *face* drifts from its neighbors' — you line up the ring, not the
14
+ * button. The group zeroes that margin (via the inherited
15
+ * `--vf-button-ring-margin`) and reserves the ring space itself as padding,
16
+ * then centers the cross axis, so the faces — not the margin boxes — align.
17
+ * - **Shared width.** Classic dialogs sized grouped buttons to the widest, even
18
+ * when a label was short ("OK" as wide as "Cancel"). The group does this with
19
+ * pure CSS — equal `1fr` grid columns resolve to the widest button's
20
+ * intrinsic width under the shrink-wrapped `inline-grid` — and stretches each
21
+ * button's face to fill (via the inherited `--vf-button-flex`). No measuring.
22
+ * `natural` opts out, letting each button size to its own label.
23
+ *
24
+ * The group is layout-neutral: it shrink-wraps to its buttons, so position it
25
+ * with the parent (e.g. `justify-self: end` for a bottom-right action row).
26
+ *
27
+ * @slot - The `vf-button`s to arrange.
28
+ * @cssprop --vf-button-group-gap - Gap between buttons (default 12px).
29
+ */
30
+ export declare class VfButtonGroup extends VfButtonGroup_base {
31
+ static styles: import("lit").CSSResult[];
32
+ /** Stack the buttons vertically instead of in a row. */
33
+ vertical: boolean;
34
+ /**
35
+ * Let each button size to its own label instead of every button sharing the
36
+ * widest button's width. Off by default: grouped buttons are uniform width,
37
+ * matching classic System 7 dialogs.
38
+ */
39
+ natural: boolean;
40
+ private readonly scale;
41
+ private readonly internals;
42
+ constructor();
43
+ render(): import("lit-html").TemplateResult<1>;
44
+ }
45
+ declare global {
46
+ interface HTMLElementTagNameMap {
47
+ 'vf-button-group': VfButtonGroup;
48
+ }
49
+ }
50
+ export {};
@@ -0,0 +1,68 @@
1
+ import { vfElement as e } from "../define.js";
2
+ import { ScaleController as t } from "../scale.js";
3
+ import n from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
+ import { VfPositioned as r } from "../position.js";
5
+ import { vfBase as i } from "../styles/recipes/host.js";
6
+ import "../pixel-frame.js";
7
+ import { LitElement as a, css as o, html as s } from "lit";
8
+ import { property as c } from "lit/decorators.js";
9
+ //#region src/components/vf-button-group.ts
10
+ var l = class extends r(a) {
11
+ static {
12
+ this.styles = [i, o`
13
+ /* Uniform row (the default): each button lands in its own auto column,
14
+ all sized 1fr so they equalize to the widest button's intrinsic width
15
+ under the shrink-wrapped inline-grid; the host of each stretches to
16
+ that column (default justify-items) and its face fills via
17
+ --vf-button-flex. align-items centers the cross axis so a shorter
18
+ child shares the row's baseline. */
19
+ :host {
20
+ /* Neutralize each default button's ring-reservation margin and reserve
21
+ the ring space here instead, so faces — not margin boxes — align and
22
+ equalize. The default gap (12px) clears the ring's ${4}px
23
+ reach on both sides, so rings never collide; a rethemed gap under
24
+ 2 × ${4}px is the one value that puts two adjacent default
25
+ rings into each other, and is left to the consumer rather than
26
+ clamped, since it only arises for two defaults in one row. */
27
+ --vf-button-ring-margin: 0px;
28
+ --vf-button-flex: 1 1 auto;
29
+ display: inline-grid;
30
+ grid-auto-flow: column;
31
+ grid-auto-columns: 1fr;
32
+ align-items: center;
33
+ gap: calc(var(--vf-scale, 1) * var(--vf-button-group-gap, 12px));
34
+ padding: calc(var(--vf-scale, 1) * ${4}px);
35
+ }
36
+ /* Vertical: stack in a single column sized to the widest button; each
37
+ button stretches to that width (justify-items defaults to stretch). */
38
+ :host([vertical]) {
39
+ grid-auto-flow: row;
40
+ }
41
+ /* Natural width: fall back to flex so columns don't equalize — each
42
+ button keeps its own content width. */
43
+ :host([natural]) {
44
+ display: inline-flex;
45
+ --vf-button-flex: 0 1 auto;
46
+ }
47
+ :host([natural][vertical]) {
48
+ flex-direction: column;
49
+ align-items: center;
50
+ }
51
+ `];
52
+ }
53
+ constructor() {
54
+ super(), this.vertical = !1, this.natural = !1, this.scale = new t(this), this.internals = this.attachInternals(), this.internals.role = "group";
55
+ }
56
+ render() {
57
+ return s`<slot></slot>`;
58
+ }
59
+ };
60
+ n([c({
61
+ type: Boolean,
62
+ reflect: !0
63
+ })], l.prototype, "vertical", void 0), n([c({
64
+ type: Boolean,
65
+ reflect: !0
66
+ })], l.prototype, "natural", void 0), l = n([e("vf-button-group")], l);
67
+ //#endregion
68
+ export { l as VfButtonGroup };
@@ -0,0 +1,169 @@
1
+ import { VfShadowRoleControl } from '../form-control.js';
2
+ declare const VfButton_base: (new (...args: any[]) => import("../position.js").VfPositionedInterface) & typeof VfShadowRoleControl;
3
+ /**
4
+ * The classic System 7 push button ("OK", "Cancel", "Install", …).
5
+ *
6
+ * A rounded-rectangle control with a 1px black border and white face that
7
+ * inverts to white-on-black while pressed. `variant="default"` draws the
8
+ * classic bold double ring around the button, marking it as the default
9
+ * action of a dialog.
10
+ *
11
+ * The rounded corners are not `border-radius` arcs: frame, face, and ring are
12
+ * stepped `clip-path` silhouettes traced pixel-for-pixel from the kit's button
13
+ * reference sheet (see `src/pixel-frame.ts`), so every corner renders as the
14
+ * exact 1-bit staircase with no antialiasing.
15
+ *
16
+ * Keyboard focus — an affordance System 7 didn't have, drawn in its idiom
17
+ * anyway — is a 1px dashed rule under the label text (`vfFocusUnderline`)
18
+ * rather than a ring around the control.
19
+ *
20
+ * Form-associated: place it inside a `<form>` and `type="submit"` submits the
21
+ * form (contributing its `name`/`value` and any `form*` override to the
22
+ * submission), `type="reset"` resets it. Enter and Space activate it via the
23
+ * inner native button, and the submission runs at the end of the click's
24
+ * propagation, so `preventDefault()` on the button cancels it the way it
25
+ * cancels a native one.
26
+ *
27
+ * One thing the platform will not allow: `event.submitter` cannot BE a
28
+ * form-associated custom element. It is the transient native proxy this
29
+ * button submits through — so read the submitting button as
30
+ * `event.submitter.closest('vf-button')`, and its identity from
31
+ * `submitter.name`/`.value` rather than by comparing element references.
32
+ *
33
+ * A host-level `aria-label` / `aria-labelledby` names the inner button, and
34
+ * `description` (or a host-level `aria-describedby`) describes it — the same
35
+ * bridge the fields use, since the role lives on a shadow-internal node the
36
+ * platform can't deliver those to. A `<label for>` deliberately does not
37
+ * name it: a `<button>` is not a labelable element.
38
+ *
39
+ * @slot - The button label.
40
+ * @csspart button - The inner native `<button>` element.
41
+ * @cssprop [--vf-button-height=20px] - `vf-button` face (the default ring's
42
+ * inner box is 80×20)
43
+ */
44
+ export declare class VfButton extends VfButton_base {
45
+ #private;
46
+ static shadowRootOptions: ShadowRootInit;
47
+ static styles: import("lit").CSSResult[];
48
+ /**
49
+ * When set to `'default'`, draws the classic double ring that marks the
50
+ * default button (activated by Return in real System 7 dialogs).
51
+ */
52
+ variant?: 'default';
53
+ /**
54
+ * Activation behavior, mirroring native `<button type>`:
55
+ * `'submit'` submits the associated form, `'reset'` resets it and
56
+ * `'button'` (the default) does nothing beyond the `click` event.
57
+ *
58
+ * Two deliberate departures from `<button>`, both pointing the same way — a
59
+ * `vf-button` never submits unless it was asked to. HTML's *missing*-value
60
+ * default is `submit`; here it is `button`, because a custom element that
61
+ * silently submitted the form it happens to sit in is the wrong surprise.
62
+ * The *invalid*-value default follows the missing one rather than HTML's
63
+ * (which is also `submit`), so a misspelling does nothing instead of
64
+ * submitting.
65
+ */
66
+ type: 'button' | 'submit' | 'reset';
67
+ /** Form field name; submitted as `name=value` when `type="submit"`. */
68
+ name: string;
69
+ /** Value submitted under `name` when `type="submit"`. */
70
+ value: string;
71
+ /**
72
+ * The submission overrides native `<button>` carries, honored on
73
+ * `type="submit"` only, exactly as HTML honors them: each is handed to the
74
+ * native proxy {@link activate} submits through, so the *behavior* is the
75
+ * platform's rather than an emulation of it.
76
+ *
77
+ * One difference from the native IDL, in the getters only: `formAction`
78
+ * returns the string you set, where `HTMLButtonElement.formAction` returns
79
+ * it resolved against the document's base URL. The submission itself
80
+ * resolves normally — it is the proxy's `formaction` doing the work.
81
+ */
82
+ formAction: string;
83
+ /** See {@link formAction}. Overrides the form's `enctype`. */
84
+ formEnctype: string;
85
+ /** See {@link formAction}. Overrides the form's `method`. */
86
+ formMethod: string;
87
+ /**
88
+ * See {@link formAction}. Skips the form's constraint validation, so a
89
+ * "Save Draft" button submits past a failing `required`.
90
+ */
91
+ formNoValidate: boolean;
92
+ /** See {@link formAction}. Overrides the form's `target`. */
93
+ formTarget: string;
94
+ /** Default-on display scaling (true 72dpi size); see src/scale.ts. */
95
+ private readonly scale;
96
+ /** Device-pixel grid snapping (opt in with applyGridSnap()); see src/grid-snap.ts. */
97
+ private readonly gridSnap;
98
+ private buttonEl;
99
+ /**
100
+ * {@link type}, resolved the way HTML resolves an enumerated attribute:
101
+ * ASCII case-insensitively, with anything unrecognized falling to the
102
+ * default.
103
+ *
104
+ * Comparing the raw property is the bug this replaces. `type="SUBMIT"` — a
105
+ * perfectly valid spelling on a native button — passed the `!== 'button'`
106
+ * guard and then failed the `=== 'submit'` one, so it submitted the form
107
+ * with its `name`/`value` silently dropped: the action taken, the payload
108
+ * lost, and in that order.
109
+ */
110
+ private get resolvedType();
111
+ /**
112
+ * Forwards a synthetic activation to the real `<button>` in the shadow
113
+ * root. A `click()` on the host dispatches at the host and propagates *up*,
114
+ * never down to the inner button's listener — so the native control, the
115
+ * actual activation surface, is handed the call instead. Its click then
116
+ * bubbles back out composed, exactly as a pointer's does. This is what the
117
+ * fields' implicit submission (Enter) activates as the form's default
118
+ * button; a disabled button swallows it natively, as it should.
119
+ *
120
+ * Before the first render there is no inner button to forward to. A native
121
+ * `click()` always fires, so rather than doing nothing this falls back to
122
+ * dispatching at the host — no activation behavior to run yet, but the
123
+ * event a caller asked for.
124
+ */
125
+ click(): void;
126
+ render(): import("lit-html").TemplateResult<1>;
127
+ /**
128
+ * The click that may become a submission or a reset.
129
+ *
130
+ * This listener sits on the inner `<button>` — the *first* stop on the
131
+ * click's path, not the last — so acting here would beat every listener a
132
+ * consumer can write. {@link deferActivation} moves the action to the end of
133
+ * the path instead, which is where HTML runs a native button's activation
134
+ * behavior and why `preventDefault()` on the button, or anywhere above it,
135
+ * cancels the submission. Same helper the toggles and the menus use.
136
+ *
137
+ * The two guards are this component's own: `#activating` keeps the submit
138
+ * proxy's own synthesised click from re-entering, and a `type="button"`
139
+ * button has no activation behavior to defer in the first place.
140
+ */
141
+ private handleClick;
142
+ /**
143
+ * The activation behavior HTML gives a `<button type="submit"|"reset">`,
144
+ * performed through a transient native proxy.
145
+ *
146
+ * A form-associated custom element cannot be a form's submitter: the
147
+ * platform rejects one outright (`requestSubmit(vfButton)` throws a
148
+ * TypeError, "not a submit button"), and a bare `requestSubmit()` submits
149
+ * with `event.submitter === null` and none of this button's name/value.
150
+ *
151
+ * The proxy is a child of THIS element carrying a `slot` no shadow root
152
+ * offers, which is three things at once. It is a light-DOM descendant of
153
+ * the host, so `event.submitter.closest('vf-button')` finds the button that
154
+ * submitted — as close to submitter identity as the platform permits, and
155
+ * the reason it lives here rather than at the end of the form. Being
156
+ * unslotted it is never rendered, never measured and never in the
157
+ * accessibility tree, so it needs no clipping to hide. And being off the
158
+ * flattened tree, its own click cannot travel back up through the shadow
159
+ * `<button>` this component's own handler is bound to — which, slotted,
160
+ * would have been an infinite recursion rather than a stray event.
161
+ */
162
+ private activate;
163
+ }
164
+ declare global {
165
+ interface HTMLElementTagNameMap {
166
+ 'vf-button': VfButton;
167
+ }
168
+ }
169
+ export {};