@effect-tui/react 0.4.0 → 0.4.2

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": "@effect-tui/react",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "React bindings for @effect-tui/core",
5
5
  "type": "module",
6
6
  "files": [
@@ -83,7 +83,7 @@
83
83
  "prepublishOnly": "bun run typecheck && bun run build"
84
84
  },
85
85
  "dependencies": {
86
- "@effect-tui/core": "^0.4.0",
86
+ "@effect-tui/core": "^0.4.2",
87
87
  "@effect/platform": "^0.94.0",
88
88
  "@effect/platform-bun": "^0.87.0",
89
89
  "@effect/rpc": "^0.73.0",
package/src/hosts/text.ts CHANGED
@@ -76,7 +76,7 @@ export class TextHost extends BaseHost {
76
76
  return { w, h }
77
77
  }
78
78
 
79
- /** Wrap text to fit within maxWidth */
79
+ /** Wrap text to fit within maxWidth, preferring word boundaries */
80
80
  private wrapText(text: string, maxWidth: number): string[] {
81
81
  const result: string[] = []
82
82
  for (const rawLine of text.split("\n")) {
@@ -84,20 +84,48 @@ export class TextHost extends BaseHost {
84
84
  result.push("")
85
85
  continue
86
86
  }
87
+
88
+ // Split into words (keeping whitespace as separate tokens)
89
+ const tokens = rawLine.split(/(\s+)/)
87
90
  let line = ""
88
91
  let lineW = 0
89
- for (const ch of rawLine) {
90
- const w = displayWidth(ch)
91
- if (lineW + w > maxWidth && line.length > 0) {
92
- result.push(line)
93
- line = ch
94
- lineW = w
92
+
93
+ for (const token of tokens) {
94
+ const tokenW = displayWidth(token)
95
+ const isWhitespace = /^\s+$/.test(token)
96
+
97
+ if (lineW + tokenW <= maxWidth) {
98
+ // Token fits on current line
99
+ line += token
100
+ lineW += tokenW
101
+ } else if (isWhitespace) {
102
+ // Whitespace doesn't fit - just skip it (don't start new line with space)
103
+ continue
104
+ } else if (tokenW <= maxWidth) {
105
+ // Word doesn't fit but is smaller than maxWidth - start new line
106
+ if (line.trimEnd()) result.push(line.trimEnd())
107
+ line = token
108
+ lineW = tokenW
95
109
  } else {
96
- line += ch
97
- lineW += w
110
+ // Word is longer than maxWidth - break it character by character
111
+ if (line.trimEnd()) result.push(line.trimEnd())
112
+ line = ""
113
+ lineW = 0
114
+ for (const ch of token) {
115
+ const chW = displayWidth(ch)
116
+ if (lineW + chW > maxWidth && line.length > 0) {
117
+ result.push(line)
118
+ line = ch
119
+ lineW = chW
120
+ } else {
121
+ line += ch
122
+ lineW += chW
123
+ }
124
+ }
98
125
  }
99
126
  }
100
- if (line.length > 0) result.push(line)
127
+ // Preserve trailing space for inline flow - only trimEnd when breaking mid-line (done above)
128
+ if (line) result.push(line)
101
129
  }
102
130
  return result.length > 0 ? result : [""]
103
131
  }