@edv4h/usketch-plugin-tool-vim 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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -0
  3. package/dist/__tests__/test-helpers.d.ts +15 -0
  4. package/dist/__tests__/test-helpers.d.ts.map +1 -0
  5. package/dist/__tests__/test-helpers.js +96 -0
  6. package/dist/__tests__/test-helpers.js.map +1 -0
  7. package/dist/candidates.d.ts +13 -0
  8. package/dist/candidates.d.ts.map +1 -0
  9. package/dist/candidates.js +47 -0
  10. package/dist/candidates.js.map +1 -0
  11. package/dist/commands.d.ts +18 -0
  12. package/dist/commands.d.ts.map +1 -0
  13. package/dist/commands.js +58 -0
  14. package/dist/commands.js.map +1 -0
  15. package/dist/config/default-config.d.ts +14 -0
  16. package/dist/config/default-config.d.ts.map +1 -0
  17. package/dist/config/default-config.js +35 -0
  18. package/dist/config/default-config.js.map +1 -0
  19. package/dist/config/schema.d.ts +51 -0
  20. package/dist/config/schema.d.ts.map +1 -0
  21. package/dist/config/schema.js +65 -0
  22. package/dist/config/schema.js.map +1 -0
  23. package/dist/constants.d.ts +6 -0
  24. package/dist/constants.d.ts.map +1 -0
  25. package/dist/constants.js +6 -0
  26. package/dist/constants.js.map +1 -0
  27. package/dist/cursor.d.ts +18 -0
  28. package/dist/cursor.d.ts.map +1 -0
  29. package/dist/cursor.js +97 -0
  30. package/dist/cursor.js.map +1 -0
  31. package/dist/extensions.d.ts +44 -0
  32. package/dist/extensions.d.ts.map +1 -0
  33. package/dist/extensions.js +2 -0
  34. package/dist/extensions.js.map +1 -0
  35. package/dist/hop.d.ts +13 -0
  36. package/dist/hop.d.ts.map +1 -0
  37. package/dist/hop.js +53 -0
  38. package/dist/hop.js.map +1 -0
  39. package/dist/index.d.ts +6 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +4 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/keymap.d.ts +17 -0
  44. package/dist/keymap.d.ts.map +1 -0
  45. package/dist/keymap.js +223 -0
  46. package/dist/keymap.js.map +1 -0
  47. package/dist/machine/actions.d.ts +23 -0
  48. package/dist/machine/actions.d.ts.map +1 -0
  49. package/dist/machine/actions.js +97 -0
  50. package/dist/machine/actions.js.map +1 -0
  51. package/dist/machine/types.d.ts +159 -0
  52. package/dist/machine/types.d.ts.map +1 -0
  53. package/dist/machine/types.js +2 -0
  54. package/dist/machine/types.js.map +1 -0
  55. package/dist/machine/vim-machine.d.ts +200 -0
  56. package/dist/machine/vim-machine.d.ts.map +1 -0
  57. package/dist/machine/vim-machine.js +425 -0
  58. package/dist/machine/vim-machine.js.map +1 -0
  59. package/dist/plugin.d.ts +5 -0
  60. package/dist/plugin.d.ts.map +1 -0
  61. package/dist/plugin.js +180 -0
  62. package/dist/plugin.js.map +1 -0
  63. package/dist/ui/help-overlay.d.ts +6 -0
  64. package/dist/ui/help-overlay.d.ts.map +1 -0
  65. package/dist/ui/help-overlay.js +104 -0
  66. package/dist/ui/help-overlay.js.map +1 -0
  67. package/dist/ui/overlay.d.ts +14 -0
  68. package/dist/ui/overlay.d.ts.map +1 -0
  69. package/dist/ui/overlay.js +97 -0
  70. package/dist/ui/overlay.js.map +1 -0
  71. package/dist/ui/status-line.d.ts +6 -0
  72. package/dist/ui/status-line.d.ts.map +1 -0
  73. package/dist/ui/status-line.js +44 -0
  74. package/dist/ui/status-line.js.map +1 -0
  75. package/dist/ui/vim-ui-store.d.ts +46 -0
  76. package/dist/ui/vim-ui-store.d.ts.map +1 -0
  77. package/dist/ui/vim-ui-store.js +36 -0
  78. package/dist/ui/vim-ui-store.js.map +1 -0
  79. package/dist/ui/which-key.d.ts +6 -0
  80. package/dist/ui/which-key.d.ts.map +1 -0
  81. package/dist/ui/which-key.js +71 -0
  82. package/dist/ui/which-key.js.map +1 -0
  83. package/dist/viewport-utils.d.ts +11 -0
  84. package/dist/viewport-utils.d.ts.map +1 -0
  85. package/dist/viewport-utils.js +26 -0
  86. package/dist/viewport-utils.js.map +1 -0
  87. package/package.json +53 -0
