@flowtty/core 1.0.0-alpha.1 → 1.0.0-alpha.11

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.
@@ -0,0 +1,184 @@
1
+ import { i as Color } from "./cells-C-GthybI.js";
2
+ import { loadYoga } from "yoga-layout/load";
3
+ //#region src/host/yoga.d.ts
4
+ type Yoga = Awaited<ReturnType<typeof loadYoga>>;
5
+ type YogaNode = ReturnType<Yoga["Node"]["create"]>;
6
+ declare function getYoga(): Promise<Yoga>;
7
+ //#endregion
8
+ //#region src/host/borders.d.ts
9
+ type BorderStyle = "single" | "double" | "round" | "bold" | "classic";
10
+ /** The library-wide default for components that draw a box-border chrome
11
+ * (DialogHost wrappers, Menu panels, Table grids). Declared once so the
12
+ * default is a single edit, not one per component. */
13
+ declare const DEFAULT_BORDER_STYLE: BorderStyle;
14
+ interface GridChars {
15
+ h: string;
16
+ v: string;
17
+ tl: string;
18
+ tr: string;
19
+ bl: string;
20
+ br: string;
21
+ tDown: string;
22
+ tUp: string;
23
+ tRight: string;
24
+ tLeft: string;
25
+ cross: string;
26
+ }
27
+ declare const GRID_CHARS: Record<BorderStyle, GridChars>;
28
+ type BorderChars = Pick<GridChars, "h" | "v" | "tl" | "tr" | "bl" | "br">;
29
+ declare const BORDER_CHARS: Record<BorderStyle, BorderChars>;
30
+ //#endregion
31
+ //#region src/host/layout.d.ts
32
+ interface Rect {
33
+ left: number;
34
+ top: number;
35
+ width: number;
36
+ height: number;
37
+ }
38
+ declare function computeLayout(container: Container, width: number, height: number): void;
39
+ declare function layoutOf(inst: Instance, offsetX?: number, offsetY?: number): Rect;
40
+ //#endregion
41
+ //#region src/host/host.d.ts
42
+ type HostType = "flowtty-box";
43
+ interface BoxProps {
44
+ /** Fixed size in cells. Strings like '100%' use Yoga's percentage sizing. */
45
+ width?: number | string;
46
+ height?: number | string;
47
+ flexDirection?: "row" | "column";
48
+ /** Default 'static' (Yoga's stack flow). 'absolute' positions via top/left/right/bottom relative to the nearest non-static ancestor. */
49
+ position?: "static" | "absolute";
50
+ top?: number;
51
+ left?: number;
52
+ right?: number;
53
+ bottom?: number;
54
+ /** Main-axis alignment of children (flexbox). */
55
+ justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
56
+ /** Cross-axis alignment of children. */
57
+ alignItems?: "flex-start" | "flex-end" | "center" | "stretch";
58
+ wrap?: "wrap" | "truncate" | "none";
59
+ color?: Color;
60
+ bold?: boolean;
61
+ dim?: boolean;
62
+ underline?: boolean;
63
+ inverse?: boolean;
64
+ strikethrough?: boolean;
65
+ link?: string;
66
+ backgroundColor?: Color;
67
+ border?: BorderStyle;
68
+ borderColor?: Color;
69
+ borderBackgroundColor?: Color;
70
+ borderTitle?: string;
71
+ padding?: number;
72
+ paddingX?: number;
73
+ paddingY?: number;
74
+ paddingTop?: number;
75
+ paddingRight?: number;
76
+ paddingBottom?: number;
77
+ paddingLeft?: number;
78
+ margin?: number;
79
+ marginX?: number;
80
+ marginY?: number;
81
+ marginTop?: number;
82
+ marginRight?: number;
83
+ marginBottom?: number;
84
+ marginLeft?: number;
85
+ gap?: number;
86
+ rowGap?: number;
87
+ columnGap?: number;
88
+ flexGrow?: number;
89
+ flexShrink?: number;
90
+ flexBasis?: number | "auto" | `${number}%`;
91
+ flexWrap?: "nowrap" | "wrap" | "wrap-reverse";
92
+ /** Cross-axis distribution of wrap lines. Only effective when flexWrap is 'wrap' or 'wrap-reverse'
93
+ * AND the parent has extra cross-axis space. Default 'flex-start'. */
94
+ alignContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly" | "stretch";
95
+ /** Minimum cell size — Yoga prevents the box from shrinking below this.
96
+ * Accepts a number (cells) or a percent string (e.g. '50%'). Undefined = no minimum. */
97
+ minWidth?: number | `${number}%`;
98
+ maxWidth?: number | `${number}%`;
99
+ minHeight?: number | `${number}%`;
100
+ maxHeight?: number | `${number}%`;
101
+ /** Width / height ratio. Yoga derives the missing dimension from the constrained one.
102
+ * CSS convention: `aspectRatio: 2` = twice as wide as tall; `0.5` = twice as tall as wide; `1` = square. */
103
+ aspectRatio?: number;
104
+ /** 'none' removes this box and all descendants from layout (siblings don't reserve space for it,
105
+ * and paint skips the subtree). Default 'flex'. Useful for conditional UI without unmounting. */
106
+ display?: "flex" | "none";
107
+ /** Fires after layout with this box's computed rect. Use to read allocated dimensions
108
+ * for responsive rendering (e.g. paginating an article reader). **Diff before setState** —
109
+ * this fires on EVERY paint, and unconditionally calling setState with a new object
110
+ * will infinite-loop. Pattern:
111
+ * onLayout={(r) => { if (!size || size.width !== r.width || size.height !== r.height) setSize(r); }} */
112
+ onLayout?: (rect: Rect) => void;
113
+ /** Stacking order within the same paint pass. Higher values paint on top.
114
+ * Default 0. Tree order is the tiebreaker. Does NOT cross pass boundaries:
115
+ * absolutes always overlay stack-flow regardless of zIndex. */
116
+ zIndex?: number;
117
+ /** Clip descendants to this box's content rect. Default 'visible' (no clipping).
118
+ * 'hidden' clips ALL descendant writes including their backgrounds and borders.
119
+ * Does NOT clip this box's own background or border (those are this box's own area). */
120
+ overflow?: "visible" | "hidden";
121
+ /** Restyle what is ALREADY painted under this box instead of covering it:
122
+ * `'dim'` dims those cells and keeps their characters and colors — the scrim
123
+ * behind a modal. Painted before the box's own background, border, text and
124
+ * children, which therefore stay bright. `dim` is a flag on a cell, not an
125
+ * opacity, so stacked backdrops never darken anything twice. */
126
+ backdrop?: "dim";
127
+ /** Scroll the content up by this many rows (0 = top). Setting either scroll
128
+ * prop makes the box a scroll viewport: it clips like `overflow: 'hidden'`
129
+ * and paints its flow children shifted. The value is clamped to the scrollable
130
+ * range at paint time, against the content's CURRENT height — so it never
131
+ * needs a second frame to catch up. `position: 'absolute'` children are
132
+ * overlays: they neither scroll nor count as content (a scrollbar, a
133
+ * "new messages" badge). */
134
+ scrollTop?: number;
135
+ /** Like `scrollTop`, but counted from the END of the content: 0 pins the last
136
+ * rows into view and keeps them there as content grows. Wins over `scrollTop`
137
+ * when both are set. */
138
+ scrollBottom?: number;
139
+ /** Fires every paint (diff before setState, like onLayout) with the numbers a
140
+ * scrolling component needs: content and viewport heights, the effective
141
+ * (clamped) `scrollTop`, and its maximum. */
142
+ onScrollMetrics?: (metrics: ScrollMetrics) => void;
143
+ }
144
+ interface ScrollMetrics {
145
+ contentHeight: number;
146
+ viewportHeight: number;
147
+ scrollTop: number;
148
+ maxScrollTop: number;
149
+ }
150
+ interface Instance {
151
+ type: "box";
152
+ props: BoxProps;
153
+ yogaNode: YogaNode;
154
+ children: Array<Instance | TextInstance>;
155
+ }
156
+ interface TextInstance {
157
+ type: "text";
158
+ text: string;
159
+ parent?: Instance;
160
+ }
161
+ /**
162
+ * Adapter-facing root container: a list of top-level Instances plus the loaded
163
+ * Yoga module. Each framework adapter (React reconciler, Vue, …) builds one of
164
+ * these and passes it to `computeLayout` + `paint`. Lives in host so layout /
165
+ * paint (in core) can depend on it without pulling in any adapter code.
166
+ */
167
+ interface Container {
168
+ children: Instance[];
169
+ Yoga: Yoga;
170
+ }
171
+ declare function createInstance(type: HostType, props: BoxProps, Yoga: Yoga): Instance;
172
+ declare function createTextInstance(text: string, _Yoga: Yoga): TextInstance;
173
+ declare function applyProps(inst: Instance, props: BoxProps, _Yoga: Yoga): void;
174
+ declare function measureText(text: string): {
175
+ width: number;
176
+ height: number;
177
+ };
178
+ declare function ownText(inst: Instance): string;
179
+ declare function refreshMeasure(inst: Instance, _Yoga: Yoga): void;
180
+ declare function appendChild(parent: Instance, child: Instance | TextInstance, Yoga: Yoga): void;
181
+ declare function removeChild(parent: Instance, child: Instance | TextInstance, Yoga: Yoga): void;
182
+ declare function insertBefore(parent: Instance, child: Instance | TextInstance, before: Instance | TextInstance, Yoga: Yoga): void;
183
+ //#endregion
184
+ export { GRID_CHARS as C, getYoga as D, YogaNode as E, DEFAULT_BORDER_STYLE as S, Yoga as T, computeLayout as _, ScrollMetrics as a, BorderChars as b, applyProps as c, insertBefore as d, measureText as f, Rect as g, removeChild as h, Instance as i, createInstance as l, refreshMeasure as m, Container as n, TextInstance as o, ownText as p, HostType as r, appendChild as s, BoxProps as t, createTextInstance as u, layoutOf as v, GridChars as w, BorderStyle as x, BORDER_CHARS as y };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,8 @@
1
- export { B as Buffer, C as Cell, S as Style } from './cells-CaXEx4lH.js';
2
- import { K as Key } from './backend-BcB7VR87.js';
3
- export { B as Backend } from './backend-BcB7VR87.js';
4
- export { a as BorderChars, b as BorderStyle, c as BoxProps, D as DEFAULT_BORDER_STYLE, G as GRID_CHARS, d as GridChars } from './host-DttBG-OZ.js';
5
- import 'yoga-layout/load';
6
-
7
- type WrapMode = 'wrap' | 'truncate' | 'none';
1
+ import { C as GRID_CHARS, S as DEFAULT_BORDER_STYLE, a as ScrollMetrics, b as BorderChars, t as BoxProps, w as GridChars, x as BorderStyle } from "./host-C98WW3Ai.js";
2
+ import { a as NAMED_COLORS, i as Color, n as Cell, o as NamedColor, r as Style, t as Buffer } from "./cells-C-GthybI.js";
3
+ import { a as NamedKey, i as NAMED_KEYS, n as Key, r as KeyName, t as Backend } from "./backend-CT8SGLO5.js";
4
+ //#region src/wrap.d.ts
5
+ type WrapMode = "wrap" | "truncate" | "none";
8
6
  /**
9
7
  * Lay out `text` into display lines fitting within `width` cells.
10
8
  * Assumes 1 code point = 1 cell (no CJK/emoji width awareness in M1d).
@@ -15,8 +13,9 @@ type WrapMode = 'wrap' | 'truncate' | 'none';
15
13
  *
16
14
  * Always returns at least one line (empty input → `['']`, matching measureText's height=1 default).
17
15
  */
