blots-editor 0.0.14 → 0.0.16

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 (43) hide show
  1. package/asset/language/en.json +4 -0
  2. package/asset/language/zh.json +4 -0
  3. package/dist/core/document/document.d.ts +41 -2
  4. package/dist/core/document/document.js +113 -36
  5. package/dist/core/{file-tree-model.d.ts → io/file-tree-model.d.ts} +12 -3
  6. package/dist/core/{file-tree-model.js → io/file-tree-model.js} +23 -12
  7. package/dist/core/{session.d.ts → io/session.d.ts} +1 -1
  8. package/dist/core/{session.js → io/session.js} +1 -1
  9. package/dist/index.js +4 -4
  10. package/dist/{view → utils/view}/click-mapping.d.ts +1 -1
  11. package/dist/{view → utils/view}/frame-clamp.d.ts +4 -0
  12. package/dist/{view → utils/view}/frame-clamp.js +8 -0
  13. package/dist/{i18n-resources.js → utils/view/i18n-resources.js} +1 -1
  14. package/dist/view/{command-bar.d.ts → editor/command-bar.d.ts} +1 -1
  15. package/dist/view/{editor-setting.js → editor/editor-setting.js} +2 -2
  16. package/dist/view/{file-tree.d.ts → editor/file-tree.d.ts} +5 -1
  17. package/dist/view/{file-tree.js → editor/file-tree.js} +46 -28
  18. package/dist/view/{information-bar.d.ts → editor/information-bar.d.ts} +1 -1
  19. package/dist/view/editor/tool-bar.d.ts +36 -0
  20. package/dist/view/editor/tool-bar.js +134 -0
  21. package/dist/view/{toolbar-store.d.ts → event/subscription/toolbar-store.d.ts} +5 -6
  22. package/dist/view/event/subscription/tree-store.d.ts +10 -0
  23. package/dist/view/{tree-width-store.js → event/subscription/tree-store.js} +9 -12
  24. package/dist/view/{editor.js → page/editor.js} +12 -12
  25. package/dist/view/{main-menu.js → page/main-menu.js} +1 -1
  26. package/dist/view/{settings.js → page/settings.js} +3 -3
  27. package/dist/view/{modal-frame.js → utils/modal-frame.js} +1 -1
  28. package/package.json +1 -1
  29. package/dist/view/tool-bar.d.ts +0 -62
  30. package/dist/view/tool-bar.js +0 -148
  31. package/dist/view/tree-width-store.d.ts +0 -6
  32. /package/dist/{view → utils/view}/click-mapping.js +0 -0
  33. /package/dist/{i18n-resources.d.ts → utils/view/i18n-resources.d.ts} +0 -0
  34. /package/dist/view/{command-bar.js → editor/command-bar.js} +0 -0
  35. /package/dist/view/{editor-setting.d.ts → editor/editor-setting.d.ts} +0 -0
  36. /package/dist/view/{information-bar.js → editor/information-bar.js} +0 -0
  37. /package/dist/view/{toolbar-store.js → event/subscription/toolbar-store.js} +0 -0
  38. /package/dist/view/{editor.d.ts → page/editor.d.ts} +0 -0
  39. /package/dist/view/{main-menu.d.ts → page/main-menu.d.ts} +0 -0
  40. /package/dist/view/{settings.d.ts → page/settings.d.ts} +0 -0
  41. /package/dist/view/{modal-frame.d.ts → utils/modal-frame.d.ts} +0 -0
  42. /package/dist/view/{sensitivity-bar.d.ts → utils/sensitivity-bar.d.ts} +0 -0
  43. /package/dist/view/{sensitivity-bar.js → utils/sensitivity-bar.js} +0 -0
