mudlet-map-editor 0.17.0 → 0.19.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.
@@ -1,5 +1,14 @@
1
- export declare function Toolbar({ title, onHelpClick, onLoadFromUrl, onSave, onSearchClick, onSettingsClick }: {
1
+ import { type ReactNode } from 'react';
2
+ import type { ToolbarAction } from '../editor/plugin';
3
+ /** `logo` is the plugin override slot. `undefined` means no plugin claimed it
4
+ * (toolbar falls back to the built-in Mudlet logo); any other value — including
5
+ * `null` — is rendered as-is, so a plugin can explicitly hide the slot.
6
+ * `transformActions` is the composed plugin transform applied to the built-in
7
+ * file-action list (see EditorPlugin#toolbarActions). */
8
+ export declare function Toolbar({ title, logo, transformActions, onHelpClick, onLoadFromUrl, onSave, onSearchClick, onSettingsClick }: {
2
9
  title?: string;
10
+ logo?: ReactNode;
11
+ transformActions?: (actions: ToolbarAction[]) => ToolbarAction[];
3
12
  onHelpClick: () => void;
4
13
  onLoadFromUrl: () => void;
5
14
  onSave?: (bytes: Uint8Array) => void;
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from 'react';
1
+ import type { CSSProperties, ReactNode } from 'react';
2
2
  import type { MudletMap, MudletRoom } from '../mapIO';
3
3
  import type { SwatchSet } from './types';
4
4
  import type { SceneHandle } from './scene';
@@ -31,6 +31,38 @@ export interface RoomPanelSection {
31
31
  id: string;
32
32
  render(props: RoomSectionProps): ReactNode;
33
33
  }
34
+ /** A button in the toolbar header row's file-action group. Plugins reshape the
35
+ * list via `toolbarActions` — filter to hide built-ins, map to override
36
+ * callbacks/labels, or push to add new entries. Built-in ids are 'new',
37
+ * 'load', 'loadUrl', and 'save'. */
38
+ export interface ToolbarAction {
39
+ /** Stable id; plugins target a specific action by matching on this. */
40
+ id: string;
41
+ /** Tooltip text shown on hover. */
42
+ title?: string;
43
+ /** Button contents — typically an SVG icon, but any node works. */
44
+ icon?: ReactNode;
45
+ /** Click handler. Ignored when `filePicker` is set. */
46
+ onClick?: () => void;
47
+ /** When set, the action renders as a `<label>` wrapping a hidden `<input
48
+ * type="file">`; clicking opens the OS file picker and the chosen file is
49
+ * passed to `onFile`. Used by the built-in "load .dat" entry. */
50
+ filePicker?: {
51
+ accept: string;
52
+ onFile: (file: File) => void;
53
+ };
54
+ /** Disable the button (greys out + ignores clicks). */
55
+ disabled?: boolean;
56
+ /** Overlay node rendered on top of the button — used by the built-in
57
+ * "save" entry to draw the dirty-marker asterisk. */
58
+ badge?: ReactNode;
59
+ /** Inline style for the button/label root. */
60
+ style?: CSSProperties;
61
+ /** Escape hatch: when set, every other field except `id` is ignored and
62
+ * this node is rendered in place. Use for controls that aren't a single
63
+ * button (e.g. a dropdown). */
64
+ render?: () => ReactNode;
65
+ }
34
66
  export interface EditorPlugin {
35
67
  /** Stable identifier used to namespace plugin warning ack keys. Defaults to array index if omitted. */
36
68
  id?: string;
@@ -39,6 +71,22 @@ export interface EditorPlugin {
39
71
  onMapClosed?(): void;
40
72
  onMapSave?(bytes: Uint8Array): void;
41
73
  renderOverlay?(): ReactNode;
74
+ /** Replace the toolbar logo. The first plugin that defines this hook claims
75
+ * the slot — its return value is rendered as-is (including `null`, which
76
+ * hides the logo entirely). When no plugin defines it, the built-in Mudlet
77
+ * logo appears. */
78
+ renderLogo?(): ReactNode;
79
+ /** Reshape the toolbar's file-action button list. The hook receives the
80
+ * current list (built-ins first, then any earlier-plugin additions) and
81
+ * returns a new list. Typical uses:
82
+ * - **Hide** a built-in: `actions.filter(a => a.id !== 'loadUrl')`
83
+ * - **Replace a callback**: `actions.map(a => a.id === 'save'
84
+ * ? { ...a, onClick: mySave } : a)` (keeps the button visuals,
85
+ * swaps the behaviour — onMapSave still fires when the editor
86
+ * serialises the map elsewhere)
87
+ * - **Add** a custom button: `[...actions, { id, title, icon, onClick }]`
88
+ * Plugin transforms are applied in plugin order. */
89
+ toolbarActions?(actions: ToolbarAction[]): ToolbarAction[];
42
90
  sidebarTabs?(): SidebarTab[];
43
91
  swatchSets?(): SwatchSet[];
44
92
  /** Contribute additional sections rendered at the bottom of the room selection panel. */
@@ -78,6 +78,7 @@ export declare class EditorArea {
78
78
  addRoomsLive(newRooms: LiveRoom[]): void;
79
79
  removeRoomById(id: number): void;
80
80
  removeRoomsById(ids: Set<number>): void;
81
+ renameRoomId(fromId: number, toId: number): void;
81
82
  rebuildPlanes(): void;
82
83
  rebuildExits(): void;
83
84
  }
@@ -120,6 +121,7 @@ export declare class EditorMapReader {
120
121
  setRoomField(id: number, field: 'name' | 'environment' | 'weight' | 'symbol', value: string | number): void;
121
122
  setRoomLock(id: number, lock: boolean): void;
122
123
  setUserDataEntry(id: number, key: string, value: string | null): void;
124
+ renameRoomId(fromId: number, toId: number): void;
123
125
  /** Add a raw room (expected `raw.rooms[id]` already set or not, we set it). */
124
126
  addRoom(id: number, rawRoom: MudletRoom): void;
125
127
  /** Bulk-add many rooms. Does one rebuildPlanes/rebuildExits per affected area. */
@@ -291,6 +291,10 @@ export type Command = {
291
291
  room: RoomSnapshot;
292
292
  areaId: number;
293
293
  neighborEdits: NeighborEdit[];
294
+ } | {
295
+ kind: 'renameRoomId';
296
+ fromId: number;
297
+ toId: number;
294
298
  } | {
295
299
  kind: 'addExit';
296
300
  fromId: number;
@@ -17,6 +17,7 @@ export declare const panelsEn: {
17
17
  };
18
18
  readonly room: {
19
19
  readonly heading: "Room #{{id}}";
20
+ readonly id: "Room ID";
20
21
  readonly centerView: "Center view on room";
21
22
  readonly exits: "Exits";
22
23
  readonly specialExits: "Special Exits";
@@ -66,7 +67,12 @@ export declare const panelsEn: {
66
67
  readonly dashDotDot: "Dash-Dot-Dot";
67
68
  readonly enterExitNameFirst: "Enter exit name first.";
68
69
  readonly updatedField: "Updated {{field}} on room {{id}}";
70
+ readonly idUpdated: "Room #{{from}} renamed to #{{to}}";
71
+ readonly idExists: "Room #{{id}} already exists.";
69
72
  readonly exitAdded: "Exit {{dir}} → room {{id}} added.";
73
+ readonly exitRoomCreated: "Created room #{{id}} {{dir}} of room #{{from}}.";
74
+ readonly exitCreateOccupied: "Cannot create room #{{id}}: cell ({{x}}, {{y}}, {{z}}) is already occupied.";
75
+ readonly exitCreateInOut: "Cannot auto-create rooms for in/out directions.";
70
76
  readonly specialExitAdded: "Special exit '{{name}}' → {{id}} added";
71
77
  readonly specialExitRemoved: "Special exit '{{name}}' removed";
72
78
  readonly customLineRemoved: "Custom line '{{name}}' removed";
@@ -126,6 +132,7 @@ export declare const panelsEn: {
126
132
  readonly moveRoom: "Move room #{{id}}";
127
133
  readonly addRoom: "Add room #{{id}}";
128
134
  readonly deleteRoom: "Delete room #{{id}}";
135
+ readonly renameRoomId: "Rename room #{{from}} -> #{{to}}";
129
136
  readonly addExitBidi: "Add exit #{{from}} {{dir}} ↔ #{{to}}";
130
137
  readonly addExitUni: "Add exit #{{from}} {{dir}} → #{{to}}";
131
138
  readonly removeExit: "Remove exit #{{from}} {{dir}}";
@@ -1,6 +1,6 @@
1
1
  import './styles.css';
2
2
  export { default as App } from './App';
3
- export type { EditorPlugin, SidebarTab, RoomPanelSection, RoomSectionProps, PluginCheckResult } from './editor/plugin';
3
+ export type { EditorPlugin, SidebarTab, RoomPanelSection, RoomSectionProps, PluginCheckResult, ToolbarAction } from './editor/plugin';
4
4
  export type { MudletMap, MudletRoom, MudletColor } from './mapIO';
5
5
  export type { SwatchSet, Swatch } from './editor/types';
6
6
  export { loadUrlIntoStore } from './editor/loadFile';