Svelteでeachの各ループの中でsetContextする

## 概要
Svelteの`each`のなかで各ループごとに`setContext`を使用し、**`each`ごとに別のContext**を配下のコンポーネントに渡します。

このTipsは`each`の中に`slot`を配置してコンポーネントを差し込みたい時に利用します。

<details open><summary>理由（長いです）</summary>
なんでそんなことしたいの？と思った人もいると思うので理由を書いておきます。

きっかけはパンくずコンポーネントです。

パンくずの最後のリンクには`aria-current="page"`を指定してあげた方が親切です。
ここで、アクセシビリティの知識がない人がこのパンくずコンポーネントを使ったとしても、最後のリンクに必ずこの属性がつくようにしたいとします。

その場合
```svelte: Breadcrumb.svelte
<script lang="ts">
  import { setContext } from 'svelte';
  import type { BreadcrumbItemLinkProps } from './BreadcrumbItemLink.svelte';

  export let label: string;
  export let items: BreadcrumbItemLinkProps[];
</script>
<nav aria-label={label}>
  <ol>
    {#each items as { href, label }, index (href)}
      <li>
        <a href={href} aria-current={items.length - 1 === index ? 'page' : undefined}>{ label }</a>
      </li>
    {/each}
  </ol>
</nav>
```
このように作っておくのもありでしょう。

パンくずのデザインがサイトの中で一つしかないのであればそもそも`li`や`a`にクラス名を振っておけばいいですが、複数の見た目があって別のクラス名を`li`や`a`に振りたい場合もあるでしょう。
その場合、`Breadcrumb.svelte`のpropsや`items`のpropsとして`class_li`や`class_link`を含める必要があります。

これって気持ち悪くないですか？
`class_li`や`class_link`は`li`や`a`でしか使用しないクラス名です。
これを`Breadcrumb`コンポーネントのpropsとして渡すのは違う気がします。

`items`に渡す場合、`items`の各オブジェクトにそのpropsを渡さなければなりません。
これもちょっと気持ち悪いですよね。
各オブジェクトに毎回渡すのもめんどくさいです。

以下のようなイメージで
```svelte
<Breadcrumb>
 // eachが必要
  <BreadcrumbItem class="item">
    <BreadcrumbItemLink class="link">
    </BreadcrumbItemLink>
  </BreadcrumbItem>
</Breadcrumb>
```
各コンポーネントに必要なpropsは各コンポーネントに渡すと自然です。

ですが、この構成だと`BreadcrumbItem`の部分を`each`で毎回回さなければなりませんし、`BreadcrumbItemLink`にループがどこまで進んだかの情報をpropsをして渡す必要が出てきてしまいます。（最後のループかどうかを判定する必要があります）

これでは当初の目的の「パンくずの最後のリンクには`aria-current="page"`を指定」を`Breadcrumb`を呼び出すたびに書かなくてはならず、漏れも出てきそうです。

これを解決するために、`Breadcrumb`コンポーネントの中で`each`を回し、中の要素は`slot`で渡すことを思いつきました。
</details>


## コード

```svelte: Breadcrumb.svelte
<script lang="ts">
  import { setContext } from 'svelte';
  import type { BreadcrumbItemLinkProps } from './BreadcrumbItemLink.svelte';

  export let label: string;
  export let items: BreadcrumbItemLinkProps[];
</script>
<nav aria-label={label}>
  <ol>
    {#each items as item, index (item)}
      {@const _ = setContext('breadcrumb_item', {
        item,
        index,
        is_last: items.length - 1 === index
      })}
      <slot />
    {/each}
  </ol>
</nav>
```
```html: BreadcrumbItem.svelte
<script lang="ts">
  let class_name: string | undefined = undefined;
  export { class_name as class };
</script>
<li class={class_name}>
  <slot />
</li>
```
```svelte: BreadcrumbItemLink.svelte
<script context="module" lang="ts">
  export type BreadcrumbItemLinkProps = {
    href: string;
    label: string;　//ここには読み上げのためにテキストを必須で入れさせたい
    hide_label?: boolean;
  };
</script>
<script lang="ts">
  import { getContext } from 'svelte';

  let { item, index, is_last } = getContext<{
    item: BreadcrumbItemLinkProps;
    index: number;
    is_last: boolean;
  }>('breadcrumb_item');

  let current = is_last;
  let href: string = item.href ?? '';
  let label: string = item.label ?? '';
  let hide_label = item.hide_label ?? false;
</script>

{#if $$slots.prefix && !hide_label}
  <span aria-hidden="true"> //アイコンは読み上げさせない
    <slot name="prefix" {index} />
  </span>
{/if}
<a
  aria-current={current ? 'page' : undefined}
  aria-label={hide_label ? label : undefined}
  {href}
>
  {#if hide_label && $$slots.prefix}
    <slot name="prefix" {index} />
  {:else}
    {label}
  {/if}
</a>

```


```svelte: 使用する側
<Breadcrumb class="list" {items} label="breadcrumb">
  <BreadcrumbItem class="item">
    <BreadcrumbItemLink class="link">
      <svelte:fragment slot="prefix" let:index>
        {#if index === 0} //最初のリンクはアイコンを表示したい
          <HomeIcon />
        {:else} //2個目以降は「＞」を表示したい
          &gt;
        {/if}
      </svelte:fragment>
    </BreadcrumbItemLink>
  </BreadcrumbItem>
</Breadcrumb>
```

## ポイント
`{@const _ = setContext...}`の部分がポイントです。

`each`の中でそのまま`{setContext}`してしまうと`setContext`の中がそのまま展開されてしまいますが、`@const`で変数に入れてしまうと実行できます。

おそらくこれはいいテクニックではないです。
今後動かなくなったりするかもしれません。

以上Tipsでした。