@mudlet/mudlet-web 0.4.2 → 0.4.3

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.
@@ -62,6 +62,14 @@ export interface LabelState {
62
62
  * `alignment`, it's a widget property that persists across a later
63
63
  * stylesheet that omits it. */
64
64
  scaledContents?: boolean;
65
+ /** Sticky Qt `wordWrap` widget property, captured from a
66
+ * `qproperty-wordWrap` declaration in any setStyleSheet call. QLabel
67
+ * defaults it to false (and TLabel never sets it), which is why label text
68
+ * in Mudlet runs past the widget edge and gets clipped instead of wrapping
69
+ * — LabelOverlay renders that as `white-space: nowrap`, and this property
70
+ * as `normal`. Sticky across a later stylesheet that omits it, like
71
+ * `alignment` and `scaledContents`. */
72
+ wordWrap?: boolean;
65
73
  /** Mudlet setLinkStyle(labelName, linkColor, linkVisitedColor, underline) —
66
74
  * styling for `<a>` links inside the label's HTML. Cleared by
67
75
  * resetLinkStyle. Colors are any CSS color string (empty = leave default). */
@@ -55,3 +55,4 @@ export declare function qtDeclarationsToCss(css: string, important?: boolean): s
55
55
  export declare function qtAlignmentToFlex(val: string): Record<string, string>;
56
56
  export declare function extractQtAlignment(css: string): string | undefined;
57
57
  export declare function extractQtScaledContents(css: string): boolean | undefined;
58
+ export declare function extractQtWordWrap(css: string): boolean | undefined;
@@ -16,4 +16,27 @@ interface ContentLayoutProps {
16
16
  vfs?: ProfileVFS | null;
17
17
  }
18
18
  export declare function ContentLayout({ session, manager, connectionId, stickyLines, commandInputRef, commandBar, contextMenuHandlerRef, scriptingEngineRef, vfs, }: ContentLayoutProps): import("react/jsx-runtime").JSX.Element;
19
+ /**
20
+ * Holds the main console's DOM while a layout branch is on screen, and hands it
21
+ * back when that branch goes away.
22
+ *
23
+ * The console is mounted once, for the lifetime of ContentLayout, into a
24
+ * detached host div; the desktop tree and the phone tree each adopt that div
25
+ * rather than rendering an OutputArea of their own. Crossing the phone
26
+ * breakpoint therefore *moves* the console instead of destroying it.
27
+ *
28
+ * This is the same trick the content pool below uses for panels, and it is not
29
+ * a refinement: OutputArea's renderer appends lines imperatively into the
30
+ * wrapper it was handed at setup, and only ever appends *new* ones. Remounting
31
+ * it handed the renderer a fresh empty wrapper, so every line already on screen
32
+ * vanished while Console.history still held all of them — one resize across
33
+ * 600px emptied a session's scrollback with no way to bring it back.
34
+ *
35
+ * display:contents on the slot keeps the host in the parent's layout, so
36
+ * .main-viewport still measures and flexes exactly as it did before.
37
+ */
38
+ export declare function ViewportSlot({ host, hidden }: {
39
+ host: HTMLDivElement;
40
+ hidden?: boolean;
41
+ }): import("react/jsx-runtime").JSX.Element;
19
42
  export {};
@@ -4,6 +4,10 @@ import type { WindowManager } from '../windows/WindowManager';
4
4
  interface MobileLayoutProps {
5
5
  session: MudSession;
6
6
  manager: WindowManager;
7
+ /** The one main console, mounted by ContentLayout and adopted here — never
8
+ * re-created, or the scrollback on screen would be lost on every
9
+ * breakpoint crossing. See ViewportSlot. */
10
+ outputHost: HTMLDivElement;
7
11
  /** Already filtered to non-popped-out windows by ContentLayout. */
8
12
  windows: ScriptWindowRenderData[];
9
13
  stickyLines?: number;
@@ -18,5 +22,5 @@ interface MobileLayoutProps {
18
22
  * portal-target divs WindowManager already maintains (same trick as the
19
23
  * desktop TabGroupPanel), so panels stay live in the background.
20
24
  */
21
- export declare function MobileLayout({ session, manager, windows, stickyLines, commandInputRef, commandBar }: MobileLayoutProps): import("react/jsx-runtime").JSX.Element;
25
+ export declare function MobileLayout({ manager, windows, outputHost, commandBar }: MobileLayoutProps): import("react/jsx-runtime").JSX.Element;
22
26
  export {};
@@ -44,8 +44,6 @@ type OutputHandlerOptions = {
44
44
  stickyArea: HTMLElement;
45
45
  isSplitView: () => boolean;
46
46
  stickyLines: number;
47
- maxElements?: number | (() => number);
48
- trimSlack?: number;
49
47
  suppressSplitView?: (durationMs: number) => void;
50
48
  /** Whether new output should scroll the view to the tail. True for a
51
49
  * scrollback; false for a console the writer rewrites wholesale — an MXP
@@ -66,5 +64,5 @@ export type OutputRendererControls = {
66
64
  push: (message: string | AnsiAwareBuffer, type?: string, timestamp?: number) => void;
67
65
  clear: () => void;
68
66
  };
69
- export declare function setupOutputRenderer(source: MessageSource | null, { outputWrapper, sentinel, stickyArea, isSplitView, stickyLines, maxElements, trimSlack, suppressSplitView, followTail, onCursorReady, }: OutputHandlerOptions): OutputRendererControls;
67
+ export declare function setupOutputRenderer(source: MessageSource | null, { outputWrapper, sentinel, stickyArea, isSplitView, stickyLines, suppressSplitView, followTail, onCursorReady, }: OutputHandlerOptions): OutputRendererControls;
70
68
  export {};
@@ -1,11 +1,17 @@
1
1
  import type { ScrollBoxManager } from './ScrollBoxManager';
2
2
  import type { LabelManager } from '../labels/LabelManager';
3
3
  import type { CommandLineManager } from '../cmdline/CommandLineManager';
4
+ import type { WindowManager } from '../windows/WindowManager';
4
5
  import './ScrollBoxOverlay.css';
5
6
  interface ScrollBoxOverlayProps {
6
7
  manager: ScrollBoxManager;
7
8
  labels: LabelManager;
8
9
  cmdLines: CommandLineManager;
10
+ /** Lets a box host the windows parented to it — Geyser.ScrollBox makes
11
+ * itself the `windowname` of its children, so a mini-console created
12
+ * inside one names the box as its parent. Optional only so a caller with
13
+ * no WindowManager to hand still renders labels and command lines. */
14
+ windows?: WindowManager;
9
15
  /** Viewport whose scroll boxes this overlay renders ('main', a userwindow
10
16
  * id, or — when nested — another scroll box's name). */
11
17
  parent: string;
@@ -14,12 +20,16 @@ interface ScrollBoxOverlayProps {
14
20
  * Renders the {@link ScrollBoxManager}'s boxes for a given parent viewport as
15
21
  * absolutely-positioned scrollable containers. Each box hosts the child overlays
16
22
  * (labels, command lines, and nested scroll boxes) scoped to the box's own name,
17
- * so widgets created with `parent = boxName` render inside it.
23
+ * so widgets created with `parent = boxName` render inside it. Each box also
24
+ * registers its scroll content as that name's overlay host, so mini-consoles
25
+ * and mappers created inside it portal into the box (see
26
+ * FloatingWindowLayer.resolveParent) instead of escaping to the document-wide
27
+ * floating root.
18
28
  *
19
29
  * Scrolling: the children are absolutely positioned and don't expand their
20
30
  * containers on their own, so each box wraps them in a content div sized to the
21
31
  * extent of its children (the furthest child edge). When that extent exceeds the
22
32
  * box, the box's `overflow:auto` produces real scrollbars.
23
33
  */
24
- export declare function ScrollBoxOverlay({ manager, labels, cmdLines, parent }: ScrollBoxOverlayProps): import("react/jsx-runtime").JSX.Element | null;
34
+ export declare function ScrollBoxOverlay({ manager, labels, cmdLines, windows, parent }: ScrollBoxOverlayProps): import("react/jsx-runtime").JSX.Element | null;
25
35
  export {};
@@ -38,6 +38,15 @@ export interface MapLoadProgress {
38
38
  */
39
39
  phase: 'rooms' | 'building';
40
40
  }
41
+ /** Geometry of one window nested under a parent viewport — enough for a
42
+ * container to size itself around its children (see subscribeChildWindows). */
43
+ export interface NestedWindowGeometry {
44
+ id: string;
45
+ x: number;
46
+ y: number;
47
+ width: number;
48
+ height: number;
49
+ }
41
50
  export type WindowsChangedFn = (windows: ScriptWindowRenderData[], dockExtents: Record<DockSide, number>) => void;
42
51
  export declare class WindowManager {
43
52
  readonly overlayZ: OverlayLayerOrder;
@@ -49,6 +58,15 @@ export declare class WindowManager {
49
58
  * from `elements` (the writable text/HTML target) so size queries report the
50
59
  * full user-window box that labels live in, not the inner output area. */
51
60
  private readonly viewports;
61
+ /** Overlay hosts contributed by widgets that are containers but not
62
+ * windows — today just Geyser.ScrollBox (see ScrollBoxOverlay). A scroll
63
+ * box sets `windowname = its own name`, so mini-consoles created inside
64
+ * it arrive here with the box's name as their parent and must portal into
65
+ * the box's scroll content instead of escaping to the floating root. */
66
+ private readonly overlayHosts;
67
+ /** Per-parent subscribers wanting the geometry of the windows nested under
68
+ * them — ScrollBoxOverlay sizes its scroll content to its children. */
69
+ private readonly childWindowListeners;
52
70
  private readonly lineBuffers;
53
71
  /** Per-window scroll/scrollbar overrides applied via CSS classes when the
54
72
  * console's wrapper element registers. Mudlet's enable/disable Scrolling
@@ -257,6 +275,16 @@ export declare class WindowManager {
257
275
  * context: `.main-overlay-root` for 'main', else the userwindow's own
258
276
  * viewport (where its panel already renders the label overlays). */
259
277
  getOverlayHost(parentId: string): HTMLElement | null;
278
+ /** Registers a non-window overlay host (a scroll box's scroll content) so
279
+ * windows parented to `id` portal into it. Notifies so a window that was
280
+ * created before its host mounted gets re-homed on the next render. */
281
+ registerOverlayHost(id: string, element: HTMLElement): void;
282
+ unregisterOverlayHost(id: string, element?: HTMLElement): void;
283
+ /** Geometry of the visible windows nested under `parentId`. */
284
+ listChildWindows(parentId: string): NestedWindowGeometry[];
285
+ /** Subscribe to {@link listChildWindows} for one parent. Fires immediately
286
+ * with the current list, like the label / cmd-line / scroll-box managers. */
287
+ subscribeChildWindows(parentId: string, fn: (children: NestedWindowGeometry[]) => void): () => void;
260
288
  register(id: string, element: HTMLElement, _kind: 'html'): void;
261
289
  pushBuffer(id: string, buffer: AnsiAwareBuffer): void;
262
290
  /** Push the current partial-line buffer (script echo without a trailing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mudlet/mudlet-web",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "type": "module",
5
5
  "description": "Mudlet Web — Mudlet in the browser, usable standalone or as a library for branded builds",
6
6
  "license": "GPL-2.0-or-later",
@@ -60,8 +60,8 @@
60
60
  "@codemirror/state": "^6.6.0",
61
61
  "@codemirror/theme-one-dark": "^6.1.3",
62
62
  "@codemirror/view": "^6.41.1",
63
+ "@lezer/highlight": "^1.2.3",
63
64
  "@sqlite.org/sqlite-wasm": "^3.53.0-build1",
64
- "@types/dompurify": "^3.0.5",
65
65
  "@zenfs/core": "^2.5.6",
66
66
  "@zenfs/dom": "^1.2.9",
67
67
  "dompurify": "^3.4.14",