kempo-ui 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css,nothing}from"../lit-all.min.js";import{boolTrueFalse}from"../utils/propConverters.js";import"./FocusCapture.js";import"./Icon.js";export default class Aside extends ShadowComponent{static properties={state:{type:String,reflect:!0},side:{type:String,reflect:!0},main:{type:String,reflect:!0},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolTrueFalse},escClose:{type:Boolean,reflect:!0,attribute:"esc-close",converter:boolTrueFalse}};constructor(){super(),this.state="offscreen",this.side="left",this.main="overlay",this.overlayClose=!0,this.escClose=!0}overlayClick=()=>{this.overlayClose&&this.hide()};handleKeyDown=e=>{this.escClose&&"Escape"===e.key&&this.hide()};updated(e){if(super.updated(e),e.has("state")){const t=e.get("state");"offscreen"===this.state||"offscreen"!==t&&void 0!==t?"offscreen"===this.state&&void 0!==t&&"offscreen"!==t&&document.removeEventListener("keydown",this.handleKeyDown):document.addEventListener("keydown",this.handleKeyDown),"overlay"===this.main&&("expanded"===this.state?document.body.classList.add("no-scroll"):document.body.classList.remove("no-scroll"));const s="offscreen"===this.state?0:this.getTargetWidth(this.state),a={aside:this,state:this.state,main:this.main,width:s};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),this.inert="offscreen"===this.state}}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown),document.body.classList.remove("no-scroll");const e={aside:this,state:"offscreen",main:this.main,width:0};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:e})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:e}))}expand=()=>this.state="expanded";collapse=()=>this.state="collapsed";hide=()=>this.state="offscreen";toggle=()=>{this.state="expanded"===this.state?"offscreen":"expanded"};getTargetWidth(e){const t=parseFloat(getComputedStyle(document.documentElement).fontSize),s="collapsed"===e?"--collapsed-width":"--width",a=getComputedStyle(this).getPropertyValue(s).trim();return(a?parseFloat(a):"collapsed"===e?3.5:20)*t}render(){const e=html`<aside><slot></slot></aside>`;return"overlay"===this.main?html`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css,nothing}from"../lit-all.min.js";import{boolTrueFalse}from"../utils/propConverters.js";import"./FocusCapture.js";import"./Icon.js";export default class Aside extends ShadowComponent{static properties={state:{type:String,reflect:!0},side:{type:String,reflect:!0},main:{type:String,reflect:!0},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolTrueFalse},escClose:{type:Boolean,reflect:!0,attribute:"esc-close",converter:boolTrueFalse},persistentId:{type:String,reflect:!0,attribute:"persistent-id"}};constructor(){super(),this.state="offscreen",this.side="left",this.main="overlay",this.overlayClose=!0,this.escClose=!0,this.persistentId=null}overlayClick=()=>{this.overlayClose&&this.hide()};handleKeyDown=e=>{this.escClose&&"Escape"===e.key&&this.hide()};updated(e){if(super.updated(e),e.has("persistentId")&&this.persistentId&&window?.localStorage){const e=window.localStorage.getItem(`aside-persistent-id-${this.persistentId}`);e&&(this.state=e)}if(e.has("state")){const t=e.get("state");"offscreen"===this.state||"offscreen"!==t&&void 0!==t?"offscreen"===this.state&&void 0!==t&&"offscreen"!==t&&document.removeEventListener("keydown",this.handleKeyDown):document.addEventListener("keydown",this.handleKeyDown),"overlay"===this.main&&("expanded"===this.state?document.body.classList.add("no-scroll"):document.body.classList.remove("no-scroll"));const s="offscreen"===this.state?0:this.getTargetWidth(this.state),a={aside:this,state:this.state,main:this.main,width:s};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),this.inert="offscreen"===this.state,this.persistentId&&window?.localStorage&&window.localStorage.setItem(`aside-persistent-id-${this.persistentId}`,this.state)}}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown),document.body.classList.remove("no-scroll");const e={aside:this,state:"offscreen",main:this.main,width:0};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:e})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:e}))}expand=()=>this.state="expanded";collapse=()=>this.state="collapsed";hide=()=>this.state="offscreen";toggle=()=>{this.state="expanded"===this.state?"offscreen":"expanded"};getTargetWidth(e){const t=parseFloat(getComputedStyle(document.documentElement).fontSize),s="collapsed"===e?"--collapsed-width":"--width",a=getComputedStyle(this).getPropertyValue(s).trim();return(a?parseFloat(a):"collapsed"===e?3.5:20)*t}render(){const e=html`<aside><slot></slot></aside>`;return"overlay"===this.main?html`
2
2
  <k-focus-capture>
3
3
  <div id="container">
4
4
  <button id="overlay-btn" @click=${this.overlayClick}>
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";export default class Main extends ShadowComponent{constructor(){super(),this.widthMap=new Map}connectedCallback(){super.connectedCallback(),window.addEventListener("aside_state_change",this.handleAsideChange),document.querySelectorAll('k-aside[main="push"]').forEach(t=>{if("offscreen"!==t.state){const e=t.getTargetWidth(t.state);e>0&&this.widthMap.set(t,{side:t.side||"left",width:e})}}),this.recalculate()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("aside_state_change",this.handleAsideChange)}handleAsideChange=t=>{const{aside:e,state:a,main:i,width:s}=t.detail;"overlay"===i||"offscreen"===a?this.widthMap.delete(e):this.widthMap.set(e,{side:e.side||"left",width:s}),this.recalculate()};recalculate=()=>{let t=0,e=0;for(const[,{side:a,width:i}]of this.widthMap)"right"===a?e=Math.max(e,i):t=Math.max(t,i);this.style.setProperty("--left-panel-width",`${t}px`),this.style.setProperty("--right-panel-width",`${e}px`)};render(){return html`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";export default class Main extends ShadowComponent{constructor(){super(),this.widthMap=new Map}connectedCallback(){super.connectedCallback(),window.addEventListener("aside_state_change",this.handleAsideChange),document.querySelectorAll('k-aside[main="push"]').forEach(t=>{if("offscreen"!==t.state&&"function"==typeof t.getTargetWidth){const e=t.getTargetWidth(t.state);e>0&&this.widthMap.set(t,{side:t.side||"left",width:e})}}),this.recalculate()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("aside_state_change",this.handleAsideChange)}handleAsideChange=t=>{const{aside:e,state:a,main:i,width:n}=t.detail;"overlay"===i||"offscreen"===a?this.widthMap.delete(e):this.widthMap.set(e,{side:e.side||"left",width:n}),this.recalculate()};recalculate=()=>{let t=0,e=0;for(const[,{side:a,width:i}]of this.widthMap)"right"===a?e=Math.max(e,i):t=Math.max(t,i);this.style.setProperty("--left-panel-width",`${t}px`),this.style.setProperty("--right-panel-width",`${e}px`)};render(){return html`
2
2
  <main>
3
3
  <slot></slot>
4
4
  </main>
@@ -247,9 +247,10 @@
247
247
 
248
248
  <k-main>
249
249
 
250
- <details class="b r mb">
251
- <summary class="p">Table of Contents</summary>
252
- <div class="m mt0 pl">
250
+ <k-accordion persistent-id="toc" class="b r mb">
251
+ <k-accordion-header for-panel="toc-panel">Table of Contents</k-accordion-header>
252
+ <k-accordion-panel name="toc-panel">
253
+ <div class="m">
253
254
  <h6>Overlay Mode</h6>
254
255
  <a href="#overlayBasic">Basic Usage</a><br />
255
256
  <a href="#overlayClose">Closing Options</a><br />
@@ -264,6 +265,7 @@
264
265
  <a href="#customWidth">Custom Width</a><br />
265
266
  <a href="#customBg">Custom Background</a><br />
266
267
  <a href="#customCollapsed">Custom Collapsed Width</a><br />
268
+ <a href="#persistentState">Persistent State</a><br />
267
269
 
268
270
  <h6 class="mt">Sub-Components</h6>
269
271
  <a href="#subItems">Items &amp; Labels</a><br />
@@ -286,7 +288,8 @@
286
288
  <a href="#asideSpacer">k-aside-spacer</a><br />
287
289
  <a href="#asideToggle">k-aside-toggle</a><br />
288
290
  </div>
289
- </details>
291
+ </k-accordion-panel>
292
+ </k-accordion>
290
293
 
291
294
  <h2>Overlay Mode</h2>
292
295
  <p>The default mode. Use <code>state="offscreen"</code> as the starting state; call <code>expand()</code> to open. Clicking the backdrop or pressing ESC closes it by default.</p>
@@ -296,12 +299,7 @@
296
299
  <div class="row -mx">
297
300
  <div class="col m-span-12 px">
298
301
  <k-card label="HTML">
299
- <pre><code class="hljs html">&lt;k-aside state="offscreen"&gt;
300
- &lt;p&gt;Overlay Menu Content&lt;/p&gt;
301
- &lt;/k-aside&gt;
302
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
303
- Open Menu
304
- &lt;/button&gt;</code></pre>
302
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Overlay Menu Content<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
305
303
  </k-card>
306
304
  </div>
307
305
  <div class="col m-span-12 px">
@@ -325,16 +323,7 @@
325
323
  <div class="row -mx">
326
324
  <div class="col m-span-12 px">
327
325
  <k-card label="HTML">
328
- <pre><code class="hljs html">&lt;k-aside state="offscreen"
329
- overlay-close="false"&gt;
330
- &lt;p&gt;Overlay Menu&lt;/p&gt;
331
- &lt;button onclick="this.closest('k-aside').hide()"&gt;
332
- Close
333
- &lt;/button&gt;
334
- &lt;/k-aside&gt;
335
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
336
- Open Menu
337
- &lt;/button&gt;</code></pre>
326
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span> <span class="hljs-attr">overlay-close</span>=<span class="hljs-string">&#x27;false&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Overlay Menu<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.closest(&quot;k-aside&quot;).hide()&#x27;</span>&gt;</span> Close <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
338
327
  </k-card>
339
328
  </div>
340
329
  <div class="col m-span-12 px">
@@ -362,13 +351,7 @@
362
351
  <div class="row -mx">
363
352
  <div class="col m-span-12 px">
364
353
  <k-card label="HTML">
365
- <pre><code class="hljs html">&lt;k-aside state="offscreen"
366
- side="right"&gt;
367
- &lt;p&gt;Right Side Menu&lt;/p&gt;
368
- &lt;/k-aside&gt;
369
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
370
- Open Right Menu
371
- &lt;/button&gt;</code></pre>
354
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span> <span class="hljs-attr">side</span>=<span class="hljs-string">&#x27;right&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Right Side Menu<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Right Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
372
355
  </k-card>
373
356
  </div>
374
357
  <div class="col m-span-12 px">
@@ -394,17 +377,7 @@
394
377
  <div class="row -mx">
395
378
  <div class="col m-span-12 px">
396
379
  <k-card label="HTML">
397
- <pre><code class="hljs html">&lt;k-aside main="push" state="offscreen"&gt;
398
- &lt;nav&gt;
399
- &lt;h3&gt;Sidebar&lt;/h3&gt;
400
- &lt;a href="#"&gt;Home&lt;/a&gt;
401
- &lt;a href="#"&gt;About&lt;/a&gt;
402
- &lt;a href="#"&gt;Contact&lt;/a&gt;
403
- &lt;/nav&gt;
404
- &lt;/k-aside&gt;
405
- &lt;button onclick="this.previousElementSibling.toggle()"&gt;
406
- Toggle Sidebar
407
- &lt;/button&gt;</code></pre>
380
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Sidebar<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.toggle()&#x27;</span>&gt;</span> Toggle Sidebar <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
408
381
  </k-card>
409
382
  </div>
410
383
  <div class="col m-span-12 px">
@@ -433,17 +406,7 @@
433
406
  <div class="row -mx">
434
407
  <div class="col m-span-12 px">
435
408
  <k-card label="HTML">
436
- <pre><code class="hljs html">&lt;k-aside main="push" state="offscreen"&gt;
437
- &lt;nav&gt;
438
- &lt;h3&gt;Menu&lt;/h3&gt;
439
- &lt;a href="#"&gt;Dashboard&lt;/a&gt;
440
- &lt;a href="#"&gt;Settings&lt;/a&gt;
441
- &lt;/nav&gt;
442
- &lt;/k-aside&gt;
443
-
444
- &lt;button onclick="aside.expand()"&gt;Expand&lt;/button&gt;
445
- &lt;button onclick="aside.collapse()"&gt;Collapse&lt;/button&gt;
446
- &lt;button onclick="aside.hide()"&gt;Hide&lt;/button&gt;</code></pre>
409
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Menu<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Settings<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.expand()&#x27;</span>&gt;</span>Expand<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.collapse()&#x27;</span>&gt;</span>Collapse<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.hide()&#x27;</span>&gt;</span>Hide<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
447
410
  </k-card>
448
411
  </div>
449
412
  <div class="col m-span-12 px">
@@ -474,16 +437,7 @@
474
437
  <div class="row -mx">
475
438
  <div class="col m-span-12 px">
476
439
  <k-card label="HTML">
477
- <pre><code class="hljs html">&lt;k-aside main="push" side="right" state="offscreen"&gt;
478
- &lt;nav&gt;
479
- &lt;h3&gt;Right Panel&lt;/h3&gt;
480
- &lt;a href="#"&gt;Item 1&lt;/a&gt;
481
- &lt;a href="#"&gt;Item 2&lt;/a&gt;
482
- &lt;/nav&gt;
483
- &lt;/k-aside&gt;
484
- &lt;button onclick="this.previousElementSibling.toggle()"&gt;
485
- Toggle Right Sidebar
486
- &lt;/button&gt;</code></pre>
440
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">side</span>=<span class="hljs-string">&#x27;right&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Right Panel<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Item 1<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Item 2<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.toggle()&#x27;</span>&gt;</span> Toggle Right Sidebar <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
487
441
  </k-card>
488
442
  </div>
489
443
  <div class="col m-span-12 px">
@@ -513,15 +467,7 @@
513
467
  <div class="row -mx">
514
468
  <div class="col m-span-12 px">
515
469
  <k-card label="HTML">
516
- <pre><code class="hljs html">&lt;style&gt;
517
- k-aside { --width: 30rem; }
518
- &lt;/style&gt;
519
- &lt;k-aside state="offscreen"&gt;
520
- &lt;p&gt;This menu is 30rem wide.&lt;/p&gt;
521
- &lt;/k-aside&gt;
522
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
523
- Open Wide Menu
524
- &lt;/button&gt;</code></pre>
470
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css"><br> k-<span class="hljs-selector-tag">aside</span> {<br> <span class="hljs-attr">--width</span>: <span class="hljs-number">30rem</span>;<br> }<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This menu is 30rem wide.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Wide Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
525
471
  </k-card>
526
472
  </div>
527
473
  <div class="col m-span-12 px">
@@ -545,19 +491,7 @@
545
491
  <div class="row -mx">
546
492
  <div class="col m-span-12 px">
547
493
  <k-card label="HTML">
548
- <pre><code class="hljs html">&lt;style&gt;
549
- k-aside { --bg: var(--c_primary); }
550
- &lt;/style&gt;
551
- &lt;k-aside state="offscreen"&gt;
552
- &lt;nav class="p tc-light"&gt;
553
- &lt;h3&gt;Branded Menu&lt;/h3&gt;
554
- &lt;a href="#" class="tc-light"&gt;Home&lt;/a&gt;
555
- &lt;a href="#" class="tc-light"&gt;About&lt;/a&gt;
556
- &lt;/nav&gt;
557
- &lt;/k-aside&gt;
558
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
559
- Open Branded Menu
560
- &lt;/button&gt;</code></pre>
494
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css"><br> k-<span class="hljs-selector-tag">aside</span> {<br> <span class="hljs-attr">--bg</span>: <span class="hljs-built_in">var</span>(--c_primary);<br> }<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&#x27;p tc-light&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Branded Menu<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&#x27;tc-light&#x27;</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&#x27;tc-light&#x27;</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Branded Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
561
495
  </k-card>
562
496
  </div>
563
497
  <div class="col m-span-12 px">
@@ -585,21 +519,7 @@
585
519
  <div class="row -mx">
586
520
  <div class="col m-span-12 px">
587
521
  <k-card label="HTML">
588
- <pre><code class="hljs html">&lt;style&gt;
589
- k-aside { --collapsed-width: 5rem; }
590
- &lt;/style&gt;
591
- &lt;k-aside main="push" state="offscreen"&gt;
592
- &lt;nav&gt;
593
- &lt;h3&gt;Sidebar&lt;/h3&gt;
594
- &lt;a href="#"&gt;Dashboard&lt;/a&gt;
595
- &lt;a href="#"&gt;Reports&lt;/a&gt;
596
- &lt;a href="#"&gt;Settings&lt;/a&gt;
597
- &lt;/nav&gt;
598
- &lt;/k-aside&gt;
599
-
600
- &lt;button onclick="aside.expand()"&gt;Expand&lt;/button&gt;
601
- &lt;button onclick="aside.collapse()"&gt;Collapse&lt;/button&gt;
602
- &lt;button onclick="aside.hide()"&gt;Hide&lt;/button&gt;</code></pre>
522
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css"><br> k-<span class="hljs-selector-tag">aside</span> {<br> <span class="hljs-attr">--collapsed-width</span>: <span class="hljs-number">5rem</span>;<br> }<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Sidebar<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Reports<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Settings<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.expand()&#x27;</span>&gt;</span>Expand<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.collapse()&#x27;</span>&gt;</span>Collapse<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.hide()&#x27;</span>&gt;</span>Hide<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
603
523
  </k-card>
604
524
  </div>
605
525
  <div class="col m-span-12 px">
@@ -627,6 +547,36 @@
627
547
  </div>
628
548
  </div>
629
549
 
550
+ <h3 id="persistentState"><a href="#persistentState" class="no-link">Persistent State</a></h3>
551
+ <p>Use <code>persistent-id</code> to remember the aside's state across page loads. The state is saved to <code>localStorage</code> under the key <code>aside-persistent-id-{id}</code> and restored when the element is connected. Works with <code>"expanded"</code>, <code>"collapsed"</code>, and <code>"offscreen"</code> states.</p>
552
+ <div class="row -mx">
553
+ <div class="col m-span-12 px">
554
+ <k-card label="HTML">
555
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span> <span class="hljs-attr">persistent-id</span>=<span class="hljs-string">&#x27;my-nav&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Sidebar Content<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span>Expand<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.collapse()&#x27;</span>&gt;</span>Collapse<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.hide()&#x27;</span>&gt;</span>Hide<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
556
+ </k-card>
557
+ </div>
558
+ <div class="col m-span-12 px">
559
+ <k-card label="Output">
560
+ <k-aside id="aside-persist" main="push" state="offscreen" persistent-id="docs-aside-persist-demo">
561
+ <div class="navbar-spacer"></div>
562
+ <nav>
563
+ <p>Sidebar Content</p>
564
+ </nav>
565
+ </k-aside>
566
+ <button id="btn-persist-expand">Expand</button>
567
+ <button id="btn-persist-collapse">Collapse</button>
568
+ <button id="btn-persist-hide">Hide</button>
569
+ <p class="mt"><small>Toggle the state and reload the page — it will be restored.</small></p>
570
+ <script>
571
+ const aPersist = document.getElementById('aside-persist');
572
+ document.getElementById('btn-persist-expand').addEventListener('click',()=> aPersist.expand());
573
+ document.getElementById('btn-persist-collapse').addEventListener('click',()=> aPersist.collapse());
574
+ document.getElementById('btn-persist-hide').addEventListener('click',()=> aPersist.hide());
575
+ </script>
576
+ </k-card>
577
+ </div>
578
+ </div>
579
+
630
580
  <h2 id="subItems"><a href="#subItems" class="no-link">Items &amp; Labels</a></h2>
631
581
  <p>Use <code>k-aside-item</code>, <code>k-aside-label</code>, and <code>k-aside-spacer</code> inside a push-mode aside for a navigation panel with icons and text. Set <code>--aside_padding: 0;</code> on the aside so the sub-components control their own spacing.</p>
632
582
  <p>Items and labels automatically react to the aside's collapsed/expanded state.</p>
@@ -663,17 +613,7 @@
663
613
  <div class="row -mx">
664
614
  <div class="col m-span-12 px">
665
615
  <k-card label="HTML">
666
- <pre><code class="hljs html">&lt;k-aside id="myAside" state="offscreen"&gt;
667
- &lt;p&gt;Open and close me to see events.&lt;/p&gt;
668
- &lt;/k-aside&gt;
669
- &lt;button onclick="myAside.expand()"&gt;Open Menu&lt;/button&gt;
670
- &lt;div id="log"&gt;&lt;/div&gt;
671
-
672
- &lt;script&gt;
673
- myAside.addEventListener('aside_state_change', e =&gt; {
674
- log.textContent = 'state: ' + e.detail.state;
675
- });
676
- &lt;/script&gt;</code></pre>
616
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&#x27;myAside&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Open and close me to see events.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;myAside.expand()&#x27;</span>&gt;</span>Open Menu<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&#x27;log&#x27;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"><br> myAside.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">&#x27;aside_state_change&#x27;</span>, <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {<br> log.<span class="hljs-property">textContent</span> = <span class="hljs-string">&#x27;state: &#x27;</span> + e.<span class="hljs-property">detail</span>.<span class="hljs-property">state</span>;<br> });<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
677
617
  </k-card>
678
618
  </div>
679
619
  <div class="col m-span-12 px">
@@ -722,6 +662,8 @@
722
662
  <p>Whether clicking the overlay backdrop closes the aside. Defaults to <code>true</code>. Syncs to <code>overlay-close</code> attribute.</p>
723
663
  <h5><code>escClose<i>: boolean</i></code></h5>
724
664
  <p>Whether pressing the ESC key closes the aside. Defaults to <code>true</code>. Syncs to <code>esc-close</code> attribute.</p>
665
+ <h5><code>persistentId<i>: string | null</i></code></h5>
666
+ <p>When set, the aside's <code>state</code> is saved to <code>localStorage</code> under <code>aside-persistent-id-{id}</code> on every change, and restored when the element connects. Defaults to <code>null</code>. Syncs to <code>persistent-id</code> attribute.</p>
725
667
 
726
668
  <h3 id="eventRef"><a href="#eventRef" class="no-link">Events</a></h3>
727
669
  <h5><code>aside_state_change</code></h5>
@@ -795,6 +737,7 @@
795
737
  <div style="height:33vh"></div>
796
738
  <script type="module" src="../src/components/Main.js"></script>
797
739
 
740
+ <script type="module" src="../src/components/Accordion.js"></script>
798
741
  <script type="module" src="../src/components/Aside.js"></script>
799
742
  <script type="module" src="../src/components/Card.js"></script>
800
743
 
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css,nothing}from"../lit-all.min.js";import{boolTrueFalse}from"../utils/propConverters.js";import"./FocusCapture.js";import"./Icon.js";export default class Aside extends ShadowComponent{static properties={state:{type:String,reflect:!0},side:{type:String,reflect:!0},main:{type:String,reflect:!0},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolTrueFalse},escClose:{type:Boolean,reflect:!0,attribute:"esc-close",converter:boolTrueFalse}};constructor(){super(),this.state="offscreen",this.side="left",this.main="overlay",this.overlayClose=!0,this.escClose=!0}overlayClick=()=>{this.overlayClose&&this.hide()};handleKeyDown=e=>{this.escClose&&"Escape"===e.key&&this.hide()};updated(e){if(super.updated(e),e.has("state")){const t=e.get("state");"offscreen"===this.state||"offscreen"!==t&&void 0!==t?"offscreen"===this.state&&void 0!==t&&"offscreen"!==t&&document.removeEventListener("keydown",this.handleKeyDown):document.addEventListener("keydown",this.handleKeyDown),"overlay"===this.main&&("expanded"===this.state?document.body.classList.add("no-scroll"):document.body.classList.remove("no-scroll"));const s="offscreen"===this.state?0:this.getTargetWidth(this.state),a={aside:this,state:this.state,main:this.main,width:s};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),this.inert="offscreen"===this.state}}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown),document.body.classList.remove("no-scroll");const e={aside:this,state:"offscreen",main:this.main,width:0};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:e})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:e}))}expand=()=>this.state="expanded";collapse=()=>this.state="collapsed";hide=()=>this.state="offscreen";toggle=()=>{this.state="expanded"===this.state?"offscreen":"expanded"};getTargetWidth(e){const t=parseFloat(getComputedStyle(document.documentElement).fontSize),s="collapsed"===e?"--collapsed-width":"--width",a=getComputedStyle(this).getPropertyValue(s).trim();return(a?parseFloat(a):"collapsed"===e?3.5:20)*t}render(){const e=html`<aside><slot></slot></aside>`;return"overlay"===this.main?html`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css,nothing}from"../lit-all.min.js";import{boolTrueFalse}from"../utils/propConverters.js";import"./FocusCapture.js";import"./Icon.js";export default class Aside extends ShadowComponent{static properties={state:{type:String,reflect:!0},side:{type:String,reflect:!0},main:{type:String,reflect:!0},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolTrueFalse},escClose:{type:Boolean,reflect:!0,attribute:"esc-close",converter:boolTrueFalse},persistentId:{type:String,reflect:!0,attribute:"persistent-id"}};constructor(){super(),this.state="offscreen",this.side="left",this.main="overlay",this.overlayClose=!0,this.escClose=!0,this.persistentId=null}overlayClick=()=>{this.overlayClose&&this.hide()};handleKeyDown=e=>{this.escClose&&"Escape"===e.key&&this.hide()};updated(e){if(super.updated(e),e.has("persistentId")&&this.persistentId&&window?.localStorage){const e=window.localStorage.getItem(`aside-persistent-id-${this.persistentId}`);e&&(this.state=e)}if(e.has("state")){const t=e.get("state");"offscreen"===this.state||"offscreen"!==t&&void 0!==t?"offscreen"===this.state&&void 0!==t&&"offscreen"!==t&&document.removeEventListener("keydown",this.handleKeyDown):document.addEventListener("keydown",this.handleKeyDown),"overlay"===this.main&&("expanded"===this.state?document.body.classList.add("no-scroll"):document.body.classList.remove("no-scroll"));const s="offscreen"===this.state?0:this.getTargetWidth(this.state),a={aside:this,state:this.state,main:this.main,width:s};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:a})),this.inert="offscreen"===this.state,this.persistentId&&window?.localStorage&&window.localStorage.setItem(`aside-persistent-id-${this.persistentId}`,this.state)}}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown),document.body.classList.remove("no-scroll");const e={aside:this,state:"offscreen",main:this.main,width:0};this.dispatchEvent(new CustomEvent("aside_state_change",{detail:e})),window.dispatchEvent(new CustomEvent("aside_state_change",{detail:e}))}expand=()=>this.state="expanded";collapse=()=>this.state="collapsed";hide=()=>this.state="offscreen";toggle=()=>{this.state="expanded"===this.state?"offscreen":"expanded"};getTargetWidth(e){const t=parseFloat(getComputedStyle(document.documentElement).fontSize),s="collapsed"===e?"--collapsed-width":"--width",a=getComputedStyle(this).getPropertyValue(s).trim();return(a?parseFloat(a):"collapsed"===e?3.5:20)*t}render(){const e=html`<aside><slot></slot></aside>`;return"overlay"===this.main?html`
2
2
  <k-focus-capture>
3
3
  <div id="container">
4
4
  <button id="overlay-btn" @click=${this.overlayClick}>
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";export default class Main extends ShadowComponent{constructor(){super(),this.widthMap=new Map}connectedCallback(){super.connectedCallback(),window.addEventListener("aside_state_change",this.handleAsideChange),document.querySelectorAll('k-aside[main="push"]').forEach(t=>{if("offscreen"!==t.state){const e=t.getTargetWidth(t.state);e>0&&this.widthMap.set(t,{side:t.side||"left",width:e})}}),this.recalculate()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("aside_state_change",this.handleAsideChange)}handleAsideChange=t=>{const{aside:e,state:a,main:i,width:s}=t.detail;"overlay"===i||"offscreen"===a?this.widthMap.delete(e):this.widthMap.set(e,{side:e.side||"left",width:s}),this.recalculate()};recalculate=()=>{let t=0,e=0;for(const[,{side:a,width:i}]of this.widthMap)"right"===a?e=Math.max(e,i):t=Math.max(t,i);this.style.setProperty("--left-panel-width",`${t}px`),this.style.setProperty("--right-panel-width",`${e}px`)};render(){return html`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";export default class Main extends ShadowComponent{constructor(){super(),this.widthMap=new Map}connectedCallback(){super.connectedCallback(),window.addEventListener("aside_state_change",this.handleAsideChange),document.querySelectorAll('k-aside[main="push"]').forEach(t=>{if("offscreen"!==t.state&&"function"==typeof t.getTargetWidth){const e=t.getTargetWidth(t.state);e>0&&this.widthMap.set(t,{side:t.side||"left",width:e})}}),this.recalculate()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("aside_state_change",this.handleAsideChange)}handleAsideChange=t=>{const{aside:e,state:a,main:i,width:n}=t.detail;"overlay"===i||"offscreen"===a?this.widthMap.delete(e):this.widthMap.set(e,{side:e.side||"left",width:n}),this.recalculate()};recalculate=()=>{let t=0,e=0;for(const[,{side:a,width:i}]of this.widthMap)"right"===a?e=Math.max(e,i):t=Math.max(t,i);this.style.setProperty("--left-panel-width",`${t}px`),this.style.setProperty("--right-panel-width",`${e}px`)};render(){return html`
2
2
  <main>
3
3
  <slot></slot>
4
4
  </main>
@@ -247,18 +247,18 @@
247
247
 
248
248
  <h1>formatTimestamp</h1>
249
249
 
250
- <details
251
- class="b r mb"
252
- >
253
- <summary class="p">Table of Contents</summary>
254
- <div class="m mt0 pl">
250
+ <k-accordion persistent-id="toc" class="b r mb">
251
+ <k-accordion-header for-panel="toc-panel">Table of Contents</k-accordion-header>
252
+ <k-accordion-panel name="toc-panel">
253
+ <div class="m">
255
254
  <h6>Usage</h6>
256
255
  <a href="#basicUsage">Basic Usage</a><br />
257
256
  <a href="#parameters">Parameters</a><br />
258
257
  <a href="#formatTokens">Format Tokens</a><br />
259
258
  <a href="#examples">Examples</a><br />
260
259
  </div>
261
- </details>
260
+ </k-accordion-panel>
261
+ </k-accordion>
262
262
 
263
263
  <h3>Description</h3>
264
264
  <p>The <code>formatTimestamp</code> utility function formats timestamps using custom format tokens or locale-specific formatting.</p>
@@ -247,18 +247,18 @@
247
247
 
248
248
  <h1>toTitleCase</h1>
249
249
 
250
- <details
251
- class="b r mb"
252
- >
253
- <summary class="p">Table of Contents</summary>
254
- <div class="m mt0 pl">
250
+ <k-accordion persistent-id="toc" class="b r mb">
251
+ <k-accordion-header for-panel="toc-panel">Table of Contents</k-accordion-header>
252
+ <k-accordion-panel name="toc-panel">
253
+ <div class="m">
255
254
  <h6>Usage</h6>
256
255
  <a href="#basicUsage">Basic Usage</a><br />
257
256
  <a href="#parameters">Parameters</a><br />
258
257
  <a href="#returnValue">Return Value</a><br />
259
258
  <a href="#examples">Examples</a><br />
260
259
  </div>
261
- </details>
260
+ </k-accordion-panel>
261
+ </k-accordion>
262
262
 
263
263
  <h3>Description</h3>
264
264
  <p>The <code>toTitleCase</code> utility function converts strings to title case format. It handles camelCase, snake_case, kebab-case, and regular text, converting them into properly capitalized title case with spaces between words.</p>
@@ -1,8 +1,9 @@
1
1
  <page pageName="Aside" title="Aside - Components - Kempo Docs - A Web Components Solution">
2
2
  <content>
3
- <details class="b r mb">
4
- <summary class="p">Table of Contents</summary>
5
- <div class="m mt0 pl">
3
+ <k-accordion persistent-id="toc" class="b r mb">
4
+ <k-accordion-header for-panel="toc-panel">Table of Contents</k-accordion-header>
5
+ <k-accordion-panel name="toc-panel">
6
+ <div class="m">
6
7
  <h6>Overlay Mode</h6>
7
8
  <a href="#overlayBasic">Basic Usage</a><br />
8
9
  <a href="#overlayClose">Closing Options</a><br />
@@ -17,6 +18,7 @@
17
18
  <a href="#customWidth">Custom Width</a><br />
18
19
  <a href="#customBg">Custom Background</a><br />
19
20
  <a href="#customCollapsed">Custom Collapsed Width</a><br />
21
+ <a href="#persistentState">Persistent State</a><br />
20
22
 
21
23
  <h6 class="mt">Sub-Components</h6>
22
24
  <a href="#subItems">Items &amp; Labels</a><br />
@@ -39,7 +41,8 @@
39
41
  <a href="#asideSpacer">k-aside-spacer</a><br />
40
42
  <a href="#asideToggle">k-aside-toggle</a><br />
41
43
  </div>
42
- </details>
44
+ </k-accordion-panel>
45
+ </k-accordion>
43
46
 
44
47
  <h2>Overlay Mode</h2>
45
48
  <p>The default mode. Use <code>state="offscreen"</code> as the starting state; call <code>expand()</code> to open. Clicking the backdrop or pressing ESC closes it by default.</p>
@@ -49,12 +52,7 @@
49
52
  <div class="row -mx">
50
53
  <div class="col m-span-12 px">
51
54
  <k-card label="HTML">
52
- <pre><code class="hljs html">&lt;k-aside state="offscreen"&gt;
53
- &lt;p&gt;Overlay Menu Content&lt;/p&gt;
54
- &lt;/k-aside&gt;
55
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
56
- Open Menu
57
- &lt;/button&gt;</code></pre>
55
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Overlay Menu Content<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
58
56
  </k-card>
59
57
  </div>
60
58
  <div class="col m-span-12 px">
@@ -78,16 +76,7 @@
78
76
  <div class="row -mx">
79
77
  <div class="col m-span-12 px">
80
78
  <k-card label="HTML">
81
- <pre><code class="hljs html">&lt;k-aside state="offscreen"
82
- overlay-close="false"&gt;
83
- &lt;p&gt;Overlay Menu&lt;/p&gt;
84
- &lt;button onclick="this.closest('k-aside').hide()"&gt;
85
- Close
86
- &lt;/button&gt;
87
- &lt;/k-aside&gt;
88
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
89
- Open Menu
90
- &lt;/button&gt;</code></pre>
79
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span> <span class="hljs-attr">overlay-close</span>=<span class="hljs-string">&#x27;false&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Overlay Menu<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.closest(&quot;k-aside&quot;).hide()&#x27;</span>&gt;</span> Close <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
91
80
  </k-card>
92
81
  </div>
93
82
  <div class="col m-span-12 px">
@@ -115,13 +104,7 @@
115
104
  <div class="row -mx">
116
105
  <div class="col m-span-12 px">
117
106
  <k-card label="HTML">
118
- <pre><code class="hljs html">&lt;k-aside state="offscreen"
119
- side="right"&gt;
120
- &lt;p&gt;Right Side Menu&lt;/p&gt;
121
- &lt;/k-aside&gt;
122
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
123
- Open Right Menu
124
- &lt;/button&gt;</code></pre>
107
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span> <span class="hljs-attr">side</span>=<span class="hljs-string">&#x27;right&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Right Side Menu<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Right Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
125
108
  </k-card>
126
109
  </div>
127
110
  <div class="col m-span-12 px">
@@ -147,17 +130,7 @@
147
130
  <div class="row -mx">
148
131
  <div class="col m-span-12 px">
149
132
  <k-card label="HTML">
150
- <pre><code class="hljs html">&lt;k-aside main="push" state="offscreen"&gt;
151
- &lt;nav&gt;
152
- &lt;h3&gt;Sidebar&lt;/h3&gt;
153
- &lt;a href="#"&gt;Home&lt;/a&gt;
154
- &lt;a href="#"&gt;About&lt;/a&gt;
155
- &lt;a href="#"&gt;Contact&lt;/a&gt;
156
- &lt;/nav&gt;
157
- &lt;/k-aside&gt;
158
- &lt;button onclick="this.previousElementSibling.toggle()"&gt;
159
- Toggle Sidebar
160
- &lt;/button&gt;</code></pre>
133
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Sidebar<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.toggle()&#x27;</span>&gt;</span> Toggle Sidebar <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
161
134
  </k-card>
162
135
  </div>
163
136
  <div class="col m-span-12 px">
@@ -186,17 +159,7 @@
186
159
  <div class="row -mx">
187
160
  <div class="col m-span-12 px">
188
161
  <k-card label="HTML">
189
- <pre><code class="hljs html">&lt;k-aside main="push" state="offscreen"&gt;
190
- &lt;nav&gt;
191
- &lt;h3&gt;Menu&lt;/h3&gt;
192
- &lt;a href="#"&gt;Dashboard&lt;/a&gt;
193
- &lt;a href="#"&gt;Settings&lt;/a&gt;
194
- &lt;/nav&gt;
195
- &lt;/k-aside&gt;
196
-
197
- &lt;button onclick="aside.expand()"&gt;Expand&lt;/button&gt;
198
- &lt;button onclick="aside.collapse()"&gt;Collapse&lt;/button&gt;
199
- &lt;button onclick="aside.hide()"&gt;Hide&lt;/button&gt;</code></pre>
162
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Menu<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Settings<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.expand()&#x27;</span>&gt;</span>Expand<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.collapse()&#x27;</span>&gt;</span>Collapse<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.hide()&#x27;</span>&gt;</span>Hide<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
200
163
  </k-card>
201
164
  </div>
202
165
  <div class="col m-span-12 px">
@@ -227,16 +190,7 @@
227
190
  <div class="row -mx">
228
191
  <div class="col m-span-12 px">
229
192
  <k-card label="HTML">
230
- <pre><code class="hljs html">&lt;k-aside main="push" side="right" state="offscreen"&gt;
231
- &lt;nav&gt;
232
- &lt;h3&gt;Right Panel&lt;/h3&gt;
233
- &lt;a href="#"&gt;Item 1&lt;/a&gt;
234
- &lt;a href="#"&gt;Item 2&lt;/a&gt;
235
- &lt;/nav&gt;
236
- &lt;/k-aside&gt;
237
- &lt;button onclick="this.previousElementSibling.toggle()"&gt;
238
- Toggle Right Sidebar
239
- &lt;/button&gt;</code></pre>
193
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">side</span>=<span class="hljs-string">&#x27;right&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Right Panel<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Item 1<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Item 2<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.toggle()&#x27;</span>&gt;</span> Toggle Right Sidebar <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
240
194
  </k-card>
241
195
  </div>
242
196
  <div class="col m-span-12 px">
@@ -266,15 +220,7 @@
266
220
  <div class="row -mx">
267
221
  <div class="col m-span-12 px">
268
222
  <k-card label="HTML">
269
- <pre><code class="hljs html">&lt;style&gt;
270
- k-aside { --width: 30rem; }
271
- &lt;/style&gt;
272
- &lt;k-aside state="offscreen"&gt;
273
- &lt;p&gt;This menu is 30rem wide.&lt;/p&gt;
274
- &lt;/k-aside&gt;
275
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
276
- Open Wide Menu
277
- &lt;/button&gt;</code></pre>
223
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css"><br> k-<span class="hljs-selector-tag">aside</span> {<br> <span class="hljs-attr">--width</span>: <span class="hljs-number">30rem</span>;<br> }<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This menu is 30rem wide.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Wide Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
278
224
  </k-card>
279
225
  </div>
280
226
  <div class="col m-span-12 px">
@@ -298,19 +244,7 @@
298
244
  <div class="row -mx">
299
245
  <div class="col m-span-12 px">
300
246
  <k-card label="HTML">
301
- <pre><code class="hljs html">&lt;style&gt;
302
- k-aside { --bg: var(--c_primary); }
303
- &lt;/style&gt;
304
- &lt;k-aside state="offscreen"&gt;
305
- &lt;nav class="p tc-light"&gt;
306
- &lt;h3&gt;Branded Menu&lt;/h3&gt;
307
- &lt;a href="#" class="tc-light"&gt;Home&lt;/a&gt;
308
- &lt;a href="#" class="tc-light"&gt;About&lt;/a&gt;
309
- &lt;/nav&gt;
310
- &lt;/k-aside&gt;
311
- &lt;button onclick="this.previousElementSibling.expand()"&gt;
312
- Open Branded Menu
313
- &lt;/button&gt;</code></pre>
247
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css"><br> k-<span class="hljs-selector-tag">aside</span> {<br> <span class="hljs-attr">--bg</span>: <span class="hljs-built_in">var</span>(--c_primary);<br> }<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&#x27;p tc-light&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Branded Menu<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&#x27;tc-light&#x27;</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&#x27;tc-light&#x27;</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span> Open Branded Menu <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
314
248
  </k-card>
315
249
  </div>
316
250
  <div class="col m-span-12 px">
@@ -338,21 +272,7 @@
338
272
  <div class="row -mx">
339
273
  <div class="col m-span-12 px">
340
274
  <k-card label="HTML">
341
- <pre><code class="hljs html">&lt;style&gt;
342
- k-aside { --collapsed-width: 5rem; }
343
- &lt;/style&gt;
344
- &lt;k-aside main="push" state="offscreen"&gt;
345
- &lt;nav&gt;
346
- &lt;h3&gt;Sidebar&lt;/h3&gt;
347
- &lt;a href="#"&gt;Dashboard&lt;/a&gt;
348
- &lt;a href="#"&gt;Reports&lt;/a&gt;
349
- &lt;a href="#"&gt;Settings&lt;/a&gt;
350
- &lt;/nav&gt;
351
- &lt;/k-aside&gt;
352
-
353
- &lt;button onclick="aside.expand()"&gt;Expand&lt;/button&gt;
354
- &lt;button onclick="aside.collapse()"&gt;Collapse&lt;/button&gt;
355
- &lt;button onclick="aside.hide()"&gt;Hide&lt;/button&gt;</code></pre>
275
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css"><br> k-<span class="hljs-selector-tag">aside</span> {<br> <span class="hljs-attr">--collapsed-width</span>: <span class="hljs-number">5rem</span>;<br> }<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Sidebar<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Reports<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&#x27;#&#x27;</span>&gt;</span>Settings<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.expand()&#x27;</span>&gt;</span>Expand<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.collapse()&#x27;</span>&gt;</span>Collapse<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;aside.hide()&#x27;</span>&gt;</span>Hide<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
356
276
  </k-card>
357
277
  </div>
358
278
  <div class="col m-span-12 px">
@@ -380,6 +300,36 @@
380
300
  </div>
381
301
  </div>
382
302
 
303
+ <h3 id="persistentState"><a href="#persistentState" class="no-link">Persistent State</a></h3>
304
+ <p>Use <code>persistent-id</code> to remember the aside's state across page loads. The state is saved to <code>localStorage</code> under the key <code>aside-persistent-id-{id}</code> and restored when the element is connected. Works with <code>"expanded"</code>, <code>"collapsed"</code>, and <code>"offscreen"</code> states.</p>
305
+ <div class="row -mx">
306
+ <div class="col m-span-12 px">
307
+ <k-card label="HTML">
308
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">main</span>=<span class="hljs-string">&#x27;push&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span> <span class="hljs-attr">persistent-id</span>=<span class="hljs-string">&#x27;my-nav&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Sidebar Content<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br> <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.expand()&#x27;</span>&gt;</span>Expand<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.collapse()&#x27;</span>&gt;</span>Collapse<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;this.previousElementSibling.hide()&#x27;</span>&gt;</span>Hide<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></code></pre>
309
+ </k-card>
310
+ </div>
311
+ <div class="col m-span-12 px">
312
+ <k-card label="Output">
313
+ <k-aside id="aside-persist" main="push" state="offscreen" persistent-id="docs-aside-persist-demo">
314
+ <div class="navbar-spacer"></div>
315
+ <nav>
316
+ <p>Sidebar Content</p>
317
+ </nav>
318
+ </k-aside>
319
+ <button id="btn-persist-expand">Expand</button>
320
+ <button id="btn-persist-collapse">Collapse</button>
321
+ <button id="btn-persist-hide">Hide</button>
322
+ <p class="mt"><small>Toggle the state and reload the page — it will be restored.</small></p>
323
+ <script>
324
+ const aPersist = document.getElementById('aside-persist');
325
+ document.getElementById('btn-persist-expand').addEventListener('click',()=> aPersist.expand());
326
+ document.getElementById('btn-persist-collapse').addEventListener('click',()=> aPersist.collapse());
327
+ document.getElementById('btn-persist-hide').addEventListener('click',()=> aPersist.hide());
328
+ </script>
329
+ </k-card>
330
+ </div>
331
+ </div>
332
+
383
333
  <h2 id="subItems"><a href="#subItems" class="no-link">Items &amp; Labels</a></h2>
384
334
  <p>Use <code>k-aside-item</code>, <code>k-aside-label</code>, and <code>k-aside-spacer</code> inside a push-mode aside for a navigation panel with icons and text. Set <code>--aside_padding: 0;</code> on the aside so the sub-components control their own spacing.</p>
385
335
  <p>Items and labels automatically react to the aside's collapsed/expanded state.</p>
@@ -416,17 +366,7 @@
416
366
  <div class="row -mx">
417
367
  <div class="col m-span-12 px">
418
368
  <k-card label="HTML">
419
- <pre><code class="hljs html">&lt;k-aside id="myAside" state="offscreen"&gt;
420
- &lt;p&gt;Open and close me to see events.&lt;/p&gt;
421
- &lt;/k-aside&gt;
422
- &lt;button onclick="myAside.expand()"&gt;Open Menu&lt;/button&gt;
423
- &lt;div id="log"&gt;&lt;/div&gt;
424
-
425
- &lt;script&gt;
426
- myAside.addEventListener('aside_state_change', e =&gt; {
427
- log.textContent = 'state: ' + e.detail.state;
428
- });
429
- &lt;/script&gt;</code></pre>
369
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-aside</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&#x27;myAside&#x27;</span> <span class="hljs-attr">state</span>=<span class="hljs-string">&#x27;offscreen&#x27;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Open and close me to see events.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-aside</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">&#x27;myAside.expand()&#x27;</span>&gt;</span>Open Menu<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&#x27;log&#x27;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript"><br> myAside.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">&#x27;aside_state_change&#x27;</span>, <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {<br> log.<span class="hljs-property">textContent</span> = <span class="hljs-string">&#x27;state: &#x27;</span> + e.<span class="hljs-property">detail</span>.<span class="hljs-property">state</span>;<br> });<br></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
430
370
  </k-card>
431
371
  </div>
432
372
  <div class="col m-span-12 px">
@@ -475,6 +415,8 @@
475
415
  <p>Whether clicking the overlay backdrop closes the aside. Defaults to <code>true</code>. Syncs to <code>overlay-close</code> attribute.</p>
476
416
  <h5><code>escClose<i>: boolean</i></code></h5>
477
417
  <p>Whether pressing the ESC key closes the aside. Defaults to <code>true</code>. Syncs to <code>esc-close</code> attribute.</p>
418
+ <h5><code>persistentId<i>: string | null</i></code></h5>
419
+ <p>When set, the aside's <code>state</code> is saved to <code>localStorage</code> under <code>aside-persistent-id-{id}</code> on every change, and restored when the element connects. Defaults to <code>null</code>. Syncs to <code>persistent-id</code> attribute.</p>
478
420
 
479
421
  <h3 id="eventRef"><a href="#eventRef" class="no-link">Events</a></h3>
480
422
  <h5><code>aside_state_change</code></h5>
@@ -545,6 +487,7 @@
545
487
  <p>No additional attributes. Automatically syncs with the parent aside's state.</p>
546
488
  </content>
547
489
  <content location="scripts">
490
+ <script type="module" src="{{pathToRoot}}src/components/Accordion.js"></script>
548
491
  <script type="module" src="{{pathToRoot}}src/components/Aside.js"></script>
549
492
  <script type="module" src="{{pathToRoot}}src/components/Card.js"></script>
550
493
  </content>
@@ -3,18 +3,18 @@
3
3
  <content>
4
4
  <h1>formatTimestamp</h1>
5
5
 
6
- <details
7
- class="b r mb"
8
- >
9
- <summary class="p">Table of Contents</summary>
10
- <div class="m mt0 pl">
6
+ <k-accordion persistent-id="toc" class="b r mb">
7
+ <k-accordion-header for-panel="toc-panel">Table of Contents</k-accordion-header>
8
+ <k-accordion-panel name="toc-panel">
9
+ <div class="m">
11
10
  <h6>Usage</h6>
12
11
  <a href="#basicUsage">Basic Usage</a><br />
13
12
  <a href="#parameters">Parameters</a><br />
14
13
  <a href="#formatTokens">Format Tokens</a><br />
15
14
  <a href="#examples">Examples</a><br />
16
15
  </div>
17
- </details>
16
+ </k-accordion-panel>
17
+ </k-accordion>
18
18
 
19
19
  <h3>Description</h3>
20
20
  <p>The <code>formatTimestamp</code> utility function formats timestamps using custom format tokens or locale-specific formatting.</p>
@@ -3,18 +3,18 @@
3
3
  <content>
4
4
  <h1>toTitleCase</h1>
5
5
 
6
- <details
7
- class="b r mb"
8
- >
9
- <summary class="p">Table of Contents</summary>
10
- <div class="m mt0 pl">
6
+ <k-accordion persistent-id="toc" class="b r mb">
7
+ <k-accordion-header for-panel="toc-panel">Table of Contents</k-accordion-header>
8
+ <k-accordion-panel name="toc-panel">
9
+ <div class="m">
11
10
  <h6>Usage</h6>
12
11
  <a href="#basicUsage">Basic Usage</a><br />
13
12
  <a href="#parameters">Parameters</a><br />
14
13
  <a href="#returnValue">Return Value</a><br />
15
14
  <a href="#examples">Examples</a><br />
16
15
  </div>
17
- </details>
16
+ </k-accordion-panel>
17
+ </k-accordion>
18
18
 
19
19
  <h3>Description</h3>
20
20
  <p>The <code>toTitleCase</code> utility function converts strings to title case format. It handles camelCase, snake_case, kebab-case, and regular text, converting them into properly capitalized title case with spaces between words.</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo-ui",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "type": "module",
5
5
  "description": "A Lit based web-component library",
6
6
  "main": "index.js",
@@ -12,8 +12,8 @@
12
12
  },
