vintage-frames 0.7.2 → 0.9.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/custom-elements.json +891 -63
- package/dist/components/vf-desktop.d.ts +4 -2
- package/dist/components/vf-desktop.js +2 -2
- package/dist/components/vf-dialog.d.ts +17 -20
- package/dist/components/vf-dialog.js +73 -135
- package/dist/components/vf-icon.d.ts +15 -5
- package/dist/components/vf-icon.js +38 -41
- package/dist/components/vf-scroll-area.d.ts +4 -2
- package/dist/components/vf-scroll-area.js +2 -2
- package/dist/components/vf-window.d.ts +4 -2
- package/dist/components/vf-window.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/open-art.d.ts +24 -11
- package/dist/open-art.js +18 -16
- package/dist/position.d.ts +55 -6
- package/dist/position.js +120 -58
- package/docs/SPEC.md +15 -15
- package/editor/vscode.html-custom-data.json +159 -4
- package/editor/web-types.json +318 -12
- package/package.json +1 -1
|
@@ -156,9 +156,11 @@ export declare class VfDesktop extends VfDesktop_base {
|
|
|
156
156
|
* in whole system px on the placement lattice, measured from the raster's
|
|
157
157
|
* corner with the bezel excluded: the pair a child dropped onto the desktop
|
|
158
158
|
* is written with. The screen sits in the shadow tree, which is why the
|
|
159
|
-
* conversion is a method here.
|
|
159
|
+
* conversion is a method here. With `child`, the pair to write to that
|
|
160
|
+
* element: the offset its `origin` adds is folded in, so its box's corner
|
|
161
|
+
* lands on the point.
|
|
160
162
|
*/
|
|
161
|
-
placementAt(clientX: number, clientY: number): {
|
|
163
|
+
placementAt(clientX: number, clientY: number, child?: Element): {
|
|
162
164
|
left: number;
|
|
163
165
|
top: number;
|
|
164
166
|
};
|
|
@@ -199,8 +199,8 @@ var j = 1e6, M = 2 * j, N = 2000001, P = 512, F = 342, I = "gray-50", L = m(f[I]
|
|
|
199
199
|
height: this.height
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
|
-
placementAt(e, t) {
|
|
203
|
-
return s(this.screen ?? this, e, t, this);
|
|
202
|
+
placementAt(e, t, n) {
|
|
203
|
+
return s(this.screen ?? this, e, t, this, n);
|
|
204
204
|
}
|
|
205
205
|
#e;
|
|
206
206
|
connectedCallback() {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { VfModalDialog } from '../modal-dialog.js';
|
|
2
|
-
import './vf-button-group.js';
|
|
3
2
|
/**
|
|
4
3
|
* `<vf-dialog>` — the System 7 modal dialog shell.
|
|
5
4
|
*
|
|
@@ -16,9 +15,8 @@ import './vf-button-group.js';
|
|
|
16
15
|
* say no), so the component enables either reading rather than enforcing
|
|
17
16
|
* one.
|
|
18
17
|
* - **`frame="plain"`:** the modal dialog box — the bare frame, no title bar —
|
|
19
|
-
* and immovable, like the original.
|
|
20
|
-
*
|
|
21
|
-
* title"); `closable` is ignored, there being no bar to carry the widget.
|
|
18
|
+
* and immovable, like the original. With no bar, `heading` only names the
|
|
19
|
+
* dialog and `closable` is ignored.
|
|
22
20
|
*
|
|
23
21
|
* Open it with `show()` (or set the `open` attribute/property); close with
|
|
24
22
|
* `close()`. Escape closes it and fires `vf-close` with
|
|
@@ -36,21 +34,20 @@ import './vf-button-group.js';
|
|
|
36
34
|
* multi-line editor Return inserts the newline while the keypad's Enter
|
|
37
35
|
* activates the button.
|
|
38
36
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
37
|
+
* Slotted children placed with `top`/`left` measure from the content region's
|
|
38
|
+
* corner — the frame's inner edge, below the title bar — and flow content
|
|
39
|
+
* starts at the same corner.
|
|
40
|
+
*
|
|
41
|
+
* @slot - Default slot: the dialog's content.
|
|
43
42
|
* @csspart frame - The outer frame (the double frame's 1px rule; the bar and
|
|
44
43
|
* the inner band sit inside it).
|
|
45
44
|
* @csspart title-bar - The striped title bar (default chrome only).
|
|
46
|
-
* @csspart title - The centered title patch (
|
|
45
|
+
* @csspart title - The centered title patch (default chrome only).
|
|
47
46
|
* @csspart close-box - The close widget (`closable`, default chrome only).
|
|
48
|
-
* @csspart body - The white content
|
|
49
|
-
* @csspart content - The scrolling region inside the body (
|
|
50
|
-
* content
|
|
51
|
-
*
|
|
52
|
-
* @csspart footer - The action row wrapping the buttons.
|
|
53
|
-
* @csspart buttons - The button group inside the footer.
|
|
47
|
+
* @csspart body - The white content region.
|
|
48
|
+
* @csspart content - The scrolling region inside the body (the slotted
|
|
49
|
+
* content). Inert while the content fits; over-stuffed, it scrolls under a
|
|
50
|
+
* System 7 rail and becomes a keyboard stop.
|
|
54
51
|
* @fires vf-close - Dialog closed. Detail `{ reason: 'escape' | 'close' |
|
|
55
52
|
* 'outside' }` — `'outside'` only under `light-dismiss`.
|
|
56
53
|
* @cssprop --vf-dots-pattern - the windoid bar's dot-grid dither — a 2×2 tile,
|
|
@@ -75,12 +72,15 @@ export declare class VfDialog extends VfModalDialog {
|
|
|
75
72
|
private readonly _drag;
|
|
76
73
|
/** Holds the centered title patch on the placement lattice (src/chrome.ts). */
|
|
77
74
|
private readonly _titleCenter;
|
|
78
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Title text: the bar's centered patch, and the dialog's accessible name.
|
|
77
|
+
* With `frame="plain"`, which has no bar, it only names the dialog.
|
|
78
|
+
*/
|
|
79
79
|
heading: string;
|
|
80
80
|
/**
|
|
81
81
|
* Accessible name for the dialog (`aria-label`), for a dialog with no
|
|
82
82
|
* `heading` — an untitled title bar has no text to be named by. Ignored when
|
|
83
|
-
* empty and a `heading` is set (the
|
|
83
|
+
* empty and a `heading` is set (the heading names the dialog then);
|
|
84
84
|
* defaults to `'Dialog'` when neither is given.
|
|
85
85
|
*/
|
|
86
86
|
label: string;
|
|
@@ -96,8 +96,6 @@ export declare class VfDialog extends VfModalDialog {
|
|
|
96
96
|
* box (the bare double frame, no bar).
|
|
97
97
|
*/
|
|
98
98
|
frame?: 'plain';
|
|
99
|
-
/** Whether the `buttons` slot has assigned content (drives the footer). */
|
|
100
|
-
private _hasButtons;
|
|
101
99
|
private _content;
|
|
102
100
|
/** Whether the body content overflows its box (drives the content stop). */
|
|
103
101
|
private _scrollable;
|
|
@@ -112,7 +110,6 @@ export declare class VfDialog extends VfModalDialog {
|
|
|
112
110
|
private _onBodySlotChange;
|
|
113
111
|
private _onCloseClick;
|
|
114
112
|
protected render(): unknown;
|
|
115
|
-
private _onButtonsSlotChange;
|
|
116
113
|
}
|
|
117
114
|
declare global {
|
|
118
115
|
interface HTMLElementTagNameMap {
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import { vfElement as e } from "../define.js";
|
|
2
2
|
import { snapSys as t, toSysExact as n } from "../scale.js";
|
|
3
3
|
import r from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import "
|
|
17
|
-
import {
|
|
18
|
-
import { property as E, query as D, state as O } from "lit/decorators.js";
|
|
19
|
-
import { styleMap as k } from "lit/directives/style-map.js";
|
|
4
|
+
import { vfBase as i } from "../styles/recipes/host.js";
|
|
5
|
+
import { vfStripes as a } from "../styles/recipes/pattern.js";
|
|
6
|
+
import { vfModalFrame as o } from "../styles/recipes/surface.js";
|
|
7
|
+
import { vfTitleBar as s, vfWindowWidgets as c } from "../styles/recipes/title-bar.js";
|
|
8
|
+
import { vfFocus as l, vfFocusRing as u } from "../styles/recipes/focus.js";
|
|
9
|
+
import { vfScrollRail as d } from "../styles/recipes/scroll-rail.js";
|
|
10
|
+
import { DragController as f } from "../drag.js";
|
|
11
|
+
import { TitleCenterController as p, chromeTitleBar as m, closeBox as h, widgetLabel as g } from "../chrome.js";
|
|
12
|
+
import { ScrollStateController as _ } from "../scroll-state.js";
|
|
13
|
+
import { ScrollRailController as v, renderScrollRail as y } from "../scroll-rail.js";
|
|
14
|
+
import { VfModalDialog as b, modalDialogStyles as x } from "../modal-dialog.js";
|
|
15
|
+
import { css as S, html as C, nothing as w } from "lit";
|
|
16
|
+
import { property as T, query as E, state as D } from "lit/decorators.js";
|
|
17
|
+
import { styleMap as O } from "lit/directives/style-map.js";
|
|
20
18
|
//#region src/components/vf-dialog.ts
|
|
21
|
-
var
|
|
19
|
+
var k = class extends b {
|
|
22
20
|
constructor(...e) {
|
|
23
|
-
super(...e), this._drag = new
|
|
21
|
+
super(...e), this._drag = new f(this, {
|
|
24
22
|
onDragStart: (e) => {
|
|
25
23
|
if (e.button !== 0 || e.composedPath().some((e) => e instanceof HTMLElement && e.classList.contains("box"))) return null;
|
|
26
24
|
let r = this._dialog;
|
|
@@ -36,21 +34,21 @@ var A = class extends x {
|
|
|
36
34
|
};
|
|
37
35
|
},
|
|
38
36
|
onDrag: (e, t) => this.placeAt(e, t)
|
|
39
|
-
}), this._titleCenter = new
|
|
37
|
+
}), this._titleCenter = new p(this), this.heading = "", this.label = "", this.closable = !1, this._scrollable = !1, this._scrollState = new _(this, () => this._content, void 0, (e) => {
|
|
40
38
|
this._scrollable = e.y;
|
|
41
|
-
}), this._rail = new
|
|
39
|
+
}), this._rail = new v(this, { getScroll: () => this._content });
|
|
42
40
|
}
|
|
43
41
|
static {
|
|
44
42
|
this.styles = [
|
|
43
|
+
i,
|
|
45
44
|
a,
|
|
45
|
+
l,
|
|
46
46
|
o,
|
|
47
|
-
u,
|
|
48
47
|
s,
|
|
49
48
|
c,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
S
|
|
53
|
-
C`
|
|
49
|
+
d,
|
|
50
|
+
x,
|
|
51
|
+
S`
|
|
54
52
|
:host {
|
|
55
53
|
display: contents;
|
|
56
54
|
}
|
|
@@ -86,34 +84,27 @@ var A = class extends x {
|
|
|
86
84
|
:host([closable]) .vf-title {
|
|
87
85
|
--vf-title-inset: 60px;
|
|
88
86
|
}
|
|
89
|
-
/*
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
the
|
|
94
|
-
frame
|
|
95
|
-
|
|
87
|
+
/* The content region: takes the slack under the title bar, and is the
|
|
88
|
+
positioning anchor for slotted children placed with top/left
|
|
89
|
+
(src/position.ts) — coordinates measure from the frame's inner edge,
|
|
90
|
+
exactly the DITL convention. No inset of its own: flow content starts
|
|
91
|
+
at the same corner a placed child does. A modal is a fixed box — the
|
|
92
|
+
frame never grows with its body — but flow content taller than the
|
|
93
|
+
box is not silently clipped: the .content region below scrolls it
|
|
94
|
+
under a System 7 rail. Placed children anchor here, outside that
|
|
95
|
+
scroller, so they hold still while it scrolls. overflow: hidden stays
|
|
96
|
+
as the frame-level backstop. A slotted vf-select's list still
|
|
97
|
+
escapes: it is position:fixed off the control's own rect (see
|
|
98
|
+
vf-select.ts). */
|
|
96
99
|
.body {
|
|
97
100
|
--vf-surface: var(--vf-white, #ffffff);
|
|
98
101
|
background: var(--vf-white, #ffffff);
|
|
102
|
+
position: relative;
|
|
99
103
|
display: flex;
|
|
100
104
|
flex-direction: column;
|
|
101
105
|
flex: 1 1 auto;
|
|
102
106
|
min-height: 0;
|
|
103
107
|
overflow: hidden;
|
|
104
|
-
padding: calc(var(--vf-scale, 1) * 16px);
|
|
105
|
-
}
|
|
106
|
-
/* The scroll region's positioned wrapper (the .scroll-frame overlay and
|
|
107
|
-
the rail overlay anchor against it). Shrink-only (flex-grow 0): with
|
|
108
|
-
slack in the box the footer sits right after the content, exactly
|
|
109
|
-
where block flow put it before this wrapper existed — the wrap only
|
|
110
|
-
gives height back when the content doesn't fit. */
|
|
111
|
-
.content-wrap {
|
|
112
|
-
position: relative;
|
|
113
|
-
display: flex;
|
|
114
|
-
flex-direction: column;
|
|
115
|
-
flex: 0 1 auto;
|
|
116
|
-
min-height: 0;
|
|
117
108
|
}
|
|
118
109
|
/* hidden, not auto, until the controller says otherwise — the two have
|
|
119
110
|
to agree on what "overflowing" means or the dialog scrolls without a
|
|
@@ -134,73 +125,38 @@ var A = class extends x {
|
|
|
134
125
|
overflow-y: hidden;
|
|
135
126
|
}
|
|
136
127
|
/* Only while genuinely over-stuffed (ScrollStateController's measured
|
|
137
|
-
signal) does the region scroll — reserving the
|
|
138
|
-
own padding
|
|
139
|
-
|
|
140
|
-
fits, none of this matches and the body renders exactly as it always
|
|
141
|
-
has. */
|
|
128
|
+
signal) does the region scroll — reserving the rail's 15px as its
|
|
129
|
+
own padding — and only then does the rail appear. While the content
|
|
130
|
+
fits, none of this matches. */
|
|
142
131
|
.content[data-overflow-y='true'] {
|
|
143
132
|
overflow-y: scroll;
|
|
144
|
-
padding-right: calc(var(--vf-scale, 1) *
|
|
145
|
-
}
|
|
146
|
-
/* The rail rides the
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
minimum height, and a short
|
|
151
|
-
with the rail shown and
|
|
152
|
-
forever. An overlay cannot move
|
|
153
|
-
pays for is the padding above.
|
|
154
|
-
scrolls. */
|
|
155
|
-
.
|
|
133
|
+
padding-right: calc(var(--vf-scale, 1) * 15px);
|
|
134
|
+
}
|
|
135
|
+
/* The rail rides the body as an OVERLAY pinned to its right edge, flush
|
|
136
|
+
against the frame's inner band — the band is the classic 16px cell's
|
|
137
|
+
outer line on three sides; the fourth is the rail's own divider —
|
|
138
|
+
deliberately out of the layout flow: a rail column's two fixed 15px
|
|
139
|
+
arrow cells would hand the region a 32px minimum height, and a short
|
|
140
|
+
dialog would then measure as fitting with the rail shown and
|
|
141
|
+
overflowing without it, flip-flopping forever. An overlay cannot move
|
|
142
|
+
the box; the channel the content pays for is the padding above.
|
|
143
|
+
Hidden until the region actually scrolls. */
|
|
144
|
+
.body > .vf-rail {
|
|
156
145
|
position: absolute;
|
|
157
|
-
top:
|
|
158
|
-
right:
|
|
159
|
-
bottom:
|
|
146
|
+
top: 0;
|
|
147
|
+
right: 0;
|
|
148
|
+
bottom: 0;
|
|
160
149
|
display: none;
|
|
161
150
|
}
|
|
162
151
|
.content[data-overflow-y='true'] ~ .vf-rail {
|
|
163
152
|
display: grid;
|
|
164
153
|
}
|
|
165
|
-
/* The 1px frame boxing the scrolling region and its rail — an overlay
|
|
166
|
-
(spanning both grid columns via inset 0) so the fitting dialog keeps
|
|
167
|
-
no reserved line. */
|
|
168
|
-
.scroll-frame {
|
|
169
|
-
position: absolute;
|
|
170
|
-
inset: 0;
|
|
171
|
-
border: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
|
|
172
|
-
pointer-events: none;
|
|
173
|
-
display: none;
|
|
174
|
-
}
|
|
175
|
-
.content[data-overflow-y='true'] ~ .scroll-frame {
|
|
176
|
-
display: block;
|
|
177
|
-
}
|
|
178
154
|
/* A scrollable region is a keyboard stop (tabindex in the template);
|
|
179
155
|
mark it with the kit's dotted ring, inset to stay in-box — the same
|
|
180
156
|
treatment as vf-scroll-area's viewport. */
|
|
181
157
|
.content:focus-visible {
|
|
182
158
|
--vf-focus-offset: -2px;
|
|
183
|
-
${
|
|
184
|
-
}
|
|
185
|
-
/* The plain frame's heading: centered chrome type at the top of the
|
|
186
|
-
body, the way dBoxProc dialogs drew their title in content (see
|
|
187
|
-
Windows/modal dialog.png). No patch, no ellipsis — it's body-top
|
|
188
|
-
text, not a bar. */
|
|
189
|
-
.plain-heading {
|
|
190
|
-
${i}
|
|
191
|
-
display: block;
|
|
192
|
-
text-align: center;
|
|
193
|
-
margin-bottom: calc(var(--vf-scale, 1) * 16px);
|
|
194
|
-
}
|
|
195
|
-
/* Optional action row (slot="buttons"): a right-aligned vf-button-group
|
|
196
|
-
that only takes space when populated. */
|
|
197
|
-
.footer {
|
|
198
|
-
display: flex;
|
|
199
|
-
justify-content: flex-end;
|
|
200
|
-
margin-top: calc(var(--vf-scale, 1) * 16px);
|
|
201
|
-
}
|
|
202
|
-
.footer.empty {
|
|
203
|
-
display: none;
|
|
159
|
+
${u}
|
|
204
160
|
}
|
|
205
161
|
`
|
|
206
162
|
];
|
|
@@ -212,44 +168,30 @@ var A = class extends x {
|
|
|
212
168
|
this.close();
|
|
213
169
|
}
|
|
214
170
|
render() {
|
|
215
|
-
let e =
|
|
171
|
+
let e = this.frame === "plain", t = !e && !this.label && this.heading !== "", n = C`
|
|
216
172
|
<div class="body" part="body">
|
|
217
|
-
<div
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
>
|
|
224
|
-
${t && this.heading !== "" ? w`<span class="plain-heading" part="title" id="title"
|
|
225
|
-
>${this.heading}</span
|
|
226
|
-
>` : T}
|
|
227
|
-
<slot @slotchange=${this._onBodySlotChange}></slot>
|
|
228
|
-
</div>
|
|
229
|
-
${b(this._rail, "vertical")}
|
|
230
|
-
<div class="scroll-frame" aria-hidden="true"></div>
|
|
231
|
-
</div>
|
|
232
|
-
<div class="footer ${this._hasButtons ? "" : "empty"}" part="footer">
|
|
233
|
-
<vf-button-group class="buttons" part="buttons">
|
|
234
|
-
<slot
|
|
235
|
-
name="buttons"
|
|
236
|
-
@slotchange=${this._onButtonsSlotChange}
|
|
237
|
-
></slot>
|
|
238
|
-
</vf-button-group>
|
|
173
|
+
<div
|
|
174
|
+
class="content vf-scroll"
|
|
175
|
+
part="content"
|
|
176
|
+
tabindex=${this._scrollable ? "0" : w}
|
|
177
|
+
role=${this._scrollable ? "group" : w}
|
|
178
|
+
>
|
|
179
|
+
<slot @slotchange=${this._onBodySlotChange}></slot>
|
|
239
180
|
</div>
|
|
181
|
+
${y(this._rail, "vertical")}
|
|
240
182
|
</div>
|
|
241
183
|
`;
|
|
242
|
-
return
|
|
184
|
+
return C`
|
|
243
185
|
<dialog
|
|
244
|
-
style=${
|
|
245
|
-
aria-labelledby=${
|
|
246
|
-
aria-label=${
|
|
186
|
+
style=${O(this.dialogSize)}
|
|
187
|
+
aria-labelledby=${t ? "title" : w}
|
|
188
|
+
aria-label=${t ? w : this.label || this.heading || "Dialog"}
|
|
247
189
|
@cancel=${this._onNativeCancel}
|
|
248
190
|
@close=${this._onNativeClose}
|
|
249
191
|
>
|
|
250
192
|
<div class="vf-modal-frame" part="frame">
|
|
251
|
-
${
|
|
252
|
-
${this.closable ? g(
|
|
193
|
+
${e ? w : m(this._drag, C`
|
|
194
|
+
${this.closable ? h(g("Close", this.heading), this._onCloseClick) : w}
|
|
253
195
|
<span class="vf-title" part="title" id="title"
|
|
254
196
|
>${this.heading}</span
|
|
255
197
|
>
|
|
@@ -259,14 +201,10 @@ var A = class extends x {
|
|
|
259
201
|
</dialog>
|
|
260
202
|
`;
|
|
261
203
|
}
|
|
262
|
-
_onButtonsSlotChange(e) {
|
|
263
|
-
let t = e.target;
|
|
264
|
-
this._hasButtons = t.assignedElements().length > 0;
|
|
265
|
-
}
|
|
266
204
|
};
|
|
267
|
-
r([
|
|
205
|
+
r([T()], k.prototype, "heading", void 0), r([T()], k.prototype, "label", void 0), r([T({
|
|
268
206
|
type: Boolean,
|
|
269
207
|
reflect: !0
|
|
270
|
-
})],
|
|
208
|
+
})], k.prototype, "closable", void 0), r([T({ reflect: !0 })], k.prototype, "frame", void 0), r([E(".content")], k.prototype, "_content", void 0), r([D()], k.prototype, "_scrollable", void 0), k = r([e("vf-dialog")], k);
|
|
271
209
|
//#endregion
|
|
272
|
-
export {
|
|
210
|
+
export { k as VfDialog };
|
|
@@ -45,6 +45,11 @@ export interface VfIconDragFollower {
|
|
|
45
45
|
x: number;
|
|
46
46
|
y: number;
|
|
47
47
|
};
|
|
48
|
+
/** How far that origin sits from the follower's box corner (its `origin`). */
|
|
49
|
+
offset: {
|
|
50
|
+
x: number;
|
|
51
|
+
y: number;
|
|
52
|
+
};
|
|
48
53
|
/** The follower's box, system px, for the group clamp. */
|
|
49
54
|
size: {
|
|
50
55
|
width: number;
|
|
@@ -183,10 +188,14 @@ declare const VfIcon_base: (new (...args: any[]) => import("../position.js").VfP
|
|
|
183
188
|
* the name's rectangle — drawn over everything with the XOR pen, the icon
|
|
184
189
|
* itself staying put until the drop. The kit draws it from what it already
|
|
185
190
|
* has: {@link deriveDragOutline} finds the ring the way the open ghost does
|
|
186
|
-
* (the silhouette from the art's alpha,
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
191
|
+
* (the silhouette from the art's alpha, the plate's rectangle united with
|
|
192
|
+
* it, the whole inset by one pixel as `FrameRgn` inset a region, the ring
|
|
193
|
+
* the inset removes — so where the art and the plate abut, the outline
|
|
194
|
+
* wraps around both), and {@link dotOutline} dots it against a 2×2 checker
|
|
195
|
+
* — compositing only, so cross-origin art derives too, and art the
|
|
196
|
+
* pipeline cannot draw falls back to the cell's rectangle. The canvas
|
|
197
|
+
* covers the frame widened to the plate, since a name wider than a
|
|
198
|
+
* declared `width` overhangs the frame.
|
|
190
199
|
* The canvas paints with the cursor's XOR recipe, `filter: invert(1)` under
|
|
191
200
|
* `mix-blend-mode: difference`: a dotted black line over a white window
|
|
192
201
|
* body, and over the desktop dither a black line, the composition
|
|
@@ -374,7 +383,8 @@ declare const VfIcon_base: (new (...args: any[]) => import("../position.js").VfP
|
|
|
374
383
|
* @csspart plate - The inked run behind the name, which each wrapped line gets
|
|
375
384
|
* its own of (inverts when selected).
|
|
376
385
|
* @csspart input - The rename field, while editing.
|
|
377
|
-
* @cssprop --vf-icon-gap - Space between the art cell and the name plate
|
|
386
|
+
* @cssprop --vf-icon-gap - Space between the art cell and the name plate;
|
|
387
|
+
* 0 by default, the plate directly under the cell as the Finder drew it
|
|
378
388
|
* @cssprop --vf-icon-label-height - The name plate's line box
|
|
379
389
|
* @fires vf-select - Selection changed by user interaction. `detail: { selected: boolean }`.
|
|
380
390
|
* @fires vf-change - The name was committed. `detail: { label: string, previous: string }`.
|
|
@@ -213,7 +213,7 @@ var D, O = {
|
|
|
213
213
|
centring below is still a whole number of system px. */
|
|
214
214
|
.caption {
|
|
215
215
|
position: relative;
|
|
216
|
-
margin-top: calc(var(--vf-scale, 1) * var(--vf-icon-gap,
|
|
216
|
+
margin-top: calc(var(--vf-scale, 1) * var(--vf-icon-gap, 0px));
|
|
217
217
|
}
|
|
218
218
|
.label {
|
|
219
219
|
${u}
|
|
@@ -395,6 +395,7 @@ var D, O = {
|
|
|
395
395
|
return {
|
|
396
396
|
icon: this,
|
|
397
397
|
origin: t,
|
|
398
|
+
offset: this.#f.offset,
|
|
398
399
|
size: this.#v(),
|
|
399
400
|
move: (e, t) => {
|
|
400
401
|
n && this.#E(n, e, t);
|
|
@@ -469,19 +470,22 @@ var D, O = {
|
|
|
469
470
|
this.#f.moveTo(t.left, t.top);
|
|
470
471
|
return;
|
|
471
472
|
}
|
|
472
|
-
let n = this.#f.bounds, r =
|
|
473
|
-
|
|
473
|
+
let n = this.#f.bounds, r = (e, t) => ({
|
|
474
|
+
x: e.x - t.x,
|
|
475
|
+
y: e.y - t.y
|
|
476
|
+
}), i = [{
|
|
477
|
+
corner: r(e.origin, this.#f.offset),
|
|
474
478
|
size: e.size
|
|
475
479
|
}, ...e.followers.map((e) => ({
|
|
476
|
-
|
|
480
|
+
corner: r(e.origin, e.offset),
|
|
477
481
|
size: e.size
|
|
478
|
-
}))],
|
|
482
|
+
}))], a = (e, t, n, r) => {
|
|
479
483
|
let a = -Infinity, o = Infinity;
|
|
480
|
-
for (let e of
|
|
484
|
+
for (let e of i) a = Math.max(a, -t(e)), o = Math.min(o, r - n(e) - t(e));
|
|
481
485
|
return o < a && (o = Infinity), Math.min(Math.max(e, a), o);
|
|
482
|
-
},
|
|
483
|
-
this.#f.moveTo(e.origin.x +
|
|
484
|
-
for (let t of e.followers) t.drop(
|
|
486
|
+
}, o = a(t.left - e.origin.x, (e) => e.corner.x, (e) => e.size.width, n.width), s = a(t.top - e.origin.y, (e) => e.corner.y, (e) => e.size.height, n.height);
|
|
487
|
+
this.#f.moveTo(e.origin.x + o, e.origin.y + s);
|
|
488
|
+
for (let t of e.followers) t.drop(o, s);
|
|
485
489
|
}
|
|
486
490
|
#w() {
|
|
487
491
|
let t = { surface: null };
|
|
@@ -490,43 +494,36 @@ var D, O = {
|
|
|
490
494
|
#T(e, t) {
|
|
491
495
|
let n = this.renderRoot, a = n?.querySelector(".frame");
|
|
492
496
|
if (!a) return null;
|
|
493
|
-
let o = r(this), s = (
|
|
494
|
-
x: Math.round((
|
|
495
|
-
y: Math.round((
|
|
496
|
-
width: Math.round(
|
|
497
|
-
height: Math.round(
|
|
498
|
-
}),
|
|
499
|
-
width:
|
|
500
|
-
height:
|
|
501
|
-
art:
|
|
502
|
-
cell:
|
|
497
|
+
let o = r(this), s = n.querySelector(".art"), c = n.querySelector(".name")?.getBoundingClientRect() ?? null, l = c ? Math.min(e.left, c.left) : e.left, u = c ? Math.min(e.top, c.top) : e.top, d = c ? Math.max(e.right, c.right) : e.right, f = c ? Math.max(e.bottom, c.bottom) : e.bottom, p = (e) => ({
|
|
498
|
+
x: Math.round((e.left - l) / o),
|
|
499
|
+
y: Math.round((e.top - u) / o),
|
|
500
|
+
width: Math.round(e.width / o),
|
|
501
|
+
height: Math.round(e.height / o)
|
|
502
|
+
}), m = Math.round((d - l) / o), h = Math.round((f - u) / o), g = this.open && this._ghost ? this._ghost : this.#t, v = g != null && (g instanceof HTMLCanvasElement ? g.width > 0 : g.complete && g.naturalWidth > 0), y = v ? g.getBoundingClientRect() : null, b = _(v ? g : null, {
|
|
503
|
+
width: m,
|
|
504
|
+
height: h,
|
|
505
|
+
art: y && y.width > 0 ? p(y) : null,
|
|
506
|
+
cell: s ? p(s.getBoundingClientRect()) : {
|
|
503
507
|
x: 0,
|
|
504
508
|
y: 0,
|
|
505
|
-
width:
|
|
506
|
-
height:
|
|
509
|
+
width: m,
|
|
510
|
+
height: h
|
|
507
511
|
},
|
|
508
|
-
plate:
|
|
512
|
+
plate: c ? p(c) : null
|
|
509
513
|
});
|
|
510
|
-
if (!
|
|
511
|
-
let
|
|
512
|
-
|
|
513
|
-
let
|
|
514
|
-
|
|
515
|
-
let
|
|
516
|
-
x:
|
|
517
|
-
y:
|
|
514
|
+
if (!b) return null;
|
|
515
|
+
let x = document.createElement("canvas");
|
|
516
|
+
x.className = "drag-outline";
|
|
517
|
+
let S = x.style;
|
|
518
|
+
S.position = "absolute", S.display = "block", S.pointerEvents = "none", S.filter = "invert(1)", S.mixBlendMode = "difference", S.imageRendering = "pixelated", S.width = i(b.width), S.height = i(b.height);
|
|
519
|
+
let C = t ?? a, w = t ? t.getBoundingClientRect() : e, T = {
|
|
520
|
+
x: Math.round((l - w.left) / o),
|
|
521
|
+
y: Math.round((u - w.top) / o)
|
|
518
522
|
};
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
y: Math.round((e.top - n.top) / o)
|
|
524
|
-
}, t.append(g);
|
|
525
|
-
} else a.append(g);
|
|
526
|
-
return {
|
|
527
|
-
ring: h,
|
|
528
|
-
canvas: g,
|
|
529
|
-
base: y,
|
|
523
|
+
return C.append(x), {
|
|
524
|
+
ring: b,
|
|
525
|
+
canvas: x,
|
|
526
|
+
base: T,
|
|
530
527
|
phase: -1
|
|
531
528
|
};
|
|
532
529
|
}
|
|
@@ -89,9 +89,11 @@ export declare class VfScrollArea extends VfScrollArea_base {
|
|
|
89
89
|
* `{ left, top }` in whole system px on the placement lattice, the pair a
|
|
90
90
|
* child dropped here is written with. The plane travels with the scroll,
|
|
91
91
|
* so its box already carries the scroll offset and the border-floor
|
|
92
|
-
* padding; nothing is left for the caller to add.
|
|
92
|
+
* padding; nothing is left for the caller to add. With `child`, the pair
|
|
93
|
+
* to write to that element: the offset its `origin` adds is folded in, so
|
|
94
|
+
* its box's corner lands on the point.
|
|
93
95
|
*/
|
|
94
|
-
placementAt(clientX: number, clientY: number): {
|
|
96
|
+
placementAt(clientX: number, clientY: number, child?: Element): {
|
|
95
97
|
left: number;
|
|
96
98
|
top: number;
|
|
97
99
|
};
|
|
@@ -23,8 +23,8 @@ var y = class extends r(f) {
|
|
|
23
23
|
}, this.addEventListener("vf-placement-change", this.#e);
|
|
24
24
|
}
|
|
25
25
|
#e;
|
|
26
|
-
placementAt(e, t) {
|
|
27
|
-
return i(this.content ?? this, e, t, this);
|
|
26
|
+
placementAt(e, t, n) {
|
|
27
|
+
return i(this.content ?? this, e, t, this, n);
|
|
28
28
|
}
|
|
29
29
|
focus(e) {
|
|
30
30
|
this.viewport?.focus(e);
|
|
@@ -201,9 +201,11 @@ export declare class VfWindow extends VfWindow_base {
|
|
|
201
201
|
* child dropped into this window is written with: the body's corner, or
|
|
202
202
|
* under `scrollbars` the scrolled plane, scroll offset included. The anchor
|
|
203
203
|
* sits in the shadow tree, which is why the conversion is a method here
|
|
204
|
-
* rather than the page's own `toSysExact` against a rect.
|
|
204
|
+
* rather than the page's own `toSysExact` against a rect. With `child`,
|
|
205
|
+
* the pair to write to that element: the offset its `origin` adds is
|
|
206
|
+
* folded in, so its box's corner lands on the point.
|
|
205
207
|
*/
|
|
206
|
-
placementAt(clientX: number, clientY: number): {
|
|
208
|
+
placementAt(clientX: number, clientY: number, child?: Element): {
|
|
207
209
|
left: number;
|
|
208
210
|
top: number;
|
|
209
211
|
};
|
|
@@ -329,9 +329,9 @@ var W = 24, G = 8, K = class extends D(c(P)) {
|
|
|
329
329
|
></div>`;
|
|
330
330
|
}
|
|
331
331
|
#t;
|
|
332
|
-
placementAt(e, t) {
|
|
333
|
-
let
|
|
334
|
-
return
|
|
332
|
+
placementAt(e, t, n) {
|
|
333
|
+
let r = this.scrollArea;
|
|
334
|
+
return r ? r.placementAt(e, t, n) : l(this.body ?? this, e, t, this, n);
|
|
335
335
|
}
|
|
336
336
|
measure() {
|
|
337
337
|
this.scrollArea?.measure();
|
package/dist/index.d.ts
CHANGED
|
@@ -155,7 +155,7 @@ export { VfTextControlBase } from './text-control.js';
|
|
|
155
155
|
export { VfToggleControl } from './toggle-control.js';
|
|
156
156
|
export type { VfToggleControlInterface } from './toggle-control.js';
|
|
157
157
|
export { PlacementController, VfPositioned } from './position.js';
|
|
158
|
-
export type { PlacementBounds, PlacementClamp, VfPositionedInterface } from './position.js';
|
|
158
|
+
export type { PlacementBounds, PlacementClamp, PlacementOrigin, VfPositionedInterface, } from './position.js';
|
|
159
159
|
export { VfSized } from './size.js';
|
|
160
160
|
export type { VfSizedInterface } from './size.js';
|
|
161
161
|
export { VfModalDialog, modalDialogStyles } from './modal-dialog.js';
|