Skip to content

Commit 0e64a4c

Browse files
committed
Bump version to 0.12.81
1 parent 9e27fe3 commit 0e64a4c

9 files changed

Lines changed: 151 additions & 65 deletions

File tree

packages/asterui/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ description: All notable changes to AsterUI
77

88
All notable changes to AsterUI are documented here.
99

10+
## v0.12.81 (2025-01-21)
11+
12+
### Bug Fixes
13+
14+
- **Terminal**: Fixed initialization error when container has no dimensions (e.g., in flexbox/splitter layouts)
15+
- **Terminal**: Fixed ESM/CJS import compatibility for xterm packages across different bundlers
16+
17+
### Documentation
18+
19+
- Added Terminal preview images for component overview page
20+
1021
## v0.12.80 (2025-01-21)
1122

1223
### Components

packages/asterui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "asterui",
3-
"version": "0.12.80",
3+
"version": "0.12.81",
44
"description": "React UI component library with DaisyUI",
55
"homepage": "https://asterui.com",
66
"repository": {

packages/asterui/src/components/Terminal.tsx

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import React, { useEffect, useRef, useImperativeHandle, forwardRef } from 'react'
2-
import XTermPkg from '@xterm/xterm'
3-
import FitAddonPkg from '@xterm/addon-fit'
2+
import * as XTermPkg from '@xterm/xterm'
3+
import * as FitAddonPkg from '@xterm/addon-fit'
44
import type { Terminal as XTermType, ITerminalOptions, ITerminalInitOnlyOptions } from '@xterm/xterm'
55
import type { FitAddon as FitAddonType } from '@xterm/addon-fit'
66
import { useTheme } from '../hooks/useTheme'
77

8-
const XTerm = XTermPkg.Terminal ?? (XTermPkg as unknown as { Terminal: typeof XTermPkg.Terminal }).Terminal
9-
const FitAddon = FitAddonPkg.FitAddon ?? (FitAddonPkg as unknown as { FitAddon: typeof FitAddonPkg.FitAddon }).FitAddon
8+
// Handle both ESM and CJS module formats
9+
const XTerm = (XTermPkg as { Terminal?: typeof XTermType }).Terminal
10+
?? (XTermPkg as { default?: { Terminal: typeof XTermType } }).default?.Terminal
11+
?? (XTermPkg as unknown as typeof XTermType)
12+
const FitAddon = (FitAddonPkg as { FitAddon?: typeof FitAddonType }).FitAddon
13+
?? (FitAddonPkg as { default?: { FitAddon: typeof FitAddonType } }).default?.FitAddon
14+
?? (FitAddonPkg as unknown as typeof FitAddonType)
1015

1116
// Inject xterm.css once (inlined for reliability across bundlers)
1217
let cssInjected = false
@@ -248,43 +253,70 @@ export const Terminal = forwardRef<TerminalRef, TerminalProps>(({
248253

249254
injectXtermCSS()
250255

251-
const terminal = new XTerm({
252-
theme: getTheme(),
253-
cursorBlink: true,
254-
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
255-
fontSize: 14,
256-
...options,
257-
})
258-
const fitAddon = new FitAddon()
256+
const container = containerRef.current
257+
let terminal: XTermType | null = null
258+
let fitAddon: FitAddonType | null = null
259+
let resizeObserver: ResizeObserver | null = null
260+
let initialized = false
259261

260-
terminal.loadAddon(fitAddon)
261-
terminal.open(containerRef.current)
262-
fitAddon.fit()
262+
const initTerminal = () => {
263+
if (initialized || !container) return
263264

264-
terminalRef.current = terminal
265-
fitAddonRef.current = fitAddon
265+
// Check container has dimensions before opening
266+
const rect = container.getBoundingClientRect()
267+
if (rect.width === 0 || rect.height === 0) return
266268

267-
if (readline) {
268-
terminal.onData(handleReadlineData)
269-
} else if (onData) {
270-
terminal.onData(onData)
271-
}
269+
initialized = true
272270

273-
onReady?.(terminal)
271+
terminal = new XTerm({
272+
theme: getTheme(),
273+
cursorBlink: true,
274+
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
275+
fontSize: 14,
276+
...options,
277+
})
278+
fitAddon = new FitAddon()
279+
280+
terminal.loadAddon(fitAddon)
281+
terminal.open(container)
282+
fitAddon.fit()
283+
284+
terminalRef.current = terminal
285+
fitAddonRef.current = fitAddon
286+
287+
if (readline) {
288+
terminal.onData(handleReadlineData)
289+
} else if (onData) {
290+
terminal.onData(onData)
291+
}
274292

275-
// Write initial prompt after onReady so welcome messages appear first
276-
if (readline) {
277-
terminal.write(prompt)
293+
onReady?.(terminal)
294+
295+
// Write initial prompt after onReady so welcome messages appear first
296+
if (readline) {
297+
terminal.write(prompt)
298+
}
278299
}
279300

280-
const resizeObserver = new ResizeObserver(() => {
281-
fitAddon.fit()
301+
// Use ResizeObserver to wait for container to have dimensions
302+
resizeObserver = new ResizeObserver((entries) => {
303+
const entry = entries[0]
304+
if (!entry) return
305+
306+
if (!initialized) {
307+
initTerminal()
308+
} else if (fitAddon) {
309+
fitAddon.fit()
310+
}
282311
})
283-
resizeObserver.observe(containerRef.current)
312+
resizeObserver.observe(container)
313+
314+
// Also try immediately in case container already has dimensions
315+
requestAnimationFrame(initTerminal)
284316

285317
return () => {
286-
resizeObserver.disconnect()
287-
terminal.dispose()
318+
resizeObserver?.disconnect()
319+
terminal?.dispose()
288320
terminalRef.current = null
289321
fitAddonRef.current = null
290322
}
10.3 KB
Loading
9.4 KB
Loading

packages/docs/scripts/capture-components.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const COMPONENTS = [
8383
'container', 'divider', 'flex', 'footer', 'grid', 'hero', 'join',
8484
'layout', 'masonry', 'responsive', 'space', 'splitter',
8585
'affix', 'browser', 'code', 'configprovider', 'kbd', 'mask', 'phone',
86-
'textrotate', 'themecontroller', 'tour', 'typography', 'watermark', 'window',
86+
'terminal', 'textrotate', 'themecontroller', 'tour', 'typography', 'watermark', 'window',
8787
]
8888

8989
async function getComponentElement(page: any, slug: string) {

packages/docs/src/content/docs/changelog.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ description: All notable changes to AsterUI
77

88
All notable changes to AsterUI are documented here.
99

10+
## v0.12.81 (2025-01-21)
11+
12+
### Bug Fixes
13+
14+
- **Terminal**: Fixed initialization error when container has no dimensions (e.g., in flexbox/splitter layouts)
15+
- **Terminal**: Fixed ESM/CJS import compatibility for xterm packages across different bundlers
16+
17+
### Documentation
18+
19+
- Added Terminal preview images for component overview page
20+
1021
## v0.12.80 (2025-01-21)
1122

1223
### Components

packages/prefixed/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aster-ui/prefixed",
3-
"version": "0.12.80",
3+
"version": "0.12.81",
44
"description": "React UI component library with DaisyUI (prefixed classes)",
55
"homepage": "https://asterui.com",
66
"repository": {

packages/prefixed/src/components/Terminal.tsx

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import React, { useEffect, useRef, useImperativeHandle, forwardRef } from 'react'
2-
import XTermPkg from '@xterm/xterm'
3-
import FitAddonPkg from '@xterm/addon-fit'
2+
import * as XTermPkg from '@xterm/xterm'
3+
import * as FitAddonPkg from '@xterm/addon-fit'
44
import type { Terminal as XTermType, ITerminalOptions, ITerminalInitOnlyOptions } from '@xterm/xterm'
55
import type { FitAddon as FitAddonType } from '@xterm/addon-fit'
66
import { useTheme } from '../hooks/useTheme'
77

8-
const XTerm = XTermPkg.Terminal ?? (XTermPkg as unknown as { Terminal: typeof XTermPkg.Terminal }).Terminal
9-
const FitAddon = FitAddonPkg.FitAddon ?? (FitAddonPkg as unknown as { FitAddon: typeof FitAddonPkg.FitAddon }).FitAddon
8+
// Handle both ESM and CJS module formats
9+
const XTerm = (XTermPkg as { Terminal?: typeof XTermType }).Terminal
10+
?? (XTermPkg as { default?: { Terminal: typeof XTermType } }).default?.Terminal
11+
?? (XTermPkg as unknown as typeof XTermType)
12+
const FitAddon = (FitAddonPkg as { FitAddon?: typeof FitAddonType }).FitAddon
13+
?? (FitAddonPkg as { default?: { FitAddon: typeof FitAddonType } }).default?.FitAddon
14+
?? (FitAddonPkg as unknown as typeof FitAddonType)
1015

1116
// Inject xterm.css once (inlined for reliability across bundlers)
1217
let cssInjected = false
@@ -248,43 +253,70 @@ export const Terminal = forwardRef<TerminalRef, TerminalProps>(({
248253

249254
injectXtermCSS()
250255

251-
const terminal = new XTerm({
252-
theme: getTheme(),
253-
cursorBlink: true,
254-
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
255-
fontSize: 14,
256-
...options,
257-
})
258-
const fitAddon = new FitAddon()
256+
const container = containerRef.current
257+
let terminal: XTermType | null = null
258+
let fitAddon: FitAddonType | null = null
259+
let resizeObserver: ResizeObserver | null = null
260+
let initialized = false
259261

260-
terminal.loadAddon(fitAddon)
261-
terminal.open(containerRef.current)
262-
fitAddon.fit()
262+
const initTerminal = () => {
263+
if (initialized || !container) return
263264

264-
terminalRef.current = terminal
265-
fitAddonRef.current = fitAddon
265+
// Check container has dimensions before opening
266+
const rect = container.getBoundingClientRect()
267+
if (rect.width === 0 || rect.height === 0) return
266268

267-
if (readline) {
268-
terminal.onData(handleReadlineData)
269-
} else if (onData) {
270-
terminal.onData(onData)
271-
}
269+
initialized = true
272270

273-
onReady?.(terminal)
271+
terminal = new XTerm({
272+
theme: getTheme(),
273+
cursorBlink: true,
274+
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
275+
fontSize: 14,
276+
...options,
277+
})
278+
fitAddon = new FitAddon()
279+
280+
terminal.loadAddon(fitAddon)
281+
terminal.open(container)
282+
fitAddon.fit()
283+
284+
terminalRef.current = terminal
285+
fitAddonRef.current = fitAddon
286+
287+
if (readline) {
288+
terminal.onData(handleReadlineData)
289+
} else if (onData) {
290+
terminal.onData(onData)
291+
}
274292

275-
// Write initial prompt after onReady so welcome messages appear first
276-
if (readline) {
277-
terminal.write(prompt)
293+
onReady?.(terminal)
294+
295+
// Write initial prompt after onReady so welcome messages appear first
296+
if (readline) {
297+
terminal.write(prompt)
298+
}
278299
}
279300

280-
const resizeObserver = new ResizeObserver(() => {
281-
fitAddon.fit()
301+
// Use ResizeObserver to wait for container to have dimensions
302+
resizeObserver = new ResizeObserver((entries) => {
303+
const entry = entries[0]
304+
if (!entry) return
305+
306+
if (!initialized) {
307+
initTerminal()
308+
} else if (fitAddon) {
309+
fitAddon.fit()
310+
}
282311
})
283-
resizeObserver.observe(containerRef.current)
312+
resizeObserver.observe(container)
313+
314+
// Also try immediately in case container already has dimensions
315+
requestAnimationFrame(initTerminal)
284316

285317
return () => {
286-
resizeObserver.disconnect()
287-
terminal.dispose()
318+
resizeObserver?.disconnect()
319+
terminal?.dispose()
288320
terminalRef.current = null
289321
fitAddonRef.current = null
290322
}

0 commit comments

Comments
 (0)