@nectary/components 1.4.0 → 2.1.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 (209) hide show
  1. package/accordion/index.js +0 -3
  2. package/accordion/types.d.ts +0 -3
  3. package/accordion-item/index.d.ts +2 -0
  4. package/accordion-item/index.js +33 -34
  5. package/action-menu/index.js +5 -1
  6. package/action-menu-option/index.js +2 -2
  7. package/alert/index.js +4 -21
  8. package/alert/utils.d.ts +0 -3
  9. package/alert/utils.js +1 -6
  10. package/avatar/index.js +5 -21
  11. package/avatar/utils.d.ts +0 -4
  12. package/avatar/utils.js +2 -15
  13. package/badge/index.js +36 -68
  14. package/badge/types.d.ts +0 -4
  15. package/badge/utils.d.ts +0 -6
  16. package/badge/utils.js +1 -17
  17. package/button/index.js +25 -27
  18. package/button/types.d.ts +2 -2
  19. package/button/utils.d.ts +0 -3
  20. package/button/utils.js +1 -9
  21. package/card/index.js +5 -16
  22. package/card/types.d.ts +0 -6
  23. package/card-container/index.js +1 -1
  24. package/chat-block/index.js +1 -1
  25. package/chat-bubble/index.d.ts +0 -1
  26. package/chat-bubble/index.js +3 -25
  27. package/checkbox/index.js +32 -33
  28. package/checkbox/types.d.ts +0 -3
  29. package/chip/index.js +54 -44
  30. package/chip/utils.d.ts +0 -1
  31. package/chip/utils.js +2 -7
  32. package/code-tag/index.js +1 -1
  33. package/color-menu/index.d.ts +0 -3
  34. package/color-menu/index.js +55 -101
  35. package/color-menu/types.d.ts +0 -4
  36. package/color-menu-option/index.d.ts +14 -0
  37. package/color-menu-option/index.js +52 -0
  38. package/color-menu-option/types.d.ts +9 -0
  39. package/color-menu-option/utils.d.ts +1 -0
  40. package/color-menu-option/utils.js +11 -0
  41. package/color-swatch/index.js +2 -5
  42. package/color-swatch/utils.d.ts +0 -1
  43. package/color-swatch/utils.js +2 -7
  44. package/date-picker/index.js +3 -40
  45. package/date-picker/types.d.ts +0 -3
  46. package/date-picker/utils.d.ts +0 -8
  47. package/date-picker/utils.js +0 -20
  48. package/dialog/index.js +2 -6
  49. package/dialog/types.d.ts +0 -2
  50. package/emoji/index.js +1 -1
  51. package/emoji-picker/index.d.ts +1 -0
  52. package/emoji-picker/index.js +36 -34
  53. package/field/index.js +39 -32
  54. package/file-drop/index.js +1 -1
  55. package/file-status/index.js +4 -25
  56. package/file-status/utils.d.ts +0 -3
  57. package/file-status/utils.js +1 -6
  58. package/flag/index.js +1 -1
  59. package/grid/index.js +1 -1
  60. package/help-tooltip/index.d.ts +0 -1
  61. package/help-tooltip/index.js +3 -13
  62. package/horizontal-stepper/index.js +1 -1
  63. package/horizontal-stepper-item/index.d.ts +2 -0
  64. package/horizontal-stepper-item/index.js +8 -12
  65. package/icon/index.js +1 -1
  66. package/icon-button/index.js +23 -27
  67. package/icon-button/utils.d.ts +0 -3
  68. package/icon-button/utils.js +1 -9
  69. package/inline-alert/index.js +20 -37
  70. package/inline-alert/utils.d.ts +0 -3
  71. package/inline-alert/utils.js +1 -6
  72. package/input/index.d.ts +0 -3
  73. package/input/index.js +22 -58
  74. package/input/types.d.ts +1 -5
  75. package/input/utils.d.ts +0 -3
  76. package/input/utils.js +1 -6
  77. package/link/index.js +35 -37
  78. package/list-item/index.js +1 -1
  79. package/package.json +11 -11
  80. package/pagination/index.js +8 -21
  81. package/pagination/types.d.ts +0 -3
  82. package/pop/index.js +39 -38
  83. package/pop/utils.d.ts +0 -3
  84. package/pop/utils.js +0 -5
  85. package/popover/index.js +42 -51
  86. package/popover/utils.d.ts +0 -3
  87. package/popover/utils.js +0 -5
  88. package/progress/index.js +20 -15
  89. package/radio/index.js +19 -6
  90. package/radio/types.d.ts +3 -3
  91. package/radio-option/index.js +35 -27
  92. package/rich-text/index.js +3 -10
  93. package/rich-text/utils.d.ts +0 -3
  94. package/rich-text/utils.js +1 -6
  95. package/segment/index.js +3 -7
  96. package/segment-collapse/index.js +2 -11
  97. package/segment-collapse/types.d.ts +0 -3
  98. package/segmented-control/index.js +0 -3
  99. package/segmented-control/types.d.ts +0 -3
  100. package/segmented-control-option/index.js +20 -19
  101. package/segmented-icon-control/index.js +1 -4
  102. package/segmented-icon-control/types.d.ts +0 -3
  103. package/segmented-icon-control-option/index.js +18 -14
  104. package/select-button/index.js +29 -31
  105. package/select-menu/index.js +18 -8
  106. package/select-menu-option/index.js +2 -5
  107. package/skeleton/index.js +1 -1
  108. package/skeleton-item/index.js +1 -1
  109. package/spinner/index.js +3 -10
  110. package/table/index.js +1 -1
  111. package/table-body/index.js +1 -1
  112. package/table-cell/index.js +1 -1
  113. package/table-head-cell/index.d.ts +1 -0
  114. package/table-head-cell/index.js +12 -3
  115. package/table-row/index.js +18 -2
  116. package/tabs/index.js +1 -4
  117. package/tabs/types.d.ts +0 -3
  118. package/tabs-icon-option/index.js +4 -2
  119. package/tabs-option/index.js +25 -20
  120. package/tag/index.js +17 -12
  121. package/tag/utils.d.ts +0 -1
  122. package/tag/utils.js +2 -7
  123. package/text/index.js +24 -21
  124. package/text/utils.d.ts +0 -3
  125. package/text/utils.js +1 -6
  126. package/textarea/index.js +10 -6
  127. package/textarea/types.d.ts +0 -3
  128. package/tile-control/index.js +23 -25
  129. package/tile-control/types.d.ts +0 -3
  130. package/tile-control-option/index.js +1 -1
  131. package/time-picker/index.js +2 -11
  132. package/time-picker/types.d.ts +0 -3
  133. package/time-picker/utils.d.ts +1 -1
  134. package/time-picker/utils.js +17 -5
  135. package/title/index.js +28 -30
  136. package/title/utils.d.ts +0 -7
  137. package/title/utils.js +1 -29
  138. package/toast/index.js +22 -39
  139. package/toast/utils.d.ts +0 -3
  140. package/toast/utils.js +1 -6
  141. package/toggle/index.js +33 -30
  142. package/toggle/types.d.ts +0 -3
  143. package/tooltip/index.js +3 -15
  144. package/tooltip/types.d.ts +0 -12
  145. package/tooltip/utils.d.ts +0 -5
  146. package/tooltip/utils.js +0 -10
  147. package/utils/dom.js +0 -5
  148. package/utils/element.js +2 -2
  149. package/utils/size.d.ts +0 -5
  150. package/utils/size.js +1 -17
  151. package/vertical-stepper/index.js +1 -1
  152. package/vertical-stepper-item/index.d.ts +2 -0
  153. package/vertical-stepper-item/index.js +8 -12
  154. package/logo/create-logo-class.d.ts +0 -1
  155. package/logo/create-logo-class.js +0 -52
  156. package/logo/engage-icon/index.d.ts +0 -11
  157. package/logo/engage-icon/index.js +0 -4
  158. package/logo/engage-icon-wordmark/index.d.ts +0 -11
  159. package/logo/engage-icon-wordmark/index.js +0 -4
  160. package/logo/sinch-icon/index.d.ts +0 -11
  161. package/logo/sinch-icon/index.js +0 -4
  162. package/logo/sinch-icon-wordmark/index.d.ts +0 -11
  163. package/logo/sinch-icon-wordmark/index.js +0 -4
  164. package/logo/types.d.ts +0 -11
  165. package/theme/accordion-item.css +0 -4
  166. package/theme/alert.css +0 -6
  167. package/theme/avatar.css +0 -25
  168. package/theme/badge.css +0 -15
  169. package/theme/button.css +0 -146
  170. package/theme/chat.css +0 -9
  171. package/theme/chip.css +0 -68
  172. package/theme/color-menu.css +0 -4
  173. package/theme/color-swatch.css +0 -71
  174. package/theme/colors.d.ts +0 -4
  175. package/theme/colors.js +0 -4
  176. package/theme/contextual.css +0 -40
  177. package/theme/date-picker.css +0 -7
  178. package/theme/dialog.css +0 -4
  179. package/theme/elevation.css +0 -7
  180. package/theme/emoji-picker.css +0 -13
  181. package/theme/emoji.css +0 -5
  182. package/theme/file-status.css +0 -7
  183. package/theme/flag.css +0 -4
  184. package/theme/fonts.css +0 -86
  185. package/theme/fonts.json +0 -89
  186. package/theme/help-tooltip.css +0 -5
  187. package/theme/horizontal-stepper.css +0 -5
  188. package/theme/icon-button.css +0 -68
  189. package/theme/icon.css +0 -7
  190. package/theme/index.css +0 -4
  191. package/theme/index.d.ts +0 -39
  192. package/theme/index.js +0 -39
  193. package/theme/inline-alert.css +0 -7
  194. package/theme/input.css +0 -10
  195. package/theme/link.css +0 -5
  196. package/theme/pagination.css +0 -5
  197. package/theme/palette.css +0 -90
  198. package/theme/segment.css +0 -4
  199. package/theme/select-button.css +0 -10
  200. package/theme/select-menu.css +0 -6
  201. package/theme/shapes.css +0 -8
  202. package/theme/size.css +0 -9
  203. package/theme/spinner.css +0 -7
  204. package/theme/tag.css +0 -67
  205. package/theme/time-picker.css +0 -4
  206. package/theme/toast.css +0 -7
  207. package/theme/typography.css +0 -16
  208. package/theme/vertical-stepper.css +0 -5
  209. /package/{logo → color-menu-option}/types.js +0 -0
