Star skammer/schism on GitHub

Install

npm i @skammer/schism

Or load directly from jsDelivr — no build step:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@skammer/schism/dist/schism.css" />
<script type="module" src="https://cdn.jsdelivr.net/npm/@skammer/schism/dist/schism.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.0-RC.6/bundles/datastar.js"></script>

One-way: layout-change → signal

The split-group emits layout-change; Datastar copies evt.detail.layout into $s1Layout.

A B C
$s1Layout =
view code
<body data-signals="{s1Layout: []}">
  <schism-group
    direction="horizontal"
    data-on:layout-change="$s1Layout = evt.detail.layout"
  >
    <schism-pane>A</schism-pane>
    <schism-resizer></schism-resizer>
    <schism-pane>B</schism-pane>
    <schism-resizer></schism-resizer>
    <schism-pane>C</schism-pane>
  </schism-group>

  <span data-text="JSON.stringify($s1Layout)"></span>
</body>

Two-way: signal ⇄ layout (animated)

data-effect calls el.setLayout($s2Layout) whenever the signal changes; the buttons just write to the signal. animate tweens between layouts.

A B C
$s2Layout =
view code
<body data-signals="{s2Layout: []}">
  <schism-group
    direction="horizontal"
    animate
    data-on:layout-change="$s2Layout = evt.detail.layout"
    data-effect="el.setLayout && $s2Layout.length === 3
                 && el.setLayout($s2Layout)"
  >
    <schism-pane default-size="20">A</schism-pane>
    <schism-resizer></schism-resizer>
    <schism-pane default-size="60">B</schism-pane>
    <schism-resizer></schism-resizer>
    <schism-pane default-size="20">C</schism-pane>
  </schism-group>

  <button data-on:click="$s2Layout = [20, 60, 20]">20 / 60 / 20</button>
  <button data-on:click="$s2Layout = [50, 25, 25]">50 / 25 / 25</button>
</body>

<!-- inside data-effect, `el` is the <schism-group>.
     length===3 guard avoids running before the WC has scanned. -->

Collapsible sidebar — events drive a signal (animated)

data-on:collapse and data-on:expand on the pane keep $sidebarCollapsed in sync; the button calls the imperative API. animate smooths the collapse.

Sidebar

Forest signature surface

Main

Workspace

$sidebarCollapsed =
view code
<body data-signals="{sidebarCollapsed: false}">
  <schism-group direction="horizontal" animate>
    <schism-pane
      min-size="120px" collapsible default-size="25"
      data-on:collapse="$sidebarCollapsed = true"
      data-on:expand="$sidebarCollapsed = false"
    >sidebar</schism-pane>
    <schism-resizer></schism-resizer>
    <schism-pane>main</schism-pane>
  </schism-group>

  <button
    data-on:click="
      const pane = el.closest('.demo').querySelector('schism-pane');
      $sidebarCollapsed ? pane.expand() : pane.collapse();
    "
    data-text="$sidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'"
  ></button>
</body>

Persisted via save-id

Persistence is independent of any signal. The signal here is just an observer.

Top

Drag — refresh — sizes restore

Bottom

Independent of any signal

$s4Layout =
view code
<body data-signals="{s4Layout: []}">
  <schism-group
    direction="vertical"
    save-id="datastar-demo"
    data-on:layout-change="$s4Layout = evt.detail.layout"
  >
    <schism-pane>top</schism-pane>
    <schism-resizer></schism-resizer>
    <schism-pane>bottom</schism-pane>
  </schism-group>
</body>

<!-- save-id is independent of any signal.
     localStorage["schism:datastar-demo"] is updated on drag,
     debounced 100 ms, and re-read on next mount. -->