@nectary/components 0.39.0 → 0.41.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 (142) hide show
  1. package/accordion/index.js +47 -84
  2. package/accordion-item/index.js +30 -53
  3. package/action-menu/index.d.ts +0 -1
  4. package/action-menu/index.js +177 -223
  5. package/action-menu/types.d.ts +8 -18
  6. package/action-menu-option/index.d.ts +1 -0
  7. package/action-menu-option/index.js +52 -62
  8. package/action-menu-option/types.d.ts +9 -0
  9. package/action-menu-option/utils.d.ts +2 -0
  10. package/action-menu-option/utils.js +3 -0
  11. package/alert/index.js +6 -20
  12. package/avatar/index.js +12 -31
  13. package/avatar-badge/index.js +8 -22
  14. package/avatar-status/index.js +1 -1
  15. package/button/index.js +46 -92
  16. package/button/types.d.ts +1 -1
  17. package/card/index.js +21 -59
  18. package/chat-avatar/index.js +8 -22
  19. package/chat-block/index.js +29 -69
  20. package/chat-bubble/index.js +6 -20
  21. package/checkbox/index.js +59 -107
  22. package/chip/index.d.ts +13 -0
  23. package/chip/index.js +140 -0
  24. package/chip/types.d.ts +37 -0
  25. package/color-menu/index.d.ts +14 -0
  26. package/color-menu/index.js +450 -0
  27. package/color-menu/types.d.ts +36 -0
  28. package/color-menu/utils.d.ts +1 -0
  29. package/color-menu/utils.js +15 -0
  30. package/color-swatch/index.d.ts +13 -0
  31. package/color-swatch/index.js +60 -0
  32. package/color-swatch/types.d.ts +11 -0
  33. package/colors.json +61 -49
  34. package/date-picker/index.js +162 -293
  35. package/dialog/index.js +70 -142
  36. package/field/index.js +44 -65
  37. package/file-drop/index.js +123 -200
  38. package/file-picker/index.d.ts +0 -1
  39. package/file-picker/index.js +55 -108
  40. package/file-status/index.js +15 -39
  41. package/help-tooltip/index.js +11 -28
  42. package/horizontal-stepper/index.js +33 -59
  43. package/horizontal-stepper-item/index.js +13 -37
  44. package/icon-button/index.d.ts +1 -0
  45. package/icon-button/index.js +51 -85
  46. package/icon-button/types.d.ts +16 -2
  47. package/icons-channel/notify/index.d.ts +11 -0
  48. package/icons-channel/notify/index.js +4 -0
  49. package/illustrations/create-illustration-class.js +1 -1
  50. package/inline-alert/index.js +29 -81
  51. package/input/index.js +117 -222
  52. package/link/index.js +51 -97
  53. package/list-item/index.js +1 -1
  54. package/package.json +12 -14
  55. package/pagination/index.js +113 -163
  56. package/pop/index.d.ts +11 -0
  57. package/pop/index.js +391 -0
  58. package/pop/types.d.ts +35 -0
  59. package/pop/utils.d.ts +7 -0
  60. package/pop/utils.js +18 -0
  61. package/popover/index.d.ts +1 -0
  62. package/popover/index.js +105 -314
  63. package/popover/types.d.ts +8 -1
  64. package/popover/utils.d.ts +5 -0
  65. package/popover/utils.js +17 -1
  66. package/progress/index.js +9 -28
  67. package/radio/index.js +103 -169
  68. package/radio-option/index.js +28 -48
  69. package/segment/index.js +49 -130
  70. package/segment-collapse/index.js +28 -49
  71. package/segmented-control/index.js +36 -73
  72. package/segmented-control-option/index.js +45 -87
  73. package/segmented-icon-control/index.js +47 -84
  74. package/segmented-icon-control-option/index.js +42 -79
  75. package/select-button/index.d.ts +13 -0
  76. package/select-button/index.js +158 -0
  77. package/select-button/types.d.ts +43 -0
  78. package/select-menu/index.d.ts +11 -0
  79. package/select-menu/index.js +345 -0
  80. package/select-menu/types.d.ts +29 -0
  81. package/{dropdown-text-option → select-menu-option}/index.d.ts +5 -7
  82. package/select-menu-option/index.js +76 -0
  83. package/{select-option → select-menu-option}/types.d.ts +8 -9
  84. package/stop-events/index.js +7 -20
  85. package/table-head-cell/index.js +7 -21
  86. package/tabs/index.js +103 -165
  87. package/tabs-option/index.js +24 -44
  88. package/tag/index.d.ts +0 -1
  89. package/tag/index.js +35 -38
  90. package/tag/types.d.ts +12 -7
  91. package/textarea/index.js +96 -167
  92. package/theme.css +146 -49
  93. package/tile-control/index.js +55 -96
  94. package/tile-control-option/index.js +45 -87
  95. package/time-picker/index.js +216 -368
  96. package/title/index.js +6 -20
  97. package/toast/index.js +32 -70
  98. package/toast-manager/index.js +141 -217
  99. package/toggle/index.js +59 -107
  100. package/tooltip/index.d.ts +2 -0
  101. package/tooltip/index.js +160 -17
  102. package/tooltip/types.d.ts +13 -0
  103. package/tooltip/utils.d.ts +5 -0
  104. package/tooltip/utils.js +25 -1
  105. package/utils/animation.d.ts +17 -0
  106. package/utils/animation.js +142 -0
  107. package/utils/colors.d.ts +5 -0
  108. package/utils/colors.js +5 -0
  109. package/utils/context.d.ts +15 -0
  110. package/utils/context.js +57 -0
  111. package/{utils.d.ts → utils/index.d.ts} +15 -11
  112. package/{utils.js → utils/index.js} +104 -48
  113. package/vertical-stepper/index.js +29 -50
  114. package/vertical-stepper-item/index.js +13 -37
  115. package/dropdown/index.d.ts +0 -12
  116. package/dropdown/index.js +0 -415
  117. package/dropdown/types.d.ts +0 -32
  118. package/dropdown-checkbox-option/index.d.ts +0 -11
  119. package/dropdown-checkbox-option/index.js +0 -88
  120. package/dropdown-checkbox-option/types.d.ts +0 -15
  121. package/dropdown-radio-option/index.d.ts +0 -11
  122. package/dropdown-radio-option/index.js +0 -88
  123. package/dropdown-radio-option/types.d.ts +0 -15
  124. package/dropdown-text-option/index.js +0 -104
  125. package/dropdown-text-option/types.d.ts +0 -16
  126. package/select/index.d.ts +0 -13
  127. package/select/index.js +0 -316
  128. package/select/types.d.ts +0 -53
  129. package/select-option/index.d.ts +0 -11
  130. package/select-option/index.js +0 -8
  131. package/tag/utils.d.ts +0 -5
  132. package/tag/utils.js +0 -6
  133. package/tag-close/index.d.ts +0 -12
  134. package/tag-close/index.js +0 -42
  135. package/tag-close/types.d.ts +0 -5
  136. /package/{dropdown-checkbox-option → chip}/types.js +0 -0
  137. /package/{dropdown-radio-option → color-menu}/types.js +0 -0
  138. /package/{dropdown-text-option → color-swatch}/types.js +0 -0
  139. /package/{dropdown → pop}/types.js +0 -0
  140. /package/{select-option → select-button}/types.js +0 -0
  141. /package/{tag-close → select-menu}/types.js +0 -0
  142. /package/{select → select-menu-option}/types.js +0 -0
