DSD, open/closed template, and light-DOM components that talk through <main-context>: children register on… callbacks and share updates as events. Served by Vite via npm run examples; examples/ is linted, formatted and typechecked.
138 lines
5.2 KiB
HTML
138 lines
5.2 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>wc-mixin examples</title>
|
||
<link rel="stylesheet" href="./style.css" />
|
||
<script type="module" src="./main.ts"></script>
|
||
</head>
|
||
<body>
|
||
<main>
|
||
<!--
|
||
The context manager: siblings below register callbacks with it and
|
||
share updates through it, instead of reaching for each other.
|
||
-->
|
||
<main-context>
|
||
<!--
|
||
Declarative shadow DOM: the parser attaches this shadow root, so the
|
||
banner renders (with its layout styles) before any JS loads. The
|
||
component's `css` adds the gradient animation once it upgrades, and its
|
||
props take over the text from here.
|
||
-->
|
||
<hero-banner id="banner" theme="sunset">
|
||
<template shadowrootmode="open">
|
||
<style>
|
||
:host { display: block; }
|
||
.stage {
|
||
display: grid;
|
||
gap: 0.75rem;
|
||
padding: clamp(2rem, 6vw, 4.5rem) clamp(1.25rem, 5vw, 3.5rem);
|
||
border-radius: 24px;
|
||
background: #0d0d14;
|
||
color: #f4f4fb;
|
||
overflow: hidden;
|
||
}
|
||
.eyebrow {
|
||
margin: 0;
|
||
font: 600 0.75rem/1 system-ui, sans-serif;
|
||
letter-spacing: 0.2em;
|
||
text-transform: uppercase;
|
||
opacity: 0.6;
|
||
}
|
||
h1 {
|
||
margin: 0;
|
||
font: 800 clamp(2.25rem, 8vw, 5rem)/1.02 system-ui, sans-serif;
|
||
letter-spacing: -0.03em;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
.tagline { margin: 0; max-width: 36rem; font-size: 1.1rem; opacity: 0.8; }
|
||
</style>
|
||
<div class="stage">
|
||
<p class="eyebrow">Declarative shadow DOM</p>
|
||
<h1>Hello, wc-mixin</h1>
|
||
<p class="tagline">Typed props, refs and styles without the boilerplate.</p>
|
||
</div>
|
||
</template>
|
||
</hero-banner>
|
||
|
||
<div class="grid">
|
||
<section class="card">
|
||
<h2>Controls <span class="kind">light DOM</span></h2>
|
||
<p>
|
||
<code><labeled-field></code> and <code><color-swatch-picker></code> render
|
||
into the light DOM; their CSS lives in a <code><style></code> in
|
||
<code><head></code>. They never touch the other components: each edit is
|
||
shared with <code><main-context></code>, which calls the
|
||
<code>on…</code> callbacks the other components registered.
|
||
</p>
|
||
<div class="controls">
|
||
<labeled-field
|
||
id="headline"
|
||
name="headline"
|
||
label="Headline"
|
||
value="Hello, wc-mixin"
|
||
required
|
||
hint="Shared as headline → hero-banner"
|
||
></labeled-field>
|
||
<labeled-field
|
||
id="tagline"
|
||
name="tagline"
|
||
label="Tagline"
|
||
value="Typed props, refs and styles without the boilerplate."
|
||
hint="Shared as tagline → hero-banner"
|
||
></labeled-field>
|
||
<color-swatch-picker id="theme" label="Banner theme"></color-swatch-picker>
|
||
<labeled-field
|
||
id="stars"
|
||
name="stars"
|
||
label="Number of stars"
|
||
type="number"
|
||
value="5"
|
||
required
|
||
hint="Shared as stars → star-rating (1–10)"
|
||
></labeled-field>
|
||
<labeled-field
|
||
id="secret"
|
||
name="secret"
|
||
label="Secret message"
|
||
value="The cake is in the closed shadow root."
|
||
placeholder="Something hidden…"
|
||
hint="Shared as secret → secret-note"
|
||
></labeled-field>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="controls">
|
||
<section class="card">
|
||
<h2><star-rating> <span class="kind">template · open shadow</span></h2>
|
||
<p>Click or hover a star. Clicking the current value clears it.</p>
|
||
<star-rating id="rating" value="3">Rate this mixin</star-rating>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<h2><secret-note> <span class="kind">template · closed shadow</span></h2>
|
||
<p>The page can't reach inside, but the component can, through <code>this.root</code>.</p>
|
||
<secret-note id="note" message="The cake is in the closed shadow root."></secret-note>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<h2>From the outside</h2>
|
||
<output id="probe"></output>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
|
||
<section class="card">
|
||
<div class="log-head">
|
||
<h2>Attribute log</h2>
|
||
<button id="clear-log" type="button">Clear</button>
|
||
</div>
|
||
<p>Each prop change reflects to an attribute, and this list records them as mutations.</p>
|
||
<ol id="log"></ol>
|
||
</section>
|
||
</main-context>
|
||
</main>
|
||
</body>
|
||
</html>
|