kempo-ui 0.0.70 → 0.0.72

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.
@@ -18,6 +18,6 @@ assignees: ''
18
18
  ## What is the suggested fix
19
19
 
20
20
  ## Tasks
21
- - [] Apply the change
22
- - [] Add docs and examples
23
- - [] Add unit tests
21
+ - [ ] Apply the change
22
+ - [ ] Add docs and examples
23
+ - [ ] Add unit tests
@@ -33,6 +33,10 @@ jobs:
33
33
 
34
34
  - run: npm ci
35
35
 
36
+ - name: Build project and documentation
37
+ run: |
38
+ npm run build
39
+
36
40
  - name: Set version type
37
41
  id: version
38
42
  run: |
@@ -0,0 +1,23 @@
1
+ name: Run Unit Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with:
14
+ token: ${{ secrets.GITHUB_TOKEN }}
15
+
16
+ - uses: actions/setup-node@v4
17
+ with:
18
+ node-version: '20.x'
19
+
20
+ - run: npm ci
21
+
22
+ - name: Run Unit Tests
23
+ run: npm test
@@ -1,4 +1,4 @@
1
- import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{boolTrueFalse}from"../utils/propConverters.js";const openDropdowns=new Set;export default class Dropdown extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0},openDirection:{type:String,reflect:!0,attribute:"open-direction"},closeOnSelect:{type:Boolean,reflect:!0,attribute:"close-on-select",converter:boolTrueFalse},closeOnClickOutside:{type:Boolean,reflect:!0,attribute:"close-on-click-outside",converter:boolTrueFalse}};anchorId=`dropdown-anchor-${Math.random().toString(36).slice(2,11)}`;constructor(){super(),this.opened=!1,this.openDirection="down left",this.closeOnSelect=!0,this.closeOnClickOutside=!0}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.handleDocumentClick),document.addEventListener("keydown",this.handleKeydown)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.handleDocumentClick),document.removeEventListener("keydown",this.handleKeydown),openDropdowns.delete(this)}updated(t){super.updated(t),t.has("opened")&&(this.opened?openDropdowns.add(this):openDropdowns.delete(this),this.dispatchEvent(new CustomEvent(this.opened?"opened":"closed",{bubbles:!0})))}handleDocumentClick=t=>{const e=t.target.closest("k-dropdown"),o=t.target.closest('[slot="trigger"]');if(e&&e!==this&&o)return void(this.opened&&this.close());if(!this.opened)return;if(e!==this)return void(this.closeOnClickOutside&&this.close());if(o)return;t.target.closest("a, button")&&this.closeOnSelect&&this.close()};handleTriggerClick=t=>{t.stopPropagation(),this.opened||openDropdowns.forEach(t=>{t!==this&&t.close()}),this.toggle()};handleMenuClick=t=>{const e=t.target.closest("a, button");if(e&&!e.hasAttribute("disabled")){const t=e.dataset?.value||e.textContent.trim();this.dispatchEvent(new CustomEvent("select",{detail:{value:t,item:e},bubbles:!0}))}};handleKeydown=t=>{if(this.opened)if("Escape"===t.key)t.preventDefault(),this.close(),this.focusTrigger();else if("ArrowDown"===t.key)t.preventDefault(),this.focusNextItem();else if("ArrowUp"===t.key)t.preventDefault(),this.focusPreviousItem();else if("Enter"===t.key||" "===t.key){const e=this.querySelector("a:focus, button:focus");e&&(t.preventDefault(),e.click())}};open(){return openDropdowns.forEach(t=>{t!==this&&t.close()}),this.opened=!0,requestAnimationFrame(()=>this.focusFirstItem()),this}close(){return this.opened=!1,this}toggle(){return this.opened?this.close():this.open()}focusTrigger(){const t=this.querySelector('[slot="trigger"]');t&&t.focus()}getMenuItems(){return[...this.querySelectorAll("a, button")].filter(t=>!t.hasAttribute("disabled")&&!t.closest('[slot="trigger"]'))}focusFirstItem(){const t=this.getMenuItems();t.length>0&&t[0].focus()}focusNextItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o+1]||t[0];n&&n.focus()}focusPreviousItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o-1]||t[t.length-1];n&&n.focus()}getPositionArea(){const t=this.openDirection.toLowerCase().trim().split(/\s+/),e={down:"bottom",up:"top",left:"left",right:"right",center:"center"};return t.map(t=>e[t]||t).join(" ")}getFallbacks(){this.getPositionArea().split(" ");const t=[];return t.push("flip-block"),t.push("flip-inline"),t.push("flip-block flip-inline"),t.join(", ")}static styles=css`
1
+ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{boolTrueFalse}from"../utils/propConverters.js";const openDropdowns=new Set;export default class Dropdown extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0},openDirection:{type:String,reflect:!0,attribute:"open-direction"},closeOnSelect:{type:Boolean,reflect:!0,attribute:"close-on-select",converter:boolTrueFalse},closeOnClickOutside:{type:Boolean,reflect:!0,attribute:"close-on-click-outside",converter:boolTrueFalse}};constructor(){super(),this.opened=!1,this.openDirection="down left",this.closeOnSelect=!0,this.closeOnClickOutside=!0}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.handleDocumentClick),document.addEventListener("keydown",this.handleKeydown)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.handleDocumentClick),document.removeEventListener("keydown",this.handleKeydown),openDropdowns.delete(this)}updated(t){super.updated(t),t.has("opened")&&(this.opened?openDropdowns.add(this):openDropdowns.delete(this),this.dispatchEvent(new CustomEvent(this.opened?"opened":"closed",{bubbles:!0})))}handleDocumentClick=t=>{const e=t.target.closest("k-dropdown"),o=t.target.closest('[slot="trigger"]');if(e&&e!==this&&o)return void(this.opened&&this.close());if(!this.opened)return;if(e!==this)return void(this.closeOnClickOutside&&this.close());if(o)return;t.target.closest("a, button")&&this.closeOnSelect&&this.close()};handleTriggerClick=t=>{t.stopPropagation(),this.opened||openDropdowns.forEach(t=>{t!==this&&t.close()}),this.toggle()};handleMenuClick=t=>{const e=t.target.closest("a, button");if(e&&!e.hasAttribute("disabled")){const t=e.dataset?.value||e.textContent.trim();this.dispatchEvent(new CustomEvent("select",{detail:{value:t,item:e},bubbles:!0}))}};handleKeydown=t=>{if(this.opened)if("Escape"===t.key)t.preventDefault(),this.close(),this.focusTrigger();else if("ArrowDown"===t.key)t.preventDefault(),this.focusNextItem();else if("ArrowUp"===t.key)t.preventDefault(),this.focusPreviousItem();else if("Enter"===t.key||" "===t.key){const e=this.querySelector("a:focus, button:focus");e&&(t.preventDefault(),e.click())}};open(){return openDropdowns.forEach(t=>{t!==this&&t.close()}),this.opened=!0,requestAnimationFrame(()=>this.focusFirstItem()),this}close(){return this.opened=!1,this}toggle(){return this.opened?this.close():this.open()}focusTrigger(){const t=this.querySelector('[slot="trigger"]');t&&t.focus()}getMenuItems(){return[...this.querySelectorAll("a, button")].filter(t=>!t.hasAttribute("disabled")&&!t.closest('[slot="trigger"]'))}focusFirstItem(){const t=this.getMenuItems();t.length>0&&t[0].focus()}focusNextItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o+1]||t[0];n&&n.focus()}focusPreviousItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o-1]||t[t.length-1];n&&n.focus()}static styles=css`
2
2
  :host {
3
3
  display: inline-block;
4
4
  position: relative;
@@ -15,8 +15,10 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
15
15
  min-width: anchor-size(width);
16
16
  background: var(--c_bg);
17
17
  border: 1px solid var(--c_border);
18
+ border-radius: var(--radius);
18
19
  box-shadow: var(--drop_shadow);
19
20
  margin: 0.25rem;
21
+ overflow: hidden;
20
22
  }