@@ -0,0 +1,450 @@
1
+ import '../color-swatch';
2
+ import '../tooltip';
3
+ import '../icons/check';
4
+ import { attrValueToPixels, defineCustomElement, getAttribute, getBooleanAttribute, getCsvSet, getIntegerAttribute, getReactEventHandler, getRect, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateIntegerAttribute } from '../utils';
5
+ import { lightColorNames, darkColorNames, vibrantColorNames, NO_COLOR } from '../utils/colors';
6
+ import { dispatchContextConnectEvent, dispatchContextDisconnectEvent } from '../utils/context';
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-check class="check"></sinch-icon-check></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';
10
+ const NUM_COLS_DEFAULT = 5;
11
+ const ITEM_WIDTH = 44;
12
+ const ITEM_HEIGHT = 56;
13
+ const template = document.createElement('template');
14
+ const optionTemplate = document.createElement('template');
15
+ template.innerHTML = templateHTML;
16
+ optionTemplate.innerHTML = optionTemplateHTML;
17
+ defineCustomElement('sinch-color-menu', class extends NectaryElement {
18
+ #$listbox;
19
+ #controller = null;
20
+ #prevColorsValue = '';
21
+ #isConnected = false;
22
+
23
+ constructor() {
24
+ super();
25
+ const shadowRoot = this.attachShadow();
26
+ shadowRoot.appendChild(template.content.cloneNode(true));
27
+ this.#$listbox = shadowRoot.querySelector('#listbox');
28
+ }
29
+
30
+ connectedCallback() {
31
+ this.#controller = new AbortController();
32
+ const {
33
+ signal
34
+ } = this.#controller;
35
+ this.setAttribute('role', 'listbox');
36
+ this.setAttribute('tabindex', '0');
37
+ this.addEventListener('keydown', this.#onListboxKeyDown, {
38
+ signal
39
+ });
40
+ this.addEventListener('-keydown', this.#onContexKeydown, {
41
+ signal
42
+ });
43
+ this.addEventListener('blur', this.#onListboxBlur, {
44
+ signal
45
+ });
46
+ this.#$listbox.addEventListener('click', this.#onListboxClick, {
47
+ signal
48
+ });
49
+ this.addEventListener('-change', this.#onChangeReactHandler, {
50
+ signal
51
+ });
52
+ this.addEventListener('-visibility', this.#onContextVisibility, {
53
+ signal
54
+ });
55
+ dispatchContextConnectEvent(this, 'visibility');
56
+ dispatchContextConnectEvent(this, 'keydown');
57
+ requestAnimationFrame(this.#onMount);
58
+ }
59
+
60
+ disconnectedCallback() {
61
+ this.#isConnected = false;
62
+ this.#prevColorsValue = null;
63
+ dispatchContextDisconnectEvent(this, 'visibility');
64
+ dispatchContextDisconnectEvent(this, 'keydown');
65
+ this.#controller.abort();
66
+ }
67
+
68
+ static get observedAttributes() {
69
+ return ['value', 'rows', 'cols', 'colors'];
70
+ }
71
+
72
+ set value(value) {
73
+ updateAttribute(this, 'value', value);
74
+ }
75
+
76
+ get value() {
77
+ return getAttribute(this, 'value', NO_COLOR);
78
+ }
79
+
80
+ set colors(value) {
81
+ updateAttribute(this, 'colors', value);
82
+ }
83
+
84
+ get colors() {
85
+ return getAttribute(this, 'colors');
86
+ }
87
+
88
+ set rows(value) {
89
+ updateIntegerAttribute(this, 'rows', value);
90
+ }
91
+
92
+ get rows() {
93
+ return getIntegerAttribute(this, 'rows', null);
94
+ }
95
+
96
+ set cols(value) {
97
+ updateIntegerAttribute(this, 'cols', value);
98
+ }
99
+
100
+ get cols() {
101
+ return getIntegerAttribute(this, 'cols', null);
102
+ }
103
+
104
+ get focusable() {
105
+ return true;
106
+ }
107
+
108
+ nthItemRect(index) {
109
+ const $item = this.#$listbox.children[index];
110
+
111
+ if ($item != null) {
112
+ return getRect($item);
113
+ }
114
+
115
+ return null;
116
+ }
117
+
118
+ attributeChangedCallback(name, oldVal, newVal) {
119
+ if (oldVal === newVal) {
120
+ return;
121
+ }
122
+
123
+ switch (name) {
124
+ case 'value':
125
+ {
126
+ if (this.#isConnected) {
127
+ this.#onValueChange();
128
+ }
129
+
130
+ break;
131
+ }
132
+
133
+ case 'colors':
134
+ {
135
+ if (this.#isConnected) {
136
+ this.#updateColors();
137
+ }
138
+
139
+ break;
140
+ }
141
+
142
+ case 'rows':
143
+ {
144
+ this.#updateRows();
145
+ break;
146
+ }
147
+
148
+ case 'cols':
149
+ {
150
+ if (this.#isConnected) {
151
+ this.#updateColumns();
152
+ }
153
+
154
+ break;
155
+ }
156
+ }
157
+ }
158
+
159
+ #updateColors() {
160
+ const colorsValue = this.colors;
161
+
162
+ if (colorsValue === this.#prevColorsValue) {
163
+ return;
164
+ }
165
+
166
+ this.#prevColorsValue = colorsValue;
167
+ const colorNames = getCsvSet(colorsValue ?? `${lightColorNames},${vibrantColorNames},${darkColorNames}`);
168
+ const fragment = document.createDocumentFragment();
169
+
170
+ for (const color of colorNames) {
171
+ if (color === NO_COLOR) {
172
+ continue;
173
+ }
174
+
175
+ const optFrag = optionTemplate.content.cloneNode(true);
176
+ const $option = optFrag.querySelector('.option');
177
+ const $swatch = optFrag.querySelector('.swatch');
178
+ const $tooltip = optFrag.querySelector('.tooltip');
179
+ updateAttribute($option, 'data-value', color);
180
+ updateAttribute($tooltip, 'text', color);
181
+ updateAttribute($swatch, 'name', color);
182
+ $option.style.setProperty('--sinch-color-icon', `var(--sinch-color-map-${color}-fg)`);
183
+ fragment.appendChild(optFrag);
184
+ }
185
+
186
+ this.#$listbox.replaceChildren(fragment);
187
+ this.#updateColumns();
188
+ this.#onValueChange();
189
+ }
190
+
191
+ #updateRows() {
192
+ const rowsValue = getAttribute(this, 'rows');
193
+ this.#$listbox.style.maxHeight = attrValueToPixels(rowsValue, {
194
+ min: 2,
195
+ itemSizeMultiplier: ITEM_HEIGHT
196
+ });
197
+ }
198
+
199
+ #updateColumns() {
200
+ const colsValue = getAttribute(this, 'cols');
201
+ const numItems = this.#$listbox.children.length;
202
+ this.#$listbox.style.width = attrValueToPixels(colsValue, {
203
+ min: 1,
204
+ max: numItems,
205
+ defaultValue: Math.min(numItems, NUM_COLS_DEFAULT),
206
+ itemSizeMultiplier: ITEM_WIDTH
207
+ });
208
+ }
209
+
210
+ #onMount = () => {
211
+ this.#updateColors();
212
+ this.#isConnected = true;
213
+ };
214
+ #onListboxBlur = () => {
215
+ this.#selectOption(null);
216
+ };
217
+ #onListboxClick = e => {
218
+ const $elem = e.target;
219
+
220
+ if ($elem === this.#$listbox) {
221
+ return;
222
+ }
223
+
224
+ const $option = getParentOption($elem);
225
+ this.#dispatchChangeEvent($option);
226
+ this.#selectOption($option);
227
+ };
228
+ #onContextVisibility = e => {
229
+ if (e.detail) {
230
+ this.#selectOption(this.#findCheckedOption());
231
+ } else {
232
+ this.#selectOption(null);
233
+ }
234
+ };
235
+ #onContexKeydown = e => {
236
+ this.#handleKeydown(e.detail);
237
+ };
238
+ #onListboxKeyDown = e => {
239
+ this.#handleKeydown(e);
240
+ };
241
+
242
+ #handleKeydown(e) {
243
+ switch (e.code) {
244
+ case 'Space':
245
+ case 'Enter':
246
+ {
247
+ const $option = this.#findSelectedOption();
248
+
249
+ if ($option !== null) {
250
+ e.preventDefault();
251
+ this.#dispatchChangeEvent($option);
252
+ }
253
+
254
+ break;
255
+ }
256
+
257
+ case 'ArrowLeft':
258
+ {
259
+ e.preventDefault();
260
+ this.#selectOption(this.#getPrevOption());
261
+ break;
262
+ }
263
+
264
+ case 'ArrowRight':
265
+ {
266
+ e.preventDefault();
267
+ this.#selectOption(this.#getNextOption());
268
+ break;
269
+ }
270
+
271
+ case 'ArrowDown':
272
+ {
273
+ e.preventDefault();
274
+ this.#selectOption(this.#getNextRowOption());
275
+ break;
276
+ }
277
+
278
+ case 'ArrowUp':
279
+ {
280
+ e.preventDefault();
281
+ this.#selectOption(this.#getPrevRowOption());
282
+ break;
283
+ }
284
+ }
285
+ }
286
+
287
+ #onValueChange() {
288
+ const value = this.value;
289
+
290
+ for (const $option of this.#getOptionElements()) {
291
+ const isChecked = value === getAttribute($option, 'data-value', '');
292
+ updateBooleanAttribute($option, 'data-checked', isChecked);
293
+ updateExplicitBooleanAttribute($option, 'aria-selected', isChecked);
294
+ }
295
+ }
296
+
297
+ #getFirstOption() {
298
+ const $options = this.#getOptionElements();
299
+ return $options[0] ?? null;
300
+ }
301
+
302
+ #getLastOption() {
303
+ const $options = this.#getOptionElements();
304
+ return $options[$options.length - 1] ?? null;
305
+ }
306
+
307
+ #getNextOption() {
308
+ const index = this.#getSelectedOptionIndex();
309
+
310
+ if (index !== null) {
311
+ const $options = this.#getOptionElements();
312
+ return $options[(1 + index) % $options.length];
313
+ }
314
+
315
+ return this.#getFirstOption();
316
+ }
317
+
318
+ #getPrevOption() {
319
+ const index = this.#getSelectedOptionIndex();
320
+
321
+ if (index !== null) {
322
+ const $options = this.#getOptionElements();
323
+ return $options[(index - 1 + $options.length) % $options.length];
324
+ }
325
+
326
+ return this.#getLastOption();
327
+ }
328
+
329
+ #getNextRowOption() {
330
+ const selectedIndex = this.#getSelectedOptionIndex();
331
+
332
+ if (selectedIndex !== null) {
333
+ const $options = this.#getOptionElements();
334
+ const numCols = Math.min(this.cols ?? NUM_COLS_DEFAULT, $options.length);
335
+ const numColsInLastRow = $options.length % numCols;
336
+
337
+ if (numColsInLastRow > 0) {
338
+ if (selectedIndex < $options.length - numCols) {
339
+ return $options[selectedIndex + numCols];
340
+ }
341
+
342
+ if (numColsInLastRow > 0 && selectedIndex < $options.length - numColsInLastRow) {
343
+ return $options[$options.length - 1];
344
+ }
345
+
346
+ return $options[selectedIndex + numColsInLastRow - $options.length];
347
+ }
348
+
349
+ return $options[(selectedIndex + numCols) % $options.length];
350
+ }
351
+
352
+ return this.#getFirstOption();
353
+ }
354
+
355
+ #getPrevRowOption() {
356
+ const selectedIndex = this.#getSelectedOptionIndex();
357
+
358
+ if (selectedIndex !== null) {
359
+ const $options = this.#getOptionElements();
360
+ const numCols = Math.min(this.cols ?? NUM_COLS_DEFAULT, $options.length);
361
+ const numColsInLastRow = $options.length % numCols;
362
+
363
+ if (selectedIndex < numColsInLastRow) {
364
+ return $options[(selectedIndex - numColsInLastRow + $options.length) % $options.length];
365
+ }
366
+
367
+ if (selectedIndex < numCols) {
368
+ return $options[(selectedIndex - numCols - numColsInLastRow + $options.length) % $options.length];
369
+ }
370
+
371
+ return $options[(selectedIndex - numCols + $options.length) % $options.length];
372
+ }
373
+
374
+ return this.#getFirstOption();
375
+ }
376
+
377
+ #selectOption($option) {
378
+ const hasRows = this.hasAttribute('rows');
379
+
380
+ for (const $op of this.#getOptionElements()) {
381
+ const isSelected = $op === $option;
382
+ updateBooleanAttribute($op, 'data-selected', isSelected);
383
+
384
+ if (isSelected && hasRows) {
385
+ $op.scrollIntoView?.({
386
+ block: 'nearest'
387
+ });
388
+ }
389
+ }
390
+ }
391
+
392
+ #getOptionElements() {
393
+ return Array.from(this.#$listbox.children);
394
+ }
395
+
396
+ #getSelectedOptionIndex() {
397
+ const elements = this.#getOptionElements();
398
+
399
+ for (let i = 0; i < elements.length; i++) {
400
+ const el = elements[i];
401
+
402
+ if (getBooleanAttribute(el, 'data-selected')) {
403
+ return i;
404
+ }
405
+ }
406
+
407
+ return null;
408
+ }
409
+
410
+ #findSelectedOption() {
411
+ const elements = this.#getOptionElements();
412
+
413
+ for (const el of elements) {
414
+ if (getBooleanAttribute(el, 'data-selected')) {
415
+ return el;
416
+ }
417
+ }
418
+
419
+ return null;
420
+ }
421
+
422
+ #findCheckedOption() {
423
+ const elements = this.#getOptionElements();
424
+ const value = this.value;
425
+
426
+ for (const $el of elements) {
427
+ if (getAttribute($el, 'data-value') === value) {
428
+ return $el;
429
+ }
430
+ }
431
+
432
+ return null;
433
+ }
434
+
435
+ #dispatchChangeEvent($opt) {
436
+ if ($opt === null) {
437
+ return;
438
+ }
439
+
440
+ if ($opt !== null) {
441
+ this.dispatchEvent(new CustomEvent('-change', {
442
+ detail: getAttribute($opt, 'data-value')
443
+ }));
444
+ }
445
+ }
446
+
447
+ #onChangeReactHandler = e => {
448
+ getReactEventHandler(this, 'on-change')?.(e);
449
+ };
450
+ });
@@ -0,0 +1,36 @@
1
+ import type { TRect, TSinchElementReact } from '../types';
2
+ export declare type TSinchSelectMenuElement = HTMLElement & {
3
+ /** Value */
4
+ value: string;
5
+ /** How many rows to show and scroll the rest */
6
+ rows: number | null;
7
+ /** How many cols to show and scroll the rest */
8
+ cols: number | null;
9
+ /** Comma-separated color names, all colors by default */
10
+ colors: string | null;
11
+ nthItemRect(index: number): TRect | null;
12
+ /** Change event */
13
+ addEventListener(type: '-change', listener: (e: CustomEvent<string>) => void): void;
14
+ /** Comma-separated color names, all colors by default */
15
+ setAttribute(name: 'colors', value: string): void;
16
+ /** Value */
17
+ setAttribute(name: 'value', value: string): void;
18
+ /** How many rows to show and scroll the rest */
19
+ setAttribute(name: 'rows', value: string): void;
20
+ /** How many cols to show and scroll the rest */
21
+ setAttribute(name: 'cols', value: string): void;
22
+ };
23
+ export declare type TSinchSelectMenuReact = TSinchElementReact<TSinchSelectMenuElement> & {
24
+ /** Value */
25
+ value: string;
26
+ /** How many rows to show and scroll the rest */
27
+ rows?: number;
28
+ /** How many cols to show and scroll the rest */
29
+ cols?: number;
30
+ /** Comma-separated color names, all colors by default */
31
+ colors?: string;
32
+ /** Label that is used for a11y */
33
+ 'aria-label': string;
34
+ /** Change event handler */
35
+ 'on-change'?: (e: CustomEvent<string>) => void;
36
+ };
@@ -0,0 +1 @@
1
+ export declare const getParentOption: ($element: Element) => Element | null;
@@ -0,0 +1,15 @@
1
+ export const getParentOption = $element => {
2
+ let $el = $element;
3
+
4
+ while (!$el.hasAttribute('data-value')) {
5
+ const parent = $el.parentElement;
6
+
7
+ if (parent === null) {
8
+ return null;
9
+ }
10
+
11
+ $el = parent;
12
+ }
13
+
14
+ return $el;
15
+ };
@@ -0,0 +1,13 @@
1
+ import '../icons/cancel';
2
+ import '../text';
3
+ import type { TSinchColorSwatchElement, TSinchColorSwatchReact } from './types';
4
+ declare global {
5
+ namespace JSX {
6
+ interface IntrinsicElements {
7
+ 'sinch-color-swatch': TSinchColorSwatchReact;
8
+ }
9
+ }
10
+ interface HTMLElementTagNameMap {
11
+ 'sinch-color-swatch': TSinchColorSwatchElement;
12
+ }
13
+ }
@@ -0,0 +1,60 @@
1
+ import '../icons/cancel';
2
+ import '../text';
3
+ import { defineCustomElement, NectaryElement, setClass, getAttribute, updateAttribute } from '../utils';
4
+ import { NO_COLOR } from '../utils/colors';
5
+ 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-map-light-orange-bg),var(--sinch-color-map-light-yellow-bg),var(--sinch-color-map-light-green-bg),var(--sinch-color-map-light-blue-bg),var(--sinch-color-map-light-violet-bg))}</style><div id="wrapper"></div>';
6
+ const template = document.createElement('template');
7
+ template.innerHTML = templateHTML;
8
+ defineCustomElement('sinch-color-swatch', class extends NectaryElement {
9
+ #$wrapper;
10
+
11
+ constructor() {
12
+ super();
13
+ const shadowRoot = this.attachShadow();
14
+ shadowRoot.appendChild(template.content.cloneNode(true));
15
+ this.#$wrapper = shadowRoot.querySelector('#wrapper');
16
+ }
17
+
18
+ connectedCallback() {
19
+ this.#updateColor();
20
+ }
21
+
22
+ get name() {
23
+ return getAttribute(this, 'name', NO_COLOR);
24
+ }
25
+
26
+ set name(value) {
27
+ updateAttribute(this, 'name', value);
28
+ }
29
+
30
+ static get observedAttributes() {
31
+ return ['name'];
32
+ }
33
+
34
+ attributeChangedCallback(name, oldValue, newVal) {
35
+ if (oldValue === newVal) {
36
+ return;
37
+ }
38
+
39
+ switch (name) {
40
+ case 'name':
41
+ {
42
+ this.#updateColor();
43
+ break;
44
+ }
45
+ }
46
+ }
47
+
48
+ #updateColor() {
49
+ const colorName = this.name;
50
+
51
+ if (colorName !== NO_COLOR) {
52
+ this.#$wrapper.style.setProperty('background-color', `var(--sinch-color-map-${colorName}-bg)`);
53
+ } else {
54
+ this.#$wrapper.style.removeProperty('background-color');
55
+ }
56
+
57
+ setClass(this.#$wrapper, 'no-color', colorName === NO_COLOR);
58
+ }
59
+
60
+ });
@@ -0,0 +1,11 @@
1
+ import type { TSinchElementReact } from '../types';
2
+ export declare type TSinchColorSwatchElement = HTMLElement & {
3
+ /** Color name */
4
+ name: string;
5
+ /** Color name */
6
+ setAttribute(name: 'name', value: string): void;
7
+ };
8
+ export declare type TSinchColorSwatchReact = TSinchElementReact<TSinchColorSwatchElement> & {
9
+ /** Color name */
10
+ name: string;
11
+ };