# CardSpin

`CardSpin` is the reel a case opening is known for. A strip of tiles races under a marker, slows down, and stops on a card. The winning tile lights up, the rest dim, and the card lifts out of it into the [reveal](https://bettertyped.github.io/react-cards-opening/docs/components/card-opening/). One press is one spin.

> Live preview: see it play at https://bettertyped.github.io/react-cards-opening/docs/components/card-spin/
>
> Press Spin. The reel stops on the next card of the deal.

## Usage

```tsx
import { useOpenedCards } from "@react-cards-opening/core";
import { CardSpin } from "@react-cards-opening/ui";

function Spins({ won, catalog }) {
  const { opened, open } = useOpenedCards("spins:42");
  return <CardSpin cards={won} pool={catalog} opened={opened} onOpen={open} />;
}
```

## The spin decides nothing

`cards` is what was won, decided before anything moves. `pool` is everything that could have come up, and it only fills the strip. Tiles are drawn from the pool by tier weight with [pickCard](https://bettertyped.github.io/react-cards-opening/docs/core/rolls/), so rare cards pass less often and the strip looks like the odds, and the tile under the marker at the end is always the card that was dealt. The strip is built from a seed, so a server and a browser lay out the same tiles.

> A reel that shows near misses is still a reel that shows the odds honestly here: what passes by is drawn with the real weights. If you sell spins, check what your market requires you to publish. [chances](https://bettertyped.github.io/react-cards-opening/docs/core/rolls/) gives you the numbers.

## Props

| Prop | Type | What it does |
| --- | --- | --- |
| `cards` | `readonly C[]` | What was won, in the order the spins stop on them. |
| `opened` | `readonly string[]` | Ids already won on the reel. |
| `onOpen` | `(id: string) => void` | A card was turned face up for the first time. |
| `pool?` | `readonly C[]` | What slides past on the reel. The deal itself when left out. |
| `theme?` | `CardTheme` | The colours. `moss` in the dark when left out. |
| `rarities?` | `readonly RarityTier[]` | Your tiers. They weigh what the strip is filled with. |
| `actions?` | `ReactNode` | Extra buttons in the header, next to the spin button. |
| `onRunChange?` | `(running: boolean) => void` | A spin started or came to rest. |
| `labels?` | `Partial<CardSpinLabels>` | Every word in the panel. |
| `landing?` | `(card) => HTMLElement \| null` | Where a won card lands, instead of its badge here. |
| `renderFace?` | `(card, info) => ReactNode` | The front of the card, instead of the ready-made face. |
| `renderBack?` | `(card) => ReactNode` | The back of the card. |
| `readingOf?` | `(card, info) => readonly string[]` | The text on a face of your own, so the card stays up long enough to read. |
| `effects?` | `EffectPlan \| false` | What each tier plays on top of the card's own reveal. The [signature shows](https://bettertyped.github.io/react-cards-opening/docs/effects/plans/) when left out, `false` for none. |
| `className?` | `string` | A class for the panel. |
| `classNames?` | `CardSpinClassNames` | A class of your own for each part: the panel's, the reel's and the reveal's. |
| `style?` | `CSSProperties` | Inline styles for the panel. |

## SpinReel on its own

`CardSpin` is `SpinReel` and `CardOpening` wired to [useCardOpening](https://bettertyped.github.io/react-cards-opening/docs/core/use-card-opening/). When the layout is yours, take the reel alone. Its handle has one call: `spin` plays the reel and hands back what `launch` on `CardOpening` takes, so the card waits for the reel and then lifts out of the winning tile.

```tsx
import { CardOpening, SpinReel, type SpinReelHandle } from "@react-cards-opening/ui";

const reel = useRef<SpinReelHandle>(null);

<SpinReel handle={reel} winner={hunt.current} pool={catalog} spinKey={spins} />
<CardOpening opening={hunt.opening} launch={(card, show) => reel.current?.spin(show) ?? null} />
```

| Prop | Type | What it does |
| --- | --- | --- |
| `winner` | `C \| null` | The card the next spin stops on. With none, the strip shows what could come up and waits. |
| `pool` | `readonly C[]` | What slides past: every card that could have come up. |
| `spinKey?` | `string \| number` | Changes with every spin, so two spins for the same card deal two different strips. |
| `theme?` | `CardTheme` | The colours. |
| `rarities?` | `readonly RarityTier[]` | Your tiers. |
| `handle?` | `Ref<SpinReelHandle>` | `spin(show, { flash, onLock })`: plays the reel and answers a launch. |
| `className?` | `string` | A class for the reel's root. |
| `classNames?` | `SpinReelClassNames` | A class of your own for each part of the reel. |
| `style?` | `CSSProperties` | Inline styles for the root: the place for `--rco-tile`. |

## Parts and variables

| Key | The library's class | The part |
| --- | --- | --- |
| `reel` | `.rco-reel` | The reel's window. `className` on a `SpinReel` used alone. |
| `strip` | `.rco-reel-strip` | The strip that slides. |
| `tile` | `.rco-reel-tile` | Every tile. The winner also gets `data-won`. |
| `tileName` | `.rco-reel-name` | The card's name under a tile's glyph. |
| `marker` | `.rco-reel-marker` | The line the reel stops under. |

| Key | The library's class | The part |
| --- | --- | --- |
| `root` | `.rco-panel` | The panel. The same as `className`. |
| `flash` | `.rco-panel-flash` | The flash over the whole panel on a loud card. |
| `head` | `.rco-panel-head` | The row that holds the words and the buttons. |
| `headline` | `.rco-panel-headline` | The headline. |
| `subline` | `.rco-panel-subline` | The line under it. |
| `actions` | `.rco-panel-actions` | The buttons' row. |
| `mainButton` | `.rco-button-main` | The main button: Spin, or Open the case. |
| `sideButton` | `.rco-button-skip` | Take all during a run, and the replay button after it. |
| `finds` | `.rco-finds` | The list of badges. |
| `badge` | `.rco-badge` | Each badge, won or not. A won one is a `button`. |
| `badgeArt` | `.rco-badge-art` | The little glyph's box in a badge. |
| `badgeName` | `.rco-badge-name` | The card's name in a badge. |
| `badgeWhere` | `.rco-badge-where` | The second line of a badge. |

| Variable | What it sets | When left out |
| --- | --- | --- |
| `--rco-tile` | A tile's width and height. | `112px`, and `92px` on a narrow screen |

## Related

- [CardOpening](https://bettertyped.github.io/react-cards-opening/docs/components/card-opening/)
- [Rolls and odds](https://bettertyped.github.io/react-cards-opening/docs/core/rolls/)
- [CardCase](https://bettertyped.github.io/react-cards-opening/docs/components/card-case/)
- [CardPack](https://bettertyped.github.io/react-cards-opening/docs/components/card-pack/)
- [Effect plans](https://bettertyped.github.io/react-cards-opening/docs/effects/plans/)

Source: https://bettertyped.github.io/react-cards-opening/docs/components/card-spin/
