@cplieger/web-terminal-ui 4.5.1 → 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 +42 -41
- package/css/30-tabs.css +76 -34
- package/css/31-switcher.css +4 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,15 +8,14 @@
|
|
|
8
8
|
[](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)
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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()
|
|
119
|
+
- `presetSingle()`: single-pane desktop UI (context menu, clipboard,
|
|
121
120
|
scroll-to-bottom, predictive echo, connection banner).
|
|
122
|
-
- `presetTouch()
|
|
123
|
-
- `presetTabbed()
|
|
124
|
-
activity monitor, and animations. Each tab's title is OSC-first
|
|
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()
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
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)
|
|
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
|
|
|
@@ -190,6 +186,11 @@ Consumers that ship this UI:
|
|
|
190
186
|
- [`vibekit`](https://github.com/cplieger/vibekit)
|
|
191
187
|
- [`web-terminal-kiro`](https://github.com/cplieger/web-terminal-kiro)
|
|
192
188
|
|
|
189
|
+
## Contributing
|
|
190
|
+
|
|
191
|
+
Issues and PRs are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the
|
|
192
|
+
conventions and how to run the checks locally.
|
|
193
|
+
|
|
193
194
|
## Disclaimer
|
|
194
195
|
|
|
195
196
|
This project is built with care and follows security best practices, but it is intended for personal / self-hosted use. No guarantees of fitness for production environments. Use at your own risk.
|
|
@@ -198,4 +199,4 @@ This project was built with AI-assisted tooling using [Claude](https://claude.co
|
|
|
198
199
|
|
|
199
200
|
## License
|
|
200
201
|
|
|
201
|
-
GPL-3.0-or-later. See
|
|
202
|
+
GPL-3.0-or-later. See [LICENSE](LICENSE).
|
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). */
|
|
@@ -121,6 +131,17 @@
|
|
|
121
131
|
overflow: hidden;
|
|
122
132
|
white-space: nowrap;
|
|
123
133
|
text-overflow: ellipsis;
|
|
134
|
+
/* Center the INK, not the line box: UI fonts carry more ascent than descent
|
|
135
|
+
(Noto Sans at 13px: 14px over / 4px under the baseline), so the flex-
|
|
136
|
+
centered line box leaves the visible text ~1.5px low — reading as
|
|
137
|
+
baseline-aligned with the activity dot's bottom instead of its center.
|
|
138
|
+
Trimming the box to the cap-height/alphabetic band makes flexbox center
|
|
139
|
+
the glyphs themselves, on every platform font. Descender ink still paints
|
|
140
|
+
(verified: ink overflow survives the overflow: hidden ellipsis clip).
|
|
141
|
+
Non-supporting browsers simply keep the untrimmed box. Shared by all
|
|
142
|
+
three chip labels (this one + the two switcher labels in
|
|
143
|
+
31-switcher.css). */
|
|
144
|
+
text-box: trim-both cap alphabetic;
|
|
124
145
|
}
|
|
125
146
|
|
|
126
147
|
/* A little breathing room after the activity dot, before the label. */
|
|
@@ -155,6 +176,13 @@
|
|
|
155
176
|
color: var(--text);
|
|
156
177
|
}
|
|
157
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
|
+
|
|
158
186
|
/* On an inactive tab the close appears only on hover, kept in the layout via
|
|
159
187
|
visibility so the tab width never jumps; on the active tab it is always shown. */
|
|
160
188
|
:where(.wt-root) .wt-tab:not(.wt-tab-active) .wt-tab-close {
|
|
@@ -210,6 +238,13 @@
|
|
|
210
238
|
background: var(--tab-active-bg);
|
|
211
239
|
}
|
|
212
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
|
+
|
|
213
248
|
/* The +/x icons are inline SVG so they center exactly in their flex-centered
|
|
214
249
|
button and stay symmetric regardless of the UI font (fixes the off-center
|
|
215
250
|
glyph and the lopsided "+"). The + is a touch larger and bolder than the x. */
|
|
@@ -329,6 +364,12 @@
|
|
|
329
364
|
background: var(--text-active);
|
|
330
365
|
}
|
|
331
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
|
+
|
|
332
373
|
:where(.wt-root) .wt-tab-menu button:disabled {
|
|
333
374
|
color: color-mix(in oklch, var(--text) 35%, transparent);
|
|
334
375
|
cursor: default;
|
|
@@ -401,15 +442,14 @@
|
|
|
401
442
|
border: 1.5px solid color-mix(in oklch, var(--text) 45%, transparent);
|
|
402
443
|
}
|
|
403
444
|
|
|
404
|
-
/* Agent working:
|
|
405
|
-
"
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
working from input; the ring separates both from done's bare disc. The old
|
|
445
|
+
/* Agent working: a solid disc with two animated cues (the status-badge
|
|
446
|
+
"processing" idiom — Ant Design's processing badge, the classic CSS
|
|
447
|
+
live-indicator ripple): the disc keeps full opacity and gently GLOWS (its
|
|
448
|
+
colors brighten mid-beat), while a ::after ring RIPPLES outward off the
|
|
449
|
+
disc's edge and dissolves, re-emitted each cycle. No static ring at rest —
|
|
450
|
+
the disc + live ripple ARE the working read; input freezes that exact ping
|
|
451
|
+
at its birth frame (see input below), so motion separates working from
|
|
452
|
+
input, and the ring separates both from done's bare disc. The old
|
|
413
453
|
single-layer pulse faded disc + ring together (opacity on the element),
|
|
414
454
|
which read as a blink and coupled the layers — an element's opacity always
|
|
415
455
|
multiplies onto its pseudos, so true independence requires animating disc
|
|
@@ -420,16 +460,15 @@
|
|
|
420
460
|
position: relative;
|
|
421
461
|
background: var(--status-working);
|
|
422
462
|
border-color: var(--status-working);
|
|
423
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--status-working) 40%, transparent);
|
|
424
463
|
animation: wt-working-glow 1.2s ease-in-out infinite;
|
|
425
464
|
}
|
|
426
465
|
|
|
427
|
-
/* The ripple layer: at scale(1) its 2px border
|
|
428
|
-
9->13px band
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
466
|
+
/* The ripple layer: at scale(1) its 2px border hugs the disc's edge (inset
|
|
467
|
+
-2px, the 9->13px band), then the wave detaches, expanding and fading.
|
|
468
|
+
transform + opacity only, so it composites without repaints. It exists only
|
|
469
|
+
in the working state — no stale layer to pin when a dot changes status.
|
|
470
|
+
(The switcher notification dot never shows working — input/done only — so
|
|
471
|
+
its position: absolute placement never meets this rule's
|
|
433
472
|
position: relative.) */
|
|
434
473
|
:where(.wt-root) .wt-status-dot[data-status="working"]::after {
|
|
435
474
|
content: "";
|
|
@@ -449,18 +488,19 @@
|
|
|
449
488
|
border-color: var(--status-done);
|
|
450
489
|
}
|
|
451
490
|
|
|
452
|
-
/* User action required (permission / approval): working
|
|
453
|
-
solid dot + 2px ring
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
agent's turn is mid-flight but
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
until you act on or switch into
|
|
491
|
+
/* User action required (permission / approval): the working ping frozen at
|
|
492
|
+
its birth frame — solid dot + the same 2px ring at the ripple's 30% birth
|
|
493
|
+
opacity, motionless (--status-input; the default orange is shifted away
|
|
494
|
+
from the old amber so it separates from both default-lime working and green
|
|
495
|
+
done). The stillness is the message: the agent's turn is mid-flight but
|
|
496
|
+
blocked on you. The ring keeps it distinct from done's bare disc without
|
|
497
|
+
leaning on hue; it derives from the same token, so a theme override
|
|
498
|
+
recolors dot + ring together. It persists until you act on or switch into
|
|
499
|
+
the tab. */
|
|
460
500
|
:where(.wt-root) .wt-status-dot[data-status="input"] {
|
|
461
501
|
background: var(--status-input);
|
|
462
502
|
border-color: var(--status-input);
|
|
463
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--status-input)
|
|
503
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--status-input) 30%, transparent);
|
|
464
504
|
}
|
|
465
505
|
|
|
466
506
|
/* Exited: a dim hollow dot, static; distinct from idle by its lower opacity. */
|
|
@@ -490,13 +530,14 @@
|
|
|
490
530
|
}
|
|
491
531
|
}
|
|
492
532
|
|
|
493
|
-
/* The ripple wave: one emission per cycle, launching off the
|
|
494
|
-
dissolving by ~2.1x.
|
|
495
|
-
|
|
533
|
+
/* The ripple wave: one emission per cycle, launching off the disc's edge and
|
|
534
|
+
dissolving by ~2.1x. The 0.3 birth opacity matches the input ring's frozen
|
|
535
|
+
weight, so a live ping and a stuck one read as the same object — subtle
|
|
536
|
+
against the bar now that no static ring doubles it at birth. */
|
|
496
537
|
@keyframes wt-working-ripple {
|
|
497
538
|
0% {
|
|
498
539
|
transform: scale(1);
|
|
499
|
-
opacity: 0.
|
|
540
|
+
opacity: 0.3;
|
|
500
541
|
}
|
|
501
542
|
|
|
502
543
|
100% {
|
|
@@ -509,13 +550,14 @@
|
|
|
509
550
|
@media (prefers-reduced-motion: reduce) {
|
|
510
551
|
:where(.wt-root) .wt-status-dot[data-status="working"] {
|
|
511
552
|
animation: none;
|
|
512
|
-
/* Motion is what separates working from input's frozen
|
|
513
|
-
|
|
514
|
-
input (solid ringed disc) and done (bare disc) by
|
|
515
|
-
(WCAG 1.4.1). The
|
|
553
|
+
/* Motion is what separates working from input's frozen ping; with it
|
|
554
|
+
removed, punch an inner hole (dot -> donut) and add a static ring so
|
|
555
|
+
working differs from input (solid ringed disc) and done (bare disc) by
|
|
556
|
+
shape, not hue alone (WCAG 1.4.1). The ring carries the same 30%
|
|
557
|
+
weight as input's. */
|
|
516
558
|
box-shadow:
|
|
517
559
|
inset 0 0 0 2px var(--bg),
|
|
518
|
-
0 0 0 2px color-mix(in srgb, var(--status-working)
|
|
560
|
+
0 0 0 2px color-mix(in srgb, var(--status-working) 30%, transparent);
|
|
519
561
|
}
|
|
520
562
|
|
|
521
563
|
/* The ripple layer disappears entirely (not just paused mid-wave). */
|
package/css/31-switcher.css
CHANGED
|
@@ -178,6 +178,8 @@
|
|
|
178
178
|
text-overflow: ellipsis;
|
|
179
179
|
white-space: nowrap;
|
|
180
180
|
text-align: left;
|
|
181
|
+
/* Ink-centering trim, same as .wt-tab-label (see 30-tabs.css). */
|
|
182
|
+
text-box: trim-both cap alphabetic;
|
|
181
183
|
}
|
|
182
184
|
|
|
183
185
|
/* Keyboard button: hidden until a keyboardToggle is wired; filled while the key
|
|
@@ -418,6 +420,8 @@
|
|
|
418
420
|
overflow: hidden;
|
|
419
421
|
text-overflow: ellipsis;
|
|
420
422
|
white-space: nowrap;
|
|
423
|
+
/* Ink-centering trim, same as .wt-tab-label (see 30-tabs.css). */
|
|
424
|
+
text-box: trim-both cap alphabetic;
|
|
421
425
|
}
|
|
422
426
|
|
|
423
427
|
/* The close sits flush at the row's right edge (no gap), vertically centered. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/web-terminal-ui",
|
|
3
|
-
"version": "4.
|
|
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",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"happy-dom": "20.11.0",
|
|
54
54
|
"html-validate": "11.5.6",
|
|
55
55
|
"knip": "6.27.0",
|
|
56
|
-
"prettier": "3.9.
|
|
56
|
+
"prettier": "3.9.6",
|
|
57
57
|
"stylelint": "17.14.1",
|
|
58
58
|
"stylelint-config-standard": "40.0.0",
|
|
59
59
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|