@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
package/dist/picking.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The one rule that makes anything a view drew into a real target.
|
|
4
|
+
*
|
|
5
|
+
* A view marks an element with `data-graview-pick="<node id>"` and that is the
|
|
6
|
+
* WHOLE contract: whatever surface the view is drawn on routes the gesture to
|
|
7
|
+
* that node. Which surface is the part that was wrong — the rule lived inside
|
|
8
|
+
* the scene's host, so a view lifted out into a full page kept its marks and
|
|
9
|
+
* lost its behaviour. Every chip on it was a button-shaped thing that did
|
|
10
|
+
* nothing, which is precisely the "I clicked it and nothing happened" the
|
|
11
|
+
* marks exist to prevent.
|
|
12
|
+
*
|
|
13
|
+
* So it lives here, and both surfaces use it.
|
|
14
|
+
*/
|
|
15
|
+
/** The node a pointer or key event is really about, if any. */
|
|
16
|
+
export function pickedFrom(target) {
|
|
17
|
+
return (target?.closest?.("[data-graview-pick]")?.getAttribute("data-graview-pick") ?? null);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Makes every `data-graview-pick` element inside a host a real control.
|
|
21
|
+
*
|
|
22
|
+
* Having made clicking the primary way to move through the graph, leaving
|
|
23
|
+
* those targets unreachable by keyboard would make the primary interaction
|
|
24
|
+
* mouse-only.
|
|
25
|
+
*
|
|
26
|
+
* Set as attributes rather than as props because the elements belong to
|
|
27
|
+
* whatever view drew them; React is not managing these, so there is nothing
|
|
28
|
+
* to fight over.
|
|
29
|
+
*/
|
|
30
|
+
export function usePickTargets(ref) {
|
|
31
|
+
/*
|
|
32
|
+
* WHEN THE CONTENT CHANGES, not after every render. This ran on every
|
|
33
|
+
* render of every host — every frame of a transition, for every card —
|
|
34
|
+
* scanning each subtree for marks that had not moved (docs/scale.md). The
|
|
35
|
+
* marks only change when a view draws something new, so the scan runs
|
|
36
|
+
* when the host mounts and when elements are added under it, at most
|
|
37
|
+
* once a frame.
|
|
38
|
+
*/
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const host = ref.current;
|
|
41
|
+
if (!host)
|
|
42
|
+
return;
|
|
43
|
+
const mark = () => {
|
|
44
|
+
for (const target of host.querySelectorAll("[data-graview-pick]")) {
|
|
45
|
+
if (target.getAttribute("tabindex") === null)
|
|
46
|
+
target.setAttribute("tabindex", "0");
|
|
47
|
+
if (target.getAttribute("role") === null && takesButton(target)) {
|
|
48
|
+
target.setAttribute("role", "button");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
mark();
|
|
53
|
+
if (typeof MutationObserver === "undefined")
|
|
54
|
+
return;
|
|
55
|
+
let queued = 0;
|
|
56
|
+
const watch = new MutationObserver(() => {
|
|
57
|
+
if (queued !== 0)
|
|
58
|
+
return;
|
|
59
|
+
queued = typeof requestAnimationFrame === "undefined" ? 0 : requestAnimationFrame(() => {
|
|
60
|
+
queued = 0;
|
|
61
|
+
mark();
|
|
62
|
+
});
|
|
63
|
+
if (queued === 0)
|
|
64
|
+
mark();
|
|
65
|
+
});
|
|
66
|
+
watch.observe(host, { childList: true, subtree: true, attributes: true, attributeFilter: ["data-graview-pick"] });
|
|
67
|
+
return () => {
|
|
68
|
+
watch.disconnect();
|
|
69
|
+
if (queued !== 0)
|
|
70
|
+
cancelAnimationFrame(queued);
|
|
71
|
+
};
|
|
72
|
+
}, [ref]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Whether `role="button"` is a legal thing to say about this element.
|
|
76
|
+
*
|
|
77
|
+
* It was said about EVERY pick target, and a view is free to mark whatever
|
|
78
|
+
* it drew — so a list whose heading was a `<header>` got
|
|
79
|
+
* `<header role="button">`, which ARIA forbids and axe reports
|
|
80
|
+
* (`aria-allowed-role`). Three of them on the first screen of the app this
|
|
81
|
+
* repository shows people first, unnoticed because nothing had ever run axe
|
|
82
|
+
* over the scene.
|
|
83
|
+
*
|
|
84
|
+
* An allowlist rather than a list of forbidden tags: the elements that carry
|
|
85
|
+
* no semantics of their own are a short, closed set, and everything else —
|
|
86
|
+
* landmarks, headings, lists, form controls, links — either already means
|
|
87
|
+
* something or is somewhere a button may not be. A target that is not on it
|
|
88
|
+
* still gets `tabindex`, so the keyboard reaches it; what it does not get is
|
|
89
|
+
* a role that is a lie about the markup.
|
|
90
|
+
*/
|
|
91
|
+
const GENERIC = new Set([
|
|
92
|
+
"div",
|
|
93
|
+
"span",
|
|
94
|
+
"p",
|
|
95
|
+
"figure",
|
|
96
|
+
"img",
|
|
97
|
+
"td",
|
|
98
|
+
"output",
|
|
99
|
+
"b",
|
|
100
|
+
"i",
|
|
101
|
+
"em",
|
|
102
|
+
"strong",
|
|
103
|
+
"small",
|
|
104
|
+
"canvas",
|
|
105
|
+
/*
|
|
106
|
+
* AND THE SHAPES, because any lens that draws a picture draws it in SVG.
|
|
107
|
+
*
|
|
108
|
+
* The allowlist was HTML only, so a map, a chart, a floor plan or a
|
|
109
|
+
* network diagram marked its regions with `data-graview-pick`, got the tab
|
|
110
|
+
* stop, and got no role at all — every target announced as nothing, which
|
|
111
|
+
* is a worse outcome than not being focusable, because a keyboard user now
|
|
112
|
+
* tabs through silent stops. ARIA permits `role="button"` on all of these,
|
|
113
|
+
* and `takesButton` still keeps `<header>`, headings and form controls
|
|
114
|
+
* safe, because the guard is an allowlist rather than a list of things to
|
|
115
|
+
* avoid.
|
|
116
|
+
*
|
|
117
|
+
* The role is the framework's half. The NAME is the view's: a shape has no
|
|
118
|
+
* text inside it, so a lens drawing in SVG sets `aria-label` on what it
|
|
119
|
+
* marks. `graview-lens` says so.
|
|
120
|
+
*/
|
|
121
|
+
"g",
|
|
122
|
+
"polygon",
|
|
123
|
+
"circle",
|
|
124
|
+
"rect",
|
|
125
|
+
"path",
|
|
126
|
+
"ellipse",
|
|
127
|
+
"polyline",
|
|
128
|
+
"line",
|
|
129
|
+
"use",
|
|
130
|
+
]);
|
|
131
|
+
function takesButton(element) {
|
|
132
|
+
/*
|
|
133
|
+
* `tagName` is upper-case on an HTML element and EXACTLY AS WRITTEN on an
|
|
134
|
+
* SVG one, so the comparison is lower-cased on both sides. `localName` is
|
|
135
|
+
* already lower-case for HTML and correct-case for SVG; these tags are all
|
|
136
|
+
* lower-case in the SVG namespace, so either answer agrees.
|
|
137
|
+
*/
|
|
138
|
+
return GENERIC.has(element.localName.toLowerCase());
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=picking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picking.js","sourceRoot":"","sources":["../src/picking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC;;;;;;;;;;;;GAYG;AAEH,+DAA+D;AAC/D,MAAM,UAAU,UAAU,CAAC,MAA0B;IACnD,OAAO,CACJ,MAA6B,EAAE,OAAO,EAAE,CAAC,qBAAqB,CAAC,EAAE,YAAY,CAC5E,mBAAmB,CACpB,IAAI,IAAI,CACV,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,GAAoC;IACjE;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC;QACzB,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAU,qBAAqB,CAAC,EAAE,CAAC;gBAC3E,IAAI,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,IAAI;oBAAE,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;gBACnF,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;oBAChE,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,IAAI,EAAE,CAAC;QACP,IAAI,OAAO,gBAAgB,KAAK,WAAW;YAAE,OAAO;QACpD,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,MAAM,KAAK,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE;YACtC,IAAI,MAAM,KAAK,CAAC;gBAAE,OAAO;YACzB,MAAM,GAAG,OAAO,qBAAqB,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,GAAG,EAAE;gBACrF,MAAM,GAAG,CAAC,CAAC;gBACX,IAAI,EAAE,CAAC;YACT,CAAC,CAAC,CAAC;YACH,IAAI,MAAM,KAAK,CAAC;gBAAE,IAAI,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QAClH,OAAO,GAAG,EAAE;YACV,KAAK,CAAC,UAAU,EAAE,CAAC;YACnB,IAAI,MAAM,KAAK,CAAC;gBAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;QACjD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;AACZ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC;IACtB,KAAK;IACL,MAAM;IACN,GAAG;IACH,QAAQ;IACR,KAAK;IACL,IAAI;IACJ,QAAQ;IACR,GAAG;IACH,GAAG;IACH,IAAI;IACJ,QAAQ;IACR,OAAO;IACP,QAAQ;IACR;;;;;;;;;;;;;;;OAeG;IACH,GAAG;IACH,SAAS;IACT,QAAQ;IACR,MAAM;IACN,MAAM;IACN,SAAS;IACT,UAAU;IACV,MAAM;IACN,KAAK;CACN,CAAC,CAAC;AAEH,SAAS,WAAW,CAAC,OAAgB;IACnC;;;;;OAKG;IACH,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;AACtD,CAAC"}
|
package/dist/plots.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type Brand } from "@graview/core";
|
|
2
|
+
import { type InterpolatedLayout } from "@graview/layout";
|
|
3
|
+
import { type ReactElement } from "react";
|
|
4
|
+
export interface Point {
|
|
5
|
+
readonly x: number;
|
|
6
|
+
readonly y: number;
|
|
7
|
+
}
|
|
8
|
+
export interface City {
|
|
9
|
+
readonly cell: number;
|
|
10
|
+
readonly originX: number;
|
|
11
|
+
readonly originY: number;
|
|
12
|
+
}
|
|
13
|
+
export interface PlotLike {
|
|
14
|
+
readonly col: number;
|
|
15
|
+
readonly row: number;
|
|
16
|
+
readonly side: number;
|
|
17
|
+
}
|
|
18
|
+
/** The four corners of a plot's tile on the canvas: back, right, front, left — clockwise from the top. */
|
|
19
|
+
export declare function tileCorners(plot: PlotLike, city: City, pan?: Point): [Point, Point, Point, Point];
|
|
20
|
+
export interface PlotsProps {
|
|
21
|
+
readonly frame: InterpolatedLayout;
|
|
22
|
+
readonly width: number;
|
|
23
|
+
readonly height: number;
|
|
24
|
+
/** The pan baked into the frame's cards, so a tile sits under its card. */
|
|
25
|
+
readonly pan: Point;
|
|
26
|
+
readonly brand?: Brand | undefined;
|
|
27
|
+
/** Which district ids are hand-placed: their kerb is dashed, as the pinned mark. */
|
|
28
|
+
readonly pinned?: ReadonlySet<string>;
|
|
29
|
+
/** The scene's own flag for a click that a drag is about to produce: a pan that ends on a tile is not a press. */
|
|
30
|
+
readonly swallowed?: {
|
|
31
|
+
readonly current: boolean;
|
|
32
|
+
};
|
|
33
|
+
onFocus?(id: string): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* One SVG for every tile, under the cards and over the fields. Aria-hidden:
|
|
37
|
+
* the district card is the thing with a name; this is the ground it stands
|
|
38
|
+
* on. The fill takes the pointer so a click on the land focuses its
|
|
39
|
+
* district, the same as a click on the card.
|
|
40
|
+
*
|
|
41
|
+
* THE GROUND IS DRAWN AT THE ORIGIN AND MOVED AS ONE. Every piece of it is
|
|
42
|
+
* computed at origin zero and the pan and origin are one translate on the
|
|
43
|
+
* group, so a pan or a tween changes one attribute. Each plot is its own
|
|
44
|
+
* memoised tile whose village is kept for as long as that plot and its
|
|
45
|
+
* members are the same, so dragging one district redraws that district and
|
|
46
|
+
* the roads, not every building in the city on every frame.
|
|
47
|
+
*/
|
|
48
|
+
export declare function Plots({ frame, width, height, pan, brand, pinned, swallowed, onFocus }: PlotsProps): ReactElement | null;
|
|
49
|
+
/** The most buildings a plot of this side holds: a sub-lattice of side+1 to a side, minus the square in the middle. */
|
|
50
|
+
export declare function villageCap(side: number): number;
|
|
51
|
+
/** A stable number in [0, 1) from an id, so a village is not a barracks and does not reshuffle on every render. */
|
|
52
|
+
export declare function heightOf(id: string): number;
|
|
53
|
+
export interface Building {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
/** The foot, in lattice units from the plot's own corner. */
|
|
56
|
+
readonly col: number;
|
|
57
|
+
readonly row: number;
|
|
58
|
+
/** How wide a building is on the ground, in lattice units. */
|
|
59
|
+
readonly footprint: number;
|
|
60
|
+
/** How tall, as a fraction of its footprint. */
|
|
61
|
+
readonly height: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* WHERE THE MEMBERS STAND. One building per member on the plot's own
|
|
65
|
+
* sub-lattice, back to front so the near ones are drawn last; the middle
|
|
66
|
+
* of the plot is the village square, where the nameplate and the kind's
|
|
67
|
+
* landmark stand, so no building is under them. Past the cap the rest are
|
|
68
|
+
* a number on the kerb.
|
|
69
|
+
*/
|
|
70
|
+
export declare function villageOf(plot: PlotLike, memberIds: readonly string[]): {
|
|
71
|
+
readonly buildings: readonly Building[];
|
|
72
|
+
readonly rest: number;
|
|
73
|
+
};
|
|
74
|
+
/** The three faces of one building on the canvas, from its foot cell. */
|
|
75
|
+
export declare function buildingFaces(building: Building, city: City, pan: Point): {
|
|
76
|
+
readonly roof: string;
|
|
77
|
+
readonly left: string;
|
|
78
|
+
readonly right: string;
|
|
79
|
+
readonly top: Point;
|
|
80
|
+
};
|
|
81
|
+
/** Lattice coordinates of a canvas point: the isometric map run backwards. */
|
|
82
|
+
export declare function toLattice(point: Point, city: City, pan: Point): {
|
|
83
|
+
readonly col: number;
|
|
84
|
+
readonly row: number;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* THE STREETS. Plots stand at multiples of BLOCK and never fill their
|
|
88
|
+
* block, so between every block there is a gutter — a row and a column
|
|
89
|
+
* of cells nothing stands on. A road runs along them: out of its plot to
|
|
90
|
+
* the gutter beside its block, along that gutter, up the gutter beside
|
|
91
|
+
* the other block, and in. Every leg is a lattice line (one coordinate
|
|
92
|
+
* held), no leg crosses a third plot, and the whole city reads as
|
|
93
|
+
* villages on a street grid rather than lines drawn over it.
|
|
94
|
+
*/
|
|
95
|
+
export declare function streetPoints(from: PlotLike, to: PlotLike): {
|
|
96
|
+
readonly col: number;
|
|
97
|
+
readonly row: number;
|
|
98
|
+
}[];
|
|
99
|
+
/**
|
|
100
|
+
* A ROAD FROM KERB TO KERB: the street between two plots, with the run
|
|
101
|
+
* inside either plot cut away, so the road starts at one kerb and ends at
|
|
102
|
+
* the other rather than diving under the buildings. Sampled and bisected,
|
|
103
|
+
* the same way a connector is clipped against a box.
|
|
104
|
+
*/
|
|
105
|
+
export declare function roadBetween(from: PlotLike, to: PlotLike, city: City, pan: Point): Point[];
|
|
106
|
+
//# sourceMappingURL=plots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plots.d.ts","sourceRoot":"","sources":["../src/plots.tsx"],"names":[],"mappings":"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"}
|
package/dist/plots.js
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { BLOCK, hueFor, roadsOf, toIso } from "@graview/core";
|
|
3
|
+
import { kindOfCard } from "@graview/layout";
|
|
4
|
+
import { memo, useCallback, useMemo, useRef } from "react";
|
|
5
|
+
import { useGraview } from "./context.js";
|
|
6
|
+
import { useFlagged } from "./hooks.js";
|
|
7
|
+
/** The four corners of a plot's tile on the canvas: back, right, front, left — clockwise from the top. */
|
|
8
|
+
export function tileCorners(plot, city, pan = { x: 0, y: 0 }) {
|
|
9
|
+
const at = (col, row) => {
|
|
10
|
+
const iso = toIso(col, row, city.cell);
|
|
11
|
+
return { x: city.originX + pan.x + iso.x, y: city.originY + pan.y + iso.y };
|
|
12
|
+
};
|
|
13
|
+
return [
|
|
14
|
+
at(plot.col, plot.row),
|
|
15
|
+
at(plot.col + plot.side, plot.row),
|
|
16
|
+
at(plot.col + plot.side, plot.row + plot.side),
|
|
17
|
+
at(plot.col, plot.row + plot.side),
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
const points = (corners) => corners.map((p) => `${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
|
|
21
|
+
/**
|
|
22
|
+
* One SVG for every tile, under the cards and over the fields. Aria-hidden:
|
|
23
|
+
* the district card is the thing with a name; this is the ground it stands
|
|
24
|
+
* on. The fill takes the pointer so a click on the land focuses its
|
|
25
|
+
* district, the same as a click on the card.
|
|
26
|
+
*
|
|
27
|
+
* THE GROUND IS DRAWN AT THE ORIGIN AND MOVED AS ONE. Every piece of it is
|
|
28
|
+
* computed at origin zero and the pan and origin are one translate on the
|
|
29
|
+
* group, so a pan or a tween changes one attribute. Each plot is its own
|
|
30
|
+
* memoised tile whose village is kept for as long as that plot and its
|
|
31
|
+
* members are the same, so dragging one district redraws that district and
|
|
32
|
+
* the roads, not every building in the city on every frame.
|
|
33
|
+
*/
|
|
34
|
+
export function Plots({ frame, width, height, pan, brand, pinned, swallowed, onFocus }) {
|
|
35
|
+
const { selection, store, emphasis } = useGraview();
|
|
36
|
+
const flagged = useFlagged();
|
|
37
|
+
const city = frame.city;
|
|
38
|
+
const tiles = frame.nodes.filter((node) => node.plot !== undefined && Math.round(node.plane) === 2);
|
|
39
|
+
const cell = city?.cell ?? 0;
|
|
40
|
+
// The callback is read when the tile is pressed, so a new one each render redraws nothing.
|
|
41
|
+
const focus = useRef(onFocus);
|
|
42
|
+
focus.current = onFocus;
|
|
43
|
+
const press = useCallback((id) => {
|
|
44
|
+
if (!focus.current || swallowed?.current)
|
|
45
|
+
return false;
|
|
46
|
+
focus.current(id);
|
|
47
|
+
return true;
|
|
48
|
+
}, [swallowed]);
|
|
49
|
+
/*
|
|
50
|
+
* THE ROADS, one per pair of plots joined by any declared edge
|
|
51
|
+
* (`roadsOf`), kerb to kerb along the gutters. They depend on every
|
|
52
|
+
* plot, so they are routed again when any plot moves — and only then.
|
|
53
|
+
*/
|
|
54
|
+
const plotsSignature = `${cell}|${tiles.map((node) => `${node.id}:${node.plot.col},${node.plot.row},${node.plot.side}`).join(";")}`;
|
|
55
|
+
const roads = useMemo(() => {
|
|
56
|
+
if (!city)
|
|
57
|
+
return [];
|
|
58
|
+
const at0 = { cell, originX: 0, originY: 0 };
|
|
59
|
+
const plotsByKind = new Map();
|
|
60
|
+
for (const node of tiles) {
|
|
61
|
+
const kind = kindOfCard(node.id);
|
|
62
|
+
if (kind !== null && node.plot)
|
|
63
|
+
plotsByKind.set(kind, node.plot);
|
|
64
|
+
}
|
|
65
|
+
return roadsOf(store.schema, plotsByKind).map((road) => ({
|
|
66
|
+
...road,
|
|
67
|
+
d: roadBetween(plotsByKind.get(road.from), plotsByKind.get(road.to), at0, { x: 0, y: 0 })
|
|
68
|
+
.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`)
|
|
69
|
+
.join(" "),
|
|
70
|
+
}));
|
|
71
|
+
// `plotsSignature` stands for the tiles and the cell.
|
|
72
|
+
}, [plotsSignature, store.schema]);
|
|
73
|
+
/* EACH PLOT'S GROUND, kept while that plot and its members are unchanged. */
|
|
74
|
+
const drawn = useRef(new Map());
|
|
75
|
+
const kept = new Map();
|
|
76
|
+
for (const node of tiles) {
|
|
77
|
+
const members = node.aggregate?.memberIds ?? [];
|
|
78
|
+
const key = `${cell}|${node.plot.col},${node.plot.row},${node.plot.side}|${members.join(",")}`;
|
|
79
|
+
const held = drawn.current.get(node.id);
|
|
80
|
+
if (held && held.key === key) {
|
|
81
|
+
kept.set(node.id, held);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const at0 = { cell, originX: 0, originY: 0 };
|
|
85
|
+
const none = { x: 0, y: 0 };
|
|
86
|
+
const { buildings, rest } = villageOf(node.plot, members);
|
|
87
|
+
const corners = tileCorners(node.plot, at0, none);
|
|
88
|
+
kept.set(node.id, {
|
|
89
|
+
key,
|
|
90
|
+
tile: points(corners),
|
|
91
|
+
front: corners[2],
|
|
92
|
+
rest,
|
|
93
|
+
buildings: buildings.map((building) => ({ id: building.id, ...buildingFaces(building, at0, none) })),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
drawn.current = kept;
|
|
97
|
+
if (!city)
|
|
98
|
+
return null;
|
|
99
|
+
const style = { position: "absolute", left: 0, top: 0, pointerEvents: "none", overflow: "visible" };
|
|
100
|
+
const chosenKey = selection.join("\n");
|
|
101
|
+
const flaggedKey = flagged.join("\n");
|
|
102
|
+
return (_jsx("svg", { className: "graview-plots", "aria-hidden": "true", "data-graview-world": "", width: width, height: height, style: style, "data-graview-plots": tiles.length, children: _jsxs("g", { transform: `translate(${(city.originX + pan.x).toFixed(1)} ${(city.originY + pan.y).toFixed(1)})`, children: [_jsx("g", { className: "graview-roads", "data-graview-roads": roads.length, children: roads.map((road) => road.d.includes("L") ? (_jsxs("g", { className: "graview-road", "data-graview-road": road.edges.join(","), "data-graview-lit": emphasis !== null && road.edges.includes(emphasis) ? "" : undefined, children: [_jsx("path", { className: "graview-road-edge", d: road.d }), _jsx("path", { className: "graview-road-bed", d: road.d })] }, `${road.from}|${road.to}`)) : null) }), tiles.map((node) => (_jsx(PlotTile, { id: node.id, hue: Math.round(hueFor(node.kind, brand?.accents)), drawing: kept.get(node.id), pinned: pinned?.has(node.id) ?? false, chosenKey: chosenKey, flaggedKey: flaggedKey, press: press }, node.id)))] }) }));
|
|
103
|
+
}
|
|
104
|
+
const PlotTile = memo(function PlotTile({ id, hue, drawing, pinned, chosenKey, flaggedKey, press, }) {
|
|
105
|
+
const chosen = new Set(chosenKey.split("\n"));
|
|
106
|
+
const broken = new Set(flaggedKey.split("\n"));
|
|
107
|
+
return (_jsxs("g", { className: "graview-plot", "data-graview-plot": id, "data-graview-pinned": pinned ? "" : undefined, style: { ["--graview-hue"]: hue }, children: [_jsx("polygon", { className: "graview-plot-tile", points: drawing.tile, onClick: (event) => {
|
|
108
|
+
if (press(id))
|
|
109
|
+
event.stopPropagation();
|
|
110
|
+
} }), drawing.buildings.length > 0 ? (_jsxs("g", { className: "graview-village", "data-graview-village": drawing.buildings.length, "data-graview-rest": drawing.rest || undefined, children: [drawing.buildings.map((faces) => (_jsxs("g", { className: "graview-building", "data-graview-building": faces.id, "data-graview-flagged": broken.has(faces.id) ? "" : undefined, "data-graview-selected": chosen.has(faces.id) ? "" : undefined, children: [_jsx("polygon", { className: "graview-iso-left", points: faces.left }), _jsx("polygon", { className: "graview-iso-right", points: faces.right }), _jsx("polygon", { className: "graview-iso-roof", points: faces.roof })] }, faces.id))), drawing.rest > 0 ? (_jsxs("text", { className: "graview-village-rest", x: drawing.front.x, y: drawing.front.y - 4, textAnchor: "middle", children: ["+", drawing.rest] })) : null] })) : null] }));
|
|
111
|
+
});
|
|
112
|
+
/* ------------------------------------------------------------ the village */
|
|
113
|
+
/** The most buildings a plot of this side holds: a sub-lattice of side+1 to a side, minus the square in the middle. */
|
|
114
|
+
export function villageCap(side) {
|
|
115
|
+
const n = side + 1;
|
|
116
|
+
return n * n - squareCells(n).length;
|
|
117
|
+
}
|
|
118
|
+
/** The sub-cells of an n×n sub-lattice that make the village square: the middle one, or the middle four; a 2×2 has no room for one. */
|
|
119
|
+
function squareCells(n) {
|
|
120
|
+
if (n < 3)
|
|
121
|
+
return [];
|
|
122
|
+
if (n % 2 === 1) {
|
|
123
|
+
const mid = (n - 1) / 2;
|
|
124
|
+
return [[mid, mid]];
|
|
125
|
+
}
|
|
126
|
+
const a = n / 2 - 1;
|
|
127
|
+
const b = n / 2;
|
|
128
|
+
return [
|
|
129
|
+
[a, a],
|
|
130
|
+
[b, a],
|
|
131
|
+
[a, b],
|
|
132
|
+
[b, b],
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
/** A stable number in [0, 1) from an id, so a village is not a barracks and does not reshuffle on every render. */
|
|
136
|
+
export function heightOf(id) {
|
|
137
|
+
let h = 2166136261;
|
|
138
|
+
for (let i = 0; i < id.length; i++)
|
|
139
|
+
h = Math.imul(h ^ id.charCodeAt(i), 16777619);
|
|
140
|
+
return ((h >>> 0) % 1000) / 1000;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* WHERE THE MEMBERS STAND. One building per member on the plot's own
|
|
144
|
+
* sub-lattice, back to front so the near ones are drawn last; the middle
|
|
145
|
+
* of the plot is the village square, where the nameplate and the kind's
|
|
146
|
+
* landmark stand, so no building is under them. Past the cap the rest are
|
|
147
|
+
* a number on the kerb.
|
|
148
|
+
*/
|
|
149
|
+
export function villageOf(plot, memberIds) {
|
|
150
|
+
const n = plot.side + 1;
|
|
151
|
+
const square = new Set(squareCells(n).map(([c, r]) => `${c},${r}`));
|
|
152
|
+
const pitch = plot.side / n;
|
|
153
|
+
const cells = [];
|
|
154
|
+
for (let r = 0; r < n; r++)
|
|
155
|
+
for (let c = 0; c < n; c++)
|
|
156
|
+
if (!square.has(`${c},${r}`))
|
|
157
|
+
cells.push([c, r]);
|
|
158
|
+
// Back to front: a smaller col+row is further from the viewer on a 2:1 lattice.
|
|
159
|
+
cells.sort((a, b) => a[0] + a[1] - (b[0] + b[1]) || a[0] - b[0]);
|
|
160
|
+
const shown = memberIds.slice(0, cells.length);
|
|
161
|
+
const buildings = shown.map((id, i) => {
|
|
162
|
+
const [c, r] = cells[i];
|
|
163
|
+
return {
|
|
164
|
+
id,
|
|
165
|
+
col: plot.col + (c + 0.5) * pitch,
|
|
166
|
+
row: plot.row + (r + 0.5) * pitch,
|
|
167
|
+
footprint: pitch * 0.62,
|
|
168
|
+
height: 0.55 + heightOf(id) * 0.7,
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
return { buildings, rest: Math.max(0, memberIds.length - shown.length) };
|
|
172
|
+
}
|
|
173
|
+
/** The three faces of one building on the canvas, from its foot cell. */
|
|
174
|
+
export function buildingFaces(building, city, pan) {
|
|
175
|
+
const half = building.footprint / 2;
|
|
176
|
+
const at = (col, row, lift = 0) => {
|
|
177
|
+
const iso = toIso(col, row, city.cell);
|
|
178
|
+
return { x: city.originX + pan.x + iso.x, y: city.originY + pan.y + iso.y - lift };
|
|
179
|
+
};
|
|
180
|
+
const rise = building.footprint * city.cell * 0.5 * building.height;
|
|
181
|
+
const back = at(building.col - half, building.row - half, rise);
|
|
182
|
+
const right = at(building.col + half, building.row - half, rise);
|
|
183
|
+
const front = at(building.col + half, building.row + half, rise);
|
|
184
|
+
const left = at(building.col - half, building.row + half, rise);
|
|
185
|
+
const frontFoot = at(building.col + half, building.row + half);
|
|
186
|
+
const leftFoot = at(building.col - half, building.row + half);
|
|
187
|
+
const rightFoot = at(building.col + half, building.row - half);
|
|
188
|
+
return {
|
|
189
|
+
roof: points([back, right, front, left]),
|
|
190
|
+
left: points([left, front, frontFoot, leftFoot]),
|
|
191
|
+
right: points([front, right, rightFoot, frontFoot]),
|
|
192
|
+
top: back,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/* --------------------------------------------------------------- the roads */
|
|
196
|
+
/** Lattice coordinates of a canvas point: the isometric map run backwards. */
|
|
197
|
+
export function toLattice(point, city, pan) {
|
|
198
|
+
const x = point.x - city.originX - pan.x;
|
|
199
|
+
const y = point.y - city.originY - pan.y;
|
|
200
|
+
return { col: x / city.cell + (2 * y) / city.cell, row: (2 * y) / city.cell - x / city.cell };
|
|
201
|
+
}
|
|
202
|
+
const insidePlot = (point, plot, city, pan) => {
|
|
203
|
+
const { col, row } = toLattice(point, city, pan);
|
|
204
|
+
return col >= plot.col && col <= plot.col + plot.side && row >= plot.row && row <= plot.row + plot.side;
|
|
205
|
+
};
|
|
206
|
+
const lerp = (a, b, t) => ({ x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t });
|
|
207
|
+
/**
|
|
208
|
+
* THE STREETS. Plots stand at multiples of BLOCK and never fill their
|
|
209
|
+
* block, so between every block there is a gutter — a row and a column
|
|
210
|
+
* of cells nothing stands on. A road runs along them: out of its plot to
|
|
211
|
+
* the gutter beside its block, along that gutter, up the gutter beside
|
|
212
|
+
* the other block, and in. Every leg is a lattice line (one coordinate
|
|
213
|
+
* held), no leg crosses a third plot, and the whole city reads as
|
|
214
|
+
* villages on a street grid rather than lines drawn over it.
|
|
215
|
+
*/
|
|
216
|
+
export function streetPoints(from, to) {
|
|
217
|
+
const ca = from.col + from.side / 2;
|
|
218
|
+
const ra = from.row + from.side / 2;
|
|
219
|
+
const cb = to.col + to.side / 2;
|
|
220
|
+
const rb = to.row + to.side / 2;
|
|
221
|
+
const blockRow = (plot) => Math.floor(plot.row / BLOCK);
|
|
222
|
+
const blockCol = (plot) => Math.floor(plot.col / BLOCK);
|
|
223
|
+
const ja = blockRow(from);
|
|
224
|
+
const jb = blockRow(to);
|
|
225
|
+
const ia = blockCol(from);
|
|
226
|
+
const ib = blockCol(to);
|
|
227
|
+
// The gutter row beside `from`, on the side `to` lies; the gutter column beside `to`, on the side `from` lies.
|
|
228
|
+
const gr = jb > ja ? ja * BLOCK + BLOCK - 0.5 : jb < ja ? ja * BLOCK - 0.5 : ja * BLOCK + BLOCK - 0.5;
|
|
229
|
+
const gc = ib > ia ? ib * BLOCK - 0.5 : ib < ia ? ib * BLOCK + BLOCK - 0.5 : ib * BLOCK - 0.5;
|
|
230
|
+
const raw = [
|
|
231
|
+
{ col: ca, row: ra },
|
|
232
|
+
{ col: ca, row: gr },
|
|
233
|
+
{ col: gc, row: gr },
|
|
234
|
+
{ col: gc, row: rb },
|
|
235
|
+
{ col: cb, row: rb },
|
|
236
|
+
];
|
|
237
|
+
// Drop a leg of no length, and a middle point that lies on the line of its neighbours.
|
|
238
|
+
const out = [];
|
|
239
|
+
for (const p of raw) {
|
|
240
|
+
const last = out[out.length - 1];
|
|
241
|
+
if (last && Math.abs(last.col - p.col) < 1e-9 && Math.abs(last.row - p.row) < 1e-9)
|
|
242
|
+
continue;
|
|
243
|
+
out.push(p);
|
|
244
|
+
}
|
|
245
|
+
for (let i = out.length - 2; i > 0; i--) {
|
|
246
|
+
const a = out[i - 1];
|
|
247
|
+
const b = out[i];
|
|
248
|
+
const c = out[i + 1];
|
|
249
|
+
const sameCol = Math.abs(a.col - b.col) < 1e-9 && Math.abs(b.col - c.col) < 1e-9;
|
|
250
|
+
const sameRow = Math.abs(a.row - b.row) < 1e-9 && Math.abs(b.row - c.row) < 1e-9;
|
|
251
|
+
if (sameCol || sameRow)
|
|
252
|
+
out.splice(i, 1);
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* A ROAD FROM KERB TO KERB: the street between two plots, with the run
|
|
258
|
+
* inside either plot cut away, so the road starts at one kerb and ends at
|
|
259
|
+
* the other rather than diving under the buildings. Sampled and bisected,
|
|
260
|
+
* the same way a connector is clipped against a box.
|
|
261
|
+
*/
|
|
262
|
+
export function roadBetween(from, to, city, pan) {
|
|
263
|
+
const points = streetPoints(from, to).map((p) => {
|
|
264
|
+
const iso = toIso(p.col, p.row, city.cell);
|
|
265
|
+
return { x: city.originX + pan.x + iso.x, y: city.originY + pan.y + iso.y };
|
|
266
|
+
});
|
|
267
|
+
// Walk out of `from`: the first point on the polyline outside its plot.
|
|
268
|
+
const out = [];
|
|
269
|
+
let started = false;
|
|
270
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
271
|
+
const a = points[i];
|
|
272
|
+
const b = points[i + 1];
|
|
273
|
+
if (!started) {
|
|
274
|
+
if (insidePlot(b, from, city, pan))
|
|
275
|
+
continue;
|
|
276
|
+
let lo = 0;
|
|
277
|
+
let hi = 1;
|
|
278
|
+
for (let k = 0; k < 12; k++) {
|
|
279
|
+
const mid = (lo + hi) / 2;
|
|
280
|
+
if (insidePlot(lerp(a, b, mid), from, city, pan))
|
|
281
|
+
lo = mid;
|
|
282
|
+
else
|
|
283
|
+
hi = mid;
|
|
284
|
+
}
|
|
285
|
+
out.push(lerp(a, b, hi));
|
|
286
|
+
started = true;
|
|
287
|
+
}
|
|
288
|
+
// Walk into `to`: the first point on the polyline inside its plot.
|
|
289
|
+
if (insidePlot(b, to, city, pan)) {
|
|
290
|
+
let lo = 0;
|
|
291
|
+
let hi = 1;
|
|
292
|
+
for (let k = 0; k < 12; k++) {
|
|
293
|
+
const mid = (lo + hi) / 2;
|
|
294
|
+
if (insidePlot(lerp(a, b, mid), to, city, pan))
|
|
295
|
+
hi = mid;
|
|
296
|
+
else
|
|
297
|
+
lo = mid;
|
|
298
|
+
}
|
|
299
|
+
out.push(lerp(a, b, lo));
|
|
300
|
+
return out;
|
|
301
|
+
}
|
|
302
|
+
out.push(b);
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=plots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plots.js","sourceRoot":"","sources":["../src/plots.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE POINTER OVER THE SCENE, for whoever asks — and NOBODY listening
|
|
3
|
+
* costs nothing.
|
|
4
|
+
*
|
|
5
|
+
* A quiet scene must not run a listener on every pointer move on the off
|
|
6
|
+
* chance something wants it. So this is a store with a subscriber count:
|
|
7
|
+
* the scene attaches its listener when the first subscriber arrives and
|
|
8
|
+
* detaches it when the last one leaves. `useScenePointer` reads it through
|
|
9
|
+
* `useSyncExternalStore`, which is what makes the count exact.
|
|
10
|
+
*/
|
|
11
|
+
export interface ScenePoint {
|
|
12
|
+
/** In scene coordinates — the same space the layout places things in. */
|
|
13
|
+
readonly x: number;
|
|
14
|
+
readonly y: number;
|
|
15
|
+
}
|
|
16
|
+
export interface PointerStore {
|
|
17
|
+
subscribe(listener: () => void): () => void;
|
|
18
|
+
snapshot(): ScenePoint | null;
|
|
19
|
+
/** The scene calls this; nobody else does. */
|
|
20
|
+
set(point: ScenePoint | null): void;
|
|
21
|
+
/** How many are listening right now. */
|
|
22
|
+
readonly listeners: number;
|
|
23
|
+
/** Told when the count crosses zero either way — attach or detach. */
|
|
24
|
+
onActive(listener: (active: boolean) => void): () => void;
|
|
25
|
+
}
|
|
26
|
+
export declare function createPointerStore(): PointerStore;
|
|
27
|
+
//# sourceMappingURL=pointer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pointer.d.ts","sourceRoot":"","sources":["../src/pointer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5C,QAAQ,IAAI,UAAU,GAAG,IAAI,CAAC;IAC9B,8CAA8C;IAC9C,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC;IACpC,wCAAwC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC3D;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAiCjD"}
|