vintage-frames 0.1.0 → 0.2.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/README.md +12 -233
- package/custom-elements.json +290 -38
- package/dist/components/vf-button.d.ts +1 -1
- package/dist/components/vf-container.d.ts +2 -2
- package/dist/components/vf-desktop.d.ts +1 -1
- package/dist/components/vf-fieldset.d.ts +1 -1
- package/dist/components/vf-fieldset.js +6 -1
- package/dist/components/vf-grid.d.ts +1 -1
- package/dist/components/vf-icon.d.ts +1 -1
- package/dist/components/vf-img.d.ts +1 -1
- package/dist/components/vf-label.d.ts +1 -1
- package/dist/components/vf-list-item.d.ts +9 -1
- package/dist/components/vf-list-item.js +15 -14
- package/dist/components/vf-list.d.ts +1 -1
- package/dist/components/vf-menu-bar.d.ts +1 -1
- package/dist/components/vf-menu-item.d.ts +10 -1
- package/dist/components/vf-menu-item.js +35 -34
- package/dist/components/vf-menu.d.ts +11 -2
- package/dist/components/vf-menu.js +33 -32
- package/dist/components/vf-option.d.ts +11 -1
- package/dist/components/vf-option.js +16 -15
- package/dist/components/vf-paragraph.d.ts +3 -3
- package/dist/components/vf-progress-bar.d.ts +1 -1
- package/dist/components/vf-scroll-area.d.ts +1 -1
- package/dist/components/vf-select.d.ts +1 -1
- package/dist/components/vf-separator.d.ts +1 -1
- package/dist/components/vf-slider.d.ts +1 -1
- package/dist/components/vf-stack.d.ts +27 -9
- package/dist/components/vf-stack.js +30 -8
- package/dist/components/vf-swatch.d.ts +1 -1
- package/dist/components/vf-window.d.ts +1 -1
- package/dist/cross-center.d.ts +76 -0
- package/dist/cross-center.js +69 -0
- package/dist/define.d.ts +2 -2
- package/dist/define.js +1 -1
- package/dist/grid-snap.d.ts +2 -24
- package/dist/grid-snap.js +7 -33
- package/dist/index.d.ts +5 -5
- package/dist/index.js +50 -50
- package/dist/position.d.ts +11 -2
- package/dist/styles/recipes/host.js +14 -1
- package/dist/styles/recipes/toggle.js +16 -0
- package/dist/text-control.d.ts +1 -1
- package/docs/SPEC.md +287 -2249
- package/editor/vscode.html-custom-data.json +48 -8
- package/editor/web-types.json +92 -12
- package/package.json +2 -4
package/README.md
CHANGED
|
@@ -1,262 +1,41 @@
|
|
|
1
1
|
# Vintage Frames
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
title bars, 1px black borders, hard offset shadows, bitmap type. 31 elements,
|
|
5
|
-
no stylesheet to load.
|
|
3
|
+
A web component kit that rebuilds the classic Apple System 7 interface elements.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
desktop: menu bar, movable windows, dialogs, icons, every control, drawn
|
|
9
|
-
cursor
|
|
10
|
-
- **[Component reference](https://aportilla.github.io/vintage-frames/examples.html)**
|
|
11
|
-
— every element, its API, and a live specimen of each state
|
|
12
|
-
- **[Integration example](https://aportilla.github.io/vintage-frames/blog.html)**
|
|
13
|
-
— an ordinary blog page (system-font copy, normal flow, no global CSS) using
|
|
14
|
-
the controls in its header, sidebar and forms
|
|
5
|
+
View the [Examples Page](https://aportilla.github.io/vintage-frames/) to see every element live, with its full API.
|
|
15
6
|
|
|
16
7
|
```sh
|
|
17
8
|
npm install vintage-frames
|
|
18
9
|
```
|
|
19
10
|
|
|
20
|
-
|
|
21
|
-
import 'vintage-frames' // registers every <vf-*> element
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Every visual constant is a `--vf-*` custom property with an inlined fallback,
|
|
25
|
-
the two bitmap faces register themselves on `document.fonts`, and each
|
|
26
|
-
component scales itself — so a component on a blank page renders correctly with
|
|
27
|
-
no global CSS at all.
|
|
11
|
+
Import the entire kit:
|
|
28
12
|
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
<vf-menu-bar>
|
|
32
|
-
<vf-menu label="File">
|
|
33
|
-
<vf-menu-item shortcut="⌘N">New Window</vf-menu-item>
|
|
34
|
-
<vf-separator></vf-separator>
|
|
35
|
-
<vf-menu-item shortcut="⌘Q">Quit</vf-menu-item>
|
|
36
|
-
</vf-menu>
|
|
37
|
-
</vf-menu-bar>
|
|
38
|
-
|
|
39
|
-
<vf-window heading="My Installer" movable width="360" height="220"
|
|
40
|
-
top="40" left="76">
|
|
41
|
-
<vf-stack fill-width gap="12">
|
|
42
|
-
<vf-paragraph>Welcome!</vf-paragraph>
|
|
43
|
-
<vf-fieldset fill-width legend="Install Location">
|
|
44
|
-
<vf-select value="hd">
|
|
45
|
-
<vf-option value="hd">Macintosh HD</vf-option>
|
|
46
|
-
</vf-select>
|
|
47
|
-
</vf-fieldset>
|
|
48
|
-
<vf-stack fill-width place="end">
|
|
49
|
-
<vf-button-group>
|
|
50
|
-
<vf-button>Quit</vf-button>
|
|
51
|
-
<vf-button variant="default">Install</vf-button>
|
|
52
|
-
</vf-button-group>
|
|
53
|
-
</vf-stack>
|
|
54
|
-
</vf-stack>
|
|
55
|
-
</vf-window>
|
|
56
|
-
</vf-desktop>
|
|
13
|
+
```ts
|
|
14
|
+
import 'vintage-frames'
|
|
57
15
|
```
|
|
58
16
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
| Element | What it is |
|
|
62
|
-
| --- | --- |
|
|
63
|
-
| `vf-desktop` | Gray dithered desktop raster. Declare `width`/`height` in system px, or derive them with `fitWithin(w, h)`. Stacks slotted windows, manages active state, floats `variant="utility"` windows on their own tier. `bezel` adds the CRT surround with rounded top screen corners |
|
|
64
|
-
| `vf-window` | Window shell: striped title bar, `closable`/`zoomable` boxes, `movable`, `resizable`, edge scroll rails (`scrollbars`), slim windoid chrome (`variant="utility"`). Declare `width`/`height` in system px |
|
|
65
|
-
| `vf-dialog` | Modal shell over a native `<dialog>`. Striped movable bar by default; `frame="plain"` is the double-rule modal frame. Declare `width`/`height`; unset `top`/`left` means centered |
|
|
66
|
-
| `vf-separator` | 1px rule, `vertical` or horizontal. Renders as the dimmed dotted rule inside a menu |
|
|
67
|
-
| `vf-button` | Push button with pixel-stepped corners. `variant="default"` draws the double ring. Form-associated: `type="submit"`/`"reset"`, `name`/`value` |
|
|
68
|
-
| `vf-button-group` | Row (or `vertical` column) of buttons sized to the widest, faces aligned so a `variant="default"` button lines up with its neighbors. `natural` keeps each button's own width |
|
|
69
|
-
| `vf-swatch` | Color-swatch button — a white-inset color well sized in system px, showing a transparency checker with no `color`. `shadow` opts into the hard drop shadow |
|
|
70
|
-
| `vf-checkbox` | Checkbox with the classic ✕ mark |
|
|
71
|
-
| `vf-radio`, `vf-radio-group` | Radio buttons; the group is the form-associated surface and owns `value` |
|
|
72
|
-
| `vf-text-field`, `vf-text-area` | Bordered text inputs. `vf-text-area` reserves a permanent scroll rail |
|
|
73
|
-
| `vf-number-field` | Numeric field with the "little arrows" stepper; `min`/`max`/`step` |
|
|
74
|
-
| `vf-select`, `vf-option` | Popup menu. Press-drag-release or click-to-open. A list taller than the screen is clipped, not scrolled, with a scroll arrow in the edge row |
|
|
75
|
-
| `vf-progress-bar` | Determinate fill or `indeterminate` barber stripes |
|
|
76
|
-
| `vf-slider` | Horizontal 1-bit slider: solid fill up to a shield-shaped handle |
|
|
77
|
-
| `vf-menu-bar`, `vf-menu`, `vf-menu-item` | Pull-down menus with ⌘ shortcuts, selection blink, press-drag-release. `rounded` masks the bar's top corners |
|
|
78
|
-
| `vf-list`, `vf-list-item` | List box: inverted selection, permanent scroll rail, first-letter type-ahead, `multiple`. Each row takes a leading graphic in its `icon` slot |
|
|
79
|
-
| `vf-scroll-area` | Container with System 7 scrollbars. Reserves the rail per `axis` — arrows always drawn, trough and thumb filling in on overflow |
|
|
80
|
-
| `vf-fieldset` | Group box with the legend punching through the border |
|
|
81
|
-
| `vf-grid` | Lattice of equal cells with 1px rules. `columns`/`rows`/`cell-width`/`cell-height`; `rules` picks the pen, `frameless` drops the perimeter, `collapse` lands a cell's border on the rule |
|
|
82
|
-
| `vf-stack` | Flexbox whose `gap`, `pad`, `width` and `height` are declared in system px. Content-governed; `fill-width`/`fill-height` on a child asks for more |
|
|
83
|
-
| `vf-container` | A plain box with a declared `width`/`height` and no paint of its own. The positioned ancestor for children placed with `top`/`left`; takes `top`/`left` itself and keeps its box (and everything placed in it) on the device-pixel grid |
|
|
84
|
-
| `vf-label` | Static caption in the chrome face. `for` focuses and names a control; `width` sets a whole-pixel caption column |
|
|
85
|
-
| `vf-paragraph` | Copy in the body face on a whole-pixel line box; `width`/`height` set the box the text wraps to |
|
|
86
|
-
| `vf-img` | Pixel art on the grid — sizes a slotted `<img>` to one system px per image px, magnified nearest-neighbor |
|
|
87
|
-
| `vf-icon` | Finder icon: art in a 32×32 or 16×16 cell with a name plate below. `selectable`, `open`, `movable`, `editable` |
|
|
88
|
-
|
|
89
|
-
The [component reference](https://aportilla.github.io/vintage-frames/examples.html)
|
|
90
|
-
shows each of these live, with its full API.
|
|
91
|
-
|
|
92
|
-
## Taking only what you use
|
|
93
|
-
|
|
94
|
-
The root import registers all 31 elements. Import by name to ship less — same
|
|
95
|
-
elements, same self-registration, one module each:
|
|
17
|
+
Or import just the elements you need:
|
|
96
18
|
|
|
97
19
|
```ts
|
|
98
20
|
import 'vintage-frames/vf-button.js'
|
|
99
21
|
import 'vintage-frames/vf-checkbox.js'
|
|
100
22
|
```
|
|
101
23
|
|
|
102
|
-
|
|
103
|
-
at resolve time rather than as a 404 in production. Bundled and minified with
|
|
104
|
-
`lit` external:
|
|
24
|
+
There is no need to import a stylesheet. The components carry their styles with them.
|
|
105
25
|
|
|
106
|
-
| Imported | min | gzip |
|
|
107
|
-
| --- | --- | --- |
|
|
108
|
-
| `vf-separator.js` — sets no chrome type, so it carries no display face | 18.8 KB | 10.3 KB |
|
|
109
|
-
| `vf-button.js` | 40.3 KB | 20.0 KB |
|
|
110
|
-
| …plus `vf-checkbox.js` | 46.0 KB | 21.6 KB |
|
|
111
|
-
| the root import — all 31 elements | 299 KB | 91.0 KB |
|
|
112
|
-
|
|
113
|
-
The first component carries the shared code; each one after it adds a couple
|
|
114
|
-
of KB, so importing by name pays off up to roughly a third of the kit. Keep it
|
|
115
|
-
one copy of one package — the scaling, grid snapping, focus modality and font
|
|
116
|
-
registration are module-scoped singletons. If a second copy loads anyway,
|
|
117
|
-
elements register through `defineElement()`, which keeps the first
|
|
118
|
-
registration and warns rather than throwing.
|
|
119
26
|
|
|
120
27
|
## Sizing
|
|
121
28
|
|
|
122
|
-
|
|
123
|
-
border is 1 and a push button 20 tall. On a Macintosh that pixel was 1/72 inch.
|
|
124
|
-
Each component reads the display density and renders one system pixel as the
|
|
125
|
-
whole number of device pixels nearest that size, so the art always lands on
|
|
126
|
-
the device-pixel grid. On by default, no setup, nested components never
|
|
127
|
-
double-scale, and page zoom is tracked and handled the same way.
|
|
128
|
-
|
|
129
|
-
So the CSS size follows the display: the same push button is 20px tall on a 1×
|
|
130
|
-
monitor and 30px on a 2× one, while the page's own 17px copy is 17px on both.
|
|
131
|
-
That suits a full-screen faux desktop; next to ordinary page text you may want
|
|
132
|
-
a fixed size. Pin it with the inherited `--vf-scale` custom property, declared
|
|
133
|
-
in a stylesheet the page loads *before* the components upgrade:
|
|
134
|
-
|
|
135
|
-
```css
|
|
136
|
-
:root { --vf-scale: 1; } /* fixed authored size: a 20px button, 16px label */
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
A hand-picked factor must keep `--vf-scale × devicePixelRatio` a whole number
|
|
140
|
-
— `1`, `2`, `3` everywhere; `1.5` only on displays it multiplies out on — or
|
|
141
|
-
the 1-bit art rasterizes gray. Two helpers put the rest of the page on the
|
|
142
|
-
same grid:
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
import { applyScale, applyGridSnap } from 'vintage-frames'
|
|
146
|
-
|
|
147
|
-
applyScale() // your own markup adopts the kit's scale via --vf-scale
|
|
148
|
-
applyGridSnap() // every component cancels a fractional offset your layout hands it
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
[docs/SIZING.md](https://github.com/aportilla/vintage-frames/blob/main/docs/SIZING.md)
|
|
152
|
-
covers the density ladder, zoom, and the three rules that keep a page on the
|
|
153
|
-
device-pixel grid.
|
|
154
|
-
|
|
155
|
-
## Layout
|
|
156
|
-
|
|
157
|
-
Two stylesheet-free ways to lay out a window's insides. `vf-stack` is a
|
|
158
|
-
flexbox whose `gap`, `pad`, `width` and `height` are declared in whole system
|
|
159
|
-
px — content-governed, with `fill-width`/`fill-height` on a child asking for
|
|
160
|
-
more. Or place each child by coordinate: nearly every component takes `top`
|
|
161
|
-
and `left` in whole system px, absolutely positioned within the nearest kit
|
|
162
|
-
container (a window's content region, a dialog, a stack, a `vf-container`).
|
|
163
|
-
Gestures write through the same properties — a title-bar drag, an icon nudge
|
|
164
|
-
and the grow box all state whole system px, so read positions off `win.left`,
|
|
165
|
-
not `style.left`.
|
|
29
|
+
The original Macintosh computers shipped with a 72 DPI 1-bit black-and-white screen. The user interface artwork was designed specifically to be legible and usable at that exact density. Modern displays, however, come in a wide range of pixel densities, so rendering at a naive 1x/2x/3x is not a viable strategy for replicating the original experience.
|
|
166
30
|
|
|
167
|
-
|
|
31
|
+
With the Vintage Frames kit, every component is authored in *system pixels*, corresponding to the original 72 DPI 1-bit art grid. Components read the browser's display pixel density and scale themselves so that one system pixel is exactly an integer number of hardware display pixels. With this technique, the art always lands on the device-pixel grid, at whatever device/system pixel ratio lands *closest* to the original 72 DPI.
|
|
168
32
|
|
|
169
|
-
|
|
170
|
-
The kit ships two parameterized shells; each archetype is a one-line recipe:
|
|
171
|
-
|
|
172
|
-
| Archetype | Recipe |
|
|
173
|
-
| --- | --- |
|
|
174
|
-
| Document window | `<vf-window closable zoomable movable resizable scrollbars="both">` |
|
|
175
|
-
| Movable modal dialog box | `<vf-dialog heading="…">` |
|
|
176
|
-
| Modal dialog box | `<vf-dialog frame="plain">` |
|
|
177
|
-
| Modeless dialog box | `<vf-window closable movable>` |
|
|
178
|
-
| Utility (floating) window | `<vf-window variant="utility" movable>` |
|
|
179
|
-
|
|
180
|
-
There is no alert component — an alert is the plain modal frame plus your own
|
|
181
|
-
icon art in a `vf-img`.
|
|
182
|
-
|
|
183
|
-
## Fonts
|
|
184
|
-
|
|
185
|
-
Two bitmap faces ship inside the components and register themselves on
|
|
186
|
-
`document.fonts`, so they render inside every shadow root with no global CSS:
|
|
187
|
-
**VF Display**, the chrome face, and **VF Body**, the body face. Both are the
|
|
188
|
-
kit's own artwork — re-drawn strikes in the style of Chicago 12pt and Geneva
|
|
189
|
-
9pt, the classic Macintosh faces designed by Susan Kare for Apple — extended
|
|
190
|
-
in the same idiom (`€`, arrows, `⌘ ⇧ ⌥ ⌃`, fractions, accents) so modern copy
|
|
191
|
-
doesn't fall back mid-sentence. Set your own text in them with `vf-label` and
|
|
192
|
-
`vf-paragraph`, whose line boxes sit on whole system pixels; every strike
|
|
193
|
-
renders at its native size.
|
|
194
|
-
|
|
195
|
-
## The cursor
|
|
196
|
-
|
|
197
|
-
The chrome sets the classic cursors with ordinary CSS. A faux desktop can also
|
|
198
|
-
draw the pointer itself:
|
|
199
|
-
|
|
200
|
-
```ts
|
|
201
|
-
import { applyCursor } from 'vintage-frames'
|
|
202
|
-
|
|
203
|
-
applyCursor() // → returns a cleanup function that restores the native pointer
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
That replaces the native pointer with the embedded System 7 set — arrow,
|
|
207
|
-
I-beam, crosshair and wristwatch as pixel art locked to the system-pixel
|
|
208
|
-
lattice, the I-beam and crosshair drawn with the classic XOR pen. Each kind
|
|
209
|
-
accepts custom art.
|
|
33
|
+
When the browser is zoomed, components raise or lower their target system DPI but keep rendering onto the native device-pixel grid at the closest integer mapping of device pixels to system pixels, so they always render crisply, with no blurred sub-pixel edges.
|
|
210
34
|
|
|
211
35
|
## Accessibility
|
|
212
36
|
|
|
213
|
-
|
|
214
|
-
pixel grid, keyboard-only. Forced-colors mode (Windows High Contrast)
|
|
215
|
-
re-declares the palette in system colors and keeps drawing the kit's artwork.
|
|
216
|
-
The platform's form vocabulary works, including into shadow roots: `<label
|
|
217
|
-
for>`, `aria-label`/`aria-labelledby`/`aria-describedby`, and `required` with
|
|
218
|
-
real constraint validation — `form.reportValidity()` blocks, `:invalid`
|
|
219
|
-
matches on the host, and `vf-button` submits like a native button.
|
|
220
|
-
|
|
221
|
-
## Editor support
|
|
222
|
-
|
|
223
|
-
The package ships a [custom elements manifest](https://github.com/webcomponents/custom-elements-manifest)
|
|
224
|
-
and the two editor formats derived from it. Point your editor at the matching
|
|
225
|
-
format and `<vf-` completes, with each attribute's doc comment on hover:
|
|
226
|
-
|
|
227
|
-
```jsonc
|
|
228
|
-
// VS Code — .vscode/settings.json
|
|
229
|
-
{ "html.customData": ["./node_modules/vintage-frames/editor/vscode.html-custom-data.json"] }
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
JetBrains IDEs read the `web-types` field in `package.json` on their own.
|
|
233
|
-
|
|
234
|
-
## Matching the kit
|
|
235
|
-
|
|
236
|
-
The toolkit the components are built from is exported from the package root —
|
|
237
|
-
the 1-bit CSS recipes (`vfPanel`, `vfTitleBar`, `vfFocusUnderline`, …), the
|
|
238
|
-
glyph sprites, the stepped-corner clip traces, the scale/zoom/snap machinery
|
|
239
|
-
and the form-control base classes — so a custom control can match the kit
|
|
240
|
-
pixel-for-pixel. [docs/TOOLKIT.md](https://github.com/aportilla/vintage-frames/blob/main/docs/TOOLKIT.md)
|
|
241
|
-
documents every export.
|
|
242
|
-
|
|
243
|
-
## Documentation
|
|
244
|
-
|
|
245
|
-
| Doc | What it covers |
|
|
246
|
-
| --- | --- |
|
|
247
|
-
| [docs/SPEC.md](https://github.com/aportilla/vintage-frames/blob/main/docs/SPEC.md) | The design spec — every token, slot, part and event. Ships in the package |
|
|
248
|
-
| [docs/DESIGN-TOKENS.md](https://github.com/aportilla/vintage-frames/blob/main/docs/DESIGN-TOKENS.md) | Every `--vf-*` theming token, its default and what reads it |
|
|
249
|
-
| [docs/SIZING.md](https://github.com/aportilla/vintage-frames/blob/main/docs/SIZING.md) | True-size rendering: the density ladder, zoom, the device-pixel grid rules, grid snapping, the tile grid |
|
|
250
|
-
| [docs/LAYOUT.md](https://github.com/aportilla/vintage-frames/blob/main/docs/LAYOUT.md) | `vf-stack`, coordinate placement, the window archetypes in full |
|
|
251
|
-
| [docs/FONTS.md](https://github.com/aportilla/vintage-frames/blob/main/docs/FONTS.md) | The bitmap faces: metrics, theming, design lineage |
|
|
252
|
-
| [docs/ICONS.md](https://github.com/aportilla/vintage-frames/blob/main/docs/ICONS.md) | `vf-img` and `vf-icon` in full |
|
|
253
|
-
| [docs/CURSOR.md](https://github.com/aportilla/vintage-frames/blob/main/docs/CURSOR.md) | The drawn cursor set and custom cursor art |
|
|
254
|
-
| [docs/ACCESSIBILITY.md](https://github.com/aportilla/vintage-frames/blob/main/docs/ACCESSIBILITY.md) | Focus, forced colors, and the form contract in full |
|
|
255
|
-
| [docs/TOOLKIT.md](https://github.com/aportilla/vintage-frames/blob/main/docs/TOOLKIT.md) | Every root export — recipes, controllers, base classes |
|
|
256
|
-
| [docs/DEVELOPING.md](https://github.com/aportilla/vintage-frames/blob/main/docs/DEVELOPING.md) | Working on the kit: demo pages, the verify suite, the generated editor data |
|
|
37
|
+
Some liberties have been taken with component interaction and design to support modern web accessibility techniques and conventions. Vintage Frames components act as standard form controls, and display focus state as a 1-bit dashed line beneath the control or label.
|
|
257
38
|
|
|
258
39
|
## License
|
|
259
40
|
|
|
260
|
-
[MIT](https://github.com/aportilla/vintage-frames/blob/main/LICENSE) © Adam
|
|
261
|
-
Portilla. The embedded faces are the kit's own re-drawn strikes; the designs
|
|
262
|
-
they re-draw — Chicago and Geneva — were created by Susan Kare for Apple.
|
|
41
|
+
[MIT](https://github.com/aportilla/vintage-frames/blob/main/LICENSE) © Adam Portilla. The embedded font faces are fully re-drawn strikes based on Chicago and Geneva, originally created by Susan Kare for Apple.
|