remobi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/LICENSE +21 -0
- package/README.md +302 -0
- package/dist/build.d.mts +17 -0
- package/dist/build.d.mts.map +1 -0
- package/dist/build.mjs +115 -0
- package/dist/build.mjs.map +1 -0
- package/dist/catppuccin-mocha-CGTshAuT.mjs +48 -0
- package/dist/catppuccin-mocha-CGTshAuT.mjs.map +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +945 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/node-compat-BzXgbTV9.mjs +83 -0
- package/dist/node-compat-BzXgbTV9.mjs.map +1 -0
- package/dist/overlay.iife.js +1 -0
- package/dist/src/config.d.mts +22 -0
- package/dist/src/config.d.mts.map +1 -0
- package/dist/src/config.mjs +384 -0
- package/dist/src/config.mjs.map +1 -0
- package/dist/src/index.d.mts +76 -0
- package/dist/src/index.d.mts.map +1 -0
- package/dist/src/index.mjs +1637 -0
- package/dist/src/index.mjs.map +1 -0
- package/dist/src/types.d.mts +183 -0
- package/dist/src/types.d.mts.map +1 -0
- package/dist/src/types.mjs +1 -0
- package/package.json +88 -0
- package/src/pwa/icons/icon-180.png +0 -0
- package/src/pwa/icons/icon-192.png +0 -0
- package/src/pwa/icons/icon-512.png +0 -0
- package/styles/base.css +475 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { n as resolveButtonArray, t as catppuccinMocha } from "../catppuccin-mocha-CGTshAuT.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/config.ts
|
|
4
|
+
/** Default font configuration */
|
|
5
|
+
const defaultFont = {
|
|
6
|
+
family: "JetBrainsMono NFM, monospace",
|
|
7
|
+
cdnUrl: "https://cdn.jsdelivr.net/gh/mshaugh/nerdfont-webfonts@latest/build/jetbrainsmono-nfm.css",
|
|
8
|
+
mobileSizeDefault: 16,
|
|
9
|
+
sizeRange: [8, 32]
|
|
10
|
+
};
|
|
11
|
+
/** Default gesture configuration */
|
|
12
|
+
const defaultGestures = {
|
|
13
|
+
swipe: {
|
|
14
|
+
enabled: true,
|
|
15
|
+
threshold: 80,
|
|
16
|
+
maxDuration: 400,
|
|
17
|
+
left: "n",
|
|
18
|
+
right: "p",
|
|
19
|
+
leftLabel: "Next tmux window",
|
|
20
|
+
rightLabel: "Previous tmux window"
|
|
21
|
+
},
|
|
22
|
+
pinch: { enabled: false },
|
|
23
|
+
scroll: {
|
|
24
|
+
enabled: true,
|
|
25
|
+
sensitivity: 40,
|
|
26
|
+
strategy: "wheel",
|
|
27
|
+
wheelIntervalMs: 24
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/** Default row 1 buttons (prefix + nav) */
|
|
31
|
+
const defaultRow1 = [
|
|
32
|
+
{
|
|
33
|
+
id: "esc",
|
|
34
|
+
label: "Esc",
|
|
35
|
+
description: "Send Escape key",
|
|
36
|
+
action: {
|
|
37
|
+
type: "send",
|
|
38
|
+
data: "\x1B"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "tmux-prefix",
|
|
43
|
+
label: "Prefix",
|
|
44
|
+
description: "Send tmux prefix key (Ctrl-B)",
|
|
45
|
+
action: {
|
|
46
|
+
type: "send",
|
|
47
|
+
data: ""
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "tab",
|
|
52
|
+
label: "Tab",
|
|
53
|
+
description: "Send Tab key",
|
|
54
|
+
action: {
|
|
55
|
+
type: "send",
|
|
56
|
+
data: " "
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "shift-tab",
|
|
61
|
+
label: "S-Tab",
|
|
62
|
+
description: "Send Shift+Tab key",
|
|
63
|
+
action: {
|
|
64
|
+
type: "send",
|
|
65
|
+
data: "\x1B[Z",
|
|
66
|
+
keyLabel: "Shift+Tab"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "left",
|
|
71
|
+
label: "←",
|
|
72
|
+
description: "Send Left arrow key",
|
|
73
|
+
action: {
|
|
74
|
+
type: "send",
|
|
75
|
+
data: "\x1B[D",
|
|
76
|
+
keyLabel: "Left"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "up",
|
|
81
|
+
label: "↑",
|
|
82
|
+
description: "Send Up arrow key",
|
|
83
|
+
action: {
|
|
84
|
+
type: "send",
|
|
85
|
+
data: "\x1B[A",
|
|
86
|
+
keyLabel: "Up"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "down",
|
|
91
|
+
label: "↓",
|
|
92
|
+
description: "Send Down arrow key",
|
|
93
|
+
action: {
|
|
94
|
+
type: "send",
|
|
95
|
+
data: "\x1B[B",
|
|
96
|
+
keyLabel: "Down"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: "right",
|
|
101
|
+
label: "→",
|
|
102
|
+
description: "Send Right arrow key",
|
|
103
|
+
action: {
|
|
104
|
+
type: "send",
|
|
105
|
+
data: "\x1B[C",
|
|
106
|
+
keyLabel: "Right"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: "ctrl-c",
|
|
111
|
+
label: "C-c",
|
|
112
|
+
description: "Send Ctrl-C interrupt",
|
|
113
|
+
action: {
|
|
114
|
+
type: "send",
|
|
115
|
+
data: ""
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: "enter",
|
|
120
|
+
label: "⏎",
|
|
121
|
+
description: "Send Enter/Return key",
|
|
122
|
+
action: {
|
|
123
|
+
type: "send",
|
|
124
|
+
data: "\r"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
];
|
|
128
|
+
/** Default row 2 buttons */
|
|
129
|
+
const defaultRow2 = [
|
|
130
|
+
{
|
|
131
|
+
id: "q",
|
|
132
|
+
label: "q",
|
|
133
|
+
description: "Send q key",
|
|
134
|
+
action: {
|
|
135
|
+
type: "send",
|
|
136
|
+
data: "q"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "alt-enter",
|
|
141
|
+
label: "M-↵",
|
|
142
|
+
description: "Send Alt+Enter (ESC + Enter)",
|
|
143
|
+
action: {
|
|
144
|
+
type: "send",
|
|
145
|
+
data: "\x1B\r",
|
|
146
|
+
keyLabel: "Alt+Enter"
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: "ctrl-d",
|
|
151
|
+
label: "C-d",
|
|
152
|
+
description: "Send Ctrl-D key",
|
|
153
|
+
action: {
|
|
154
|
+
type: "send",
|
|
155
|
+
data: ""
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "drawer-toggle",
|
|
160
|
+
label: "☰ More",
|
|
161
|
+
description: "Open command drawer",
|
|
162
|
+
action: { type: "drawer-toggle" }
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: "paste",
|
|
166
|
+
label: "Paste",
|
|
167
|
+
description: "Paste from clipboard",
|
|
168
|
+
action: { type: "paste" }
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: "backspace",
|
|
172
|
+
label: "⌫",
|
|
173
|
+
description: "Send Backspace key",
|
|
174
|
+
action: {
|
|
175
|
+
type: "send",
|
|
176
|
+
data: "",
|
|
177
|
+
keyLabel: "Backspace"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: "space",
|
|
182
|
+
label: "Space",
|
|
183
|
+
description: "Send Space key",
|
|
184
|
+
action: {
|
|
185
|
+
type: "send",
|
|
186
|
+
data: " "
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
/** Default drawer commands */
|
|
191
|
+
const defaultDrawerButtons = [
|
|
192
|
+
{
|
|
193
|
+
id: "tmux-new-window",
|
|
194
|
+
label: "+ Win",
|
|
195
|
+
description: "Create tmux window",
|
|
196
|
+
action: {
|
|
197
|
+
type: "send",
|
|
198
|
+
data: "c"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: "tmux-split-vertical",
|
|
203
|
+
label: "Split |",
|
|
204
|
+
description: "Split pane vertically",
|
|
205
|
+
action: {
|
|
206
|
+
type: "send",
|
|
207
|
+
data: "%"
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: "tmux-split-horizontal",
|
|
212
|
+
label: "Split —",
|
|
213
|
+
description: "Split pane horizontally",
|
|
214
|
+
action: {
|
|
215
|
+
type: "send",
|
|
216
|
+
data: "\""
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
id: "tmux-zoom",
|
|
221
|
+
label: "Zoom",
|
|
222
|
+
description: "Toggle pane zoom",
|
|
223
|
+
action: {
|
|
224
|
+
type: "send",
|
|
225
|
+
data: "z"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: "tmux-sessions",
|
|
230
|
+
label: "Sessions",
|
|
231
|
+
description: "Choose tmux session",
|
|
232
|
+
action: {
|
|
233
|
+
type: "send",
|
|
234
|
+
data: "s"
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: "tmux-windows",
|
|
239
|
+
label: "Windows",
|
|
240
|
+
description: "Choose tmux window",
|
|
241
|
+
action: {
|
|
242
|
+
type: "send",
|
|
243
|
+
data: "w"
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
id: "page-up",
|
|
248
|
+
label: "PgUp",
|
|
249
|
+
description: "Send Page Up key",
|
|
250
|
+
action: {
|
|
251
|
+
type: "send",
|
|
252
|
+
data: "\x1B[5~",
|
|
253
|
+
keyLabel: "Page Up"
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: "page-down",
|
|
258
|
+
label: "PgDn",
|
|
259
|
+
description: "Send Page Down key",
|
|
260
|
+
action: {
|
|
261
|
+
type: "send",
|
|
262
|
+
data: "\x1B[6~",
|
|
263
|
+
keyLabel: "Page Down"
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
id: "tmux-copy",
|
|
268
|
+
label: "Copy",
|
|
269
|
+
description: "Enter tmux copy mode",
|
|
270
|
+
action: {
|
|
271
|
+
type: "send",
|
|
272
|
+
data: "["
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
id: "tmux-help",
|
|
277
|
+
label: "Help",
|
|
278
|
+
description: "List tmux key bindings",
|
|
279
|
+
action: {
|
|
280
|
+
type: "send",
|
|
281
|
+
data: "?"
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "tmux-kill-pane",
|
|
286
|
+
label: "Kill",
|
|
287
|
+
description: "Kill current pane (with confirm)",
|
|
288
|
+
action: {
|
|
289
|
+
type: "send",
|
|
290
|
+
data: "x"
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: "combo-picker",
|
|
295
|
+
label: "Combo",
|
|
296
|
+
description: "Open combo sender (Ctrl/Alt + key)",
|
|
297
|
+
action: { type: "combo-picker" }
|
|
298
|
+
}
|
|
299
|
+
];
|
|
300
|
+
/** Default mobile configuration */
|
|
301
|
+
const defaultMobile = {
|
|
302
|
+
initData: null,
|
|
303
|
+
widthThreshold: 768
|
|
304
|
+
};
|
|
305
|
+
/** Default PWA configuration */
|
|
306
|
+
const defaultPwa = {
|
|
307
|
+
enabled: true,
|
|
308
|
+
themeColor: "#1e1e2e"
|
|
309
|
+
};
|
|
310
|
+
/** Complete default configuration */
|
|
311
|
+
const defaultConfig = {
|
|
312
|
+
name: "remobi",
|
|
313
|
+
theme: catppuccinMocha,
|
|
314
|
+
font: defaultFont,
|
|
315
|
+
toolbar: {
|
|
316
|
+
row1: defaultRow1,
|
|
317
|
+
row2: defaultRow2
|
|
318
|
+
},
|
|
319
|
+
drawer: { buttons: defaultDrawerButtons },
|
|
320
|
+
gestures: defaultGestures,
|
|
321
|
+
mobile: defaultMobile,
|
|
322
|
+
floatingButtons: [],
|
|
323
|
+
pwa: defaultPwa,
|
|
324
|
+
reconnect: { enabled: true }
|
|
325
|
+
};
|
|
326
|
+
/** Deep merge two objects, with `override` taking precedence */
|
|
327
|
+
function deepMerge(base, override) {
|
|
328
|
+
const result = { ...base };
|
|
329
|
+
for (const key of Object.keys(override)) {
|
|
330
|
+
const overrideVal = override[key];
|
|
331
|
+
if (overrideVal === void 0) continue;
|
|
332
|
+
const baseVal = base[key];
|
|
333
|
+
if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) result[key] = deepMerge(baseVal, overrideVal);
|
|
334
|
+
else result[key] = overrideVal;
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Merge a config overrides object against a base config.
|
|
340
|
+
* Button arrays support array or function form via `ButtonArrayInput`.
|
|
341
|
+
*/
|
|
342
|
+
function mergeConfig(base, overrides) {
|
|
343
|
+
const row1Input = overrides.toolbar?.row1;
|
|
344
|
+
const row2Input = overrides.toolbar?.row2;
|
|
345
|
+
const drawerInput = overrides.drawer?.buttons;
|
|
346
|
+
const merged = deepMerge(base, {
|
|
347
|
+
...overrides,
|
|
348
|
+
toolbar: overrides.toolbar !== void 0 ? {
|
|
349
|
+
...overrides.toolbar,
|
|
350
|
+
row1: void 0,
|
|
351
|
+
row2: void 0
|
|
352
|
+
} : void 0,
|
|
353
|
+
drawer: overrides.drawer !== void 0 ? {
|
|
354
|
+
...overrides.drawer,
|
|
355
|
+
buttons: void 0
|
|
356
|
+
} : void 0
|
|
357
|
+
});
|
|
358
|
+
const row1 = resolveButtonArray(base.toolbar.row1, row1Input);
|
|
359
|
+
const row2 = resolveButtonArray(base.toolbar.row2, row2Input);
|
|
360
|
+
const drawerButtons = resolveButtonArray(base.drawer.buttons, drawerInput);
|
|
361
|
+
return {
|
|
362
|
+
...merged,
|
|
363
|
+
toolbar: {
|
|
364
|
+
row1,
|
|
365
|
+
row2
|
|
366
|
+
},
|
|
367
|
+
drawer: { buttons: drawerButtons }
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/** Define a remobi configuration with defaults filled in */
|
|
371
|
+
function defineConfig(overrides = {}) {
|
|
372
|
+
return mergeConfig(defaultConfig, overrides);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Serialise theme to ttyd `-t theme=...` JSON string.
|
|
376
|
+
* Used by the shell wrapper to pass theme via CLI flags.
|
|
377
|
+
*/
|
|
378
|
+
function serialiseThemeForTtyd(config) {
|
|
379
|
+
return JSON.stringify(config.theme);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
//#endregion
|
|
383
|
+
export { defaultConfig, defaultDrawerButtons, defineConfig, mergeConfig, serialiseThemeForTtyd };
|
|
384
|
+
//# sourceMappingURL=config.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.mjs","names":[],"sources":["../../src/config.ts"],"sourcesContent":["import { resolveButtonArray } from './config-resolve'\nimport { catppuccinMocha } from './theme/catppuccin-mocha'\nimport type {\n\tControlButton,\n\tDeepPartial,\n\tPwaConfig,\n\tRemobiConfig,\n\tRemobiConfigOverrides,\n} from './types'\n\n/** Default font configuration */\nconst defaultFont: RemobiConfig['font'] = {\n\tfamily: 'JetBrainsMono NFM, monospace',\n\tcdnUrl:\n\t\t'https://cdn.jsdelivr.net/gh/mshaugh/nerdfont-webfonts@latest/build/jetbrainsmono-nfm.css',\n\tmobileSizeDefault: 16,\n\tsizeRange: [8, 32],\n}\n\n/** Default gesture configuration */\nconst defaultGestures: RemobiConfig['gestures'] = {\n\tswipe: {\n\t\tenabled: true,\n\t\tthreshold: 80,\n\t\tmaxDuration: 400,\n\t\tleft: '\\x02n',\n\t\tright: '\\x02p',\n\t\tleftLabel: 'Next tmux window',\n\t\trightLabel: 'Previous tmux window',\n\t},\n\tpinch: { enabled: false },\n\tscroll: { enabled: true, sensitivity: 40, strategy: 'wheel', wheelIntervalMs: 24 },\n}\n\n/** Default row 1 buttons (prefix + nav) */\nconst defaultRow1: RemobiConfig['toolbar']['row1'] = [\n\t{\n\t\tid: 'esc',\n\t\tlabel: 'Esc',\n\t\tdescription: 'Send Escape key',\n\t\taction: { type: 'send', data: '\\x1b' },\n\t},\n\t{\n\t\tid: 'tmux-prefix',\n\t\tlabel: 'Prefix',\n\t\tdescription: 'Send tmux prefix key (Ctrl-B)',\n\t\taction: { type: 'send', data: '\\x02' },\n\t},\n\t{ id: 'tab', label: 'Tab', description: 'Send Tab key', action: { type: 'send', data: '\\t' } },\n\t{\n\t\tid: 'shift-tab',\n\t\tlabel: 'S-Tab',\n\t\tdescription: 'Send Shift+Tab key',\n\t\taction: { type: 'send', data: '\\x1b[Z', keyLabel: 'Shift+Tab' },\n\t},\n\t{\n\t\tid: 'left',\n\t\tlabel: '\\u2190',\n\t\tdescription: 'Send Left arrow key',\n\t\taction: { type: 'send', data: '\\x1b[D', keyLabel: 'Left' },\n\t},\n\t{\n\t\tid: 'up',\n\t\tlabel: '\\u2191',\n\t\tdescription: 'Send Up arrow key',\n\t\taction: { type: 'send', data: '\\x1b[A', keyLabel: 'Up' },\n\t},\n\t{\n\t\tid: 'down',\n\t\tlabel: '\\u2193',\n\t\tdescription: 'Send Down arrow key',\n\t\taction: { type: 'send', data: '\\x1b[B', keyLabel: 'Down' },\n\t},\n\t{\n\t\tid: 'right',\n\t\tlabel: '\\u2192',\n\t\tdescription: 'Send Right arrow key',\n\t\taction: { type: 'send', data: '\\x1b[C', keyLabel: 'Right' },\n\t},\n\t{\n\t\tid: 'ctrl-c',\n\t\tlabel: 'C-c',\n\t\tdescription: 'Send Ctrl-C interrupt',\n\t\taction: { type: 'send', data: '\\x03' },\n\t},\n\t{\n\t\tid: 'enter',\n\t\tlabel: '\\u23CE',\n\t\tdescription: 'Send Enter/Return key',\n\t\taction: { type: 'send', data: '\\r' },\n\t},\n]\n\n/** Default row 2 buttons */\nconst defaultRow2: RemobiConfig['toolbar']['row2'] = [\n\t{\n\t\tid: 'q',\n\t\tlabel: 'q',\n\t\tdescription: 'Send q key',\n\t\taction: { type: 'send', data: 'q' },\n\t},\n\t{\n\t\tid: 'alt-enter',\n\t\tlabel: 'M-↵',\n\t\tdescription: 'Send Alt+Enter (ESC + Enter)',\n\t\taction: { type: 'send', data: '\\x1b\\r', keyLabel: 'Alt+Enter' },\n\t},\n\t{\n\t\tid: 'ctrl-d',\n\t\tlabel: 'C-d',\n\t\tdescription: 'Send Ctrl-D key',\n\t\taction: { type: 'send', data: '\\x04' },\n\t},\n\t{\n\t\tid: 'drawer-toggle',\n\t\tlabel: '\\u2630 More',\n\t\tdescription: 'Open command drawer',\n\t\taction: { type: 'drawer-toggle' },\n\t},\n\t{ id: 'paste', label: 'Paste', description: 'Paste from clipboard', action: { type: 'paste' } },\n\t{\n\t\tid: 'backspace',\n\t\tlabel: '\\u232b',\n\t\tdescription: 'Send Backspace key',\n\t\taction: { type: 'send', data: '\\x7f', keyLabel: 'Backspace' },\n\t},\n\t{\n\t\tid: 'space',\n\t\tlabel: 'Space',\n\t\tdescription: 'Send Space key',\n\t\taction: { type: 'send', data: ' ' },\n\t},\n]\n\n/** Default drawer commands */\nexport const defaultDrawerButtons: readonly ControlButton[] = [\n\t{\n\t\tid: 'tmux-new-window',\n\t\tlabel: '+ Win',\n\t\tdescription: 'Create tmux window',\n\t\taction: { type: 'send', data: '\\x02c' },\n\t},\n\t{\n\t\tid: 'tmux-split-vertical',\n\t\tlabel: 'Split |',\n\t\tdescription: 'Split pane vertically',\n\t\taction: { type: 'send', data: '\\x02%' },\n\t},\n\t{\n\t\tid: 'tmux-split-horizontal',\n\t\tlabel: 'Split \\u2014',\n\t\tdescription: 'Split pane horizontally',\n\t\taction: { type: 'send', data: '\\x02\"' },\n\t},\n\t{\n\t\tid: 'tmux-zoom',\n\t\tlabel: 'Zoom',\n\t\tdescription: 'Toggle pane zoom',\n\t\taction: { type: 'send', data: '\\x02z' },\n\t},\n\t{\n\t\tid: 'tmux-sessions',\n\t\tlabel: 'Sessions',\n\t\tdescription: 'Choose tmux session',\n\t\taction: { type: 'send', data: '\\x02s' },\n\t},\n\t{\n\t\tid: 'tmux-windows',\n\t\tlabel: 'Windows',\n\t\tdescription: 'Choose tmux window',\n\t\taction: { type: 'send', data: '\\x02w' },\n\t},\n\t{\n\t\tid: 'page-up',\n\t\tlabel: 'PgUp',\n\t\tdescription: 'Send Page Up key',\n\t\taction: { type: 'send', data: '\\x1b[5~', keyLabel: 'Page Up' },\n\t},\n\t{\n\t\tid: 'page-down',\n\t\tlabel: 'PgDn',\n\t\tdescription: 'Send Page Down key',\n\t\taction: { type: 'send', data: '\\x1b[6~', keyLabel: 'Page Down' },\n\t},\n\t{\n\t\tid: 'tmux-copy',\n\t\tlabel: 'Copy',\n\t\tdescription: 'Enter tmux copy mode',\n\t\taction: { type: 'send', data: '\\x02[' },\n\t},\n\t{\n\t\tid: 'tmux-help',\n\t\tlabel: 'Help',\n\t\tdescription: 'List tmux key bindings',\n\t\taction: { type: 'send', data: '\\x02?' },\n\t},\n\t{\n\t\tid: 'tmux-kill-pane',\n\t\tlabel: 'Kill',\n\t\tdescription: 'Kill current pane (with confirm)',\n\t\taction: { type: 'send', data: '\\x02x' },\n\t},\n\t{\n\t\tid: 'combo-picker',\n\t\tlabel: 'Combo',\n\t\tdescription: 'Open combo sender (Ctrl/Alt + key)',\n\t\taction: { type: 'combo-picker' },\n\t},\n]\n\n/** Default mobile configuration */\nconst defaultMobile: RemobiConfig['mobile'] = {\n\tinitData: null,\n\twidthThreshold: 768,\n}\n\n/** Default PWA configuration */\nconst defaultPwa: PwaConfig = {\n\tenabled: true,\n\tthemeColor: '#1e1e2e',\n}\n\n/** Complete default configuration */\nexport const defaultConfig: RemobiConfig = {\n\tname: 'remobi',\n\ttheme: catppuccinMocha,\n\tfont: defaultFont,\n\ttoolbar: { row1: defaultRow1, row2: defaultRow2 },\n\tdrawer: { buttons: defaultDrawerButtons },\n\tgestures: defaultGestures,\n\tmobile: defaultMobile,\n\tfloatingButtons: [],\n\tpwa: defaultPwa,\n\treconnect: { enabled: true },\n}\n\n/** Deep merge two objects, with `override` taking precedence */\nfunction deepMerge(\n\tbase: Record<string, unknown>,\n\toverride: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { ...base }\n\tfor (const key of Object.keys(override)) {\n\t\tconst overrideVal = override[key]\n\t\tif (overrideVal === undefined) continue\n\t\tconst baseVal = base[key]\n\t\tif (\n\t\t\tbaseVal !== null &&\n\t\t\ttypeof baseVal === 'object' &&\n\t\t\t!Array.isArray(baseVal) &&\n\t\t\toverrideVal !== null &&\n\t\t\ttypeof overrideVal === 'object' &&\n\t\t\t!Array.isArray(overrideVal)\n\t\t) {\n\t\t\t/* oxlint-disable typescript/consistent-type-assertions -- generic deepMerge on runtime-narrowed objects */\n\t\t\tresult[key] = deepMerge(\n\t\t\t\tbaseVal as Record<string, unknown>,\n\t\t\t\toverrideVal as Record<string, unknown>,\n\t\t\t)\n\t\t\t/* oxlint-enable typescript/consistent-type-assertions */\n\t\t} else {\n\t\t\tresult[key] = overrideVal\n\t\t}\n\t}\n\treturn result\n}\n\n/**\n * Merge a config overrides object against a base config.\n * Button arrays support array or function form via `ButtonArrayInput`.\n */\nexport function mergeConfig(base: RemobiConfig, overrides: RemobiConfigOverrides): RemobiConfig {\n\t// Extract button array inputs before deep-merging (they are not plain arrays)\n\tconst row1Input = overrides.toolbar?.row1\n\tconst row2Input = overrides.toolbar?.row2\n\tconst drawerInput = overrides.drawer?.buttons\n\n\t// Strip button array inputs from overrides before deep-merge so deepMerge\n\t// doesn't try to replace them (they may be functions, not arrays)\n\tconst strippedOverrides: DeepPartial<RemobiConfig> = {\n\t\t...overrides,\n\t\ttoolbar:\n\t\t\toverrides.toolbar !== undefined\n\t\t\t\t? {\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/consistent-type-assertions -- bridge typed overrides to untyped merge\n\t\t\t\t\t\t...(overrides.toolbar as DeepPartial<RemobiConfig['toolbar']>),\n\t\t\t\t\t\trow1: undefined,\n\t\t\t\t\t\trow2: undefined,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\tdrawer:\n\t\t\toverrides.drawer !== undefined\n\t\t\t\t? {\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/consistent-type-assertions -- bridge typed overrides to untyped merge\n\t\t\t\t\t\t...(overrides.drawer as DeepPartial<RemobiConfig['drawer']>),\n\t\t\t\t\t\tbuttons: undefined,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t}\n\n\t/* oxlint-disable typescript/consistent-type-assertions -- bridge typed config to untyped deepMerge */\n\tconst merged = deepMerge(\n\t\tbase as unknown as Record<string, unknown>,\n\t\tstrippedOverrides as unknown as Record<string, unknown>,\n\t) as unknown as RemobiConfig\n\t/* oxlint-enable typescript/consistent-type-assertions */\n\n\t// Resolve button arrays\n\tconst row1 = resolveButtonArray(base.toolbar.row1, row1Input)\n\tconst row2 = resolveButtonArray(base.toolbar.row2, row2Input)\n\tconst drawerButtons = resolveButtonArray(base.drawer.buttons, drawerInput)\n\n\treturn {\n\t\t...merged,\n\t\ttoolbar: { row1, row2 },\n\t\tdrawer: { buttons: drawerButtons },\n\t}\n}\n\n/** Define a remobi configuration with defaults filled in */\nexport function defineConfig(overrides: RemobiConfigOverrides = {}): RemobiConfig {\n\treturn mergeConfig(defaultConfig, overrides)\n}\n\n/**\n * Serialise theme to ttyd `-t theme=...` JSON string.\n * Used by the shell wrapper to pass theme via CLI flags.\n */\nexport function serialiseThemeForTtyd(config: RemobiConfig): string {\n\treturn JSON.stringify(config.theme)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ButtonAction, ButtonArrayInput, ControlButton, FloatingButtonGroup, FloatingDirection, FloatingPosition, ReconnectConfig, RemobiConfig, RemobiConfigOverrides, TermTheme, XTerminal } from "./types.mjs";
|
|
2
|
+
import { defineConfig } from "./config.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/hooks/registry.d.ts
|
|
5
|
+
type SendSource = 'toolbar' | 'drawer' | 'floating-buttons' | 'mobile-init';
|
|
6
|
+
interface BeforeSendDataContext {
|
|
7
|
+
readonly term: XTerminal;
|
|
8
|
+
readonly config: RemobiConfig;
|
|
9
|
+
readonly source: SendSource;
|
|
10
|
+
readonly actionType: ButtonAction['type'];
|
|
11
|
+
readonly kbWasOpen: boolean;
|
|
12
|
+
readonly data: string;
|
|
13
|
+
}
|
|
14
|
+
interface BeforeSendDataResult {
|
|
15
|
+
readonly data?: string;
|
|
16
|
+
readonly block?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface AfterSendDataContext {
|
|
19
|
+
readonly term: XTerminal;
|
|
20
|
+
readonly config: RemobiConfig;
|
|
21
|
+
readonly source: SendSource;
|
|
22
|
+
readonly actionType: ButtonAction['type'];
|
|
23
|
+
readonly kbWasOpen: boolean;
|
|
24
|
+
readonly data: string;
|
|
25
|
+
}
|
|
26
|
+
interface OverlayInitContext {
|
|
27
|
+
readonly term: XTerminal;
|
|
28
|
+
readonly config: RemobiConfig;
|
|
29
|
+
readonly mobile: boolean;
|
|
30
|
+
}
|
|
31
|
+
interface ToolbarCreatedContext {
|
|
32
|
+
readonly term: XTerminal;
|
|
33
|
+
readonly config: RemobiConfig;
|
|
34
|
+
readonly toolbar: HTMLDivElement;
|
|
35
|
+
}
|
|
36
|
+
interface DrawerCreatedContext {
|
|
37
|
+
readonly term: XTerminal;
|
|
38
|
+
readonly config: RemobiConfig;
|
|
39
|
+
readonly drawer: HTMLDivElement;
|
|
40
|
+
readonly backdrop: HTMLDivElement;
|
|
41
|
+
}
|
|
42
|
+
interface HookMap {
|
|
43
|
+
beforeSendData: (context: BeforeSendDataContext) => BeforeSendDataResult | undefined | Promise<BeforeSendDataResult | undefined>;
|
|
44
|
+
afterSendData: (context: AfterSendDataContext) => void | Promise<void>;
|
|
45
|
+
overlayInitStart: (context: OverlayInitContext) => void | Promise<void>;
|
|
46
|
+
overlayReady: (context: OverlayInitContext) => void | Promise<void>;
|
|
47
|
+
toolbarCreated: (context: ToolbarCreatedContext) => void | Promise<void>;
|
|
48
|
+
drawerCreated: (context: DrawerCreatedContext) => void | Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
type HookName = keyof HookMap;
|
|
51
|
+
interface HookRegistry {
|
|
52
|
+
on: <K extends HookName>(name: K, hook: HookMap[K]) => {
|
|
53
|
+
dispose(): void;
|
|
54
|
+
};
|
|
55
|
+
runBeforeSendData: (context: BeforeSendDataContext) => Promise<{
|
|
56
|
+
readonly blocked: boolean;
|
|
57
|
+
readonly data: string;
|
|
58
|
+
}>;
|
|
59
|
+
runAfterSendData: (context: AfterSendDataContext) => Promise<void>;
|
|
60
|
+
runOverlayInitStart: (context: OverlayInitContext) => Promise<void>;
|
|
61
|
+
runOverlayReady: (context: OverlayInitContext) => Promise<void>;
|
|
62
|
+
runToolbarCreated: (context: ToolbarCreatedContext) => Promise<void>;
|
|
63
|
+
runDrawerCreated: (context: DrawerCreatedContext) => Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
declare function createHookRegistry(): HookRegistry;
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/index.d.ts
|
|
68
|
+
/**
|
|
69
|
+
* Initialise the remobi overlay.
|
|
70
|
+
* Called automatically when loaded in a browser (via the IIFE in build output).
|
|
71
|
+
* Config is embedded at build time.
|
|
72
|
+
*/
|
|
73
|
+
declare function init(config?: RemobiConfig, hooks?: HookRegistry): void;
|
|
74
|
+
//#endregion
|
|
75
|
+
export { type ButtonAction, type ButtonArrayInput, type ControlButton, type FloatingButtonGroup, type FloatingDirection, type FloatingPosition, type HookRegistry, type ReconnectConfig, type RemobiConfig, type RemobiConfigOverrides, type SendSource, type TermTheme, createHookRegistry, defineConfig, init };
|
|
76
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/hooks/registry.ts","../../src/index.ts"],"mappings":";;;;KAEY,UAAA;AAAA,UAEK,qBAAA;EAAA,SACP,IAAA,EAAM,SAAA;EAAA,SACN,MAAA,EAAQ,YAAA;EAAA,SACR,MAAA,EAAQ,UAAA;EAAA,SACR,UAAA,EAAY,YAAA;EAAA,SACZ,SAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGA,oBAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;AAAA;AAAA,UAGO,oBAAA;EAAA,SACP,IAAA,EAAM,SAAA;EAAA,SACN,MAAA,EAAQ,YAAA;EAAA,SACR,MAAA,EAAQ,UAAA;EAAA,SACR,UAAA,EAAY,YAAA;EAAA,SACZ,SAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGO,kBAAA;EAAA,SACP,IAAA,EAAM,SAAA;EAAA,SACN,MAAA,EAAQ,YAAA;EAAA,SACR,MAAA;AAAA;AAAA,UAGO,qBAAA;EAAA,SACP,IAAA,EAAM,SAAA;EAAA,SACN,MAAA,EAAQ,YAAA;EAAA,SACR,OAAA,EAAS,cAAA;AAAA;AAAA,UAGF,oBAAA;EAAA,SACP,IAAA,EAAM,SAAA;EAAA,SACN,MAAA,EAAQ,YAAA;EAAA,SACR,MAAA,EAAQ,cAAA;EAAA,SACR,QAAA,EAAU,cAAA;AAAA;AAAA,UAGV,OAAA;EACT,cAAA,GACC,OAAA,EAAS,qBAAA,KACL,oBAAA,eAAmC,OAAA,CAAQ,oBAAA;EAChD,aAAA,GAAgB,OAAA,EAAS,oBAAA,YAAgC,OAAA;EACzD,gBAAA,GAAmB,OAAA,EAAS,kBAAA,YAA8B,OAAA;EAC1D,YAAA,GAAe,OAAA,EAAS,kBAAA,YAA8B,OAAA;EACtD,cAAA,GAAiB,OAAA,EAAS,qBAAA,YAAiC,OAAA;EAC3D,aAAA,GAAgB,OAAA,EAAS,oBAAA,YAAgC,OAAA;AAAA;AAAA,KAGrD,QAAA,SAAiB,OAAA;AAAA,UAEL,YAAA;EAChB,EAAA,aAAe,QAAA,EAAU,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,OAAA,CAAQ,CAAA;IAAS,OAAA;EAAA;EACzD,iBAAA,GACC,OAAA,EAAS,qBAAA,KACL,OAAA;IAAA,SAAmB,OAAA;IAAA,SAA2B,IAAA;EAAA;EACnD,gBAAA,GAAmB,OAAA,EAAS,oBAAA,KAAyB,OAAA;EACrD,mBAAA,GAAsB,OAAA,EAAS,kBAAA,KAAuB,OAAA;EACtD,eAAA,GAAkB,OAAA,EAAS,kBAAA,KAAuB,OAAA;EAClD,iBAAA,GAAoB,OAAA,EAAS,qBAAA,KAA0B,OAAA;EACvD,gBAAA,GAAmB,OAAA,EAAS,oBAAA,KAAyB,OAAA;AAAA;AAAA,iBAOtC,kBAAA,CAAA,GAAsB,YAAA;;;;;AAvEtC;;;iBC4CgB,IAAA,CACf,MAAA,GAAQ,YAAA,EACR,KAAA,GAAO,YAAA"}
|