vintage-frames 0.18.0 → 0.19.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 CHANGED
@@ -25,7 +25,7 @@ There is no need to import a stylesheet. The components carry their styles with
25
25
 
26
26
  ## The shell
27
27
 
28
- `vintage-frames/shell` is an experimental second entry point that runs applications over one desktop: a window manager, a menu bar that shows the front application's menus, and a Finder with folders, filing, Clean Up and the Trash.
28
+ `vintage-frames/shell` is an experimental second entry point that runs applications over one desktop: a window manager, a menu bar that shows the front application's menus, and a Finder with folders, aliases, filing, Clean Up and the Trash. A System Folder's contents set the Apple menu and what opens at startup.
29
29
 
30
30
  ```ts
31
31
  import 'vintage-frames'
@@ -5681,6 +5681,17 @@
5681
5681
  "attribute": "open",
5682
5682
  "reflects": true
5683
5683
  },
5684
+ {
5685
+ "kind": "field",
5686
+ "name": "alias",
5687
+ "type": {
5688
+ "text": "boolean"
5689
+ },
5690
+ "default": "false",
5691
+ "description": "The icon is an alias, an item standing for another: its name is set in\nitalics, the body face's own, and the plate widens to the slant's last\npixel.",
5692
+ "attribute": "alias",
5693
+ "reflects": true
5694
+ },
5684
5695
  {
5685
5696
  "kind": "field",
5686
5697
  "name": "movable",
@@ -6272,6 +6283,25 @@
6272
6283
  },
6273
6284
  "description": "Size the plate to a whole, EVEN number of system pixels.\n\nThis is the whole alignment argument, so it is worth stating plainly. The\nframe centers two things over one axis — the art cell and the name — and a\ncentered child's offset is `(box − child) / 2`. That is a whole number\nexactly when the box and the child have the SAME PARITY. The cell is 32 or\n16 and a declared `width` is required even, so if the plate is even too,\nevery offset in the component is whole by construction: no correction, no\nsnapping, nothing for the compositor to round.\n\nThe text is measured rather than the plate, with a Range over its own\ncontents — the plate already carries the width this computed last time, so\nreading the element back would just return it. The measurement is in\nsystem px and so is scale-invariant: the same name is the same number of\nart pixels wide at every display density, which is why nothing here\nre-runs when the scale changes.\n\nRounding UP to even (never down) means the plate never clips the run it\nwas measured from; the leftover is at most one system pixel of extra plate\nafter the text, since the embedded faces advance in whole pixels and only\na fallback face measures fractionally."
6274
6285
  },
6286
+ {
6287
+ "kind": "method",
6288
+ "name": "#lean",
6289
+ "privacy": "private",
6290
+ "return": {
6291
+ "type": {
6292
+ "text": "number"
6293
+ }
6294
+ },
6295
+ "parameters": [
6296
+ {
6297
+ "name": "plate",
6298
+ "type": {
6299
+ "text": "HTMLElement"
6300
+ }
6301
+ }
6302
+ ],
6303
+ "description": "How far an alias's italic name runs past its advance, in whole system px:\nthe slant leans the tops of the last letters right, by up to 5. Read off\nthe glyphs' ink, in a canvas set in the plate's own font."
6304
+ },
6275
6305
  {
6276
6306
  "kind": "field",
6277
6307
  "name": "#plateWidthCss",
@@ -6769,6 +6799,15 @@
6769
6799
  "description": "The icon's window is on screen, so the art paints as the Finder's open\nghost — outline held, interior re-filled with the kit's loose dither —\nderived in the client from the slotted art itself (see the class doc).\nSet it when handling `vf-open`, clear it when the window goes away.\nSelection inverts the ghost exactly as it inverts the art.",
6770
6800
  "fieldName": "open"
6771
6801
  },
6802
+ {
6803
+ "name": "alias",
6804
+ "type": {
6805
+ "text": "boolean"
6806
+ },
6807
+ "default": "false",
6808
+ "description": "The icon is an alias, an item standing for another: its name is set in\nitalics, the body face's own, and the plate widens to the slant's last\npixel.",
6809
+ "fieldName": "alias"
6810
+ },
6772
6811
  {
6773
6812
  "name": "movable",
6774
6813
  "type": {
@@ -6,8 +6,8 @@
6
6
  import type { AppManifest } from '../shell/app-file.js';
7
7
  /** What {@link packApp} packs. */
8
8
  export interface PackAppInput {
9
- /** The manifest's fields but its format and icon, which the packer fills in. */
10
- manifest: Omit<AppManifest, 'format' | 'icon'>;
9
+ /** The manifest's fields but its format, app API and icon, which the packer fills in. */
10
+ manifest: Omit<AppManifest, 'format' | 'api' | 'icon'>;
11
11
  /** The icon's PNG, 32 × 32. */
12
12
  icon: Uint8Array;
13
13
  /** The application's code: one ES module whose default export is its factory. */
@@ -24,6 +24,7 @@ async function p({ manifest: e, icon: t, code: n, artwork: r }) {
24
24
  let i = {
25
25
  ...e,
26
26
  format: 1,
27
+ api: 2,
27
28
  icon: `data:image/png;base64,${m(t)}`
28
29
  };
29
30
  return f(await l({
@@ -32,8 +32,8 @@ export interface AppFileOptions {
32
32
  export declare function appFile(options: AppFileOptions): Plugin;
33
33
  /**
34
34
  * Builds app files into a site. An import of `*.png?app` reads the file and
35
- * refuses one that isn't an app file, or whose `requires` this kit's
36
- * version doesn't meet. Its default export is the application's factory,
35
+ * refuses one that isn't an app file, or one this kit doesn't run
36
+ * (`appRuns`). Its default export is the application's factory,
37
37
  * its definition given the manifest's icon, and `manifest` is the manifest.
38
38
  * The code imports the kit by name, so the page keeps one copy of it. A new
39
39
  * file reloads the dev server's page.
@@ -1,41 +1,41 @@
1
- import { inspectAppFile as e, isVersion as t, satisfies as n } from "../shell/app-file.js";
2
- import { VERSION as r } from "../shell/version.js";
3
- import { packApp as i } from "./app-file.js";
4
- import { mkdir as a, readFile as o, writeFile as s } from "node:fs/promises";
5
- import { join as c, relative as l, resolve as u } from "node:path";
1
+ import { VERSION as e } from "../shell/version.js";
2
+ import { appRuns as t, inspectAppFile as n, isVersion as r, satisfies as i } from "../shell/app-file.js";
3
+ import { packApp as a } from "./app-file.js";
4
+ import { mkdir as o, readFile as s, writeFile as c } from "node:fs/promises";
5
+ import { join as l, relative as u, resolve as d } from "node:path";
6
6
  //#region src/build/plugins.ts
7
- var d = [
7
+ var f = [
8
8
  "vintage-frames",
9
9
  "vintage-frames/shell",
10
10
  "vintage-frames/shell/pure"
11
- ], f = "app-code";
12
- function p(e) {
11
+ ], p = "app-code";
12
+ function m(e) {
13
13
  let t = e.match(/(?<=[\\/]node_modules[\\/])(?:@[^\\/]+[\\/])?[^\\/]+/g)?.at(-1)?.replace("\\", "/");
14
14
  return t === "vintage-frames" ? "a copy of vintage-frames" : t && /^(?:lit|lit-html|lit-element|@lit\/.+|@lit-labs\/.+)$/.test(t) ? `Lit (${t})` : null;
15
15
  }
16
- async function m(e) {
17
- let n = JSON.parse(await o(c(e, "package.json"), "utf8")), i = n.devDependencies?.["vintage-frames"] ?? n.dependencies?.["vintage-frames"];
16
+ async function h(t) {
17
+ let n = JSON.parse(await s(l(t, "package.json"), "utf8")), i = n.devDependencies?.["vintage-frames"] ?? n.dependencies?.["vintage-frames"];
18
18
  if (typeof i != "string") throw Error("package.json has no vintage-frames dev dependency");
19
- if (!i.startsWith("^") || !t(i.slice(1))) throw Error(`package.json's vintage-frames range is "${i}", and an app file requires a caret range: ^${r}`);
19
+ if (!i.startsWith("^") || !r(i.slice(1))) throw Error(`package.json's vintage-frames range is "${i}", and an app file requires a caret range: ^${e}`);
20
20
  return i;