package/chip/index.js CHANGED
@@ -1,22 +1,22 @@
1
1
  import '../text';
2
2
  import '../icon';
3
- import { defineCustomElement, getBooleanAttribute, getAttribute, updateBooleanAttribute, updateAttribute, NectaryElement, getReactEventHandler, getCssVar } from '../utils';
4
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:row;align-items:center;gap:4px;width:100%;height:24px;padding:0 5px 0 9px;border-radius:12px;background-color:var(--sinch-chip-color-default-bg);color:var(--sinch-chip-color-default-fg);box-sizing:border-box;cursor:pointer;--sinch-color-icon:var(--sinch-chip-color-default-fg);--sinch-size-icon:16px}#button:focus-visible::after{content:"";position:absolute;inset:-4px;border-radius:16px;border:2px solid var(--sinch-color-border-focus);pointer-events:none}#text{flex:1}:host([small]:not([small=false])) #button{height:20px;border-radius:10px;padding:0 3px 0 7px}:host([small]:not([small=false])) #button:focus-visible::after{border-radius:14px}::slotted(*){margin-left:-4px}</style><button id="button"><slot name="icon"></slot><sinch-text id="text" type="xs" ellipsis></sinch-text><sinch-icon id="icon-close"></sinch-icon></button>';
5
- import { assertChipColor, getChipColorBg, getChipColorFg } from './utils';
3
+ import { defineCustomElement, getBooleanAttribute, getAttribute, updateBooleanAttribute, updateAttribute, NectaryElement, getReactEventHandler, isAttrTrue } from '../utils';
4
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:row;align-items:center;gap:4px;width:100%;height:var(--sinch-comp-chip-size-container-m);padding:0 5px 0 9px;border-radius:var(--sinch-comp-chip-shape-radius);background-color:var(--sinch-comp-chip-color-neutral-default-background-initial);box-sizing:border-box;cursor:pointer;--sinch-global-color-text:var(--sinch-comp-chip-color-neutral-default-foreground-initial);--sinch-global-color-icon:var(--sinch-comp-chip-color-neutral-default-foreground-initial);--sinch-global-size-icon:var(--sinch-comp-chip-size-icon-m)}:host(:focus-visible)>#button::after{content:"";position:absolute;inset:-4px;border-radius:calc(var(--sinch-comp-chip-shape-radius) + 4px);border:2px solid var(--sinch-comp-chip-color-outiline-focus);pointer-events:none}#text{flex:1;--sinch-comp-text-font:var(--sinch-comp-chip-font-size-m-label)}:host([small]) #button{height:var(--sinch-comp-chip-size-container-s);padding:0 3px 0 7px;--sinch-global-size-icon:var(--sinch-comp-chip-size-icon-s)}:host([small]) #text{--sinch-comp-text-font:var(--sinch-comp-chip-font-size-s-label)}::slotted(*){margin-left:-4px}</style><div id="button" inert><slot name="icon"></slot><sinch-text id="text" type="xs" ellipsis></sinch-text><sinch-icon id="icon-close" name="cancel"></sinch-icon></div>';
5
+ import { getChipColorBg, getChipColorFg } from './utils';
6
6
  const template = document.createElement('template');
