# Selectable Card

## Usage

`SelectableCard` is a card with a selected state. The keyboard stop is a visually hidden checkbox. Bind the state with `v-model:is-selected`, or pass `:is-selected` and handle `update:isSelected` when several cards share one value.

The selected card draws an accent border and an inset ring. `elevation` stays in the shadow, and the ring is composed on top of it. `variant` recolors that accent.

```vue
<script setup lang="ts">
import { SelectableCard } from '@astryx-vue/core/SelectableCard'
import { ref } from 'vue'

const selected = ref('pro')
</script>

<template>
  <SelectableCard
    :is-selected="selected === 'pro'"
    label="Pro"
    @update:is-selected="(next) => { if (next) selected = 'pro' }"
  >
    Pro
  </SelectableCard>
</template>
```

### Anatomy

- **Container**: Interactive div with accent border on selection.
- **Content**: Children rendered inside the card.

## Examples

### Elevated

Starter and Pro sit on a low shadow. The selection ring layers on top.

```vue
<script setup lang="ts">
import { Grid } from '@astryx-vue/core/Grid'
import { SelectableCard } from '@astryx-vue/core/SelectableCard'
import { Text } from '@astryx-vue/core/Text'
import { ref } from 'vue'

const plans = [
  { id: 'starter', name: 'Starter' },
  { id: 'pro', name: 'Pro' },
]

const selected = ref('pro')

function choose(id: string, next: boolean) {
  if (next)
    selected.value = id
}
</script>

<template>
  <Grid :columns="2" :gap="3" :width="420">
    <SelectableCard
      v-for="plan in plans"
      :key="plan.id"
      elevation="low"
      :is-selected="selected === plan.id"
      :label="plan.name"
      @update:is-selected="choose(plan.id, $event)"
    >
      <Text type="body" weight="bold">
        {{ plan.name }}
      </Text>
      <Text color="secondary" type="supporting">
        The resting shadow stays put — the selection ring layers on top.
      </Text>
    </SelectableCard>
  </Grid>
</template>
```
### Multi-select

React, TypeScript, Node.js, Python, Rust, and Go. Each card keeps its own color, and more than one can be selected.

```vue
<script setup lang="ts">
import type { CardVariant } from '@astryx-vue/core/Card'
import { Grid } from '@astryx-vue/core/Grid'
import { SelectableCard } from '@astryx-vue/core/SelectableCard'
import { Text } from '@astryx-vue/core/Text'
import { ref } from 'vue'

const tags: Array<{ id: string, name: string, variant: CardVariant }> = [
  { id: 'react', name: 'React', variant: 'blue' },
  { id: 'typescript', name: 'TypeScript', variant: 'cyan' },
  { id: 'node', name: 'Node.js', variant: 'green' },
  { id: 'python', name: 'Python', variant: 'yellow' },
  { id: 'rust', name: 'Rust', variant: 'orange' },
  { id: 'go', name: 'Go', variant: 'teal' },
]

const selected = ref(new Set(['react', 'typescript']))

function toggle(id: string, next: boolean) {
  const copy = new Set(selected.value)
  if (next)
    copy.add(id)
  else
    copy.delete(id)
  selected.value = copy
}
</script>

<template>
  <Grid :columns="3" :gap="2" :width="400">
    <SelectableCard
      v-for="tag in tags"
      :key="tag.id"
      :is-selected="selected.has(tag.id)"
      :label="tag.name"
      :variant="tag.variant"
      @update:is-selected="toggle(tag.id, $event)"
    >
      <Text type="body" weight="bold">
        {{ tag.name }}
      </Text>
    </SelectableCard>
  </Grid>
</template>
```

## Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | - | Accessible name of the hidden checkbox. |
| `isSelected` | `boolean` | - | Whether the card is selected. Bind with `v-model:isSelected`. |
| `isDisabled` | `boolean` | `false` | The card ignores activation. |
| `variant` | `CardVariant` | `'default'` | Background variant. A selected card uses that hue for the ring. |
| `elevation` | `CardElevation` | `'none'` | Resting shadow. The selection ring is composed with it. |
| `padding` | `SpacingStep` | - | Padding forwarded to `Card`. |
| `width` | `number \| string` | - | Width. Numbers are pixels. |
| `height` | `number \| string` | - | Height. Numbers are pixels. |
| `maxWidth` | `number \| string` | - | Maximum width. |

## Events

| Name | Payload | Description |
| --- | --- | --- |
| `update:isSelected` | `boolean` | The next selected state. |
| `change` | `boolean` | Emitted with `update:isSelected`. |

## Slots

The default slot is the card body. Nested buttons and links keep their own activation.
