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,117 @@
1
+ import { LitElement } from 'lit';
2
+ import type { PropertyValues } from 'lit';
3
+ declare const VfLabel_base: (new (...args: any[]) => import("../size.js").VfSizedInterface) & (new (...args: any[]) => import("../position.js").VfPositionedInterface) & typeof LitElement;
4
+ /**
5
+ * `<vf-label>` — a static System 7 caption.
6
+ *
7
+ * The "Name:" beside a field, the "Mode" heading over a group of radios, a
8
+ * numeric readout beside a slider. Text the page was previously setting by hand
9
+ * in the display face — this is that, as a component, on the kit's grid:
10
+ *
11
+ * - the **Chicago-style chrome face** by default (dialog captions are chrome),
12
+ * with `face="body"` to switch to Geneva — which is also the kit's fine
13
+ * print, as it was System 7's: a dialog's small captions are Geneva 9 at
14
+ * its own strike size;
15
+ * - a **whole-system-pixel line box at the face's native pitch**
16
+ * (`--vf-label-line-height`: 16px — Chicago 12's own line, which is also the
17
+ * em; `face="body"` drops to 12px, Geneva 9's), so a column of captions
18
+ * accumulates whole offsets instead of pushing what follows off the
19
+ * device-pixel grid the way a ratio `line-height` does (docs/SIZING.md
20
+ * rule 2);
21
+ * - its own {@link GridSnapController}, so the bitmap stems stay on the grid
22
+ * wherever the page puts it;
23
+ * - a **declared `width`** ({@link VfSized}) — the shared width of a caption
24
+ * column, so a run of label-and-field rows lands every field on one x.
25
+ * Left to its text a caption measures whatever its glyphs measure (the
26
+ * showcase's Apple menu title came to 32.641 system px) and anything sized
27
+ * from it inherits the fraction; a declared width is whole, and so is the
28
+ * row built on it (layout contract rule 3). A caption wider than its column
29
+ * overflows rather than reflowing the row: the number is the column, and a
30
+ * caption that doesn't fit is a number to raise.
31
+ *
32
+ * `for` points at a control by id, as a native `<label>` does — clicking the
33
+ * caption focuses that control, and the caption text becomes its accessible
34
+ * name (see {@link for} for how, and for what it deliberately doesn't do).
35
+ *
36
+ * Chrome text, so the host is not selectable (SPEC §1); prose belongs in
37
+ * `<vf-paragraph>`, which is.
38
+ *
39
+ * @slot - The caption text.
40
+ * @csspart label - The inner text box.
41
+ * @cssprop --vf-label-line-height - The caption's own line box, in system px.
42
+ * Unset (the default) the box follows the face tokens below; set, it
43
+ * overrides both faces for labels alone. Keep any override a whole *even*
44
+ * number — a ratio puts every following line off the grid, and an odd value
45
+ * halves into the em's half-leading and puts the baseline on a half pixel.
46
+ * @cssprop --vf-line-height - The body face's native line (default `12px`,
47
+ * Geneva 9's) — the face-level knob a body-face retheme states alongside
48
+ * `--vf-font-family` / `--vf-font-size`.
49
+ * @cssprop --vf-line-height-display - The display face's native line
50
+ * (default `16px`, Chicago 12's) — the display retheme's third number.
51
+ */
52
+ export declare class VfLabel extends VfLabel_base {
53
+ #private;
54
+ static styles: import("lit").CSSResult[];
55
+ /** Default-on display scaling (true 72dpi size); see src/scale.ts. */
56
+ private readonly scale;
57
+ /** Device-pixel grid snapping (opt in with applyGridSnap()); see src/grid-snap.ts. */
58
+ private readonly gridSnap;
59
+ /**
60
+ * The id of the control this caption names, resolved in the label's own tree
61
+ * scope (its document or shadow root), like a native `<label for>`.
62
+ *
63
+ * Two things follow from it. **Clicking the caption focuses the control** —
64
+ * a focus shortcut, not an activation: the kit's toggles carry their own
65
+ * labels, so forwarding a click to one would double up on the label they
66
+ * already have. And **the caption text becomes the control's accessible
67
+ * name**, by whichever route reaches it:
68
+ *
69
+ * - a `vf-*` control's focusable element lives in its shadow root, where an
70
+ * `aria-label` on the host cannot reach it — which is why each of them
71
+ * exposes a `label` property that lands on the inner control. That property
72
+ * is what gets filled in, and only when the consumer left it empty.
73
+ * - anything else (a native `<input>`, an element with a role) is in this
74
+ * label's own tree scope, so an `aria-labelledby` id reference works; it is
75
+ * set only when the target has no name of its own — and a name computed
76
+ * from the target's *content* counts: a `vf-checkbox` with slotted text, a
77
+ * `vf-button`, a native `<button>` are already named by what they show, and
78
+ * the caption declines rather than stamping over it.
79
+ *
80
+ * The one target neither route reaches is a control whose focusable element
81
+ * is shadow-internal but which exposes no `label` property because it names
82
+ * from content — `vf-button` is the kit's case. With visible text it needs
83
+ * no caption; an icon-only one should carry its name on the art (`alt` on
84
+ * the slotted `<img>`), which name-from-content picks up the same way.
85
+ *
86
+ * Either way the label puts back what it found when it is removed, the id
87
+ * changes, or the caption text does.
88
+ *
89
+ * Left `undefined` rather than `''` so an unset `for` reflects no attribute
90
+ * at all: `vf-label[for]` is a selector a page will reasonably write, and an
91
+ * empty `for=""` on every plain caption would make it match all of them.
92
+ */
93
+ for?: string;
94
+ /**
95
+ * Which embedded face to set the caption in — `'display'` (the Chicago-style
96
+ * chrome face, the default) or `'body'` (Geneva). Applied by
97
+ * `vfStaticText`; declared here so it types and reflects.
98
+ */
99
+ face?: 'display' | 'body';
100
+ /**
101
+ * Greys the caption to `--vf-disabled`. System 7 dims the label, not the
102
+ * control (SPEC §1), so this is what a caption beside a disabled control
103
+ * wears — the control keeps its solid black box.
104
+ */
105
+ dim: boolean;
106
+ constructor();
107
+ connectedCallback(): void;
108
+ disconnectedCallback(): void;
109
+ protected updated(changed: PropertyValues<this>): void;
110
+ protected render(): import("lit-html").TemplateResult<1>;
111
+ }
112
+ declare global {
113
+ interface HTMLElementTagNameMap {
114
+ 'vf-label': VfLabel;
115
+ }
116
+ }
117
+ export {};
@@ -0,0 +1,151 @@
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 { vfDisplayDecls as i } from "../styles/recipes/display-face.js";
6
+ import { vfBase as a } from "../styles/recipes/host.js";
7
+ import { vfStaticText as o } from "../styles/recipes/static-text.js";
8
+ import { GridSnapController as s } from "../grid-snap.js";
9
+ import { VfSized as c } from "../size.js";
10
+ import { LitElement as l, css as u, html as d } from "lit";
11
+ import { property as f } from "lit/decorators.js";
12
+ //#region src/components/vf-label.ts
13
+ var p = 0, m = /* @__PURE__ */ new Set([
14
+ "button",
15
+ "checkbox",
16
+ "link",
17
+ "menuitem",
18
+ "menuitemcheckbox",
19
+ "menuitemradio",
20
+ "option",
21
+ "radio",
22
+ "switch",
23
+ "tab",
24
+ "treeitem"
25
+ ]);
26
+ function h(e) {
27
+ if (!(e.textContent ?? "").trim()) return !1;
28
+ let t = e.getAttribute("role");
29
+ if (t) return m.has(t.split(/\s+/)[0] ?? "");
30
+ let n = e.localName;
31
+ return n.includes("-") ? !0 : n === "button" || n === "summary" || n === "a" && e.hasAttribute("href");
32
+ }
33
+ var g = class extends c(r(l)) {
34
+ static {
35
+ this.styles = [
36
+ a,
37
+ o,
38
+ u`
39
+ :host {
40
+ /* A real box, so a page can give a caption column a shared width
41
+ (layout contract rule 3) — inline text can't take one. */
42
+ display: inline-block;
43
+ /* Chrome by default; vfStaticText's face="body" overrides it. */
44
+ ${i}
45
+ /* Whole system px, never a ratio — see the class comment. The pitch
46
+ is the face's, so it reads the face token under a per-component
47
+ override. 16px is Chicago 12's native line and the faces' own em
48
+ (12 above the baseline + 4 below), which is also vf-menu-item's row
49
+ pitch, so a caption beside a menu or a popup sits on the same
50
+ rhythm. */
51
+ line-height: calc(
52
+ var(--vf-scale, 1) *
53
+ var(--vf-label-line-height, var(--vf-line-height-display, 16px))
54
+ );
55
+ cursor: var(--vf-cursor, default);
56
+ }
57
+ /* Fine print sits on Geneva 9's native 12px line, like the paragraph's
58
+ body copy and vf-icon's name plate — the 16px em centers into it,
59
+ baseline at 10. Later sheet than vfStaticText's face rule, so the
60
+ pitch follows the face. */
61
+ :host([face='body']) {
62
+ line-height: calc(
63
+ var(--vf-scale, 1) *
64
+ var(--vf-label-line-height, var(--vf-line-height, 12px))
65
+ );
66
+ }
67
+ `
68
+ ];
69
+ }
70
+ #e;
71
+ #t;
72
+ constructor() {
73
+ super(), this.scale = new t(this), this.gridSnap = new s(this), this.dim = !1, this.#e = null, this.#r = () => {
74
+ this.for && this.#a();
75
+ }, this.#i = () => {
76
+ this.isConnected && this.#a();
77
+ }, this.#s = () => {
78
+ let e = this.#n();
79
+ e && ((e.isDisabled ?? e.hasAttribute("disabled")) || e.focus());
80
+ }, this.addEventListener("click", this.#s);
81
+ }
82
+ connectedCallback() {
83
+ super.connectedCallback(), this.#t ??= new MutationObserver(() => {
84
+ this.for && this.#i();
85
+ }), this.#t.observe(this, {
86
+ characterData: !0,
87
+ childList: !0,
88
+ subtree: !0
89
+ }), this.#a();
90
+ }
91
+ disconnectedCallback() {
92
+ super.disconnectedCallback(), this.#t?.disconnect(), this.#o();
93
+ }
94
+ updated(e) {
95
+ e.has("for") && this.#a();
96
+ }
97
+ render() {
98
+ return d`<span class="vf-snap" part="label"
99
+ ><slot @slotchange=${this.#r}></slot
100
+ ></span>`;
101
+ }
102
+ #n() {
103
+ if (!this.for) return null;
104
+ let e = this.getRootNode();
105
+ return e instanceof Document || e instanceof ShadowRoot ? e.getElementById(this.for) : null;
106
+ }
107
+ #r;
108
+ #i;
109
+ #a() {
110
+ this.#o();
111
+ let e = this.#n();
112
+ if (!e) {
113
+ this.for && document.readyState === "loading" && document.addEventListener("DOMContentLoaded", this.#i, { once: !0 });
114
+ return;
115
+ }
116
+ let t = e.localName;
117
+ if (t.includes("-") && !customElements.get(t)) {
118
+ customElements.whenDefined(t).then(() => {
119
+ this.isConnected && !this.#e && this.#a();
120
+ });
121
+ return;
122
+ }
123
+ let n = (this.textContent ?? "").trim();
124
+ if (n) {
125
+ if ("label" in e) {
126
+ typeof e.label == "string" && !e.label && (e.label = n, this.#e = {
127
+ target: e,
128
+ via: "property",
129
+ value: n
130
+ });
131
+ return;
132
+ }
133
+ e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby") || h(e) || (this.id ||= `vf-label-${++p}`, e.setAttribute("aria-labelledby", this.id), this.#e = {
134
+ target: e,
135
+ via: "aria",
136
+ value: this.id
137
+ });
138
+ }
139
+ }
140
+ #o() {
141
+ let e = this.#e;
142
+ this.#e = null, e && (e.via === "property" ? e.target.label === e.value && (e.target.label = "") : e.target.getAttribute("aria-labelledby") === e.value && e.target.removeAttribute("aria-labelledby"));
143
+ }
144
+ #s;
145
+ };
146
+ n([f({ reflect: !0 })], g.prototype, "for", void 0), n([f({ reflect: !0 })], g.prototype, "face", void 0), n([f({
147
+ type: Boolean,
148
+ reflect: !0
149
+ })], g.prototype, "dim", void 0), g = n([e("vf-label")], g);
150
+ //#endregion
151
+ export { g as VfLabel };
@@ -0,0 +1,48 @@
1
+ import { LitElement } from 'lit';
2
+ /**
3
+ * `<vf-list-item>` — a row inside a `<vf-list>` list box.
4
+ *
5
+ * A 20px-tall single-line row; when selected the entire row inverts
6
+ * (white-on-black), the classic System 7 selection style. Selection and
7
+ * keyboard focus are managed by the parent `<vf-list>`.
8
+ *
9
+ * @slot - The row's text/content.
10
+ * @slot icon - A leading graphic — usually a `vf-img` holding a 16×16 System 7
11
+ * small icon, but any element rides here. The row lays it out as the icon
12
+ * gutter: flex-centered vertically (keep the difference between the row
13
+ * height and the icon height even, so the centering offset stays a whole
14
+ * pixel — 16 in a 20px row is a whole 2px), with the reference art's 4px gap
15
+ * to the text. Contributes no text, so first-letter type-ahead still reads
16
+ * the row's words. On a selected row the graphic rides the inverted bar
17
+ * as-is — System 7 left color icons unfiltered on the highlight.
18
+ * @csspart text - The text span beside the icon gutter (ellipsizes).
19
+ */
20
+ export declare class VfListItem extends LitElement {
21
+ #private;
22
+ static styles: import("lit").CSSResult[];
23
+ private readonly scale;
24
+ /** The value this row contributes to the list's `value`/`values`. */
25
+ value: string;
26
+ /** Whether the row is selected (inverted). Managed by `<vf-list>`. */
27
+ selected: boolean;
28
+ /** Disables the row: dimmed text, not selectable or focusable. */
29
+ disabled: boolean;
30
+ /**
31
+ * True while the containing `<vf-list>` is disabled. Managed by the list —
32
+ * not intended to be set by consumers. Kept distinct from `disabled` so
33
+ * re-enabling the list doesn't clear rows that are disabled in their own
34
+ * right. (The dimming already arrives by inheritance: the list host sets
35
+ * `color: var(--vf-disabled)` and rows inherit it.) Mirrors
36
+ * `vf-radio.groupDisabled`.
37
+ */
38
+ listDisabled: boolean;
39
+ constructor();
40
+ connectedCallback(): void;
41
+ protected updated(changed: Map<PropertyKey, unknown>): void;
42
+ protected render(): import("lit-html").TemplateResult<1>;
43
+ }
44
+ declare global {
45
+ interface HTMLElementTagNameMap {
46
+ 'vf-list-item': VfListItem;
47
+ }
48
+ }
@@ -0,0 +1,98 @@
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 { vfBase as r } from "../styles/recipes/host.js";
5
+ import { vfFocusRing as i } from "../styles/recipes/focus.js";
6
+ import { emit as a } from "../events.js";
7
+ import { LitElement as o, css as s, html as c } from "lit";
8
+ import { property as l } from "lit/decorators.js";
9
+ //#region src/components/vf-list-item.ts
10
+ var u = class extends o {
11
+ static {
12
+ this.styles = [r, s`
13
+ :host {
14
+ display: flex;
15
+ align-items: center;
16
+ /* Icon-to-text gap, per the reference art (Menus.png's icon-gutter
17
+ popup: 16px icon cell, 4px to the first glyph). Collapses to
18
+ nothing when the icon slot is empty — no icon, no flex item. */
19
+ gap: calc(var(--vf-scale, 1) * 4px);
20
+ height: calc(var(--vf-scale, 1) * 20px);
21
+ line-height: calc(var(--vf-scale, 1) * 20px);
22
+ padding: 0 calc(var(--vf-scale, 1) * 6px);
23
+ cursor: var(--vf-cursor, default);
24
+ background: transparent;
25
+ }
26
+ ::slotted([slot='icon']) {
27
+ flex: none;
28
+ }
29
+ .text {
30
+ /* min-width lets the span shrink below its content so the ellipsis
31
+ can happen (flex items otherwise floor at min-content). */
32
+ flex: 1;
33
+ min-width: 0;
34
+ white-space: nowrap;
35
+ overflow: hidden;
36
+ text-overflow: ellipsis;
37
+ }
38
+ /* Plain :focus, not :focus-visible — vf-list drives a roving tabindex and
39
+ moves the cursor with item.focus(), and programmatic focus that isn't
40
+ preceded by a keyboard event doesn't match :focus-visible, so a
41
+ mouse-clicked cursor row would show no ring until the next Arrow key.
42
+ The roving tabindex guarantees only the cursor row is focusable, so
43
+ :focus is exactly the cursor. Matches sibling vf-menu-item. On a
44
+ *selected* row the ring rides currentColor (see vfFocusRing) and
45
+ inverts to white on the highlight bar — it has to stay legible there,
46
+ because in multiple mode Ctrl+Arrow deliberately moves the cursor
47
+ across selected rows while Space still acts on it. */
48
+ :host(:focus) {
49
+ --vf-focus-offset: -1px;
50
+ ${i}
51
+ }
52
+ :host([selected]) {
53
+ background: var(--vf-highlight, #000);
54
+ color: var(--vf-highlight-text, #fff);
55
+ /* Forced colors: both tokens already remap to the user's
56
+ Highlight/HighlightText pair (vfBase), but the mode also paints an
57
+ opaque Canvas READABILITY BACKPLATE behind any text run whose
58
+ backdrop it doesn't consider a flat opaque color — and Chromium's
59
+ Highlight carries alpha, so the plate lands ON the highlight bar
60
+ and the row's text drowns in it (measured: the bar renders as a
61
+ Canvas slab under HighlightText ink). Opting the inverted row out
62
+ of forced adjustments drops the backplate; every color in play is
63
+ a system pair anyway, so this changes nothing else. The same
64
+ exemption rides every 1-bit inversion in the kit — vf-option,
65
+ vf-menu-item, vf-menu's open label, vf-icon's plate. */
66
+ @media (forced-colors: active) {
67
+ forced-color-adjust: none;
68
+ }
69
+ }
70
+ :host([disabled]) {
71
+ color: var(--vf-disabled, #c0c0c0);
72
+ }
73
+ `];
74
+ }
75
+ #e;
76
+ constructor() {
77
+ super(), this.scale = new t(this), this.value = "", this.selected = !1, this.disabled = !1, this.listDisabled = !1, this.#e = this.attachInternals(), this.#e.role = "option";
78
+ }
79
+ connectedCallback() {
80
+ super.connectedCallback(), this.hasAttribute("tabindex") || (this.tabIndex = -1);
81
+ }
82
+ updated(e) {
83
+ e.has("selected") && (this.#e.ariaSelected = this.selected ? "true" : "false"), (e.has("disabled") || e.has("listDisabled")) && (this.#e.ariaDisabled = this.disabled || this.listDisabled ? "true" : null), e.has("disabled") && e.get("disabled") !== void 0 && a(this, "vf-list-item-disabled-change", { item: this }, { composed: !1 });
84
+ }
85
+ render() {
86
+ return c`<slot name="icon"></slot
87
+ ><span class="text" part="text"><slot></slot></span>`;
88
+ }
89
+ };
90
+ n([l()], u.prototype, "value", void 0), n([l({
91
+ type: Boolean,
92
+ reflect: !0
93
+ })], u.prototype, "selected", void 0), n([l({
94
+ type: Boolean,
95
+ reflect: !0
96
+ })], u.prototype, "disabled", void 0), n([l({ attribute: !1 })], u.prototype, "listDisabled", void 0), u = n([e("vf-list-item")], u);
97
+ //#endregion
98
+ export { u as VfListItem };
@@ -0,0 +1,77 @@
1
+ import { LitElement } from 'lit';
2
+ declare const VfList_base: (new (...args: any[]) => import("../position.js").VfPositionedInterface) & typeof LitElement;
3
+ /**
4
+ * `<vf-list>` — the classic System 7 list box.
5
+ *
6
+ * A white, black-bordered scrolling box of `<vf-list-item>` rows with the
7
+ * kit-drawn System 7 scroll rail (dither trough, boxed arrow buttons, fixed
8
+ * thumb — the shared `vfScrollRail` subtree, synced to the native scrolling
9
+ * by {@link ScrollRailController}). The vertical rail is a permanent
10
+ * placeholder — arrows on an empty white channel when the rows fit, the
11
+ * dither and thumb filling in only on overflow (driven by
12
+ * {@link ScrollStateController}). Selection inverts rows. Supports single and
13
+ * multiple selection, roving tabindex, arrow-key navigation, and classic Finder
14
+ * first-letter type-ahead.
15
+ *
16
+ * Max height defaults to 200px; override with `--vf-list-max-height`.
17
+ *
18
+ * @slot - `vf-list-item` elements.
19
+ * @csspart list - The scrolling viewport around the slotted items.
20
+ * @fires vf-change - When the user changes the selection.
21
+ * `detail: { value: string, values: string[] }`.
22
+ * @cssprop [--vf-list-max-height=200px] - `vf-list` max height before its rail
23
+ * takes over (the host adds the 2px frame)
24
+ * @cssprop --vf-scrollbar-thumb - scrollbar thumb/elevator (white)
25
+ * @cssprop --vf-scrollbar-track - the scroll trough's base color under the
26
+ * dot-dither (white)
27
+ */
28
+ export declare class VfList extends VfList_base {
29
+ #private;
30
+ static styles: import("lit").CSSResult[];
31
+ private readonly scale;
32
+ /** Device-pixel grid snapping (opt in with applyGridSnap()); see src/grid-snap.ts. */
33
+ private readonly gridSnap;
34
+ private viewport;
35
+ private content;
36
+ /** Reserves the vertical rail and toggles it active on overflow. */
37
+ private readonly scrollState;
38
+ /** Syncs the drawn rail to the row viewport and drives its interactions. */
39
+ private readonly rail;
40
+ /** Whether the rows actually overflow the box (either axis). */
41
+ private _scrollable;
42
+ /** Allows multiple selection (Shift extends, Cmd/Ctrl toggles). */
43
+ multiple: boolean;
44
+ /** Value of the (first) selected item. Settable. */
45
+ value: string;
46
+ /** Values of all selected items (multiple mode). Settable. */
47
+ values: string[];
48
+ /** Disables the whole list: dimmed, no interaction. */
49
+ disabled: boolean;
50
+ /**
51
+ * Accessible name for the list, applied as `aria-label` on the host (which
52
+ * carries `role="listbox"`). Without it a caption-less list is announced
53
+ * anonymously. A consumer-supplied `aria-label`/`aria-labelledby` attribute
54
+ * is left alone.
55
+ */
56
+ label: string;
57
+ private _items;
58
+ constructor();
59
+ /**
60
+ * Moves keyboard focus to the row holding the roving tab stop — or, while
61
+ * the list is disabled, to the scrolling viewport (the disabled list's own
62
+ * Tab stop; the rows are all at -1 then). Overridden because the platform's
63
+ * `focus()` is a silent no-op on this host — no `delegatesFocus`, no host
64
+ * tabindex — so `vf-label for` (which calls `target.focus()`) never reached
65
+ * the list.
66
+ */
67
+ focus(options?: FocusOptions): void;
68
+ disconnectedCallback(): void;
69
+ protected updated(changed: Map<PropertyKey, unknown>): void;
70
+ protected render(): import("lit-html").TemplateResult<1>;
71
+ }
72
+ declare global {
73
+ interface HTMLElementTagNameMap {
74
+ 'vf-list': VfList;
75
+ }
76
+ }
77
+ export {};