7
7
  template.innerHTML = templateHTML;
8
8
  defineCustomElement('sinch-chip', class extends NectaryElement {
9
9
  #$text;
10
10
  #$button;
11
- #$iconClose;
12
11
  #controller = null;
13
12
  constructor() {
14
13
  super();
15
- const shadowRoot = this.attachShadow();
14
+ const shadowRoot = this.attachShadow({
15
+ delegatesFocus: false
16
+ });
16
17
  shadowRoot.appendChild(template.content.cloneNode(true));
17
18
  this.#$button = shadowRoot.querySelector('#button');
18
19
  this.#$text = shadowRoot.querySelector('#text');
19
- this.#$iconClose = shadowRoot.querySelector('#icon-close');
20
20
  }
21
21
  connectedCallback() {
22
22
  super.connectedCallback();
@@ -24,14 +24,18 @@ defineCustomElement('sinch-chip', class extends NectaryElement {
24
24
  const {
25
25
  signal
26
26
  } = this.#controller;
27
- this.setAttribute('role', 'button');
28
- this.#$button.addEventListener('click', this.#onButtonClick, {
27
+ this.role = 'button';
28
+ this.tabIndex = 0;
29
+ this.addEventListener('click', this.#onClick, {
30
+ signal
31
+ });
32
+ this.addEventListener('focus', this.#onFocus, {
29
33
  signal
30
34
  });
31
- this.#$button.addEventListener('focus', this.#onButtonFocus, {
35
+ this.addEventListener('blur', this.#onBlur, {
32
36
  signal
33
37
  });
34
- this.#$button.addEventListener('blur', this.#onButtonBlur, {
38
+ this.addEventListener('keydown', this.#onKeydown, {
35
39
  signal
36
40
  });
37
41
  this.addEventListener('-click', this.#onClickReactHandler, {
@@ -43,13 +47,37 @@ defineCustomElement('sinch-chip', class extends NectaryElement {
43
47
  this.addEventListener('-blur', this.#onBlurReactHandler, {
44
48
  signal
45
49
  });
46
- updateAttribute(this.#$iconClose, 'name', getCssVar(this, '--sinch-chip-icon-close'));
47
50
  this.#updateColor();
48
51
  }
49
52
  disconnectedCallback() {
50
53
  super.disconnectedCallback();
51
54
  this.#controller.abort();
52
55
  }
56
+ static get observedAttributes() {
57
+ return ['text', 'color', 'small'];
58
+ }
59
+ attributeChangedCallback(name, oldVal, newVal) {
60
+ if (oldVal === newVal) {
61
+ return;
62
+ }
63
+ switch (name) {
64
+ case 'color':
65
+ {
66
+ this.#updateColor();
67
+ break;
68
+ }
69
+ case 'text':
70
+ {
71
+ this.#$text.textContent = newVal;
72
+ break;
73
+ }
74
+ case 'small':
75
+ {
76
+ updateBooleanAttribute(this, name, isAttrTrue(newVal));
77
+ break;
78
+ }
79
+ }
80
+ }
53
81
  get color() {
54
82
  return getAttribute(this, 'color');
55
83
  }
@@ -68,59 +96,41 @@ defineCustomElement('sinch-chip', class extends NectaryElement {
68
96
  set small(isSmall) {
69
97
  updateBooleanAttribute(this, 'small', isSmall);
70
98
  }
71
- static get observedAttributes() {
72
- return ['text', 'color'];
73
- }
74
- attributeChangedCallback(name, _, newVal) {
75
- switch (name) {
76
- case 'color':
77
- {
78
- this.#updateColor();
79
- break;
80
- }
81
- case 'text':
82
- {
83
- this.#$text.textContent = newVal;
84
- break;
85
- }
86
- }
87
- }
88
99
  #updateColor() {
89
100
  if (!this.isConnected) {
90
101
  return;
91
102
  }
92
103
  const colorName = this.color;
93
104
  if (colorName !== null && colorName.length > 0) {
94
- if ('production' !== 'production') {
95
- assertChipColor(this, colorName);
96
- }
97
105
  const bg = getChipColorBg(colorName);
98
106
  const fg = getChipColorFg(colorName);
99
107
  this.#$button.style.setProperty('background-color', bg);
100
- this.#$button.style.setProperty('color', fg);
101
- this.#$button.style.setProperty('--sinch-color-icon', fg);
108
+ this.#$button.style.setProperty('--sinch-global-color-text', fg);
109
+ this.#$button.style.setProperty('--sinch-global-color-icon', fg);
102
110
  } else {
103
111
  this.#$button.style.removeProperty('background-color');
104
- this.#$button.style.removeProperty('color');
105
- this.#$button.style.removeProperty('--sinch-color-icon');
112
+ this.#$button.style.removeProperty('--sinch-global-color-text');
113
+ this.#$button.style.removeProperty('--sinch-global-color-icon');
106
114
  }
107
115
  }
108
116
  get focusable() {
109
117
  return true;
110
118
  }
111
- focus() {
112
- this.#$button.focus();
113
- }
114
- blur() {
115
- this.#$button.blur();
116
- }
117
- #onButtonClick = () => {
119
+ #onKeydown = e => {
120
+ switch (e.code) {
121
+ case 'Space':
122
+ {
123
+ this.click();
124
+ }
125
+ }
126
+ };
127
+ #onClick = () => {
118
128
  this.dispatchEvent(new CustomEvent('-click'));
119
129
  };
120
- #onButtonFocus = () => {
130
+ #onFocus = () => {
121
131
  this.dispatchEvent(new CustomEvent('-focus'));
122
132
  };
123
- #onButtonBlur = () => {
133
+ #onBlur = () => {
124
134
  this.dispatchEvent(new CustomEvent('-blur'));
125
135
  };
