@nectary/components 0.44.1 → 0.45.1

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 (110) hide show
  1. package/accordion-item/index.js +1 -1
  2. package/action-menu/index.js +3 -11
  3. package/alert/index.js +3 -1
  4. package/avatar/index.js +12 -13
  5. package/avatar/types.d.ts +4 -4
  6. package/avatar/utils.d.ts +1 -4
  7. package/avatar/utils.js +4 -7
  8. package/badge/index.js +9 -7
  9. package/badge/types.d.ts +4 -4
  10. package/badge/utils.d.ts +1 -4
  11. package/badge/utils.js +0 -6
  12. package/button/index.js +88 -23
  13. package/button/types.d.ts +12 -11
  14. package/button/utils.d.ts +4 -1
  15. package/button/utils.js +9 -1
  16. package/card-container/index.js +1 -1
  17. package/chat-block/index.js +1 -1
  18. package/chat-bubble/index.js +1 -1
  19. package/checkbox/index.js +4 -2
  20. package/chip/index.js +7 -6
  21. package/color-menu/index.js +9 -18
  22. package/color-swatch/index.js +5 -7
  23. package/date-picker/index.js +1 -1
  24. package/dialog/index.js +4 -7
  25. package/emoji/index.js +2 -6
  26. package/emoji-picker/index.js +6 -14
  27. package/field/index.js +1 -1
  28. package/file-status/index.js +4 -2
  29. package/flag/index.d.ts +11 -0
  30. package/flag/index.js +43 -0
  31. package/flag/types.d.ts +11 -0
  32. package/flag/types.js +1 -0
  33. package/flag/utils.d.ts +1 -0
  34. package/flag/utils.js +19 -0
  35. package/icon/index.js +1 -1
  36. package/icon-button/index.js +77 -9
  37. package/icon-button/types.d.ts +14 -6
  38. package/icon-button/utils.d.ts +5 -0
  39. package/icon-button/utils.js +9 -0
  40. package/icons/create-icon-class.js +1 -1
  41. package/inline-alert/index.js +3 -1
  42. package/input/index.d.ts +3 -0
  43. package/input/index.js +148 -71
  44. package/input/types.d.ts +7 -0
  45. package/link/index.js +1 -1
  46. package/package.json +2 -4
  47. package/pagination/index.js +1 -1
  48. package/pop/index.js +15 -37
  49. package/popover/index.js +7 -9
  50. package/radio-option/index.js +1 -1
  51. package/segment/index.js +10 -6
  52. package/segment/types.d.ts +4 -4
  53. package/segment/utils.d.ts +3 -5
  54. package/segment/utils.js +14 -4
  55. package/segment-collapse/index.js +1 -1
  56. package/segmented-control-option/index.js +1 -1
  57. package/segmented-icon-control-option/index.js +1 -1
  58. package/select-button/index.js +93 -28
  59. package/select-button/types.d.ts +8 -1
  60. package/select-menu/index.d.ts +5 -0
  61. package/select-menu/index.js +46 -17
  62. package/select-menu-option/index.d.ts +1 -0
  63. package/select-menu-option/index.js +3 -0
  64. package/select-menu-option/types.d.ts +1 -0
  65. package/spinner/index.js +52 -7
  66. package/spinner/types.d.ts +4 -5
  67. package/stop-events/index.js +9 -5
  68. package/table/index.js +1 -1
  69. package/tag/index.js +2 -6
  70. package/text/index.js +3 -1
  71. package/textarea/index.js +1 -1
  72. package/theme/button.css +146 -0
  73. package/{theme.css → theme/contextual.css} +3 -25
  74. package/theme/elevation.css +1 -1
  75. package/theme/flag.css +4 -0
  76. package/theme/fonts.css +0 -33
  77. package/theme/fonts.json +0 -33
  78. package/theme/icon-button.css +68 -0
  79. package/theme/index.css +4 -0
  80. package/theme/index.d.ts +21 -0
  81. package/theme/index.js +21 -0
  82. package/theme/input.css +7 -0
  83. package/theme/select-button.css +7 -0
  84. package/theme/shapes.css +4 -3
  85. package/theme/size.css +9 -0
  86. package/theme/spinner.css +7 -0
  87. package/theme/typography.css +7 -7
  88. package/tile-control-option/index.js +1 -1
  89. package/time-picker/index.js +1 -1
  90. package/title/index.js +7 -3
  91. package/toast/index.js +3 -1
  92. package/toggle/index.js +1 -1
  93. package/tooltip/index.js +8 -6
  94. package/utils/context.d.ts +14 -9
  95. package/utils/context.js +60 -26
  96. package/utils/countries.d.ts +5 -0
  97. package/utils/countries.js +2 -0
  98. package/utils/countries.json +998 -0
  99. package/utils/debounce.d.ts +4 -0
  100. package/utils/debounce.js +21 -0
  101. package/utils/element.d.ts +4 -0
  102. package/utils/element.js +10 -0
  103. package/utils/index.d.ts +1 -0
  104. package/utils/index.js +1 -0
  105. package/utils/size.d.ts +10 -0
  106. package/utils/size.js +19 -0
  107. package/utils/throttle.d.ts +2 -2
  108. package/utils/throttle.js +4 -9
  109. package/spinner/utils.d.ts +0 -2
  110. package/spinner/utils.js +0 -1
@@ -1,6 +1,6 @@
1
1
  import '../icons/keyboard-arrow-down';
2
2
  import { defineCustomElement, getAttribute, getBooleanAttribute, getLiteralAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateLiteralAttribute } from '../utils';
3
- const templateHTML = '<style>:host{display:block;outline:0;min-height:48px}#wrapper{display:flex;flex-direction:column;position:relative;width:100%;height:100%;box-sizing:border-box;overflow:hidden;border-bottom:1px solid var(--sinch-color-stormy-200);--sinch-size-icon:16px}#button{all:initial;cursor:pointer;display:flex;align-items:center;gap:8px;box-sizing:border-box;width:100%;height:48px;padding:12px 8px;font:var(--sinch-font-title-s);color:var(--sinch-color-text-default);fill:var(--sinch-color-stormy-500)}#button>*{pointer-events:none}#button:disabled{cursor:initial;color:var(--sinch-color-stormy-100);fill:var(--sinch-color-stormy-100)}#button::before{width:8px;height:8px;border-radius:50%;margin-left:2px;margin-right:8px}:host([status=success]) #button::before{content:"";background-color:var(--sinch-color-success-500)}:host([status=warn]) #button::before{content:"";background-color:var(--sinch-color-warning-500)}:host([status=error]) #button::before{content:"";background-color:var(--sinch-color-error-500)}:host([status=info]) #button::before{content:"";background-color:var(--sinch-color-informative-500)}#title{flex:1;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}#content{display:none;overflow-y:auto;flex-shrink:1;min-height:0;padding:0 8px 18px;font:var(--sinch-font-body);color:var(--sinch-color-text-default)}#dropdown-icon{--sinch-size-icon:24px}#button[aria-expanded=true]>#dropdown-icon{transform:rotate(180deg)}#button[aria-expanded=true]+#content{display:block}#optional{font:var(--sinch-font-small-text);color:var(--sinch-color-stormy-300)}</style><div id="wrapper"><button id="button" aria-controls="content" aria-expanded="false"><slot name="icon"></slot><span id="title"></span><span id="optional"></span><sinch-icon-keyboard-arrow-down id="dropdown-icon"></sinch-icon-keyboard-arrow-down></button><div id="content" role="region" aria-labelledby="button"><slot name="content"></slot></div></div>';
3
+ const templateHTML = '<style>:host{display:block;outline:0;min-height:48px}#wrapper{display:flex;flex-direction:column;position:relative;width:100%;height:100%;box-sizing:border-box;overflow:hidden;border-bottom:1px solid var(--sinch-color-stormy-200);--sinch-size-icon:16px}#button{all:initial;cursor:pointer;display:flex;align-items:center;gap:8px;box-sizing:border-box;width:100%;height:48px;padding:12px 8px;font:var(--sinch-font-title-s);color:var(--sinch-color-text-default);--sinch-color-icon:var(--sinch-color-stormy-500)}#button>*{pointer-events:none}#button:disabled{cursor:initial;color:var(--sinch-color-stormy-100);--sinch-color-icon:var(--sinch-color-stormy-100)}#button::before{width:8px;height:8px;border-radius:50%;margin-left:2px;margin-right:8px}:host([status=success]) #button::before{content:"";background-color:var(--sinch-color-success-500)}:host([status=warn]) #button::before{content:"";background-color:var(--sinch-color-warning-500)}:host([status=error]) #button::before{content:"";background-color:var(--sinch-color-error-500)}:host([status=info]) #button::before{content:"";background-color:var(--sinch-color-informative-500)}#title{flex:1;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}#content{display:none;overflow-y:auto;flex-shrink:1;min-height:0;padding:0 8px 18px;font:var(--sinch-font-text-m);color:var(--sinch-color-text-default)}#dropdown-icon{--sinch-size-icon:24px}#button[aria-expanded=true]>#dropdown-icon{transform:rotate(180deg)}#button[aria-expanded=true]+#content{display:block}#optional{font:var(--sinch-font-text-s);color:var(--sinch-color-stormy-300)}</style><div id="wrapper"><button id="button" aria-controls="content" aria-expanded="false"><slot name="icon"></slot><span id="title"></span><span id="optional"></span><sinch-icon-keyboard-arrow-down id="dropdown-icon"></sinch-icon-keyboard-arrow-down></button><div id="content" role="region" aria-labelledby="button"><slot name="content"></slot></div></div>';
4
4
  import { statusValues } from './utils';
