@cel-tui/core 0.2.0 → 0.3.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/package.json +2 -2
- package/src/cel.ts +25 -10
- package/src/keys.ts +1 -0
- package/src/primitives/text-input.ts +8 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cel-tui/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Core framework engine for cel-tui — primitives, layout, rendering, input",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"layout"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@cel-tui/types": "0.
|
|
37
|
+
"@cel-tui/types": "0.3.0",
|
|
38
38
|
"get-east-asian-width": "^1.5.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
package/src/cel.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
collectKeyPressHandlers,
|
|
9
9
|
collectFocusable,
|
|
10
10
|
} from "./hit-test.js";
|
|
11
|
-
import { parseKey, isEditingKey
|
|
11
|
+
import { parseKey, isEditingKey } from "./keys.js";
|
|
12
12
|
import { layout, type LayoutNode } from "./layout.js";
|
|
13
13
|
import {
|
|
14
14
|
paint,
|
|
@@ -555,11 +555,15 @@ function handleMouseEvent(event: MouseEvent): void {
|
|
|
555
555
|
if (props.onScroll) {
|
|
556
556
|
// Controlled scroll: notify app.
|
|
557
557
|
// Use batch accumulator if available (multiple events in one chunk),
|
|
558
|
-
// otherwise read from props.
|
|
559
|
-
|
|
558
|
+
// otherwise read from props. Clamp to maxOffset first so that
|
|
559
|
+
// Infinity (sticky-bottom) resolves to a finite value before
|
|
560
|
+
// applying the delta — otherwise Infinity + (-1) = Infinity
|
|
561
|
+
// and scrolling up never unsticks.
|
|
562
|
+
const rawBase =
|
|
560
563
|
batchScrollOffsets?.get(props) ??
|
|
561
564
|
(props as any).scrollOffset ??
|
|
562
565
|
0;
|
|
566
|
+
const baseOffset = Math.min(rawBase, maxOffset);
|
|
563
567
|
const newOffset = Math.max(
|
|
564
568
|
0,
|
|
565
569
|
Math.min(maxOffset, baseOffset + delta),
|
|
@@ -685,12 +689,13 @@ function handleKeyEvent(key: string, rawData?: string): void {
|
|
|
685
689
|
const props = focusedInput.node
|
|
686
690
|
.props as import("@cel-tui/types").TextInputProps;
|
|
687
691
|
|
|
688
|
-
//
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
692
|
+
// onKeyPress fires before editing — return false prevents the default action
|
|
693
|
+
if (props.onKeyPress) {
|
|
694
|
+
const result = props.onKeyPress(key);
|
|
695
|
+
if (result === false) {
|
|
696
|
+
cel.render();
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
694
699
|
}
|
|
695
700
|
|
|
696
701
|
// Editing keys are consumed by TextInput
|
|
@@ -728,6 +733,7 @@ function handleKeyEvent(key: string, rawData?: string): void {
|
|
|
728
733
|
}
|
|
729
734
|
break;
|
|
730
735
|
case "enter":
|
|
736
|
+
case "shift+enter":
|
|
731
737
|
newState = insertChar(editState, "\n");
|
|
732
738
|
break;
|
|
733
739
|
case "tab":
|
|
@@ -766,7 +772,16 @@ function handleKeyEvent(key: string, rawData?: string): void {
|
|
|
766
772
|
for (let i = currentLayouts.length - 1; i >= 0; i--) {
|
|
767
773
|
const path = findPathTo(currentLayouts[i]!, focused);
|
|
768
774
|
if (path) {
|
|
769
|
-
|
|
775
|
+
let handlers = collectKeyPressHandlers(path);
|
|
776
|
+
// If a TextInput's onKeyPress was already called in the pre-editing
|
|
777
|
+
// hook above, exclude it from bubbling to avoid calling it twice.
|
|
778
|
+
if (
|
|
779
|
+
focusedInput &&
|
|
780
|
+
handlers.length > 0 &&
|
|
781
|
+
handlers[0]!.layoutNode === focusedInput
|
|
782
|
+
) {
|
|
783
|
+
handlers = handlers.slice(1);
|
|
784
|
+
}
|
|
770
785
|
if (handlers.length > 0) {
|
|
771
786
|
let consumed = false;
|
|
772
787
|
for (const h of handlers) {
|
package/src/keys.ts
CHANGED
|
@@ -12,9 +12,12 @@ import type { TextInputNode, TextInputProps } from "@cel-tui/types";
|
|
|
12
12
|
* responds to mouse wheel automatically.
|
|
13
13
|
*
|
|
14
14
|
* TextInput is always focusable. When focused, text-editing keys
|
|
15
|
-
* (printable characters, arrows, backspace, Tab) are consumed.
|
|
15
|
+
* (printable characters, arrows, backspace, Enter, Tab) are consumed.
|
|
16
16
|
* Modifier combos (e.g., `ctrl+s`) bubble up to ancestor `onKeyPress` handlers.
|
|
17
17
|
*
|
|
18
|
+
* Use `onKeyPress` to intercept keys before editing. Return `false` to
|
|
19
|
+
* prevent the default editing action for that key.
|
|
20
|
+
*
|
|
18
21
|
* @param props - Value, callbacks, sizing, styling, and focus props.
|
|
19
22
|
* @returns A text input node for the UI tree.
|
|
20
23
|
*
|
|
@@ -26,14 +29,15 @@ import type { TextInputNode, TextInputProps } from "@cel-tui/types";
|
|
|
26
29
|
* })
|
|
27
30
|
*
|
|
28
31
|
* @example
|
|
29
|
-
* // Growing input with max height
|
|
32
|
+
* // Growing input with max height, Enter submits
|
|
30
33
|
* TextInput({
|
|
31
34
|
* flex: 1,
|
|
32
35
|
* maxHeight: 10,
|
|
33
36
|
* value: text,
|
|
34
37
|
* onChange: handleChange,
|
|
35
|
-
*
|
|
36
|
-
*
|
|
38
|
+
* onKeyPress: (key) => {
|
|
39
|
+
* if (key === "enter") { handleSend(); return false; }
|
|
40
|
+
* },
|
|
37
41
|
* placeholder: Text("type a message...", { fgColor: "color08" }),
|
|
38
42
|
* })
|
|
39
43
|
*/
|