@cplieger/web-terminal-ui 3.4.1 → 3.4.3
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/css/00-tokens.css +8 -2
- package/css/06-mobile.css +12 -0
- package/package.json +1 -1
- package/src/features/tabs.ts +38 -26
package/css/00-tokens.css
CHANGED
|
@@ -19,9 +19,15 @@
|
|
|
19
19
|
in oklch,
|
|
20
20
|
var(--accent) 30%,
|
|
21
21
|
var(--surface)
|
|
22
|
-
); /* active tab fill: accent-derived (a blue by default; themed per consumer), so the active tab reads blue with
|
|
22
|
+
); /* active tab fill: accent-derived (a blue by default; themed per consumer), so the active tab reads blue with a subtle lighter edge below */
|
|
23
|
+
|
|
23
24
|
--tab-active-fg: var(--text); /* active tab text */
|
|
24
|
-
--tab-active-border: color-mix(
|
|
25
|
+
--tab-active-border: color-mix(
|
|
26
|
+
in oklch,
|
|
27
|
+
var(--tab-active-bg),
|
|
28
|
+
var(--text) 25%
|
|
29
|
+
); /* subtle edge: the fill lightened + slightly desaturated, matching the inactive chip's faint border rather than a vivid accent outline */
|
|
30
|
+
|
|
25
31
|
--radius: 0.75rem;
|
|
26
32
|
--radius-inner: 0.5rem;
|
|
27
33
|
/* Small square icon buttons (e.g. the 24px tab-close x): at that size the
|
package/css/06-mobile.css
CHANGED
|
@@ -254,6 +254,18 @@
|
|
|
254
254
|
margin-inline-start: 0;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/* When the tab list expands the switch button collapses too (its job is done:
|
|
258
|
+
the list is open), mirroring the keyboard button's collapse in the same
|
|
259
|
+
animation (07-animations.css animates width + margin + opacity). Placed after
|
|
260
|
+
the .wt-switcher-multi reveal so it wins when both apply (expanded, two or
|
|
261
|
+
more tabs). */
|
|
262
|
+
.wt-switcher-expanded .wt-switcher-switch {
|
|
263
|
+
width: 0;
|
|
264
|
+
opacity: 0;
|
|
265
|
+
margin-inline-start: calc(-1 * var(--sp-1));
|
|
266
|
+
pointer-events: none;
|
|
267
|
+
}
|
|
268
|
+
|
|
257
269
|
@media (hover: hover) {
|
|
258
270
|
.wt-switcher-switch:hover {
|
|
259
271
|
background: var(--tab-hover-bg);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/web-terminal-ui",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.3",
|
|
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",
|
package/src/features/tabs.ts
CHANGED
|
@@ -160,10 +160,12 @@ export interface TabsOptions {
|
|
|
160
160
|
const CLOSE_SVG = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6 18 18M18 6 6 18"/></svg>`;
|
|
161
161
|
const NEW_SVG = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>`;
|
|
162
162
|
const KB_SVG = `<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="3.5"/><path d="M15 15 9.5 9.5M9.5 13V9.5H13"/></svg>`;
|
|
163
|
-
// Two-
|
|
164
|
-
// button
|
|
165
|
-
//
|
|
166
|
-
|
|
163
|
+
// Two-overlapping-windows glyph for the mobile switcher's dedicated open/close
|
|
164
|
+
// button: the browser-style "tab switcher" icon, more recognisable than the
|
|
165
|
+
// prior swap-arrows (which read like a keyboard Tab key). A latest-wins
|
|
166
|
+
// background-tab notification dot rides on it (see switchButtonHTML). Same
|
|
167
|
+
// viewBox + stroke=currentcolor treatment as the others.
|
|
168
|
+
const SWITCH_SVG = `<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="8" width="13" height="13" rx="2"/><path d="M8 8V6a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-3"/></svg>`;
|
|
167
169
|
|
|
168
170
|
// chipContent is the ONE builder for a tab chip's content — a status dot, a
|
|
169
171
|
// label, and a close (x) — shared by all three chip sites: the desktop strip
|
|
@@ -1099,33 +1101,43 @@ export function tabs(opts: TabsOptions = {}): TerminalFeature<TabsApi> {
|
|
|
1099
1101
|
from = first - el.getBoundingClientRect().top; // survivor: old spot -> new
|
|
1100
1102
|
} else {
|
|
1101
1103
|
from = dir === "next" ? pitch : -pitch; // newcomer: in from the trailing edge
|
|
1102
|
-
el.style.opacity = "0";
|
|
1104
|
+
el.style.opacity = "0"; // fades in as it rotates to its slot (below)
|
|
1103
1105
|
}
|
|
1104
1106
|
el.style.transition = "none";
|
|
1105
1107
|
el.style.transform = `translateY(${String(Math.round(from))}px)`;
|
|
1106
1108
|
}
|
|
1107
1109
|
const exit = dir === "next" ? -pitch : pitch; // leaving row off the leading edge
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1110
|
+
// The leaving row starts at its captured spot, fully opaque.
|
|
1111
|
+
ghost.style.transition = "none";
|
|
1112
|
+
ghost.style.transform = "translateY(0)";
|
|
1113
|
+
ghost.style.opacity = "1";
|
|
1114
|
+
// Commit the from-state (transforms + opacities) with a forced reflow
|
|
1115
|
+
// BEFORE the to-state, so BOTH the transform and the opacity transitions
|
|
1116
|
+
// fire from it. The prior code used a bare rAF (letting the browser
|
|
1117
|
+
// collapse from->to into one recalc) and reverted the entering row's
|
|
1118
|
+
// opacity to "" (no explicit end value), so the fade never animated
|
|
1119
|
+
// (the reported "no fade in / fade out"). The modern display/visibility
|
|
1120
|
+
// transition (transition-behavior: allow-discrete + @starting-style,
|
|
1121
|
+
// Baseline 2024) does NOT apply here: these rows are reused and moved by
|
|
1122
|
+
// a JS transform FLIP, not toggled via display:none, so the reliable
|
|
1123
|
+
// path is a real reflow plus an explicit opacity transition.
|
|
1124
|
+
swList.getBoundingClientRect(); // read forces the reflow (commit the from-state)
|
|
1125
|
+
// Couple opacity to the SAME easing + duration as the transform so a
|
|
1126
|
+
// row's fade tracks its DISTANCE from its target slot (each reel row
|
|
1127
|
+
// travels one pitch): a row is transparent a pitch away (at the clipped
|
|
1128
|
+
// edge) and only fully opaque once it settles. Entering rows fade IN as
|
|
1129
|
+
// they rotate in, the leaving row fades OUT as it exits: no hard cutoff
|
|
1130
|
+
// at the list edges and no permanent edge mask.
|
|
1131
|
+
const trans =
|
|
1132
|
+
"transform 0.25s cubic-bezier(0.2, 0, 0, 1), opacity 0.25s cubic-bezier(0.2, 0, 0, 1)";
|
|
1133
|
+
for (const el of rowEls.values()) {
|
|
1134
|
+
el.style.transition = trans;
|
|
1135
|
+
el.style.transform = "translateY(0)";
|
|
1136
|
+
el.style.opacity = "1";
|
|
1137
|
+
}
|
|
1138
|
+
ghost.style.transition = trans;
|
|
1139
|
+
ghost.style.transform = `translateY(${String(Math.round(exit))}px)`;
|
|
1140
|
+
ghost.style.opacity = "0";
|
|
1129
1141
|
reelTimer = setTimeout(endReelNow, REEL_MS);
|
|
1130
1142
|
};
|
|
1131
1143
|
}
|