18
- declare function wrapText(text: string, width: number, mode: WrapMode): string[];
19
-
16
+ export declare function wrapText(text: string, width: number, mode: WrapMode): string[];
17
+ //#endregion
18
+ //#region src/visualLines.d.ts
20
19
  /**
21
20
  * Split a multi-line source text into visual lines for paginated rendering
22
21
  * with an optional line-number gutter.
@@ -39,12 +38,13 @@ declare function wrapText(text: string, width: number, mode: WrapMode): string[]
39
38
  * ```
40
39
  */
41
40
  interface VisualLine {
42
- text: string;
43
- /** Source-file line number for the first visual line of a wrapped source line; null for continuation lines. 1-based. */
44
- lineNum: number | null;
41
+ text: string;
42
+ /** Source-file line number for the first visual line of a wrapped source line; null for continuation lines. 1-based. */
43
+ lineNum: number | null;
45
44
  }
46
- declare function splitVisualLines(text: string, mode: 'wrap' | 'nowrap', width: number): VisualLine[];
47
-
45
+ export declare function splitVisualLines(text: string, mode: "wrap" | "nowrap", width: number): VisualLine[];
46
+ //#endregion
47
+ //#region src/windowAround.d.ts
48
48
  /**
49
49
  * Center a `visible`-sized window of items around `cursor`, clamped so the
50
50
  * window never starts before 0 or extends past the end of the list. Returns
@@ -62,82 +62,132 @@ declare function splitVisualLines(text: string, mode: 'wrap' | 'nowrap', width:
62
62
  * The window prefers to center the cursor; near the edges it sticks to the
63
63
  * top/bottom so the cursor remains visible without empty padding.
64
64
  */