5
5
  const template = document.createElement('template');
6
6
  template.innerHTML = templateHTML;
@@ -1,5 +1,5 @@
1
1
  import { isSinchActionMenuOption } from '../action-menu-option/utils';
2
- import { attrValueToPixels, defineCustomElement, dispatchContextConnectEvent, dispatchContextDisconnectEvent, getBooleanAttribute, getIntegerAttribute, NectaryElement, updateBooleanAttribute, updateIntegerAttribute } from '../utils';
2
+ import { attrValueToPixels, defineCustomElement, getBooleanAttribute, getIntegerAttribute, NectaryElement, subscribeContext, updateBooleanAttribute, updateIntegerAttribute } from '../utils';
3
3
  const templateHTML = '<style>:host{display:block;outline:0}#listbox{overflow-y:auto}</style><div id="listbox" role="presentation"><slot></slot></div>';
4
4
  const ITEM_HEIGHT = 40;
5
5
  const template = document.createElement('template');
@@ -22,12 +22,6 @@ defineCustomElement('sinch-action-menu', class extends NectaryElement {
22
22
  } = this.#controller;
23
23
  this.setAttribute('role', 'listbox');
24
24
  this.setAttribute('tabindex', '0');
25
- this.addEventListener('-keydown', this.#onContextKeyDown, {
26
- signal
27
- });
28
- this.addEventListener('-visibility', this.#onContextVisibility, {
29
- signal
30
- });
31
25
  this.addEventListener('keydown', this.#onListboxKeyDown, {
32
26
  signal
33
27
  });
@@ -37,12 +31,10 @@ defineCustomElement('sinch-action-menu', class extends NectaryElement {
37
31
  this.#$listbox.addEventListener('click', this.#onListboxClick, {
38
32
  signal
39
33
  });
