@opengeni/react 7.6.1 → 7.7.0-canary.37111190284001
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 +47 -2
- package/dist/{browser-viewer-5X47I6T2.js → browser-viewer-63TXMINB.js} +6 -5
- package/dist/{chunk-5EXGU7UF.js → chunk-55DDDVKU.js} +3 -3
- package/dist/{chunk-UINDK6C3.js → chunk-7CYYXWHU.js} +5 -8
- package/dist/chunk-7CYYXWHU.js.map +1 -0
- package/dist/{chunk-LZ3KHA55.js → chunk-A2L5N3EI.js} +332 -339
- package/dist/chunk-A2L5N3EI.js.map +1 -0
- package/dist/{chunk-KGENSZKS.js → chunk-AAG4R3QN.js} +4 -3
- package/dist/chunk-AAG4R3QN.js.map +1 -0
- package/dist/{chunk-Z3DISEQN.js → chunk-CWWKTNKK.js} +35 -18
- package/dist/chunk-CWWKTNKK.js.map +1 -0
- package/dist/{chunk-WZ55DVGK.js → chunk-ELCE5SXV.js} +8 -4
- package/dist/chunk-ELCE5SXV.js.map +1 -0
- package/dist/{chunk-YSMMDOOE.js → chunk-GISEVGS6.js} +10 -2
- package/dist/chunk-GISEVGS6.js.map +1 -0
- package/dist/{chunk-BI57CQUV.js → chunk-I7IWRQLN.js} +2 -2
- package/dist/{chunk-XA6R7DJQ.js → chunk-IQUCRAT7.js} +3 -3
- package/dist/{chunk-CHPKSLPN.js → chunk-NBZ64YY7.js} +4 -2
- package/dist/chunk-NBZ64YY7.js.map +1 -0
- package/dist/{chunk-DV2DBNPQ.js → chunk-Q5QBEZIQ.js} +48 -29
- package/dist/chunk-Q5QBEZIQ.js.map +1 -0
- package/dist/{chunk-FGBCYQOT.js → chunk-RDKBXMWX.js} +120 -74
- package/dist/chunk-RDKBXMWX.js.map +1 -0
- package/dist/{chunk-45GE35O7.js → chunk-TKB4SB44.js} +10 -2
- package/dist/chunk-TKB4SB44.js.map +1 -0
- package/dist/{chunk-YCGBREUV.js → chunk-TOAH2BKA.js} +6 -2
- package/dist/{chunk-YCGBREUV.js.map → chunk-TOAH2BKA.js.map} +1 -1
- package/dist/chunk-UGLEYEMP.js +33 -0
- package/dist/chunk-UGLEYEMP.js.map +1 -0
- package/dist/{chunk-UJRYEWZI.js → chunk-UTRTG6LH.js} +48 -8
- package/dist/chunk-UTRTG6LH.js.map +1 -0
- package/dist/{chunk-YRYF2GLG.js → chunk-WYVLAAJA.js} +39 -31
- package/dist/chunk-WYVLAAJA.js.map +1 -0
- package/dist/{chunk-VGIKFIO2.js → chunk-XOAMRDDK.js} +6 -3
- package/dist/chunk-XOAMRDDK.js.map +1 -0
- package/dist/{chunk-6NEZPF53.js → chunk-YN7I3STW.js} +153 -32
- package/dist/chunk-YN7I3STW.js.map +1 -0
- package/dist/{chunk-KZ73RL76.js → chunk-YQEAA6LT.js} +7 -3
- package/dist/chunk-YQEAA6LT.js.map +1 -0
- package/dist/client.d.ts +4 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/approval-surface.d.ts +15 -0
- package/dist/components/session-conversation.d.ts +3 -0
- package/dist/composer.js +8 -7
- package/dist/{computer-viewer-7GF35SNY.js → computer-viewer-X2MBRZY4.js} +5 -4
- package/dist/connect.js +3 -3
- package/dist/hooks/use-browser-session.d.ts +4 -0
- package/dist/hooks/use-composer.d.ts +2 -0
- package/dist/hooks/use-computer-session.d.ts +2 -0
- package/dist/hooks/use-file-attachments.d.ts +2 -0
- package/dist/hooks/use-session-events.d.ts +1 -1
- package/dist/hooks/use-workspace-sessions.d.ts +15 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +28 -21
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +1 -1
- package/dist/interaction.js +6 -5
- package/dist/interaction.js.map +1 -1
- package/dist/{latest-question-3BJGKQQ6.js → latest-question-CNEZ5KAN.js} +3 -3
- package/dist/lib/error-message.d.ts +7 -0
- package/dist/lib/format.d.ts +27 -3
- package/dist/lib/interaction-errors.d.ts +3 -0
- package/dist/machines.js +5 -4
- package/dist/{model-policy-picker-menu-PUTA5JOB.js → model-policy-picker-menu-GN2LTB7Z.js} +4 -4
- package/dist/model-policy.js +1 -1
- package/dist/provider.d.ts +5 -1
- package/dist/{queue-surface-implementation-2CAQAIHM.js → queue-surface-implementation-HENWYFWA.js} +3 -2
- package/dist/{queue-surface-implementation-2CAQAIHM.js.map → queue-surface-implementation-HENWYFWA.js.map} +1 -1
- package/dist/realtime.js +2 -2
- package/dist/{sandbox-files-AEJTWGT4.js → sandbox-files-BBC47SLD.js} +4 -3
- package/dist/session-ui.d.ts +1 -1
- package/dist/session-ui.js +13 -12
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +7 -6
- package/dist/usage.js +2 -1
- package/dist/usage.js.map +1 -1
- package/package.json +3 -3
- package/src/client.ts +5 -1
- package/src/commands/registry.ts +18 -15
- package/src/commands/types.ts +2 -0
- package/src/components/approval-surface.tsx +166 -42
- package/src/components/browser-viewer.tsx +38 -9
- package/src/components/composer.tsx +9 -2
- package/src/components/computer-viewer.tsx +160 -30
- package/src/components/generated-video-player.tsx +4 -2
- package/src/components/human-input-form.tsx +18 -5
- package/src/components/message-timeline.tsx +120 -168
- package/src/components/model-policy-picker.tsx +2 -15
- package/src/components/open-geni-chat.tsx +11 -4
- package/src/components/queue-surface-state.tsx +3 -1
- package/src/components/session-chrome.tsx +5 -2
- package/src/components/session-commands-panel.tsx +3 -1
- package/src/components/session-conversation.tsx +10 -3
- package/src/components/session-list.tsx +7 -5
- package/src/components/session-mcp-capability-card.tsx +11 -1
- package/src/hooks/internal.ts +3 -2
- package/src/hooks/use-browser-session.ts +115 -79
- package/src/hooks/use-composer.ts +70 -31
- package/src/hooks/use-computer-session.ts +57 -6
- package/src/hooks/use-file-attachments.ts +16 -3
- package/src/hooks/use-goal.ts +2 -1
- package/src/hooks/use-session-capabilities.ts +3 -2
- package/src/hooks/use-session-events.ts +15 -8
- package/src/hooks/use-slash-commands.ts +6 -11
- package/src/hooks/use-turn-queue.ts +2 -1
- package/src/hooks/use-workspace-sessions.ts +40 -7
- package/src/index.ts +7 -2
- package/src/interaction.ts +1 -0
- package/src/lib/error-message.ts +37 -0
- package/src/lib/format.ts +73 -9
- package/src/lib/interaction-errors.ts +15 -0
- package/src/model-policy.ts +6 -1
- package/src/provider.tsx +12 -4
- package/src/session-ui.ts +1 -1
- package/src/timeline/projection.ts +12 -1
- package/styles/compiled.css +14 -30
- package/dist/chunk-45GE35O7.js.map +0 -1
- package/dist/chunk-6NEZPF53.js.map +0 -1
- package/dist/chunk-CHPKSLPN.js.map +0 -1
- package/dist/chunk-DV2DBNPQ.js.map +0 -1
- package/dist/chunk-FGBCYQOT.js.map +0 -1
- package/dist/chunk-KGENSZKS.js.map +0 -1
- package/dist/chunk-KZ73RL76.js.map +0 -1
- package/dist/chunk-LZ3KHA55.js.map +0 -1
- package/dist/chunk-UINDK6C3.js.map +0 -1
- package/dist/chunk-UJRYEWZI.js.map +0 -1
- package/dist/chunk-VGIKFIO2.js.map +0 -1
- package/dist/chunk-WZ55DVGK.js.map +0 -1
- package/dist/chunk-YRYF2GLG.js.map +0 -1
- package/dist/chunk-YSMMDOOE.js.map +0 -1
- package/dist/chunk-Z3DISEQN.js.map +0 -1
- package/dist/components/timeline-pill-geometry.d.ts +0 -8
- package/dist/components/timeline-pill-placement.d.ts +0 -24
- package/dist/timeline-pill-geometry-Z23V243M.js +0 -110
- package/dist/timeline-pill-geometry-Z23V243M.js.map +0 -1
- package/src/components/timeline-pill-geometry.ts +0 -169
- package/src/components/timeline-pill-placement.ts +0 -99
- /package/dist/{browser-viewer-5X47I6T2.js.map → browser-viewer-63TXMINB.js.map} +0 -0
- /package/dist/{chunk-5EXGU7UF.js.map → chunk-55DDDVKU.js.map} +0 -0
- /package/dist/{chunk-BI57CQUV.js.map → chunk-I7IWRQLN.js.map} +0 -0
- /package/dist/{chunk-XA6R7DJQ.js.map → chunk-IQUCRAT7.js.map} +0 -0
- /package/dist/{computer-viewer-7GF35SNY.js.map → computer-viewer-X2MBRZY4.js.map} +0 -0
- /package/dist/{latest-question-3BJGKQQ6.js.map → latest-question-CNEZ5KAN.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-PUTA5JOB.js.map → model-policy-picker-menu-GN2LTB7Z.js.map} +0 -0
- /package/dist/{sandbox-files-AEJTWGT4.js.map → sandbox-files-BBC47SLD.js.map} +0 -0
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
// src/components/timeline-pill-geometry.ts
|
|
2
|
-
var INTERACTIVE = 'a[href], button, input, select, textarea, summary, [role="button"], [role="link"], [role="menuitem"], [role="tab"], [role="switch"], [role="checkbox"], [contenteditable="true"]';
|
|
3
|
-
var ROW_WIDTH_RATIO = 0.8;
|
|
4
|
-
function chooseQuestionPosition(pill, frame, scroller, preference, current) {
|
|
5
|
-
const rect = pill.getBoundingClientRect();
|
|
6
|
-
const bounds = frame.getBoundingClientRect();
|
|
7
|
-
const view = scroller.getBoundingClientRect();
|
|
8
|
-
if (!rect.width || !view.width) return current;
|
|
9
|
-
const style = getComputedStyle(frame);
|
|
10
|
-
const baseTop = bounds.top - current.offsetY;
|
|
11
|
-
const left = (placement) => placement === "start" ? bounds.left + parseFloat(style.paddingLeft || "0") : placement === "end" ? bounds.right - parseFloat(style.paddingRight || "0") - rect.width : bounds.left + (bounds.width - rect.width) / 2;
|
|
12
|
-
const controls = [];
|
|
13
|
-
for (const control of scroller.querySelectorAll(INTERACTIVE)) {
|
|
14
|
-
const box = control.getBoundingClientRect();
|
|
15
|
-
if (!box.width || !box.height || box.bottom <= baseTop || box.top >= view.bottom) continue;
|
|
16
|
-
if (box.width < view.width * ROW_WIDTH_RATIO) controls.push(box);
|
|
17
|
-
else {
|
|
18
|
-
for (const icon of control.querySelectorAll("svg, img, canvas, video"))
|
|
19
|
-
controls.push(icon.getBoundingClientRect());
|
|
20
|
-
const walker = scroller.ownerDocument.createTreeWalker(control, NodeFilter.SHOW_TEXT);
|
|
21
|
-
for (let text = walker.nextNode(); text; text = walker.nextNode()) {
|
|
22
|
-
if (!text.textContent?.trim()) continue;
|
|
23
|
-
const range = scroller.ownerDocument.createRange();
|
|
24
|
-
range.selectNodeContents(text);
|
|
25
|
-
controls.push(...range.getClientRects());
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
const clear = (placement, offsetY) => !controls.some(
|
|
30
|
-
(control) => control.right > left(placement) && control.left < left(placement) + rect.width && control.bottom > baseTop + offsetY && control.top < baseTop + offsetY + rect.height
|
|
31
|
-
);
|
|
32
|
-
const order = [current.placement, ...preference.filter((value) => value !== current.placement)];
|
|
33
|
-
for (const placement of order) if (clear(placement, 0)) return { placement, offsetY: 0 };
|
|
34
|
-
const offsets = [...new Set(controls.map((control) => control.bottom + 4 - baseTop))].filter((offset) => offset > 0 && baseTop + offset + rect.height <= view.bottom).sort((a, b) => a - b);
|
|
35
|
-
for (const offsetY of offsets) {
|
|
36
|
-
for (const placement of order) if (clear(placement, offsetY)) return { placement, offsetY };
|
|
37
|
-
}
|
|
38
|
-
return current;
|
|
39
|
-
}
|
|
40
|
-
function choosePlacement(pill, frame, scroller, preference, current) {
|
|
41
|
-
const pillRect = pill.getBoundingClientRect();
|
|
42
|
-
const frameRect = frame.getBoundingClientRect();
|
|
43
|
-
const view = scroller.getBoundingClientRect();
|
|
44
|
-
if (pillRect.width === 0 || view.width === 0) return current;
|
|
45
|
-
const inset = Math.max(0, pillRect.left - frameRect.left, frameRect.right - pillRect.right);
|
|
46
|
-
const gutter = Math.min(inset, parseFloat(getComputedStyle(scroller).paddingLeft) || 16);
|
|
47
|
-
const left = (placement) => placement === "start" ? frameRect.left + gutter : placement === "end" ? frameRect.right - gutter - pillRect.width : frameRect.left + (frameRect.width - pillRect.width) / 2;
|
|
48
|
-
const collisions = (placement) => countCollisions(
|
|
49
|
-
pill,
|
|
50
|
-
scroller,
|
|
51
|
-
view,
|
|
52
|
-
left(placement),
|
|
53
|
-
pillRect.top,
|
|
54
|
-
pillRect.width,
|
|
55
|
-
pillRect.height
|
|
56
|
-
);
|
|
57
|
-
if (collisions(current) === 0) return current;
|
|
58
|
-
let best = current;
|
|
59
|
-
let fewest = Number.POSITIVE_INFINITY;
|
|
60
|
-
for (const candidate of preference) {
|
|
61
|
-
const count = candidate === current ? collisions(current) : collisions(candidate);
|
|
62
|
-
if (count === 0) return candidate;
|
|
63
|
-
if (count < fewest) {
|
|
64
|
-
fewest = count;
|
|
65
|
-
best = candidate;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return best;
|
|
69
|
-
}
|
|
70
|
-
function countCollisions(pill, scroller, view, left, top, width, height) {
|
|
71
|
-
const document = scroller.ownerDocument;
|
|
72
|
-
let count = 0;
|
|
73
|
-
for (const fx of [0.06, 0.3, 0.5, 0.7, 0.94]) {
|
|
74
|
-
for (const fy of [0.2, 0.5, 0.8]) {
|
|
75
|
-
const x = left + width * fx;
|
|
76
|
-
const y = top + height * fy;
|
|
77
|
-
if (x < view.left || x > view.right || y < view.top || y > view.bottom) continue;
|
|
78
|
-
if (coversControl(document.elementsFromPoint(x, y), pill, scroller, view, x, y)) count += 1;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return count;
|
|
82
|
-
}
|
|
83
|
-
function coversControl(stack, pill, scroller, view, x, y) {
|
|
84
|
-
for (const element of stack) {
|
|
85
|
-
if (pill.contains(element)) continue;
|
|
86
|
-
if (!scroller.contains(element) || element === scroller) return false;
|
|
87
|
-
const control = element.closest(INTERACTIVE);
|
|
88
|
-
if (!control || !scroller.contains(control)) return false;
|
|
89
|
-
if (control.getBoundingClientRect().width < view.width * ROW_WIDTH_RATIO) return true;
|
|
90
|
-
if (element.closest("svg, img, canvas, video")) return true;
|
|
91
|
-
return textUnderPoint(element, x, y);
|
|
92
|
-
}
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
function textUnderPoint(element, x, y) {
|
|
96
|
-
const range = element.ownerDocument.createRange();
|
|
97
|
-
for (const node of element.childNodes) {
|
|
98
|
-
if (node.nodeType !== Node.TEXT_NODE || !node.textContent?.trim()) continue;
|
|
99
|
-
range.selectNodeContents(node);
|
|
100
|
-
for (const rect of range.getClientRects()) {
|
|
101
|
-
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) return true;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
export {
|
|
107
|
-
choosePlacement,
|
|
108
|
-
chooseQuestionPosition
|
|
109
|
-
};
|
|
110
|
-
//# sourceMappingURL=timeline-pill-geometry-Z23V243M.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/timeline-pill-geometry.ts"],"sourcesContent":["import type { TimelinePillPlacement, TimelinePillPosition } from \"./timeline-pill-placement\";\n\nconst INTERACTIVE =\n 'a[href], button, input, select, textarea, summary, [role=\"button\"], [role=\"link\"], [role=\"menuitem\"], [role=\"tab\"], [role=\"switch\"], [role=\"checkbox\"], [contenteditable=\"true\"]';\n\n/** A control this wide is a row (a disclosure header); only what it draws counts. */\nconst ROW_WIDTH_RATIO = 0.8;\n\n/** The full contextual label may not fit beside a compact toolbar on phones. */\nexport function chooseQuestionPosition(\n pill: HTMLElement,\n frame: HTMLElement,\n scroller: HTMLElement,\n preference: readonly TimelinePillPlacement[],\n current: TimelinePillPosition,\n): TimelinePillPosition {\n const rect = pill.getBoundingClientRect();\n const bounds = frame.getBoundingClientRect();\n const view = scroller.getBoundingClientRect();\n if (!rect.width || !view.width) return current;\n const style = getComputedStyle(frame);\n const baseTop = bounds.top - current.offsetY;\n const left = (placement: TimelinePillPlacement) =>\n placement === \"start\"\n ? bounds.left + parseFloat(style.paddingLeft || \"0\")\n : placement === \"end\"\n ? bounds.right - parseFloat(style.paddingRight || \"0\") - rect.width\n : bounds.left + (bounds.width - rect.width) / 2;\n const controls: DOMRect[] = [];\n for (const control of scroller.querySelectorAll<HTMLElement>(INTERACTIVE)) {\n const box = control.getBoundingClientRect();\n if (!box.width || !box.height || box.bottom <= baseTop || box.top >= view.bottom) continue;\n if (box.width < view.width * ROW_WIDTH_RATIO) controls.push(box);\n else {\n for (const icon of control.querySelectorAll(\"svg, img, canvas, video\"))\n controls.push(icon.getBoundingClientRect());\n const walker = scroller.ownerDocument.createTreeWalker(control, NodeFilter.SHOW_TEXT);\n for (let text = walker.nextNode(); text; text = walker.nextNode()) {\n if (!text.textContent?.trim()) continue;\n const range = scroller.ownerDocument.createRange();\n range.selectNodeContents(text);\n controls.push(...range.getClientRects());\n }\n }\n }\n const clear = (placement: TimelinePillPlacement, offsetY: number) =>\n !controls.some(\n (control) =>\n control.right > left(placement) &&\n control.left < left(placement) + rect.width &&\n control.bottom > baseTop + offsetY &&\n control.top < baseTop + offsetY + rect.height,\n );\n const order = [current.placement, ...preference.filter((value) => value !== current.placement)];\n // Return to the normal strip once it is clear, without touching scroll geometry.\n for (const placement of order) if (clear(placement, 0)) return { placement, offsetY: 0 };\n const offsets = [...new Set(controls.map((control) => control.bottom + 4 - baseTop))]\n .filter((offset) => offset > 0 && baseTop + offset + rect.height <= view.bottom)\n .sort((a, b) => a - b);\n for (const offsetY of offsets) {\n for (const placement of order) if (clear(placement, offsetY)) return { placement, offsetY };\n }\n return current;\n}\n\n/**\n * Hit-testing for useTimelinePillPlacement, loaded only once a pill shows so it\n * stays out of a session's first load.\n */\nexport function choosePlacement(\n pill: HTMLElement,\n frame: HTMLElement,\n scroller: HTMLElement,\n preference: readonly TimelinePillPlacement[],\n current: TimelinePillPlacement,\n): TimelinePillPlacement {\n const pillRect = pill.getBoundingClientRect();\n const frameRect = frame.getBoundingClientRect();\n const view = scroller.getBoundingClientRect();\n if (pillRect.width === 0 || view.width === 0) return current;\n const inset = Math.max(0, pillRect.left - frameRect.left, frameRect.right - pillRect.right);\n const gutter = Math.min(inset, parseFloat(getComputedStyle(scroller).paddingLeft) || 16);\n const left = (placement: TimelinePillPlacement) =>\n placement === \"start\"\n ? frameRect.left + gutter\n : placement === \"end\"\n ? frameRect.right - gutter - pillRect.width\n : frameRect.left + (frameRect.width - pillRect.width) / 2;\n const collisions = (placement: TimelinePillPlacement) =>\n countCollisions(\n pill,\n scroller,\n view,\n left(placement),\n pillRect.top,\n pillRect.width,\n pillRect.height,\n );\n // Stay put while the current spot is clear, so the pill does not wander.\n if (collisions(current) === 0) return current;\n let best = current;\n let fewest = Number.POSITIVE_INFINITY;\n for (const candidate of preference) {\n const count = candidate === current ? collisions(current) : collisions(candidate);\n if (count === 0) return candidate;\n if (count < fewest) {\n fewest = count;\n best = candidate;\n }\n }\n return best;\n}\n\nfunction countCollisions(\n pill: HTMLElement,\n scroller: HTMLElement,\n view: DOMRect,\n left: number,\n top: number,\n width: number,\n height: number,\n): number {\n const document = scroller.ownerDocument;\n let count = 0;\n for (const fx of [0.06, 0.3, 0.5, 0.7, 0.94]) {\n for (const fy of [0.2, 0.5, 0.8]) {\n const x = left + width * fx;\n const y = top + height * fy;\n if (x < view.left || x > view.right || y < view.top || y > view.bottom) continue;\n if (coversControl(document.elementsFromPoint(x, y), pill, scroller, view, x, y)) count += 1;\n }\n }\n return count;\n}\n\nfunction coversControl(\n stack: Element[],\n pill: HTMLElement,\n scroller: HTMLElement,\n view: DOMRect,\n x: number,\n y: number,\n): boolean {\n for (const element of stack) {\n if (pill.contains(element)) continue;\n if (!scroller.contains(element) || element === scroller) return false;\n const control = element.closest(INTERACTIVE);\n if (!control || !scroller.contains(control)) return false;\n // A compact control (a link, an icon button) is covered anywhere on its box.\n if (control.getBoundingClientRect().width < view.width * ROW_WIDTH_RATIO) return true;\n // A full-width row (a disclosure header) only where it draws something: an\n // icon or the glyphs of its label, never its empty background.\n if (element.closest(\"svg, img, canvas, video\")) return true;\n return textUnderPoint(element, x, y);\n }\n return false;\n}\n\nfunction textUnderPoint(element: Element, x: number, y: number): boolean {\n const range = element.ownerDocument.createRange();\n for (const node of element.childNodes) {\n if (node.nodeType !== Node.TEXT_NODE || !node.textContent?.trim()) continue;\n range.selectNodeContents(node);\n for (const rect of range.getClientRects()) {\n if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) return true;\n }\n }\n return false;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import type { TimelinePillPlacement, TimelinePillPosition } from "./timeline-pill-placement";
|
|
2
|
-
|
|
3
|
-
const INTERACTIVE =
|
|
4
|
-
'a[href], button, input, select, textarea, summary, [role="button"], [role="link"], [role="menuitem"], [role="tab"], [role="switch"], [role="checkbox"], [contenteditable="true"]';
|
|
5
|
-
|
|
6
|
-
/** A control this wide is a row (a disclosure header); only what it draws counts. */
|
|
7
|
-
const ROW_WIDTH_RATIO = 0.8;
|
|
8
|
-
|
|
9
|
-
/** The full contextual label may not fit beside a compact toolbar on phones. */
|
|
10
|
-
export function chooseQuestionPosition(
|
|
11
|
-
pill: HTMLElement,
|
|
12
|
-
frame: HTMLElement,
|
|
13
|
-
scroller: HTMLElement,
|
|
14
|
-
preference: readonly TimelinePillPlacement[],
|
|
15
|
-
current: TimelinePillPosition,
|
|
16
|
-
): TimelinePillPosition {
|
|
17
|
-
const rect = pill.getBoundingClientRect();
|
|
18
|
-
const bounds = frame.getBoundingClientRect();
|
|
19
|
-
const view = scroller.getBoundingClientRect();
|
|
20
|
-
if (!rect.width || !view.width) return current;
|
|
21
|
-
const style = getComputedStyle(frame);
|
|
22
|
-
const baseTop = bounds.top - current.offsetY;
|
|
23
|
-
const left = (placement: TimelinePillPlacement) =>
|
|
24
|
-
placement === "start"
|
|
25
|
-
? bounds.left + parseFloat(style.paddingLeft || "0")
|
|
26
|
-
: placement === "end"
|
|
27
|
-
? bounds.right - parseFloat(style.paddingRight || "0") - rect.width
|
|
28
|
-
: bounds.left + (bounds.width - rect.width) / 2;
|
|
29
|
-
const controls: DOMRect[] = [];
|
|
30
|
-
for (const control of scroller.querySelectorAll<HTMLElement>(INTERACTIVE)) {
|
|
31
|
-
const box = control.getBoundingClientRect();
|
|
32
|
-
if (!box.width || !box.height || box.bottom <= baseTop || box.top >= view.bottom) continue;
|
|
33
|
-
if (box.width < view.width * ROW_WIDTH_RATIO) controls.push(box);
|
|
34
|
-
else {
|
|
35
|
-
for (const icon of control.querySelectorAll("svg, img, canvas, video"))
|
|
36
|
-
controls.push(icon.getBoundingClientRect());
|
|
37
|
-
const walker = scroller.ownerDocument.createTreeWalker(control, NodeFilter.SHOW_TEXT);
|
|
38
|
-
for (let text = walker.nextNode(); text; text = walker.nextNode()) {
|
|
39
|
-
if (!text.textContent?.trim()) continue;
|
|
40
|
-
const range = scroller.ownerDocument.createRange();
|
|
41
|
-
range.selectNodeContents(text);
|
|
42
|
-
controls.push(...range.getClientRects());
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const clear = (placement: TimelinePillPlacement, offsetY: number) =>
|
|
47
|
-
!controls.some(
|
|
48
|
-
(control) =>
|
|
49
|
-
control.right > left(placement) &&
|
|
50
|
-
control.left < left(placement) + rect.width &&
|
|
51
|
-
control.bottom > baseTop + offsetY &&
|
|
52
|
-
control.top < baseTop + offsetY + rect.height,
|
|
53
|
-
);
|
|
54
|
-
const order = [current.placement, ...preference.filter((value) => value !== current.placement)];
|
|
55
|
-
// Return to the normal strip once it is clear, without touching scroll geometry.
|
|
56
|
-
for (const placement of order) if (clear(placement, 0)) return { placement, offsetY: 0 };
|
|
57
|
-
const offsets = [...new Set(controls.map((control) => control.bottom + 4 - baseTop))]
|
|
58
|
-
.filter((offset) => offset > 0 && baseTop + offset + rect.height <= view.bottom)
|
|
59
|
-
.sort((a, b) => a - b);
|
|
60
|
-
for (const offsetY of offsets) {
|
|
61
|
-
for (const placement of order) if (clear(placement, offsetY)) return { placement, offsetY };
|
|
62
|
-
}
|
|
63
|
-
return current;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Hit-testing for useTimelinePillPlacement, loaded only once a pill shows so it
|
|
68
|
-
* stays out of a session's first load.
|
|
69
|
-
*/
|
|
70
|
-
export function choosePlacement(
|
|
71
|
-
pill: HTMLElement,
|
|
72
|
-
frame: HTMLElement,
|
|
73
|
-
scroller: HTMLElement,
|
|
74
|
-
preference: readonly TimelinePillPlacement[],
|
|
75
|
-
current: TimelinePillPlacement,
|
|
76
|
-
): TimelinePillPlacement {
|
|
77
|
-
const pillRect = pill.getBoundingClientRect();
|
|
78
|
-
const frameRect = frame.getBoundingClientRect();
|
|
79
|
-
const view = scroller.getBoundingClientRect();
|
|
80
|
-
if (pillRect.width === 0 || view.width === 0) return current;
|
|
81
|
-
const inset = Math.max(0, pillRect.left - frameRect.left, frameRect.right - pillRect.right);
|
|
82
|
-
const gutter = Math.min(inset, parseFloat(getComputedStyle(scroller).paddingLeft) || 16);
|
|
83
|
-
const left = (placement: TimelinePillPlacement) =>
|
|
84
|
-
placement === "start"
|
|
85
|
-
? frameRect.left + gutter
|
|
86
|
-
: placement === "end"
|
|
87
|
-
? frameRect.right - gutter - pillRect.width
|
|
88
|
-
: frameRect.left + (frameRect.width - pillRect.width) / 2;
|
|
89
|
-
const collisions = (placement: TimelinePillPlacement) =>
|
|
90
|
-
countCollisions(
|
|
91
|
-
pill,
|
|
92
|
-
scroller,
|
|
93
|
-
view,
|
|
94
|
-
left(placement),
|
|
95
|
-
pillRect.top,
|
|
96
|
-
pillRect.width,
|
|
97
|
-
pillRect.height,
|
|
98
|
-
);
|
|
99
|
-
// Stay put while the current spot is clear, so the pill does not wander.
|
|
100
|
-
if (collisions(current) === 0) return current;
|
|
101
|
-
let best = current;
|
|
102
|
-
let fewest = Number.POSITIVE_INFINITY;
|
|
103
|
-
for (const candidate of preference) {
|
|
104
|
-
const count = candidate === current ? collisions(current) : collisions(candidate);
|
|
105
|
-
if (count === 0) return candidate;
|
|
106
|
-
if (count < fewest) {
|
|
107
|
-
fewest = count;
|
|
108
|
-
best = candidate;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return best;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function countCollisions(
|
|
115
|
-
pill: HTMLElement,
|
|
116
|
-
scroller: HTMLElement,
|
|
117
|
-
view: DOMRect,
|
|
118
|
-
left: number,
|
|
119
|
-
top: number,
|
|
120
|
-
width: number,
|
|
121
|
-
height: number,
|
|
122
|
-
): number {
|
|
123
|
-
const document = scroller.ownerDocument;
|
|
124
|
-
let count = 0;
|
|
125
|
-
for (const fx of [0.06, 0.3, 0.5, 0.7, 0.94]) {
|
|
126
|
-
for (const fy of [0.2, 0.5, 0.8]) {
|
|
127
|
-
const x = left + width * fx;
|
|
128
|
-
const y = top + height * fy;
|
|
129
|
-
if (x < view.left || x > view.right || y < view.top || y > view.bottom) continue;
|
|
130
|
-
if (coversControl(document.elementsFromPoint(x, y), pill, scroller, view, x, y)) count += 1;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return count;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function coversControl(
|
|
137
|
-
stack: Element[],
|
|
138
|
-
pill: HTMLElement,
|
|
139
|
-
scroller: HTMLElement,
|
|
140
|
-
view: DOMRect,
|
|
141
|
-
x: number,
|
|
142
|
-
y: number,
|
|
143
|
-
): boolean {
|
|
144
|
-
for (const element of stack) {
|
|
145
|
-
if (pill.contains(element)) continue;
|
|
146
|
-
if (!scroller.contains(element) || element === scroller) return false;
|
|
147
|
-
const control = element.closest(INTERACTIVE);
|
|
148
|
-
if (!control || !scroller.contains(control)) return false;
|
|
149
|
-
// A compact control (a link, an icon button) is covered anywhere on its box.
|
|
150
|
-
if (control.getBoundingClientRect().width < view.width * ROW_WIDTH_RATIO) return true;
|
|
151
|
-
// A full-width row (a disclosure header) only where it draws something: an
|
|
152
|
-
// icon or the glyphs of its label, never its empty background.
|
|
153
|
-
if (element.closest("svg, img, canvas, video")) return true;
|
|
154
|
-
return textUnderPoint(element, x, y);
|
|
155
|
-
}
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function textUnderPoint(element: Element, x: number, y: number): boolean {
|
|
160
|
-
const range = element.ownerDocument.createRange();
|
|
161
|
-
for (const node of element.childNodes) {
|
|
162
|
-
if (node.nodeType !== Node.TEXT_NODE || !node.textContent?.trim()) continue;
|
|
163
|
-
range.selectNodeContents(node);
|
|
164
|
-
for (const rect of range.getClientRects()) {
|
|
165
|
-
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) return true;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { type RefObject, useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
/** Where a floating timeline pill sits along its edge of the conversation. */
|
|
4
|
-
export type TimelinePillPlacement = "start" | "center" | "end";
|
|
5
|
-
export type TimelinePillPosition = { placement: TimelinePillPlacement; offsetY: number };
|
|
6
|
-
|
|
7
|
-
const RECHECK_MS = 1000;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Floating pills (Jump to latest, Back to your message) sit over the scrolling
|
|
11
|
-
* conversation. Prefer sliding one sideways when its spot would cover
|
|
12
|
-
* a control: a link, a button, or the label and chevron of a full-width row
|
|
13
|
-
* such as the active turn's "Working" header. Plain prose may sit under a pill;
|
|
14
|
-
* controls may not. The top contextual pill can also move below a toolbar when
|
|
15
|
-
* no horizontal slot fits. Only the pill moves — the scroller's size, padding, and
|
|
16
|
-
* scroll position never change — so timeline anchoring stays untouched.
|
|
17
|
-
*/
|
|
18
|
-
export function useTimelinePillPlacement({
|
|
19
|
-
pillRef,
|
|
20
|
-
scrollerRef,
|
|
21
|
-
active,
|
|
22
|
-
preference,
|
|
23
|
-
allowDownwardFallback = false,
|
|
24
|
-
}: {
|
|
25
|
-
pillRef: RefObject<HTMLElement | null>;
|
|
26
|
-
scrollerRef: RefObject<HTMLElement | null>;
|
|
27
|
-
active: boolean;
|
|
28
|
-
/** Placements in order of preference; the first is the resting position. */
|
|
29
|
-
preference: readonly TimelinePillPlacement[];
|
|
30
|
-
allowDownwardFallback?: boolean;
|
|
31
|
-
}): TimelinePillPosition {
|
|
32
|
-
const [position, setPosition] = useState<TimelinePillPosition>({
|
|
33
|
-
placement: preference[0]!,
|
|
34
|
-
offsetY: 0,
|
|
35
|
-
});
|
|
36
|
-
const key = preference.join(",");
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (!active) {
|
|
40
|
-
setPosition({ placement: preference[0]!, offsetY: 0 });
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const scroller = scrollerRef.current;
|
|
44
|
-
if (!scroller) return;
|
|
45
|
-
let frame = 0;
|
|
46
|
-
let current: TimelinePillPosition = { placement: preference[0]!, offsetY: 0 };
|
|
47
|
-
let geometry: typeof import("./timeline-pill-geometry") | null = null;
|
|
48
|
-
let disposed = false;
|
|
49
|
-
void import("./timeline-pill-geometry").then((loaded) => {
|
|
50
|
-
if (disposed) return;
|
|
51
|
-
geometry = loaded;
|
|
52
|
-
schedule();
|
|
53
|
-
});
|
|
54
|
-
const evaluate = () => {
|
|
55
|
-
frame = 0;
|
|
56
|
-
const pill = pillRef.current;
|
|
57
|
-
const frameElement = pill?.offsetParent;
|
|
58
|
-
if (!geometry || !pill || !(frameElement instanceof HTMLElement)) return;
|
|
59
|
-
const next = allowDownwardFallback
|
|
60
|
-
? geometry.chooseQuestionPosition(pill, frameElement, scroller, preference, current)
|
|
61
|
-
: {
|
|
62
|
-
placement: geometry.choosePlacement(
|
|
63
|
-
pill,
|
|
64
|
-
frameElement,
|
|
65
|
-
scroller,
|
|
66
|
-
preference,
|
|
67
|
-
current.placement,
|
|
68
|
-
),
|
|
69
|
-
offsetY: 0,
|
|
70
|
-
};
|
|
71
|
-
if (next.placement !== current.placement || next.offsetY !== current.offsetY) {
|
|
72
|
-
current = next;
|
|
73
|
-
setPosition(next);
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
const schedule = () => {
|
|
77
|
-
if (frame === 0) frame = requestAnimationFrame(evaluate);
|
|
78
|
-
};
|
|
79
|
-
schedule();
|
|
80
|
-
const view = scroller.ownerDocument.defaultView;
|
|
81
|
-
scroller.addEventListener("scroll", schedule, { passive: true });
|
|
82
|
-
view?.addEventListener("resize", schedule);
|
|
83
|
-
// Content and panel width can change under a stationary reader (a streaming
|
|
84
|
-
// row, a ticking elapsed time, a resized host panel), so look again now and
|
|
85
|
-
// then while the pill is shown.
|
|
86
|
-
const timer = setInterval(schedule, RECHECK_MS);
|
|
87
|
-
return () => {
|
|
88
|
-
disposed = true;
|
|
89
|
-
if (frame !== 0) cancelAnimationFrame(frame);
|
|
90
|
-
scroller.removeEventListener("scroll", schedule);
|
|
91
|
-
view?.removeEventListener("resize", schedule);
|
|
92
|
-
clearInterval(timer);
|
|
93
|
-
};
|
|
94
|
-
// `key` stands in for the preference array's contents.
|
|
95
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
96
|
-
}, [active, key, pillRef, scrollerRef, allowDownwardFallback]);
|
|
97
|
-
|
|
98
|
-
return active ? position : { placement: preference[0]!, offsetY: 0 };
|
|
99
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{model-policy-picker-menu-PUTA5JOB.js.map → model-policy-picker-menu-GN2LTB7Z.js.map}
RENAMED
|
File without changes
|
|
File without changes
|