mirror of
http://10.0.2.1:3031/sauer/claude-code.git
synced 2026-06-30 19:26:58 +10:00
112 lines
12 KiB
TypeScript
112 lines
12 KiB
TypeScript
|
|
import { c as _c } from "react/compiler-runtime";
|
||
|
|
import React, { createContext, useEffect, useState } from 'react';
|
||
|
|
import { FRAME_INTERVAL_MS } from '../constants.js';
|
||
|
|
import { useTerminalFocus } from '../hooks/use-terminal-focus.js';
|
||
|
|
export type Clock = {
|
||
|
|
subscribe: (onChange: () => void, keepAlive: boolean) => () => void;
|
||
|
|
now: () => number;
|
||
|
|
setTickInterval: (ms: number) => void;
|
||
|
|
};
|
||
|
|
export function createClock(tickIntervalMs: number): Clock {
|
||
|
|
const subscribers = new Map<() => void, boolean>();
|
||
|
|
let interval: ReturnType<typeof setInterval> | null = null;
|
||
|
|
let currentTickIntervalMs = tickIntervalMs;
|
||
|
|
let startTime = 0;
|
||
|
|
// Snapshot of the current tick's time, ensuring all subscribers in the same
|
||
|
|
// tick see the same value (keeps animations synchronized)
|
||
|
|
let tickTime = 0;
|
||
|
|
function tick(): void {
|
||
|
|
tickTime = Date.now() - startTime;
|
||
|
|
for (const onChange of subscribers.keys()) {
|
||
|
|
onChange();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function updateInterval(): void {
|
||
|
|
const anyKeepAlive = [...subscribers.values()].some(Boolean);
|
||
|
|
if (anyKeepAlive) {
|
||
|
|
if (interval) {
|
||
|
|
clearInterval(interval);
|
||
|
|
interval = null;
|
||
|
|
}
|
||
|
|
if (startTime === 0) {
|
||
|
|
startTime = Date.now();
|
||
|
|
}
|
||
|
|
interval = setInterval(tick, currentTickIntervalMs);
|
||
|
|
} else if (interval) {
|
||
|
|
clearInterval(interval);
|
||
|
|
interval = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
subscribe(onChange, keepAlive) {
|
||
|
|
subscribers.set(onChange, keepAlive);
|
||
|
|
updateInterval();
|
||
|
|
return () => {
|
||
|
|
subscribers.delete(onChange);
|
||
|
|
updateInterval();
|
||
|
|
};
|
||
|
|
},
|
||
|
|
now() {
|
||
|
|
if (startTime === 0) {
|
||
|
|
startTime = Date.now();
|
||
|
|
}
|
||
|
|
// When the clock interval is running, return the synchronized tickTime
|
||
|
|
// so all subscribers in the same tick see the same value.
|
||
|
|
// When paused (no keepAlive subscribers), return real-time to avoid
|
||
|
|
// returning a stale tickTime from the last tick before the pause.
|
||
|
|
if (interval && tickTime) {
|
||
|
|
return tickTime;
|
||
|
|
}
|
||
|
|
return Date.now() - startTime;
|
||
|
|
},
|
||
|
|
setTickInterval(ms) {
|
||
|
|
if (ms === currentTickIntervalMs) return;
|
||
|
|
currentTickIntervalMs = ms;
|
||
|
|
updateInterval();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
export const ClockContext = createContext<Clock | null>(null);
|
||
|
|
const BLURRED_TICK_INTERVAL_MS = FRAME_INTERVAL_MS * 2;
|
||
|
|
|
||
|
|
// Own component so App.tsx doesn't re-render when the clock is created.
|
||
|
|
// The clock value is stable (created once via useState), so the provider
|
||
|
|
// never causes consumer re-renders on its own.
|
||
|
|
export function ClockProvider(t0) {
|
||
|
|
const $ = _c(7);
|
||
|
|
const {
|
||
|
|
children
|
||
|
|
} = t0;
|
||
|
|
const [clock] = useState(_temp);
|
||
|
|
const focused = useTerminalFocus();
|
||
|
|
let t1;
|
||
|
|
let t2;
|
||
|
|
if ($[0] !== clock || $[1] !== focused) {
|
||
|
|
t1 = () => {
|
||
|
|
clock.setTickInterval(focused ? FRAME_INTERVAL_MS : BLURRED_TICK_INTERVAL_MS);
|
||
|
|
};
|
||
|
|
t2 = [clock, focused];
|
||
|
|
$[0] = clock;
|
||
|
|
$[1] = focused;
|
||
|
|
$[2] = t1;
|
||
|
|
$[3] = t2;
|
||
|
|
} else {
|
||
|
|
t1 = $[2];
|
||
|
|
t2 = $[3];
|
||
|
|
}
|
||
|
|
useEffect(t1, t2);
|
||
|
|
let t3;
|
||
|
|
if ($[4] !== children || $[5] !== clock) {
|
||
|
|
t3 = <ClockContext.Provider value={clock}>{children}</ClockContext.Provider>;
|
||
|
|
$[4] = children;
|
||
|
|
$[5] = clock;
|
||
|
|
$[6] = t3;
|
||
|
|
} else {
|
||
|
|
t3 = $[6];
|
||
|
|
}
|
||
|
|
return t3;
|
||
|
|
}
|
||
|
|
function _temp() {
|
||
|
|
return createClock(FRAME_INTERVAL_MS);
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsImNyZWF0ZUNvbnRleHQiLCJ1c2VFZmZlY3QiLCJ1c2VTdGF0ZSIsIkZSQU1FX0lOVEVSVkFMX01TIiwidXNlVGVybWluYWxGb2N1cyIsIkNsb2NrIiwic3Vic2NyaWJlIiwib25DaGFuZ2UiLCJrZWVwQWxpdmUiLCJub3ciLCJzZXRUaWNrSW50ZXJ2YWwiLCJtcyIsImNyZWF0ZUNsb2NrIiwidGlja0ludGVydmFsTXMiLCJzdWJzY3JpYmVycyIsIk1hcCIsImludGVydmFsIiwiUmV0dXJuVHlwZSIsInNldEludGVydmFsIiwiY3VycmVudFRpY2tJbnRlcnZhbE1zIiwic3RhcnRUaW1lIiwidGlja1RpbWUiLCJ0aWNrIiwiRGF0ZSIsImtleXMiLCJ1cGRhdGVJbnRlcnZhbCIsImFueUtlZXBBbGl2ZSIsInZhbHVlcyIsInNvbWUiLCJCb29sZWFuIiwiY2xlYXJJbnRlcnZhbCIsInNldCIsImRlbGV0ZSIsIkNsb2NrQ29udGV4dCIsIkJMVVJSRURfVElDS19JTlRFUlZBTF9NUyIsIkNsb2NrUHJvdmlkZXIiLCJ0MCIsIiQiLCJfYyIsImNoaWxkcmVuIiwiY2xvY2siLCJfdGVtcCIsImZvY3VzZWQiLCJ0MSIsInQyIiwidDMiXSwic291cmNlcyI6WyJDbG9ja0NvbnRleHQudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBSZWFjdCwgeyBjcmVhdGVDb250ZXh0LCB1c2VFZmZlY3QsIHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBGUkFNRV9JTlRFUlZBTF9NUyB9IGZyb20gJy4uL2NvbnN0YW50cy5qcydcbmltcG9ydCB7IHVzZVRlcm1pbmFsRm9jdXMgfSBmcm9tICcuLi9ob29rcy91c2UtdGVybWluYWwtZm9jdXMuanMnXG5cbmV4cG9ydCB0eXBlIENsb2NrID0ge1xuICBzdWJzY3JpYmU6IChvbkNoYW5nZTogKCkgPT4gdm9pZCwga2VlcEFsaXZlOiBib29sZWFuKSA9PiAoKSA9PiB2b2lkXG4gIG5vdzogKCkgPT4gbnVtYmVyXG4gIHNldFRpY2tJbnRlcnZhbDogKG1zOiBudW1iZXIpID0+IHZvaWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNsb2NrKHRpY2tJbnRlcnZhbE1zOiBudW1iZXIpOiBDbG9jayB7XG4gIGNvbnN0IHN1YnNjcmliZXJzID0gbmV3IE1hcDwoKSA9PiB2b2lkLCBib29sZWFuPigpXG4gIGxldCBpbnRlcnZhbDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0SW50ZXJ2YWw+IHwgbnVsbCA9IG51bGxcbiAgbGV0IGN1cnJlbnRUaWNrSW50ZXJ2YWxNcyA9IHRpY2tJbnRlcnZhbE1zXG4gIGxldCBzdGFydFRpbWUgPSAwXG4gIC8vIFNuYXBzaG90IG9mIHRoZSBjdXJyZW50IHRpY2sncyB0aW1lLCBlbnN1cmluZyBhbGwgc3Vic2NyaWJlcnMgaW4gdGhlIHNhbWVcbiAgLy8gdGljayBzZWUgdGhlIHNhbWUgdmFsdWUgKGtlZXBzIGFuaW1hdGlvbnMgc3luY2hyb25pemVkKVxuICBsZXQgdGlja1RpbWUgPSAwXG5cbiAgZnVuY3Rpb24gdGljaygpOiB2b2lkIHtcbiAgICB0aWNrVGltZSA9IERhdGUubm93KCkgLSBzdGFydFRpbWVcbiAgICBmb3IgKGNvbnN0IG9uQ2hhbmdlIG9mIHN1YnNjcmliZXJzLmtleXMoKSkge1xuICAgICAgb25DaGFuZ2UoKVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZUludGVydmFsKCk6IHZvaWQge1xuICAgIGNvbnN0IGFueUtlZXBBbGl2ZSA9IFsuLi5zdWJzY3JpYmVycy52YWx1ZXMoKV0uc29tZShCb29sZWFuKVxuXG4gICAgaWYgKGFueUtlZXBBbGl2ZSkge1xuICAgICAgaWYgKGludGVydmFsKSB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwoaW50ZXJ2YWwpXG4gICAgICAgIGludGVydmFsID0gbnVsbFxuICAgICAgfVxuICAgICAgaWYgKHN0YXJ0VGltZSA9PT0gMCkge1xuICAgICAgICBzdGFydFRpbWUgPSBEYXRlLm5vdygpXG4gICAgICB9XG4gICAgICBpbnRlcnZhbCA9IHNldEludGVydmFsKHRpY2ssIGN1cnJlbnRUaWNrSW50ZXJ2YWxNcylcbiAgICB9IGVsc2UgaWYgKGludGVydmFsKSB7XG4gICAgICBjbGVhckludGVydmFsKGludGVydmFsKVxuICAgICAgaW50ZXJ2YWwgPSBudWxsXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBzdWJzY3JpYmUob25DaGFuZ2UsIGtlZXBBbGl2ZSkge1xuICAgICAgc3Vic2NyaWJlcnMuc2V0KG9uQ2hhbmdlLCBrZWVwQWxpdmUpXG4gICAgICB1cGRhdGVJbnRlcnZhbCgpXG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBzdWJzY3JpYmVycy5kZWxldGUob25DaGFuZ2UpXG4gICAgICAgIHVwZGF0ZUludGVydmFsKClcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgbm93KCkge1xuICAgICAgaWYgKHN0YXJ0VGltZSA9PT0gMCkge1xuICAgICAgICBzdGFydFRpbWUgPSBEYXRlLm5vdygpXG4gICAgICB9XG4gICAgICAvLyBXaGVuIHRoZSBjbG9jayBpbnRlcnZhbCBpcyBydW5uaW5nLCByZXR1cm4gdGhlIHN5bmNocm9uaXplZCB0aWNrVGltZVxuICAgICAgLy8gc28gYWxsIHN1YnNjcmliZXJzIGluIHRoZSBzYW1lIHRpY2sgc2VlIHRoZSBzYW1lIHZhbHVlLlxuICAgICAgLy8gV2hlbiBwYXVzZWQgKG5vIGtlZXBBbGl2ZSBzdWJzY3JpYmVycyksIHJldHVybiByZWFsLXRpbWUgdG8gYXZvaWRcbiAgICAgIC8vIHJldHVybmluZyBhIHN0YWxlIHRpY2tUaW1lIGZyb20gdGhlIGxhc3QgdGljayBiZWZvcmUgdGhlIHBhdXNlLlxuICAgICAgaWYgKGludGVydmFsICYmIHRpY2tUaW1lKSB7XG4gICAgICAgIHJldHVybiB0aWNrVGltZVxuICAgICAgfVxuICAgICAgcmV0dXJuIERhdGUubm93KCkgLSBzdGFydFRpbWVcbiAgICB9LFxuXG4gICAgc2V0VGlja0ludGVydmFsKG1zKSB7XG4gICAgICBpZiAobXMgPT09IGN1cnJlbnRUaWNrSW50ZXJ2YWxNcykgcmV0dXJuXG4gICAgICBjdXJyZW50VGlja0ludGVydmFsTXMgPSBtc1xuICAgICAgdXBkYXRlSW50ZXJ2YWwoKVxuICAgIH0sXG4gIH1cbn1cblxuZXhwb3J0IGNvbnN0IENsb2NrQ29udGV4dCA9IGNyZWF0ZUNvbnRleHQ8Q2xvY2sgfCBudWxsPihudWxsKVxuXG5jb25zdCBCTFVSUkVEX1RJQ0tfSU5URVJWQUxfTVMgPSBGUkFNRV9JTlRFUlZBTF9NUyAqIDJcblxuLy8gT3duIGNvbXBvbmVudCBzbyBBcHAudHN4IGRvZXNuJ3QgcmUtcmVuZGVyIHdoZW4gdGhlIGNsb2NrIGlzIGNyZWF0ZWQuXG4vLyB
|