@graview/primitives 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 (207) hide show
  1. package/LICENSE +96 -0
  2. package/README.md +25 -0
  3. package/dist/arrange-bar.d.ts +49 -0
  4. package/dist/arrange-bar.d.ts.map +1 -0
  5. package/dist/arrange-bar.js +264 -0
  6. package/dist/arrange-bar.js.map +1 -0
  7. package/dist/chat.d.ts +46 -0
  8. package/dist/chat.d.ts.map +1 -0
  9. package/dist/chat.js +343 -0
  10. package/dist/chat.js.map +1 -0
  11. package/dist/companion.d.ts +58 -0
  12. package/dist/companion.d.ts.map +1 -0
  13. package/dist/companion.js +433 -0
  14. package/dist/companion.js.map +1 -0
  15. package/dist/connections.d.ts +23 -0
  16. package/dist/connections.d.ts.map +1 -0
  17. package/dist/connections.js +100 -0
  18. package/dist/connections.js.map +1 -0
  19. package/dist/default-views.d.ts +35 -0
  20. package/dist/default-views.d.ts.map +1 -0
  21. package/dist/default-views.js +605 -0
  22. package/dist/default-views.js.map +1 -0
  23. package/dist/editable.d.ts +71 -0
  24. package/dist/editable.d.ts.map +1 -0
  25. package/dist/editable.js +225 -0
  26. package/dist/editable.js.map +1 -0
  27. package/dist/figure.d.ts +30 -0
  28. package/dist/figure.d.ts.map +1 -0
  29. package/dist/figure.js +66 -0
  30. package/dist/figure.js.map +1 -0
  31. package/dist/find.d.ts +5 -0
  32. package/dist/find.d.ts.map +1 -0
  33. package/dist/find.js +252 -0
  34. package/dist/find.js.map +1 -0
  35. package/dist/index.d.ts +51 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +44 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/installation.d.ts +17 -0
  40. package/dist/installation.d.ts.map +1 -0
  41. package/dist/installation.js +37 -0
  42. package/dist/installation.js.map +1 -0
  43. package/dist/ladder.d.ts +2 -0
  44. package/dist/ladder.d.ts.map +1 -0
  45. package/dist/ladder.js +53 -0
  46. package/dist/ladder.js.map +1 -0
  47. package/dist/lens/arranging.d.ts +41 -0
  48. package/dist/lens/arranging.d.ts.map +1 -0
  49. package/dist/lens/arranging.js +38 -0
  50. package/dist/lens/arranging.js.map +1 -0
  51. package/dist/lens/board.d.ts +146 -0
  52. package/dist/lens/board.d.ts.map +1 -0
  53. package/dist/lens/board.js +658 -0
  54. package/dist/lens/board.js.map +1 -0
  55. package/dist/lens/calendar-dates.d.ts +19 -0
  56. package/dist/lens/calendar-dates.d.ts.map +1 -0
  57. package/dist/lens/calendar-dates.js +55 -0
  58. package/dist/lens/calendar-dates.js.map +1 -0
  59. package/dist/lens/calendar-drawing.d.ts +59 -0
  60. package/dist/lens/calendar-drawing.d.ts.map +1 -0
  61. package/dist/lens/calendar-drawing.js +229 -0
  62. package/dist/lens/calendar-drawing.js.map +1 -0
  63. package/dist/lens/calendar-options.d.ts +107 -0
  64. package/dist/lens/calendar-options.d.ts.map +1 -0
  65. package/dist/lens/calendar-options.js +19 -0
  66. package/dist/lens/calendar-options.js.map +1 -0
  67. package/dist/lens/calendar-placing.d.ts +35 -0
  68. package/dist/lens/calendar-placing.d.ts.map +1 -0
  69. package/dist/lens/calendar-placing.js +113 -0
  70. package/dist/lens/calendar-placing.js.map +1 -0
  71. package/dist/lens/calendar-spans.d.ts +48 -0
  72. package/dist/lens/calendar-spans.d.ts.map +1 -0
  73. package/dist/lens/calendar-spans.js +146 -0
  74. package/dist/lens/calendar-spans.js.map +1 -0
  75. package/dist/lens/calendar-view.d.ts +34 -0
  76. package/dist/lens/calendar-view.d.ts.map +1 -0
  77. package/dist/lens/calendar-view.js +228 -0
  78. package/dist/lens/calendar-view.js.map +1 -0
  79. package/dist/lens/calendar.d.ts +43 -0
  80. package/dist/lens/calendar.d.ts.map +1 -0
  81. package/dist/lens/calendar.js +43 -0
  82. package/dist/lens/calendar.js.map +1 -0
  83. package/dist/lens/coverage.d.ts +183 -0
  84. package/dist/lens/coverage.d.ts.map +1 -0
  85. package/dist/lens/coverage.js +732 -0
  86. package/dist/lens/coverage.js.map +1 -0
  87. package/dist/lens/horizon.d.ts +14 -0
  88. package/dist/lens/horizon.d.ts.map +1 -0
  89. package/dist/lens/horizon.js +20 -0
  90. package/dist/lens/horizon.js.map +1 -0
  91. package/dist/lens/more.d.ts +16 -0
  92. package/dist/lens/more.d.ts.map +1 -0
  93. package/dist/lens/more.js +17 -0
  94. package/dist/lens/more.js.map +1 -0
  95. package/dist/lens/plan-lens.d.ts +17 -0
  96. package/dist/lens/plan-lens.d.ts.map +1 -0
  97. package/dist/lens/plan-lens.js +24 -0
  98. package/dist/lens/plan-lens.js.map +1 -0
  99. package/dist/lens/plan-state.d.ts +122 -0
  100. package/dist/lens/plan-state.d.ts.map +1 -0
  101. package/dist/lens/plan-state.js +152 -0
  102. package/dist/lens/plan-state.js.map +1 -0
  103. package/dist/lens/plan-view.d.ts +10 -0
  104. package/dist/lens/plan-view.d.ts.map +1 -0
  105. package/dist/lens/plan-view.js +576 -0
  106. package/dist/lens/plan-view.js.map +1 -0
  107. package/dist/lens/plan.d.ts +25 -0
  108. package/dist/lens/plan.d.ts.map +1 -0
  109. package/dist/lens/plan.js +25 -0
  110. package/dist/lens/plan.js.map +1 -0
  111. package/dist/lens/reach.d.ts +47 -0
  112. package/dist/lens/reach.d.ts.map +1 -0
  113. package/dist/lens/reach.js +67 -0
  114. package/dist/lens/reach.js.map +1 -0
  115. package/dist/lens/timeline.d.ts +137 -0
  116. package/dist/lens/timeline.d.ts.map +1 -0
  117. package/dist/lens/timeline.js +426 -0
  118. package/dist/lens/timeline.js.map +1 -0
  119. package/dist/markup.d.ts +23 -0
  120. package/dist/markup.d.ts.map +1 -0
  121. package/dist/markup.js +24 -0
  122. package/dist/markup.js.map +1 -0
  123. package/dist/places.d.ts +24 -0
  124. package/dist/places.d.ts.map +1 -0
  125. package/dist/places.js +227 -0
  126. package/dist/places.js.map +1 -0
  127. package/dist/popover.d.ts +28 -0
  128. package/dist/popover.d.ts.map +1 -0
  129. package/dist/popover.js +59 -0
  130. package/dist/popover.js.map +1 -0
  131. package/dist/primitives/index.d.ts +214 -0
  132. package/dist/primitives/index.d.ts.map +1 -0
  133. package/dist/primitives/index.js +381 -0
  134. package/dist/primitives/index.js.map +1 -0
  135. package/dist/profile.d.ts +65 -0
  136. package/dist/profile.d.ts.map +1 -0
  137. package/dist/profile.js +233 -0
  138. package/dist/profile.js.map +1 -0
  139. package/dist/quick-relations.d.ts +16 -0
  140. package/dist/quick-relations.d.ts.map +1 -0
  141. package/dist/quick-relations.js +183 -0
  142. package/dist/quick-relations.js.map +1 -0
  143. package/dist/relation-key.d.ts +44 -0
  144. package/dist/relation-key.d.ts.map +1 -0
  145. package/dist/relation-key.js +196 -0
  146. package/dist/relation-key.js.map +1 -0
  147. package/dist/seat.d.ts +137 -0
  148. package/dist/seat.d.ts.map +1 -0
  149. package/dist/seat.js +162 -0
  150. package/dist/seat.js.map +1 -0
  151. package/dist/seats.d.ts +21 -0
  152. package/dist/seats.d.ts.map +1 -0
  153. package/dist/seats.js +62 -0
  154. package/dist/seats.js.map +1 -0
  155. package/dist/seeding.d.ts +150 -0
  156. package/dist/seeding.d.ts.map +1 -0
  157. package/dist/seeding.js +538 -0
  158. package/dist/seeding.js.map +1 -0
  159. package/dist/shell.d.ts +74 -0
  160. package/dist/shell.d.ts.map +1 -0
  161. package/dist/shell.js +86 -0
  162. package/dist/shell.js.map +1 -0
  163. package/dist/theme.d.ts +50 -0
  164. package/dist/theme.d.ts.map +1 -0
  165. package/dist/theme.js +1692 -0
  166. package/dist/theme.js.map +1 -0
  167. package/dist/wordmark.d.ts +15 -0
  168. package/dist/wordmark.d.ts.map +1 -0
  169. package/dist/wordmark.js +55 -0
  170. package/dist/wordmark.js.map +1 -0
  171. package/dist/workbench/activity.d.ts +75 -0
  172. package/dist/workbench/activity.d.ts.map +1 -0
  173. package/dist/workbench/activity.js +259 -0
  174. package/dist/workbench/activity.js.map +1 -0
  175. package/dist/workbench/agent-seat.d.ts +51 -0
  176. package/dist/workbench/agent-seat.d.ts.map +1 -0
  177. package/dist/workbench/agent-seat.js +112 -0
  178. package/dist/workbench/agent-seat.js.map +1 -0
  179. package/dist/workbench/answer-args.d.ts +31 -0
  180. package/dist/workbench/answer-args.d.ts.map +1 -0
  181. package/dist/workbench/answer-args.js +257 -0
  182. package/dist/workbench/answer-args.js.map +1 -0
  183. package/dist/workbench/back-out.d.ts +71 -0
  184. package/dist/workbench/back-out.d.ts.map +1 -0
  185. package/dist/workbench/back-out.js +238 -0
  186. package/dist/workbench/back-out.js.map +1 -0
  187. package/dist/workbench/following.d.ts +7 -0
  188. package/dist/workbench/following.d.ts.map +1 -0
  189. package/dist/workbench/following.js +26 -0
  190. package/dist/workbench/following.js.map +1 -0
  191. package/dist/workbench/index.d.ts +23 -0
  192. package/dist/workbench/index.d.ts.map +1 -0
  193. package/dist/workbench/index.js +23 -0
  194. package/dist/workbench/index.js.map +1 -0
  195. package/dist/workbench/inspector.d.ts +27 -0
  196. package/dist/workbench/inspector.d.ts.map +1 -0
  197. package/dist/workbench/inspector.js +745 -0
  198. package/dist/workbench/inspector.js.map +1 -0
  199. package/dist/workbench/standing.d.ts +16 -0
  200. package/dist/workbench/standing.d.ts.map +1 -0
  201. package/dist/workbench/standing.js +102 -0
  202. package/dist/workbench/standing.js.map +1 -0
  203. package/dist/workbench/trail.d.ts +35 -0
  204. package/dist/workbench/trail.d.ts.map +1 -0
  205. package/dist/workbench/trail.js +150 -0
  206. package/dist/workbench/trail.js.map +1 -0
  207. package/package.json +62 -0
