@graview/pages 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +96 -0
  2. package/README.md +47 -0
  3. package/dist/ask.d.ts +21 -0
  4. package/dist/ask.d.ts.map +1 -0
  5. package/dist/ask.js +109 -0
  6. package/dist/ask.js.map +1 -0
  7. package/dist/face-controls.d.ts +68 -0
  8. package/dist/face-controls.d.ts.map +1 -0
  9. package/dist/face-controls.js +231 -0
  10. package/dist/face-controls.js.map +1 -0
  11. package/dist/face-placed.d.ts +16 -0
  12. package/dist/face-placed.d.ts.map +1 -0
  13. package/dist/face-placed.js +34 -0
  14. package/dist/face-placed.js.map +1 -0
  15. package/dist/facts.d.ts +115 -0
  16. package/dist/facts.d.ts.map +1 -0
  17. package/dist/facts.js +180 -0
  18. package/dist/facts.js.map +1 -0
  19. package/dist/form.d.ts +53 -0
  20. package/dist/form.d.ts.map +1 -0
  21. package/dist/form.js +183 -0
  22. package/dist/form.js.map +1 -0
  23. package/dist/index.d.ts +15 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +8 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/page-context.d.ts +74 -0
  28. package/dist/page-context.d.ts.map +1 -0
  29. package/dist/page-context.js +38 -0
  30. package/dist/page-context.js.map +1 -0
  31. package/dist/page-home.d.ts +19 -0
  32. package/dist/page-home.d.ts.map +1 -0
  33. package/dist/page-home.js +67 -0
  34. package/dist/page-home.js.map +1 -0
  35. package/dist/page-list.d.ts +23 -0
  36. package/dist/page-list.d.ts.map +1 -0
  37. package/dist/page-list.js +196 -0
  38. package/dist/page-list.js.map +1 -0
  39. package/dist/page-map.d.ts +20 -0
  40. package/dist/page-map.d.ts.map +1 -0
  41. package/dist/page-map.js +71 -0
  42. package/dist/page-map.js.map +1 -0
  43. package/dist/page-places.d.ts +72 -0
  44. package/dist/page-places.d.ts.map +1 -0
  45. package/dist/page-places.js +304 -0
  46. package/dist/page-places.js.map +1 -0
  47. package/dist/page-problems.d.ts +58 -0
  48. package/dist/page-problems.d.ts.map +1 -0
  49. package/dist/page-problems.js +113 -0
  50. package/dist/page-problems.js.map +1 -0
  51. package/dist/page-record.d.ts +14 -0
  52. package/dist/page-record.d.ts.map +1 -0
  53. package/dist/page-record.js +111 -0
  54. package/dist/page-record.js.map +1 -0
  55. package/dist/page-search.d.ts +50 -0
  56. package/dist/page-search.d.ts.map +1 -0
  57. package/dist/page-search.js +108 -0
  58. package/dist/page-search.js.map +1 -0
  59. package/dist/page-shell.d.ts +43 -0
  60. package/dist/page-shell.d.ts.map +1 -0
  61. package/dist/page-shell.js +171 -0
  62. package/dist/page-shell.js.map +1 -0
  63. package/dist/page-typography.d.ts +54 -0
  64. package/dist/page-typography.d.ts.map +1 -0
  65. package/dist/page-typography.js +166 -0
  66. package/dist/page-typography.js.map +1 -0
  67. package/dist/pages.d.ts +19 -0
  68. package/dist/pages.d.ts.map +1 -0
  69. package/dist/pages.js +19 -0
  70. package/dist/pages.js.map +1 -0
  71. package/dist/registry.d.ts +111 -0
  72. package/dist/registry.d.ts.map +1 -0
  73. package/dist/registry.js +105 -0
  74. package/dist/registry.js.map +1 -0
  75. package/dist/router.d.ts +35 -0
  76. package/dist/router.d.ts.map +1 -0
  77. package/dist/router.js +155 -0
  78. package/dist/router.js.map +1 -0
  79. package/package.json +63 -0