126
136
  #onFocusReactHandler = () => {
package/chip/utils.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export declare const getChipColorBg: (id: string) => string;
2
2
  export declare const getChipColorFg: (id: string) => string;
3
- export declare const assertChipColor: (root: Element, id: string | null) => void;
package/chip/utils.js CHANGED
@@ -1,11 +1,6 @@
1
1
  export const getChipColorBg = id => {
2
- return `var(--sinch-chip-color-${id}-bg)`;
2
+ return `var(--sinch-comp-chip-color-${id}-default-background-initial)`;
3
3
  };
4
4
  export const getChipColorFg = id => {
5
- return `var(--sinch-chip-color-${id}-fg)`;
6
- };
7
- export const assertChipColor = (root, id) => {
8
- if (id === null || window.getComputedStyle(root).getPropertyValue(`--sinch-chip-color-${id}-bg`).length === 0) {
9
- throw new Error(`Invalid sinch-chip color name: ${id}`);
10
- }
5
+ return `var(--sinch-comp-chip-color-${id}-default-foreground-initial)`;
11
6
  };
package/code-tag/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defineCustomElement, getAttribute, updateAttribute, NectaryElement } from '../utils';
2
- const templateHTML = '<style>:host{display:inline}#content{font:var(--sinch-font-mono-text-s);font-size:inherit;line-height:inherit;text-decoration:inherit;border:1px solid var(--sinch-color-border-light);background-color:var(--sinch-color-bg-primary-contrast);padding:0 .25em;border-radius:var(--sinch-shape-radius-xs)}</style><span id="content"></span>';
2
+ const templateHTML = '<style>:host{display:inline}#content{font:var(--sinch-comp-code-tag-font-text);font-size:inherit;line-height:inherit;color:var(--sinch-comp-code-tag-color-default-text-initial);border:1px solid var(--sinch-comp-code-tag-color-default-border-initial);background-color:var(--sinch-comp-code-tag-color-default-background-initial);padding:0 .25em;border-radius:var(--sinch-comp-code-tag-shape-radius);white-space:var(--sinch-global-text-white-space,normal)}</style><span id="content"></span>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-code-tag', class extends NectaryElement {
@@ -1,6 +1,3 @@
1
- import '../color-swatch';
2
- import '../tooltip';
3
- import '../icon';
4
1
  import type { TSinchColorMenuElement, TSinchColorMenuReact } from './types';
5
2
  declare global {
6
3
  namespace JSX {
@@ -1,29 +1,22 @@
1
- import '../color-swatch';
2
- import '../tooltip';
3
- import '../icon';
4
- import { getSwatchColorFg } from '../color-swatch/utils';
5
- import { lightColorNames, darkColorNames, vibrantColorNames } from '../theme/colors';
6
- import { attrValueToPixels, defineCustomElement, getAttribute, getBooleanAttribute, unpackCsv, getIntegerAttribute, getReactEventHandler, getRect, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateIntegerAttribute, subscribeContext, getCssVar } from '../utils';
7
- const optionTemplateHTML = '<div class="option" role="option"><sinch-tooltip inverted class="tooltip"><div class="swatch-wrapper"><sinch-color-swatch class="swatch"></sinch-color-swatch><sinch-icon class="check"></sinch-icon></div></sinch-tooltip></div>';
8
- const templateHTML = '<style>:host{display:block;outline:0}#listbox{display:flex;flex-direction:row;flex-wrap:wrap;padding:4px 10px;overflow-y:auto}#listbox:empty{display:none}.option{padding:12px 6px;--sinch-color-icon:var(--sinch-color-stormy-500)}.swatch-wrapper{position:relative;cursor:pointer;width:32px;height:32px}.swatch-wrapper::after{content:"";position:absolute;width:34px;height:34px;inset:-3px;border:2px solid transparent;border-radius:50%;pointer-events:none}.option[data-selected]:not([data-checked]) .swatch-wrapper::after{border-color:var(--sinch-color-border-focus)}.check{display:none;position:absolute;left:4px;top:4px;pointer-events:none;--sinch-size-icon:24px}.option[data-checked] .check{display:block}</style><div id="listbox" role="presentation"></div>';
9
- import { getParentOption } from './utils';
1
+ import { attrValueToPixels, defineCustomElement, getAttribute, getBooleanAttribute, getIntegerAttribute, getReactEventHandler, getRect, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateIntegerAttribute, subscribeContext } from '../utils';
2
+ const templateHTML = '<style>:host{display:block;outline:0}#listbox{display:flex;flex-direction:row;flex-wrap:wrap;padding:4px 10px;overflow-y:auto}#listbox.empty{display:none}</style><div id="listbox" role="presentation"><slot id="options"></slot></div>';
10
3
  const NUM_COLS_DEFAULT = 5;
11
4
  const ITEM_WIDTH = 44;
12
5
  const ITEM_HEIGHT = 56;
13
6
  const template = document.createElement('template');
14
- const optionTemplate = document.createElement('template');
15
7
  template.innerHTML = templateHTML;
16
- optionTemplate.innerHTML = optionTemplateHTML;
17
8
  defineCustomElement('sinch-color-menu', class extends NectaryElement {
18
9
  #$listbox;
10
+ #$optionsSlot;
19
11
  #controller = null;
20
- #prevColorsValue = '';
21
- #checkIconName = null;
22
12
  constructor() {
23
13
  super();
24
- const shadowRoot = this.attachShadow();
14
+ const shadowRoot = this.attachShadow({
15
+ delegatesFocus: false
16
+ });
25
17
  shadowRoot.appendChild(template.content.cloneNode(true));
26
18
  this.#$listbox = shadowRoot.querySelector('#listbox');
19
+ this.#$optionsSlot = shadowRoot.querySelector('#options');
27
20
  }
28
21
  connectedCallback() {
29
22
  super.connectedCallback();
@@ -31,32 +24,53 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
31
24
  const {
32
25
  signal
33
26
  } = this.#controller;
34
- this.setAttribute('role', 'listbox');
35
- this.setAttribute('tabindex', '0');
36
- this.addEventListener('keydown', this.#onListboxKeyDown, {
37
- signal
38
- });
39
- this.addEventListener('blur', this.#onListboxBlur, {
40
- signal
41
- });
42
- this.#$listbox.addEventListener('click', this.#onListboxClick, {
27
+ const options = {
43
28
  signal
44
- });
45
- this.addEventListener('-change', this.#onChangeReactHandler, {
46
- signal
47
- });
29
+ };
30
+ this.role = 'listbox';
31
+ this.tabIndex = 0;
32
+ this.addEventListener('keydown', this.#onListboxKeyDown, options);
33
+ this.addEventListener('blur', this.#onListboxBlur, options);
34
+ this.#$listbox.addEventListener('click', this.#onListboxClick, options);
35
+ this.#$optionsSlot.addEventListener('slotchange', this.#onSlotChange, options);
36
+ this.addEventListener('-change', this.#onChangeReactHandler, options);
48
37
  subscribeContext(this, 'keydown', this.#onContextKeyDown, signal);
49
38
  subscribeContext(this, 'visibility', this.#onContextVisibility, signal);
50
- this.#checkIconName = getCssVar(this, '--sinch-color-menu-icon-check');
51
- requestAnimationFrame(this.#onMount);
39
+ this.#updateColumns();
52
40
  }
53
41
  disconnectedCallback() {
54
42
  super.disconnectedCallback();
55
- this.#prevColorsValue = null;
56
43
  this.#controller.abort();
44
+ this.#controller = null;
57
45
  }
58
46
  static get observedAttributes() {
59
- return ['value', 'rows', 'cols', 'colors'];
47
+ return ['value', 'rows', 'cols'];
48
+ }
49
+ attributeChangedCallback(name, oldVal, newVal) {
50
+ if (oldVal === newVal) {
51
+ return;
52
+ }
53
+ switch (name) {
54
+ case 'value':
55
+ {
56
+ if (this.isConnected) {
57
+ this.#onValueChange();
58
+ }
59
+ break;
60
+ }
61
+ case 'rows':
62
+ {
63
+ this.#updateRows();
64
+ break;
65
+ }
66
+ case 'cols':
67
+ {
68
+ if (this.isConnected) {
69
+ this.#updateColumns();
70
+ }
71
+ break;
72
+ }
73
+ }
60
74
  }
61
75
  set value(value) {
62
76
  updateAttribute(this, 'value', value);
@@ -86,73 +100,16 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
86
100
  return true;
87
101
  }
88
102
  nthItemRect(index) {
89
- const $item = this.#$listbox.children[index];
103
+ const $item = this.#getOptionElements()[index];
90
104
  if ($item != null) {
91
105
  return getRect($item);
92
106
  }
93
107
  return null;
94
108
  }
95
- attributeChangedCallback(name, oldVal, newVal) {
96
- if (oldVal === newVal) {
97
- return;
98
- }
99
- switch (name) {
100
- case 'value':
101
- {
102
- if (this.isConnected) {
103
- this.#onValueChange();
104
- }
105
- break;
106
- }
107
- case 'colors':
108
- {
109
- if (this.isConnected) {
110
- this.#updateColors();
111
- }
112
- break;
113
- }
114
- case 'rows':
115
- {
116
- this.#updateRows();
117
- break;
118
- }
119
- case 'cols':
120
- {
121
- if (this.isConnected) {
122
- this.#updateColumns();
123
- }
124
- break;
125
- }
126
- }
127
- }
128
- #updateColors() {
129
- const colorsValue = this.colors;
130
- if (colorsValue === this.#prevColorsValue) {
131
- return;
132
- }
133
- this.#prevColorsValue = colorsValue;
134
- const colorNames = unpackCsv(colorsValue ?? `${lightColorNames},${vibrantColorNames},${darkColorNames}`);
135
- const fragment = document.createDocumentFragment();
136
- for (const color of colorNames) {
137
- if (color.length === 0) {
138
- continue;
139
- }
140
- const optFrag = optionTemplate.content.cloneNode(true);
141
- const $option = optFrag.querySelector('.option');
142
- const $swatch = optFrag.querySelector('.swatch');
143
- const $tooltip = optFrag.querySelector('.tooltip');
144
- const $checkIcon = optFrag.querySelector('.check');
145
- updateAttribute($option, 'data-value', color);
146
- updateAttribute($tooltip, 'text', color);
147
- updateAttribute($swatch, 'name', color);
148
- updateAttribute($checkIcon, 'name', this.#checkIconName);
149
- $option.style.setProperty('--sinch-color-icon', getSwatchColorFg(color));
150
- fragment.appendChild(optFrag);
151
- }
152
- this.#$listbox.replaceChildren(fragment);
109
+ #onSlotChange = () => {
153
110
  this.#updateColumns();
154
111
  this.#onValueChange();
155
- }
112
+ };
156
113
  #updateRows() {
157
114
  const rowsValue = getAttribute(this, 'rows');
158
115
  this.#$listbox.style.maxHeight = attrValueToPixels(rowsValue, {
@@ -162,7 +119,7 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
162
119
  }
163
120
  #updateColumns() {
164
121
  const colsValue = getAttribute(this, 'cols');
165
- const numItems = this.#$listbox.children.length;
122
+ const numItems = this.#getOptionElements().length;
166
123
  this.#$listbox.style.width = attrValueToPixels(colsValue, {
167
124
  min: 1,
168
125
  max: numItems,
@@ -170,9 +127,6 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
170
127
  itemSizeMultiplier: ITEM_WIDTH
171
128
  });
172
129
  }
173
- #onMount = () => {
174
- this.#updateColors();
175
- };
176
130
  #onListboxBlur = () => {
