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.
- package/LICENSE +21 -0
- package/README.md +262 -0
- package/custom-elements.json +19807 -0
- package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js +9 -0
- package/dist/chrome.d.ts +73 -0
- package/dist/chrome.js +94 -0
- package/dist/components/vf-button-group.d.ts +50 -0
- package/dist/components/vf-button-group.js +68 -0
- package/dist/components/vf-button.d.ts +169 -0
- package/dist/components/vf-button.js +234 -0
- package/dist/components/vf-checkbox.d.ts +60 -0
- package/dist/components/vf-checkbox.js +135 -0
- package/dist/components/vf-container.d.ts +95 -0
- package/dist/components/vf-container.js +86 -0
- package/dist/components/vf-desktop.d.ts +243 -0
- package/dist/components/vf-desktop.js +310 -0
- package/dist/components/vf-dialog.d.ts +105 -0
- package/dist/components/vf-dialog.js +280 -0
- package/dist/components/vf-fieldset.d.ts +34 -0
- package/dist/components/vf-fieldset.js +76 -0
- package/dist/components/vf-grid.d.ts +124 -0
- package/dist/components/vf-grid.js +133 -0
- package/dist/components/vf-icon.d.ts +356 -0
- package/dist/components/vf-icon.js +507 -0
- package/dist/components/vf-img.d.ts +63 -0
- package/dist/components/vf-img.js +65 -0
- package/dist/components/vf-label.d.ts +117 -0
- package/dist/components/vf-label.js +151 -0
- package/dist/components/vf-list-item.d.ts +48 -0
- package/dist/components/vf-list-item.js +98 -0
- package/dist/components/vf-list.d.ts +77 -0
- package/dist/components/vf-list.js +256 -0
- package/dist/components/vf-menu-bar.d.ts +64 -0
- package/dist/components/vf-menu-bar.js +236 -0
- package/dist/components/vf-menu-item.d.ts +91 -0
- package/dist/components/vf-menu-item.js +252 -0
- package/dist/components/vf-menu.d.ts +95 -0
- package/dist/components/vf-menu.js +346 -0
- package/dist/components/vf-number-field.d.ts +60 -0
- package/dist/components/vf-number-field.js +248 -0
- package/dist/components/vf-option.d.ts +49 -0
- package/dist/components/vf-option.js +119 -0
- package/dist/components/vf-paragraph.d.ts +73 -0
- package/dist/components/vf-paragraph.js +66 -0
- package/dist/components/vf-progress-bar.d.ts +69 -0
- package/dist/components/vf-progress-bar.js +272 -0
- package/dist/components/vf-radio-group.d.ts +109 -0
- package/dist/components/vf-radio-group.js +105 -0
- package/dist/components/vf-radio.d.ts +59 -0
- package/dist/components/vf-radio.js +135 -0
- package/dist/components/vf-scroll-area.d.ts +75 -0
- package/dist/components/vf-scroll-area.js +124 -0
- package/dist/components/vf-select.d.ts +334 -0
- package/dist/components/vf-select.js +658 -0
- package/dist/components/vf-separator.d.ts +38 -0
- package/dist/components/vf-separator.js +55 -0
- package/dist/components/vf-slider.d.ts +80 -0
- package/dist/components/vf-slider.js +255 -0
- package/dist/components/vf-stack.d.ts +188 -0
- package/dist/components/vf-stack.js +168 -0
- package/dist/components/vf-swatch.d.ts +98 -0
- package/dist/components/vf-swatch.js +201 -0
- package/dist/components/vf-text-area.d.ts +77 -0
- package/dist/components/vf-text-area.js +121 -0
- package/dist/components/vf-text-field.d.ts +53 -0
- package/dist/components/vf-text-field.js +79 -0
- package/dist/components/vf-window.d.ts +157 -0
- package/dist/components/vf-window.js +377 -0
- package/dist/cursor-art.d.ts +37 -0
- package/dist/cursor-art.js +41 -0
- package/dist/cursor.d.ts +49 -0
- package/dist/cursor.js +171 -0
- package/dist/define.d.ts +45 -0
- package/dist/define.js +15 -0
- package/dist/document-listeners.d.ts +62 -0
- package/dist/document-listeners.js +29 -0
- package/dist/drag.d.ts +49 -0
- package/dist/drag.js +30 -0
- package/dist/events.d.ts +79 -0
- package/dist/events.js +25 -0
- package/dist/focus-modality.d.ts +94 -0
- package/dist/focus-modality.js +56 -0
- package/dist/form-control.d.ts +247 -0
- package/dist/form-control.js +127 -0
- package/dist/glyphs.d.ts +117 -0
- package/dist/glyphs.js +100 -0
- package/dist/grid-snap.d.ts +73 -0
- package/dist/grid-snap.js +135 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.js +71 -0
- package/dist/menu-press.d.ts +60 -0
- package/dist/menu-press.js +97 -0
- package/dist/modal-dialog.d.ts +148 -0
- package/dist/modal-dialog.js +155 -0
- package/dist/motion.d.ts +72 -0
- package/dist/motion.js +22 -0
- package/dist/number.d.ts +24 -0
- package/dist/number.js +12 -0
- package/dist/open-art.d.ts +40 -0
- package/dist/open-art.js +35 -0
- package/dist/pixel-frame.d.ts +102 -0
- package/dist/pixel-frame.js +77 -0
- package/dist/popup-overflow.d.ts +157 -0
- package/dist/popup-overflow.js +45 -0
- package/dist/position.d.ts +187 -0
- package/dist/position.js +74 -0
- package/dist/scale.d.ts +259 -0
- package/dist/scale.js +133 -0
- package/dist/scroll-rail.d.ts +112 -0
- package/dist/scroll-rail.js +194 -0
- package/dist/scroll-state.d.ts +113 -0
- package/dist/scroll-state.js +55 -0
- package/dist/size.d.ts +47 -0
- package/dist/size.js +30 -0
- package/dist/styles/base.d.ts +38 -0
- package/dist/styles/body-font.d.ts +7 -0
- package/dist/styles/body-font.js +9 -0
- package/dist/styles/display-font.d.ts +7 -0
- package/dist/styles/display-font.js +9 -0
- package/dist/styles/recipes/body-face.d.ts +14 -0
- package/dist/styles/recipes/body-face.js +6 -0
- package/dist/styles/recipes/display-face.d.ts +23 -0
- package/dist/styles/recipes/display-face.js +10 -0
- package/dist/styles/recipes/field.d.ts +20 -0
- package/dist/styles/recipes/field.js +68 -0
- package/dist/styles/recipes/focus.d.ts +76 -0
- package/dist/styles/recipes/focus.js +39 -0
- package/dist/styles/recipes/host.d.ts +5 -0
- package/dist/styles/recipes/host.js +62 -0
- package/dist/styles/recipes/pattern.d.ts +80 -0
- package/dist/styles/recipes/pattern.js +82 -0
- package/dist/styles/recipes/scroll-rail.d.ts +69 -0
- package/dist/styles/recipes/scroll-rail.js +222 -0
- package/dist/styles/recipes/shadow.d.ts +13 -0
- package/dist/styles/recipes/shadow.js +5 -0
- package/dist/styles/recipes/static-text.d.ts +24 -0
- package/dist/styles/recipes/static-text.js +17 -0
- package/dist/styles/recipes/surface.d.ts +28 -0
- package/dist/styles/recipes/surface.js +27 -0
- package/dist/styles/recipes/tile.d.ts +122 -0
- package/dist/styles/recipes/tile.js +40 -0
- package/dist/styles/recipes/title-bar.d.ts +49 -0
- package/dist/styles/recipes/title-bar.js +134 -0
- package/dist/styles/recipes/toggle.d.ts +10 -0
- package/dist/styles/recipes/toggle.js +20 -0
- package/dist/styles/register-embedded-font.d.ts +64 -0
- package/dist/styles/register-embedded-font.js +30 -0
- package/dist/text-control.d.ts +131 -0
- package/dist/text-control.js +83 -0
- package/dist/tile-grid.d.ts +111 -0
- package/dist/tile-grid.js +53 -0
- package/dist/toggle-control.d.ts +60 -0
- package/dist/toggle-control.js +41 -0
- package/dist/track-width.d.ts +42 -0
- package/dist/track-width.js +30 -0
- package/dist/type-ahead.d.ts +35 -0
- package/dist/type-ahead.js +20 -0
- package/dist/zoom.d.ts +204 -0
- package/dist/zoom.js +105 -0
- package/docs/SPEC.md +2471 -0
- package/editor/vscode.html-custom-data.json +1320 -0
- package/editor/web-types.json +3237 -0
- 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 };
|
package/dist/chrome.d.ts
ADDED
|
@@ -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 {};
|