@@ -0,0 +1,171 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { LadderSetting, useMarkup } from "@graview/primitives";
3
+ import { Link, useLocation, useNavigate, useSearchParams } from "react-router-dom";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { kindMap } from "./facts.js";
6
+ import { kindOfSlug, pluralSlug } from "./registry.js";
7
+ import { StartFreshLink, useStoreTick } from "./page-context.js";
8
+ import { placesOf } from "./page-places.js";
9
+ import { usePlacedOnTheFace } from "./face-placed.js";
10
+ import { DISPLAY, WIDE, column, liveKinds, plain, pluralOf, quiet } from "./page-typography.js";
11
+ /**
12
+ * The shell: the installation's masthead, one row of navigation, the way to
13
+ * the scene. The pictures are the home, so they are not also a row of the
14
+ * nav — the row is the kinds, the map and the standing, and on a phone it
15
+ * scrolls sideways inside itself rather than wrapping to three rows over
16
+ * the page.
17
+ */
18
+ export function DefaultShell({ context, children, }) {
19
+ const { store, brand, sceneHref = "/", invariantContext } = context;
20
+ useStoreTick(store);
21
+ const logo = useMarkup(brand?.logo);
22
+ const location = useLocation();
23
+ const problems = store.violations(invariantContext).length;
24
+ const current = (path) => path === "/"
25
+ ? location.pathname === "/" || location.pathname === "/places" || location.pathname.startsWith("/places/")
26
+ : location.pathname === path || location.pathname.startsWith(`${path}/`);
27
+ const navLink = (path) => ({
28
+ ...plain,
29
+ fontSize: "0.9375rem",
30
+ padding: "8px 0",
31
+ flexShrink: 0,
32
+ color: current(path) ? "var(--graview-ink)" : "var(--graview-ink-muted)",
33
+ borderBottom: current(path) ? "2px solid var(--graview-accent)" : "2px solid transparent",
34
+ });
35
+ const tab = (path, label, extra) => (_jsx(Link, { to: path, style: { ...navLink(path), ...extra }, ...(current(path) ? { "aria-current": "page" } : {}), children: label }, path));
36
+ return (_jsxs("div", { style: {
37
+ minHeight: "100vh",
38
+ display: "flex",
39
+ flexDirection: "column",
40
+ background: "var(--graview-ground)",
41
+ color: "var(--graview-ink)",
42
+ fontFamily: "var(--graview-font-body, system-ui)",
43
+ fontSize: "1.0625rem",
44
+ lineHeight: 1.6,
45
+ }, children: [_jsx("header", { style: { borderBottom: "1px solid var(--graview-edge)", background: "var(--graview-bar)" }, children: _jsxs("div", { style: {
46
+ maxWidth: WIDE,
47
+ margin: "0 auto",
48
+ padding: "14px 20px 0",
49
+ display: "flex",
50
+ flexDirection: "column",
51
+ gap: 2,
52
+ }, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 14, flexWrap: "wrap" }, children: [_jsxs(Link, { to: "/", "data-testid": "masthead", style: {
53
+ ...plain,
54
+ display: "inline-flex",
55
+ alignItems: "center",
56
+ gap: 10,
57
+ fontFamily: DISPLAY,
58
+ fontSize: "1.3125rem",
59
+ fontWeight: 600,
60
+ letterSpacing: "-0.01em",
61
+ minHeight: 32,
62
+ }, children: [brand?.logo ? (_jsx("span", { "aria-hidden": "true", style: { display: "inline-flex", color: "var(--graview-accent)" },
63
+ // The logo is the brand's own markup, declared by the
64
+ // installation — not supplied by a user.
65
+ dangerouslySetInnerHTML: logo })) : null, brand?.name ?? "Graview"] }), _jsx(PageFind, { context: context }), _jsx("a", { href: sceneHref, style: { ...plain, ...quiet, whiteSpace: "nowrap" }, title: "The same thing, as a scene", children: "Open the scene \u2197" })] }), _jsxs("nav", { "aria-label": "Pages", "data-testid": "shell-nav", style: {
66
+ display: "flex",
67
+ gap: 18,
68
+ alignItems: "baseline",
69
+ overflowX: "auto",
70
+ whiteSpace: "nowrap",
71
+ scrollbarWidth: "thin",
72
+ minWidth: 0,
73
+ }, children: [tab("/", placesOf(context).length > 0 ? "Pictures" : "Home"), liveKinds(store, context.principal).map((kind) => tab(`/${pluralSlug(store.schema, kind)}`, pluralOf(store, kind))), kindMap(store).relations.length > 0 ? tab("/map", "Map") : null, tab("/problems", _jsxs(_Fragment, { children: ["Problems", problems > 0 ? (_jsx("span", { "data-testid": "problems-count", style: {
74
+ fontSize: "0.8125rem",
75
+ lineHeight: 1,
76
+ padding: "3px 7px",
77
+ borderRadius: 999,
78
+ color: "var(--graview-warn)",
79
+ border: "1px solid var(--graview-warn)",
80
+ }, children: problems })) : null] }),
81
+ // At the end of the row, set apart from the sections: the standing.
82
+ { display: "inline-flex", alignItems: "center", gap: 6, marginLeft: "auto" })] })] }) }), _jsx("div", { style: { flex: 1 }, children: children }), _jsx("footer", { style: {
83
+ borderTop: "1px solid var(--graview-edge)",
84
+ padding: "18px 20px 28px",
85
+ ...quiet,
86
+ fontSize: "0.875rem",
87
+ }, children: _jsxs("div", { style: { maxWidth: WIDE, margin: "0 auto", display: "flex", gap: 14, flexWrap: "wrap", alignItems: "center" }, children: [_jsx("span", { children: brand?.name ?? "Graview" }), context.views ? _jsx(LadderSetting, {}) : null, context.remembers ? (_jsxs("span", { "data-testid": "remembered", style: { marginLeft: "auto" }, children: ["Remembered in this browser \u00B7 ", _jsx(StartFreshLink, {})] })) : null] }) })] }));
88
+ }
89
+ /**
90
+ * A page's outer element: <main> when the face owns the document, a plain
91
+ * section when it is embedded in a page that has its own — `main` allows no
92
+ * other role, so the tag itself has to change.
93
+ */
94
+ export function PageMain({ context, style, children, ...rest }) {
95
+ // Somebody above owns the landmark: the host page, or the app's own shell.
96
+ const Tag = (context.embedded || context.framed ? "section" : "main");
97
+ return (_jsx(Tag, { style: { ...column, ...style }, ...rest, children: children }));
98
+ }
99
+ /**
100
+ * THE NAV'S FIND BOX. On a kind's list it narrows that list — `?q=` is the
101
+ * list's own word — and anywhere else it goes to `/search`. Typing is an
102
+ * adjustment of the page you are on, so each keystroke replaces the address
103
+ * rather than piling up history; the first keystroke away from a list or
104
+ * the search page is the one step Back undoes.
105
+ *
106
+ * Exported for a shell an app draws itself. `narrowsLists: false` is for an
107
+ * app whose own list pages already carry a box for their words: then this
108
+ * one always goes to `/search`, and a list never has two.
109
+ *
110
+ * Placed by a shell, it is THE face's Find box: the face's root sees it and
111
+ * draws no second one above the shell (face-controls.tsx).
112
+ */
113
+ export function PageFind({ context, narrowsLists = true, }) {
114
+ usePlacedOnTheFace("find");
115
+ const location = useLocation();
116
+ const navigate = useNavigate();
117
+ const [params, setParams] = useSearchParams();
118
+ const segments = location.pathname.split("/").filter(Boolean);
119
+ const onList = narrowsLists && segments.length === 1 && kindOfSlug(context.store.schema, segments[0]) !== undefined;
120
+ const onSearch = location.pathname === "/search";
121
+ const addressed = onList || onSearch ? (params.get("q") ?? "") : "";
122
+ const [typed, setTyped] = useState(addressed);
123
+ /*
124
+ * Back, a link, or the list's own row changed the words: the box follows
125
+ * the address. But not its own words coming back: each keystroke writes the
126
+ * address, and an address that caught up after the next key was taken for
127
+ * a change and written over the box — a key typed quickly on a slow phone
128
+ * was lost ("digital" searched as "dgtl"). Words the box handed over are
129
+ * its own echo.
130
+ */
131
+ const handed = useRef(new Set([addressed]));
132
+ useEffect(() => {
133
+ if (handed.current.has(addressed))
134
+ return;
135
+ handed.current = new Set([addressed]);
136
+ setTyped(addressed);
137
+ }, [addressed]);
138
+ const go = (words) => {
139
+ setTyped(words);
140
+ handed.current.add(words);
141
+ if (onList) {
142
+ const next = new URLSearchParams(params);
143
+ if (words.trim())
144
+ next.set("q", words);
145
+ else
146
+ next.delete("q");
147
+ setParams(next, { replace: true });
148
+ return;
149
+ }
150
+ const to = words.trim() ? `/search?${new URLSearchParams({ q: words }).toString()}` : "/search";
151
+ navigate(to, { replace: onSearch });
152
+ };
153
+ return (_jsx("form", { role: "search", "aria-label": onList ? "Narrow this list" : "Find anything", style: { marginLeft: "auto", display: "flex", minWidth: 0, flex: "0 1 16rem" }, onSubmit: (event) => {
154
+ event.preventDefault();
155
+ // Enter from a list widens the look to everything the words find.
156
+ if (onList && typed.trim())
157
+ navigate(`/search?${new URLSearchParams({ q: typed }).toString()}`);
158
+ }, children: _jsx("input", { type: "search", "data-testid": "nav-find", value: typed, onChange: (event) => go(event.target.value), placeholder: onList ? "Narrow…" : "Find…", "aria-label": onList ? "Narrow this list" : "Find anything", style: {
159
+ width: "100%",
160
+ minWidth: 0,
161
+ minHeight: 32,
162
+ padding: "4px 10px",
163
+ font: "inherit",
164
+ fontSize: "0.9375rem",
165
+ color: "var(--graview-ink)",
166
+ background: "var(--graview-ground)",
167
+ border: "1px solid var(--graview-edge)",
168
+ borderRadius: 8,
169
+ } }) }));
170
+ }
171
+ //# sourceMappingURL=page-shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-shell.js","sourceRoot":"","sources":["../src/page-shell.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { type AnyNodeDefinition, type AnySchema, type Brand, type Operation, type Principal, type Store, nameOfAuthor } from "@graview/core";
2
+ export declare const DISPLAY = "var(--graview-font-display, var(--graview-font-body, system-ui))";
3
+ export declare const column: React.CSSProperties;
4
+ export declare const WIDE = 1160;
5
+ export declare const wide: React.CSSProperties;
6
+ export declare const h1: React.CSSProperties;
7
+ export declare const h2: React.CSSProperties;
8
+ export declare const eyebrow: React.CSSProperties;
9
+ export declare const lede: React.CSSProperties;
10
+ export declare const quiet: React.CSSProperties;
11
+ export declare const rule: React.CSSProperties;
12
+ export declare const link: React.CSSProperties;
13
+ export declare const plain: React.CSSProperties;
14
+ export declare const button: React.CSSProperties;
15
+ /** The kind's own colour, as a small mark — the thread the scene wears too. */
16
+ /**
17
+ * The mark beside a kind's name — its FIGURE where it has one, and the dot
18
+ * it has always had where it does not.
19
+ *
20
+ * One component in `@graview/primitives`, so the routed face, the scene and
21
+ * the relation key draw the same thing from the same declaration. A second
22
+ * rendering here would be a second place for a kind's picture to be wrong.
23
+ */
24
+ export declare function KindMark({ kind, brand, size, schema, }: {
25
+ kind: string;
26
+ brand?: Brand;
27
+ size?: number;
28
+ schema?: AnySchema;
29
+ }): import("react").JSX.Element;
30
+ /**
31
+ * The kinds on the far end of a connections group, in their own plurals:
32
+ * "Owners" over an item's assignment, "Items" over the owner's.
33
+ */
34
+ export declare function listed<S extends AnySchema>(store: Store<S>, group: {
35
+ readonly targets: readonly {
36
+ readonly kind: string;
37
+ }[];
38
+ readonly edgeKind: string;
39
+ }): string;
40
+ /** Words for who did something, from the op's own author. */
41
+ /** Who did an op, as the person at the keyboard reads it: "you" only for their own work. */
42
+ export declare function whoDid(op: Operation, principal?: Principal, where?: Parameters<typeof nameOfAuthor>[1]): string;
43
+ /** A node's own one-line facts, for a list line or a front-page glance. */
44
+ export declare function glance(node: Record<string, unknown>, definition: AnyNodeDefinition | undefined, said: string): string;
45
+ /** The plural, as declared. */
46
+ export declare const pluralOf: <S extends AnySchema>(store: Store<S>, kind: string) => string;
47
+ /**
48
+ * The kinds this face lists: not a disabled module's, and not an administered
49
+ * module's unless the seat administers it — a gardener's pages never have a
50
+ * People section, the coordinator's always do.
51
+ */
52
+ export declare const liveKinds: <S extends AnySchema>(store: Store<S>, principal?: Principal) => readonly string[];
53
+ export declare const capitalise: (text: string) => string;
54
+ //# sourceMappingURL=page-typography.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-typography.d.ts","sourceRoot":"","sources":["../src/page-typography.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,KAAK,EACV,YAAY,EACb,MAAM,eAAe,CAAC;AASvB,eAAO,MAAM,OAAO,qEAAqE,CAAC;AAC1F,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,aAmB1B,CAAC;AAQF,eAAO,MAAM,IAAI,OAAO,CAAC;AACzB,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,aAA6C,CAAC;AACvE,eAAO,MAAM,EAAE,EAAE,KAAK,CAAC,aAQtB,CAAC;AACF,eAAO,MAAM,EAAE,EAAE,KAAK,CAAC,aAOtB,CAAC;AACF,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,aAM3B,CAAC;AACF,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,aAMxB,CAAC;AACF,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,aAA4E,CAAC;AACvG,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,aAA8E,CAAC;AAExG,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,aAOxB,CAAC;AAUF,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,aAMzB,CAAC;AACF,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,aAS1B,CAAC;AAEF,+EAA+E;AAC/E;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,IAAS,EACT,MAAM,GACP,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,+BAIA;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EACxC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,KAAK,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3F,MAAM,CAOR;AAED,6DAA6D;AAC7D,4FAA4F;AAC5F,wBAAgB,MAAM,CACpB,EAAE,EAAE,SAAS,EACb,SAAS,CAAC,EAAE,SAAS,EACrB,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,GACzC,MAAM,CAMR;AAED,2EAA2E;AAC3E,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,iBAAiB,GAAG,SAAS,EACzC,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED,+BAA+B;AAC/B,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,SAAS,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,MAAM,KAAG,MACtB,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,SAAS,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,SAAS,KAAG,SAAS,MAAM,EAKtG,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,MAAsD,CAAC"}
@@ -0,0 +1,166 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { KindFigure } from "@graview/primitives";
3
+ import { humaniseField, readableFields, nameOfAuthor, } from "@graview/core";
4
+ /*
5
+ * A reading column, a real scale. The scene's chrome is set at 14px because
6
+ * it is chrome; a page is read, so it gets the size a page gets. Headings
7
+ * take the brand's display face through the token the theme already sets —
8
+ * as a variable, never a `font` shorthand, which would silently beat it.
9
+ */
10
+ export const DISPLAY = "var(--graview-font-display, var(--graview-font-body, system-ui))";
11
+ export const column = {
12
+ maxWidth: 760,
13
+ margin: "0 auto",
14
+ padding: "40px 20px 96px",
15
+ display: "grid",
16
+ /*
17
+ * A TRACK THAT MAY BE NARROWER THAN WHAT IS IN IT.
18
+ *
19
+ * An `auto` track is at least the min-content width of its item, and a
20
+ * grid item's own `min-width: auto` is the same measure — so a section
21
+ * whose min-content the engine puts above the column's width pushes the
22
+ * whole page sideways. The engines do not agree on that measure: at a
23
+ * 32px root on a 390 screen, WebKit and Firefox made the list page's
24
+ * header 388 in a 350 track and the document scrolled two ways, while
25
+ * Chromium fitted it. `minmax(0, 1fr)` says the column is the width it
26
+ * was given, and what is inside it wraps.
27
+ */
28
+ gridTemplateColumns: "minmax(0, 1fr)",
29
+ gap: 40,
30
+ };
31
+ /*
32
+ * TWO WIDTHS, ONE FACE. A page that is READ keeps the 760 measure above; a
33
+ * page that is LOOKED AT — the home's gallery, a picture at full width, the
34
+ * shell that frames both — takes the room a desk has. The pictures were the
35
+ * one thing on the face that was the app's own, and at 288 pixels in a 760
36
+ * column they were the smallest thing on it.
37
+ */
38
+ export const WIDE = 1160;
39
+ export const wide = { ...column, maxWidth: WIDE };
40
+ export const h1 = {
41
+ margin: 0,
42
+ fontFamily: DISPLAY,
43
+ fontSize: "clamp(30px, 4.6vw, 40px)",
44
+ lineHeight: 1.12,
45
+ fontWeight: 600,
46
+ letterSpacing: "-0.012em",
47
+ overflowWrap: "anywhere",
48
+ };
49
+ export const h2 = {
50
+ margin: 0,
51
+ fontFamily: DISPLAY,
52
+ fontSize: "1.4375rem",
53
+ lineHeight: 1.25,
54
+ fontWeight: 600,
55
+ letterSpacing: "-0.006em",
56
+ };
57
+ export const eyebrow = {
58
+ margin: 0,
59
+ fontSize: "0.8125rem",
60
+ letterSpacing: "0.14em",
61
+ textTransform: "uppercase",
62
+ color: "var(--graview-ink-muted)",
63
+ };
64
+ export const lede = {
65
+ margin: 0,
66
+ fontSize: "1.1875rem",
67
+ lineHeight: 1.5,
68
+ color: "var(--graview-ink-muted)",
69
+ maxWidth: "58ch",
70
+ };
71
+ export const quiet = { color: "var(--graview-ink-muted)", fontSize: "0.9375rem" };
72
+ export const rule = { borderTop: "1px solid var(--graview-edge)", paddingTop: 24 };
73
+ // A link is a target: tall enough for a fingertip without leaving the line.
74
+ export const link = {
75
+ color: "inherit",
76
+ textDecorationColor: "var(--graview-edge-bright)",
77
+ textUnderlineOffset: 3,
78
+ display: "inline-flex",
79
+ alignItems: "center",
80
+ minHeight: 24,
81
+ };
82
+ /*
83
+ * An UNDERLINED link is a target and an undecorated one is the same target.
84
+ *
85
+ * `link` carried the 24px minimum and `plain` — the same thing without the
86
+ * underline, used on the record page's eyebrow, the list's rows and the
87
+ * masthead — did not, so the framework's own record page had a 19-pixel
88
+ * control on it. One site had already patched the minimum back in by hand,
89
+ * which is the style telling you where it should have lived.
90
+ */
91
+ export const plain = {
92
+ color: "inherit",
93
+ textDecoration: "none",
94
+ display: "inline-flex",
95
+ alignItems: "center",
96
+ minHeight: 24,
97
+ };
98
+ export const button = {
99
+ font: "inherit",
100
+ fontSize: "0.9375rem",
101
+ padding: "8px 14px",
102
+ borderRadius: "var(--graview-radius-sm, 8px)",
103
+ border: "1px solid var(--graview-edge-bright)",
104
+ background: "var(--graview-panel)",
105
+ color: "var(--graview-ink)",
106
+ cursor: "pointer",
107
+ };
108
+ /** The kind's own colour, as a small mark — the thread the scene wears too. */
109
+ /**
110
+ * The mark beside a kind's name — its FIGURE where it has one, and the dot
111
+ * it has always had where it does not.
112
+ *
113
+ * One component in `@graview/primitives`, so the routed face, the scene and
114
+ * the relation key draw the same thing from the same declaration. A second
115
+ * rendering here would be a second place for a kind's picture to be wrong.
116
+ */
117
+ export function KindMark({ kind, brand, size = 10, schema, }) {
118
+ // A figure wants more room than a dot: the dot is the figure's own inner
119
+ // circle, so passing the dot's size straight through would draw a stamp.
120
+ return _jsx(KindFigure, { kind: kind, ...(schema ? { schema } : {}), ...(brand ? { brand } : {}), size: Math.round(size * 1.6) });
121
+ }
122
+ /**
123
+ * The kinds on the far end of a connections group, in their own plurals:
124
+ * "Owners" over an item's assignment, "Items" over the owner's.
125
+ */
126
+ export function listed(store, group) {
127
+ const kinds = [...new Set(group.targets.map((target) => target.kind))];
128
+ const said = kinds.map((kind) => {
129
+ const definition = store.schema.tryDefinition(kind);
130
+ return definition?.plural ?? humaniseField(kind);
131
+ });
132
+ return said.length > 0 ? said.join(" and ") : humaniseField(group.edgeKind);
133
+ }
134
+ /** Words for who did something, from the op's own author. */
135
+ /** Who did an op, as the person at the keyboard reads it: "you" only for their own work. */
136
+ export function whoDid(op, principal, where) {
137
+ if (op.author.kind === "human" && (op.author.id === undefined || principal?.id === undefined || op.author.id === principal.id))
138
+ return "you";
139
+ // By name where the graph or the seats have one — never an id a person was not offered.
140
+ if (where)
141
+ return nameOfAuthor(op.author, where);
142
+ if (op.author.kind === "agent")
143
+ return op.author.id ?? "an agent";
144
+ return op.author.id ?? op.author.kind;
145
+ }
146
+ /** A node's own one-line facts, for a list line or a front-page glance. */
147
+ export function glance(node, definition, said) {
148
+ // A bare number says nothing on its own — "12 · 8" is not a sentence —
149
+ // so each fact is read the way it stands alone, the same words a card uses.
150
+ return readableFields(node, definition, { limit: 3, said: [said], glance: true })
151
+ .map((field) => field.alone)
152
+ .join(" · ");
153
+ }
154
+ /** The plural, as declared. */
155
+ export const pluralOf = (store, kind) => store.schema.tryDefinition(kind)?.plural ?? `${kind}s`;
156
+ /**
157
+ * The kinds this face lists: not a disabled module's, and not an administered
158
+ * module's unless the seat administers it — a gardener's pages never have a
159
+ * People section, the coordinator's always do.
160
+ */
161
+ export const liveKinds = (store, principal) => {
162
+ const kept = store.kindsKeptFrom(principal);
163
+ return store.schema.kinds.filter((kind) => !store.modules.disabledKinds.has(kind) && !kept.has(kind));
164
+ };
165
+ export const capitalise = (text) => text.charAt(0).toUpperCase() + text.slice(1);
166
+ //# sourceMappingURL=page-typography.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-typography.js","sourceRoot":"","sources":["../src/page-typography.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * THE PAGES FACE: the same graph as the scene, as routed, responsive pages.
3
+ *
4
+ * Every page here is derived from the declaration — a shell, a map of the
5
+ * kinds, the places an app names, a home, a list per kind, a record, and
6
+ * the problems — so an app with no pages of its own already has all of
7
+ * them, and one that writes its own replaces them one at a time.
8
+ */
9
+ export * from "./page-context.js";
10
+ export * from "./page-typography.js";
11
+ export * from "./page-shell.js";
12
+ export * from "./page-map.js";
13
+ export * from "./page-places.js";
14
+ export * from "./page-home.js";
15
+ export * from "./page-list.js";
16
+ export * from "./page-record.js";
17
+ export * from "./page-problems.js";
18
+ export * from "./page-search.js";
19
+ //# sourceMappingURL=pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../src/pages.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
package/dist/pages.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * THE PAGES FACE: the same graph as the scene, as routed, responsive pages.
3
+ *
4
+ * Every page here is derived from the declaration — a shell, a map of the
5
+ * kinds, the places an app names, a home, a list per kind, a record, and
6
+ * the problems — so an app with no pages of its own already has all of
7
+ * them, and one that writes its own replaces them one at a time.
8
+ */
9
+ export * from "./page-context.js";
10
+ export * from "./page-typography.js";
11
+ export * from "./page-shell.js";
12
+ export * from "./page-map.js";
13
+ export * from "./page-places.js";
14
+ export * from "./page-home.js";
15
+ export * from "./page-list.js";
16
+ export * from "./page-record.js";
17
+ export * from "./page-problems.js";
18
+ export * from "./page-search.js";
19
+ //# sourceMappingURL=pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../src/pages.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,111 @@
1
+ import type { AnySchema, KindOfSchema } from "@graview/core";
2
+ import type { ComponentType, ReactNode } from "react";
3
+ import type { PageContext } from "./page-context.js";
4
+ import type { FaceControl } from "./face-placed.js";
5
+ /**
6
+ * The frame around every route: it is handed the page as `children`.
7
+ *
8
+ * The skill says a shell "receives `{ context, children }`", and the only
9
+ * signature `surface` had was a page's, which has no children — so every
10
+ * design registered its shell with `as PageComponent<S>`, and the worked
11
+ * examples taught the cast.
12
+ */
13
+ export type ShellComponent<S extends AnySchema> = ComponentType<{
14
+ readonly context: PageContext<S>;
15
+ readonly children: ReactNode;
16
+ }>;
17
+ /**
18
+ * The page registry, shaped like the view registry ON PURPOSE.
19
+ *
20
+ * (kind × page type) → component, defaults registered first, an app
21
+ * overriding per cell — an author who has registered a view already knows
22
+ * how to register a page, and that symmetry is the whole SDK story. The
23
+ * layout shell is itself a registration, so custom chrome is the same
24
+ * authoring move as a custom record page.
25
+ */
26
+ export type PageType = "list" | "record";
27
+ /** App-level surfaces that are not per-kind: the shell and the fixed pages. */
28
+ export type SurfaceType = "shell" | "home" | "problems";
29
+ /**
30
+ * What a shell may say it goes without: the routed face's Find box, its way
31
+ * back. Without this said, a shell that does not place `<PageFind>` or
32
+ * `<PageUndo>` gets them drawn around it.
33
+ */
34
+ export interface ShellOptions {
35
+ readonly without?: readonly FaceControl[];
36
+ }
37
+ export interface PageRegistration<P = unknown> {
38
+ readonly kind: string;
39
+ readonly page: PageType;
40
+ readonly component: P;
41
+ }
42
+ /** A page the schema knows nothing about, at a path the app chose. */
43
+ export interface RouteRegistration<P = unknown> {
44
+ readonly path: string;
45
+ readonly component: P;
46
+ }
47
+ export interface PageRegistry<S extends AnySchema, P = unknown> {
48
+ register<K extends KindOfSchema<S>>(kind: K, page: PageType, component: P): PageRegistry<S, P>;
49
+ surface(surface: "shell", component: ShellComponent<S>, options?: ShellOptions): PageRegistry<S, P>;
50
+ surface(surface: SurfaceType, component: P): PageRegistry<S, P>;
51
+ /**
52
+ * A PAGE THAT IS NOT ABOUT A KIND.
53
+ *
54
+ * The derived routes are `/`, `/problems`, `/:plural` and `/:plural/:id`,
55
+ * and the registry let an app REPLACE any of them. It could not ADD one —
56
+ * so an onboarding, a settings page, an import screen, an about, or a desk
57
+ * that takes photographs and proposes a survey had nowhere to live. The
58
+ * workaround every app reaches for is to have its shell read `useLocation`
59
+ * and swap its children, which works and lies to the router: `/:slug`
60
+ * still matches, the kind switch still runs, and the shell overrides the
61
+ * result.
62
+ *
63
+ * Registered routes are matched BEFORE the derived ones, so a path of the
64
+ * app's own is never swallowed by the list route. Rendered inside the
65
+ * shell like any other page.
66
+ */
67
+ route(path: string, component: P): PageRegistry<S, P>;
68
+ lookup(kind: string, page: PageType): P | undefined;
69
+ lookupSurface(surface: SurfaceType): P | undefined;
70
+ /** The face's own controls the shell said it goes without. */
71
+ without(): ReadonlySet<FaceControl>;
72
+ /** The app's own routes, in registration order. */
73
+ routes(): readonly RouteRegistration<P>[];
74
+ all(): readonly PageRegistration<P>[];
75
+ }
76
+ export declare function createPageRegistry<S extends AnySchema, P = ComponentType<never>>(schema: S): PageRegistry<S, P>;
77
+ /**
78
+ * Routes derive from the schema: `/:plural` and `/:plural/:id` off the
79
+ * plural the declaration already carries. One slug per kind — `graview
80
+ * check` refuses two kinds whose plurals collide, because a route that
81
+ * depends on registration order is a route nobody can link to.
82
+ */
83
+ export declare function pluralSlug(schema: AnySchema, kind: string): string;
84
+ /** kind ← slug, the other direction of `pluralSlug`. */
85
+ export declare function kindOfSlug(schema: AnySchema, slug: string): string | undefined;
86
+ /** The routed address of one node — shared ids are what make two faces one app. */
87
+ export declare function recordPath(schema: AnySchema, kind: string, id: string): string;
88
+ /** The spatial stop for the same node, for the link back into the scene. */
89
+ export declare function spatialHref(id: string): string;
90
+ /**
91
+ * The spatial stop that shows one NAMED PLACE — a lens, by the name it was
92
+ * registered under.
93
+ *
94
+ * A page that has just drawn three areas wants to link to the map, and could
95
+ * only ever say "open the scene and press The grounds", because the long form
96
+ * of that stop needs the aggregate id of the kind behind the picture and a
97
+ * page has no business knowing how the layout spells one. A place's name is
98
+ * unique across an app, so naming it is enough: the scene looks it up and
99
+ * focuses the group it is a picture of.
100
+ *
101
+ * `placeSlug(title)` in `@graview/core` turns a registered title into the
102
+ * name to pass here.
103
+ */
104
+ export declare function placeHref(as: string, sceneHref?: string): string;
105
+ /**
106
+ * The routed address of one PLACE — a lens, by the name it was registered
107
+ * under — on this face. Namespaced under `/places/` so it can never collide
108
+ * with a kind's plural, whatever an app calls its pictures.
109
+ */
110
+ export declare function placePath(as: string): string;
111
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}