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.
Files changed (47) hide show
  1. package/README.md +12 -233
  2. package/custom-elements.json +290 -38
  3. package/dist/components/vf-button.d.ts +1 -1
  4. package/dist/components/vf-container.d.ts +2 -2
  5. package/dist/components/vf-desktop.d.ts +1 -1
  6. package/dist/components/vf-fieldset.d.ts +1 -1
  7. package/dist/components/vf-fieldset.js +6 -1
  8. package/dist/components/vf-grid.d.ts +1 -1
  9. package/dist/components/vf-icon.d.ts +1 -1
  10. package/dist/components/vf-img.d.ts +1 -1
  11. package/dist/components/vf-label.d.ts +1 -1
  12. package/dist/components/vf-list-item.d.ts +9 -1
  13. package/dist/components/vf-list-item.js +15 -14
  14. package/dist/components/vf-list.d.ts +1 -1
  15. package/dist/components/vf-menu-bar.d.ts +1 -1
  16. package/dist/components/vf-menu-item.d.ts +10 -1
  17. package/dist/components/vf-menu-item.js +35 -34
  18. package/dist/components/vf-menu.d.ts +11 -2
  19. package/dist/components/vf-menu.js +33 -32
  20. package/dist/components/vf-option.d.ts +11 -1
  21. package/dist/components/vf-option.js +16 -15
  22. package/dist/components/vf-paragraph.d.ts +3 -3
  23. package/dist/components/vf-progress-bar.d.ts +1 -1
  24. package/dist/components/vf-scroll-area.d.ts +1 -1
  25. package/dist/components/vf-select.d.ts +1 -1
  26. package/dist/components/vf-separator.d.ts +1 -1
  27. package/dist/components/vf-slider.d.ts +1 -1
  28. package/dist/components/vf-stack.d.ts +27 -9
  29. package/dist/components/vf-stack.js +30 -8
  30. package/dist/components/vf-swatch.d.ts +1 -1
  31. package/dist/components/vf-window.d.ts +1 -1
  32. package/dist/cross-center.d.ts +76 -0
  33. package/dist/cross-center.js +69 -0
  34. package/dist/define.d.ts +2 -2
  35. package/dist/define.js +1 -1
  36. package/dist/grid-snap.d.ts +2 -24
  37. package/dist/grid-snap.js +7 -33
  38. package/dist/index.d.ts +5 -5
  39. package/dist/index.js +50 -50
  40. package/dist/position.d.ts +11 -2
  41. package/dist/styles/recipes/host.js +14 -1
  42. package/dist/styles/recipes/toggle.js +16 -0
  43. package/dist/text-control.d.ts +1 -1
  44. package/docs/SPEC.md +287 -2249
  45. package/editor/vscode.html-custom-data.json +48 -8
  46. package/editor/web-types.json +92 -12
  47. package/package.json +2 -4
package/README.md CHANGED
@@ -1,262 +1,41 @@
1
1
  # Vintage Frames
2
2
 
3
- Lit web components that rebuild the Mac OS System 7 interface — racing-stripe
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
- - **[Showcase](https://aportilla.github.io/vintage-frames/)** a full faux
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
- ```ts
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
- ```html
30
- <vf-desktop width="512" height="342">
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
- ## Components
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
- Those subpaths and the root are the whole export surface; a deeper path fails
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
- Every component is authored in *system pixels* the 1-bit art grid, where a
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
- ## Window archetypes
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
- The 1992 *Macintosh Human Interface Guidelines* names five standard windows.
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
- Keyboard focus is drawn in the 1-bit vocabulary a dashed underline on the
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.