wenay-react2 1.0.45 → 1.0.47
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/README.md +7 -1
- package/doc/changes/v1.0.46.md +16 -0
- package/doc/changes/v1.0.47.md +9 -0
- package/doc/examples/README.md +6 -0
- package/doc/examples/peer-call-media.tsx +8 -0
- package/doc/examples/stand.tsx +6 -0
- package/doc/native.md +37 -0
- package/doc/progress/common2-adoption-1.0.74.md +24 -0
- package/doc/progress/stand-as-examples-audit.md +22 -0
- package/doc/target/my.md +12 -0
- package/doc/wenay-react2.md +1 -1
- package/lib/common/demo/peerMedia.d.ts +6 -0
- package/lib/common/demo/peerMedia.js +128 -0
- package/lib/common/src/components/Toolbar/Toolbar.d.ts +4 -0
- package/lib/common/src/components/Toolbar/Toolbar.js +16 -7
- package/lib/common/src/components/index.d.ts +12 -0
- package/lib/common/src/components/index.js +12 -0
- package/lib/common/src/grid/columnState/CardList.d.ts +2 -0
- package/lib/common/src/grid/columnState/CardList.js +1 -1
- package/lib/common/src/grid/columnState/ColumnsMenu.d.ts +2 -0
- package/lib/common/src/grid/columnState/ColumnsMenu.js +3 -2
- package/lib/common/src/grid/columnState/columnState.d.ts +15 -0
- package/lib/common/src/grid/columnState/columnState.js +53 -5
- package/lib/common/src/hooks/index.d.ts +1 -0
- package/lib/common/src/hooks/index.js +1 -0
- package/lib/common/src/hooks/usePeerCall.d.ts +68 -0
- package/lib/common/src/hooks/usePeerCall.js +79 -0
- package/lib/common/src/hooks/useReorder.d.ts +2 -0
- package/lib/common/src/hooks/useReorder.js +3 -1
- package/lib/common/src/utils/memoryStore.d.ts +2 -2
- package/lib/common/testUseReact/qa.d.ts +1 -0
- package/lib/common/testUseReact/qa.js +1148 -0
- package/lib/common/testUseReact/replayVideo.d.ts +14 -0
- package/lib/common/testUseReact/replayVideo.js +311 -0
- package/lib/common/testUseReact/testParams.d.ts +1 -0
- package/lib/common/testUseReact/testParams.js +15 -0
- package/lib/common/testUseReact/useGrid.d.ts +2 -0
- package/lib/common/testUseReact/useGrid.js +62 -0
- package/lib/native/columnDots.d.ts +41 -0
- package/lib/native/columnDots.js +104 -0
- package/lib/native/columnState.d.ts +69 -0
- package/lib/native/columnState.js +209 -0
- package/lib/native/index.d.ts +3 -0
- package/lib/native/index.js +3 -0
- package/lib/style/style.css +24 -0
- package/package.json +6 -3
|
@@ -21,6 +21,8 @@ export function createColumnState(opts) {
|
|
|
21
21
|
const st = memoryGetOrCreate(opts.key, defConfig());
|
|
22
22
|
const stApi = createUpdateApi(st);
|
|
23
23
|
const [emitChange, onChange] = createListen();
|
|
24
|
+
const previewRt = { order: null };
|
|
25
|
+
const previewApi = createUpdateApi(previewRt);
|
|
24
26
|
/** Runtime-only, never persisted: actual = which keys the attached grid has;
|
|
25
27
|
* gate = optional app-level availability over a stable grid schema (standards,
|
|
26
28
|
* mode blocks). Consumers see actual AND gate as one presence map. */
|
|
@@ -126,6 +128,33 @@ export function createColumnState(opts) {
|
|
|
126
128
|
const getConfig = () => normalize();
|
|
127
129
|
const setConfig = (next) => commit(next, false);
|
|
128
130
|
const reset = () => commit(defConfig(), false);
|
|
131
|
+
function displayConfig() {
|
|
132
|
+
const cfg = normalize();
|
|
133
|
+
return previewRt.order ? { ...cfg, order: previewRt.order.slice() } : cfg;
|
|
134
|
+
}
|
|
135
|
+
function useDisplayConfig() {
|
|
136
|
+
stApi.use();
|
|
137
|
+
previewApi.use();
|
|
138
|
+
return displayConfig();
|
|
139
|
+
}
|
|
140
|
+
function setPreviewOrder(order) {
|
|
141
|
+
const cfg = normalize();
|
|
142
|
+
const known = new Set(cfg.order);
|
|
143
|
+
const next = order ? pinFixedOrder(order.filter(k => known.has(k)), opts.columns) : null;
|
|
144
|
+
if (JSON.stringify(next) == JSON.stringify(previewRt.order))
|
|
145
|
+
return;
|
|
146
|
+
previewRt.order = next;
|
|
147
|
+
previewApi.render();
|
|
148
|
+
if (!gridApi || gridApi.isDestroyed?.())
|
|
149
|
+
return;
|
|
150
|
+
applying = true;
|
|
151
|
+
try {
|
|
152
|
+
gridApi.applyColumnState({ state: (next ?? cfg.order).map(colId => ({ colId })), applyOrder: true });
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
applying = false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
129
158
|
function useConfig() {
|
|
130
159
|
stApi.use();
|
|
131
160
|
return normalize();
|
|
@@ -154,14 +183,22 @@ export function createColumnState(opts) {
|
|
|
154
183
|
* they edit the SAME config. */
|
|
155
184
|
const listSource = {
|
|
156
185
|
useConfig() {
|
|
157
|
-
const c =
|
|
186
|
+
const c = useDisplayConfig();
|
|
158
187
|
return { order: c.order, visible: c.visible };
|
|
159
188
|
},
|
|
160
189
|
getConfig() {
|
|
190
|
+
const c = displayConfig();
|
|
191
|
+
return { order: c.order, visible: c.visible };
|
|
192
|
+
},
|
|
193
|
+
useBaseConfig() {
|
|
194
|
+
const c = useConfig();
|
|
195
|
+
return { order: c.order, visible: c.visible };
|
|
196
|
+
},
|
|
197
|
+
getBaseConfig() {
|
|
161
198
|
const c = normalize();
|
|
162
199
|
return { order: c.order, visible: c.visible };
|
|
163
200
|
},
|
|
164
|
-
setConfig(next) {
|
|
201
|
+
setPreview: setPreviewOrder, setConfig(next) {
|
|
165
202
|
const cfg = normalize();
|
|
166
203
|
// an editor over a SUBSET of columns must not lose the rest:
|
|
167
204
|
// unknown incoming keys are dropped by normalize, missing ones re-appended
|
|
@@ -262,9 +299,20 @@ export function createColumnState(opts) {
|
|
|
262
299
|
function onGridEvent(e) {
|
|
263
300
|
if (applying || e?.source == 'api')
|
|
264
301
|
return;
|
|
265
|
-
|
|
266
|
-
|
|
302
|
+
if (e?.type == 'columnMoved' && e.finished === false && gridApi) {
|
|
303
|
+
const known = new Set(opts.columns.map(c => c.key));
|
|
304
|
+
const order = gridApi.getColumnState().map(c => c.colId).filter((k) => !!k && known.has(k));
|
|
305
|
+
for (const k of normalize().order)
|
|
306
|
+
if (!order.includes(k))
|
|
307
|
+
order.push(k);
|
|
308
|
+
setPreviewOrder(order);
|
|
267
309
|
return;
|
|
310
|
+
}
|
|
311
|
+
if (e?.type == 'columnMoved' && previewRt.order) {
|
|
312
|
+
readFromGrid();
|
|
313
|
+
setPreviewOrder(null);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
268
316
|
clearTimeout(saveTimer);
|
|
269
317
|
saveTimer = setTimeout(readFromGrid, opts.saveMs ?? 300);
|
|
270
318
|
}
|
|
@@ -310,7 +358,7 @@ export function createColumnState(opts) {
|
|
|
310
358
|
* (dots, cards, icon menus) render from these + the config. */
|
|
311
359
|
columns: opts.columns,
|
|
312
360
|
api: { getConfig, setConfig, useConfig, onChange, reset, show, move, setSort, toggleSort, visibleKeys,
|
|
313
|
-
getPresent, usePresent, isPresent, setPresent, getPresentGate, setPresentGate, listSource },
|
|
361
|
+
getPresent, usePresent, isPresent, setPresent, getPresentGate, setPresentGate, useDisplayConfig, setPreviewOrder, listSource },
|
|
314
362
|
grid: { attach, detach },
|
|
315
363
|
};
|
|
316
364
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Peer } from "wenay-common2";
|
|
2
|
+
export type PeerPresence = {
|
|
3
|
+
account: string;
|
|
4
|
+
online: boolean;
|
|
5
|
+
};
|
|
6
|
+
/** React binding for common2 host presence. Subscribe before list(): `changes` is the
|
|
7
|
+
* authoritative edge stream and React does not create its own presence transport. */
|
|
8
|
+
export declare function usePeerPresence(presence: Peer.PeerRemote["presence"] | undefined): {
|
|
9
|
+
accounts: string[];
|
|
10
|
+
online: (account: string) => boolean;
|
|
11
|
+
};
|
|
12
|
+
/** Thin UI binding over common2 CallManager. Signaling, busy/glare policy, timeout,
|
|
13
|
+
* offline verdict and lifecycle ownership stay in common2; callers own manager.close(). */
|
|
14
|
+
export declare function usePeerCalls(manager: Peer.CallManager): {
|
|
15
|
+
ready: boolean;
|
|
16
|
+
active: {
|
|
17
|
+
id: string;
|
|
18
|
+
peer: string;
|
|
19
|
+
direction: "out" | "in";
|
|
20
|
+
meta: unknown;
|
|
21
|
+
state: () => Peer.tCallState;
|
|
22
|
+
reason: () => Peer.tCallEnd | null;
|
|
23
|
+
changed: import("wenay-common2").ListenApi<[Peer.tCallState]>;
|
|
24
|
+
ended: Promise<Peer.tCallEnd>;
|
|
25
|
+
accept(): void;
|
|
26
|
+
decline(why?: Peer.tCallEnd): void;
|
|
27
|
+
hangup(): void;
|
|
28
|
+
} | null;
|
|
29
|
+
rings: {
|
|
30
|
+
id: string;
|
|
31
|
+
peer: string;
|
|
32
|
+
direction: "out" | "in";
|
|
33
|
+
meta: unknown;
|
|
34
|
+
state: () => Peer.tCallState;
|
|
35
|
+
reason: () => Peer.tCallEnd | null;
|
|
36
|
+
changed: import("wenay-common2").ListenApi<[Peer.tCallState]>;
|
|
37
|
+
ended: Promise<Peer.tCallEnd>;
|
|
38
|
+
accept(): void;
|
|
39
|
+
decline(why?: Peer.tCallEnd): void;
|
|
40
|
+
hangup(): void;
|
|
41
|
+
}[];
|
|
42
|
+
calls: {
|
|
43
|
+
id: string;
|
|
44
|
+
peer: string;
|
|
45
|
+
direction: "out" | "in";
|
|
46
|
+
meta: unknown;
|
|
47
|
+
state: () => Peer.tCallState;
|
|
48
|
+
reason: () => Peer.tCallEnd | null;
|
|
49
|
+
changed: import("wenay-common2").ListenApi<[Peer.tCallState]>;
|
|
50
|
+
ended: Promise<Peer.tCallEnd>;
|
|
51
|
+
accept(): void;
|
|
52
|
+
decline(why?: Peer.tCallEnd): void;
|
|
53
|
+
hangup(): void;
|
|
54
|
+
}[];
|
|
55
|
+
call: (account: string, meta?: unknown) => {
|
|
56
|
+
id: string;
|
|
57
|
+
peer: string;
|
|
58
|
+
direction: "out" | "in";
|
|
59
|
+
meta: unknown;
|
|
60
|
+
state: () => Peer.tCallState;
|
|
61
|
+
reason: () => Peer.tCallEnd | null;
|
|
62
|
+
changed: import("wenay-common2").ListenApi<[Peer.tCallState]>;
|
|
63
|
+
ended: Promise<Peer.tCallEnd>;
|
|
64
|
+
accept(): void;
|
|
65
|
+
decline(why?: Peer.tCallEnd): void;
|
|
66
|
+
hangup(): void;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
/** React binding for common2 host presence. Subscribe before list(): `changes` is the
|
|
3
|
+
* authoritative edge stream and React does not create its own presence transport. */
|
|
4
|
+
export function usePeerPresence(presence) {
|
|
5
|
+
const [accounts, setAccounts] = useState([]);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (!presence) {
|
|
8
|
+
setAccounts([]);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
let alive = true;
|
|
12
|
+
const off = presence.changes.on(({ account, online }) => {
|
|
13
|
+
if (!alive)
|
|
14
|
+
return;
|
|
15
|
+
setAccounts(current => online
|
|
16
|
+
? current.includes(account) ? current : [...current, account].sort()
|
|
17
|
+
: current.filter(value => value !== account));
|
|
18
|
+
});
|
|
19
|
+
Promise.resolve(presence.list()).then(list => {
|
|
20
|
+
if (alive)
|
|
21
|
+
setAccounts([...new Set(list)].sort());
|
|
22
|
+
});
|
|
23
|
+
return () => { alive = false; off(); };
|
|
24
|
+
}, [presence]);
|
|
25
|
+
return useMemo(() => ({ accounts, online: (account) => accounts.includes(account) }), [accounts]);
|
|
26
|
+
}
|
|
27
|
+
/** Thin UI binding over common2 CallManager. Signaling, busy/glare policy, timeout,
|
|
28
|
+
* offline verdict and lifecycle ownership stay in common2; callers own manager.close(). */
|
|
29
|
+
export function usePeerCalls(manager) {
|
|
30
|
+
const calls = useRef(new Map());
|
|
31
|
+
const [version, setVersion] = useState(0);
|
|
32
|
+
const touch = useCallback(() => setVersion(value => value + 1), []);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
let alive = true;
|
|
35
|
+
const offs = new Map();
|
|
36
|
+
const watch = (call) => {
|
|
37
|
+
if (calls.current.has(call.id))
|
|
38
|
+
return;
|
|
39
|
+
calls.current.set(call.id, call);
|
|
40
|
+
offs.set(call.id, call.changed.on(touch));
|
|
41
|
+
void call.ended.then(() => {
|
|
42
|
+
offs.get(call.id)?.();
|
|
43
|
+
offs.delete(call.id);
|
|
44
|
+
calls.current.delete(call.id);
|
|
45
|
+
if (alive)
|
|
46
|
+
touch();
|
|
47
|
+
});
|
|
48
|
+
touch();
|
|
49
|
+
};
|
|
50
|
+
const offRings = manager.rings.on(watch);
|
|
51
|
+
void manager.ready.then(() => { if (alive)
|
|
52
|
+
touch(); });
|
|
53
|
+
return () => {
|
|
54
|
+
alive = false;
|
|
55
|
+
offRings();
|
|
56
|
+
offs.forEach(off => off());
|
|
57
|
+
calls.current.clear();
|
|
58
|
+
};
|
|
59
|
+
}, [manager, touch]);
|
|
60
|
+
const call = useCallback((account, meta) => {
|
|
61
|
+
const handle = manager.call(account, meta);
|
|
62
|
+
// Outgoing calls do not arrive through `rings`; register them immediately.
|
|
63
|
+
calls.current.set(handle.id, handle);
|
|
64
|
+
const off = handle.changed.on(touch);
|
|
65
|
+
void handle.ended.then(() => { off(); calls.current.delete(handle.id); touch(); });
|
|
66
|
+
touch();
|
|
67
|
+
return handle;
|
|
68
|
+
}, [manager, touch]);
|
|
69
|
+
return useMemo(() => {
|
|
70
|
+
const known = [...calls.current.values()];
|
|
71
|
+
return {
|
|
72
|
+
ready: version > 0,
|
|
73
|
+
active: manager.active(),
|
|
74
|
+
rings: known.filter(handle => handle.state() === "ringing"),
|
|
75
|
+
calls: known,
|
|
76
|
+
call,
|
|
77
|
+
};
|
|
78
|
+
}, [manager, call, version]);
|
|
79
|
+
}
|
|
@@ -27,6 +27,8 @@ export type ReorderOptions = {
|
|
|
27
27
|
preview?: 'slots' | 'measure';
|
|
28
28
|
/** hold before the drag starts (touch-friendly fields); default 0 */
|
|
29
29
|
holdMs?: number;
|
|
30
|
+
/** transient simulated order while dragging; null on drop/cancel */
|
|
31
|
+
onPreviewChange?: (next: string[] | null) => void;
|
|
30
32
|
};
|
|
31
33
|
export type ReorderItem = {
|
|
32
34
|
/** spread on the block element */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useRef, useState } from 'react';
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useDraggableApi } from './useDraggable';
|
|
3
3
|
export function useReorder(o) {
|
|
4
4
|
const listRef = useRef(null);
|
|
@@ -96,6 +96,8 @@ export function useReorder(o) {
|
|
|
96
96
|
const from = dragKey != null ? o.order.indexOf(dragKey) : -1;
|
|
97
97
|
const target = from != -1 ? dragTarget(from, local(drag.position.x), local(drag.position.y)) : -1;
|
|
98
98
|
const preview = from != -1 && dragKey != null ? move(o.order, dragKey, target) : null;
|
|
99
|
+
const previewKey = preview?.join("\u0000") ?? "";
|
|
100
|
+
useEffect(() => o.onPreviewChange?.(preview), [previewKey]);
|
|
99
101
|
function item(key) {
|
|
100
102
|
const active = preview != null;
|
|
101
103
|
const dragging = key == dragKey;
|
|
@@ -27,8 +27,8 @@ export declare const memoryCache: {
|
|
|
27
27
|
getArr: [k: string, v: Map<string, unknown>][];
|
|
28
28
|
};
|
|
29
29
|
export declare const memoryMaps: {
|
|
30
|
-
rnd: ObservableMap<string, import("../components
|
|
30
|
+
rnd: ObservableMap<string, import("../components").FloatingWindowSavedGeometry>;
|
|
31
31
|
resize: ObservableMap<string, import("./persistedMaps").ResizableSavedSize>;
|
|
32
|
-
rightMenu: ObservableMap<string, import("../components
|
|
32
|
+
rightMenu: ObservableMap<string, import("../components").MenuRightSavedState>;
|
|
33
33
|
other: ObservableMap<string, object>;
|
|
34
34
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function QABoard(): import("react/jsx-runtime").JSX.Element;
|