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,32 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { STROKE_FORCED_COLORS as e, strokeBorder as t, strokeEdgeShadow as n, strokePadding as r } from "./stroke.js";
|
|
2
|
+
import { css as i, unsafeCSS as a } from "lit";
|
|
2
3
|
//#region src/styles/recipes/rule.ts
|
|
3
|
-
var
|
|
4
|
+
var o = [
|
|
4
5
|
"top",
|
|
5
6
|
"right",
|
|
6
7
|
"bottom",
|
|
7
8
|
"left"
|
|
8
|
-
],
|
|
9
|
+
], s = (e) => a(`
|
|
10
|
+
--_vf-rule-${e}: ${n(e, 1)};
|
|
11
|
+
padding-${e}: ${r(0, 1)};
|
|
12
|
+
border-${e}: ${t(1)};
|
|
13
|
+
`), c = i`
|
|
14
|
+
.vf-rule-top,
|
|
15
|
+
.vf-rule-right,
|
|
16
|
+
.vf-rule-bottom,
|
|
17
|
+
.vf-rule-left {
|
|
18
|
+
--_vf-stroke-ink: var(--vf-black, #000);
|
|
19
|
+
--_vf-rule-top: 0 0 transparent;
|
|
20
|
+
--_vf-rule-right: 0 0 transparent;
|
|
21
|
+
--_vf-rule-bottom: 0 0 transparent;
|
|
22
|
+
--_vf-rule-left: 0 0 transparent;
|
|
23
|
+
box-shadow: var(--_vf-rule-top), var(--_vf-rule-right), var(--_vf-rule-bottom),
|
|
24
|
+
var(--_vf-rule-left);
|
|
25
|
+
${a(e)}
|
|
26
|
+
}
|
|
9
27
|
.vf-rule-top {
|
|
10
|
-
|
|
28
|
+
${s("top")}
|
|
11
29
|
}
|
|
12
30
|
.vf-rule-right {
|
|
13
|
-
|
|
31
|
+
${s("right")}
|
|
14
32
|
}
|
|
15
33
|
.vf-rule-bottom {
|
|
16
|
-
|
|
34
|
+
${s("bottom")}
|
|
17
35
|
}
|
|
18
36
|
.vf-rule-left {
|
|
19
|
-
|
|
37
|
+
${s("left")}
|
|
20
38
|
}
|
|
21
39
|
`;
|
|
22
|
-
function
|
|
40
|
+
function l(e) {
|
|
23
41
|
if (e == null) return [];
|
|
24
|
-
let t = e.trim().split(/\s+/).filter(Boolean),
|
|
25
|
-
for (let e of
|
|
26
|
-
return
|
|
42
|
+
let t = e.trim().split(/\s+/).filter(Boolean), n = new Set(t);
|
|
43
|
+
for (let e of n) if (!o.includes(e)) return null;
|
|
44
|
+
return o.filter((e) => n.has(e));
|
|
27
45
|
}
|
|
28
|
-
function
|
|
46
|
+
function u(e) {
|
|
29
47
|
return e.map((e) => `vf-rule-${e}`).join(" ");
|
|
30
48
|
}
|
|
31
49
|
//#endregion
|
|
32
|
-
export {
|
|
50
|
+
export { o as RULE_EDGES, l as parseRule, u as ruleClasses, c as vfRule };
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The trough's 25% lattice is the library's `gray-25` — QuickDraw's
|
|
3
|
+
* `ltGray`, and the UI kit's "Scroll bg" sprite — on its minimal cell: a
|
|
4
|
+
* 4×2-system-px motif with a dot at (0,0) and (2,1). The DOM trough repeats
|
|
5
|
+
* it as a tile drawn at the display's resolution (`--_vf-trough-tile`,
|
|
6
|
+
* written by `ScrollRailController` — 1-bit at every scale, zoom-minted ones
|
|
7
|
+
* included); the SVG span tile below is the forced-colors mask, which
|
|
8
|
+
* repaints the same art in the remapped ink token.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TROUGH: import("../../patterns.js").PatternMotif;
|
|
4
11
|
/**
|
|
5
12
|
* System 7 scroll rails, drawn by the kit as ordinary shadow DOM — the skin
|
|
6
13
|
* for the subtree `renderScrollRail()` (src/scroll-rail.ts) produces. The
|
|
@@ -17,20 +24,21 @@ export declare const TROUGH_RECTS: readonly import("./tile.js").TileRect[];
|
|
|
17
24
|
* is kit art: subpixel layout device-snaps at paint like every other element,
|
|
18
25
|
* and the whole defect class is unrepresentable. It also renders identically
|
|
19
26
|
* in every engine (Firefox included), is assertable headless, and lets the
|
|
20
|
-
* trough adopt the
|
|
27
|
+
* trough adopt the repeating tile the other dithers use.
|
|
21
28
|
*
|
|
22
29
|
* Geometry (system px) — the classic 16px cell, of which the outermost line
|
|
23
30
|
* is the component's own 1px frame: the rail element is the 15 inside it —
|
|
24
|
-
* a 1px divider on the content side (the rail's own
|
|
31
|
+
* a 1px divider on the content side (the rail's own stroke) plus the 14px
|
|
25
32
|
* channel. Arrow cells are 15 long (14 interior + the 1px divider facing the
|
|
26
33
|
* track); their glyphs are the 16-unit sprites windowed to the 14×14
|
|
27
34
|
* interior (`viewBox="1 1 14 14"`), since the sprite's outer ring is exactly
|
|
28
|
-
* the frame/divider lines the
|
|
29
|
-
* box spanning the channel, its
|
|
35
|
+
* the frame/divider lines the strokes draw. The thumb is a fixed 16px white
|
|
36
|
+
* box spanning the channel, its stroke reading as inset 1px from each
|
|
30
37
|
* channel rail over its extent. The component supplies the outer frame as a
|
|
31
|
-
*
|
|
32
|
-
* so the state selectors below can reach the rail from the
|
|
33
|
-
* attributes.
|
|
38
|
+
* stroke of its own and lays the rail out as a sibling of the scroller —
|
|
39
|
+
* AFTER it, so the state selectors below can reach the rail from the
|
|
40
|
+
* scroller's attributes. Every line here is a stroke (vfStrokeDecls):
|
|
41
|
+
* padding holds it and an inset shadow paints it.
|
|
34
42
|
*
|
|
35
43
|
* States, keyed off the attributes `ScrollStateController` writes on the
|
|
36
44
|
* scroller (now styling real elements, so there is no scrollbar-pseudo
|
|
@@ -52,9 +60,9 @@ export declare const TROUGH_RECTS: readonly import("./tile.js").TileRect[];
|
|
|
52
60
|
* through the vfBase token remap like every other element. The arrows are
|
|
53
61
|
* inline `currentColor` SVG now, so they re-ink with the palette (the old
|
|
54
62
|
* `::-webkit-scrollbar` skin's one genuine residual — mask-image is ignored
|
|
55
|
-
* on scrollbar pseudos — dies here). The trough
|
|
56
|
-
* it
|
|
57
|
-
*
|
|
63
|
+
* on scrollbar pseudos — dies here). The trough's tile keeps literal ink, so
|
|
64
|
+
* it goes and the trough repaints as the ink token masked by the same art
|
|
65
|
+
* (the vfDots idiom; the span mask keeps the zoom caveat every masked
|
|
58
66
|
* surface has, an accepted residual).
|
|
59
67
|
*/
|
|
60
68
|
export declare const vfScrollRail: import("lit").CSSResult;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { tileImage as e, tileRects as t, vfTileMaskSize as n } from "./tile.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { vfRepeatTileSize as r } from "../../tile-grid.js";
|
|
3
|
+
import { PATTERNS as i, patternMotif as a } from "../../patterns.js";
|
|
4
|
+
import { vfStrokeDecls as o } from "./stroke.js";
|
|
5
|
+
import { css as s, unsafeCSS as c } from "lit";
|
|
4
6
|
//#region src/styles/recipes/scroll-rail.ts
|
|
5
|
-
var
|
|
7
|
+
var l = a(i["gray-25"]), u = e(l.width, l.height, t(l.rects)), d = s`
|
|
6
8
|
/* Hide the native bar, keep the native scrolling. Both lines ship:
|
|
7
9
|
scrollbar-width reaches Chromium 121+/Firefox/Safari 18.2+, the pseudo
|
|
8
10
|
covers older WebKit — the last scrollbar pseudo left in the kit.
|
|
@@ -36,7 +38,7 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
36
38
|
calc(var(--vf-scale, 1) * 15px)
|
|
37
39
|
1fr
|
|
38
40
|
calc(var(--vf-scale, 1) * 15px);
|
|
39
|
-
|
|
41
|
+
${o({ edges: ["left"] })}
|
|
40
42
|
}
|
|
41
43
|
.vf-rail--horizontal {
|
|
42
44
|
height: calc(var(--vf-scale, 1) * 15px);
|
|
@@ -44,7 +46,7 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
44
46
|
calc(var(--vf-scale, 1) * 15px)
|
|
45
47
|
1fr
|
|
46
48
|
calc(var(--vf-scale, 1) * 15px);
|
|
47
|
-
|
|
49
|
+
${o({ edges: ["top"] })}
|
|
48
50
|
}
|
|
49
51
|
/* Explicit placement, so hiding the arrows (inactive-window/degenerate
|
|
50
52
|
states) never reflows the track into an arrow cell — its box holds still
|
|
@@ -69,11 +71,11 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
/* Arrow cells: white boxes carrying only the 1px divider that faces the
|
|
72
|
-
track — the frame edges are the component's
|
|
73
|
-
rail's own divider — so no line ever doubles to 2px. Each cell's
|
|
74
|
+
track — the frame edges are the component's stroke, the content edge the
|
|
75
|
+
rail's own divider — so no line ever doubles to 2px. Each cell's content
|
|
74
76
|
box is by construction the sprite's 14×14 interior, wherever the cell
|
|
75
77
|
sits (flush to the frame, or against the corner cell), so the glyph
|
|
76
|
-
lands at the
|
|
78
|
+
lands at the content origin with no per-variant offsets. */
|
|
77
79
|
.vf-rail-button {
|
|
78
80
|
display: grid;
|
|
79
81
|
place-items: start;
|
|
@@ -81,16 +83,16 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
81
83
|
overflow: hidden;
|
|
82
84
|
}
|
|
83
85
|
.vf-rail--vertical .vf-rail-button--decrement {
|
|
84
|
-
|
|
86
|
+
${o({ edges: ["bottom"] })}
|
|
85
87
|
}
|
|
86
88
|
.vf-rail--vertical .vf-rail-button--increment {
|
|
87
|
-
|
|
89
|
+
${o({ edges: ["top"] })}
|
|
88
90
|
}
|
|
89
91
|
.vf-rail--horizontal .vf-rail-button--decrement {
|
|
90
|
-
|
|
92
|
+
${o({ edges: ["right"] })}
|
|
91
93
|
}
|
|
92
94
|
.vf-rail--horizontal .vf-rail-button--increment {
|
|
93
|
-
|
|
95
|
+
${o({ edges: ["left"] })}
|
|
94
96
|
}
|
|
95
97
|
.vf-rail-arrow {
|
|
96
98
|
display: block;
|
|
@@ -117,28 +119,19 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
117
119
|
min-width: 0;
|
|
118
120
|
min-height: 0;
|
|
119
121
|
}
|
|
120
|
-
/* The trough: the token base color
|
|
121
|
-
|
|
122
|
+
/* The trough: the dither over the token base color — the repeating tile
|
|
123
|
+
ScrollRailController writes (src/tile-grid.ts), 1-bit at every scale. */
|
|
122
124
|
.vf-rail-trough {
|
|
123
125
|
position: absolute;
|
|
124
126
|
inset: 0;
|
|
125
|
-
overflow: hidden;
|
|
126
127
|
background-color: var(--vf-scrollbar-track, var(--vf-white, #fff));
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
/* The dither raster ScrollRailController sizes and writes — one image px
|
|
130
|
-
per system px, magnified nearest-neighbor (the vf-img idiom), so the
|
|
131
|
-
lattice is 1-bit at every scale. */
|
|
132
|
-
.vf-rail-trough-art {
|
|
133
|
-
position: absolute;
|
|
134
|
-
top: 0;
|
|
135
|
-
left: 0;
|
|
136
|
-
background-size: 100% 100%;
|
|
137
|
-
background-repeat: no-repeat;
|
|
128
|
+
background-image: var(--_vf-trough-tile, none);
|
|
129
|
+
${r}
|
|
138
130
|
image-rendering: pixelated;
|
|
131
|
+
pointer-events: none;
|
|
139
132
|
}
|
|
140
133
|
/* The fixed System 7 thumb (never proportional): a white 16px box spanning
|
|
141
|
-
the channel. Its
|
|
134
|
+
the channel. Its stroke reads as inset 1px from each channel rail — the
|
|
142
135
|
divider and the frame — over its extent; the controller writes its
|
|
143
136
|
travel as a whole-system-px translate. */
|
|
144
137
|
.vf-rail-thumb {
|
|
@@ -146,7 +139,7 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
146
139
|
top: 0;
|
|
147
140
|
left: 0;
|
|
148
141
|
background: var(--vf-scrollbar-thumb, #ffffff);
|
|
149
|
-
|
|
142
|
+
${o()}
|
|
150
143
|
}
|
|
151
144
|
.vf-rail--vertical .vf-rail-thumb {
|
|
152
145
|
width: 100%;
|
|
@@ -169,8 +162,7 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
169
162
|
width: calc(var(--vf-scale, 1) * 15px);
|
|
170
163
|
height: calc(var(--vf-scale, 1) * 15px);
|
|
171
164
|
background: var(--vf-white, #fff);
|
|
172
|
-
|
|
173
|
-
border-left: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
|
|
165
|
+
${o({ edges: ["top", "left"] })}
|
|
174
166
|
}
|
|
175
167
|
|
|
176
168
|
/* ── Always-a-rail (driven by ScrollStateController) ─────────────────────
|
|
@@ -207,21 +199,19 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
|
|
|
207
199
|
display: none;
|
|
208
200
|
}
|
|
209
201
|
|
|
210
|
-
/* Forced colors: the
|
|
202
|
+
/* Forced colors: the tile keeps literal ink, so it goes and the trough
|
|
211
203
|
repaints as the remapped ink token masked by the same art (the vfDots
|
|
212
204
|
idiom — and like every masked tile, the span mask keeps the zoom
|
|
213
205
|
caveat). Everything else re-inks through the vfBase token remap; the
|
|
214
206
|
arrows are currentColor SVG and follow the palette by themselves. */
|
|
215
207
|
@media (forced-colors: active) {
|
|
216
208
|
.vf-rail-trough {
|
|
209
|
+
background-image: none;
|
|
217
210
|
background-color: var(--vf-black, #000);
|
|
218
|
-
mask-image: ${
|
|
219
|
-
${n(
|
|
220
|
-
}
|
|
221
|
-
.vf-rail-trough-art {
|
|
222
|
-
display: none;
|
|
211
|
+
mask-image: ${c(u)};
|
|
212
|
+
${n(l.width, l.height)}
|
|
223
213
|
}
|
|
224
214
|
}
|
|
225
215
|
`;
|
|
226
216
|
//#endregion
|
|
227
|
-
export {
|
|
217
|
+
export { l as TROUGH, d as vfScrollRail };
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
* with no blur and no spread, System 7's only depth cue. The offset is
|
|
4
4
|
* tokenized via `--vf-shadow-offset` and scales with `--vf-scale`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* {
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
|
|
6
|
+
* The shadow value, for a list: a stroked surface passes it to
|
|
7
|
+
* `vfStrokeDecls({ shadows: vfHardShadow })`, which paints it after the
|
|
8
|
+
* stroke. Every raised surface in the kit does — {@link vfPanel} (menus,
|
|
9
|
+
* popups) and {@link vfChromeFrame} (window frames). One value, so the kit
|
|
10
|
+
* can't grow two shadows.
|
|
11
|
+
*/
|
|
12
|
+
export declare const vfHardShadow: import("lit").CSSResult;
|
|
13
|
+
/**
|
|
14
|
+
* {@link vfHardShadow} as the whole `box-shadow` declaration, for a box that
|
|
15
|
+
* casts the shadow and draws no stroke.
|
|
12
16
|
*/
|
|
13
17
|
export declare const vfHardShadowDecls: import("lit").CSSResult;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { unsafeCSS as e } from "lit";
|
|
2
2
|
//#region src/styles/recipes/shadow.ts
|
|
3
|
-
var t = e("
|
|
3
|
+
var t = e("calc(var(--vf-scale, 1) * var(--vf-shadow-offset, 2px))\n calc(var(--vf-scale, 1) * var(--vf-shadow-offset, 2px)) 0 0\n var(--vf-black, #000)"), n = e(`
|
|
4
|
+
box-shadow: ${t};
|
|
5
|
+
`);
|
|
4
6
|
//#endregion
|
|
5
|
-
export { t as vfHardShadowDecls };
|
|
7
|
+
export { t as vfHardShadow, n as vfHardShadowDecls };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type CSSResult } from 'lit';
|
|
2
|
+
import type { RuleEdge } from './rule.js';
|
|
3
|
+
/** One to four values in shorthand order, as top/right/bottom/left. */
|
|
4
|
+
type Sides<T> = T | readonly T[];
|
|
5
|
+
/** The padding under a stroked edge: the element's own plus the stroke's. */
|
|
6
|
+
export declare function strokePadding(own: number | string, width: number): string;
|
|
7
|
+
/** The border a stroked edge becomes under forced colors; 0 wide otherwise. */
|
|
8
|
+
export declare function strokeBorder(width: number): string;
|
|
9
|
+
/** The inset shadow that paints one edge's stroke. */
|
|
10
|
+
export declare function strokeEdgeShadow(edge: RuleEdge, width: number): string;
|
|
11
|
+
/** The forced-colors switch every stroked element carries. */
|
|
12
|
+
export declare const STROKE_FORCED_COLORS = "@media (forced-colors: active) {\n --_vf-stroke-pad: 0;\n }";
|
|
13
|
+
/**
|
|
14
|
+
* The inset shadow of a stroke `width` system px wide on all four edges — the
|
|
15
|
+
* value to restate when only the painted width changes, as vf-checkbox's
|
|
16
|
+
* press does. Reads the ink and forced-colors switch the element's
|
|
17
|
+
* {@link vfStrokeDecls} declares.
|
|
18
|
+
*/
|
|
19
|
+
export declare function vfStrokeShadow(width?: number): CSSResult;
|
|
20
|
+
/** The options of {@link vfStrokeDecls}. */
|
|
21
|
+
export interface VfStrokeOptions {
|
|
22
|
+
/** The stroked edges. Default all four. */
|
|
23
|
+
edges?: readonly RuleEdge[];
|
|
24
|
+
/**
|
|
25
|
+
* The stroke's width in whole system px, one to four values in shorthand
|
|
26
|
+
* order. Default 1.
|
|
27
|
+
*/
|
|
28
|
+
width?: Sides<number>;
|
|
29
|
+
/**
|
|
30
|
+
* The element's own padding, in system px, one to four values in shorthand
|
|
31
|
+
* order; each stroked edge adds its stroke. A value is a number or a
|
|
32
|
+
* system-px CSS length (`'var(--vf-select-gutter, 16px)'`). Omitted, the
|
|
33
|
+
* declarations set padding on the stroked edges alone, to the stroke.
|
|
34
|
+
*/
|
|
35
|
+
padding?: Sides<number | string>;
|
|
36
|
+
/**
|
|
37
|
+
* More shadows, painted with the stroke: the hard drop shadow
|
|
38
|
+
* ({@link vfHardShadow}), a white ring. The stroke comes first in the list.
|
|
39
|
+
*/
|
|
40
|
+
shadows?: string | CSSResult;
|
|
41
|
+
/** The stroke's color. Default `var(--vf-black, #000)`. */
|
|
42
|
+
ink?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A 1-bit stroke that isn't a line width. The declarations for a box whose
|
|
46
|
+
* edges carry a black line of whole system px — every frame, well, rule and
|
|
47
|
+
* box in the kit — for interpolating into the box's rule:
|
|
48
|
+
* `.card { ${vfStrokeDecls({ padding: [4, 8] })} }`.
|
|
49
|
+
*
|
|
50
|
+
* Safari rounds a border width to device px before it applies page zoom, so a
|
|
51
|
+
* `border` of `calc(var(--vf-scale, 1) * 1px)` draws thinner than the art
|
|
52
|
+
* around it at most zoom levels, and moves everything inside the box off the
|
|
53
|
+
* device grid. Padding and box-shadow lengths are not rounded that way. So the
|
|
54
|
+
* stroke's space is padding on each stroked edge, added to the element's own,
|
|
55
|
+
* and the black is an inset `box-shadow`, with `shadows` after it in the same
|
|
56
|
+
* list. Both land on whole device px at every zoom.
|
|
57
|
+
*
|
|
58
|
+
* What changes from a border:
|
|
59
|
+
* - The declarations own `padding` on the stroked edges (on all four, when
|
|
60
|
+
* `padding` is passed) and `box-shadow`. Pass the element's own padding and
|
|
61
|
+
* shadows here; a later `padding` or `box-shadow` on the element replaces
|
|
62
|
+
* the stroke's.
|
|
63
|
+
* - A child placed against the box measures from its outer edge. Offset it by
|
|
64
|
+
* the stroke with {@link vfStrokeInset}.
|
|
65
|
+
* - An `overflow: hidden` box clips at its outer edge, so its content can
|
|
66
|
+
* paint over the stroke. Clip on an inner element instead.
|
|
67
|
+
* - Forced colors paints no `box-shadow`, so there each stroke is a border
|
|
68
|
+
* again and the padding is the element's own: the same box a border draws.
|
|
69
|
+
*
|
|
70
|
+
* The color goes through a private property the declarations set, so pass a
|
|
71
|
+
* `var()` as `ink` to change it from a state rule without restating the
|
|
72
|
+
* shadow list.
|
|
73
|
+
*/
|
|
74
|
+
export declare function vfStrokeDecls(options?: VfStrokeOptions): CSSResult;
|
|
75
|
+
/**
|
|
76
|
+
* A length `base` system px in from a stroke's inner edge, measured from the
|
|
77
|
+
* box's outer edge, on an edge carrying `stroke` system px of it (see
|
|
78
|
+
* {@link vfStrokeDecls}): the inset for a child placed against a stroked box
|
|
79
|
+
* (`right: ${vfStrokeInset(0)}` is flush inside a 1px frame), or a padding
|
|
80
|
+
* that restates the stroke's (`padding: ${vfStrokeInset(0)} ${vfStrokeInset(6)}`).
|
|
81
|
+
* `base` is a number or a system-px CSS length. Under forced colors, where
|
|
82
|
+
* the stroke is a border, it is `base`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function vfStrokeInset(base: number | string, stroke?: number): CSSResult;
|
|
85
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { unsafeCSS as e } from "lit";
|
|
2
|
+
//#region src/styles/recipes/stroke.ts
|
|
3
|
+
var t = [
|
|
4
|
+
"top",
|
|
5
|
+
"right",
|
|
6
|
+
"bottom",
|
|
7
|
+
"left"
|
|
8
|
+
], n = "var(--_vf-stroke-pad, 1)", r = "var(--_vf-stroke-ink)";
|
|
9
|
+
function i(e) {
|
|
10
|
+
let t = Array.isArray(e) ? e : [e], n = t[0], r = t[1] ?? n;
|
|
11
|
+
return [
|
|
12
|
+
n,
|
|
13
|
+
r,
|
|
14
|
+
t[2] ?? n,
|
|
15
|
+
t[3] ?? r
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
var a = (e) => typeof e == "number" ? `${e}px` : e, o = (e) => `calc(var(--vf-scale, 1) * ${e}px * ${n})`;
|
|
19
|
+
function s(e, t) {
|
|
20
|
+
return e === 0 ? o(t) : `calc(var(--vf-scale, 1) * (${a(e)} + ${t}px * ${n}))`;
|
|
21
|
+
}
|
|
22
|
+
function c(e) {
|
|
23
|
+
return `calc(var(--vf-scale, 1) * ${e}px * (1 - ${n})) solid ${r}`;
|
|
24
|
+
}
|
|
25
|
+
function l(e, t) {
|
|
26
|
+
let i = (e) => `calc(var(--vf-scale, 1) * ${e * t}px * ${n})`;
|
|
27
|
+
switch (e) {
|
|
28
|
+
case "top": return `inset 0 ${i(1)} 0 0 ${r}`;
|
|
29
|
+
case "right": return `inset ${i(-1)} 0 0 0 ${r}`;
|
|
30
|
+
case "bottom": return `inset 0 ${i(-1)} 0 0 ${r}`;
|
|
31
|
+
case "left": return `inset ${i(1)} 0 0 0 ${r}`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var u = "@media (forced-colors: active) {\n --_vf-stroke-pad: 0;\n }";
|
|
35
|
+
function d(t = 1) {
|
|
36
|
+
return e(`inset 0 0 0 ${o(t)} ${r}`);
|
|
37
|
+
}
|
|
38
|
+
function f(n = {}) {
|
|
39
|
+
let r = new Set(n.edges ?? t), o = i(n.width ?? 1), f = i(n.padding ?? 0), p = t.map((e, t) => r.has(e) ? o[t] : 0), m = p.every((e) => e > 0 && e === p[0]), h = [`--_vf-stroke-ink: ${n.ink ?? "var(--vf-black, #000)"};`], g = [];
|
|
40
|
+
return t.forEach((e, t) => {
|
|
41
|
+
let r = p[t];
|
|
42
|
+
if (!r) {
|
|
43
|
+
n.padding !== void 0 && h.push(`padding-${e}: calc(var(--vf-scale, 1) * ${a(f[t])});`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
h.push(`padding-${e}: ${s(f[t], r)};`), h.push(`border-${e}: ${c(r)};`), m || g.push(l(e, r));
|
|
47
|
+
}), m && g.push(String(d(p[0]))), n.shadows && g.push(String(n.shadows)), h.push(`box-shadow: ${g.length ? g.join(", ") : "none"};`), h.push(u), e(h.join("\n "));
|
|
48
|
+
}
|
|
49
|
+
function p(t, n = 1) {
|
|
50
|
+
return e(s(t, n));
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { u as STROKE_FORCED_COLORS, c as strokeBorder, l as strokeEdgeShadow, s as strokePadding, f as vfStrokeDecls, p as vfStrokeInset, d as vfStrokeShadow };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Panel recipe for menus and popups: white face, 1px black
|
|
2
|
+
* Panel recipe for menus and popups: white face, 1px black frame, hard
|
|
3
3
|
* offset shadow.
|
|
4
4
|
*/
|
|
5
5
|
export declare const vfPanel: import("lit").CSSResult;
|
|
6
6
|
/**
|
|
7
7
|
* Chrome-frame recipe for the desktop window (vf-window): the same white
|
|
8
|
-
* face, 1px black
|
|
8
|
+
* face, 1px black frame and hard offset shadow as {@link vfPanel}. Apply
|
|
9
9
|
* `.vf-frame` to the outer frame element.
|
|
10
10
|
*
|
|
11
11
|
* Skin only — the component adds its own layout (a full-size flex column: the
|
|
@@ -14,7 +14,7 @@ export declare const vfPanel: import("lit").CSSResult;
|
|
|
14
14
|
*/
|
|
15
15
|
export declare const vfChromeFrame: import("lit").CSSResult;
|
|
16
16
|
/**
|
|
17
|
-
* The classic modal-dialog (dBoxProc) frame: 1px outer
|
|
17
|
+
* The classic modal-dialog (dBoxProc) frame: 1px outer rule, 2px white gap,
|
|
18
18
|
* 2px inner band — and NO drop shadow, per the `Windows/modal dialog.png`
|
|
19
19
|
* reference. System 7's alert box drew the
|
|
20
20
|
* *mirror* trace (2px outer, 2px gap, 1px inner rule, with the hard shadow) —
|
|
@@ -30,10 +30,14 @@ export declare const vfChromeFrame: import("lit").CSSResult;
|
|
|
30
30
|
* six stripes / 3 white rows, the title patch's 7px margins) sits directly
|
|
31
31
|
* under the outer rule, inset 2px at either end so its stripes keep the same
|
|
32
32
|
* 2px of white from the outer rule that the inner band keeps; the bar's own
|
|
33
|
-
* 1px rule plus the inner box's 1px top
|
|
33
|
+
* 1px rule plus the inner box's 1px top stroke make the 2px band its floor,
|
|
34
34
|
* which then continues down both sides and along the bottom as the band
|
|
35
35
|
* around the body. No shadow anywhere. Put the `.vf-title-bar` between the
|
|
36
36
|
* two elements, as the first child of `.vf-modal-frame`, and the three rules
|
|
37
37
|
* below do the rest.
|
|
38
|
+
*
|
|
39
|
+
* Both lines are strokes ({@link vfStrokeDecls}): padding holds their space
|
|
40
|
+
* and an inset shadow paints them, so the recipe owns both elements' padding
|
|
41
|
+
* and box-shadow.
|
|
38
42
|
*/
|
|
39
43
|
export declare const vfModalFrame: import("lit").CSSResult;
|
|
@@ -1,42 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { vfHardShadow as e } from "./shadow.js";
|
|
2
|
+
import { vfStrokeDecls as t, vfStrokeInset as n } from "./stroke.js";
|
|
3
|
+
import { css as r, unsafeCSS as i } from "lit";
|
|
3
4
|
//#region src/styles/recipes/surface.ts
|
|
4
|
-
var
|
|
5
|
+
var a = i(`
|
|
5
6
|
background: var(--vf-white, #fff);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`), i = t`
|
|
7
|
+
${t({ shadows: e })}
|
|
8
|
+
`), o = r`
|
|
9
9
|
.vf-panel {
|
|
10
|
-
${
|
|
10
|
+
${a}
|
|
11
11
|
}
|
|
12
|
-
`,
|
|
12
|
+
`, s = r`
|
|
13
13
|
.vf-frame {
|
|
14
|
-
${
|
|
14
|
+
${a}
|
|
15
15
|
}
|
|
16
|
-
`,
|
|
16
|
+
`, c = r`
|
|
17
17
|
.vf-modal-frame {
|
|
18
18
|
background: var(--vf-white, #fff);
|
|
19
|
-
|
|
19
|
+
${t()}
|
|
20
20
|
}
|
|
21
21
|
.vf-modal-frame-inner {
|
|
22
22
|
margin: calc(var(--vf-scale, 1) * 2px);
|
|
23
|
-
|
|
23
|
+
${t({ width: 2 })}
|
|
24
24
|
}
|
|
25
25
|
/* The bar set into the frame: 2px in from the outer rule at either end, its
|
|
26
26
|
stripes flush to the bar's own edge (vfStripes' 1px side inset is the
|
|
27
|
-
window frame's buffer — here the frame's gap is that buffer).
|
|
27
|
+
window frame's buffer — here the frame's gap is that buffer). The bottom
|
|
28
|
+
inset counts the bar's rule, which is padding (vfTitleBar). */
|
|
28
29
|
.vf-modal-frame > .vf-title-bar {
|
|
29
30
|
margin: 0 calc(var(--vf-scale, 1) * 2px);
|
|
30
31
|
}
|
|
31
32
|
.vf-modal-frame > .vf-title-bar .vf-stripes {
|
|
32
|
-
inset: calc(var(--vf-scale, 1) * 3px) 0;
|
|
33
|
+
inset: calc(var(--vf-scale, 1) * 3px) 0 ${n(3)};
|
|
33
34
|
}
|
|
34
|
-
/* Under a bar, the inner box's top
|
|
35
|
+
/* Under a bar, the inner box's top stroke is the second row of the band —
|
|
35
36
|
the bar's 1px rule is the first — and there is no gap row between. */
|
|
36
37
|
.vf-modal-frame > .vf-title-bar + .vf-modal-frame-inner {
|
|
37
38
|
margin-top: 0;
|
|
38
|
-
|
|
39
|
+
${t({ width: [
|
|
40
|
+
1,
|
|
41
|
+
2,
|
|
42
|
+
2,
|
|
43
|
+
2
|
|
44
|
+
] })}
|
|
39
45
|
}
|
|
40
46
|
`;
|
|
41
47
|
//#endregion
|
|
42
|
-
export {
|
|
48
|
+
export { s as vfChromeFrame, c as vfModalFrame, o as vfPanel };
|
|
@@ -61,8 +61,9 @@ export type TileRect = readonly [x: number, y: number, w: number, h: number, fil
|
|
|
61
61
|
export declare function tileRects(rects: readonly TileRect[]): string;
|
|
62
62
|
/**
|
|
63
63
|
* The motif tiled over `spanWidth × spanHeight` system px as a RASTER image —
|
|
64
|
-
* a PNG data URI at
|
|
65
|
-
*
|
|
64
|
+
* a PNG data URI at `density` image px per system px (one by default) — the
|
|
65
|
+
* encoder behind the tile every kit surface repeats (`repeatTile`,
|
|
66
|
+
* src/tile-grid.ts).
|
|
66
67
|
*
|
|
67
68
|
* A raster because of how engines rasterize a fill's art, not how they place
|
|
68
69
|
* its box. Chromium rasterizes an SVG image at the box's *stored* (layout)
|
|
@@ -79,8 +80,15 @@ export declare function tileRects(rects: readonly TileRect[]): string;
|
|
|
79
80
|
* out as a data URI and released — kit art only, so there is nothing
|
|
80
81
|
* cross-origin to taint). Where canvas is unavailable the SVG tile is
|
|
81
82
|
* returned instead, so the declaration still paints.
|
|
83
|
+
*
|
|
84
|
+
* `density` draws each system px as a `density × density` block of whole
|
|
85
|
+
* image px. An image drawn at the device px per system px it will be shown
|
|
86
|
+
* at is copied 1:1 onto the device grid, so no engine's image filter has
|
|
87
|
+
* anything to decide — Safari smooths a magnified image on its repeating
|
|
88
|
+
* path whatever `image-rendering` says. It is still one pattern bit per
|
|
89
|
+
* system px; only who scales it changes.
|
|
82
90
|
*/
|
|
83
|
-
export declare function tileRaster(motifWidth: number, motifHeight: number, rects: readonly TileRect[], spanWidth?: number, spanHeight?: number): string;
|
|
91
|
+
export declare function tileRaster(motifWidth: number, motifHeight: number, rects: readonly TileRect[], spanWidth?: number, spanHeight?: number, density?: number): string;
|
|
84
92
|
/**
|
|
85
93
|
* `background-size` for a REPEATING tile — stated as the motif, sized as the
|
|
86
94
|
* span that motif tiles at ({@link tileSpan}).
|
|
@@ -11,18 +11,18 @@ function i(e, t, n, i = r(e), a = r(t)) {
|
|
|
11
11
|
function a(e) {
|
|
12
12
|
return e.map(([e, t, n, r, i]) => `%3Crect ${(e ? `x='${e}' ` : "") + (t ? `y='${t}' ` : "")}width='${n}' height='${r}'${i ? ` fill='${encodeURIComponent(i)}'` : ""}/%3E`).join("");
|
|
13
13
|
}
|
|
14
|
-
function o(e, t, n, o = r(e), s = r(t)) {
|
|
15
|
-
let
|
|
16
|
-
if (typeof document > "u") return
|
|
17
|
-
let
|
|
18
|
-
|
|
19
|
-
let
|
|
20
|
-
if (!
|
|
21
|
-
for (let [e, t, r, i, a] of n)
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
let
|
|
25
|
-
return !
|
|
14
|
+
function o(e, t, n, o = r(e), s = r(t), c = 1) {
|
|
15
|
+
let l = () => i(e, t, a(n), o, s);
|
|
16
|
+
if (typeof document > "u") return l();
|
|
17
|
+
let u = document.createElement("canvas");
|
|
18
|
+
u.width = e * c, u.height = t * c;
|
|
19
|
+
let d = u.getContext("2d");
|
|
20
|
+
if (!d) return l();
|
|
21
|
+
for (let [e, t, r, i, a] of n) d.fillStyle = a ?? "#000000", d.fillRect(e * c, t * c, r * c, i * c);
|
|
22
|
+
let f = document.createElement("canvas");
|
|
23
|
+
f.width = o * c, f.height = s * c;
|
|
24
|
+
let p = f.getContext("2d"), m = p?.createPattern(u, "repeat");
|
|
25
|
+
return !p || !m ? l() : (p.fillStyle = m, p.fillRect(0, 0, f.width, f.height), `url("${f.toDataURL("image/png")}")`);
|
|
26
26
|
}
|
|
27
27
|
function s(t, n = t) {
|
|
28
28
|
return e`
|
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
* drag handle, vf-window's only when `[movable]` — suppressing touch scrolling
|
|
33
33
|
* on a bar that can't be dragged would be a real behavior change, so each
|
|
34
34
|
* component keeps that one declaration under its own selector.
|
|
35
|
+
*
|
|
36
|
+
* The rule is a stroke ({@link vfStrokeDecls}): the bottom row is padding, so
|
|
37
|
+
* the texture layers placed inside the bar count it in their bottom insets.
|
|
35
38
|
*/
|
|
36
39
|
export declare const vfTitleBar: import("lit").CSSResult;
|
|
37
40
|
/**
|
|
@@ -45,5 +48,9 @@ export declare const vfTitleBar: import("lit").CSSResult;
|
|
|
45
48
|
* Geometry is the standard 18px bar's; vf-window's utility variant overrides
|
|
46
49
|
* the sizes under its own selector. Host-state rules (hiding widgets on an
|
|
47
50
|
* inactive window) stay with the component — a dialog has no inactive state.
|
|
51
|
+
*
|
|
52
|
+
* Each box's line is a stroke ({@link vfStrokeDecls}), its white patch ring
|
|
53
|
+
* the next shadow in the same list. State rules recolor the line through
|
|
54
|
+
* `--_vf-stroke-ink`.
|
|
48
55
|
*/
|
|
49
56
|
export declare const vfWindowWidgets: import("lit").CSSResult;
|