@nectary/components 2.1.4 → 2.2.0

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.
Files changed (56) hide show
  1. package/action-menu/index.js +2 -3
  2. package/action-menu-option/index.js +1 -0
  3. package/avatar/index.js +1 -1
  4. package/button/index.js +4 -5
  5. package/card/index.js +3 -2
  6. package/checkbox/index.js +28 -32
  7. package/chip/index.js +3 -4
  8. package/color-menu/index.js +3 -5
  9. package/color-swatch/index.js +1 -1
  10. package/date-picker/index.js +11 -9
  11. package/date-picker/utils.d.ts +1 -0
  12. package/date-picker/utils.js +8 -0
  13. package/dialog/index.js +3 -2
  14. package/emoji/index.js +1 -1
  15. package/emoji-picker/index.js +2 -1
  16. package/field/index.js +2 -1
  17. package/flag/index.js +1 -1
  18. package/help-tooltip/index.js +1 -0
  19. package/icon-button/index.js +4 -5
  20. package/input/index.js +374 -41
  21. package/input/types.d.ts +14 -0
  22. package/input/utils.d.ts +24 -0
  23. package/input/utils.js +302 -1
  24. package/package.json +1 -1
  25. package/pop/index.js +5 -5
  26. package/popover/index.js +1 -0
  27. package/progress-stepper/index.d.ts +11 -0
  28. package/progress-stepper/index.js +209 -0
  29. package/progress-stepper/types.d.ts +22 -0
  30. package/progress-stepper/types.js +1 -0
  31. package/progress-stepper-item/index.d.ts +12 -0
  32. package/progress-stepper-item/index.js +82 -0
  33. package/progress-stepper-item/types.d.ts +23 -0
  34. package/progress-stepper-item/types.js +1 -0
  35. package/progress-stepper-item/utils.d.ts +11 -0
  36. package/progress-stepper-item/utils.js +13 -0
  37. package/select-button/index.js +3 -4
  38. package/select-menu/index.js +3 -4
  39. package/spinner/index.js +1 -0
  40. package/stop-events/index.js +1 -0
  41. package/tabs/index.js +1 -0
  42. package/tabs-icon-option/index.js +5 -3
  43. package/tabs-option/index.js +5 -3
  44. package/tag/index.js +1 -1
  45. package/textarea/index.js +5 -2
  46. package/time-picker/index.js +1 -0
  47. package/time-picker/utils.js +2 -15
  48. package/toggle/index.js +28 -31
  49. package/tooltip/index.js +4 -3
  50. package/utils/countries.d.ts +1 -0
  51. package/utils/countries.json +487 -268
  52. package/utils/element.d.ts +1 -1
  53. package/utils/element.js +6 -6
  54. package/utils/event-target.d.ts +1 -0
  55. package/utils/event-target.js +9 -0
  56. package/utils/get-react-event-handler.js +1 -1
