unimal-jp / spear

The spear OSS repository
https://late-cloud-6411.spearly.app
MIT License
10 stars 1 forks source link

Support Slot features #131

Closed mantaroh closed 1 year ago

mantaroh commented 1 year ago

What is this?

This PR is enabling to Slot feature (#104 describe to Slot features. )

What is slot?

Slots are a mechanism for component oriented framework that allows you to compose your components in a way other than the strict parent-child relationship. Slots give you an outlet to place content in new places or make components more generic.

Single slot

The way to most use is single slot. Spear will inject the component into page if there are component name tag in page.

<!-- A following sample is /index.html -->
<div>
  <main-component></main-component>
</div>
<-- A bellow sample is /component/main-component.spear -->
<div>
 <p>here is main component</p>
</div>

In above sample, Spear inject /component/main-component.spear into /index.html. However, spear couldn't inject data of /index.html into component.

For example:

<!-- A following sample is /index.html -->
<div>
  <main-component>I'd like to inject here text into component</main-component>
</div>
<-- A bellow sample is /component/main-component.spear -->
<div>
 <p>here is main component</p>
</div>

In above sample, Spear couldn't I'd like to inject here text into component text into component. The Slot feature allow this mechanism.

Now, we can write an above sample like the following:

<!-- A following sample is /index.html -->
<div>
  <main-component>I'd like to inject here text into component</main-component>
</div>
<-- A bellow sample is /component/main-component.spear -->
<div>
 <p>here is main component. </slot></slot></p>
</div>

Almost of snipet is same from previous code, but component has <slot> element. Spear replace this <slot> element to the component's child element. The generated result will be the following:

<div>
  <div>
    <p>here is main component. I'd like to inject here text into component</p>
  </div>
</div>

After landing this PR, we can use this single slot feature.

Multiple slot (aka named slot)

Sometime, we want to specify the multiple slot into one component like:

<!-- A following sample is /index.html -->
<div>
  <main-component></main-component>
</div>
<!-- A bellow sample is /component/main-component.spear -->
<div>
  <ul>
    <li><slot></slot></li>  <!-- want to show first step description from parent page -->
    <li><slot></slot></li>  <!-- want to show second step description from parent page -->
    <li><slot></slot></li>  <!-- want to show third step description from parent page -->
  </ul>
</div>

An above sample is displaying specified three slot as list. The Single Slot cannot allow the such multiple slot. So Spear should have a way to specify the multiple slot.

@qst-exe suggest this feature from vue's named slot. (https://github.com/unimal-jp/spear/issues/104#issuecomment-1432759379)

So we provide named feature that inspiring from vue's named slot feature.

<!-- A following sample is /index.html -->
<div>
  <main-component>
    <div slot="first">This is first description</div>
    <div slot="second">This is second description</div>
    <div slot="third">This is third description</div>
  </main-component>
</div>
<!-- A bellow sample is /component/main-component.spear -->
<div>
  <ul>
    <li><slot name="first"></slot></li>
    <li><slot name="second"></slot></li>
    <li><slot name="third"></slot></li>
  </ul>
</div>

In above sample, Spear will replace the <slot> element to parent's child element which has same attribute value. The generated result will be the following:

<div>
  <div>
    <ul>
     <li><div>This is first description</div></li>
     <li><div>This is second description</div></li>
     <li><div>This is third description</div></li>
   </ul>
  </div>
</div>

After landing this PR, we can use this named slot feature.


これは何?

この PR は Slot 機能を実現するものです (#104 Slot 機能への記述。)。

スロットって何?

スロットはコンポーネント指向フレームワークの機構で、厳密な親子関係以外の方法でコンポーネントを構成することを可能にします。スロットは、コンテンツを新しい場所に配置したり、コンポーネントをより汎用的なものにするための出口となります。

シングルスロット

最も使いやすい方法はシングルスロットです。Spearは、ページ内にコンポーネント名タグがあれば、そのコンポーネントをページに注入します。

<!-- 以下のサンプルは /index.html です。 --> 
<div>
  <main-conponent></main-component>
</div>
<-- 以下のサンプルは /component/main-component.spear です。 -->
<div>
 <p>ここはメインコンポーネントです。</p>
</div>

上記のサンプルでは、Spear は /component/main-component.spear/index.html にインジェクトしています。しかし、spear は /index.html のデータをコンポーネントに注入することができませんでした。

例えば、以下のようなケースです。

<!-- 以下のサンプルは /index.html です。 --> 
<div>
  <main-component>ここにあるテキストをコンポーネントに注入したい</main-component>。
</div>
<-- 以下のサンプルは /component/main-component.spear です。 -->
<div>
 <p>ここはメインコンポーネントです。</p>
</div>

上記のサンプルでは、Spearは「ここにあるテキストをコンポーネントに注入したい」というテキストをコンポーネントに注入することができませんでした。この仕組みを実現するのが、Slot機能です。

さて、上記のサンプルを Slot 機能を使えば、次のように書くことができます。

<!-- 以下のサンプルは /index.html です。 --> 
<div>
  <main-component>ここにあるテキストをコンポーネントに注入したい</main-component>。
</div>
<-- 以下のサンプルは /component/main-component.spear です。 -->
<div>
 <p>ここはメインコンポーネントです。</slot></slot></p>。
</div>

スニペットの大部分は以前のコードと同じですが、コンポーネントには <slot> 要素があります。Spearはこの <slot> 要素をコンポーネントの子要素に置き換えます。生成される結果は次のようになります。

<div>
  <div
    <p>ここはメインコンポーネントです。ここにあるテキストをコンポーネントに注入したい</p>
  </div>
</div>

このPRを導入後は、このシングルスロットの機能を使うことができるのです。

マルチプルスロット(別名:名前付きスロット)

複数のスロットを1つのコンポーネントにまとめて指定したい場合があります。

<!-- 以下のサンプルは /index.html です。 --> 
<div>
  <main-conponent></main-component>
</div>
<!-- 以下のサンプルは /component/main-component.spear です。 -->
<div>
  <ul>
    <li><slot></slot></li> <!-- 親ページにある最初の説明をここに表示したい。 -->
    <li><slot></slot></li> <!-- 親ページにある2番目の説明をここに表示したい。 -->
    <li><slot></slot></li> <!-- 親ページにある3番目の説明をここに表示したい。 -->
  </ul>
</div>

上記のサンプルは、指定した3つのスロットをリストとして表示するものです。「シングルスロット」では、このような複数スロットの表示を許可することはできません。そこで、Spearでは複数のスロットを指定できるようにする必要があります。

この機能はvueのnamed slotで実現できていると、@qst-exeが提案してくれました。(https://github.com/unimal-jp/spear/issues/104#issuecomment-1432759379)

そこで、vueの名前付きスロット機能をヒントにした、名前付き機能を用意しました。

<!-- 以下のサンプルは /index.html です。 --> 
<div>
  <main-component>
    <div slot="first">これは1番目の記述です</div>
    <div slot="second">これは2番目の記述です</div>
    <div slot="third">これは3番目の記述です</div>
  </main-component>
</div>
<!-- 以下のサンプルは /component/main-component.spear です。 -->
<div>
  <ul>
    <li><slot name="first"></slot></li>
    <li><slot name="second"></slot></li>
    <li><slot name="third"></slot></li>
  </ul>
</div>

上記のサンプルでは、Spear は <slot> 要素を、同じ属性値を持つ親の子要素に置換します。生成される結果は以下のようになります。

<div>
  <div>
    <ul
     <li><div>これは1番目の記述です</div></div>
     <li><div>これは2番目の記述です</div></div>
     <li><div>これは3番目の記述です</div></div>
   </ul>
  </div>
</div>

このPRを取り込んだ後、この名前のついたスロット機能を使うことができます。