drop-spinner
v0.0.14
Published
Random picker with drop animation — a spinner alternative.
Maintainers
Readme
drop-spinner
drop-spinner es una librería ligera para seleccionar elementos al azar con una interfaz visual opcional. Está pensada para ser usada como componente React, como utilidad programática y (opcionalmente) como Web Component. El paquete está preparado para publicarse en npm y es compatible con entornos SSR como Next.js.
Contenido del README:
- Instalación
- Uso rápido (React)
- Uso en Next.js (SSR)
- Uso programático
- API
- Build y publicación
- Ejemplo local
Instalación
npm install drop-spinnerNota: el paquete debe declarar react y react-dom como peerDependencies. Asegúrate de instalarlos en tu proyecto consumidor.
Uso rápido — Componente React
import { RandomImagePicker, ImageOption } from 'drop-spinner';
const items: ImageOption[] = [
{ name: 'Apple', url: '/img/apple.png' },
{ name: 'Banana', url: '/img/banana.png' },
{ name: 'Cherry' }
];
export default function Page() {
return <RandomImagePicker items={items} />;
}Uso adicional: CircularWheel
El paquete también incluye un componente visual tipo rueda/slot llamado CircularWheel pensado para mostrar imágenes alrededor de una rueda o en un viewport de 'slot'. Usa el mismo tipo ImageOption.
Ejemplo de uso:
import { CircularWheel, ImageOption } from 'drop-spinner';
const images: ImageOption[] = [
{ name: 'Burger', url: 'https://images.unsplash.com/photo-1568901346375-23c9450c58cd' },
{ name: 'Pizza', url: 'https://images.unsplash.com/photo-1544982503-9f984c14501a' },
{ name: 'Coffee', url: 'https://images.unsplash.com/photo-1533776992670-a72f4c28235e' },
{ name: 'Donut', url: 'https://images.unsplash.com/photo-1733754348967-62a6870f51b7' }
];
export default function Page() {
const handleSpin = (winnerIndex: number, winnerName: string) => {
console.log('Ganador:', winnerIndex, winnerName);
};
return <CircularWheel images={images} size={360} onSpin={handleSpin} />;
}Notas:
imagesaceptaImageOption[]dondeImageOption = { name: string; url?: string }.onSpinse invoca cuando la animación termina con(winnerIndex, winnerName).
El componente es sencillo: recibe items: ImageOption[] y muestra el elemento seleccionado (o un texto si no hay imagen). ImageOption es { name: string; url?: string }.
Uso en Next.js / SSR
Si usas características que dependen del DOM (registro de Web Components o utilidades que montan nodos), registra el componente solo en el cliente:
import { useEffect } from 'react';
import { registerDropSpinner, dropSpinner } from 'drop-spinner';
export default function Page() {
useEffect(() => {
if (typeof registerDropSpinner === 'function') registerDropSpinner();
}, []);
async function handlePick() {
const result = await dropSpinner({ items: ['A','B','C'] });
alert('Picked: ' + result);
}
return <button onClick={handlePick}>Pick</button>;
}Registra el Web Component (si existe) dentro de useEffect para evitar fallos en SSR (no existe window en el servidor).
Uso recomendado: wrapper server + componente cliente
El paquete exporta dos variantes:
RandomImagePicker— server-safe placeholder (se puede importar desde componentes server sin causar errores de hidratación).RandomImagePickerClient— componente con toda la interactividad; debe importarse desde un Client Component.
Ejemplo (page.tsx — Server Component):
import { RandomImagePicker } from 'drop-spinner';
export default function Page() {
const items = [{ name: 'Apple' }, { name: 'Banana' }, { name: 'Cherry' }];
return <RandomImagePicker items={items} />; // server-safe
}Ejemplo (PickerClient.tsx — Client Component):
'use client';
import { RandomImagePickerClient } from 'drop-spinner';
export default function PickerClient({ items }) {
return <RandomImagePickerClient items={items} />;
}Si quieres montar dinámicamente el componente cliente desde un componente server puedes usar next/dynamic:
import dynamic from 'next/dynamic';
const DynamicPicker = dynamic(() => import('drop-spinner').then(m => m.RandomImagePickerClient), { ssr: false });
export default function Page() {
const items = [{ name: 'Apple' }, { name: 'Banana' }];
return <DynamicPicker items={items} />;
}Uso programático
La utilidad dropSpinner(options) permite invocar la selección programáticamente. En cliente retorna una Promise que se resuelve tras la animación; en entornos sin DOM puede comportarse de forma síncrona.
import { dropSpinner } from 'drop-spinner';
const winner = await dropSpinner({
items: ['🍎','🍌','🍇'],
animationSpeed: 1200,
circleSize: 200,
onPick: (item) => console.log('picked', item)
});API (resumen)
RandomImagePicker— componente React. Props:items: ImageOption[]
getRandomItem(items: ImageOption[]): ImageOption | undefined— devuelve un item aleatorio oundefinedsi la lista está vacía.dropSpinner(options: DropSpinnerOptions)— función útil para lanzar la selección con animación.registerDropSpinner()— registra el Web Component en el cliente (si el paquete lo exporta).
Tipos importantes:
ImageOption={ name: string; url?: string }DropSpinnerOptions={ items: string[] | ImageOption[]; animationSpeed?: number; circleSize?: number; onPick?: (item: any) => void }
Build y publicación
El proyecto usa tsup para generar bundles ESM/CJS y tipados.
Antes de publicar:
- Asegúrate de que
package.jsontiene los camposname,version,main,module,typesyexportscorrectamente configurados. - Ejecuta:
npm run build- Comprueba el contenido del paquete:
npm pack --dry-run- Publica en npm:
npm publish --access publicRecomendación: mantener react/react-dom en peerDependencies y @types/react en devDependencies.
Ejemplo local (Next.js)
El repositorio incluye un ejemplo minimal en example/next-app. Para ejecutarlo localmente:
cd example/next-app
npm install
npm run devEl ejemplo está configurado para usar el paquete local empaquetado (tarball) como dependencia de desarrollo.
Limpieza y publicación segura
- Añade
.npmignorepara excluir código fuente y archivos de desarrollo del paquete publicado. - Añade
.gitignorepara evitar subirnode_modules, artefactos de build y tarballs.
Contribuciones
PRs y issues son bienvenidos. Incluye tests y actualiza README.md si cambias la API.
Licencia
MIT
