@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.
Files changed (97) hide show
  1. package/README.md +8 -0
  2. package/dist-lib/assets/qt-resources/index.d.ts +16 -0
  3. package/dist-lib/branding.d.ts +1 -1
  4. package/dist-lib/hooks/useMudSession.d.ts +1 -1
  5. package/dist-lib/hooks/useOutput.d.ts +3 -1
  6. package/dist-lib/import/defaultPackages.d.ts +35 -2
  7. package/dist-lib/import/defaults/generic_mapper/generic_mapper.mpackage +0 -0
  8. package/dist-lib/import/defaults/gui-drop/gui-drop.mpackage +0 -0
  9. package/dist-lib/import/defaults/{run-lua-code.mpackage → mudlet-base-ui/mudlet-base-ui.mpackage} +0 -0
  10. package/dist-lib/import/defaults/run-lua-code/run-lua-code.mpackage +0 -0
  11. package/dist-lib/import/packageExport.d.ts +71 -0
  12. package/dist-lib/import/packageInstaller.d.ts +4 -1
  13. package/dist-lib/index.js +45935 -40688
  14. package/dist-lib/logging/SessionLogger.d.ts +66 -1
  15. package/dist-lib/map/MapStore.d.ts +32 -4
  16. package/dist-lib/map/mapImageExport.d.ts +1 -1
  17. package/dist-lib/map/mapZoom.d.ts +71 -0
  18. package/dist-lib/mud/ItemIdSequence.d.ts +23 -0
  19. package/dist-lib/mud/MudSession.d.ts +113 -11
  20. package/dist-lib/mud/PatternEngine.d.ts +6 -1
  21. package/dist-lib/mud/commandSplit.d.ts +16 -0
  22. package/dist-lib/mud/connection/LineAssembler.d.ts +56 -0
  23. package/dist-lib/mud/connection/MudClient.d.ts +120 -16
  24. package/dist-lib/mud/connection/TelnetNegotiator.d.ts +39 -0
  25. package/dist-lib/mud/connection/telnetByteTags.d.ts +35 -0
  26. package/dist-lib/mud/events.d.ts +19 -4
  27. package/dist-lib/mud/games/bundledGames.d.ts +29 -0
  28. package/dist-lib/mud/games/gameIcons.d.ts +5 -0
  29. package/dist-lib/mud/keybindings/KeyEngine.d.ts +9 -2
  30. package/dist-lib/mud/keybindings/browserReservedKeys.d.ts +5 -1
  31. package/dist-lib/mud/keybindings/keyEventTarget.d.ts +17 -0
  32. package/dist-lib/mud/keybindings/qtKeys.d.ts +2 -0
  33. package/dist-lib/mud/protocol/charLoginFlow.d.ts +68 -0
  34. package/dist-lib/mud/protocol/charset.d.ts +27 -5
  35. package/dist-lib/mud/protocol/constants.d.ts +1 -0
  36. package/dist-lib/mud/protocol/gmcp.d.ts +19 -3
  37. package/dist-lib/mud/protocol/index.d.ts +1 -1
  38. package/dist-lib/mud/protocol/mxp.d.ts +28 -5
  39. package/dist-lib/mud/replay/ReplayPlayer.d.ts +17 -0
  40. package/dist-lib/mud/text/Console.d.ts +64 -0
  41. package/dist-lib/mud/text/FormatState.d.ts +66 -3
  42. package/dist-lib/mud/text/hyperlinkVisibility.d.ts +35 -0
  43. package/dist-lib/mud/text/osc8Docs.d.ts +23 -0
  44. package/dist-lib/mud/text/serverWrap.d.ts +191 -0
  45. package/dist-lib/mud/timers/TimerEngine.d.ts +43 -12
  46. package/dist-lib/mud/triggers/TriggerEngine.d.ts +112 -3
  47. package/dist-lib/scripting/EngineHost.d.ts +56 -3
  48. package/dist-lib/scripting/IScriptingRuntime.d.ts +16 -0
  49. package/dist-lib/scripting/MxpFrameManager.d.ts +118 -0
  50. package/dist-lib/scripting/ScriptingAPI.d.ts +323 -54
  51. package/dist-lib/scripting/ScriptingEngine.d.ts +180 -23
  52. package/dist-lib/scripting/http/HttpService.d.ts +51 -1
  53. package/dist-lib/scripting/lua/LuaRuntime.d.ts +151 -2
  54. package/dist-lib/scripting/lua/bindings/map.d.ts +0 -12
  55. package/dist-lib/scripting/lua/utf8Patterns.d.ts +59 -0
  56. package/dist-lib/storage/index.d.ts +1 -1
  57. package/dist-lib/storage/persistentStorage.d.ts +10 -0
  58. package/dist-lib/storage/schema.d.ts +116 -0
  59. package/dist-lib/styles.css +1 -1
  60. package/dist-lib/ui/BundledGameGrid.d.ts +21 -0
  61. package/dist-lib/ui/CommandBar.d.ts +7 -1
  62. package/dist-lib/ui/ConnectionGrid.d.ts +4 -1
  63. package/dist-lib/ui/FilePickerModal.d.ts +3 -3
  64. package/dist-lib/ui/HelpModal.d.ts +11 -0
  65. package/dist-lib/ui/LogBrowserModal.d.ts +4 -1
  66. package/dist-lib/ui/PlayerMarkerPreview.d.ts +20 -0
  67. package/dist-lib/ui/Toolbar.d.ts +2 -1
  68. package/dist-lib/ui/VfsPickerModal.d.ts +26 -0
  69. package/dist-lib/ui/components/FileSourceButton.d.ts +47 -0
  70. package/dist-lib/ui/components/index.d.ts +1 -0
  71. package/dist-lib/ui/helpTopics.d.ts +19 -0
  72. package/dist-lib/ui/labels/LabelManager.d.ts +7 -0
  73. package/dist-lib/ui/layout/ScriptWindow.d.ts +11 -2
  74. package/dist-lib/ui/markdown.d.ts +10 -1
  75. package/dist-lib/ui/output/OutputArea.d.ts +11 -1
  76. package/dist-lib/ui/output/OutputContextMenu.d.ts +3 -1
  77. package/dist-lib/ui/output/OutputRenderer.d.ts +7 -1
  78. package/dist-lib/ui/output/OutputSearchBar.d.ts +25 -0
  79. package/dist-lib/ui/output/StickyOutputPanel.d.ts +5 -1
  80. package/dist-lib/ui/output/outputSearch.d.ts +130 -0
  81. package/dist-lib/ui/search/matcher.d.ts +15 -0
  82. package/dist-lib/ui/search/useDebounced.d.ts +3 -0
  83. package/dist-lib/ui/tts/TtsManager.d.ts +3 -0
  84. package/dist-lib/ui/useCommandHistory.d.ts +4 -2
  85. package/dist-lib/ui/useOpenProfiles.d.ts +26 -0
  86. package/dist-lib/ui/video/VideoManager.d.ts +17 -0
  87. package/dist-lib/ui/windows/WindowManager.d.ts +132 -2
  88. package/dist-lib/ui/windows/panels/MapPanel.d.ts +4 -1
  89. package/dist-lib/ui/windows/panels/PackageExportModal.d.ts +18 -0
  90. package/dist-lib/ui/windows/panels/TextPanel.d.ts +3 -1
  91. package/dist-lib/ui/windows/types.d.ts +35 -0
  92. package/dist-lib/utils/describeThrown.d.ts +22 -0
  93. package/dist-lib/utils/fontLoader.d.ts +5 -0
  94. package/dist-lib/vite.js +22 -0
  95. package/package.json +10 -6
  96. package/dist-lib/scripting/lua/mudlet-lua/generic-mapper/generic_mapper.mpackage +0 -0
  97. package/dist-lib/ui/windows/panels/VfsModulePickerModal.d.ts +0 -8