@@ -0,0 +1,6 @@
1
+ import type { VimUiStore } from "./vim-ui-store.js";
2
+ /** `:help` で開く全画面ヘルプ(fixed レイヤー)。Esc または再度 :help で閉じる。 */
3
+ export declare function VimHelpOverlay({ store }: {
4
+ store: VimUiStore;
5
+ }): import("react/jsx-runtime").JSX.Element | null;
6
+ //# sourceMappingURL=help-overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-overlay.d.ts","sourceRoot":"","sources":["../../src/ui/help-overlay.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAiEpD,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,kDAgF9D"}
@@ -0,0 +1,104 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useSyncExternalStore } from "react";
3
+ const SECTIONS = [
4
+ {
5
+ title: "NORMAL",
6
+ rows: [
7
+ ["h j k l", "カーソル移動"],
8
+ ["{count}j", "回数指定 (例 5j)"],
9
+ ["H J K L", "画角を移動 (pan)"],
10
+ ["i", "insert モードへ"],
11
+ ["v / V", "visual / 複数選択へ"],
12
+ [":", "command モードへ"],
13
+ ["x / d", "削除 (選択 or カーソル最近傍)"],
14
+ ["y / p", "ヤンク / 貼り付け"],
15
+ ["u / Ctrl+r", "undo / redo"],
16
+ ["+ / -", "ズーム イン / アウト"],
17
+ ["zz", "ビューポートをカーソルへ寄せる"],
18
+ ["M", "カーソルを画面中央へ"],
19
+ ["f", "hop: ラベルを表示しジャンプ"],
20
+ ["gg / G", "最初 / 最後の shape へ"],
21
+ ["m{a-z}", "マークを設定"],
22
+ ["`{a-z}", "マークへジャンプ"],
23
+ ["?", "which-key ヒントの表示切替"],
24
+ ],
25
+ },
26
+ {
27
+ title: "INSERT",
28
+ rows: [
29
+ ["a-z…", "shape 名を入力 (候補表示)"],
30
+ ["Tab / S-Tab", "候補を次 / 前へ"],
31
+ ["Enter", "カーソル位置に shape 追加"],
32
+ ["Esc", "normal へ戻る"],
33
+ ],
34
+ },
35
+ {
36
+ title: "VISUAL",
37
+ rows: [
38
+ ["(入った時)", "カーソル最近傍を選択"],
39
+ ["h j k l", "方向最近傍へ選択を移動"],
40
+ ["V", "複数選択モードへ"],
41
+ ["d / x", "選択を削除"],
42
+ ["y", "選択をヤンク"],
43
+ ["Esc", "選択解除して normal へ"],
44
+ ],
45
+ },
46
+ {
47
+ title: "COMMAND ( : )",
48
+ rows: [
49
+ [":q / :wq", "Vim を抜ける"],
50
+ [":tool <id>", "ツールを切替"],
51
+ [":set bg=dots|grid|none", "背景を変更"],
52
+ [":zoom <n>", "ズーム率を指定"],
53
+ [":center", "カーソルを画面中央へ"],
54
+ [":export <fmt>", "png / svg / json で書き出し"],
55
+ [":help", "このヘルプの表示切替"],
56
+ ],
57
+ },
58
+ ];
59
+ /** `:help` で開く全画面ヘルプ(fixed レイヤー)。Esc または再度 :help で閉じる。 */
60
+ export function VimHelpOverlay({ store }) {
61
+ const s = useSyncExternalStore(store.subscribe, store.getSnapshot);
62
+ if (!s.active || !s.helpVisible)
63
+ return null;
64
+ return (_jsx("div", { style: {
65
+ position: "absolute",
66
+ inset: 0,
67
+ display: "flex",
68
+ alignItems: "center",
69
+ justifyContent: "center",
70
+ background: "rgba(10,10,18,0.55)",
71
+ backdropFilter: "blur(2px)",
72
+ pointerEvents: "none",
73
+ zIndex: 1,
74
+ }, children: _jsxs("div", { style: {
75
+ width: "min(880px, 92vw)",
76
+ maxHeight: "82vh",
77
+ overflow: "auto",
78
+ // 外側の pointerEvents:none を継承するとスクロールできないため上書き。
79
+ pointerEvents: "auto",
80
+ background: "#181825",
81
+ color: "#cdd6f4",
82
+ border: "1px solid #313244",
83
+ borderRadius: 12,
84
+ boxShadow: "0 16px 48px rgba(0,0,0,0.5)",
85
+ font: "13px ui-monospace, SFMono-Regular, Menlo, monospace",
86
+ }, children: [_jsxs("div", { style: {
87
+ display: "flex",
88
+ alignItems: "baseline",
89
+ justifyContent: "space-between",
90
+ padding: "14px 20px",
91
+ borderBottom: "1px solid #313244",
92
+ }, children: [_jsx("strong", { style: { fontSize: 15, letterSpacing: 1 }, children: "uSketch Vim \u2014 Help" }), _jsx("span", { style: { opacity: 0.6 }, children: "Esc \u307E\u305F\u306F :help \u3067\u9589\u3058\u308B" })] }), _jsx("div", { style: {
93
+ display: "grid",
94
+ gridTemplateColumns: "repeat(auto-fit, minmax(360px, 1fr))",
95
+ gap: 4,
96
+ padding: "12px 8px 18px",
97
+ }, children: SECTIONS.map((section) => (_jsxs("div", { style: { padding: "8px 12px" }, children: [_jsx("div", { style: {
98
+ color: "#f9e2af",
99
+ opacity: 0.9,
100
+ letterSpacing: 1,
101
+ margin: "4px 0 8px",
102
+ }, children: section.title }), section.rows.map(([keys, desc]) => (_jsxs("div", { style: { display: "flex", gap: 12, padding: "2px 0" }, children: [_jsx("span", { style: { color: "#a6e3a1", minWidth: 150, whiteSpace: "nowrap" }, children: keys }), _jsx("span", { style: { opacity: 0.85 }, children: desc })] }, keys)))] }, section.title))) })] }) }));
103
+ }
104
+ //# sourceMappingURL=help-overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-overlay.js","sourceRoot":"","sources":["../../src/ui/help-overlay.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Viewport } from "@edv4h/usketch-shared";
2
+ import type { VimUiStore } from "./vim-ui-store.js";
3
+ interface Props {
4
+ store: VimUiStore;
5
+ viewport: Viewport;
6
+ }
7
+ /**
8
+ * キャンバス上のオーバーレイ(fixed レイヤー)。
9
+ * 論理カーソルの十字、insert モードのゴースト shape、候補ポップアップを描画する。
10
+ * world 座標 → screen 座標は viewport から手計算する(キャンバスエンジン非依存)。
11
+ */
12
+ export declare function VimOverlay({ store, viewport }: Props): import("react/jsx-runtime").JSX.Element | null;
13
+ export {};
14
+ //# sourceMappingURL=overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/ui/overlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,UAAU,KAAK;IACd,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,kDAiJpD"}
@@ -0,0 +1,97 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useSyncExternalStore } from "react";
3
+ /**
4
+ * キャンバス上のオーバーレイ(fixed レイヤー)。
5
+ * 論理カーソルの十字、insert モードのゴースト shape、候補ポップアップを描画する。
6
+ * world 座標 → screen 座標は viewport から手計算する(キャンバスエンジン非依存)。
7
+ */
8
+ export function VimOverlay({ store, viewport }) {
9
+ const s = useSyncExternalStore(store.subscribe, store.getSnapshot);
10
+ if (!s.active)
11
+ return null;
12
+ const sx = s.cursor.x * viewport.zoom + viewport.x;
13
+ const sy = s.cursor.y * viewport.zoom + viewport.y;
14
+ const showGhost = s.mode === "insert" && s.ghost !== null;
15
+ return (_jsxs("div", { style: { position: "absolute", inset: 0, pointerEvents: "none", overflow: "hidden" }, children: [s.mode === "hop" &&
16
+ s.hopTargets.map((t) => {
17
+ const tx = t.cx * viewport.zoom + viewport.x;
18
+ const ty = t.cy * viewport.zoom + viewport.y;
19
+ const rest = t.matched ? t.label.slice(s.hopBuffer.length) : t.label;
20
+ return (_jsxs("div", { style: {
21
+ position: "absolute",
22
+ left: tx,
23
+ top: ty,
24
+ transform: "translate(-50%, -50%)",
25
+ font: "700 13px ui-monospace, monospace",
26
+ padding: "1px 5px",
27
+ borderRadius: 4,
28
+ background: t.matched ? "#f9e2af" : "#45475a",
29
+ color: t.matched ? "#11111b" : "#7f849c",
30
+ opacity: t.matched ? 1 : 0.5,
31
+ boxShadow: "0 1px 4px rgba(0,0,0,0.4)",
32
+ }, children: [s.hopBuffer && t.matched && _jsx("span", { style: { opacity: 0.45 }, children: s.hopBuffer }), rest] }, t.label));
33
+ }), _jsx("div", { style: {
34
+ position: "absolute",
35
+ left: sx - 8,
36
+ top: sy - 1,
37
+ width: 16,
38
+ height: 2,
39
+ background: "#7c3aed",
40
+ opacity: 0.9,
41
+ } }), _jsx("div", { style: {
42
+ position: "absolute",
43
+ left: sx - 1,
44
+ top: sy - 8,
45
+ width: 2,
46
+ height: 16,
47
+ background: "#7c3aed",
48
+ opacity: 0.9,
49
+ } }), _jsx("div", { style: {
50
+ position: "absolute",
51
+ left: sx - 5,
52
+ top: sy - 5,
53
+ width: 10,
54
+ height: 10,
55
+ border: "1.5px solid #7c3aed",
56
+ borderRadius: 2,
57
+ boxShadow: "0 0 0 1px rgba(255,255,255,0.6)",
58
+ } }), showGhost && s.ghost && (_jsxs(_Fragment, { children: [_jsx("div", { style: {
59
+ position: "absolute",
60
+ left: sx,
61
+ top: sy,
62
+ width: s.ghost.width * viewport.zoom,
63
+ height: s.ghost.height * viewport.zoom,
64
+ border: "2px dashed #7c3aed",
65
+ background: "rgba(124,58,237,0.08)",
66
+ borderRadius: 4,
67
+ } }), _jsx("div", { style: {
68
+ position: "absolute",
69
+ left: sx,
70
+ top: sy - 20,
71
+ font: "12px ui-monospace, monospace",
72
+ color: "#7c3aed",
73
+ background: "rgba(255,255,255,0.85)",
74
+ padding: "1px 6px",
75
+ borderRadius: 4,
76
+ whiteSpace: "nowrap",
77
+ }, children: s.ghost.label })] })), s.mode === "insert" && s.candidates.length > 0 && (_jsx("div", { style: {
78
+ position: "absolute",
79
+ left: sx,
80
+ top: sy + (showGhost && s.ghost ? s.ghost.height * viewport.zoom + 8 : 20),
81
+ minWidth: 160,
82
+ maxHeight: 200,
83
+ overflow: "hidden",
84
+ background: "#1e1e2e",
85
+ color: "#e5e7eb",
86
+ borderRadius: 6,
87
+ boxShadow: "0 4px 16px rgba(0,0,0,0.35)",
88
+ font: "12px ui-monospace, monospace",
89
+ }, children: s.candidates.slice(0, 8).map((c, i) => (_jsxs("div", { style: {
90
+ display: "flex",
91
+ justifyContent: "space-between",
92
+ gap: 12,
93
+ padding: "4px 10px",
94
+ background: i === s.candidateIndex ? "#7c3aed" : "transparent",
95
+ }, children: [_jsx("span", { children: c.alias }), _jsx("span", { style: { opacity: 0.6 }, children: c.label })] }, c.alias))) }))] }));
96
+ }
97
+ //# sourceMappingURL=overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/ui/overlay.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { VimUiStore } from "./vim-ui-store.js";
2
+ /** 画面下部の Vim ステータスライン(fixed レイヤー)。 */
3
+ export declare function VimStatusLine({ store }: {
4
+ store: VimUiStore;
5
+ }): import("react/jsx-runtime").JSX.Element | null;
6
+ //# sourceMappingURL=status-line.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-line.d.ts","sourceRoot":"","sources":["../../src/ui/status-line.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAepD,sCAAsC;AACtC,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,kDA2D7D"}
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useSyncExternalStore } from "react";
3
+ const MODE_COLOR = {
4
+ normal: "#3b82f6",
5
+ insert: "#10b981",
6
+ visual: "#f59e0b",
7
+ command: "#6366f1",
8
+ hop: "#f9e2af",
9
+ };
10
+ function modeLabel(mode, visualMulti) {
11
+ if (mode === "visual")
12
+ return visualMulti ? "V-BLOCK" : "VISUAL";
13
+ return mode.toUpperCase();
14
+ }
15
+ /** 画面下部の Vim ステータスライン(fixed レイヤー)。 */
16
+ export function VimStatusLine({ store }) {
17
+ const s = useSyncExternalStore(store.subscribe, store.getSnapshot);
18
+ if (!s.active)
19
+ return null;
20
+ return (_jsxs("div", { "data-testid": "vim-status-line", style: {
21
+ position: "absolute",
22
+ left: 0,
23
+ right: 0,
24
+ bottom: 0,
25
+ height: 26,
26
+ display: "flex",
27
+ alignItems: "center",
28
+ gap: 12,
29
+ padding: "0 10px",
30
+ background: "#11111b",
31
+ color: "#cdd6f4",
32
+ font: "12px ui-monospace, SFMono-Regular, Menlo, monospace",
33
+ borderTop: "1px solid #313244",
34
+ pointerEvents: "none",
35
+ userSelect: "none",
36
+ }, children: [_jsx("span", { style: {
37
+ background: MODE_COLOR[s.mode],
38
+ color: "#0b0b12",
39
+ fontWeight: 700,
40
+ padding: "2px 8px",
41
+ borderRadius: 3,
42
+ }, children: modeLabel(s.mode, s.visualMulti) }), s.mode === "command" ? (_jsxs("span", { style: { flex: 1 }, children: [":", s.commandBuffer, _jsx("span", { style: { opacity: 0.6 }, children: "\u258F" })] })) : s.mode === "hop" ? (_jsxs("span", { style: { flex: 1, opacity: 0.85 }, children: ["hop \u2192 ", s.hopBuffer || "ラベルを入力", "\uFF08", s.hopTargets.length, " \u500B\uFF09"] })) : (_jsx("span", { style: { flex: 1, opacity: 0.85 }, children: s.mode === "insert" && s.inputBuffer ? `⟶ ${s.inputBuffer}` : (s.lastMessage ?? "") })), _jsx("span", { style: { opacity: 0.6 }, children: `@ ${Math.round(s.cursor.x)},${Math.round(s.cursor.y)}` }), s.registerCount > 0 && _jsx("span", { style: { opacity: 0.6 }, children: `"${s.registerCount}` }), s.count != null && _jsx("span", { style: { opacity: 0.9 }, children: s.count })] }));
43
+ }
44
+ //# sourceMappingURL=status-line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-line.js","sourceRoot":"","sources":["../../src/ui/status-line.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { Point } from "@edv4h/usketch-shared";
2
+ import type { VimMode } from "../machine/types.js";
3
+ /** UI レイヤーが描画に必要とする machine 状態のフラットなスナップショット。 */
4
+ export interface VimSnapshot {
5
+ /** vim ツールがアクティブか(非アクティブなら全 UI を隠す)。 */
6
+ active: boolean;
7
+ mode: VimMode;
8
+ visualMulti: boolean;
9
+ cursor: Point;
10
+ count: number | null;
11
+ inputBuffer: string;
12
+ candidates: {
13
+ alias: string;
14
+ label: string;
15
+ }[];
16
+ candidateIndex: number;
17
+ /** 選択中候補のゴースト寸法(insert のプレビュー用)。 */
18
+ ghost: {
19
+ width: number;
20
+ height: number;
21
+ label: string;
22
+ } | null;
23
+ commandBuffer: string;
24
+ whichKeyVisible: boolean;
25
+ helpVisible: boolean;
26
+ /** hop ラベル(world 座標 + 現在の入力にマッチするか)。 */
27
+ hopTargets: {
28
+ label: string;
29
+ cx: number;
30
+ cy: number;
31
+ matched: boolean;
32
+ }[];
33
+ /** hop で入力済みのラベル文字。 */
34
+ hopBuffer: string;
35
+ lastMessage: string | null;
36
+ registerCount: number;
37
+ }
38
+ export declare const INITIAL_SNAPSHOT: VimSnapshot;
39
+ export interface VimUiStore {
40
+ getSnapshot(): VimSnapshot;
41
+ subscribe(listener: () => void): () => void;
42
+ set(snapshot: VimSnapshot): void;
43
+ }
44
+ /** useSyncExternalStore 互換の最小外部ストア。 */
45
+ export declare function createVimUiStore(): VimUiStore;
46
+ //# sourceMappingURL=vim-ui-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vim-ui-store.d.ts","sourceRoot":"","sources":["../../src/ui/vim-ui-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,iDAAiD;AACjD,MAAM,WAAW,WAAW;IAC3B,wCAAwC;IACxC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,wCAAwC;IACxC,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAC1E,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,WAiB9B,CAAC;AAEF,MAAM,WAAW,UAAU;IAC1B,WAAW,IAAI,WAAW,CAAC;IAC3B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5C,GAAG,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;CACjC;AAED,uCAAuC;AACvC,wBAAgB,gBAAgB,IAAI,UAAU,CAc7C"}
@@ -0,0 +1,36 @@
1
+ export const INITIAL_SNAPSHOT = {
2
+ active: false,
3
+ mode: "normal",
4
+ visualMulti: false,
5
+ cursor: { x: 0, y: 0 },
6
+ count: null,
7
+ inputBuffer: "",
8
+ candidates: [],
9
+ candidateIndex: 0,
10
+ ghost: null,
11
+ commandBuffer: "",
12
+ whichKeyVisible: false,
13
+ helpVisible: false,
14
+ hopTargets: [],
15
+ hopBuffer: "",
16
+ lastMessage: null,
17
+ registerCount: 0,
18
+ };
19
+ /** useSyncExternalStore 互換の最小外部ストア。 */
20
+ export function createVimUiStore() {
21
+ let snapshot = INITIAL_SNAPSHOT;
22
+ const listeners = new Set();
23
+ return {
24
+ getSnapshot: () => snapshot,
25
+ subscribe(listener) {
26
+ listeners.add(listener);
27
+ return () => listeners.delete(listener);
28
+ },
29
+ set(next) {
30
+ snapshot = next;
31
+ for (const l of listeners)
32
+ l();
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=vim-ui-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vim-ui-store.js","sourceRoot":"","sources":["../../src/ui/vim-ui-store.ts"],"names":[],"mappings":"AA2BA,MAAM,CAAC,MAAM,gBAAgB,GAAgB;IAC5C,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,KAAK;IAClB,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IACtB,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,EAAE;IACf,UAAU,EAAE,EAAE;IACd,cAAc,EAAE,CAAC;IACjB,KAAK,EAAE,IAAI;IACX,aAAa,EAAE,EAAE;IACjB,eAAe,EAAE,KAAK;IACtB,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,EAAE;IACd,SAAS,EAAE,EAAE;IACb,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,CAAC;CAChB,CAAC;AAQF,uCAAuC;AACvC,MAAM,UAAU,gBAAgB;IAC/B,IAAI,QAAQ,GAAG,gBAAgB,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;IACxC,OAAO;QACN,WAAW,EAAE,GAAG,EAAE,CAAC,QAAQ;QAC3B,SAAS,CAAC,QAAQ;YACjB,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QACD,GAAG,CAAC,IAAI;YACP,QAAQ,GAAG,IAAI,CAAC;YAChB,KAAK,MAAM,CAAC,IAAI,SAAS;gBAAE,CAAC,EAAE,CAAC;QAChC,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { VimUiStore } from "./vim-ui-store.js";
2
+ /** 現在モードの利用可能キー一覧(fixed レイヤー、`?` でトグル)。 */
3
+ export declare function VimWhichKey({ store }: {
4
+ store: VimUiStore;
5
+ }): import("react/jsx-runtime").JSX.Element | null;
6
+ //# sourceMappingURL=which-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"which-key.d.ts","sourceRoot":"","sources":["../../src/ui/which-key.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA4CpD,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,kDAyC3D"}
@@ -0,0 +1,71 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useSyncExternalStore } from "react";
3
+ const HINTS = {
4
+ normal: [
5
+ ["h j k l", "カーソル移動"],
6
+ ["H J K L", "画角を移動 (pan)"],
7
+ ["0-9", "回数 (例 5j)"],
8
+ ["i", "insert モード"],
9
+ ["v / V", "visual / 複数選択"],
10
+ [":", "コマンド"],
11
+ ["x / d", "削除 y / p ヤンク/貼付"],
12
+ ["u / C-r", "undo / redo"],
13
+ ["+ / -", "ズーム zz ビューを寄せる"],
14
+ ["M", "カーソルを画面中央へ"],
15
+ ["f", "hop(ラベルジャンプ)"],
16
+ ["gg / G", "最初 / 最後の shape"],
17
+ ["m{a-z} / `{a-z}", "マーク設定 / ジャンプ"],
18
+ ["?", "このヘルプを閉じる"],
19
+ ],
20
+ insert: [
21
+ ["a-z…", "shape 名を入力"],
22
+ ["Tab", "候補を切替"],
23
+ ["Enter", "カーソル位置に追加"],
24
+ ["Esc", "normal へ戻る"],
25
+ ],
26
+ visual: [
27
+ ["h j k l", "最近傍の shape へ選択を移動"],
28
+ ["V", "複数選択モード"],
29
+ ["d / x", "削除 y ヤンク"],
30
+ ["Esc", "選択解除して normal へ"],
31
+ ],
32
+ hop: [
33
+ ["ラベル文字", "その shape へカーソルをジャンプ"],
34
+ ["Esc", "キャンセル"],
35
+ ],
36
+ command: [
37
+ [":q", "Vim を抜ける"],
38
+ [":tool <id>", "ツール切替"],
39
+ [":set bg=dots|grid|none", "背景"],
40
+ [":zoom <n>", "ズーム :export <fmt> 書き出し"],
41
+ [":help", "ヘルプ"],
42
+ ],
43
+ };
44
+ /** 現在モードの利用可能キー一覧(fixed レイヤー、`?` でトグル)。 */
45
+ export function VimWhichKey({ store }) {
46
+ const s = useSyncExternalStore(store.subscribe, store.getSnapshot);
47
+ if (!s.active || !s.whichKeyVisible)
48
+ return null;
49
+ const hints = HINTS[s.mode];
50
+ return (_jsxs("div", { style: {
51
+ position: "absolute",
52
+ right: 12,
53
+ bottom: 38,
54
+ width: 320,
55
+ background: "#181825",
56
+ color: "#cdd6f4",
57
+ borderRadius: 8,
58
+ border: "1px solid #313244",
59
+ boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
60
+ font: "12px ui-monospace, monospace",
61
+ padding: "8px 0",
62
+ pointerEvents: "none",
63
+ userSelect: "none",
64
+ }, children: [_jsxs("div", { style: {
65
+ padding: "2px 12px 6px",
66
+ opacity: 0.6,
67
+ textTransform: "uppercase",
68
+ letterSpacing: 1,
69
+ }, children: [s.mode, " keys"] }), hints.map(([keys, desc]) => (_jsxs("div", { style: { display: "flex", gap: 10, padding: "3px 12px" }, children: [_jsx("span", { style: { color: "#a6e3a1", minWidth: 110, whiteSpace: "nowrap" }, children: keys }), _jsx("span", { style: { opacity: 0.85 }, children: desc })] }, keys)))] }));
70
+ }
71
+ //# sourceMappingURL=which-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"which-key.js","sourceRoot":"","sources":["../../src/ui/which-key.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { BoardStore, Point } from "@edv4h/usketch-shared";
2
+ /** ビューポート(キャンバス)のサイズ。テスト等で window が無い場合は既定値。 */
3
+ export declare function getScreenSize(): {
4
+ width: number;
5
+ height: number;
6
+ };
7
+ /** 画面中央に対応する world 座標。 */
8
+ export declare function screenCenterWorld(store: BoardStore): Point;
9
+ /** world 座標 `target` が画面中央に来るようビューポートを移動する。 */
10
+ export declare function centerViewportOn(store: BoardStore, target: Point): void;
11
+ //# sourceMappingURL=viewport-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-utils.d.ts","sourceRoot":"","sources":["../src/viewport-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE/D,gDAAgD;AAChD,wBAAgB,aAAa,IAAI;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAGjE;AAED,0BAA0B;AAC1B,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK,CAO1D;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,GAAG,IAAI,CAQvE"}
@@ -0,0 +1,26 @@
1
+ /** ビューポート(キャンバス)のサイズ。テスト等で window が無い場合は既定値。 */
2
+ export function getScreenSize() {
3
+ if (typeof window === "undefined")
4
+ return { width: 1280, height: 720 };
5
+ return { width: window.innerWidth, height: window.innerHeight };
6
+ }
7
+ /** 画面中央に対応する world 座標。 */
8
+ export function screenCenterWorld(store) {
9
+ const { width, height } = getScreenSize();
10
+ const vp = store.getViewport();
11
+ return {
12
+ x: (width / 2 - vp.x) / vp.zoom,
13
+ y: (height / 2 - vp.y) / vp.zoom,
14
+ };
15
+ }
16
+ /** world 座標 `target` が画面中央に来るようビューポートを移動する。 */
17
+ export function centerViewportOn(store, target) {
18
+ const { width, height } = getScreenSize();
19
+ const vp = store.getViewport();
20
+ store.setViewport({
21
+ x: width / 2 - target.x * vp.zoom,
22
+ y: height / 2 - target.y * vp.zoom,
23
+ zoom: vp.zoom,
24
+ });
25
+ }
26
+ //# sourceMappingURL=viewport-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-utils.js","sourceRoot":"","sources":["../src/viewport-utils.ts"],"names":[],"mappings":"AAEA,gDAAgD;AAChD,MAAM,UAAU,aAAa;IAC5B,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;AACjE,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,iBAAiB,CAAC,KAAiB;IAClD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAC/B,OAAO;QACN,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI;QAC/B,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI;KAChC,CAAC;AACH,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,gBAAgB,CAAC,KAAiB,EAAE,MAAa;IAChE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAC/B,KAAK,CAAC,WAAW,CAAC;QACjB,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI;QACjC,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI;QAClC,IAAI,EAAE,EAAE,CAAC,IAAI;KACb,CAAC,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@edv4h/usketch-plugin-tool-vim",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.ts",
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "xstate": "^5.18.0",
16
+ "zod": "^4.0.0",
17
+ "@edv4h/usketch-core": "2.0.2",
18
+ "@edv4h/usketch-shared": "4.1.0",
19
+ "@edv4h/usketch-store": "3.0.1",
20
+ "@edv4h/usketch-tool-helpers": "0.3.1"
21
+ },
22
+ "peerDependencies": {
23
+ "react": ">=19"
24
+ },
25
+ "devDependencies": {
26
+ "@types/react": "19.2.14",
27
+ "typescript": "5.9.3",
28
+ "vitest": "3.2.4"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "README.md"
36
+ ],
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/EdV4H/usketch.git",
41
+ "directory": "plugins/usketch-plugin-tool-vim"
42
+ },
43
+ "homepage": "https://github.com/EdV4H/usketch#readme",
44
+ "bugs": {
45
+ "url": "https://github.com/EdV4H/usketch/issues"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc -p tsconfig.json",
49
+ "typecheck": "tsc --noEmit",
50
+ "test": "vitest run --passWithNoTests",
51
+ "clean": "rm -rf dist"
52
+ }
53
+ }