dsh-plugin-lookatstudy 0.26.0 → 0.26.1
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/lib/client.js +113 -24
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -1787,6 +1787,64 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
1787
1787
|
}));
|
|
1788
1788
|
}
|
|
1789
1789
|
//#endregion
|
|
1790
|
+
//#region src/client/stage-session.ts
|
|
1791
|
+
/** The plugin's private retention label (never the view owner's 'mainView'). */
|
|
1792
|
+
const STAGE_SOURCE = "lookatstudy";
|
|
1793
|
+
/** Which staging generation the host speaks ('retain' wins when both exist). */
|
|
1794
|
+
function stagingMode(sessions) {
|
|
1795
|
+
return typeof sessions.retain === "function" ? "retain" : "open";
|
|
1796
|
+
}
|
|
1797
|
+
let held = null;
|
|
1798
|
+
/**
|
|
1799
|
+
* Stage `sessionId` for observation + addressability.
|
|
1800
|
+
* alpha: holds the plugin's reference. rc: `open()` navigation. Throws
|
|
1801
|
+
* whatever the host face throws — callers keep their existing catch policy.
|
|
1802
|
+
*/
|
|
1803
|
+
function stageSession(sessions, sessionId) {
|
|
1804
|
+
if (stagingMode(sessions) === "retain") {
|
|
1805
|
+
if (held !== null && held.sessionId === sessionId) return;
|
|
1806
|
+
const previous = held;
|
|
1807
|
+
held = sessions.retain(sessionId, { source: STAGE_SOURCE });
|
|
1808
|
+
previous?.release();
|
|
1809
|
+
} else sessions.open?.(sessionId);
|
|
1810
|
+
}
|
|
1811
|
+
/** Release the held alpha reference (plugin dispose — across open/close
|
|
1812
|
+
* toggles the reference stays held, mirroring rc's sticky current). */
|
|
1813
|
+
function unstageSession() {
|
|
1814
|
+
held?.release();
|
|
1815
|
+
held = null;
|
|
1816
|
+
}
|
|
1817
|
+
/**
|
|
1818
|
+
* Hold a TRANSIENT alpha reference for an effect's lifetime so scope/binding
|
|
1819
|
+
* resolve for an un-staged session (E1/E6 projections, thread rename).
|
|
1820
|
+
* rc: a no-op closer — listed ids are addressable there without help, and
|
|
1821
|
+
* calling open() from inside an effect would trip the rc hand-back.
|
|
1822
|
+
* alpha: undefined only when the retain is refused (treat as feature-absent).
|
|
1823
|
+
*/
|
|
1824
|
+
function acquireStageReference(sessions, sessionId) {
|
|
1825
|
+
if (sessions.retain === void 0) return () => {};
|
|
1826
|
+
let ref;
|
|
1827
|
+
try {
|
|
1828
|
+
ref = sessions.retain(sessionId, { source: STAGE_SOURCE });
|
|
1829
|
+
} catch {
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
return () => {
|
|
1833
|
+
ref?.release();
|
|
1834
|
+
ref = void 0;
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* Derive the host main-view selection from a list snapshot the way
|
|
1839
|
+
* ui-workspace does: alpha removed `list.current`, and the view owner's
|
|
1840
|
+
* `mainView` retention is the only public trace of the main selection.
|
|
1841
|
+
* Pure; rc snapshots carry no `retainedBy` and read as no selection.
|
|
1842
|
+
*/
|
|
1843
|
+
function mainSelectionOf(byId) {
|
|
1844
|
+
if (byId === void 0) return void 0;
|
|
1845
|
+
for (const entry of Object.entries(byId)) if ((entry[1]?.retainedBy?.mainView ?? 0) > 0) return entry[0];
|
|
1846
|
+
}
|
|
1847
|
+
//#endregion
|
|
1790
1848
|
//#region src/client/data.ts
|
|
1791
1849
|
/**
|
|
1792
1850
|
* Shared client-side study store: one module-level poller over the host
|
|
@@ -8485,9 +8543,9 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8485
8543
|
}
|
|
8486
8544
|
const shell = PANEL_SHELL.current;
|
|
8487
8545
|
if (shell !== null) shell.suppressHandBack(() => {
|
|
8488
|
-
ctx.sessions
|
|
8546
|
+
stageSession(ctx.sessions, sessionId);
|
|
8489
8547
|
});
|
|
8490
|
-
else ctx.sessions
|
|
8548
|
+
else stageSession(ctx.sessions, sessionId);
|
|
8491
8549
|
const actx = ctx.sessions.scope(sessionId);
|
|
8492
8550
|
const face = actx === void 0 ? void 0 : ctx.sessions.sessionOf(actx);
|
|
8493
8551
|
if (face === void 0) throw new Error("import session is not addressable yet");
|
|
@@ -8530,6 +8588,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8530
8588
|
(0, react.useEffect)(() => {
|
|
8531
8589
|
setPressure(null);
|
|
8532
8590
|
if (boundId === null) return;
|
|
8591
|
+
const closeStage = acquireStageReference(ctx.sessions, boundId);
|
|
8533
8592
|
let disposed = false;
|
|
8534
8593
|
let off;
|
|
8535
8594
|
try {
|
|
@@ -8555,22 +8614,27 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8555
8614
|
}
|
|
8556
8615
|
};
|
|
8557
8616
|
read();
|
|
8558
|
-
off = proj.subscribe(
|
|
8617
|
+
off = proj.subscribe(() => {
|
|
8618
|
+
queueMicrotask(read);
|
|
8619
|
+
});
|
|
8559
8620
|
return () => {
|
|
8560
8621
|
disposed = true;
|
|
8561
8622
|
off?.();
|
|
8623
|
+
closeStage?.();
|
|
8562
8624
|
};
|
|
8563
8625
|
}
|
|
8564
8626
|
} catch {}
|
|
8565
8627
|
return () => {
|
|
8566
8628
|
disposed = true;
|
|
8567
8629
|
off?.();
|
|
8630
|
+
closeStage?.();
|
|
8568
8631
|
};
|
|
8569
8632
|
}, [boundId, ctx.sessions]);
|
|
8570
8633
|
const [modelFace, setModelFace] = (0, react.useState)(null);
|
|
8571
8634
|
(0, react.useEffect)(() => {
|
|
8572
8635
|
setModelFace(null);
|
|
8573
8636
|
if (boundId === null) return;
|
|
8637
|
+
const closeStage = acquireStageReference(ctx.sessions, boundId);
|
|
8574
8638
|
let disposed = false;
|
|
8575
8639
|
let off;
|
|
8576
8640
|
try {
|
|
@@ -8582,16 +8646,20 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8582
8646
|
if (!disposed && snap !== void 0 && typeof snap === "object" && snap.next !== void 0 && snap.next !== null) setModelFace(snap.next);
|
|
8583
8647
|
};
|
|
8584
8648
|
read();
|
|
8585
|
-
off = proj.subscribe(
|
|
8649
|
+
off = proj.subscribe(() => {
|
|
8650
|
+
queueMicrotask(read);
|
|
8651
|
+
});
|
|
8586
8652
|
return () => {
|
|
8587
8653
|
disposed = true;
|
|
8588
8654
|
off?.();
|
|
8655
|
+
closeStage?.();
|
|
8589
8656
|
};
|
|
8590
8657
|
}
|
|
8591
8658
|
} catch {}
|
|
8592
8659
|
return () => {
|
|
8593
8660
|
disposed = true;
|
|
8594
8661
|
off?.();
|
|
8662
|
+
closeStage?.();
|
|
8595
8663
|
};
|
|
8596
8664
|
}, [boundId, ctx.sessions]);
|
|
8597
8665
|
(0, react.useEffect)(() => {
|
|
@@ -8620,7 +8688,9 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8620
8688
|
};
|
|
8621
8689
|
update();
|
|
8622
8690
|
setFeedAttached(true);
|
|
8623
|
-
offSource = source.subscribe(
|
|
8691
|
+
offSource = source.subscribe(() => {
|
|
8692
|
+
queueMicrotask(update);
|
|
8693
|
+
});
|
|
8624
8694
|
return true;
|
|
8625
8695
|
};
|
|
8626
8696
|
const stage = () => {
|
|
@@ -8628,13 +8698,17 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8628
8698
|
try {
|
|
8629
8699
|
const shell = PANEL_SHELL.current;
|
|
8630
8700
|
if (shell !== null) shell.suppressHandBack(() => {
|
|
8631
|
-
ctx.sessions
|
|
8701
|
+
stageSession(ctx.sessions, boundId);
|
|
8632
8702
|
});
|
|
8633
|
-
else ctx.sessions
|
|
8703
|
+
else stageSession(ctx.sessions, boundId);
|
|
8634
8704
|
} catch {}
|
|
8635
8705
|
};
|
|
8636
8706
|
const reconcile = () => {
|
|
8637
8707
|
if (disposed || offSource !== void 0) return true;
|
|
8708
|
+
if (stagingMode(ctx.sessions) === "retain") {
|
|
8709
|
+
stage();
|
|
8710
|
+
return attach();
|
|
8711
|
+
}
|
|
8638
8712
|
if (ctx.sessions.list?.getSnapshot().current !== boundId) {
|
|
8639
8713
|
stage();
|
|
8640
8714
|
return false;
|
|
@@ -8648,10 +8722,12 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8648
8722
|
}, 150);
|
|
8649
8723
|
const list = ctx.sessions.list;
|
|
8650
8724
|
if (list !== void 0) offList = list.subscribe(() => {
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8725
|
+
queueMicrotask(() => {
|
|
8726
|
+
if (disposed || reconcile()) {
|
|
8727
|
+
offList?.();
|
|
8728
|
+
offList = void 0;
|
|
8729
|
+
}
|
|
8730
|
+
});
|
|
8655
8731
|
});
|
|
8656
8732
|
return () => {
|
|
8657
8733
|
disposed = true;
|
|
@@ -8716,9 +8792,9 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8716
8792
|
}
|
|
8717
8793
|
const shell = PANEL_SHELL.current;
|
|
8718
8794
|
if (shell !== null) shell.suppressHandBack(() => {
|
|
8719
|
-
ctx.sessions
|
|
8795
|
+
stageSession(ctx.sessions, sessionId);
|
|
8720
8796
|
});
|
|
8721
|
-
else ctx.sessions
|
|
8797
|
+
else stageSession(ctx.sessions, sessionId);
|
|
8722
8798
|
const actx = ctx.sessions.scope(sessionId);
|
|
8723
8799
|
const face = actx === void 0 ? void 0 : ctx.sessions.sessionOf(actx);
|
|
8724
8800
|
if (face === void 0) throw new Error("lesson session is not addressable yet");
|
|
@@ -8758,9 +8834,9 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8758
8834
|
bindLessonSession(lesson.lessonId, sessionId);
|
|
8759
8835
|
const shell = PANEL_SHELL.current;
|
|
8760
8836
|
if (shell !== null) shell.suppressHandBack(() => {
|
|
8761
|
-
ctx.sessions
|
|
8837
|
+
stageSession(ctx.sessions, sessionId);
|
|
8762
8838
|
});
|
|
8763
|
-
else ctx.sessions
|
|
8839
|
+
else stageSession(ctx.sessions, sessionId);
|
|
8764
8840
|
};
|
|
8765
8841
|
const startNewThread = () => {
|
|
8766
8842
|
if (lesson === null) return;
|
|
@@ -8773,8 +8849,12 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
8773
8849
|
const renameLessonThreadUi = (sessionId, title) => {
|
|
8774
8850
|
if (lesson === null) return;
|
|
8775
8851
|
lessonThreadOp(lesson.lessonId, sessionId, "rename", { title }).then(() => {
|
|
8852
|
+
const closeRef = acquireStageReference(ctx.sessions, sessionId);
|
|
8853
|
+
if (closeRef === void 0) return;
|
|
8776
8854
|
const actx = ctx.sessions.scope(sessionId);
|
|
8777
|
-
(actx === void 0 ? void 0 : ctx.sessions.sessionOf(actx))?.rename?.(title).catch(() => {})
|
|
8855
|
+
(actx === void 0 ? void 0 : ctx.sessions.sessionOf(actx))?.rename?.(title).catch(() => {}).finally(() => {
|
|
8856
|
+
closeRef();
|
|
8857
|
+
});
|
|
8778
8858
|
}, (err) => {
|
|
8779
8859
|
setSendError(friendlyError(err, "action"));
|
|
8780
8860
|
});
|
|
@@ -11127,8 +11207,8 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
11127
11207
|
* event.
|
|
11128
11208
|
*
|
|
11129
11209
|
* Differences from stardeck's original: our own attribute namespace, a
|
|
11130
|
-
* hand-back SUPPRESSION hook (the panel itself
|
|
11131
|
-
*
|
|
11210
|
+
* hand-back SUPPRESSION hook (the panel itself stages the focus lesson's
|
|
11211
|
+
* thread through stage-session.ts — an internal navigation must not close the
|
|
11132
11212
|
* panel; only USER session navigation hands the column back), and dsw-token
|
|
11133
11213
|
* styling via the injected stylesheet.
|
|
11134
11214
|
* @module dsh-plugin-lookatstudy/client/shell-entry
|
|
@@ -11287,13 +11367,21 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
11287
11367
|
doc.addEventListener(ACTIVATE_EVENT, onOtherActivate);
|
|
11288
11368
|
let unsubscribeSessions;
|
|
11289
11369
|
if (sessions?.list !== void 0) {
|
|
11290
|
-
|
|
11370
|
+
const readSelection = () => {
|
|
11371
|
+
const snap = sessions.list.getSnapshot();
|
|
11372
|
+
if (snap.current !== void 0) return snap.current;
|
|
11373
|
+
return mainSelectionOf(snap.byId);
|
|
11374
|
+
};
|
|
11375
|
+
let lastCurrent = readSelection();
|
|
11291
11376
|
unsubscribeSessions = sessions.list.subscribe(() => {
|
|
11292
|
-
const
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11377
|
+
const wasSuppressed = suppressed;
|
|
11378
|
+
queueMicrotask(() => {
|
|
11379
|
+
const next = readSelection();
|
|
11380
|
+
if (next === lastCurrent) return;
|
|
11381
|
+
const wasHydration = lastCurrent === void 0;
|
|
11382
|
+
lastCurrent = next;
|
|
11383
|
+
if (shouldHandBack(wasSuppressed, wasHydration)) state.setOpen(false);
|
|
11384
|
+
});
|
|
11297
11385
|
});
|
|
11298
11386
|
}
|
|
11299
11387
|
const unsubscribe = state.subscribe(applyActive);
|
|
@@ -11318,6 +11406,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
11318
11406
|
doc.removeEventListener(ACTIVATE_EVENT, onOtherActivate);
|
|
11319
11407
|
unsubscribeSessions?.();
|
|
11320
11408
|
unsubscribe();
|
|
11409
|
+
unstageSession();
|
|
11321
11410
|
root?.unmount();
|
|
11322
11411
|
container?.remove();
|
|
11323
11412
|
row.remove();
|