@cel-tui/core 0.4.1 → 0.5.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cel-tui/core",
3
- "version": "0.4.1",
3
+ "version": "0.5.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.4.1",
37
+ "@cel-tui/types": "0.5.0",
38
38
  "get-east-asian-width": "^1.5.0"
39
39
  },
40
40
  "peerDependencies": {
package/src/index.ts CHANGED
@@ -2,8 +2,9 @@
2
2
  * @module @cel-tui/core
3
3
  *
4
4
  * Core framework package. Provides the four primitives ({@link VStack},
5
- * {@link HStack}, {@link Text}, {@link TextInput}) and the framework
6
- * entrypoint ({@link cel}).
5
+ * {@link HStack}, {@link Text}, {@link TextInput}), the framework
6
+ * entrypoint ({@link cel}), and measurement helpers such as
7
+ * {@link measureContentHeight}.
7
8
  *
8
9
  * All types are re-exported from `@cel-tui/types`.
9
10
  *
@@ -45,6 +46,7 @@ export { VStack, HStack } from "./primitives/stacks.js";
45
46
  export { Text } from "./primitives/text.js";
46
47
  export { TextInput } from "./primitives/text-input.js";
47
48
  export { cel } from "./cel.js";
49
+ export { measureContentHeight } from "./layout.js";
48
50
  export { CellBuffer, EMPTY_CELL, type Cell } from "./cell-buffer.js";
49
51
  export { emitBuffer, defaultTheme } from "./emitter.js";
50
52
  export { visibleWidth, extractAnsiCode } from "./width.js";
package/src/layout.ts CHANGED
@@ -121,6 +121,15 @@ function intrinsicMainSize(
121
121
  resolveSizeValue(cProps?.width, 0) ??
122
122
  intrinsicMainSize(child, false, innerCross);
123
123
  }
124
+ if (cProps) {
125
+ const minMain = isVertical
126
+ ? (cProps.minHeight ?? 0)
127
+ : (cProps.minWidth ?? 0);
128
+ const maxMain = isVertical
129
+ ? (cProps.maxHeight ?? Infinity)
130
+ : (cProps.maxWidth ?? Infinity);
131
+ childMain = clamp(childMain, minMain, maxMain);
132
+ }
124
133
  total += childMain;
125
134
  if (i < node.children.length - 1) total += gap;
126
135
  }
@@ -150,9 +159,12 @@ function intrinsicMainSize(
150
159
  }
151
160
  }
152
161
  wrapWidths.push(w);
153
- const h =
162
+ let h =
154
163
  resolveSizeValue(cProps?.height, 0) ??
155
164
  intrinsicMainSize(child, true, innerCross);
165
+ if (cProps) {
166
+ h = clamp(h, cProps.minHeight ?? 0, cProps.maxHeight ?? Infinity);
167
+ }
156
168
  wrapHeights.push(h);
157
169
  }
158
170
  const wrapRows = assignWrapRows(wrapWidths, innerCross, gap);
@@ -259,6 +271,37 @@ function largestRemainder(fractions: number[], total: number): number[] {
259
271
 
260
272
  // --- Main layout ---
261
273
 
274
+ /**
275
+ * Measure a node tree's intrinsic content height at the provided width.
276
+ *
277
+ * This is a content-measurement helper, not a viewport/clipping helper.
278
+ * The caller-provided `width` is the authoritative wrapping width for the
279
+ * measured subtree. Measurement starts at the given node, ignores that
280
+ * node's own main-axis height constraints, and walks downward through its
281
+ * descendants. Descendant sizing rules still apply normally.
282
+ *
283
+ * Use this for intrinsically sized content such as scrollback/message
284
+ * history chunks. If a wrapper's visible height is controlled by `height`,
285
+ * `flex`, or percentage sizing, measure the content subtree inside that
286
+ * wrapper instead.
287
+ *
288
+ * @example
289
+ * ```ts
290
+ * const addedHeight = measureContentHeight(
291
+ * VStack({}, olderMessages.map(renderMessage)),
292
+ * { width: historyContentWidth },
293
+ * );
294
+ *
295
+ * scrollOffset += addedHeight;
296
+ * ```
297
+ */
298
+ export function measureContentHeight(
299
+ node: Node,
300
+ options: { width: number },
301
+ ): number {
302
+ return intrinsicMainSize(node, true, options.width);
303
+ }
304
+
262
305
  /**
263
306
  * Compute the layout for a UI tree.
264
307
  *