177
131
  this.#selectOption(null);
178
132
  };
@@ -181,8 +135,8 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
181
135
  if ($elem === this.#$listbox) {
182
136
  return;
183
137
  }
184
- const $option = getParentOption($elem);
185
- this.#dispatchChangeEvent($option);
138
+ this.focus();
139
+ this.#dispatchChangeEvent($elem);
186
140
  };
187
141
  #onContextVisibility = e => {
188
142
  if (e.detail) {
@@ -238,7 +192,7 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
238
192
  #onValueChange() {
239
193
  const value = this.value;
240
194
  for (const $option of this.#getOptionElements()) {
241
- const isChecked = value === getAttribute($option, 'data-value', '');
195
+ const isChecked = value === getAttribute($option, 'value', '');
242
196
  updateBooleanAttribute($option, 'data-checked', isChecked);
243
197
  updateBooleanAttribute($option, 'data-selected', isChecked);
244
198
  updateExplicitBooleanAttribute($option, 'aria-selected', isChecked);
@@ -316,7 +270,7 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
316
270
  }
317
271
  }
318
272
  #getOptionElements() {
319
- return Array.from(this.#$listbox.children);
273
+ return this.#$optionsSlot.assignedElements();
320
274
  }
321
275
  #getSelectedOptionIndex() {
