@nectary/components 2.1.4 → 2.1.5

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.
@@ -10,9 +10,7 @@ defineCustomElement('sinch-action-menu', class extends NectaryElement {
10
10
  #controller = null;
11
11
  constructor() {
12
12
  super();
13
- const shadowRoot = this.attachShadow({
14
- delegatesFocus: false
15
- });
13
+ const shadowRoot = this.attachShadow();
16
14
  shadowRoot.appendChild(template.content.cloneNode(true));
17
15
  this.#$optionSlot = shadowRoot.querySelector('slot');
18
16
  this.#$listbox = shadowRoot.querySelector('#listbox');
package/button/index.js CHANGED
@@ -11,9 +11,7 @@ defineCustomElement('sinch-button', class extends NectaryElement {
11
11
  #sizeContext;
12
12
  constructor() {
13
13
  super();
14
- const shadowRoot = this.attachShadow({
15
- delegatesFocus: false
16
- });
14
+ const shadowRoot = this.attachShadow();
17
15
  shadowRoot.appendChild(template.content.cloneNode(true));
18
16
  this.#$button = shadowRoot.querySelector('#button');
19
17
  this.#$text = shadowRoot.querySelector('#text');
package/checkbox/index.js CHANGED
@@ -1,33 +1,36 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{display:flex;flex-direction:row;box-sizing:border-box;width:100%;--sinch-local-size:24px;--sinch-local-color-background:var(--sinch-comp-checkbox-color-default-background-initial);--sinch-local-color-background-hover:var(--sinch-comp-checkbox-color-default-background-hover);--sinch-local-color-background-active:var(--sinch-comp-checkbox-color-default-background-active);--sinch-local-color-border:var(--sinch-comp-checkbox-color-default-border-initial);--sinch-local-color-border-hover:var(--sinch-comp-checkbox-color-default-border-hover);--sinch-local-color-border-active:var(--sinch-comp-checkbox-color-default-border-active);--sinch-local-color-text:var(--sinch-comp-checkbox-color-default-text-initial)}:host([invalid])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-invalid-background-initial);--sinch-local-color-background-hover:var(--sinch-comp-checkbox-color-invalid-background-hover);--sinch-local-color-background-active:var(--sinch-comp-checkbox-color-invalid-background-active);--sinch-local-color-border:var(--sinch-comp-checkbox-color-invalid-border-initial);--sinch-local-color-border-hover:var(--sinch-comp-checkbox-color-invalid-border-hover);--sinch-local-color-border-active:var(--sinch-comp-checkbox-color-invalid-border-active);--sinch-local-color-text:var(--sinch-comp-checkbox-color-invalid-text-initial)}:host([checked])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-checked-background-initial);--sinch-local-color-background-hover:var(--sinch-comp-checkbox-color-checked-background-hover);--sinch-local-color-background-active:var(--sinch-comp-checkbox-color-checked-background-active);--sinch-local-color-border:var(--sinch-comp-checkbox-color-checked-border-initial);--sinch-local-color-border-hover:var(--sinch-comp-checkbox-color-checked-border-hover);--sinch-local-color-border-active:var(--sinch-comp-checkbox-color-checked-border-active)}:host([disabled])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-disabled-background-initial);--sinch-local-color-border:var(--sinch-comp-checkbox-color-disabled-border-initial);--sinch-local-color-text:var(--sinch-comp-checkbox-color-disabled-text-initial)}:host([disabled][checked])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-checked-disabled-background-initial);--sinch-local-color-border:var(--sinch-comp-checkbox-color-checked-disabled-border-initial)}#checkbox{all:initial;display:block;width:var(--sinch-local-size);height:var(--sinch-local-size);cursor:pointer}#checkbox:disabled{cursor:initial}#icon-container{position:relative;width:var(--sinch-local-size);height:var(--sinch-local-size);align-self:flex-start}#checkbox::before{content:"";position:absolute;top:0;left:0;width:var(--sinch-local-size);height:var(--sinch-local-size);border:2px solid var(--sinch-comp-checkbox-color-default-outline-focus);border-radius:calc(var(--sinch-comp-checkbox-shape-radius) + 3px);transition:opacity .1s linear;opacity:0;box-sizing:border-box;pointer-events:none}#checkbox:focus-visible::before{opacity:1}#checkbox::after{content:"";position:absolute;width:18px;height:18px;inset:0;margin:auto;background-color:var(--sinch-local-color-background);border:1px solid var(--sinch-local-color-border);border-radius:var(--sinch-comp-checkbox-shape-radius);transition:background-color .1s linear;box-sizing:border-box;pointer-events:none}#checkbox:enabled:hover::after{background-color:var(--sinch-local-color-background-hover);border-color:var(--sinch-local-color-border-hover)}#checkbox:enabled:active::after{background-color:var(--sinch-local-color-background-active);border-color:var(--sinch-local-color-border-active)}#icon-checkmark,#icon-indeterminate{position:absolute;left:4px;top:4px;width:16px;height:16px;transition:opacity .1s linear;opacity:0;pointer-events:none;fill:var(--sinch-sys-color-container-main-default)}@media (prefers-reduced-motion){#checkbox::after,#checkbox::before,#icon-checkmark,#icon-indeterminate{transition:none}}#label{display:none;flex:1;align-self:center;padding-left:7px;font:var(--sinch-comp-checkbox-font-label);color:var(--sinch-local-color-text);cursor:pointer}:host([disabled]) #label{cursor:initial}:host([text]:not([text=""])) #label{display:block}:host(:not([indeterminate])) #checkbox:checked~#icon-checkmark{opacity:1}:host([indeterminate]) #checkbox:checked~#icon-indeterminate{opacity:1}</style><div id="wrapper"><div id="icon-container"><input id="checkbox" type="checkbox"/><svg id="icon-checkmark" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 16.17 5.53 12.7a.996.996 0 1 0-1.41 1.41l4.18 4.18c.39.39 1.02.39 1.41 0L20.29 7.71a.996.996 0 1 0-1.41-1.41L9 16.17Z"/></svg><svg id="icon-indeterminate" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 13H6c-.55 0-1-.45-1-1s.45-1 1-1h12c.55 0 1 .45 1 1s-.45 1-1 1Z"/></svg></div><label for="checkbox" id="label"></label></div>';
2
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{display:flex;flex-direction:row;box-sizing:border-box;width:100%;--sinch-local-size:24px;--sinch-local-color-background:var(--sinch-comp-checkbox-color-default-background-initial);--sinch-local-color-background-hover:var(--sinch-comp-checkbox-color-default-background-hover);--sinch-local-color-background-active:var(--sinch-comp-checkbox-color-default-background-active);--sinch-local-color-border:var(--sinch-comp-checkbox-color-default-border-initial);--sinch-local-color-border-hover:var(--sinch-comp-checkbox-color-default-border-hover);--sinch-local-color-border-active:var(--sinch-comp-checkbox-color-default-border-active);--sinch-local-color-text:var(--sinch-comp-checkbox-color-default-text-initial)}:host([invalid])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-invalid-background-initial);--sinch-local-color-background-hover:var(--sinch-comp-checkbox-color-invalid-background-hover);--sinch-local-color-background-active:var(--sinch-comp-checkbox-color-invalid-background-active);--sinch-local-color-border:var(--sinch-comp-checkbox-color-invalid-border-initial);--sinch-local-color-border-hover:var(--sinch-comp-checkbox-color-invalid-border-hover);--sinch-local-color-border-active:var(--sinch-comp-checkbox-color-invalid-border-active);--sinch-local-color-text:var(--sinch-comp-checkbox-color-invalid-text-initial)}:host([checked])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-checked-background-initial);--sinch-local-color-background-hover:var(--sinch-comp-checkbox-color-checked-background-hover);--sinch-local-color-background-active:var(--sinch-comp-checkbox-color-checked-background-active);--sinch-local-color-border:var(--sinch-comp-checkbox-color-checked-border-initial);--sinch-local-color-border-hover:var(--sinch-comp-checkbox-color-checked-border-hover);--sinch-local-color-border-active:var(--sinch-comp-checkbox-color-checked-border-active)}:host([disabled])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-disabled-background-initial);--sinch-local-color-border:var(--sinch-comp-checkbox-color-disabled-border-initial);--sinch-local-color-text:var(--sinch-comp-checkbox-color-disabled-text-initial)}:host([disabled][checked])>#wrapper{--sinch-local-color-background:var(--sinch-comp-checkbox-color-checked-disabled-background-initial);--sinch-local-color-border:var(--sinch-comp-checkbox-color-checked-disabled-border-initial)}#checkbox{width:var(--sinch-local-size);height:var(--sinch-local-size);cursor:pointer}:host([disabled]) #checkbox{cursor:initial}#icon-container{position:relative;width:var(--sinch-local-size);height:var(--sinch-local-size);align-self:flex-start}#checkbox::before{content:"";position:absolute;top:0;left:0;width:var(--sinch-local-size);height:var(--sinch-local-size);border:2px solid var(--sinch-comp-checkbox-color-default-outline-focus);border-radius:calc(var(--sinch-comp-checkbox-shape-radius) + 3px);transition:opacity .1s linear;opacity:0;box-sizing:border-box;pointer-events:none}:host(:focus-visible) #checkbox::before{opacity:1}#checkbox::after{content:"";position:absolute;width:18px;height:18px;inset:0;margin:auto;background-color:var(--sinch-local-color-background);border:1px solid var(--sinch-local-color-border);border-radius:var(--sinch-comp-checkbox-shape-radius);transition:background-color .1s linear;box-sizing:border-box;pointer-events:none}:host(:hover:not([disabled])) #checkbox::after{background-color:var(--sinch-local-color-background-hover);border-color:var(--sinch-local-color-border-hover)}:host(:active:not([disabled])) #checkbox::after{background-color:var(--sinch-local-color-background-active);border-color:var(--sinch-local-color-border-active)}#icon-checkmark,#icon-indeterminate{position:absolute;left:4px;top:4px;width:16px;height:16px;transition:opacity .1s linear;opacity:0;pointer-events:none;fill:var(--sinch-sys-color-container-main-default)}:host(:not([indeterminate])[checked]) #icon-checkmark{opacity:1}:host([indeterminate][checked]) #icon-indeterminate{opacity:1}@media (prefers-reduced-motion){#checkbox::after,#checkbox::before,#icon-checkmark,#icon-indeterminate{transition:none}}#label{flex:1;align-self:center;padding-left:7px;font:var(--sinch-comp-checkbox-font-label);color:var(--sinch-local-color-text);cursor:pointer}#label:empty{display:none}:host([disabled]) #label{cursor:initial}</style><div id="wrapper"><div id="icon-container"><div id="checkbox"></div><svg id="icon-checkmark" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 16.17 5.53 12.7a.996.996 0 1 0-1.41 1.41l4.18 4.18c.39.39 1.02.39 1.41 0L20.29 7.71a.996.996 0 1 0-1.41-1.41L9 16.17Z"/></svg><svg id="icon-indeterminate" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 13H6c-.55 0-1-.45-1-1s.45-1 1-1h12c.55 0 1 .45 1 1s-.45 1-1 1Z"/></svg></div><span id="label"></span></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-checkbox', class extends NectaryElement {
6
- #$input;
7
6
  #$label;