21
21
  }
22
- function h(e) {
23
- let { app: l, entry: f, icon: h, artwork: g, copyTo: _ } = e;
22
+ function g(t) {
23
+ let { app: n, entry: u, icon: p, artwork: g, copyTo: _ } = t;
24
24
  for (let e of [
25
25
  "id",
26
26
  "name",
27
27
  "version",
28
28
  "author"
29
- ]) if (typeof l?.[e] != "string" || !l[e]) throw Error(`vintage-frames appFile(): app.${e} is missing`);
30
- if (!t(l.version)) throw Error(`vintage-frames appFile(): app.version, ${l.version}, is not a version`);
31
- if (!f || !h) throw Error(`vintage-frames appFile(): ${f ? "icon" : "entry"} is missing`);
32
- let v = `${l.name.replace(/[\\/:*?"<>|]/g, "-")}.png`, y = "", b = null;
29
+ ]) if (typeof n?.[e] != "string" || !n[e]) throw Error(`vintage-frames appFile(): app.${e} is missing`);
30
+ if (!r(n.version)) throw Error(`vintage-frames appFile(): app.version, ${n.version}, is not a version`);
31
+ if (!u || !p) throw Error(`vintage-frames appFile(): ${u ? "icon" : "entry"} is missing`);
32
+ let v = `${n.name.replace(/[\\/:*?"<>|]/g, "-")}.png`, y = "", b = null;
33
33
  return {
34
34
  name: "vintage-frames:app-file",
35
35
  apply: "build",
36
36
  config: () => ({ build: {
37
37
  lib: {
38
- entry: f,
38
+ entry: u,
39
39
  formats: ["es"],
40
40
  fileName: "app"
41
41
  },
@@ -50,44 +50,44 @@ function h(e) {
50
50
  },
51
51
  buildStart() {
52
52
  for (let e of [
53
- h,
53
+ p,
54
54
  g,
55
55
  "package.json"
56
- ]) e && this.addWatchFile(u(y, e));
56
+ ]) e && this.addWatchFile(d(y, e));
57
57
  },
58
58
  generateBundle: {
59
59
  order: "post",
60
- async handler(e, t) {
61
- let a = Object.values(t), s = a.filter((e) => e.type === "chunk"), c = a.filter((e) => e.type === "asset").map((e) => e.fileName);
62
- c.length && this.error(`${l.name} emits ${c.join(", ")} beside its code, and an app file holds one module: no CSS import, no source map file, its art inlined.`);
63
- let [f] = s;
64
- (!f || s.length > 1) && this.error(`${l.name} builds to ${s.length} modules, and an app file holds one.`);
65
- for (let e of Object.keys(f.modules)) {
66
- let t = p(e);
67
- t && this.error(`${l.name} bundles ${t}. It composes the page's kit and brings none of its own.`);
60
+ async handler(t, r) {
61
+ let o = Object.values(r), c = o.filter((e) => e.type === "chunk"), l = o.filter((e) => e.type === "asset").map((e) => e.fileName);
62
+ l.length && this.error(`${n.name} emits ${l.join(", ")} beside its code, and an app file holds one module: no CSS import, no source map file, its art inlined.`);
63
+ let [u] = c;
64
+ (!u || c.length > 1) && this.error(`${n.name} builds to ${c.length} modules, and an app file holds one.`);
65
+ for (let e of Object.keys(u.modules)) {
66
+ let t = m(e);
67
+ t && this.error(`${n.name} bundles ${t}. It composes the page's kit and brings none of its own.`);
68
68
  }
69
- let _ = [...f.imports, ...f.dynamicImports].filter((e) => !d.includes(e));
70
- _.length && this.error(`${l.name} imports ${_.join(", ")}. An application imports ${d.join(", ")} and its own files.`);
69
+ let _ = [...u.imports, ...u.dynamicImports].filter((e) => !f.includes(e));
70
+ _.length && this.error(`${n.name} imports ${_.join(", ")}. An application imports ${f.join(", ")} and its own files.`);
71
71
  try {
72
- let e = await m(y);
73
- if (!n("0.18.0", e)) throw Error(`package.json requires vintage-frames ${e}, and the build is on ${r}: move the range`);
74
- b = await i({
72
+ let t = await h(y);
73
+ if (!i("0.19.0", t)) throw Error(`package.json requires vintage-frames ${t}, and the build is on ${e}: move the range`);
74
+ b = await a({
75
75
  manifest: {
76
- id: l.id,
77
- name: l.name,
78
- version: l.version,
79
- requires: e,
80
- author: l.author,
81
- description: l.description
76
+ id: n.id,
77
+ name: n.name,
78
+ version: n.version,
79
+ requires: t,
80
+ author: n.author,
81
+ description: n.description
82
82
  },
83
- icon: new Uint8Array(await o(u(y, h))),
84
- code: f.code,
85
- artwork: g ? new Uint8Array(await o(u(y, g))) : void 0
83
+ icon: new Uint8Array(await s(d(y, p))),
84
+ code: u.code,
85
+ artwork: g ? new Uint8Array(await s(d(y, g))) : void 0
86
86
  });
87
87
  } catch (e) {
88
- this.error(`${l.name}: ${e.message}`);
88
+ this.error(`${n.name}: ${e.message}`);
89
89
  }
90
- delete t[f.fileName], this.emitFile({
90
+ delete r[u.fileName], this.emitFile({
91
91
  type: "asset",
92
92
  fileName: v,
93
93
  source: b
@@ -96,31 +96,34 @@ function h(e) {
96
96
  },
97
97
  async writeBundle() {
98
98
  if (!_ || !b) return;
99
- let e = u(y, _);
100
- await a(e, { recursive: !0 }), await s(c(e, v), b);
99
+ let e = d(y, _);
100
+ await o(e, { recursive: !0 }), await c(l(e, v), b);
101
101
  }
102
102
  };
103
103
  }
104
- function g() {
105
- let t = "";
104
+ function _(t) {
105
+ return t.api === void 0 ? `requires vintage-frames ${t.requires}, and this site has ${e}` : `is built for app API ${t.api}, and this site's kit runs app API 2`;
106
+ }
107
+ function v() {
108
+ let r = "";
106
109
  return {
107
110
  name: "vintage-frames:app-files",
108
111
  enforce: "pre",
109
112
  configResolved(e) {
110
- t = e.root;
113
+ r = e.root;
111
114
  },
112
115
  async load(i) {
113
116
  let a = i.indexOf("?");
114
117
  if (a < 0) return null;
115
- let s = i.slice(0, a), c = new URLSearchParams(i.slice(a + 1));
116
- if (!s.endsWith(".png") || !(c.has("app") || c.has(f))) return null;
117
- this.addWatchFile(s);
118
- let u = l(t, s), d = await e(new Uint8Array(await o(s)));
119
- typeof d == "string" && this.error(`${u} is not an app file: ${d}.`);
120
- let { manifest: p, code: m } = d;
121
- return c.has(f) ? m : (n("0.18.0", p.requires) || this.error(`${u}: ${p.name} ${p.version} requires vintage-frames ${p.requires}, and this site has ${r}. Build ${p.name} on ${r} and copy its app file in.`), [
122
- `import factory from ${JSON.stringify(`${s}?${f}`)}`,
123
- `export const manifest = ${JSON.stringify(p)}`,
118
+ let o = i.slice(0, a), c = new URLSearchParams(i.slice(a + 1));
119
+ if (!o.endsWith(".png") || !(c.has("app") || c.has(p))) return null;
120
+ this.addWatchFile(o);
121
+ let l = u(r, o), d = await n(new Uint8Array(await s(o)));
122
+ typeof d == "string" && this.error(`${l} is not an app file: ${d}.`);
123
+ let { manifest: f, code: m } = d;
124
+ return c.has(p) ? m : (t(f) || this.error(`${l}: ${f.name} ${f.version} ${_(f)}. Build ${f.name} on ${e} and copy its app file in.`), [
125
+ `import factory from ${JSON.stringify(`${o}?${p}`)}`,
126
+ `export const manifest = ${JSON.stringify(f)}`,
124
127
  "export default (...args) => ({ ...factory(...args), icon: manifest.icon })",
125
128
  ""
126
129
  ].join("\n"));
@@ -128,4 +131,4 @@ function g() {
128
131
  };
129
132
  }
130
133
  //#endregion
131
- export { h as appFile, g as appFiles };
134
+ export { g as appFile, v as appFiles };
@@ -1,4 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
+ import '../styles/body-italic-font.js';
2
3
  /** Which member of the icon family paints — the two System 7 resource sizes. */
3
4
  export type VfIconSize = 'large' | 'small';
4
5
  /**
@@ -523,6 +524,12 @@ export declare class VfIcon extends VfIcon_base {
523
524
  * Selection inverts the ghost exactly as it inverts the art.
524
525
  */
525
526
  open: boolean;
527
+ /**
528
+ * The icon is an alias, an item standing for another: its name is set in
529
+ * italics, the body face's own, and the plate widens to the slant's last
530
+ * pixel.
531
+ */
532
+ alias: boolean;
526
533
  /**
527
534
  * Drag to move — `movable`, never `draggable`, which is a platform attribute
528
535
  * and accessor (see the class doc). Arrow keys move a focused icon too, which