UNPKG

@zeix/ui-element

Version:

UIElement - minimal reactive framework based on Web Components

672 lines (606 loc) 96 kB
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Examples & Recipes – UIElement Docs</title> <meta name="description" content="Common use cases and demos" /> <base href="./examples-recipes.html" /> <link rel="stylesheet" href="assets/main.css" /> <script type="module" src="assets/main.js"></script> </head> <body> <header class="content-grid"> <h1 class="content"> UIElement Docs <small>Version 0.12.2</small> </h1> <nav class="breakout"> <ol> <li> <a href="index.html"> <span class="icon">📖</span> <strong>Introduction</strong> <small>Overview and key benefits of UIElement</small> </a> </li> <li> <a href="getting-started.html"> <span class="icon">🚀</span> <strong>Getting Started</strong> <small>Installation, setup, and first steps</small> </a> </li> <li> <a href="building-components.html"> <span class="icon">🏗️</span> <strong>Building Components</strong> <small>Anatomy, lifecycle, signals, effects</small> </a> </li> <li> <a href="styling-components.html"> <span class="icon">🎨</span> <strong>Styling Components</strong> <small>Scoped styles, CSS custom properties</small> </a> </li> <li> <a href="data-flow.html"> <span class="icon">🔄</span> <strong>Data Flow</strong> <small>Passing state, events, context</small> </a> </li> <li> <a href="patterns-techniques.html"> <span class="icon">💡</span> <strong>Patterns & Techniques</strong> <small>Composition, scheduling, best practices</small> </a> </li> <li> <a href="examples-recipes.html" class="active"> <span class="icon">🍽️</span> <strong>Examples & Recipes</strong> <small>Common use cases and demos</small> </a> </li> <li> <a href="api-reference.html"> <span class="icon">📚</span> <strong>API Reference</strong> <small>Detailed documentation of classes and functions</small> </a> </li> <li> <a href="about-community.html"> <span class="icon">🤝</span> <strong>About & Community</strong> <small>License, versioning, getting involved</small> </a> </li> </ol> </nav> </header> <main><section class="hero"> <h1 id="examples-amp-recipes"> <a name="examples-amp-recipes" class="anchor" href="#examples-amp-recipes"> <span class="permalink">🔗</span> </a> 🍽️ Examples &amp; Recipes </h1><p class="lead">Discover practical examples and patterns for building reactive, modular components with UIElement. Each example focuses on showcasing a specific feature or best practice, guiding you through real-world use cases.</p> </section> <section> <h2 id="what-you39ll-learn"> <a name="what-you39ll-learn" class="anchor" href="#what-you39ll-learn"> <span class="permalink">🔗</span> </a> What You&#39;ll Learn </h2><p>This collection of examples demonstrates a range of scenarios, from simple state updates in a single component to managing complex interactions across multiple components. Here&#39;s an overview of what you&#39;ll find:</p> <ul> <li><strong>Basic Composition</strong>: <code>TabList</code> and <code>AccordionPanel</code> - See how a parent component can control the visibility of multiple child components, showcasing state sharing and communication between components.</li> <li><strong>Syntax Highlighting</strong>: - See how wrapping content in a <code>CodeBlock</code> component enables syntax highlighting on the client, demonstrating integration with third-party libraries.</li> <li><strong>Fetching Data Example</strong>: <code>LazyLoad</code> - Learn how to fetch content only when needed, handling asynchronous operations and updating state reactively as data is loaded.</li> <li><strong>Form Validation Example</strong>: <code>InputField</code> with Client-Side &amp; Server-Side Validation - Validate input fields based on requirements passed from the server and dynamically check the validity of entries, such as checking the availability of usernames via server requests.</li> <li><strong>Context Example</strong>: <code>MediaContext</code> - Discover how to share state globally across components using context, with practical use cases like adapting to media queries and responsive design.</li> </ul> <p>Whether you&#39;re getting started with a basic component or building a full-featured application, these examples will help you understand how to use <code>UIElement</code> effectively to build reactive Web Components.</p> </section> <section> <h2 id="tablist-and-accordionpanel-example"> <a name="tablist-and-accordionpanel-example" class="anchor" href="#tablist-and-accordionpanel-example"> <span class="permalink">🔗</span> </a> TabList and AccordionPanel Example </h2><component-demo> <div class="preview"> <tab-list> <menu> <li><button type="button" aria-pressed="true">Tab 1</button></li> <li><button type="button">Tab 2</button></li> <li><button type="button">Tab 3</button></li> </menu> <accordion-panel> <details open aria-disabled="true"> <summary class="visually-hidden"> <div class="summary">Tab 1</div> </summary> Content for Tab 1 </details> </accordion-panel> <accordion-panel> <details aria-disabled="true"> <summary class="visually-hidden"> <div class="summary">Tab 2</div> </summary> Content for Tab 2 </details> </accordion-panel> <accordion-panel> <details aria-disabled="true"> <summary class="visually-hidden"> <div class="summary">Tab 3</div> </summary> Content for Tab 3 </details> </accordion-panel> </tab-list> </div> <accordion-panel collapsible> <details> <summary>TabList Source Code</summary> <lazy-load src="./examples/tab-list.html"> <p class="loading">Loading...</p> </lazy-load> </details> </accordion-panel> <accordion-panel collapsible> <details> <summary>AccordionPanel Source Code</summary> <lazy-load src="./examples/accordion-panel.html"> <p class="loading">Loading...</p> </lazy-load> </details> </accordion-panel> </component-demo> </section> <section> <h2 id="codeblock-example"> <a name="codeblock-example" class="anchor" href="#codeblock-example"> <span class="permalink">🔗</span> </a> CodeBlock Example </h2><component-demo> <div class="preview"> <code-block collapsed language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="file">code-block.html</span> <span class="language">html</span> </p> <pre class="language-html"><code>&lt;code-block collapsed language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"&gt; &lt;p class="meta"&gt; &lt;span class="file"&gt;code-block.html&lt;/span&gt; &lt;span class="language"&gt;html&lt;/span&gt; &lt;/p&gt; &lt;pre&gt;&lt;code class="language-html"&gt;&lt;code-block collapsed language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"&gt; &lt;p class="meta"&gt; &lt;span class="file"&gt;code-block.html&lt;/span&gt; &lt;span class="language"&gt;html&lt;/span&gt; &lt;/p&gt; &lt;pre&gt;&lt;code class="language-html"&gt;&lt;/code&gt;&lt;/pre&gt; &lt;input-button class="copy"&gt; &lt;button type="button" class="secondary small"&gt;Copy&lt;/button&gt; &lt;/input-button&gt; &lt;button type="button" class="overlay"&gt;Expand&lt;/button&gt; &lt;/code-block&gt;&lt;/code&gt;&lt;/pre&gt; &lt;input-button class="copy"&gt; &lt;button type="button" class="secondary small"&gt;Copy&lt;/button&gt; &lt;/input-button&gt; &lt;button type="button" class="overlay"&gt;Expand&lt;/button&gt; &lt;/code-block&gt;</code></pre> <input-button class="copy"> <button type="button" class="secondary small">Copy</button> </input-button> <button type="button" class="overlay">Expand</button> </code-block> </div> <accordion-panel collapsible> <details> <summary>CodeBlock Source Code</summary> <lazy-load src="./examples/code-block.html"> <p class="loading">Loading...</p> </lazy-load> </details> </accordion-panel> <accordion-panel collapsible> <details> <summary>InputButton Source Code</summary> <lazy-load src="./examples/input-button.html"> <p class="loading">Loading...</p> </lazy-load> </details> </accordion-panel> </component-demo> </section> <section> <h2 id="lazyload-example"> <a name="lazyload-example" class="anchor" href="#lazyload-example"> <span class="permalink">🔗</span> </a> LazyLoad Example </h2><component-demo> <div class="preview"> <lazy-load src="./examples/snippets/snippet.html"> <p class="loading">Loading...</p> <p class="error"></p> </lazy-load> </div> <accordion-panel collapsible> <details> <summary>LazyLoad Source Code</summary> <lazy-load src="./examples/lazy-load.html"> <p class="loading">Loading...</p> </lazy-load> </details> </accordion-panel> </component-demo> </section> <section> <h2 id="inputfield-example"> <a name="inputfield-example" class="anchor" href="#inputfield-example"> <span class="permalink">🔗</span> </a> InputField Example </h2><component-demo> <div class="preview"> <input-field> <label for="name-input">Name</label> <div class="row"> <div class="group auto"> <input type="text" id="name-input" name="name" autocomplete="name" required> </div> </div> <p class="error" aria-live="assertive" id="name-error"></p> </input-field> <input-field integer> <label for="bday-year-input">Birthday Year</label> <div class="row"> <div class="group short"> <input type="number" id="bday-year-input" name="bday-year" autocomplete="bday-year" required minlength="4" maxlength="4" min="1900" max="2024" step="1"> </div> <div class="spinbutton" data-step="1"> <button type="button" class="decrement" aria-label="Decrement">−</button> <button type="button" class="increment" aria-label="Increment">+</button> </div> </div> <p class="error" aria-live="assertive" id="bday-year-error"></p> <p class="description" aria-live="polite" id="bday-year-description"></p> </input-field> <input-field validate="./examples/snippets/validate.html"> <label for="username-input">Username</label> <div class="row"> <div class="group auto"> <input type="text" id="username-input" name="username" autocomplete="username" aria-describedby="username-description" required minlength="4" maxlength="20"> </div> </div> <p class="error" aria-live="assertive" id="username-error"></p> <p class="description" aria-live="polite" id="username-description" data-remaining="${x} characters remaining">Max. 20 characters</p> </input-field> </div> <accordion-panel collapsible> <details> <summary>InputField Source Code</summary> <lazy-load src="./examples/input-field.html"> <p class="loading">Loading...</p> </lazy-load> </details> </accordion-panel> </component-demo> </section> <section> <h2 id="mediacontext-example"> <a name="mediacontext-example" class="anchor" href="#mediacontext-example"> <span class="permalink">🔗</span> </a> MediaContext Example </h2><p>The <code>MediaContext</code> component provides global state to any sub-components in its DOM tree by exposing context for responsive and adaptive features. It tracks the following: </p> <ul> <li><strong>Media Motion</strong> (<code>media-motion</code>): Indicates whether the user prefers reduced motion based on the <code>(prefers-reduced-motion)</code> media query.</li> <li>*<strong>Media Theme</strong> (<code>media-theme</code>): Provides the user&#39;s preferred color scheme, such as dark mode, based on the <code>(prefers-color-scheme)</code> media query.</li> <li><strong>Media Viewport</strong> (<code>media-viewport</code>): Indicates the current viewport size and is classified into different sizes (e.g., <code>xs</code>, <code>sm</code>, <code>md</code>, <code>lg</code>, <code>xl</code>). Custom breakpoints can be configured by setting attributes on the <code>&lt;media-context&gt;</code> element.</li> <li><strong>Media Orientation</strong> (<code>media-orientation</code>): Tracks the device&#39;s screen orientation, switching between <code>landscape</code> and <code>portrait</code>.</li> </ul> <h3 id="configuring-breakpoints"> <a name="configuring-breakpoints" class="anchor" href="#configuring-breakpoints"> <span class="permalink">🔗</span> </a> Configuring Breakpoints </h3><p>The viewport sizes can be customized by providing attributes on the <code>&lt;media-context&gt;</code> element:</p> <ul> <li><code>sm</code>: Small screen breakpoint (default: <code>32em</code>).</li> <li><code>md</code>: Medium screen breakpoint (default: <code>48em</code>).</li> <li><code>lg</code>: Large screen breakpoint (default: <code>72em</code>).</li> <li><code>xl</code>: Extra large screen breakpoint (default: <code>108em</code>).</li> </ul> <p>For example, to set a small breakpoint at 40em and a medium breakpoint at 60em, use:</p> <code-block language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="language">html</span> </p> <pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">&#x3C;</span><span style="color:#F92672">media-context</span><span style="color:#A6E22E"> sm</span><span style="color:#F8F8F2">=</span><span style="color:#E6DB74">"40em"</span><span style="color:#A6E22E"> md</span><span style="color:#F8F8F2">=</span><span style="color:#E6DB74">"60em"</span><span style="color:#F8F8F2">>&#x3C;/</span><span style="color:#F92672">media-context</span><span style="color:#F8F8F2">></span></span> <span class="line"></span></code></pre> <input-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </input-button> </code-block> <p>Source code:</p> <code-block collapsed language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="language">js</span> </p> <pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F92672">import</span><span style="color:#F8F8F2"> { UIElement, maybe } </span><span style="color:#F92672">from</span><span style="color:#E6DB74"> '@zeix/ui-element'</span></span> <span class="line"></span> <span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> VIEWPORT_XS </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'xs'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> VIEWPORT_SM </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'sm'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> VIEWPORT_MD </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'md'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> VIEWPORT_LG </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'lg'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> VIEWPORT_XL </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'xl'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> ORIENTATION_LANDSCAPE </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'landscape'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic">const</span><span style="color:#F8F8F2"> ORIENTATION_PORTRAIT </span><span style="color:#F92672">=</span><span style="color:#E6DB74"> 'portrait'</span><span style="color:#F8F8F2">;</span></span> <span class="line"></span> <span class="line"><span style="color:#66D9EF;font-style:italic">class</span><span> </span><span style="color:#A6E22E;text-decoration:underline">MediaContext</span><span style="color:#F92672"> extends</span><span> </span><span style="color:#A6E22E;font-style:italic;text-decoration:underline">UIElement</span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#F92672">static</span><span style="color:#F8F8F2"> providedContexts </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> [</span><span style="color:#E6DB74">'media-motion'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'media-theme'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'media-viewport'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'media-orientation'</span><span style="color:#F8F8F2">];</span></span> <span class="line"></span> <span class="line"><span style="color:#A6E22E">connectedCallback</span><span style="color:#F8F8F2">() {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#A6E22E"> getBreakpoints</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#A6E22E"> parseBreakpoint</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> (</span><span style="color:#FD971F;font-style:italic">breakpoint</span><span style="color:#F8F8F2">) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> attr </span><span style="color:#F92672">=</span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">getAttribute</span><span style="color:#F8F8F2">(breakpoint)?.</span><span style="color:#A6E22E">trim</span><span style="color:#F8F8F2">();</span></span> <span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (</span><span style="color:#F92672">!</span><span style="color:#F8F8F2">attr) </span><span style="color:#F92672">return</span><span style="color:#AE81FF"> null</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> unit </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> attr.</span><span style="color:#A6E22E">match</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">/em</span><span style="color:#F92672">$</span><span style="color:#E6DB74">/</span><span style="color:#F8F8F2">) </span><span style="color:#F92672">?</span><span style="color:#E6DB74"> 'em'</span><span style="color:#F92672"> :</span><span style="color:#E6DB74"> 'px'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> value </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> maybe</span><span style="color:#F8F8F2">(</span><span style="color:#A6E22E">parseFloat</span><span style="color:#F8F8F2">(attr)).</span><span style="color:#A6E22E">filter</span><span style="color:#F8F8F2">(Number.isFinite)[</span><span style="color:#AE81FF">0</span><span style="color:#F8F8F2">];</span></span> <span class="line"><span style="color:#F92672"> return</span><span style="color:#F8F8F2"> value </span><span style="color:#F92672">?</span><span style="color:#F8F8F2"> value </span><span style="color:#F92672">+</span><span style="color:#F8F8F2"> unit </span><span style="color:#F92672">:</span><span style="color:#AE81FF"> null</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#F8F8F2"> };</span></span> <span class="line"></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> sm </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> parseBreakpoint</span><span style="color:#F8F8F2">(VIEWPORT_SM) </span><span style="color:#F92672">||</span><span style="color:#E6DB74"> '32em'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> md </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> parseBreakpoint</span><span style="color:#F8F8F2">(VIEWPORT_MD) </span><span style="color:#F92672">||</span><span style="color:#E6DB74"> '48em'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> lg </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> parseBreakpoint</span><span style="color:#F8F8F2">(VIEWPORT_LG) </span><span style="color:#F92672">||</span><span style="color:#E6DB74"> '72em'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> xl </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> parseBreakpoint</span><span style="color:#F8F8F2">(VIEWPORT_XL) </span><span style="color:#F92672">||</span><span style="color:#E6DB74"> '108em'</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#F92672"> return</span><span style="color:#F8F8F2"> { sm, md, lg, xl };</span></span> <span class="line"><span style="color:#F8F8F2"> };</span></span> <span class="line"><span style="color:#F8F8F2"> </span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> breakpoints </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> getBreakpoints</span><span style="color:#F8F8F2">();</span></span> <span class="line"></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> reducedMotion </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> matchMedia</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'(prefers-reduced-motion: reduce)'</span><span style="color:#F8F8F2">);</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> darkMode </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> matchMedia</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'(prefers-color-scheme: dark)'</span><span style="color:#F8F8F2">);</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> screenSmall </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> matchMedia</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">`(min-width: </span><span style="color:#F92672">${</span><span style="color:#F8F8F2">breakpoints.sm</span><span style="color:#F92672">}</span><span style="color:#E6DB74">)`</span><span style="color:#F8F8F2">);</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> screenMedium </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> matchMedia</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">`(min-width: </span><span style="color:#F92672">${</span><span style="color:#F8F8F2">breakpoints.md</span><span style="color:#F92672">}</span><span style="color:#E6DB74">)`</span><span style="color:#F8F8F2">);</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> screenLarge </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> matchMedia</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">`(min-width: </span><span style="color:#F92672">${</span><span style="color:#F8F8F2">breakpoints.lg</span><span style="color:#F92672">}</span><span style="color:#E6DB74">)`</span><span style="color:#F8F8F2">);</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> screenXLarge </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> matchMedia</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">`(min-width: </span><span style="color:#F92672">${</span><span style="color:#F8F8F2">breakpoints.xl</span><span style="color:#F92672">}</span><span style="color:#E6DB74">)`</span><span style="color:#F8F8F2">);</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> screenOrientation </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> matchMedia</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'(orientation: landscape)'</span><span style="color:#F8F8F2">);</span></span> <span class="line"></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#A6E22E"> getViewport</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (screenXLarge.matches) </span><span style="color:#F92672">return</span><span style="color:#F8F8F2"> VIEWPORT_XL;</span></span> <span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (screenLarge.matches) </span><span style="color:#F92672">return</span><span style="color:#F8F8F2"> VIEWPORT_LG;</span></span> <span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (screenMedium.matches) </span><span style="color:#F92672">return</span><span style="color:#F8F8F2"> VIEWPORT_MD;</span></span> <span class="line"><span style="color:#F92672"> if</span><span style="color:#F8F8F2"> (screenSmall.matches) </span><span style="color:#F92672">return</span><span style="color:#F8F8F2"> VIEWPORT_SM;</span></span> <span class="line"><span style="color:#F92672"> return</span><span style="color:#F8F8F2"> VIEWPORT_XS;</span></span> <span class="line"><span style="color:#F8F8F2"> };</span></span> <span class="line"></span> <span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-motion'</span><span style="color:#F8F8F2">, reducedMotion.matches);</span></span> <span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-theme'</span><span style="color:#F8F8F2">, darkMode.matches);</span></span> <span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-viewport'</span><span style="color:#F8F8F2">, </span><span style="color:#A6E22E">getViewport</span><span style="color:#F8F8F2">());</span></span> <span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-orientation'</span><span style="color:#F8F8F2">, screenOrientation.matches </span><span style="color:#F92672">?</span><span style="color:#F8F8F2"> ORIENTATION_LANDSCAPE </span><span style="color:#F92672">:</span><span style="color:#F8F8F2"> ORIENTATION_PORTRAIT);</span></span> <span class="line"></span> <span class="line"><span style="color:#F8F8F2"> reducedMotion.</span><span style="color:#A6E22E">onchange</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> (</span><span style="color:#FD971F;font-style:italic">e</span><span style="color:#F8F8F2">) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-motion'</span><span style="color:#F8F8F2">, e.matches);</span></span> <span class="line"><span style="color:#F8F8F2"> darkMode.</span><span style="color:#A6E22E">onchange</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> (</span><span style="color:#FD971F;font-style:italic">e</span><span style="color:#F8F8F2">) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-theme'</span><span style="color:#F8F8F2">, e.matches);</span></span> <span class="line"><span style="color:#F8F8F2"> screenSmall.</span><span style="color:#A6E22E">onchange</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-viewport'</span><span style="color:#F8F8F2">, </span><span style="color:#A6E22E">getViewport</span><span style="color:#F8F8F2">());</span></span> <span class="line"><span style="color:#F8F8F2"> screenMedium.</span><span style="color:#A6E22E">onchange</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-viewport'</span><span style="color:#F8F8F2">, </span><span style="color:#A6E22E">getViewport</span><span style="color:#F8F8F2">());</span></span> <span class="line"><span style="color:#F8F8F2"> screenLarge.</span><span style="color:#A6E22E">onchange</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-viewport'</span><span style="color:#F8F8F2">, </span><span style="color:#A6E22E">getViewport</span><span style="color:#F8F8F2">());</span></span> <span class="line"><span style="color:#F8F8F2"> screenXLarge.</span><span style="color:#A6E22E">onchange</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-viewport'</span><span style="color:#F8F8F2">, </span><span style="color:#A6E22E">getViewport</span><span style="color:#F8F8F2">());</span></span> <span class="line"><span style="color:#F8F8F2"> screenOrientation.</span><span style="color:#A6E22E">onchange</span><span style="color:#F92672"> =</span><span style="color:#F8F8F2"> (</span><span style="color:#FD971F;font-style:italic">e</span><span style="color:#F8F8F2">) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">set</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-orientation'</span><span style="color:#F8F8F2">, e.matches </span><span style="color:#F92672">?</span><span style="color:#F8F8F2"> ORIENTATION_LANDSCAPE </span><span style="color:#F92672">:</span><span style="color:#F8F8F2"> ORIENTATION_PORTRAIT);</span></span> <span class="line"><span style="color:#F8F8F2">}</span></span> <span class="line"><span style="color:#F8F8F2">}</span></span> <span class="line"></span> <span class="line"><span style="color:#F8F8F2">MediaContext.</span><span style="color:#A6E22E">define</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-context'</span><span style="color:#F8F8F2">);</span></span> <span class="line"></span></code></pre> <input-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </input-button> <button type="button" class="overlay">Expand</button> </code-block> </section> <section> <h2 id="themedcomponent-example"> <a name="themedcomponent-example" class="anchor" href="#themedcomponent-example"> <span class="permalink">🔗</span> </a> ThemedComponent Example </h2><!-- Live component preview wrapped in media-context --> <media-context> <themed-component> This component changes its background based on the theme! </themed-component> </media-context> <!-- Source code with progressive disclosure --> <details> <summary>Source Code</summary> <!-- Tabs for HTML, CSS, and JavaScript --> <tab-list> <!-- HTML Tab Panel --> <tab-panel label="HTML"> <h3 id="html"> <a name="html" class="anchor" href="#html"> <span class="permalink">🔗</span> </a> HTML </h3><code-block language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="language">html</span> </p> <pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">&#x3C;</span><span style="color:#F92672">media-context</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2"> &#x3C;</span><span style="color:#F92672">themed-component</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2"> This component changes its background based on the theme!</span></span> <span class="line"><span style="color:#F8F8F2"> &#x3C;/</span><span style="color:#F92672">themed-component</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2">&#x3C;/</span><span style="color:#F92672">media-context</span><span style="color:#F8F8F2">></span></span> <span class="line"></span></code></pre> <input-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </input-button> </code-block> </tab-panel> <!-- CSS Tab Panel --> <tab-panel label="CSS"> <h3 id="css"> <a name="css" class="anchor" href="#css"> <span class="permalink">🔗</span> </a> CSS </h3><code-block collapsed language="css" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="language">css</span> </p> <pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F92672">themed-component</span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> display</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">block</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> padding</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">20</span><span style="color:#F92672">px</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> color</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">white</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> transition</span><span style="color:#F8F8F2">: background-color </span><span style="color:#AE81FF">0.3</span><span style="color:#F92672">s</span><span style="color:#66D9EF"> ease</span><span style="color:#F8F8F2">;</span></span> <span class="line"></span> <span class="line"><span style="color:#F8F8F2"> &#x26;.dark {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> background-color</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">black</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#F8F8F2"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#F8F8F2"> &#x26;</span><span style="color:#A6E22E">.light</span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> background-color</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">lightgray</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#F8F8F2"> }</span></span> <span class="line"><span style="color:#F8F8F2">}</span></span> <span class="line"></span></code></pre> <input-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </input-button> <button type="button" class="overlay">Expand</button> </code-block> </tab-panel> <!-- JavaScript Tab Panel --> <tab-panel label="JavaScript"> <h3 id="javascript"> <a name="javascript" class="anchor" href="#javascript"> <span class="permalink">🔗</span> </a> JavaScript </h3><code-block collapsed language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="language">js</span> </p> <pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F92672">import</span><span style="color:#F8F8F2"> { UIElement, toggleClass } </span><span style="color:#F92672">from</span><span style="color:#E6DB74"> '@zeix/ui-element'</span><span style="color:#F8F8F2">;</span></span> <span class="line"></span> <span class="line"><span style="color:#66D9EF;font-style:italic">class</span><span> </span><span style="color:#A6E22E;text-decoration:underline">ThemedComponent</span><span style="color:#F92672"> extends</span><span> </span><span style="color:#A6E22E;font-style:italic;text-decoration:underline">UIElement</span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#F92672"> static</span><span style="color:#F8F8F2"> consumedContexts </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> [</span><span style="color:#E6DB74">'media-theme'</span><span style="color:#F8F8F2">];</span></span> <span class="line"></span> <span class="line"><span style="color:#A6E22E"> connectedCallback</span><span style="color:#F8F8F2">() {</span></span> <span class="line"><span style="color:#88846F"> // Toggle the class based on 'media-theme' signal</span></span> <span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.self.</span><span style="color:#A6E22E">sync</span><span style="color:#F8F8F2">(</span><span style="color:#A6E22E">toggleClass</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'dark'</span><span style="color:#F8F8F2">, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">get</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-theme'</span><span style="color:#F8F8F2">)));</span></span> <span class="line"><span style="color:#FD971F"> this</span><span style="color:#F8F8F2">.self.</span><span style="color:#A6E22E">sync</span><span style="color:#F8F8F2">(</span><span style="color:#A6E22E">toggleClass</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'light'</span><span style="color:#F8F8F2">, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F92672"> !</span><span style="color:#FD971F">this</span><span style="color:#F8F8F2">.</span><span style="color:#A6E22E">get</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'media-theme'</span><span style="color:#F8F8F2">)));</span></span> <span class="line"><span style="color:#F8F8F2"> }</span></span> <span class="line"><span style="color:#F8F8F2">}</span></span> <span class="line"><span style="color:#F8F8F2">ThemedComponent.</span><span style="color:#A6E22E">define</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'themed-component'</span><span style="color:#F8F8F2">);</span></span> <span class="line"></span></code></pre> <input-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </input-button> <button type="button" class="overlay">Expand</button> </code-block> </tab-panel> </tab-list> </details> </section> <section> <h2 id="animatedcomponent-example"> <a name="animatedcomponent-example" class="anchor" href="#animatedcomponent-example"> <span class="permalink">🔗</span> </a> AnimatedComponent Example </h2><!-- Live component preview wrapped in media-context --> <media-context> <animated-component> <div class="animated-box">Box 1</div> <div class="animated-box">Box 2</div> <div class="animated-box">Box 3</div> </animated-component> </media-context> <!-- Source code with progressive disclosure --> <details> <summary>Source Code</summary> <!-- Tabs for HTML, CSS, and JavaScript --> <tab-list> <!-- HTML Tab Panel --> <tab-panel label="HTML"> <h3 id="html"> <a name="html" class="anchor" href="#html"> <span class="permalink">🔗</span> </a> HTML </h3><code-block language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="language">html</span> </p> <pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">&#x3C;</span><span style="color:#F92672">media-context</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2"> &#x3C;</span><span style="color:#F92672">animated-component</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2"> &#x3C;</span><span style="color:#F92672">div</span><span style="color:#A6E22E"> class</span><span style="color:#F8F8F2">=</span><span style="color:#E6DB74">"animated-box"</span><span style="color:#F8F8F2">>Box 1&#x3C;/</span><span style="color:#F92672">div</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2"> &#x3C;</span><span style="color:#F92672">div</span><span style="color:#A6E22E"> class</span><span style="color:#F8F8F2">=</span><span style="color:#E6DB74">"animated-box"</span><span style="color:#F8F8F2">>Box 2&#x3C;/</span><span style="color:#F92672">div</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2"> &#x3C;</span><span style="color:#F92672">div</span><span style="color:#A6E22E"> class</span><span style="color:#F8F8F2">=</span><span style="color:#E6DB74">"animated-box"</span><span style="color:#F8F8F2">>Box 3&#x3C;/</span><span style="color:#F92672">div</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2"> &#x3C;/</span><span style="color:#F92672">animated-component</span><span style="color:#F8F8F2">></span></span> <span class="line"><span style="color:#F8F8F2">&#x3C;/</span><span style="color:#F92672">media-context</span><span style="color:#F8F8F2">></span></span> <span class="line"></span></code></pre> <input-button class="copy"> <button type="button" class="secondary small"> <span class="label">Copy</span> </button> </input-button> </code-block> </tab-panel> <!-- CSS Tab Panel --> <tab-panel label="CSS"> <h3 id="css"> <a name="css" class="anchor" href="#css"> <span class="permalink">🔗</span> </a> CSS </h3><code-block collapsed language="css" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"> <p class="meta"> <span class="language">css</span> </p> <pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F92672">animated-component</span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> display</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">block</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> padding</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">20</span><span style="color:#F92672">px</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> overflow</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">hidden</span><span style="color:#F8F8F2">;</span></span> <span class="line"></span> <span class="line"><span style="color:#F8F8F2"> .animated-box {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> width</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">50</span><span style="color:#F92672">px</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> height</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">50</span><span style="color:#F92672">px</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> margin</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">10</span><span style="color:#F92672">px</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> background-color</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">lightblue</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> text-align</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">center</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> line-height</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">50</span><span style="color:#F92672">px</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> font-weight</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">bold</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> color</span><span style="color:#F8F8F2">: </span><span style="color:#66D9EF">white</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#F8F8F2"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#F8F8F2"> &#x26;</span><span style="color:#A6E22E">.no-motion</span><span style="color:#A6E22E"> .animated-box</span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> opacity</span><span style="color:#F8F8F2">: </span><span style="color:#AE81FF">0</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> transition</span><span style="color:#F8F8F2">: opacity </span><span style="color:#AE81FF">1</span><span style="color:#F92672">s</span><span style="color:#66D9EF"> ease-in</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#F8F8F2"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#F8F8F2"> &#x26;</span><span style="color:#A6E22E">.motion</span><span style="color:#A6E22E"> .animated-box</span><span style="color:#F8F8F2"> {</span></span> <span class="line"><span style="color:#66D9EF;font-style:italic"> animation</span><span style="color:#F8F8F2">: moveAndFlash </span><span style="color:#AE81FF">2</span><span style="color:#F92672">s</span><span style="color:#66D9EF"> infinite</span><span style="color:#66D9EF"> ease-in-out</span><span style="color:#66D9EF"> alternate</span><span style="color:#F8F8F2">;</span></span> <span class="line"><span style="color:#F8F8F2"> }</span><