@peers-app/peers-ui 0.11.2 → 0.12.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/dist/components/chat-overlay.js +2 -1
- package/dist/components/inverse-lazy-list.d.ts +25 -0
- package/dist/components/inverse-lazy-list.js +103 -0
- package/dist/components/left-bar.d.ts +3 -1
- package/dist/components/left-bar.js +97 -9
- package/dist/components/main-content-container.js +3 -1
- package/dist/components/markdown-editor/markdown-plugin.d.ts +0 -2
- package/dist/components/markdown-editor/markdown-plugin.js +4 -32
- package/dist/components/tabs.d.ts +1 -0
- package/dist/components/tabs.js +6 -5
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/screens/settings/voice-settings-agent.d.ts +2 -0
- package/dist/screens/settings/voice-settings-agent.js +76 -0
- package/dist/screens/settings/voice-settings-api-keys.d.ts +13 -0
- package/dist/screens/settings/voice-settings-api-keys.js +35 -0
- package/dist/screens/settings/voice-settings-output.d.ts +16 -0
- package/dist/screens/settings/voice-settings-output.js +45 -0
- package/dist/screens/settings/voice-settings-providers.d.ts +9 -0
- package/dist/screens/settings/voice-settings-providers.js +23 -0
- package/dist/screens/settings/voice-settings-types.d.ts +33 -0
- package/dist/screens/settings/voice-settings-types.js +55 -0
- package/dist/screens/settings/voice-settings-wake-word.d.ts +9 -0
- package/dist/screens/settings/voice-settings-wake-word.js +39 -0
- package/dist/screens/settings/voice-settings.d.ts +0 -19
- package/dist/screens/settings/voice-settings.js +28 -133
- package/package.json +8 -9
- package/src/components/chat-overlay.tsx +3 -1
- package/src/components/inverse-lazy-list.tsx +106 -0
- package/src/components/left-bar.tsx +77 -6
- package/src/components/main-content-container.tsx +4 -1
- package/src/components/markdown-editor/markdown-plugin.tsx +3 -33
- package/src/components/tabs.tsx +8 -5
- package/src/index.tsx +4 -3
- package/src/screens/settings/voice-settings-agent.tsx +72 -0
- package/src/screens/settings/voice-settings-api-keys.tsx +89 -0
- package/src/screens/settings/voice-settings-output.tsx +125 -0
- package/src/screens/settings/voice-settings-providers.tsx +45 -0
- package/src/screens/settings/voice-settings-types.ts +91 -0
- package/src/screens/settings/voice-settings-wake-word.tsx +78 -0
- package/src/screens/settings/voice-settings.tsx +57 -327
|
@@ -65,6 +65,7 @@ function getChatOverlayThreadPvar() {
|
|
|
65
65
|
}
|
|
66
66
|
return chatOverlayThreadPvar;
|
|
67
67
|
}
|
|
68
|
+
const voiceHubActive = (0, peers_sdk_1.deviceVar)('voiceHub:active', { defaultValue: false });
|
|
68
69
|
// Voice settings pvar (shared with voice-settings.tsx and voice-service.ts)
|
|
69
70
|
const voiceSettingsPvar = (0, peers_sdk_1.userVar)('voiceSettings', { defaultValue: DEFAULT_VOICE_SETTINGS });
|
|
70
71
|
const DEFAULT_POSITION = { x: 20, y: 20 };
|
|
@@ -190,7 +191,7 @@ const ChatOverlay = ({ position = 'bottom-right', }) => {
|
|
|
190
191
|
setTranscription('');
|
|
191
192
|
setError(null);
|
|
192
193
|
}
|
|
193
|
-
if (event.data.state === 'recording') {
|
|
194
|
+
if (event.data.state === 'recording' && !voiceHubActive()) {
|
|
194
195
|
setIsExpanded(true);
|
|
195
196
|
}
|
|
196
197
|
}),
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IInverseLazyListProps<T> {
|
|
3
|
+
/** Unique id for the scroll container — required to avoid id collisions */
|
|
4
|
+
scrollableId: string;
|
|
5
|
+
/** Called to fetch the next older batch. Receives the current newest-first items array. */
|
|
6
|
+
loadMore: (existingItems: T[]) => Promise<T[]>;
|
|
7
|
+
/** Render all loaded items. Receives the newest-first array. */
|
|
8
|
+
renderItems: (items: T[]) => React.ReactNode;
|
|
9
|
+
/** Optional ref that will be set to a function to prepend a single live item */
|
|
10
|
+
prependRef?: React.MutableRefObject<((item: T) => void) | null>;
|
|
11
|
+
/** Custom loading indicator */
|
|
12
|
+
loadingIndicator?: React.ReactNode;
|
|
13
|
+
/** Change this value to reset the list and reload from scratch */
|
|
14
|
+
resetTrigger?: any;
|
|
15
|
+
/** Style for the outer scroll container */
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Infinite scroll list for chat-style history (newest at bottom, load older on scroll up).
|
|
20
|
+
* Uses react-infinite-scroll-component with inverse=true and column-reverse layout.
|
|
21
|
+
*
|
|
22
|
+
* Items state is managed internally. Use prependRef to push live inserts from outside.
|
|
23
|
+
*/
|
|
24
|
+
export declare function InverseLazyList<T>(props: IInverseLazyListProps<T>): React.JSX.Element;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.InverseLazyList = InverseLazyList;
|
|
40
|
+
const react_1 = __importStar(require("react"));
|
|
41
|
+
const react_infinite_scroll_component_1 = __importDefault(require("react-infinite-scroll-component"));
|
|
42
|
+
const PRELOAD_THRESHOLD = 20;
|
|
43
|
+
/**
|
|
44
|
+
* Infinite scroll list for chat-style history (newest at bottom, load older on scroll up).
|
|
45
|
+
* Uses react-infinite-scroll-component with inverse=true and column-reverse layout.
|
|
46
|
+
*
|
|
47
|
+
* Items state is managed internally. Use prependRef to push live inserts from outside.
|
|
48
|
+
*/
|
|
49
|
+
function InverseLazyList(props) {
|
|
50
|
+
const [items, setItems] = (0, react_1.useState)([]);
|
|
51
|
+
const [allLoaded, setAllLoaded] = (0, react_1.useState)(false);
|
|
52
|
+
const isLoadingRef = (0, react_1.useRef)(false);
|
|
53
|
+
const itemsRef = (0, react_1.useRef)([]);
|
|
54
|
+
// Keep ref in sync so loadMore always sees the latest items
|
|
55
|
+
itemsRef.current = items;
|
|
56
|
+
// Expose prepend function via ref so callers can push live updates
|
|
57
|
+
(0, react_1.useEffect)(() => {
|
|
58
|
+
if (props.prependRef) {
|
|
59
|
+
props.prependRef.current = (item) => setItems(prev => [item, ...prev]);
|
|
60
|
+
}
|
|
61
|
+
return () => {
|
|
62
|
+
if (props.prependRef)
|
|
63
|
+
props.prependRef.current = null;
|
|
64
|
+
};
|
|
65
|
+
}, [props.prependRef]);
|
|
66
|
+
async function loadMore() {
|
|
67
|
+
if (isLoadingRef.current || allLoaded)
|
|
68
|
+
return;
|
|
69
|
+
isLoadingRef.current = true;
|
|
70
|
+
try {
|
|
71
|
+
const moreItems = await props.loadMore(itemsRef.current);
|
|
72
|
+
if (!moreItems.length) {
|
|
73
|
+
setAllLoaded(true);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
setItems(prev => [...prev, ...moreItems]);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
isLoadingRef.current = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Auto-preload when items are sparse
|
|
84
|
+
(0, react_1.useEffect)(() => {
|
|
85
|
+
if (items.length < PRELOAD_THRESHOLD && !allLoaded && !isLoadingRef.current) {
|
|
86
|
+
loadMore();
|
|
87
|
+
}
|
|
88
|
+
}, [items.length, allLoaded]);
|
|
89
|
+
// Reset when resetTrigger changes
|
|
90
|
+
(0, react_1.useEffect)(() => {
|
|
91
|
+
setItems([]);
|
|
92
|
+
setAllLoaded(false);
|
|
93
|
+
isLoadingRef.current = false;
|
|
94
|
+
}, [props.resetTrigger]);
|
|
95
|
+
return (react_1.default.createElement("div", { id: props.scrollableId, style: {
|
|
96
|
+
overflow: 'auto',
|
|
97
|
+
display: 'flex',
|
|
98
|
+
flexDirection: 'column-reverse',
|
|
99
|
+
...props.style,
|
|
100
|
+
} },
|
|
101
|
+
react_1.default.createElement(react_infinite_scroll_component_1.default, { dataLength: items.length, next: loadMore, style: { display: 'flex', flexDirection: 'column-reverse', overflow: 'hidden' }, inverse: true, hasMore: !allLoaded, loader: props.loadingIndicator ?? (react_1.default.createElement("div", { className: "d-flex justify-content-center py-2" },
|
|
102
|
+
react_1.default.createElement("div", { className: "spinner-border spinner-border-sm text-secondary", role: "status" }))), scrollableTarget: props.scrollableId }, props.renderItems(items))));
|
|
103
|
+
}
|
|
@@ -1,32 +1,120 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
5
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
36
|
exports.LeftBarContent = exports.LeftBar = void 0;
|
|
7
37
|
const peers_sdk_1 = require("@peers-app/peers-sdk");
|
|
8
|
-
const react_1 =
|
|
38
|
+
const react_1 = __importStar(require("react"));
|
|
9
39
|
const globals_1 = require("../globals");
|
|
10
40
|
const hooks_1 = require("../hooks");
|
|
11
41
|
const off_canvas_1 = require("./off-canvas");
|
|
12
42
|
// import { useObservable } from 'peers-ui';
|
|
13
43
|
const offCanvasEffects = { hide: () => { } };
|
|
44
|
+
const LEFT_BAR_WIDTH_KEY = 'leftBarWidth';
|
|
45
|
+
const DEFAULT_LEFT_BAR_WIDTH = 300;
|
|
46
|
+
function getStoredLeftBarWidth() {
|
|
47
|
+
const stored = localStorage.getItem(LEFT_BAR_WIDTH_KEY);
|
|
48
|
+
return stored ? parseInt(stored, 10) : DEFAULT_LEFT_BAR_WIDTH;
|
|
49
|
+
}
|
|
50
|
+
function setStoredLeftBarWidth(width) {
|
|
51
|
+
localStorage.setItem(LEFT_BAR_WIDTH_KEY, String(width));
|
|
52
|
+
document.documentElement.style.setProperty('--left-bar-width', `${width}px`);
|
|
53
|
+
}
|
|
54
|
+
// Set initial CSS variable on load
|
|
55
|
+
setStoredLeftBarWidth(getStoredLeftBarWidth());
|
|
14
56
|
const LeftBar = () => {
|
|
15
57
|
const [_isDesktop] = (0, hooks_1.useObservable)(globals_1.isDesktop);
|
|
58
|
+
const [width, setWidth] = (0, react_1.useState)(() => getStoredLeftBarWidth());
|
|
59
|
+
const isDragging = (0, react_1.useRef)(false);
|
|
60
|
+
const startX = (0, react_1.useRef)(0);
|
|
61
|
+
const startWidth = (0, react_1.useRef)(0);
|
|
62
|
+
const onMouseMove = (0, react_1.useCallback)((e) => {
|
|
63
|
+
if (!isDragging.current)
|
|
64
|
+
return;
|
|
65
|
+
const delta = e.clientX - startX.current;
|
|
66
|
+
const newWidth = Math.max(150, Math.min(600, startWidth.current + delta));
|
|
67
|
+
setWidth(newWidth);
|
|
68
|
+
setStoredLeftBarWidth(newWidth);
|
|
69
|
+
}, []);
|
|
70
|
+
const onMouseUp = (0, react_1.useCallback)(() => {
|
|
71
|
+
isDragging.current = false;
|
|
72
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
73
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
74
|
+
document.body.style.cursor = '';
|
|
75
|
+
document.body.style.userSelect = '';
|
|
76
|
+
}, [onMouseMove]);
|
|
77
|
+
const onMouseDown = (0, react_1.useCallback)((e) => {
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
isDragging.current = true;
|
|
80
|
+
startX.current = e.clientX;
|
|
81
|
+
startWidth.current = width;
|
|
82
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
83
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
84
|
+
document.body.style.cursor = 'col-resize';
|
|
85
|
+
document.body.style.userSelect = 'none';
|
|
86
|
+
}, [width, onMouseMove, onMouseUp]);
|
|
87
|
+
(0, react_1.useEffect)(() => {
|
|
88
|
+
return () => {
|
|
89
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
90
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
91
|
+
};
|
|
92
|
+
}, [onMouseMove, onMouseUp]);
|
|
16
93
|
// const [usersAndGroups, setUsersAndGroups] = useState<(IUser | IGroup)[]>([]);
|
|
17
94
|
if (_isDesktop) {
|
|
18
|
-
return (react_1.default.createElement("div", { className: 'left-bar-desktop', style: { position: 'fixed', top: 0, left: 0 } },
|
|
19
|
-
react_1.default.createElement(exports.LeftBarContent,
|
|
95
|
+
return (react_1.default.createElement("div", { className: 'left-bar-desktop', style: { position: 'fixed', top: 0, left: 0, width, display: 'flex', flexDirection: 'row' } },
|
|
96
|
+
react_1.default.createElement(exports.LeftBarContent, { width: width }),
|
|
97
|
+
react_1.default.createElement("div", { onMouseDown: onMouseDown, title: "Drag to resize", style: {
|
|
98
|
+
position: 'absolute',
|
|
99
|
+
top: 0,
|
|
100
|
+
right: '-3px',
|
|
101
|
+
width: '6px',
|
|
102
|
+
height: '100%',
|
|
103
|
+
cursor: 'col-resize',
|
|
104
|
+
zIndex: 200,
|
|
105
|
+
backgroundColor: 'transparent',
|
|
106
|
+
}, onMouseEnter: e => { e.target.style.backgroundColor = 'rgba(128,128,128,0.4)'; }, onMouseLeave: e => { e.target.style.backgroundColor = 'transparent'; } })));
|
|
20
107
|
}
|
|
21
108
|
else {
|
|
22
109
|
return (react_1.default.createElement(off_canvas_1.OffCanvas, { id: "leftBar", position: "left", keepOpen: _isDesktop, effects: offCanvasEffects },
|
|
23
|
-
react_1.default.createElement(exports.LeftBarContent,
|
|
110
|
+
react_1.default.createElement(exports.LeftBarContent, { width: DEFAULT_LEFT_BAR_WIDTH })));
|
|
24
111
|
}
|
|
25
112
|
};
|
|
26
113
|
exports.LeftBar = LeftBar;
|
|
27
|
-
const LeftBarContent = () => {
|
|
114
|
+
const LeftBarContent = ({ width } = {}) => {
|
|
28
115
|
const [contentPath] = (0, hooks_1.useObservable)(globals_1.mainContentPath);
|
|
29
116
|
const [_isDesktop] = (0, hooks_1.useObservable)(globals_1.isDesktop);
|
|
117
|
+
const barWidth = width ?? DEFAULT_LEFT_BAR_WIDTH;
|
|
30
118
|
const packagesWithNavItems = (0, hooks_1.usePromise)(async () => {
|
|
31
119
|
const packages = await (0, peers_sdk_1.Packages)().list();
|
|
32
120
|
return packages.filter(pkg => pkg.appNavs?.length);
|
|
@@ -38,7 +126,7 @@ const LeftBarContent = () => {
|
|
|
38
126
|
];
|
|
39
127
|
const knowledgeSublinkActive = contentPath.startsWith('knowledge-') || knowledgeSublinks.find(ks => contentPath.startsWith(ks.path || ks.text.toLowerCase()));
|
|
40
128
|
const containerClassName = `d-flex flex-column flex-shrink-0 p-2 text-white ` + (_isDesktop ? 'bg-dark-subtle' : 'bg-dark');
|
|
41
|
-
const content = (react_1.default.createElement("div", { className: containerClassName, style: { width:
|
|
129
|
+
const content = (react_1.default.createElement("div", { className: containerClassName, style: { width: barWidth, height: "calc(100vh - 25px)" } },
|
|
42
130
|
react_1.default.createElement("div", { className: "clearfix" },
|
|
43
131
|
react_1.default.createElement("div", { className: "dropdown", style: { display: 'inline-block', width: '200px' } },
|
|
44
132
|
react_1.default.createElement("a", { id: "dropdownUser1", "data-bs-toggle": "dropdown", "aria-expanded": "false", className: "d-flex align-items-center text-white text-decoration-none", href: "#", tabIndex: -1 },
|
|
@@ -43,6 +43,8 @@ const globals_1 = require("../globals");
|
|
|
43
43
|
const thread_view_1 = require("./messages/thread-view");
|
|
44
44
|
const router_1 = require("./router");
|
|
45
45
|
const hooks_1 = require("../hooks");
|
|
46
|
+
const LEFT_BAR_WIDTH_KEY = 'leftBarWidth';
|
|
47
|
+
const DEFAULT_LEFT_BAR_WIDTH = 300;
|
|
46
48
|
const MainContentContainer = () => {
|
|
47
49
|
const splitPositionGlobalName = 'mainContentContainerSplitPos';
|
|
48
50
|
let [splitPos, setSplitPos] = (0, react_1.useState)(localStorage.getItem(splitPositionGlobalName) || '800');
|
|
@@ -83,7 +85,7 @@ const MainContentContainer = () => {
|
|
|
83
85
|
react_1.default.createElement("div", { className: 'thread-view', style: {
|
|
84
86
|
height: `calc(100vh - 25px)`,
|
|
85
87
|
overflowY: 'scroll',
|
|
86
|
-
width: `calc(100vw - ${splitPos}px -
|
|
88
|
+
width: `calc(100vw - ${splitPos}px - ${parseInt(localStorage.getItem(LEFT_BAR_WIDTH_KEY) || String(DEFAULT_LEFT_BAR_WIDTH), 10)}px)`,
|
|
87
89
|
} },
|
|
88
90
|
react_1.default.createElement(thread_view_1.ThreadContainer, null))));
|
|
89
91
|
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { ElementTransformer } from "@lexical/markdown";
|
|
2
1
|
import { Observable } from "@peers-app/peers-sdk";
|
|
3
|
-
export declare const PRESERVE_NEWLINES: ElementTransformer;
|
|
4
2
|
export declare const customMarkdownTransformers: import("@lexical/markdown").Transformer[];
|
|
5
3
|
interface IProps {
|
|
6
4
|
markdownObs: Observable<string>;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.customMarkdownTransformers =
|
|
3
|
+
exports.customMarkdownTransformers = void 0;
|
|
4
4
|
exports.MarkdownPlugin = MarkdownPlugin;
|
|
5
5
|
const list_1 = require("@lexical/list");
|
|
6
6
|
const markdown_1 = require("@lexical/markdown");
|
|
7
7
|
const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext");
|
|
8
8
|
const peers_sdk_1 = require("@peers-app/peers-sdk");
|
|
9
|
-
const lexical_1 = require("lexical");
|
|
10
9
|
const react_1 = require("react");
|
|
11
10
|
const mention_node_1 = require("./mention-node");
|
|
12
11
|
// Amount of spaces that define indentation level
|
|
@@ -118,27 +117,7 @@ const MENTION_TRANSFORMER = {
|
|
|
118
117
|
textNode.replace(node);
|
|
119
118
|
},
|
|
120
119
|
};
|
|
121
|
-
exports.PRESERVE_NEWLINES = {
|
|
122
|
-
type: 'element',
|
|
123
|
-
dependencies: [lexical_1.ParagraphNode],
|
|
124
|
-
export: (node) => {
|
|
125
|
-
if ((0, lexical_1.$isParagraphNode)(node)) {
|
|
126
|
-
const content = node.getTextContent();
|
|
127
|
-
if (!content.trim()) {
|
|
128
|
-
return '\n \n';
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return null;
|
|
132
|
-
},
|
|
133
|
-
regExp: /^ $/, // a line with only a space
|
|
134
|
-
replace: (textNode, nodes, _, isImport) => {
|
|
135
|
-
if (isImport && nodes.length === 1) {
|
|
136
|
-
textNode.append((0, lexical_1.$createTextNode)(''));
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
120
|
exports.customMarkdownTransformers = [
|
|
141
|
-
exports.PRESERVE_NEWLINES,
|
|
142
121
|
MENTION_TRANSFORMER,
|
|
143
122
|
CHECK_LIST_TRANSFORMER, // This needs to be first or checklists will be treated as unordered lists
|
|
144
123
|
...markdown_1.TRANSFORMERS.filter(transformer => {
|
|
@@ -162,9 +141,7 @@ function MarkdownPlugin(props) {
|
|
|
162
141
|
}
|
|
163
142
|
markdown = newMarkdown;
|
|
164
143
|
editor.update(() => {
|
|
165
|
-
|
|
166
|
-
const shouldMergeAdjacentLines = false;
|
|
167
|
-
(0, markdown_1.$convertFromMarkdownString)(markdown, exports.customMarkdownTransformers, undefined, shouldPreserveNewLines, shouldMergeAdjacentLines);
|
|
144
|
+
(0, markdown_1.$convertFromMarkdownString)(markdown, exports.customMarkdownTransformers, undefined, true, false);
|
|
168
145
|
});
|
|
169
146
|
}
|
|
170
147
|
setMarkdown();
|
|
@@ -172,13 +149,8 @@ function MarkdownPlugin(props) {
|
|
|
172
149
|
setMarkdown();
|
|
173
150
|
});
|
|
174
151
|
const sub2Dispose = editor.registerUpdateListener(({ editorState }) => {
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
let newMarkdown = (0, markdown_1.$convertToMarkdownString)(exports.customMarkdownTransformers, undefined, shouldPreserveNewLines);
|
|
178
|
-
newMarkdown = newMarkdown.replace(/\n\n\n \n\n\n/gm, '\n\n \n\n');
|
|
179
|
-
if (newMarkdown === "\n \n") {
|
|
180
|
-
newMarkdown = '';
|
|
181
|
-
}
|
|
152
|
+
editorState.read(() => {
|
|
153
|
+
const newMarkdown = (0, markdown_1.$convertToMarkdownString)(exports.customMarkdownTransformers, undefined, true);
|
|
182
154
|
if (newMarkdown !== markdown) {
|
|
183
155
|
markdown = newMarkdown;
|
|
184
156
|
markdownObs(markdown);
|
|
@@ -6,6 +6,7 @@ interface ITabsProps {
|
|
|
6
6
|
active?: true;
|
|
7
7
|
}[];
|
|
8
8
|
contentClassName?: string;
|
|
9
|
+
activeTabName?: string;
|
|
9
10
|
}
|
|
10
11
|
export declare const Tabs: (props: ITabsProps) => React.JSX.Element;
|
|
11
12
|
export declare const ScreenTabBody: (props: React.PropsWithChildren) => React.JSX.Element;
|
package/dist/components/tabs.js
CHANGED
|
@@ -44,22 +44,23 @@ const Tabs = (props) => {
|
|
|
44
44
|
activeTabName = activeTabName.toLowerCase();
|
|
45
45
|
const _activeTab = tabs.find(tab => tab.name.toLowerCase() === activeTabName) || tabs[0];
|
|
46
46
|
lastActive = _activeTab.name;
|
|
47
|
-
// TODO setup query persistence on tabs
|
|
48
|
-
// setTimeout(() => queryParam('tab', lastActive.toLowerCase()));
|
|
49
47
|
return _activeTab;
|
|
50
48
|
});
|
|
49
|
+
// Allow parent to control the active tab imperatively
|
|
50
|
+
const resolvedActiveTab = props.activeTabName
|
|
51
|
+
? (tabs.find(tab => tab.name.toLowerCase() === props.activeTabName.toLowerCase()) ?? activeTab)
|
|
52
|
+
: activeTab;
|
|
51
53
|
function setActiveTab(tab) {
|
|
52
54
|
_setActiveTab(tab);
|
|
53
|
-
// queryParam('tab', tab.name.toLowerCase());
|
|
54
55
|
lastActive = tab.name;
|
|
55
56
|
}
|
|
56
57
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
57
58
|
react_1.default.createElement("ul", { className: "nav nav-tabs" }, tabs.map((tab, iTab) => {
|
|
58
59
|
return (react_1.default.createElement("li", { key: tab.name + iTab, className: "nav-item" },
|
|
59
|
-
react_1.default.createElement("a", { href: "#", className: "nav-link " + (
|
|
60
|
+
react_1.default.createElement("a", { href: "#", className: "nav-link " + (resolvedActiveTab.name === tab.name ? 'active' : ''), onClick: evt => (evt.preventDefault(), setActiveTab(tab)) }, tab.name)));
|
|
60
61
|
})),
|
|
61
62
|
react_1.default.createElement("div", { className: "tab-content " + (props.contentClassName ?? 'mt-3') }, tabs.map((tab, iTab) => {
|
|
62
|
-
return (react_1.default.createElement("div", { key: tab.name + iTab, hidden:
|
|
63
|
+
return (react_1.default.createElement("div", { key: tab.name + iTab, hidden: resolvedActiveTab.name !== tab.name }, tab.content));
|
|
63
64
|
}))));
|
|
64
65
|
};
|
|
65
66
|
exports.Tabs = Tabs;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export * from "./screens/events/cron";
|
|
2
2
|
export * from "./tabs-layout/tabs-layout";
|
|
3
|
+
export { activeTabId, activeTabs, TabState } from "./tabs-layout/tabs-state";
|
|
3
4
|
export * from "./components/voice-indicator";
|
|
4
5
|
export * from "./components/chat-overlay";
|
|
5
6
|
export * from "./components/sortable-list";
|
|
6
7
|
export * from "./components/tabs";
|
|
8
|
+
export * from "./components/inverse-lazy-list";
|
|
7
9
|
export * from "./components/markdown-editor/editor-inline";
|
|
10
|
+
export * from "./components/markdown-editor/editor";
|
package/dist/index.js
CHANGED
|
@@ -14,10 +14,16 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.activeTabs = exports.activeTabId = void 0;
|
|
17
18
|
__exportStar(require("./screens/events/cron"), exports);
|
|
18
19
|
__exportStar(require("./tabs-layout/tabs-layout"), exports);
|
|
20
|
+
var tabs_state_1 = require("./tabs-layout/tabs-state");
|
|
21
|
+
Object.defineProperty(exports, "activeTabId", { enumerable: true, get: function () { return tabs_state_1.activeTabId; } });
|
|
22
|
+
Object.defineProperty(exports, "activeTabs", { enumerable: true, get: function () { return tabs_state_1.activeTabs; } });
|
|
19
23
|
__exportStar(require("./components/voice-indicator"), exports);
|
|
20
24
|
__exportStar(require("./components/chat-overlay"), exports);
|
|
21
25
|
__exportStar(require("./components/sortable-list"), exports);
|
|
22
26
|
__exportStar(require("./components/tabs"), exports);
|
|
27
|
+
__exportStar(require("./components/inverse-lazy-list"), exports);
|
|
23
28
|
__exportStar(require("./components/markdown-editor/editor-inline"), exports);
|
|
29
|
+
__exportStar(require("./components/markdown-editor/editor"), exports);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.VoiceSettingsAgent = void 0;
|
|
37
|
+
const react_1 = __importStar(require("react"));
|
|
38
|
+
const peers_sdk_1 = require("@peers-app/peers-sdk");
|
|
39
|
+
const VOICE_HUB_AGENT_ASSISTANT_ID = '00mh0wlipkdbeaw8vhagent01';
|
|
40
|
+
// Must match the pvar names in peers-core/src/data/voice-agent-config.ts and
|
|
41
|
+
// peers-electron/src/server/voice/voice-agent-config.ts — pvar instances are
|
|
42
|
+
// singletons keyed by name+scope so all three share the same underlying value.
|
|
43
|
+
const voiceAgentAssistantIdPvar = (0, peers_sdk_1.userVar)('voice:agentAssistantId', { defaultValue: VOICE_HUB_AGENT_ASSISTANT_ID });
|
|
44
|
+
const VoiceSettingsAgent = () => {
|
|
45
|
+
const [assistants, setAssistants] = (0, react_1.useState)([]);
|
|
46
|
+
const [selectedId, setSelectedId] = (0, react_1.useState)(VOICE_HUB_AGENT_ASSISTANT_ID);
|
|
47
|
+
const [saving, setSaving] = (0, react_1.useState)(false);
|
|
48
|
+
const [saved, setSaved] = (0, react_1.useState)(false);
|
|
49
|
+
(0, react_1.useEffect)(() => {
|
|
50
|
+
const load = async () => {
|
|
51
|
+
await voiceAgentAssistantIdPvar.loadingPromise;
|
|
52
|
+
setSelectedId(voiceAgentAssistantIdPvar() ?? VOICE_HUB_AGENT_ASSISTANT_ID);
|
|
53
|
+
const all = await (0, peers_sdk_1.Assistants)().list({});
|
|
54
|
+
setAssistants(all);
|
|
55
|
+
};
|
|
56
|
+
load();
|
|
57
|
+
}, []);
|
|
58
|
+
const handleSave = (0, react_1.useCallback)(async () => {
|
|
59
|
+
setSaving(true);
|
|
60
|
+
setSaved(false);
|
|
61
|
+
await voiceAgentAssistantIdPvar.loadingPromise;
|
|
62
|
+
voiceAgentAssistantIdPvar(selectedId || undefined);
|
|
63
|
+
setSaving(false);
|
|
64
|
+
setSaved(true);
|
|
65
|
+
setTimeout(() => setSaved(false), 2000);
|
|
66
|
+
}, [selectedId]);
|
|
67
|
+
return (react_1.default.createElement("div", null,
|
|
68
|
+
react_1.default.createElement("h6", null, "Voice Agent"),
|
|
69
|
+
react_1.default.createElement("p", { className: "text-muted small mb-2" }, "When you give a voice command that requires action (e.g. \"add milk to the shopping list\"), it is dispatched to this assistant as a background task."),
|
|
70
|
+
react_1.default.createElement("div", { className: "d-flex align-items-center gap-2" },
|
|
71
|
+
react_1.default.createElement("select", { className: "form-select form-select-sm", value: selectedId, onChange: e => setSelectedId(e.target.value), disabled: saving }, assistants.map(a => (react_1.default.createElement("option", { key: a.assistantId, value: a.assistantId },
|
|
72
|
+
a.name,
|
|
73
|
+
a.assistantId === VOICE_HUB_AGENT_ASSISTANT_ID ? ' (default)' : '')))),
|
|
74
|
+
react_1.default.createElement("button", { className: "btn btn-sm btn-primary", onClick: handleSave, disabled: saving, style: { whiteSpace: 'nowrap' } }, saving ? 'Saving…' : saved ? 'Saved!' : 'Save'))));
|
|
75
|
+
};
|
|
76
|
+
exports.VoiceSettingsAgent = VoiceSettingsAgent;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { VoiceSettings, PicovoiceKeyError } from './voice-settings-types';
|
|
3
|
+
interface ApiKeysProps {
|
|
4
|
+
settings: VoiceSettings;
|
|
5
|
+
picovoiceKey: string;
|
|
6
|
+
openaiKey: string;
|
|
7
|
+
keyError: PicovoiceKeyError | null;
|
|
8
|
+
onPicovoiceKeyChange: (value: string) => void;
|
|
9
|
+
onOpenaiKeyChange: (value: string) => void;
|
|
10
|
+
onDismissKeyError: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const VoiceSettingsApiKeys: React.FC<ApiKeysProps>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.VoiceSettingsApiKeys = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const tooltip_1 = require("../../components/tooltip");
|
|
9
|
+
const voice_settings_types_1 = require("./voice-settings-types");
|
|
10
|
+
const VoiceSettingsApiKeys = ({ settings, picovoiceKey, openaiKey, keyError, onPicovoiceKeyChange, onOpenaiKeyChange, onDismissKeyError, }) => (react_1.default.createElement(react_1.default.Fragment, null,
|
|
11
|
+
react_1.default.createElement("div", { className: "mb-4" },
|
|
12
|
+
react_1.default.createElement("label", { className: "form-label" },
|
|
13
|
+
"Picovoice Access Key",
|
|
14
|
+
react_1.default.createElement(tooltip_1.Tooltip, { markdownContent: "Required for wake word detection. Get a free key at [console.picovoice.ai](https://console.picovoice.ai)" }),
|
|
15
|
+
settings.picovoiceAccessKeySet && (react_1.default.createElement("span", { className: "badge bg-success ms-2" }, "Set"))),
|
|
16
|
+
react_1.default.createElement("input", { type: "password", className: "form-control", value: picovoiceKey, onChange: (e) => onPicovoiceKeyChange(e.target.value), placeholder: settings.picovoiceAccessKeySet ? '••••••••••••••••' : 'Enter your Picovoice access key' }),
|
|
17
|
+
react_1.default.createElement("small", { className: "text-muted" },
|
|
18
|
+
react_1.default.createElement("a", { href: "https://console.picovoice.ai", target: "_blank", rel: "noopener noreferrer" }, "Get a free access key"),
|
|
19
|
+
settings.picovoiceAccessKeySet && ' (leave blank to keep existing key)')),
|
|
20
|
+
keyError && (react_1.default.createElement("div", { className: "alert alert-warning alert-dismissible mb-4", role: "alert" },
|
|
21
|
+
react_1.default.createElement("div", { className: "d-flex align-items-start gap-2" },
|
|
22
|
+
react_1.default.createElement("i", { className: "bi bi-exclamation-triangle-fill flex-shrink-0 mt-1" }),
|
|
23
|
+
react_1.default.createElement("div", null,
|
|
24
|
+
react_1.default.createElement("strong", null, voice_settings_types_1.PICOVOICE_KEY_ERROR_MESSAGES[keyError].heading),
|
|
25
|
+
react_1.default.createElement("div", { className: "mt-1" }, voice_settings_types_1.PICOVOICE_KEY_ERROR_MESSAGES[keyError].body),
|
|
26
|
+
react_1.default.createElement("a", { href: "https://console.picovoice.ai", target: "_blank", rel: "noopener noreferrer", className: "alert-link mt-1 d-inline-block" }, "Open console.picovoice.ai"))),
|
|
27
|
+
react_1.default.createElement("button", { type: "button", className: "btn-close", onClick: onDismissKeyError }))),
|
|
28
|
+
react_1.default.createElement("div", { className: "mb-3" },
|
|
29
|
+
react_1.default.createElement("label", { className: "form-label" },
|
|
30
|
+
"OpenAI API Key",
|
|
31
|
+
react_1.default.createElement(tooltip_1.Tooltip, { markdownContent: "Required for cloud STT (Whisper) and cloud TTS. Leave empty to use local/browser alternatives." }),
|
|
32
|
+
settings.openaiApiKeySet && (react_1.default.createElement("span", { className: "badge bg-success ms-2" }, "Set"))),
|
|
33
|
+
react_1.default.createElement("input", { type: "password", className: "form-control", value: openaiKey, onChange: (e) => onOpenaiKeyChange(e.target.value), placeholder: settings.openaiApiKeySet ? '••••••••••••••••' : 'sk-...' }),
|
|
34
|
+
settings.openaiApiKeySet && (react_1.default.createElement("small", { className: "text-muted" }, "Leave blank to keep existing key")))));
|
|
35
|
+
exports.VoiceSettingsApiKeys = VoiceSettingsApiKeys;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { VoiceSettings } from './voice-settings-types';
|
|
3
|
+
interface OutputProps {
|
|
4
|
+
settings: VoiceSettings;
|
|
5
|
+
localSettings: VoiceSettings;
|
|
6
|
+
saving: boolean;
|
|
7
|
+
testText: string;
|
|
8
|
+
hasUnsavedChanges: boolean;
|
|
9
|
+
audioDevices: string[];
|
|
10
|
+
onChange: (patch: Partial<VoiceSettings>) => void;
|
|
11
|
+
onTestTextChange: (text: string) => void;
|
|
12
|
+
onTestTTS: () => void;
|
|
13
|
+
onTestRecording: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const VoiceSettingsOutput: React.FC<OutputProps>;
|
|
16
|
+
export {};
|