@harborclient/sdk 1.4.4 → 1.5.0
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/CHANGELOG.md +12 -0
- package/dist/components/SidebarItem/SidebarWebsiteItem.d.ts +11 -2
- package/dist/components/SidebarItem/SidebarWebsiteItem.d.ts.map +1 -1
- package/dist/components/SidebarItem/SidebarWebsiteItem.js +6 -3
- package/dist/components/TabBar/index.d.ts +11 -1
- package/dist/components/TabBar/index.d.ts.map +1 -1
- package/dist/components/TabBar/index.js +51 -8
- package/dist/components/VariableInput/index.d.ts +10 -1
- package/dist/components/VariableInput/index.d.ts.map +1 -1
- package/dist/components/VariableInput/index.js +19 -2
- package/dist/runtime/createBridgedPluginContext.js +76 -19
- package/dist/runtime/livePageHandle.d.ts +50 -0
- package/dist/runtime/{webpageHandle.js → livePageHandle.js} +125 -47
- package/dist/snippets.d.ts +34 -12
- package/dist/types.d.ts +521 -14
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/runtime/webpageHandle.d.ts +0 -50
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 1.5.0 - 2026-08-01
|
|
8
|
+
|
|
9
|
+
- feat(live-page): introduce live page functionality and refactor related components. (`16f1f304`)
|
|
10
|
+
|
|
11
|
+
## 1.4.5 - 2026-08-01
|
|
12
|
+
|
|
13
|
+
- feat(websites): implement Add Live Page modal and import functionality. (`1bdbf8a4`)
|
|
14
|
+
- feat(live-page): refactor live page settings panel and update related functionality. (`6a3dfb3e`)
|
|
15
|
+
- feat(live-server): implement Add Live Server modal and import functionality. (`a36916fb`)
|
|
16
|
+
- feat(live-server): enhance live server and live page management. (`fba086b7`)
|
|
17
|
+
- feat(live-server): add openPathOnStartup configuration for live server. (`039b74dc`)
|
|
18
|
+
|
|
7
19
|
## 1.4.4 - 2026-08-01
|
|
8
20
|
|
|
9
21
|
- refactor(teamHub): introduce soft-connection handling for team hubs. (`5fc744ec`)
|
|
@@ -13,6 +13,10 @@ interface Props {
|
|
|
13
13
|
* Globe (or other) icon used when no favicon is available.
|
|
14
14
|
*/
|
|
15
15
|
fallbackIcon: IconDefinition;
|
|
16
|
+
/**
|
|
17
|
+
* Optional connection badge text (e.g. storage location name).
|
|
18
|
+
*/
|
|
19
|
+
connectionBadge?: string;
|
|
16
20
|
/**
|
|
17
21
|
* Whether this row is part of a multi-selection or is the active open website.
|
|
18
22
|
*/
|
|
@@ -25,6 +29,10 @@ interface Props {
|
|
|
25
29
|
* Called when the primary row area is activated.
|
|
26
30
|
*/
|
|
27
31
|
onClick?: (event: MouseEvent<HTMLElement>) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Called when the primary row area is double-clicked (e.g. open page settings).
|
|
34
|
+
*/
|
|
35
|
+
onDoubleClick?: (event: MouseEvent<HTMLElement>) => void;
|
|
28
36
|
/**
|
|
29
37
|
* Called when Enter is pressed on the primary row area.
|
|
30
38
|
*/
|
|
@@ -42,8 +50,9 @@ interface Props {
|
|
|
42
50
|
* Renders a website row in the Collections sidebar Websites section.
|
|
43
51
|
*
|
|
44
52
|
* Shows the site favicon when available, otherwise a globe fallback icon, plus
|
|
45
|
-
* the last known page title
|
|
53
|
+
* the last known page title and an optional storage-location badge inline with
|
|
54
|
+
* the name.
|
|
46
55
|
*/
|
|
47
|
-
export declare function SidebarWebsiteItem({ name, faviconDataUrl, fallbackIcon, selected, onContextMenu, onClick, onEnter, actions, as }: Props): JSX.Element;
|
|
56
|
+
export declare function SidebarWebsiteItem({ name, faviconDataUrl, fallbackIcon, connectionBadge, selected, onContextMenu, onClick, onDoubleClick, onEnter, actions, as }: Props): JSX.Element;
|
|
48
57
|
export {};
|
|
49
58
|
//# sourceMappingURL=SidebarWebsiteItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SidebarWebsiteItem.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarItem/SidebarWebsiteItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,KAAK,GAAG,EAAsB,KAAK,UAAU,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SidebarWebsiteItem.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarItem/SidebarWebsiteItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,KAAK,GAAG,EAAsB,KAAK,UAAU,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAMhG,UAAU,KAAK;IACb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B;;OAEG;IACH,YAAY,EAAE,cAAc,CAAC;IAE7B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAEzD;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAEnD;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAEzD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,EAAE,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,cAAc,EACd,YAAY,EACZ,eAAe,EACf,QAAgB,EAChB,aAAa,EACb,OAAO,EACP,aAAa,EACb,OAAO,EACP,OAAO,EACP,EAAS,EACV,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAkErB"}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { FaIcon } from '../FaIcon/index.js';
|
|
4
|
+
import { SidebarBadge } from './SidebarBadge.js';
|
|
4
5
|
import { SidebarItem } from './SidebarItem.js';
|
|
5
6
|
import { SIDEBAR_ITEM_BUTTON_CLASS } from './sidebarItemClasses.js';
|
|
6
7
|
/**
|
|
7
8
|
* Renders a website row in the Collections sidebar Websites section.
|
|
8
9
|
*
|
|
9
10
|
* Shows the site favicon when available, otherwise a globe fallback icon, plus
|
|
10
|
-
* the last known page title
|
|
11
|
+
* the last known page title and an optional storage-location badge inline with
|
|
12
|
+
* the name.
|
|
11
13
|
*/
|
|
12
|
-
export function SidebarWebsiteItem({ name, faviconDataUrl, fallbackIcon, selected = false, onContextMenu, onClick, onEnter, actions, as = 'li' }) {
|
|
14
|
+
export function SidebarWebsiteItem({ name, faviconDataUrl, fallbackIcon, connectionBadge, selected = false, onContextMenu, onClick, onDoubleClick, onEnter, actions, as = 'li' }) {
|
|
13
15
|
const useListboxOption = as === 'li';
|
|
14
16
|
const [brokenFaviconUrl, setBrokenFaviconUrl] = useState(null);
|
|
15
17
|
const showFavicon = Boolean(faviconDataUrl) && brokenFaviconUrl !== faviconDataUrl;
|
|
@@ -35,7 +37,8 @@ export function SidebarWebsiteItem({ name, faviconDataUrl, fallbackIcon, selecte
|
|
|
35
37
|
return (_jsx(SidebarItem, { selected: selected, onContextMenu: onContextMenu, actions: actions, as: as, listboxOption: useListboxOption
|
|
36
38
|
? {
|
|
37
39
|
onClick,
|
|
40
|
+
onDoubleClick,
|
|
38
41
|
onKeyDown: onEnter != null ? handleKeyDown : undefined
|
|
39
42
|
}
|
|
40
|
-
: undefined, children: _jsxs("span", { className: `${SIDEBAR_ITEM_BUTTON_CLASS} gap-2 rounded-md px-2 py-1`, children: [showFavicon && faviconDataUrl ? (_jsx("img", { src: faviconDataUrl, alt: "", "aria-hidden": true, className: "h-3.5 w-3.5 shrink-0 object-contain", onError: handleFaviconError })) : (_jsx(FaIcon, { icon: fallbackIcon, className: "h-3.5 w-3.5 shrink-0 text-muted", "aria-hidden": true })),
|
|
43
|
+
: undefined, children: _jsxs("span", { className: `${SIDEBAR_ITEM_BUTTON_CLASS} gap-2 rounded-md px-2 py-1`, children: [showFavicon && faviconDataUrl ? (_jsx("img", { src: faviconDataUrl, alt: "", "aria-hidden": true, className: "h-3.5 w-3.5 shrink-0 object-contain", onError: handleFaviconError })) : (_jsx(FaIcon, { icon: fallbackIcon, className: "h-3.5 w-3.5 shrink-0 text-muted", "aria-hidden": true })), _jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-1.5", children: [_jsx("span", { className: "min-w-0 truncate", children: name }), connectionBadge != null ? (_jsx(SidebarBadge, { variant: "info", title: `Stored in ${connectionBadge}`, children: connectionBadge })) : null] })] }) }));
|
|
41
44
|
}
|
|
@@ -50,6 +50,16 @@ interface Props<TId extends string | number> {
|
|
|
50
50
|
* Builds grouped context menu entries when a tab is right-clicked.
|
|
51
51
|
*/
|
|
52
52
|
buildContextMenuGroups?: (targetId: TId, orderedIds: TId[]) => MenuItem[][];
|
|
53
|
+
/**
|
|
54
|
+
* Awaited before the context menu paints. Hosts use this to prepare overlays
|
|
55
|
+
* that must sit above native layers (for example Electron WebContentsView).
|
|
56
|
+
*/
|
|
57
|
+
beforeContextMenuOpen?: () => void | Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Called when the tab context menu closes, or when the tab bar unmounts after a
|
|
60
|
+
* beforeOpen cover may have been applied.
|
|
61
|
+
*/
|
|
62
|
+
onContextMenuClose?: () => void;
|
|
53
63
|
/**
|
|
54
64
|
* When ArrowDown is pressed on a focused tab, returns true if focus moved into
|
|
55
65
|
* the linked panel (for example request editor content).
|
|
@@ -80,7 +90,7 @@ interface Props<TId extends string | number> {
|
|
|
80
90
|
* Document-style tab bar with drag reorder, keyboard navigation, close animation,
|
|
81
91
|
* optional context menu, and a new-tab control.
|
|
82
92
|
*/
|
|
83
|
-
export declare function TabBar<TId extends string | number>({ tabs, activeId, wrap, ariaLabel, tabIdPrefix, panelIdPrefix, sortablePrefix, newTab, onSelect, onClose, onReorder, buildContextMenuGroups, onArrowDownIntoPanel, onFocusTab, renderScrollContainer, maxTabWidthClass, sortableCursor, className }: Props<TId>): JSX.Element;
|
|
93
|
+
export declare function TabBar<TId extends string | number>({ tabs, activeId, wrap, ariaLabel, tabIdPrefix, panelIdPrefix, sortablePrefix, newTab, onSelect, onClose, onReorder, buildContextMenuGroups, beforeContextMenuOpen, onContextMenuClose, onArrowDownIntoPanel, onFocusTab, renderScrollContainer, maxTabWidthClass, sortableCursor, className }: Props<TId>): JSX.Element;
|
|
84
94
|
export type { TabBarItem, TabBarNewTab, TabBarSortableCursor } from './types.js';
|
|
85
95
|
export { TabNewButton } from './TabNewButton.js';
|
|
86
96
|
export { TabContextMenu } from './TabContextMenu.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TabBar/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAkB,GAAG,EAA6B,SAAS,EAAE,MAAM,OAAO,CAAC;AACvF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAM3D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAgCjF,UAAU,KAAK,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IACzC;;OAEG;IACH,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;IAExB;;OAEG;IACH,QAAQ,EAAE,GAAG,CAAC;IAEd;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,MAAM,EAAE,YAAY,CAAC;IAErB;;OAEG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IAE5B;;OAEG;IACH,OAAO,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IAE3B;;OAEG;IACH,SAAS,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,EAAE,CAAC;IAE5E;;;OAGG;IACH,oBAAoB,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC;IAE5C;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IAE/B;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,SAAS,CAAC;IAEtD;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAEtC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqDD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,EAClD,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,WAAW,EACX,aAAa,EACb,cAAc,EACd,MAAM,EACN,QAAQ,EACR,OAAO,EACP,SAAS,EACT,sBAAsB,EACtB,oBAAoB,EACpB,UAAU,EACV,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,SAAS,EACV,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TabBar/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
|
|
2
2
|
import { DndContext as DndContextBase, DragOverlay as DragOverlayBase, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors } from '@dnd-kit/core';
|
|
3
3
|
import { SortableContext, arrayMove, horizontalListSortingStrategy, rectSortingStrategy, sortableKeyboardCoordinates } from '@dnd-kit/sortable';
|
|
4
|
-
import { useEffect, useMemo, useState } from '@harborclient/sdk/react';
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from '@harborclient/sdk/react';
|
|
5
5
|
import { cn, resolveTabListKeyAction } from '../utils.js';
|
|
6
6
|
import { ClosingTabShell } from './ClosingTabShell.js';
|
|
7
7
|
import { TabBarShell } from './TabBarShell.js';
|
|
@@ -57,13 +57,60 @@ function resolveFocusedTabIndex(tabs, activeId, tabIdPrefix) {
|
|
|
57
57
|
* Document-style tab bar with drag reorder, keyboard navigation, close animation,
|
|
58
58
|
* optional context menu, and a new-tab control.
|
|
59
59
|
*/
|
|
60
|
-
export function TabBar({ tabs, activeId, wrap, ariaLabel, tabIdPrefix, panelIdPrefix, sortablePrefix, newTab, onSelect, onClose, onReorder, buildContextMenuGroups, onArrowDownIntoPanel, onFocusTab, renderScrollContainer, maxTabWidthClass, sortableCursor, className }) {
|
|
60
|
+
export function TabBar({ tabs, activeId, wrap, ariaLabel, tabIdPrefix, panelIdPrefix, sortablePrefix, newTab, onSelect, onClose, onReorder, buildContextMenuGroups, beforeContextMenuOpen, onContextMenuClose, onArrowDownIntoPanel, onFocusTab, renderScrollContainer, maxTabWidthClass, sortableCursor, className }) {
|
|
61
61
|
const resolvedSortablePrefix = sortablePrefix ?? `${tabIdPrefix}sort:`;
|
|
62
62
|
const [activeDragId, setActiveDragId] = useState(null);
|
|
63
63
|
const [contextMenu, setContextMenu] = useState(null);
|
|
64
|
+
const contextMenuOpenRequestRef = useRef(0);
|
|
65
|
+
const beforeContextMenuOpenRef = useRef(beforeContextMenuOpen);
|
|
66
|
+
const onContextMenuCloseRef = useRef(onContextMenuClose);
|
|
67
|
+
/**
|
|
68
|
+
* Keeps context-menu lifecycle callbacks current without rebinding open/close helpers.
|
|
69
|
+
*/
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
beforeContextMenuOpenRef.current = beforeContextMenuOpen;
|
|
72
|
+
onContextMenuCloseRef.current = onContextMenuClose;
|
|
73
|
+
}, [beforeContextMenuOpen, onContextMenuClose]);
|
|
64
74
|
const getId = useMemo(() => (item) => item.id, []);
|
|
65
75
|
const sortableEnabled = tabs.length >= 2;
|
|
66
76
|
const { completeExit, getExitingBefore, removedIds } = useExitingTabItems(tabs, getId);
|
|
77
|
+
/**
|
|
78
|
+
* Closes the tab context menu and notifies the host so overlay covers can release.
|
|
79
|
+
*/
|
|
80
|
+
const closeContextMenu = useCallback(() => {
|
|
81
|
+
contextMenuOpenRequestRef.current += 1;
|
|
82
|
+
setContextMenu(null);
|
|
83
|
+
onContextMenuCloseRef.current?.();
|
|
84
|
+
}, []);
|
|
85
|
+
/**
|
|
86
|
+
* Opens the tab context menu after awaiting any host preparation (guest cover, etc.).
|
|
87
|
+
*
|
|
88
|
+
* @param targetId - Tab that was right-clicked.
|
|
89
|
+
* @param x - Viewport X for the menu anchor.
|
|
90
|
+
* @param y - Viewport Y for the menu anchor.
|
|
91
|
+
*/
|
|
92
|
+
const openContextMenu = useCallback(async (targetId, x, y) => {
|
|
93
|
+
const requestId = ++contextMenuOpenRequestRef.current;
|
|
94
|
+
const gate = beforeContextMenuOpenRef.current;
|
|
95
|
+
if (gate) {
|
|
96
|
+
await gate();
|
|
97
|
+
// A newer open or close owns lifecycle; do not uncover here (close already did,
|
|
98
|
+
// or the in-flight open still needs the host cover).
|
|
99
|
+
if (requestId !== contextMenuOpenRequestRef.current) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
setContextMenu({ targetId, x, y });
|
|
104
|
+
}, []);
|
|
105
|
+
/**
|
|
106
|
+
* Releases host overlay covers on unmount, including opens still awaiting beforeOpen.
|
|
107
|
+
*/
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
return () => {
|
|
110
|
+
contextMenuOpenRequestRef.current += 1;
|
|
111
|
+
onContextMenuCloseRef.current?.();
|
|
112
|
+
};
|
|
113
|
+
}, []);
|
|
67
114
|
/**
|
|
68
115
|
* Stable sortable ids for open tabs.
|
|
69
116
|
*/
|
|
@@ -200,11 +247,7 @@ export function TabBar({ tabs, activeId, wrap, ariaLabel, tabIdPrefix, panelIdPr
|
|
|
200
247
|
nodes.push(_jsx(TabBarShell, { item: tab, tabIndex: 0, sortableId: tabSortableId(resolvedSortablePrefix, tab.id), sortableDisabled: !sortableEnabled, tabIdPrefix: tabIdPrefix, panelIdPrefix: panelIdPrefix, maxTabWidthClass: maxTabWidthClass, sortableCursor: sortableCursor, onSelect: onSelect, onClose: onClose, onContextMenu: buildContextMenuGroups == null
|
|
201
248
|
? undefined
|
|
202
249
|
: (id, event) => {
|
|
203
|
-
|
|
204
|
-
targetId: id,
|
|
205
|
-
x: event.clientX,
|
|
206
|
-
y: event.clientY
|
|
207
|
-
});
|
|
250
|
+
void openContextMenu(id, event.clientX, event.clientY);
|
|
208
251
|
} }, `live-${String(tab.id)}`));
|
|
209
252
|
return nodes;
|
|
210
253
|
}), getExitingBefore(null).map((exitingTab) => (_jsx(ClosingTabShell, { onComplete: () => completeExit(exitingTab.exitKey), children: renderTabShell(exitingTab.item, {
|
|
@@ -215,7 +258,7 @@ export function TabBar({ tabs, activeId, wrap, ariaLabel, tabIdPrefix, panelIdPr
|
|
|
215
258
|
const defaultScrollContainer = (row) => (_jsx("div", { className: "min-w-0 flex-1 overflow-x-auto", children: row }));
|
|
216
259
|
const scrollContainer = renderScrollContainer ?? defaultScrollContainer;
|
|
217
260
|
const containerClassName = cn('app-no-drag flex shrink-0 items-end bg-sidebar pr-2 pl-0', className);
|
|
218
|
-
return (_jsxs("div", { className: containerClassName, children: [wrap ? _jsx("div", { className: "min-w-0 flex-1", children: tabRow }) : scrollContainer(tabRow), contextMenu != null && buildContextMenuGroups != null && (_jsx(TabContextMenu, { groups: contextMenuGroups, position: { x: contextMenu.x, y: contextMenu.y }, onClose:
|
|
261
|
+
return (_jsxs("div", { className: containerClassName, children: [wrap ? _jsx("div", { className: "min-w-0 flex-1", children: tabRow }) : scrollContainer(tabRow), contextMenu != null && buildContextMenuGroups != null && (_jsx(TabContextMenu, { groups: contextMenuGroups, position: { x: contextMenu.x, y: contextMenu.y }, onClose: closeContextMenu }))] }));
|
|
219
262
|
}
|
|
220
263
|
export { TabNewButton } from './TabNewButton.js';
|
|
221
264
|
export { TabContextMenu } from './TabContextMenu.js';
|
|
@@ -65,6 +65,15 @@ export interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
65
65
|
* @param open - Whether suggestions are open.
|
|
66
66
|
*/
|
|
67
67
|
onSuggestionsOpenChange?: (open: boolean) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Called after a suggestion is applied via click or keyboard selection.
|
|
70
|
+
*
|
|
71
|
+
* Runs after {@link Props.onChange} with the same value so hosts can treat
|
|
72
|
+
* autocomplete acceptance as a commit (for example navigating a browser).
|
|
73
|
+
*
|
|
74
|
+
* @param item - Selected suggestion value.
|
|
75
|
+
*/
|
|
76
|
+
onSuggestionSelect?: (item: string) => void;
|
|
68
77
|
}
|
|
69
78
|
/**
|
|
70
79
|
* Text input that highlights {{variable}} tokens and shows resolved values on hover.
|
|
@@ -72,5 +81,5 @@ export interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
72
81
|
* Token highlight color (`text-[#32D2E2]`) and the tooltip `app-no-drag` class rely on
|
|
73
82
|
* host styling in HarborClient `styles.css`.
|
|
74
83
|
*/
|
|
75
|
-
export declare function VariableInput({ value, onChange, variables, placeholder, onKeyDown, className, wrapperClassName, onEditVariable, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, source, beforeSuggestionsOpen, onSuggestionsOpenChange, ...props }: Props): JSX.Element;
|
|
84
|
+
export declare function VariableInput({ value, onChange, variables, placeholder, onKeyDown, className, wrapperClassName, onEditVariable, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, source, beforeSuggestionsOpen, onSuggestionsOpenChange, onSuggestionSelect, ...props }: Props): JSX.Element;
|
|
76
85
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/VariableInput/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,aAAa,EAAc,MAAM,OAAO,CAAC;AACtF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAwBnE,MAAM,WAAW,KAAM,SAAQ,IAAI,CACjC,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,GAAG,WAAW,GAAG,IAAI,GAAG,YAAY,GAAG,iBAAiB,GAAG,WAAW,GAAG,UAAU,CAC9F;IACC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAEzD;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAE5B;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/VariableInput/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,aAAa,EAAc,MAAM,OAAO,CAAC;AACtF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAwBnE,MAAM,WAAW,KAAM,SAAQ,IAAI,CACjC,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,GAAG,WAAW,GAAG,IAAI,GAAG,YAAY,GAAG,iBAAiB,GAAG,WAAW,GAAG,UAAU,CAC9F;IACC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAEzD;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAE5B;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAElD;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,WAAW,EACX,SAAS,EACT,SAAc,EACd,gBAAgB,EAChB,cAAc,EACd,EAAE,EACF,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,MAAM,EACN,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAinBrB"}
|
|
@@ -18,7 +18,7 @@ const TOOLTIP_HIDE_DELAY_MS = 400;
|
|
|
18
18
|
* Token highlight color (`text-[#32D2E2]`) and the tooltip `app-no-drag` class rely on
|
|
19
19
|
* host styling in HarborClient `styles.css`.
|
|
20
20
|
*/
|
|
21
|
-
export function VariableInput({ value, onChange, variables, placeholder, onKeyDown, className = '', wrapperClassName, onEditVariable, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, source, beforeSuggestionsOpen, onSuggestionsOpenChange, ...props }) {
|
|
21
|
+
export function VariableInput({ value, onChange, variables, placeholder, onKeyDown, className = '', wrapperClassName, onEditVariable, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, source, beforeSuggestionsOpen, onSuggestionsOpenChange, onSuggestionSelect, ...props }) {
|
|
22
22
|
const safeValue = value ?? '';
|
|
23
23
|
const wrapperRef = useRef(null);
|
|
24
24
|
const inputRef = useRef(null);
|
|
@@ -32,14 +32,31 @@ export function VariableInput({ value, onChange, variables, placeholder, onKeyDo
|
|
|
32
32
|
const tooltipEntered = useRef(false);
|
|
33
33
|
const tooltipSourceRef = useRef(null);
|
|
34
34
|
const activeTokenIndexRef = useRef(null);
|
|
35
|
+
const onSuggestionSelectRef = useRef(onSuggestionSelect);
|
|
35
36
|
const [tooltip, setTooltip] = useState(null);
|
|
36
37
|
const [tooltipSource, setTooltipSource] = useState(null);
|
|
37
38
|
const [activeTokenIndex, setActiveTokenIndex] = useState(null);
|
|
38
39
|
const tooltipId = useId();
|
|
40
|
+
/**
|
|
41
|
+
* Keeps the suggestion-select callback current without retriggering autocomplete setup.
|
|
42
|
+
*/
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
onSuggestionSelectRef.current = onSuggestionSelect;
|
|
45
|
+
}, [onSuggestionSelect]);
|
|
46
|
+
/**
|
|
47
|
+
* Applies a suggestion to the controlled value, then notifies hosts that accept
|
|
48
|
+
* autocomplete as a commit action.
|
|
49
|
+
*
|
|
50
|
+
* @param item - Selected suggestion value.
|
|
51
|
+
*/
|
|
52
|
+
function handleSuggestionSelect(item) {
|
|
53
|
+
onChange(item);
|
|
54
|
+
onSuggestionSelectRef.current?.(item);
|
|
55
|
+
}
|
|
39
56
|
const { open: autocompleteOpen, items: autocompleteItems, activeIndex: autocompleteActiveIndex, listboxId, onFocus: openAutocomplete, onBlur: closeAutocomplete, onInputKeyDown, selectItem, setActiveIndex, closeSuggestions } = useAutocomplete({
|
|
40
57
|
source,
|
|
41
58
|
value: safeValue,
|
|
42
|
-
onSelect:
|
|
59
|
+
onSelect: handleSuggestionSelect,
|
|
43
60
|
anchorRef: inputRef,
|
|
44
61
|
beforeOpen: beforeSuggestionsOpen,
|
|
45
62
|
onOpenChange: onSuggestionsOpenChange
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
registerContributionHeaderActions
|
|
6
6
|
} from './contributionRegistry.js';
|
|
7
7
|
import { bridgeInvoke, bridgeOn } from './hcBridge.js';
|
|
8
|
+
import { openLivePage } from './livePageHandle.js';
|
|
8
9
|
import { createPluginDatabaseApi } from './pluginDatabaseApi.js';
|
|
9
10
|
import { setHostReact } from './reactHost.js';
|
|
10
|
-
import { openWebpage } from './webpageHandle.js';
|
|
11
11
|
|
|
12
12
|
/** @type {Map<string, Set<(...args: unknown[]) => void | Promise<void>>>} */
|
|
13
13
|
const commandHandlers = new Map();
|
|
@@ -354,7 +354,7 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
354
354
|
const assertAi = () => assertPermission('ai');
|
|
355
355
|
|
|
356
356
|
/**
|
|
357
|
-
* Asserts browser permission for embedded
|
|
357
|
+
* Asserts browser permission for embedded live page control.
|
|
358
358
|
*/
|
|
359
359
|
const assertBrowser = () => assertPermission('browser');
|
|
360
360
|
|
|
@@ -364,43 +364,56 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
364
364
|
const assertLiveServer = () => assertPermission('live-server');
|
|
365
365
|
|
|
366
366
|
/**
|
|
367
|
-
*
|
|
367
|
+
* Asserts live-pages permission for saved live page (website) APIs.
|
|
368
|
+
*/
|
|
369
|
+
const assertLivePages = () => assertPermission('live-pages');
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Invokes a livePage session op on the host renderer via the plugin bridge.
|
|
368
373
|
*
|
|
369
|
-
* @param {Record<string, unknown>} req -
|
|
374
|
+
* @param {Record<string, unknown>} req - ScriptLivePageRequest-shaped payload.
|
|
370
375
|
* @returns {Promise<unknown>} Host session result.
|
|
371
376
|
*/
|
|
372
|
-
const
|
|
377
|
+
const callLivePage = async (req) => {
|
|
373
378
|
const op = String(req.op ?? '');
|
|
374
379
|
switch (op) {
|
|
375
380
|
case 'open':
|
|
376
|
-
return bridgeInvoke('
|
|
381
|
+
return bridgeInvoke('livePage.open', { url: req.url, reuse: req.reuse });
|
|
377
382
|
case 'focus':
|
|
378
|
-
return bridgeInvoke('
|
|
383
|
+
return bridgeInvoke('livePage.focus', { tabId: req.tabId });
|
|
379
384
|
case 'close':
|
|
380
|
-
return bridgeInvoke('
|
|
385
|
+
return bridgeInvoke('livePage.close', { tabId: req.tabId });
|
|
381
386
|
case 'query':
|
|
382
|
-
return bridgeInvoke('
|
|
387
|
+
return bridgeInvoke('livePage.query', {
|
|
383
388
|
tabId: req.tabId,
|
|
384
389
|
selector: req.selector,
|
|
385
390
|
all: req.all,
|
|
386
391
|
maxElements: req.maxElements
|
|
387
392
|
});
|
|
388
393
|
case 'evaluate':
|
|
389
|
-
return bridgeInvoke('
|
|
394
|
+
return bridgeInvoke('livePage.evaluate', {
|
|
390
395
|
tabId: req.tabId,
|
|
391
396
|
expression: req.expression
|
|
392
397
|
});
|
|
393
398
|
case 'injectScript':
|
|
394
|
-
return bridgeInvoke('
|
|
399
|
+
return bridgeInvoke('livePage.injectScript', { tabId: req.tabId, source: req.source });
|
|
395
400
|
case 'injectStylesheet':
|
|
396
|
-
return bridgeInvoke('
|
|
401
|
+
return bridgeInvoke('livePage.injectStylesheet', { tabId: req.tabId, css: req.css });
|
|
397
402
|
case 'screenshot':
|
|
398
|
-
return bridgeInvoke('
|
|
403
|
+
return bridgeInvoke('livePage.screenshot', {
|
|
399
404
|
tabId: req.tabId,
|
|
400
405
|
fullPage: req.fullPage === true
|
|
401
406
|
});
|
|
407
|
+
case 'goBack':
|
|
408
|
+
return bridgeInvoke('livePage.goBack', { tabId: req.tabId });
|
|
409
|
+
case 'goForward':
|
|
410
|
+
return bridgeInvoke('livePage.goForward', { tabId: req.tabId });
|
|
411
|
+
case 'reload':
|
|
412
|
+
return bridgeInvoke('livePage.reload', { tabId: req.tabId });
|
|
413
|
+
case 'navigate':
|
|
414
|
+
return bridgeInvoke('livePage.navigate', { tabId: req.tabId, url: req.url });
|
|
402
415
|
default:
|
|
403
|
-
throw new Error(`Unsupported
|
|
416
|
+
throw new Error(`Unsupported livePage bridge op: ${op}`);
|
|
404
417
|
}
|
|
405
418
|
};
|
|
406
419
|
|
|
@@ -860,6 +873,28 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
860
873
|
});
|
|
861
874
|
});
|
|
862
875
|
},
|
|
876
|
+
registerLivePageChromeAction: (action) => {
|
|
877
|
+
assertManifestContribution('livePageChromeActions', action.id);
|
|
878
|
+
if (!isAgent) {
|
|
879
|
+
return noopDisposable();
|
|
880
|
+
}
|
|
881
|
+
void bridgeInvoke('registerContribution', {
|
|
882
|
+
kind: 'livePageChromeActions',
|
|
883
|
+
contribution: {
|
|
884
|
+
pluginId,
|
|
885
|
+
id: action.id,
|
|
886
|
+
title: action.title,
|
|
887
|
+
command: action.command,
|
|
888
|
+
icon: action.icon
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
return track(() => {
|
|
892
|
+
void bridgeInvoke('unregisterContribution', {
|
|
893
|
+
kind: 'livePageChromeActions',
|
|
894
|
+
contributionId: action.id
|
|
895
|
+
});
|
|
896
|
+
});
|
|
897
|
+
},
|
|
863
898
|
registerScriptEditorAction: (action) => {
|
|
864
899
|
assertManifestContribution('scriptEditorActions', action.id);
|
|
865
900
|
if (!isAgent) {
|
|
@@ -1341,6 +1376,28 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
1341
1376
|
});
|
|
1342
1377
|
}
|
|
1343
1378
|
},
|
|
1379
|
+
livePages: {
|
|
1380
|
+
list: async () => {
|
|
1381
|
+
assertLivePages();
|
|
1382
|
+
return bridgeInvoke('livePages.list');
|
|
1383
|
+
},
|
|
1384
|
+
get: async (idOrUuid) => {
|
|
1385
|
+
assertLivePages();
|
|
1386
|
+
return bridgeInvoke('livePages.get', { idOrUuid });
|
|
1387
|
+
},
|
|
1388
|
+
create: async (input) => {
|
|
1389
|
+
assertLivePages();
|
|
1390
|
+
return bridgeInvoke('livePages.create', { input });
|
|
1391
|
+
},
|
|
1392
|
+
update: async (input) => {
|
|
1393
|
+
assertLivePages();
|
|
1394
|
+
return bridgeInvoke('livePages.update', { input });
|
|
1395
|
+
},
|
|
1396
|
+
delete: async (id) => {
|
|
1397
|
+
assertLivePages();
|
|
1398
|
+
await bridgeInvoke('livePages.delete', { id });
|
|
1399
|
+
}
|
|
1400
|
+
},
|
|
1344
1401
|
ai: {
|
|
1345
1402
|
registerChatPointer: (config) => {
|
|
1346
1403
|
assertAi();
|
|
@@ -1375,13 +1432,13 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
1375
1432
|
/**
|
|
1376
1433
|
* Opens or reuses an embedded browser tab and returns a control handle.
|
|
1377
1434
|
*
|
|
1378
|
-
* Requires the `browser` permission. Same semantics as request-script `hc.
|
|
1435
|
+
* Requires the `browser` permission. Same semantics as request-script `hc.livePage`.
|
|
1379
1436
|
*
|
|
1380
1437
|
* @param {string} [url] - Optional URL; omit to bind the active browser tab.
|
|
1381
1438
|
* @param {{ reuse?: boolean }} [options] - Optional `{ reuse }` (default true).
|
|
1382
|
-
* @returns {Promise<import('../types').
|
|
1439
|
+
* @returns {Promise<import('../types').PluginLivePageHandle>} Webpage handle.
|
|
1383
1440
|
*/
|
|
1384
|
-
|
|
1441
|
+
livePage: async (url, options) => {
|
|
1385
1442
|
assertBrowser();
|
|
1386
1443
|
/**
|
|
1387
1444
|
* Writes screenshot PNG bytes via the plugin filesystem bridge.
|
|
@@ -1394,11 +1451,11 @@ export function createBridgedPluginContext({ pluginId, mode, contributionId, rea
|
|
|
1394
1451
|
assertPermission('filesystem:write');
|
|
1395
1452
|
const result = await bridgeInvoke('fs.writeBytes', { path, base64: pngBase64 });
|
|
1396
1453
|
if (typeof result !== 'string' || !result.trim()) {
|
|
1397
|
-
throw new Error('hc.
|
|
1454
|
+
throw new Error('hc.livePage().screenshot failed to resolve write path');
|
|
1398
1455
|
}
|
|
1399
1456
|
return result;
|
|
1400
1457
|
};
|
|
1401
|
-
return
|
|
1458
|
+
return openLivePage(callLivePage, url, options, writeScreenshotBytes);
|
|
1402
1459
|
}
|
|
1403
1460
|
};
|
|
1404
1461
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { PluginLivePageHandle } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Throws when a live-page bridge result is an `{ error }` object.
|
|
5
|
+
*
|
|
6
|
+
* @param result - Raw bridge result.
|
|
7
|
+
* @returns The result when it is not an error.
|
|
8
|
+
* @throws When the bridge returned `{ error: string }`.
|
|
9
|
+
*/
|
|
10
|
+
export function unwrapLivePageBridgeResult(result: unknown): unknown;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Normalizes the optional second argument to `hc.livePage(url, options)`.
|
|
14
|
+
*
|
|
15
|
+
* @param options - User-provided options.
|
|
16
|
+
* @returns Normalized open options.
|
|
17
|
+
*/
|
|
18
|
+
export function normalizeLivePageOpenOptions(options?: unknown): { reuse?: boolean };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Builds a live-page handle whose methods call the host live-page bridge.
|
|
22
|
+
*
|
|
23
|
+
* @param tab - Opened tab metadata from the bridge.
|
|
24
|
+
* @param callLivePage - Bridge transport.
|
|
25
|
+
* @returns Plain-object handle for the plugin world.
|
|
26
|
+
*/
|
|
27
|
+
export function createLivePageHandle(
|
|
28
|
+
tab: {
|
|
29
|
+
tabId: string;
|
|
30
|
+
url: string;
|
|
31
|
+
title: string;
|
|
32
|
+
canGoBack?: boolean;
|
|
33
|
+
canGoForward?: boolean;
|
|
34
|
+
},
|
|
35
|
+
callLivePage: (req: Record<string, unknown>) => Promise<unknown>
|
|
36
|
+
): PluginLivePageHandle;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Opens or reuses an embedded browser tab and returns a control handle.
|
|
40
|
+
*
|
|
41
|
+
* @param callLivePage - Bridge transport that accepts ScriptLivePageRequest-shaped payloads.
|
|
42
|
+
* @param url - Optional URL; omit to bind the active browser tab.
|
|
43
|
+
* @param openOptions - Optional `{ reuse }` (default true).
|
|
44
|
+
* @returns Live-page handle.
|
|
45
|
+
*/
|
|
46
|
+
export function openLivePage(
|
|
47
|
+
callLivePage: (req: Record<string, unknown>) => Promise<unknown>,
|
|
48
|
+
url?: unknown,
|
|
49
|
+
openOptions?: unknown
|
|
50
|
+
): Promise<PluginLivePageHandle>;
|