@@ -1,4 +1,5 @@
1
1
  import type { MediaCaptionInfo } from '../sound/closedCaption';
2
+ import type { MediaOrigin } from '../sound/SoundManager';
2
3
  type LoaderFn = (path: string) => Promise<ArrayBuffer | null>;
3
4
  export interface PlayVideoOptions {
4
5
  name: string;
@@ -11,6 +12,10 @@ export interface PlayVideoOptions {
11
12
  height?: string;
12
13
  /** Optional closed-caption text (Mudlet's media `caption`). */
13
14
  caption?: string;
15
+ /** Which mute gate governs this playback. Default 'api' — the only way to
16
+ * reach a video today is Lua's `playVideoFile`, but GMCP `Client.Media`
17
+ * defines a video type, so the gate is parameterised like the sounds'. */
18
+ origin?: MediaOrigin;
14
19
  }
15
20
  export declare class VideoManager {
16
21
  private loader;
@@ -20,6 +25,14 @@ export declare class VideoManager {
20
25
  private active;
21
26
  /** Buffers fetched ahead of play via loadVideoFile, keyed by VFS path. */
22
27
  private prefetched;
28
+ /**
29
+ * Per-origin mute gates, the video half of {@link SoundManager}'s. A muted
30
+ * origin's videos keep playing (picture and position both advance) with the
31
+ * element muted, and new ones start muted — nothing is stopped, so unmuting
32
+ * restores audio mid-clip. `volume` is left alone so `getPlayingVideos`
33
+ * still reports what the script asked for.
34
+ */
35
+ private muted;
23
36
  /** Fires when a video ends naturally or is stopped — mirrors Mudlet's
24
37
  * sysMediaFinished. */
25
38
  onEnded: ((name: string, path: string) => void) | null;
@@ -28,6 +41,10 @@ export declare class VideoManager {
28
41
  onMediaCaption: ((info: MediaCaptionInfo) => void) | null;
29
42
  setLoader(fn: LoaderFn | null): void;
30
43
  setMountPoint(fn: (() => HTMLElement | null) | null): void;
44
+ /** Mudlet `muteMediaAPI` / `muteMediaGame`, applied to video playback. See
45
+ * {@link muted}; the sound-side twin is `SoundManager.setOriginMuted`. */
46
+ setOriginMuted(origin: MediaOrigin, muted: boolean): void;
47
+ isOriginMuted(origin: MediaOrigin): boolean;
31
48
  /**
32
49
  * Mudlet `loadVideoFile`. Preloads (fetches + caches) a VFS-backed video so
33
50
  * the first playVideoFile has no fetch latency. http(s)/data/blob URLs need
@@ -1,7 +1,7 @@
1
1
  import { type OutputRendererControls } from '../output/OutputRenderer';
2
2
  import type { Console } from '../../mud/text/Console';
3
3
  import type { AnsiAwareBuffer } from '../../mud/text/FormatState';
4
- import type { DockSide, WindowHandle, WindowOpenOptions, ScriptWindowRenderData } from './types';
4
+ import type { DockSide, MxpTabPage, WindowHandle, WindowOpenOptions, ScriptWindowRenderData } from './types';
5
5
  import { MapStore } from '../../map/MapStore';
6
6
  import { OverlayLayerOrder } from '../layout/overlayLayerOrder';
7
7
  /** Live handle onto a mounted map renderer, registered by MapPanel. Backs the
@@ -103,6 +103,17 @@ export declare class WindowManager {
103
103
  * from openUserWindow panels for windowType() reporting. */
104
104
  private mainViewportEl;
105
105
  private readonly miniConsoles;
106
+ /** MXP `<FRAME>` tab strips, keyed by the frame that hosts the strip. Each
107
+ * page is another frame's console nested inside this one's viewport, so
108
+ * switching tabs just swaps which child is visible. Purely transient — MXP
109
+ * frames are torn down on reconnect and never persisted to a layout hint. */
110
+ private readonly frameTabs;
111
+ /** Consoles backing an MXP `<FRAME>`. They render with a hairline border,
112
+ * the way Mudlet outlines every frame container (TMxpFrameManager's
113
+ * `1px solid #444444`), so a server's panes read as separate panes. */
114
+ private readonly mxpFrameIds;
115
+ /** See getMxpBorders. */
116
+ private mxpBorders;
106
117
  private consoleRegistry;
107
118
  private windowHints;
108
119
  private nextZ;
@@ -359,7 +370,7 @@ export declare class WindowManager {
359
370
  private readonly mapViews;
360
371
  /** View ids start at 1 — Mudlet treats 0 as "no view". */
361
372
  private nextMapViewId;
362
- /** The window id backing a map view. */
373
+ /** The window id backing a map view. Reserved to the client — see types.ts. */
363
374
  private static mapViewWindowId;
364
375
  /**
365
376
  * Mudlet `createMapView([areaID])` — open a secondary map window. Returns
@@ -529,6 +540,38 @@ export declare class WindowManager {
529
540
  loadMapXml(xmlText: string): boolean;
530
541
  markAsMiniConsole(id: string): void;
531
542
  isMiniConsole(id: string): boolean;
543
+ /** Flag a console as an MXP frame so it renders with a frame border. Also
544
+ * hides its scrollbar: Mudlet's frames are `TConsole::SubConsole`s, which
545
+ * start with theirs hidden, and no MXP server ever calls enableScrollBar.
546
+ * Idempotent — the layout re-places a frame on every reflow. */
547
+ markAsMxpFrame(id: string): void;
548
+ /** Install (or replace) an MXP frame's tab strip. An empty `pages` list
549
+ * removes it. Pages other than the active one are hidden, which keeps their
550
+ * panel mounted — the content pool renders every open window regardless of
551
+ * visibility, so a background tab keeps its scrollback. */
552
+ setFrameTabs(id: string, pages: MxpTabPage[], active: string): void;
553
+ /** Switch an MXP frame's visible tab. Ignored for an unknown strip or page. */
554
+ selectFrameTab(id: string, pageId: string): void;
555
+ getFrameTabs(id: string): {
556
+ pages: MxpTabPage[];
557
+ active: string;
558
+ } | undefined;
559
+ /** Pixel insets MXP frames have carved out of the main console. Kept apart
560
+ * from the profile's setBorder* sizes (Mudlet splits them the same way, as
561
+ * Host::mUserBorders vs mMxpBorders) so a server layout never overwrites
562
+ * what a script or the settings modal set — OutputArea adds the two. */
563
+ getMxpBorders(): {
564
+ top: number;
565
+ right: number;
566
+ bottom: number;
567
+ left: number;
568
+ };
569
+ setMxpBorders(borders: {
570
+ top: number;
571
+ right: number;
572
+ bottom: number;
573
+ left: number;
574
+ }): void;
532
575
  getRoomIDbyHash(hash: string): number | undefined;
533
576
  setPosition(id: string, x: number, y: number): void;
534
577
  /** Mudlet setWindow for miniconsole / mapper panels — re-portal the panel
@@ -544,6 +587,24 @@ export declare class WindowManager {
544
587
  * override and lets the inherited font take over. */
545
588
  setFont(id: string, family: string): boolean;
546
589
  getFont(id: string): string | null;
590
+ /** Pin a console's rendered row height, in px. Consoles normally lay rows
591
+ * out at the stylesheet's `line-height`, which is roomier than the type
592
+ * itself; an MXP frame instead has to match Mudlet's row metric
593
+ * (`TTextEdit::mFontHeight` = ascent + descent), because its whole geometry
594
+ * contract is "this many rows fit in this box". Undefined restores the
595
+ * stylesheet default. */
596
+ setLineHeight(id: string, px: number | undefined): boolean;
597
+ /** Pin a console back to the first line. Consoles are scrollbacks and follow
598
+ * the tail, which is wrong for a pane the server rewrites wholesale: such a
599
+ * redraw arrives over several network flushes, so following the tail makes
600
+ * the content visibly slide as the rows land, then snap back on the next
601
+ * clear. No-op before the panel mounts. */
602
+ scrollToTop(id: string): void;
603
+ /** Consoles pinned to their first row rather than following the tail. See
604
+ * scrollToTop; TextPanel reads this live through the renderer's followTail. */
605
+ private readonly topAnchored;
606
+ setTopAnchored(id: string, anchored: boolean): void;
607
+ isTopAnchored(id: string): boolean;
547
608
  /** Mudlet setWindowWrap. 0 (or any non-positive value) clears the override. */
548
609
  setWrap(id: string, wrapAt: number): boolean;
549
610
  getWrap(id: string): number | null;
@@ -561,6 +622,14 @@ export declare class WindowManager {
561
622
  * on a console wrapper. Wheel/keyboard scrolling continues regardless; only
562
623
  * the gutter rendering is affected. Persists across mounts; idempotent. */
563
624
  setScrollBarVisible(id: string, visible: boolean): void;
625
+ /**
626
+ * Mudlet `getScrollBarVisible([window])`. Reads back the *intent* set by
627
+ * enable/disableScrollBar rather than whether a gutter is on screen right
628
+ * now: a console that is hidden still answers for the scroll bar it will
629
+ * have when shown. Only the main window starts with one — a miniconsole is
630
+ * created without, as in Mudlet.
631
+ */
632
+ scrollBarVisible(id: string): boolean;
564
633
  /** Mudlet enable/disableHorizontalScrollBar — toggle a horizontal scrollbar
565
634
  * on a console wrapper. mudix wraps long lines by default so this is rarely
566
635
  * needed; included for parity. */
@@ -569,6 +638,26 @@ export declare class WindowManager {
569
638
  * bottom (wheel/touch/keys cannot scroll back). Mudlet forbids this on the
570
639
  * main window; we follow that policy. Returns false on 'main', true otherwise. */
571
640
  setScrollingEnabled(id: string, enabled: boolean): boolean;
641
+ /**
642
+ * Mudlet `timeStampsEnabled(window)` — whether the console is showing its
643
+ * timestamp column. Null when the window has no renderer registered, which
644
+ * is how the Lua wrapper tells a missing window from one that simply has
645
+ * timestamps off. Pre-mount, a queued preference wins over the default.
646
+ */
647
+ timeStampsEnabled(id: string): boolean | null;
648
+ /**
649
+ * Mudlet `enable/disableTimeStamps(window)`. The renderer owns the column,
650
+ * but a script can ask for it before the panel has mounted — openUserWindow
651
+ * followed immediately by enableTimeStamps — so the preference is queued and
652
+ * applied by registerTextPanel. False when the window doesn't exist at all.
653
+ */
654
+ setTimeStamps(id: string, visible: boolean): boolean;
655
+ /** Timestamp preference asked for before the panel mounted. */
656
+ private readonly pendingTimestamps;
657
+ /** Mudlet `scrollingActive(window)` — whether scrollback is currently
658
+ * allowed. Always true for `'main'`, which setScrollingEnabled refuses to
659
+ * change, and true for any console nobody has called disableScrolling on. */
660
+ isScrollingEnabled(id: string): boolean;
572
661
  /** Buffer-line index of the topmost visible line in `id`'s wrapper. In tail
573
662
  * mode returns the last line number (matching Mudlet's mCursorY behaviour at
574
663
  * the end of the buffer). Returns 0 if the element is unmounted or empty.
@@ -577,6 +666,26 @@ export declare class WindowManager {
577
666
  * is `position: relative` — child offsetTop is relative to *that*, not to the
578
667
  * scroll-container `.output-wrapper`, so the rectangles are the unambiguous
579
668
  * way to relate child position to the scroll viewport. */
669
+ /** Whether `id`'s wrapper is mounted with laid-out lines, i.e. whether
670
+ * {@link getScrollLine}'s measurement means anything. A console whose panel
671
+ * isn't on screen yet measures as 0, which is indistinguishable from being
672
+ * genuinely scrolled to the top. */
673
+ canMeasureScroll(id: string): boolean;
674
+ /**
675
+ * Where `scrollTo` last parked each console, as a buffer line index; absent
676
+ * means tail mode (or that only the user has scrolled it).
677
+ *
678
+ * Mudlet's getScroll/scrollTo are buffer-index operations. mudix measured
679
+ * the DOM instead, which is fine for a console the player is looking at but
680
+ * answers nothing useful for one whose panel has not been laid out yet — and
681
+ * a script that scrolls and reads back in the same breath never gives React
682
+ * a chance to commit in between. So the scripted position is remembered here
683
+ * and the measurement is the fallback, not the source of truth.
684
+ */
685
+ private readonly scriptScrollLine;
686
+ /** Called when the *user* scrolls a console, so a script's remembered
687
+ * position stops overriding what they can see. */
688
+ noteUserScroll(id: string): void;
580
689
  getScrollLine(id: string): number;
581
690
  /** Scroll `id`'s wrapper so `line` (0-indexed) sits at the top. `undefined`
582
691
  * resumes tail mode (scroll-to-bottom); negative values count from the end
@@ -611,6 +720,14 @@ export declare class WindowManager {
611
720
  * translates it through cmdLineQssToScopedCss at render time. Returns
612
721
  * false when the window doesn't exist. */
613
722
  setCmdLineStyleSheet(id: string, qss: string): boolean;
723
+ /**
724
+ * Mudlet setCommandForegroundColor / setCommandBackgroundColor for a named
725
+ * window. Mudlet styles a per-window command line through QSS, so the colour
726
+ * is patched into the same `cmdLineStyleSheet` a script could have set by
727
+ * hand rather than kept as a parallel piece of state. False when the window
728
+ * doesn't exist.
729
+ */
730
+ setCmdLineColor(id: string, property: 'color' | 'background-color', r: number, g: number, b: number, a: number): boolean;
614
731
  /** Bind the Lua callback fired when the user presses Enter in this
615
732
  * window's command line. Pass null to clear. Returns false when the
616
733
  * window doesn't exist. */
@@ -687,6 +804,19 @@ export declare class WindowManager {
687
804
  * behaviour). Returns false when the named window doesn't exist.
688
805
  */
689
806
  setTitle(id: string, title?: string): boolean;
807
+ /** Mudlet `getUserWindowTitle(name)` — the header text, whether it was set
808
+ * or generated. Null when there is no such window. */
809
+ getTitle(id: string): string | null;
810
+ /**
811
+ * The title a window carries when nobody has set one. Mudlet builds it from
812
+ * the profile and the window's own name ("<profile> - <window>"), which is
813
+ * what a player sees on a freshly opened user window; mudix used to fall
814
+ * back to the bare id, so resetting a title lost the profile half of it.
815
+ * The profile name is injected by ScriptingAPI — the manager has no other
816
+ * reason to know it.
817
+ */
818
+ profileName: string;
819
+ defaultTitle(id: string): string;
690
820
  focus(id: string): void;
691
821
  has(id: string): boolean;
692
822
  getElement(id: string): HTMLElement | null;
@@ -1,8 +1,11 @@
1
1
  import type { WindowManager } from '../WindowManager';
2
+ import type { ProfileVFS } from '../../../scripting/vfs/ProfileVFS';
2
3
  interface MapPanelProps {
3
4
  id: string;
4
5
  manager: WindowManager;
5
6
  connectionId: string;
7
+ /** Lets "Load map…" read a .dat/.xml the profile already holds. */
8
+ vfs?: ProfileVFS | null;
6
9
  }
7
- export declare function MapPanel({ id, manager, connectionId }: MapPanelProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function MapPanel({ id, manager, connectionId, vfs }: MapPanelProps): import("react/jsx-runtime").JSX.Element;
8
11
  export {};
@@ -0,0 +1,18 @@
1
+ import type { ProfileVFS } from '../../../scripting/vfs/ProfileVFS';
2
+ import './PackageExportModal.css';
3
+ export type ExportCategory = 'triggers' | 'aliases' | 'scripts' | 'timers' | 'keys' | 'buttons';
4
+ interface Props {
5
+ connectionId: string;
6
+ vfs: ProfileVFS | null;
7
+ /** Pre-check this item (and its subtree), as Mudlet does when the exporter is
8
+ * opened from a right-click in the editor tree. */
9
+ preselect?: {
10
+ category: ExportCategory;
11
+ id: string;
12
+ } | null;
13
+ onClose: () => void;
14
+ /** Reported back for the editor's log pane. */
15
+ onExported?: (message: string) => void;
16
+ }
17
+ export declare function PackageExportModal({ connectionId, vfs, preselect, onClose, onExported }: Props): import("react/jsx-runtime").JSX.Element;
18
+ export {};
@@ -13,6 +13,8 @@ interface TextPanelProps {
13
13
  scrollBoxes?: ScrollBoxManager;
14
14
  fontSize?: number;
15
15
  fontFamily?: string;
16
+ /** Rendered row height in px (MXP frames). See WindowManager.setLineHeight. */
17
+ lineHeight?: number;
16
18
  wrapAt?: number;
17
19
  wrapIndent?: number;
18
20
  wrapHangingIndent?: number;
@@ -31,5 +33,5 @@ interface TextPanelProps {
31
33
  cmdLineValue?: string;
32
34
  cmdLineValueSeq?: number;
33
35
  }
34
- export declare function TextPanel({ id, title, manager, labels, cmdLines, scrollBoxes, fontSize, fontFamily, wrapAt, wrapIndent, wrapHangingIndent, backgroundColor, backgroundImage, cmdLineEnabled, cmdLineStyleSheet, cmdLineValue, cmdLineValueSeq }: TextPanelProps): import("react/jsx-runtime").JSX.Element;
36
+ export declare function TextPanel({ id, title, manager, labels, cmdLines, scrollBoxes, fontSize, fontFamily, lineHeight, wrapAt, wrapIndent, wrapHangingIndent, backgroundColor, backgroundImage, cmdLineEnabled, cmdLineStyleSheet, cmdLineValue, cmdLineValueSeq }: TextPanelProps): import("react/jsx-runtime").JSX.Element;
35
37
  export {};
@@ -11,6 +11,27 @@ export interface DragState {
11
11
  /** true = insert before target in cross-axis; false = after. */
12
12
  splitBefore?: boolean;
13
13
  }
14
+ /** One page of an MXP `<FRAME>` tab strip. `id` is the frame whose console the
15
+ * tab shows — the host frame itself for the first page, a `DOCK`ed child
16
+ * otherwise. See MxpFrameManager. */
17
+ export interface MxpTabPage {
18
+ id: string;
19
+ title: string;
20
+ }
21
+ /** The dockable map widget — the toolbar's Map button and Lua openMapWidget. */
22
+ export declare const MAP_WIDGET_ID = "sys:map";
23
+ /** The embedded mapper created by Lua createMapper / Geyser.Mapper. */
24
+ export declare const MAPPER_WIDGET_ID = "sys:mapper";
25
+ /** Window id backing secondary map views (Lua createMapView). */
26
+ export declare function mapViewWindowId(viewId: number): string;
27
+ export declare const MAP_VIEW_ID_RE: RegExp;
28
+ /**
29
+ * Saved window hints predate the prefix, so a profile stored the map widget's
30
+ * geometry under the bare `map`. Rename it on load, or every existing profile
31
+ * loses its Map position, size and dock side. Bare `mapper`/`mapViewN` need no
32
+ * migration: neither is ever restored from a hint.
33
+ */
34
+ export declare function migrateClientWindowHints(hints: Record<string, WindowOpenOptions>): Record<string, WindowOpenOptions>;
14
35
  export interface WindowOpenOptions {
15
36
  title?: string;
16
37
  kind?: 'text' | 'html' | 'map';
@@ -46,6 +67,10 @@ export interface WindowOpenOptions {
46
67
  fontSize?: number;
47
68
  /** Output font family override (Mudlet setFont). */
48
69
  fontFamily?: string;
70
+ /** Rendered row height in px, overriding the stylesheet's line-height. Set
71
+ * for MXP frames so a box of N rows really holds N rows. See
72
+ * WindowManager.setLineHeight. */
73
+ lineHeight?: number;
49
74
  /** Character-column wrap width (Mudlet setWindowWrap). 0/undefined disables. */
50
75
  wrapAt?: number;
51
76
  /** Indent (in characters) of newline-started lines (Mudlet setWindowWrapIndent). */
@@ -102,6 +127,8 @@ export interface ScriptWindowRenderData {
102
127
  splitFlex?: number;
103
128
  fontSize?: number;
104
129
  fontFamily?: string;
130
+ /** See WindowOpenOptions.lineHeight. */
131
+ lineHeight?: number;
105
132
  wrapAt?: number;
106
133
  wrapIndent?: number;
107
134
  wrapHangingIndent?: number;
@@ -142,4 +169,12 @@ export interface ScriptWindowRenderData {
142
169
  * still trigger React's seed effect (otherwise printCmdLine('x') after a
143
170
  * user types 'x' would do nothing). */
144
171
  cmdLineValueSeq?: number;
172
+ /** MXP `<FRAME TITLE=…>` tab strip rendered as this window's chrome. Absent
173
+ * for every other window; set only by MxpFrameManager. */
174
+ frameTabs?: {
175
+ pages: MxpTabPage[];
176
+ active: string;
177
+ };
178
+ /** True for a console backing an MXP `<FRAME>` — draws the frame border. */
179
+ isMxpFrame?: boolean;
145
180
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Render a caught value for a user-facing error line.
3
+ *
4
+ * `String(err)` is the usual shorthand, but it collapses every non-`Error`
5
+ * object to the literal text "[object Object]" — which is exactly what the
6
+ * script error log showed for errors that never went through Lua's own
7
+ * `error()`. Those come from a JS exception escaping the wasm boundary: the
8
+ * metamethod trampolines wasmoon installs for JS objects (`__index`,
9
+ * `__newindex`, `__tostring`) don't wrap the call, so a throw inside a getter
10
+ * unwinds straight past Lua into whoever called `resume`. Nothing rewrites it
11
+ * into a Lua error string on the way, so the value arrives raw — and a raw
12
+ * plain object rendered with `String` says nothing at all.
13
+ *
14
+ * Errors keep rendering as their bare `message` (unchanged); everything else is
15
+ * described by what it actually is.
16
+ *
17
+ * Pass `label` (the entity or event the failure is attributed to) to also
18
+ * record the live value in devtools when it is opaque — such a value carries no
19
+ * stack of its own, so the object itself is the only handle on where it came
20
+ * from.
21
+ */
22
+ export declare function describeThrown(err: unknown, label?: string): string;
@@ -34,6 +34,11 @@ export interface LocalFontEntry {
34
34
  }
35
35
  export declare function isLocalFontApiSupported(): boolean;
36
36
  export declare function queryLocalFonts(): Promise<LocalFontEntry[]>;
37
+ /** The family consoles actually render in when the profile sets none — the
38
+ * bundled face App.css applies (picked to match Mudlet's default look). Mudlet
39
+ * always reports a concrete family from getFont, never an empty string, and
40
+ * UI_spec checks that what comes back is a real name. */
41
+ export declare const DEFAULT_OUTPUT_FONT_FAMILY = "Bitstream Vera Sans Mono";
37
42
  export declare function getUniversalDefaultFonts(): readonly string[];
38
43
  export declare function getCachedLocalFonts(): string[];
39
44
  export declare function setLocalFontsCache(families: Iterable<string>): void;
package/dist-lib/vite.js CHANGED
@@ -95,6 +95,28 @@ export default function mudix() {
95
95
  {
96
96
  name: 'mudix:config',
97
97
  config: () => ({
98
+ resolve: {
99
+ // Exactly one React instance, always. `mudlet-map-editor`
100
+ // declares react/react-dom as plain *dependencies* (not
101
+ // peers), so the moment its range outruns the range the
102
+ // app resolved, the package manager nests a second copy
103
+ // under the editor. The editor's `App` is then rendered by
104
+ // mudix's React while its hooks come from the nested one,
105
+ // whose dispatcher is null — "Invalid hook call", and with
106
+ // no error boundary above the lazy boundary the throw
107
+ // unmounts the whole root, so opening the map editor
108
+ // blanked the entire UI in dev and in production alike.
109
+ // Deduping is the structural fix: it survives the next
110
+ // version skew, and consumers of the library (which
111
+ // externalizes react) get it through this plugin too.
112
+ dedupe: ['react', 'react-dom'],
113
+ },
114
+ // A Mudlet package archive is a zip, not source. `?url` imports
115
+ // get away without this (the explicit query short-circuits
116
+ // import analysis), but `?inline` — which the busted fixtures
117
+ // use to carry an archive into the VFS — reaches the asset
118
+ // pipeline and needs the extension declared.
119
+ assetsInclude: ['**/*.mpackage'],
98
120
  optimizeDeps: {
99
121
  // 'mudix': the library entry carries relative `?url` asset
100
122
  // imports (external in the lib build); the dep optimizer's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mudlet/mudlet-web",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
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",
@@ -45,10 +45,11 @@
45
45
  "test": "vitest run",
46
46
  "test:watch": "vitest",
47
47
  "dev:busted": "vite --mode busted --port 5174 --strictPort",
48
- "pretest:e2e": "npm run gen:busted-manifest",
49
48
  "test:e2e": "playwright test",
50
- "gen:busted-manifest": "playwright test -c playwright.manifest.config.ts",
51
- "sync:mudlet-specs": "node scripts/sync-mudlet-specs.mjs"
49
+ "busted:failures": "playwright test -c playwright.failures.config.ts",
50
+ "sync:mudlet-specs": "node scripts/sync-mudlet-specs.mjs",
51
+ "sync:mudlet-lua": "node scripts/sync-mudlet-lua.mjs",
52
+ "sync:mudlet-games": "node scripts/sync-mudlet-games.mjs"
52
53
  },
53
54
  "dependencies": {
54
55
  "@codemirror/autocomplete": "^6.20.1",
@@ -63,12 +64,12 @@
63
64
  "@types/dompurify": "^3.0.5",
64
65
  "@zenfs/core": "^2.5.6",
65
66
  "@zenfs/dom": "^1.2.9",
66
- "dompurify": "^3.4.12",
67
+ "dompurify": "^3.4.14",
67
68
  "fflate": "^0.8.2",
68
69
  "lucide-react": "^1.14.0",
69
70
  "marked": "^18.0.4",
70
71
  "mudlet-map-binary-reader": "^1.2.0",
71
- "mudlet-map-editor": "^1.3.1",
72
+ "mudlet-map-editor": "^1.3.2",
72
73
  "mudlet-map-renderer": "^2.6.1",
73
74
  "pako": "^2.1.0",
74
75
  "pcre2-wasm-universal": "^1.0.0",
@@ -89,5 +90,8 @@
89
90
  "typescript": "^5.0.0",
90
91
  "vite": "8.0.16",
91
92
  "vitest": "^4.1.7"
93
+ },
94
+ "resolutions": {
95
+ "dompurify": "^3.4.14"
92
96
  }
93
97
  }
@@ -1,8 +0,0 @@
1
- import type { ProfileVFS } from '../../../scripting/vfs/ProfileVFS';
2
- interface Props {
3
- vfs: ProfileVFS;
4
- onClose: () => void;
5
- onPick: (absolutePath: string) => void;
6
- }
7
- export declare function VfsModulePickerModal({ vfs, onClose, onPick }: Props): import("react/jsx-runtime").JSX.Element;
8
- export {};