@@ -0,0 +1,35 @@
1
+ import { type AnySchema } from "@graview/core";
2
+ import { type ReactViewRegistry } from "@graview/react";
3
+ /**
4
+ * A generic view for every cell of the matrix, derived from the declaration.
5
+ *
6
+ * This is what makes "a new node kind renders acceptably at all three
7
+ * fidelities with zero custom view code" true rather than aspirational: the
8
+ * declaration already carries the label, the plural and the fields, so a
9
+ * sensible rendering exists the moment the kind does. An author overrides
10
+ * only the cells they actually care about.
11
+ */
12
+ import { hueFor } from "@graview/render";
13
+ export { hueFor };
14
+ /** The declared accent when the installation named one, else the hash. */
15
+ export declare function useHue(kind: string): number;
16
+ /**
17
+ * WHAT AN OPENED DISTRICT LISTS: the rows the layout kept room for
18
+ * (`openedRows`), in as many columns as its names can be READ in. Two
19
+ * columns of ninety-five pixels turned every vehicle into "2026 Ma…"; a
20
+ * name needs about seven and a half pixels a character in a 212-pixel
21
+ * roster, and a district of long names keeps one column.
22
+ */
23
+ export declare function rosterOf(names: readonly string[], rows: number): {
24
+ readonly columns: number;
25
+ readonly shown: number;
26
+ };
27
+ /**
28
+ * How many members a drive-in's thumbnail hands its lens: enough for its
29
+ * shape, never the population. A thumbnail is 58 pixels wide: twelve rows
30
+ * is already more than it can show, and a matrix of 12 × 12 is 144 cells
31
+ * where 24 × 24 was 576.
32
+ */
33
+ export declare const THUMBNAIL_BUDGET = 12;
34
+ export declare function registerDefaultViews<S extends AnySchema>(schema: S, registry?: ReactViewRegistry<S>): ReactViewRegistry<S>;
35
+ //# sourceMappingURL=default-views.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-views.d.ts","sourceRoot":"","sources":["../src/default-views.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EAIf,MAAM,eAAe,CAAC;AAEvB,OAAO,EAUL,KAAK,iBAAiB,EAEN,MAAM,gBAAgB,CAAC;AAOzC;;;;;;;;GAQG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,0EAA0E;AAC1E,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG3C;AAyBD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAMrH;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAuJnC,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,SAAS,EACtD,MAAM,EAAE,CAAC,EACT,QAAQ,GAAE,iBAAiB,CAAC,CAAC,CAAuB,GACnD,iBAAiB,CAAC,CAAC,CAAC,CA+zBtB"}
@@ -0,0 +1,605 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { arrange, describeNode, labelOf, readableFields, violationsTouching, } from "@graview/core";
3
+ import { aggregateId, kindCardId, marqueeHeightFor, rosterRows, withFocus, withJackIn, withOverview, withPast, withWithin } from "@graview/layout";
4
+ import { createViews, useFound, useGraview, useKit, useNavigation, useReached, useSceneStill, useSelection, useViolations, markDefaultView } from "@graview/react";
5
+ import { memo, useEffect, useMemo, useRef, useState } from "react";
6
+ import { ArrangeBar, arrangementOf, withArrangement } from "./arrange-bar.js";
7
+ import { Connections } from "./connections.js";
8
+ import { EditableTitle, Fields } from "./editable.js";
9
+ import { Aggregate, Chip, Panel, Roster } from "./primitives/index.js";
10
+ /**
11
+ * A generic view for every cell of the matrix, derived from the declaration.
12
+ *
13
+ * This is what makes "a new node kind renders acceptably at all three
14
+ * fidelities with zero custom view code" true rather than aspirational: the
15
+ * declaration already carries the label, the plural and the fields, so a
16
+ * sensible rendering exists the moment the kind does. An author overrides
17
+ * only the cells they actually care about.
18
+ */
19
+ // The canonical hue lives beside the other colour logic in @graview/render;
20
+ // re-exported here because every view author already imports it from views.
21
+ import { hueFor } from "@graview/render";
22
+ import { hasFigure, KindFigure } from "./figure.js";
23
+ export { hueFor };
24
+ /** The declared accent when the installation named one, else the hash. */
25
+ export function useHue(kind) {
26
+ const { brand } = useGraview();
27
+ return hueFor(kind, brand?.accents);
28
+ }
29
+ /**
30
+ * The field a shortened label was shortened FROM, when there is one.
31
+ *
32
+ * Matched by stem rather than by name, because which field a label came from
33
+ * is the app's business — `label: (node) => summarise(node.text)` names no
34
+ * field the framework can see, and asking every app to declare it would be
35
+ * asking them to repeat themselves.
36
+ */
37
+ function longFormOf(node, short) {
38
+ if (!short.endsWith("…") && !short.endsWith("..."))
39
+ return undefined;
40
+ const stem = short.replace(/[…]|\.\.\.$/g, "").trim();
41
+ if (stem.length < 12)
42
+ return undefined;
43
+ for (const value of Object.values(node)) {
44
+ if (typeof value !== "string")
45
+ continue;
46
+ if (value.length > stem.length && value.startsWith(stem))
47
+ return value;
48
+ }
49
+ return undefined;
50
+ }
51
+ /**
52
+ * WHAT AN OPENED DISTRICT LISTS: the rows the layout kept room for
53
+ * (`openedRows`), in as many columns as its names can be READ in. Two
54
+ * columns of ninety-five pixels turned every vehicle into "2026 Ma…"; a
55
+ * name needs about seven and a half pixels a character in a 212-pixel
56
+ * roster, and a district of long names keeps one column.
57
+ */
58
+ export function rosterOf(names, rows) {
59
+ const widest = Math.max(0, ...names.slice(0, rows * 2).map((name) => name.length));
60
+ const columns = widest * 7.5 + 28 <= 212 / 2 ? 2 : 1;
61
+ const room = rows * columns;
62
+ // The count line needs no row of its own: it is part of the room reserved.
63
+ return { columns, shown: Math.min(names.length, room) };
64
+ }
65
+ /**
66
+ * How many members a drive-in's thumbnail hands its lens: enough for its
67
+ * shape, never the population. A thumbnail is 58 pixels wide: twelve rows
68
+ * is already more than it can show, and a matrix of 12 × 12 is 144 cells
69
+ * where 24 × 24 was 576.
70
+ */
71
+ export const THUMBNAIL_BUDGET = 12;
72
+ /*
73
+ * ONE THUMBNAIL A FRAME. A city of districts with named pictures would build
74
+ * them all in the frame the scene came to rest in — four lenses in one long
75
+ * task. Each waits its turn, one per animation frame.
76
+ */
77
+ const turns = [];
78
+ let turning = false;
79
+ function takeTurn(mount) {
80
+ turns.push(mount);
81
+ const next = () => {
82
+ const run = turns.shift();
83
+ if (!run) {
84
+ turning = false;
85
+ return;
86
+ }
87
+ run();
88
+ requestAnimationFrame(next);
89
+ };
90
+ if (!turning && typeof requestAnimationFrame !== "undefined") {
91
+ turning = true;
92
+ requestAnimationFrame(next);
93
+ }
94
+ else if (typeof requestAnimationFrame === "undefined")
95
+ next();
96
+ return () => {
97
+ const at = turns.indexOf(mount);
98
+ if (at >= 0)
99
+ turns.splice(at, 1);
100
+ };
101
+ }
102
+ /**
103
+ * The members worth drawing when not all can be: the flagged first, then
104
+ * the most connected, in their own order otherwise — the same reading the
105
+ * relation band's relevance gives (docs/scale.md).
106
+ */
107
+ function mostRelevant(members, budget, flagged, graph) {
108
+ if (members.length <= budget)
109
+ return members;
110
+ const trouble = new Set(flagged ?? []);
111
+ return members
112
+ .map((node, index) => ({ node, index, trouble: trouble.has(node.id) ? 0 : 1, ties: -graph.neighbors(node.id).length }))
113
+ .sort((a, b) => a.trouble - b.trouble || a.ties - b.ties || a.index - b.index)
114
+ .slice(0, budget)
115
+ .sort((a, b) => a.index - b.index)
116
+ .map((entry) => entry.node);
117
+ }
118
+ /**
119
+ * DRAWN WHEN SEEN, AND WHEN STILL. A thumbnail off the screen, or built
120
+ * while the camera flies, spends a frame on a picture nobody can read. It
121
+ * mounts the first time it is on screen with the scene at rest, and then
122
+ * stays — unmounting on every flight would rebuild it on every landing.
123
+ */
124
+ function WhenSeen({ children }) {
125
+ const still = useSceneStill();
126
+ const box = useRef(null);
127
+ const [seen, setSeen] = useState(false);
128
+ const [shown, setShown] = useState(false);
129
+ useEffect(() => {
130
+ const element = box.current;
131
+ if (!element || seen)
132
+ return;
133
+ if (typeof IntersectionObserver === "undefined") {
134
+ setSeen(true);
135
+ return;
136
+ }
137
+ const watch = new IntersectionObserver((entries) => {
138
+ if (entries.some((entry) => entry.isIntersecting))
139
+ setSeen(true);
140
+ }, { rootMargin: "120px" });
141
+ watch.observe(element);
142
+ return () => watch.disconnect();
143
+ }, [seen]);
144
+ useEffect(() => {
145
+ if (!seen || !still || shown)
146
+ return;
147
+ return takeTurn(() => setShown(true));
148
+ }, [seen, still, shown]);
149
+ return (
150
+ /*
151
+ * A real box, not `display: contents`: an element with no box never
152
+ * intersects anything. And a box as tall as a picture, not one pixel:
153
+ * drawn at a twentieth of its size a pixel is a twentieth of one, which
154
+ * the browser counts as no area at all — the Albums district's two
155
+ * pictures waited forever while the Artists one, drawn twice as large,
156
+ * was seen.
157
+ */
158
+ _jsx("span", { ref: box, style: { display: "block", minHeight: shown ? undefined : 360 }, "data-graview-thumbnail": shown ? "drawn" : "waiting", children: shown ? children : null }));
159
+ }
160
+ /**
161
+ * A LENS DRAWN SMALL, AND ONLY WHEN WHAT IT DRAWS CHANGES.
162
+ *
163
+ * The board renders the real component for every showing a kind has, and
164
+ * the card around it re-renders on every frame of a flight — so choosing
165
+ * a picture re-drew three matrices and a calendar sixty times a second
166
+ * while the camera moved, which is where "slow and glitchy" came from.
167
+ * Nothing about a thumbnail depends on the size of the card it sits in:
168
+ * memoised on what it actually draws, the flight costs one render each.
169
+ */
170
+ const Picture = memo(function Picture({ lens: Lens, nodes, label, flagged, budget, total, }) {
171
+ return (_jsx(Lens, { nodes: nodes, label: label, ...(budget !== undefined ? { budget } : {}), ...(total !== undefined ? { total } : {}), fidelity: "full", cardinality: "many", mode: "scene", selected: false, ...(flagged ? { flagged } : {}) }));
172
+ }, (was, now) => was.lens === now.lens &&
173
+ was.label === now.label &&
174
+ was.total === now.total &&
175
+ was.nodes.length === now.nodes.length &&
176
+ was.nodes.every((node, at) => node === now.nodes[at]) &&
177
+ (was.flagged ?? []).length === (now.flagged ?? []).length &&
178
+ (was.flagged ?? []).every((id, at) => id === (now.flagged ?? [])[at]));
179
+ export function registerDefaultViews(schema, registry = createViews(schema)) {
180
+ for (const kind of schema.kinds) {
181
+ const definition = schema.tryDefinition(kind);
182
+ const plural = definition?.plural ?? `${String(kind)}s`;
183
+ const Full = (props) => {
184
+ const node = props.node;
185
+ /*
186
+ * WHAT IS WRONG WITH IT, ON IT.
187
+ *
188
+ * A flagged record wore the warning TONE and said nothing: a
189
+ * background tint, no words, no mark, nothing in the accessibility
190
+ * tree. The chips in a district get a "⚠" in their own label and the
191
+ * routed record page carries the rule's sentence — the biggest drawing
192
+ * of the same record, the one you travelled to, was the only place the
193
+ * problem existed purely as a shade. That is W-014's shape, one view
194
+ * along: emphasis painted and not said.
195
+ */
196
+ const violations = useViolations();
197
+ if (!node)
198
+ return null;
199
+ /*
200
+ * On a page, the heading is the WHOLE thing.
201
+ *
202
+ * A kind whose label is its own prose shortened — a rationale, a note, a
203
+ * reason — gets a heading cut at sixty characters, which is right on a
204
+ * card in the scene and wrong on a page that has room for all of it.
205
+ * Shortening then ALSO listing the full text below is worse again: the
206
+ * same sentence twice, one of them mutilated.
207
+ *
208
+ * So the page looks for the long form of its own heading and uses that,
209
+ * and `Fields` then drops it as already said. The abbreviation was for
210
+ * the card.
211
+ */
212
+ const short = labelOf(definition, node);
213
+ const heading = props.mode === "fullscreen" ? (longFormOf(node, short) ?? short) : short;
214
+ const touching = violationsTouching(violations, [node.id]);
215
+ return (_jsxs(Panel
216
+ // The name is the rename control. Nothing else on the page repeats
217
+ // it, so the thing you click to change it is the thing itself.
218
+ , {
219
+ // The name is the rename control. Nothing else on the page repeats
220
+ // it, so the thing you click to change it is the thing itself.
221
+ title: _jsx(EditableTitle, { nodeId: node.id, children: heading }),
222
+ /*
223
+ * What THIS node is, when the declaration can say — and only the
224
+ * kind's own description as a fallback.
225
+ *
226
+ * A subtitle that is the kind's description is identical on every
227
+ * node of that kind, which makes it furniture rather than
228
+ * information: it tells you what a rationale is, on a page you
229
+ * reached by choosing one particular rationale.
230
+ */
231
+ subtitle:
232
+ // `describeNode` falls back to "<kind> <label>", which would put
233
+ // the heading back under the heading — so only take it when the
234
+ // declaration actually supplied one.
235
+ definition?.describe
236
+ ? describeNode(definition, node)
237
+ : (definition?.description ?? String(kind)), selected: props.selected, ...(props.flagged?.includes(node.id) ? { tone: "warning" } : {}),
238
+ // A card in the scene; a document on a page. Same component, and the
239
+ // only difference is which of those two things it is sitting on.
240
+ fit: true, children: [_jsxs("div", { style: {
241
+ display: "grid",
242
+ gridTemplateColumns: "minmax(200px, 1fr) minmax(220px, 1.4fr)",
243
+ gap: "22px 34px",
244
+ alignItems: "start",
245
+ }, children: [_jsx(Fields, { id: node.id,
246
+ // What the panel already said: its title and its subtitle. A
247
+ // record repeating its own heading is what made this read as a
248
+ // debug dump rather than as a page about something.
249
+ shown: [heading, short, definition?.description] }), _jsx(Connections, { id: node.id, empty: `Nothing is connected to this ${String(kind)} yet.` })] }), touching.length > 0 ? (_jsx("p", { "data-graview-broken": "", style: {
250
+ margin: "14px 0 0",
251
+ paddingTop: 12,
252
+ borderTop: "1px solid var(--graview-edge)",
253
+ fontSize: "0.875rem",
254
+ color: "var(--graview-warn)",
255
+ }, children: touching.map((violation) => violation.message).join(" · ") })) : null] }));
256
+ };
257
+ /**
258
+ * Summary is not "full, but smaller". Receded text must stay LEGIBLE, so
259
+ * this drops to a denser arrangement rather than scaling the same content
260
+ * down into mush — that is the whole reason fidelity is an axis.
261
+ */
262
+ const Summary = (props) => {
263
+ const node = props.node;
264
+ if (!node)
265
+ return null;
266
+ // The same question the record on a page asks, answered by the same
267
+ // function — they used to answer it separately and diverge.
268
+ const fields = readableFields(node, definition, {
269
+ limit: 3,
270
+ said: [labelOf(definition, node)],
271
+ glance: true,
272
+ });
273
+ const hue = useHue(kind);
274
+ return (_jsx(Panel, { title: labelOf(definition, node), selected: props.selected, tone: props.flagged?.includes(node.id) ? "warning" : "muted", fit: true, children: _jsx(Roster, { items: fields.map((field) => ({
275
+ id: field.key,
276
+ // Alone on a chip a number or a yes/no is no fact at all.
277
+ label: field.alone,
278
+ hue,
279
+ })), max: 3 }) }));
280
+ };
281
+ const Glyph = (props) => {
282
+ const node = props.node;
283
+ const hue = useHue(kind);
284
+ // The mark a broken rule leaves is the kit's, not a literal here.
285
+ const flag = useKit().marks.flag;
286
+ if (!node)
287
+ return null;
288
+ const broken = props.flagged?.includes(node.id) ?? false;
289
+ return (_jsx(Chip, { label: broken ? `${labelOf(definition, node)} ${flag}` : labelOf(definition, node), hue: hue, selected: props.selected, title: broken ? `${String(kind)} — implicated in a problem` : String(kind) }));
290
+ };
291
+ const Group = (props) => {
292
+ const { brand, store } = useGraview();
293
+ const { view, go } = useNavigation();
294
+ const members = props.nodes ?? [];
295
+ /*
296
+ * THE DEFAULT PICTURE ARRANGES TOO. What a kind can be sorted, filtered
297
+ * and grouped by is in its declaration, and the choice travels in the
298
+ * stop (`in.sort`, `in.filter`, `in.group`, `in.q`) like the calendar's
299
+ * month does — so an arranged district is a link, and Back restores it.
300
+ * The row is drawn at full fidelity, where there is room to read it;
301
+ * the arrangement holds at every fidelity, because the stop does.
302
+ */
303
+ const arrangement = arrangementOf(view);
304
+ const arranged = arrange(members, arrangement, { schema, graph: store.graph, flagged: new Set(props.flagged ?? []) });
305
+ const item = (member) => ({
306
+ id: member.id,
307
+ label: labelOf(schema.tryDefinition(member.kind), member),
308
+ hue: hueFor(member.kind, brand?.accents),
309
+ });
310
+ const bar = props.fidelity === "full" && members.length > 1 ? (_jsx(ArrangeBar, { schema: schema, graph: store.graph, kind: String(kind), arrangement: arrangement, onChange: (next) => go(withArrangement(view, next)), kept: { shown: arranged.nodes.length, of: members.length }, style: { marginBottom: 8 } })) : null;
311
+ // A receded group still has to report trouble inside it, or the only
312
+ // way to find a problem is to open every group in turn.
313
+ const flagged = (nodes) => nodes.some((member) => props.flagged?.includes(member.id));
314
+ if (!arranged.grouped) {
315
+ return (_jsxs("div", { style: { display: "grid", gap: 4 }, children: [bar, _jsx(Aggregate, { label: props.label ?? plural, count: arranged.nodes.length, flagged: flagged(arranged.nodes), items: arranged.nodes.map(item) })] }));
316
+ }
317
+ return (_jsxs("div", { style: { display: "grid", gap: 8 }, "data-graview-grouped": arrangement.group?.by, children: [bar, arranged.groups.map((group) => (_jsx(Aggregate, { label: `${props.label ?? plural} · ${group.label}`, count: group.nodes.length, flagged: flagged(group.nodes), items: group.nodes.map(item) }, group.key || "-")))] }));
318
+ };
319
+ /**
320
+ * A group at glyph fidelity.
321
+ *
322
+ * It names its MEMBERS, not just how many there are. "4 AGREEMENTS" tells
323
+ * you a number and nothing you wanted to know; the whole point of a
324
+ * context plane is to be glanceable, and a count is not a glance at
325
+ * anything. What fits, fits; the rest is "+n".
326
+ */
327
+ /**
328
+ * A group at glyph fidelity — the card the kinds plane is made of.
329
+ *
330
+ * Its name, how many there are, and what it is FOR on hover. The members
331
+ * used to be listed and it was the wrong answer: ten cards each showing
332
+ * three truncated names is ten unreadable things, and "which kinds exist
333
+ * and how big are they" is the question a map of kinds is asked. The
334
+ * description has been on every declaration since the first commit and
335
+ * nothing has ever shown it.
336
+ */
337
+ const GroupGlyph = (props) => {
338
+ const members = props.nodes ?? [];
339
+ const roster = rosterOf(members.map((member) => labelOf(definition, member)), props.openedRows ?? rosterRows(members.length));
340
+ const hue = useHue(kind);
341
+ /*
342
+ * THE KIND'S OWN DRAWING, where it has one.
343
+ *
344
+ * The isometric city gives every kind the same block; a figure is
345
+ * what makes one of them a person and another a plot of ground. The
346
+ * brand's say comes first, so an installation with its own drawing
347
+ * keeps the domain's declaration as the domain's.
348
+ */
349
+ const { brand } = useGraview();
350
+ const figure = hasFigure(String(kind), schema, brand);
351
+ const flag = useKit().marks.flag;
352
+ const { selection } = useSelection();
353
+ const { toggle, view, go } = useNavigation();
354
+ const { views, hiddenKinds, store } = useGraview();
355
+ /*
356
+ * THE DRIVE-IN'S MARQUEE. A kind with a named picture has a drive-in
357
+ * from altitude: a dark screen on its plot and, under it, the showings
358
+ * as real buttons. Pressing one focuses the kind with that showing and
359
+ * descends in one gesture — the lens is already drawn at the plot, so
360
+ * the descent reads as walking up to the screen. On the drive-in that
361
+ * is focused, pressing another showing switches the picture without
362
+ * descending; pressing the one already showing walks up to it.
363
+ */
364
+ const showings = view.overview && !hiddenKinds.has(String(kind)) ? views.places().filter((place) => place.kind === String(kind)) : [];
365
+ const showingNow = props.focused ? (view.within?.["view"] ?? showings[0]?.as) : undefined;
366
+ // A thumbnail is a picture of the lens, not the lens: its most relevant members, never the population.
367
+ const thumbnailMembers = useMemo(() => (showings.length > 0 ? mostRelevant(members, THUMBNAIL_BUDGET, props.flagged, store.graph) : []),
368
+ // eslint-disable-next-line react-hooks/exhaustive-deps
369
+ [showings.length, members, props.flagged, store]);
370
+ const broken = members.filter((member) => props.flagged?.includes(member.id)).length;
371
+ const trouble = broken > 0;
372
+ const accent = props.focused || props.raised;
373
+ /*
374
+ * A kind the focus does not touch is QUIETER, not hidden.
375
+ *
376
+ * The layout already draws it smaller and further back; this is the
377
+ * other half of the same reading, so the card does not look like a
378
+ * full-size one that merely shrank. It stays a real card with a real
379
+ * name — a secondary relation is still somewhere you can go.
380
+ */
381
+ const secondary = props.rank === "secondary" && !accent;
382
+ const nested = props.nestedUnder !== undefined;
383
+ /*
384
+ * How many of this kind's members the SELECTION reaches, one edge away.
385
+ *
386
+ * "What is this thing actually tied to" was unanswerable from the
387
+ * shelf: you selected a span in the calendar and every kind card sat
388
+ * unchanged. The implicated set has always known; the card just never
389
+ * read it. Selected members themselves do not count — a card does not
390
+ * announce a tie to the thing that IS the selection.
391
+ */
392
+ const chosen = new Set(selection);
393
+ // What the selection reaches — never what a search lit, which is counted apart below.
394
+ const reached = useReached();
395
+ const tied = accent
396
+ ? 0
397
+ : members.filter((member) => reached.includes(member.id) && !chosen.has(member.id)).length;
398
+ /*
399
+ * WHAT THE WORDS FOUND HERE. With a search open, a district with hits
400
+ * is lit and says how many; one with none recedes. Pressing the count
401
+ * descends into the district already narrowed by the same words — the
402
+ * arrangement's `in.q` — so search hands off to the arrangement rather
403
+ * than competing with it.
404
+ */
405
+ const found = useFound();
406
+ const hits = found && !nested ? (found.byKind[String(kind)] ?? 0) : 0;
407
+ /*
408
+ * The block's height from altitude, in viewBox units: population under
409
+ * a square root, so one giant kind is a tall building rather than a
410
+ * tower the scene scrolls for.
411
+ */
412
+ const rise = nested ? 8 : Math.min(46, 10 + Math.round(Math.sqrt(members.length) * 8));
413
+ /*
414
+ * The district's NAME, lifted out of the markup because a figure stands
415
+ * beside it and a name written twice is a name that drifts.
416
+ */
417
+ const name = (_jsx("span", { style: {
418
+ /*
419
+ * A DISTRICT'S NAME IS READ, not glanced at. Thirteen pixels
420
+ * before the kinds plane's own recession put it on the screen at
421
+ * ten, and the kind above it at under eight — small enough that
422
+ * the bottom of the picture was a row of grey marks rather than
423
+ * a map of the domain.
424
+ */
425
+ fontSize: nested ? "0.75rem" : "0.9375rem",
426
+ lineHeight: 1.25,
427
+ letterSpacing: "0.05em",
428
+ textTransform: "uppercase",
429
+ color: accent ? "var(--graview-accent)" : "var(--graview-ink-muted)",
430
+ /*
431
+ * A tucked card is a corner peeking out from behind its parent,
432
+ * so its name gets one line. "Unavailability" wrapped to two and
433
+ * pushed the count out of a card that has no spare rows — and
434
+ * the alternative, growing the tuck until it fits, makes it the
435
+ * same size as the thing it is meant to be behind.
436
+ */
437
+ ...(nested
438
+ ? { whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }
439
+ : { overflowWrap: "anywhere" }),
440
+ }, children: props.label ?? plural }));
441
+ return (_jsxs("div", { className: "graview-kind-card", "data-graview-rank": props.rank, "data-graview-landmark": figure || undefined, "data-graview-nested": nested || undefined, "data-graview-tied": tied || undefined, "data-graview-hits": found && !nested ? hits : undefined, "data-graview-emphasis": found && !nested ? (hits > 0 ? "lit" : "dimmed") : undefined, ...(definition?.description || nested
442
+ ? {
443
+ title: nested
444
+ ? [props.label ?? plural, definition?.description].filter(Boolean).join(" — ")
445
+ : definition.description,
446
+ }
447
+ : {}), style: {
448
+ position: "relative",
449
+ height: "100%",
450
+ ["--graview-hue"]: Math.round(hue),
451
+ /*
452
+ * THE ROOM THE MARQUEE TAKES, told to the drawing under it. The
453
+ * building is sized from the card's height, and the layout grew
454
+ * the card by the marquee's band — so the building grew into the
455
+ * band and the showings stood on its roof. The band's height is
456
+ * the layout's own estimate, and the building sizes from what is
457
+ * left.
458
+ */
459
+ ["--graview-marquee-room"]: showings.length > 0 ? `${marqueeHeightFor(showings.map((place) => place.title), 132) + (figure ? 4 : 42)}px` : "0px",
460
+ }, children: [figure ? (_jsx("span", { className: "graview-kind-block graview-kind-landmark", "data-graview-opened": props.opened || undefined, "aria-hidden": "true", style: { ["--graview-rise"]: rise }, children: _jsx(KindFigure, { kind: String(kind), schema: schema, ...(brand ? { brand } : {}), size: 96 }) })) : /*
461
+ * A KIND WITH NO DRAWING STANDS AS ITS VILLAGE. The anonymous iso
462
+ * block — one box for every kind, its population a height nobody
463
+ * read — is retired at altitude: the members stand as buildings
464
+ * on the plot the scene draws under this card, and the population
465
+ * is the size of the cluster.
466
+ */
467
+ null, _jsxs("div", { className: "graview-kind-face", "data-graview-opened": props.opened || undefined, style: {
468
+ display: "flex",
469
+ flexDirection: "column",
470
+ gap: nested ? 1 : 3,
471
+ padding: nested ? "5px 7px" : "7px 10px",
472
+ borderRadius: "var(--graview-radius-sm, 9px)",
473
+ /*
474
+ * PLANE 2 IS A GLYPH. Its own fidelity says so.
475
+ *
476
+ * These were 190 by 107 holding a name, a number and a mark, and
477
+ * the band they sit in took a fifth of the window. A card sized
478
+ * for content it does not have is not a map, it is a margin.
479
+ */
480
+ justifyContent: "center",
481
+ position: "relative",
482
+ height: "100%",
483
+ overflow: "hidden",
484
+ boxSizing: "border-box",
485
+ border: accent
486
+ ? "1px solid var(--graview-accent)"
487
+ : tied > 0
488
+ ? "1px solid var(--graview-accent-dim)"
489
+ : `1px solid hsl(${Math.round(hue)} 55% var(--graview-tint-lightness) / 0.34)`,
490
+ // The kind you are looking at is brighter and lit, not labelled:
491
+ // a ninety-pixel card has no room for a word that says so.
492
+ /*
493
+ * An OPAQUE face under the tint. A card that was only a wash of
494
+ * colour let every connector show through it — a road running
495
+ * through a building rather than behind it — and in daylight the
496
+ * wash alone read as a pastel sticky note.
497
+ */
498
+ backgroundColor: "var(--graview-panel)",
499
+ backgroundImage: `linear-gradient(hsl(${Math.round(hue)} 55% var(--graview-tint-lightness) / calc(var(--graview-tint-alpha) * ${accent ? 1.1 : secondary ? 0.28 : 0.5})), hsl(${Math.round(hue)} 55% var(--graview-tint-lightness) / calc(var(--graview-tint-alpha) * ${accent ? 1.1 : secondary ? 0.28 : 0.5})))`,
500
+ boxShadow: accent ? "0 0 0 1px var(--graview-accent-dim)" : undefined,
501
+ }, children: [!nested && members.length > 0 ? (_jsx("div", { "data-graview-tally": members.length, "data-graview-broken": broken || undefined, "aria-hidden": "true", style: {
502
+ // On the card's own edge, out of the flow: a glyph this size
503
+ // has no spare rows, and taking one made the content overflow.
504
+ position: "absolute",
505
+ left: 0,
506
+ right: 0,
507
+ top: 0,
508
+ display: "flex",
509
+ height: 3,
510
+ background: `hsl(${Math.round(hue)} 55% var(--graview-tint-lightness) / 0.4)`,
511
+ }, children: broken > 0 ? (_jsx("span", { style: {
512
+ width: `${Math.max(6, Math.round((broken / members.length) * 100))}%`,
513
+ background: "var(--graview-warn)",
514
+ } })) : null })) : null, figure ? (_jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: nested ? 4 : 6 }, children: [_jsx(KindFigure, { kind: String(kind), schema: schema, ...(brand ? { brand } : {}),
515
+ /*
516
+ * The size the LINE can carry, not the size the card looks
517
+ * like it could: the name beside it sets the row's height, and
518
+ * a drawing taller than that grows the row and puts the card's
519
+ * content over its own edge again — which is what twenty-six
520
+ * did on the shortest card in the strip.
521
+ */
522
+ size: nested ? 14 : 18 }), name] })) : (name), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5, fontSize: "0.875rem" }, children: [_jsx("span", { style: {
523
+ fontVariantNumeric: "tabular-nums",
524
+ color: trouble ? "var(--graview-warn)" : "var(--graview-ink-faint)",
525
+ }, children: members.length === 0 ? "none yet" : `${trouble ? `${flag} ` : ""}${members.length}` }), (props.retired ?? 0) > 0 ? (_jsxs("button", { type: "button", className: "graview-kind-past", "data-graview-retired": props.retired, title: `${props.retired} retired ${plural.toLowerCase()} — press to widen the view to the past`, onClick: (event) => {
526
+ event.stopPropagation();
527
+ go(withPast(view, true));
528
+ }, onDoubleClick: (event) => event.stopPropagation(), onPointerDown: (event) => event.stopPropagation(), children: ["+", props.retired, " past"] })) : null, hits > 0 ? (_jsxs("button", { type: "button", className: "graview-kind-hits", "data-testid": `hits-${String(kind)}`, title: `${hits} ${hits === 1 ? "match" : "matches"} for “${view.q ?? ""}” — press to go in, narrowed`, onClick: (event) => {
529
+ event.stopPropagation();
530
+ // The same descent a double-click on the lit district makes: one transition, not three.
531
+ go(withJackIn(view, kindCardId(String(kind)), { ownPicture: true, ...(view.q ? { carry: view.q } : {}) }));
532
+ }, onDoubleClick: (event) => event.stopPropagation(), onPointerDown: (event) => event.stopPropagation(), children: [hits, " match"] })) : null, tied > 0 ? (_jsxs("span", { style: { fontSize: "0.8125rem", color: "var(--graview-accent)" }, children: [tied, " tied"] })) : null, props.hasOwnView ? (_jsx("span", { title: `${plural} has a view of its own`, "aria-label": "has its own view", style: { fontSize: "0.6875rem", color: "var(--graview-accent)" }, children: "\u25C6" })) : null, !nested && members.length > 0 && !props.focused ? (_jsxs("button", { type: "button", className: "graview-kind-open", "data-testid": `open-${String(kind)}`, "aria-expanded": props.opened ?? false, title: props.opened ? "Close it up" : `See the ${plural} in here`, onClick: (event) => {
533
+ event.stopPropagation();
534
+ toggle(kindCardId(String(kind)));
535
+ }, onDoubleClick: (event) => event.stopPropagation(), onPointerDown: (event) => event.stopPropagation(), children: [_jsx("span", { className: "graview-kind-open-word", children: props.opened ? "close" : "open" }), " ", props.opened ? "▴" : "▾"] })) : null] }), props.opened ? (
536
+ /*
537
+ * BUILDINGS. An opened neighbourhood lays its members out inside
538
+ * its plot as a small grid on the lattice — `side` to a row, the
539
+ * plot's own width in cells — rather than a column of chips. Each
540
+ * is still a Chip with a pick id, so measuring, ties and the
541
+ * keyboard work for free; past `side × side` the rest are counted.
542
+ */
543
+ _jsxs("div", { className: "graview-kind-members", "data-graview-buildings": props.plot?.side ?? 1, style: {
544
+ display: "grid",
545
+ /*
546
+ * A NAME YOU CAN READ BEATS A GRID THAT MATCHES THE PLOT.
547
+ *
548
+ * The members were laid out `side` to a row so the chips
549
+ * echoed the buildings on the lattice — which at a district's
550
+ * own width meant sixty pixels a chip, and "Enough bodies for
551
+ * the drill" arrived as "Eno…". Opening a district is the
552
+ * gesture that asks WHICH ONE; a row of initials cannot
553
+ * answer it. So the columns are set by what the widest name
554
+ * needs, and a district only wide enough for one keeps one.
555
+ */
556
+ gridTemplateColumns: `repeat(${roster.columns}, minmax(0, 1fr))`,
557
+ gap: 3,
558
+ }, children: [members.slice(0, roster.shown).map((member) => {
559
+ /*
560
+ * WHICH ONE. The card's own count already says "⚠ 1" —
561
+ * opening the district to find out which member that is was
562
+ * the whole point of opening it, and every chip came out
563
+ * unmarked. The glyph view marks a flagged node exactly this
564
+ * way; the members inside a district simply never asked.
565
+ */
566
+ const broken = props.flagged?.includes(member.id) ?? false;
567
+ const name = labelOf(definition, member);
568
+ return (_jsx(Chip, { pickId: member.id, label: broken ? `${name} ${flag}` : name, title: broken ? `${name} — implicated in a problem` : undefined, hue: hue, selected: chosen.has(member.id) }, member.id));
569
+ }), members.length > roster.shown ? (_jsxs("span", { style: { fontSize: "0.75rem", color: "var(--graview-ink-faint)", padding: "2px 4px", gridColumn: "1 / -1" }, children: ["+", members.length - roster.shown, " more \u2014 double-click to go in"] })) : null] })) : null] }), !nested && showings.length > 0 ? (_jsx("div", { className: "graview-drive-in", "data-testid": `drive-in-${String(kind)}`, "data-graview-showing": showingNow, onPointerDown: (event) => event.stopPropagation(), onDoubleClick: (event) => event.stopPropagation(), children: _jsx("div", { className: "graview-drive-in-marquee", role: "group", "aria-label": `${plural}: pictures`, "data-graview-thumbs": showings.length === 1 ? "one" : "two", children: showings.map((place) => {
570
+ const showing = showingNow === place.as;
571
+ const registration = views.resolve(String(kind), { cardinality: "many", fidelity: "full" }, place.as);
572
+ const Lens = registration?.view;
573
+ return (
574
+ /*
575
+ * A FRAME HOLDING A PICTURE AND A BUTTON, not a button
576
+ * holding a picture. The lens drawn small keeps its own
577
+ * controls — a calendar's Previous and Next — and a
578
+ * button inside a button is invalid HTML however inert
579
+ * the inner one is: React said so on every chapter
580
+ * with a calendar. The press lies over the picture, so
581
+ * the whole thumbnail is still one target.
582
+ */
583
+ _jsxs("div", { className: "graview-drive-in-thumb", "data-graview-pressed": showing || undefined, children: [_jsx("span", { className: "graview-drive-in-thumb-picture", "aria-hidden": "true", inert: true, children: Lens ? (_jsx("span", { className: "graview-drive-in-thumb-natural", children: _jsx(WhenSeen, { children: _jsx(Picture, { lens: Lens, nodes: thumbnailMembers, label: place.title, budget: THUMBNAIL_BUDGET, total: members.length, ...(props.flagged ? { flagged: props.flagged } : {}) }) }) })) : null }), _jsx("span", { className: "graview-drive-in-thumb-title", "aria-hidden": "true", children: place.title }), _jsx("button", { type: "button", className: "graview-drive-in-thumb-press", "data-testid": `showing-${place.as}`, "aria-label": `${plural}: ${place.title}`, "aria-pressed": showing, title: showing ? `${place.title} is showing` : `Show ${place.title} on the billboard`, onClick: (event) => {
584
+ event.stopPropagation();
585
+ if (showing && props.focused)
586
+ return;
587
+ go(withWithin(withFocus(withOverview(view, true), aggregateId(String(kind))), "view", place.as));
588
+ } })] }, place.as));
589
+ }) }) })) : null] }));
590
+ };
591
+ // Marked so the interface can tell a view the app chose from one the
592
+ // framework fell back to.
593
+ Group.generic = true;
594
+ GroupGlyph.generic = true;
595
+ registry
596
+ .register(kind, { cardinality: "one", fidelity: "full" }, Full)
597
+ .register(kind, { cardinality: "one", fidelity: "summary" }, Summary)
598
+ .register(kind, { cardinality: "one", fidelity: "glyph" }, Glyph)
599
+ .register(kind, { cardinality: "many", fidelity: "full" }, markDefaultView(Group))
600
+ .register(kind, { cardinality: "many", fidelity: "summary" }, markDefaultView(Group))
601
+ .register(kind, { cardinality: "many", fidelity: "glyph" }, markDefaultView(GroupGlyph));
602
+ }
603
+ return registry;
604
+ }
605
+ //# sourceMappingURL=default-views.js.map