@puredesktop/puredesktop-ui-bridge 2.1.7 → 2.1.9
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/package.json +89 -5
- package/src/agents/mcpServerPresets.test.ts +105 -0
- package/src/agents/mcpServerPresets.ts +380 -0
- package/src/agents/runtime/index.ts +7 -0
- package/src/agents/runtime/mapAgentSnapshot.ts +11 -8
- package/src/agents/runtime/pendingAsks.test.ts +117 -0
- package/src/agents/runtime/pendingAsks.ts +110 -0
- package/src/bridge/agentScopeDefaults.ts +65 -0
- package/src/bridge/agentTypes.ts +57 -3
- package/src/bridge/agents.d.mts +6 -0
- package/src/bridge/agents.mjs +10 -0
- package/src/bridge/agents.ts +4 -0
- package/src/bridge/collectionImagePaste.ts +19 -1
- package/src/bridge/context.mjs +32 -0
- package/src/bridge/credentials.d.mts +62 -0
- package/src/bridge/credentials.mjs +53 -0
- package/src/bridge/documents.d.mts +76 -0
- package/src/bridge/documents.mjs +40 -0
- package/src/bridge/events.d.mts +1 -0
- package/src/bridge/events.mjs +1 -0
- package/src/bridge/googleAuth.ts +7 -152
- package/src/bridge/mcpClient.d.mts +74 -0
- package/src/bridge/mcpClient.mjs +79 -0
- package/src/bridge/methods.d.mts +45 -0
- package/src/bridge/methods.mjs +46 -0
- package/src/bridge/notifications.d.mts +12 -0
- package/src/bridge/notifications.mjs +36 -0
- package/src/bridge/operations.d.mts +44 -0
- package/src/bridge/operations.mjs +40 -0
- package/src/bridge/pureRender/base.css +44 -0
- package/src/bridge/pureRender/document.ts +29 -2
- package/src/bridge/pureRender/index.ts +3 -0
- package/src/bridge/pureRender/normalize.ts +167 -0
- package/src/bridge/pureRender/sanitizeExportBody.test.ts +51 -0
- package/src/bridge/pureRender/sanitizeExportBody.ts +61 -0
- package/src/bridge/pureRender/styles.ts +125 -5
- package/src/bridge/pureRender/theme.test.ts +259 -0
- package/src/bridge/pureRender/theme.ts +19 -1
- package/src/bridge/pureRender/types.ts +33 -0
- package/src/bridge/pureRender/visualLayoutInspection.test.ts +26 -0
- package/src/bridge/pureRender/visualLayoutInspection.ts +75 -0
- package/src/bridge/react/useDocumentHotkeys.ts +41 -0
- package/src/bridge/react/useDocumentLifecycle.tsx +359 -0
- package/src/bridge/react/usePlatformAgentSessionDrive.test.tsx +29 -10
- package/src/bridge/react/usePlatformAgentSessionDrive.tsx +10 -81
- package/src/bridge/react/usePlatformAppSettings.test.tsx +105 -0
- package/src/bridge/react/usePlatformAppSettings.tsx +104 -0
- package/src/bridge/react/usePlatformJsonStore.test.tsx +152 -0
- package/src/bridge/react/usePlatformJsonStore.tsx +149 -0
- package/src/bridge/react/usePlatformOperations.tsx +75 -0
- package/src/bridge/storage.d.mts +23 -10
- package/src/bridge/storage.mjs +6 -3
- package/src/bridge/storage.test.ts +6 -6
- package/src/bridge/types.ts +7 -0
- package/src/components/agents/AgentComposer.tsx +10 -6
- package/src/components/agents/AgentDrawerPanel.test.tsx +2 -205
- package/src/components/agents/AgentDrawerPanel.tsx +23 -62
- package/src/components/agents/AgentMessageBubble.tsx +59 -33
- package/src/components/agents/AgentMessageList.tsx +4 -4
- package/src/components/agents/AgentQuestionPromptList.tsx +34 -212
- package/src/components/agents/AgentToolApprovalActions.tsx +13 -11
- package/src/components/agents/AgentToolCallCard.tsx +20 -20
- package/src/components/agents/AgentToolPendingList.tsx +6 -6
- package/src/components/agents/AgentToolPendingReview.tsx +6 -6
- package/src/components/agents/ContextPicker.tsx +239 -0
- package/src/components/agents/QuestionRequestList.tsx +278 -0
- package/src/components/agents/agentPanelStyles.ts +8 -31
- package/src/components/agents/agentTypes.ts +25 -41
- package/src/components/agents/index.ts +4 -0
- package/src/components/assets/asset-library/sidebar/AssetLibraryList.tsx +10 -4
- package/src/components/chrome/WorkspaceTabStrip.tsx +22 -4
- package/src/components/chrome/workspaceTabTypes.ts +2 -0
- package/src/components/common/chat/ChatBox.tsx +9 -9
- package/src/components/common/chat/ChatModelMenu.tsx +34 -4
- package/src/components/common/chat/ChatThread.tsx +23 -7
- package/src/components/common/connections/ProviderConnection.test.tsx +208 -0
- package/src/components/common/connections/ProviderConnection.tsx +277 -0
- package/src/components/common/connections/index.ts +5 -0
- package/src/components/common/containers/AppFrame.test.tsx +4 -4
- package/src/components/common/containers/AppFrame.tsx +26 -10
- package/src/components/common/containers/AppHeader.tsx +37 -15
- package/src/components/common/documents/DocumentHeaderActions.tsx +206 -0
- package/src/components/common/documents/DocumentSwitcher.tsx +1181 -0
- package/src/components/common/documents/index.ts +8 -0
- package/src/components/common/dropdown/MenuDropdownItem.tsx +14 -2
- package/src/components/common/dropdown/MenuPortal.tsx +3 -1
- package/src/components/common/dropdown/menuViewportPosition.test.ts +20 -10
- package/src/components/common/dropdown/menuViewportPosition.ts +35 -27
- package/src/components/common/overlays/Modal.tsx +13 -2
- package/src/components/common/research/EvidenceDossier.tsx +1232 -150
- package/src/components/common/research/index.ts +2 -0
- package/src/components/editor/EditorLinkPromptDialog.tsx +1 -1
- package/src/components/print-design/PrintDesignPanel.test.tsx +430 -40
- package/src/components/print-design/PrintDesignPanel.tsx +1770 -207
- package/src/components/print-design/index.ts +2 -0
- package/src/components/print-design/previewContent.test.ts +32 -0
- package/src/components/print-design/previewContent.ts +31 -0
- package/src/context/buildContextDocument.test.ts +240 -0
- package/src/context/buildContextDocument.ts +309 -0
- package/src/context/contextAccess.ts +66 -0
- package/src/context/contextConfig.ts +72 -0
- package/src/context/contextDocument.test.ts +155 -0
- package/src/context/contextDocument.ts +300 -0
- package/src/context/contextSections.test.ts +88 -0
- package/src/context/contextSections.ts +84 -0
- package/src/context/htmlToContextMarkdown.test.ts +134 -0
- package/src/context/htmlToContextMarkdown.ts +369 -0
- package/src/ics/generateIcs.test.ts +153 -0
- package/src/ics/generateIcs.ts +197 -0
- package/src/index.ts +3 -0
- package/src/net/httpRetry.test.ts +117 -0
- package/src/net/httpRetry.ts +111 -0
- package/src/theme/appAccents.test.ts +36 -35
- package/src/theme/appAccents.ts +93 -104
- package/src/theme/appIdentityCss.mjs +178 -229
- package/src/theme/appIdentityCss.ts +222 -231
- package/src/theme/themes/dark.ts +3 -1
- package/src/theme/themes/light.ts +3 -1
- package/src/bridge/googleProviderConfig.ts +0 -73
|
@@ -83,12 +83,24 @@ export function MenuDropdownItem({
|
|
|
83
83
|
$hasIcon={Boolean(item.icon)}
|
|
84
84
|
$tone={item.tone}
|
|
85
85
|
onPointerDown={event => {
|
|
86
|
-
|
|
86
|
+
// Select on pointerdown for pointing devices (fires before the menu
|
|
87
|
+
// closes) and preventDefault so the item doesn't steal focus.
|
|
88
|
+
if (
|
|
89
|
+
event.pointerType === 'mouse' ||
|
|
90
|
+
event.pointerType === 'touch' ||
|
|
91
|
+
event.pointerType === 'pen'
|
|
92
|
+
) {
|
|
87
93
|
event.preventDefault()
|
|
88
94
|
selectItem()
|
|
89
95
|
}
|
|
90
96
|
}}
|
|
91
|
-
onClick={
|
|
97
|
+
onClick={event => {
|
|
98
|
+
// A pointer interaction already selected on pointerdown above; the
|
|
99
|
+
// browser still fires a follow-up click, which would run the action a
|
|
100
|
+
// SECOND time (e.g. inserting two equations). Only handle genuine
|
|
101
|
+
// keyboard activation here — Enter/Space produce a click with detail 0.
|
|
102
|
+
if (event.detail === 0) selectItem()
|
|
103
|
+
}}
|
|
92
104
|
>
|
|
93
105
|
{item.icon ? (
|
|
94
106
|
<span className="menu-item-icon" aria-hidden="true">
|
|
@@ -137,9 +137,11 @@ export function MenuPortal({
|
|
|
137
137
|
|
|
138
138
|
const surfaceStyle: CSSProperties = layout
|
|
139
139
|
? {
|
|
140
|
-
top: layout.top,
|
|
141
140
|
left: layout.left,
|
|
142
141
|
maxHeight: layout.maxHeight,
|
|
142
|
+
// Above-opening menus are pinned by `bottom` so they grow upward.
|
|
143
|
+
...(layout.top !== undefined ? { top: layout.top } : {}),
|
|
144
|
+
...(layout.bottom !== undefined ? { bottom: layout.bottom } : {}),
|
|
143
145
|
...(layout.width !== undefined ? { width: layout.width } : {}),
|
|
144
146
|
...style,
|
|
145
147
|
}
|
|
@@ -71,7 +71,8 @@ describe('resolveMenuViewportLayout', () => {
|
|
|
71
71
|
expect(layout.width).toBeGreaterThanOrEqual(120)
|
|
72
72
|
})
|
|
73
73
|
|
|
74
|
-
it('
|
|
74
|
+
it('bottom-anchors a below-start menu that flips above at the viewport bottom', () => {
|
|
75
|
+
const viewportHeight = 760
|
|
75
76
|
const layout = resolveMenuViewportLayout({
|
|
76
77
|
anchorRect: {
|
|
77
78
|
top: 720,
|
|
@@ -83,16 +84,23 @@ describe('resolveMenuViewportLayout', () => {
|
|
|
83
84
|
preferredTop: 752,
|
|
84
85
|
preferredLeft: 120,
|
|
85
86
|
placement: 'below-start',
|
|
87
|
+
// Menu measured collapsed (pre-expansion) — must not drive the height.
|
|
86
88
|
menuWidth: 200,
|
|
87
|
-
menuHeight:
|
|
89
|
+
menuHeight: 8,
|
|
88
90
|
viewportWidth: 1000,
|
|
89
|
-
viewportHeight
|
|
91
|
+
viewportHeight,
|
|
90
92
|
})
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
// Pinned by bottom (grows upward), not top; its bottom edge sits above the
|
|
95
|
+
// anchor and it gets the real space above (not the ~0 measured height).
|
|
96
|
+
expect(layout.top).toBeUndefined()
|
|
97
|
+
expect(layout.bottom).toBeGreaterThan(0)
|
|
98
|
+
expect(viewportHeight - (layout.bottom ?? 0)).toBeLessThanOrEqual(720)
|
|
99
|
+
expect(layout.maxHeight).toBeGreaterThan(100)
|
|
93
100
|
})
|
|
94
101
|
|
|
95
|
-
it('
|
|
102
|
+
it('bottom-anchors above-start menus so they grow upward from the anchor', () => {
|
|
103
|
+
const viewportHeight = 760
|
|
96
104
|
const layout = resolveMenuViewportLayout({
|
|
97
105
|
anchorRect: {
|
|
98
106
|
top: 720,
|
|
@@ -105,13 +113,14 @@ describe('resolveMenuViewportLayout', () => {
|
|
|
105
113
|
preferredLeft: 120,
|
|
106
114
|
placement: 'above-start',
|
|
107
115
|
menuWidth: 200,
|
|
108
|
-
menuHeight:
|
|
116
|
+
menuHeight: 8,
|
|
109
117
|
viewportWidth: 1000,
|
|
110
|
-
viewportHeight
|
|
118
|
+
viewportHeight,
|
|
111
119
|
})
|
|
112
120
|
|
|
113
|
-
expect(layout.top).
|
|
114
|
-
expect(layout.
|
|
121
|
+
expect(layout.top).toBeUndefined()
|
|
122
|
+
expect(viewportHeight - (layout.bottom ?? 0)).toBeLessThanOrEqual(720)
|
|
123
|
+
expect(layout.maxHeight).toBeGreaterThan(100)
|
|
115
124
|
})
|
|
116
125
|
|
|
117
126
|
it('limits menu height to the remaining viewport space', () => {
|
|
@@ -134,6 +143,7 @@ describe('resolveMenuViewportLayout', () => {
|
|
|
134
143
|
})
|
|
135
144
|
|
|
136
145
|
expect(layout.maxHeight).toBeLessThanOrEqual(280)
|
|
137
|
-
expect(layout.top
|
|
146
|
+
expect(layout.top).toBeDefined()
|
|
147
|
+
expect((layout.top ?? 0) + layout.maxHeight).toBeLessThanOrEqual(300)
|
|
138
148
|
})
|
|
139
149
|
})
|
|
@@ -10,7 +10,14 @@ export const MENU_DEFAULT_MAX_HEIGHT_PX = 320
|
|
|
10
10
|
export type MenuWidthMode = 'intrinsic' | 'anchor'
|
|
11
11
|
|
|
12
12
|
export interface ResolvedMenuLayout {
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Exactly one of `top`/`bottom` is set. Above-opening menus pin by `bottom`
|
|
15
|
+
* so they grow upward — deriving `top`/height from the menu's own measurement
|
|
16
|
+
* is circular (it's measured collapsed, before the open transition expands
|
|
17
|
+
* it, which clipped bottom-anchored menus to ~0px).
|
|
18
|
+
*/
|
|
19
|
+
top?: number
|
|
20
|
+
bottom?: number
|
|
14
21
|
left: number
|
|
15
22
|
maxHeight: number
|
|
16
23
|
/** Set only for `anchor` width mode. */
|
|
@@ -78,45 +85,46 @@ export function resolveMenuViewportLayout({
|
|
|
78
85
|
Math.max(margin, viewportWidth - layoutWidth - margin),
|
|
79
86
|
)
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
const spaceAbove = Math.max(0, anchorRect.top - gap - margin)
|
|
82
89
|
|
|
90
|
+
let opensAbove: boolean
|
|
83
91
|
if (placement === 'above-start') {
|
|
84
|
-
top = anchorRect.top - gap - menuHeight
|
|
85
|
-
const spaceAbove = Math.max(0, anchorRect.top - gap - margin)
|
|
86
92
|
const spaceBelow = Math.max(
|
|
87
93
|
0,
|
|
88
94
|
viewportHeight - anchorRect.bottom - gap - margin,
|
|
89
95
|
)
|
|
90
|
-
if
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
placement === 'below-menubar-start' ||
|
|
96
|
-
placement === 'at-point'
|
|
97
|
-
) {
|
|
96
|
+
// Prefer above; flip below only if it can't fit above but fits better below.
|
|
97
|
+
opensAbove = !(menuHeight > spaceAbove && spaceBelow > spaceAbove)
|
|
98
|
+
} else {
|
|
99
|
+
// below-start / below-menubar-start / at-point: prefer below, flip above
|
|
100
|
+
// when there's no room below but more above.
|
|
98
101
|
const opensBelow = preferredTop >= anchorRect.bottom - 0.5
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (menuHeight > spaceBelow && spaceAbove > spaceBelow) {
|
|
103
|
-
top = anchorRect.top - gap - menuHeight
|
|
104
|
-
}
|
|
105
|
-
}
|
|
102
|
+
const spaceBelow = Math.max(0, viewportHeight - preferredTop - margin)
|
|
103
|
+
opensAbove =
|
|
104
|
+
opensBelow && menuHeight > spaceBelow && spaceAbove > spaceBelow
|
|
106
105
|
}
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
if (opensAbove) {
|
|
108
|
+
// Pin the panel's bottom just above the anchor so it grows UPWARD; its
|
|
109
|
+
// pre-expansion measured height can't misplace or clip it.
|
|
110
|
+
const bottom = Math.max(margin, viewportHeight - (anchorRect.top - gap))
|
|
111
|
+
return {
|
|
112
|
+
bottom,
|
|
113
|
+
left,
|
|
114
|
+
maxHeight: Math.min(maxHeight, spaceAbove),
|
|
115
|
+
...(widthMode === 'anchor' ? { width: layoutWidth } : {}),
|
|
116
|
+
}
|
|
117
|
+
}
|
|
115
118
|
|
|
119
|
+
const top = clamp(
|
|
120
|
+
placement === 'above-start' ? anchorRect.bottom + gap : preferredTop,
|
|
121
|
+
margin,
|
|
122
|
+
Math.max(margin, viewportHeight - margin),
|
|
123
|
+
)
|
|
116
124
|
return {
|
|
117
125
|
top,
|
|
118
126
|
left,
|
|
119
|
-
maxHeight:
|
|
127
|
+
maxHeight: Math.min(maxHeight, Math.max(0, viewportHeight - top - margin)),
|
|
120
128
|
...(widthMode === 'anchor' ? { width: layoutWidth } : {}),
|
|
121
129
|
}
|
|
122
130
|
}
|
|
@@ -15,7 +15,7 @@ import { zi } from '../../../theme/themeVars.js'
|
|
|
15
15
|
import { PlatformIcon } from '../../chrome/PlatformIcon.js'
|
|
16
16
|
import { ModalChromeHeader } from './ModalChromeHeader.js'
|
|
17
17
|
|
|
18
|
-
export type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'fullscreen'
|
|
18
|
+
export type ModalSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'fullscreen'
|
|
19
19
|
|
|
20
20
|
export interface ModalProps {
|
|
21
21
|
open: boolean
|
|
@@ -42,6 +42,7 @@ const FOCUSABLE_SELECTOR = [
|
|
|
42
42
|
].join(',')
|
|
43
43
|
|
|
44
44
|
const sizeWidths = {
|
|
45
|
+
xs: 'min(420px, calc(100vw - var(--platform-spacing-xl)))',
|
|
45
46
|
sm: '42dvw',
|
|
46
47
|
md: '50dvw',
|
|
47
48
|
lg: '68dvw',
|
|
@@ -122,6 +123,9 @@ const StyledDialog = styled.div<{ $size: ModalSize; $chrome: boolean }>`
|
|
|
122
123
|
}};
|
|
123
124
|
min-height: ${({ $size, $chrome }) => {
|
|
124
125
|
if ($size === 'fullscreen') return '100%'
|
|
126
|
+
// Compact dialogs (confirmations, single-field prompts) hug their content —
|
|
127
|
+
// no forced aspect-ratio min-height that leaves a tall, empty box.
|
|
128
|
+
if ($size === 'xs') return 'auto'
|
|
125
129
|
if ($chrome && $size === 'xl') {
|
|
126
130
|
return 'min(460px, calc(100vh - var(--platform-spacing-xl)))'
|
|
127
131
|
}
|
|
@@ -314,7 +318,14 @@ export function Modal({
|
|
|
314
318
|
title={title}
|
|
315
319
|
titleId={titleId}
|
|
316
320
|
onClose={onClose}
|
|
317
|
-
|
|
321
|
+
// A modal that opens fullscreen has nothing to maximize — hide the
|
|
322
|
+
// no-op toggle. (Gate on the requested size, not the computed one,
|
|
323
|
+
// so a modal maximized via this button keeps its Restore control.)
|
|
324
|
+
onMaximize={
|
|
325
|
+
size === 'fullscreen'
|
|
326
|
+
? undefined
|
|
327
|
+
: () => setMaximized(current => !current)
|
|
328
|
+
}
|
|
318
329
|
maximized={maximized}
|
|
319
330
|
trailing={chromeTrailing}
|
|
320
331
|
/>
|