askeroo
Version:
A modern CLI prompt library with flow control, history navigation, and conditional prompts
96 lines • 3.7 kB
JavaScript
import { createPrompt } from "../../core/registry.js";
import { SpinnerDisplay } from "./Spinner.js";
import { spinnerStore } from "./spinner-store.js";
// Track the most recent spinner ID
let currentSpinnerId = null;
// Internal plugin implementation
const spinnerInternal = createPrompt({
type: "spinner",
component: SpinnerDisplay,
});
// Function to update spinner state
function updateSpinnerState(spinnerId, status, label, currentStyle) {
spinnerStore.update((s) => {
const currentState = s.spinners.get(spinnerId) || { status: "idle" };
// Merge style with existing style instead of replacing
const mergedStyle = currentStyle
? { ...currentState.currentStyle, ...currentStyle }
: currentState.currentStyle;
// Handle symbol update - if style contains a symbol, update currentSymbol
const updatedSymbol = currentStyle?.symbol !== undefined
? currentStyle.symbol
: currentState.currentSymbol;
s.spinners.set(spinnerId, {
status,
currentLabel: label !== undefined ? label : currentState.currentLabel,
currentStyle: mergedStyle,
currentSymbol: updatedSymbol,
gracePeriodActive: false, // Clear grace period when state changes
});
s.revision++;
});
}
// Public API function
export async function spinner(label, options) {
// Generate unique spinner ID
const spinnerId = `spinner_${Date.now()}_${Math.random()
.toString(36)
.substring(2, 11)}`;
currentSpinnerId = spinnerId;
// Extract style from options
const initialStyle = options?.style;
// Initialize spinner as idle in the store with grace period active
spinnerStore.update((s) => {
s.spinners.set(spinnerId, {
status: "idle",
currentStyle: initialStyle,
currentSymbol: options?.style?.symbol,
gracePeriodActive: true, // Initially in grace period to avoid symbol flash
});
s.revision++;
});
// End grace period after 100ms (allows start() to be called without showing idle symbol)
setTimeout(() => {
spinnerStore.update((s) => {
const spinner = s.spinners.get(spinnerId);
if (spinner?.gracePeriodActive) {
s.spinners.set(spinnerId, {
...spinner,
gracePeriodActive: false,
});
s.revision++;
}
});
}, 100);
// Start the prompt in the background
let promptResolve = null;
const promptPromise = spinnerInternal({
label: label,
spinnerId: spinnerId,
hideOnCompletion: options?.hideOnCompletion,
submitDelay: options?.submitDelay,
style: options?.style,
});
// Create controller object with async methods
const controller = {
start: async (label, style) => {
updateSpinnerState(spinnerId, "running", label, style);
},
pause: async (label, style) => {
updateSpinnerState(spinnerId, "paused", label, style);
},
resume: async (label, style) => {
updateSpinnerState(spinnerId, "running", label, style);
},
stop: async (label, style) => {
updateSpinnerState(spinnerId, "stopped", label, style);
// Wait for the prompt to complete
await promptPromise;
},
};
// Wait a bit to ensure the component is mounted
await new Promise((resolve) => setTimeout(resolve, 50));
// Return controller immediately so user can control it
return controller;
}
//# sourceMappingURL=index.js.map