@ahmedramez-org/nexus-chat 1.0.0-beta.23 → 1.0.0-beta.24
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 +3 -2
- package/package.json +1 -1
- package/react.d.ts +1 -1
- package/window.js +19 -16
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ build itself is not in this package: Copilot serves it, and each GitHub Release
|
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Incorta serves this script next to `embed.html`; it is not in this package and needs no build. It
|
|
20
|
-
draws the Incorta Intelligence launcher at the bottom right and opens the embedded chat (below)
|
|
20
|
+
draws the Incorta Intelligence launcher at the bottom right (bottom left on a `dir="rtl"` page) and opens the embedded chat (below)
|
|
21
21
|
floating, docked or full screen, on the user's Incorta session, so the page holds no token. It is
|
|
22
22
|
one classic script with no imports, so a page on any origin loads it without CORS.
|
|
23
23
|
|
|
@@ -42,7 +42,8 @@ import { NexusChat } from '@incorta/nexus-chat/react';
|
|
|
42
42
|
|
|
43
43
|
It draws its own window: an Incorta Intelligence launcher at the bottom right opens the chat
|
|
44
44
|
floating (a card lifted off the page, opening out of the launcher, which stays under it to hide
|
|
45
|
-
it) or docked flush on the right (the page makes room).
|
|
45
|
+
it) or docked flush on the right (the page makes room). On a `dir="rtl"` page the launcher and
|
|
46
|
+
window sit on the left, following a live `dir` change. The chat's own top bar switches between
|
|
46
47
|
the windows (Float, Dock to the side, Enter full screen: every allowed one but the current) and
|
|
47
48
|
closes it back to the launcher; nothing sits above the chat. `modes` limits the windows (default
|
|
48
49
|
all three, in that order) and `defaultMode` opens one on load. Below 768px wide the chat covers
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ahmedramez-org/nexus-chat",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.24",
|
|
4
4
|
"description": "NexusChat for any app: a connector and React component that load the prebuilt chat from IncortaCopilot (or a pinned copy), and the host contract types and checks.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
package/react.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export type NexusChatMode = NexusChatWindowMode;
|
|
|
75
75
|
/**
|
|
76
76
|
* The chat in an <iframe> served by Incorta, on the user's own Incorta
|
|
77
77
|
* session (the app never holds a token). It draws its window: a launcher
|
|
78
|
-
* icon that opens the chat floating, docked on the right, or fullscreen.
|
|
78
|
+
* icon that opens the chat floating, docked on the right (left on an RTL page), or fullscreen.
|
|
79
79
|
*/
|
|
80
80
|
export interface EmbeddedNexusChatProps {
|
|
81
81
|
/** Incorta's chat page: `<incorta>/copilot/nexus-chat/embed.html`. */
|
package/window.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// The chat's window, without a framework: a launcher icon that opens a panel
|
|
2
|
-
// floating, docked
|
|
2
|
+
// floating, docked at the page's end edge (the page makes room; left in RTL) or full screen, and the
|
|
3
3
|
// embedded chat's side of the iframe protocol. <NexusChat> (react.js) and the
|
|
4
4
|
// one-line script (widget.js) both draw the window with this, so they behave
|
|
5
5
|
// the same.
|
|
@@ -7,7 +7,7 @@ import { ICON, PALETTE, reducedMotion, showNexusChatSkeleton } from './index.js'
|
|
|
7
7
|
|
|
8
8
|
export const MODES = ['floating', 'docked', 'fullscreen'];
|
|
9
9
|
const PANEL_WIDTH = 400;
|
|
10
|
-
/** The floating window opens out of the launcher,
|
|
10
|
+
/** The floating window opens out of the launcher, end edges aligned, 12px above it. */
|
|
11
11
|
const FLOATING = { width: 380, height: 620, edge: 24, launcher: 52, gap: 12 };
|
|
12
12
|
/** Below this width a floating or docked chat would crush the app, so it covers it. */
|
|
13
13
|
const NARROW_VIEWPORT = 768;
|
|
@@ -32,45 +32,48 @@ const { edge, launcher: LAUNCHER_SIZE, gap } = FLOATING;
|
|
|
32
32
|
/** Every placement property any mode sets, cleared before the next mode's. */
|
|
33
33
|
const PLACED = [
|
|
34
34
|
'top',
|
|
35
|
-
'
|
|
35
|
+
'insetInlineEnd',
|
|
36
36
|
'bottom',
|
|
37
|
-
'
|
|
37
|
+
'insetInlineStart',
|
|
38
38
|
'inset',
|
|
39
39
|
'width',
|
|
40
40
|
'height',
|
|
41
41
|
'border',
|
|
42
|
-
'
|
|
42
|
+
'borderInlineStart',
|
|
43
43
|
'borderRadius',
|
|
44
44
|
'boxShadow',
|
|
45
45
|
'transformOrigin',
|
|
46
46
|
];
|
|
47
47
|
|
|
48
48
|
const isNarrow = () => typeof window !== 'undefined' && window.innerWidth < NARROW_VIEWPORT;
|
|
49
|
+
/** Placement follows the page's `dir`: logical properties, plus this for what has none. */
|
|
50
|
+
const isRtl = () =>
|
|
51
|
+
typeof document !== 'undefined' && getComputedStyle(document.documentElement).direction === 'rtl';
|
|
49
52
|
const tone = (theme) => (theme === 'dark' ? 'dark' : 'light');
|
|
50
53
|
|
|
51
54
|
function placement(mode, theme) {
|
|
52
55
|
const palette = PALETTE[tone(theme)];
|
|
53
56
|
if (mode === 'docked') {
|
|
54
|
-
// Flush against the page's
|
|
57
|
+
// Flush against the page's end edge (right, or left in RTL), full height: only a hairline between them.
|
|
55
58
|
return {
|
|
56
59
|
top: '0',
|
|
57
|
-
|
|
60
|
+
insetInlineEnd: '0',
|
|
58
61
|
bottom: '0',
|
|
59
62
|
width: `${PANEL_WIDTH}px`,
|
|
60
|
-
|
|
63
|
+
borderInlineStart: `1px solid ${palette.line}`,
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
if (mode === 'fullscreen') return { inset: '0' };
|
|
64
67
|
// A card lifted off the page, opening out of the launcher below it.
|
|
65
68
|
return {
|
|
66
|
-
|
|
69
|
+
insetInlineEnd: `${edge}px`,
|
|
67
70
|
bottom: `${edge + LAUNCHER_SIZE + gap}px`,
|
|
68
71
|
width: `min(${FLOATING.width}px, calc(100vw - ${2 * edge}px))`,
|
|
69
72
|
height: `min(${FLOATING.height}px, calc(100vh - ${2 * edge + LAUNCHER_SIZE + gap}px))`,
|
|
70
73
|
border: `1px solid ${palette.line}`,
|
|
71
74
|
borderRadius: '16px',
|
|
72
75
|
boxShadow: LIFT[tone(theme)],
|
|
73
|
-
transformOrigin:
|
|
76
|
+
transformOrigin: `bottom ${isRtl() ? 'left' : 'right'}`,
|
|
74
77
|
};
|
|
75
78
|
}
|
|
76
79
|
|
|
@@ -129,12 +132,12 @@ export function createChatWindow({ into, panel, modes = MODES, defaultMode, them
|
|
|
129
132
|
close.title = 'Close';
|
|
130
133
|
close.textContent = '×';
|
|
131
134
|
close.style.cssText =
|
|
132
|
-
'position:absolute;top:12px;
|
|
135
|
+
'position:absolute;top:12px;inset-inline-end:14px;z-index:1;width:36px;height:36px;border:0;border-radius:8px;background:transparent;color:inherit;font:20px/1 system-ui,sans-serif;cursor:pointer';
|
|
133
136
|
close.onclick = () => show('minimized');
|
|
134
137
|
|
|
135
138
|
const button = document.createElement('button');
|
|
136
139
|
button.type = 'button';
|
|
137
|
-
button.style.cssText = `position:fixed;
|
|
140
|
+
button.style.cssText = `position:fixed;inset-inline-end:${edge}px;bottom:${edge}px;z-index:50;box-sizing:border-box;width:${LAUNCHER_SIZE}px;height:${LAUNCHER_SIZE}px;padding:0;border-radius:50%;place-items:center;cursor:pointer`;
|
|
138
141
|
button.onclick = () =>
|
|
139
142
|
show(view === 'floating' && !narrow ? 'minimized' : (last ?? 'fullscreen'));
|
|
140
143
|
into.appendChild(button);
|
|
@@ -175,10 +178,10 @@ export function createChatWindow({ into, panel, modes = MODES, defaultMode, them
|
|
|
175
178
|
// A docked panel takes its width from the page instead of covering it.
|
|
176
179
|
const root = document.documentElement;
|
|
177
180
|
if (now === 'docked' && paddedFrom === undefined) {
|
|
178
|
-
paddedFrom = root.style.
|
|
179
|
-
root.style.
|
|
181
|
+
paddedFrom = root.style.paddingInlineEnd;
|
|
182
|
+
root.style.paddingInlineEnd = `${PANEL_WIDTH}px`;
|
|
180
183
|
} else if (now !== 'docked' && paddedFrom !== undefined) {
|
|
181
|
-
root.style.
|
|
184
|
+
root.style.paddingInlineEnd = paddedFrom;
|
|
182
185
|
paddedFrom = undefined;
|
|
183
186
|
}
|
|
184
187
|
shownBefore = now;
|
|
@@ -257,7 +260,7 @@ export function createChatWindow({ into, panel, modes = MODES, defaultMode, them
|
|
|
257
260
|
destroy() {
|
|
258
261
|
destroyed = true;
|
|
259
262
|
window.removeEventListener('resize', onResize);
|
|
260
|
-
if (paddedFrom !== undefined) document.documentElement.style.
|
|
263
|
+
if (paddedFrom !== undefined) document.documentElement.style.paddingInlineEnd = paddedFrom;
|
|
261
264
|
paddedFrom = undefined;
|
|
262
265
|
button.remove();
|
|
263
266
|
close.remove();
|