65
- declare function windowAround<T>(items: readonly T[], cursor: number, visible: number): {
66
- start: number;
67
- items: T[];
65
+ export declare function windowAround<T>(items: readonly T[], cursor: number, visible: number): {
66
+ start: number;
67
+ items: T[];
68
68
  };
69
-
69
+ //#endregion
70
+ //#region src/displayWidth.d.ts
70
71
  /**
71
72
  * Display width in terminal cells of a single Unicode code point: 0 for control
72
73
  * / combining / zero-width, 2 for East Asian Wide & Fullwidth (and most emoji),
73
74
  * 1 otherwise. Pass a code point (e.g. from `String#codePointAt`), not a string.
74
75
  */
75
- declare function charWidth(cp: number): 0 | 1 | 2;
76
+ export declare function charWidth(cp: number): 0 | 1 | 2;
76
77
  /**
77
78
  * Display width in terminal cells of a string, summing `charWidth` over its
78
79
  * code points (surrogate pairs counted once). See the file header for the
79
80
  * grapheme-cluster caveat. Expects plain text, not ANSI-styled.
80
81
  */
81
- declare function stringWidth(str: string): number;
82
-
82
+ export declare function stringWidth(str: string): number;
83
+ //#endregion
84
+ //#region src/editor.d.ts
83
85
  interface EditorState {
84
- value: string;
85
- cursor: number;
86
+ value: string;
87
+ /** UTF-16 index into `value` (so `value.slice(0, cursor)` is the text before
88
+ * the caret). It only ever rests on a character boundary: movement and
89
+ * deletion step over a whole code point, and a cursor handed in between the
90
+ * two halves of a surrogate pair is snapped back before anything else. */
91
+ cursor: number;
86
92
  }
87
93
  type EditorAction = {
88
- kind: 'edit';
89
- state: EditorState;
94
+ kind: "edit";
95
+ state: EditorState;
90
96
  } | {
91
- kind: 'submit';
97
+ kind: "submit";
92
98
  } | {
93
- kind: 'cancel';
99
+ kind: "cancel";
94
100
  } | {
95
- kind: 'noop';
101
+ kind: "noop";
96
102
  };
97
- declare function reduce$2(state: EditorState, key: Key): EditorAction;
98
-
103
+ interface EditorOptions {
104
+ /** Multi-line editing: line breaks are part of the value. Shift+Enter,
105
+ * Alt+Enter and backslash-then-Enter insert one (plain Enter still submits),
106
+ * up/down move between visual rows, Home/End and the kill bindings work
107
+ * within the current line, and a paste keeps its line breaks. */
108
+ multiline?: boolean;
109
+ /** Wrap width in cells — what up/down use to walk soft-wrapped rows. Only
110
+ * read when `multiline`; without it each source line counts as one row.
111
+ * It MUST be the width the field is actually drawn with (the one passed to
112
+ * `inputRows` / `caretPosition`): a host that renders the rows itself computes
113
+ * both, and a mismatch makes up/down land on a different column than shown. */
114
+ width?: number;
115
+ }
116
+ /**
117
+ * One key against an editor state. Contract hosts rely on: a key the editor has
118
+ * no meaning for (Tab, Ctrl+R, PgUp, the wheel, an unrecognized sequence …)
119
+ * returns `{ kind: 'noop' }` — never an edit — so a host can handle its own keys
120
+ * first and pass everything else through.
121
+ */
122
+ declare function reduce(state: EditorState, key: Key, opts?: EditorOptions): EditorAction;
123
+ //#endregion
124
+ //#region src/inputRows.d.ts
125
+ interface InputRow {
126
+ /** Text of this visual row (no line break). */
127
+ text: string;
128
+ /** Index into the value where this row starts. */
129
+ start: number;
130
+ /** True for a soft-wrap continuation of the previous row's source line. */
131
+ continuation: boolean;
132
+ }
133
+ export declare function inputRows(value: string, width: number, cursor?: number): InputRow[];
134
+ /** UTF-16 index of character column `col` within `row` (clamped to its end). */
135
+ export declare function rowIndexAt(row: InputRow, col: number): number;
136
+ export declare function caretPosition(value: string, cursor: number, width: number): {
137
+ row: number;
138
+ col: number;
139
+ };
140
+ //#endregion
141
+ //#region src/selectReducer.d.ts
99
142
  interface SelectItem<T> {
100
- label: string;
101
- value: T;
143
+ label: string;
144
+ value: T;
102
145
  }
103
146
  interface SelectState {
104
- cursor: number;
105
- filter: string;
147
+ cursor: number;
148
+ filter: string;
106
149
  }
107
150
  type SelectAction = {
108
- kind: 'state';
109
- state: SelectState;
151
+ kind: "state";
152
+ state: SelectState;
110
153
  } | {
111
- kind: 'submit';
112
- index: number;
154
+ kind: "submit";
155
+ index: number;
113
156
  } | {
114
- kind: 'cancel';
157
+ kind: "cancel";
115
158
  } | {
116
- kind: 'noop';
159
+ kind: "noop";
117
160
  };
118
161
  /**
119
162
  * Indices into `items` of items whose label contains `filter` (case-insensitive
120
163
  * substring). Empty filter → all indices.
121
164
  */
122
- declare function visibleIndices<T>(items: SelectItem<T>[], filter: string): number[];
123
- declare function reduce$1<T>(items: SelectItem<T>[], state: SelectState, key: Key): SelectAction;
124
-
165
+ export declare function visibleIndices<T>(items: SelectItem<T>[], filter: string): number[];
166
+ declare function reduce$2<T>(items: SelectItem<T>[], state: SelectState, key: Key): SelectAction;
167
+ //#endregion
168
+ //#region src/multiSelectReducer.d.ts
125
169
  interface MultiSelectState {
126
- cursor: number;
170
+ cursor: number;
127
171
  }
128
172
  type MultiSelectAction = {
129
- kind: 'state';
130
- state: MultiSelectState;
173
+ kind: "state";
174
+ state: MultiSelectState;
131
175
  } | {
132
- kind: 'toggle';
133
- index: number;
176
+ kind: "toggle";
177
+ index: number;
134
178
  } | {
135
- kind: 'submit';
179
+ kind: "submit";
136
180
  } | {
137
- kind: 'cancel';
181
+ kind: "cancel";
138
182
  } | {
139
- kind: 'noop';
183
+ kind: "noop";
140
184
  };
141
- declare function reduce<T>(items: SelectItem<T>[], state: MultiSelectState, key: Key): MultiSelectAction;
142
-
143
- export { type EditorAction, type EditorState, Key, type MultiSelectAction, type MultiSelectState, type SelectAction, type SelectItem, type SelectState, type VisualLine, type WrapMode, charWidth, reduce$2 as editorReducer, reduce as multiSelectReducer, reduce$1 as selectReducer, splitVisualLines, stringWidth, visibleIndices, windowAround, wrapText };
185
+ interface MultiSelectOptions {
186
+ /** Rows after the items that the cursor can stand on but that hold no item —
187
+ * e.g. a trailing "+ add new" row. Navigation wraps over items + extra rows;
188
+ * Space on an extra row toggles nothing. Default 0. */
189
+ extraRows?: number;
190
+ }
191
+ declare function reduce$1<T>(items: SelectItem<T>[], state: MultiSelectState, key: Key, opts?: MultiSelectOptions): MultiSelectAction;
192
+ //#endregion
193
+ export { type Backend, type BorderChars, type BorderStyle, type BoxProps, Buffer, type Cell, type Color, DEFAULT_BORDER_STYLE, type EditorAction, type EditorOptions, type EditorState, GRID_CHARS, type GridChars, type InputRow, type Key, type KeyName, type MultiSelectAction, type MultiSelectOptions, type MultiSelectState, NAMED_COLORS, NAMED_KEYS, type NamedColor, type NamedKey, type ScrollMetrics, type SelectAction, type SelectItem, type SelectState, type Style, type VisualLine, type WrapMode, reduce as editorReducer, reduce$1 as multiSelectReducer, reduce$2 as selectReducer };