@graview/react 0.1.10 → 0.1.14
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/dist/activity.d.ts +0 -30
- package/dist/activity.d.ts.map +1 -1
- package/dist/activity.js +0 -54
- package/dist/activity.js.map +1 -1
- package/dist/attention.d.ts +33 -0
- package/dist/attention.d.ts.map +1 -0
- package/dist/attention.js +60 -0
- package/dist/attention.js.map +1 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +13 -4
- package/dist/context.js.map +1 -1
- package/dist/drawing.d.ts +25 -0
- package/dist/drawing.d.ts.map +1 -0
- package/dist/drawing.js +22 -0
- package/dist/drawing.js.map +1 -0
- package/dist/drawn.d.ts +21 -0
- package/dist/drawn.d.ts.map +1 -1
- package/dist/drawn.js +40 -1
- package/dist/drawn.js.map +1 -1
- package/dist/edge-signs.js +2 -1
- package/dist/edge-signs.js.map +1 -1
- package/dist/editable-fields.d.ts +16 -0
- package/dist/editable-fields.d.ts.map +1 -0
- package/dist/editable-fields.js +23 -0
- package/dist/editable-fields.js.map +1 -0
- package/dist/emphasis.d.ts +25 -0
- package/dist/emphasis.d.ts.map +1 -0
- package/dist/emphasis.js +84 -0
- package/dist/emphasis.js.map +1 -0
- package/dist/error-report.d.ts +15 -0
- package/dist/error-report.d.ts.map +1 -0
- package/dist/error-report.js +4 -0
- package/dist/error-report.js.map +1 -0
- package/dist/hooks.d.ts +7 -68
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +5 -281
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +16 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -6
- package/dist/index.js.map +1 -1
- package/dist/occupants.js +1 -1
- package/dist/occupants.js.map +1 -1
- package/dist/picked.d.ts +3 -0
- package/dist/picked.d.ts.map +1 -0
- package/dist/picked.js +9 -0
- package/dist/picked.js.map +1 -0
- package/dist/picking.d.ts +7 -2
- package/dist/picking.d.ts.map +1 -1
- package/dist/picking.js +17 -3
- package/dist/picking.js.map +1 -1
- package/dist/placement.d.ts +59 -0
- package/dist/placement.d.ts.map +1 -0
- package/dist/placement.js +85 -0
- package/dist/placement.js.map +1 -0
- package/dist/plots.d.ts +4 -3
- package/dist/plots.d.ts.map +1 -1
- package/dist/plots.js +4 -3
- package/dist/plots.js.map +1 -1
- package/dist/presence.d.ts +0 -57
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +2 -85
- package/dist/presence.js.map +1 -1
- package/dist/provider.d.ts +12 -9
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +10 -6
- package/dist/provider.js.map +1 -1
- package/dist/resolved-view.d.ts.map +1 -1
- package/dist/resolved-view.js +2 -1
- package/dist/resolved-view.js.map +1 -1
- package/dist/scene-camera.js +1 -1
- package/dist/scene-camera.js.map +1 -1
- package/dist/scene-lines.d.ts.map +1 -1
- package/dist/scene-lines.js +39 -0
- package/dist/scene-lines.js.map +1 -1
- package/dist/scene-root.d.ts.map +1 -1
- package/dist/scene-root.js +130 -117
- package/dist/scene-root.js.map +1 -1
- package/dist/url-sync.d.ts +32 -0
- package/dist/url-sync.d.ts.map +1 -0
- package/dist/url-sync.js +205 -0
- package/dist/url-sync.js.map +1 -0
- package/dist/view-boundary.d.ts +2 -12
- package/dist/view-boundary.d.ts.map +1 -1
- package/dist/view-boundary.js +3 -3
- package/dist/view-boundary.js.map +1 -1
- package/dist/view-host.d.ts +2 -2
- package/dist/view-host.d.ts.map +1 -1
- package/dist/view-host.js +11 -7
- package/dist/view-host.js.map +1 -1
- package/package.json +9 -5
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AnySchema } from "@graview/core";
|
|
2
|
+
import { type EditableField } from "@graview/tools/edit";
|
|
3
|
+
/**
|
|
4
|
+
* The fields of a node that can be changed where they are shown, and the way
|
|
5
|
+
* to change one.
|
|
6
|
+
*
|
|
7
|
+
* `commit` runs the mutation the framework found, with the author set to a
|
|
8
|
+
* person — so an in-place edit lands in the op log, can be undone, and is
|
|
9
|
+
* judged by the invariants exactly like an edit made from the actions strip.
|
|
10
|
+
* There is no second write path.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useEditableFields<S extends AnySchema>(id: string | null): {
|
|
13
|
+
readonly fields: readonly EditableField[];
|
|
14
|
+
commit: (field: EditableField, value: unknown, rest?: Record<string, unknown>) => void;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=editable-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editable-fields.d.ts","sourceRoot":"","sources":["../src/editable-fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzE;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,SAAS,EACnD,EAAE,EAAE,MAAM,GAAG,IAAI,GAChB;IACD,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACxF,CAkBA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { editableFields } from "@graview/tools/edit";
|
|
2
|
+
import { useCallback, useMemo } from "react";
|
|
3
|
+
import { useGraph, useGraview } from "./context.js";
|
|
4
|
+
/**
|
|
5
|
+
* The fields of a node that can be changed where they are shown, and the way
|
|
6
|
+
* to change one.
|
|
7
|
+
*
|
|
8
|
+
* `commit` runs the mutation the framework found, with the author set to a
|
|
9
|
+
* person — so an in-place edit lands in the op log, can be undone, and is
|
|
10
|
+
* judged by the invariants exactly like an edit made from the actions strip.
|
|
11
|
+
* There is no second write path.
|
|
12
|
+
*/
|
|
13
|
+
export function useEditableFields(id) {
|
|
14
|
+
const { store, principal } = useGraview();
|
|
15
|
+
const nodes = useGraph();
|
|
16
|
+
const fields = useMemo(() => (id === null ? [] : editableFields(store, id)), [store, id, nodes]);
|
|
17
|
+
const commit = useCallback((field, value, rest = {}) => {
|
|
18
|
+
const call = field.call(value);
|
|
19
|
+
store.apply({ name: call.name, args: { ...call.args, ...rest } }, { author: principal });
|
|
20
|
+
}, [store, principal]);
|
|
21
|
+
return { fields, commit };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=editable-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editable-fields.js","sourceRoot":"","sources":["../src/editable-fields.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,EAAiB;IAKjB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,UAAU,EAAK,CAAC;IAC7C,MAAM,KAAK,GAAG,QAAQ,EAAK,CAAC;IAC5B,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EACpD,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CACnB,CAAC;IACF,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,KAAoB,EAAE,KAAc,EAAE,OAAgC,EAAE,EAAE,EAAE;QAC3E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,CAAC,KAAK,CACT,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,EACpD,EAAE,MAAM,EAAE,SAAS,EAAE,CACtB,CAAC;IACJ,CAAC,EACD,CAAC,KAAK,EAAE,SAAS,CAAC,CACnB,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Ids implicated in some current violation, for marking them in place. */
|
|
2
|
+
export declare function useFlagged(): readonly string[];
|
|
3
|
+
/**
|
|
4
|
+
* Everything the selection reaches: the selected nodes, plus everything one
|
|
5
|
+
* edge away from them.
|
|
6
|
+
*
|
|
7
|
+
* Selecting a person and having the week sit there unchanged is the same
|
|
8
|
+
* failure as clicking an event and getting an empty plane — the graph knows
|
|
9
|
+
* which five events that person is in, and the calendar is right there
|
|
10
|
+
* drawing all eighteen of them. A view that receives this can say so in its
|
|
11
|
+
* own idiom: a calendar lights up the spans, a roster rings the chips.
|
|
12
|
+
*
|
|
13
|
+
* Empty when nothing is selected, which every view must read as "no
|
|
14
|
+
* emphasis" rather than "nothing is related".
|
|
15
|
+
*/
|
|
16
|
+
export declare function useImplicated(): readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* What the SELECTION alone reaches — `useImplicated` without the search.
|
|
19
|
+
* For the one reading that must not confuse the two: a district's "tied"
|
|
20
|
+
* count is about what you picked, not what you typed.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useReached(): readonly string[];
|
|
23
|
+
/** Stands in the implicated set when a search found nothing, so every view dims. */
|
|
24
|
+
export declare const NOTHING_FOUND = "search:nothing";
|
|
25
|
+
//# sourceMappingURL=emphasis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emphasis.d.ts","sourceRoot":"","sources":["../src/emphasis.ts"],"names":[],"mappings":"AAUA,2EAA2E;AAC3E,wBAAgB,UAAU,IAAI,SAAS,MAAM,EAAE,CAM9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,IAAI,SAAS,MAAM,EAAE,CAgBjD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,SAAS,MAAM,EAAE,CA0B9C;AAED,oFAAoF;AACpF,eAAO,MAAM,aAAa,mBAAmB,CAAC"}
|
package/dist/emphasis.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useFound, useGraph, useGraview } from "./context.js";
|
|
3
|
+
import { useViolations } from "./hooks.js";
|
|
4
|
+
/*
|
|
5
|
+
* WHAT A VIEW LIGHTS AND DIMS: the flagged, the reached and the implicated.
|
|
6
|
+
* A file of its own, apart from the hooks the frame reads before anything is
|
|
7
|
+
* drawn, so a page that has drawn no view yet carries none of it.
|
|
8
|
+
*/
|
|
9
|
+
/** Ids implicated in some current violation, for marking them in place. */
|
|
10
|
+
export function useFlagged() {
|
|
11
|
+
const violations = useViolations();
|
|
12
|
+
return useMemo(() => [...new Set(violations.flatMap((violation) => violation.nodeIds))], [violations]);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Everything the selection reaches: the selected nodes, plus everything one
|
|
16
|
+
* edge away from them.
|
|
17
|
+
*
|
|
18
|
+
* Selecting a person and having the week sit there unchanged is the same
|
|
19
|
+
* failure as clicking an event and getting an empty plane — the graph knows
|
|
20
|
+
* which five events that person is in, and the calendar is right there
|
|
21
|
+
* drawing all eighteen of them. A view that receives this can say so in its
|
|
22
|
+
* own idiom: a calendar lights up the spans, a roster rings the chips.
|
|
23
|
+
*
|
|
24
|
+
* Empty when nothing is selected, which every view must read as "no
|
|
25
|
+
* emphasis" rather than "nothing is related".
|
|
26
|
+
*/
|
|
27
|
+
export function useImplicated() {
|
|
28
|
+
const reachedBySelection = useReached();
|
|
29
|
+
const found = useFound();
|
|
30
|
+
/*
|
|
31
|
+
* AND WHAT THE WORDS FIND. A search lights its hits in whatever picture
|
|
32
|
+
* is open, through the same set every view already dims by — so a lens
|
|
33
|
+
* learns nothing new to take part. Words that find nothing dim it all:
|
|
34
|
+
* the one id nothing is called keeps the set non-empty.
|
|
35
|
+
*/
|
|
36
|
+
return useMemo(() => {
|
|
37
|
+
if (!found)
|
|
38
|
+
return reachedBySelection;
|
|
39
|
+
// Every match, not the strip's capped index: a real hit is never drawn dimmed.
|
|
40
|
+
const hits = found.matched;
|
|
41
|
+
if (hits.length === 0 && reachedBySelection.length === 0)
|
|
42
|
+
return [NOTHING_FOUND];
|
|
43
|
+
return [...new Set([...reachedBySelection, ...hits])];
|
|
44
|
+
}, [found, reachedBySelection]);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* What the SELECTION alone reaches — `useImplicated` without the search.
|
|
48
|
+
* For the one reading that must not confuse the two: a district's "tied"
|
|
49
|
+
* count is about what you picked, not what you typed.
|
|
50
|
+
*/
|
|
51
|
+
export function useReached() {
|
|
52
|
+
const { store, selection } = useGraview();
|
|
53
|
+
const nodes = useGraph();
|
|
54
|
+
return useMemo(() => {
|
|
55
|
+
if (selection.length === 0)
|
|
56
|
+
return [];
|
|
57
|
+
const chosen = new Set(selection);
|
|
58
|
+
const reached = new Set(chosen);
|
|
59
|
+
for (const edge of store.graph.allEdges()) {
|
|
60
|
+
if (chosen.has(edge.from))
|
|
61
|
+
reached.add(edge.to);
|
|
62
|
+
if (chosen.has(edge.to))
|
|
63
|
+
reached.add(edge.from);
|
|
64
|
+
}
|
|
65
|
+
/*
|
|
66
|
+
* What a selected thing JUDGES, as well as what it touches.
|
|
67
|
+
*
|
|
68
|
+
* A rule has no edges, so selecting one reached nothing and the screen
|
|
69
|
+
* did not change — it read as broken. What a rule is about is derivable
|
|
70
|
+
* from its violations, which name the nodes they implicate, so selecting
|
|
71
|
+
* one now lights those wherever they are drawn.
|
|
72
|
+
*/
|
|
73
|
+
for (const violation of store.violations()) {
|
|
74
|
+
if (violation.subjectId !== undefined && chosen.has(violation.subjectId)) {
|
|
75
|
+
for (const id of violation.nodeIds)
|
|
76
|
+
reached.add(id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return [...reached];
|
|
80
|
+
}, [store, selection, nodes]);
|
|
81
|
+
}
|
|
82
|
+
/** Stands in the implicated set when a search found nothing, so every view dims. */
|
|
83
|
+
export const NOTHING_FOUND = "search:nothing";
|
|
84
|
+
//# sourceMappingURL=emphasis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emphasis.js","sourceRoot":"","sources":["../src/emphasis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AAEH,2EAA2E;AAC3E,MAAM,UAAU,UAAU;IACxB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EACxE,CAAC,UAAU,CAAC,CACb,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,kBAAkB,GAAG,UAAU,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB;;;;;OAKG;IACH,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI,CAAC,KAAK;YAAE,OAAO,kBAAkB,CAAC;QACtC,+EAA+E;QAC/E,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC;QAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,aAAa,CAAC,CAAC;QACjF,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,kBAAkB,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC1C,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAChD,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,CAAC;QACD;;;;;;;WAOG;QACH,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC;YAC3C,IAAI,SAAS,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzE,KAAK,MAAM,EAAE,IAAI,SAAS,CAAC,OAAO;oBAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;IACtB,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHERE A CAUGHT ERROR IS TOLD, beside the console (FR-24). A host that
|
|
3
|
+
* embeds an app observes its failures without reading what was on screen:
|
|
4
|
+
* a boundary tells this the error and the framework module it was caught
|
|
5
|
+
* in, and the host decides what of the error to keep.
|
|
6
|
+
*
|
|
7
|
+
* A file of its own: the frame provides the report before anything draws,
|
|
8
|
+
* and the boundary that tells it is drawn only with a view.
|
|
9
|
+
*/
|
|
10
|
+
export type ErrorReport = (error: unknown, where: {
|
|
11
|
+
readonly module: string;
|
|
12
|
+
}) => void;
|
|
13
|
+
/** The report every boundary under it tells. Null outside any: the console alone. */
|
|
14
|
+
export declare const ErrorReportContext: import("react").Context<ErrorReport | null>;
|
|
15
|
+
//# sourceMappingURL=error-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-report.d.ts","sourceRoot":"","sources":["../src/error-report.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAC;AAEvF,qFAAqF;AACrF,eAAO,MAAM,kBAAkB,6CAA0C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-report.js","sourceRoot":"","sources":["../src/error-report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAatC,qFAAqF;AACrF,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAqB,IAAI,CAAC,CAAC"}
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { AnySchema } from "@graview/core";
|
|
2
2
|
import { type ViewState } from "@graview/layout/view";
|
|
3
|
-
import { type EditableField } from "@graview/tools/frame";
|
|
4
3
|
/** The current selection, and the ways an interface changes it. */
|
|
5
4
|
export declare function useSelection(): {
|
|
6
5
|
selection: readonly string[];
|
|
@@ -19,30 +18,6 @@ export declare function useSelection(): {
|
|
|
19
18
|
* week, and it should never require hunting for it.
|
|
20
19
|
*/
|
|
21
20
|
export declare function useViolations<S extends AnySchema>(): import("@graview/core").Violation[];
|
|
22
|
-
/** Ids implicated in some current violation, for marking them in place. */
|
|
23
|
-
export declare function useFlagged(): readonly string[];
|
|
24
|
-
/**
|
|
25
|
-
* Everything the selection reaches: the selected nodes, plus everything one
|
|
26
|
-
* edge away from them.
|
|
27
|
-
*
|
|
28
|
-
* Selecting a person and having the week sit there unchanged is the same
|
|
29
|
-
* failure as clicking an event and getting an empty plane — the graph knows
|
|
30
|
-
* which five events that person is in, and the calendar is right there
|
|
31
|
-
* drawing all eighteen of them. A view that receives this can say so in its
|
|
32
|
-
* own idiom: a calendar lights up the spans, a roster rings the chips.
|
|
33
|
-
*
|
|
34
|
-
* Empty when nothing is selected, which every view must read as "no
|
|
35
|
-
* emphasis" rather than "nothing is related".
|
|
36
|
-
*/
|
|
37
|
-
export declare function useImplicated(): readonly string[];
|
|
38
|
-
/**
|
|
39
|
-
* What the SELECTION alone reaches — `useImplicated` without the search.
|
|
40
|
-
* For the one reading that must not confuse the two: a district's "tied"
|
|
41
|
-
* count is about what you picked, not what you typed.
|
|
42
|
-
*/
|
|
43
|
-
export declare function useReached(): readonly string[];
|
|
44
|
-
/** Stands in the implicated set when a search found nothing, so every view dims. */
|
|
45
|
-
export declare const NOTHING_FOUND = "search:nothing";
|
|
46
21
|
/** Navigation: every stop is a view, and every view is a URL. */
|
|
47
22
|
export declare function useNavigation(): {
|
|
48
23
|
view: ViewState;
|
|
@@ -52,20 +27,6 @@ export declare function useNavigation(): {
|
|
|
52
27
|
toggle: (aggregateId: string) => void;
|
|
53
28
|
go: (next: ViewState) => void;
|
|
54
29
|
};
|
|
55
|
-
/**
|
|
56
|
-
* Keeps the view in the URL fragment and honours the back button.
|
|
57
|
-
*
|
|
58
|
-
* The back button returning to the exact prior view is not a nicety here: it
|
|
59
|
-
* is the thing that makes a spatial interface navigable at all, because it
|
|
60
|
-
* means no arrangement is ever unreachable once you have left it.
|
|
61
|
-
*/
|
|
62
|
-
/**
|
|
63
|
-
* `useUrlSync` as a component, for shells that make syncing conditional —
|
|
64
|
-
* a hook inside `if (syncUrl)` is a Rules-of-Hooks trap the moment the
|
|
65
|
-
* flag ever changes; a conditionally RENDERED component is not.
|
|
66
|
-
*/
|
|
67
|
-
export declare function UrlSync(): null;
|
|
68
|
-
export declare function useUrlSync(): void;
|
|
69
30
|
/**
|
|
70
31
|
* Where you are in your own history.
|
|
71
32
|
*
|
|
@@ -79,22 +40,13 @@ export declare function useUrlSync(): void;
|
|
|
79
40
|
* that re-created it per component would count each navigation once per
|
|
80
41
|
* mounted consumer.
|
|
81
42
|
*/
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* WHETHER A CHANGE IS A STOP OR JUST A NUDGE OF THE ONE YOU ARE ON.
|
|
91
|
-
*
|
|
92
|
-
* Exported so it can be read and held to: what belongs in here is the
|
|
93
|
-
* difference between the back button meaning something and meaning "one
|
|
94
|
-
* pixel ago", and the two things that went wrong went wrong silently — the
|
|
95
|
-
* address changed, no entry was pushed, and the arrows stayed grey.
|
|
96
|
-
*/
|
|
97
|
-
export declare function adjustment(before: ViewState | null, after: ViewState): boolean;
|
|
43
|
+
/** Where you are in your own history: the pushes `useUrlSync` makes and the pops the browser reports. */
|
|
44
|
+
export declare const trail: {
|
|
45
|
+
at: number;
|
|
46
|
+
depth: number;
|
|
47
|
+
listeners: Set<() => void>;
|
|
48
|
+
tell(): void;
|
|
49
|
+
};
|
|
98
50
|
/**
|
|
99
51
|
* Whether there is anywhere to go, and the way to go there.
|
|
100
52
|
*
|
|
@@ -123,17 +75,4 @@ export declare function useJackIn(): {
|
|
|
123
75
|
exit: () => void;
|
|
124
76
|
isJackedIn: boolean;
|
|
125
77
|
};
|
|
126
|
-
/**
|
|
127
|
-
* The fields of a node that can be changed where they are shown, and the way
|
|
128
|
-
* to change one.
|
|
129
|
-
*
|
|
130
|
-
* `commit` runs the mutation the framework found, with the author set to a
|
|
131
|
-
* person — so an in-place edit lands in the op log, can be undone, and is
|
|
132
|
-
* judged by the invariants exactly like an edit made from the actions strip.
|
|
133
|
-
* There is no second write path.
|
|
134
|
-
*/
|
|
135
|
-
export declare function useEditableFields<S extends AnySchema>(id: string | null): {
|
|
136
|
-
readonly fields: readonly EditableField[];
|
|
137
|
-
commit: (field: EditableField, value: unknown, rest?: Record<string, unknown>) => void;
|
|
138
|
-
};
|
|
139
78
|
//# sourceMappingURL=hooks.d.ts.map
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAwE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAI5H,mEAAmE;AACnE,wBAAgB,YAAY;;eAKX,SAAS,MAAM,EAAE;;iBAEf,MAAM;qBAIF,MAAM;EAI5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,SAAS,yCAKhD;AA4BD,iEAAiE;AACjE,wBAAgB,aAAa;;;gBAMX,MAAM,GAAG,IAAI;qBACR,MAAM,GAAG,IAAI;0BACR,MAAM;eAEjB,SAAS;EAIzB;AAGD;;;;;;;;;;;;GAYG;AAEH,yGAAyG;AACzG,eAAO,MAAM,KAAK;;;yBAGS,IAAI;;CAI9B,CAAC;AAcF;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI;IAC9B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAwBA;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS;;gBASQ,MAAM;;;EAOtC"}
|
package/dist/hooks.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { useFound, useGraph, useGraview } from "./context.js";
|
|
1
|
+
import { toggleExpanded, toUrl, withFocus, withRelation, withZoom, withJackIn } from "@graview/layout/view";
|
|
2
|
+
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
|
3
|
+
import { useGraph, useGraview } from "./context.js";
|
|
5
4
|
/** The current selection, and the ways an interface changes it. */
|
|
6
5
|
export function useSelection() {
|
|
7
6
|
const { selection, setSelection } = useGraview();
|
|
@@ -43,81 +42,6 @@ function violationsOf(store) {
|
|
|
43
42
|
entry.violations ??= store.violations();
|
|
44
43
|
return entry.violations;
|
|
45
44
|
}
|
|
46
|
-
/** Ids implicated in some current violation, for marking them in place. */
|
|
47
|
-
export function useFlagged() {
|
|
48
|
-
const violations = useViolations();
|
|
49
|
-
return useMemo(() => [...new Set(violations.flatMap((violation) => violation.nodeIds))], [violations]);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Everything the selection reaches: the selected nodes, plus everything one
|
|
53
|
-
* edge away from them.
|
|
54
|
-
*
|
|
55
|
-
* Selecting a person and having the week sit there unchanged is the same
|
|
56
|
-
* failure as clicking an event and getting an empty plane — the graph knows
|
|
57
|
-
* which five events that person is in, and the calendar is right there
|
|
58
|
-
* drawing all eighteen of them. A view that receives this can say so in its
|
|
59
|
-
* own idiom: a calendar lights up the spans, a roster rings the chips.
|
|
60
|
-
*
|
|
61
|
-
* Empty when nothing is selected, which every view must read as "no
|
|
62
|
-
* emphasis" rather than "nothing is related".
|
|
63
|
-
*/
|
|
64
|
-
export function useImplicated() {
|
|
65
|
-
const reachedBySelection = useReached();
|
|
66
|
-
const found = useFound();
|
|
67
|
-
/*
|
|
68
|
-
* AND WHAT THE WORDS FIND. A search lights its hits in whatever picture
|
|
69
|
-
* is open, through the same set every view already dims by — so a lens
|
|
70
|
-
* learns nothing new to take part. Words that find nothing dim it all:
|
|
71
|
-
* the one id nothing is called keeps the set non-empty.
|
|
72
|
-
*/
|
|
73
|
-
return useMemo(() => {
|
|
74
|
-
if (!found)
|
|
75
|
-
return reachedBySelection;
|
|
76
|
-
// Every match, not the strip's capped index: a real hit is never drawn dimmed.
|
|
77
|
-
const hits = found.matched;
|
|
78
|
-
if (hits.length === 0 && reachedBySelection.length === 0)
|
|
79
|
-
return [NOTHING_FOUND];
|
|
80
|
-
return [...new Set([...reachedBySelection, ...hits])];
|
|
81
|
-
}, [found, reachedBySelection]);
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* What the SELECTION alone reaches — `useImplicated` without the search.
|
|
85
|
-
* For the one reading that must not confuse the two: a district's "tied"
|
|
86
|
-
* count is about what you picked, not what you typed.
|
|
87
|
-
*/
|
|
88
|
-
export function useReached() {
|
|
89
|
-
const { store, selection } = useGraview();
|
|
90
|
-
const nodes = useGraph();
|
|
91
|
-
return useMemo(() => {
|
|
92
|
-
if (selection.length === 0)
|
|
93
|
-
return [];
|
|
94
|
-
const chosen = new Set(selection);
|
|
95
|
-
const reached = new Set(chosen);
|
|
96
|
-
for (const edge of store.graph.allEdges()) {
|
|
97
|
-
if (chosen.has(edge.from))
|
|
98
|
-
reached.add(edge.to);
|
|
99
|
-
if (chosen.has(edge.to))
|
|
100
|
-
reached.add(edge.from);
|
|
101
|
-
}
|
|
102
|
-
/*
|
|
103
|
-
* What a selected thing JUDGES, as well as what it touches.
|
|
104
|
-
*
|
|
105
|
-
* A rule has no edges, so selecting one reached nothing and the screen
|
|
106
|
-
* did not change — it read as broken. What a rule is about is derivable
|
|
107
|
-
* from its violations, which name the nodes they implicate, so selecting
|
|
108
|
-
* one now lights those wherever they are drawn.
|
|
109
|
-
*/
|
|
110
|
-
for (const violation of store.violations()) {
|
|
111
|
-
if (violation.subjectId !== undefined && chosen.has(violation.subjectId)) {
|
|
112
|
-
for (const id of violation.nodeIds)
|
|
113
|
-
reached.add(id);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return [...reached];
|
|
117
|
-
}, [store, selection, nodes]);
|
|
118
|
-
}
|
|
119
|
-
/** Stands in the implicated set when a search found nothing, so every view dims. */
|
|
120
|
-
export const NOTHING_FOUND = "search:nothing";
|
|
121
45
|
/** Navigation: every stop is a view, and every view is a URL. */
|
|
122
46
|
export function useNavigation() {
|
|
123
47
|
const { view, setView } = useGraview();
|
|
@@ -130,124 +54,6 @@ export function useNavigation() {
|
|
|
130
54
|
go: (next) => setView(next),
|
|
131
55
|
}), [view, setView]);
|
|
132
56
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Keeps the view in the URL fragment and honours the back button.
|
|
135
|
-
*
|
|
136
|
-
* The back button returning to the exact prior view is not a nicety here: it
|
|
137
|
-
* is the thing that makes a spatial interface navigable at all, because it
|
|
138
|
-
* means no arrangement is ever unreachable once you have left it.
|
|
139
|
-
*/
|
|
140
|
-
/**
|
|
141
|
-
* `useUrlSync` as a component, for shells that make syncing conditional —
|
|
142
|
-
* a hook inside `if (syncUrl)` is a Rules-of-Hooks trap the moment the
|
|
143
|
-
* flag ever changes; a conditionally RENDERED component is not.
|
|
144
|
-
*/
|
|
145
|
-
export function UrlSync() {
|
|
146
|
-
useUrlSync();
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
export function useUrlSync() {
|
|
150
|
-
const { view, setView, views } = useGraview();
|
|
151
|
-
/*
|
|
152
|
-
* A STOP THAT NAMES A PLACE AND NOT ITS GROUP STILL GOES THERE.
|
|
153
|
-
*
|
|
154
|
-
* `#view=grounds-map` is the link a page can actually write: the page knows
|
|
155
|
-
* the picture it is talking about, not how the layout spells the aggregate
|
|
156
|
-
* id of the kind behind it. The registry does know — a named place carries
|
|
157
|
-
* its kind — so the place is looked up here and the group it is a picture
|
|
158
|
-
* of becomes the focus. Without this the short form lands on the default
|
|
159
|
-
* view, which is the pasted-link problem one level up.
|
|
160
|
-
*/
|
|
161
|
-
const settled = useCallback((state) => {
|
|
162
|
-
const asked = state.within?.["view"];
|
|
163
|
-
if (asked === undefined || state.focusId)
|
|
164
|
-
return state;
|
|
165
|
-
const place = views.places().find((candidate) => candidate.as === asked);
|
|
166
|
-
return place ? { ...state, focusId: aggregateId(place.kind) } : state;
|
|
167
|
-
}, [views]);
|
|
168
|
-
/*
|
|
169
|
-
* Adopt the fragment on FIRST load, not only on navigation.
|
|
170
|
-
*
|
|
171
|
-
* "Every stop is a URL" was only half true: the view was written to the
|
|
172
|
-
* fragment and the back button honoured it, but opening a shared link
|
|
173
|
-
* landed on the default view and silently overwrote the address bar. A
|
|
174
|
-
* pasted link that does not go where it says is worse than no link.
|
|
175
|
-
*/
|
|
176
|
-
useEffect(() => {
|
|
177
|
-
if (typeof window === "undefined")
|
|
178
|
-
return;
|
|
179
|
-
const initial = settled(fromUrl(window.location.hash));
|
|
180
|
-
// Adopt ANY address that says something — overview, zoom, a selection —
|
|
181
|
-
// not only the focus-shaped ones. A pasted link that does not go where
|
|
182
|
-
// it says is worse than no link.
|
|
183
|
-
if (!sameView(initial, EMPTY_VIEW)) {
|
|
184
|
-
setView(initial);
|
|
185
|
-
}
|
|
186
|
-
// Once, on mount: later changes are this hook's own writes.
|
|
187
|
-
}, []);
|
|
188
|
-
useEffect(() => {
|
|
189
|
-
if (typeof window === "undefined")
|
|
190
|
-
return;
|
|
191
|
-
const onPop = () => setView(settled(fromUrl(window.location.hash)));
|
|
192
|
-
window.addEventListener("popstate", onPop);
|
|
193
|
-
window.addEventListener("hashchange", onPop);
|
|
194
|
-
return () => {
|
|
195
|
-
window.removeEventListener("popstate", onPop);
|
|
196
|
-
window.removeEventListener("hashchange", onPop);
|
|
197
|
-
};
|
|
198
|
-
}, [setView, settled]);
|
|
199
|
-
const landed = useRef(false);
|
|
200
|
-
const written = useRef(null);
|
|
201
|
-
useEffect(() => {
|
|
202
|
-
if (typeof window === "undefined")
|
|
203
|
-
return;
|
|
204
|
-
const next = toUrl(view);
|
|
205
|
-
// Only write when the view actually changed, or the back stack fills with
|
|
206
|
-
// duplicates and the back button stops meaning anything. The baseline
|
|
207
|
-
// still moves: after a popstate re-syncs the view, a stale baseline made
|
|
208
|
-
// the next drag read as travel and push a phantom stop.
|
|
209
|
-
if (window.location.hash === next) {
|
|
210
|
-
written.current = view;
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
/*
|
|
214
|
-
* ARRIVING is not a navigation.
|
|
215
|
-
*
|
|
216
|
-
* The first write is the app adopting its own default view, and pushing it
|
|
217
|
-
* put a stop in the history that nobody went to — so the back control was
|
|
218
|
-
* offered the moment the page loaded, and pressing it went to the blank
|
|
219
|
-
* URL the app had just left. Replacing is what a page does when it tidies
|
|
220
|
-
* its own address.
|
|
221
|
-
*/
|
|
222
|
-
if (!landed.current) {
|
|
223
|
-
landed.current = true;
|
|
224
|
-
written.current = view;
|
|
225
|
-
window.history.replaceState({ graview: trail.at }, "", next);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
/*
|
|
229
|
-
* MOVING THE FURNITURE IS NOT TRAVELLING.
|
|
230
|
-
*
|
|
231
|
-
* A drag writes the view state on every pointer move, because that is what
|
|
232
|
-
* makes the connectors follow the card. Pushed, one drag would be sixty
|
|
233
|
-
* history entries and Back would mean "one pixel ago". A change that
|
|
234
|
-
* touches only the camera or where things were dragged is an adjustment of
|
|
235
|
-
* the stop you are on, so it replaces: the address stays shareable and
|
|
236
|
-
* Back still means the place you were before you started fiddling.
|
|
237
|
-
*/
|
|
238
|
-
if (adjustment(written.current, view)) {
|
|
239
|
-
window.history.replaceState({ graview: trail.at }, "", next);
|
|
240
|
-
written.current = view;
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
written.current = view;
|
|
244
|
-
window.history.pushState({ graview: ++trail.at }, "", next);
|
|
245
|
-
// A new stop discards anything that was ahead of it, exactly as the
|
|
246
|
-
// browser does.
|
|
247
|
-
trail.depth = trail.at;
|
|
248
|
-
trail.tell();
|
|
249
|
-
}, [view]);
|
|
250
|
-
}
|
|
251
57
|
/**
|
|
252
58
|
* Where you are in your own history.
|
|
253
59
|
*
|
|
@@ -261,71 +67,8 @@ export function useUrlSync() {
|
|
|
261
67
|
* that re-created it per component would count each navigation once per
|
|
262
68
|
* mounted consumer.
|
|
263
69
|
*/
|
|
264
|
-
/**
|
|
265
|
-
|
|
266
|
-
*
|
|
267
|
-
* Where you are is the focus, the relation, what is expanded and whether you
|
|
268
|
-
* have risen above the stack. Where you dragged things to is not a different
|
|
269
|
-
* place; it is the same place, rearranged.
|
|
270
|
-
*/
|
|
271
|
-
/**
|
|
272
|
-
* WHETHER A CHANGE IS A STOP OR JUST A NUDGE OF THE ONE YOU ARE ON.
|
|
273
|
-
*
|
|
274
|
-
* Exported so it can be read and held to: what belongs in here is the
|
|
275
|
-
* difference between the back button meaning something and meaning "one
|
|
276
|
-
* pixel ago", and the two things that went wrong went wrong silently — the
|
|
277
|
-
* address changed, no entry was pushed, and the arrows stayed grey.
|
|
278
|
-
*/
|
|
279
|
-
export function adjustment(before, after) {
|
|
280
|
-
if (!before)
|
|
281
|
-
return false;
|
|
282
|
-
return (before.focusId === after.focusId &&
|
|
283
|
-
before.relation === after.relation &&
|
|
284
|
-
(before.overview ?? false) === (after.overview ?? false) &&
|
|
285
|
-
(before.zoom ?? false) === (after.zoom ?? false) &&
|
|
286
|
-
(before.past ?? false) === (after.past ?? false) &&
|
|
287
|
-
before.expanded.join(",") === after.expanded.join(",") &&
|
|
288
|
-
/*
|
|
289
|
-
* SHOWING A MODULE IS TRAVELLING. "Show the installation" raises whole
|
|
290
|
-
* districts into the scene — who is here, who has been invited — and
|
|
291
|
-
* its own comment always said it was a stop Back knew the way out of.
|
|
292
|
-
* It was not: `shown` was missing from this comparison, so the address
|
|
293
|
-
* gained `show=installation` and the entry was REPLACED, the arrows
|
|
294
|
-
* stayed grey, and one Back from the installation left the app.
|
|
295
|
-
*/
|
|
296
|
-
(before.shown ?? []).join(",") === (after.shown ?? []).join(",") &&
|
|
297
|
-
/*
|
|
298
|
-
* A VIEW MOVING ALONG ITS OWN DIMENSION IS TRAVELLING.
|
|
299
|
-
*
|
|
300
|
-
* Turning the calendar to October is going somewhere: a URL to send
|
|
301
|
-
* somebody, a place to come back to, a Back that means "the month I was
|
|
302
|
-
* looking at". Left out of this comparison it read as an adjustment of
|
|
303
|
-
* the stop — the address updated, no entry was pushed, and one Back
|
|
304
|
-
* from October landed past the calendar entirely, at the place before
|
|
305
|
-
* anyone opened it. That is the exact failure `within` exists to fix.
|
|
306
|
-
*/
|
|
307
|
-
sameWithin(before.within, after.within));
|
|
308
|
-
}
|
|
309
|
-
function sameWithin(before, after) {
|
|
310
|
-
const say = (held) => Object.entries(held ?? {})
|
|
311
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
312
|
-
.map(([key, value]) => `${key}=${value}`)
|
|
313
|
-
.join("&");
|
|
314
|
-
return say(withoutWords(before)) === say(withoutWords(after));
|
|
315
|
-
}
|
|
316
|
-
/*
|
|
317
|
-
* TYPING IS NOT TRAVELLING. The words a row narrows by (`in.q`) change on
|
|
318
|
-
* every keystroke, and each one pushed a history entry — five letters, five
|
|
319
|
-
* Backs to leave a list. The scene's own `q` was never compared; the row's
|
|
320
|
-
* words are the same act and read the same way.
|
|
321
|
-
*/
|
|
322
|
-
function withoutWords(held) {
|
|
323
|
-
if (!held || !("q" in held))
|
|
324
|
-
return held;
|
|
325
|
-
const { q: _words, ...rest } = held;
|
|
326
|
-
return rest;
|
|
327
|
-
}
|
|
328
|
-
const trail = {
|
|
70
|
+
/** Where you are in your own history: the pushes `useUrlSync` makes and the pops the browser reports. */
|
|
71
|
+
export const trail = {
|
|
329
72
|
at: 0,
|
|
330
73
|
depth: 0,
|
|
331
74
|
listeners: new Set(),
|
|
@@ -390,23 +133,4 @@ export function useJackIn() {
|
|
|
390
133
|
const jackedIn = view.zoom ? view.focusId : null;
|
|
391
134
|
return useMemo(() => ({ jackedIn, enter, exit, isJackedIn: view.zoom === true }), [jackedIn, enter, exit, view.zoom]);
|
|
392
135
|
}
|
|
393
|
-
/**
|
|
394
|
-
* The fields of a node that can be changed where they are shown, and the way
|
|
395
|
-
* to change one.
|
|
396
|
-
*
|
|
397
|
-
* `commit` runs the mutation the framework found, with the author set to a
|
|
398
|
-
* person — so an in-place edit lands in the op log, can be undone, and is
|
|
399
|
-
* judged by the invariants exactly like an edit made from the actions strip.
|
|
400
|
-
* There is no second write path.
|
|
401
|
-
*/
|
|
402
|
-
export function useEditableFields(id) {
|
|
403
|
-
const { store, principal } = useGraview();
|
|
404
|
-
const nodes = useGraph();
|
|
405
|
-
const fields = useMemo(() => (id === null ? [] : editableFields(store, id)), [store, id, nodes]);
|
|
406
|
-
const commit = useCallback((field, value, rest = {}) => {
|
|
407
|
-
const call = field.call(value);
|
|
408
|
-
store.apply({ name: call.name, args: { ...call.args, ...rest } }, { author: principal });
|
|
409
|
-
}, [store, principal]);
|
|
410
|
-
return { fields, commit };
|
|
411
|
-
}
|
|
412
136
|
//# sourceMappingURL=hooks.js.map
|