@mudlet/mudlet-web 0.3.1 → 0.4.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/README.md +8 -0
- package/dist-lib/assets/qt-resources/index.d.ts +16 -0
- package/dist-lib/branding.d.ts +1 -1
- package/dist-lib/hooks/useMudSession.d.ts +1 -1
- package/dist-lib/hooks/useOutput.d.ts +3 -1
- package/dist-lib/import/defaultPackages.d.ts +35 -2
- package/dist-lib/import/defaults/generic_mapper/generic_mapper.mpackage +0 -0
- package/dist-lib/import/defaults/gui-drop/gui-drop.mpackage +0 -0
- package/dist-lib/import/defaults/{run-lua-code.mpackage → mudlet-base-ui/mudlet-base-ui.mpackage} +0 -0
- package/dist-lib/import/defaults/run-lua-code/run-lua-code.mpackage +0 -0
- package/dist-lib/import/packageExport.d.ts +71 -0
- package/dist-lib/import/packageInstaller.d.ts +4 -1
- package/dist-lib/index.js +45935 -40688
- package/dist-lib/logging/SessionLogger.d.ts +66 -1
- package/dist-lib/map/MapStore.d.ts +32 -4
- package/dist-lib/map/mapImageExport.d.ts +1 -1
- package/dist-lib/map/mapZoom.d.ts +71 -0
- package/dist-lib/mud/ItemIdSequence.d.ts +23 -0
- package/dist-lib/mud/MudSession.d.ts +113 -11
- package/dist-lib/mud/PatternEngine.d.ts +6 -1
- package/dist-lib/mud/commandSplit.d.ts +16 -0
- package/dist-lib/mud/connection/LineAssembler.d.ts +56 -0
- package/dist-lib/mud/connection/MudClient.d.ts +120 -16
- package/dist-lib/mud/connection/TelnetNegotiator.d.ts +39 -0
- package/dist-lib/mud/connection/telnetByteTags.d.ts +35 -0
- package/dist-lib/mud/events.d.ts +19 -4
- package/dist-lib/mud/games/bundledGames.d.ts +29 -0
- package/dist-lib/mud/games/gameIcons.d.ts +5 -0
- package/dist-lib/mud/keybindings/KeyEngine.d.ts +9 -2
- package/dist-lib/mud/keybindings/browserReservedKeys.d.ts +5 -1
- package/dist-lib/mud/keybindings/keyEventTarget.d.ts +17 -0
- package/dist-lib/mud/keybindings/qtKeys.d.ts +2 -0
- package/dist-lib/mud/protocol/charLoginFlow.d.ts +68 -0
- package/dist-lib/mud/protocol/charset.d.ts +27 -5
- package/dist-lib/mud/protocol/constants.d.ts +1 -0
- package/dist-lib/mud/protocol/gmcp.d.ts +19 -3
- package/dist-lib/mud/protocol/index.d.ts +1 -1
- package/dist-lib/mud/protocol/mxp.d.ts +28 -5
- package/dist-lib/mud/replay/ReplayPlayer.d.ts +17 -0
- package/dist-lib/mud/text/Console.d.ts +64 -0
- package/dist-lib/mud/text/FormatState.d.ts +66 -3
- package/dist-lib/mud/text/hyperlinkVisibility.d.ts +35 -0
- package/dist-lib/mud/text/osc8Docs.d.ts +23 -0
- package/dist-lib/mud/text/serverWrap.d.ts +191 -0
- package/dist-lib/mud/timers/TimerEngine.d.ts +43 -12
- package/dist-lib/mud/triggers/TriggerEngine.d.ts +112 -3
- package/dist-lib/scripting/EngineHost.d.ts +56 -3
- package/dist-lib/scripting/IScriptingRuntime.d.ts +16 -0
- package/dist-lib/scripting/MxpFrameManager.d.ts +118 -0
- package/dist-lib/scripting/ScriptingAPI.d.ts +323 -54
- package/dist-lib/scripting/ScriptingEngine.d.ts +180 -23
- package/dist-lib/scripting/http/HttpService.d.ts +51 -1
- package/dist-lib/scripting/lua/LuaRuntime.d.ts +151 -2
- package/dist-lib/scripting/lua/bindings/map.d.ts +0 -12
- package/dist-lib/scripting/lua/utf8Patterns.d.ts +59 -0
- package/dist-lib/storage/index.d.ts +1 -1
- package/dist-lib/storage/persistentStorage.d.ts +10 -0
- package/dist-lib/storage/schema.d.ts +116 -0
- package/dist-lib/styles.css +1 -1
- package/dist-lib/ui/BundledGameGrid.d.ts +21 -0
- package/dist-lib/ui/CommandBar.d.ts +7 -1
- package/dist-lib/ui/ConnectionGrid.d.ts +4 -1
- package/dist-lib/ui/FilePickerModal.d.ts +3 -3
- package/dist-lib/ui/HelpModal.d.ts +11 -0
- package/dist-lib/ui/LogBrowserModal.d.ts +4 -1
- package/dist-lib/ui/PlayerMarkerPreview.d.ts +20 -0
- package/dist-lib/ui/Toolbar.d.ts +2 -1
- package/dist-lib/ui/VfsPickerModal.d.ts +26 -0
- package/dist-lib/ui/components/FileSourceButton.d.ts +47 -0
- package/dist-lib/ui/components/index.d.ts +1 -0
- package/dist-lib/ui/helpTopics.d.ts +19 -0
- package/dist-lib/ui/labels/LabelManager.d.ts +7 -0
- package/dist-lib/ui/layout/ScriptWindow.d.ts +11 -2
- package/dist-lib/ui/markdown.d.ts +10 -1
- package/dist-lib/ui/output/OutputArea.d.ts +11 -1
- package/dist-lib/ui/output/OutputContextMenu.d.ts +3 -1
- package/dist-lib/ui/output/OutputRenderer.d.ts +7 -1
- package/dist-lib/ui/output/OutputSearchBar.d.ts +25 -0
- package/dist-lib/ui/output/StickyOutputPanel.d.ts +5 -1
- package/dist-lib/ui/output/outputSearch.d.ts +130 -0
- package/dist-lib/ui/search/matcher.d.ts +15 -0
- package/dist-lib/ui/search/useDebounced.d.ts +3 -0
- package/dist-lib/ui/tts/TtsManager.d.ts +3 -0
- package/dist-lib/ui/useCommandHistory.d.ts +4 -2
- package/dist-lib/ui/useOpenProfiles.d.ts +26 -0
- package/dist-lib/ui/video/VideoManager.d.ts +17 -0
- package/dist-lib/ui/windows/WindowManager.d.ts +132 -2
- package/dist-lib/ui/windows/panels/MapPanel.d.ts +4 -1
- package/dist-lib/ui/windows/panels/PackageExportModal.d.ts +18 -0
- package/dist-lib/ui/windows/panels/TextPanel.d.ts +3 -1
- package/dist-lib/ui/windows/types.d.ts +35 -0
- package/dist-lib/utils/describeThrown.d.ts +22 -0
- package/dist-lib/utils/fontLoader.d.ts +5 -0
- package/dist-lib/vite.js +22 -0
- package/package.json +10 -6
- package/dist-lib/scripting/lua/mudlet-lua/generic-mapper/generic_mapper.mpackage +0 -0
- package/dist-lib/ui/windows/panels/VfsModulePickerModal.d.ts +0 -8
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type BundledGame } from '../mud/games/bundledGames';
|
|
2
|
+
import type { MudConnection } from '../storage';
|
|
3
|
+
/** The connection record a game turns into. Mudlet's catalogue is host/port, so
|
|
4
|
+
* these are proxied `mud` profiles — the same thing the Add form builds. */
|
|
5
|
+
export declare function connectionFromGame(game: BundledGame): Omit<MudConnection, 'id'>;
|
|
6
|
+
interface Props {
|
|
7
|
+
/** Profiles that already exist, so a game someone has played is offered by
|
|
8
|
+
* its profile tile above rather than a second time down here. */
|
|
9
|
+
connections: MudConnection[];
|
|
10
|
+
busy: boolean;
|
|
11
|
+
/** Create the profile and start playing. */
|
|
12
|
+
onPlay: (game: BundledGame) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The games Mudlet ships with, offered the way Mudlet offers them: a browsable
|
|
16
|
+
* list you can start playing without filling in a form. Picking one is what
|
|
17
|
+
* turns it into a profile — until then nothing is stored, so the list is not a
|
|
18
|
+
* pile of empty profiles a player has to tidy up.
|
|
19
|
+
*/
|
|
20
|
+
export declare function BundledGameGrid({ connections, busy, onPlay }: Props): import("react/jsx-runtime").JSX.Element | null;
|
|
21
|
+
export {};
|
|
@@ -10,8 +10,14 @@ interface CommandBarProps {
|
|
|
10
10
|
/** Tab-completion suggestions added via Mudlet's addCmdLineSuggestion API.
|
|
11
11
|
* Merged ahead of command history (dedup, case-insensitive). */
|
|
12
12
|
suggestions?: string[];
|
|
13
|
+
/** Words Mudlet's addCmdLineBlacklist API has taken out of Tab completion.
|
|
14
|
+
* Subtractive across every source below, not just `suggestions`. */
|
|
15
|
+
blacklist?: string[];
|
|
16
|
+
/** Mudlet's per-command-line setSaveCommandHistory. False keeps the history
|
|
17
|
+
* for this session but stops persisting it. */
|
|
18
|
+
saveHistory?: boolean;
|
|
13
19
|
/** Recency-ordered words seen in output, for argument-word Tab completion. */
|
|
14
20
|
bufferWords?: BufferWordIndex | null;
|
|
15
21
|
}
|
|
16
|
-
export declare function CommandBar({ command, onCommandChange, passwordMode, commandInputRef, onSubmit, cmdLineMenu, suggestions, bufferWords }: CommandBarProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function CommandBar({ command, onCommandChange, passwordMode, commandInputRef, onSubmit, cmdLineMenu, suggestions, blacklist, saveHistory, bufferWords }: CommandBarProps): import("react/jsx-runtime").JSX.Element;
|
|
17
23
|
export {};
|
|
@@ -4,6 +4,9 @@ interface Props {
|
|
|
4
4
|
connecting: boolean;
|
|
5
5
|
connectingId: string | null;
|
|
6
6
|
editingId: string | null;
|
|
7
|
+
/** Ids already open in another browser tab — one tab per profile, so these
|
|
8
|
+
* can't be opened here until that tab releases them. */
|
|
9
|
+
openIds: Set<string>;
|
|
7
10
|
onConnect: (c: MudConnection) => void;
|
|
8
11
|
onOpen: (c: MudConnection) => void;
|
|
9
12
|
onEdit: (c: MudConnection) => void;
|
|
@@ -14,5 +17,5 @@ interface Props {
|
|
|
14
17
|
/** Draggable, animated grid of profile cards. Reordering lifts the dragged tile
|
|
15
18
|
* into a floating clone, opens a dashed placeholder at the target slot, and
|
|
16
19
|
* slides the remaining tiles into their new positions with a FLIP animation. */
|
|
17
|
-
export declare function ConnectionGrid({ connections, connecting, connectingId, editingId, onConnect, onOpen, onEdit, onDelete, onReorder, onAddClick, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare function ConnectionGrid({ connections, connecting, connectingId, editingId, openIds, onConnect, onOpen, onEdit, onDelete, onReorder, onAddClick, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
18
21
|
export {};
|
|
@@ -5,9 +5,9 @@ import type { ProfileVFS } from '../scripting/vfs/ProfileVFS';
|
|
|
5
5
|
* header ✕) must call `onDone` — with the picked absolute VFS path, or '' for
|
|
6
6
|
* cancel (Mudlet's return value for a dismissed dialog).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* The tree itself is VfsPickerModal, shared with the app's "pick from profile
|
|
9
|
+
* files" buttons; this wrapper only narrows it to the single-path contract Lua
|
|
10
|
+
* expects.
|
|
11
11
|
*/
|
|
12
12
|
interface FilePickerModalProps {
|
|
13
13
|
vfs: ProfileVFS | null;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import './HelpModal.css';
|
|
2
|
+
interface HelpModalProps {
|
|
3
|
+
/** Bounds are remembered per profile; omitted on the start screen, where
|
|
4
|
+
* there is no active connection to key them by. */
|
|
5
|
+
connectionId?: string;
|
|
6
|
+
/** Topic to open on — defaults to the migration guide. */
|
|
7
|
+
initialTopic?: string;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function HelpModal({ connectionId, initialTopic, onClose }: HelpModalProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import type { ProfileVFS } from '../scripting/vfs/ProfileVFS';
|
|
1
2
|
interface LogBrowserModalProps {
|
|
2
3
|
connectionId: string;
|
|
3
4
|
connectionName: string;
|
|
5
|
+
/** Lets "Import…" read a log export the profile already holds. */
|
|
6
|
+
vfs?: ProfileVFS | null;
|
|
4
7
|
onClose: () => void;
|
|
5
8
|
}
|
|
6
|
-
export declare function LogBrowserModal({ connectionId, connectionName, onClose }: LogBrowserModalProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function LogBrowserModal({ connectionId, connectionName, vfs, onClose }: LogBrowserModalProps): import("react/jsx-runtime").JSX.Element;
|
|
7
10
|
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type MapperSettings } from '../storage';
|
|
2
|
+
interface PlayerMarkerPreviewProps {
|
|
3
|
+
/** The profile's live mapper settings — the preview honours all of them
|
|
4
|
+
* (room shape/size, borders, exit colour, background, grid), not just the
|
|
5
|
+
* marker, so what it shows is what the map will look like. */
|
|
6
|
+
mapper: MapperSettings | undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Live preview of the player-position marker, rendered by the *actual*
|
|
10
|
+
* `MapRenderer` against a five-room stub map.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately not a hand-drawn SVG mock: the marker's geometry (size relative
|
|
13
|
+
* to `roomSize`, dash phase, the rect/circle switch driven by `matchRoomShape`
|
|
14
|
+
* + `roomShape`, the rounded-rectangle corner radius) all lives in the
|
|
15
|
+
* renderer, and a reimplementation here would drift silently the first time
|
|
16
|
+
* the library changes it. Konva is already in the bundle for MapPanel, so this
|
|
17
|
+
* costs a stage, not a chunk.
|
|
18
|
+
*/
|
|
19
|
+
export declare function PlayerMarkerPreview({ mapper }: PlayerMarkerPreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
package/dist-lib/ui/Toolbar.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ interface ToolbarProps {
|
|
|
12
12
|
onOpenFiles: () => void;
|
|
13
13
|
onOpenLogs: () => void;
|
|
14
14
|
onOpenDocs: () => void;
|
|
15
|
+
onOpenHelp: () => void;
|
|
15
16
|
onOpenSettings: () => void;
|
|
16
17
|
/** Mudlet-format replay recording toggle state + handler. */
|
|
17
18
|
replayRecording: boolean;
|
|
@@ -25,5 +26,5 @@ interface ToolbarProps {
|
|
|
25
26
|
/** Capabilities handed to brand toolbar buttons (send / raiseEvent). */
|
|
26
27
|
brandContext?: BrandToolbarContext;
|
|
27
28
|
}
|
|
28
|
-
export declare function Toolbar({ connectionName, status, ping, onDisconnect, onReconnect, onNewConnection, onOpenMap, onOpenScripts, onOpenFiles, onOpenLogs, onOpenDocs, onOpenSettings, replayRecording, onToggleReplayRecording, replaySpeed, onReplaySpeedChange, onReplayStop, onContextMenu, brandContext }: ToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export declare function Toolbar({ connectionName, status, ping, onDisconnect, onReconnect, onNewConnection, onOpenMap, onOpenScripts, onOpenFiles, onOpenLogs, onOpenDocs, onOpenHelp, onOpenSettings, replayRecording, onToggleReplayRecording, replaySpeed, onReplaySpeedChange, onReplayStop, onContextMenu, brandContext }: ToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
29
30
|
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ProfileVFS } from '../scripting/vfs/ProfileVFS';
|
|
2
|
+
/**
|
|
3
|
+
* The profile-VFS file/folder picker. Backs both Lua's `invokeFileDialog`
|
|
4
|
+
* (single file or folder — see FilePickerModal) and the "pick from profile
|
|
5
|
+
* files" half of every place the app would otherwise only take an upload from
|
|
6
|
+
* the user's computer.
|
|
7
|
+
*
|
|
8
|
+
* `mode`:
|
|
9
|
+
* - `file` — one file (QFileDialog::getOpenFileName)
|
|
10
|
+
* - `files` — several files, checkbox per row
|
|
11
|
+
* - `folder` — one directory, files hidden (getExistingDirectory)
|
|
12
|
+
*/
|
|
13
|
+
export type VfsPickerMode = 'file' | 'files' | 'folder';
|
|
14
|
+
interface VfsPickerModalProps {
|
|
15
|
+
vfs: ProfileVFS | null;
|
|
16
|
+
mode: VfsPickerMode;
|
|
17
|
+
title?: string;
|
|
18
|
+
/** VFS path to reveal on open; '' or invalid falls back to the root. */
|
|
19
|
+
location?: string;
|
|
20
|
+
/** Filename filter — non-matching files are hidden (folders always show). */
|
|
21
|
+
accept?: RegExp;
|
|
22
|
+
/** Picked absolute VFS paths; an empty array means the user cancelled. */
|
|
23
|
+
onDone: (paths: string[]) => void;
|
|
24
|
+
}
|
|
25
|
+
export declare function VfsPickerModal({ vfs, mode, title, location, accept, onDone }: VfsPickerModalProps): import("react").ReactPortal;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
import type { ProfileVFS } from '../../scripting/vfs/ProfileVFS';
|
|
3
|
+
export interface PickedFile {
|
|
4
|
+
file: File;
|
|
5
|
+
/** Absolute VFS path — set only when the file came from the profile. */
|
|
6
|
+
vfsPath?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FileSourceOptions {
|
|
9
|
+
vfs: ProfileVFS | null;
|
|
10
|
+
/** `accept` for the OS picker; also derives the VFS filter when `vfsAccept` is absent. */
|
|
11
|
+
accept?: string;
|
|
12
|
+
/** Filename filter for the VFS tree. Pass `null` to show every file. */
|
|
13
|
+
vfsAccept?: RegExp | null;
|
|
14
|
+
multiple?: boolean;
|
|
15
|
+
/** Start directory for the VFS picker. */
|
|
16
|
+
location?: string;
|
|
17
|
+
/** Title of the VFS picker window. */
|
|
18
|
+
pickerTitle?: string;
|
|
19
|
+
onPick: (files: PickedFile[]) => void | Promise<void>;
|
|
20
|
+
/** Surfaces a VFS read failure; falls back to console.warn when absent. */
|
|
21
|
+
onError?: (message: string) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Turn an `accept` attribute into a filename filter for the VFS tree.
|
|
25
|
+
* Extensions and `type/*` wildcards translate; a concrete MIME type
|
|
26
|
+
* (`application/json`) doesn't, since VFS entries carry no content type — those
|
|
27
|
+
* contribute nothing, and an accept list of only such entries filters nothing
|
|
28
|
+
* rather than hiding every file.
|
|
29
|
+
*/
|
|
30
|
+
export declare function acceptToRegExp(accept?: string): RegExp | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Headless half of the dual-source picker, for call sites whose trigger isn't a
|
|
33
|
+
* plain `Button` (the map overlay's own buttons, hamburger menu entries).
|
|
34
|
+
* Render `elements` anywhere in the subtree and call `open(triggerElement)`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useFileSource({ vfs, accept, vfsAccept, multiple, location, pickerTitle, onPick, onError, }: FileSourceOptions): {
|
|
37
|
+
open: (anchor: HTMLElement | DOMRect | null) => void;
|
|
38
|
+
elements: ReactNode;
|
|
39
|
+
};
|
|
40
|
+
type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'icon' | 'danger';
|
|
41
|
+
interface FileSourceButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'onError'>, FileSourceOptions {
|
|
42
|
+
label: ReactNode;
|
|
43
|
+
variant?: ButtonVariant;
|
|
44
|
+
size?: 'sm' | 'md';
|
|
45
|
+
}
|
|
46
|
+
export declare function FileSourceButton({ vfs, label, accept, vfsAccept, multiple, location, pickerTitle, onPick, onError, variant, size, ...buttonProps }: FileSourceButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
export {};
|
|
@@ -2,6 +2,7 @@ export { Button } from './Button';
|
|
|
2
2
|
export { Input } from './Input';
|
|
3
3
|
export { FormField, CheckField } from './FormField';
|
|
4
4
|
export { ContextMenu } from './ContextMenu';
|
|
5
|
+
export { FileSourceButton, useFileSource, acceptToRegExp, type PickedFile } from './FileSourceButton';
|
|
5
6
|
export { ConfirmDialog, ConfirmProvider, useConfirm } from './ConfirmDialog';
|
|
6
7
|
export type { ConfirmButton, ConfirmOptions } from './ConfirmDialog';
|
|
7
8
|
export { FontPicker } from './FontPicker';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface HelpTopic {
|
|
2
|
+
/** Stable id used in state and (eventually) deep links. */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Sidebar label. Kept short — the markdown's own H1 is the real title. */
|
|
5
|
+
title: string;
|
|
6
|
+
/** One line under the label, so the sidebar answers "which one do I want?" */
|
|
7
|
+
blurb: string;
|
|
8
|
+
/** Basename in docs/help/, for resolving relative links between topics. */
|
|
9
|
+
file: string;
|
|
10
|
+
markdown: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const HELP_TOPICS: HelpTopic[];
|
|
13
|
+
export declare const DEFAULT_HELP_TOPIC: string;
|
|
14
|
+
/** Resolve a markdown link href to a topic id, or null if it isn't one of ours.
|
|
15
|
+
* Handles `./storage.md`, `storage.md`, `docs/help/storage.md` and a `#anchor`
|
|
16
|
+
* suffix — the shapes a relative link between these files can take. */
|
|
17
|
+
export declare function topicForHref(href: string): string | null;
|
|
18
|
+
/** Topics whose title, blurb or body mention `query`. Empty query = everything. */
|
|
19
|
+
export declare function searchHelpTopics(query: string): HelpTopic[];
|
|
@@ -167,6 +167,13 @@ export declare class LabelManager {
|
|
|
167
167
|
/** Mudlet setMovie — install (or replace) the label's GIF player. */
|
|
168
168
|
setMovie(name: string, player: MoviePlayer): boolean;
|
|
169
169
|
getMovie(name: string): MoviePlayer | null;
|
|
170
|
+
/** Mudlet's `getProfileStats().gifs`: how many labels carry a movie, and
|
|
171
|
+
* how many of those are actually running. Deleting a label takes its movie
|
|
172
|
+
* out of both counts, since the label is where a movie lives. */
|
|
173
|
+
movieStats(): {
|
|
174
|
+
total: number;
|
|
175
|
+
active: number;
|
|
176
|
+
};
|
|
170
177
|
/** Mudlet scaleMovie — autoscale tracks the label size (CSS 100%);
|
|
171
178
|
* autoscale=false freezes the scale at the label's current geometry.
|
|
172
179
|
* False when the label has no movie (matches Mudlet's warning case). */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DockSide, DragState } from '../windows/types';
|
|
1
|
+
import type { DockSide, DragState, MxpTabPage } from '../windows/types';
|
|
2
2
|
import type { WindowManager } from '../windows/WindowManager';
|
|
3
3
|
interface ScriptWindowProps {
|
|
4
4
|
id: string;
|
|
@@ -17,6 +17,15 @@ interface ScriptWindowProps {
|
|
|
17
17
|
/** When true, dragging the titlebar still moves the window but never
|
|
18
18
|
* enters a dock zone — mirrors Mudlet's openUserWindow(..., autoDock=false). */
|
|
19
19
|
lockFloating?: boolean;
|
|
20
|
+
/** MXP `<FRAME TITLE=…>` tab strip drawn above the content. The first page
|
|
21
|
+
* is this window's own console; the rest are `DOCK`ed frames nested inside
|
|
22
|
+
* its viewport. See MxpFrameManager. */
|
|
23
|
+
frameTabs?: {
|
|
24
|
+
pages: MxpTabPage[];
|
|
25
|
+
active: string;
|
|
26
|
+
};
|
|
27
|
+
/** Console backing an MXP `<FRAME>` — outlines it, like Mudlet does. */
|
|
28
|
+
isMxpFrame?: boolean;
|
|
20
29
|
onFocus: () => void;
|
|
21
30
|
onMoved: (x: number, y: number) => void;
|
|
22
31
|
onResized: (w: number, h: number) => void;
|
|
@@ -25,5 +34,5 @@ interface ScriptWindowProps {
|
|
|
25
34
|
onTitlebarContextMenu: (e: React.MouseEvent) => void;
|
|
26
35
|
onHide: () => void;
|
|
27
36
|
}
|
|
28
|
-
export declare function ScriptWindow({ id, title, visible, x, y, width, height, zIndex, manager, isMiniConsole, lockFloating, onFocus, onMoved, onResized, onDock, onDragStateChange, onTitlebarContextMenu, onHide, }: ScriptWindowProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export declare function ScriptWindow({ id, title, visible, x, y, width, height, zIndex, manager, isMiniConsole, lockFloating, frameTabs, isMxpFrame, onFocus, onMoved, onResized, onDock, onDragStateChange, onTitlebarContextMenu, onHide, }: ScriptWindowProps): import("react/jsx-runtime").JSX.Element;
|
|
29
38
|
export {};
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
interface RenderOptions {
|
|
2
|
+
/** Turn a single newline into a `<br>`. On for user-written notes, where
|
|
3
|
+
* `gfm + breaks` matches the behavior most note apps render. Off for
|
|
4
|
+
* hard-wrapped prose documents, where source line breaks are just wrapping
|
|
5
|
+
* and rendering them would shred every paragraph — which is also how GitHub
|
|
6
|
+
* renders a `.md` file. */
|
|
7
|
+
breaks?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function renderMarkdown(src: string, { breaks }?: RenderOptions): string;
|
|
10
|
+
export {};
|
|
@@ -4,6 +4,16 @@ interface OutputAreaProps {
|
|
|
4
4
|
session: MudSession;
|
|
5
5
|
stickyLines?: number;
|
|
6
6
|
commandInputRef?: React.RefObject<HTMLInputElement | HTMLTextAreaElement | null>;
|
|
7
|
+
/** Extra insets claimed by edge-aligned MXP `<FRAME>`s, on top of the
|
|
8
|
+
* profile's setBorder* sizes. Mudlet keeps the two apart the same way
|
|
9
|
+
* (Host::mUserBorders + mMxpBorders) so a server layout and a script never
|
|
10
|
+
* clobber each other's borders. */
|
|
11
|
+
mxpBorders?: {
|
|
12
|
+
top: number;
|
|
13
|
+
right: number;
|
|
14
|
+
bottom: number;
|
|
15
|
+
left: number;
|
|
16
|
+
};
|
|
7
17
|
}
|
|
8
|
-
export declare function OutputArea({ session, stickyLines, commandInputRef }: OutputAreaProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function OutputArea({ session, stickyLines, commandInputRef, mxpBorders }: OutputAreaProps): import("react/jsx-runtime").JSX.Element;
|
|
9
19
|
export {};
|
|
@@ -12,6 +12,8 @@ interface OutputContextMenuProps {
|
|
|
12
12
|
onCopy: () => void;
|
|
13
13
|
onCopyHtml: () => void;
|
|
14
14
|
onCopyImage: () => void;
|
|
15
|
+
/** Opens the find bar — only the main console passes this. */
|
|
16
|
+
onFind?: () => void;
|
|
15
17
|
/** Timestamp toggle — only the main console passes these. */
|
|
16
18
|
showTimestamps?: boolean;
|
|
17
19
|
onToggleTimestamps?: () => void;
|
|
@@ -19,5 +21,5 @@ interface OutputContextMenuProps {
|
|
|
19
21
|
extraItems?: OutputMenuExtraItem[];
|
|
20
22
|
onClose: () => void;
|
|
21
23
|
}
|
|
22
|
-
export declare function OutputContextMenu({ x, y, hasSelection, onSelectAll, onCopy, onCopyHtml, onCopyImage, showTimestamps, onToggleTimestamps, extraItems, onClose, }: OutputContextMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export declare function OutputContextMenu({ x, y, hasSelection, onSelectAll, onCopy, onCopyHtml, onCopyImage, onFind, showTimestamps, onToggleTimestamps, extraItems, onClose, }: OutputContextMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
23
25
|
export {};
|
|
@@ -47,6 +47,12 @@ type OutputHandlerOptions = {
|
|
|
47
47
|
maxElements?: number | (() => number);
|
|
48
48
|
trimSlack?: number;
|
|
49
49
|
suppressSplitView?: (durationMs: number) => void;
|
|
50
|
+
/** Whether new output should scroll the view to the tail. True for a
|
|
51
|
+
* scrollback; false for a console the writer rewrites wholesale — an MXP
|
|
52
|
+
* frame written with `<DEST … EOF>` — where following the tail makes the
|
|
53
|
+
* content slide as a multi-flush redraw lands. Read live on every write, so
|
|
54
|
+
* a console can become top-anchored after it is already mounted. */
|
|
55
|
+
followTail?: () => boolean;
|
|
50
56
|
/** Called once the cursor ops are ready; wire them to ScriptingAPI/session. */
|
|
51
57
|
onCursorReady?: (ops: CursorOps) => void;
|
|
52
58
|
};
|
|
@@ -60,5 +66,5 @@ export type OutputRendererControls = {
|
|
|
60
66
|
push: (message: string | AnsiAwareBuffer, type?: string, timestamp?: number) => void;
|
|
61
67
|
clear: () => void;
|
|
62
68
|
};
|
|
63
|
-
export declare function setupOutputRenderer(source: MessageSource | null, { outputWrapper, sentinel, stickyArea, isSplitView, stickyLines, maxElements, trimSlack, suppressSplitView, onCursorReady, }: OutputHandlerOptions): OutputRendererControls;
|
|
69
|
+
export declare function setupOutputRenderer(source: MessageSource | null, { outputWrapper, sentinel, stickyArea, isSplitView, stickyLines, maxElements, trimSlack, suppressSplitView, followTail, onCursorReady, }: OutputHandlerOptions): OutputRendererControls;
|
|
64
70
|
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { MudSession } from '../../mud/MudSession';
|
|
3
|
+
import './OutputSearchBar.css';
|
|
4
|
+
interface OutputSearchBarProps {
|
|
5
|
+
session: MudSession;
|
|
6
|
+
/** The `.output-wrapper` scroller holding the rendered scrollback. */
|
|
7
|
+
outputRef: React.RefObject<HTMLDivElement | null>;
|
|
8
|
+
/** Changes on every Ctrl+F. Re-focuses the box and re-seeds it from the
|
|
9
|
+
* output selection, so pressing the shortcut again behaves like the
|
|
10
|
+
* browser's find rather than doing nothing. */
|
|
11
|
+
focusNonce: number;
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
/** Rebuilds the split-view panel from the (now highlighted) source lines —
|
|
14
|
+
* its contents are clones, so marks only reach it via a re-populate. */
|
|
15
|
+
refreshSticky?: () => void;
|
|
16
|
+
/** Focus target once the bar closes, so the player can keep typing. */
|
|
17
|
+
commandInputRef?: React.RefObject<HTMLInputElement | HTMLTextAreaElement | null>;
|
|
18
|
+
/** Mudlet's `f3SearchEnabled` — the accessibility mode for buffer search.
|
|
19
|
+
* Turns each step into a screen-reader event: only the current hit stays
|
|
20
|
+
* tinted, focus parks on it, and the whole matched line is announced.
|
|
21
|
+
* See docs/config-api.md. */
|
|
22
|
+
a11ySearch?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function OutputSearchBar({ session, outputRef, focusNonce, onClose, refreshSticky, commandInputRef, a11ySearch, }: OutputSearchBarProps): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export {};
|
|
@@ -13,6 +13,8 @@ interface StickyOutputPanelProps {
|
|
|
13
13
|
foreground?: string;
|
|
14
14
|
showTimestamps?: boolean;
|
|
15
15
|
onToggleTimestamps?: () => void;
|
|
16
|
+
/** Opens the find bar from the right-click menu — main console only. */
|
|
17
|
+
onFind?: () => void;
|
|
16
18
|
/** Script-provided right-click entries (Mudlet addMouseEvent), evaluated
|
|
17
19
|
* lazily when the menu opens since the registry can change. */
|
|
18
20
|
getMenuExtraItems?: () => OutputMenuExtraItem[];
|
|
@@ -20,9 +22,11 @@ interface StickyOutputPanelProps {
|
|
|
20
22
|
className?: string;
|
|
21
23
|
fontSize?: number;
|
|
22
24
|
fontFamily?: string;
|
|
25
|
+
/** Rendered row height in px, overriding the stylesheet line-height. */
|
|
26
|
+
lineHeight?: number;
|
|
23
27
|
wrapAt?: number;
|
|
24
28
|
wrapIndent?: number;
|
|
25
29
|
wrapHangingIndent?: number;
|
|
26
30
|
}
|
|
27
|
-
export declare function StickyOutputPanel({ outputRef, sentinelRef, stickyAreaRef, isSplitView, scrollToBottom, background, backgroundExtra, foreground, showTimestamps, onToggleTimestamps, getMenuExtraItems, commandInputRef, className, fontSize, fontFamily, wrapAt, wrapIndent, wrapHangingIndent, }: StickyOutputPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function StickyOutputPanel({ outputRef, sentinelRef, stickyAreaRef, isSplitView, scrollToBottom, background, backgroundExtra, foreground, showTimestamps, onToggleTimestamps, onFind, getMenuExtraItems, commandInputRef, className, fontSize, fontFamily, lineHeight, wrapAt, wrapIndent, wrapHangingIndent, }: StickyOutputPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
28
32
|
export {};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find-in-output: scans the rendered scrollback for a query and tints every hit.
|
|
3
|
+
*
|
|
4
|
+
* This works purely on the rendered DOM rather than on the `AnsiAwareBuffer`
|
|
5
|
+
* model behind each line. Two reasons:
|
|
6
|
+
*
|
|
7
|
+
* - Highlighting is transient. `buffer.applyFormat()` rewrites segment state,
|
|
8
|
+
* so undoing a search highlight would mean snapshotting and restoring every
|
|
9
|
+
* touched line's formatting — and a script that recolours a line mid-search
|
|
10
|
+
* would lose its change. Wrapping text nodes in `<mark>` leaves the model
|
|
11
|
+
* untouched, and unwrapping restores the DOM exactly.
|
|
12
|
+
* - Offsets line up by construction. `appendCells` can substitute text on the
|
|
13
|
+
* way to the DOM (tab-stop expansion, Mudlet control-character glyphs), so
|
|
14
|
+
* `buffer.text` offsets do not always index the rendered line. Searching the
|
|
15
|
+
* rendered text means we match what the player can actually see.
|
|
16
|
+
*
|
|
17
|
+
* The sticky split-view panel holds `cloneNode` copies of the last N lines, so
|
|
18
|
+
* it is not scanned — it lives outside the `.output-wrapper` scroller we walk.
|
|
19
|
+
* Re-populating it after highlighting copies the marks along with the lines.
|
|
20
|
+
*/
|
|
21
|
+
import type { MatchRange, SearchMatcher } from '../search/matcher';
|
|
22
|
+
export declare const HIT_CLASS = "output-search-hit";
|
|
23
|
+
export declare const CURRENT_HIT_CLASS = "output-search-hit--current";
|
|
24
|
+
export interface OutputMatch {
|
|
25
|
+
/** The `.output-msg` line element containing this hit. */
|
|
26
|
+
line: HTMLElement;
|
|
27
|
+
/** Offsets into the line's rendered text — `[start, end)`. */
|
|
28
|
+
range: MatchRange;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Every match in the output, in document (i.e. chronological) order.
|
|
32
|
+
*
|
|
33
|
+
* Cheap enough to re-run on each keystroke: the per-line cost is one
|
|
34
|
+
* `textContent` read plus the matcher's scan, and only lines that actually hit
|
|
35
|
+
* get walked node-by-node later, in {@link applyHighlights}.
|
|
36
|
+
*/
|
|
37
|
+
export declare function scanOutput(container: HTMLElement, matcher: SearchMatcher): OutputMatch[];
|
|
38
|
+
/**
|
|
39
|
+
* Tint every match, giving `matches[currentIndex]` the "current hit" treatment.
|
|
40
|
+
*
|
|
41
|
+
* Callers must {@link clearHighlights} first — marking an already-marked line
|
|
42
|
+
* would nest marks. Matches whose line has since been evicted from the DOM are
|
|
43
|
+
* skipped rather than treated as an error; the scrollback trims as new output
|
|
44
|
+
* arrives and a stale match is normal, not exceptional.
|
|
45
|
+
*/
|
|
46
|
+
export declare function applyHighlights(matches: OutputMatch[], currentIndex: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* Whether an Escape that reached the document should close the find bar.
|
|
49
|
+
*
|
|
50
|
+
* The bar's own input handles Escape directly, but the player usually leaves
|
|
51
|
+
* focus in the command line while reading results, and there Escape did nothing
|
|
52
|
+
* — the bar just stayed up. So the bar also listens on the document, in the
|
|
53
|
+
* BUBBLE phase, and defers to everything with a better claim on the key:
|
|
54
|
+
*
|
|
55
|
+
* - `defaultPrevented` — someone already acted on it. Covers the bar's own
|
|
56
|
+
* input, and layers correctly under CommandBar, which preventDefaults
|
|
57
|
+
* Escape only while an autocomplete ghost is showing: first Escape dismisses
|
|
58
|
+
* the ghost, a second one closes the bar.
|
|
59
|
+
* - Modals (`useModalFocus`) stopPropagation on their own node, and
|
|
60
|
+
* CaretReviewPanel uses capture + stopImmediatePropagation while focused, so
|
|
61
|
+
* neither ever reaches a document bubble listener in the first place.
|
|
62
|
+
* - The origin is then required to be inside `.app`, the profile-session shell
|
|
63
|
+
* that owns the bar — toolbar, output, command line, docked panels. Floating
|
|
64
|
+
* script windows portal to `<body>` instead (`.floating-window-root`), so
|
|
65
|
+
* they fall outside it structurally and keep their own Escape.
|
|
66
|
+
*
|
|
67
|
+
* Pure apart from reading the event's target, so it is unit-testable.
|
|
68
|
+
*/
|
|
69
|
+
export declare function shouldCloseSearchOnEscape(e: KeyboardEvent): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Which way `e` steps through search results — `1` for F3, `-1` for Shift+F3,
|
|
72
|
+
* or null when it isn't the search-step key at all. Mudlet's binding
|
|
73
|
+
* (`TConsole::setF3SearchEnabled` wires F3 to slot_searchBufferDown and
|
|
74
|
+
* Shift+F3 to slot_searchBufferUp).
|
|
75
|
+
*
|
|
76
|
+
* Any other modifier disqualifies it, so Ctrl+F3 / Alt+F3 / Cmd+F3 stay
|
|
77
|
+
* available to the browser and the OS. Pure — reads only `key` and the modifier
|
|
78
|
+
* flags — and shared by the bar (which steps) and the output area (which opens
|
|
79
|
+
* the bar when it's closed), so the two can never drift apart.
|
|
80
|
+
*/
|
|
81
|
+
export declare function searchStepDirection(e: KeyboardEvent): -1 | 1 | null;
|
|
82
|
+
/**
|
|
83
|
+
* The rendered text of a whole matched line, for announcing a hit to a screen
|
|
84
|
+
* reader. Mudlet's `focusOnSearchResultAndAnnounce` speaks the entire buffer
|
|
85
|
+
* line rather than the matched fragment, so a listener hears the hit in context.
|
|
86
|
+
* Excludes the timestamp column, like {@link scanOutput}.
|
|
87
|
+
*/
|
|
88
|
+
export declare function matchLineText(match: OutputMatch): string;
|
|
89
|
+
/**
|
|
90
|
+
* Park keyboard focus on the current hit so a screen reader's virtual cursor
|
|
91
|
+
* lands *on* the match in the live output — the reachable half of Mudlet's
|
|
92
|
+
* `focusOnSearchResultAndAnnounce`, which moves its caret to the found column.
|
|
93
|
+
*
|
|
94
|
+
* The mark is made programmatically focusable (`tabIndex = -1`), so it takes
|
|
95
|
+
* focus without joining the tab order. Scrolling is suppressed: `revealLine`
|
|
96
|
+
* has already centred the line, and the browser's own focus scroll would
|
|
97
|
+
* fight it. Returns false when there is no current hit to focus.
|
|
98
|
+
*/
|
|
99
|
+
export declare function focusCurrentHit(container: HTMLElement): boolean;
|
|
100
|
+
/** Unwrap every mark this module added, restoring the pristine rendered line.
|
|
101
|
+
* `normalize()` re-merges the text nodes `splitText` created so a subsequent
|
|
102
|
+
* scan sees the same node layout it started with. */
|
|
103
|
+
export declare function clearHighlights(container: HTMLElement): void;
|
|
104
|
+
/**
|
|
105
|
+
* Scroll the output so `line` sits mid-viewport.
|
|
106
|
+
*
|
|
107
|
+
* Deliberately not `scrollIntoView` — that walks up and scrolls every scrollable
|
|
108
|
+
* ancestor, which in a docked layout drags the whole panel around. Measuring
|
|
109
|
+
* against the wrapper's own rect keeps the movement inside the output.
|
|
110
|
+
*/
|
|
111
|
+
export declare function revealLine(container: HTMLElement, line: HTMLElement): void;
|
|
112
|
+
/**
|
|
113
|
+
* Index of the match nearest the current viewport — where a fresh search should
|
|
114
|
+
* start so the first Enter moves from what the player is looking at rather than
|
|
115
|
+
* from the top of a thousand-line scrollback. Falls back to the last (most
|
|
116
|
+
* recent) match when nothing is on screen.
|
|
117
|
+
*/
|
|
118
|
+
export declare function indexNearViewport(container: HTMLElement, matches: OutputMatch[]): number;
|
|
119
|
+
/**
|
|
120
|
+
* Text to prefill the find box with — whatever the player has selected *in the
|
|
121
|
+
* output*, mirroring the browser's own find.
|
|
122
|
+
*
|
|
123
|
+
* Scoped to `container` on purpose. The command line keeps its last command
|
|
124
|
+
* selected after sending, and `window.getSelection()` can surface that, which
|
|
125
|
+
* would seed the box with the command the player just ran.
|
|
126
|
+
*/
|
|
127
|
+
export declare function seedFromSelection(container: HTMLElement | null): string;
|
|
128
|
+
/** Locate `target` in a freshly rescanned match list, so incoming MUD output
|
|
129
|
+
* does not move the player's place in the results. */
|
|
130
|
+
export declare function findMatchIndex(matches: OutputMatch[], target: OutputMatch | null): number;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The query compiler shared by every search bar in the app (the script editor's
|
|
3
|
+
* `ScriptSearch`, the output find bar). Turns a raw query plus the case/regex
|
|
4
|
+
* toggles into something that hands back match ranges for any string.
|
|
5
|
+
*/
|
|
6
|
+
/** Half-open `[start, end)` character offsets of one match. */
|
|
7
|
+
export type MatchRange = [number, number];
|
|
8
|
+
export interface SearchMatcher {
|
|
9
|
+
/** False when `useRegex` was set and the pattern failed to compile — the
|
|
10
|
+
* caller shows the input as invalid rather than reporting "no results". */
|
|
11
|
+
valid: boolean;
|
|
12
|
+
ranges: (s: string) => MatchRange[];
|
|
13
|
+
}
|
|
14
|
+
/** Compile a search bar query into a matcher honouring the case / regex flags. */
|
|
15
|
+
export declare function buildMatcher(pattern: string, matchCase: boolean, useRegex: boolean): SearchMatcher;
|
|
@@ -64,5 +64,8 @@ export declare class TtsManager {
|
|
|
64
64
|
private advance;
|
|
65
65
|
private beginUtterance;
|
|
66
66
|
private setState;
|
|
67
|
+
/** Text of the most recent ttsSpeechStarted, so speaking over a running
|
|
68
|
+
* utterance can tell a genuinely new one from a repeat. */
|
|
69
|
+
private lastStarted;
|
|
67
70
|
}
|
|
68
71
|
export {};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/** Reactive MRU command history wrapper around localStorage. History is scoped
|
|
2
2
|
* to `connectionId` so each profile keeps its own. `saveSize` caps how many
|
|
3
|
-
* entries are persisted (Mudlet's `commandLineHistorySaveSize`)
|
|
4
|
-
|
|
3
|
+
* entries are persisted (Mudlet's `commandLineHistorySaveSize`); `persist`
|
|
4
|
+
* is Mudlet's per-command-line `setSaveCommandHistory`, which stops the writing
|
|
5
|
+
* without touching the history this session already has. */
|
|
6
|
+
export declare function useCommandHistory(connectionId: string | null, saveSize?: number, persist?: boolean): {
|
|
5
7
|
history: string[];
|
|
6
8
|
add: (item: string) => void;
|
|
7
9
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection ids currently open in *another* browser tab.
|
|
3
|
+
*
|
|
4
|
+
* Every open profile holds an exclusive Web Lock named `mudix:profile:<id>`
|
|
5
|
+
* (see profileLock.ts), and `navigator.locks.query()` lists held locks across
|
|
6
|
+
* all same-origin tabs — so the held profile locks are exactly the open set.
|
|
7
|
+
* The connection screen renders with no profile active, so this tab holds no
|
|
8
|
+
* profile lock of its own and every hit belongs to someone else; no
|
|
9
|
+
* self-filtering is needed.
|
|
10
|
+
*
|
|
11
|
+
* Polled, because Web Locks has no change event. The refresh is also driven by
|
|
12
|
+
* focus/visibility so returning to the launcher tab after closing a profile
|
|
13
|
+
* elsewhere updates immediately instead of waiting out the interval.
|
|
14
|
+
*
|
|
15
|
+
* Returns an empty set where the API is unavailable (legacy browser, insecure
|
|
16
|
+
* context, test env) — the same "can't tell, so don't claim anything" fallback
|
|
17
|
+
* the lock itself uses.
|
|
18
|
+
*/
|
|
19
|
+
/** The profile ids among a `navigator.locks.query()` held-lock list. Non-profile
|
|
20
|
+
* locks (any other feature using Web Locks) and unnamed entries are ignored. */
|
|
21
|
+
export declare function openProfileIds(held: readonly {
|
|
22
|
+
name?: string;
|
|
23
|
+
}[] | undefined): Set<string>;
|
|
24
|
+
/** Whether two id sets hold the same members — used to skip no-op state updates. */
|
|
25
|
+
export declare const sameIds: (a: ReadonlySet<string>, b: ReadonlySet<string>) => boolean;
|
|
26
|
+
export declare function useOpenProfiles(enabled?: boolean, refreshMs?: number): Set<string>;
|