vintage-frames 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +262 -0
- package/custom-elements.json +19807 -0
- package/dist/_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js +9 -0
- package/dist/chrome.d.ts +73 -0
- package/dist/chrome.js +94 -0
- package/dist/components/vf-button-group.d.ts +50 -0
- package/dist/components/vf-button-group.js +68 -0
- package/dist/components/vf-button.d.ts +169 -0
- package/dist/components/vf-button.js +234 -0
- package/dist/components/vf-checkbox.d.ts +60 -0
- package/dist/components/vf-checkbox.js +135 -0
- package/dist/components/vf-container.d.ts +95 -0
- package/dist/components/vf-container.js +86 -0
- package/dist/components/vf-desktop.d.ts +243 -0
- package/dist/components/vf-desktop.js +310 -0
- package/dist/components/vf-dialog.d.ts +105 -0
- package/dist/components/vf-dialog.js +280 -0
- package/dist/components/vf-fieldset.d.ts +34 -0
- package/dist/components/vf-fieldset.js +76 -0
- package/dist/components/vf-grid.d.ts +124 -0
- package/dist/components/vf-grid.js +133 -0
- package/dist/components/vf-icon.d.ts +356 -0
- package/dist/components/vf-icon.js +507 -0
- package/dist/components/vf-img.d.ts +63 -0
- package/dist/components/vf-img.js +65 -0
- package/dist/components/vf-label.d.ts +117 -0
- package/dist/components/vf-label.js +151 -0
- package/dist/components/vf-list-item.d.ts +48 -0
- package/dist/components/vf-list-item.js +98 -0
- package/dist/components/vf-list.d.ts +77 -0
- package/dist/components/vf-list.js +256 -0
- package/dist/components/vf-menu-bar.d.ts +64 -0
- package/dist/components/vf-menu-bar.js +236 -0
- package/dist/components/vf-menu-item.d.ts +91 -0
- package/dist/components/vf-menu-item.js +252 -0
- package/dist/components/vf-menu.d.ts +95 -0
- package/dist/components/vf-menu.js +346 -0
- package/dist/components/vf-number-field.d.ts +60 -0
- package/dist/components/vf-number-field.js +248 -0
- package/dist/components/vf-option.d.ts +49 -0
- package/dist/components/vf-option.js +119 -0
- package/dist/components/vf-paragraph.d.ts +73 -0
- package/dist/components/vf-paragraph.js +66 -0
- package/dist/components/vf-progress-bar.d.ts +69 -0
- package/dist/components/vf-progress-bar.js +272 -0
- package/dist/components/vf-radio-group.d.ts +109 -0
- package/dist/components/vf-radio-group.js +105 -0
- package/dist/components/vf-radio.d.ts +59 -0
- package/dist/components/vf-radio.js +135 -0
- package/dist/components/vf-scroll-area.d.ts +75 -0
- package/dist/components/vf-scroll-area.js +124 -0
- package/dist/components/vf-select.d.ts +334 -0
- package/dist/components/vf-select.js +658 -0
- package/dist/components/vf-separator.d.ts +38 -0
- package/dist/components/vf-separator.js +55 -0
- package/dist/components/vf-slider.d.ts +80 -0
- package/dist/components/vf-slider.js +255 -0
- package/dist/components/vf-stack.d.ts +188 -0
- package/dist/components/vf-stack.js +168 -0
- package/dist/components/vf-swatch.d.ts +98 -0
- package/dist/components/vf-swatch.js +201 -0
- package/dist/components/vf-text-area.d.ts +77 -0
- package/dist/components/vf-text-area.js +121 -0
- package/dist/components/vf-text-field.d.ts +53 -0
- package/dist/components/vf-text-field.js +79 -0
- package/dist/components/vf-window.d.ts +157 -0
- package/dist/components/vf-window.js +377 -0
- package/dist/cursor-art.d.ts +37 -0
- package/dist/cursor-art.js +41 -0
- package/dist/cursor.d.ts +49 -0
- package/dist/cursor.js +171 -0
- package/dist/define.d.ts +45 -0
- package/dist/define.js +15 -0
- package/dist/document-listeners.d.ts +62 -0
- package/dist/document-listeners.js +29 -0
- package/dist/drag.d.ts +49 -0
- package/dist/drag.js +30 -0
- package/dist/events.d.ts +79 -0
- package/dist/events.js +25 -0
- package/dist/focus-modality.d.ts +94 -0
- package/dist/focus-modality.js +56 -0
- package/dist/form-control.d.ts +247 -0
- package/dist/form-control.js +127 -0
- package/dist/glyphs.d.ts +117 -0
- package/dist/glyphs.js +100 -0
- package/dist/grid-snap.d.ts +73 -0
- package/dist/grid-snap.js +135 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.js +71 -0
- package/dist/menu-press.d.ts +60 -0
- package/dist/menu-press.js +97 -0
- package/dist/modal-dialog.d.ts +148 -0
- package/dist/modal-dialog.js +155 -0
- package/dist/motion.d.ts +72 -0
- package/dist/motion.js +22 -0
- package/dist/number.d.ts +24 -0
- package/dist/number.js +12 -0
- package/dist/open-art.d.ts +40 -0
- package/dist/open-art.js +35 -0
- package/dist/pixel-frame.d.ts +102 -0
- package/dist/pixel-frame.js +77 -0
- package/dist/popup-overflow.d.ts +157 -0
- package/dist/popup-overflow.js +45 -0
- package/dist/position.d.ts +187 -0
- package/dist/position.js +74 -0
- package/dist/scale.d.ts +259 -0
- package/dist/scale.js +133 -0
- package/dist/scroll-rail.d.ts +112 -0
- package/dist/scroll-rail.js +194 -0
- package/dist/scroll-state.d.ts +113 -0
- package/dist/scroll-state.js +55 -0
- package/dist/size.d.ts +47 -0
- package/dist/size.js +30 -0
- package/dist/styles/base.d.ts +38 -0
- package/dist/styles/body-font.d.ts +7 -0
- package/dist/styles/body-font.js +9 -0
- package/dist/styles/display-font.d.ts +7 -0
- package/dist/styles/display-font.js +9 -0
- package/dist/styles/recipes/body-face.d.ts +14 -0
- package/dist/styles/recipes/body-face.js +6 -0
- package/dist/styles/recipes/display-face.d.ts +23 -0
- package/dist/styles/recipes/display-face.js +10 -0
- package/dist/styles/recipes/field.d.ts +20 -0
- package/dist/styles/recipes/field.js +68 -0
- package/dist/styles/recipes/focus.d.ts +76 -0
- package/dist/styles/recipes/focus.js +39 -0
- package/dist/styles/recipes/host.d.ts +5 -0
- package/dist/styles/recipes/host.js +62 -0
- package/dist/styles/recipes/pattern.d.ts +80 -0
- package/dist/styles/recipes/pattern.js +82 -0
- package/dist/styles/recipes/scroll-rail.d.ts +69 -0
- package/dist/styles/recipes/scroll-rail.js +222 -0
- package/dist/styles/recipes/shadow.d.ts +13 -0
- package/dist/styles/recipes/shadow.js +5 -0
- package/dist/styles/recipes/static-text.d.ts +24 -0
- package/dist/styles/recipes/static-text.js +17 -0
- package/dist/styles/recipes/surface.d.ts +28 -0
- package/dist/styles/recipes/surface.js +27 -0
- package/dist/styles/recipes/tile.d.ts +122 -0
- package/dist/styles/recipes/tile.js +40 -0
- package/dist/styles/recipes/title-bar.d.ts +49 -0
- package/dist/styles/recipes/title-bar.js +134 -0
- package/dist/styles/recipes/toggle.d.ts +10 -0
- package/dist/styles/recipes/toggle.js +20 -0
- package/dist/styles/register-embedded-font.d.ts +64 -0
- package/dist/styles/register-embedded-font.js +30 -0
- package/dist/text-control.d.ts +131 -0
- package/dist/text-control.js +83 -0
- package/dist/tile-grid.d.ts +111 -0
- package/dist/tile-grid.js +53 -0
- package/dist/toggle-control.d.ts +60 -0
- package/dist/toggle-control.js +41 -0
- package/dist/track-width.d.ts +42 -0
- package/dist/track-width.js +30 -0
- package/dist/type-ahead.d.ts +35 -0
- package/dist/type-ahead.js +20 -0
- package/dist/zoom.d.ts +204 -0
- package/dist/zoom.js +105 -0
- package/docs/SPEC.md +2471 -0
- package/editor/vscode.html-custom-data.json +1320 -0
- package/editor/web-types.json +3237 -0
- package/package.json +118 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
import { vfElement as e } from "../define.js";
|
|
2
|
+
import { ScaleController as t, effectiveScale as n, toSysExact as r } from "../scale.js";
|
|
3
|
+
import i from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
|
|
4
|
+
import { PlacementController as a, VfPositioned as o, warnMovableContract as s } from "../position.js";
|
|
5
|
+
import { vfBodyDecls as c } from "../styles/recipes/body-face.js";
|
|
6
|
+
import { vfBase as l } from "../styles/recipes/host.js";
|
|
7
|
+
import { vfFocusUnderline as u } from "../styles/recipes/focus.js";
|
|
8
|
+
import { GridSnapController as d } from "../grid-snap.js";
|
|
9
|
+
import { DocumentListenersController as f } from "../document-listeners.js";
|
|
10
|
+
import { DragController as p } from "../drag.js";
|
|
11
|
+
import { emit as m } from "../events.js";
|
|
12
|
+
import "../motion.js";
|
|
13
|
+
import { FocusRuleController as h } from "../focus-modality.js";
|
|
14
|
+
import { deriveOpenArt as g } from "../open-art.js";
|
|
15
|
+
import { LitElement as _, css as v, html as y, nothing as b } from "lit";
|
|
16
|
+
import { property as x, state as S } from "lit/decorators.js";
|
|
17
|
+
//#region src/components/vf-icon.ts
|
|
18
|
+
var C = {
|
|
19
|
+
large: 32,
|
|
20
|
+
small: 16
|
|
21
|
+
}, w = 1, T = 8, E = (e, t) => t <= 0 ? Math.max(e, 0) : Math.min(Math.max(e, 0), t), D = class extends o(_) {
|
|
22
|
+
constructor(...e) {
|
|
23
|
+
super(...e), this.label = "", this.size = "large", this.selectable = !1, this.selected = !1, this.open = !1, this.movable = !1, this.editable = !1, this.maxlength = 31, this.scale = new t(this), this.gridSnap = new d(this), this.focusRule = new h(this), this._editing = !1, this._draft = "", this.#e = 0, this._ghost = null, this.#t = null, this.#n = this.attachInternals(), this.#i = "", this.#a = "", this.#o = 0, this.#s = -Infinity, this.#c = new f(this, () => [[
|
|
24
|
+
document,
|
|
25
|
+
"pointerdown",
|
|
26
|
+
this.#A,
|
|
27
|
+
!0
|
|
28
|
+
]]), this.#l = (e, t, n) => ({
|
|
29
|
+
x: E(e, n.width - r(this.offsetWidth, this)),
|
|
30
|
+
y: E(t, n.height - r(this.offsetHeight, this))
|
|
31
|
+
}), this.#u = new a(this, (e, t, n) => this.#l(e, t, n)), this.#d = {
|
|
32
|
+
x: 0,
|
|
33
|
+
y: 0
|
|
34
|
+
}, this.#f = new p(this, {
|
|
35
|
+
onDragStart: (e) => !this.movable || e.button !== 0 || this._editing ? null : (this.#m(), this.#d = this.#u.seed()),
|
|
36
|
+
onDrag: (e, t) => {
|
|
37
|
+
(e !== this.#d.x || t !== this.#d.y) && this.#S(), this.#u.moveTo(e, t);
|
|
38
|
+
}
|
|
39
|
+
}), this.#p = !1, this.#_ = () => {
|
|
40
|
+
this.#y(), this.#C();
|
|
41
|
+
}, this.#v = () => {
|
|
42
|
+
this.#b();
|
|
43
|
+
}, this.#O = (e) => {
|
|
44
|
+
if (e.button !== 0 || this._editing) return;
|
|
45
|
+
let t = e.composedPath().some((e) => e instanceof HTMLElement && e.classList.contains("label")), n = this.selected, r = e.timeStamp - this.#s < 800;
|
|
46
|
+
this.#s = e.timeStamp, this.#S(), this.selectable && (e.shiftKey || e.metaKey ? this.#D(!this.selected) : this.#D(!0)), this.editable && t && n && !r && !e.shiftKey && !e.metaKey && this.#x(), this.#T && (this.focus({ preventScroll: !0 }), this.focusRule.suppress()), this.#f.onPointerDown(e);
|
|
47
|
+
}, this.#k = () => {
|
|
48
|
+
this._editing || m(this, "vf-open", {});
|
|
49
|
+
}, this.#A = (e) => {
|
|
50
|
+
e.composedPath().includes(this) || (this.#S(), !(e.shiftKey || e.metaKey) && this.#D(!1));
|
|
51
|
+
}, this.#j = (e) => {
|
|
52
|
+
let t = e.target, n = e.data ?? e.dataTransfer?.getData("text") ?? "";
|
|
53
|
+
if (n === "") return;
|
|
54
|
+
let r = t.selectionStart ?? t.value.length, i = t.selectionEnd ?? r, a = t.value.slice(0, r) + n + t.value.slice(i);
|
|
55
|
+
a.length > this.maxlength && this.#N(a);
|
|
56
|
+
}, this.#M = (e) => {
|
|
57
|
+
let t = e.target;
|
|
58
|
+
if (t.value.length > this.maxlength) {
|
|
59
|
+
let e = t.value, n = Math.min(t.selectionStart ?? this.maxlength, this.maxlength);
|
|
60
|
+
t.value = e.slice(0, this.maxlength), t.setSelectionRange(n, n), this.#N(e);
|
|
61
|
+
}
|
|
62
|
+
this._draft = t.value;
|
|
63
|
+
}, this.#P = (e) => {
|
|
64
|
+
e.key === "Enter" ? (e.preventDefault(), this.commitEditing(), this.focus()) : e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), this.cancelEditing(), this.focus());
|
|
65
|
+
}, this.#F = (e) => {
|
|
66
|
+
if (this.#S(), !(this._editing || e.defaultPrevented)) {
|
|
67
|
+
if ((e.metaKey || e.ctrlKey) && !e.altKey && (e.key.toLowerCase() === "o" || e.key === "ArrowDown")) {
|
|
68
|
+
e.preventDefault(), m(this, "vf-open", {});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
switch (e.key) {
|
|
72
|
+
case "Enter":
|
|
73
|
+
if (!this.editable) return;
|
|
74
|
+
e.preventDefault(), this.startEditing();
|
|
75
|
+
return;
|
|
76
|
+
case " ":
|
|
77
|
+
if (!this.selectable) return;
|
|
78
|
+
e.preventDefault(), this.focusRule.reveal(), this.#D(!this.selected);
|
|
79
|
+
return;
|
|
80
|
+
case "ArrowLeft":
|
|
81
|
+
case "ArrowRight":
|
|
82
|
+
case "ArrowUp":
|
|
83
|
+
case "ArrowDown": {
|
|
84
|
+
if (!this.movable) return;
|
|
85
|
+
e.preventDefault(), this.focusRule.reveal();
|
|
86
|
+
let t = e.shiftKey ? T : w, n = e.key === "ArrowLeft" ? -t : e.key === "ArrowRight" ? t : 0, r = e.key === "ArrowUp" ? -t : e.key === "ArrowDown" ? t : 0;
|
|
87
|
+
this.#m();
|
|
88
|
+
let i = this.#u.seed();
|
|
89
|
+
this.#u.moveTo(i.x + n, i.y + r);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
static {
|
|
96
|
+
this.styles = [l, v`
|
|
97
|
+
:host {
|
|
98
|
+
display: inline-block;
|
|
99
|
+
cursor: var(--vf-cursor, default);
|
|
100
|
+
/* The reserved cell, resolved once so the art box and the no-label
|
|
101
|
+
focus rule share one definition. Not a public token: the two sizes
|
|
102
|
+
are the two icon resources, not a taste. */
|
|
103
|
+
--_cell: 32px;
|
|
104
|
+
}
|
|
105
|
+
:host([size='small']) {
|
|
106
|
+
--_cell: 16px;
|
|
107
|
+
}
|
|
108
|
+
.frame {
|
|
109
|
+
display: flex;
|
|
110
|
+
flex-direction: column;
|
|
111
|
+
align-items: center;
|
|
112
|
+
}
|
|
113
|
+
.art {
|
|
114
|
+
position: relative;
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
width: calc(var(--vf-scale, 1) * var(--_cell));
|
|
119
|
+
height: calc(var(--vf-scale, 1) * var(--_cell));
|
|
120
|
+
/* Art larger than its cell is clipped rather than allowed to collide
|
|
121
|
+
with the plate — a wrong-size asset stays a visibly wrong asset. */
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
}
|
|
124
|
+
/* The classic selected icon: the art is ink and opaque white on a
|
|
125
|
+
transparent surround, so inverting flips the two and the surround
|
|
126
|
+
stays out of it (see the class doc). The open ghost keeps exactly
|
|
127
|
+
that shape, so the same rule is the whole of selected-open too. */
|
|
128
|
+
:host([selected]) .art {
|
|
129
|
+
filter: invert(1);
|
|
130
|
+
}
|
|
131
|
+
/* The open ghost replaces the slotted art while there is one — the
|
|
132
|
+
slot stays in the tree (it is where the art loads and re-loads
|
|
133
|
+
from) but paints nothing. Gated on the class, not :host([open]):
|
|
134
|
+
art the pipeline cannot draw keeps rendering as itself rather than
|
|
135
|
+
vanishing behind a state it cannot show. */
|
|
136
|
+
.art.open slot {
|
|
137
|
+
display: none;
|
|
138
|
+
}
|
|
139
|
+
/* The derived raster displays on the terms vf-img gives the art it
|
|
140
|
+
came from: natural size in system px (the inline style it carries),
|
|
141
|
+
nearest-neighbor on whole device pixels. */
|
|
142
|
+
.ghost {
|
|
143
|
+
display: block;
|
|
144
|
+
image-rendering: pixelated;
|
|
145
|
+
}
|
|
146
|
+
/* Sized by the plate, and deliberately NOT clamped to the frame: a name
|
|
147
|
+
wider than the cell has to straddle the centre line, not start at the
|
|
148
|
+
cell's left edge and run off to the right. Clamping it left the art
|
|
149
|
+
and the name on two different axes — and since the plate is even and
|
|
150
|
+
the cell is even, the negative offset a wider caption gets from the
|
|
151
|
+
centring below is still a whole number of system px. */
|
|
152
|
+
.caption {
|
|
153
|
+
position: relative;
|
|
154
|
+
margin-top: calc(var(--vf-scale, 1) * var(--vf-icon-gap, 2px));
|
|
155
|
+
}
|
|
156
|
+
.label {
|
|
157
|
+
${c}
|
|
158
|
+
font-weight: var(--vf-font-weight, 700);
|
|
159
|
+
/* Whole system px, never a ratio — layout contract rule 2. 12, not
|
|
160
|
+
the face's 16px em: the Finder's plate is 12 system px tall, and
|
|
161
|
+
the em centered in it lands the ink exactly where the Finder put
|
|
162
|
+
it — 3px above the ascenders, descenders on the bottom edge. The
|
|
163
|
+
half-leading is (12 − 16) / 2, so an override must keep the box's
|
|
164
|
+
parity even for the baseline to stay on a whole pixel. */
|
|
165
|
+
line-height: calc(
|
|
166
|
+
var(--vf-scale, 1) * var(--vf-icon-label-height, 12px)
|
|
167
|
+
);
|
|
168
|
+
/* One line, always. A name is never abbreviated and never wrapped: it
|
|
169
|
+
is at most 31 characters, and it overflows its cell rather than
|
|
170
|
+
folding — which is also what keeps its x whole (see the class doc). */
|
|
171
|
+
white-space: nowrap;
|
|
172
|
+
text-align: center;
|
|
173
|
+
}
|
|
174
|
+
/* Inline, not block, so the plate hugs each line separately — a wrapped
|
|
175
|
+
name reads as stacked bars of different widths, which is how System 7
|
|
176
|
+
drew it. The clone value is what repeats the 1px side padding onto
|
|
177
|
+
every fragment instead of only the first and last. */
|
|
178
|
+
/* The plate: an inline-block sized to a whole EVEN number of system px
|
|
179
|
+
(see #measurePlate). That parity is the whole alignment argument —
|
|
180
|
+
with it, both things the frame centers land on a whole pixel by
|
|
181
|
+
construction rather than by correction. */
|
|
182
|
+
.name {
|
|
183
|
+
display: inline-block;
|
|
184
|
+
/* The plate is opaque white in its own right, not the surrounding
|
|
185
|
+
surface: on the desktop dither the name reads because it sits on a
|
|
186
|
+
plate, and --vf-surface is unset out there. */
|
|
187
|
+
background: var(--vf-white, #fff);
|
|
188
|
+
color: var(--vf-black, #000);
|
|
189
|
+
/* Whole system px, and NOT centered inside the plate: the text starts
|
|
190
|
+
at the padding edge, so its own x is the plate's x plus one whole
|
|
191
|
+
pixel. Centering here would re-introduce the half pixel the even
|
|
192
|
+
width just removed, one level down. Any slack from rounding up to
|
|
193
|
+
even lands after the text, where it is a hairline of extra plate. */
|
|
194
|
+
padding: 0 calc(var(--vf-scale, 1) * 1px);
|
|
195
|
+
text-align: left;
|
|
196
|
+
}
|
|
197
|
+
:host([selected]) .name {
|
|
198
|
+
/* Forced colors: exempt the inverted plate from the mode's text
|
|
199
|
+
backplate, which would land a Canvas slab on the highlight bar —
|
|
200
|
+
see vf-list-item's forced-colors note. The pair is already the
|
|
201
|
+
user's own via the vfBase token remap. */
|
|
202
|
+
@media (forced-colors: active) {
|
|
203
|
+
forced-color-adjust: none;
|
|
204
|
+
}
|
|
205
|
+
background: var(--vf-highlight, #000);
|
|
206
|
+
color: var(--vf-highlight-text, #fff);
|
|
207
|
+
}
|
|
208
|
+
/* Editing: the plate keeps rendering the draft — still measured, still
|
|
209
|
+
even — so the box tracks the typed width the way the Finder's rename
|
|
210
|
+
box grew, while handing its pixels to the field overlaying it.
|
|
211
|
+
white-space: pre holds the spaces a name may legitimately end in,
|
|
212
|
+
which the collapsing default would drop from the measurement. */
|
|
213
|
+
.caption.editing .label {
|
|
214
|
+
visibility: hidden;
|
|
215
|
+
white-space: pre;
|
|
216
|
+
}
|
|
217
|
+
/* The rename box: a 1px border with a 1px white well inside it, boxing
|
|
218
|
+
the highlighted name rather than letting it touch the rule, the way
|
|
219
|
+
the classic rename box did. The border and well are a wrapper rather
|
|
220
|
+
than the input's own border and padding, because the selection behind
|
|
221
|
+
a highlighted name paints at the face's full 16px em and is clipped
|
|
222
|
+
only at the input's own edge — on one element the em-tall selection
|
|
223
|
+
floods the padding and lands on the border. Splitting them sizes the
|
|
224
|
+
input to the plate's line box, which clips the selection to the same
|
|
225
|
+
12px the plate stands, and keeps the well white outside it.
|
|
226
|
+
Out by the border sideways, and by border-plus-well top and bottom:
|
|
227
|
+
border + well comes to 1px in from the caption horizontally against
|
|
228
|
+
the plate's 1px padding, and 2px in vertically against the 2px it
|
|
229
|
+
was pushed out by, so the run sits exactly where the plate put it
|
|
230
|
+
and nothing shifts when the field opens. */
|
|
231
|
+
.rename-box {
|
|
232
|
+
position: absolute;
|
|
233
|
+
inset: calc(var(--vf-scale, 1) * -2px) calc(var(--vf-scale, 1) * -1px);
|
|
234
|
+
background: var(--vf-white, #fff);
|
|
235
|
+
border: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
|
|
236
|
+
padding: calc(var(--vf-scale, 1) * 1px);
|
|
237
|
+
}
|
|
238
|
+
.rename {
|
|
239
|
+
display: block;
|
|
240
|
+
width: 100%;
|
|
241
|
+
/* The plate's own line box, stated as height too: the input clips its
|
|
242
|
+
selection paint at this edge, which is the whole reason it has no
|
|
243
|
+
border of its own (see .rename-box). */
|
|
244
|
+
height: calc(var(--vf-scale, 1) * var(--vf-icon-label-height, 12px));
|
|
245
|
+
${c}
|
|
246
|
+
font-weight: var(--vf-font-weight, 700);
|
|
247
|
+
line-height: calc(
|
|
248
|
+
var(--vf-scale, 1) * var(--vf-icon-label-height, 12px)
|
|
249
|
+
);
|
|
250
|
+
/* Hand-rolled rather than composed from vfField: that recipe sets the
|
|
251
|
+
Chicago display face, and pulling it in would ship the whole chrome
|
|
252
|
+
WOFF2 with an element that otherwise sets only body type (see the
|
|
253
|
+
note at the top of styles/base.ts). The Finder renamed in the same
|
|
254
|
+
face it labelled in, so this is the faithful reading too. */
|
|
255
|
+
background: none;
|
|
256
|
+
color: var(--vf-black, #000);
|
|
257
|
+
border: none;
|
|
258
|
+
border-radius: 0;
|
|
259
|
+
padding: 0;
|
|
260
|
+
margin: 0;
|
|
261
|
+
/* Left, matching the plate it overlays: same text x, so the name does
|
|
262
|
+
not shift by half a pixel the moment you start typing — and the
|
|
263
|
+
field's own run stays on the grid for the same reason the plate's
|
|
264
|
+
does. */
|
|
265
|
+
text-align: left;
|
|
266
|
+
user-select: text;
|
|
267
|
+
-webkit-user-select: text;
|
|
268
|
+
outline: none;
|
|
269
|
+
-webkit-appearance: none;
|
|
270
|
+
appearance: none;
|
|
271
|
+
}
|
|
272
|
+
.rename::selection {
|
|
273
|
+
background-color: var(--vf-highlight, #000);
|
|
274
|
+
color: var(--vf-highlight-text, #fff);
|
|
275
|
+
}
|
|
276
|
+
/* Keyboard focus is the kit's dashed rule below the plate, not a ring
|
|
277
|
+
around the icon (see vfFocusUnderline). Below rather than inside it:
|
|
278
|
+
every pixel of the plate is either the name or the fill inverting
|
|
279
|
+
behind it, so there is no interior to lend — the vf-select placement,
|
|
280
|
+
for the same reason. -2px puts it in the second row under a box whose
|
|
281
|
+
ink runs to its own edge. Drawn in currentColor, so it turns white
|
|
282
|
+
along with the name on a selected plate.
|
|
283
|
+
Gated on a class, not :focus-visible: the host takes focus from its own
|
|
284
|
+
pointerdown so a press-drag can own the pointer, and Blink reads that
|
|
285
|
+
as a visible focus (see focus-modality.ts). */
|
|
286
|
+
.caption.focus-rule .label::after {
|
|
287
|
+
--vf-focus-underline-offset: -2px;
|
|
288
|
+
${u}
|
|
289
|
+
}
|
|
290
|
+
/* No name, no plate — the rule falls back to the art cell. */
|
|
291
|
+
.art.focus-rule::after {
|
|
292
|
+
--vf-focus-underline-offset: -2px;
|
|
293
|
+
${u}
|
|
294
|
+
}
|
|
295
|
+
:host(:focus) {
|
|
296
|
+
outline: none;
|
|
297
|
+
}
|
|
298
|
+
`];
|
|
299
|
+
}
|
|
300
|
+
#e;
|
|
301
|
+
#t;
|
|
302
|
+
#n;
|
|
303
|
+
get #r() {
|
|
304
|
+
return this.closest("[role=\"listbox\"]") !== null;
|
|
305
|
+
}
|
|
306
|
+
#i;
|
|
307
|
+
#a;
|
|
308
|
+
#o;
|
|
309
|
+
#s;
|
|
310
|
+
#c;
|
|
311
|
+
#l;
|
|
312
|
+
#u;
|
|
313
|
+
#d;
|
|
314
|
+
#f;
|
|
315
|
+
connectedCallback() {
|
|
316
|
+
super.connectedCallback(), this.#E(), this.#C(), this.addEventListener("keydown", this.#F);
|
|
317
|
+
}
|
|
318
|
+
disconnectedCallback() {
|
|
319
|
+
super.disconnectedCallback(), this.removeEventListener("keydown", this.#F), this.#S();
|
|
320
|
+
}
|
|
321
|
+
updated(e) {
|
|
322
|
+
if (e.has("selectable") && this.#E(), (e.has("selectable") || e.has("selected") || e.has("label")) && this.#C(), (e.has("selected") || e.has("selectable")) && (this.selectable && this.selected ? this.#c.attach() : this.#c.detach()), e.has("_editing") && this._editing) {
|
|
323
|
+
let e = this.renderRoot.querySelector("input");
|
|
324
|
+
e?.focus(), e?.select();
|
|
325
|
+
}
|
|
326
|
+
(e.has("label") || e.has("_draft") || e.has("_editing")) && this.#h(), (e.has("open") || e.has("size")) && this.#y();
|
|
327
|
+
}
|
|
328
|
+
#p;
|
|
329
|
+
#m() {
|
|
330
|
+
this.#p ||= s(this, `vf-icon${this.label ? ` ("${this.label}")` : ""}`, "<vf-icon movable label=\"Read Me\" width=\"64\" top=\"16\" left=\"16\">");
|
|
331
|
+
}
|
|
332
|
+
firstUpdated() {
|
|
333
|
+
document.fonts.ready.then(() => this.#h());
|
|
334
|
+
}
|
|
335
|
+
#h() {
|
|
336
|
+
let e = this.renderRoot?.querySelector(".name");
|
|
337
|
+
if (!e) {
|
|
338
|
+
this.#e = 0;
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
let t = 0;
|
|
342
|
+
if (e.firstChild) {
|
|
343
|
+
let n = document.createRange();
|
|
344
|
+
n.selectNodeContents(e), t = n.getBoundingClientRect().width, n.detach();
|
|
345
|
+
}
|
|
346
|
+
let r = t / n(this) + 2, i = Math.max(2, Math.ceil(r / 2) * 2);
|
|
347
|
+
this.#e = this._editing && t === 0 ? Math.max(i, C[this.size]) : i, e.style.width = this.#g;
|
|
348
|
+
}
|
|
349
|
+
get #g() {
|
|
350
|
+
return this.#e ? `calc(var(--vf-scale, 1) * ${this.#e}px)` : "";
|
|
351
|
+
}
|
|
352
|
+
#_;
|
|
353
|
+
#v;
|
|
354
|
+
#y() {
|
|
355
|
+
let e = this.renderRoot?.querySelector(`slot[name='${this.size}']`), t = null;
|
|
356
|
+
for (let n of e?.assignedElements({ flatten: !0 }) ?? []) {
|
|
357
|
+
let e = n instanceof HTMLImageElement || n instanceof HTMLCanvasElement ? n : n.querySelector("img, canvas");
|
|
358
|
+
if (e instanceof HTMLImageElement || e instanceof HTMLCanvasElement) {
|
|
359
|
+
t = e;
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
t !== this.#t && (this.#t?.removeEventListener("load", this.#v), this.#t?.removeEventListener("error", this.#v), this.#t = t, t?.addEventListener("load", this.#v), t?.addEventListener("error", this.#v)), this.#b();
|
|
364
|
+
}
|
|
365
|
+
#b() {
|
|
366
|
+
let e = this.#t, t = e instanceof HTMLImageElement ? e.complete && e.naturalWidth > 0 : e != null && e.width > 0;
|
|
367
|
+
if (!this.open || e == null || !t) {
|
|
368
|
+
this._ghost = null, this.#i = "";
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
let n = e instanceof HTMLImageElement ? `${this.size} ${e.currentSrc}` : "";
|
|
372
|
+
if (n !== "" && n === this.#i && this._ghost) return;
|
|
373
|
+
let r = g(e);
|
|
374
|
+
if (r) {
|
|
375
|
+
r.className = "ghost", r.style.width = `calc(var(--vf-scale, 1) * ${r.width}px)`, r.style.height = `calc(var(--vf-scale, 1) * ${r.height}px)`;
|
|
376
|
+
let t = e instanceof HTMLImageElement ? e.alt : "";
|
|
377
|
+
t && (r.setAttribute("role", "img"), r.setAttribute("aria-label", t));
|
|
378
|
+
}
|
|
379
|
+
this._ghost = r, this.#i = r ? n : "";
|
|
380
|
+
}
|
|
381
|
+
#x() {
|
|
382
|
+
this.#S(), this.#o = window.setTimeout(() => {
|
|
383
|
+
this.#o = 0, this.startEditing();
|
|
384
|
+
}, 800);
|
|
385
|
+
}
|
|
386
|
+
#S() {
|
|
387
|
+
this.#o &&= (clearTimeout(this.#o), 0);
|
|
388
|
+
}
|
|
389
|
+
startEditing() {
|
|
390
|
+
this.#S(), !(!this.editable || this._editing) && (this.#a = this.label, this._draft = this.label, this._editing = !0);
|
|
391
|
+
}
|
|
392
|
+
commitEditing() {
|
|
393
|
+
if (!this._editing) return;
|
|
394
|
+
this._editing = !1;
|
|
395
|
+
let e = this.#a, t = this._draft;
|
|
396
|
+
if (t.trim() === "") {
|
|
397
|
+
this._draft = e, t !== e && m(this, "vf-name-rejected", {
|
|
398
|
+
attempted: t,
|
|
399
|
+
kept: e,
|
|
400
|
+
reason: "empty"
|
|
401
|
+
});
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
t !== e && (this.label = t, m(this, "vf-change", {
|
|
405
|
+
label: t,
|
|
406
|
+
previous: e
|
|
407
|
+
}));
|
|
408
|
+
}
|
|
409
|
+
cancelEditing() {
|
|
410
|
+
this._editing && (this._editing = !1, this._draft = this.#a);
|
|
411
|
+
}
|
|
412
|
+
render() {
|
|
413
|
+
let e = this._editing, t = e ? this._draft : this.label, n = this.focusRule.marked && !e, r = t !== "" || e, i = `caption${e ? " editing" : ""}${n && t ? " focus-rule" : ""}`, a = `art${this.open && this._ghost ? " open" : ""}${n && !t ? " focus-rule" : ""}`, o = this.width ? `width: calc(var(--vf-scale, 1) * ${this.width}px)` : "";
|
|
414
|
+
return y`<div
|
|
415
|
+
class="frame vf-snap"
|
|
416
|
+
part="frame"
|
|
417
|
+
style=${o}
|
|
418
|
+
@pointerdown=${this.#O}
|
|
419
|
+
@pointermove=${this.#f.onPointerMove}
|
|
420
|
+
@pointerup=${this.#f.onPointerUp}
|
|
421
|
+
@pointercancel=${this.#f.onPointerUp}
|
|
422
|
+
@dblclick=${this.#k}
|
|
423
|
+
>
|
|
424
|
+
<div class=${a} part="icon">
|
|
425
|
+
${this.size === "small" ? y`<slot name="small" @slotchange=${this.#_}></slot>` : y`<slot name="large" @slotchange=${this.#_}></slot>`}${this._ghost ?? b}
|
|
426
|
+
</div>
|
|
427
|
+
${r ? y`<div class=${i}>
|
|
428
|
+
<!-- No whitespace around the span: it is the measured run, and a
|
|
429
|
+
stray space would widen it. -->
|
|
430
|
+
<div class="label" part="label"><span
|
|
431
|
+
class="name"
|
|
432
|
+
part="plate"
|
|
433
|
+
style=${this.#e ? `width: ${this.#g}` : ""}
|
|
434
|
+
>${t}</span
|
|
435
|
+
></div>
|
|
436
|
+
${e ? y`<div class="rename-box">
|
|
437
|
+
<input
|
|
438
|
+
class="rename"
|
|
439
|
+
part="input"
|
|
440
|
+
type="text"
|
|
441
|
+
maxlength=${this.maxlength}
|
|
442
|
+
.value=${this._draft}
|
|
443
|
+
@beforeinput=${this.#j}
|
|
444
|
+
@input=${this.#M}
|
|
445
|
+
@keydown=${this.#P}
|
|
446
|
+
@blur=${this.commitEditing}
|
|
447
|
+
/>
|
|
448
|
+
</div>` : b}
|
|
449
|
+
</div>` : b}
|
|
450
|
+
</div>`;
|
|
451
|
+
}
|
|
452
|
+
#C() {
|
|
453
|
+
if (!this.selectable) {
|
|
454
|
+
this.#n.role = null, this.#n.ariaSelected = null, this.#n.ariaLabel = null;
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (this.#r) {
|
|
458
|
+
this.#n.role = "option", this.#n.ariaSelected = this.selected ? "true" : "false", this.#n.ariaLabel = null;
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
this.#n.role = "img", this.#n.ariaSelected = null, this.#n.ariaLabel = this.label || this.#w || null;
|
|
462
|
+
}
|
|
463
|
+
get #w() {
|
|
464
|
+
return this.#t instanceof HTMLImageElement ? this.#t.alt : "";
|
|
465
|
+
}
|
|
466
|
+
get #T() {
|
|
467
|
+
return this.selectable;
|
|
468
|
+
}
|
|
469
|
+
#E() {
|
|
470
|
+
this.hasAttribute("tabindex") || (this.#T ? this.tabIndex = 0 : this.removeAttribute("tabindex"));
|
|
471
|
+
}
|
|
472
|
+
#D(e) {
|
|
473
|
+
e !== this.selected && (this.selected = e, m(this, "vf-select", { selected: e }));
|
|
474
|
+
}
|
|
475
|
+
#O;
|
|
476
|
+
#k;
|
|
477
|
+
#A;
|
|
478
|
+
#j;
|
|
479
|
+
#M;
|
|
480
|
+
#N(e) {
|
|
481
|
+
m(this, "vf-name-too-long", {
|
|
482
|
+
attempted: e,
|
|
483
|
+
accepted: e.slice(0, this.maxlength),
|
|
484
|
+
limit: this.maxlength
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
#P;
|
|
488
|
+
#F;
|
|
489
|
+
};
|
|
490
|
+
i([x()], D.prototype, "label", void 0), i([x({ reflect: !0 })], D.prototype, "size", void 0), i([x({
|
|
491
|
+
type: Boolean,
|
|
492
|
+
reflect: !0
|
|
493
|
+
})], D.prototype, "selectable", void 0), i([x({
|
|
494
|
+
type: Boolean,
|
|
495
|
+
reflect: !0
|
|
496
|
+
})], D.prototype, "selected", void 0), i([x({
|
|
497
|
+
type: Boolean,
|
|
498
|
+
reflect: !0
|
|
499
|
+
})], D.prototype, "open", void 0), i([x({
|
|
500
|
+
type: Boolean,
|
|
501
|
+
reflect: !0
|
|
502
|
+
})], D.prototype, "movable", void 0), i([x({
|
|
503
|
+
type: Boolean,
|
|
504
|
+
reflect: !0
|
|
505
|
+
})], D.prototype, "editable", void 0), i([x({ type: Number })], D.prototype, "width", void 0), i([x({ type: Number })], D.prototype, "maxlength", void 0), i([S()], D.prototype, "_editing", void 0), i([S()], D.prototype, "_draft", void 0), i([S()], D.prototype, "_ghost", void 0), D = i([e("vf-icon")], D);
|
|
506
|
+
//#endregion
|
|
507
|
+
export { D as VfIcon };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
declare const VfImg_base: (new (...args: any[]) => import("../position.js").VfPositionedInterface) & typeof LitElement;
|
|
3
|
+
/**
|
|
4
|
+
* `<vf-img>` — a raster image on the kit's pixel grid.
|
|
5
|
+
*
|
|
6
|
+
* The reference art is full of small pixel graphics that are *pictures*, not
|
|
7
|
+
* glyphs: the Apple menu's logo, desk-accessory and document icons, the
|
|
8
|
+
* about-box machine portrait. This component displays one — a slotted native
|
|
9
|
+
* `<img>` — at the kit's own magnification, treating **one image pixel as one
|
|
10
|
+
* system pixel**:
|
|
11
|
+
*
|
|
12
|
+
* - the image is sized to `naturalWidth × naturalHeight` system px, multiplied
|
|
13
|
+
* by `--vf-scale` in `calc()` like every other metric, so a source pixel
|
|
14
|
+
* covers exactly `scale × dpr` device pixels (a whole number, per layout
|
|
15
|
+
* contract rule 1);
|
|
16
|
+
* - `image-rendering: pixelated` keeps the resampling nearest-neighbor, and on
|
|
17
|
+
* a whole-device-pixel box that is bit-exact magnification — no smoothing,
|
|
18
|
+
* no half-covered edge rows;
|
|
19
|
+
* - its own {@link GridSnapController}, so the image's origin holds the device
|
|
20
|
+
* grid wherever the page puts it (a fractional origin would slide the whole
|
|
21
|
+
* box across device pixels and shear every source pixel's coverage).
|
|
22
|
+
*
|
|
23
|
+
* The graphic stays a real `<img>` in the consumer's light DOM — it keeps
|
|
24
|
+
* native loading, `alt` text (use `alt=""` for a decorative icon) and the
|
|
25
|
+
* consumer's own asset URLs; the kit ships no raster files. `width`/`height`
|
|
26
|
+
* (in system px, whole numbers) state the box up front so the page doesn't
|
|
27
|
+
* shift when the file lands — until a size is known the box is 0×0, never a
|
|
28
|
+
* flash of the image at some other scale. They also override the natural size
|
|
29
|
+
* deliberately: a whole multiple (`width="32"` on 16-px art) magnifies on the
|
|
30
|
+
* same grid.
|
|
31
|
+
*
|
|
32
|
+
* @slot - The image: a single `<img>` element.
|
|
33
|
+
* @csspart frame - The sized box the image fills.
|
|
34
|
+
*/
|
|
35
|
+
export declare class VfImg extends VfImg_base {
|
|
36
|
+
#private;
|
|
37
|
+
static styles: import("lit").CSSResult[];
|
|
38
|
+
/** Default-on display scaling (true 72dpi size); see src/scale.ts. */
|
|
39
|
+
private readonly scale;
|
|
40
|
+
/** Device-pixel grid snapping (opt in with applyGridSnap()); see src/grid-snap.ts. */
|
|
41
|
+
private readonly gridSnap;
|
|
42
|
+
/**
|
|
43
|
+
* The displayed width in system px — a whole number. Defaults to the slotted
|
|
44
|
+
* image's `naturalWidth` (one image px = one system px); state it explicitly
|
|
45
|
+
* to reserve the box before the file loads, or a whole multiple to magnify.
|
|
46
|
+
*/
|
|
47
|
+
width?: number;
|
|
48
|
+
/** The displayed height in system px; see {@link width}. */
|
|
49
|
+
height?: number;
|
|
50
|
+
/** The slotted image's intrinsic size, 0 until it has one. */
|
|
51
|
+
private _naturalWidth;
|
|
52
|
+
private _naturalHeight;
|
|
53
|
+
/** True when the slotted image has settled with no natural size (a failed
|
|
54
|
+
* load); see {@link #measure}. */
|
|
55
|
+
private _failed;
|
|
56
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
57
|
+
}
|
|
58
|
+
declare global {
|
|
59
|
+
interface HTMLElementTagNameMap {
|
|
60
|
+
'vf-img': VfImg;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
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 { GridSnapController as a } from "../grid-snap.js";
|
|
7
|
+
import { LitElement as o, css as s, html as c, nothing as l } from "lit";
|
|
8
|
+
import { property as u, state as d } from "lit/decorators.js";
|
|
9
|
+
//#region src/components/vf-img.ts
|
|
10
|
+
var f = class extends r(o) {
|
|
11
|
+
constructor(...e) {
|
|
12
|
+
super(...e), this.scale = new t(this), this.gridSnap = new a(this), this._naturalWidth = 0, this._naturalHeight = 0, this._failed = !1, this.#e = null, this.#t = (e) => {
|
|
13
|
+
let t = e.target.assignedElements({ flatten: !0 }).find((e) => e instanceof HTMLImageElement) ?? null;
|
|
14
|
+
t !== this.#e && (this.#e?.removeEventListener("load", this.#n), this.#e?.removeEventListener("error", this.#n), this.#e = t, t?.addEventListener("load", this.#n), t?.addEventListener("error", this.#n)), this.#r();
|
|
15
|
+
}, this.#n = () => {
|
|
16
|
+
this.#r();
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
static {
|
|
20
|
+
this.styles = [i, s`
|
|
21
|
+
:host {
|
|
22
|
+
display: inline-block;
|
|
23
|
+
}
|
|
24
|
+
.frame {
|
|
25
|
+
display: block;
|
|
26
|
+
}
|
|
27
|
+
::slotted(img) {
|
|
28
|
+
display: block;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
/* Nearest-neighbor: the whole point. The box is whole device px, so
|
|
32
|
+
magnification is bit-exact and no edge row is half-covered. */
|
|
33
|
+
image-rendering: pixelated;
|
|
34
|
+
/* Chrome, not content: System 7 icons don't drag out of the UI. */
|
|
35
|
+
-webkit-user-drag: none;
|
|
36
|
+
}
|
|
37
|
+
/* A failed, undeclared image (see render()): released from the stretch
|
|
38
|
+
so the browser renders it as a native broken <img> — alt text at its
|
|
39
|
+
own size — instead of scaling it into a 0×0 frame. */
|
|
40
|
+
.frame.failed ::slotted(img) {
|
|
41
|
+
width: auto;
|
|
42
|
+
height: auto;
|
|
43
|
+
}
|
|
44
|
+
`];
|
|
45
|
+
}
|
|
46
|
+
#e;
|
|
47
|
+
render() {
|
|
48
|
+
let e = this.width ?? this._naturalWidth, t = this.height ?? this._naturalHeight, n = this._failed && this.width == null && this.height == null;
|
|
49
|
+
return c`<span
|
|
50
|
+
class="frame vf-snap ${n ? "failed" : ""}"
|
|
51
|
+
part="frame"
|
|
52
|
+
style=${n ? l : `width: calc(var(--vf-scale, 1) * ${e}px); height: calc(var(--vf-scale, 1) * ${t}px)`}
|
|
53
|
+
><slot @slotchange=${this.#t}></slot
|
|
54
|
+
></span>`;
|
|
55
|
+
}
|
|
56
|
+
#t;
|
|
57
|
+
#n;
|
|
58
|
+
#r() {
|
|
59
|
+
let e = this.#e;
|
|
60
|
+
this._naturalWidth = e?.naturalWidth ?? 0, this._naturalHeight = e?.naturalHeight ?? 0, this._failed = e != null && e.complete && e.naturalWidth === 0 && e.src !== "";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
n([u({ type: Number })], f.prototype, "width", void 0), n([u({ type: Number })], f.prototype, "height", void 0), n([d()], f.prototype, "_naturalWidth", void 0), n([d()], f.prototype, "_naturalHeight", void 0), n([d()], f.prototype, "_failed", void 0), f = n([e("vf-img")], f);
|
|
64
|
+
//#endregion
|
|
65
|
+
export { f as VfImg };
|