@@ -0,0 +1,82 @@
1
+ import '../text';
2
+ import { defineCustomElement, getAttribute, getBooleanAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
3
+ const templateHTML = '<style>:host{display:block;outline:0}#button{position:relative;display:flex;flex-direction:column;gap:4px;width:100%;height:100%;padding:8px 4px 4px;box-sizing:border-box;cursor:pointer;border-radius:var(--sinch-comp-progress-stepper-step-shape-radius)}:host([data-status=inactive])>#button{cursor:not-allowed}:host([data-status=incomplete]:hover)>#button{background-color:var(--sinch-comp-progress-stepper-step-color-incomplete-background-hover)}:host([data-status=complete]:hover)>#button{background-color:var(--sinch-comp-progress-stepper-step-color-complete-background-hover)}:host([data-status=invalid]:hover)>#button{background-color:var(--sinch-comp-progress-stepper-step-color-invalid-background-hover)}#outline{position:absolute;inset:-2px;border:2px solid var(--sinch-comp-progress-stepper-step-color-outline-focus);border-radius:calc(var(--sinch-comp-progress-stepper-step-shape-radius) + 2px);pointer-events:none;opacity:0}:host(:focus-visible) #outline{opacity:1}#text{flex-shrink:1;flex-basis:auto;min-width:0;transform:translate(0,0);will-change:transform;transition:transform .25s ease-out;padding-right:24px}:host([data-status=incomplete]) #text{--sinch-global-color-text:var(--sinch-comp-progress-stepper-step-color-incomplete-label-default);--sinch-comp-text-font:var(--sinch-comp-progress-stepper-step-font-incomplete-label)}:host([data-status=complete]) #text{--sinch-global-color-text:var(--sinch-comp-progress-stepper-step-color-complete-label-default);--sinch-comp-text-font:var(--sinch-comp-progress-stepper-step-font-complete-label)}:host([data-status=inactive]) #text{--sinch-global-color-text:var(--sinch-comp-progress-stepper-step-color-inactive-label-default);--sinch-comp-text-font:var(--sinch-comp-progress-stepper-step-font-inactive-label)}:host([invalid]) #text{--sinch-global-color-text:var(--sinch-comp-progress-stepper-step-color-invalid-label-default);--sinch-comp-text-font:var(--sinch-comp-progress-stepper-step-font-invalid-label);transform:translate(24px,0)}:host([data-status=incomplete][data-checked]) #text{--sinch-global-color-text:var(--sinch-comp-progress-stepper-step-color-incomplete-current-label-default);--sinch-comp-text-font:var(--sinch-comp-progress-stepper-step-font-incomplete-current-label)}:host([data-status=complete][data-checked]) #text{--sinch-global-color-text:var(--sinch-comp-progress-stepper-step-color-complete-current-label-default);--sinch-comp-text-font:var(--sinch-comp-progress-stepper-step-font-complete-current-label)}:host([invalid][data-checked]) #text{--sinch-global-color-text:var(--sinch-comp-progress-stepper-step-color-invalid-label-default);--sinch-comp-text-font:var(--sinch-comp-progress-stepper-step-font-invalid-current-label)}#icon-error{position:absolute;left:0;top:4px;pointer-events:none;opacity:0;transition:opacity .25s ease-in-out;--sinch-global-color-icon:var(--sinch-comp-progress-stepper-step-color-invalid-icon-default);--sinch-global-size-icon:16px}:host([invalid]) #icon-error{opacity:1}#progress{height:8px;border-radius:4px;transition:background-color .25s ease-in-out}:host([data-status=incomplete]) #progress{background-color:var(--sinch-comp-progress-stepper-step-color-incomplete-progress-background)}:host([data-status=complete]) #progress{background-color:var(--sinch-comp-progress-stepper-step-color-complete-progress-background)}:host([data-status=inactive]) #progress{background-color:var(--sinch-comp-progress-stepper-step-color-inactive-progress-background)}:host([invalid]) #progress{background-color:var(--sinch-comp-progress-stepper-step-color-invalid-progress-background)}#bar{width:8px;height:8px;border-radius:4px;opacity:0;transition:width .25s ease-in-out,opacity .25s ease-in-out}:host([data-status=incomplete]) #bar{background-color:var(--sinch-comp-progress-stepper-step-color-incomplete-progress-bar)}:host([data-status=complete]) #bar{background-color:var(--sinch-comp-progress-stepper-step-color-complete-progress-bar);width:100%}:host([data-status=complete]:not([invalid])) #bar,:host([data-status=incomplete]:not([invalid])) #bar{opacity:1}#label-bar{position:relative}</style><div id="button"><div id="progress"><div id="bar"></div></div><div id="label-bar"><sinch-icon id="icon-error" name="report_problem" aria-hidden="true"></sinch-icon><sinch-text id="text" type="m"></sinch-text></div><div id="outline"></div></div>';
4
+ import { ATTR_PROGRESS_STEPPER_ITEM_ACTIVE_DESCENDANT, ATTR_PROGRESS_STEPPER_ITEM_CHECKED, ATTR_PROGRESS_STEPPER_ITEM_STATUS, isProgressStepperItemActive, isProgressStepperItemActiveDescendant } from './utils';
5
+ const template = document.createElement('template');
6
+ template.innerHTML = templateHTML;
7
+ defineCustomElement('sinch-progress-stepper-item', class extends NectaryElement {
8
+ #$text;
9
+ constructor() {
10
+ super();
11
+ const shadowRoot = this.attachShadow({
12
+ delegatesFocus: false
13
+ });
14
+ shadowRoot.appendChild(template.content.cloneNode(true));
15
+ this.#$text = shadowRoot.querySelector('#text');
16
+ }
17
+ connectedCallback() {
18
+ this.role = 'tab';
19
+ }
20
+ disconnectedCallback() {}
21
+ static get observedAttributes() {
22
+ return ['text', 'invalid', ATTR_PROGRESS_STEPPER_ITEM_STATUS, ATTR_PROGRESS_STEPPER_ITEM_CHECKED, ATTR_PROGRESS_STEPPER_ITEM_ACTIVE_DESCENDANT];
23
+ }
24
+ attributeChangedCallback(name, oldVal, newVal) {
25
+ if (oldVal === newVal) {
26
+ return;
27
+ }
28
+ switch (name) {
29
+ case 'text':
30
+ {
31
+ this.#$text.textContent = newVal;
32
+ break;
33
+ }
34
+ case ATTR_PROGRESS_STEPPER_ITEM_CHECKED:
35
+ {
36
+ updateExplicitBooleanAttribute(this, 'aria-selected', isAttrTrue(newVal));
37
+ break;
38
+ }
39
+ case ATTR_PROGRESS_STEPPER_ITEM_STATUS:
40
+ {
41
+ this.#updateTabIndex();
42
+ break;
43
+ }
44
+ case ATTR_PROGRESS_STEPPER_ITEM_ACTIVE_DESCENDANT:
45
+ {
46
+ this.#updateTabIndex();
47
+ break;
48
+ }
49
+ case 'invalid':
50
+ {
51
+ const isInvalid = isAttrTrue(newVal);
52
+ updateBooleanAttribute(this, 'invalid', isInvalid);
53
+ updateExplicitBooleanAttribute(this, 'aria-invalid', isInvalid);
54
+ break;
55
+ }
56
+ }
57
+ }
58
+ set value(value) {
59
+ updateAttribute(this, 'value', value);
60
+ }
61
+ get value() {
62
+ return getAttribute(this, 'value', '');
63
+ }
64
+ set text(value) {
65
+ updateAttribute(this, 'text', value);
66
+ }
67
+ get text() {
68
+ return getAttribute(this, 'text', '');
69
+ }
70
+ set invalid(isInvalid) {
71
+ updateBooleanAttribute(this, 'invalid', isInvalid);
72
+ }
73
+ get invalid() {
74
+ return getBooleanAttribute(this, 'invalid');
75
+ }
76
+ get focusable() {
77
+ return true;
78
+ }
79
+ #updateTabIndex() {
80
+ this.tabIndex = isProgressStepperItemActiveDescendant(this) && isProgressStepperItemActive(this) ? 0 : -1;
81
+ }
82
+ });
@@ -0,0 +1,23 @@
1
+ import type { TSinchElementReact } from '../types';
2
+ export type TSinchProgressStepperItemElement = HTMLElement & {
3
+ /** Value */
4
+ value: string;
5
+ /** Text */
6
+ text: string;
7
+ /** Invalid */
8
+ invalid: boolean;
9
+ /** Value */
10
+ setAttribute(name: 'value', value: string): void;
11
+ /** Text */
12
+ setAttribute(name: 'text', value: string): void;
13
+ /** Invalid */
14
+ setAttribute(name: 'invalid', value: ''): void;
15
+ };
16
+ export type TSinchProgressStepperItemReact = TSinchElementReact<TSinchProgressStepperItemElement> & {
17
+ /** Value */
18
+ value: string;
19
+ /** Text */
20
+ text: string;
21
+ /** Invalid */
22
+ invalid?: boolean;
23
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ type TSinchProgressStepperItemStatus = 'inactive' | 'incomplete' | 'invalid' | 'complete';
2
+ export declare const ATTR_PROGRESS_STEPPER_ITEM_CHECKED = "data-checked";
3
+ export declare const ATTR_PROGRESS_STEPPER_ITEM_STATUS = "data-status";
4
+ export declare const ATTR_PROGRESS_STEPPER_ITEM_ACTIVE_DESCENDANT = "data-active-descendant";
5
+ export declare const isProgressStepperItemChecked: ($el: Element) => boolean;
6
+ export declare const setProgressStepperItemChecked: ($el: Element, isChecked: boolean) => void;
7
+ export declare const isProgressStepperItemActive: ($el: Element) => boolean;
8
+ export declare const setProgressStepperItemStatus: ($el: Element, status: TSinchProgressStepperItemStatus) => void;
9
+ export declare const isProgressStepperItemActiveDescendant: ($el: Element) => boolean;
10
+ export declare const setProgressStepperItemActiveDescendant: ($el: Element, isActiveDescendant: boolean) => void;
11
+ export {};
@@ -0,0 +1,13 @@
1
+ import { getAttribute, getBooleanAttribute, updateAttribute, updateBooleanAttribute } from '../utils';
2
+ export const ATTR_PROGRESS_STEPPER_ITEM_CHECKED = 'data-checked';
3
+ export const ATTR_PROGRESS_STEPPER_ITEM_STATUS = 'data-status';
4
+ export const ATTR_PROGRESS_STEPPER_ITEM_ACTIVE_DESCENDANT = 'data-active-descendant';
5
+ export const isProgressStepperItemChecked = $el => getBooleanAttribute($el, ATTR_PROGRESS_STEPPER_ITEM_CHECKED);
6
+ export const setProgressStepperItemChecked = ($el, isChecked) => updateBooleanAttribute($el, ATTR_PROGRESS_STEPPER_ITEM_CHECKED, isChecked);
7
+ export const isProgressStepperItemActive = $el => {
8
+ const attrValue = getAttribute($el, ATTR_PROGRESS_STEPPER_ITEM_STATUS);
9
+ return attrValue !== null && attrValue !== 'inactive';
10
+ };
11
+ export const setProgressStepperItemStatus = ($el, status) => updateAttribute($el, ATTR_PROGRESS_STEPPER_ITEM_STATUS, status);
12
+ export const isProgressStepperItemActiveDescendant = $el => getBooleanAttribute($el, ATTR_PROGRESS_STEPPER_ITEM_ACTIVE_DESCENDANT);
13
+ export const setProgressStepperItemActiveDescendant = ($el, isActiveDescendant) => updateBooleanAttribute($el, ATTR_PROGRESS_STEPPER_ITEM_ACTIVE_DESCENDANT, isActiveDescendant);
@@ -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');
@@ -66,6 +64,7 @@ defineCustomElement('sinch-select-button', class extends NectaryElement {
66
64
  disconnectedCallback() {
67
65
  super.disconnectedCallback();
68
66
  this.#controller.abort();
67
+ this.#controller = null;
69
68
  }
70
69
  static get observedAttributes() {
71
70
  return ['text', 'placeholder', 'invalid', 'disabled', 'size', 'data-size'];
@@ -160,7 +159,7 @@ defineCustomElement('sinch-select-button', class extends NectaryElement {
160
159
  }
161
160
  };
162
161
  #onSizeUpdate() {
163
- if (!this.isConnected) {
162
+ if (!this.isDomConnected) {
164
163
  return;
165
164
  }
166
165
  const size = this.getAttribute('data-size') ?? DEFAULT_SIZE;
@@ -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');
@@ -49,8 +47,9 @@ defineCustomElement('sinch-select-menu', class extends NectaryElement {
49
47
  this.#onOptionSlotChange();
50
48
  }
51
49
  disconnectedCallback() {
52
- this.#controller.abort();
53
50
  this.#searchDebounce.cancel();
51
+ this.#controller.abort();
52
+ this.#controller = null;
54
53
  }
55
54
  static get observedAttributes() {
56
55
  return ['value', 'rows', 'multiple'];
package/spinner/index.js CHANGED
@@ -18,6 +18,7 @@ defineCustomElement('sinch-spinner', class extends NectaryElement {
18
18
  }
19
19
  disconnectedCallback() {
20
20
  this.#controller.abort();
21
+ this.#controller = null;
21
22
  }
22
23
  static get observedAttributes() {
23
24
  return ['size'];
@@ -19,6 +19,7 @@ defineCustomElement('sinch-stop-events', class extends HTMLElement {
19
19
  }
20
20
  disconnectedCallback() {
21
21
  this.#controller.abort();
22
+ this.#controller = null;
22
23
  }
23
24
  #stopEvent = e => {
24
25
  e.stopPropagation();
package/tabs/index.js CHANGED
@@ -29,6 +29,7 @@ defineCustomElement('sinch-tabs', class extends NectaryElement {
29
29
  }
30
30
  disconnectedCallback() {
31
31
  this.#controller.abort();
32
+ this.#controller = null;
32
33
  }
33
34
  static get observedAttributes() {
34
35
  return ['value'];
@@ -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/tag/index.js CHANGED
@@ -62,7 +62,7 @@ defineCustomElement('sinch-tag', class extends NectaryElement {
62
62
  }
63
63
  }
64
64
  #updateColor() {
65
- if (!this.isConnected) {
65
+ if (!this.isDomConnected) {
66
66
  return;
67
67
  }
68
68
  const colorName = this.color;
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"]');
@@ -45,6 +47,7 @@ defineCustomElement('sinch-textarea', class extends NectaryElement {
45
47
  disconnectedCallback() {
46
48
  super.disconnectedCallback();
47
49
  this.#controller.abort();
50
+ this.#controller = null;
48
51
  }
49
52
  static get observedAttributes() {
50
53
  return ['value', 'placeholder', 'invalid', 'disabled', 'rows', 'resizable'];
@@ -201,7 +204,7 @@ defineCustomElement('sinch-textarea', class extends NectaryElement {
201
204
  setClass(this.#$bottomWrapper, 'empty', isEmpty);
202
205
  };
203
206
  #onSizeUpdate() {
204
- if (!this.isConnected) {
207
+ if (!this.isDomConnected) {
205
208
  return;
206
209
  }
207
210
  const size = this.getAttribute('data-size') ?? DEFAULT_SIZE;
@@ -105,6 +105,7 @@ defineCustomElement('sinch-time-picker', class extends NectaryElement {
105
105
  }
106
106
  disconnectedCallback() {
107
107
  this.#controller.abort();
108
+ this.#controller = null;
108
109
  }
109
110
  static get observedAttributes() {
110
111
  return ['value', 'ampm', 'submit-aria-label'];
@@ -6,15 +6,8 @@ export const parseTime = value => {
6
6
  };
7
7
  }
8
8
  const timeParts = value.split(':');
9
- if (timeParts.length < 3) {
10
- return {
11
- hours: 0,
12
- minutes: 0
13
- };
14
- }
15
- const hours = parseInt(timeParts[0]);
16
- const minutes = parseInt(timeParts[1]);
17
- const seconds = parseInt(timeParts[2]);
9
+ const hours = parseInt(timeParts[0] ?? '00');
10
+ const minutes = parseInt(timeParts[1] ?? '00');
18
11
  if (isNaN(hours) || hours > 23 || hours < 0) {
19
12
  return {
20
13
  hours: 0,
@@ -27,12 +20,6 @@ export const parseTime = value => {
27
20
  minutes: 0
28
21
  };
29
22
  }
30
- if (isNaN(seconds) || seconds > 59 || seconds < 0) {
31
- return {
32
- hours: 0,
33
- minutes: 0
34
- };
35
- }
36
23
  return {
37
24
  hours,
38
25
  minutes
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/tooltip/index.js CHANGED
@@ -57,9 +57,10 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
57
57
  this.#updateText();
58
58
  }
59
59
  disconnectedCallback() {
60
+ this.#tooltipState.destroy();
60
61
  super.disconnectedCallback();
61
62
  this.#controller.abort();
62
- this.#tooltipState.destroy();
63
+ this.#controller = null;
63
64
  }
64
65
  static get observedAttributes() {
65
66
  return ['text', 'orientation', 'type'];
@@ -191,7 +192,7 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
191
192
  setClass(this.#$tip, 'hidden', rectOverlap(targetRect, contentRect));
192
193
  };
193
194
  #updateText() {
194
- if (!this.isConnected) {
195
+ if (!this.isDomConnected) {
195
196
  return;
196
197
  }
197
198
  const text = this.text;
@@ -206,7 +207,7 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
206
207
  }
207
208
  }
208
209
  #subscribeMouseEnterEvent() {
209
- if (!this.isConnected || this.#isSubscribed) {
210
+ if (!this.isDomConnected || this.#isSubscribed) {
210
211
  return;
211
212
  }
212
213
  this.#$target.addEventListener('mouseenter', this.#onMouseEnter, {
@@ -1,5 +1,6 @@
1
1
  export type TSinchCountry = {
2
2
  name: string;
3
3
  phoneCode: string;
4
+ phoneMask: string | null;
4
5
  };
5
6
  export declare const countries: Record<string, TSinchCountry>;