21
23
  :host([opened]) #menu {
22
24
  display: block;
@@ -6,7 +6,7 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
6
6
  <div class="tree-root">
7
7
  ${e?e.map(([e,t])=>Tree.renderValue(t,e,1,this.depth)):Tree.renderValue(this.data,null,0,this.depth)}
8
8
  </div>
9
- `}static nodes=[];static addNode=(...e)=>{[...e].reverse().forEach(e=>{Object.prototype.hasOwnProperty.call(e,"nodeTag")||(e.nodeTag="k-tree-node-"+nodeTagCounter++,window.customElements.define(e.nodeTag,e)),Tree.nodes.unshift(e)})};static renderValue(e,t=null,s=0,r=0){const n=Tree.nodes.find(t=>t.detect(e))??TreeNode,a=document.createElement(n.nodeTag);return a.value=e,a.key=t,a.depth=s,a.maxDepth=r,a}}window.customElements.define("k-tree",Tree);export class TreeNode extends ShadowComponent{static nodeTag="k-tree-node";static properties={value:{type:Object},key:{attribute:!1},depth:{type:Number},maxDepth:{type:Number},opened:{type:Boolean,converter:boolExists,reflect:!0},icon:{type:String}};constructor(){super(),this.value=null,this.key=null,this.depth=0,this.maxDepth=0,this.opened=!1,this.icon=null}connectedCallback(){super.connectedCallback(),this.depth<=this.maxDepth&&(this.opened=!0)}get tree(){return this.closest("k-tree")}toggle=()=>{this.opened=!this.opened};renderLabel(){return"object"==typeof this.value&&null!==this.value?html`${Array.isArray(this.value)?"Array":"Object"}`:html`${this.value}`}getChildren(){return"object"!=typeof this.value||null===this.value?null:Array.isArray(this.value)?this.value.map((e,t)=>[t,e]):Object.entries(this.value)}renderIcon(){return this.icon?html`<k-icon name="${this.icon}"></k-icon>`:html`<k-icon name="chevron" class="toggle-icon" direction="${this.opened?"down":"right"}"></k-icon>`}render(){const e=this.getChildren(),t=null!==this.key?html`<span class="${"number"==typeof this.key?"tc-muted":""}">${this.key}: </span>`:"";return e?html`
9
+ `}static nodes=[];static addNode=(...e)=>{[...e].reverse().forEach(e=>{Object.prototype.hasOwnProperty.call(e,"nodeTag")||(e.nodeTag="k-tree-node-"+nodeTagCounter++,window.customElements.define(e.nodeTag,e)),Tree.nodes.unshift(e)})};static renderValue(e,t=null,s=0,n=0){const r=Tree.nodes.find(t=>t.detect(e));if(r){const s=new r(e),n=null!==t?html`<span class="${"number"==typeof t?"tc-muted":""}">${t}: </span>`:"";return html`<span class="d-b">${n}${s.renderLabel()}</span>`}const a=document.createElement(TreeNode.nodeTag);return a.value=e,a.key=t,a.depth=s,a.maxDepth=n,a}}window.customElements.define("k-tree",Tree);export class TreeNode extends ShadowComponent{static nodeTag="k-tree-node";static properties={value:{type:Object},key:{attribute:!1},depth:{type:Number},maxDepth:{type:Number},opened:{type:Boolean,converter:boolExists,reflect:!0},icon:{type:String}};constructor(e){super(),this.value=void 0!==e?e:null,this.key=null,this.depth=0,this.maxDepth=0,this.opened=!1,this.icon=null}connectedCallback(){super.connectedCallback(),this.depth<=this.maxDepth&&(this.opened=!0)}get tree(){return this.closest("k-tree")}toggle=()=>{this.opened=!this.opened};renderLabel(){return"object"==typeof this.value&&null!==this.value?html`${Array.isArray(this.value)?"Array":"Object"}`:html`${this.value}`}getChildren(){return"object"!=typeof this.value||null===this.value?null:Array.isArray(this.value)?this.value.map((e,t)=>[t,e]):Object.entries(this.value)}renderIcon(){return this.icon?html`<k-icon name="${this.icon}"></k-icon>`:html`<k-icon name="chevron" class="toggle-icon" direction="${this.opened?"down":"right"}"></k-icon>`}render(){const e=this.getChildren(),t=null!==this.key?html`<span class="${"number"==typeof this.key?"tc-muted":""}">${this.key}: </span>`:"";return e?html`
10
10
  <div>
