vintage-frames 0.12.8 → 0.14.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 +26 -26
- package/dist/chrome.d.ts +1 -1
- package/dist/components/vf-checkbox.d.ts +6 -5
- package/dist/components/vf-checkbox.js +41 -37
- package/dist/components/vf-container.d.ts +16 -20
- package/dist/components/vf-container.js +25 -17
- package/dist/components/vf-desktop.d.ts +4 -5
- package/dist/components/vf-desktop.js +13 -18
- package/dist/components/vf-fieldset.js +30 -22
- package/dist/components/vf-icon.js +55 -55
- package/dist/components/vf-list.js +30 -29
- package/dist/components/vf-menu.js +24 -22
- package/dist/components/vf-number-field.js +32 -30
- package/dist/components/vf-progress-bar.d.ts +2 -2
- package/dist/components/vf-progress-bar.js +65 -52
- package/dist/components/vf-radio.js +3 -4
- package/dist/components/vf-scroll-area.js +27 -26
- package/dist/components/vf-select.js +108 -90
- package/dist/components/vf-separator.d.ts +5 -5
- package/dist/components/vf-separator.js +36 -10
- package/dist/components/vf-slider.js +11 -11
- package/dist/components/vf-swatch.d.ts +2 -2
- package/dist/components/vf-swatch.js +73 -72
- package/dist/components/vf-text-area.js +37 -35
- package/dist/components/vf-text-field.js +20 -18
- package/dist/components/vf-window.d.ts +6 -9
- package/dist/components/vf-window.js +106 -87
- package/dist/index.d.ts +20 -10
- package/dist/index.js +63 -62
- package/dist/pattern-fill.d.ts +21 -50
- package/dist/pattern-fill.js +19 -54
- package/dist/scroll-rail.d.ts +6 -6
- package/dist/scroll-rail.js +24 -29
- package/dist/styles/base.d.ts +3 -1
- package/dist/styles/recipes/field.d.ts +10 -6
- package/dist/styles/recipes/field.js +8 -7
- package/dist/styles/recipes/focus.d.ts +7 -3
- package/dist/styles/recipes/pattern.d.ts +19 -10
- package/dist/styles/recipes/pattern.js +27 -18
- package/dist/styles/recipes/rule.d.ts +11 -8
- package/dist/styles/recipes/rule.js +31 -13
- package/dist/styles/recipes/scroll-rail.d.ts +21 -13
- package/dist/styles/recipes/scroll-rail.js +27 -37
- package/dist/styles/recipes/shadow.d.ts +10 -6
- package/dist/styles/recipes/shadow.js +4 -2
- package/dist/styles/recipes/stroke.d.ts +85 -0
- package/dist/styles/recipes/stroke.js +53 -0
- package/dist/styles/recipes/surface.d.ts +8 -4
- package/dist/styles/recipes/surface.js +23 -17
- package/dist/styles/recipes/tile.d.ts +11 -3
- package/dist/styles/recipes/tile.js +12 -12
- package/dist/styles/recipes/title-bar.d.ts +7 -0
- package/dist/styles/recipes/title-bar.js +25 -22
- package/dist/styles/recipes/toggle.js +3 -3
- package/dist/tile-grid.d.ts +98 -64
- package/dist/tile-grid.js +63 -30
- package/dist/track-width.d.ts +1 -2
- package/dist/zoom.d.ts +9 -9
- package/docs/SPEC.md +33 -32
- package/editor/vscode.html-custom-data.json +5 -5
- package/editor/web-types.json +8 -8
- package/package.json +1 -1
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { vfDisplayDecls as e } from "./display-face.js";
|
|
2
|
-
import {
|
|
2
|
+
import { vfStrokeDecls as t, vfStrokeInset as n } from "./stroke.js";
|
|
3
|
+
import { css as r } from "lit";
|
|
3
4
|
//#region src/styles/recipes/title-bar.ts
|
|
4
|
-
var
|
|
5
|
+
var i = r`
|
|
5
6
|
.vf-title-bar {
|
|
6
7
|
position: relative;
|
|
7
8
|
/* Inert unless the frame is a flex column (vf-window); on vf-dialog's plain
|
|
8
9
|
block frame the shorthand simply doesn't apply. */
|
|
9
10
|
flex: none;
|
|
10
11
|
height: calc(var(--vf-scale, 1) * var(--vf-titlebar-height, 18px));
|
|
11
|
-
border-bottom: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
|
|
12
12
|
display: flex;
|
|
13
13
|
/* flex-start, not center: the title states its own whole-pixel row (see
|
|
14
14
|
the margin below); centering 16 into 17 would land it on a half. */
|
|
15
15
|
align-items: flex-start;
|
|
16
16
|
justify-content: center;
|
|
17
17
|
overflow: hidden;
|
|
18
|
+
${t({ edges: ["bottom"] })}
|
|
19
|
+
}
|
|
20
|
+
.vf-title-bar > .vf-stripes {
|
|
21
|
+
bottom: ${n(3)};
|
|
22
|
+
}
|
|
23
|
+
.vf-title-bar > .vf-dots {
|
|
24
|
+
bottom: ${n(2)};
|
|
18
25
|
}
|
|
19
26
|
.vf-title {
|
|
20
27
|
/* Chicago-style title (chrome); slotted body copy keeps the body face. */
|
|
@@ -36,7 +43,7 @@ var n = t`
|
|
|
36
43
|
overflow: hidden;
|
|
37
44
|
text-overflow: ellipsis;
|
|
38
45
|
}
|
|
39
|
-
`,
|
|
46
|
+
`, a = r`
|
|
40
47
|
.box {
|
|
41
48
|
position: absolute;
|
|
42
49
|
/* 11×11 box with 3px of clear white above and below it (title-bar
|
|
@@ -45,21 +52,18 @@ var n = t`
|
|
|
45
52
|
z-index: 1;
|
|
46
53
|
width: calc(var(--vf-scale, 1) * 11px);
|
|
47
54
|
height: calc(var(--vf-scale, 1) * 11px);
|
|
48
|
-
padding: 0;
|
|
49
55
|
margin: 0;
|
|
50
|
-
border: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000000);
|
|
51
56
|
background: var(--vf-white, #ffffff);
|
|
52
|
-
/* A 1px white patch ring that interrupts the stripes around the
|
|
53
|
-
box (no bevel — flat 1-bit), same buffer the stripes keep from the
|
|
54
|
-
frame edges. --vf-widget-ring is internal geometry, not a theming
|
|
55
|
-
knob: vf-window's utility variant widens it to 2px, the clearance
|
|
56
|
-
the windoid sheet cuts into its dither. */
|
|
57
|
-
box-shadow: 0 0 0 calc(var(--vf-scale, 1) * var(--vf-widget-ring, 1px))
|
|
58
|
-
var(--vf-white, #ffffff);
|
|
59
57
|
font: inherit;
|
|
60
58
|
cursor: var(--vf-cursor, default);
|
|
61
59
|
-webkit-appearance: none;
|
|
62
60
|
appearance: none;
|
|
61
|
+
/* After the stroke, a 1px white patch ring that interrupts the stripes
|
|
62
|
+
around the box (no bevel — flat 1-bit), same buffer the stripes keep
|
|
63
|
+
from the frame edges. --vf-widget-ring is internal geometry, not a
|
|
64
|
+
theming knob: vf-window's utility variant widens it to 2px, the
|
|
65
|
+
clearance the windoid sheet cuts into its dither. */
|
|
66
|
+
${t({ shadows: "0 0 0 calc(var(--vf-scale, 1) * var(--vf-widget-ring, 1px)) var(--vf-white, #ffffff)" })}
|
|
63
67
|
}
|
|
64
68
|
.close {
|
|
65
69
|
left: calc(var(--vf-scale, 1) * 8px);
|
|
@@ -73,7 +77,7 @@ var n = t`
|
|
|
73
77
|
traced pixel-for-pixel from the UI kit's close-button-active-state
|
|
74
78
|
sprite. Both widgets flash the identical graphic while pressed. That
|
|
75
79
|
sprite is the whole 11×11 box; its outer ring is this element's own 1px
|
|
76
|
-
|
|
80
|
+
stroke, so the SVG draws just the 9×9 interior, centered in the box. */
|
|
77
81
|
.box:active {
|
|
78
82
|
background-color: var(--vf-white, #ffffff);
|
|
79
83
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='9'%3E%3Cpath d='M4 0h1v1h-1zM1 1h1v1h-1zM4 1h1v1h-1zM7 1h1v1h-1zM2 2h1v1h-1zM4 2h1v1h-1zM6 2h1v1h-1zM0 4h3v1h-3zM6 4h3v1h-3zM2 6h1v1h-1zM4 6h1v1h-1zM6 6h1v1h-1zM1 7h1v1h-1zM4 7h1v1h-1zM7 7h1v1h-1zM4 8h1v1h-1z'/%3E%3C/svg%3E");
|
|
@@ -85,17 +89,16 @@ var n = t`
|
|
|
85
89
|
content: '';
|
|
86
90
|
position: absolute;
|
|
87
91
|
/* A small box nested in the TOP-LEFT corner of the widget (classic
|
|
88
|
-
System 7 zoom box). It shares the widget's own top and left
|
|
89
|
-
only its right and bottom edges are drawn: a 6×6 box anchored
|
|
90
|
-
|
|
92
|
+
System 7 zoom box). It shares the widget's own top and left line, so
|
|
93
|
+
only its right and bottom edges are drawn: a 6×6 box anchored inside
|
|
94
|
+
the widget's stroke whose 1px right/bottom strokes land the vertical at
|
|
91
95
|
sprite col 6 and the horizontal at row 6. Traced from the UI kit
|
|
92
96
|
zoom-button rest sprite. */
|
|
93
|
-
top: 0;
|
|
94
|
-
left: 0;
|
|
97
|
+
top: ${n(0)};
|
|
98
|
+
left: ${n(0)};
|
|
95
99
|
width: calc(var(--vf-scale, 1) * 6px);
|
|
96
100
|
height: calc(var(--vf-scale, 1) * 6px);
|
|
97
|
-
|
|
98
|
-
border-bottom: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000000);
|
|
101
|
+
${t({ edges: ["right", "bottom"] })}
|
|
99
102
|
}
|
|
100
103
|
/* While pressed the zoom box shows the same sunburst as the close box, so
|
|
101
104
|
its inner detail square gives way to it. */
|
|
@@ -131,4 +134,4 @@ var n = t`
|
|
|
131
134
|
}
|
|
132
135
|
`;
|
|
133
136
|
//#endregion
|
|
134
|
-
export {
|
|
137
|
+
export { i as vfTitleBar, a as vfWindowWidgets };
|
|
@@ -7,7 +7,7 @@ var t = e`
|
|
|
7
7
|
gap: calc(var(--vf-scale, 1) * 6px);
|
|
8
8
|
cursor: var(--vf-cursor, default);
|
|
9
9
|
}
|
|
10
|
-
/* The well PAINTS 3 system px below the row top. Centering
|
|
10
|
+
/* The radio's 13px well PAINTS 3 system px below the row top. Centering it
|
|
11
11
|
in the 20px row is the layout — kept, because the host's height and its
|
|
12
12
|
exported baseline are consumer-visible (moving them off the well's
|
|
13
13
|
centered bottom reflowed every line holding a toggle) — but centering
|
|
@@ -18,8 +18,8 @@ var t = e`
|
|
|
18
18
|
compose the variable), landing the ink on row 3: ties resolve toward the
|
|
19
19
|
start, as QuickDraw's "div 2" did — the title-bar and vf-stack
|
|
20
20
|
convention. The half-pixel gap between layout box and painted box is the
|
|
21
|
-
documented snap idiom, not a fault.
|
|
22
|
-
|
|
21
|
+
documented snap idiom, not a fault. The checkbox's 12px box centers on
|
|
22
|
+
row 4 exactly and needs no step; both wells end on row 15. */
|
|
23
23
|
.circle {
|
|
24
24
|
top: calc(var(--vf-snap-dy, 0px) - var(--vf-scale, 1) * 0.5px);
|
|
25
25
|
}
|
package/dist/tile-grid.d.ts
CHANGED
|
@@ -1,51 +1,39 @@
|
|
|
1
|
-
import { type CSSResult, type TemplateResult } from 'lit';
|
|
1
|
+
import { type CSSResult, type ReactiveController, type ReactiveControllerHost, type TemplateResult } from 'lit';
|
|
2
2
|
import { type TileRect } from './styles/recipes/tile.js';
|
|
3
3
|
/**
|
|
4
|
-
* The tiled-fill machinery
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The tiled-fill machinery behind the kit's patterned surfaces — the desktop
|
|
5
|
+
* and container patterns, the windoid dots, the swatch checker, the barber
|
|
6
|
+
* stripes and the scroll trough.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
8
|
+
* **Kit art is a CSS repeat of one pre-scaled tile** ({@link repeatTile}):
|
|
9
|
+
* the motif laid over {@link REPEAT_TILE} system px square and drawn at n
|
|
10
|
+
* image px per system px, n = `--vf-scale × trueDpr` — whole by the scale
|
|
11
|
+
* contract — so the engine copies the tile to the device grid 1:1 and has no
|
|
12
|
+
* filtering to choose. The surface states the tile's size as
|
|
13
|
+
* {@link vfRepeatTileSize}, a length every engine holds exactly at every
|
|
14
|
+
* density and zoom, so each repeat lands exactly. The tile depends only on
|
|
15
|
+
* the art and n: it is encoded once per pair for the whole page, drawn again
|
|
16
|
+
* when zoom or the display changes n, and never on a resize.
|
|
17
|
+
* {@link RepeatTileController} keeps a box's tile current.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* Why 120, and why pre-scaled (TILE-REPEAT-PLAN.md, in git history at
|
|
20
|
+
* commit 5bc45c2, has the measurements): Safari smooths a repeated image it
|
|
21
|
+
* has to magnify, whatever
|
|
22
|
+
* `image-rendering` says, so the image must already be at device
|
|
23
|
+
* resolution; and WebKit on a 3× display now and then draws one small tile a
|
|
24
|
+
* device px narrow and resamples it, which tiles of 192 device px and up
|
|
25
|
+
* never showed. The repeat replaced one raster the size of the whole surface,
|
|
26
|
+
* re-encoded as it was resized.
|
|
21
27
|
*
|
|
22
|
-
* **
|
|
23
|
-
*
|
|
24
|
-
* as a raster image at one image px per system px (`tileRaster`), stretched
|
|
25
|
-
* `background-size: 100% 100%` under `image-rendering: pixelated`. Exact at
|
|
26
|
-
* every scale, holdable or not, for two measured reasons: nearest-neighbor
|
|
27
|
-
* sampling can only produce source colors, and ONE box has no interior
|
|
28
|
-
* boundaries — Chromium paints an image background to the box's *unsnapped*
|
|
29
|
-
* layout rect with antialiased edges, so any fill assembled from several
|
|
30
|
-
* boxes blends a one-device-px line at every interior seam at a zoom-minted
|
|
31
|
-
* scale, no matter how exactly the boxes were placed. (That measurement is
|
|
32
|
-
* what buried both this plan's original per-tile form and SVG art of any
|
|
33
|
-
* kind: Chromium rasterizes SVG images at the fractional layout size and
|
|
34
|
-
* ignores `image-rendering` for them.) The box's own edge is the one place a
|
|
35
|
-
* partial device pixel remains — the same status every component box already
|
|
36
|
-
* has. The sampling stays exact because the box's stored length errs at most
|
|
37
|
-
* 1/128 CSS px over the WHOLE surface: the relative error shrinks as the
|
|
38
|
-
* surface grows, so the nearest-neighbor grid cannot slip a pixel at any
|
|
39
|
-
* realistic size.
|
|
40
|
-
*
|
|
41
|
-
* **Consumer art (token set): the placed tile grid** — a flat set of
|
|
42
|
-
* absolutely positioned `.vf-tile` boxes, each `T × T` system px at
|
|
28
|
+
* **Consumer art (a pattern token set): the placed tile grid** — a flat set
|
|
29
|
+
* of absolutely positioned `.vf-tile` boxes, each `T × T` system px at
|
|
43
30
|
* `left: calc(var(--vf-scale, 1) * kT px)`: one single-multiplication length
|
|
44
31
|
* per tile, quantized once, so each box paint-snaps onto the device grid
|
|
45
32
|
* independently and the documented tile geometry (`--vf-*-pattern` art on a
|
|
46
|
-
* 30- or 60-system-px tile) renders verbatim.
|
|
47
|
-
*
|
|
48
|
-
*
|
|
33
|
+
* 30- or 60-system-px tile) renders verbatim. A token is any CSS image —
|
|
34
|
+
* SVG included — so it cannot be pre-scaled the way kit art is. Positions
|
|
35
|
+
* never accumulate error; at a scale the layout grid cannot hold, what
|
|
36
|
+
* remains is a hairline per tile boundary, never surface-wide smear. Raster
|
|
49
37
|
* consumer art additionally magnifies nearest-neighbor (the `vf-img` idiom).
|
|
50
38
|
*
|
|
51
39
|
* The trap that must not come back: NEVER lay tiles out with CSS grid,
|
|
@@ -55,22 +43,18 @@ import { type TileRect } from './styles/recipes/tile.js';
|
|
|
55
43
|
* returns. Flat absolute placement with one multiplication per tile is the
|
|
56
44
|
* correctness, not a style choice.
|
|
57
45
|
*
|
|
58
|
-
* Wiring: the *container* — the layer the fill
|
|
46
|
+
* Wiring the grid: the *container* — the layer the fill paints on, or a
|
|
59
47
|
* dedicated child filling it — takes the `vf-tile-grid` class (clip and
|
|
60
48
|
* pointer transparency; it must be positioned, which every kit layer already
|
|
61
|
-
* is).
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* path the component renders a `.vf-tile-raster` child whose
|
|
65
|
-
* `background-image` it writes from `tileRaster(...)`, regenerated only when
|
|
66
|
-
* the declared system-px size changes (density and zoom re-render nothing:
|
|
67
|
-
* the box lengths are live against `--vf-scale`).
|
|
49
|
+
* is). It resolves `--_vf-tile-image` — the pattern-token `var()` each tile
|
|
50
|
+
* stretches over its box, stated once so no data URI is repeated per tile —
|
|
51
|
+
* and {@link tileGrid} renders the tiles.
|
|
68
52
|
*
|
|
69
|
-
* Forced colors keeps each surface's existing
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
53
|
+
* Forced colors keeps each surface's existing branches (flat Canvas desktop,
|
|
54
|
+
* span-masked dots, barber and trough, the swatch's forced-color-adjust) — no
|
|
55
|
+
* mask pipeline rasterizes exactly at a zoom-minted scale (image-rendering
|
|
56
|
+
* does not reach masks), so forced-colors-plus-zoom remains the one accepted
|
|
57
|
+
* residual.
|
|
74
58
|
*/
|
|
75
59
|
export declare const vfTileGrid: CSSResult;
|
|
76
60
|
/**
|
|
@@ -89,9 +73,9 @@ export declare function tileGrid({ cols, rows, tile, }: {
|
|
|
89
73
|
}): TemplateResult[];
|
|
90
74
|
/**
|
|
91
75
|
* The consumer's override of a pattern token, or `''` when the token is unset
|
|
92
|
-
* and the surface should paint its own art — how a
|
|
93
|
-
*
|
|
94
|
-
*
|
|
76
|
+
* and the surface should paint its own art — how a surface picks between its
|
|
77
|
+
* repeating kit tile and its placed tile grid (consumer art at the
|
|
78
|
+
* documented tile geometry).
|
|
95
79
|
*
|
|
96
80
|
* Read with `getComputedStyle` at update time, not observed live: a pattern
|
|
97
81
|
* token swapped at runtime without touching the component wants a nudge (any
|
|
@@ -99,15 +83,65 @@ export declare function tileGrid({ cols, rows, tile, }: {
|
|
|
99
83
|
* contract the component's other measured inputs follow.
|
|
100
84
|
*/
|
|
101
85
|
export declare function patternOverride(el: Element, token: string): string;
|
|
86
|
+
/** A motif as rect data over the cell it tiles at, in system px. */
|
|
87
|
+
export interface TileMotif {
|
|
88
|
+
readonly width: number;
|
|
89
|
+
readonly height: number;
|
|
90
|
+
readonly rects: readonly TileRect[];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The side of a kit repeat tile in system px: a whole number of every motif
|
|
94
|
+
* the kit draws (8 × 15 — the 2-, 4-, 8- and 12-px cells all divide it), and
|
|
95
|
+
* a whole number of layout px in every engine at every density and zoom
|
|
96
|
+
* (120n device px over the engine's ratio: 40n at 3×, 60n at 2×).
|
|
97
|
+
*/
|
|
98
|
+
export declare const REPEAT_TILE = 120;
|
|
99
|
+
/**
|
|
100
|
+
* `background-size` for a {@link repeatTile}: {@link REPEAT_TILE} system px
|
|
101
|
+
* square, live against `--vf-scale`.
|
|
102
|
+
*/
|
|
103
|
+
export declare const vfRepeatTileSize: CSSResult;
|
|
102
104
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
* The motif laid over {@link REPEAT_TILE} system px square and drawn at `n`
|
|
106
|
+
* image px per system px, as a CSS `url()` — the image a
|
|
107
|
+
* {@link vfRepeatTileSize} repeat copies 1:1 at that density. Cached for the
|
|
108
|
+
* page by the motif's content and `n`.
|
|
109
|
+
*/
|
|
110
|
+
export declare function repeatTile(motif: TileMotif, n: number): string;
|
|
111
|
+
/**
|
|
112
|
+
* Device px per system px at `el`: its `--vf-scale` (a consumer override
|
|
113
|
+
* included) times the true device pixel ratio — the `n` a {@link repeatTile}
|
|
114
|
+
* shown there is drawn at.
|
|
115
|
+
*/
|
|
116
|
+
export declare function devicePxAt(el: Element): number;
|
|
117
|
+
/** What a component hands {@link RepeatTileController}. */
|
|
118
|
+
export interface RepeatTileOptions {
|
|
119
|
+
/** The element the tile's custom property is written on. */
|
|
120
|
+
getBox: () => HTMLElement | null | undefined;
|
|
121
|
+
/** The art to tile, or null to write nothing (a consumer token owns the
|
|
122
|
+
* surface, or the component isn't showing it). Return the same object for
|
|
123
|
+
* the same art: an unchanged motif and density cost nothing. */
|
|
124
|
+
getArt: () => TileMotif | null | undefined;
|
|
125
|
+
/** The custom property the surface's `background-image` reads. */
|
|
126
|
+
property: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Keeps a box's {@link repeatTile} current: writes it as a custom property on
|
|
130
|
+
* the box's inline style after each host update, drawn for the density at
|
|
131
|
+
* the box, and again when zoom or the display changes that density
|
|
132
|
+
* ({@link onScaleChange}); removes it the moment there is nothing to paint.
|
|
133
|
+
* A custom-property channel rather than `background-image` itself, so a
|
|
134
|
+
* surface's forced-colors rule can out-cascade it without `!important`.
|
|
135
|
+
*
|
|
136
|
+
* The surface's stylesheet does the rest: `background-image` from the
|
|
137
|
+
* property, {@link vfRepeatTileSize}, `background-repeat: repeat`, and
|
|
138
|
+
* `image-rendering: pixelated` for the frame between a zoom and the new
|
|
139
|
+
* tile.
|
|
109
140
|
*/
|
|
110
|
-
export declare class
|
|
141
|
+
export declare class RepeatTileController implements ReactiveController {
|
|
111
142
|
#private;
|
|
112
|
-
|
|
143
|
+
constructor(host: ReactiveControllerHost, opts: RepeatTileOptions);
|
|
144
|
+
hostConnected(): void;
|
|
145
|
+
hostDisconnected(): void;
|
|
146
|
+
hostUpdated(): void;
|
|
113
147
|
}
|
package/dist/tile-grid.js
CHANGED
|
@@ -1,53 +1,86 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { truePixelRatio as e } from "./zoom.js";
|
|
2
|
+
import { effectiveScale as t, onScaleChange as n, sysLength as r } from "./scale.js";
|
|
3
|
+
import { tileRaster as i } from "./styles/recipes/tile.js";
|
|
4
|
+
import { css as a, html as o } from "lit";
|
|
4
5
|
//#region src/tile-grid.ts
|
|
5
|
-
var
|
|
6
|
+
var s = a`
|
|
6
7
|
.vf-tile-grid {
|
|
7
8
|
/* Clip the overdraw: a fill overdrawn past a box that is not a whole
|
|
8
|
-
number of tiles
|
|
9
|
+
number of tiles crops here. */
|
|
9
10
|
overflow: hidden;
|
|
10
11
|
pointer-events: none;
|
|
11
12
|
}
|
|
12
|
-
.vf-tile
|
|
13
|
-
.vf-tile-raster {
|
|
13
|
+
.vf-tile {
|
|
14
14
|
position: absolute;
|
|
15
15
|
/* The box IS the size — never the image's intrinsic size, and never an
|
|
16
16
|
intra-box repeat: a consumer tile smaller than its box repeating
|
|
17
17
|
inside it would re-import the accumulation this module removes. */
|
|
18
|
+
background-image: var(--_vf-tile-image);
|
|
18
19
|
background-size: 100% 100%;
|
|
19
20
|
background-repeat: no-repeat;
|
|
20
|
-
/*
|
|
21
|
-
|
|
22
|
-
for SVG (which is why kit art is raster; see tileRaster). */
|
|
21
|
+
/* Consumer raster art samples nearest-neighbor — the vf-img idiom. A
|
|
22
|
+
no-op for SVG. */
|
|
23
23
|
image-rendering: pixelated;
|
|
24
24
|
}
|
|
25
|
-
.vf-tile {
|
|
26
|
-
background-image: var(--_vf-tile-image);
|
|
27
|
-
}
|
|
28
|
-
.vf-tile-raster {
|
|
29
|
-
top: 0;
|
|
30
|
-
left: 0;
|
|
31
|
-
}
|
|
32
25
|
`;
|
|
33
|
-
function
|
|
34
|
-
let
|
|
35
|
-
for (let s = 0; s <
|
|
26
|
+
function c({ cols: e, rows: t, tile: n }) {
|
|
27
|
+
let i = r(n), a = [];
|
|
28
|
+
for (let s = 0; s < t; s++) for (let t = 0; t < e; t++) a.push(o`<span
|
|
36
29
|
class="vf-tile"
|
|
37
|
-
style="left:${
|
|
30
|
+
style="left:${r(t * n)};top:${r(s * n)};width:${i};height:${i}"
|
|
38
31
|
></span>`);
|
|
39
|
-
return
|
|
32
|
+
return a;
|
|
40
33
|
}
|
|
41
|
-
function
|
|
34
|
+
function l(e, t) {
|
|
42
35
|
return typeof getComputedStyle > "u" ? "" : getComputedStyle(e).getPropertyValue(t).trim();
|
|
43
36
|
}
|
|
44
|
-
var
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
var u = 120, d = a`
|
|
38
|
+
background-size: calc(var(--vf-scale, 1) * ${120}px)
|
|
39
|
+
calc(var(--vf-scale, 1) * ${120}px);
|
|
40
|
+
`, f = /* @__PURE__ */ new Map();
|
|
41
|
+
function p(e, t) {
|
|
42
|
+
let n = `${e.width}×${e.height}|${t}|${e.rects.join(";")}`, r = f.get(n);
|
|
43
|
+
return r || (r = i(e.width, e.height, e.rects, 120, 120, t), f.set(n, r)), r;
|
|
44
|
+
}
|
|
45
|
+
function m(n) {
|
|
46
|
+
return Math.max(1, Math.round(t(n) * e()));
|
|
47
|
+
}
|
|
48
|
+
var h = class {
|
|
49
|
+
#e;
|
|
50
|
+
#t;
|
|
51
|
+
#n = null;
|
|
52
|
+
#r = null;
|
|
53
|
+
#i = 0;
|
|
54
|
+
#a = "";
|
|
55
|
+
constructor(e, t) {
|
|
56
|
+
this.#e = t, e.addController(this);
|
|
57
|
+
}
|
|
58
|
+
hostConnected() {
|
|
59
|
+
this.#t = n(() => this.#o());
|
|
60
|
+
}
|
|
61
|
+
hostDisconnected() {
|
|
62
|
+
this.#t?.(), this.#t = void 0;
|
|
63
|
+
}
|
|
64
|
+
hostUpdated() {
|
|
65
|
+
this.#o();
|
|
66
|
+
}
|
|
67
|
+
#o() {
|
|
68
|
+
let e = this.#e.getBox() ?? null;
|
|
69
|
+
e !== this.#n && (this.#s(), this.#n = e);
|
|
70
|
+
let t = this.#e.getArt() ?? null;
|
|
71
|
+
if (!e || !t) {
|
|
72
|
+
this.#s();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
let n = m(e);
|
|
76
|
+
if (t === this.#r && n === this.#i && this.#a) return;
|
|
77
|
+
this.#r = t, this.#i = n;
|
|
78
|
+
let r = p(t, n);
|
|
79
|
+
r !== this.#a && (this.#a = r, e.style.setProperty(this.#e.property, r));
|
|
80
|
+
}
|
|
81
|
+
#s() {
|
|
82
|
+
this.#r = null, this.#i = 0, this.#a && (this.#a = "", this.#n?.style.removeProperty(this.#e.property));
|
|
50
83
|
}
|
|
51
84
|
};
|
|
52
85
|
//#endregion
|
|
53
|
-
export {
|
|
86
|
+
export { u as REPEAT_TILE, h as RepeatTileController, m as devicePxAt, l as patternOverride, p as repeatTile, c as tileGrid, d as vfRepeatTileSize, s as vfTileGrid };
|
package/dist/track-width.d.ts
CHANGED
|
@@ -22,8 +22,7 @@ import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
|
22
22
|
* runs on every update.
|
|
23
23
|
*
|
|
24
24
|
* The height comes along from the same observation, for a box measured on
|
|
25
|
-
* both axes
|
|
26
|
-
* raster to a box whose extent nobody declared.
|
|
25
|
+
* both axes.
|
|
27
26
|
*/
|
|
28
27
|
export declare class TrackWidthController implements ReactiveController {
|
|
29
28
|
private readonly host;
|
package/dist/zoom.d.ts
CHANGED
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
*
|
|
18
18
|
* The work is knowing the zoom at all. Zoom multiplies device-px-per-CSS-px in
|
|
19
19
|
* every engine — that is what zoom is — but the engines differ in whether they
|
|
20
|
-
* report it: Chrome and
|
|
21
|
-
* `devicePixelRatio` to the hardware and moves `innerWidth`
|
|
22
|
-
* tracker watches two signals:
|
|
20
|
+
* report it: Chrome, Firefox and Safari 27 fold it into `devicePixelRatio`;
|
|
21
|
+
* older Safari pins `devicePixelRatio` to the hardware and moves `innerWidth`
|
|
22
|
+
* instead. So the tracker watches two signals:
|
|
23
23
|
*
|
|
24
24
|
* 1. `devicePixelRatio`, via a resolution media query re-armed at each new
|
|
25
25
|
* value. A dpr change is *either* zoom or the window moving to a
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* report those members in zoom-affected CSS px) means zoom; anything else
|
|
32
32
|
* means a display change, which rebases the baseline and reports nothing.
|
|
33
33
|
* 2. `innerWidth`/`innerHeight` against `outerWidth`/`outerHeight`, for
|
|
34
|
-
* Safari: zoom rescales the inner (CSS-px) viewport on both axes by the
|
|
34
|
+
* older Safari: zoom rescales the inner (CSS-px) viewport on both axes by the
|
|
35
35
|
* same factor while the outer (screen-px) window holds still. A change in
|
|
36
36
|
* the outer size is a real window resize and rebases; a one-axis inner
|
|
37
37
|
* change (an edge drag, devtools docking, a sidebar) is never zoom and
|
|
@@ -170,12 +170,12 @@ export declare function getZoom(): number;
|
|
|
170
170
|
/**
|
|
171
171
|
* Device px per CSS px *right now* — the number every "snap to the device
|
|
172
172
|
* grid" computation must divide by. `window.devicePixelRatio` is that number
|
|
173
|
-
* only in engines that fold zoom into it; Safari's is simply wrong about
|
|
174
|
-
* current rasterization density at any non-100% zoom. Reading the live dpr
|
|
175
|
-
* folding the tracked zoom back in is correct in both:
|
|
173
|
+
* only in engines that fold zoom into it; older Safari's is simply wrong about
|
|
174
|
+
* the current rasterization density at any non-100% zoom. Reading the live dpr
|
|
175
|
+
* and folding the tracked zoom back in is correct in both:
|
|
176
176
|
*
|
|
177
|
-
* Chrome/Firefox (latched) dpr already includes zoom → dpr
|
|
178
|
-
* Safari (never latches)
|
|
177
|
+
* Chrome/Firefox/Safari 27 (latched) dpr already includes zoom → dpr
|
|
178
|
+
* older Safari (never latches) dpr is the hardware → dpr × zoom
|
|
179
179
|
*
|
|
180
180
|
* The live read matters: a monitor move changes the true density whether or
|
|
181
181
|
* not the tracker is running, and this stays exactly as correct as the old
|