@cplieger/web-terminal-ui 4.5.2 → 4.6.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/README.md CHANGED
@@ -8,15 +8,14 @@
8
8
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/cplieger/web-terminal-ui/badge)](https://scorecard.dev/viewer/?uri=github.com/cplieger/web-terminal-ui)
9
9
 
10
10
  The reference touch-first browser UI for
11
- [`@cplieger/web-terminal-engine`](https://github.com/cplieger/web-terminal-engine) — the part
12
- that turns the engine's render/scroll/connection/keyboard modules into a
13
- usable terminal on a phone as well as a desktop.
11
+ [`@cplieger/web-terminal-engine`](https://github.com/cplieger/web-terminal-engine).
12
+ It turns the engine's render/scroll/connection/keyboard modules into a usable
13
+ terminal on a phone as well as a desktop.
14
14
 
15
15
  One `createTerminal(root, { features })` call builds the entire terminal UI
16
16
  inside a single container element you provide. A small always-present kernel
17
- (the display output, the hidden keyboard textarea, IME, engine wiring, the
18
- sanitizing input funnel, connection-state, and named layout regions) composes
19
- with opt-in feature modules that own everything above the raw terminal:
17
+ composes with opt-in feature modules that own everything above the raw
18
+ terminal:
20
19
 
21
20
  - a **display-only** terminal output (native text selection survives redraws)
22
21
  and a hidden `<textarea>` that owns the keyboard and IME (the kernel)
@@ -44,7 +43,7 @@ depend on the engine directly and skip this package.
44
43
  npm install @cplieger/web-terminal-ui @cplieger/web-terminal-engine
45
44
  ```
46
45
 
47
- `@cplieger/web-terminal-engine` is a peer dependency — the UI is built on the
46
+ `@cplieger/web-terminal-engine` is a peer dependency: the UI is built on the
48
47
  engine, so the consumer pins the engine version explicitly. Pairing compatibility
49
48
  is governed by the engine's
50
49
  [directional wire contract](https://github.com/cplieger/web-terminal-engine#wire-protocol),
@@ -57,14 +56,14 @@ Serve a CSS bundle matching how you embed the terminal, plus a minimal HTML
57
56
  page that has one empty container element, then call
58
57
  `createTerminal(root, { features })` from your entry module.
59
58
 
60
- **Full-page host** (the terminal IS the page — `web-terminal-server`,
59
+ **Full-page host** (the terminal IS the page, as in `web-terminal-server` and
61
60
  `web-terminal-kiro`): concatenate `css/MANIFEST` into the `style.css` your page
62
61
  links. That reference bundle is `css/page.css` (the page kit: `html/body`
63
62
  reset + the terminal web font's `@font-face`, expecting the font files at
64
63
  `/vendor/fonts/`) plus the complete component set.
65
64
 
66
- **Embedder** (the terminal lives inside your app's layout — a panel, a pane):
67
- concatenate the per-preset manifest matching your composition instead —
65
+ **Embedder** (the terminal lives inside your app's layout, as a panel or pane):
66
+ concatenate the per-preset manifest matching your composition instead:
68
67
  `css/MANIFEST.single`, `css/MANIFEST.touch`, or `css/MANIFEST.tabbed`. These
69
68
  contain ONLY root-scoped component styles: no page reset, no fonts, no
70
69
  document-level rules, nothing to quarantine. Pass `layout: "container"` so the
@@ -99,7 +98,7 @@ entry modules beside it:
99
98
  ```
100
99
 
101
100
  `createTerminal(root, opts?)` builds the entire terminal subtree (the kernel
102
- plus every feature's chrome) inside `root` itself — there is no element-id
101
+ plus every feature's chrome) inside `root` itself. There is no element-id
103
102
  contract for the host page to reproduce, and every style and CSS custom
104
103
  property is scoped to the `wt-root` class it stamps on your element (removed
105
104
  again by `destroy()`). Call it exactly once; the engine's
@@ -109,46 +108,43 @@ to copy and adapt.
109
108
 
110
109
  Four presets are provided; each is a plain feature-array factory, so you can
111
110
  spread and edit it. Import the barrel (`@cplieger/web-terminal-ui/presets`) for
112
- convenience, or a per-preset entry module for the minimal delivered import
113
- graph — `…/presets/single`, `…/presets/touch`, `…/presets/tabbed`,
114
- `…/presets/agent-tabbed` (the barrel statically reaches every feature; the
115
- touch entry, for example, never imports the tabs module). Individual features
111
+ convenience, or a per-preset entry module (`…/presets/single`, `…/presets/touch`,
112
+ `…/presets/tabbed`, `…/presets/agent-tabbed`) for the minimal delivered import
113
+ graph; the barrel statically reaches every feature, while the touch entry, for
114
+ example, never imports the tabs module. Individual features
116
115
  are importable from `…/features/<name>` (`clipboard`, `context-menu`,
117
116
  `scroll-to-bottom`, `predictive-echo`, `connection-banner`, `mobile-toolbar`,
118
117
  `tabs`, `activity-monitor`, `animations`) for hand-picked compositions:
119
118
 
120
- - `presetSingle()` — single-pane desktop UI (context menu, clipboard,
119
+ - `presetSingle()`: single-pane desktop UI (context menu, clipboard,
121
120
  scroll-to-bottom, predictive echo, connection banner).
122
- - `presetTouch()` — `presetSingle()` plus the mobile key toolbar.
123
- - `presetTabbed()` — the generic tabbed UI: `presetTouch()` plus tabs, the
124
- activity monitor, and animations. Each tab's title is OSC-first — it follows
121
+ - `presetTouch()`: `presetSingle()` plus the mobile key toolbar.
122
+ - `presetTabbed()`: the generic tabbed UI, `presetTouch()` plus tabs, the
123
+ activity monitor, and animations. Each tab's title is OSC-first: it follows
125
124
  the process window title (OSC 0/2) when the program sets one and keeps it
126
125
  updated, otherwise the last command submitted. The per-tab activity dot
127
126
  reveals itself only when a session reports OSC 9;4 progress, so a plain shell
128
127
  keeps clean, label-only tabs. Requires a server that speaks the session API
129
128
  (`/api/sessions` and `/ws?session=`), such as `web-terminal-server`.
130
- - `presetAgentTabbed()` — the same feature set as `presetTabbed()` (activity
131
- monitor included), tuned for an agent shell such as `web-terminal-kiro`: with
132
- `preferInputTitle`, each tab's label follows the latest submitted line
133
- (persisted server-side and recovered on reload) and the program's non-empty
134
- but useless OSC 0/2 title is ignored; and with `presumeReports`, the idle
135
- activity dot shows from tab creation instead of waiting for the session's
136
- first OSC 9;4 signal — every session is an agent, so there is nothing to
137
- prove. Its status dots (idle / working / done / needs-input) come from the
138
- same activity monitor, driven by the server's status SSE and its OSC-9
139
- classifier.
129
+ - `presetAgentTabbed()`: the same feature set as `presetTabbed()`, tuned for an
130
+ agent shell such as `web-terminal-kiro`. With `preferInputTitle`, each tab's
131
+ label follows the latest submitted line (persisted server-side and recovered
132
+ on reload) and the program's OSC 0/2 title is ignored. With `presumeReports`,
133
+ the idle activity dot shows from tab creation instead of waiting for the
134
+ session's first OSC 9;4 signal. Its status dots (idle / working / done /
135
+ needs-input) come from the same activity monitor.
140
136
 
141
137
  ### Options
142
138
 
143
- | Option | Default | Purpose |
144
- | -------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
145
- | `features` | _(none — bare kernel)_ | The feature list. Omitted or empty builds only the terminal (no chrome). Use a preset from `./presets` or a hand-picked array. |
146
- | `layout` | `"viewport"` | How the terminal claims space. `"viewport"`: the root becomes a fixed full-viewport box (the full-page product). `"container"`: the root fills your container element, which becomes the styling and positioning boundary (the embedded case). |
147
- | `wsPath` | `"/ws"` | WebSocket endpoint path the engine connects to. |
148
- | `fontReady` | `'14px "MonaspiceNe NFM"'` | CSS font shorthand awaited before the first resize, so the server is sized against the real web font's cell metrics rather than a fallback. |
149
- | `loading` | _(none)_ | A pre-JS loading overlay element (kept in your served HTML so it paints before this module loads); it is faded out and removed once the first frame renders. |
150
- | `onFatalError` | _(built-in recovery)_ | Called after a fatal feature setup failure has stopped the connection, released the terminal runtime, and cleared the root. It receives `{ phase, feature, cause }`. Return `true` only after rendering replacement recovery UI into the root; otherwise the kernel shows its Reload page surface. |
151
- | `theme` | _(none)_ | Theme overrides (CSS custom properties on the terminal root): `--accent`, `--tab-bg`, `--tab-hover-bg`, `--tab-active-bg`, `--tab-active-fg`, `--tab-active-border`, plus the activity-dot palette `--status-working`, `--status-done`, `--status-input` (the working ripple and the input ring derive from their own tokens). The library ships neutral defaults. |
139
+ | Option | Default | Purpose |
140
+ | -------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
141
+ | `features` | _(none; bare kernel)_ | The feature list. Omitted or empty builds only the terminal (no chrome). Use a preset from `./presets` or a hand-picked array. |
142
+ | `layout` | `"viewport"` | How the terminal claims space. `"viewport"`: the root becomes a fixed full-viewport box (the full-page product). `"container"`: the root fills your container element, which becomes the styling and positioning boundary (the embedded case). |
143
+ | `wsPath` | `"/ws"` | WebSocket endpoint path the engine connects to. |
144
+ | `fontReady` | `'14px "MonaspiceNe NFM"'` | CSS font shorthand awaited before the first resize, so the server is sized against the real web font's cell metrics rather than a fallback. |
145
+ | `loading` | _(none)_ | A pre-JS loading overlay element (kept in your served HTML so it paints before this module loads); it is faded out and removed once the first frame renders. |
146
+ | `onFatalError` | _(built-in recovery)_ | Called with `{ phase, feature, cause }` after a fatal feature setup failure; behavior below. |
147
+ | `theme` | _(none)_ | Theme overrides (CSS custom properties on the terminal root): `--accent`, `--tab-bg`, `--tab-hover-bg`, `--tab-active-bg`, `--tab-active-fg`, `--tab-active-border`, plus the activity-dot palette `--status-working`, `--status-done`, `--status-input`. The library ships neutral defaults. |
152
148
 
153
149
  `createTerminal()` returns a handle: `focus()` re-focuses the terminal input
154
150
  (and opens the soft keyboard on touch); `send(bytes)` sends bytes to the active
@@ -178,10 +174,10 @@ replacement recovery UI into the terminal root.
178
174
 
179
175
  The web-terminal family:
180
176
 
181
- - [`web-terminal-engine`](https://github.com/cplieger/web-terminal-engine) — the
177
+ - [`web-terminal-engine`](https://github.com/cplieger/web-terminal-engine): the
182
178
  Go session engine + TypeScript browser renderer this UI is built on (peer
183
179
  dependency).
184
- - [`web-terminal-server`](https://github.com/cplieger/web-terminal-server) — a
180
+ - [`web-terminal-server`](https://github.com/cplieger/web-terminal-server): a
185
181
  ready-to-run container that serves this UI over HTTP + WebSocket for any
186
182
  command.
187
183
 
package/css/30-tabs.css CHANGED
@@ -104,6 +104,16 @@
104
104
  color: var(--tab-active-fg);
105
105
  }
106
106
 
107
+ /* Press (mousedown / touch-hold): one rung past the hover lift — same recipe,
108
+ deeper mix — so hover -> press reads as a single dimension. After the hover
109
+ rule so it wins while both apply. Scoped like hover: clicking the active tab
110
+ selects nothing (it is already active), so it presses like the static surface
111
+ it is. */
112
+ :where(.wt-root) .wt-tab:not(.wt-tab-active):active {
113
+ background: color-mix(in oklch, var(--tab-bg), var(--text) 25%);
114
+ color: var(--tab-active-fg);
115
+ }
116
+
107
117
  /* The active tab reads clearly above the inactive chips: a stronger fill plus an
108
118
  accent-coloured edge (inactive chips carry a faint white --border; the active
109
119
  one gets the accent equivalent). Themeable via --accent (web-terminal-kiro -> purple). */
@@ -166,6 +176,13 @@
166
176
  color: var(--text);
167
177
  }
168
178
 
179
+ /* Press: deepen the hover box (--text-active is a 15% --text wash; press doubles
180
+ it to 30%) so mousedown visibly registers before the tab disappears. */
181
+ :where(.wt-root) .wt-tab-close:active {
182
+ background: color-mix(in oklch, var(--text) 30%, transparent);
183
+ color: var(--text);
184
+ }
185
+
169
186
  /* On an inactive tab the close appears only on hover, kept in the layout via
170
187
  visibility so the tab width never jumps; on the active tab it is always shown. */
171
188
  :where(.wt-root) .wt-tab:not(.wt-tab-active) .wt-tab-close {
@@ -221,6 +238,13 @@
221
238
  background: var(--tab-active-bg);
222
239
  }
223
240
 
241
+ /* Press: brighten the hover fill with the active-tab fg (the
242
+ .wt-switcher-current press recipe — a lighter press over an already-filled
243
+ control), keeping the accent glyph. */
244
+ :where(.wt-root) .wt-tab-new:active {
245
+ background: color-mix(in oklch, var(--tab-active-bg), var(--tab-active-fg) 12%);
246
+ }
247
+
224
248
  /* The +/x icons are inline SVG so they center exactly in their flex-centered
225
249
  button and stay symmetric regardless of the UI font (fixes the off-center
226
250
  glyph and the lopsided "+"). The + is a touch larger and bolder than the x. */
@@ -340,6 +364,12 @@
340
364
  background: var(--text-active);
341
365
  }
342
366
 
367
+ /* Press: deepen the hover wash to 30% --text (the .wt-tab-close press rung) so
368
+ the click registers before the menu closes. */
369
+ :where(.wt-root) .wt-tab-menu button:enabled:active {
370
+ background: color-mix(in oklch, var(--text) 30%, transparent);
371
+ }
372
+
343
373
  :where(.wt-root) .wt-tab-menu button:disabled {
344
374
  color: color-mix(in oklch, var(--text) 35%, transparent);
345
375
  cursor: default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/web-terminal-ui",
3
- "version": "4.5.2",
3
+ "version": "4.6.0",
4
4
  "type": "module",
5
5
  "description": "Reference touch-first browser UI for @cplieger/web-terminal-engine: a composable kernel + feature modules (tabs, activity monitor, mobile toolbar, context menu, IME, predictive echo, viewport handling) and CSS. One createTerminal() call.",
6
6
  "license": "GPL-3.0-or-later",