Rocket Letter Stream Pro

Rocket is a Pro feature, currently in beta.

Demo

Explanation #

This is the kind of component where plain setup() is still the right tool: it owns local animated state, but it does not need any rendered refs. The outer loop uses the default i index, while the inner loops bind j and k.

The component starts from a seed string, derives named blocks and rows from that stream, and appends one more letter per animation frame until it reaches Z.

Usage Example #

1<alphabet-stream seed="ABCDEF"></alphabet-stream>

Rocket Component #

  1import { rocket } from 'datastar'
  2
  3rocket('alphabet-stream', {
  4  props({ string }) {
  5    return { seed: string.default('ABCDEF') }
  6  },
  7  setup({ props, $$ }) {
  8    $$.letters = props.seed.split('')
  9    $$.blocks = () => {
 10      const letters = [...$$.letters]
 11      const blocks = []
 12      for (let offset = 0; offset < letters.length; offset += 9) {
 13        const rows = []
 14        for (let rowOffset = offset; rowOffset < offset + 9; rowOffset += 3) {
 15          const cells = letters.slice(rowOffset, rowOffset + 3)
 16          if (!cells.length) continue
 17          rows.push({
 18            name: `Row ${rows.length + 1}`,
 19            cells,
 20          })
 21        }
 22        if (!rows.length) continue
 23        blocks.push({
 24          name: `Block ${blocks.length + 1}`,
 25          rows,
 26        })
 27      }
 28      return blocks
 29    }
 30    let nextCode = 65 + $$.letters.length
 31    const streamNextLetter = () => {
 32      $$.letters.push(String.fromCharCode(nextCode++))
 33      if (nextCode <= 90) requestAnimationFrame(streamNextLetter)
 34    }
 35    requestAnimationFrame(streamNextLetter)
 36  },
 37  render: ({ html }) => html`
 38    <section>
 39      <style>
 40        :host {
 41          display: block;
 42        }
 43
 44        section {
 45          display: grid;
 46          gap: 0.75rem;
 47        }
 48
 49        ul,
 50        ol {
 51          display: flex;
 52          flex-wrap: wrap;
 53          gap: 0.5rem;
 54          list-style: none;
 55          padding: 0;
 56          margin: 0;
 57        }
 58
 59        .block-list {
 60          display: grid;
 61          gap: 1rem;
 62        }
 63
 64        .block-card {
 65          display: grid;
 66          gap: 0.75rem;
 67          padding: 1rem;
 68          border: 1px solid var(--gray-5);
 69          border-radius: 1rem;
 70          background: linear-gradient(180deg, var(--gray-1), var(--gray-2));
 71        }
 72
 73        .block-card h4,
 74        .block-card h5 {
 75          margin: 0;
 76        }
 77
 78        .row-list {
 79          display: grid;
 80          gap: 0.75rem;
 81        }
 82
 83        .cell-list li {
 84          padding: 0.35rem 0.6rem;
 85          border-radius: 999px;
 86          background: var(--blue-2);
 87          color: var(--blue-12);
 88          border: 1px solid var(--blue-6);
 89        }
 90
 91        li strong {
 92          font-variant-numeric: tabular-nums;
 93          margin-right: 0.25rem;
 94        }
 95
 96        p {
 97          margin: 0;
 98          color: var(--gray-11);
 99        }
100
101        code {
102          color: var(--gray-12);
103        }
104      </style>
105
106      <h3>Letter Stream</h3>
107      <p>
108        This example nests three Rocket loops to exercise default and named aliases:
109        outer <code>i</code>, middle <code>j</code>, inner <code>k</code>.
110      </p>
111      <div class="block-list">
112        <template data-for="block in $$blocks">
113          <section class="block-card">
114            <h4 data-text="block.name"></h4>
115            <div class="row-list">
116              <template data-for="row, j in block.rows">
117                <article>
118                  <h5 data-text="row.name"></h5>
119                  <ol class="cell-list">
120                    <template data-for="letter, k in row.cells">
121                      <li>
122                        <strong data-text="letter"></strong>
123                        <span data-text="i + ':' + j + ':' + k"></span>
124                      </li>
125                    </template>
126                  </ol>
127                </article>
128              </template>
129            </div>
130          </section>
131        </template>
132      </div>
133      <div data-text="$$letters.join(' ')"></div>
134    </section>
135  `,
136})