13
13
  "scripts": {
14
14
  "build": "node scripts/build.js",
15
- "prod": "npx kempo-server --root docs --config docs/prod.config.json",
16
- "dev": "npx kempo-server --root docs-src",
15
+ "docs": "npx kempo-server --root docs --config docs/prod.config.json",
16
+ "dev": "npx kempo-server --root docs-src --port 8083",
17
17
  "icon": "node bin/icon.js",
18
18
  "geticon": "node bin/get_icon.js",
19
19
  "listicons": "node bin/list_icons.js",
@@ -10,7 +10,8 @@ export default class Aside extends ShadowComponent {
10
10
  side: { type: String, reflect: true },
11
11
  main: { type: String, reflect: true },
12
12
  overlayClose: { type: Boolean, reflect: true, attribute: 'overlay-close', converter: boolTrueFalse },
13
- escClose: { type: Boolean, reflect: true, attribute: 'esc-close', converter: boolTrueFalse }
13
+ escClose: { type: Boolean, reflect: true, attribute: 'esc-close', converter: boolTrueFalse },
14
+ persistentId: { type: String, reflect: true, attribute: 'persistent-id' }
14
15
  };
15
16
 
16
17
  constructor() {
@@ -20,6 +21,7 @@ export default class Aside extends ShadowComponent {
20
21
  this.main = 'overlay';
21
22
  this.overlayClose = true;
22
23
  this.escClose = true;
24
+ this.persistentId = null;
23
25
  }
24
26
 
25
27
  /*
@@ -39,6 +41,11 @@ export default class Aside extends ShadowComponent {
39
41
  updated(changedProperties) {
40
42
  super.updated(changedProperties);
41
43
 
44
+ if(changedProperties.has('persistentId') && this.persistentId && window?.localStorage) {
45
+ const saved = window.localStorage.getItem(`aside-persistent-id-${this.persistentId}`);
46
+ if(saved) this.state = saved;
47
+ }
48
+
42
49
  if(changedProperties.has('state')) {
43
50
  const prev = changedProperties.get('state');
44
51
 
@@ -61,6 +68,10 @@ export default class Aside extends ShadowComponent {
61
68
  this.dispatchEvent(new CustomEvent('aside_state_change', { detail }));
62
69
  window.dispatchEvent(new CustomEvent('aside_state_change', { detail }));
63
70
  this.inert = this.state === 'offscreen';
71
+
72
+ if(this.persistentId && window?.localStorage) {
73
+ window.localStorage.setItem(`aside-persistent-id-${this.persistentId}`, this.state);
74
+ }
64
75
  }
65
76
  }
66
77
 
@@ -15,7 +15,7 @@ export default class Main extends ShadowComponent {
15
15
  window.addEventListener('aside_state_change', this.handleAsideChange);
16
16
 
17
17
  document.querySelectorAll('k-aside[main="push"]').forEach(aside => {
18
- if(aside.state !== 'offscreen') {
18
+ if(aside.state !== 'offscreen' && typeof aside.getTargetWidth === 'function') {
19
19
  const width = aside.getTargetWidth(aside.state);
20
20
  if(width > 0) {
21
21
  this.widthMap.set(aside, { side: aside.side || 'left', width });
@@ -452,6 +452,81 @@ export default {
452
452
  pass('Dispatches offscreen event on disconnect');
453
453
  },
454
454
 
455
+ /*
456
+ Persistent ID
457
+ */
458
+ 'persistentId: should default to null': async ({pass, fail}) => {
459
+ const aside = await createAside();
460
+ if(aside.persistentId !== null) {
461
+ cleanup(aside);
462
+ return fail(`Expected persistentId null, got ${aside.persistentId}`);
463
+ }
464
+ cleanup(aside);
465
+ pass('persistentId defaults to null');
466
+ },
467
+
468
+ 'persistentId: should save state to localStorage on state change': async ({pass, fail}) => {
469
+ const id = `test-aside-save-${Date.now()}`;
470
+ const key = `aside-persistent-id-${id}`;
471
+ localStorage.removeItem(key);
472
+ const aside = await createAside({ main: 'push', state: 'offscreen' });
473
+ aside.persistentId = id;
474
+ await aside.updateComplete;
475
+ aside.expand();
476
+ await aside.updateComplete;
477
+ const saved = localStorage.getItem(key);
478
+ localStorage.removeItem(key);
479
+ cleanup(aside);
480
+ if(saved !== 'expanded') return fail(`Expected "expanded" in localStorage, got "${saved}"`);
481
+ pass('persistentId saves state to localStorage');
482
+ },
483
+
484
+ 'persistentId: should restore state from localStorage on connect': async ({pass, fail}) => {
485
+ const id = `test-aside-restore-${Date.now()}`;
486
+ const key = `aside-persistent-id-${id}`;
487
+ localStorage.setItem(key, 'expanded');
488
+ const aside = document.createElement('k-aside');
489
+ aside.setAttribute('main', 'push');
490
+ aside.setAttribute('state', 'offscreen');
491
+ aside.setAttribute('persistent-id', id);
492
+ document.body.appendChild(aside);
493
+ await aside.updateComplete;
494
+ // Wait for the property change to apply
495
+ await new Promise(r => setTimeout(r, 50));
496
+ const state = aside.state;
497
+ localStorage.removeItem(key);
498
+ cleanup(aside);
499
+ if(state !== 'expanded') return fail(`Expected restored state "expanded", got "${state}"`);
500
+ pass('persistentId restores state from localStorage');
501
+ },
502
+
503
+ 'persistentId: should save collapsed state': async ({pass, fail}) => {
504
+ const id = `test-aside-collapsed-${Date.now()}`;
505
+ const key = `aside-persistent-id-${id}`;
506
+ localStorage.removeItem(key);
507
+ const aside = await createAside({ main: 'push', state: 'offscreen' });
508
+ aside.persistentId = id;
509
+ await aside.updateComplete;
510
+ aside.collapse();
511
+ await aside.updateComplete;
512
+ const saved = localStorage.getItem(key);
513
+ localStorage.removeItem(key);
514
+ cleanup(aside);
515
+ if(saved !== 'collapsed') return fail(`Expected "collapsed" in localStorage, got "${saved}"`);
516
+ pass('persistentId saves collapsed state');
517
+ },
518
+
519
+ 'persistentId: should not save state when not set': async ({pass, fail}) => {
520
+ const aside = await createAside({ main: 'push', state: 'offscreen' });
521
+ const keysBefore = Object.keys(localStorage).filter(k => k.startsWith('aside-persistent-id-'));
522
+ aside.expand();
523
+ await aside.updateComplete;
524
+ const keysAfter = Object.keys(localStorage).filter(k => k.startsWith('aside-persistent-id-'));
525
+ cleanup(aside);
526
+ if(keysAfter.length > keysBefore.length) return fail('Should not save to localStorage when persistentId is null');
527
+ pass('Does not save to localStorage without persistentId');
528
+ },
529
+
455
530
  /*
456
531
  AsideItem
457
532
  */