@@ -1,148 +0,0 @@
1
- import { Box, Text, measureElement, useWindowSize } from "ink";
2
- import { useI18n, useKeyboard, useMouseRegion } from "ink-cartridge";
3
- import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
- import { clampFrame } from "./frame-clamp.js";
5
- import { getBarPosition, setBarPosition, useBarPosition } from "./toolbar-store.js";
6
- import { useTreeWidth } from "./tree-width-store.js";
7
- /**
8
- * Clamp the bar's top-left: inside the terminal, below the information bar,
9
- * and — while the file tree is open — left of the tree pane.
10
- */
11
- function clampBarPos(left, top, width, height, columns, rows, fileTreeOpen, treeWidth) {
12
- const clamped = clampFrame(left, top, columns, rows, width, height);
13
- const maxLeft = fileTreeOpen ? columns - treeWidth - width : columns - width;
14
- return {
15
- left: Math.min(Math.max(0, clamped.left), Math.max(0, maxLeft)),
16
- top: Math.max(1, clamped.top),
17
- };
18
- }
19
- function ToolButton({ priority, onClick, text, focused = false, onDragStart, onDragMove, onDragEnd, dragging = false, }) {
20
- const [hover, setHover] = useState(false);
21
- const ref = useMouseRegion({
22
- onClick: (event) => onClick(event),
23
- onEnter: () => setHover(true),
24
- onLeave: () => setHover(false),
25
- onDragStart,
26
- onDragMove,
27
- onDragEnd,
28
- }, { priority });
29
- // Dragging outranks everything (the bar is moving), then keyboard focus,
30
- // then the transient hover tint.
31
- const borderColor = dragging ? "red" : focused ? "blue" : hover ? "green" : "white";
32
- return (React.createElement(Box, { ref: ref, borderColor: borderColor, borderStyle: "bold",
33
- // Match the editor's surface so the floating bar reads as part of it.
34
- backgroundColor: "#1e1e1e", height: "100%", justifyContent: "center", alignItems: "center", borderBackgroundColor: "#1e1e1e", paddingLeft: 2, paddingRight: 2 },
35
- React.createElement(Text, null, text)));
36
- }
37
- /**
38
- * Floating toolbar, bottom-center of the terminal until the user drags it.
39
- * Dragging switches it to absolute positioning and clamps it inside the
40
- * terminal view (clampFrame, top ≥ 1 to preserve the information bar).
41
- * Purely presentational for now: one centered button with hover/focus states.
42
- * The editor owns the layer that hosts this bar (and the ctrl+tab toggle);
43
- * this component only adds the normal-mode keyboard navigation
44
- * (ctrl+left/ctrl+right move the focus ring, enter selects). The activator
45
- * is bare Enter, not ctrl+enter: terminals send the same byte (`\r`) for
46
- * both, so a ctrl-modified Enter can never reach the engine. Insert mode
47
- * stays mouse-only because these bindings are mode-restricted and never
48
- * fire there.
49
- */
50
- export function ToolBar({ mode = null, tools, session = null, onToggleFileTree, onOpenSettings, fileTreeOpen = false, }) {
51
- const { rows, columns } = useWindowSize();
52
- const { t } = useI18n();
53
- const { boundKeyboard } = useKeyboard();
54
- const [activeIndex, setActiveIndex] = useState(0);
55
- // The default tools need live context, so they are built per instance
56
- // instead of at module level; `tools` stays the extension point.
57
- const defaultTools = useMemo(() => [
58
- {
59
- id: "save",
60
- labelKey: "toolbar.save",
61
- onClick: () => {
62
- session?.save();
63
- },
64
- },
65
- {
66
- id: "file-tree",
67
- labelKey: "toolbar.fileTree",
68
- onClick: onToggleFileTree ?? (() => { }),
69
- },
70
- {
71
- id: "settings",
72
- labelKey: "toolbar.settings",
73
- onClick: onOpenSettings ?? (() => { }),
74
- },
75
- ], [session, onToggleFileTree, onOpenSettings]);
76
- const activeTools = tools ?? defaultTools;
77
- // null = bar sits at the bottom-center via flex layout; once the user
78
- // grabs it, absolute positioning takes over so it follows the cursor.
79
- // Position lives in a module store so erase/re-apply remounts (prop
80
- // updates) do not reset a dragged bar back to the bottom.
81
- const pos = useBarPosition();
82
- // Live pane width, so the drag clamp follows the tree's adaptive size.
83
- const treeWidth = useTreeWidth();
84
- const [dragging, setDragging] = useState(false);
85
- const barRef = useRef(null);
86
- // Grab offset (where inside the bar the cursor went down) plus the bar's
87
- // size at grab time, kept in a ref so drag moves need no re-measurement.
88
- const grabRef = useRef({ dx: 0, dy: 0, width: 0, height: 0 });
89
- const startDrag = useCallback((event) => {
90
- const node = barRef.current;
91
- if (!node) {
92
- return;
93
- }
94
- // Measure the bar itself, not the hit region — a button may be the
95
- // captured target, and its rect would put the bar's corner at the
96
- // button's corner.
97
- const m = measureElement(node);
98
- grabRef.current = {
99
- dx: event.x - m.x - 1,
100
- dy: event.y - m.y - 1,
101
- width: m.width,
102
- height: m.height,
103
- };
104
- // Switch from flex centering to absolute positioning at the current
105
- // rect — seamless, no jump on the first frame.
106
- setBarPosition({ top: m.y, left: m.x });
107
- setDragging(true);
108
- }, []);
109
- const moveDrag = useCallback((event) => {
110
- const { dx, dy, width, height } = grabRef.current;
111
- setBarPosition(clampBarPos(event.x - dx - 1, event.y - dy - 1, width, height, columns, rows, fileTreeOpen, treeWidth));
112
- }, [columns, rows, fileTreeOpen, treeWidth]);
113
- const endDrag = useCallback(() => setDragging(false), []);
114
- // The drag clamp only runs while dragging — a terminal resize can shrink
115
- // the viewport under an absolutely-positioned bar afterwards (and opening
116
- // the file tree can shrink the free area). Re-clamp whenever any of the
117
- // layout inputs change so the bar never extends past its allowed region.
118
- useEffect(() => {
119
- const node = barRef.current;
120
- if (!node) {
121
- return;
122
- }
123
- // Read the latest position imperatively — no `pos` dependency, so this
124
- // effect only runs when a layout input actually changes.
125
- const m = measureElement(node);
126
- const current = getBarPosition();
127
- if (!current) {
128
- return;
129
- }
130
- const next = clampBarPos(current.left, current.top, m.width, m.height, columns, rows, fileTreeOpen, treeWidth);
131
- if (next.left !== current.left || next.top !== current.top) {
132
- setBarPosition(next);
133
- }
134
- }, [columns, rows, fileTreeOpen, treeWidth]);
135
- const showFocus = mode === "normal";
136
- useEffect(() => {
137
- const unbinds = [
138
- boundKeyboard(["ctrl+left"], () => setActiveIndex((i) => (i - 1 + activeTools.length) % activeTools.length), { mode: "normal" }),
139
- boundKeyboard(["ctrl+right"], () => setActiveIndex((i) => (i + 1) % activeTools.length), { mode: "normal" }),
140
- boundKeyboard(["return"], () => activeTools[activeIndex]?.onClick(), {
141
- mode: "normal",
142
- }),
143
- ];
144
- return () => unbinds.forEach((fn) => fn());
145
- }, [boundKeyboard, activeTools, activeIndex]);
146
- return (React.createElement(Box, { width: "100%", height: "100%", justifyContent: "center", alignItems: "flex-end" },
147
- React.createElement(Box, { ref: barRef, position: pos ? "absolute" : undefined, top: pos?.top, left: pos?.left, height: 3, flexDirection: "row", justifyContent: "center", alignItems: "center" }, activeTools.map((tool, index) => (React.createElement(ToolButton, { key: tool.id, text: t(tool.labelKey), priority: 1, focused: showFocus && index === activeIndex, onClick: tool.onClick, dragging: dragging, onDragStart: startDrag, onDragMove: moveDrag, onDragEnd: endDrag }))))));
148
- }
@@ -1,6 +0,0 @@
1
- /** Imperative read for drag handlers. */
2
- export declare function getTreeWidth(): number;
3
- /** Update the reported pane width (no-op when unchanged). */
4
- export declare function setTreeWidth(next: number): void;
5
- /** Reactive binding: re-renders whenever the pane width changes. */
6
- export declare function useTreeWidth(): number;
File without changes
File without changes
File without changes