Skip to content

Commit a39631c

Browse files
V48 (implementation-only): Fix Processing ellipsis cursor layout jitter
Reserve a fixed 3ch ellipsis slot and animate dots via clip-width instead of TypingAnimation retyping "...", so the caret after Processing no longer shifts as dots cycle.
1 parent 3d417e1 commit a39631c

2 files changed

Lines changed: 93 additions & 10 deletions

File tree

uapi/components/bitcode/indicators/ProcessingIndicator/ProcessingIndicator.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
'use client';
22

3-
import TypingAnimation from '@/components/bitcode/TypingAnimation/TypingAnimation';
3+
/**
4+
* ProcessingIndicator — live-run status chrome (orb + label + ellipsis + cursor).
5+
*
6+
* Ellipsis uses a fixed-width slot so the typing cursor does not jitter as
7+
* dots cycle (TypingAnimation previously retyped "..." and shifted layout).
8+
*/
9+
410
import React, { useEffect, useRef, memo } from 'react';
511

612
interface ProcessingIndicatorProps {
@@ -86,13 +92,12 @@ export const ProcessingIndicator = memo(({ label = 'Processing', stalled = false
8692
: 'processing-text text-brand-emerald text-neon'
8793
}
8894
>
89-
{label}
90-
<TypingAnimation
91-
loop={true}
92-
text="..."
93-
duration={150}
94-
className="!text-[13px] !font-light !leading-none !tracking-wider !text-left"
95-
/>
95+
<span className="processing-label">{label}</span>
96+
{/* Fixed-width ellipsis slot: dots clip-reveal in-place; cursor stays put. */}
97+
<span className="processing-ellipsis" aria-hidden="true">
98+
<span className="processing-ellipsis-fill" />
99+
</span>
100+
<span className="processing-cursor" aria-hidden="true" />
96101
</div>
97102

98103
{/* Subtle underline animation */}

uapi/styles/processing-indicator.css

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,91 @@
8888
letter-spacing: 0.1em;
8989
opacity: 0.8;
9090
padding: 4px;
91-
display: flex;
91+
display: inline-flex;
9292
align-items: baseline;
93-
gap: 4px;
93+
gap: 0;
9494

9595
animation: processing-text-breathe 4s ease-in-out infinite;
9696
}
9797

98+
.processing-label {
99+
flex: 0 0 auto;
100+
}
101+
102+
/*
103+
* Fixed-width ellipsis slot: outer box is always 3ch so the cursor never
104+
* shifts. Inner clip reveals 0→3 dots without changing layout width.
105+
*/
106+
.processing-ellipsis {
107+
display: inline-block;
108+
width: 3ch;
109+
min-width: 3ch;
110+
max-width: 3ch;
111+
flex: 0 0 3ch;
112+
overflow: hidden;
113+
white-space: nowrap;
114+
vertical-align: baseline;
115+
letter-spacing: 0.02em;
116+
font-variant-numeric: tabular-nums;
117+
line-height: inherit;
118+
}
119+
120+
.processing-ellipsis-fill {
121+
display: inline-block;
122+
white-space: nowrap;
123+
overflow: hidden;
124+
width: 0;
125+
max-width: 3ch;
126+
animation: processing-ellipsis-reveal 1.2s steps(4, end) infinite;
127+
}
128+
129+
.processing-ellipsis-fill::before {
130+
content: '...';
131+
}
132+
133+
@keyframes processing-ellipsis-reveal {
134+
0% {
135+
width: 0;
136+
}
137+
100% {
138+
width: 3ch;
139+
}
140+
}
141+
142+
/* Stable caret after the fixed ellipsis slot — never moves with dots. */
143+
.processing-cursor {
144+
display: inline-block;
145+
width: 2px;
146+
height: 1.05em;
147+
margin-left: 2px;
148+
flex: 0 0 2px;
149+
align-self: center;
150+
background-color: rgba(103, 254, 183, 0.9);
151+
box-shadow:
152+
0 0 8px rgba(103, 254, 183, 0.5),
153+
0 0 12px rgba(103, 254, 183, 0.3);
154+
border-radius: 1px;
155+
vertical-align: middle;
156+
animation: processing-cursor-blink 0.8s step-end infinite;
157+
}
158+
159+
.processing-text.text-amber-400 .processing-cursor {
160+
background-color: rgba(251, 191, 36, 0.9);
161+
box-shadow:
162+
0 0 8px rgba(251, 191, 36, 0.45),
163+
0 0 12px rgba(251, 191, 36, 0.25);
164+
}
165+
166+
@keyframes processing-cursor-blink {
167+
0%,
168+
100% {
169+
opacity: 1;
170+
}
171+
50% {
172+
opacity: 0;
173+
}
174+
}
175+
98176
/* Underline animation */
99177
.processing-underline {
100178
position: absolute;

0 commit comments

Comments
 (0)