322
276
  const elements = this.#getOptionElements();
@@ -341,7 +295,7 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
341
295
  const elements = this.#getOptionElements();
342
296
  const value = this.value;
343
297
  for (const $el of elements) {
344
- if (getAttribute($el, 'data-value') === value) {
298
+ if (getAttribute($el, 'value') === value) {
345
299
  return $el;
346
300
  }
347
301
  }
@@ -353,7 +307,7 @@ defineCustomElement('sinch-color-menu', class extends NectaryElement {
353
307
  }
354
308
  if ($opt !== null) {
355
309
  this.dispatchEvent(new CustomEvent('-change', {
356
- detail: getAttribute($opt, 'data-value')
310
+ detail: getAttribute($opt, 'value')
357
311
  }));
358
312
  }
359
313
  }
@@ -6,8 +6,6 @@ export type TSinchColorMenuElement = HTMLElement & {
6
6
  rows: number | null;
7
7
  /** How many cols to show and scroll the rest */
8
8
  cols: number | null;
9
- /** Comma-separated color names, all colors by default */
10
- colors: string | null;
11
9
  nthItemRect(index: number): TRect | null;
12
10
  /** Change event */
13
11
  addEventListener(type: '-change', listener: (e: CustomEvent<string>) => void): void;
@@ -27,8 +25,6 @@ export type TSinchColorMenuReact = TSinchElementReact<TSinchColorMenuElement> &
27
25
  rows?: number;
28
26
  /** How many cols to show and scroll the rest */
29
27
  cols?: number;
30
- /** Comma-separated color names, all colors by default */
31
- colors?: string;
32
28
  /** Label that is used for a11y */
33
29
  'aria-label': string;
34
30
  /** Change event handler */
@@ -0,0 +1,14 @@
1
+ import '../color-swatch';
2
+ import '../tooltip';
3
+ import '../icon';
4
+ import type { TSinchColorMenuOptionElement, TSinchColorMenuOptionReact } from './types';
5
+ declare global {
6
+ namespace JSX {
7
+ interface IntrinsicElements {
8
+ 'sinch-color-menu-option': TSinchColorMenuOptionReact;
9
+ }
10
+ }
11
+ interface HTMLElementTagNameMap {
12
+ 'sinch-color-menu-option': TSinchColorMenuOptionElement;
13
+ }
14
+ }
@@ -0,0 +1,52 @@
1
+ import '../color-swatch';
2
+ import '../tooltip';
3
+ import '../icon';
4
+ import { getSwatchColorFg } from '../color-swatch/utils';
5
+ import { defineCustomElement, getAttribute, NectaryElement, updateAttribute } from '../utils';
6
+ const templateHTML = '<style>:host{display:block;outline:0}#wrapper{width:44px;height:56px;padding:12px 6px;box-sizing:border-box;--sinch-global-color-icon:var(--sinch-color-menu-color-icon)}#swatch-wrapper{position:relative;cursor:pointer;width:32px;height:32px}#swatch-wrapper::after{content:"";position:absolute;width:34px;height:34px;inset:-3px;border:2px solid transparent;border-radius:50%;pointer-events:none}:host([data-selected]:not([data-checked])) #swatch-wrapper::after{border-color:var(--sinch-comp-color-swatch-color-outline-focus)}#check{display:none;position:absolute;left:4px;top:4px;pointer-events:none;--sinch-global-size-icon:24px}:host([data-checked]) #check{display:block}</style><div id="wrapper"><sinch-tooltip id="tooltip"><div id="swatch-wrapper"><sinch-color-swatch id="swatch"></sinch-color-swatch><sinch-icon id="check" name="check"></sinch-icon></div></sinch-tooltip></div>';
7
+ const template = document.createElement('template');
8
+ template.innerHTML = templateHTML;
9
+ defineCustomElement('sinch-color-menu-option', class extends NectaryElement {
10
+ #$wrapper;
11
+ #$tooltip;
12
+ #$swatch;
13
+ constructor() {
14
+ super();
15
+ const shadowRoot = this.attachShadow();
16
+ shadowRoot.appendChild(template.content.cloneNode(true));
17
+ this.#$wrapper = shadowRoot.querySelector('#wrapper');
18
+ this.#$tooltip = shadowRoot.querySelector('#tooltip');
19
+ this.#$swatch = shadowRoot.querySelector('#swatch');
20
+ }
21
+ connectedCallback() {
22
+ this.role = 'option';
23
+ }
24
+ disconnectedCallback() {}
25
+ static get observedAttributes() {
26
+ return ['value'];
27
+ }
28
+ attributeChangedCallback(name, oldVal, newVal) {
29
+ if (oldVal === newVal) {
30
+ return;
31
+ }
32
+ switch (name) {
33
+ case 'value':
34
+ {
35
+ updateAttribute(this.#$tooltip, 'text', newVal);
36
+ updateAttribute(this.#$swatch, 'name', newVal);
37
+ if (newVal !== null) {
38
+ this.#$wrapper.style.setProperty('--sinch-global-color-icon', getSwatchColorFg(newVal));
39
+ } else {
40
+ this.#$wrapper.style.removeProperty('--sinch-global-color-icon');
41
+ }
42
+ break;
43
+ }
44
+ }
45
+ }
46
+ set value(value) {
47
+ updateAttribute(this, 'value', value);
48
+ }
49
+ get value() {
50
+ return getAttribute(this, 'value', '');
51
+ }
52
+ });
@@ -0,0 +1,9 @@
1
+ import type { TSinchElementReact } from '../types';
2
+ export type TSinchColorMenuOptionElement = HTMLElement & {
3
+ /** Value */
4
+ value: string;
5
+ };
6
+ export type TSinchColorMenuOptionReact = TSinchElementReact<TSinchColorMenuOptionElement> & {
7
+ /** Value */
8
+ value: string;
9
+ };
@@ -0,0 +1 @@
1
+ export declare const getParentOption: ($element: Element) => Element | null;
@@ -0,0 +1,11 @@
1
+ export const getParentOption = $element => {
2
+ let $el = $element;
3
+ while (!$el.hasAttribute('data-value')) {
4
+ const parent = $el.parentElement;
5
+ if (parent === null) {
6
+ return null;
7
+ }
8
+ $el = parent;
9
+ }
10
+ return $el;
11
+ };
@@ -1,7 +1,7 @@
1
1
  import '../text';
2
2
  import { defineCustomElement, NectaryElement, setClass, getAttribute, updateAttribute } from '../utils';
3
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle}#wrapper{width:var(--sinch-size-icon,32px);height:var(--sinch-size-icon,32px);border-radius:50%}#wrapper.no-color{background:linear-gradient(45deg,var(--sinch-color-swatch-color-light-orange-bg),var(--sinch-color-swatch-color-light-yellow-bg),var(--sinch-color-swatch-color-light-green-bg),var(--sinch-color-swatch-color-light-blue-bg),var(--sinch-color-swatch-color-light-violet-bg))}</style><div id="wrapper"></div>';
4
- import { assertSwatchColor, getSwatchColorBg } from './utils';
3
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle}#wrapper{width:var(--sinch-global-size-icon,32px);height:var(--sinch-global-size-icon,32px);border-radius:50%}#wrapper.no-color{background:linear-gradient(45deg,var(--sinch-ref-color-complementary-orange-200),var(--sinch-ref-color-complementary-bolt-200),var(--sinch-ref-color-complementary-grass-200),var(--sinch-ref-color-complementary-night-200),var(--sinch-ref-color-complementary-violet-200))}</style><div id="wrapper"></div>';
4
+ import { getSwatchColorBg } from './utils';
5
5
  const template = document.createElement('template');
6
6
  template.innerHTML = templateHTML;
7
7
  defineCustomElement('sinch-color-swatch', class extends NectaryElement {
@@ -43,9 +43,6 @@ defineCustomElement('sinch-color-swatch', class extends NectaryElement {
43
43
  }
44
44
  const colorName = this.name;
45
45
  if (colorName !== null && colorName.length > 0) {
46
- if ('production' !== 'production') {
47
- assertSwatchColor(this, colorName);
48
- }
49
46
  const bg = getSwatchColorBg(colorName);
50
47
  this.#$wrapper.style.setProperty('background-color', bg);
51
48
  setClass(this.#$wrapper, 'no-color', false);
@@ -1,3 +1,2 @@
1
1
  export declare const getSwatchColorBg: (id: string) => string;
2
2
  export declare const getSwatchColorFg: (id: string) => string;
3
- export declare const assertSwatchColor: (root: Element, id: string | null) => void;
@@ -1,11 +1,6 @@
1
1
  export const getSwatchColorBg = id => {
2
- return `var(--sinch-color-swatch-color-${id}-bg)`;
2
+ return `var(--sinch-comp-color-swatch-color-${id}-background)`;
3
3
  };
4
4
  export const getSwatchColorFg = id => {
5
- return `var(--sinch-color-swatch-color-${id}-fg)`;
6
- };
7
- export const assertSwatchColor = (root, id) => {
8
- if (id === null || window.getComputedStyle(root).getPropertyValue(`--sinch-color-swatch-color-${id}-bg`).length === 0) {
9
- throw new Error(`Invalid sinch-color-swatch color name: ${id}`);
10
- }
5
+ return `var(--sinch-comp-color-swatch-color-${id}-foreground)`;
11
6
  };