40
- dispatchContextConnectEvent(this, 'keydown');
41
- dispatchContextConnectEvent(this, 'visibility');
34
+ subscribeContext(this, 'keydown', this.#onContextKeyDown, signal);
35
+ subscribeContext(this, 'visibility', this.#onContextVisibility, signal);
42
36
  }
43
37
  disconnectedCallback() {
44
- dispatchContextDisconnectEvent(this, 'keydown');
45
- dispatchContextDisconnectEvent(this, 'visibility');
46
38
  this.#controller.abort();
47
39
  }
48
40
  static get observedAttributes() {
package/alert/index.js CHANGED
@@ -37,7 +37,9 @@ defineCustomElement('sinch-alert', class extends NectaryElement {
37
37
  switch (name) {
38
38
  case 'type':
39
39
  {
40
- assertType(newVal);
40
+ if ('production' !== 'production') {
41
+ assertType(newVal);
42
+ }
41
43
  break;
42
44
  }
43
45
  case 'text':
package/avatar/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { defineCustomElement, getAttribute, getLiteralAttribute, NectaryElement, updateAttribute, updateLiteralAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{position:relative;width:40px;height:40px;background-color:var(--sinch-color-snow-100);border-radius:50%;--sinch-avatar-badge-size:16px;--sinch-avatar-badge-font:700 12px/14px "Gilroy","Arial","sans-serif"}#circle{position:relative;width:calc(100% - 2px);height:calc(100% - 2px);left:1px;top:1px;border-radius:50%;-webkit-mask:linear-gradient(#fff,#000);mask:linear-gradient(#fff,#000);background-color:var(--sinch-avatar-color-default-bg);color:var(--sinch-avatar-color-default-fg)}#text{display:block;width:100%;height:100%;font:var(--sinch-font-title-s);line-height:38px;text-transform:uppercase;text-align:center}:host([size="l"]) #wrapper{width:56px;height:56px;--sinch-avatar-badge-size:20px;--sinch-avatar-badge-font:700 12px/18px "Gilroy","Arial","sans-serif"}:host([size="l"]) #text{font:var(--sinch-font-title-m);line-height:54px}:host([size="s"]) #wrapper{width:24px;height:24px;--sinch-avatar-badge-size:11px;--sinch-avatar-badge-font:500 8px/9px "Gilroy","Arial","sans-serif"}:host([size="s"]) #text{font:var(--sinch-font-extra-small-text);line-height:22px}#image{display:none;position:absolute;left:0;top:0;width:100%;height:100%;object-fit:contain}:host([src]:not([src=""])) #image{display:block}#status-wrapper{position:absolute;left:calc(85% - 5px);top:calc(85% - 5px);width:10px;height:10px;padding:1px;box-sizing:border-box;border-radius:50%;background-color:var(--sinch-color-snow-100);display:none;pointer-events:none}#status{width:8px;height:8px;border-radius:50%}:host([status=away]) #status-wrapper,:host([status=busy]) #status-wrapper,:host([status=offline]) #status-wrapper,:host([status=online]) #status-wrapper{display:block}:host([status=online]) #status{background-color:var(--sinch-avatar-status-color-online)}:host([status=away]) #status{background-color:var(--sinch-avatar-status-color-away)}:host([status=busy]) #status{background-color:var(--sinch-avatar-status-color-busy)}:host([status=offline]) #status{background-color:var(--sinch-avatar-status-color-offline)}</style><div id="wrapper"><div id="circle"><span id="text"></span><img id="image" alt=""/></div><div id="status-wrapper"><div id="status"></div></div></div>';
3
- import { assertAvatarColor, assertSize, assertStatus, getAvatarColorBg, getAvatarColorFg, sizeValues, statusValues } from './utils';
2
+ import { assertSize, DEFAULT_SIZE, sizeValues } from '../utils/size';
3
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{position:relative;width:40px;height:40px;background-color:var(--sinch-color-snow-100);border-radius:50%}#circle{position:relative;width:calc(100% - 2px);height:calc(100% - 2px);left:1px;top:1px;border-radius:50%;-webkit-mask:linear-gradient(#fff,#000);mask:linear-gradient(#fff,#000);background-color:var(--sinch-avatar-color-default-bg);color:var(--sinch-avatar-color-default-fg)}#text{display:block;width:100%;height:100%;font:var(--sinch-font-title-s);line-height:38px;text-transform:uppercase;text-align:center}:host([size="l"]) #wrapper{width:56px;height:56px}:host([size="l"]) #text{font:var(--sinch-font-title-m);line-height:54px}:host([size="s"]) #wrapper{width:24px;height:24px}:host([size="s"]) #text{font:var(--sinch-font-text-xs);line-height:22px}#image{display:none;position:absolute;left:0;top:0;width:100%;height:100%;object-fit:contain}:host([src]:not([src=""])) #image{display:block}#status-wrapper{position:absolute;left:calc(85% - 5px);top:calc(85% - 5px);width:10px;height:10px;padding:1px;box-sizing:border-box;border-radius:50%;background-color:var(--sinch-color-snow-100);display:none;pointer-events:none}#status{width:8px;height:8px;border-radius:50%}:host([status=away]) #status-wrapper,:host([status=busy]) #status-wrapper,:host([status=offline]) #status-wrapper,:host([status=online]) #status-wrapper{display:block}:host([status=online]) #status{background-color:var(--sinch-avatar-status-color-online)}:host([status=away]) #status{background-color:var(--sinch-avatar-status-color-away)}:host([status=busy]) #status{background-color:var(--sinch-avatar-status-color-busy)}:host([status=offline]) #status{background-color:var(--sinch-avatar-status-color-offline)}</style><div id="wrapper"><div id="circle"><span id="text"></span><img id="image" alt=""/></div><div id="status-wrapper"><div id="status"></div></div></div>';
4
+ import { assertAvatarColor, assertStatus, getAvatarColorBg, getAvatarColorFg, statusValues } from './utils';
4
5
  const template = document.createElement('template');
5
6
  template.innerHTML = templateHTML;
6
7
  defineCustomElement('sinch-avatar', class extends NectaryElement {
7
8
  #$circle;
8
9
  #$text;
9
10
  #$image;
10
- #isConnected = false;
11
11
  constructor() {
12
12
  super();
13
13
  const shadowRoot = this.attachShadow();
@@ -17,12 +17,9 @@ defineCustomElement('sinch-avatar', class extends NectaryElement {
17
17
  this.#$image = shadowRoot.querySelector('#image');
18
18
  }
19
19
  connectedCallback() {
20
- this.#isConnected = true;
20
+ super.connectedCallback();
21
21
  this.#updateColor();
22
22
  }
23
- disconnectedCallback() {
24
- this.#isConnected = false;
25
- }
26
23
  get src() {
27
24
  return getAttribute(this, 'src');
28
25
  }
@@ -42,7 +39,7 @@ defineCustomElement('sinch-avatar', class extends NectaryElement {
42
39
  updateAttribute(this, 'color', value);
43
40
  }
44
41
  get size() {
45
- return getLiteralAttribute(this, sizeValues, 'size', 'm');
42
+ return getLiteralAttribute(this, sizeValues, 'size', DEFAULT_SIZE);
46
43
  }
47
44
  set size(value) {
48
45
  updateLiteralAttribute(this, sizeValues, 'size', value);
@@ -71,14 +68,14 @@ defineCustomElement('sinch-avatar', class extends NectaryElement {
71
68
  }
72
69
  case 'size':
73
70
  {
74
- if (newVal !== null) {
75
- assertSize(newVal);
71
+ if ('production' !== 'production') {
72
+ assertSize(newVal, 'sinch-avatar');
76
73
  }
77
74
  break;
78
75
  }
79
76
  case 'status':
80
77
  {
81
- if (newVal !== null) {
78
+ if ('production' !== 'production') {
82
79
  assertStatus(newVal);
83
80
  }
84
81
  break;
@@ -90,12 +87,14 @@ defineCustomElement('sinch-avatar', class extends NectaryElement {
90
87
  }
91
88
  }
92
89
  #updateColor() {
93
- if (!this.#isConnected) {
90
+ if (!this.isConnected) {
94
91
  return;
95
92
  }
96
93
  const colorName = this.color;
97
94
  if (colorName !== null && colorName.length > 0) {
98
- assertAvatarColor(this, colorName);
95
+ if ('production' !== 'production') {
96
+ assertAvatarColor(this, colorName);
97
+ }
99
98
  const bg = getAvatarColorBg(colorName);
100
99
  const fg = getAvatarColorFg(colorName);
101
100
  this.#$circle.style.setProperty('background-color', bg);
package/avatar/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { TSinchElementReact } from '../types';
2
- export declare type TSinchAvatarSize = 'l' | 'm' | 's';
2
+ import type { TSinchSize } from '../utils/size';
3
3
  export declare type TSinchAvatarStatus = 'online' | 'busy' | 'away' | 'offline';
4
4
  export declare type TSinchAvatarElement = HTMLElement & {
5
5
  /** Image source */
@@ -11,7 +11,7 @@ export declare type TSinchAvatarElement = HTMLElement & {
11
11
  /** Status */
12
12
  status: TSinchAvatarStatus | null;
13
13
  /** Size, `m` by default */
14
- size: TSinchAvatarSize;
14
+ size: TSinchSize;
15
15
  /** Image source */
16
16
  setAttribute(name: 'src', value: string): void;
17
17
  /** Alt text */
@@ -19,7 +19,7 @@ export declare type TSinchAvatarElement = HTMLElement & {
19
19
  /** Background color */
20
20
  setAttribute(name: 'color', value: string): void;
21
21
  /** Size, `m` by default */
22
- setAttribute(name: 'size', value: TSinchAvatarSize): void;
22
+ setAttribute(name: 'size', value: TSinchSize): void;
23
23
  /** Status */
24
24
  setAttribute(name: 'status', value: TSinchAvatarStatus): void;
25
25
  };
@@ -31,7 +31,7 @@ export declare type TSinchAvatarReact = TSinchElementReact<TSinchAvatarElement>
31
31
  /** Background color */
32
32
  color?: string;
33
33
  /** Size, `m` by default */
34
- size?: TSinchAvatarSize;
34
+ size?: TSinchSize;
35
35
  /** Status */
36
36
  status?: TSinchAvatarStatus;
37
37
  };
package/avatar/utils.d.ts CHANGED
@@ -1,8 +1,5 @@
1
- import type { TSinchAvatarSize, TSinchAvatarStatus } from './types';
2
- export declare const sizeValues: readonly TSinchAvatarSize[];
1
+ import type { TSinchAvatarStatus } from './types';
3
2
  export declare const statusValues: readonly TSinchAvatarStatus[];
4
- declare type TAssertSize = (value: string | null) => asserts value is TSinchAvatarSize;
5
- export declare const assertSize: TAssertSize;
6
3
  declare type TAssertStatus = (value: string | null) => asserts value is TSinchAvatarStatus;
7
4
  export declare const assertStatus: TAssertStatus;
8
5
  export declare const getAvatarColorBg: (id: string) => string;
package/avatar/utils.js CHANGED
@@ -1,12 +1,9 @@
1
- export const sizeValues = ['l', 'm', 's'];
2
1
  export const statusValues = ['online', 'busy', 'away', 'offline'];
3
- export const assertSize = value => {
4
- if (value === null || !sizeValues.includes(value)) {
5
- throw new Error(`sinch-avatar: invalid size attribute: ${value}`);
6
- }
7
- };
8
2
  export const assertStatus = value => {
9
- if (value === null || !statusValues.includes(value)) {
3
+ if (value === null || value.length === 0) {
4
+ return;
5
+ }
6
+ if (!statusValues.includes(value)) {
10
7
  throw new Error(`sinch-avatar: invalid status attribute: ${value}`);
11
8
  }
12
9
  };
package/badge/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, getLiteralAttribute, getRect, NectaryElement, setClass, updateAttribute, updateBooleanAttribute, updateLiteralAttribute } from '../utils';
2
+ import { assertSize, DEFAULT_SIZE, sizeValues } from '../utils/size';
2
3
  const templateHTML = '<style>:host{display:inline-flex;flex-direction:column;position:relative}#badge-wrapper{position:absolute;left:0;top:0;width:fit-content;border-radius:11px;padding:1px;pointer-events:none;background-color:var(--sinch-color-snow-100)}#badge{box-sizing:border-box;color:var(--sinch-badge-color-default-fg);background-color:var(--sinch-badge-color-default-bg);width:20px;height:20px;border-radius:10px}#badge.long{width:fit-content;padding:0 5px}#text{display:block;width:100%;height:100%;text-align:center;font-family:var(--sinch-font-mono-family);font-weight:400;font-size:14px;line-height:20px;text-rendering:optimizelegibility}:host([size="m"]) #badge-wrapper{left:calc(100% - 8px);top:-8px}:host([size="m"]) #badge{width:14px;height:14px}:host([size="m"]) #badge.long{width:fit-content;padding:0 3px}:host([size="m"]) #text{font-size:12px;line-height:14px}:host([size="s"]) #badge{width:8px;height:8px;padding:0}:host([size="s"]) #text{display:none}:host([hidden]:not([hidden=false])) #badge-wrapper{display:none}</style><slot id="slot"></slot><div id="badge-wrapper"><div id="badge"><span id="text"></span></div></div>';
3
- import { assertBadgeColor, assertMode, assertSize, getBadgeColorBg, getBadgeColorFg, modeValues, sizeValues } from './utils';
4
+ import { assertBadgeColor, assertMode, getBadgeColorBg, getBadgeColorFg, modeValues } from './utils';
4
5
  const template = document.createElement('template');
5
6
  template.innerHTML = templateHTML;
6
7
  defineCustomElement('sinch-badge', class extends NectaryElement {
7
8
  #$badgeWrapper;
8
9
  #$badge;
9
10
  #$text;
10
- #isConnected = false;
11
11
  #observer;
12
12
  constructor() {
13
13
  super();
@@ -19,13 +19,13 @@ defineCustomElement('sinch-badge', class extends NectaryElement {
19
19
  this.#observer = new ResizeObserver(this.#onResize);
20
20
  }
21
21
  connectedCallback() {
22
- this.#isConnected = true;
22
+ super.connectedCallback();
23
23
  this.#updateColor();
24
24
  this.#observer.observe(this);
25
25
  }
26
26
  disconnectedCallback() {
27
+ super.disconnectedCallback();
27
28
  this.#observer.unobserve(this);
28
- this.#isConnected = false;
29
29
  }
30
30
  get text() {
31
31
  return getAttribute(this, 'text', '');
@@ -34,7 +34,7 @@ defineCustomElement('sinch-badge', class extends NectaryElement {
34
34
  updateAttribute(this, 'text', value);
35
35
  }
36
36
  get size() {
37
- return getLiteralAttribute(this, sizeValues, 'size', 'm');
37
+ return getLiteralAttribute(this, sizeValues, 'size', DEFAULT_SIZE);
38
38
  }
39
39
  set size(value) {
40
40
  updateLiteralAttribute(this, sizeValues, 'size', value);
@@ -82,7 +82,9 @@ defineCustomElement('sinch-badge', class extends NectaryElement {
82
82
  }
83
83
  case 'size':
84
84
  {
85
- assertSize(newVal);
85
+ if ('production' !== 'production') {
86
+ assertSize(newVal, 'sinch-badge');
87
+ }
86
88
  this.#updatePosition();
87
89
  break;
88
90
  }
@@ -105,7 +107,7 @@ defineCustomElement('sinch-badge', class extends NectaryElement {
105
107
  }
106
108
  }
107
109
  #updateColor() {
108
- if (!this.#isConnected) {
110
+ if (!this.isConnected) {
109
111
  return;
110
112
  }
111
113
  const colorName = this.color;
package/badge/types.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import type { TRect, TSinchElementReact } from '../types';
2
- export declare type TSinchBadgeSize = 'l' | 'm' | 's';
2
+ import type { TSinchSize } from '../utils/size';
3
3
  export declare type TSinchBadgeMode = 'square' | 'circle';
4
4
  export declare type TSinchBadgeElement = HTMLElement & {
5
5
  /** Text */
6
6
  text: string;
7
7
  /** Size */
8
- size: TSinchBadgeSize;
8
+ size: TSinchSize;
9
9
  /** Mode, `square` by default */
10
10
  mode: TSinchBadgeMode;
11
11
  /** Color */
@@ -16,7 +16,7 @@ export declare type TSinchBadgeElement = HTMLElement & {
16
16
  /** Text */
17
17
  setAttribute(name: 'text', value: string): void;
18
18
  /** Size */
19
- setAttribute(name: 'size', value: TSinchBadgeSize): void;
19
+ setAttribute(name: 'size', value: TSinchSize): void;
20
20
  /** Mode, `square` by default */
21
21
  setAttribute(name: 'mode', value: TSinchBadgeMode): void;
22
22
  /** Color */
@@ -28,7 +28,7 @@ export declare type TSinchBadgeReact = TSinchElementReact<TSinchBadgeElement> &
28
28
  /** Text */
29
29
  text: string;
30
30
  /** Size */
31
- size: TSinchBadgeSize;
31
+ size?: TSinchSize;
32
32
  /** Mode, `square` by default */
33
33
  mode?: TSinchBadgeMode;
34
34
  /** Color */
package/badge/utils.d.ts CHANGED
@@ -1,7 +1,4 @@
1
- import type { TSinchBadgeMode, TSinchBadgeSize } from './types';
2
- export declare const sizeValues: readonly TSinchBadgeSize[];
3
- declare type TAssertSize = (value: string | null) => asserts value is TSinchBadgeSize;
4
- export declare const assertSize: TAssertSize;
1
+ import type { TSinchBadgeMode } from './types';
5
2
  export declare const modeValues: readonly TSinchBadgeMode[];
6
3
  declare type TAssertMode = (value: string | null) => asserts value is TSinchBadgeMode;
7
4
  export declare const assertMode: TAssertMode;
package/badge/utils.js CHANGED
@@ -1,9 +1,3 @@
1
- export const sizeValues = ['l', 'm', 's'];
2
- export const assertSize = value => {
3
- if (value === null || !sizeValues.includes(value)) {
4
- throw new Error(`sinch-badge: invalid size attribute: ${value}`);
5
- }
6
- };
7
1
  export const modeValues = ['square', 'circle'];
8
2
  export const assertMode = value => {
9
3
  if (value === null || !modeValues.includes(value)) {
package/button/index.js CHANGED
@@ -1,37 +1,59 @@
1
- import { defineCustomElement, getBooleanAttribute, getAttribute, getLiteralAttribute, isAttrTrue, updateBooleanAttribute, updateAttribute, updateLiteralAttribute, NectaryElement, getReactEventHandler } from '../utils';
2
- const templateHTML = '<style>:host{--sinch-button-color-background:var(--sinch-color-tropical-500);--sinch-button-color-background-hover:var(--sinch-color-tropical-400);--sinch-button-color-background-active:var(--sinch-color-tropical-600);--sinch-button-color-background-disabled:var(--sinch-color-tropical-100);--sinch-button-color-border:var(--sinch-color-transparent);--sinch-button-color-border-disabled:var(--sinch-color-transparent);--sinch-button-color-text:var(--sinch-color-snow-100);--sinch-button-color-text-disabled:var(--sinch-color-snow-100);--sinch-button-shape-radius:var(--sinch-shape-radius-l);display:inline-block;vertical-align:middle;outline:0}#button{--sinch-color-icon:var(--sinch-button-color-text);--sinch-color-spinner-bg:var(--sinch-color-tropical-300);--sinch-color-spinner-fg:var(--sinch-color-snow-100)}#button:disabled{--sinch-color-icon:var(--sinch-button-color-text-disabled);--sinch-color-spinner-bg:var(--sinch-color-snow-100);--sinch-color-spinner-fg:var(--sinch-color-tropical-200)}:host([small]:not([small=false])){--sinch-button-shape-radius:var(--sinch-shape-radius-m)}:host([type=secondary]){--sinch-button-color-background:var(--sinch-color-snow-100);--sinch-button-color-background-hover:var(--sinch-color-tropical-100);--sinch-button-color-background-active:var(--sinch-color-tropical-100);--sinch-button-color-background-disabled:var(--sinch-color-snow-100);--sinch-button-color-border:var(--sinch-color-tropical-500);--sinch-button-color-border-disabled:var(--sinch-color-tropical-200);--sinch-button-color-text:var(--sinch-color-tropical-500);--sinch-button-color-text-disabled:var(--sinch-color-tropical-200)}:host([type=secondary])>#button{--sinch-color-spinner-bg:var(--sinch-color-tropical-500);--sinch-color-spinner-fg:var(--sinch-color-tropical-100)}:host([type=secondary]) #button:enabled:active,:host([type=secondary]) #button:enabled:hover{--sinch-color-spinner-fg:var(--sinch-color-tropical-200)}:host([type=secondary]) #button:disabled{--sinch-color-spinner-bg:var(--sinch-color-tropical-200)}:host([type=cta-primary]){--sinch-button-color-background:var(--sinch-color-honey-500);--sinch-button-color-background-hover:var(--sinch-color-honey-400);--sinch-button-color-background-active:var(--sinch-color-honey-600);--sinch-button-color-background-disabled:var(--sinch-color-honey-200);--sinch-button-color-text:var(--sinch-color-stormy-500);--sinch-button-color-text-disabled:var(--sinch-color-stormy-300)}:host([type=cta-primary])>#button{--sinch-color-spinner-bg:var(--sinch-color-honey-700);--sinch-color-spinner-fg:var(--sinch-color-stormy-500)}:host([type=cta-primary])>#button:disabled{--sinch-color-spinner-bg:var(--sinch-color-honey-100);--sinch-color-spinner-fg:var(--sinch-color-stormy-300)}:host([type=cta-secondary]){--sinch-button-color-background:transparent;--sinch-button-color-background-hover:#F1F3F4;--sinch-button-color-background-active:#E3E6E8;--sinch-button-color-background-disabled:transparent;--sinch-button-color-text:var(--sinch-color-stormy-500);--sinch-button-color-text-disabled:var(--sinch-color-stormy-100);--sinch-button-color-border:var(--sinch-color-stormy-500);--sinch-button-color-border-disabled:var(--sinch-color-stormy-100)}:host([type=cta-secondary])>#button{--sinch-color-spinner-bg:var(--sinch-color-snow-700);--sinch-color-spinner-fg:var(--sinch-color-stormy-500)}:host([type=cta-secondary])>#button:disabled{--sinch-color-spinner-bg:var(--sinch-color-snow-500);--sinch-color-spinner-fg:var(--sinch-color-stormy-100)}:host([type=cta-secondary])>#button::before{mix-blend-mode:multiply}:host([type=destructive]){--sinch-button-color-background:var(--sinch-color-snow-100);--sinch-button-color-background-hover:var(--sinch-color-raspberry-100);--sinch-button-color-background-active:var(--sinch-color-raspberry-100);--sinch-button-color-background-disabled:var(--sinch-color-snow-100);--sinch-button-color-text:var(--sinch-color-raspberry-500);--sinch-button-color-text-disabled:var(--sinch-color-raspberry-200);--sinch-button-color-border:var(--sinch-color-raspberry-500);--sinch-button-color-border-disabled:var(--sinch-color-raspberry-200)}:host([type=destructive])>#button{--sinch-color-spinner-bg:var(--sinch-color-raspberry-100);--sinch-color-spinner-fg:var(--sinch-color-raspberry-500)}:host([type=destructive])>#button:enabled:active,:host([type=destructive])>#button:enabled:hover{--sinch-color-spinner-bg:var(--sinch-color-raspberry-200);--sinch-color-spinner-fg:var(--sinch-color-raspberry-500)}:host([type=destructive])>#button:disabled{--sinch-color-spinner-bg:var(--sinch-color-raspberry-100);--sinch-color-spinner-fg:var(--sinch-color-raspberry-200)}#button{all:initial;display:block;position:relative;width:100%;height:48px;font:var(--sinch-font-title-s);color:var(--sinch-button-color-text);cursor:pointer;--sinch-size-icon:24px}#button::before{content:"";position:absolute;left:0;top:0;bottom:0;right:0;border:1px solid var(--sinch-button-color-border);border-radius:var(--sinch-button-shape-radius);background-color:var(--sinch-button-color-background);box-shadow:var(--sinch-elevation-level-1);pointer-events:none}#button:focus-visible::after{position:absolute;content:"";left:-4px;top:-4px;right:-4px;bottom:-4px;border:2px solid var(--sinch-color-border-focus);border-radius:calc(var(--sinch-button-shape-radius) + 4px);pointer-events:none}@supports not selector(:focus-visible){#button:focus::after{position:absolute;content:"";left:-4px;top:-4px;right:-4px;bottom:-4px;border:2px solid var(--sinch-color-border-focus);border-radius:calc(var(--sinch-button-shape-radius) + 4px);pointer-events:none}}#button:enabled:hover::before{background-color:var(--sinch-button-color-background-hover)}#button:enabled:active::before{background-color:var(--sinch-button-color-background-active);border-width:2px;box-shadow:var(--sinch-elevation-level-0)}#button:disabled{color:var(--sinch-button-color-text-disabled);cursor:initial}#button:disabled::before{background-color:var(--sinch-button-color-background-disabled);border-color:var(--sinch-button-color-border-disabled)}:host([type=cta-primary])>#button::before,:host([type=primary])>#button::before{border-width:0}#content{position:relative;display:flex;align-items:center;justify-content:center;gap:12px;width:100%;height:100%;padding:0 16px;box-sizing:border-box;pointer-events:none}:host([small]:not([small=false]))>#button{font:var(--sinch-font-title-xs);height:32px;--sinch-size-icon:16px}:host([small]:not([small=false])) #content{padding:0 12px;gap:8px}#text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;flex-shrink:1;min-width:0}</style><button id="button"><div id="content"><slot name="left-icon"></slot><span id="text"></span><slot name="right-icon"></slot></div></button>';
3
- import { buttonTypes } from './utils';
1
+ import { defineCustomElement, getBooleanAttribute, getAttribute, isAttrTrue, updateBooleanAttribute, updateAttribute, NectaryElement, getReactEventHandler, getLiteralAttribute, updateLiteralAttribute, Context, subscribeContext } from '../utils';
2
+ import { assertSize, DEFAULT_SIZE, sizeValues } from '../utils/size';
3
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;--sinch-size:var(--sinch-size-m);--sinch-size-icon:var(--sinch-button-icon-size-m);--sinch-shape-radius:var(--sinch-shape-radius-m);--sinch-button-font:var(--sinch-button-font-m)}:host([data-size="l"]){--sinch-size:var(--sinch-size-l);--sinch-size-icon:var(--sinch-button-icon-size-l);--sinch-shape-radius:var(--sinch-shape-radius-l);--sinch-button-font:var(--sinch-button-font-l)}:host([data-size="m"]){--sinch-size:var(--sinch-size-m);--sinch-size-icon:var(--sinch-button-icon-size-m);--sinch-shape-radius:var(--sinch-shape-radius-m);--sinch-button-font:var(--sinch-button-font-m)}:host([data-size="s"]){--sinch-size:var(--sinch-size-s);--sinch-size-icon:var(--sinch-button-icon-size-s);--sinch-shape-radius:var(--sinch-shape-radius-s);--sinch-button-font:var(--sinch-button-font-s)}:host([type=primary]){--sinch-button-color-background:var(--sinch-button-primary-color-background);--sinch-button-color-background-hover:var(--sinch-button-primary-color-background-hover);--sinch-button-color-background-active:var(--sinch-button-primary-color-background-active);--sinch-button-color-background-disabled:var(--sinch-button-primary-color-background-disabled);--sinch-button-color-border:var(--sinch-button-primary-color-border);--sinch-button-color-border-hover:var(--sinch-button-primary-color-border-hover);--sinch-button-color-border-active:var(--sinch-button-primary-color-border-active);--sinch-button-color-border-disabled:var(--sinch-button-primary-color-border-disabled);--sinch-button-color-text:var(--sinch-button-primary-color-text);--sinch-button-color-text-hover:var(--sinch-button-primary-color-text-hover);--sinch-button-color-text-active:var(--sinch-button-primary-color-text-active);--sinch-button-color-text-disabled:var(--sinch-button-primary-color-text-disabled);--sinch-button-color-icon:var(--sinch-button-primary-color-icon);--sinch-button-color-icon-hover:var(--sinch-button-primary-color-icon-hover);--sinch-button-color-icon-active:var(--sinch-button-primary-color-icon-active);--sinch-button-color-icon-disabled:var(--sinch-button-primary-color-icon-disabled);--sinch-button-mix-blend-mode:var(--sinch-button-primary-mix-blend-mode);--sinch-elevation-level:var(--sinch-elevation-level-1)}:host([type=secondary]){--sinch-button-color-background:var(--sinch-button-secondary-color-background);--sinch-button-color-background-hover:var(--sinch-button-secondary-color-background-hover);--sinch-button-color-background-active:var(--sinch-button-secondary-color-background-active);--sinch-button-color-background-disabled:var(--sinch-button-secondary-color-background-disabled);--sinch-button-color-border:var(--sinch-button-secondary-color-border);--sinch-button-color-border-hover:var(--sinch-button-secondary-color-border-hover);--sinch-button-color-border-active:var(--sinch-button-secondary-color-border-active);--sinch-button-color-border-disabled:var(--sinch-button-secondary-color-border-disabled);--sinch-button-color-text:var(--sinch-button-secondary-color-text);--sinch-button-color-text-hover:var(--sinch-button-secondary-color-text-hover);--sinch-button-color-text-active:var(--sinch-button-secondary-color-text-active);--sinch-button-color-text-disabled:var(--sinch-button-secondary-color-text-disabled);--sinch-button-color-icon:var(--sinch-button-secondary-color-icon);--sinch-button-color-icon-hover:var(--sinch-button-secondary-color-icon-hover);--sinch-button-color-icon-active:var(--sinch-button-secondary-color-icon-active);--sinch-button-color-icon-disabled:var(--sinch-button-secondary-color-icon-disabled);--sinch-button-mix-blend-mode:var(--sinch-button-secondary-mix-blend-mode);--sinch-elevation-level:var(--sinch-elevation-level-1)}:host([type=tertiary]){--sinch-button-color-background:var(--sinch-button-tertiary-color-background);--sinch-button-color-background-hover:var(--sinch-button-tertiary-color-background-hover);--sinch-button-color-background-active:var(--sinch-button-tertiary-color-background-active);--sinch-button-color-background-disabled:var(--sinch-button-tertiary-color-background-disabled);--sinch-button-color-border:var(--sinch-button-tertiary-color-border);--sinch-button-color-border-hover:var(--sinch-button-tertiary-color-border-hover);--sinch-button-color-border-active:var(--sinch-button-tertiary-color-border-active);--sinch-button-color-border-disabled:var(--sinch-button-tertiary-color-border-disabled);--sinch-button-color-text:var(--sinch-button-tertiary-color-text);--sinch-button-color-text-hover:var(--sinch-button-tertiary-color-text-hover);--sinch-button-color-text-active:var(--sinch-button-tertiary-color-text-active);--sinch-button-color-text-disabled:var(--sinch-button-tertiary-color-text-disabled);--sinch-button-color-icon:var(--sinch-button-tertiary-color-icon);--sinch-button-color-icon-hover:var(--sinch-button-tertiary-color-icon-hover);--sinch-button-color-icon-active:var(--sinch-button-tertiary-color-icon-active);--sinch-button-color-icon-disabled:var(--sinch-button-tertiary-color-icon-disabled);--sinch-button-mix-blend-mode:var(--sinch-button-tertiary-mix-blend-mode);--sinch-elevation-level:var(--sinch-elevation-level-0)}:host([type=cta-primary]){--sinch-button-color-background:var(--sinch-button-cta-primary-color-background);--sinch-button-color-background-hover:var(--sinch-button-cta-primary-color-background-hover);--sinch-button-color-background-active:var(--sinch-button-cta-primary-color-background-active);--sinch-button-color-background-disabled:var(--sinch-button-cta-primary-color-background-disabled);--sinch-button-color-border:var(--sinch-button-cta-primary-color-border);--sinch-button-color-border-hover:var(--sinch-button-cta-primary-color-border-hover);--sinch-button-color-border-active:var(--sinch-button-cta-primary-color-border-active);--sinch-button-color-border-disabled:var(--sinch-button-cta-primary-color-border-disabled);--sinch-button-color-text:var(--sinch-button-cta-primary-color-text);--sinch-button-color-text-hover:var(--sinch-button-cta-primary-color-text-hover);--sinch-button-color-text-active:var(--sinch-button-cta-primary-color-text-active);--sinch-button-color-text-disabled:var(--sinch-button-cta-primary-color-text-disabled);--sinch-button-color-icon:var(--sinch-button-cta-primary-color-icon);--sinch-button-color-icon-hover:var(--sinch-button-cta-primary-color-icon-hover);--sinch-button-color-icon-active:var(--sinch-button-cta-primary-color-icon-active);--sinch-button-color-icon-disabled:var(--sinch-button-cta-primary-color-icon-disabled);--sinch-button-mix-blend-mode:var(--sinch-button-cta-primary-mix-blend-mode);--sinch-elevation-level:var(--sinch-elevation-level-1)}:host([type=cta-secondary]){--sinch-button-color-background:var(--sinch-button-cta-secondary-color-background);--sinch-button-color-background-hover:var(--sinch-button-cta-secondary-color-background-hover);--sinch-button-color-background-active:var(--sinch-button-cta-secondary-color-background-active);--sinch-button-color-background-disabled:var(--sinch-button-cta-secondary-color-background-disabled);--sinch-button-color-border:var(--sinch-button-cta-secondary-color-border);--sinch-button-color-border-hover:var(--sinch-button-cta-secondary-color-border-hover);--sinch-button-color-border-active:var(--sinch-button-cta-secondary-color-border-active);--sinch-button-color-border-disabled:var(--sinch-button-cta-secondary-color-border-disabled);--sinch-button-color-text:var(--sinch-button-cta-secondary-color-text);--sinch-button-color-text-hover:var(--sinch-button-cta-secondary-color-text-hover);--sinch-button-color-text-active:var(--sinch-button-cta-secondary-color-text-active);--sinch-button-color-text-disabled:var(--sinch-button-cta-secondary-color-text-disabled);--sinch-button-color-icon:var(--sinch-button-cta-secondary-color-icon);--sinch-button-color-icon-hover:var(--sinch-button-cta-secondary-color-icon-hover);--sinch-button-color-icon-active:var(--sinch-button-cta-secondary-color-icon-active);--sinch-button-color-icon-disabled:var(--sinch-button-cta-secondary-color-icon-disabled);--sinch-button-mix-blend-mode:var(--sinch-button-cta-secondary-mix-blend-mode);--sinch-elevation-level:var(--sinch-elevation-level-1)}:host([type=destructive]){--sinch-button-color-background:var(--sinch-button-destructive-color-background);--sinch-button-color-background-hover:var(--sinch-button-destructive-color-background-hover);--sinch-button-color-background-active:var(--sinch-button-destructive-color-background-active);--sinch-button-color-background-disabled:var(--sinch-button-destructive-color-background-disabled);--sinch-button-color-border:var(--sinch-button-destructive-color-border);--sinch-button-color-border-hover:var(--sinch-button-destructive-color-border-hover);--sinch-button-color-border-active:var(--sinch-button-destructive-color-border-active);--sinch-button-color-border-disabled:var(--sinch-button-destructive-color-border-disabled);--sinch-button-color-text:var(--sinch-button-destructive-color-text);--sinch-button-color-text-hover:var(--sinch-button-destructive-color-text-hover);--sinch-button-color-text-active:var(--sinch-button-destructive-color-text-active);--sinch-button-color-text-disabled:var(--sinch-button-destructive-color-text-disabled);--sinch-button-color-icon:var(--sinch-button-destructive-color-icon);--sinch-button-color-icon-hover:var(--sinch-button-destructive-color-icon-hover);--sinch-button-color-icon-active:var(--sinch-button-destructive-color-icon-active);--sinch-button-color-icon-disabled:var(--sinch-button-destructive-color-icon-disabled);--sinch-button-mix-blend-mode:var(--sinch-button-destructive-mix-blend-mode);--sinch-elevation-level:var(--sinch-elevation-level-1)}#button{all:initial;display:block;position:relative;width:100%;height:var(--sinch-size);font:var(--sinch-button-font);color:var(--sinch-button-color-text);cursor:pointer;--sinch-color-icon:var(--sinch-button-color-icon)}#button::before{content:"";position:absolute;inset:0;background-color:var(--sinch-button-color-background);border:1px solid var(--sinch-button-color-border);border-radius:var(--sinch-shape-radius);box-shadow:var(--sinch-elevation-level);pointer-events:none;mix-blend-mode:var(--sinch-button-mix-blend-mode)}#button:focus-visible::after{position:absolute;content:"";inset:-3px;border:2px solid var(--sinch-color-border-focus);border-radius:calc(var(--sinch-shape-radius) + 3px);pointer-events:none}#button:disabled{color:var(--sinch-button-color-text-disabled);cursor:initial;--sinch-color-icon:var(--sinch-button-color-icon-disabled)}#button:disabled::before{background-color:var(--sinch-button-color-background-disabled);border-color:var(--sinch-button-color-border-disabled);box-shadow:var(--sinch-elevation-level-0)}#button:enabled:hover{--sinch-color-icon:var(--sinch-button-color-icon-hover)}#button:enabled:hover::before{background-color:var(--sinch-button-color-background-hover);border-color:var(--sinch-button-color-border-hover)}#button:enabled:active{--sinch-color-icon:var(--sinch-button-color-icon-active)}#button:enabled:active::before{background-color:var(--sinch-button-color-background-active);border-color:var(--sinch-button-color-border-active);border-width:2px;box-shadow:var(--sinch-elevation-level-0)}#content{position:relative;display:flex;align-items:center;justify-content:center;gap:.75em;width:100%;height:100%;padding:0 1em;box-sizing:border-box;pointer-events:none}#text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;flex-shrink:1;min-width:0}</style><button id="button"><div id="content"><slot name="left-icon"></slot><span id="text"></span><slot name="right-icon"></slot></div></button>';
4
+ import { assertType, typeValues } from './utils';
4
5
  const template = document.createElement('template');
5
6
  template.innerHTML = templateHTML;
6
7
  defineCustomElement('sinch-button', class extends NectaryElement {
7
8
  #$button;
8
9
  #$text;
10
+ #controller = null;
11
+ #sizeContext;
9
12
  constructor() {
10
13
  super();
11
- const shadowRoot = this.attachShadow();
14
+ const shadowRoot = this.attachShadow({
15
+ delegatesFocus: true
16
+ });
12
17
  shadowRoot.appendChild(template.content.cloneNode(true));
13
18
  this.#$button = shadowRoot.querySelector('#button');
14
19
  this.#$text = shadowRoot.querySelector('#text');
20
+ this.#sizeContext = new Context(this.#$button, 'size');
15
21
  }
16
22
  connectedCallback() {
23
+ super.connectedCallback();
24
+ this.#controller = new AbortController();
25
+ const {
26
+ signal
27
+ } = this.#controller;
17
28
  this.setAttribute('role', 'button');
18
- this.#$button.addEventListener('click', this.#onButtonClick);
19
- this.#$button.addEventListener('focus', this.#onButtonFocus);
20
- this.#$button.addEventListener('blur', this.#onButtonBlur);
21
- this.addEventListener('-click', this.#onClickReactHandler);
22
- this.addEventListener('-focus', this.#onFocusReactHandler);
23
- this.addEventListener('-blur', this.#onBlurReactHandler);
29
+ this.#$button.addEventListener('click', this.#onButtonClick, {
30
+ signal
31
+ });
32
+ this.#$button.addEventListener('focus', this.#onButtonFocus, {
33
+ signal
34
+ });
35
+ this.#$button.addEventListener('blur', this.#onButtonBlur, {
36
+ signal
37
+ });
38
+ this.addEventListener('-click', this.#onClickReactHandler, {
39
+ signal
40
+ });
41
+ this.addEventListener('-focus', this.#onFocusReactHandler, {
42
+ signal
43
+ });
44
+ this.addEventListener('-blur', this.#onBlurReactHandler, {
45
+ signal
46
+ });
47
+ subscribeContext(this, 'size', this.#onContextSize, signal);
48
+ this.#sizeContext.listen(signal);
49
+ this.#onSizeUpdate();
24
50
  }
25
51
  disconnectedCallback() {
26
- this.#$button.removeEventListener('click', this.#onButtonClick);
27
- this.#$button.removeEventListener('focus', this.#onButtonFocus);
28
- this.#$button.removeEventListener('blur', this.#onButtonBlur);
29
- this.removeEventListener('-click', this.#onClickReactHandler);
30
- this.removeEventListener('-focus', this.#onFocusReactHandler);
31
- this.removeEventListener('-blur', this.#onBlurReactHandler);
52
+ super.disconnectedCallback();
53
+ this.#controller.abort();
32
54
  }
33
55
  static get observedAttributes() {
34
- return ['text', 'disabled'];
56
+ return ['text', 'disabled', 'size', 'type', 'data-size'];
35
57
  }
36
58
  attributeChangedCallback(name, _, newVal) {
37
59
  switch (name) {
@@ -47,13 +69,33 @@ defineCustomElement('sinch-button', class extends NectaryElement {
47
69
  updateBooleanAttribute(this, 'disabled', isDisabled);
48
70
  break;
49
71
  }
72
+ case 'type':
73
+ {
74
+ if ('production' !== 'production') {
75
+ assertType(newVal);
76
+ }
77
+ break;
78
+ }
79
+ case 'size':
80
+ {
81
+ updateAttribute(this, 'data-size', newVal);
82
+ break;
83
+ }
84
+ case 'data-size':
85
+ {
86
+ if ('production' !== 'production') {
87
+ assertSize(newVal, 'sinch-button');
88
+ }
89
+ this.#onSizeUpdate();
90
+ break;
91
+ }
50
92
  }
51
93
  }
52
94
  set type(value) {
53
- updateLiteralAttribute(this, buttonTypes, 'type', value);
95
+ updateLiteralAttribute(this, typeValues, 'type', value);
54
96
  }
55
97
  get type() {
56
- return getLiteralAttribute(this, buttonTypes, 'type', 'primary');
98
+ return getLiteralAttribute(this, typeValues, 'type', 'primary');
57
99
  }
58
100
  set text(value) {
59
101
  updateAttribute(this, 'text', value);
@@ -67,11 +109,11 @@ defineCustomElement('sinch-button', class extends NectaryElement {
67
109
  get disabled() {
68
110
  return getBooleanAttribute(this, 'disabled');
69
111
  }
70
- set small(isSmall) {
71
- updateBooleanAttribute(this, 'small', isSmall);
112
+ set size(size) {
113
+ updateLiteralAttribute(this, sizeValues, 'size', size);
72
114
  }
73
- get small() {
74
- return getBooleanAttribute(this, 'small');
115
+ get size() {
116
+ return getLiteralAttribute(this, sizeValues, 'size', DEFAULT_SIZE);
75
117
  }
76
118
  get focusable() {
77
119
  return true;
@@ -82,6 +124,29 @@ defineCustomElement('sinch-button', class extends NectaryElement {
82
124
  blur() {
83
125
  this.#$button.blur();
84
126
  }
127
+ #onSizeUpdate() {
128
+ if (!this.isConnected) {
129
+ return;
130
+ }
131
+ const size = getAttribute(this, 'data-size', DEFAULT_SIZE);
132
+ this.#sizeContext.dispatch(size);
133
+ }
134
+ #onContextSize = e => {
135
+ if (this.hasAttribute('size')) {
136
+ return;
137
+ }
138
+ switch (e.detail) {
139
+ case 'l':
140
+ {
141
+ this.setAttribute('data-size', 'm');
142
+ break;
143
+ }
144
+ default:
145
+ {
146
+ this.setAttribute('data-size', 's');
147
+ }
148
+ }
149
+ };
85
150
  #onButtonClick = () => {
86
151
  this.dispatchEvent(new CustomEvent('-click'));
87
152
  };
package/button/types.d.ts CHANGED
@@ -1,40 +1,41 @@
1
1
  import type { TSinchElementReact } from '../types';
2
- export declare type TSinchButtonType = 'primary' | 'secondary' | 'cta-primary' | 'cta-secondary' | 'destructive';
2
+ import type { TSinchSize } from '../utils/size';
3
+ export declare type TSinchButtonType = 'primary' | 'secondary' | 'tertiary' | 'cta-primary' | 'cta-secondary' | 'destructive';
3
4
  export declare type TSinchButtonElement = HTMLElement & {
4
- /** Type */
5
+ /** Type, `primary` by default */
5
6
  type: TSinchButtonType;
7
+ /** Size, `m` by default */
8
+ size: TSinchSize;
6
9
  /** Text content */
7
10
  text: string;
8
11
  /** Disabled */
9
12
  disabled: boolean;
10
- /** Small */
11
- small: boolean;
12
13
  /** Click event */
13
14
  addEventListener(type: '-click', listener: (e: CustomEvent<void>) => void): void;
14
15
  /** Focus event */
15
16
  addEventListener(type: '-focus', listener: (e: CustomEvent<void>) => void): void;
16
17
  /** Blur event */
17
18
  addEventListener(type: '-blur', listener: (e: CustomEvent<void>) => void): void;
18
- /** Type */
19
+ /** Type, `primary` by default */
19
20
  setAttribute(attr: 'type', value: TSinchButtonType): void;
21
+ /** Size, `m` by default */
22
+ setAttribute(attr: 'size', value: TSinchSize): void;
20
23
  /** Text content */
21
24
  setAttribute(attr: 'text', value: string): void;
22
25
  /** Disabled */
23
26
  setAttribute(attr: 'disabled', value: ''): void;
24
- /** Small */
25
- setAttribute(attr: 'small', value: ''): void;
26
27
  };
27
28
  export declare type TSinchButtonReact = TSinchElementReact<TSinchButtonElement> & {
28
- /** Type */
29
- type: TSinchButtonType;
29
+ /** Type, `primary` by default */
30
+ type?: TSinchButtonType;
31
+ /** Size, `m` by default */
32
+ size?: TSinchSize;
30
33
  /** Text content */
31
34
  text: string;
32
35
  /** Label that is used for a11y */
33
36
  'aria-label': string;
34
37
  /** Disabled */
35
38
  disabled?: boolean;
36
- /** Small */
37
- small?: boolean;
38
39
  /** Click event handler */
39
40
  'on-click'?: (e: CustomEvent<void>) => void;
40
41
  /** Focus event handler */
package/button/utils.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  import type { TSinchButtonType } from './types';
2
- export declare const buttonTypes: readonly TSinchButtonType[];
2
+ export declare const typeValues: readonly TSinchButtonType[];
3
+ declare type TAssertType = (value: string | null) => asserts value is TSinchButtonType;
4
+ export declare const assertType: TAssertType;
5
+ export {};
package/button/utils.js CHANGED
@@ -1 +1,9 @@
1
- export const buttonTypes = ['primary', 'secondary', 'cta-primary', 'cta-secondary', 'destructive'];
1
+ export const typeValues = ['primary', 'secondary', 'tertiary', 'cta-primary', 'cta-secondary', 'destructive'];
2
+ export const assertType = value => {
3
+ if (value === null || value.length === 0) {
4
+ return;
5
+ }
6
+ if (!typeValues.includes(value)) {
7
+ throw new Error(`sinch-button: invalid type attribute: ${value}`);
8
+ }
9
+ };
@@ -1,5 +1,5 @@
1
1
  import { defineCustomElement, NectaryElement } from '../utils';
2
- const templateHTML = '<style>:host{display:block}#wrapper{height:100%;padding:20px 0;box-sizing:border-box;background-color:var(--sinch-color-snow-100);border-radius:var(--sinch-shape-radius-l);border:1px solid var(--sinch-color-snow-700);font:var(--sinch-font-body)}#scroll{overflow:auto;height:100%;box-sizing:border-box;padding:4px 24px}</style><div id="wrapper"><div id="scroll"><slot></slot></div></div>';
2
+ const templateHTML = '<style>:host{display:block}#wrapper{height:100%;padding:20px 0;box-sizing:border-box;background-color:var(--sinch-color-snow-100);border-radius:var(--sinch-shape-radius-l);border:1px solid var(--sinch-color-snow-700);font:var(--sinch-font-text-m)}#scroll{overflow:auto;height:100%;box-sizing:border-box;padding:4px 24px}</style><div id="wrapper"><div id="scroll"><slot></slot></div></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-card-container', class extends NectaryElement {
@@ -1,6 +1,6 @@
1
1
  import { typeValues } from '../chat-bubble/utils';
2
2
  import { defineCustomElement, getAttribute, getLiteralAttribute, NectaryElement, updateAttribute, updateLiteralAttribute } from '../utils';
3
- const templateHTML = '<style>:host{display:block;outline:0}#wrapper{position:relative;display:flex;flex-direction:column;gap:4px;align-items:flex-end;padding-left:72px}#stamp{display:flex;gap:4px;margin:0;font:var(--sinch-font-extra-small-text);color:var(--sinch-color-stormy-400)}#avatar{display:none;position:absolute;left:0;top:24px}:host([type=customer])>#wrapper{align-items:flex-start}:host([type=customer]) #avatar{display:block}</style><div id="wrapper"><div id="avatar"><slot name="avatar"></slot></div><p id="stamp"><span id="firstname"></span><span id="lastname"></span>&bull;<span id="time"></span></p><slot name="bubble"></slot></div>';
3
+ const templateHTML = '<style>:host{display:block;outline:0}#wrapper{position:relative;display:flex;flex-direction:column;gap:4px;align-items:flex-end;padding-left:72px}#stamp{display:flex;gap:4px;margin:0;font:var(--sinch-font-text-xs);color:var(--sinch-color-stormy-400)}#avatar{display:none;position:absolute;left:0;top:24px}:host([type=customer])>#wrapper{align-items:flex-start}:host([type=customer]) #avatar{display:block}</style><div id="wrapper"><div id="avatar"><slot name="avatar"></slot></div><p id="stamp"><span id="firstname"></span><span id="lastname"></span>&bull;<span id="time"></span></p><slot name="bubble"></slot></div>';
4
4
  const template = document.createElement('template');
5
5
  template.innerHTML = templateHTML;
6
6
  defineCustomElement('sinch-chat-block', class extends NectaryElement {
@@ -3,7 +3,7 @@ import '../icons/check';
3
3
  import '../icons/done-all';
4
4
  import '../icons/error-outline';
5
5
  import { defineCustomElement, getAttribute, getLiteralAttribute, NectaryElement, updateAttribute, updateLiteralAttribute } from '../utils';
6
- const templateHTML = '<style>:host{display:block;outline:0}#wrapper{position:relative;padding:12px 16px;border-radius:16px;max-width:595px;box-sizing:border-box}:host([data-type=customer])>#wrapper{background-color:var(--sinch-color-snow-500);border-top-left-radius:0}:host([data-type=agent-prev])>#wrapper{background-color:var(--sinch-color-snow-700);border-top-right-radius:0}:host([data-type=agent])>#wrapper{background-color:var(--sinch-color-honey-200);border-top-right-radius:0}#text{font:var(--sinch-font-body);color:var(--sinch-color-stormy-500)}sinch-icon-check,sinch-icon-done-all,sinch-icon-error-outline,sinch-icon-query-builder{display:none;position:absolute;right:16px;bottom:12px;--sinch-size-icon:16px;--sinch-color-icon:var(--sinch-color-stormy-500)}:host([status=sending]) sinch-icon-query-builder{display:block}:host([status=sent]) sinch-icon-check{display:block}:host([status=received]) sinch-icon-done-all{display:block}:host([status=seen]) sinch-icon-done-all{display:block;--sinch-color-icon:var(--sinch-color-success-500)}:host([status=error]) sinch-icon-error-outline{display:block;--sinch-color-icon:var(--sinch-color-error-500)}:host([status]:not([status=""])) #wrapper{padding-right:42px}</style><div id="wrapper"><span id="text"></span><sinch-icon-query-builder></sinch-icon-query-builder><sinch-icon-check></sinch-icon-check><sinch-icon-done-all></sinch-icon-done-all><sinch-icon-error-outline></sinch-icon-error-outline></div>';
6
+ const templateHTML = '<style>:host{display:block;outline:0}#wrapper{position:relative;padding:12px 16px;border-radius:16px;max-width:595px;box-sizing:border-box}:host([data-type=customer])>#wrapper{background-color:var(--sinch-color-snow-500);border-top-left-radius:0}:host([data-type=agent-prev])>#wrapper{background-color:var(--sinch-color-snow-700);border-top-right-radius:0}:host([data-type=agent])>#wrapper{background-color:var(--sinch-color-honey-200);border-top-right-radius:0}#text{font:var(--sinch-font-text-m);color:var(--sinch-color-stormy-500)}sinch-icon-check,sinch-icon-done-all,sinch-icon-error-outline,sinch-icon-query-builder{display:none;position:absolute;right:16px;bottom:12px;--sinch-size-icon:16px;--sinch-color-icon:var(--sinch-color-stormy-500)}:host([status=sending]) sinch-icon-query-builder{display:block}:host([status=sent]) sinch-icon-check{display:block}:host([status=received]) sinch-icon-done-all{display:block}:host([status=seen]) sinch-icon-done-all{display:block;--sinch-color-icon:var(--sinch-color-success-500)}:host([status=error]) sinch-icon-error-outline{display:block;--sinch-color-icon:var(--sinch-color-error-500)}:host([status]:not([status=""])) #wrapper{padding-right:42px}</style><div id="wrapper"><span id="text"></span><sinch-icon-query-builder></sinch-icon-query-builder><sinch-icon-check></sinch-icon-check><sinch-icon-done-all></sinch-icon-done-all><sinch-icon-error-outline></sinch-icon-error-outline></div>';
7
7
  import { statusValues, typeValues } from './utils';
8
8
  const template = document.createElement('template');
9
9
  template.innerHTML = templateHTML;