7
+ #controller = null;
8
8
  constructor() {
9
9
  super();
10
10
  const shadowRoot = this.attachShadow();
11
11
  shadowRoot.appendChild(template.content.cloneNode(true));
12
- this.#$input = shadowRoot.querySelector('input');
13
- this.#$label = shadowRoot.querySelector('label');
12
+ this.#$label = shadowRoot.querySelector('#label');
14
13
  }
15
14
  connectedCallback() {
16
- this.setAttribute('role', 'checkbox');
17
- this.#$input.addEventListener('input', this.#onCheckboxInput);
18
- this.#$input.addEventListener('focus', this.#onCheckboxFocus);
19
- this.#$input.addEventListener('blur', this.#onCheckboxBlur);
20
- this.addEventListener('-change', this.#onChangeReactHandler);
21
- this.addEventListener('-focus', this.#onFocusReactHandler);
22
- this.addEventListener('-blur', this.#onBlurReactHandler);
15
+ this.#controller = new AbortController();
16
+ const {
17
+ signal
18
+ } = this.#controller;
19
+ const options = {
20
+ signal
21
+ };
22
+ this.role = 'checkbox';
23
+ this.tabIndex = 0;
24
+ this.addEventListener('click', this.#onClick, options);
25
+ this.addEventListener('focus', this.#onFocus, options);
26
+ this.addEventListener('blur', this.#onBlur, options);
27
+ this.addEventListener('-change', this.#onChangeReactHandler, options);
28
+ this.addEventListener('-focus', this.#onFocusReactHandler, options);
29
+ this.addEventListener('-blur', this.#onBlurReactHandler, options);
23
30
  }
24
31
  disconnectedCallback() {
25
- this.#$input.removeEventListener('input', this.#onCheckboxInput);
26
- this.#$input.removeEventListener('focus', this.#onCheckboxFocus);
27
- this.#$input.removeEventListener('blur', this.#onCheckboxBlur);
28
- this.removeEventListener('-change', this.#onChangeReactHandler);
29
- this.removeEventListener('-focus', this.#onFocusReactHandler);
30
- this.removeEventListener('-blur', this.#onBlurReactHandler);
32
+ this.#controller.abort();
33
+ this.#controller = null;
31
34
  }
32
35
  static get observedAttributes() {
33
36
  return ['checked', 'disabled', 'text', 'invalid', 'indeterminate'];
@@ -45,7 +48,6 @@ defineCustomElement('sinch-checkbox', class extends NectaryElement {
45
48
  case 'checked':
46
49
  {
47
50
  const isChecked = isAttrTrue(newVal);
48
- this.#$input.checked = isChecked;
49
51
  updateExplicitBooleanAttribute(this, 'aria-checked', isChecked);
50
52
  updateBooleanAttribute(this, 'checked', isChecked);
51
53
  break;
@@ -53,7 +55,7 @@ defineCustomElement('sinch-checkbox', class extends NectaryElement {
53
55
  case 'disabled':
54
56
  {
55
57
  const isDisabled = isAttrTrue(newVal);
56
- this.#$input.disabled = isDisabled;
58
+ updateExplicitBooleanAttribute(this, 'aria-disabled', isDisabled);
57
59
  updateBooleanAttribute(this, 'disabled', isDisabled);
58
60
  break;
59
61
  }
@@ -98,24 +100,18 @@ defineCustomElement('sinch-checkbox', class extends NectaryElement {
98
100
  get focusable() {
99
101
  return true;
100
102
  }
101
- focus() {
102
- this.#$input.focus();
103
- }
104
- blur() {
105
- this.#$input.blur();
106
- }
107
- #onCheckboxInput = e => {
108
- e.stopPropagation();
109
- const isChecked = this.#$input.checked;
110
- this.#$input.checked = this.checked;
103
+ #onClick = () => {
104
+ if (this.disabled) {
105
+ return;
106
+ }
111
107
  this.dispatchEvent(new CustomEvent('-change', {
112
- detail: isChecked
108
+ detail: !this.checked
113
109
  }));
114
110
  };
115
- #onCheckboxFocus = () => {
111
+ #onFocus = () => {
116
112
  this.dispatchEvent(new CustomEvent('-focus'));
117
113
  };
118
- #onCheckboxBlur = () => {
114
+ #onBlur = () => {
119
115
  this.dispatchEvent(new CustomEvent('-blur'));
120
116
  };
121
117
  #onChangeReactHandler = e => {
package/chip/index.js CHANGED
@@ -11,9 +11,7 @@ defineCustomElement('sinch-chip', class extends NectaryElement {
11
11
  #controller = null;
12
12
  constructor() {
13
13
  super();
14
- const shadowRoot = this.attachShadow({
15
- delegatesFocus: false
16
- });
14
+ const shadowRoot = this.attachShadow();
17
15
  shadowRoot.appendChild(template.content.cloneNode(true));
18
16
  this.#$button = shadowRoot.querySelector('#button');
19
17
  this.#$text = shadowRoot.querySelector('#text');
@@ -11,9 +11,7 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
11
11
  #controller = null;
12
12
  constructor() {
13
13
  super();
14
- const shadowRoot = this.attachShadow({
15
- delegatesFocus: false
16
- });
14
+ const shadowRoot = this.attachShadow();
17
15
  shadowRoot.appendChild(template.content.cloneNode(true));
18
16
  this.#$listbox = shadowRoot.querySelector('#listbox');
19
17
  this.#$optionsSlot = shadowRoot.querySelector('#options');
package/field/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, getFirstSlotElement, isAttrTrue, NectaryElement, setClass, updateAttribute, updateBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle}#wrapper{display:flex;flex-direction:column;width:100%}#bottom,#top{display:flex;align-items:baseline}#top{height:24px;margin-bottom:2px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-comp-field-font-label);color:var(--sinch-comp-field-color-default-label-initial)}#optional{flex:1;font:var(--sinch-comp-field-font-optional);color:var(--sinch-comp-field-color-default-optional-initial);text-align:right}#additional{flex:1;text-align:right;font:var(--sinch-comp-field-font-additional);color:var(--sinch-comp-field-color-default-additional-initial);line-height:20px;margin-top:2px}#additional:empty{display:none}#invalid{font:var(--sinch-comp-field-font-invalid);color:var(--sinch-comp-field-color-invalid-text-initial);line-height:20px;margin-top:2px}#invalid:empty{display:none}#tooltip{align-self:center;margin:0 8px;display:flex}#tooltip.empty{display:none}:host([disabled]) #label{color:var(--sinch-comp-field-color-disabled-label-initial)}:host([disabled]) #additional{color:var(--sinch-comp-field-color-disabled-additional-initial)}:host([disabled]) #optional{color:var(--sinch-comp-field-color-disabled-optional-initial)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><div id="tooltip"><slot name="tooltip"></slot></div><span id="optional"></span></div><slot name="input"></slot><div id="bottom"><div id="invalid"></div><div id="additional"></div></div></div>';
2
+ const templateHTML = '<style>:host{display:block}#wrapper{display:flex;flex-direction:column;width:100%}#bottom,#top{display:flex;align-items:baseline}#top{height:24px;margin-bottom:2px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-comp-field-font-label);color:var(--sinch-comp-field-color-default-label-initial)}#optional{flex:1;font:var(--sinch-comp-field-font-optional);color:var(--sinch-comp-field-color-default-optional-initial);text-align:right}#additional{flex:1;text-align:right;font:var(--sinch-comp-field-font-additional);color:var(--sinch-comp-field-color-default-additional-initial);line-height:20px;margin-top:2px}#additional:empty{display:none}#invalid{font:var(--sinch-comp-field-font-invalid);color:var(--sinch-comp-field-color-invalid-text-initial);line-height:20px;margin-top:2px}#invalid:empty{display:none}#tooltip{align-self:center;margin:0 8px;display:flex}#tooltip.empty{display:none}:host([disabled]) #label{color:var(--sinch-comp-field-color-disabled-label-initial)}:host([disabled]) #additional{color:var(--sinch-comp-field-color-disabled-additional-initial)}:host([disabled]) #optional{color:var(--sinch-comp-field-color-disabled-optional-initial)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><div id="tooltip"><slot name="tooltip"></slot></div><span id="optional"></span></div><slot name="input"></slot><div id="bottom"><div id="invalid"></div><div id="additional"></div></div></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-field', class extends NectaryElement {
@@ -12,9 +12,7 @@ defineCustomElement('sinch-icon-button', class extends NectaryElement {
12
12
  #sizeContext;
13
13
  constructor() {
14
14
  super();
15
- const shadowRoot = this.attachShadow({
16
- delegatesFocus: false
17
- });
15
+ const shadowRoot = this.attachShadow();
18
16
  shadowRoot.appendChild(template.content.cloneNode(true));
19
17
  this.#$button = shadowRoot.querySelector('#button');
20
18
  this.#$tooltip = shadowRoot.querySelector('#tooltip');
package/input/index.js CHANGED
@@ -19,7 +19,9 @@ defineCustomElement('sinch-input', class extends NectaryElement {
19
19
  #sizeContext;
20
20
  constructor() {
21
21
  super();
22
- const shadowRoot = this.attachShadow();
22
+ const shadowRoot = this.attachShadow({
23
+ delegatesFocus: true
24
+ });
23
25
  shadowRoot.appendChild(template.content.cloneNode(true));
24
26
  this.#$input = shadowRoot.querySelector('#input');
25
27
  this.#$iconSlot = shadowRoot.querySelector('slot[name="icon"]');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
4
4
  "files": [
5
5
  "**/*/*.css",
6
6
  "**/*/*.json",
@@ -15,9 +15,7 @@ defineCustomElement('sinch-select-button', class extends NectaryElement {
15
15
  #sizeContext;
16
16
  constructor() {
17
17
  super();
18
- const shadowRoot = this.attachShadow({
19
- delegatesFocus: false
20
- });
18
+ const shadowRoot = this.attachShadow();
21
19
  shadowRoot.appendChild(template.content.cloneNode(true));
22
20
  this.#$text = shadowRoot.querySelector('#text');
23
21
  this.#$placeholder = shadowRoot.querySelector('#placeholder');
@@ -18,9 +18,7 @@ defineCustomElement('sinch-select-menu', class extends NectaryElement {
18
18
  #searchDebounce;
19
19
  constructor() {
20
20
  super();
21
- const shadowRoot = this.attachShadow({
22
- delegatesFocus: false
23
- });
21
+ const shadowRoot = this.attachShadow();
24
22
  shadowRoot.appendChild(template.content.cloneNode(true));
25
23
  this.#$optionSlot = shadowRoot.querySelector('slot');
26
24
  this.#$listbox = shadowRoot.querySelector('#listbox');
@@ -1,5 +1,5 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::before{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::after{content:"";position:absolute;left:4px;right:4px;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}::slotted(*){display:block}</style><sinch-tooltip id="tooltip"><button id="button"><slot name="icon"></slot></button></sinch-tooltip>';
2
+ const templateHTML = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}::slotted(*){display:block}</style><sinch-tooltip id="tooltip"><button id="button" tabindex="0"><slot name="icon"></slot></button></sinch-tooltip>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-tabs-icon-option', class extends NectaryElement {
@@ -7,13 +7,15 @@ defineCustomElement('sinch-tabs-icon-option', class extends NectaryElement {
7
7
  #$tooltip;
8
8
  constructor() {
9
9
  super();
10
- const shadowRoot = this.attachShadow();
10
+ const shadowRoot = this.attachShadow({
11
+ delegatesFocus: true
12
+ });
11
13
  shadowRoot.appendChild(template.content.cloneNode(true));
12
14
  this.#$button = shadowRoot.querySelector('#button');
13
15
  this.#$tooltip = shadowRoot.querySelector('#tooltip');
14
16
  }
15
17
  connectedCallback() {
16
- this.setAttribute('role', 'tab');
18
+ this.role = 'tab';
17
19
  this.#$button.addEventListener('click', this.#onClick);
18
20
  }
19
21
  disconnectedCallback() {
@@ -1,6 +1,6 @@
1
1
  import '../text';
2
2
  import { defineCustomElement, getAttribute, getBooleanAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
3
- const templateHTML = '<style>:host{display:block}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::before{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::after{content:"";position:absolute;left:4px;right:4px;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block}</style><button id="button"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></button>';
3
+ const templateHTML = '<style>:host{display:block}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block}</style><button id="button" tabindex="0"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></button>';
4
4
  const template = document.createElement('template');
5
5
  template.innerHTML = templateHTML;
6
6
  defineCustomElement('sinch-tabs-option', class extends NectaryElement {
@@ -8,13 +8,15 @@ defineCustomElement('sinch-tabs-option', class extends NectaryElement {
8
8
  #$text;
9
9
  constructor() {
10
10
  super();
11
- const shadowRoot = this.attachShadow();
11
+ const shadowRoot = this.attachShadow({
12
+ delegatesFocus: true
13
+ });
12
14
  shadowRoot.appendChild(template.content.cloneNode(true));
13
15
  this.#$button = shadowRoot.querySelector('#button');
14
16
  this.#$text = shadowRoot.querySelector('#text');
15
17
  }
16
18
  connectedCallback() {
17
- this.setAttribute('role', 'tab');
19
+ this.role = 'tab';
18
20
  this.#$button.addEventListener('click', this.#onClick);
19
21
  }
20
22
  disconnectedCallback() {
package/textarea/index.js CHANGED
@@ -13,7 +13,9 @@ defineCustomElement('sinch-textarea', class extends NectaryElement {
13
13
  #sizeContext;
14
14
  constructor() {
15
15
  super();
16
- const shadowRoot = this.attachShadow();
16
+ const shadowRoot = this.attachShadow({
17
+ delegatesFocus: true
18
+ });
17
19
  shadowRoot.appendChild(template.content.cloneNode(true));
18
20
  this.#$input = shadowRoot.querySelector('#input');
19
21
  this.#$bottomSlot = shadowRoot.querySelector('slot[name="bottom"]');
package/toggle/index.js CHANGED
@@ -1,33 +1,36 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle}#wrapper{position:relative;display:flex;flex-direction:row;align-items:center;box-sizing:border-box;width:100%;height:var(--sinch-local-size);--sinch-local-size:24px}:host([small]) #wrapper{--sinch-local-size:22px}#input{all:initial;display:block;position:absolute;left:0;top:2px;width:40px;height:20px;cursor:pointer;pointer-events:initial}#input:disabled{cursor:initial}#input:focus-visible::after{position:absolute;content:"";left:-4px;top:-4px;right:-4px;bottom:-4px;border:2px solid var(--sinch-comp-toggle-color-default-outline-focus);border-radius:18px;pointer-events:none}:host([small]) #input{width:32px;height:16px;top:3px}#knob-container{position:relative;box-sizing:border-box;width:40px;height:20px;border-radius:10px;pointer-events:none;padding:2px;background-color:var(--sinch-comp-toggle-color-default-background-initial);overflow:hidden}:host([small]) #knob-container{width:32px;height:16px;border-radius:8px}#input:checked~#knob-container{background-color:var(--sinch-comp-toggle-color-checked-background-initial)}#input:disabled~#knob-container{background-color:var(--sinch-comp-toggle-color-disabled-background-initial)}#input:checked:disabled~#knob-container{background-color:var(--sinch-comp-toggle-color-checked-disabled-background-initial)}#knob{position:relative;box-sizing:border-box;width:16px;height:16px;border-radius:50%;background-color:var(--sinch-comp-toggle-color-default-knob-background-initial);box-shadow:var(--sinch-comp-toggle-shadow-knob-default);transform:translateX(0);transition:transform .1s ease-in-out;will-change:transform}:host([small]) #knob{width:12px;height:12px}#input:disabled+#knob-container>#knob{box-shadow:var(--sinch-comp-toggle-shadow-knob-disabled)}#input:checked+#knob-container>#knob{transform:translateX(20px)}:host([small]) #input:checked+#knob-container>#knob{transform:translateX(16px)}#knob::after,#knob::before{font:var(--sinch-comp-toggle-font-size-m-inside-text);color:var(--sinch-comp-toggle-color-default-text-inside-initial);text-transform:uppercase;font-size:8px;line-height:16px;display:none;position:absolute;top:0;padding:0 3px}#knob::before{content:"on";right:100%}#knob::after{content:"off";left:100%}:host([labeled]:not([small])) #knob::after,:host([labeled]:not([small])) #knob::before{display:block}@media (prefers-reduced-motion){#knob{transition:none}}#label{flex:1;align-self:center;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding-left:8px;font:var(--sinch-comp-toggle-font-size-m-label);color:var(--sinch-comp-toggle-color-default-label-initial)}#label:empty{display:none}:host([small]) #label{font:var(--sinch-comp-toggle-font-size-s-label)}#input:disabled~#label{color:var(--sinch-comp-toggle-color-disabled-label-initial)}</style><div id="wrapper"><input id="input" type="checkbox"><div id="knob-container"><div id="knob"></div></div><label id="label" for="input"></label></div>';
2
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{position:relative;display:flex;flex-direction:row;align-items:center;box-sizing:border-box;width:100%;height:var(--sinch-local-size);--sinch-local-size:24px}:host([small]) #wrapper{--sinch-local-size:22px}#input{all:initial;display:block;position:absolute;left:0;top:2px;width:40px;height:20px;cursor:pointer;pointer-events:initial}:host([disabled]) #input{cursor:initial}:host(:focus-visible) #input::after{position:absolute;content:"";left:-4px;top:-4px;right:-4px;bottom:-4px;border:2px solid var(--sinch-comp-toggle-color-default-outline-focus);border-radius:18px;pointer-events:none}:host([small]) #input{width:32px;height:16px;top:3px}#knob-container{position:relative;box-sizing:border-box;width:40px;height:20px;border-radius:10px;pointer-events:none;padding:2px;background-color:var(--sinch-comp-toggle-color-default-background-initial);overflow:hidden}:host([small]) #knob-container{width:32px;height:16px;border-radius:8px}:host([checked]) #knob-container{background-color:var(--sinch-comp-toggle-color-checked-background-initial)}:host([disabled]) #knob-container{background-color:var(--sinch-comp-toggle-color-disabled-background-initial)}:host([checked][disabled]) #knob-container{background-color:var(--sinch-comp-toggle-color-checked-disabled-background-initial)}#knob{position:relative;box-sizing:border-box;width:16px;height:16px;border-radius:50%;background-color:var(--sinch-comp-toggle-color-default-knob-background-initial);box-shadow:var(--sinch-comp-toggle-shadow-knob-default);transform:translateX(0);transition:transform .1s ease-in-out;will-change:transform}:host([small]) #knob{width:12px;height:12px}:host([disabled]) #knob-container>#knob{box-shadow:var(--sinch-comp-toggle-shadow-knob-disabled)}:host([checked]) #knob-container>#knob{transform:translateX(20px)}:host([small][checked]) #knob-container>#knob{transform:translateX(16px)}#knob::after,#knob::before{font:var(--sinch-comp-toggle-font-size-m-inside-text);color:var(--sinch-comp-toggle-color-default-text-inside-initial);text-transform:uppercase;font-size:8px;line-height:16px;display:none;position:absolute;top:0;padding:0 3px}#knob::before{content:"on";right:100%}#knob::after{content:"off";left:100%}:host([labeled]:not([small])) #knob::after,:host([labeled]:not([small])) #knob::before{display:block}@media (prefers-reduced-motion){#knob{transition:none}}#label{flex:1;align-self:center;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding-left:8px;font:var(--sinch-comp-toggle-font-size-m-label);color:var(--sinch-comp-toggle-color-default-label-initial);cursor:pointer}#label:empty{display:none}:host([small]) #label{font:var(--sinch-comp-toggle-font-size-s-label)}:host([disabled]) #label{color:var(--sinch-comp-toggle-color-disabled-label-initial);cursor:initial}</style><div id="wrapper"><div id="input"></div><div id="knob-container"><div id="knob"></div></div><span id="label"></span></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-toggle', class extends NectaryElement {
6
- #$input;
7
6
  #$label;
7
+ #controller = null;
8
8
  constructor() {
9
9
  super();
10
10
  const shadowRoot = this.attachShadow();
11
11
  shadowRoot.appendChild(template.content.cloneNode(true));
12
- this.#$input = shadowRoot.querySelector('#input');
13
12
  this.#$label = shadowRoot.querySelector('#label');
14
13
  }
15
14
  connectedCallback() {
16
- this.setAttribute('role', 'checkbox');
17
- this.#$input.addEventListener('input', this.#onInput);
18
- this.#$input.addEventListener('focus', this.#onCheckboxFocus);
19
- this.#$input.addEventListener('blur', this.#onCheckboxBlur);
20
- this.addEventListener('-change', this.#onChangeReactHandler);
21
- this.addEventListener('-focus', this.#onFocusReactHandler);
22
- this.addEventListener('-blur', this.#onBlurReactHandler);
15
+ this.#controller = new AbortController();
16
+ const {
17
+ signal
18
+ } = this.#controller;
19
+ const options = {
20
+ signal
21
+ };
22
+ this.role = 'checkbox';
23
+ this.tabIndex = 0;
24
+ this.addEventListener('click', this.#onClick, options);
25
+ this.addEventListener('focus', this.#onFocus, options);
26
+ this.addEventListener('blur', this.#onBlur, options);
27
+ this.addEventListener('-change', this.#onChangeReactHandler, options);
28
+ this.addEventListener('-focus', this.#onFocusReactHandler, options);
29
+ this.addEventListener('-blur', this.#onBlurReactHandler, options);
23
30
  }
24
31
  disconnectedCallback() {
25
- this.#$input.removeEventListener('input', this.#onInput);
26
- this.#$input.removeEventListener('focus', this.#onCheckboxFocus);
27
- this.#$input.removeEventListener('blur', this.#onCheckboxBlur);
28
- this.removeEventListener('-change', this.#onChangeReactHandler);
29
- this.removeEventListener('-focus', this.#onFocusReactHandler);
30
- this.removeEventListener('-blur', this.#onBlurReactHandler);
32
+ this.#controller.abort();
33
+ this.#controller = null;
31
34
  }
32
35
  static get observedAttributes() {
33
36
  return ['checked', 'disabled', 'text', 'labeled', 'small'];
@@ -45,14 +48,14 @@ defineCustomElement('sinch-toggle', class extends NectaryElement {
45
48
  case 'checked':
46
49
  {
47
50
  const isChecked = isAttrTrue(newVal);
48
- this.#$input.checked = isChecked;
49
51
  updateExplicitBooleanAttribute(this, 'aria-checked', isChecked);
52
+ updateBooleanAttribute(this, name, isChecked);
50
53
  break;
51
54
  }
52
55
  case 'disabled':
53
56
  {
54
57
  const isDisabled = isAttrTrue(newVal);
55
- this.#$input.disabled = isDisabled;
58
+ updateExplicitBooleanAttribute(this, 'aria-disabled', isDisabled);
56
59
  updateBooleanAttribute(this, name, isDisabled);
57
60
  break;
58
61
  }
@@ -97,24 +100,18 @@ defineCustomElement('sinch-toggle', class extends NectaryElement {
97
100
  get focusable() {
98
101
  return true;
99
102
  }
100
- focus() {
101
- this.#$input.focus();
102
- }
103
- blur() {
104
- this.#$input.blur();
105
- }
106
- #onInput = e => {
107
- e.stopPropagation();
108
- const isChecked = this.#$input.checked;
109
- this.#$input.checked = this.checked;
103
+ #onClick = () => {
104
+ if (this.disabled) {
105
+ return;
106
+ }
110
107
  this.dispatchEvent(new CustomEvent('-change', {
111
- detail: isChecked
108
+ detail: !this.checked
112
109
  }));
113
110
  };
114
- #onCheckboxFocus = () => {
111
+ #onFocus = () => {
115
112
  this.dispatchEvent(new CustomEvent('-focus'));
116
113
  };
117
- #onCheckboxBlur = () => {
114
+ #onBlur = () => {
118
115
  this.dispatchEvent(new CustomEvent('-blur'));
119
116
  };
120
117
  #onChangeReactHandler = e => {
package/utils/element.js CHANGED
@@ -26,7 +26,7 @@ export class NectaryElement extends HTMLElement {
26
26
  attachShadow(options) {
27
27
  return super.attachShadow({
28
28
  mode: 'open',
29
- delegatesFocus: true,
29
+ delegatesFocus: false,
30
30
  customElements: nectaryRegistry,
31
31
  ...options
32
32
  });