@inkandswitch/patchwork-pkg-base 0.0.77 → 0.0.79

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.
@@ -1 +1 @@
1
- automerge:rLkAjbaRPW3NECRfSP5kdrfeRUa
1
+ automerge:33GLVfPfbJyp9X1keJrvthsJUaKf
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkandswitch/patchwork-pkg-base",
3
- "version": "0.0.77",
3
+ "version": "0.0.79",
4
4
  "type": "module",
5
5
  "description": "Base packages for the Patchwork system",
6
6
  "repository": {
@@ -0,0 +1,62 @@
1
+ // src/links.js
2
+ import {
3
+ isImmutableString,
4
+ isValidAutomergeUrl
5
+ } from "@automerge/automerge-repo/slim";
6
+ function asString(v) {
7
+ if (typeof v === "string") return v;
8
+ if (isImmutableString(v)) return String(v);
9
+ return void 0;
10
+ }
11
+ function asUrl(v) {
12
+ const s = asString(v);
13
+ return s !== void 0 && isValidAutomergeUrl(s) ? s : void 0;
14
+ }
15
+ function isDirectoryDoc(doc) {
16
+ return asString(doc?.["@patchwork"]?.type) === "directory";
17
+ }
18
+ var DIRECTORY_RESERVED = /* @__PURE__ */ new Set(["@patchwork", "lastSyncAt"]);
19
+ function fileType(name) {
20
+ const dot = name.lastIndexOf(".");
21
+ return dot > 0 ? name.slice(dot + 1) : "file";
22
+ }
23
+ function folderLinks(doc) {
24
+ const links = [];
25
+ for (const link of Array.isArray(doc?.docs) ? doc.docs : []) {
26
+ const url = asUrl(link?.url);
27
+ if (!url) continue;
28
+ links.push({
29
+ url,
30
+ name: asString(link.name) ?? "Untitled",
31
+ type: asString(link.type) ?? ""
32
+ });
33
+ }
34
+ return links;
35
+ }
36
+ function directoryLinks(doc, path = "") {
37
+ const prefix = path ? `${path}/` : "";
38
+ const dirs = /* @__PURE__ */ new Set();
39
+ const files = [];
40
+ for (const [key, value] of Object.entries(doc ?? {})) {
41
+ if (DIRECTORY_RESERVED.has(key) || !key.startsWith(prefix)) continue;
42
+ const url = asUrl(value);
43
+ if (!url) continue;
44
+ const rest = key.slice(prefix.length).split("/").filter(Boolean);
45
+ if (rest.length === 0) continue;
46
+ if (rest.length > 1) dirs.add(rest[0]);
47
+ else files.push({ url, name: rest[0], type: fileType(rest[0]) });
48
+ }
49
+ const byName = (a, b) => a.name.localeCompare(b.name);
50
+ return [
51
+ ...[...dirs].map((name) => ({ name, type: "folder", path: prefix + name })).sort(byName),
52
+ ...files.sort(byName)
53
+ ];
54
+ }
55
+
56
+ export {
57
+ asString,
58
+ isDirectoryDoc,
59
+ folderLinks,
60
+ directoryLinks
61
+ };
62
+ //# sourceMappingURL=chunk-WN53YCSZ.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/links.js"],
4
+ "sourcesContent": ["import {\n isImmutableString,\n isValidAutomergeUrl,\n} from \"@automerge/automerge-repo/slim\";\n\n/**\n * A folder entry as the view sees it, whichever doc shape it came from.\n * `path` is set (and `url` isn't) for a subdirectory of a pushwork directory\n * doc, which has no doc of its own.\n * @typedef {{ name: string, type: string, url?: string, path?: string }} Link\n */\n\n// Any string in a doc may be stored as a plain string or as an\n// ImmutableString (pushwork writes links that way); read them the same.\nexport function asString(v) {\n if (typeof v === \"string\") return v;\n if (isImmutableString(v)) return String(v);\n return undefined;\n}\n\nexport function asUrl(v) {\n const s = asString(v);\n return s !== undefined && isValidAutomergeUrl(s) ? s : undefined;\n}\n\n// A pushwork \"vfs\" directory doc:\n// { \"@patchwork\": { type: \"directory\", title? }, \"a/b.txt\": url, ... }\n// Every other key is a slash-separated path to a leaf doc.\nexport function isDirectoryDoc(doc) {\n return asString(doc?.[\"@patchwork\"]?.type) === \"directory\";\n}\n\nconst DIRECTORY_RESERVED = new Set([\"@patchwork\", \"lastSyncAt\"]);\n\n// Mirrors pushwork's folder shape, which types a file link by its extension.\nfunction fileType(name) {\n const dot = name.lastIndexOf(\".\");\n return dot > 0 ? name.slice(dot + 1) : \"file\";\n}\n\n/** @returns {Link[]} the links in a folder doc's `docs` list. */\nexport function folderLinks(doc) {\n const links = [];\n for (const link of Array.isArray(doc?.docs) ? doc.docs : []) {\n const url = asUrl(link?.url);\n if (!url) continue;\n links.push({\n url,\n name: asString(link.name) ?? \"Untitled\",\n type: asString(link.type) ?? \"\",\n });\n }\n return links;\n}\n\n/**\n * The immediate children of `path` (\"\" for the top) in a directory doc:\n * subdirectories first, then files, each by name.\n * @returns {Link[]}\n */\nexport function directoryLinks(doc, path = \"\") {\n const prefix = path ? `${path}/` : \"\";\n const dirs = new Set();\n const files = [];\n for (const [key, value] of Object.entries(doc ?? {})) {\n if (DIRECTORY_RESERVED.has(key) || !key.startsWith(prefix)) continue;\n const url = asUrl(value);\n if (!url) continue;\n const rest = key.slice(prefix.length).split(\"/\").filter(Boolean);\n if (rest.length === 0) continue;\n if (rest.length > 1) dirs.add(rest[0]);\n else files.push({ url, name: rest[0], type: fileType(rest[0]) });\n }\n const byName = (a, b) => a.name.localeCompare(b.name);\n return [\n ...[...dirs]\n .map((name) => ({ name, type: \"folder\", path: prefix + name }))\n .sort(byName),\n ...files.sort(byName),\n ];\n}\n"],
5
+ "mappings": ";AAAA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAWA,SAAS,SAAS,GAAG;AAC1B,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,kBAAkB,CAAC,EAAG,QAAO,OAAO,CAAC;AACzC,SAAO;AACT;AAEO,SAAS,MAAM,GAAG;AACvB,QAAM,IAAI,SAAS,CAAC;AACpB,SAAO,MAAM,UAAa,oBAAoB,CAAC,IAAI,IAAI;AACzD;AAKO,SAAS,eAAe,KAAK;AAClC,SAAO,SAAS,MAAM,YAAY,GAAG,IAAI,MAAM;AACjD;AAEA,IAAM,qBAAqB,oBAAI,IAAI,CAAC,cAAc,YAAY,CAAC;AAG/D,SAAS,SAAS,MAAM;AACtB,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,SAAO,MAAM,IAAI,KAAK,MAAM,MAAM,CAAC,IAAI;AACzC;AAGO,SAAS,YAAY,KAAK;AAC/B,QAAM,QAAQ,CAAC;AACf,aAAW,QAAQ,MAAM,QAAQ,KAAK,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG;AAC3D,UAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,QAAI,CAAC,IAAK;AACV,UAAM,KAAK;AAAA,MACT;AAAA,MACA,MAAM,SAAS,KAAK,IAAI,KAAK;AAAA,MAC7B,MAAM,SAAS,KAAK,IAAI,KAAK;AAAA,IAC/B,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAOO,SAAS,eAAe,KAAK,OAAO,IAAI;AAC7C,QAAM,SAAS,OAAO,GAAG,IAAI,MAAM;AACnC,QAAM,OAAO,oBAAI,IAAI;AACrB,QAAM,QAAQ,CAAC;AACf,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,CAAC,CAAC,GAAG;AACpD,QAAI,mBAAmB,IAAI,GAAG,KAAK,CAAC,IAAI,WAAW,MAAM,EAAG;AAC5D,UAAM,MAAM,MAAM,KAAK;AACvB,QAAI,CAAC,IAAK;AACV,UAAM,OAAO,IAAI,MAAM,OAAO,MAAM,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/D,QAAI,KAAK,WAAW,EAAG;AACvB,QAAI,KAAK,SAAS,EAAG,MAAK,IAAI,KAAK,CAAC,CAAC;AAAA,QAChC,OAAM,KAAK,EAAE,KAAK,MAAM,KAAK,CAAC,GAAG,MAAM,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;AAAA,EACjE;AACA,QAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI;AACpD,SAAO;AAAA,IACL,GAAG,CAAC,GAAG,IAAI,EACR,IAAI,CAAC,UAAU,EAAE,MAAM,MAAM,UAAU,MAAM,SAAS,KAAK,EAAE,EAC7D,KAAK,MAAM;AAAA,IACd,GAAG,MAAM,KAAK,MAAM;AAAA,EACtB;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,41 @@
1
+ import {
2
+ asString
3
+ } from "./chunk-WN53YCSZ.js";
4
+
5
+ // src/datatype.js
6
+ var FolderDatatype = {
7
+ init(doc) {
8
+ doc.title = "New Folder";
9
+ doc.docs = [];
10
+ },
11
+ getTitle: (doc) => asString(doc.title) || "Unnamed Folder",
12
+ setTitle: (doc, title) => {
13
+ doc.title = title;
14
+ }
15
+ };
16
+ var DirectoryDatatype = {
17
+ init: () => {
18
+ throw new Error("Can't create an empty Directory");
19
+ },
20
+ getTitle: (doc) => asString(doc["@patchwork"]?.title) || "Unnamed Directory",
21
+ setTitle: (doc, title) => {
22
+ doc["@patchwork"].title = title;
23
+ }
24
+ };
25
+ var FileDatatype = {
26
+ init: () => {
27
+ throw new Error("Can't create empty File");
28
+ },
29
+ getTitle(doc) {
30
+ return asString(doc.name) || "Unnamed File";
31
+ },
32
+ setTitle(doc, title) {
33
+ doc.name = title;
34
+ }
35
+ };
36
+ export {
37
+ DirectoryDatatype,
38
+ FileDatatype,
39
+ FolderDatatype
40
+ };
41
+ //# sourceMappingURL=datatype-AGCTQZ52.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/datatype.js"],
4
+ "sourcesContent": ["import { asString } from './links.js';\n\nexport const FolderDatatype = {\n init(doc) {\n doc.title = 'New Folder';\n doc.docs = [];\n },\n getTitle: (doc) => asString(doc.title) || 'Unnamed Folder',\n setTitle: (doc, title) => {\n doc.title = title;\n },\n};\n\n// A pushwork directory doc: its title lives in its `@patchwork` metadata, and\n// its entries are made by pushwork, not here.\nexport const DirectoryDatatype = {\n init: () => {\n throw new Error(\"Can't create an empty Directory\");\n },\n getTitle: (doc) => asString(doc['@patchwork']?.title) || 'Unnamed Directory',\n setTitle: (doc, title) => {\n doc['@patchwork'].title = title;\n },\n};\n\nexport const FileDatatype = {\n init: () => {\n throw new Error(\"Can't create empty File\");\n },\n getTitle(doc) {\n return asString(doc.name) || 'Unnamed File';\n },\n setTitle(doc, title) {\n doc.name = title;\n },\n};\n"],
5
+ "mappings": ";;;;;AAEO,IAAM,iBAAiB;AAAA,EAC5B,KAAK,KAAK;AACR,QAAI,QAAQ;AACZ,QAAI,OAAO,CAAC;AAAA,EACd;AAAA,EACA,UAAU,CAAC,QAAQ,SAAS,IAAI,KAAK,KAAK;AAAA,EAC1C,UAAU,CAAC,KAAK,UAAU;AACxB,QAAI,QAAQ;AAAA,EACd;AACF;AAIO,IAAM,oBAAoB;AAAA,EAC/B,MAAM,MAAM;AACV,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAAA,EACA,UAAU,CAAC,QAAQ,SAAS,IAAI,YAAY,GAAG,KAAK,KAAK;AAAA,EACzD,UAAU,CAAC,KAAK,UAAU;AACxB,QAAI,YAAY,EAAE,QAAQ;AAAA,EAC5B;AACF;AAEO,IAAM,eAAe;AAAA,EAC1B,MAAM,MAAM;AACV,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAAA,EACA,SAAS,KAAK;AACZ,WAAO,SAAS,IAAI,IAAI,KAAK;AAAA,EAC/B;AAAA,EACA,SAAS,KAAK,OAAO;AACnB,QAAI,OAAO;AAAA,EACb;AACF;",
6
+ "names": []
7
+ }
@@ -6,17 +6,28 @@ var plugins = [
6
6
  name: "Folder",
7
7
  icon: "Folder",
8
8
  async load() {
9
- const { FolderDatatype } = await import("./datatype-HWGUFBTQ.js");
9
+ const { FolderDatatype } = await import("./datatype-AGCTQZ52.js");
10
10
  return FolderDatatype;
11
11
  }
12
12
  },
