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,135 @@
1
+ import { vfElement as e } from "../define.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
3
+ import { VfPositioned as n } from "../position.js";
4
+ import { vfDisplay as r } from "../styles/recipes/display-face.js";
5
+ import { vfBase as i } from "../styles/recipes/host.js";
6
+ import { vfFocusUnderline as a } from "../styles/recipes/focus.js";
7
+ import { vfToggle as o } from "../styles/recipes/toggle.js";
8
+ import { emit as s } from "../events.js";
9
+ import { RADIO_DOT as c, RADIO_FACE as l, RADIO_RING as u, RADIO_RING_PRESSED as d } from "../glyphs.js";
10
+ import { VfToggleControl as f } from "../toggle-control.js";
11
+ import { LitElement as p, css as m, html as h } from "lit";
12
+ import { property as g } from "lit/decorators.js";
13
+ import { classMap as _ } from "lit/directives/class-map.js";
14
+ //#region src/components/vf-radio.ts
15
+ var v = class extends n(f(p)) {
16
+ static {
17
+ this.styles = [
18
+ i,
19
+ r,
20
+ o,
21
+ m`
22
+ /* Keyboard focus underlines the circle itself — not the label, and not a
23
+ ring around either (see vfFocusUnderline). One blank row below the
24
+ well, which is where vf-checkbox puts its own: −2 rather than that
25
+ control's −3 only because this well is unbordered, so the two rules
26
+ land on the same row of a mixed list. The 12px sprite sits half a
27
+ pixel proud of the 13px well, so the gap reads as one row or two
28
+ depending on which way that rounds — the well is the anchor, not the
29
+ sprite. */
30
+ :host(:focus-visible) .circle::after {
31
+ --vf-focus-underline-offset: -2px;
32
+ ${a}
33
+ /* …and narrower than the well, because the shape above it is round:
34
+ a full-width rule reads as wider than the circle it marks. 9 of the
35
+ 13px (5 dashes) is the closest to two thirds that still insets by a
36
+ whole 2px each side and keeps ink at both ends. */
37
+ left: calc(var(--vf-scale, 1) * 2px);
38
+ right: calc(var(--vf-scale, 1) * 2px);
39
+ }
40
+ .circle {
41
+ position: relative;
42
+ flex: none;
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+ width: calc(var(--vf-scale, 1) * 13px);
47
+ height: calc(var(--vf-scale, 1) * 13px);
48
+ color: var(--vf-black, #000);
49
+ }
50
+ /* Native 12×12 sprite centered in the 13×13 focus box; scales with the
51
+ circle, crispEdges keeps it whole-device-pixel at any dpr. */
52
+ .circle svg {
53
+ display: block;
54
+ width: calc(var(--vf-scale, 1) * 12px);
55
+ height: calc(var(--vf-scale, 1) * 12px);
56
+ }
57
+ /* White control face, black ring + dot — the ring path covers the
58
+ face's outer edge so no anti-aliasing shows. */
59
+ .face {
60
+ fill: var(--vf-white, #fff);
61
+ }
62
+ .ring,
63
+ .ring-pressed,
64
+ .dot {
65
+ fill: currentColor;
66
+ }
67
+ .ring-pressed,
68
+ .dot {
69
+ display: none;
70
+ }
71
+ :host([checked]) .dot {
72
+ display: inline;
73
+ }
74
+ /* Pressed: swap to the 2px-thick ring (classic press feedback). */
75
+ :host(:active) .circle:not(.dim) .ring {
76
+ display: none;
77
+ }
78
+ :host(:active) .circle:not(.dim) .ring-pressed {
79
+ display: inline;
80
+ }
81
+ `
82
+ ];
83
+ }
84
+ constructor() {
85
+ super(), this.checked = !1, this.disabled = !1, this.value = "", this.groupDisabled = !1, this.internals = this.attachInternals(), this.internals.role = "radio";
86
+ }
87
+ get toggleInternals() {
88
+ return this.internals;
89
+ }
90
+ get toggleDisabled() {
91
+ return this.disabled || this.groupDisabled;
92
+ }
93
+ get externallyCoordinated() {
94
+ return !!this.closest("vf-radio-group");
95
+ }
96
+ render() {
97
+ let e = this.toggleDisabled;
98
+ return h`
99
+ <span
100
+ class=${_({
101
+ circle: !0,
102
+ dim: e,
103
+ "vf-snap": !0
104
+ })}
105
+ part="circle"
106
+ aria-hidden="true"
107
+ >
108
+ <svg viewBox="0 0 12 12" shape-rendering="crispEdges">
109
+ <path class="face" d=${l.d}></path>
110
+ <path class="ring" d=${u.d}></path>
111
+ <path class="ring-pressed" d=${d.d}></path>
112
+ <path class="dot" d=${c.d}></path>
113
+ </svg>
114
+ </span>
115
+ <span class=${_({
116
+ label: !0,
117
+ dim: e
118
+ })} part="label">
119
+ <slot></slot>
120
+ </span>
121
+ `;
122
+ }
123
+ activate() {
124
+ this.checked || (this.externallyCoordinated || (this.checked = !0), this.focus(), s(this, "vf-change", { value: this.value }));
125
+ }
126
+ };
127
+ t([g({
128
+ type: Boolean,
129
+ reflect: !0
130
+ })], v.prototype, "checked", void 0), t([g({
131
+ type: Boolean,
132
+ reflect: !0
133
+ })], v.prototype, "disabled", void 0), t([g()], v.prototype, "value", void 0), t([g({ attribute: !1 })], v.prototype, "groupDisabled", void 0), v = t([e("vf-radio")], v);
134
+ //#endregion
135
+ export { v as VfRadio };
@@ -0,0 +1,75 @@
1
+ import { LitElement } from 'lit';
2
+ declare const VfScrollArea_base: (new (...args: any[]) => import("../position.js").VfPositionedInterface) & typeof LitElement;
3
+ /**
4
+ * `<vf-scroll-area>` — a container whose scrollbars look like System 7.
5
+ *
6
+ * White box with a 1px black frame, an inner scrolling viewport, and scroll
7
+ * rails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):
8
+ * boxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the
9
+ * classic fixed 16px thumb. The native scrollbar is hidden, never the native
10
+ * scrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech
11
+ * scrolling stay the platform's, and {@link ScrollRailController} keeps the
12
+ * rail in sync while driving the classic interactions (thumb drag, trough
13
+ * paging, arrow stepping with auto-repeat). Every engine renders the same
14
+ * rail — there is no Firefox fallback skin anymore.
15
+ *
16
+ * Each reserved scroll rail is a permanent placeholder: arrow buttons on an
17
+ * empty white channel sit in the gutter even when the content fits, the
18
+ * dither and thumb filling in only once that axis overflows (System 7 drew
19
+ * an active window's no-overflow bar as arrows on a bare channel; driven
20
+ * by {@link ScrollStateController}). Which rails are reserved is set by
21
+ * {@link axis}; when both are reserved the bottom-right corner joins them.
22
+ *
23
+ * Size the host (width/height) from the outside; the viewport fills it.
24
+ *
25
+ * @slot - Scrollable content.
26
+ * @csspart viewport - The inner scrolling container.
27
+ * @cssprop --vf-scrollbar-thumb - scrollbar thumb/elevator (white)
28
+ * @cssprop --vf-scrollbar-track - the scroll trough's base color under the
29
+ * dot-dither (white)
30
+ */
31
+ export declare class VfScrollArea extends VfScrollArea_base {
32
+ private readonly scale;
33
+ /** Device-pixel grid snapping (opt in with applyGridSnap()); see src/grid-snap.ts. */
34
+ private readonly gridSnap;
35
+ /**
36
+ * Which scroll rails to reserve as permanent placeholders: `vertical`
37
+ * (default), `horizontal`, or `both`. Each reserved rail shows an empty white
38
+ * channel until its axis overflows; the unreserved axis still scrolls
39
+ * natively (wheel, keyboard) but draws no rail.
40
+ */
41
+ axis: 'vertical' | 'horizontal' | 'both';
42
+ /**
43
+ * Accessible name for the scrolling viewport, applied as its `aria-label`
44
+ * (an `aria-label` on the host would not reach into the shadow DOM). The
45
+ * viewport is keyboard-focusable while its content overflows, so without a
46
+ * name it is announced only as an anonymous scrollable group; setting
47
+ * `label` also promotes it to a named `role="region"` landmark. While
48
+ * `label` is empty the viewport is a plain `group` when scrollable (an
49
+ * unnamed region is inert) and role-less when not.
50
+ */
51
+ label: string;
52
+ private viewport;
53
+ private content;
54
+ /** Reports overflow per axis so the reserved rail(s) activate on overflow. */
55
+ private readonly scrollState;
56
+ /** Syncs the drawn rails to the viewport and drives their interactions. */
57
+ private readonly rail;
58
+ /** Whether the content actually overflows the viewport (either axis). */
59
+ private _scrollable;
60
+ /**
61
+ * Moves keyboard focus to the scrolling viewport — the focusable element
62
+ * lives inside the shadow root, where the platform's `focus()` can't reach
63
+ * (no `delegatesFocus`, no host tabindex), so `vf-label for` and consumer
64
+ * scripts silently no-opped on the host.
65
+ */
66
+ focus(options?: FocusOptions): void;
67
+ static styles: import("lit").CSSResult[];
68
+ protected render(): import("lit-html").TemplateResult<1>;
69
+ }
70
+ declare global {
71
+ interface HTMLElementTagNameMap {
72
+ 'vf-scroll-area': VfScrollArea;
73
+ }
74
+ }
75
+ export {};
@@ -0,0 +1,124 @@
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 { vfFocusRing as a } from "../styles/recipes/focus.js";
7
+ import { vfScrollRail as o } from "../styles/recipes/scroll-rail.js";
8
+ import { GridSnapController as s } from "../grid-snap.js";
9
+ import { ScrollStateController as c } from "../scroll-state.js";
10
+ import { ScrollRailController as l, renderScrollRail as u } from "../scroll-rail.js";
11
+ import { LitElement as d, css as f, html as p, nothing as m } from "lit";
12
+ import { property as h, query as g, state as _ } from "lit/decorators.js";
13
+ //#region src/components/vf-scroll-area.ts
14
+ var v = class extends r(d) {
15
+ constructor(...e) {
16
+ super(...e), this.scale = new t(this), this.gridSnap = new s(this), this.axis = "vertical", this.label = "", this.scrollState = new c(this, () => this.viewport, () => this.content, (e) => {
17
+ this._scrollable = e.x || e.y;
18
+ }), this.rail = new l(this, {
19
+ getScroll: () => this.viewport,
20
+ getContent: () => this.content
21
+ }), this._scrollable = !1;
22
+ }
23
+ focus(e) {
24
+ this.viewport?.focus(e);
25
+ }
26
+ static {
27
+ this.styles = [
28
+ i,
29
+ o,
30
+ f`
31
+ :host {
32
+ display: block;
33
+ }
34
+ /* The snapped wrapper: a real 1px frame (the rails' outer line is this
35
+ border), a grid that reserves each rail as its own edge column/row —
36
+ the rails size themselves to the 15px inside the frame — and the
37
+ scroller and rails riding the grid-snap offset as one. */
38
+ .box {
39
+ width: 100%;
40
+ height: 100%;
41
+ display: grid;
42
+ grid-template-columns: 1fr;
43
+ grid-template-rows: 1fr;
44
+ border: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
45
+ background: var(--vf-white, #fff);
46
+ }
47
+ :host(:not([axis])) .box,
48
+ :host([axis='vertical']) .box,
49
+ :host([axis='both']) .box {
50
+ grid-template-columns: 1fr auto;
51
+ }
52
+ :host([axis='horizontal']) .box,
53
+ :host([axis='both']) .box {
54
+ grid-template-rows: 1fr auto;
55
+ }
56
+ .viewport {
57
+ grid-area: 1 / 1;
58
+ background: var(--vf-white, #fff);
59
+ /* Native scrolling on every axis; the bar itself is hidden by the
60
+ recipe (.vf-scroll) and the reservation is the rail element, not a
61
+ native gutter. The unreserved axis still scrolls, railless.
62
+
63
+ 8px inset plus border-floor compensation: engines floor the
64
+ fractional frame border to whole CSS px, and the mod() term is
65
+ exactly what they floored away — so slotted content (and the (0,0)
66
+ of placed children) sits exactly 9 system px from the frame box at
67
+ every scale, as it did under the borderless-scroller construction.
68
+ (mod is 0 at whole scales.) */
69
+ overflow: auto;
70
+ min-width: 0;
71
+ min-height: 0;
72
+ padding: calc(
73
+ var(--vf-scale, 1) * 8px + mod(var(--vf-scale, 1) * 1px, 1px)
74
+ );
75
+ }
76
+ .vf-rail--vertical {
77
+ grid-area: 1 / 2;
78
+ }
79
+ .vf-rail--horizontal {
80
+ grid-area: 2 / 1;
81
+ }
82
+ .vf-rail-corner {
83
+ grid-area: 2 / 2;
84
+ }
85
+ /* The positioning anchor for slotted children placed with top/left
86
+ (src/position.ts). It must be THIS wrapper and not .box: .content
87
+ rides the scroll, so positioned children travel with the content —
88
+ anchored to .box they would hang fixed over the rail while the plane
89
+ moved beneath them. Inside the viewport's 8px padding, so (0,0) is
90
+ where flow content starts. */
91
+ .content {
92
+ position: relative;
93
+ }
94
+ /* Focusable so keyboard users can scroll; inset ring to stay in-box. */
95
+ .viewport:focus-visible {
96
+ --vf-focus-offset: -2px;
97
+ ${a}
98
+ }
99
+ `
100
+ ];
101
+ }
102
+ render() {
103
+ let e = this.axis !== "horizontal", t = this.axis === "horizontal" || this.axis === "both";
104
+ return p`
105
+ <div class="box vf-snap">
106
+ <div
107
+ class="viewport vf-scroll"
108
+ part="viewport"
109
+ tabindex=${this._scrollable ? "0" : m}
110
+ role=${this.label ? "region" : this._scrollable ? "group" : m}
111
+ aria-label=${this.label || m}
112
+ >
113
+ <div class="content"><slot></slot></div>
114
+ </div>
115
+ ${e ? u(this.rail, "vertical") : m}
116
+ ${t ? u(this.rail, "horizontal") : m}
117
+ ${e && t ? p`<div class="vf-rail-corner" aria-hidden="true"></div>` : m}
118
+ </div>
119
+ `;
120
+ }
121
+ };
122
+ n([h({ reflect: !0 })], v.prototype, "axis", void 0), n([h()], v.prototype, "label", void 0), n([g(".viewport")], v.prototype, "viewport", void 0), n([g(".content")], v.prototype, "content", void 0), n([_()], v.prototype, "_scrollable", void 0), v = n([e("vf-scroll-area")], v);
123
+ //#endregion
124
+ export { v as VfScrollArea };
@@ -0,0 +1,334 @@
1
+ import type { PropertyValues } from 'lit';
2
+ import { VfShadowRoleControl } from '../form-control.js';
3
+ declare const VfSelect_base: (new (...args: any[]) => import("../position.js").VfPositionedInterface) & typeof VfShadowRoleControl;
4
+ /**
5
+ * `<vf-select>` — the classic System 7 popup menu control ("Macintosh HD ▼").
6
+ *
7
+ * Children are `<vf-option>` elements in the default slot. The closed control
8
+ * is a white box with a 1px black border, the small 1px hard shadow, the
9
+ * selected option's label on the left and a solid black ▼ triangle on the
10
+ * right. The open panel uses the shared `.vf-panel` recipe and is positioned
11
+ * `position: fixed` (computed from `getBoundingClientRect()`) so it escapes
12
+ * clipping containers; when possible the currently-selected item opens
13
+ * directly over the control, like the real popup menu.
14
+ *
15
+ * Pointer — two interaction styles are supported and disambiguated by the
16
+ * gesture itself, resolved at the first pointer release:
17
+ * - System 7 press-drag-release: press the pill (the list appears under the
18
+ * pointer), drag onto an item, release over it to pick — one continuous
19
+ * press. Releasing over the current item or off the list closes with no
20
+ * change.
21
+ * - Modern click-to-open: a quick in-place click (no drag, released within
22
+ * {@link PRESS_HOLD_MS}) leaves the list open; a second, independent click
23
+ * then picks an item.
24
+ * The two share one opening trigger (pointerdown) and diverge only on how the
25
+ * press ends — whether the pointer travelled to another item, and (for an
26
+ * in-place release) whether it was a quick tap or a held press. The pull-down
27
+ * menus drive themselves the same way, on the same threshold; that half lives
28
+ * in src/menu-press.ts, because one menu press may travel across a whole bar.
29
+ *
30
+ * A list too tall for the screen is **clipped**, never scrolled: the edge slot
31
+ * with items beyond it shows a solid arrow instead of a row, which rolls the
32
+ * list one row at a time while the pointer rests on it. The clamp is quantized
33
+ * to the pill lattice, so a clipped popup still opens with its selected row
34
+ * over the closed pill — and the panel keeps every slot the list asked for, so
35
+ * a box that had to slide to fit the screen opens with *blank rows* at whichever
36
+ * end the list no longer reaches: the exact travel it will roll through, in
37
+ * either direction. See src/popup-overflow.ts.
38
+ *
39
+ * Keyboard: Space/Enter/ArrowDown open; while open ArrowUp/ArrowDown move the
40
+ * highlight, Home/End jump, Enter/Space select, Escape cancels. Selecting an
41
+ * item plays the classic inversion blink (~250 ms) before closing. Keyboard
42
+ * focus is marked with the kit's 1px dashed rule under the closed pill
43
+ * (`vfFocusUnderline`) rather than a ring around it — keyboard only, which
44
+ * here means the page's input modality rather than `:focus-visible` (the pill
45
+ * drives its own focus, and Blink reads that as visible either way).
46
+ *
47
+ * Form-associated: submits `value` under `name`.
48
+ *
49
+ * @fires vf-change - After a selection commits. `detail: { value: string }`.
50
+ * @fires input - Native event, dispatched from the host per committed pick
51
+ * (with `change`, the pair a native `<select>` fires). A programmatic
52
+ * `value` set fires nothing.
53
+ * @fires change - Native event, dispatched from the host per committed pick
54
+ * so form delegation and framework bindings hear it.
55
+ *
56
+ * @slot - `<vf-option>` elements.
57
+ *
58
+ * @csspart control - The closed popup control box.
59
+ * @csspart label - The selected-option label inside the control.
60
+ * @csspart arrow - The black ▼ triangle.
61
+ * @csspart panel - The popup panel (listbox).
62
+ * @csspart scroll-arrow - Either of the two scroll arrows a clipped panel shows
63
+ * in its edge row slots.
64
+ * @cssprop [--vf-popup-height=18px] - `vf-select` pill (border box; its 1px
65
+ * hard shadow makes the sheet's 157×19 ink box)
66
+ * @cssprop [--vf-popup-inset-top=4px] - room a clipped popup panel keeps clear
67
+ * at the TOP screen edge — set it once on `:root` (or the `vf-desktop`) to
68
+ * clear a `vf-menu-bar`: `24px` is the 20px bar plus the default 4
69
+ * @cssprop [--vf-popup-inset-bottom=4px] - room a clipped popup panel keeps
70
+ * clear at the BOTTOM screen edge
71
+ * @cssprop [--vf-select-gutter=16px] - checkmark column: `vf-select` left inset
72
+ * / `vf-option` + `vf-menu-item` ✓ column (shared so the value doesn't shift
73
+ * on open)
74
+ */
75
+ export declare class VfSelect extends VfSelect_base {
76
+ /**
77
+ * Fallback height of one option row — the pill's *content* height
78
+ * (`--vf-popup-height` 18px minus its two 1px borders). Used to overlay the
79
+ * selected row's white cell exactly on the closed pill. `positionPanel`
80
+ * prefers the row's *rendered* height so a re-themed `--vf-popup-height`
81
+ * keeps the overlay aligned; this is the no-options fallback and must match
82
+ * `vf-option`'s default row height.
83
+ */
84
+ private static readonly ITEM_HEIGHT;
85
+ static styles: import("lit").CSSResult[];
86
+ /** Value of the selected option. Adopts the first enabled option if unset. */
87
+ value: string;
88
+ /** Form field name used when submitting the associated form. */
89
+ name: string;
90
+ /**
91
+ * Accessible name for the combobox control (`aria-label`). Left empty, the
92
+ * name falls back to whatever the host carries — `aria-labelledby`,
93
+ * `aria-label` or an associated `<label for>` — via
94
+ * {@link VfShadowRoleControl.hostLabel}; with neither, the control is announced by
95
+ * its contents, i.e. the selected value.
96
+ */
97
+ label: string;
98
+ /** No option committed — the state `required` calls a missing value. */
99
+ protected get valueMissing(): boolean;
100
+ /** The message a native `<select required>` reports. */
101
+ protected get valueMissingMessage(): string;
102
+ /** Whether the popup panel is open. */
103
+ private open;
104
+ private controlEl;
105
+ private panelEl;
106
+ private rowsEl;
107
+ private upArrowEl;
108
+ private downArrowEl;
109
+ private assignedOptions;
110
+ /**
111
+ * Assigned options, cached from the last slotchange. `render()` reads this
112
+ * reactive state (via {@link optionItems}) instead of the live query above,
113
+ * which is empty on the first paint — the source of the empty-label /
114
+ * zero-width-sizer flash.
115
+ */
116
+ private cachedOptions;
117
+ /** Default-on display scaling (true 72dpi size); see src/scale.ts. */
118
+ private readonly scale;
119
+ /** Device-pixel grid snapping (opt in with applyGridSnap()); see src/grid-snap.ts. */
120
+ private readonly gridSnap;
121
+ /**
122
+ * Whether the closed pill wears the kit's dashed focus rule — keyboard focus
123
+ * only, which this control can't read off `:focus-visible` (see the CSS).
124
+ */
125
+ private readonly focusRule;
126
+ /** While the panel is open: outside dismissal, and closing when a scroll or
127
+ * resize would strand the fixed-position panel away from the pill. */
128
+ private readonly panelListeners;
129
+ /** While a press gesture is in flight: track it to its release anywhere. */
130
+ private readonly pressListeners;
131
+ /** Index of the highlighted option while the panel is open. */
132
+ private activeIndex;
133
+ /**
134
+ * Overflow state for the open panel, all three settled by
135
+ * {@link positionPanel} and only the scroll moving afterwards. `rowScroll` is
136
+ * how many rows the strip is rolled up past the panel's top edge, so slot `i`
137
+ * shows option `rowScroll + i` — and it deliberately leaves the range that
138
+ * would fill every slot, which is the reserved blank the list rolls through:
139
+ * negative for blank above, past `rowCount − visibleSlots` for blank below.
140
+ * See src/popup-overflow.ts. (Named for the rows and not just `scroll`
141
+ * because `HTMLElement.scroll()` already owns that word.)
142
+ */
143
+ private rowScroll;
144
+ /** Row slots the open panel was drawn with (`R`). */
145
+ private visibleSlots;
146
+ /** Measured height of one option row, CSS px — the roll's own step. */
147
+ private rowHeight;
148
+ /** Whether rows are hidden above / below what the panel shows. */
149
+ private get showUpArrow();
150
+ private get showDownArrow();
151
+ /**
152
+ * The one arrow-scroll timer, with the direction it is rolling. A single
153
+ * owner for both entry paths (a resting pointer, and a press-drag into the
154
+ * arrow's zone) so the two can't stack two intervals on one arrow.
155
+ */
156
+ private arrowScroll;
157
+ /** Set when a press *began* in an arrow zone — that press is not a pick. */
158
+ private pressStartArrow;
159
+ /**
160
+ * Pointer press-gesture state. A press starts on `pointerdown` and is
161
+ * resolved on the matching `pointerup`/`pointercancel`; see the class doc.
162
+ */
163
+ private pressing;
164
+ /** True when *this* press is the one that opened the panel. */
165
+ private pressOpenedPanel;
166
+ /** Set once the pointer leaves the option it pressed on (a drag-pick). */
167
+ private pressMoved;
168
+ /** The option the press started over — origin for {@link pressMoved}. */
169
+ private pressStartOption;
170
+ /** `event.timeStamp` of the opening pointerdown (for the hold threshold). */
171
+ private pressDownTime;
172
+ private pressDownX;
173
+ private pressDownY;
174
+ /**
175
+ * Swallows the one `click` the browser synthesises after a pointer press
176
+ * (pointerdown+pointerup), so the pointer handlers — not
177
+ * {@link handleHostClick} — own mouse/touch input. A `click` with no
178
+ * preceding pointerdown (keyboard / assistive-tech activation) still reaches
179
+ * the click handler.
180
+ */
181
+ private swallowClick;
182
+ /** True while the classic selection blink is playing (input is ignored). */
183
+ private blinking;
184
+ private blinkHandle;
185
+ /** First-letter type-ahead over the open list; see src/type-ahead.ts. */
186
+ private readonly typeAhead;
187
+ constructor();
188
+ disconnectedCallback(): void;
189
+ /** Focuses the popup control. */
190
+ focus(options?: FocusOptions): void;
191
+ protected updated(changed: PropertyValues<this>): void;
192
+ /**
193
+ * Form-associated lifecycle: also re-syncs the form value immediately (the
194
+ * gated `updated()` doesn't run on a `formDisabled` change) and closes an open
195
+ * panel when an ancestor `<fieldset disabled>` disables us.
196
+ */
197
+ formDisabledCallback(disabled: boolean): void;
198
+ /** Restores the initial value when the associated form resets. */
199
+ formResetCallback(): void;
200
+ private get optionItems();
201
+ /** Resolved value of an option (falls back to its text, like `<option>`). */
202
+ private optionValue;
203
+ /** Marks the option matching `value` as selected. */
204
+ private applySelection;
205
+ private handleSlotChange;
206
+ private openPanel;
207
+ /**
208
+ * Positions the fixed-position panel so the selected item sits directly over
209
+ * the closed control (classic popup behavior), clipped to the usable screen
210
+ * band at a whole number of row slots.
211
+ */
212
+ private positionPanel;
213
+ private closePanel;
214
+ /**
215
+ * Writes the current scroll state to the panel: the strip's offset, and which
216
+ * arrows are showing. Both are imperative rather than rendered — an arrow
217
+ * step has to be visible to the very next hit-test in a drag, and nothing
218
+ * else re-renders this component while the panel is open.
219
+ */
220
+ private applyScroll;
221
+ /** Rolls the list so row `index` sits in a pickable slot (no-op if it does). */
222
+ private revealRow;
223
+ /** One row toward `dir`; returns false at the bound (nothing left to roll). */
224
+ private stepArrowScroll;
225
+ /**
226
+ * Starts rolling the list while the pointer holds an arrow. Steps once
227
+ * immediately — a brief touch of the arrow must do *something* — then once
228
+ * per {@link MENU_SCROLL_INTERVAL_MS} until the bound or {@link
229
+ * stopArrowScroll}. Idempotent per direction, so the hover path and the
230
+ * press-drag path can both claim the same arrow without stacking timers.
231
+ */
232
+ private startArrowScroll;
233
+ private stopArrowScroll;
234
+ /**
235
+ * Which arrow's zone the viewport point falls in, for the press-drag path.
236
+ *
237
+ * The zone is the arrow's row **extended past the panel edge** in its own
238
+ * direction — the classic ergonomics of slamming the pointer to the screen
239
+ * edge to keep a menu scrolling. Hover entry doesn't use this (it rides
240
+ * `pointerenter` on the slot itself); a pointer that has left the panel
241
+ * entirely is only scrolling because a press is dragging it there.
242
+ */
243
+ private arrowZoneAtPoint;
244
+ /**
245
+ * Which arrow *slot* the point is inside — the drawn row itself, with none of
246
+ * {@link arrowZoneAtPoint}'s reach past the panel edge. This is the plain
247
+ * "is the pointer on the arrow" question the hover contract asks.
248
+ */
249
+ private arrowSlotAtPoint;
250
+ /** Apply the hover contract at a point: on an arrow it rolls, off one it stops. */
251
+ private hoverArrowAt;
252
+ /**
253
+ * `pointerenter` **and** `pointermove` on the slots: a pointer that was
254
+ * already still where the arrow appeared never gets an enter event, and it
255
+ * is exactly the pointer most likely to be there — an arrow shows up under
256
+ * the very click that opened the panel whenever the pill sits near a screen
257
+ * edge. `pointerup` covers the wholly motionless case (see
258
+ * {@link handlePressPointerUp}); this covers the first twitch after it.
259
+ */
260
+ private handleArrowEnter;
261
+ private handleArrowLeave;
262
+ private setActive;
263
+ private clearActive;
264
+ /** Moves the highlight by `delta`, skipping disabled options. No wrap. */
265
+ private moveActive;
266
+ private firstEnabledIndex;
267
+ private lastEnabledIndex;
268
+ /** Plays the classic selection blink, then commits and closes. */
269
+ private selectOption;
270
+ private cancelBlink;
271
+ private commit;
272
+ private optionFromEvent;
273
+ /**
274
+ * `click` handler for *synthesised* activation — keyboard/assistive-tech
275
+ * clicks that arrive with no preceding pointerdown. Real mouse/touch clicks
276
+ * are swallowed here (their {@link swallowClick} flag was set on pointerdown)
277
+ * because the pointer handlers already resolved the gesture.
278
+ */
279
+ private handleHostClick;
280
+ /**
281
+ * Starts a press: opens the list if closed, then tracks the press to its
282
+ * release. Both interaction styles begin here; the gesture is classified in
283
+ * {@link handlePressPointerUp}.
284
+ */
285
+ private handleHostPointerDown;
286
+ private handlePressPointerMove;
287
+ private handlePressPointerUp;
288
+ private handlePressCancel;
289
+ private endPress;
290
+ /**
291
+ * The option whose row currently contains the viewport point, if any.
292
+ *
293
+ * Two guards keep a clipped panel honest. The point must be inside the
294
+ * panel's own box — rows rolled out of view keep truthful rects *outside* the
295
+ * clip, so without this a drag above the panel would highlight a hidden row.
296
+ * And only the pickable range is searched: a row lying under a shown arrow is
297
+ * covered, and covered is not clickable.
298
+ */
299
+ private optionAtPoint;
300
+ /** Live highlight during a press-drag; never moves DOM focus off the control. */
301
+ private trackHighlight;
302
+ /**
303
+ * Resolves a press that ended as a pick/dismiss (not a click-to-open): commit
304
+ * a different, enabled option (with the blink); otherwise close with no change
305
+ * — released on the current item, a disabled item, or off the list (the
306
+ * classic "release outside" cancel).
307
+ */
308
+ private resolveRelease;
309
+ private handleHostKeyDown;
310
+ private handleHostPointerOver;
311
+ private handleHostFocusOut;
312
+ private handleDocumentPointerDown;
313
+ /**
314
+ * Any scroll strands a `position: fixed` panel away from the pill it was
315
+ * placed against, so the popup closes. That now includes a scroll of the
316
+ * panel itself: it is a clip, not a scroll surface, and nothing in the
317
+ * component ever scrolls it — but an `overflow: hidden` box is still
318
+ * programmatically scrollable, and a browser that decides to scroll one
319
+ * (find-in-page, an outside `scrollIntoView`) would slide the rows off the
320
+ * lattice. Closing is the safe read of a scroll that can't legitimately
321
+ * happen.
322
+ */
323
+ private handleWindowScroll;
324
+ /** Close on viewport resize: the fixed panel was placed from the control's
325
+ * rect when it opened and would otherwise drift out of alignment. */
326
+ private handleWindowResize;
327
+ protected render(): import("lit-html").TemplateResult<1>;
328
+ }
329
+ declare global {
330
+ interface HTMLElementTagNameMap {
331
+ 'vf-select': VfSelect;
332
+ }
333
+ }
334
+ export {};