11
11
  <button class="branch-label no-btn" @click=${this.toggle} aria-expanded="${this.opened}">
12
12
  ${this.renderIcon()}
@@ -1 +1 @@
1
- export default(e,i,t)=>{const s=new Date(parseInt(e));if(i){const e=(e,i)=>("000"+e).slice(-1*i),t={YYYY:s.getFullYear(),YY:String(s.getFullYear()).slice(-2),MM:e(s.getMonth()+1,2),M:s.getMonth()+1,DD:e(s.getDate(),2),D:s.getDate(),hh:e(s.getHours(),2),h:s.getHours(),mm:e(s.getMinutes(),2),m:s.getMinutes(),ss:e(s.getSeconds(),2),s:s.getSeconds(),iiii:e(s.getMilliseconds(),3),iii:e(s.getMilliseconds(),3),ii:e(s.getMilliseconds(),2),i:s.getMilliseconds()};return i.replace(/YYYY|YY|MM|M|DD|D|hh|h|mm|m|ss|s|iiii|iii|ii|i/g,e=>t[e])}return s.toLocaleString(t||navigator.language)};
1
+ export default(e,i,t)=>{const s=new Date(parseInt(e));if(i){const e=(e,i)=>("000"+e).slice(-1*i),t={YYYY:s.getFullYear(),YY:String(s.getFullYear()).slice(-2),MM:e(s.getMonth()+1,2),M:s.getMonth()+1,DD:e(s.getDate(),2),D:s.getDate(),hh:e(s.getHours(),2),h:s.getHours(),mm:e(s.getMinutes(),2),m:s.getMinutes(),ss:e(s.getSeconds(),2),s:s.getSeconds(),iiii:e(s.getMilliseconds(),3),iii:e(s.getMilliseconds(),3),ii:e(s.getMilliseconds(),2),i:s.getMilliseconds()};return i.replace(/YYYY|YY|MM|M|DD|D|hh|h|mm|m|ss|s|iiii|iii|ii|i/g,e=>t[e])}return s.toLocaleString(t||Intl.DateTimeFormat().resolvedOptions().locale)};
@@ -35,6 +35,7 @@
35
35
  <a href="#attributes">Attributes</a><br />
36
36
  <a href="#methods">Methods</a><br />
37
37
  <a href="#eventsRef">Events</a><br />
38
+ <a href="#cssVars">CSS Custom Properties</a><br />
38
39
  </div>
39
40
  </k-accordion-panel>
40
41
  </k-accordion>
@@ -270,6 +271,10 @@
270
271
  <li><code>Escape</code> - Close the dropdown</li>
271
272
  </ul>
272
273
 
274
+ <h3 id="cssVars"><a href="#cssVars" class="no-link">CSS Custom Properties</a></h3>
275
+ <h5><code>--radius</code></h5>
276
+ <p>Controls the border radius of the dropdown menu. Defaults to the global <code>--radius</code> value.</p>
277
+
273
278
  </main>
274
279
  <div style="height:33vh"></div>
275
280
  <script type="module" src="../src/components/Dropdown.js"></script>
@@ -1,4 +1,4 @@
1
- import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{boolTrueFalse}from"../utils/propConverters.js";const openDropdowns=new Set;export default class Dropdown extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0},openDirection:{type:String,reflect:!0,attribute:"open-direction"},closeOnSelect:{type:Boolean,reflect:!0,attribute:"close-on-select",converter:boolTrueFalse},closeOnClickOutside:{type:Boolean,reflect:!0,attribute:"close-on-click-outside",converter:boolTrueFalse}};anchorId=`dropdown-anchor-${Math.random().toString(36).slice(2,11)}`;constructor(){super(),this.opened=!1,this.openDirection="down left",this.closeOnSelect=!0,this.closeOnClickOutside=!0}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.handleDocumentClick),document.addEventListener("keydown",this.handleKeydown)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.handleDocumentClick),document.removeEventListener("keydown",this.handleKeydown),openDropdowns.delete(this)}updated(t){super.updated(t),t.has("opened")&&(this.opened?openDropdowns.add(this):openDropdowns.delete(this),this.dispatchEvent(new CustomEvent(this.opened?"opened":"closed",{bubbles:!0})))}handleDocumentClick=t=>{const e=t.target.closest("k-dropdown"),o=t.target.closest('[slot="trigger"]');if(e&&e!==this&&o)return void(this.opened&&this.close());if(!this.opened)return;if(e!==this)return void(this.closeOnClickOutside&&this.close());if(o)return;t.target.closest("a, button")&&this.closeOnSelect&&this.close()};handleTriggerClick=t=>{t.stopPropagation(),this.opened||openDropdowns.forEach(t=>{t!==this&&t.close()}),this.toggle()};handleMenuClick=t=>{const e=t.target.closest("a, button");if(e&&!e.hasAttribute("disabled")){const t=e.dataset?.value||e.textContent.trim();this.dispatchEvent(new CustomEvent("select",{detail:{value:t,item:e},bubbles:!0}))}};handleKeydown=t=>{if(this.opened)if("Escape"===t.key)t.preventDefault(),this.close(),this.focusTrigger();else if("ArrowDown"===t.key)t.preventDefault(),this.focusNextItem();else if("ArrowUp"===t.key)t.preventDefault(),this.focusPreviousItem();else if("Enter"===t.key||" "===t.key){const e=this.querySelector("a:focus, button:focus");e&&(t.preventDefault(),e.click())}};open(){return openDropdowns.forEach(t=>{t!==this&&t.close()}),this.opened=!0,requestAnimationFrame(()=>this.focusFirstItem()),this}close(){return this.opened=!1,this}toggle(){return this.opened?this.close():this.open()}focusTrigger(){const t=this.querySelector('[slot="trigger"]');t&&t.focus()}getMenuItems(){return[...this.querySelectorAll("a, button")].filter(t=>!t.hasAttribute("disabled")&&!t.closest('[slot="trigger"]'))}focusFirstItem(){const t=this.getMenuItems();t.length>0&&t[0].focus()}focusNextItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o+1]||t[0];n&&n.focus()}focusPreviousItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o-1]||t[t.length-1];n&&n.focus()}getPositionArea(){const t=this.openDirection.toLowerCase().trim().split(/\s+/),e={down:"bottom",up:"top",left:"left",right:"right",center:"center"};return t.map(t=>e[t]||t).join(" ")}getFallbacks(){this.getPositionArea().split(" ");const t=[];return t.push("flip-block"),t.push("flip-inline"),t.push("flip-block flip-inline"),t.join(", ")}static styles=css`
1
+ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{boolTrueFalse}from"../utils/propConverters.js";const openDropdowns=new Set;export default class Dropdown extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0},openDirection:{type:String,reflect:!0,attribute:"open-direction"},closeOnSelect:{type:Boolean,reflect:!0,attribute:"close-on-select",converter:boolTrueFalse},closeOnClickOutside:{type:Boolean,reflect:!0,attribute:"close-on-click-outside",converter:boolTrueFalse}};constructor(){super(),this.opened=!1,this.openDirection="down left",this.closeOnSelect=!0,this.closeOnClickOutside=!0}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.handleDocumentClick),document.addEventListener("keydown",this.handleKeydown)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.handleDocumentClick),document.removeEventListener("keydown",this.handleKeydown),openDropdowns.delete(this)}updated(t){super.updated(t),t.has("opened")&&(this.opened?openDropdowns.add(this):openDropdowns.delete(this),this.dispatchEvent(new CustomEvent(this.opened?"opened":"closed",{bubbles:!0})))}handleDocumentClick=t=>{const e=t.target.closest("k-dropdown"),o=t.target.closest('[slot="trigger"]');if(e&&e!==this&&o)return void(this.opened&&this.close());if(!this.opened)return;if(e!==this)return void(this.closeOnClickOutside&&this.close());if(o)return;t.target.closest("a, button")&&this.closeOnSelect&&this.close()};handleTriggerClick=t=>{t.stopPropagation(),this.opened||openDropdowns.forEach(t=>{t!==this&&t.close()}),this.toggle()};handleMenuClick=t=>{const e=t.target.closest("a, button");if(e&&!e.hasAttribute("disabled")){const t=e.dataset?.value||e.textContent.trim();this.dispatchEvent(new CustomEvent("select",{detail:{value:t,item:e},bubbles:!0}))}};handleKeydown=t=>{if(this.opened)if("Escape"===t.key)t.preventDefault(),this.close(),this.focusTrigger();else if("ArrowDown"===t.key)t.preventDefault(),this.focusNextItem();else if("ArrowUp"===t.key)t.preventDefault(),this.focusPreviousItem();else if("Enter"===t.key||" "===t.key){const e=this.querySelector("a:focus, button:focus");e&&(t.preventDefault(),e.click())}};open(){return openDropdowns.forEach(t=>{t!==this&&t.close()}),this.opened=!0,requestAnimationFrame(()=>this.focusFirstItem()),this}close(){return this.opened=!1,this}toggle(){return this.opened?this.close():this.open()}focusTrigger(){const t=this.querySelector('[slot="trigger"]');t&&t.focus()}getMenuItems(){return[...this.querySelectorAll("a, button")].filter(t=>!t.hasAttribute("disabled")&&!t.closest('[slot="trigger"]'))}focusFirstItem(){const t=this.getMenuItems();t.length>0&&t[0].focus()}focusNextItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o+1]||t[0];n&&n.focus()}focusPreviousItem(){const t=this.getMenuItems(),e=document.activeElement,o=t.indexOf(e),n=t[o-1]||t[t.length-1];n&&n.focus()}static styles=css`
2
2
  :host {
3
3
  display: inline-block;
4
4
  position: relative;
@@ -15,8 +15,10 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
15
15
  min-width: anchor-size(width);
16
16
  background: var(--c_bg);
17
17
  border: 1px solid var(--c_border);
18
+ border-radius: var(--radius);
18
19
  box-shadow: var(--drop_shadow);
19
20
  margin: 0.25rem;
21
+ overflow: hidden;
20
22
  }
21
23
  :host([opened]) #menu {
22
24
  display: block;
@@ -6,7 +6,7 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
6
6
  <div class="tree-root">
7
7
  ${e?e.map(([e,t])=>Tree.renderValue(t,e,1,this.depth)):Tree.renderValue(this.data,null,0,this.depth)}
8
8
  </div>
9
- `}static nodes=[];static addNode=(...e)=>{[...e].reverse().forEach(e=>{Object.prototype.hasOwnProperty.call(e,"nodeTag")||(e.nodeTag="k-tree-node-"+nodeTagCounter++,window.customElements.define(e.nodeTag,e)),Tree.nodes.unshift(e)})};static renderValue(e,t=null,s=0,r=0){const n=Tree.nodes.find(t=>t.detect(e))??TreeNode,a=document.createElement(n.nodeTag);return a.value=e,a.key=t,a.depth=s,a.maxDepth=r,a}}window.customElements.define("k-tree",Tree);export class TreeNode extends ShadowComponent{static nodeTag="k-tree-node";static properties={value:{type:Object},key:{attribute:!1},depth:{type:Number},maxDepth:{type:Number},opened:{type:Boolean,converter:boolExists,reflect:!0},icon:{type:String}};constructor(){super(),this.value=null,this.key=null,this.depth=0,this.maxDepth=0,this.opened=!1,this.icon=null}connectedCallback(){super.connectedCallback(),this.depth<=this.maxDepth&&(this.opened=!0)}get tree(){return this.closest("k-tree")}toggle=()=>{this.opened=!this.opened};renderLabel(){return"object"==typeof this.value&&null!==this.value?html`${Array.isArray(this.value)?"Array":"Object"}`:html`${this.value}`}getChildren(){return"object"!=typeof this.value||null===this.value?null:Array.isArray(this.value)?this.value.map((e,t)=>[t,e]):Object.entries(this.value)}renderIcon(){return this.icon?html`<k-icon name="${this.icon}"></k-icon>`:html`<k-icon name="chevron" class="toggle-icon" direction="${this.opened?"down":"right"}"></k-icon>`}render(){const e=this.getChildren(),t=null!==this.key?html`<span class="${"number"==typeof this.key?"tc-muted":""}">${this.key}: </span>`:"";return e?html`
9
+ `}static nodes=[];static addNode=(...e)=>{[...e].reverse().forEach(e=>{Object.prototype.hasOwnProperty.call(e,"nodeTag")||(e.nodeTag="k-tree-node-"+nodeTagCounter++,window.customElements.define(e.nodeTag,e)),Tree.nodes.unshift(e)})};static renderValue(e,t=null,s=0,n=0){const r=Tree.nodes.find(t=>t.detect(e));if(r){const s=new r(e),n=null!==t?html`<span class="${"number"==typeof t?"tc-muted":""}">${t}: </span>`:"";return html`<span class="d-b">${n}${s.renderLabel()}</span>`}const a=document.createElement(TreeNode.nodeTag);return a.value=e,a.key=t,a.depth=s,a.maxDepth=n,a}}window.customElements.define("k-tree",Tree);export class TreeNode extends ShadowComponent{static nodeTag="k-tree-node";static properties={value:{type:Object},key:{attribute:!1},depth:{type:Number},maxDepth:{type:Number},opened:{type:Boolean,converter:boolExists,reflect:!0},icon:{type:String}};constructor(e){super(),this.value=void 0!==e?e:null,this.key=null,this.depth=0,this.maxDepth=0,this.opened=!1,this.icon=null}connectedCallback(){super.connectedCallback(),this.depth<=this.maxDepth&&(this.opened=!0)}get tree(){return this.closest("k-tree")}toggle=()=>{this.opened=!this.opened};renderLabel(){return"object"==typeof this.value&&null!==this.value?html`${Array.isArray(this.value)?"Array":"Object"}`:html`${this.value}`}getChildren(){return"object"!=typeof this.value||null===this.value?null:Array.isArray(this.value)?this.value.map((e,t)=>[t,e]):Object.entries(this.value)}renderIcon(){return this.icon?html`<k-icon name="${this.icon}"></k-icon>`:html`<k-icon name="chevron" class="toggle-icon" direction="${this.opened?"down":"right"}"></k-icon>`}render(){const e=this.getChildren(),t=null!==this.key?html`<span class="${"number"==typeof this.key?"tc-muted":""}">${this.key}: </span>`:"";return e?html`
10
10
  <div>
11
11
  <button class="branch-label no-btn" @click=${this.toggle} aria-expanded="${this.opened}">
12
12
  ${this.renderIcon()}
@@ -1 +1 @@
1
- export default(e,i,t)=>{const s=new Date(parseInt(e));if(i){const e=(e,i)=>("000"+e).slice(-1*i),t={YYYY:s.getFullYear(),YY:String(s.getFullYear()).slice(-2),MM:e(s.getMonth()+1,2),M:s.getMonth()+1,DD:e(s.getDate(),2),D:s.getDate(),hh:e(s.getHours(),2),h:s.getHours(),mm:e(s.getMinutes(),2),m:s.getMinutes(),ss:e(s.getSeconds(),2),s:s.getSeconds(),iiii:e(s.getMilliseconds(),3),iii:e(s.getMilliseconds(),3),ii:e(s.getMilliseconds(),2),i:s.getMilliseconds()};return i.replace(/YYYY|YY|MM|M|DD|D|hh|h|mm|m|ss|s|iiii|iii|ii|i/g,e=>t[e])}return s.toLocaleString(t||navigator.language)};
1
+ export default(e,i,t)=>{const s=new Date(parseInt(e));if(i){const e=(e,i)=>("000"+e).slice(-1*i),t={YYYY:s.getFullYear(),YY:String(s.getFullYear()).slice(-2),MM:e(s.getMonth()+1,2),M:s.getMonth()+1,DD:e(s.getDate(),2),D:s.getDate(),hh:e(s.getHours(),2),h:s.getHours(),mm:e(s.getMinutes(),2),m:s.getMinutes(),ss:e(s.getSeconds(),2),s:s.getSeconds(),iiii:e(s.getMilliseconds(),3),iii:e(s.getMilliseconds(),3),ii:e(s.getMilliseconds(),2),i:s.getMilliseconds()};return i.replace(/YYYY|YY|MM|M|DD|D|hh|h|mm|m|ss|s|iiii|iii|ii|i/g,e=>t[e])}return s.toLocaleString(t||Intl.DateTimeFormat().resolvedOptions().locale)};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo-ui",
3
- "version": "0.0.70",
3
+ "version": "0.0.72",
4
4
  "type": "module",
