@cplieger/web-terminal-ui 6.1.1 → 6.1.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/page.css +25 -6
- package/package.json +2 -2
- package/src/features/tabs/index.ts +42 -1
package/css/page.css
CHANGED
|
@@ -73,10 +73,15 @@ body {
|
|
|
73
73
|
--wt-loading-bg: #000;
|
|
74
74
|
--wt-loading-bar-inline-size: min(220px, 62vw);
|
|
75
75
|
--wt-loading-bar-block-size: 5px;
|
|
76
|
-
/* Symmetric
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
/* Symmetric, deliberately NOT one of the component easing tokens: those are all
|
|
77
|
+
asymmetric (they settle at one end), which reads as a stutter on a looping
|
|
78
|
+
indeterminate sweep. It is also deliberately NOT an ease-in-out-cubic
|
|
79
|
+
(`cubic-bezier(0.65, 0, 0.35, 1)`, what this was): a curve with zero velocity
|
|
80
|
+
at both ends spends its two slow phases exactly where the sweep is clipped
|
|
81
|
+
off-screen, which measured as 315 ms of blank track at each end of every
|
|
82
|
+
1.5 s lap. Non-zero end velocity keeps the symmetry and cuts that to 90 ms,
|
|
83
|
+
below the point where the loop reads as a stall. */
|
|
84
|
+
--wt-loading-sweep-easing: cubic-bezier(0.3, 0.25, 0.7, 0.75);
|
|
80
85
|
--wt-loading-sweep-duration: 1.5s;
|
|
81
86
|
|
|
82
87
|
position: fixed;
|
|
@@ -129,6 +134,15 @@ body {
|
|
|
129
134
|
content: "";
|
|
130
135
|
position: absolute;
|
|
131
136
|
inset-block: 0;
|
|
137
|
+
/* Load-bearing, and the whole reason the sweep used to enter mid-track: with
|
|
138
|
+
both inline offsets `auto` an absolutely positioned box falls back to its
|
|
139
|
+
STATIC position, and .wt-loading sets `text-align: center`, which centres
|
|
140
|
+
that static position inside the 220px track. The keyframes below are written
|
|
141
|
+
against the track's left edge, so every offset was silently shifted right by
|
|
142
|
+
(220 - 92.4) / 2 = 64px: the sweep was already visible at t=0 near the left
|
|
143
|
+
of centre, and it left the track at ~73% of the cycle. Pinning the origin is
|
|
144
|
+
what makes translateX(-100%) mean "one full sweep-width off the left edge". */
|
|
145
|
+
inset-inline-start: 0;
|
|
132
146
|
inline-size: 42%;
|
|
133
147
|
border-radius: inherit;
|
|
134
148
|
background: linear-gradient(
|
|
@@ -167,12 +181,17 @@ body {
|
|
|
167
181
|
opacity: 0;
|
|
168
182
|
}
|
|
169
183
|
|
|
184
|
+
/* Offsets are percentages of the SWEEP (42% of the track), not of the track, so
|
|
185
|
+
-100% is exactly one sweep-width left of the origin (fully clipped, flush with
|
|
186
|
+
the left edge) and 100% / 0.42 = 238% puts its left edge flush with the right
|
|
187
|
+
edge. Flush at both ends rather than over-travelled: every pixel of travel
|
|
188
|
+
outside the track is dead time on a screen whose only job is to look alive. */
|
|
170
189
|
@keyframes wt-loading-slide {
|
|
171
190
|
0% {
|
|
172
|
-
transform: translateX(-
|
|
191
|
+
transform: translateX(-100%);
|
|
173
192
|
}
|
|
174
193
|
100% {
|
|
175
|
-
transform: translateX(
|
|
194
|
+
transform: translateX(238%);
|
|
176
195
|
}
|
|
177
196
|
}
|
|
178
197
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/web-terminal-ui",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.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": "MPL-2.0",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"eslint": "10.8.1",
|
|
57
57
|
"fast-check": "4.9.0",
|
|
58
58
|
"happy-dom": "20.11.2",
|
|
59
|
-
"html-validate": "11.
|
|
59
|
+
"html-validate": "11.7.0",
|
|
60
60
|
"knip": "6.32.2",
|
|
61
61
|
"prettier": "3.9.6",
|
|
62
62
|
"stylelint": "17.14.1",
|
|
@@ -152,7 +152,13 @@ export interface TabsOptions {
|
|
|
152
152
|
*
|
|
153
153
|
* Not every platform honours it: Safari caches the first icon it fetched and
|
|
154
154
|
* ignores later changes, and an installed app has no tab icon at all. The
|
|
155
|
-
* title count is not gated on this, so those cases lose nothing.
|
|
155
|
+
* title count is not gated on this, so those cases lose nothing.
|
|
156
|
+
*
|
|
157
|
+
* The links are restored on `pagehide` as well as on teardown, because a
|
|
158
|
+
* browser remembers one icon per URL and renders it for the bookmark, the
|
|
159
|
+
* history row and the new-tab tile. Best-effort there, since the write races
|
|
160
|
+
* the unload. Deliberately not on `freeze`: a frozen background tab is still in
|
|
161
|
+
* the strip rendering its icon, which is the case this exists for. */
|
|
156
162
|
attentionIcons?: boolean;
|
|
157
163
|
}
|
|
158
164
|
|
|
@@ -601,6 +607,39 @@ export function tabs(opts: TabsOptions = {}): TerminalFeature<TabsApi> {
|
|
|
601
607
|
}
|
|
602
608
|
document.addEventListener("visibilitychange", onPageVisible);
|
|
603
609
|
|
|
610
|
+
// onPageGone hands the page's own icon back before the page GOES AWAY,
|
|
611
|
+
// which is a different question from the page being hidden and needs a
|
|
612
|
+
// different event. A browser remembers ONE icon per URL and renders it for
|
|
613
|
+
// the bookmark, the history row and the new-tab tile, so a tab closed while
|
|
614
|
+
// a cue was lit leaves a status variant standing in for the app until the
|
|
615
|
+
// page is next loaded.
|
|
616
|
+
//
|
|
617
|
+
// `pagehide`, and deliberately NOT `freeze`. freeze fires for a background
|
|
618
|
+
// tab the browser is conserving resources on (Android after five minutes in
|
|
619
|
+
// the background; desktop for a collapsed tab group and, since Chrome 133, a
|
|
620
|
+
// CPU-heavy tab under Energy Saver), and that tab is STILL in the strip
|
|
621
|
+
// rendering its icon — restoring there would blank the cue in exactly the
|
|
622
|
+
// case the cue exists for. pagehide fires on unload, tab close and bfcache
|
|
623
|
+
// entry, where no strip entry is left to render.
|
|
624
|
+
//
|
|
625
|
+
// Through apply() rather than the icon sink directly, because the sinks are
|
|
626
|
+
// change-gated on the last applied value: writing behind that memo would
|
|
627
|
+
// leave it believing the variant is still up, and a page restored from the
|
|
628
|
+
// bfcache would then never repaint it. Which is what onPageBack is for — a
|
|
629
|
+
// bfcache restore re-runs the fold, so the cue returns for a page that did
|
|
630
|
+
// not actually go away. Best-effort on a real unload, where the icon write
|
|
631
|
+
// races the teardown, and a no-op when nothing was lit.
|
|
632
|
+
function onPageGone(): void {
|
|
633
|
+
attention.apply(NO_ATTENTION);
|
|
634
|
+
}
|
|
635
|
+
function onPageBack(event: PageTransitionEvent): void {
|
|
636
|
+
if (event.persisted) {
|
|
637
|
+
paintAttention();
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
window.addEventListener("pagehide", onPageGone);
|
|
641
|
+
window.addEventListener("pageshow", onPageBack);
|
|
642
|
+
|
|
604
643
|
// paintAttention re-derives the whole attention state from the tab list and
|
|
605
644
|
// this viewer's acknowledgements, and hands it to the surfaces.
|
|
606
645
|
//
|
|
@@ -4115,6 +4154,8 @@ export function tabs(opts: TabsOptions = {}): TerminalFeature<TabsApi> {
|
|
|
4115
4154
|
offMenuKey();
|
|
4116
4155
|
document.removeEventListener("click", onDocClickMenu);
|
|
4117
4156
|
document.removeEventListener("visibilitychange", onPageVisible);
|
|
4157
|
+
window.removeEventListener("pagehide", onPageGone);
|
|
4158
|
+
window.removeEventListener("pageshow", onPageBack);
|
|
4118
4159
|
document.removeEventListener("contextmenu", onDocContextMenu);
|
|
4119
4160
|
document.removeEventListener("pointerup", onDocTapDismiss, true);
|
|
4120
4161
|
document.removeEventListener("dragover", onDocTabDrop);
|