@graview/react 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.
- package/LICENSE +96 -0
- package/README.md +20 -0
- package/dist/activity.d.ts +113 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +207 -0
- package/dist/activity.js.map +1 -0
- package/dist/animation.d.ts +64 -0
- package/dist/animation.d.ts.map +1 -0
- package/dist/animation.js +245 -0
- package/dist/animation.js.map +1 -0
- package/dist/captions.d.ts +43 -0
- package/dist/captions.d.ts.map +1 -0
- package/dist/captions.js +61 -0
- package/dist/captions.js.map +1 -0
- package/dist/channels.d.ts +15 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +114 -0
- package/dist/channels.js.map +1 -0
- package/dist/connectors.d.ts +176 -0
- package/dist/connectors.d.ts.map +1 -0
- package/dist/connectors.js +837 -0
- package/dist/connectors.js.map +1 -0
- package/dist/context.d.ts +348 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +568 -0
- package/dist/context.js.map +1 -0
- package/dist/drawn.d.ts +60 -0
- package/dist/drawn.d.ts.map +1 -0
- package/dist/drawn.js +58 -0
- package/dist/drawn.js.map +1 -0
- package/dist/edge-signs.d.ts +13 -0
- package/dist/edge-signs.d.ts.map +1 -0
- package/dist/edge-signs.js +76 -0
- package/dist/edge-signs.js.map +1 -0
- package/dist/hooks.d.ts +160 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +457 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/keyboard.d.ts +5 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +178 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/kit.d.ts +10 -0
- package/dist/kit.d.ts.map +1 -0
- package/dist/kit.js +32 -0
- package/dist/kit.js.map +1 -0
- package/dist/local-intelligence.d.ts +31 -0
- package/dist/local-intelligence.d.ts.map +1 -0
- package/dist/local-intelligence.js +66 -0
- package/dist/local-intelligence.js.map +1 -0
- package/dist/motion.d.ts +17 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +26 -0
- package/dist/motion.js.map +1 -0
- package/dist/occupants.d.ts +45 -0
- package/dist/occupants.d.ts.map +1 -0
- package/dist/occupants.js +57 -0
- package/dist/occupants.js.map +1 -0
- package/dist/parallel.d.ts +19 -0
- package/dist/parallel.d.ts.map +1 -0
- package/dist/parallel.js +30 -0
- package/dist/parallel.js.map +1 -0
- package/dist/picking.d.ts +30 -0
- package/dist/picking.d.ts.map +1 -0
- package/dist/picking.js +140 -0
- package/dist/picking.js.map +1 -0
- package/dist/plots.d.ts +106 -0
- package/dist/plots.d.ts.map +1 -0
- package/dist/plots.js +306 -0
- package/dist/plots.js.map +1 -0
- package/dist/pointer.d.ts +27 -0
- package/dist/pointer.d.ts.map +1 -0
- package/dist/pointer.js +39 -0
- package/dist/pointer.js.map +1 -0
- package/dist/presence.d.ts +110 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +280 -0
- package/dist/presence.js.map +1 -0
- package/dist/rails.d.ts +11 -0
- package/dist/rails.d.ts.map +1 -0
- package/dist/rails.js +15 -0
- package/dist/rails.js.map +1 -0
- package/dist/resolved-view.d.ts +78 -0
- package/dist/resolved-view.d.ts.map +1 -0
- package/dist/resolved-view.js +365 -0
- package/dist/resolved-view.js.map +1 -0
- package/dist/robot.d.ts +114 -0
- package/dist/robot.d.ts.map +1 -0
- package/dist/robot.js +93 -0
- package/dist/robot.js.map +1 -0
- package/dist/routes.d.ts +50 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +150 -0
- package/dist/routes.js.map +1 -0
- package/dist/scene-camera.d.ts +25 -0
- package/dist/scene-camera.d.ts.map +1 -0
- package/dist/scene-camera.js +130 -0
- package/dist/scene-camera.js.map +1 -0
- package/dist/scene-hand.d.ts +110 -0
- package/dist/scene-hand.d.ts.map +1 -0
- package/dist/scene-hand.js +317 -0
- package/dist/scene-hand.js.map +1 -0
- package/dist/scene-helpers.d.ts +46 -0
- package/dist/scene-helpers.d.ts.map +1 -0
- package/dist/scene-helpers.js +108 -0
- package/dist/scene-helpers.js.map +1 -0
- package/dist/scene-lines.d.ts +76 -0
- package/dist/scene-lines.d.ts.map +1 -0
- package/dist/scene-lines.js +578 -0
- package/dist/scene-lines.js.map +1 -0
- package/dist/scene-root.d.ts +71 -0
- package/dist/scene-root.d.ts.map +1 -0
- package/dist/scene-root.js +790 -0
- package/dist/scene-root.js.map +1 -0
- package/dist/scene.d.ts +17 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +17 -0
- package/dist/scene.js.map +1 -0
- package/dist/seat-marks.d.ts +35 -0
- package/dist/seat-marks.d.ts.map +1 -0
- package/dist/seat-marks.js +43 -0
- package/dist/seat-marks.js.map +1 -0
- package/dist/settings.d.ts +30 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +73 -0
- package/dist/settings.js.map +1 -0
- package/dist/view-boundary.d.ts +33 -0
- package/dist/view-boundary.d.ts.map +1 -0
- package/dist/view-boundary.js +53 -0
- package/dist/view-boundary.js.map +1 -0
- package/dist/view-host.d.ts +57 -0
- package/dist/view-host.d.ts.map +1 -0
- package/dist/view-host.js +474 -0
- package/dist/view-host.js.map +1 -0
- package/dist/view-registry.d.ts +122 -0
- package/dist/view-registry.d.ts.map +1 -0
- package/dist/view-registry.js +20 -0
- package/dist/view-registry.js.map +1 -0
- package/dist/where-drawn.d.ts +151 -0
- package/dist/where-drawn.d.ts.map +1 -0
- package/dist/where-drawn.js +231 -0
- package/dist/where-drawn.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { labelOf } from "@graview/core";
|
|
3
|
+
import { mixStyles, styleFor, transformFor, hueFor } from "@graview/render";
|
|
4
|
+
import { useEffect, useRef, useLayoutEffect, useState, } from "react";
|
|
5
|
+
import { useGraview } from "./context.js";
|
|
6
|
+
import { pickedFrom, usePickTargets } from "./picking.js";
|
|
7
|
+
import { WHO } from "./where-drawn.js";
|
|
8
|
+
import { cssTransform, planeShadow } from "./scene-helpers.js";
|
|
9
|
+
/**
|
|
10
|
+
* One view's box. Absolutely positioned so the canvas can place it, and sized
|
|
11
|
+
* so the capture texture matches the DOM exactly.
|
|
12
|
+
*/
|
|
13
|
+
export function SceneViewHost({ node, useDom, touched, frontY, centreY, screen, onDrawnHeight, crowded, activity, scheme, canvasWidth, canvasHeight, selected, onSelect, onPick, onTravel, onMenu, selection, onJackIn, onDragStart, onDragMove, onDragEnd, swallowClick, children, }) {
|
|
14
|
+
// The tag's dot must agree with every other dot in a branded app.
|
|
15
|
+
const { brand: hostBrand, store: hostStore, actsDoor } = useGraview();
|
|
16
|
+
/*
|
|
17
|
+
* The name a screen reader reads for this box: the group's plural, or the
|
|
18
|
+
* node's own label — never the id, which is an address.
|
|
19
|
+
*/
|
|
20
|
+
const hostName = node.beyond
|
|
21
|
+
? /* Not a thing in the graph: the row saying what it could not hold. */
|
|
22
|
+
`${node.beyond.length} more district${node.beyond.length === 1 ? "" : "s"}`
|
|
23
|
+
: node.aggregate?.opens?.in === "place"
|
|
24
|
+
? /* A band's group is heard with its count: "Single, 80 albums". */
|
|
25
|
+
`${node.aggregate.label}, ${node.aggregate.memberIds.length} ${node.aggregate.memberIds.length === 1 ? node.aggregate.kind.replace(/-/g, " ") : (hostStore.schema.tryDefinition(node.aggregate.kind)?.plural ?? `${node.aggregate.kind}s`).toLowerCase()}`
|
|
26
|
+
: node.aggregate
|
|
27
|
+
? node.aggregate.label
|
|
28
|
+
: (() => {
|
|
29
|
+
const graphNode = hostStore.graph.getNode(node.id);
|
|
30
|
+
if (!graphNode)
|
|
31
|
+
return node.id;
|
|
32
|
+
return labelOf(hostStore.schema.tryDefinition(node.kind), graphNode);
|
|
33
|
+
})();
|
|
34
|
+
/*
|
|
35
|
+
* The tag hugs the PANEL, not the band slot. A host flex-centres a
|
|
36
|
+
* panel shorter than its slot, so a fixed top offset hung the tag in
|
|
37
|
+
* open ground above the card it names — measured against the drawn
|
|
38
|
+
* child instead, the same lesson every measured surface here learned.
|
|
39
|
+
*/
|
|
40
|
+
const [tagAt, setTagAt] = useState(null);
|
|
41
|
+
const tagged = Math.round(node.plane) === 0 && !node.aggregate;
|
|
42
|
+
/*
|
|
43
|
+
* Measured when the panel's SIZE changes, not on every render — from the
|
|
44
|
+
* observer, when the layout is already clean, so the reads are free.
|
|
45
|
+
*
|
|
46
|
+
* It ran after every render and read two bounding boxes, and a host
|
|
47
|
+
* renders every frame of a transition — so every frame forced the browser
|
|
48
|
+
* to lay the whole scene out before it could paint it (docs/scale.md, a
|
|
49
|
+
* third of the frame landing on a hub). An observer reports once when it
|
|
50
|
+
* starts watching, after layout and before paint, so the tag is placed
|
|
51
|
+
* in its first frame without forcing one.
|
|
52
|
+
*/
|
|
53
|
+
useLayoutEffect(() => {
|
|
54
|
+
if (!tagged)
|
|
55
|
+
return;
|
|
56
|
+
const host = ref.current;
|
|
57
|
+
if (!host)
|
|
58
|
+
return;
|
|
59
|
+
const place = () => {
|
|
60
|
+
/*
|
|
61
|
+
* The PANEL, never the tag itself.
|
|
62
|
+
*
|
|
63
|
+
* `firstElementChild` was the drawn panel right up until the view had
|
|
64
|
+
* nothing to draw — a focus on a node an act had just removed — and
|
|
65
|
+
* then the tag was the only child, so this measured the tag against
|
|
66
|
+
* its own host and moved it by the offset below, every render, until
|
|
67
|
+
* React gave up with "Maximum update depth exceeded" and blanked the
|
|
68
|
+
* page. A measurement that can read its own output has to say which
|
|
69
|
+
* child it means.
|
|
70
|
+
*/
|
|
71
|
+
const child = [...host.children].find(
|
|
72
|
+
// An empty data attribute reads as "", so presence is the question.
|
|
73
|
+
(element) => element.dataset["graviewKindtag"] === undefined);
|
|
74
|
+
if (!child)
|
|
75
|
+
return;
|
|
76
|
+
/*
|
|
77
|
+
* Drawn boxes, in the host's own units. Offsets would ignore the
|
|
78
|
+
* natural box's centring and shrink (the stamp at altitude) and land
|
|
79
|
+
* the tag mid-card; a box difference includes them, and dividing by
|
|
80
|
+
* the host's drawn scale takes the plane's scale back out.
|
|
81
|
+
*/
|
|
82
|
+
const hostBox = host.getBoundingClientRect();
|
|
83
|
+
const childBox = child.getBoundingClientRect();
|
|
84
|
+
const scale = host.offsetWidth > 0 ? hostBox.width / host.offsetWidth : 1;
|
|
85
|
+
const next = {
|
|
86
|
+
top: Math.round((childBox.top - hostBox.top) / scale) - 9,
|
|
87
|
+
right: Math.round((hostBox.right - childBox.right) / scale) + 14,
|
|
88
|
+
};
|
|
89
|
+
setTagAt((current) => current && current.top === next.top && current.right === next.right ? current : next);
|
|
90
|
+
};
|
|
91
|
+
if (typeof ResizeObserver === "undefined") {
|
|
92
|
+
place();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const watch = new ResizeObserver(place);
|
|
96
|
+
watch.observe(host);
|
|
97
|
+
for (const element of host.children)
|
|
98
|
+
watch.observe(element);
|
|
99
|
+
return () => watch.disconnect();
|
|
100
|
+
}, [tagged, node.id]);
|
|
101
|
+
/*
|
|
102
|
+
* A node's depth is its plane, pulled forward by however near it sits
|
|
103
|
+
* within that plane.
|
|
104
|
+
*
|
|
105
|
+
* Mid-transition a plane is already fractional so the treatment is mixed
|
|
106
|
+
* rather than snapping, and `depth` uses the same machinery: a card at the
|
|
107
|
+
* near end of the arc is treated as 1.6 planes back rather than 2, which is
|
|
108
|
+
* what makes the arc curve away instead of lying flat.
|
|
109
|
+
*/
|
|
110
|
+
const at = node.plane - (1 - (node.depth ?? 1)) * 0.55;
|
|
111
|
+
const lower = Math.max(0, Math.min(2, Math.floor(at)));
|
|
112
|
+
const upper = Math.max(0, Math.min(2, Math.ceil(at)));
|
|
113
|
+
const style = lower === upper
|
|
114
|
+
? styleFor(lower, scheme)
|
|
115
|
+
: mixStyles(styleFor(lower, scheme), styleFor(upper, scheme), at - lower);
|
|
116
|
+
const transform = transformFor(style, node.x, node.y, canvasWidth, canvasHeight);
|
|
117
|
+
/*
|
|
118
|
+
* The blur is the NEAREST plane's, not a mix. It is under half a pixel,
|
|
119
|
+
* nobody can see it tween, and a filter whose radius changes is a filter
|
|
120
|
+
* repainted — every host, every frame of every transition
|
|
121
|
+
* (docs/scale.md). Snapped, it changes once, halfway.
|
|
122
|
+
*/
|
|
123
|
+
const blur = styleFor(Math.max(0, Math.min(2, Math.round(at))), scheme).blur;
|
|
124
|
+
const ref = useRef(null);
|
|
125
|
+
usePickTargets(ref);
|
|
126
|
+
/*
|
|
127
|
+
* A view drawn smaller than it was designed for is SCALED, not re-solved.
|
|
128
|
+
*
|
|
129
|
+
* When the layout gives a node a natural size, the view lays itself out at
|
|
130
|
+
* that size and the whole result is transformed down into the slot. That is
|
|
131
|
+
* the same picture, smaller — which is what a captured texture would do on
|
|
132
|
+
* the GPU path anyway, and what keeps the shrunk interface an interface:
|
|
133
|
+
* every pick target inside it is still a real target, because nothing here
|
|
134
|
+
* is an image.
|
|
135
|
+
*
|
|
136
|
+
* Rendering into the slot instead is what broke it: a coverage matrix asked
|
|
137
|
+
* to lay itself out in a third of its width piled its rotated column
|
|
138
|
+
* headers into a corner and clipped its rows.
|
|
139
|
+
*/
|
|
140
|
+
const natural = node.natural;
|
|
141
|
+
const shrink = natural
|
|
142
|
+
? Math.min(node.width / natural.width, node.height / natural.height)
|
|
143
|
+
: 1;
|
|
144
|
+
/*
|
|
145
|
+
* A BILLBOARD REPORTS ITS PICTURE'S HEIGHT.
|
|
146
|
+
*
|
|
147
|
+
* The lens lays itself out in the natural box, as tall as the window, and
|
|
148
|
+
* a lens is built to fill what it is given: a header, then a scroll
|
|
149
|
+
* region that takes the rest. So neither the box nor the lens's own
|
|
150
|
+
* height says how tall the PICTURE is. What does: the extent of what is
|
|
151
|
+
* in flow, plus what every scroll region inside needs beyond what it has
|
|
152
|
+
* (negative when it has room to spare). From the whole box that comes to
|
|
153
|
+
* header-plus-rows; cut to that, the scroll region holds exactly its
|
|
154
|
+
* rows and the measure is its own fixed point. Watched for size and for
|
|
155
|
+
* content, because rows come and go without anything resizing; withdrawn
|
|
156
|
+
* when this box stops being the screen.
|
|
157
|
+
*/
|
|
158
|
+
const naturalRef = useRef(null);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (!screen || !onDrawnHeight)
|
|
161
|
+
return;
|
|
162
|
+
const box = naturalRef.current;
|
|
163
|
+
if (!box || typeof ResizeObserver === "undefined")
|
|
164
|
+
return;
|
|
165
|
+
const measure = () => {
|
|
166
|
+
let extent = 0;
|
|
167
|
+
let wanted = 0;
|
|
168
|
+
for (const child of box.children) {
|
|
169
|
+
if (!(child instanceof HTMLElement) || child.classList.contains("graview-screen-fullscreen"))
|
|
170
|
+
continue;
|
|
171
|
+
extent = Math.max(extent, child.offsetTop + child.offsetHeight);
|
|
172
|
+
for (const el of [child, ...child.querySelectorAll("*")]) {
|
|
173
|
+
const overflow = getComputedStyle(el).overflowY;
|
|
174
|
+
if (overflow === "auto" || overflow === "scroll")
|
|
175
|
+
wanted += el.scrollHeight - el.clientHeight;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
onDrawnHeight(extent + wanted);
|
|
179
|
+
};
|
|
180
|
+
let queued = 0;
|
|
181
|
+
const later = () => {
|
|
182
|
+
if (queued)
|
|
183
|
+
return;
|
|
184
|
+
queued = requestAnimationFrame(() => {
|
|
185
|
+
queued = 0;
|
|
186
|
+
measure();
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
measure();
|
|
190
|
+
const sizes = new ResizeObserver(later);
|
|
191
|
+
sizes.observe(box);
|
|
192
|
+
for (const child of box.children)
|
|
193
|
+
sizes.observe(child);
|
|
194
|
+
const content = new MutationObserver(later);
|
|
195
|
+
content.observe(box, { childList: true, subtree: true, characterData: true, attributes: true });
|
|
196
|
+
return () => {
|
|
197
|
+
if (queued)
|
|
198
|
+
cancelAnimationFrame(queued);
|
|
199
|
+
sizes.disconnect();
|
|
200
|
+
content.disconnect();
|
|
201
|
+
onDrawnHeight(undefined);
|
|
202
|
+
};
|
|
203
|
+
}, [screen, onDrawnHeight, node.id]);
|
|
204
|
+
const domOnly = useDom
|
|
205
|
+
? {
|
|
206
|
+
transform: cssTransform(transform),
|
|
207
|
+
transformOrigin: "0 0",
|
|
208
|
+
filter: blur > 0 ? `blur(${blur}px)` : undefined,
|
|
209
|
+
// Recession dims toward the ground; entering and leaving nodes carry
|
|
210
|
+
// their own fade on top of it.
|
|
211
|
+
opacity: (1 - style.falloff * 0.55) * (node.opacity ?? 1),
|
|
212
|
+
/*
|
|
213
|
+
* Depth is handed DOWN as the elevation token, not painted on the
|
|
214
|
+
* host.
|
|
215
|
+
*
|
|
216
|
+
* A host box-shadow outlines the box the layout allotted, which is
|
|
217
|
+
* only the same shape as the view when the view fills it. Once a
|
|
218
|
+
* detail panel sized to its own content, every focused node picked
|
|
219
|
+
* up a large ghost rectangle behind it. Setting the token means the
|
|
220
|
+
* panel casts the plane's shadow from its own edges — and any view
|
|
221
|
+
* built on `Panel` gets it without knowing planes exist.
|
|
222
|
+
*/
|
|
223
|
+
["--graview-lift-low"]: planeShadow(style.shadow, scheme),
|
|
224
|
+
...(frontY !== undefined ? { ["--graview-front-y"]: `${frontY.toFixed(1)}px` } : {}),
|
|
225
|
+
...(centreY !== undefined ? { ["--graview-centre-y"]: `${centreY.toFixed(1)}px` } : {}),
|
|
226
|
+
}
|
|
227
|
+
: // The GPU path does NOT fade the host: the shader owns opacity there,
|
|
228
|
+
// and applying it in both places made an entering view fade as
|
|
229
|
+
// opacity² — visibly faster and dimmer than the DOM path, so the two
|
|
230
|
+
// renderers disagreed about the same transition. It also meant a view
|
|
231
|
+
// captured mid-fade baked its own transparency into the texture.
|
|
232
|
+
{};
|
|
233
|
+
return (_jsxs("div", { ref: ref, "data-graview-view": node.id, "data-graview-plane": Math.round(node.plane), "data-graview-selected": selected || undefined, "data-graview-touched": touched || undefined, "data-graview-plot": frontY !== undefined ? "" : undefined, "data-graview-screen": screen ? "" : undefined, "data-graview-nested": node.nestedUnder ?? undefined, "data-graview-crowded": crowded || undefined, "data-graview-pinned": node.pinned || undefined, "data-graview-activity": activity ? activity.manner : undefined, "data-graview-wrote": activity?.wrote || undefined, "data-graview-read": activity && !activity.wrote ? true : undefined, "data-graview-broke": activity?.broke || undefined,
|
|
234
|
+
/*
|
|
235
|
+
* "Open X" only where clicking raises X. On plane 0 the group IS what
|
|
236
|
+
* you are looking at, so the tooltip promised something clicking does
|
|
237
|
+
* not do — and it shadowed the more specific titles a view puts on its
|
|
238
|
+
* own contents.
|
|
239
|
+
*/
|
|
240
|
+
/*
|
|
241
|
+
* While something is happening here, the tooltip says WHAT — the
|
|
242
|
+
* intent the op recorded, in the app's own words. Watching should not
|
|
243
|
+
* require opening the activity list to find out what the light meant.
|
|
244
|
+
*/
|
|
245
|
+
title: activity
|
|
246
|
+
? `${WHO[activity.manner]} ${activity.wrote ? "changed this" : "read this"}: ${activity.intent}`
|
|
247
|
+
: node.aggregate && Math.round(node.plane) !== 0
|
|
248
|
+
? `Open ${node.aggregate.label}`
|
|
249
|
+
: undefined, role: "group", "aria-label": hostName, "aria-keyshortcuts": actsDoor && !node.beyond ? actsDoor.key : undefined, tabIndex: 0, onPointerDown: onDragStart, onPointerMove: onDragMove, onPointerUp: onDragEnd, onPointerCancel: onDragEnd, onClick: (event) => {
|
|
250
|
+
// A drag that ends on a card must not also select it.
|
|
251
|
+
if (swallowClick.current)
|
|
252
|
+
return;
|
|
253
|
+
/*
|
|
254
|
+
* A CONTROL INSIDE A VIEW HAS ITS OWN MEANING, and selecting the
|
|
255
|
+
* card it sits on is not it.
|
|
256
|
+
*
|
|
257
|
+
* The keyboard path below has said so since it was written; the
|
|
258
|
+
* pointer path had not, because until a view drew a real control
|
|
259
|
+
* nothing noticed. The calendar draws several — previous, next,
|
|
260
|
+
* today, the range, "+3 more" — and pressing any of them also
|
|
261
|
+
* selected every task in the district the calendar was drawing, so
|
|
262
|
+
* changing the month lit up the whole month.
|
|
263
|
+
*/
|
|
264
|
+
const inControl = event.target?.closest("input, textarea, select, button, a[href], [contenteditable='true']");
|
|
265
|
+
if (inControl && !inControl.hasAttribute("data-graview-pick"))
|
|
266
|
+
return;
|
|
267
|
+
const additive = event.metaKey || event.shiftKey;
|
|
268
|
+
/*
|
|
269
|
+
* A view may nominate its own inner targets.
|
|
270
|
+
*
|
|
271
|
+
* Any element carrying `data-graview-pick="<node id>"` is a real
|
|
272
|
+
* thing in the graph, and clicking it means that thing — not the
|
|
273
|
+
* view that happens to be drawing it. One rule, in one place, and
|
|
274
|
+
* every view gets it: a span in the calendar, a row in a roster, a
|
|
275
|
+
* chip in a summary.
|
|
276
|
+
*
|
|
277
|
+
* Without this, clicking an event in the week could only ever mean
|
|
278
|
+
* "the week", which is why clicking an event appeared to do nothing.
|
|
279
|
+
*/
|
|
280
|
+
const picked = pickedFrom(event.target);
|
|
281
|
+
if (picked && picked !== node.id) {
|
|
282
|
+
event.stopPropagation();
|
|
283
|
+
onPick(picked, additive);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
onSelect(additive);
|
|
287
|
+
}, onKeyDown: (event) => {
|
|
288
|
+
/*
|
|
289
|
+
* ITS ACTS, ONE KEY AWAY. The keyboard's right-click: what the key
|
|
290
|
+
* lands on is chosen, as a right-click chooses it, and the seat
|
|
291
|
+
* opens on its acts with the keyboard in them. Only on the card
|
|
292
|
+
* itself — a letter typed into a field inside it is a letter.
|
|
293
|
+
*/
|
|
294
|
+
if (actsDoor &&
|
|
295
|
+
!node.beyond &&
|
|
296
|
+
event.key.toLowerCase() === actsDoor.key.toLowerCase() &&
|
|
297
|
+
!event.metaKey &&
|
|
298
|
+
!event.ctrlKey &&
|
|
299
|
+
!event.altKey &&
|
|
300
|
+
!event.target?.closest("input, textarea, select, [contenteditable='true']")) {
|
|
301
|
+
event.preventDefault();
|
|
302
|
+
event.stopPropagation();
|
|
303
|
+
const on = pickedFrom(event.target) ?? node.id;
|
|
304
|
+
if (!selection.includes(on))
|
|
305
|
+
onPick(on, false);
|
|
306
|
+
// Back to what the keyboard stood on — the card, or the mark inside it it had reached.
|
|
307
|
+
actsDoor.open(event.target instanceof HTMLElement ? event.target : event.currentTarget);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
311
|
+
return;
|
|
312
|
+
/*
|
|
313
|
+
* NEVER STEAL A KEY FROM A CONTROL THAT HAS ITS OWN MEANING FOR IT.
|
|
314
|
+
*
|
|
315
|
+
* A card is a target, and so are the pick marks a view draws inside
|
|
316
|
+
* it — but a real control is not. Preventing the default before
|
|
317
|
+
* asking swallowed Enter inside the title's own editor, so renaming
|
|
318
|
+
* a record in place stopped committing: the field stayed open and
|
|
319
|
+
* nothing was written. `pnpm remember` is what noticed.
|
|
320
|
+
*/
|
|
321
|
+
const inControl = event.target?.closest("input, textarea, select, button, [contenteditable='true']");
|
|
322
|
+
if (inControl)
|
|
323
|
+
return;
|
|
324
|
+
const picked = pickedFrom(event.target);
|
|
325
|
+
event.preventDefault();
|
|
326
|
+
event.stopPropagation();
|
|
327
|
+
/*
|
|
328
|
+
* THE CARD ITSELF ANSWERS THE KEYBOARD.
|
|
329
|
+
*
|
|
330
|
+
* It was a tab stop that did nothing: the handler returned unless the
|
|
331
|
+
* key had landed on an inner pick target, on the grounds that the
|
|
332
|
+
* host "has its own meaning" — which was true, and reachable only
|
|
333
|
+
* with a pointer. On a blank app that is the whole of it. The one
|
|
334
|
+
* district is the only thing on screen, selecting it is what opens
|
|
335
|
+
* the strip, and the strip is where the first act lives, so a
|
|
336
|
+
* keyboard alone could not add the first record to a new product.
|
|
337
|
+
*
|
|
338
|
+
* Enter on the host does what a click on it does; Enter again on a
|
|
339
|
+
* card already selected alone does what the second click does — the
|
|
340
|
+
* same two-step the inner targets have.
|
|
341
|
+
*/
|
|
342
|
+
if (!picked || picked === node.id) {
|
|
343
|
+
const already = selection.length === 1 && selection[0] === node.id;
|
|
344
|
+
if (already && !event.metaKey && !event.shiftKey)
|
|
345
|
+
onJackIn();
|
|
346
|
+
else
|
|
347
|
+
onSelect(event.metaKey || event.shiftKey);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
/*
|
|
351
|
+
* Enter selects; Enter again on something already selected alone
|
|
352
|
+
* travels. The keyboard needs the same two-step the pointer has, and
|
|
353
|
+
* a modifier would have been a worse answer than repeating yourself.
|
|
354
|
+
*/
|
|
355
|
+
const already = selection.length === 1 && selection[0] === picked;
|
|
356
|
+
if (already && !event.metaKey && !event.shiftKey)
|
|
357
|
+
onTravel(picked);
|
|
358
|
+
else
|
|
359
|
+
onPick(picked, event.metaKey || event.shiftKey);
|
|
360
|
+
}, onContextMenu: (event) => {
|
|
361
|
+
const picked = pickedFrom(event.target);
|
|
362
|
+
event.preventDefault();
|
|
363
|
+
event.stopPropagation();
|
|
364
|
+
/*
|
|
365
|
+
* Right-click SELECTS, always — through onPick, never onSelect,
|
|
366
|
+
* because onSelect's kind-card branch toggles the raised relation
|
|
367
|
+
* and returns without selecting, which opened a menu about nothing
|
|
368
|
+
* (and quietly raised People on the way).
|
|
369
|
+
*/
|
|
370
|
+
const on = picked && picked !== node.id ? picked : node.id;
|
|
371
|
+
onPick(on, false);
|
|
372
|
+
/*
|
|
373
|
+
* The menu is about THIS, and says so. Without the name the
|
|
374
|
+
* derivation could only rank by the selection, and a rule that
|
|
375
|
+
* implicates several nodes in one violation put somebody else's
|
|
376
|
+
* repair at the top of the menu you opened on yours.
|
|
377
|
+
*/
|
|
378
|
+
onMenu({ x: event.clientX, y: event.clientY, on });
|
|
379
|
+
}, onDoubleClick: (event) => {
|
|
380
|
+
const picked = pickedFrom(event.target);
|
|
381
|
+
if (picked && picked !== node.id) {
|
|
382
|
+
event.stopPropagation();
|
|
383
|
+
onTravel(picked);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
onJackIn();
|
|
387
|
+
}, style: {
|
|
388
|
+
position: "absolute",
|
|
389
|
+
/*
|
|
390
|
+
* On the capture path the host is OUT of hit-testing entirely.
|
|
391
|
+
*
|
|
392
|
+
* This is the fix for the defect that kept the GPU path off by
|
|
393
|
+
* default. It was recorded as "a click crashes the renderer process",
|
|
394
|
+
* and that was a symptom rather than the cause: bisected in Chromium
|
|
395
|
+
* 154, a plain HOVER over a captured view brings the process down just
|
|
396
|
+
* as reliably, while selecting the same node from the keyboard does
|
|
397
|
+
* not. What is fatal is the browser's own hit-test descending into a
|
|
398
|
+
* `layoutsubtree` canvas child.
|
|
399
|
+
*
|
|
400
|
+
* Nothing is lost by removing it. `updateElementGeometry` does not
|
|
401
|
+
* redirect hit-testing in this build, so a DOM hit-test on a captured
|
|
402
|
+
* view was already returning the wrong answer — it reported the box
|
|
403
|
+
* where the element was LAID OUT rather than where it was DRAWN, which
|
|
404
|
+
* is why `PointerRouter` exists at all. The compositor already runs one
|
|
405
|
+
* on the canvas; this stops the platform racing it into a crash.
|
|
406
|
+
*
|
|
407
|
+
* Keyboard reach and the accessibility tree are untouched:
|
|
408
|
+
* `pointer-events` says nothing about focus, and the views stay real,
|
|
409
|
+
* focusable DOM.
|
|
410
|
+
*
|
|
411
|
+
* On the DOM path the theme narrows the host's hit area to its drawn
|
|
412
|
+
* content (`[data-graview-stage="dom"] [data-graview-view]`): the
|
|
413
|
+
* box is the layout's, the target is the view's.
|
|
414
|
+
*/
|
|
415
|
+
...(useDom ? {} : { pointerEvents: "none" }),
|
|
416
|
+
// Each host sits at its own layout position, on BOTH paths.
|
|
417
|
+
//
|
|
418
|
+
// Under `layoutsubtree` every child is laid out at the canvas origin,
|
|
419
|
+
// so hosts pinned to 0,0 pile up on each other and only some of them
|
|
420
|
+
// end up with usable paint records — five views captured completely
|
|
421
|
+
// blank because of it. Giving each its own box keeps them distinct
|
|
422
|
+
// for the capture. The GPU still draws each wherever its plane
|
|
423
|
+
// transform says; this only decides what gets rasterised.
|
|
424
|
+
// Nearer planes paint over further ones — and an OPENED district
|
|
425
|
+
// comes to the front outright: its roster grows over whatever is
|
|
426
|
+
// beside it, and a chip half-hidden behind the live view is a chip
|
|
427
|
+
// nobody can press.
|
|
428
|
+
zIndex: node.opened ? 11 : 10 - Math.round(node.plane),
|
|
429
|
+
left: useDom ? 0 : Math.round(node.x),
|
|
430
|
+
top: useDom ? 0 : Math.round(node.y),
|
|
431
|
+
// Whole pixels, matching what the renderer allocates a texture for.
|
|
432
|
+
// A host of height 399.4 rasterises into 400 rows; a texture sized
|
|
433
|
+
// from the rounded 399 rejects the copy, and the view keeps whatever
|
|
434
|
+
// was in the texture before — silently.
|
|
435
|
+
width: Math.round(node.width),
|
|
436
|
+
height: Math.round(node.height),
|
|
437
|
+
boxSizing: "border-box",
|
|
438
|
+
// A view that sizes to its content is centred in the box the layout
|
|
439
|
+
// gave it, rather than pinned to the top with the remainder left as
|
|
440
|
+
// dead white space.
|
|
441
|
+
display: "flex",
|
|
442
|
+
flexDirection: "column",
|
|
443
|
+
justifyContent: "center",
|
|
444
|
+
...domOnly,
|
|
445
|
+
}, children: [natural ? (
|
|
446
|
+
/*
|
|
447
|
+
* Centred on the slot and scaled about its own middle, so the
|
|
448
|
+
* proportions the view chose survive a slot that does not share them.
|
|
449
|
+
* `position: absolute` keeps the natural box out of the host's flow —
|
|
450
|
+
* it must not be able to push the host's own geometry around, since
|
|
451
|
+
* the capture allocates a texture from that.
|
|
452
|
+
*/
|
|
453
|
+
_jsx("div", { ref: naturalRef, "data-graview-natural": `${Math.round(natural.width)}x${Math.round(natural.height)}`, style: {
|
|
454
|
+
position: "absolute",
|
|
455
|
+
left: "50%",
|
|
456
|
+
top: "50%",
|
|
457
|
+
width: natural.width,
|
|
458
|
+
height: natural.height,
|
|
459
|
+
transform: `translate(-50%, -50%) scale(${shrink})`,
|
|
460
|
+
transformOrigin: "50% 50%",
|
|
461
|
+
display: "flex",
|
|
462
|
+
flexDirection: "column",
|
|
463
|
+
}, children: children })) : (children), Math.round(node.plane) === 0 && !node.aggregate ? (_jsxs("span", { "data-graview-kindtag": "", className: "graview-kind-tag", "aria-hidden": "true", style: {
|
|
464
|
+
...(tagAt ?? {}),
|
|
465
|
+
["--graview-hue"]: Math.round(hueFor(node.kind, hostBrand?.accents)),
|
|
466
|
+
}, children: [_jsx("span", { style: {
|
|
467
|
+
width: 6,
|
|
468
|
+
height: 6,
|
|
469
|
+
borderRadius: 999,
|
|
470
|
+
flex: "0 0 auto",
|
|
471
|
+
background: `hsl(${Math.round(hueFor(node.kind, hostBrand?.accents))} 55% var(--graview-tint-lightness) / 0.9)`,
|
|
472
|
+
} }), node.kind] })) : null] }));
|
|
473
|
+
}
|
|
474
|
+
//# sourceMappingURL=view-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-host.js","sourceRoot":"","sources":["../src/view-host.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { type AnySchema, type Cardinality, type Fidelity, type KindOfSchema, type NodeOfKind, type NodeOfSchema, type ViewCell, type ViewMeta, type ViewRegistry } from "@graview/core";
|
|
2
|
+
import type { ComponentType } from "react";
|
|
3
|
+
import type { ViewMode } from "./context.js";
|
|
4
|
+
/**
|
|
5
|
+
* What a view receives. Deliberately small: a node (or a group of them), how
|
|
6
|
+
* it is being drawn, and whether it is selected.
|
|
7
|
+
*
|
|
8
|
+
* Everything else a view needs it gets from ordinary hooks, because views are
|
|
9
|
+
* ordinary React components. That is the entire reason the capture approach
|
|
10
|
+
* is worth its cost — authors write normal components, not a scene DSL.
|
|
11
|
+
*/
|
|
12
|
+
export interface ViewProps<S extends AnySchema, K extends KindOfSchema<S> = KindOfSchema<S>> {
|
|
13
|
+
/** The node, for a `one` view. */
|
|
14
|
+
readonly node?: NodeOfKind<S, K>;
|
|
15
|
+
/** The members, for a `many` view standing in for a kind. */
|
|
16
|
+
readonly nodes?: readonly NodeOfSchema<S>[];
|
|
17
|
+
/** Plural label for an aggregate, from the kind's declaration. */
|
|
18
|
+
readonly label?: string;
|
|
19
|
+
/**
|
|
20
|
+
* THE MOST THIS PICTURE SHOULD DRAW (docs/scale.md). Set where the room is
|
|
21
|
+
* small — a drive-in's thumbnail hands a lens its 24 most relevant members
|
|
22
|
+
* and says so. A lens that reads the store for more than `nodes` (a
|
|
23
|
+
* coverage's columns) holds itself to it; any lens handed fewer than
|
|
24
|
+
* `total` says how many more there are. Absent: the picture is the
|
|
25
|
+
* person's, and draws what it draws.
|
|
26
|
+
*/
|
|
27
|
+
readonly budget?: number;
|
|
28
|
+
/** How many members there are in all, when `nodes` is fewer. */
|
|
29
|
+
readonly total?: number;
|
|
30
|
+
readonly fidelity: Fidelity;
|
|
31
|
+
readonly cardinality: Cardinality;
|
|
32
|
+
/**
|
|
33
|
+
* Captured into the scene, or lifted out as a full page. A view MUST render
|
|
34
|
+
* correctly either way; jacking in is a familiarity affordance, not an
|
|
35
|
+
* escape hatch from a scene that does not work.
|
|
36
|
+
*/
|
|
37
|
+
readonly mode: ViewMode;
|
|
38
|
+
readonly selected: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Ids the current selection reaches — itself plus everything one edge
|
|
41
|
+
* away. Absent or empty means nothing is selected, which a view must read
|
|
42
|
+
* as "no emphasis" rather than "nothing is related".
|
|
43
|
+
*/
|
|
44
|
+
readonly implicated?: readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* Ids implicated in a current invariant violation, so a view can mark them
|
|
47
|
+
* where they actually are. A problem you can only find through a list is a
|
|
48
|
+
* problem you have to go looking for.
|
|
49
|
+
*/
|
|
50
|
+
readonly flagged?: readonly string[];
|
|
51
|
+
/** This group's members are currently raised onto the relation plane. */
|
|
52
|
+
readonly raised?: boolean;
|
|
53
|
+
/** This group is the kind currently in focus. */
|
|
54
|
+
readonly focused?: boolean;
|
|
55
|
+
/** The aggregate is opened in place, showing its members (the ring). */
|
|
56
|
+
readonly opened?: boolean;
|
|
57
|
+
/** The rows of members an opened district has room for (the layout's `openedRows`). */
|
|
58
|
+
readonly openedRows?: number;
|
|
59
|
+
/**
|
|
60
|
+
* The district's address in the city, when it is drawn at altitude: its
|
|
61
|
+
* corner in lattice cells and how many cells it takes on a side today —
|
|
62
|
+
* which is how many buildings a row holds when it is opened.
|
|
63
|
+
*/
|
|
64
|
+
readonly plot?: {
|
|
65
|
+
readonly col: number;
|
|
66
|
+
readonly row: number;
|
|
67
|
+
readonly side: number;
|
|
68
|
+
};
|
|
69
|
+
/** Members behind the horizon: retired, counted, one step away. */
|
|
70
|
+
readonly retired?: number;
|
|
71
|
+
/**
|
|
72
|
+
* How near this kind is to the one in focus: `primary` is one declared edge
|
|
73
|
+
* away, `secondary` is further. Absent when nothing is focused, and when
|
|
74
|
+
* the focus touches nothing — a strip where every card is secondary says
|
|
75
|
+
* no more than one where none is.
|
|
76
|
+
*
|
|
77
|
+
* A view is expected to read it as EMPHASIS, not as a filter: a secondary
|
|
78
|
+
* card is still the same card, quieter.
|
|
79
|
+
*/
|
|
80
|
+
readonly rank?: "primary" | "secondary";
|
|
81
|
+
/** Drawn tucked behind another kind's card, because it is reachable only through it. */
|
|
82
|
+
readonly nestedUnder?: string;
|
|
83
|
+
/**
|
|
84
|
+
* The app registered a view of its own for this kind, rather than leaving
|
|
85
|
+
* it on the framework's generic one — so there is a picture to go into.
|
|
86
|
+
*
|
|
87
|
+
* Derived rather than declared: `registerDefaultViews` marks what it
|
|
88
|
+
* registers, and an app's own registration replaces it. True the moment
|
|
89
|
+
* someone writes a lens, false the moment they remove it.
|
|
90
|
+
*/
|
|
91
|
+
readonly hasOwnView?: boolean;
|
|
92
|
+
}
|
|
93
|
+
export type ViewComponent<S extends AnySchema, K extends KindOfSchema<S> = KindOfSchema<S>> = ComponentType<ViewProps<S, K>>;
|
|
94
|
+
export interface ReactViewRegistry<S extends AnySchema> extends ViewRegistry<S, ViewComponent<S>> {
|
|
95
|
+
/**
|
|
96
|
+
* Registering a view for a kind the schema never declared is a TYPECHECK
|
|
97
|
+
* failure — `K` is constrained to the schema's kinds, so the mistake
|
|
98
|
+
* surfaces at build time rather than at render.
|
|
99
|
+
*
|
|
100
|
+
* A view written over the whole schema — every lens is, and it is what
|
|
101
|
+
* `graview-lens` tells an app to write — registers on any one kind
|
|
102
|
+
* without a cast. React's `FunctionComponent<P>` is covariant in `P`
|
|
103
|
+
* (its `propTypes`), so a `ViewComponent<S>` was not assignable to
|
|
104
|
+
* `ViewComponent<S, "plot">` and every lens in the framework's own apps
|
|
105
|
+
* carried `as ViewComponent<S>` to get past it; a project following the
|
|
106
|
+
* skill verbatim did not typecheck.
|
|
107
|
+
*/
|
|
108
|
+
register<K extends KindOfSchema<S>>(kind: K, cell: ViewCell, view: ViewComponent<S, K> | ViewComponent<S>, meta?: ViewMeta): ReactViewRegistry<S>;
|
|
109
|
+
}
|
|
110
|
+
export declare function createViews<S extends AnySchema>(schema: S): ReactViewRegistry<S>;
|
|
111
|
+
export type { Cardinality, Fidelity, ViewCell };
|
|
112
|
+
/**
|
|
113
|
+
* The mark a framework-supplied view carries, so a scene can tell a group
|
|
114
|
+
* shown by the framework's own list from one an app gave a picture of its
|
|
115
|
+
* own. From altitude the first is its district; the second keeps its card.
|
|
116
|
+
*/
|
|
117
|
+
export declare const DEFAULT_VIEW: unique symbol;
|
|
118
|
+
/** Marks a view as the framework's own. Returns the same component. */
|
|
119
|
+
export declare function markDefaultView<V extends object>(view: V): V;
|
|
120
|
+
/** Whether a view is the framework's own rather than the app's. */
|
|
121
|
+
export declare function isDefaultView(view: unknown): boolean;
|
|
122
|
+
//# sourceMappingURL=view-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-registry.d.ts","sourceRoot":"","sources":["../src/view-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createViewRegistry, } from "@graview/core";
|
|
2
|
+
export function createViews(schema) {
|
|
3
|
+
return createViewRegistry(schema);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The mark a framework-supplied view carries, so a scene can tell a group
|
|
7
|
+
* shown by the framework's own list from one an app gave a picture of its
|
|
8
|
+
* own. From altitude the first is its district; the second keeps its card.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_VIEW = Symbol.for("graview.default-view");
|
|
11
|
+
/** Marks a view as the framework's own. Returns the same component. */
|
|
12
|
+
export function markDefaultView(view) {
|
|
13
|
+
Object.defineProperty(view, DEFAULT_VIEW, { value: true, enumerable: false });
|
|
14
|
+
return view;
|
|
15
|
+
}
|
|
16
|
+
/** Whether a view is the framework's own rather than the app's. */
|
|
17
|
+
export function isDefaultView(view) {
|
|
18
|
+
return typeof view === "function" && view[DEFAULT_VIEW] === true;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=view-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-registry.js","sourceRoot":"","sources":["../src/view-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAUnB,MAAM,eAAe,CAAC;AAsHvB,MAAM,UAAU,WAAW,CAAsB,MAAS;IACxD,OAAO,kBAAkB,CAAsB,MAAM,CAAyB,CAAC;AACjF,CAAC;AAID;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAkB,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;AAE9E,uEAAuE;AACvE,MAAM,UAAU,eAAe,CAAmB,IAAO;IACvD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,aAAa,CAAC,IAAa;IACzC,OAAO,OAAO,IAAI,KAAK,UAAU,IAAK,IAAqC,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;AACrG,CAAC"}
|