13
+ {
14
+ type: "patchwork:datatype",
15
+ id: "directory",
16
+ name: "Directory",
17
+ icon: "Folder",
18
+ unlisted: true,
19
+ async load() {
20
+ const { DirectoryDatatype } = await import("./datatype-AGCTQZ52.js");
21
+ return DirectoryDatatype;
22
+ }
23
+ },
13
24
  {
14
25
  type: "patchwork:tool",
15
26
  id: "folder-viewer",
16
27
  name: "Folder Viewer",
17
- supportedDatatypes: ["folder"],
28
+ supportedDatatypes: ["folder", "directory"],
18
29
  async load() {
19
- const { FolderTool } = await import("./tool-EOCAL24F.js");
30
+ const { FolderTool } = await import("./tool-JSQNX2I6.js");
20
31
  return FolderTool;
21
32
  }
22
33
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.js"],
4
- "sourcesContent": ["export const plugins = [\n {\n type: 'patchwork:datatype',\n id: 'folder',\n name: 'Folder',\n icon: 'Folder',\n async load() {\n const { FolderDatatype } = await import('./datatype.js');\n return FolderDatatype;\n },\n },\n {\n type: 'patchwork:tool',\n id: 'folder-viewer',\n name: 'Folder Viewer',\n supportedDatatypes: ['folder'],\n async load() {\n const { FolderTool } = await import('./tool.js');\n return FolderTool;\n },\n }\n];\n"],
5
- "mappings": ";AAAO,IAAM,UAAU;AAAA,EACrB;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,OAAO;AACX,YAAM,EAAE,eAAe,IAAI,MAAM,OAAO,wBAAe;AACvD,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,oBAAoB,CAAC,QAAQ;AAAA,IAC7B,MAAM,OAAO;AACX,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAW;AAC/C,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["export const plugins = [\n {\n type: 'patchwork:datatype',\n id: 'folder',\n name: 'Folder',\n icon: 'Folder',\n async load() {\n const { FolderDatatype } = await import('./datatype.js');\n return FolderDatatype;\n },\n },\n {\n type: 'patchwork:datatype',\n id: 'directory',\n name: 'Directory',\n icon: 'Folder',\n unlisted: true,\n async load() {\n const { DirectoryDatatype } = await import('./datatype.js');\n return DirectoryDatatype;\n },\n },\n {\n type: 'patchwork:tool',\n id: 'folder-viewer',\n name: 'Folder Viewer',\n supportedDatatypes: ['folder', 'directory'],\n async load() {\n const { FolderTool } = await import('./tool.js');\n return FolderTool;\n },\n }\n];\n"],
5
+ "mappings": ";AAAO,IAAM,UAAU;AAAA,EACrB;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,OAAO;AACX,YAAM,EAAE,eAAe,IAAI,MAAM,OAAO,wBAAe;AACvD,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,MAAM,OAAO;AACX,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,wBAAe;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,oBAAoB,CAAC,UAAU,WAAW;AAAA,IAC1C,MAAM,OAAO;AACX,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAW;AAC/C,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,10 @@
1
+ import {
2
+ asString,
3
+ directoryLinks,
4
+ folderLinks,
5
+ isDirectoryDoc
6
+ } from "./chunk-WN53YCSZ.js";
7
+
1
8
  // src/tool.js
2
9
  import {
3
10
  parseAutomergeUrl,
@@ -10,7 +17,7 @@ import {
10
17
  } from "@inkandswitch/patchwork-plugins";
11
18
 
12
19
  // src/styles.css
13
- var styles_default = "@layer package {\n:root,\n:host,\n[theme] {\n /* The well the cards sit in \u2014 slightly recessed surface. */\n --folder-view-well: var(--editor-fill-offset-10, #f2f2f2);\n --folder-view-well-edge: var(--editor-fill-offset-30, #d6d6d6);\n --folder-view-fg: var(--editor-line, black);\n --folder-view-muted: var(--editor-line-offset-50, #999);\n --folder-view-border: var(--editor-fill-offset-20, #e5e5e5);\n\n /* A card = a raised surface sitting on the well. */\n --folder-view-card: var(--editor-fill, white);\n --folder-view-card-border: var(--editor-fill-offset-20, #e5e5e5);\n\n --folder-view-accent: var(--studio-primary-fill, var(--studio-primary, #35f7ca));\n --folder-view-accent-line: var(--studio-primary-line, var(--editor-fill, white));\n --folder-view-accent-text: var(--editor-primary-text, var(--studio-primary-text, var(--studio-primary, #35f7ca)));\n --folder-view-hover: var(--editor-fill-offset-10, #f2f2f2);\n\n /* Layered drop shadow so a card reads as a solid object resting on the\n well \u2014 a tight contact shadow plus a softer cast one. Derived from the\n theme line colour so it inverts in dark themes. */\n --folder-view-card-shadow: 0 1px 2px\n color-mix(in oklch, var(--editor-line, black), transparent 94%),\n 0 2px 8px color-mix(in oklch, var(--editor-line, black), transparent 96%);\n --folder-view-card-shadow-hover: 0 2px 4px\n color-mix(in oklch, var(--editor-line, black), transparent 90%),\n 0 8px 20px color-mix(in oklch, var(--editor-line, black), transparent 93%);\n\n --folder-view-family: var(--editor-family-sans, system-ui, sans-serif);\n}\n}\n\n/* Block: the whole tool. A sunken well with an inset edge. */\n.folder-view {\n height: 100%;\n overflow: auto;\n padding: var(--studio-space-md, 1rem);\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-fg);\n background: var(--folder-view-well);\n /* No outer border: the host frame already draws the lines around the pane, so\n the well reads as flush rather than double-edged. */\n}\n\n/* State: a document is being dragged in from the sidebar. Outline the well\n with the accent colour so it reads as an active drop target. */\n.folder-view[data-drop-active] {\n border-color: var(--folder-view-accent);\n box-shadow: inset 0 0 0 2px var(--folder-view-accent);\n}\n\n/* Composition: header row. New-doc button on the left, count on the right. */\n.folder-view .folder-view-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding-bottom: var(--studio-space-sm, 0.5rem);\n border-bottom: 1px solid var(--folder-view-border);\n}\n\n/* Composition: the create-new control \u2014 a button anchoring a type-picker. */\n.folder-view .folder-create {\n position: relative;\n}\n\n.folder-view .folder-create-button {\n display: inline-flex;\n align-items: center;\n gap: var(--studio-space-2xs, 0.25rem);\n font: inherit;\n font-size: 0.8rem;\n color: var(--folder-view-accent-line);\n background: var(--folder-view-accent);\n border: 1px solid transparent;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n transition: filter var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-create-button:hover {\n filter: brightness(0.96);\n}\n\n.folder-view .folder-create-icon {\n font-size: 1rem;\n line-height: 1;\n}\n\n/* The type-picker popover, anchored under the button. */\n.folder-view .folder-create-menu {\n position: absolute;\n top: calc(100% + var(--studio-space-2xs, 0.25rem));\n left: 0;\n z-index: 10;\n min-width: 12rem;\n max-height: 16rem;\n overflow: auto;\n display: flex;\n flex-direction: column;\n padding: var(--studio-space-3xs, 0.125rem);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-md, 8px);\n box-shadow: var(--folder-view-card-shadow-hover);\n}\n\n.folder-view .folder-create-menu[hidden] {\n display: none;\n}\n\n.folder-view .folder-create-item {\n text-align: left;\n font: inherit;\n font-size: 0.85rem;\n color: var(--folder-view-fg);\n background: transparent;\n border: 0;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n}\n\n.folder-view .folder-create-item:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-create-empty {\n padding: var(--studio-space-sm, 0.5rem);\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n}\n\n.folder-view .folder-view-count {\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-round, 9999px);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-border);\n}\n\n/* Composition: the list of cards. */\n.folder-view .folder-view-list {\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n padding-bottom: var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-view-empty {\n text-align: center;\n color: var(--folder-view-muted);\n padding: var(--studio-space-xl, 2rem) 0;\n}\n\n.folder-view-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-muted);\n background: var(--folder-view-card);\n}\n\n/* Block: one rendered file/folder card \u2014 sitting on the well. */\n.folder-view .folder-entry {\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-lg, 12px);\n box-shadow: var(--folder-view-card-shadow);\n overflow: hidden;\n transition: box-shadow var(--studio-transition, 0.15s ease),\n transform var(--studio-transition, 0.15s ease);\n}\n\n.folder-view .folder-entry:hover {\n box-shadow: var(--folder-view-card-shadow-hover);\n /* Lift slightly so the card feels like it peels up off the well. */\n transform: translateY(-1px);\n}\n\n.folder-view .folder-entry-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding: var(--studio-space-sm, 0.5rem) var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-entry-title {\n display: flex;\n align-items: baseline;\n gap: var(--studio-space-sm, 0.5rem);\n min-width: 0;\n}\n\n.folder-view .folder-entry-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.folder-view .folder-entry-type {\n font-size: 0.7rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-3xs, 0.125rem) var(--studio-space-2xs, 0.25rem);\n border: 1px solid var(--folder-view-border);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.folder-view .folder-entry-open {\n font-size: 0.8rem;\n color: var(--folder-view-accent-text);\n text-decoration: none;\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n transition: background var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-entry-open:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-entry-hint {\n margin: 0;\n padding: 0 var(--studio-space-md, 1rem) var(--studio-space-md, 1rem);\n font-size: 0.85rem;\n color: var(--folder-view-muted);\n}\n\n/* Block: embedded preview body. */\n.folder-view .folder-entry-body {\n flex: 1 1 auto;\n min-height: 0;\n max-height: 300px;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--folder-view-border);\n}\n\n.folder-view .folder-entry-scroll {\n height: 100%;\n overflow: auto;\n}\n\n.folder-view .folder-entry-scroll patchwork-view {\n display: block;\n height: 100%;\n}\n";
20
+ var styles_default = "@layer package {\n:root,\n:host,\n[theme] {\n /* The well the cards sit in \u2014 slightly recessed surface. */\n --folder-view-well: var(--editor-fill-offset-10, #f2f2f2);\n --folder-view-well-edge: var(--editor-fill-offset-30, #d6d6d6);\n --folder-view-fg: var(--editor-line, black);\n --folder-view-muted: var(--editor-line-offset-50, #999);\n --folder-view-border: var(--editor-fill-offset-20, #e5e5e5);\n\n /* A card = a raised surface sitting on the well. */\n --folder-view-card: var(--editor-fill, white);\n --folder-view-card-border: var(--editor-fill-offset-20, #e5e5e5);\n\n --folder-view-accent: var(--studio-primary-fill, var(--studio-primary, #35f7ca));\n --folder-view-accent-line: var(--studio-primary-line, var(--editor-fill, white));\n --folder-view-accent-text: var(--editor-primary-text, var(--studio-primary-text, var(--studio-primary, #35f7ca)));\n --folder-view-hover: var(--editor-fill-offset-10, #f2f2f2);\n\n /* Layered drop shadow so a card reads as a solid object resting on the\n well \u2014 a tight contact shadow plus a softer cast one. Derived from the\n theme line colour so it inverts in dark themes. */\n --folder-view-card-shadow: 0 1px 2px\n color-mix(in oklch, var(--editor-line, black), transparent 94%),\n 0 2px 8px color-mix(in oklch, var(--editor-line, black), transparent 96%);\n --folder-view-card-shadow-hover: 0 2px 4px\n color-mix(in oklch, var(--editor-line, black), transparent 90%),\n 0 8px 20px color-mix(in oklch, var(--editor-line, black), transparent 93%);\n\n --folder-view-family: var(--editor-family-sans, system-ui, sans-serif);\n}\n}\n\n/* Block: the whole tool. A sunken well with an inset edge. */\n.folder-view {\n height: 100%;\n overflow: auto;\n padding: var(--studio-space-md, 1rem);\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-fg);\n background: var(--folder-view-well);\n /* No outer border: the host frame already draws the lines around the pane, so\n the well reads as flush rather than double-edged. */\n}\n\n/* State: a document is being dragged in from the sidebar. Outline the well\n with the accent colour so it reads as an active drop target. */\n.folder-view[data-drop-active] {\n border-color: var(--folder-view-accent);\n box-shadow: inset 0 0 0 2px var(--folder-view-accent);\n}\n\n/* Composition: header row. New-doc button on the left, count on the right. */\n.folder-view .folder-view-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding-bottom: var(--studio-space-sm, 0.5rem);\n border-bottom: 1px solid var(--folder-view-border);\n}\n\n/* Composition: where we are inside a pushwork directory doc, in place of the\n create-new control (pushwork owns those entries). */\n.folder-view .folder-view-crumbs:not([hidden]) {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--studio-space-2xs, 0.25rem);\n min-width: 0;\n font-size: 0.85rem;\n}\n\n.folder-view .folder-view-crumb {\n font: inherit;\n color: var(--folder-view-fg);\n background: none;\n border: none;\n padding: var(--studio-space-2xs, 0.25rem);\n border-radius: var(--studio-radius-sm, 4px);\n}\n\n.folder-view button.folder-view-crumb {\n color: var(--folder-view-accent-text);\n cursor: pointer;\n}\n\n.folder-view button.folder-view-crumb:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-view-crumb-sep {\n color: var(--folder-view-muted);\n}\n\n/* Composition: the create-new control \u2014 a button anchoring a type-picker. */\n.folder-view .folder-create {\n position: relative;\n}\n\n.folder-view .folder-create-button {\n display: inline-flex;\n align-items: center;\n gap: var(--studio-space-2xs, 0.25rem);\n font: inherit;\n font-size: 0.8rem;\n color: var(--folder-view-accent-line);\n background: var(--folder-view-accent);\n border: 1px solid transparent;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n transition: filter var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-create-button:hover {\n filter: brightness(0.96);\n}\n\n.folder-view .folder-create-icon {\n font-size: 1rem;\n line-height: 1;\n}\n\n/* The type-picker popover, anchored under the button. */\n.folder-view .folder-create-menu {\n position: absolute;\n top: calc(100% + var(--studio-space-2xs, 0.25rem));\n left: 0;\n z-index: 10;\n min-width: 12rem;\n max-height: 16rem;\n overflow: auto;\n display: flex;\n flex-direction: column;\n padding: var(--studio-space-3xs, 0.125rem);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-md, 8px);\n box-shadow: var(--folder-view-card-shadow-hover);\n}\n\n.folder-view .folder-create-menu[hidden] {\n display: none;\n}\n\n.folder-view .folder-create-item {\n text-align: left;\n font: inherit;\n font-size: 0.85rem;\n color: var(--folder-view-fg);\n background: transparent;\n border: 0;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n}\n\n.folder-view .folder-create-item:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-create-empty {\n padding: var(--studio-space-sm, 0.5rem);\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n}\n\n.folder-view .folder-view-count {\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-round, 9999px);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-border);\n}\n\n/* Composition: the list of cards. */\n.folder-view .folder-view-list {\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n padding-bottom: var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-view-empty {\n text-align: center;\n color: var(--folder-view-muted);\n padding: var(--studio-space-xl, 2rem) 0;\n}\n\n.folder-view-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-muted);\n background: var(--folder-view-card);\n}\n\n/* Block: one rendered file/folder card \u2014 sitting on the well. */\n.folder-view .folder-entry {\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-lg, 12px);\n box-shadow: var(--folder-view-card-shadow);\n overflow: hidden;\n transition: box-shadow var(--studio-transition, 0.15s ease),\n transform var(--studio-transition, 0.15s ease);\n}\n\n.folder-view .folder-entry:hover {\n box-shadow: var(--folder-view-card-shadow-hover);\n /* Lift slightly so the card feels like it peels up off the well. */\n transform: translateY(-1px);\n}\n\n.folder-view .folder-entry-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding: var(--studio-space-sm, 0.5rem) var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-entry-title {\n display: flex;\n align-items: baseline;\n gap: var(--studio-space-sm, 0.5rem);\n min-width: 0;\n}\n\n.folder-view .folder-entry-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.folder-view .folder-entry-type {\n font-size: 0.7rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-3xs, 0.125rem) var(--studio-space-2xs, 0.25rem);\n border: 1px solid var(--folder-view-border);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.folder-view .folder-entry-open {\n font: inherit;\n font-size: 0.8rem;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--folder-view-accent-text);\n text-decoration: none;\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n transition: background var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-entry-open:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-entry-hint {\n margin: 0;\n padding: 0 var(--studio-space-md, 1rem) var(--studio-space-md, 1rem);\n font-size: 0.85rem;\n color: var(--folder-view-muted);\n}\n\n/* Block: embedded preview body. */\n.folder-view .folder-entry-body {\n flex: 1 1 auto;\n min-height: 0;\n max-height: 300px;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--folder-view-border);\n}\n\n.folder-view .folder-entry-scroll {\n height: 100%;\n overflow: auto;\n}\n\n.folder-view .folder-entry-scroll patchwork-view {\n display: block;\n height: 100%;\n}\n";
14
21
 
15
22
  // src/tool.js
16
23
  var DND_DATA_TYPES = [
@@ -83,17 +90,28 @@ function el(tag, attrs, ...children) {
83
90
  function entryHref(docLink) {
84
91
  return `#doc=${parseAutomergeUrl(docLink.url).documentId}&type=${docLink.type}`;
85
92
  }
93
+ function entryKey(docLink) {
94
+ return docLink.url ?? `path:${docLink.path}`;
95
+ }
86
96
  function renderLoading() {
87
97
  return el("div", { className: "folder-view-loading" }, "Loading\u2026");
88
98
  }
89
- function buildEntry(docLink) {
99
+ function buildEntry(docLink, enter) {
90
100
  const isFolder = docLink.type === "folder";
91
101
  const nameEl = el("span", { className: "folder-entry-name" }, docLink.name);
92
102
  const typeEl = el("span", { className: "folder-entry-type" }, docLink.type);
93
- const openEl = el(
103
+ const openEl = docLink.url ? el(
94
104
  "a",
95
105
  { className: "folder-entry-open", href: entryHref(docLink) },
96
106
  "Open"
107
+ ) : el(
108
+ "button",
109
+ {
110
+ className: "folder-entry-open",
111
+ type: "button",
112
+ onClick: () => enter(docLink.path)
113
+ },
114
+ "Open"
97
115
  );
98
116
  const node = el(
99
117
  "div",
@@ -137,6 +155,7 @@ function updateEntry(entry, docLink) {
137
155
  if (entry.node.getAttribute("data-type") !== docLink.type) {
138
156
  entry.node.setAttribute("data-type", docLink.type);
139
157
  }
158
+ if (!docLink.url) return;
140
159
  const href = entryHref(docLink);
141
160
  if (entry.openEl.getAttribute("href") !== href) {
142
161
  entry.openEl.setAttribute("href", href);
@@ -242,8 +261,14 @@ var FolderTool = (handle, element) => {
242
261
  const entries = /* @__PURE__ */ new Map();
243
262
  const styleEl = el("style");
244
263
  styleEl.textContent = styles_default;
264
+ let path = "";
265
+ function enter(next) {
266
+ path = next;
267
+ render();
268
+ }
245
269
  const countEl = el("span", { className: "folder-view-count" });
246
270
  const listEl = el("div", { className: "folder-view-list" });
271
+ const crumbsEl = el("nav", { className: "folder-view-crumbs", hidden: "" });
247
272
  const createNew = buildCreateNew(handle, element);
248
273
  const shell = el(
249
274
  "div",
@@ -252,10 +277,32 @@ var FolderTool = (handle, element) => {
252
277
  "div",
253
278
  { className: "folder-view-header" },
254
279
  createNew.node,
280
+ crumbsEl,
255
281
  countEl
256
282
  ),
257
283
  listEl
258
284
  );
285
+ function renderCrumbs(title) {
286
+ const parts = path ? path.split("/") : [];
287
+ const crumbs = [{ name: title, path: "" }].concat(
288
+ parts.map((name, i) => ({ name, path: parts.slice(0, i + 1).join("/") }))
289
+ );
290
+ crumbsEl.replaceChildren(
291
+ ...crumbs.flatMap((crumb, i) => {
292
+ const last = i === crumbs.length - 1;
293
+ const node = last ? el("span", { className: "folder-view-crumb" }, crumb.name) : el(
294
+ "button",
295
+ {
296
+ className: "folder-view-crumb",
297
+ type: "button",
298
+ onClick: () => enter(crumb.path)
299
+ },
300
+ crumb.name
301
+ );
302
+ return i === 0 ? [node] : [el("span", { className: "folder-view-crumb-sep" }, "/"), node];
303
+ })
304
+ );
305
+ }
259
306
  element.append(styleEl);
260
307
  let dragDepth = 0;
261
308
  function endDrag() {
@@ -264,8 +311,8 @@ var FolderTool = (handle, element) => {
264
311
  }
265
312
  function addDroppedDocs(event) {
266
313
  const folder = handle.doc();
267
- if (!folder) return;
268
- const existing = new Set(folder.docs.map((docLink) => docLink.url));
314
+ if (!folder || isDirectoryDoc(folder)) return;
315
+ const existing = new Set(folderLinks(folder).map((docLink) => docLink.url));
269
316
  const selfUrl = handle.url;
270
317
  const links = [];
271
318
  for (const item of getDndItems(event)) {
@@ -280,27 +327,31 @@ var FolderTool = (handle, element) => {
280
327
  }
281
328
  if (links.length === 0) return;
282
329
  handle.change((doc) => {
330
+ if (!Array.isArray(doc.docs)) doc.docs = [];
283
331
  doc.docs.push(...links);
284
332
  });
285
333
  }
334
+ function acceptsDrops(event) {
335
+ return hasDocumentDrag(event.dataTransfer) && !isDirectoryDoc(handle.doc());
336
+ }
286
337
  shell.addEventListener("dragenter", (event) => {
287
- if (!hasDocumentDrag(event.dataTransfer)) return;
338
+ if (!acceptsDrops(event)) return;
288
339
  event.preventDefault();
289
340
  dragDepth++;
290
341
  shell.setAttribute("data-drop-active", "");
291
342
  });
292
343
  shell.addEventListener("dragover", (event) => {
293
- if (!hasDocumentDrag(event.dataTransfer)) return;
344
+ if (!acceptsDrops(event)) return;
294
345
  event.preventDefault();
295
346
  event.dataTransfer.dropEffect = "link";
296
347
  });
297
348
  shell.addEventListener("dragleave", (event) => {
298
- if (!hasDocumentDrag(event.dataTransfer)) return;
349
+ if (!acceptsDrops(event)) return;
299
350
  dragDepth--;
300
351
  if (dragDepth <= 0) endDrag();
301
352
  });
302
353
  shell.addEventListener("drop", (event) => {
303
- if (!hasDocumentDrag(event.dataTransfer)) return;
354
+ if (!acceptsDrops(event)) return;
304
355
  event.preventDefault();
305
356
  endDrag();
306
357
  addDroppedDocs(event);
@@ -320,8 +371,21 @@ var FolderTool = (handle, element) => {
320
371
  return;
321
372
  }
322
373
  show(shell);
323
- countEl.textContent = `${folder.docs.length} ${folder.docs.length === 1 ? "document" : "documents"}`;
324
- if (folder.docs.length === 0) {
374
+ const directory = isDirectoryDoc(folder);
375
+ let links;
376
+ if (directory) {
377
+ links = directoryLinks(folder, path);
378
+ renderCrumbs(
379
+ asString(folder["@patchwork"].title) || "Directory"
380
+ );
381
+ } else {
382
+ path = "";
383
+ links = folderLinks(folder);
384
+ }
385
+ createNew.node.hidden = directory;
386
+ crumbsEl.hidden = !directory;
387
+ countEl.textContent = `${links.length} ${links.length === 1 ? "document" : "documents"}`;
388
+ if (links.length === 0) {
325
389
  entries.clear();
326
390
  listEl.replaceChildren(
327
391
  el("div", { className: "folder-view-empty" }, "This folder is empty")
@@ -330,21 +394,22 @@ var FolderTool = (handle, element) => {
330
394
  }
331
395
  const seen = /* @__PURE__ */ new Set();
332
396
  const ordered = [];
333
- for (const docLink of folder.docs) {
334
- seen.add(docLink.url);
397
+ for (const docLink of links) {
398
+ const key = entryKey(docLink);
399
+ seen.add(key);
335
400
  const isFolder = docLink.type === "folder";
336
- let entry = entries.get(docLink.url);
401
+ let entry = entries.get(key);
337
402
  if (!entry || entry.isFolder !== isFolder) {
338
- entry = buildEntry(docLink);
339
- entries.set(docLink.url, entry);
403
+ entry = buildEntry(docLink, enter);
404
+ entries.set(key, entry);
340
405
  } else {
341
406
  updateEntry(entry, docLink);
342
407
  }
343
408
  ordered.push(entry.node);
344
409
  }
345
- for (const url of [...entries.keys()]) {
346
- if (seen.has(url)) continue;
347
- entries.delete(url);
410
+ for (const key of [...entries.keys()]) {
411
+ if (seen.has(key)) continue;
412
+ entries.delete(key);
348
413
  }
349
414
  listEl.replaceChildren(...ordered);
350
415
  }
@@ -362,4 +427,4 @@ var FolderTool = (handle, element) => {
362
427
  export {
363
428
  FolderTool
364
429
  };
365
- //# sourceMappingURL=tool-EOCAL24F.js.map
430
+ //# sourceMappingURL=tool-JSQNX2I6.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tool.js", "../src/styles.css"],
4
+ "sourcesContent": ["import {\n parseAutomergeUrl,\n isValidAutomergeUrl,\n} from \"@automerge/automerge-repo/slim\";\nimport { openDocument } from \"@inkandswitch/patchwork-elements\";\nimport {\n getRegistry,\n createDocOfDatatype2,\n} from \"@inkandswitch/patchwork-plugins\";\nimport {\n asString,\n directoryLinks,\n folderLinks,\n isDirectoryDoc,\n} from \"./links.js\";\nimport styles from \"./styles.css\";\n\n// MIME types we can extract document drags from, in order of preference.\n// These mirror what the sideboard sets on dragstart so dropping a sidebar\n// item into the folder view adds it to the folder.\nconst DND_DATA_TYPES = [\n \"text/x-patchwork-dnd\",\n \"text/x-patchwork-urls\",\n \"text/uri-list\",\n \"text/plain\",\n];\n\nfunction hasDocumentDrag(dataTransfer) {\n return Boolean(\n dataTransfer &&\n DND_DATA_TYPES.some((type) => dataTransfer.types.includes(type))\n );\n}\n\nfunction urlFromText(text) {\n const trimmed = text.trim();\n if (isValidAutomergeUrl(trimmed)) return trimmed;\n // patchwork web links carry the document id in the fragment: #doc=<documentId>\n const docId = trimmed.match(/#doc=([^&\\s]+)/)?.[1];\n if (docId && isValidAutomergeUrl(`automerge:${docId}`)) {\n return `automerge:${docId}`;\n }\n return null;\n}\n\n// Extract the dragged documents from a drop event. Returns an array of\n// { url, name?, type? } items, or an empty array if there's nothing droppable.\nfunction getDndItems(event) {\n const data = event.dataTransfer;\n if (!data) return [];\n\n const dndData = data.getData(\"text/x-patchwork-dnd\");\n if (dndData) {\n try {\n const parsed = JSON.parse(dndData);\n if (Array.isArray(parsed?.items) && parsed.items.length > 0) {\n return parsed.items.filter((item) => isValidAutomergeUrl(item?.url));\n }\n } catch {\n // fall through to the other types\n }\n }\n\n const urlData = data.getData(\"text/x-patchwork-urls\");\n if (urlData) {\n try {\n const urls = JSON.parse(urlData);\n const items = (Array.isArray(urls) ? urls : [])\n .filter((url) => isValidAutomergeUrl(url))\n .map((url) => ({ url }));\n if (items.length > 0) return items;\n } catch {\n // fall through to the other types\n }\n }\n\n const text = data.getData(\"text/uri-list\") || data.getData(\"text/plain\");\n return text\n .split(/\\r?\\n/)\n .map(urlFromText)\n .filter((url) => url !== null)\n .map((url) => ({ url }));\n}\n\nfunction el(tag, attrs, ...children) {\n const node = document.createElement(tag);\n if (attrs) {\n for (const [key, value] of Object.entries(attrs)) {\n if (value == null || value === false) continue;\n if (key === \"className\") {\n node.className = value;\n } else if (key.startsWith(\"on\") && typeof value === \"function\") {\n node.addEventListener(key.slice(2).toLowerCase(), value);\n } else {\n node.setAttribute(key, value);\n }\n }\n }\n for (const child of children.flat()) {\n if (child == null || child === false) continue;\n node.appendChild(\n typeof child === \"string\" ? document.createTextNode(child) : child\n );\n }\n return node;\n}\n\nfunction entryHref(docLink) {\n return `#doc=${parseAutomergeUrl(docLink.url).documentId}&type=${docLink.type}`;\n}\n\n// A link is keyed by its doc, or, for a pushwork subdirectory with no doc of\n// its own, by its path.\nfunction entryKey(docLink) {\n return docLink.url ?? `path:${docLink.path}`;\n}\n\nfunction renderLoading() {\n return el(\"div\", { className: \"folder-view-loading\" }, \"Loading\u2026\");\n}\n\n// `enter(path)` opens a pushwork subdirectory in place.\nfunction buildEntry(docLink, enter) {\n const isFolder = docLink.type === \"folder\";\n const nameEl = el(\"span\", { className: \"folder-entry-name\" }, docLink.name);\n const typeEl = el(\"span\", { className: \"folder-entry-type\" }, docLink.type);\n const openEl = docLink.url\n ? el(\n \"a\",\n { className: \"folder-entry-open\", href: entryHref(docLink) },\n \"Open\"\n )\n : el(\n \"button\",\n {\n className: \"folder-entry-open\",\n type: \"button\",\n onClick: () => enter(docLink.path),\n },\n \"Open\"\n );\n\n // The nested view names the doc without heads; resolution (the drafts\n // `repo:handle-descriptor` answer) pins it to the active checkpoint when one\n // is checked out, so the entry freezes with the folder it lives in.\n const node = el(\n \"div\",\n { className: \"folder-entry\", \"data-type\": docLink.type },\n el(\n \"div\",\n { className: \"folder-entry-head\" },\n el(\"div\", { className: \"folder-entry-title\" }, nameEl, typeEl),\n openEl\n ),\n isFolder\n ? el(\n \"p\",\n { className: \"folder-entry-hint\" },\n 'Click \"Open\" to view folder contents'\n )\n : el(\n \"div\",\n { className: \"folder-entry-body\" },\n el(\n \"div\",\n { className: \"folder-entry-scroll\" },\n el(\"patchwork-view\", { \"doc-url\": docLink.url })\n )\n )\n );\n\n return {\n node,\n nameEl,\n typeEl,\n openEl,\n isFolder,\n url: docLink.url,\n };\n}\n\nfunction updateEntry(entry, docLink) {\n if (entry.nameEl.textContent !== docLink.name) {\n entry.nameEl.textContent = docLink.name;\n }\n if (entry.typeEl.textContent !== docLink.type) {\n entry.typeEl.textContent = docLink.type;\n }\n if (entry.node.getAttribute(\"data-type\") !== docLink.type) {\n entry.node.setAttribute(\"data-type\", docLink.type);\n }\n if (!docLink.url) return;\n const href = entryHref(docLink);\n if (entry.openEl.getAttribute(\"href\") !== href) {\n entry.openEl.setAttribute(\"href\", href);\n }\n}\n\n// The listable document types, sorted by name. `file` and other unlisted\n// datatypes are hidden \u2014 you can't create an empty File, for instance.\nfunction listableDatatypes() {\n return getRegistry(\"patchwork:datatype\")\n .all()\n .filter((datatype) => !datatype.unlisted)\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\n// Create a fresh document of the given datatype and return a DocLink for it.\n// Mirrors the sideboard's createNew: load the plugin on demand, create the doc,\n// then read its title.\nasync function createDocLink(repo, datatype) {\n const loaded = await getRegistry(\"patchwork:datatype\").load(datatype.id);\n if (!loaded) throw new Error(`couldn't load datatype \"${datatype.id}\"`);\n const docHandle = await createDocOfDatatype2(loaded, repo);\n return {\n url: docHandle.url,\n name: loaded.module.getTitle(docHandle.doc()),\n type: datatype.id,\n };\n}\n\n// The \"New\" button plus its type-picker popover. Creating a doc appends a\n// DocLink to the folder and opens it. Returns { node, dispose }.\nfunction buildCreateNew(handle, element) {\n const menu = el(\"div\", { className: \"folder-create-menu\", hidden: \"\" });\n const button = el(\n \"button\",\n {\n className: \"folder-create-button\",\n type: \"button\",\n \"aria-label\": \"Create new document\",\n },\n el(\"span\", { className: \"folder-create-icon\" }, \"+\"),\n \"New\"\n );\n const node = el(\"div\", { className: \"folder-create\" }, button, menu);\n\n let open = false;\n\n function setOpen(next) {\n open = next;\n if (open) {\n renderMenu();\n menu.removeAttribute(\"hidden\");\n node.setAttribute(\"data-open\", \"\");\n } else {\n menu.setAttribute(\"hidden\", \"\");\n node.removeAttribute(\"data-open\");\n }\n }\n\n function renderMenu() {\n const datatypes = listableDatatypes();\n if (datatypes.length === 0) {\n menu.replaceChildren(\n el(\n \"div\",\n { className: \"folder-create-empty\" },\n \"No document types available\"\n )\n );\n return;\n }\n menu.replaceChildren(\n ...datatypes.map((datatype) =>\n el(\n \"button\",\n {\n className: \"folder-create-item\",\n type: \"button\",\n onClick: () => pick(datatype),\n },\n datatype.name\n )\n )\n );\n }\n\n async function pick(datatype) {\n setOpen(false);\n const repo = element.repo;\n if (!repo) return;\n try {\n const link = await createDocLink(repo, datatype);\n handle.change((doc) => {\n doc.docs.push(link);\n });\n openDocument(element, link.url);\n } catch (error) {\n console.error(\"folder: couldn't create document\", error);\n }\n }\n\n button.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n setOpen(!open);\n });\n\n // Dismiss the menu on an outside click or Escape.\n const onPointerDown = (event) => {\n if (open && !node.contains(event.target)) setOpen(false);\n };\n const onKeyDown = (event) => {\n if (open && event.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n\n const dispose = () => {\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n\n return { node, dispose };\n}\n\nexport const FolderTool = (handle, element) => {\n const entries = new Map();\n\n const styleEl = el(\"style\");\n styleEl.textContent = styles;\n\n // Where we are inside a pushwork directory doc, which keeps its whole tree\n // in one doc. \"\" is the top.\n let path = \"\";\n\n function enter(next) {\n path = next;\n render();\n }\n\n const countEl = el(\"span\", { className: \"folder-view-count\" });\n const listEl = el(\"div\", { className: \"folder-view-list\" });\n const crumbsEl = el(\"nav\", { className: \"folder-view-crumbs\", hidden: \"\" });\n const createNew = buildCreateNew(handle, element);\n const shell = el(\n \"div\",\n { className: \"folder-view\" },\n el(\n \"div\",\n { className: \"folder-view-header\" },\n createNew.node,\n crumbsEl,\n countEl\n ),\n listEl\n );\n\n function renderCrumbs(title) {\n const parts = path ? path.split(\"/\") : [];\n const crumbs = [{ name: title, path: \"\" }].concat(\n parts.map((name, i) => ({ name, path: parts.slice(0, i + 1).join(\"/\") }))\n );\n crumbsEl.replaceChildren(\n ...crumbs.flatMap((crumb, i) => {\n const last = i === crumbs.length - 1;\n const node = last\n ? el(\"span\", { className: \"folder-view-crumb\" }, crumb.name)\n : el(\n \"button\",\n {\n className: \"folder-view-crumb\",\n type: \"button\",\n onClick: () => enter(crumb.path),\n },\n crumb.name\n );\n return i === 0\n ? [node]\n : [el(\"span\", { className: \"folder-view-crumb-sep\" }, \"/\"), node];\n })\n );\n }\n\n element.append(styleEl);\n\n // --- drag-and-drop: accept documents dragged in from the sidebar ---\n\n // dragenter/dragleave fire for every descendant, so track nesting depth to\n // know when the pointer has actually left the folder view.\n let dragDepth = 0;\n\n function endDrag() {\n dragDepth = 0;\n shell.removeAttribute(\"data-drop-active\");\n }\n\n function addDroppedDocs(event) {\n const folder = handle.doc();\n if (!folder || isDirectoryDoc(folder)) return;\n\n const existing = new Set(folderLinks(folder).map((docLink) => docLink.url));\n const selfUrl = handle.url;\n\n const links = [];\n for (const item of getDndItems(event)) {\n if (item.url === selfUrl) continue; // don't nest a folder inside itself\n if (existing.has(item.url)) continue; // already here\n existing.add(item.url); // de-dupe within a single drop too\n links.push({\n url: item.url,\n name: item.name || \"Untitled\",\n type: item.type || \"\",\n });\n }\n\n if (links.length === 0) return;\n\n handle.change((doc) => {\n if (!Array.isArray(doc.docs)) doc.docs = [];\n doc.docs.push(...links);\n });\n }\n\n // pushwork owns a directory doc's entries, so it's read-only here.\n function acceptsDrops(event) {\n return hasDocumentDrag(event.dataTransfer) && !isDirectoryDoc(handle.doc());\n }\n\n shell.addEventListener(\"dragenter\", (event) => {\n if (!acceptsDrops(event)) return;\n event.preventDefault();\n dragDepth++;\n shell.setAttribute(\"data-drop-active\", \"\");\n });\n\n shell.addEventListener(\"dragover\", (event) => {\n if (!acceptsDrops(event)) return;\n event.preventDefault();\n // \"link\": dropping here adds a new DocLink to the same automerge url \u2014 the\n // doc isn't moved or cloned. Requires the source's effectAllowed to permit\n // link (the sideboard sets \"all\").\n event.dataTransfer.dropEffect = \"link\";\n });\n\n shell.addEventListener(\"dragleave\", (event) => {\n if (!acceptsDrops(event)) return;\n dragDepth--;\n if (dragDepth <= 0) endDrag();\n });\n\n shell.addEventListener(\"drop\", (event) => {\n if (!acceptsDrops(event)) return;\n event.preventDefault();\n endDrag();\n addDroppedDocs(event);\n });\n\n let mounted = null;\n\n function show(node) {\n if (mounted !== node) {\n // keep the injected <style>, swap the rendered tree\n if (mounted) mounted.remove();\n element.append(node);\n mounted = node;\n }\n }\n\n function render() {\n const folder = handle.doc();\n if (!folder) {\n show(renderLoading());\n return;\n }\n\n show(shell);\n\n const directory = isDirectoryDoc(folder);\n let links;\n if (directory) {\n links = directoryLinks(folder, path);\n renderCrumbs(\n asString(folder[\"@patchwork\"].title) || \"Directory\"\n );\n } else {\n path = \"\";\n links = folderLinks(folder);\n }\n createNew.node.hidden = directory;\n crumbsEl.hidden = !directory;\n\n countEl.textContent = `${links.length} ${\n links.length === 1 ? \"document\" : \"documents\"\n }`;\n\n if (links.length === 0) {\n entries.clear();\n listEl.replaceChildren(\n el(\"div\", { className: \"folder-view-empty\" }, \"This folder is empty\")\n );\n return;\n }\n\n const seen = new Set();\n const ordered = [];\n for (const docLink of links) {\n const key = entryKey(docLink);\n seen.add(key);\n const isFolder = docLink.type === \"folder\";\n let entry = entries.get(key);\n // Rebuild only if folder/non-folder shape flipped \u2014 that's the one\n // case where the body structure differs.\n if (!entry || entry.isFolder !== isFolder) {\n entry = buildEntry(docLink, enter);\n entries.set(key, entry);\n } else {\n updateEntry(entry, docLink);\n }\n ordered.push(entry.node);\n }\n\n for (const key of [...entries.keys()]) {\n if (seen.has(key)) continue;\n entries.delete(key);\n }\n\n listEl.replaceChildren(...ordered);\n }\n\n const onChange = () => render();\n handle.on(\"change\", onChange);\n render();\n\n return () => {\n handle.off(\"change\", onChange);\n createNew.dispose();\n element.replaceChildren();\n entries.clear();\n mounted = null;\n };\n};\n", "@layer package {\n:root,\n:host,\n[theme] {\n /* The well the cards sit in \u2014 slightly recessed surface. */\n --folder-view-well: var(--editor-fill-offset-10, #f2f2f2);\n --folder-view-well-edge: var(--editor-fill-offset-30, #d6d6d6);\n --folder-view-fg: var(--editor-line, black);\n --folder-view-muted: var(--editor-line-offset-50, #999);\n --folder-view-border: var(--editor-fill-offset-20, #e5e5e5);\n\n /* A card = a raised surface sitting on the well. */\n --folder-view-card: var(--editor-fill, white);\n --folder-view-card-border: var(--editor-fill-offset-20, #e5e5e5);\n\n --folder-view-accent: var(--studio-primary-fill, var(--studio-primary, #35f7ca));\n --folder-view-accent-line: var(--studio-primary-line, var(--editor-fill, white));\n --folder-view-accent-text: var(--editor-primary-text, var(--studio-primary-text, var(--studio-primary, #35f7ca)));\n --folder-view-hover: var(--editor-fill-offset-10, #f2f2f2);\n\n /* Layered drop shadow so a card reads as a solid object resting on the\n well \u2014 a tight contact shadow plus a softer cast one. Derived from the\n theme line colour so it inverts in dark themes. */\n --folder-view-card-shadow: 0 1px 2px\n color-mix(in oklch, var(--editor-line, black), transparent 94%),\n 0 2px 8px color-mix(in oklch, var(--editor-line, black), transparent 96%);\n --folder-view-card-shadow-hover: 0 2px 4px\n color-mix(in oklch, var(--editor-line, black), transparent 90%),\n 0 8px 20px color-mix(in oklch, var(--editor-line, black), transparent 93%);\n\n --folder-view-family: var(--editor-family-sans, system-ui, sans-serif);\n}\n}\n\n/* Block: the whole tool. A sunken well with an inset edge. */\n.folder-view {\n height: 100%;\n overflow: auto;\n padding: var(--studio-space-md, 1rem);\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-fg);\n background: var(--folder-view-well);\n /* No outer border: the host frame already draws the lines around the pane, so\n the well reads as flush rather than double-edged. */\n}\n\n/* State: a document is being dragged in from the sidebar. Outline the well\n with the accent colour so it reads as an active drop target. */\n.folder-view[data-drop-active] {\n border-color: var(--folder-view-accent);\n box-shadow: inset 0 0 0 2px var(--folder-view-accent);\n}\n\n/* Composition: header row. New-doc button on the left, count on the right. */\n.folder-view .folder-view-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding-bottom: var(--studio-space-sm, 0.5rem);\n border-bottom: 1px solid var(--folder-view-border);\n}\n\n/* Composition: where we are inside a pushwork directory doc, in place of the\n create-new control (pushwork owns those entries). */\n.folder-view .folder-view-crumbs:not([hidden]) {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--studio-space-2xs, 0.25rem);\n min-width: 0;\n font-size: 0.85rem;\n}\n\n.folder-view .folder-view-crumb {\n font: inherit;\n color: var(--folder-view-fg);\n background: none;\n border: none;\n padding: var(--studio-space-2xs, 0.25rem);\n border-radius: var(--studio-radius-sm, 4px);\n}\n\n.folder-view button.folder-view-crumb {\n color: var(--folder-view-accent-text);\n cursor: pointer;\n}\n\n.folder-view button.folder-view-crumb:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-view-crumb-sep {\n color: var(--folder-view-muted);\n}\n\n/* Composition: the create-new control \u2014 a button anchoring a type-picker. */\n.folder-view .folder-create {\n position: relative;\n}\n\n.folder-view .folder-create-button {\n display: inline-flex;\n align-items: center;\n gap: var(--studio-space-2xs, 0.25rem);\n font: inherit;\n font-size: 0.8rem;\n color: var(--folder-view-accent-line);\n background: var(--folder-view-accent);\n border: 1px solid transparent;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n transition: filter var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-create-button:hover {\n filter: brightness(0.96);\n}\n\n.folder-view .folder-create-icon {\n font-size: 1rem;\n line-height: 1;\n}\n\n/* The type-picker popover, anchored under the button. */\n.folder-view .folder-create-menu {\n position: absolute;\n top: calc(100% + var(--studio-space-2xs, 0.25rem));\n left: 0;\n z-index: 10;\n min-width: 12rem;\n max-height: 16rem;\n overflow: auto;\n display: flex;\n flex-direction: column;\n padding: var(--studio-space-3xs, 0.125rem);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-md, 8px);\n box-shadow: var(--folder-view-card-shadow-hover);\n}\n\n.folder-view .folder-create-menu[hidden] {\n display: none;\n}\n\n.folder-view .folder-create-item {\n text-align: left;\n font: inherit;\n font-size: 0.85rem;\n color: var(--folder-view-fg);\n background: transparent;\n border: 0;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n}\n\n.folder-view .folder-create-item:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-create-empty {\n padding: var(--studio-space-sm, 0.5rem);\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n}\n\n.folder-view .folder-view-count {\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-round, 9999px);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-border);\n}\n\n/* Composition: the list of cards. */\n.folder-view .folder-view-list {\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n padding-bottom: var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-view-empty {\n text-align: center;\n color: var(--folder-view-muted);\n padding: var(--studio-space-xl, 2rem) 0;\n}\n\n.folder-view-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-muted);\n background: var(--folder-view-card);\n}\n\n/* Block: one rendered file/folder card \u2014 sitting on the well. */\n.folder-view .folder-entry {\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-lg, 12px);\n box-shadow: var(--folder-view-card-shadow);\n overflow: hidden;\n transition: box-shadow var(--studio-transition, 0.15s ease),\n transform var(--studio-transition, 0.15s ease);\n}\n\n.folder-view .folder-entry:hover {\n box-shadow: var(--folder-view-card-shadow-hover);\n /* Lift slightly so the card feels like it peels up off the well. */\n transform: translateY(-1px);\n}\n\n.folder-view .folder-entry-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding: var(--studio-space-sm, 0.5rem) var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-entry-title {\n display: flex;\n align-items: baseline;\n gap: var(--studio-space-sm, 0.5rem);\n min-width: 0;\n}\n\n.folder-view .folder-entry-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.folder-view .folder-entry-type {\n font-size: 0.7rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-3xs, 0.125rem) var(--studio-space-2xs, 0.25rem);\n border: 1px solid var(--folder-view-border);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.folder-view .folder-entry-open {\n font: inherit;\n font-size: 0.8rem;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--folder-view-accent-text);\n text-decoration: none;\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n transition: background var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-entry-open:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-entry-hint {\n margin: 0;\n padding: 0 var(--studio-space-md, 1rem) var(--studio-space-md, 1rem);\n font-size: 0.85rem;\n color: var(--folder-view-muted);\n}\n\n/* Block: embedded preview body. */\n.folder-view .folder-entry-body {\n flex: 1 1 auto;\n min-height: 0;\n max-height: 300px;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--folder-view-border);\n}\n\n.folder-view .folder-entry-scroll {\n height: 100%;\n overflow: auto;\n}\n\n.folder-view .folder-entry-scroll patchwork-view {\n display: block;\n height: 100%;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -500,8 +500,8 @@
500
500
  display: flex;
501
501
  justify-content: flex-end;
502
502
  align-items: center;
503
- padding-top: 0.65rem;
504
- border-top: 1px solid var(--pw-packages-border);
503
+ padding-bottom: 0.65rem;
504
+ border-bottom: 1px solid var(--pw-packages-border);
505
505
  }
506
506
 
507
507
  /* show-more toggle, valid inside the plugin/registry <ul>s */
@@ -1 +1 @@
1
- automerge:2TeZFFdZxDRtJpNyQQKLQiMX18qs
1
+ automerge:2svkrnCFj1bKneLTeSEYaeXXSrjP
@@ -1,27 +0,0 @@
1
- // src/datatype.js
2
- var FolderDatatype = {
3
- init(doc) {
4
- doc.title = "New Folder";
5
- doc.docs = [];
6
- },
7
- getTitle: (doc) => doc.title || "Unnamed Folder",
8
- setTitle: (doc, title) => {
9
- doc.title = title;
10
- }
11
- };
12
- var FileDatatype = {
13
- init: () => {
14
- throw new Error("Can't create empty File");
15
- },
16
- getTitle(doc) {
17
- return doc.name || "Unnamed File";
18
- },
19
- setTitle(doc, title) {
20
- doc.name = title;
21
- }
22
- };
23
- export {
24
- FileDatatype,
25
- FolderDatatype
26
- };
27
- //# sourceMappingURL=datatype-HWGUFBTQ.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/datatype.js"],
4
- "sourcesContent": ["export const FolderDatatype = {\n init(doc) {\n doc.title = 'New Folder';\n doc.docs = [];\n },\n getTitle: (doc) => doc.title || 'Unnamed Folder',\n setTitle: (doc, title) => {\n doc.title = title;\n },\n};\n\nexport const FileDatatype = {\n init: () => {\n throw new Error(\"Can't create empty File\");\n },\n getTitle(doc) {\n return doc.name || 'Unnamed File';\n },\n setTitle(doc, title) {\n doc.name = title;\n },\n};\n"],
5
- "mappings": ";AAAO,IAAM,iBAAiB;AAAA,EAC5B,KAAK,KAAK;AACR,QAAI,QAAQ;AACZ,QAAI,OAAO,CAAC;AAAA,EACd;AAAA,EACA,UAAU,CAAC,QAAQ,IAAI,SAAS;AAAA,EAChC,UAAU,CAAC,KAAK,UAAU;AACxB,QAAI,QAAQ;AAAA,EACd;AACF;AAEO,IAAM,eAAe;AAAA,EAC1B,MAAM,MAAM;AACV,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAAA,EACA,SAAS,KAAK;AACZ,WAAO,IAAI,QAAQ;AAAA,EACrB;AAAA,EACA,SAAS,KAAK,OAAO;AACnB,QAAI,OAAO;AAAA,EACb;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/tool.js", "../src/styles.css"],
4
- "sourcesContent": ["import {\n parseAutomergeUrl,\n isValidAutomergeUrl,\n} from \"@automerge/automerge-repo/slim\";\nimport { openDocument } from \"@inkandswitch/patchwork-elements\";\nimport {\n getRegistry,\n createDocOfDatatype2,\n} from \"@inkandswitch/patchwork-plugins\";\nimport styles from \"./styles.css\";\n\n// MIME types we can extract document drags from, in order of preference.\n// These mirror what the sideboard sets on dragstart so dropping a sidebar\n// item into the folder view adds it to the folder.\nconst DND_DATA_TYPES = [\n \"text/x-patchwork-dnd\",\n \"text/x-patchwork-urls\",\n \"text/uri-list\",\n \"text/plain\",\n];\n\nfunction hasDocumentDrag(dataTransfer) {\n return Boolean(\n dataTransfer &&\n DND_DATA_TYPES.some((type) => dataTransfer.types.includes(type))\n );\n}\n\nfunction urlFromText(text) {\n const trimmed = text.trim();\n if (isValidAutomergeUrl(trimmed)) return trimmed;\n // patchwork web links carry the document id in the fragment: #doc=<documentId>\n const docId = trimmed.match(/#doc=([^&\\s]+)/)?.[1];\n if (docId && isValidAutomergeUrl(`automerge:${docId}`)) {\n return `automerge:${docId}`;\n }\n return null;\n}\n\n// Extract the dragged documents from a drop event. Returns an array of\n// { url, name?, type? } items, or an empty array if there's nothing droppable.\nfunction getDndItems(event) {\n const data = event.dataTransfer;\n if (!data) return [];\n\n const dndData = data.getData(\"text/x-patchwork-dnd\");\n if (dndData) {\n try {\n const parsed = JSON.parse(dndData);\n if (Array.isArray(parsed?.items) && parsed.items.length > 0) {\n return parsed.items.filter((item) => isValidAutomergeUrl(item?.url));\n }\n } catch {\n // fall through to the other types\n }\n }\n\n const urlData = data.getData(\"text/x-patchwork-urls\");\n if (urlData) {\n try {\n const urls = JSON.parse(urlData);\n const items = (Array.isArray(urls) ? urls : [])\n .filter((url) => isValidAutomergeUrl(url))\n .map((url) => ({ url }));\n if (items.length > 0) return items;\n } catch {\n // fall through to the other types\n }\n }\n\n const text = data.getData(\"text/uri-list\") || data.getData(\"text/plain\");\n return text\n .split(/\\r?\\n/)\n .map(urlFromText)\n .filter((url) => url !== null)\n .map((url) => ({ url }));\n}\n\nfunction el(tag, attrs, ...children) {\n const node = document.createElement(tag);\n if (attrs) {\n for (const [key, value] of Object.entries(attrs)) {\n if (value == null || value === false) continue;\n if (key === \"className\") {\n node.className = value;\n } else if (key.startsWith(\"on\") && typeof value === \"function\") {\n node.addEventListener(key.slice(2).toLowerCase(), value);\n } else {\n node.setAttribute(key, value);\n }\n }\n }\n for (const child of children.flat()) {\n if (child == null || child === false) continue;\n node.appendChild(\n typeof child === \"string\" ? document.createTextNode(child) : child\n );\n }\n return node;\n}\n\nfunction entryHref(docLink) {\n return `#doc=${parseAutomergeUrl(docLink.url).documentId}&type=${docLink.type}`;\n}\n\nfunction renderLoading() {\n return el(\"div\", { className: \"folder-view-loading\" }, \"Loading\u2026\");\n}\n\nfunction buildEntry(docLink) {\n const isFolder = docLink.type === \"folder\";\n const nameEl = el(\"span\", { className: \"folder-entry-name\" }, docLink.name);\n const typeEl = el(\"span\", { className: \"folder-entry-type\" }, docLink.type);\n const openEl = el(\n \"a\",\n { className: \"folder-entry-open\", href: entryHref(docLink) },\n \"Open\"\n );\n\n // The nested view names the doc without heads; resolution (the drafts\n // `repo:handle-descriptor` answer) pins it to the active checkpoint when one\n // is checked out, so the entry freezes with the folder it lives in.\n const node = el(\n \"div\",\n { className: \"folder-entry\", \"data-type\": docLink.type },\n el(\n \"div\",\n { className: \"folder-entry-head\" },\n el(\"div\", { className: \"folder-entry-title\" }, nameEl, typeEl),\n openEl\n ),\n isFolder\n ? el(\n \"p\",\n { className: \"folder-entry-hint\" },\n 'Click \"Open\" to view folder contents'\n )\n : el(\n \"div\",\n { className: \"folder-entry-body\" },\n el(\n \"div\",\n { className: \"folder-entry-scroll\" },\n el(\"patchwork-view\", { \"doc-url\": docLink.url })\n )\n )\n );\n\n return {\n node,\n nameEl,\n typeEl,\n openEl,\n isFolder,\n url: docLink.url,\n };\n}\n\nfunction updateEntry(entry, docLink) {\n if (entry.nameEl.textContent !== docLink.name) {\n entry.nameEl.textContent = docLink.name;\n }\n if (entry.typeEl.textContent !== docLink.type) {\n entry.typeEl.textContent = docLink.type;\n }\n if (entry.node.getAttribute(\"data-type\") !== docLink.type) {\n entry.node.setAttribute(\"data-type\", docLink.type);\n }\n const href = entryHref(docLink);\n if (entry.openEl.getAttribute(\"href\") !== href) {\n entry.openEl.setAttribute(\"href\", href);\n }\n}\n\n// The listable document types, sorted by name. `file` and other unlisted\n// datatypes are hidden \u2014 you can't create an empty File, for instance.\nfunction listableDatatypes() {\n return getRegistry(\"patchwork:datatype\")\n .all()\n .filter((datatype) => !datatype.unlisted)\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\n// Create a fresh document of the given datatype and return a DocLink for it.\n// Mirrors the sideboard's createNew: load the plugin on demand, create the doc,\n// then read its title.\nasync function createDocLink(repo, datatype) {\n const loaded = await getRegistry(\"patchwork:datatype\").load(datatype.id);\n if (!loaded) throw new Error(`couldn't load datatype \"${datatype.id}\"`);\n const docHandle = await createDocOfDatatype2(loaded, repo);\n return {\n url: docHandle.url,\n name: loaded.module.getTitle(docHandle.doc()),\n type: datatype.id,\n };\n}\n\n// The \"New\" button plus its type-picker popover. Creating a doc appends a\n// DocLink to the folder and opens it. Returns { node, dispose }.\nfunction buildCreateNew(handle, element) {\n const menu = el(\"div\", { className: \"folder-create-menu\", hidden: \"\" });\n const button = el(\n \"button\",\n {\n className: \"folder-create-button\",\n type: \"button\",\n \"aria-label\": \"Create new document\",\n },\n el(\"span\", { className: \"folder-create-icon\" }, \"+\"),\n \"New\"\n );\n const node = el(\"div\", { className: \"folder-create\" }, button, menu);\n\n let open = false;\n\n function setOpen(next) {\n open = next;\n if (open) {\n renderMenu();\n menu.removeAttribute(\"hidden\");\n node.setAttribute(\"data-open\", \"\");\n } else {\n menu.setAttribute(\"hidden\", \"\");\n node.removeAttribute(\"data-open\");\n }\n }\n\n function renderMenu() {\n const datatypes = listableDatatypes();\n if (datatypes.length === 0) {\n menu.replaceChildren(\n el(\n \"div\",\n { className: \"folder-create-empty\" },\n \"No document types available\"\n )\n );\n return;\n }\n menu.replaceChildren(\n ...datatypes.map((datatype) =>\n el(\n \"button\",\n {\n className: \"folder-create-item\",\n type: \"button\",\n onClick: () => pick(datatype),\n },\n datatype.name\n )\n )\n );\n }\n\n async function pick(datatype) {\n setOpen(false);\n const repo = element.repo;\n if (!repo) return;\n try {\n const link = await createDocLink(repo, datatype);\n handle.change((doc) => {\n doc.docs.push(link);\n });\n openDocument(element, link.url);\n } catch (error) {\n console.error(\"folder: couldn't create document\", error);\n }\n }\n\n button.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n setOpen(!open);\n });\n\n // Dismiss the menu on an outside click or Escape.\n const onPointerDown = (event) => {\n if (open && !node.contains(event.target)) setOpen(false);\n };\n const onKeyDown = (event) => {\n if (open && event.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n\n const dispose = () => {\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n\n return { node, dispose };\n}\n\nexport const FolderTool = (handle, element) => {\n const entries = new Map();\n\n const styleEl = el(\"style\");\n styleEl.textContent = styles;\n\n const countEl = el(\"span\", { className: \"folder-view-count\" });\n const listEl = el(\"div\", { className: \"folder-view-list\" });\n const createNew = buildCreateNew(handle, element);\n const shell = el(\n \"div\",\n { className: \"folder-view\" },\n el(\n \"div\",\n { className: \"folder-view-header\" },\n createNew.node,\n countEl\n ),\n listEl\n );\n\n element.append(styleEl);\n\n // --- drag-and-drop: accept documents dragged in from the sidebar ---\n\n // dragenter/dragleave fire for every descendant, so track nesting depth to\n // know when the pointer has actually left the folder view.\n let dragDepth = 0;\n\n function endDrag() {\n dragDepth = 0;\n shell.removeAttribute(\"data-drop-active\");\n }\n\n function addDroppedDocs(event) {\n const folder = handle.doc();\n if (!folder) return;\n\n const existing = new Set(folder.docs.map((docLink) => docLink.url));\n const selfUrl = handle.url;\n\n const links = [];\n for (const item of getDndItems(event)) {\n if (item.url === selfUrl) continue; // don't nest a folder inside itself\n if (existing.has(item.url)) continue; // already here\n existing.add(item.url); // de-dupe within a single drop too\n links.push({\n url: item.url,\n name: item.name || \"Untitled\",\n type: item.type || \"\",\n });\n }\n\n if (links.length === 0) return;\n\n handle.change((doc) => {\n doc.docs.push(...links);\n });\n }\n\n shell.addEventListener(\"dragenter\", (event) => {\n if (!hasDocumentDrag(event.dataTransfer)) return;\n event.preventDefault();\n dragDepth++;\n shell.setAttribute(\"data-drop-active\", \"\");\n });\n\n shell.addEventListener(\"dragover\", (event) => {\n if (!hasDocumentDrag(event.dataTransfer)) return;\n event.preventDefault();\n // \"link\": dropping here adds a new DocLink to the same automerge url \u2014 the\n // doc isn't moved or cloned. Requires the source's effectAllowed to permit\n // link (the sideboard sets \"all\").\n event.dataTransfer.dropEffect = \"link\";\n });\n\n shell.addEventListener(\"dragleave\", (event) => {\n if (!hasDocumentDrag(event.dataTransfer)) return;\n dragDepth--;\n if (dragDepth <= 0) endDrag();\n });\n\n shell.addEventListener(\"drop\", (event) => {\n if (!hasDocumentDrag(event.dataTransfer)) return;\n event.preventDefault();\n endDrag();\n addDroppedDocs(event);\n });\n\n let mounted = null;\n\n function show(node) {\n if (mounted !== node) {\n // keep the injected <style>, swap the rendered tree\n if (mounted) mounted.remove();\n element.append(node);\n mounted = node;\n }\n }\n\n function render() {\n const folder = handle.doc();\n if (!folder) {\n show(renderLoading());\n return;\n }\n\n show(shell);\n countEl.textContent = `${folder.docs.length} ${\n folder.docs.length === 1 ? \"document\" : \"documents\"\n }`;\n\n if (folder.docs.length === 0) {\n entries.clear();\n listEl.replaceChildren(\n el(\"div\", { className: \"folder-view-empty\" }, \"This folder is empty\")\n );\n return;\n }\n\n const seen = new Set();\n const ordered = [];\n for (const docLink of folder.docs) {\n seen.add(docLink.url);\n const isFolder = docLink.type === \"folder\";\n let entry = entries.get(docLink.url);\n // Rebuild only if folder/non-folder shape flipped \u2014 that's the one\n // case where the body structure differs.\n if (!entry || entry.isFolder !== isFolder) {\n entry = buildEntry(docLink);\n entries.set(docLink.url, entry);\n } else {\n updateEntry(entry, docLink);\n }\n ordered.push(entry.node);\n }\n\n for (const url of [...entries.keys()]) {\n if (seen.has(url)) continue;\n entries.delete(url);\n }\n\n listEl.replaceChildren(...ordered);\n }\n\n const onChange = () => render();\n handle.on(\"change\", onChange);\n render();\n\n return () => {\n handle.off(\"change\", onChange);\n createNew.dispose();\n element.replaceChildren();\n entries.clear();\n mounted = null;\n };\n};\n", "@layer package {\n:root,\n:host,\n[theme] {\n /* The well the cards sit in \u2014 slightly recessed surface. */\n --folder-view-well: var(--editor-fill-offset-10, #f2f2f2);\n --folder-view-well-edge: var(--editor-fill-offset-30, #d6d6d6);\n --folder-view-fg: var(--editor-line, black);\n --folder-view-muted: var(--editor-line-offset-50, #999);\n --folder-view-border: var(--editor-fill-offset-20, #e5e5e5);\n\n /* A card = a raised surface sitting on the well. */\n --folder-view-card: var(--editor-fill, white);\n --folder-view-card-border: var(--editor-fill-offset-20, #e5e5e5);\n\n --folder-view-accent: var(--studio-primary-fill, var(--studio-primary, #35f7ca));\n --folder-view-accent-line: var(--studio-primary-line, var(--editor-fill, white));\n --folder-view-accent-text: var(--editor-primary-text, var(--studio-primary-text, var(--studio-primary, #35f7ca)));\n --folder-view-hover: var(--editor-fill-offset-10, #f2f2f2);\n\n /* Layered drop shadow so a card reads as a solid object resting on the\n well \u2014 a tight contact shadow plus a softer cast one. Derived from the\n theme line colour so it inverts in dark themes. */\n --folder-view-card-shadow: 0 1px 2px\n color-mix(in oklch, var(--editor-line, black), transparent 94%),\n 0 2px 8px color-mix(in oklch, var(--editor-line, black), transparent 96%);\n --folder-view-card-shadow-hover: 0 2px 4px\n color-mix(in oklch, var(--editor-line, black), transparent 90%),\n 0 8px 20px color-mix(in oklch, var(--editor-line, black), transparent 93%);\n\n --folder-view-family: var(--editor-family-sans, system-ui, sans-serif);\n}\n}\n\n/* Block: the whole tool. A sunken well with an inset edge. */\n.folder-view {\n height: 100%;\n overflow: auto;\n padding: var(--studio-space-md, 1rem);\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-fg);\n background: var(--folder-view-well);\n /* No outer border: the host frame already draws the lines around the pane, so\n the well reads as flush rather than double-edged. */\n}\n\n/* State: a document is being dragged in from the sidebar. Outline the well\n with the accent colour so it reads as an active drop target. */\n.folder-view[data-drop-active] {\n border-color: var(--folder-view-accent);\n box-shadow: inset 0 0 0 2px var(--folder-view-accent);\n}\n\n/* Composition: header row. New-doc button on the left, count on the right. */\n.folder-view .folder-view-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding-bottom: var(--studio-space-sm, 0.5rem);\n border-bottom: 1px solid var(--folder-view-border);\n}\n\n/* Composition: the create-new control \u2014 a button anchoring a type-picker. */\n.folder-view .folder-create {\n position: relative;\n}\n\n.folder-view .folder-create-button {\n display: inline-flex;\n align-items: center;\n gap: var(--studio-space-2xs, 0.25rem);\n font: inherit;\n font-size: 0.8rem;\n color: var(--folder-view-accent-line);\n background: var(--folder-view-accent);\n border: 1px solid transparent;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n transition: filter var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-create-button:hover {\n filter: brightness(0.96);\n}\n\n.folder-view .folder-create-icon {\n font-size: 1rem;\n line-height: 1;\n}\n\n/* The type-picker popover, anchored under the button. */\n.folder-view .folder-create-menu {\n position: absolute;\n top: calc(100% + var(--studio-space-2xs, 0.25rem));\n left: 0;\n z-index: 10;\n min-width: 12rem;\n max-height: 16rem;\n overflow: auto;\n display: flex;\n flex-direction: column;\n padding: var(--studio-space-3xs, 0.125rem);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-md, 8px);\n box-shadow: var(--folder-view-card-shadow-hover);\n}\n\n.folder-view .folder-create-menu[hidden] {\n display: none;\n}\n\n.folder-view .folder-create-item {\n text-align: left;\n font: inherit;\n font-size: 0.85rem;\n color: var(--folder-view-fg);\n background: transparent;\n border: 0;\n border-radius: var(--studio-radius-sm, 4px);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n cursor: pointer;\n}\n\n.folder-view .folder-create-item:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-create-empty {\n padding: var(--studio-space-sm, 0.5rem);\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n}\n\n.folder-view .folder-view-count {\n font-size: 0.8rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-round, 9999px);\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-border);\n}\n\n/* Composition: the list of cards. */\n.folder-view .folder-view-list {\n display: flex;\n flex-direction: column;\n gap: var(--studio-space-md, 1rem);\n padding-bottom: var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-view-empty {\n text-align: center;\n color: var(--folder-view-muted);\n padding: var(--studio-space-xl, 2rem) 0;\n}\n\n.folder-view-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--studio-space-md, 1rem);\n font-family: var(--folder-view-family);\n color: var(--folder-view-muted);\n background: var(--folder-view-card);\n}\n\n/* Block: one rendered file/folder card \u2014 sitting on the well. */\n.folder-view .folder-entry {\n background: var(--folder-view-card);\n border: 1px solid var(--folder-view-card-border);\n border-radius: var(--studio-radius-lg, 12px);\n box-shadow: var(--folder-view-card-shadow);\n overflow: hidden;\n transition: box-shadow var(--studio-transition, 0.15s ease),\n transform var(--studio-transition, 0.15s ease);\n}\n\n.folder-view .folder-entry:hover {\n box-shadow: var(--folder-view-card-shadow-hover);\n /* Lift slightly so the card feels like it peels up off the well. */\n transform: translateY(-1px);\n}\n\n.folder-view .folder-entry-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--studio-space-sm, 0.5rem);\n padding: var(--studio-space-sm, 0.5rem) var(--studio-space-md, 1rem);\n}\n\n.folder-view .folder-entry-title {\n display: flex;\n align-items: baseline;\n gap: var(--studio-space-sm, 0.5rem);\n min-width: 0;\n}\n\n.folder-view .folder-entry-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.folder-view .folder-entry-type {\n font-size: 0.7rem;\n color: var(--folder-view-muted);\n padding: var(--studio-space-3xs, 0.125rem) var(--studio-space-2xs, 0.25rem);\n border: 1px solid var(--folder-view-border);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.folder-view .folder-entry-open {\n font-size: 0.8rem;\n color: var(--folder-view-accent-text);\n text-decoration: none;\n padding: var(--studio-space-2xs, 0.25rem) var(--studio-space-sm, 0.5rem);\n border-radius: var(--studio-radius-sm, 4px);\n flex-shrink: 0;\n transition: background var(--studio-transition-fast, 0.1s ease);\n}\n\n.folder-view .folder-entry-open:hover {\n background: var(--folder-view-hover);\n}\n\n.folder-view .folder-entry-hint {\n margin: 0;\n padding: 0 var(--studio-space-md, 1rem) var(--studio-space-md, 1rem);\n font-size: 0.85rem;\n color: var(--folder-view-muted);\n}\n\n/* Block: embedded preview body. */\n.folder-view .folder-entry-body {\n flex: 1 1 auto;\n min-height: 0;\n max-height: 300px;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--folder-view-border);\n}\n\n.folder-view .folder-entry-scroll {\n height: 100%;\n overflow: auto;\n}\n\n.folder-view .folder-entry-scroll patchwork-view {\n display: block;\n height: 100%;\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }