kempo-ui 0.3.2 → 0.3.4

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{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},requestEdit:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-edit"},requestDelete:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-delete"},placeholder:{type:String,reflect:!0},filteredPlaceholder:{type:String,reflect:!0,attribute:"filtered-placeholder"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1),void 0===this.requestEdit&&(this.requestEdit=!1),void 0===this.requestDelete&&(this.requestDelete=!1),void 0===this.placeholder&&(this.placeholder="No Records"),void 0===this.filteredPlaceholder&&(this.filteredPlaceholder="")}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
1
+ import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},requestEdit:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-edit"},requestDelete:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-delete"},placeholder:{type:String,reflect:!0},filteredPlaceholder:{type:String,reflect:!0,attribute:"filtered-placeholder"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1),void 0===this.requestEdit&&(this.requestEdit=!1),void 0===this.requestDelete&&(this.requestDelete=!1),void 0===this.placeholder&&(this.placeholder="No Records"),void 0===this.filteredPlaceholder&&(this.filteredPlaceholder="")}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.getDisplayedRecords().length>0&&this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
2
2
  <th class="controls field-select">
3
3
  <input type="checkbox" id="select-all" @change=${this.handleSelectAllChange} />
4
4
  </th>
@@ -1,7 +1,12 @@
1
- import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Tags extends ShadowComponent{static properties={value:{type:String,reflect:!0},allowedTags:{type:String,reflect:!0,attribute:"allowed-tags"},disallowedTags:{type:String,reflect:!0,attribute:"disallowed-tags"}};constructor(){super(),this.value="",this.allowedTags="",this.disallowedTags=""}firstUpdated(){super.firstUpdated(),this.renderTags()}updated(t){if(super.updated(t),t.has("value")){const a=t.get("value"),e=this.validateTags();e!==this.value?this.value=e:(this.dispatchEvent(new CustomEvent("change",{detail:{oldValue:a,newValue:this.value},bubbles:!0})),this.renderTags())}if(t.has("allowedTags")||t.has("disallowedTags")){const a=t.get("allowedTags")||t.get("disallowedTags"),e=this.allowedTags||this.disallowedTags,s=this.validateTags();if(s!==this.value)this.value=s;else{const s=t.has("allowedTags")?"allowedtagschange":"disallowedtagschange";this.dispatchEvent(new CustomEvent(s,{detail:{oldValue:a,newValue:e},bubbles:!0})),this.renderTags()}}}handleInputChange=()=>{const t=this.shadowRoot.getElementById("tagsInput"),a=t.value.trim();a&&(this.addTag(a),t.value="")};handleInputInput=t=>{if(","===t.data||"insertFromPaste"===t.inputType){const t=this.shadowRoot.getElementById("tagsInput"),a=t.value.split(",").filter(t=>!!t.trim());a.length&&(a.forEach(t=>this.addTag(t.trim())),t.value="")}};async renderTags(){await this.updateComplete;const t=this.shadowRoot.getElementById("tags");t.innerHTML="",this.value&&this.value.split(",").forEach(a=>{const e=new Tag(a.trim(),this);t.appendChild(e)})}addTag(t){const a=new Set(this.value.split(",").filter(t=>!!t.trim()));a.add(t.trim()),this.value=[...a].filter(t=>!!t).join(","),this.dispatchEvent(new CustomEvent("addtag",{detail:{tag:t},bubbles:!0}))}removeTag(t){const a=new Set(this.value.split(",").filter(t=>!!t.trim()));a.delete(t),this.value=[...a].join(","),this.dispatchEvent(new CustomEvent("removetag",{detail:{tag:t},bubbles:!0}))}validateTags(){return this.value.split(",").map(t=>t.trim()).map(t=>{const a=new Set(this.allowedTags.split(",").filter(t=>!!t.trim()));if(a.size)return a.has(t)?t:"";const e=new Set(this.disallowedTags.split(",").filter(t=>!!t.trim()));return e.size&&e.has(t)?"":t}).filter(t=>!!t).join(",")}static styles=css`
1
+ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Tags extends ShadowComponent{static properties={value:{type:String,reflect:!0},allowedTags:{type:String,reflect:!0,attribute:"allowed-tags"},disallowedTags:{type:String,reflect:!0,attribute:"disallowed-tags"},disabled:{type:Boolean,reflect:!0}};constructor(){super(),this.value="",this.allowedTags="",this.disallowedTags="",this.disabled=!1}firstUpdated(){super.firstUpdated(),this.renderTags()}updated(t){if(super.updated(t),t.has("value")){const e=t.get("value"),a=this.validateTags();a!==this.value?this.value=a:(this.dispatchEvent(new CustomEvent("change",{detail:{oldValue:e,newValue:this.value},bubbles:!0})),this.renderTags())}if(t.has("allowedTags")||t.has("disallowedTags")){const e=t.get("allowedTags")||t.get("disallowedTags"),a=this.allowedTags||this.disallowedTags,s=this.validateTags();if(s!==this.value)this.value=s;else{const s=t.has("allowedTags")?"allowedtagschange":"disallowedtagschange";this.dispatchEvent(new CustomEvent(s,{detail:{oldValue:e,newValue:a},bubbles:!0})),this.renderTags()}}}handleInputChange=()=>{if(this.disabled)return;const t=this.shadowRoot.getElementById("tagsInput"),e=t.value.trim();e&&(this.addTag(e),t.value="")};handleInputInput=t=>{if(!this.disabled&&(","===t.data||"insertFromPaste"===t.inputType)){const t=this.shadowRoot.getElementById("tagsInput"),e=t.value.split(",").filter(t=>!!t.trim());e.length&&(e.forEach(t=>this.addTag(t.trim())),t.value="")}};async renderTags(){await this.updateComplete;const t=this.shadowRoot.getElementById("tags");t.innerHTML="",this.value&&this.value.split(",").forEach(e=>{const a=new Tag(e.trim(),this);t.appendChild(a)})}addTag(t){const e=new Set(this.value.split(",").filter(t=>!!t.trim()));e.add(t.trim()),this.value=[...e].filter(t=>!!t).join(","),this.dispatchEvent(new CustomEvent("addtag",{detail:{tag:t},bubbles:!0}))}removeTag(t){const e=new Set(this.value.split(",").filter(t=>!!t.trim()));e.delete(t),this.value=[...e].join(","),this.dispatchEvent(new CustomEvent("removetag",{detail:{tag:t},bubbles:!0}))}validateTags(){return this.value.split(",").map(t=>t.trim()).map(t=>{const e=new Set(this.allowedTags.split(",").filter(t=>!!t.trim()));if(e.size)return e.has(t)?t:"";const a=new Set(this.disallowedTags.split(",").filter(t=>!!t.trim()));return a.size&&a.has(t)?"":t}).filter(t=>!!t).join(",")}static styles=css`
2
2
  :host {
3
3
  display: block;
4
-
4
+ }
5
+ :host([disabled]) {
6
+ opacity: 0.5;
7
+ cursor: not-allowed;
8
+ pointer-events: none;
9
+ }
5
10
  #tagsHolder {
6
11
  display: flex;
7
12
  flex-wrap: wrap;
@@ -46,13 +51,14 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
46
51
  <div id="tagsHolder">
47
52
  <span id="tags"></span>
48
53
  <input
49
- id="tagsInput"
54
+ id="tagsInput"
55
+ ?disabled=${this.disabled}
50
56
  @change=${this.handleInputChange}
51
57
  @input=${this.handleInputInput}
52
58
  />
53
59
  </div>
54
60
  </label>
55
- `}}class Tag extends ShadowComponent{constructor(t,a){super(),this.tag=t,this.tagsComponent=a,this.innerHTML=t}handleClick=()=>{this.tagsComponent.removeTag(this.tag)};static styles=css`
61
+ `}}class Tag extends ShadowComponent{constructor(t,e){super(),this.tag=t,this.tagsComponent=e,this.innerHTML=t}handleClick=()=>{this.tagsComponent.disabled||this.tagsComponent.removeTag(this.tag)};static styles=css`
56
62
  :host {
57
63
  display: inline-block;
58
64
  width: min-content;
@@ -1,4 +1,4 @@
1
- import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Toggle extends ShadowComponent{static properties={value:{type:Boolean,reflect:!0}};constructor(){super(),this.value=!1,this.tabIndex=0}updated(e){super.updated(e),e.has("value")&&this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))}connectedCallback(){super.connectedCallback(),this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("click",this.handleClick),this.removeEventListener("keydown",this.handleKeyDown)}handleClick=()=>{this.toggle()};handleKeyDown=e=>{["Space","Enter"].includes(e.code)&&(e.preventDefault(),this.toggle())};on(){return this.value=!0,this.dispatchEvent(new CustomEvent("on",{detail:{value:!0},bubbles:!0})),this}off(){return this.value=!1,this.dispatchEvent(new CustomEvent("off",{detail:{value:!1},bubbles:!0})),this}toggle(){return this.value?this.off():this.on(),this.dispatchEvent(new CustomEvent("toggle",{detail:{value:this.value},bubbles:!0})),this}render(){return html`
1
+ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Toggle extends ShadowComponent{static properties={value:{type:Boolean,reflect:!0},disabled:{type:Boolean,reflect:!0}};constructor(){super(),this.value=!1,this.disabled=!1,this.tabIndex=0}updated(e){super.updated(e),e.has("value")&&this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))}connectedCallback(){super.connectedCallback(),this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("click",this.handleClick),this.removeEventListener("keydown",this.handleKeyDown)}handleClick=()=>{this.disabled||this.toggle()};handleKeyDown=e=>{this.disabled||["Space","Enter"].includes(e.code)&&(e.preventDefault(),this.toggle())};on(){return this.value=!0,this.dispatchEvent(new CustomEvent("on",{detail:{value:!0},bubbles:!0})),this}off(){return this.value=!1,this.dispatchEvent(new CustomEvent("off",{detail:{value:!1},bubbles:!0})),this}toggle(){return this.value?this.off():this.on(),this.dispatchEvent(new CustomEvent("toggle",{detail:{value:this.value},bubbles:!0})),this}render(){return html`
2
2
  <div id="switch">
3
3
  <div id="handle"></div>
4
4
  </div>
@@ -26,6 +26,11 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
26
26
  outline: none;
27
27
  }
28
28
 
29
+ :host([disabled]) {
30
+ opacity: 0.5;
31
+ cursor: not-allowed;
32
+ pointer-events: none;
33
+ }
29
34
  #switch {
30
35
  display: flex;
31
36
  align-items: center;
@@ -24,6 +24,7 @@
24
24
  <a href="#basicUsage">Basic Usage</a><br />
25
25
  <a href="#allowedTags">Allowed Tags</a><br />
26
26
  <a href="#disallowedTags">Disallowed Tags</a><br />
27
+ <a href="#disabled">Disabled</a><br />
27
28
 
28
29
  <h6 class="mt"><a href="#jsRef" class="no-link">JavaScript Reference</a></h6>
29
30
  <a href="#constructor">Constructor</a><br />
@@ -98,6 +99,24 @@
98
99
 
99
100
 
100
101
 
102
+ <h3 id="disabled"><a href="#disabled" class="no-link">Disabled</a></h3>
103
+ <p>Use the <code>disabled</code> attribute to prevent the user from adding or removing tags while still displaying the current value.</p>
104
+ <div class="row -mx mb">
105
+ <div class="col d-span-6 m-span-12 px">
106
+ <k-card label="HTML">
107
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-tags</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;design,ui&quot;</span>&gt;</span><br> <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Tags<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">k-tags</span>&gt;</span></code></pre>
108
+ </k-card>
109
+ </div>
110
+ <div class="col d-span-6 m-span-12 px">
111
+ <k-card label="Results">
112
+ <k-tags disabled value="design,ui">
113
+ <label>Tags</label>
114
+ </k-tags>
115
+ </k-card>
116
+ </div>
117
+ </div>
118
+
119
+
101
120
  <h2 id="jsRef"><a href="#jsRef" class="no-link">JavaScript Reference</a></h2>
102
121
 
103
122
  <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
@@ -120,6 +139,8 @@
120
139
  <h5><code>disallowedTags<i>: string</i></code></h5>
121
140
  <p>A comma-separated list of disallowed tags. If specified, these tags cannot be added. Syncs with the
122
141
  <code>disallowed-tags</code> attribute.</p>
142
+ <h5><code>disabled<i>: boolean</i></code></h5>
143
+ <p>When <code>true</code>, prevents the user from adding or removing tags. The current value is still displayed. The element appears at 50% opacity. Syncs with the <code>disabled</code> attribute.</p>
123
144
 
124
145
  <h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
125
146
  <h5><code>addTag(tag)<i>: void</i></code></h5>
@@ -26,6 +26,7 @@
26
26
  <a href="#responsiveBehavior">Responsive Behavior</a><br />
27
27
  <a href="#customStyles">Custom Styles</a><br />
28
28
  <a href="#javascriptUsage">JavaScript Usage</a><br />
29
+ <a href="#disabled">Disabled</a><br />
29
30
 
30
31
  <h6 class="mt"><a href="jsRef" class="no-link">JavaScript Reference</a></h6>
31
32
  <a href="#constructor">Constructor</a><br />
@@ -137,6 +138,22 @@
137
138
  </div>
138
139
  </div>
139
140
 
141
+ <h3 id="disabled"><a href="#disabled" class="no-link">Disabled</a></h3>
142
+ <p>The <code>disabled</code> attribute prevents the user from changing the toggle's state while still displaying its current value.</p>
143
+ <div class="row -mx">
144
+ <div class="col m-span-12 px">
145
+ <k-card label="HTML">
146
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-toggle</span> <span class="hljs-attr">disabled</span>&gt;</span>Disabled Off<span class="hljs-tag">&lt;/<span class="hljs-name">k-toggle</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">k-toggle</span> <span class="hljs-attr">disabled</span> <span class="hljs-attr">value</span>&gt;</span>Disabled On<span class="hljs-tag">&lt;/<span class="hljs-name">k-toggle</span>&gt;</span></code></pre>
147
+ </k-card>
148
+ </div>
149
+ <div class="col m-span-12 px">
150
+ <k-card label="Output">
151
+ <k-toggle disabled>Disabled Off</k-toggle>
152
+ <k-toggle disabled value>Disabled On</k-toggle>
153
+ </k-card>
154
+ </div>
155
+ </div>
156
+
140
157
  <h2 id="jsRef"><a href="jsRef" class="no-link">JavaScript Reference</a></h2>
141
158
 
142
159
  <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
@@ -155,6 +172,9 @@
155
172
  <p>A boolean that indicates if the switch is on or off, the default value is <code>false</code>. Syncs to <code>value</code> attribute.</p>
156
173
  <p>This can be set directly, but it is not recommended as it only triggers the a <code>change</code> event and not a <code>on</code>, <code>off</code> or <code>toggle</code> event as the methods do, so the methods are preferrable.</p>
157
174
 
175
+ <h5><code>disabled<i>: boolean</i></code></h5>
176
+ <p>When <code>true</code>, the toggle cannot be changed by user interaction. The current state is still displayed. The element will appear at 50% opacity. Syncs to <code>disabled</code> attribute.</p>
177
+
158
178
  <h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
159
179
  <h5><code>on()<i>: this</i></code></h5>
160
180
  <p>Set's the <code>value</code> to <code>true</code>, dispatches a <code><i>change</i></code> and an <code><i>on</i></code> event. The switch visual changes to the <b>on</b> state.</p>
@@ -1,4 +1,4 @@
1
- import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},requestEdit:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-edit"},requestDelete:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-delete"},placeholder:{type:String,reflect:!0},filteredPlaceholder:{type:String,reflect:!0,attribute:"filtered-placeholder"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1),void 0===this.requestEdit&&(this.requestEdit=!1),void 0===this.requestDelete&&(this.requestDelete=!1),void 0===this.placeholder&&(this.placeholder="No Records"),void 0===this.filteredPlaceholder&&(this.filteredPlaceholder="")}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
1
+ import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},requestEdit:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-edit"},requestDelete:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-delete"},placeholder:{type:String,reflect:!0},filteredPlaceholder:{type:String,reflect:!0,attribute:"filtered-placeholder"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1),void 0===this.requestEdit&&(this.requestEdit=!1),void 0===this.requestDelete&&(this.requestDelete=!1),void 0===this.placeholder&&(this.placeholder="No Records"),void 0===this.filteredPlaceholder&&(this.filteredPlaceholder="")}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.getDisplayedRecords().length>0&&this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
2
2
  <th class="controls field-select">
3
3
  <input type="checkbox" id="select-all" @change=${this.handleSelectAllChange} />
4
4
  </th>
@@ -1,7 +1,12 @@
1
- import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Tags extends ShadowComponent{static properties={value:{type:String,reflect:!0},allowedTags:{type:String,reflect:!0,attribute:"allowed-tags"},disallowedTags:{type:String,reflect:!0,attribute:"disallowed-tags"}};constructor(){super(),this.value="",this.allowedTags="",this.disallowedTags=""}firstUpdated(){super.firstUpdated(),this.renderTags()}updated(t){if(super.updated(t),t.has("value")){const a=t.get("value"),e=this.validateTags();e!==this.value?this.value=e:(this.dispatchEvent(new CustomEvent("change",{detail:{oldValue:a,newValue:this.value},bubbles:!0})),this.renderTags())}if(t.has("allowedTags")||t.has("disallowedTags")){const a=t.get("allowedTags")||t.get("disallowedTags"),e=this.allowedTags||this.disallowedTags,s=this.validateTags();if(s!==this.value)this.value=s;else{const s=t.has("allowedTags")?"allowedtagschange":"disallowedtagschange";this.dispatchEvent(new CustomEvent(s,{detail:{oldValue:a,newValue:e},bubbles:!0})),this.renderTags()}}}handleInputChange=()=>{const t=this.shadowRoot.getElementById("tagsInput"),a=t.value.trim();a&&(this.addTag(a),t.value="")};handleInputInput=t=>{if(","===t.data||"insertFromPaste"===t.inputType){const t=this.shadowRoot.getElementById("tagsInput"),a=t.value.split(",").filter(t=>!!t.trim());a.length&&(a.forEach(t=>this.addTag(t.trim())),t.value="")}};async renderTags(){await this.updateComplete;const t=this.shadowRoot.getElementById("tags");t.innerHTML="",this.value&&this.value.split(",").forEach(a=>{const e=new Tag(a.trim(),this);t.appendChild(e)})}addTag(t){const a=new Set(this.value.split(",").filter(t=>!!t.trim()));a.add(t.trim()),this.value=[...a].filter(t=>!!t).join(","),this.dispatchEvent(new CustomEvent("addtag",{detail:{tag:t},bubbles:!0}))}removeTag(t){const a=new Set(this.value.split(",").filter(t=>!!t.trim()));a.delete(t),this.value=[...a].join(","),this.dispatchEvent(new CustomEvent("removetag",{detail:{tag:t},bubbles:!0}))}validateTags(){return this.value.split(",").map(t=>t.trim()).map(t=>{const a=new Set(this.allowedTags.split(",").filter(t=>!!t.trim()));if(a.size)return a.has(t)?t:"";const e=new Set(this.disallowedTags.split(",").filter(t=>!!t.trim()));return e.size&&e.has(t)?"":t}).filter(t=>!!t).join(",")}static styles=css`
1
+ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Tags extends ShadowComponent{static properties={value:{type:String,reflect:!0},allowedTags:{type:String,reflect:!0,attribute:"allowed-tags"},disallowedTags:{type:String,reflect:!0,attribute:"disallowed-tags"},disabled:{type:Boolean,reflect:!0}};constructor(){super(),this.value="",this.allowedTags="",this.disallowedTags="",this.disabled=!1}firstUpdated(){super.firstUpdated(),this.renderTags()}updated(t){if(super.updated(t),t.has("value")){const e=t.get("value"),a=this.validateTags();a!==this.value?this.value=a:(this.dispatchEvent(new CustomEvent("change",{detail:{oldValue:e,newValue:this.value},bubbles:!0})),this.renderTags())}if(t.has("allowedTags")||t.has("disallowedTags")){const e=t.get("allowedTags")||t.get("disallowedTags"),a=this.allowedTags||this.disallowedTags,s=this.validateTags();if(s!==this.value)this.value=s;else{const s=t.has("allowedTags")?"allowedtagschange":"disallowedtagschange";this.dispatchEvent(new CustomEvent(s,{detail:{oldValue:e,newValue:a},bubbles:!0})),this.renderTags()}}}handleInputChange=()=>{if(this.disabled)return;const t=this.shadowRoot.getElementById("tagsInput"),e=t.value.trim();e&&(this.addTag(e),t.value="")};handleInputInput=t=>{if(!this.disabled&&(","===t.data||"insertFromPaste"===t.inputType)){const t=this.shadowRoot.getElementById("tagsInput"),e=t.value.split(",").filter(t=>!!t.trim());e.length&&(e.forEach(t=>this.addTag(t.trim())),t.value="")}};async renderTags(){await this.updateComplete;const t=this.shadowRoot.getElementById("tags");t.innerHTML="",this.value&&this.value.split(",").forEach(e=>{const a=new Tag(e.trim(),this);t.appendChild(a)})}addTag(t){const e=new Set(this.value.split(",").filter(t=>!!t.trim()));e.add(t.trim()),this.value=[...e].filter(t=>!!t).join(","),this.dispatchEvent(new CustomEvent("addtag",{detail:{tag:t},bubbles:!0}))}removeTag(t){const e=new Set(this.value.split(",").filter(t=>!!t.trim()));e.delete(t),this.value=[...e].join(","),this.dispatchEvent(new CustomEvent("removetag",{detail:{tag:t},bubbles:!0}))}validateTags(){return this.value.split(",").map(t=>t.trim()).map(t=>{const e=new Set(this.allowedTags.split(",").filter(t=>!!t.trim()));if(e.size)return e.has(t)?t:"";const a=new Set(this.disallowedTags.split(",").filter(t=>!!t.trim()));return a.size&&a.has(t)?"":t}).filter(t=>!!t).join(",")}static styles=css`
2
2
  :host {
3
3
  display: block;
4
-
4
+ }
5
+ :host([disabled]) {
6
+ opacity: 0.5;
7
+ cursor: not-allowed;
8
+ pointer-events: none;
9
+ }
5
10
  #tagsHolder {
6
11
  display: flex;
7
12
  flex-wrap: wrap;
@@ -46,13 +51,14 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
46
51
  <div id="tagsHolder">
47
52
  <span id="tags"></span>
48
53
  <input
49
- id="tagsInput"
54
+ id="tagsInput"
55
+ ?disabled=${this.disabled}
50
56
  @change=${this.handleInputChange}
51
57
  @input=${this.handleInputInput}
52
58
  />
53
59
  </div>
54
60
  </label>
55
- `}}class Tag extends ShadowComponent{constructor(t,a){super(),this.tag=t,this.tagsComponent=a,this.innerHTML=t}handleClick=()=>{this.tagsComponent.removeTag(this.tag)};static styles=css`
61
+ `}}class Tag extends ShadowComponent{constructor(t,e){super(),this.tag=t,this.tagsComponent=e,this.innerHTML=t}handleClick=()=>{this.tagsComponent.disabled||this.tagsComponent.removeTag(this.tag)};static styles=css`
56
62
  :host {
57
63
  display: inline-block;
58
64
  width: min-content;
@@ -1,4 +1,4 @@
1
- import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Toggle extends ShadowComponent{static properties={value:{type:Boolean,reflect:!0}};constructor(){super(),this.value=!1,this.tabIndex=0}updated(e){super.updated(e),e.has("value")&&this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))}connectedCallback(){super.connectedCallback(),this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("click",this.handleClick),this.removeEventListener("keydown",this.handleKeyDown)}handleClick=()=>{this.toggle()};handleKeyDown=e=>{["Space","Enter"].includes(e.code)&&(e.preventDefault(),this.toggle())};on(){return this.value=!0,this.dispatchEvent(new CustomEvent("on",{detail:{value:!0},bubbles:!0})),this}off(){return this.value=!1,this.dispatchEvent(new CustomEvent("off",{detail:{value:!1},bubbles:!0})),this}toggle(){return this.value?this.off():this.on(),this.dispatchEvent(new CustomEvent("toggle",{detail:{value:this.value},bubbles:!0})),this}render(){return html`
1
+ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";export default class Toggle extends ShadowComponent{static properties={value:{type:Boolean,reflect:!0},disabled:{type:Boolean,reflect:!0}};constructor(){super(),this.value=!1,this.disabled=!1,this.tabIndex=0}updated(e){super.updated(e),e.has("value")&&this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))}connectedCallback(){super.connectedCallback(),this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("click",this.handleClick),this.removeEventListener("keydown",this.handleKeyDown)}handleClick=()=>{this.disabled||this.toggle()};handleKeyDown=e=>{this.disabled||["Space","Enter"].includes(e.code)&&(e.preventDefault(),this.toggle())};on(){return this.value=!0,this.dispatchEvent(new CustomEvent("on",{detail:{value:!0},bubbles:!0})),this}off(){return this.value=!1,this.dispatchEvent(new CustomEvent("off",{detail:{value:!1},bubbles:!0})),this}toggle(){return this.value?this.off():this.on(),this.dispatchEvent(new CustomEvent("toggle",{detail:{value:this.value},bubbles:!0})),this}render(){return html`
2
2
  <div id="switch">
3
3
  <div id="handle"></div>
4
4
  </div>
@@ -26,6 +26,11 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
26
26
  outline: none;
27
27
  }
28
28
 
29
+ :host([disabled]) {
30
+ opacity: 0.5;
31
+ cursor: not-allowed;
32
+ pointer-events: none;
33
+ }
29
34
  #switch {
30
35
  display: flex;
31
36
  align-items: center;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo-ui",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "type": "module",
5
5
  "description": "A Lit based web-component library",
6
6
  "main": "index.js",
@@ -13,7 +13,7 @@
13
13
  "scripts": {
14
14
  "build": "node scripts/build.js",
15
15
  "prod": "node scripts/docs.js",
16
- "dev": "node scripts/docs.js --src --logging silent",
16
+ "dev": "node scripts/docs.js --src --port 9875",
17
17
  "icon": "node bin/icon.js",
18
18
  "geticon": "node bin/get_icon.js",
19
19
  "listicons": "node bin/list_icons.js",
@@ -92,7 +92,7 @@ export default class Table extends ShadowComponent {
92
92
  if(this.enableSelection) {
93
93
  const selectAllCheckbox = this.shadowRoot.getElementById('select-all');
94
94
  if(selectAllCheckbox) {
95
- selectAllCheckbox.checked = this.allOnPageSelected();
95
+ selectAllCheckbox.checked = this.getDisplayedRecords().length > 0 && this.allOnPageSelected();
96
96
  }
97
97
  }
98
98
  }
@@ -8,7 +8,8 @@ export default class Tags extends ShadowComponent {
8
8
  static properties = {
9
9
  value: { type: String, reflect: true },
10
10
  allowedTags: { type: String, reflect: true, attribute: 'allowed-tags' },
11
- disallowedTags: { type: String, reflect: true, attribute: 'disallowed-tags' }
11
+ disallowedTags: { type: String, reflect: true, attribute: 'disallowed-tags' },
12
+ disabled: { type: Boolean, reflect: true }
12
13
  };
13
14
 
14
15
  constructor() {
@@ -16,6 +17,7 @@ export default class Tags extends ShadowComponent {
16
17
  this.value = '';
17
18
  this.allowedTags = '';
18
19
  this.disallowedTags = '';
20
+ this.disabled = false;
19
21
  }
20
22
 
21
23
  /*
@@ -64,6 +66,7 @@ export default class Tags extends ShadowComponent {
64
66
  Event Handlers
65
67
  */
66
68
  handleInputChange = () => {
69
+ if(this.disabled) return;
67
70
  const tagsInput = this.shadowRoot.getElementById('tagsInput');
68
71
  const tag = tagsInput.value.trim();
69
72
  if(tag) {
@@ -73,6 +76,7 @@ export default class Tags extends ShadowComponent {
73
76
  };
74
77
 
75
78
  handleInputInput = (event) => {
79
+ if(this.disabled) return;
76
80
  if(event.data === ',' || event.inputType === 'insertFromPaste') {
77
81
  const tagsInput = this.shadowRoot.getElementById('tagsInput');
78
82
  const tags = tagsInput.value.split(',').filter(tag => !!tag.trim());
@@ -140,7 +144,12 @@ export default class Tags extends ShadowComponent {
140
144
  static styles = css`
141
145
  :host {
142
146
  display: block;
143
-
147
+ }
148
+ :host([disabled]) {
149
+ opacity: 0.5;
150
+ cursor: not-allowed;
151
+ pointer-events: none;
152
+ }
144
153
  #tagsHolder {
145
154
  display: flex;
146
155
  flex-wrap: wrap;
@@ -191,7 +200,8 @@ export default class Tags extends ShadowComponent {
191
200
  <div id="tagsHolder">
192
201
  <span id="tags"></span>
193
202
  <input
194
- id="tagsInput"
203
+ id="tagsInput"
204
+ ?disabled=${this.disabled}
195
205
  @change=${this.handleInputChange}
196
206
  @input=${this.handleInputInput}
197
207
  />
@@ -216,6 +226,7 @@ class Tag extends ShadowComponent {
216
226
  Event Handlers
217
227
  */
218
228
  handleClick = () => {
229
+ if(this.tagsComponent.disabled) return;
219
230
  this.tagsComponent.removeTag(this.tag);
220
231
  };
221
232
 
@@ -3,12 +3,14 @@ import ShadowComponent from './ShadowComponent.js';
3
3
 
4
4
  export default class Toggle extends ShadowComponent {
5
5
  static properties = {
6
- value: { type: Boolean, reflect: true }
6
+ value: { type: Boolean, reflect: true },
7
+ disabled: { type: Boolean, reflect: true }
7
8
  };
8
9
 
9
10
  constructor() {
10
11
  super();
11
12
  this.value = false;
13
+ this.disabled = false;
12
14
  this.tabIndex = 0;
13
15
  }
14
16
 
@@ -42,10 +44,12 @@ export default class Toggle extends ShadowComponent {
42
44
  Event Handlers
43
45
  */
44
46
  handleClick = () => {
47
+ if(this.disabled) return;
45
48
  this.toggle();
46
49
  };
47
50
 
48
51
  handleKeyDown = (event) => {
52
+ if(this.disabled) return;
49
53
  if (['Space', 'Enter'].includes(event.code)) {
50
54
  event.preventDefault();
51
55
  this.toggle();
@@ -120,6 +124,11 @@ export default class Toggle extends ShadowComponent {
120
124
  outline: none;
121
125
  }
122
126
 
127
+ :host([disabled]) {
128
+ opacity: 0.5;
129
+ cursor: not-allowed;
130
+ pointer-events: none;
131
+ }
123
132
  #switch {
124
133
  display: flex;
125
134
  align-items: center;
@@ -600,5 +600,110 @@ export default {
600
600
 
601
601
  cleanup(container);
602
602
  pass('Whitespace-only tags not added');
603
+ },
604
+
605
+ /*
606
+ Disabled
607
+ */
608
+ 'disabled should default to false': async ({pass, fail}) => {
609
+ const { container, tags } = await createTags();
610
+ if(tags.disabled !== false){
611
+ cleanup(container);
612
+ return fail(`Expected disabled to be false, got ${tags.disabled}`);
613
+ }
614
+ cleanup(container);
615
+ pass('disabled defaults to false');
616
+ },
617
+
618
+ 'should reflect disabled attribute': async ({pass, fail}) => {
619
+ const container = document.createElement('div');
620
+ container.innerHTML = '<k-tags disabled></k-tags>';
621
+ document.body.appendChild(container);
622
+ const tags = container.querySelector('k-tags');
623
+ await tags.updateComplete;
624
+ if(!tags.hasAttribute('disabled')){
625
+ cleanup(container);
626
+ return fail('Tags should have disabled attribute');
627
+ }
628
+ if(tags.disabled !== true){
629
+ cleanup(container);
630
+ return fail(`Expected disabled property to be true, got ${tags.disabled}`);
631
+ }
632
+ cleanup(container);
633
+ pass('disabled attribute reflects correctly');
634
+ },
635
+
636
+ 'input change should not add tag when disabled': async ({pass, fail}) => {
637
+ const container = document.createElement('div');
638
+ container.innerHTML = '<k-tags disabled></k-tags>';
639
+ document.body.appendChild(container);
640
+ const tags = container.querySelector('k-tags');
641
+ await tags.updateComplete;
642
+ const input = tags.shadowRoot.getElementById('tagsInput');
643
+ input.value = 'newtag';
644
+ input.dispatchEvent(new Event('change'));
645
+ await tags.updateComplete;
646
+ if(tags.value !== ''){
647
+ cleanup(container);
648
+ return fail(`Expected value to remain empty when disabled, got "${tags.value}"`);
649
+ }
650
+ cleanup(container);
651
+ pass('Input change does not add tag when disabled');
652
+ },
653
+
654
+ 'input event should not add tag when disabled': async ({pass, fail}) => {
655
+ const container = document.createElement('div');
656
+ container.innerHTML = '<k-tags disabled></k-tags>';
657
+ document.body.appendChild(container);
658
+ const tags = container.querySelector('k-tags');
659
+ await tags.updateComplete;
660
+ const input = tags.shadowRoot.getElementById('tagsInput');
661
+ input.value = 'tag1,tag2,';
662
+ input.dispatchEvent(new InputEvent('input', { data: ',' }));
663
+ await tags.updateComplete;
664
+ if(tags.value !== ''){
665
+ cleanup(container);
666
+ return fail(`Expected value to remain empty when disabled, got "${tags.value}"`);
667
+ }
668
+ cleanup(container);
669
+ pass('Input event does not add tag when disabled');
670
+ },
671
+
672
+ 'clicking tag should not remove it when disabled': async ({pass, fail}) => {
673
+ const container = document.createElement('div');
674
+ container.innerHTML = '<k-tags disabled value="design,ui"></k-tags>';
675
+ document.body.appendChild(container);
676
+ const tags = container.querySelector('k-tags');
677
+ await tags.updateComplete;
678
+ await new Promise(r => setTimeout(r, 50));
679
+ const tagEl = tags.shadowRoot.getElementById('tags').querySelector('k-tag');
680
+ if(!tagEl){
681
+ cleanup(container);
682
+ return fail('Expected a k-tag element to be rendered');
683
+ }
684
+ const span = tagEl.shadowRoot.querySelector('span');
685
+ span.click();
686
+ await tags.updateComplete;
687
+ if(!tags.value.includes('design') || !tags.value.includes('ui')){
688
+ cleanup(container);
689
+ return fail(`Tags should not be removed when disabled, got "${tags.value}"`);
690
+ }
691
+ cleanup(container);
692
+ pass('Clicking tag does not remove it when disabled');
693
+ },
694
+
695
+ 'input should be disabled when disabled attribute is set': async ({pass, fail}) => {
696
+ const container = document.createElement('div');
697
+ container.innerHTML = '<k-tags disabled></k-tags>';
698
+ document.body.appendChild(container);
699
+ const tags = container.querySelector('k-tags');
700
+ await tags.updateComplete;
701
+ const input = tags.shadowRoot.getElementById('tagsInput');
702
+ if(!input.disabled){
703
+ cleanup(container);
704
+ return fail('Input should be disabled when Tags is disabled');
705
+ }
706
+ cleanup(container);
707
+ pass('Input is disabled when Tags is disabled');
603
708
  }
604
709
  };
@@ -584,5 +584,67 @@ export default {
584
584
  toggle.remove();
585
585
  cleanup(container);
586
586
  pass('Handles disconnection and reconnection');
587
+ },
588
+
589
+ /*
590
+ Disabled
591
+ */
592
+ 'disabled should default to false': async ({pass, fail}) => {
593
+ const { container, toggle } = await createToggle();
594
+ if(toggle.disabled !== false){
595
+ cleanup(container);
596
+ return fail(`Expected disabled to be false, got ${toggle.disabled}`);
597
+ }
598
+ cleanup(container);
599
+ pass('disabled defaults to false');
600
+ },
601
+
602
+ 'should reflect disabled attribute': async ({pass, fail}) => {
603
+ const container = document.createElement('div');
604
+ container.innerHTML = '<k-toggle disabled></k-toggle>';
605
+ document.body.appendChild(container);
606
+ const toggle = container.querySelector('k-toggle');
607
+ await toggle.updateComplete;
608
+ if(!toggle.hasAttribute('disabled')){
609
+ cleanup(container);
610
+ return fail('Toggle should have disabled attribute');
611
+ }
612
+ if(toggle.disabled !== true){
613
+ cleanup(container);
614
+ return fail(`Expected disabled property to be true, got ${toggle.disabled}`);
615
+ }
616
+ cleanup(container);
617
+ pass('disabled attribute reflects correctly');
618
+ },
619
+
620
+ 'click should not change value when disabled': async ({pass, fail}) => {
621
+ const container = document.createElement('div');
622
+ container.innerHTML = '<k-toggle disabled></k-toggle>';
623
+ document.body.appendChild(container);
624
+ const toggle = container.querySelector('k-toggle');
625
+ await toggle.updateComplete;
626
+ toggle.click();
627
+ if(toggle.value !== false){
628
+ cleanup(container);
629
+ return fail(`Expected value to remain false after click when disabled, got ${toggle.value}`);
630
+ }
631
+ cleanup(container);
632
+ pass('Click does not change value when disabled');
633
+ },
634
+
635
+ 'keydown should not change value when disabled': async ({pass, fail}) => {
636
+ const container = document.createElement('div');
637
+ container.innerHTML = '<k-toggle disabled></k-toggle>';
638
+ document.body.appendChild(container);
639
+ const toggle = container.querySelector('k-toggle');
640
+ await toggle.updateComplete;
641
+ const event = new KeyboardEvent('keydown', { code: 'Space', bubbles: true });
642
+ toggle.dispatchEvent(event);
643
+ if(toggle.value !== false){
644
+ cleanup(container);
645
+ return fail(`Expected value to remain false after Space key when disabled, got ${toggle.value}`);
646
+ }
647
+ cleanup(container);
648
+ pass('Keydown does not change value when disabled');
587
649
  }
588
650
  };