5
5
  "description": "A Lit based web-component library",
6
6
  "main": "index.js",
@@ -13,8 +13,6 @@ export default class Dropdown extends ShadowComponent {
13
13
  closeOnClickOutside: { type: Boolean, reflect: true, attribute: 'close-on-click-outside', converter: boolTrueFalse }
14
14
  };
15
15
 
16
- anchorId = `dropdown-anchor-${Math.random().toString(36).slice(2, 11)}`;
17
-
18
16
  constructor() {
19
17
  super();
20
18
  this.opened = false;
@@ -182,35 +180,6 @@ export default class Dropdown extends ShadowComponent {
182
180
  if(prev) prev.focus();
183
181
  }
184
182
 
185
- getPositionArea() {
186
- const dir = this.openDirection.toLowerCase().trim();
187
- const parts = dir.split(/\s+/);
188
- // Map friendly names to position-area values
189
- const mapping = {
190
- 'down': 'bottom',
191
- 'up': 'top',
192
- 'left': 'left',
193
- 'right': 'right',
194
- 'center': 'center'
195
- };
196
- const mapped = parts.map(p => mapping[p] || p);
197
- // position-area expects: row column (e.g., "bottom left")
198
- // "down left" -> "bottom left", "up right" -> "top right"
199
- return mapped.join(' ');
200
- }
201
-
202
- getFallbacks() {
203
- const primary = this.getPositionArea();
204
- const parts = primary.split(' ');
205
- // Generate sensible fallbacks
206
- const fallbacks = [];
207
- // flip-block flips vertical, flip-inline flips horizontal
208
- fallbacks.push('flip-block');
209
- fallbacks.push('flip-inline');
210
- fallbacks.push('flip-block flip-inline');
211
- return fallbacks.join(', ');
212
- }
213
-
214
183
  /*
215
184
  Styles
216
185
  */
@@ -231,8 +200,10 @@ export default class Dropdown extends ShadowComponent {
231
200
  min-width: anchor-size(width);
232
201
  background: var(--c_bg);
233
202
  border: 1px solid var(--c_border);
203
+ border-radius: var(--radius);
234
204
  box-shadow: var(--drop_shadow);
235
205
  margin: 0.25rem;
206
+ overflow: hidden;
236
207
  }
237
208
  :host([opened]) #menu {
238
209
  display: block;
@@ -59,8 +59,15 @@ export default class Tree extends ShadowComponent {
59
59
 
60
60
  /* Static Methods */
61
61
  static renderValue(value, key = null, depth = 0, maxDepth = 0){
62
- const NodeClass = Tree.nodes.find(n => n.detect(value)) ?? TreeNode;
63
- const el = document.createElement(NodeClass.nodeTag);
62
+ const LeafClass = Tree.nodes.find(n => n.detect(value));
63
+ if(LeafClass){
64
+ const instance = new LeafClass(value);
65
+ const keyLabel = key !== null
66
+ ? html`<span class="${typeof key === 'number' ? 'tc-muted' : ''}">${key}: </span>`
67
+ : '';
68
+ return html`<span class="d-b">${keyLabel}${instance.renderLabel()}</span>`;
69
+ }
70
+ const el = document.createElement(TreeNode.nodeTag);
64
71
  el.value = value;
65
72
  el.key = key;
66
73
  el.depth = depth;
@@ -84,9 +91,9 @@ export class TreeNode extends ShadowComponent {
84
91
  icon: { type: String }
85
92
  };
86
93
 
87
- constructor(){
94
+ constructor(value){
88
95
  super();
89
- this.value = null;
96
+ this.value = value !== undefined ? value : null;
90
97
  this.key = null;
91
98
  this.depth = 0;
92
99
  this.maxDepth = 0;
@@ -22,6 +22,6 @@ export default (timestamp, format, forceLocale) => {
22
22
  };
23
23
  return format.replace(/YYYY|YY|MM|M|DD|D|hh|h|mm|m|ss|s|iiii|iii|ii|i/g, (matched) => tokens[matched]);
24
24
  } else {
25
- return date.toLocaleString(forceLocale || navigator.language);
25
+ return date.toLocaleString(forceLocale || Intl.DateTimeFormat().resolvedOptions().locale);
26
26
  }
27
27
  }
@@ -537,6 +537,28 @@ export default {
537
537
  pass('All open-direction values accepted');
538
538
  },
539
539
 
540
+ /*
541
+ Styles
542
+ */
543
+ 'menu should have border-radius using --radius': async ({pass, fail}) => {
544
+ const { container, dropdown } = await createDropdown();
545
+ const menu = dropdown.shadowRoot.querySelector('#menu');
546
+ if(!menu) {
547
+ cleanup(container);
548
+ return fail('Menu element should exist');
549
+ }
550
+ document.documentElement.style.setProperty('--radius', '8px');
551
+ const styles = window.getComputedStyle(menu);
552
+ const borderRadius = styles.borderRadius;
553
+ document.documentElement.style.removeProperty('--radius');
554
+ if(borderRadius !== '8px') {
555
+ cleanup(container);
556
+ return fail(`Expected menu border-radius to use --radius (8px), got ${borderRadius}`);
557
+ }
558
+ cleanup(container);
559
+ pass('Menu has border-radius applied using --radius');
560
+ },
561
+
540
562
  /*
541
563
  Disabled Items
542
564
  */