@tooee/shell 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/README.md +5 -0
- package/dist/CommandPaletteOverlay.d.ts +7 -0
- package/dist/CommandPaletteOverlay.d.ts.map +1 -0
- package/dist/CommandPaletteOverlay.js +29 -0
- package/dist/CommandPaletteOverlay.js.map +1 -0
- package/dist/ThemePickerOverlay.d.ts +6 -0
- package/dist/ThemePickerOverlay.d.ts.map +1 -0
- package/dist/ThemePickerOverlay.js +20 -0
- package/dist/ThemePickerOverlay.js.map +1 -0
- package/dist/command-palette.d.ts +9 -0
- package/dist/command-palette.d.ts.map +1 -0
- package/dist/command-palette.js +51 -0
- package/dist/command-palette.js.map +1 -0
- package/dist/commands.d.ts +18 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +49 -0
- package/dist/commands.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/launch.d.ts +6 -0
- package/dist/launch.d.ts.map +1 -0
- package/dist/launch.js +12 -0
- package/dist/launch.js.map +1 -0
- package/dist/modal.d.ts +34 -0
- package/dist/modal.d.ts.map +1 -0
- package/dist/modal.js +440 -0
- package/dist/modal.js.map +1 -0
- package/dist/overlay.d.ts +11 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +145 -0
- package/dist/overlay.js.map +1 -0
- package/dist/provider.d.ts +11 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +13 -0
- package/dist/provider.js.map +1 -0
- package/dist/search.d.ts +2 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +20 -0
- package/dist/search.js.map +1 -0
- package/dist/theme-picker.d.ts +16 -0
- package/dist/theme-picker.d.ts.map +1 -0
- package/dist/theme-picker.js +48 -0
- package/dist/theme-picker.js.map +1 -0
- package/package.json +49 -0
- package/src/CommandPaletteOverlay.tsx +44 -0
- package/src/ThemePickerOverlay.tsx +28 -0
- package/src/command-palette.ts +73 -0
- package/src/commands.ts +60 -0
- package/src/index.ts +11 -0
- package/src/launch.tsx +15 -0
- package/src/modal.ts +504 -0
- package/src/overlay.tsx +220 -0
- package/src/provider.tsx +46 -0
- package/src/search.ts +18 -0
- package/src/theme-picker.ts +84 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAoB,MAAM,eAAe,CAAA;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,eAAe,EAAa,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAS/C,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,MAAM,EACN,MAAM,EAAE,eAAe,EACvB,WAAW,GACQ;IACnB,OAAO,CACL,KAAC,cAAc,IAAC,SAAS,EAAE,eAAe,YACxC,KAAC,kBAAkB,IAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,YACzD,QAAQ,GACU,GACN,CAClB,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,EAC1B,QAAQ,EACR,MAAM,EACN,WAAW,GAKZ;IACC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,OAAO,CACL,KAAC,qBAAqB,IAAC,YAAY,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,YACtF,KAAC,eAAe,IAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,YAC5E,KAAC,eAAe,cAAE,QAAQ,GAAmB,GAC7B,GACI,CACzB,CAAA;AACH,CAAC"}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBvE"}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function findMatchingLines(text, query) {
|
|
2
|
+
if (!query)
|
|
3
|
+
return [];
|
|
4
|
+
const lowerQuery = query.toLowerCase();
|
|
5
|
+
const results = [];
|
|
6
|
+
let lineStart = 0;
|
|
7
|
+
let lineNum = 0;
|
|
8
|
+
for (let i = 0; i <= text.length; i++) {
|
|
9
|
+
if (i === text.length || text[i] === "\n") {
|
|
10
|
+
const line = text.slice(lineStart, i).toLowerCase();
|
|
11
|
+
if (line.includes(lowerQuery)) {
|
|
12
|
+
results.push(lineNum);
|
|
13
|
+
}
|
|
14
|
+
lineStart = i + 1;
|
|
15
|
+
lineNum++;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return results;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,KAAa;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IACrB,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAA;IACtC,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;YACnD,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACvB,CAAC;YACD,SAAS,GAAG,CAAC,GAAG,CAAC,CAAA;YACjB,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ThemePickerEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ThemePickerState {
|
|
6
|
+
isOpen: boolean;
|
|
7
|
+
open: () => void;
|
|
8
|
+
close: () => void;
|
|
9
|
+
confirm: (name: string) => void;
|
|
10
|
+
preview: (name: string) => void;
|
|
11
|
+
entries: ThemePickerEntry[];
|
|
12
|
+
originalTheme: string;
|
|
13
|
+
currentTheme: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function useThemePicker(): ThemePickerState;
|
|
16
|
+
//# sourceMappingURL=theme-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-picker.d.ts","sourceRoot":"","sources":["../src/theme-picker.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB;AAID,wBAAgB,cAAc,IAAI,gBAAgB,CA0DjD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from "react";
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import { useThemeSwitcher } from "@tooee/themes";
|
|
4
|
+
import { useOverlay } from "@tooee/overlays";
|
|
5
|
+
import { ThemePickerOverlay } from "./ThemePickerOverlay.jsx";
|
|
6
|
+
const OVERLAY_ID = "theme-picker";
|
|
7
|
+
export function useThemePicker() {
|
|
8
|
+
const { allThemes, setTheme, name: currentTheme } = useThemeSwitcher();
|
|
9
|
+
const overlay = useOverlay();
|
|
10
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
11
|
+
const originalThemeRef = useRef(currentTheme);
|
|
12
|
+
const entries = allThemes.map((name) => ({
|
|
13
|
+
id: name,
|
|
14
|
+
title: name,
|
|
15
|
+
}));
|
|
16
|
+
const close = useCallback(() => {
|
|
17
|
+
setTheme(originalThemeRef.current);
|
|
18
|
+
setIsOpen(false);
|
|
19
|
+
overlay.hide(OVERLAY_ID);
|
|
20
|
+
}, [setTheme, overlay]);
|
|
21
|
+
const confirm = useCallback((name) => {
|
|
22
|
+
setTheme(name);
|
|
23
|
+
setIsOpen(false);
|
|
24
|
+
overlay.hide(OVERLAY_ID);
|
|
25
|
+
}, [setTheme, overlay]);
|
|
26
|
+
const preview = useCallback((name) => {
|
|
27
|
+
setTheme(name);
|
|
28
|
+
}, [setTheme]);
|
|
29
|
+
const open = useCallback(() => {
|
|
30
|
+
originalThemeRef.current = currentTheme;
|
|
31
|
+
setIsOpen(true);
|
|
32
|
+
overlay.open(OVERLAY_ID, ({ close }) => createElement(ThemePickerOverlay, {
|
|
33
|
+
originalTheme: currentTheme,
|
|
34
|
+
close: () => close(),
|
|
35
|
+
}), null, { mode: "insert", dismissOnEscape: true, onClose: () => setIsOpen(false) });
|
|
36
|
+
}, [overlay, currentTheme]);
|
|
37
|
+
return {
|
|
38
|
+
isOpen,
|
|
39
|
+
open,
|
|
40
|
+
close,
|
|
41
|
+
confirm,
|
|
42
|
+
preview,
|
|
43
|
+
entries,
|
|
44
|
+
originalTheme: originalThemeRef.current,
|
|
45
|
+
currentTheme,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=theme-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-picker.js","sourceRoot":"","sources":["../src/theme-picker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAkB7D,MAAM,UAAU,GAAG,cAAc,CAAA;AAEjC,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACtE,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,gBAAgB,GAAG,MAAM,CAAS,YAAY,CAAC,CAAA;IAErD,MAAM,OAAO,GAAuB,SAAS,CAAC,GAAG,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;QACnE,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC,CAAA;IAEH,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAA;QAClC,SAAS,CAAC,KAAK,CAAC,CAAA;QAChB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAC1B,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;IAEvB,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,IAAY,EAAE,EAAE;QACf,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,SAAS,CAAC,KAAK,CAAC,CAAA;QAChB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAC1B,CAAC,EACD,CAAC,QAAQ,EAAE,OAAO,CAAC,CACpB,CAAA;IAED,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,IAAY,EAAE,EAAE;QACf,QAAQ,CAAC,IAAI,CAAC,CAAA;IAChB,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,gBAAgB,CAAC,OAAO,GAAG,YAAY,CAAA;QACvC,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,OAAO,CAAC,IAAI,CACV,UAAU,EACV,CAAC,EAAE,KAAK,EAAoD,EAAE,EAAE,CAC9D,aAAa,CAAC,kBAAkB,EAAE;YAChC,aAAa,EAAE,YAAY;YAC3B,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE;SACrB,CAAC,EACJ,IAAI,EACJ,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAC3E,CAAA;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAA;IAE3B,OAAO;QACL,MAAM;QACN,IAAI;QACJ,KAAK;QACL,OAAO;QACP,OAAO;QACP,OAAO;QACP,aAAa,EAAE,gBAAgB,CAAC,OAAO;QACvC,YAAY;KACb,CAAA;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tooee/shell",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Composition layer wiring Tooee apps together",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Gareth Andrew",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/gingerhendrix/tooee.git",
|
|
10
|
+
"directory": "packages/shell"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/gingerhendrix/tooee",
|
|
13
|
+
"bugs": "https://github.com/gingerhendrix/tooee/issues",
|
|
14
|
+
"keywords": ["tui", "terminal", "cli", "opentui"],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": {
|
|
19
|
+
"@tooee/source": "./src/index.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": ["dist", "src"],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@tooee/commands": "0.0.0",
|
|
30
|
+
"@tooee/config": "0.0.0",
|
|
31
|
+
"@tooee/clipboard": "0.0.0",
|
|
32
|
+
"@tooee/layout": "0.0.0",
|
|
33
|
+
"@tooee/overlays": "0.0.0",
|
|
34
|
+
"@tooee/renderers": "0.0.0",
|
|
35
|
+
"@tooee/themes": "0.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@opentui/core": "^0.1.67",
|
|
39
|
+
"@opentui/react": "^0.1.67",
|
|
40
|
+
"@types/bun": "^1.3.5",
|
|
41
|
+
"@types/react": "^19.1.10",
|
|
42
|
+
"typescript": "^5.8.3"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@opentui/core": "^0.1.67",
|
|
46
|
+
"@opentui/react": "^0.1.67",
|
|
47
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createElement, useMemo } from "react"
|
|
2
|
+
import type { ReactNode } from "react"
|
|
3
|
+
import { useCommandContext } from "@tooee/commands"
|
|
4
|
+
import type { Mode } from "@tooee/commands"
|
|
5
|
+
import { CommandPalette } from "@tooee/renderers"
|
|
6
|
+
|
|
7
|
+
const DEFAULT_MODES: Mode[] = ["cursor"]
|
|
8
|
+
|
|
9
|
+
export function CommandPaletteOverlay({
|
|
10
|
+
launchMode,
|
|
11
|
+
close,
|
|
12
|
+
}: {
|
|
13
|
+
launchMode: Mode
|
|
14
|
+
close: () => void
|
|
15
|
+
}): ReactNode {
|
|
16
|
+
const { commands, invoke } = useCommandContext()
|
|
17
|
+
|
|
18
|
+
const entries = useMemo(
|
|
19
|
+
() =>
|
|
20
|
+
commands
|
|
21
|
+
.filter((cmd) => !cmd.hidden)
|
|
22
|
+
.filter((cmd) => {
|
|
23
|
+
const cmdModes = cmd.modes ?? DEFAULT_MODES
|
|
24
|
+
return cmdModes.includes(launchMode)
|
|
25
|
+
})
|
|
26
|
+
.map((cmd) => ({
|
|
27
|
+
id: cmd.id,
|
|
28
|
+
title: cmd.title,
|
|
29
|
+
hotkey: cmd.defaultHotkey,
|
|
30
|
+
category: cmd.category,
|
|
31
|
+
icon: cmd.icon,
|
|
32
|
+
})),
|
|
33
|
+
[commands, launchMode],
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return createElement(CommandPalette, {
|
|
37
|
+
commands: entries,
|
|
38
|
+
onSelect: (id: string) => {
|
|
39
|
+
close()
|
|
40
|
+
invoke(id)
|
|
41
|
+
},
|
|
42
|
+
onClose: close,
|
|
43
|
+
})
|
|
44
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createElement } from "react"
|
|
2
|
+
import type { ReactNode } from "react"
|
|
3
|
+
import { useThemeSwitcher, ThemePicker } from "@tooee/themes"
|
|
4
|
+
|
|
5
|
+
export function ThemePickerOverlay({
|
|
6
|
+
originalTheme,
|
|
7
|
+
close,
|
|
8
|
+
}: {
|
|
9
|
+
originalTheme: string
|
|
10
|
+
close: () => void
|
|
11
|
+
}): ReactNode {
|
|
12
|
+
const { allThemes, name: currentTheme, setTheme } = useThemeSwitcher()
|
|
13
|
+
const entries = allThemes.map((name: string) => ({ id: name, title: name }))
|
|
14
|
+
|
|
15
|
+
return createElement(ThemePicker, {
|
|
16
|
+
entries,
|
|
17
|
+
currentTheme,
|
|
18
|
+
onNavigate: setTheme,
|
|
19
|
+
onSelect: (name: string) => {
|
|
20
|
+
setTheme(name)
|
|
21
|
+
close()
|
|
22
|
+
},
|
|
23
|
+
onClose: () => {
|
|
24
|
+
setTheme(originalTheme)
|
|
25
|
+
close()
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from "react"
|
|
2
|
+
import { createElement } from "react"
|
|
3
|
+
import { useCommandContext, useCommand, useMode } from "@tooee/commands"
|
|
4
|
+
import type { Mode } from "@tooee/commands"
|
|
5
|
+
import { useOverlay } from "@tooee/overlays"
|
|
6
|
+
import type { OverlayCloseReason } from "@tooee/overlays"
|
|
7
|
+
import type { CommandPaletteEntry } from "@tooee/renderers"
|
|
8
|
+
import { CommandPaletteOverlay } from "./CommandPaletteOverlay.jsx"
|
|
9
|
+
|
|
10
|
+
const DEFAULT_MODES: Mode[] = ["cursor"]
|
|
11
|
+
const OVERLAY_ID = "command-palette"
|
|
12
|
+
|
|
13
|
+
export interface CommandPaletteState {
|
|
14
|
+
isOpen: boolean
|
|
15
|
+
open: () => void
|
|
16
|
+
close: () => void
|
|
17
|
+
entries: CommandPaletteEntry[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function useCommandPalette(): CommandPaletteState {
|
|
21
|
+
const { commands } = useCommandContext()
|
|
22
|
+
const mode = useMode()
|
|
23
|
+
const overlay = useOverlay()
|
|
24
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
25
|
+
const launchModeRef = useRef<Mode>(mode)
|
|
26
|
+
|
|
27
|
+
const launchMode = launchModeRef.current
|
|
28
|
+
const entries = useMemo(() => {
|
|
29
|
+
return commands
|
|
30
|
+
.filter((cmd) => !cmd.hidden)
|
|
31
|
+
.filter((cmd) => {
|
|
32
|
+
const cmdModes = cmd.modes ?? DEFAULT_MODES
|
|
33
|
+
return cmdModes.includes(launchMode)
|
|
34
|
+
})
|
|
35
|
+
.map((cmd) => ({
|
|
36
|
+
id: cmd.id,
|
|
37
|
+
title: cmd.title,
|
|
38
|
+
hotkey: cmd.defaultHotkey,
|
|
39
|
+
category: cmd.category,
|
|
40
|
+
icon: cmd.icon,
|
|
41
|
+
}))
|
|
42
|
+
}, [commands, launchMode])
|
|
43
|
+
|
|
44
|
+
const close = useCallback(() => {
|
|
45
|
+
setIsOpen(false)
|
|
46
|
+
overlay.hide(OVERLAY_ID)
|
|
47
|
+
}, [overlay])
|
|
48
|
+
|
|
49
|
+
const open = useCallback(() => {
|
|
50
|
+
launchModeRef.current = mode
|
|
51
|
+
setIsOpen(true)
|
|
52
|
+
overlay.open(
|
|
53
|
+
OVERLAY_ID,
|
|
54
|
+
({ close }: { close: (reason?: OverlayCloseReason) => void }) =>
|
|
55
|
+
createElement(CommandPaletteOverlay, {
|
|
56
|
+
launchMode: mode,
|
|
57
|
+
close: () => close(),
|
|
58
|
+
}),
|
|
59
|
+
null,
|
|
60
|
+
{ mode: "insert", dismissOnEscape: true, onClose: () => setIsOpen(false) },
|
|
61
|
+
)
|
|
62
|
+
}, [overlay, mode])
|
|
63
|
+
|
|
64
|
+
useCommand({
|
|
65
|
+
id: "command-palette",
|
|
66
|
+
title: "Command Palette",
|
|
67
|
+
hotkey: ":",
|
|
68
|
+
modes: ["cursor"],
|
|
69
|
+
handler: open,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
return { isOpen, open, close, entries }
|
|
73
|
+
}
|
package/src/commands.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useRenderer } from "@opentui/react"
|
|
2
|
+
import { copyToClipboard } from "@tooee/clipboard"
|
|
3
|
+
import { useCommand, type CommandWhen } from "@tooee/commands"
|
|
4
|
+
import { useThemePicker, type ThemePickerState } from "./theme-picker.js"
|
|
5
|
+
|
|
6
|
+
export function useThemeCommands(opts?: { when?: CommandWhen }): {
|
|
7
|
+
name: string
|
|
8
|
+
picker: ThemePickerState
|
|
9
|
+
} {
|
|
10
|
+
const picker = useThemePicker()
|
|
11
|
+
|
|
12
|
+
useCommand({
|
|
13
|
+
id: "cycle-theme",
|
|
14
|
+
title: "Choose theme",
|
|
15
|
+
hotkey: "t",
|
|
16
|
+
when: opts?.when,
|
|
17
|
+
handler: () => {
|
|
18
|
+
picker.open()
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return { name: picker.currentTheme, picker }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useQuitCommand(opts?: {
|
|
26
|
+
hotkey?: string
|
|
27
|
+
when?: CommandWhen
|
|
28
|
+
onQuit?: () => void
|
|
29
|
+
}) {
|
|
30
|
+
const renderer = useRenderer()
|
|
31
|
+
|
|
32
|
+
useCommand({
|
|
33
|
+
id: "quit",
|
|
34
|
+
title: "Quit",
|
|
35
|
+
hotkey: opts?.hotkey ?? "q",
|
|
36
|
+
when: opts?.when,
|
|
37
|
+
handler: () => {
|
|
38
|
+
if (opts?.onQuit) {
|
|
39
|
+
opts.onQuit()
|
|
40
|
+
} else {
|
|
41
|
+
renderer.destroy()
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function useCopyCommand(opts: { getText: () => string | undefined; when?: CommandWhen }) {
|
|
48
|
+
useCommand({
|
|
49
|
+
id: "copy",
|
|
50
|
+
title: "Copy to clipboard",
|
|
51
|
+
hotkey: "y",
|
|
52
|
+
when: opts.when,
|
|
53
|
+
handler: () => {
|
|
54
|
+
const text = opts.getText()
|
|
55
|
+
if (text) {
|
|
56
|
+
void copyToClipboard(text)
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { useThemeCommands, useQuitCommand, useCopyCommand } from "./commands.js"
|
|
2
|
+
export { useModalNavigationCommands } from "./modal.js"
|
|
3
|
+
export type { ModalNavigationState, ModalNavigationOptions, Position } from "./modal.js"
|
|
4
|
+
export { findMatchingLines } from "./search.js"
|
|
5
|
+
export { TooeeProvider } from "./provider.jsx"
|
|
6
|
+
export { launchCli } from "./launch.jsx"
|
|
7
|
+
export { useCommandPalette } from "./command-palette.js"
|
|
8
|
+
export type { CommandPaletteState } from "./command-palette.js"
|
|
9
|
+
export { useThemePicker } from "./theme-picker.js"
|
|
10
|
+
export type { ThemePickerState, ThemePickerEntry } from "./theme-picker.js"
|
|
11
|
+
export { OverlayProvider } from "./overlay.jsx"
|
package/src/launch.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from "react"
|
|
2
|
+
import { createCliRenderer } from "@opentui/core"
|
|
3
|
+
import { createRoot } from "@opentui/react"
|
|
4
|
+
import { TooeeProvider } from "./provider.jsx"
|
|
5
|
+
|
|
6
|
+
export async function launchCli(
|
|
7
|
+
node: ReactNode,
|
|
8
|
+
opts?: { useAlternateScreen?: boolean; exitOnCtrlC?: boolean },
|
|
9
|
+
): Promise<void> {
|
|
10
|
+
const renderer = await createCliRenderer({
|
|
11
|
+
useAlternateScreen: opts?.useAlternateScreen ?? true,
|
|
12
|
+
exitOnCtrlC: opts?.exitOnCtrlC ?? true,
|
|
13
|
+
})
|
|
14
|
+
createRoot(renderer).render(<TooeeProvider>{node}</TooeeProvider>)
|
|
15
|
+
}
|