@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,105 @@
1
+ export function createPageRegistry(schema) {
2
+ const entries = new Map();
3
+ const surfaces = new Map();
4
+ const registrations = [];
5
+ const routed = [];
6
+ let goesWithout = new Set();
7
+ const registry = {
8
+ register(kind, page, component) {
9
+ entries.set(`${kind}|${page}`, component);
10
+ registrations.push({ kind, page, component });
11
+ return registry;
12
+ },
13
+ surface(surface, component, options) {
14
+ surfaces.set(surface, component);
15
+ if (surface === "shell")
16
+ goesWithout = new Set(options?.without ?? []);
17
+ return registry;
18
+ },
19
+ route(path, component) {
20
+ const at = path.startsWith("/") ? path : `/${path}`;
21
+ /*
22
+ * A route that shadows a derived one is almost always a mistake, and
23
+ * a silent one: the kind's list would simply stop appearing. Said out
24
+ * loud rather than refused, because an app that means it — a list page
25
+ * so different it is not a list — is entitled to mean it, and
26
+ * `register(kind, "list")` is the way to say so on purpose.
27
+ */
28
+ const head = at.split("/")[1] ?? "";
29
+ const shadowed = schema.kinds.find((kind) => pluralSlug(schema, kind) === head);
30
+ if (shadowed !== undefined || head === "problems" || head === "search") {
31
+ console.warn(`[graview] route("${at}") shadows the derived ${shadowed === undefined ? `${head} page` : `list of ${shadowed}`}. Use register("${shadowed ?? ""}", "list", …) to replace it, or choose another path.`);
32
+ }
33
+ routed.push({ path: at, component });
34
+ return registry;
35
+ },
36
+ lookup(kind, page) {
37
+ return entries.get(`${kind}|${page}`);
38
+ },
39
+ lookupSurface(surface) {
40
+ return surfaces.get(surface);
41
+ },
42
+ without() {
43
+ return goesWithout;
44
+ },
45
+ routes() {
46
+ return routed;
47
+ },
48
+ all() {
49
+ return registrations;
50
+ },
51
+ };
52
+ return registry;
53
+ }
54
+ /**
55
+ * Routes derive from the schema: `/:plural` and `/:plural/:id` off the
56
+ * plural the declaration already carries. One slug per kind — `graview
57
+ * check` refuses two kinds whose plurals collide, because a route that
58
+ * depends on registration order is a route nobody can link to.
59
+ */
60
+ export function pluralSlug(schema, kind) {
61
+ const definition = schema.tryDefinition(kind);
62
+ const plural = definition?.plural ?? `${kind}s`;
63
+ return plural
64
+ .toLowerCase()
65
+ .replace(/[^a-z0-9]+/g, "-")
66
+ .replace(/^-|-$/g, "");
67
+ }
68
+ /** kind ← slug, the other direction of `pluralSlug`. */
69
+ export function kindOfSlug(schema, slug) {
70
+ return schema.kinds.find((kind) => pluralSlug(schema, kind) === slug);
71
+ }
72
+ /** The routed address of one node — shared ids are what make two faces one app. */
73
+ export function recordPath(schema, kind, id) {
74
+ return `/${pluralSlug(schema, kind)}/${encodeURIComponent(id)}`;
75
+ }
76
+ /** The spatial stop for the same node, for the link back into the scene. */
77
+ export function spatialHref(id) {
78
+ return `/#focus=${encodeURIComponent(id)}`;
79
+ }
80
+ /**
81
+ * The spatial stop that shows one NAMED PLACE — a lens, by the name it was
82
+ * registered under.
83
+ *
84
+ * A page that has just drawn three areas wants to link to the map, and could
85
+ * only ever say "open the scene and press The grounds", because the long form
86
+ * of that stop needs the aggregate id of the kind behind the picture and a
87
+ * page has no business knowing how the layout spells one. A place's name is
88
+ * unique across an app, so naming it is enough: the scene looks it up and
89
+ * focuses the group it is a picture of.
90
+ *
91
+ * `placeSlug(title)` in `@graview/core` turns a registered title into the
92
+ * name to pass here.
93
+ */
94
+ export function placeHref(as, sceneHref = "/") {
95
+ return `${sceneHref}#view=${encodeURIComponent(as)}`;
96
+ }
97
+ /**
98
+ * The routed address of one PLACE — a lens, by the name it was registered
99
+ * under — on this face. Namespaced under `/places/` so it can never collide
100
+ * with a kind's plural, whatever an app calls its pictures.
101
+ */
102
+ export function placePath(as) {
103
+ return `/places/${encodeURIComponent(as)}`;
104
+ }
105
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { AnySchema } from "@graview/core";
2
+ import { type ComponentType } from "react";
3
+ import { type PageContext } from "./pages.js";
4
+ import { createPageRegistry, type PageRegistry } from "./registry.js";
5
+ /**
6
+ * The routed face, assembled: `/` home, `/:plural` a list per kind,
7
+ * `/:plural/:id` a record per node, `/problems` the standing. Routes derive
8
+ * from the schema; the registry overrides components per cell; the shell is
9
+ * itself a registration. One store underneath — the two faces are one
10
+ * application because the ids are.
11
+ */
12
+ export type PageComponent<S extends AnySchema> = ComponentType<{
13
+ context: PageContext<S>;
14
+ }>;
15
+ export interface PagesAppProps<S extends AnySchema> {
16
+ readonly context: PageContext<S>;
17
+ readonly registry?: PageRegistry<S, PageComponent<S>>;
18
+ /** Mount path when the scene owns "/" — e.g. "/pages". */
19
+ readonly basename?: string;
20
+ /**
21
+ * For tests and SSR: render at a fixed address with no real history.
22
+ *
23
+ * BASENAME-RELATIVE, like every `to` on this face. Given `basename`, the
24
+ * router is mounted at it and this path is joined on — so what a test
25
+ * renders is what a browser renders.
26
+ */
27
+ readonly initialPath?: string;
28
+ }
29
+ export declare function PagesRoutes<S extends AnySchema>({ context, registry, }: {
30
+ readonly context: PageContext<S>;
31
+ readonly registry?: PageRegistry<S, PageComponent<S>>;
32
+ }): import("react").JSX.Element;
33
+ export declare function PagesApp<S extends AnySchema>({ context, registry, basename, initialPath, }: PagesAppProps<S>): import("react").JSX.Element;
34
+ export { createPageRegistry };
35
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAsC,KAAK,aAAa,EAAkB,MAAM,OAAO,CAAC;AAI/F,OAAO,EAAkK,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9M,OAAO,EAAE,kBAAkB,EAAc,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlF;;;;;;GAMG;AAEH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,SAAS,IAAI,aAAa,CAAC;IAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC,CAAC;AAE5F,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,SAAS;IAChD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AA0GD,wBAAgB,WAAW,CAAC,CAAC,SAAS,SAAS,EAAE,EAC/C,OAAO,EACP,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;CACvD,+BAmDA;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,SAAS,EAAE,EAC5C,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,WAAW,GACZ,EAAE,aAAa,CAAC,CAAC,CAAC,+BAsDlB;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
package/dist/router.js ADDED
@@ -0,0 +1,155 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { BrowserRouter, MemoryRouter, Route, Routes } from "react-router-dom";
3
+ import { useEffect, useLayoutEffect, useRef } from "react";
4
+ import { GraviewProvider, useTheKeyboardLandsSomewhere } from "@graview/react";
5
+ import { PageAsk } from "./ask.js";
6
+ import { FaceControlsRoot } from "./face-controls.js";
7
+ import { DefaultHomePage, DefaultListPage, DefaultMapPage, DefaultPlacePage, DefaultPlacesPage, DefaultProblemsPage, DefaultRecordPage, DefaultSearchPage, DefaultShell } from "./pages.js";
8
+ import { createPageRegistry, kindOfSlug } from "./registry.js";
9
+ import { useLocation, useNavigationType, useParams } from "react-router-dom";
10
+ function KindSwitch({ context, registry, page, }) {
11
+ const params = useParams();
12
+ const kind = kindOfSlug(context.store.schema, params["slug"] ?? "");
13
+ const Fallback = page === "list" ? DefaultListPage : DefaultRecordPage;
14
+ const Registered = kind ? registry?.lookup(kind, page) : undefined;
15
+ const Component = (Registered ?? Fallback);
16
+ return _jsx(Component, { context: context });
17
+ }
18
+ /*
19
+ * A NEW PAGE OPENS AT ITS TOP.
20
+ *
21
+ * The router keeps the document where it was: press a card at the foot of
22
+ * the gallery and the picture's page opened already scrolled to its own
23
+ * foot, with the heading somewhere above the window. A browser resets the
24
+ * scroll on a full navigation and this face never had one, which the
25
+ * readme-shaped home was short enough to hide.
26
+ *
27
+ * Reset on a NEW address only: Back and Forward are left to the browser,
28
+ * which restores the position it recorded for that entry, and a change of
29
+ * search alone — the list page writes `?q=` as you type — is an adjustment
30
+ * of the page you are on, not a page. What scrolls is whatever holds the
31
+ * face: the window when it owns the document, the nearest ancestor that
32
+ * scrolls when it is inside an embed's frame or a shell's own region — so
33
+ * a host page with three embeds is never yanked to the top of one of them.
34
+ */
35
+ /**
36
+ * The routed face's root: the rule that the keyboard always lands
37
+ * somewhere, and the controls the face offers whichever shell draws it —
38
+ * Find and the way back (face-controls.tsx).
39
+ */
40
+ function FaceRoot({ context, registry, children, }) {
41
+ const root = useRef(null);
42
+ useTheKeyboardLandsSomewhere(root);
43
+ return (_jsx("div", { ref: root, "data-graview-face": "pages", style: { display: "contents" }, children: _jsx(FaceControlsRoot, { context: context, registry: registry, root: root, children: children }) }));
44
+ }
45
+ function ScrollReset() {
46
+ const { pathname } = useLocation();
47
+ const type = useNavigationType();
48
+ const mark = useRef(null);
49
+ useLayoutEffect(() => {
50
+ if (type === "POP")
51
+ return;
52
+ for (let at = mark.current?.parentElement; at; at = at.parentElement) {
53
+ const { overflowY } = getComputedStyle(at);
54
+ if ((overflowY === "auto" || overflowY === "scroll") && at.scrollHeight > at.clientHeight) {
55
+ at.scrollTop = 0;
56
+ return;
57
+ }
58
+ }
59
+ window.scrollTo(0, 0);
60
+ // The address is the page; its search and hash are where you are on it.
61
+ // eslint-disable-next-line react-hooks/exhaustive-deps
62
+ }, [pathname]);
63
+ /*
64
+ * A NEW PAGE TAKES THE KEYBOARD AT ITS HEADING. Following a link removes
65
+ * the page the link was on, and with it the keyboard, which fell to
66
+ * <body>: Tab started again at the top of the document and a screen
67
+ * reader said nothing about where it had arrived. Where the keyboard was
68
+ * on the page that left, it lands on the heading of the one that came —
69
+ * which a reader then hears — and nowhere else, so a person who was
70
+ * typing in the search box is not moved.
71
+ */
72
+ // The first page is where the reader arrived, not where they went.
73
+ const arrivedAt = useRef(pathname);
74
+ const moved = useRef(false);
75
+ useEffect(() => {
76
+ if (!moved.current && pathname === arrivedAt.current)
77
+ return;
78
+ moved.current = true;
79
+ const active = document.activeElement;
80
+ if (active !== null && active !== document.body && active !== document.documentElement)
81
+ return;
82
+ const main = mark.current?.closest("main") ?? document.querySelector("main");
83
+ const heading = main?.querySelector("h1") ?? null;
84
+ const target = heading ?? main ?? null;
85
+ if (!target)
86
+ return;
87
+ if (!target.hasAttribute("tabindex"))
88
+ target.setAttribute("tabindex", "-1");
89
+ target.focus({ preventScroll: true });
90
+ // eslint-disable-next-line react-hooks/exhaustive-deps
91
+ }, [pathname]);
92
+ return _jsx("span", { ref: mark, hidden: true, "data-graview-scroll-reset": "" });
93
+ }
94
+ export function PagesRoutes({ context, registry, }) {
95
+ const own = registry?.lookupSurface("shell");
96
+ const Shell = (own ?? DefaultShell);
97
+ const Home = (registry?.lookupSurface("home") ?? DefaultHomePage);
98
+ const Problems = (registry?.lookupSurface("problems") ?? DefaultProblemsPage);
99
+ /*
100
+ * A SHELL OF THE APP'S OWN OWNS THE LANDMARK.
101
+ *
102
+ * `graview-pages` tells a design's shell to render the one `main`, and the
103
+ * framework's own pages went on wrapping themselves in `PageMain`
104
+ * underneath it — so every route a design left derived had a main inside a
105
+ * main, and so did the not-found page, which is reachable in EVERY design
106
+ * because there is no kind to register it on. The registry already knows;
107
+ * the pages under the shell just had to be told.
108
+ */
109
+ const inside = own ? { ...context, framed: true } : context;
110
+ return (
111
+ // The routed face holds the keyboard the way the scene does, and offers Find and the way back, whichever shell an app draws.
112
+ _jsx(FaceRoot, { context: context, registry: registry, children: _jsxs(Shell, { context: context, children: [_jsx(ScrollReset, {}), _jsxs(Routes, { children: [(registry?.routes() ?? []).map(({ path, component }) => {
113
+ const Page = component;
114
+ return _jsx(Route, { path: path, element: _jsx(Page, { context: inside }) }, path);
115
+ }), _jsx(Route, { path: "/", element: _jsx(Home, { context: inside }) }), _jsx(Route, { path: "/problems", element: _jsx(Problems, { context: inside }) }), _jsx(Route, { path: "/search", element: _jsx(DefaultSearchPage, { context: inside }) }), _jsx(Route, { path: "/map", element: _jsx(DefaultMapPage, { context: inside }) }), _jsx(Route, { path: "/places", element: _jsx(DefaultPlacesPage, { context: inside }) }), _jsx(Route, { path: "/places/:as", element: _jsx(DefaultPlacePage, { context: inside }) }), _jsx(Route, { path: "/:slug", element: _jsx(KindSwitch, { context: inside, registry: registry, page: "list" }) }), _jsx(Route, { path: "/:slug/:id", element: _jsx(KindSwitch, { context: inside, registry: registry, page: "record" }) })] })] }) }));
116
+ }
117
+ export function PagesApp({ context, registry, basename, initialPath, }) {
118
+ const routed = _jsx(PagesRoutes, { context: context, ...(registry ? { registry } : {}) });
119
+ /*
120
+ * A PROVIDER UNDER THE PAGES when the app handed over its views, so a lens
121
+ * drawn on a page finds the store, the seat and the registry its hooks ask
122
+ * for — the same provider the embed puts under this face. No scene, no
123
+ * URL sync: the router owns the address here.
124
+ */
125
+ /*
126
+ * THE SEAT BELONGS TO THE FACE, NOT TO ONE SHELL. Mounted here rather
127
+ * than inside the derived chrome, so an app that replaced every surface
128
+ * with a design of its own still has the assistant — the same panel, on
129
+ * every route, however the pages around it are drawn.
130
+ */
131
+ const inner = context.views ? (_jsxs(GraviewProvider, { store: context.store, views: context.views, ...(context.principal ? { principal: context.principal } : {}), ...(context.brand ? { brand: context.brand } : {}), ...(context.settings ? { settings: context.settings } : {}), ...(context.presence ? { presence: context.presence } : {}), children: [routed, _jsx(PageAsk, { context: context })] })) : (routed);
132
+ if (initialPath !== undefined) {
133
+ /*
134
+ * THE TEST ROUTER CARRIES THE BASENAME TOO, OR THE TESTS ARE A LIE.
135
+ *
136
+ * `MemoryRouter` used to be handed the path and nothing else, so under
137
+ * `basename="/pages"` a `<Link to="/survey">` rendered `/survey` in a
138
+ * test and `/pages/survey` in a browser — and a link written the other
139
+ * way round, `to="/pages/survey"`, rendered correctly in every test and
140
+ * doubled to `/pages/pages/survey` the moment anybody opened it. A
141
+ * product shipped nine of those with twenty-five green tests asserting
142
+ * the exact hrefs.
143
+ *
144
+ * `initialPath` is basename-RELATIVE, like every `to` on this face, and
145
+ * the router is given both — so a test renders the hrefs a browser will.
146
+ * A path that already carries the basename now doubles here as well,
147
+ * which is the whole point: the mistake fails where it is cheap.
148
+ */
149
+ const entry = basename === undefined ? initialPath : `${basename.replace(/\/$/, "")}${initialPath}`;
150
+ return (_jsx(MemoryRouter, { initialEntries: [entry], ...(basename === undefined ? {} : { basename }), children: inner }));
151
+ }
152
+ return _jsx(BrowserRouter, { ...(basename === undefined ? {} : { basename }), children: inner });
153
+ }
154
+ export { createPageRegistry };
155
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.tsx"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@graview/pages",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "dependencies": {
14
+ "react-router-dom": "^7.1.1",
15
+ "@graview/core": "0.1.0",
16
+ "@graview/react": "0.1.0",
17
+ "@graview/primitives": "0.1.0",
18
+ "@graview/tools": "0.1.0",
19
+ "@graview/layout": "0.1.0"
20
+ },
21
+ "peerDependencies": {
22
+ "react": ">=18"
23
+ },
24
+ "devDependencies": {
25
+ "zod": "^4.4.3"
26
+ },
27
+ "description": "The traditional face: a routed webapp derived from the same declaration that drives the scene.",
28
+ "keywords": [
29
+ "graview",
30
+ "context-graph",
31
+ "typed-graph",
32
+ "interface",
33
+ "declarative",
34
+ "react",
35
+ "routing",
36
+ "pages",
37
+ "crud"
38
+ ],
39
+ "files": [
40
+ "dist",
41
+ "README.md"
42
+ ],
43
+ "sideEffects": false,
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/en-dash-consulting/graview.git",
47
+ "directory": "packages/pages"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "license": "Elastic-2.0",
53
+ "homepage": "https://graview.dev/docs/packages/pages.html",
54
+ "bugs": {
55
+ "url": "https://github.com/en-dash-consulting/graview/issues"
56
+ },
57
+ "engines": {
58
+ "node": ">=22"
59
+ },
60
+ "scripts": {
61
+ "build": "tsc -b"
62
+ }
63
+ }