@nectary/components 1.2.1 → 1.3.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.
package/colors.json CHANGED
@@ -73,9 +73,9 @@
73
73
  "colorCeltic700": "#003B7E",
74
74
  "colorCeltic400": "#2071CE",
75
75
  "colorCeltic200": "#D5E5F8",
76
- "colorJasper700": "#882024",
77
- "colorJasper400": "#D13D42",
78
- "colorJasper200": "#FBD5D5",
76
+ "colorJasper700": "#B71C1C",
77
+ "colorJasper400": "#F44336",
78
+ "colorJasper200": "#FFCDD2",
79
79
  "colorPumpkin700": "#9C2E00",
80
80
  "colorPumpkin400": "#F35B1C",
81
81
  "colorPumpkin200": "#FFE8D6",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "files": [
5
5
  "**/*/*.css",
6
6
  "**/*/*.json",
@@ -2,10 +2,10 @@ import '../input';
2
2
  import '../icon-button';
3
3
  import '../icon';
4
4
  import '../text';
5
- import { attrValueToPixels, defineCustomElement, getAttribute, getBooleanAttribute, unpackCsv, getFirstCsvValue, getIntegerAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateCsv, updateExplicitBooleanAttribute, updateIntegerAttribute, debounceTimeout, setClass, subscribeContext, getCssVar } from '../utils';
5
+ import { attrValueToPixels, defineCustomElement, getAttribute, getBooleanAttribute, unpackCsv, getFirstCsvValue, getIntegerAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateCsv, updateExplicitBooleanAttribute, updateIntegerAttribute, debounceTimeout, setClass, subscribeContext, getCssVar, hasClass } from '../utils';
6
6
  const templateHTML = '<style>:host{display:block;outline:0}#listbox{overflow-y:auto}#search{display:none;margin:10px}#search.active{display:block}#not-found{display:none;width:100%;height:30px;align-items:center;justify-content:center;margin-bottom:10px;color:var(--sinch-color-text-muted);pointer-events:none;user-select:none}#not-found.active{display:flex}::slotted(.hidden){display:none}</style><sinch-input id="search" size="s" placeholder="Search"><sinch-icon id="icon-search" slot="icon"></sinch-icon></sinch-input><div id="not-found"><sinch-text type="m">No results</sinch-text></div><div id="listbox" role="presentation"><slot></slot></div>';
7
7
  const ITEM_HEIGHT = 40;
8
- const NUM_ITEMS_SEARCH = 20;
8
+ const NUM_ITEMS_SEARCH = 7;
9
9
  const template = document.createElement('template');
10
10
  template.innerHTML = templateHTML;
11
11
  defineCustomElement('sinch-select-menu', class extends NectaryElement {
@@ -29,35 +29,23 @@ defineCustomElement('sinch-select-menu', class extends NectaryElement {
29
29
  }
30
30
  connectedCallback() {
31
31
  this.#controller = new AbortController();
32
- const {
33
- signal
34
- } = this.#controller;
32
+ const options = {
33
+ signal: this.#controller.signal
34
+ };
35
35
  this.setAttribute('role', 'listbox');
36
36
  this.setAttribute('tabindex', '0');
37
- this.addEventListener('keydown', this.#onListboxKeyDown, {
38
- signal
39
- });
40
- this.addEventListener('blur', this.#onListboxBlur, {
41
- signal
42
- });
43
- this.#$listbox.addEventListener('mousedown', this.#onListboxMousedown, {
44
- signal
45
- });
46
- this.#$listbox.addEventListener('click', this.#onListboxClick, {
47
- signal
48
- });
49
- this.#$search.addEventListener('-change', this.#onSearchChange, {
50
- signal
51
- });
52
- this.#$optionSlot.addEventListener('slotchange', this.#onOptionSlotChange, {
53
- signal
54
- });
55
- this.addEventListener('-change', this.#onChangeReactHandler, {
56
- signal
57
- });
58
- subscribeContext(this, 'keydown', this.#onContextKeyDown, signal);
59
- subscribeContext(this, 'visibility', this.#onContextVisibility, signal);
37
+ this.addEventListener('keydown', this.#onListboxKeyDown, options);
38
+ this.addEventListener('focus', this.#onFocus, options);
39
+ this.addEventListener('blur', this.#onListboxBlur, options);
40
+ this.#$listbox.addEventListener('mousedown', this.#onListboxMousedown, options);
41
+ this.#$listbox.addEventListener('click', this.#onListboxClick, options);
42
+ this.#$search.addEventListener('-change', this.#onSearchChange, options);
43
+ this.#$optionSlot.addEventListener('slotchange', this.#onOptionSlotChange, options);
44
+ this.addEventListener('-change', this.#onChangeReactHandler, options);
45
+ subscribeContext(this, 'keydown', this.#onContextKeyDown, this.#controller.signal);
46
+ subscribeContext(this, 'visibility', this.#onContextVisibility, this.#controller.signal);
60
47
  updateAttribute(this.#$iconSearch, 'name', getCssVar(this, '--sinch-select-menu-icon-search'));
48
+ this.#onOptionSlotChange();
61
49
  }
62
50
  disconnectedCallback() {
63
51
  this.#controller.abort();
@@ -66,24 +54,6 @@ defineCustomElement('sinch-select-menu', class extends NectaryElement {
66
54
  static get observedAttributes() {
67
55
  return ['value', 'rows', 'multiple'];
68
56
  }
69
- set value(value) {
70
- updateAttribute(this, 'value', value);
71
- }
72
- get value() {
73
- return getAttribute(this, 'value', '');
74
- }
75
- set rows(value) {
76
- updateIntegerAttribute(this, 'rows', value);
77
- }
78
- get rows() {
79
- return getIntegerAttribute(this, 'rows', null);
80
- }
81
- set multiple(isMultiple) {
82
- updateBooleanAttribute(this, 'multiple', isMultiple);
83
- }
84
- get multiple() {
85
- return getBooleanAttribute(this, 'multiple');
86
- }
87
57
  attributeChangedCallback(name, oldVal, newVal) {
88
58
  if (oldVal === newVal) {
89
59
  return;
@@ -110,6 +80,33 @@ defineCustomElement('sinch-select-menu', class extends NectaryElement {
110
80
  }
111
81
  }
112
82
  }
83
+ set value(value) {
84
+ updateAttribute(this, 'value', value);
85
+ }
86
+ get value() {
87
+ return getAttribute(this, 'value', '');
88
+ }
89
+ set rows(value) {
90
+ updateIntegerAttribute(this, 'rows', value);
91
+ }
92
+ get rows() {
93
+ return getIntegerAttribute(this, 'rows', null);
94
+ }
95
+ set multiple(isMultiple) {
96
+ updateBooleanAttribute(this, 'multiple', isMultiple);
97
+ }
98
+ get multiple() {
99
+ return getBooleanAttribute(this, 'multiple');
100
+ }
101
+ get focusable() {
102
+ return true;
103
+ }
104
+ #onFocus = () => {
105
+ const isSearchActive = hasClass(this.#$search, 'active');
106
+ if (isSearchActive) {
107
+ this.#$search.focus();
108
+ }
109
+ };
113
110
  #onListboxMousedown = e => {
114
111
  const $elem = e.target;
115
112
  if (!getBooleanAttribute($elem, 'disabled')) {
@@ -147,6 +144,7 @@ defineCustomElement('sinch-select-menu', class extends NectaryElement {
147
144
  #onContextVisibility = e => {
148
145
  if (e.detail) {
149
146
  this.#selectOption(this.#findCheckedOption());
147
+ this.#onFocus();
150
148
  } else {
151
149
  this.#selectOption(null);
152
150
  }
@@ -306,7 +304,4 @@ defineCustomElement('sinch-select-menu', class extends NectaryElement {
306
304
  #onChangeReactHandler = e => {
307
305
  getReactEventHandler(this, 'on-change')?.(e);
308
306
  };
309
- get focusable() {
310
- return true;
311
- }
312
307
  });
@@ -0,0 +1,11 @@
1
+ import type { TSinchSkeletonElement, TSinchSkeletonReact } from './types';
2
+ declare global {
3
+ namespace JSX {
4
+ interface IntrinsicElements {
5
+ 'sinch-skeleton': TSinchSkeletonReact;
6
+ }
7
+ }
8
+ interface HTMLElementTagNameMap {
9
+ 'sinch-skeleton': TSinchSkeletonElement;
10
+ }
11
+ }
@@ -0,0 +1,75 @@
1
+ import { defineCustomElement, getUid, isAttrTrue, NectaryElement, shouldReduceMotion } from '../utils';
2
+ const templateHTML = '<style>:host{display:block}#wrapper{position:relative;display:flex;flex-direction:column;gap:16px;height:100%;box-sizing:border-box;overflow:hidden}:host([card]:not([card=false]))>#wrapper{padding:16px;background-color:var(--sinch-color-snow-100);border-radius:var(--sinch-shape-radius-l);border:1px solid var(--sinch-color-snow-500)}#shimmer{position:absolute;inset:0;background-image:linear-gradient(90deg,transparent 0,var(--sinch-color-snow-400) 100px,transparent 200px);clip-path:url("#clip")}#svg{display:block;width:0;height:0}</style><svg id="svg"><defs><clipPath id="clip"></clipPath></defs></svg><div id="wrapper"><slot></slot><div id="shimmer"></div></div>';
3
+ const template = document.createElement('template');
4
+ template.innerHTML = templateHTML;
5
+ const ANIMATION_DURATION = 2000;
6
+ const BORDER_WIDTH = 1;
7
+ defineCustomElement('sinch-skeleton', class extends NectaryElement {
8
+ #animation = null;
9
+ #shimmer;
10
+ #controller = null;
11
+ #clip;
12
+ #borderWidth = 0;
13
+ constructor() {
14
+ super();
15
+ const shadowRoot = this.attachShadow();
16
+ shadowRoot.appendChild(template.content.cloneNode(true));
17
+ this.#shimmer = shadowRoot.querySelector('#shimmer');
18
+ this.#clip = shadowRoot.querySelector('#clip');
19
+ }
20
+ connectedCallback() {
21
+ const id = getUid();
22
+ this.#shimmer.style.setProperty('clip-path', `url(#${id})`);
23
+ this.#clip.setAttribute('id', id);
24
+ this.#controller = new AbortController();
25
+ if (!shouldReduceMotion()) {
26
+ this.addEventListener('skeleton-item-data', this.#onSkeletonItemData, {
27
+ signal: this.#controller.signal
28
+ });
29
+ this.#updateAnimation();
30
+ }
31
+ }
32
+ disconnectedCallback() {
33
+ this.#animation.cancel();
34
+ this.#animation = null;
35
+ this.#controller.abort();
36
+ this.#controller = null;
37
+ }
38
+ static get observedAttributes() {
39
+ return ['card'];
40
+ }
41
+ attributeChangedCallback(name, oldVal, newVal) {
42
+ if (oldVal === newVal) {
43
+ return;
44
+ }
45
+ switch (name) {
46
+ case 'card':
47
+ {
48
+ this.#borderWidth = isAttrTrue(newVal) ? BORDER_WIDTH : 0;
49
+ break;
50
+ }
51
+ }
52
+ }
53
+ #updateAnimation() {
54
+ const bb = this.getBoundingClientRect();
55
+ const bgWidth = bb.width * 4;
56
+ this.#shimmer.style.setProperty('background-size', `${bgWidth}px`);
57
+ this.#animation = this.#shimmer.animate({
58
+ backgroundPosition: [`0px`, `${bgWidth}px`]
59
+ }, {
60
+ duration: ANIMATION_DURATION,
61
+ iterations: Infinity
62
+ });
63
+ }
64
+ #onSkeletonItemData = e => {
65
+ const bb = this.getBoundingClientRect();
66
+ const data = e.detail;
67
+ const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
68
+ rect.setAttribute('x', (data.x - bb.x - this.#borderWidth).toString());
69
+ rect.setAttribute('y', (data.y - bb.y - this.#borderWidth).toString());
70
+ rect.setAttribute('width', data.width.toString());
71
+ rect.setAttribute('height', data.height.toString());
72
+ rect.setAttribute('rx', data.radius.toString());
73
+ this.#clip.appendChild(rect);
74
+ };
75
+ });
@@ -0,0 +1,9 @@
1
+ import type { TSinchElementReact } from '../types';
2
+ export type TSinchSkeletonElement = HTMLElement & {
3
+ /** Card like container */
4
+ setAttribute(name: 'card', value: ''): void;
5
+ };
6
+ export type TSinchSkeletonReact = TSinchElementReact<TSinchSkeletonElement> & {
7
+ /** Card like container */
8
+ card?: boolean;
9
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { TSinchSkeletonItemElement, TSinchSkeletonItemReact } from './types';
2
+ declare global {
3
+ namespace JSX {
4
+ interface IntrinsicElements {
5
+ 'sinch-skeleton-item': TSinchSkeletonItemReact;
6
+ }
7
+ }
8
+ interface HTMLElementTagNameMap {
9
+ 'sinch-skeleton-item': TSinchSkeletonItemElement;
10
+ }
11
+ }
@@ -0,0 +1,38 @@
1
+ import { defineCustomElement, getCssVar, NectaryElement, attrValueToInteger, shouldReduceMotion } from '../utils';
2
+ const templateHTML = '<style>:host{display:block;height:var(--sinch-size-m);--sinch-shape-radius:var(--sinch-shape-radius-m)}:host([size=xs]){height:var(--sinch-size-xs);--sinch-shape-radius:var(--sinch-shape-radius-xs)}:host([size="s"]){height:var(--sinch-size-s);--sinch-shape-radius:var(--sinch-shape-radius-s)}:host([size="m"]){height:var(--sinch-size-m);--sinch-shape-radius:var(--sinch-shape-radius-m)}:host([size="l"]){height:var(--sinch-size-l);--sinch-shape-radius:var(--sinch-shape-radius-l)}#content{height:100%;background-color:var(--sinch-color-snow-500);border-radius:var(--sinch-shape-radius)}</style><div id="content"></div>';
3
+ const template = document.createElement('template');
4
+ template.innerHTML = templateHTML;
5
+ defineCustomElement('sinch-skeleton-item', class extends NectaryElement {
6
+ constructor() {
7
+ super();
8
+ const shadowRoot = this.attachShadow();
9
+ shadowRoot.appendChild(template.content.cloneNode(true));
10
+ }
11
+ connectedCallback() {
12
+ if (!shouldReduceMotion()) {
13
+ requestAnimationFrame(() => {
14
+ const {
15
+ x,
16
+ y,
17
+ width,
18
+ height
19
+ } = this.getBoundingClientRect();
20
+ const radiusStr = getCssVar(this, '--sinch-shape-radius') ?? '0';
21
+ const radius = attrValueToInteger(radiusStr, {
22
+ min: 0,
23
+ defaultValue: 0
24
+ });
25
+ this.dispatchEvent(new CustomEvent('skeleton-item-data', {
26
+ bubbles: true,
27
+ detail: {
28
+ x,
29
+ y,
30
+ width,
31
+ height,
32
+ radius
33
+ }
34
+ }));
35
+ });
36
+ }
37
+ }
38
+ });
@@ -0,0 +1,13 @@
1
+ import type { TRect, TSinchElementReact } from '../types';
2
+ import type { TSinchSizeEx } from '../utils/size';
3
+ export type TSinchSkeletonItemBoundingBox = TRect & {
4
+ radius: number;
5
+ };
6
+ export type TSinchSkeletonItemElement = HTMLElement & {
7
+ /** Size */
8
+ setAttribute(name: 'size', value: TSinchSizeEx): void;
9
+ };
10
+ export type TSinchSkeletonItemReact = TSinchElementReact<TSinchSkeletonItemElement> & {
11
+ /** Size */
12
+ size?: TSinchSizeEx;
13
+ };
@@ -0,0 +1 @@
1
+ export {};
package/theme/chip.css CHANGED
@@ -18,6 +18,8 @@
18
18
  --sinch-chip-color-light-violet-fg: var(--sinch-color-violet-700);
19
19
  --sinch-chip-color-light-yellow-bg: var(--sinch-color-bolt-200);
20
20
  --sinch-chip-color-light-yellow-fg: var(--sinch-color-bolt-700);
21
+ --sinch-chip-color-light-red-bg: var(--sinch-color-jasper-200);
22
+ --sinch-chip-color-light-red-fg: var(--sinch-color-jasper-700);
21
23
  --sinch-chip-color-dark-blue-bg: var(--sinch-color-night-700);
22
24
  --sinch-chip-color-dark-blue-fg: var(--sinch-color-night-200);
23
25
  --sinch-chip-color-dark-brown-bg: var(--sinch-color-mud-700);
@@ -34,6 +36,8 @@
34
36
  --sinch-chip-color-dark-violet-fg: var(--sinch-color-violet-200);
35
37
  --sinch-chip-color-dark-yellow-bg: var(--sinch-color-bolt-700);
36
38
  --sinch-chip-color-dark-yellow-fg: var(--sinch-color-bolt-200);
39
+ --sinch-chip-color-dark-red-bg: var(--sinch-color-jasper-700);
40
+ --sinch-chip-color-dark-red-fg: var(--sinch-color-jasper-200);
37
41
  --sinch-chip-color-blue-bg: var(--sinch-color-night-400);
38
42
  --sinch-chip-color-blue-fg: var(--sinch-color-snow-100);
39
43
  --sinch-chip-color-brown-bg: var(--sinch-color-mud-400);
@@ -50,6 +54,8 @@
50
54
  --sinch-chip-color-violet-fg: var(--sinch-color-stormy-500);
51
55
  --sinch-chip-color-yellow-bg: var(--sinch-color-bolt-400);
52
56
  --sinch-chip-color-yellow-fg: var(--sinch-color-stormy-500);
57
+ --sinch-chip-color-red-bg: var(--sinch-color-jasper-400);
58
+ --sinch-chip-color-red-fg: var(--sinch-color-stormy-500);
53
59
  --sinch-chip-color-celtic-bg: var(--sinch-color-feedback-info-bg);
54
60
  --sinch-chip-color-celtic-fg: var(--sinch-color-feedback-info-contrast);
55
61
  --sinch-chip-color-olive-bg: var(--sinch-color-feedback-success-bg);
@@ -18,6 +18,8 @@
18
18
  --sinch-color-swatch-color-light-violet-fg: var(--sinch-color-violet-700);
19
19
  --sinch-color-swatch-color-light-yellow-bg: var(--sinch-color-bolt-200);
20
20
  --sinch-color-swatch-color-light-yellow-fg: var(--sinch-color-bolt-700);
21
+ --sinch-color-swatch-color-light-red-bg: var(--sinch-color-jasper-200);
22
+ --sinch-color-swatch-color-light-red-fg: var(--sinch-color-jasper-700);
21
23
  --sinch-color-swatch-color-dark-blue-bg: var(--sinch-color-night-700);
22
24
  --sinch-color-swatch-color-dark-blue-fg: var(--sinch-color-night-200);
23
25
  --sinch-color-swatch-color-dark-brown-bg: var(--sinch-color-mud-700);
@@ -34,6 +36,8 @@
34
36
  --sinch-color-swatch-color-dark-violet-fg: var(--sinch-color-violet-200);
35
37
  --sinch-color-swatch-color-dark-yellow-bg: var(--sinch-color-bolt-700);
36
38
  --sinch-color-swatch-color-dark-yellow-fg: var(--sinch-color-bolt-200);
39
+ --sinch-color-swatch-color-dark-red-bg: var(--sinch-color-jasper-700);
40
+ --sinch-color-swatch-color-dark-red-fg: var(--sinch-color-jasper-200);
37
41
  --sinch-color-swatch-color-blue-bg: var(--sinch-color-night-400);
38
42
  --sinch-color-swatch-color-blue-fg: var(--sinch-color-snow-100);
39
43
  --sinch-color-swatch-color-brown-bg: var(--sinch-color-mud-400);
@@ -50,6 +54,8 @@
50
54
  --sinch-color-swatch-color-violet-fg: var(--sinch-color-stormy-500);
51
55
  --sinch-color-swatch-color-yellow-bg: var(--sinch-color-bolt-400);
52
56
  --sinch-color-swatch-color-yellow-fg: var(--sinch-color-stormy-500);
57
+ --sinch-color-swatch-color-red-bg: var(--sinch-color-jasper-400);
58
+ --sinch-color-swatch-color-red-fg: var(--sinch-color-stormy-500);
53
59
  --sinch-color-swatch-color-skin-tone-0-bg: var(--sinch-color-skin-tone-0);
54
60
  --sinch-color-swatch-color-skin-tone-0-fg: var(--sinch-color-stormy-500);
55
61
  --sinch-color-swatch-color-skin-tone-10-bg: var(--sinch-color-skin-tone-10);
package/theme/colors.js CHANGED
@@ -1,4 +1,4 @@
1
- export const lightColorNames = ['light-violet', 'light-blue', 'light-green', 'light-yellow', 'light-orange', 'light-pink', 'light-brown', 'light-gray'].join(',');
2
- export const darkColorNames = ['dark-violet', 'dark-blue', 'dark-green', 'dark-yellow', 'dark-orange', 'dark-pink', 'dark-brown', 'dark-gray'].join(',');
3
- export const vibrantColorNames = ['violet', 'blue', 'green', 'yellow', 'orange', 'pink', 'brown', 'gray'].join(',');
1
+ export const lightColorNames = ['light-violet', 'light-blue', 'light-green', 'light-yellow', 'light-orange', 'light-red', 'light-pink', 'light-brown', 'light-gray'].join(',');
2
+ export const darkColorNames = ['dark-violet', 'dark-blue', 'dark-green', 'dark-yellow', 'dark-orange', 'dark-red', 'dark-pink', 'dark-brown', 'dark-gray'].join(',');
3
+ export const vibrantColorNames = ['violet', 'blue', 'green', 'yellow', 'orange', 'red', 'pink', 'brown', 'gray'].join(',');
4
4
  export const skinToneColorNames = ['skin-tone-0', 'skin-tone-10', 'skin-tone-20', 'skin-tone-30', 'skin-tone-40', 'skin-tone-50'].join(',');
package/theme/palette.css CHANGED
@@ -74,9 +74,9 @@
74
74
  --sinch-color-celtic-700: #003B7E;
75
75
  --sinch-color-celtic-400: #2071CE;
76
76
  --sinch-color-celtic-200: #D5E5F8;
77
- --sinch-color-jasper-700: #882024;
78
- --sinch-color-jasper-400: #D13D42;
79
- --sinch-color-jasper-200: #FBD5D5;
77
+ --sinch-color-jasper-700: #B71C1C;
78
+ --sinch-color-jasper-400: #F44336;
79
+ --sinch-color-jasper-200: #FFCDD2;
80
80
  --sinch-color-pumpkin-700: #9C2E00;
81
81
  --sinch-color-pumpkin-400: #F35B1C;
82
82
  --sinch-color-pumpkin-200: #FFE8D6;
package/theme/tag.css CHANGED
@@ -18,6 +18,8 @@
18
18
  --sinch-tag-color-light-violet-fg: var(--sinch-color-violet-700);
19
19
  --sinch-tag-color-light-yellow-bg: var(--sinch-color-bolt-200);
20
20
  --sinch-tag-color-light-yellow-fg: var(--sinch-color-bolt-700);
21
+ --sinch-tag-color-light-red-bg: var(--sinch-color-jasper-200);
22
+ --sinch-tag-color-light-red-fg: var(--sinch-color-jasper-700);
21
23
  --sinch-tag-color-dark-blue-bg: var(--sinch-color-night-700);
22
24
  --sinch-tag-color-dark-blue-fg: var(--sinch-color-night-200);
23
25
  --sinch-tag-color-dark-brown-bg: var(--sinch-color-mud-700);
@@ -34,6 +36,8 @@
34
36
  --sinch-tag-color-dark-violet-fg: var(--sinch-color-violet-200);
35
37
  --sinch-tag-color-dark-yellow-bg: var(--sinch-color-bolt-700);
36
38
  --sinch-tag-color-dark-yellow-fg: var(--sinch-color-bolt-200);
39
+ --sinch-tag-color-dark-red-bg: var(--sinch-color-jasper-700);
40
+ --sinch-tag-color-dark-red-fg: var(--sinch-color-jasper-200);
37
41
  --sinch-tag-color-blue-bg: var(--sinch-color-night-400);
38
42
  --sinch-tag-color-blue-fg: var(--sinch-color-snow-100);
39
43
  --sinch-tag-color-brown-bg: var(--sinch-color-mud-400);
@@ -50,6 +54,8 @@
50
54
  --sinch-tag-color-violet-fg: var(--sinch-color-stormy-500);
51
55
  --sinch-tag-color-yellow-bg: var(--sinch-color-bolt-400);
52
56
  --sinch-tag-color-yellow-fg: var(--sinch-color-stormy-500);
57
+ --sinch-tag-color-red-bg: var(--sinch-color-jasper-400);
58
+ --sinch-tag-color-red-fg: var(--sinch-color-stormy-500);
53
59
  --sinch-tag-color-celtic-bg: var(--sinch-color-feedback-info-bg);
54
60
  --sinch-tag-color-celtic-fg: var(--sinch-color-feedback-info-contrast);
55
61
  --sinch-tag-color-olive-bg: var(--sinch-color-feedback-success-bg);
@@ -1,6 +1,6 @@
1
1
  import '../title';
2
2
  import '../text';
3
- import { cloneNode, defineCustomElement, getRect, NectaryElement } from '../utils';
3
+ import { cloneNode, defineCustomElement, getRect, NectaryElement, shouldReduceMotion } from '../utils';
4
4
  const templateHTML = '<style>:host{display:block}#items{display:block;width:0;height:0;visibility:hidden;overflow:hidden}#list{display:flex;flex-direction:column;position:fixed;z-index:1;bottom:0;right:16px}.item-wrapper{height:0;opacity:0;position:relative}.item-wrapper[data-deleting]::after{content:"";position:absolute;top:0;left:0;bottom:0;right:0}</style><slot id="items"></slot><div id="list"></div>';
5
5
  const DURATION_ADD = 250;
6
6
  const DURATION_REMOVE = 250;
@@ -11,7 +11,7 @@ defineCustomElement('sinch-toast-manager', class extends NectaryElement {
11
11
  #$slot;
12
12
  #$list;
13
13
  #map = new WeakMap();
14
- #shouldReduceMotion = false;
14
+ #shouldReduceMotion;
15
15
  #animations = new Set();
16
16
  constructor() {
17
17
  super();
@@ -19,10 +19,10 @@ defineCustomElement('sinch-toast-manager', class extends NectaryElement {
19
19
  shadowRoot.appendChild(template.content.cloneNode(true));
20
20
  this.#$slot = shadowRoot.querySelector('slot');
21
21
  this.#$list = shadowRoot.querySelector('#list');
22
+ this.#shouldReduceMotion = shouldReduceMotion();
22
23
  }
23
24
  connectedCallback() {
24
25
  this.#$slot.addEventListener('slotchange', this.#onSlotChange);
25
- this.#shouldReduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
26
26
  }
27
27
  disconnectedCallback() {
28
28
  this.#$slot.removeEventListener('slotchange', this.#onSlotChange);
package/tooltip/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import '../text';
2
2
  import '../pop';
3
- import { defineCustomElement, getBooleanAttribute, getAttribute, getLiteralAttribute, updateBooleanAttribute, updateAttribute, updateLiteralAttribute, NectaryElement, setClass, rectOverlap, getReactEventHandler } from '../utils';
3
+ import { defineCustomElement, getBooleanAttribute, getAttribute, getLiteralAttribute, updateBooleanAttribute, updateAttribute, updateLiteralAttribute, NectaryElement, setClass, rectOverlap, getReactEventHandler, shouldReduceMotion } from '../utils';
4
4
  const templateHTML = '<style>:host{display:contents}#content-wrapper{padding-bottom:8px}#content{position:relative;display:block;max-width:300px;padding:2px 6px;box-sizing:border-box;color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-600);border-radius:var(--sinch-shape-radius-xs);pointer-events:none;opacity:0}:host([orientation=left]) #content-wrapper{padding-bottom:0;padding-right:8px}:host([orientation=right]) #content-wrapper{padding-bottom:0;padding-left:8px}:host([orientation^=bottom]) #content-wrapper{padding-bottom:0;padding-top:8px}#text{word-break:break-word;pointer-events:none}#tip{position:absolute;left:50%;top:100%;transform:translateX(-50%) rotate(0);transform-origin:top center;fill:var(--sinch-color-snow-600);pointer-events:none}#tip.hidden{display:none}:host([orientation=left]) #tip{transform:translateX(-50%) rotate(270deg);top:50%;left:100%}:host([orientation=right]) #tip{transform:translateX(-50%) rotate(90deg);top:50%;left:0}:host([orientation^=bottom]) #tip{transform:translateX(-50%) rotate(180deg);top:0}:host([inverted]:not([inverted=false])) #content{background-color:var(--sinch-color-stormy-500);color:var(--sinch-color-text-inverted)}:host([inverted]:not([inverted=false])) #tip{fill:var(--sinch-color-stormy-500)}</style><sinch-pop id="pop"><slot id="target" slot="target"></slot><div id="content-wrapper" slot="content"><div id="content"><sinch-text id="text" type="s"></sinch-text><svg id="tip" width="8" height="4" aria-hidden="true"><path d="m4 4 4-4h-8l4 4Z"/></svg></div></div></sinch-pop>';
5
5
  import { TooltipState } from './tooltip-state';
6
6
  import { assertOrientation, getPopOrientation, orientationValues } from './utils';
@@ -32,7 +32,7 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
32
32
  this.#$contentWrapper = shadowRoot.querySelector('#content-wrapper');
33
33
  this.#$tip = shadowRoot.querySelector('#tip');
34
34
  this.#$target = shadowRoot.querySelector('#target');
35
- this.#shouldReduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
35
+ this.#shouldReduceMotion = shouldReduceMotion();
36
36
  this.#tooltipState = new TooltipState({
37
37
  showDelay: SHOW_DELAY,
38
38
  hideDelay: this.#shouldReduceMotion ? HIDE_DELAY + ANIMATION_DURATION : HIDE_DELAY,
package/utils/dom.d.ts CHANGED
@@ -25,7 +25,9 @@ export declare function getIntegerAttribute($element: Element, attrName: string)
25
25
  export declare function getIntegerAttribute($element: Element, attrName: string, defaultValue: null): number | null;
26
26
  export declare function getIntegerAttribute($element: Element, attrName: string, defaultValue: number): number;
27
27
  export declare const setClass: (elem: Element, name: string, isSet: boolean) => void;
28
+ export declare const hasClass: (elem: Element, name: string) => boolean;
28
29
  export declare const getCssVar: (element: Element, variableName: string) => string | null;
29
30
  export declare const getCssVars: (element: Element, variableNames: string[]) => (string | null)[];
30
31
  export declare const cloneNode: (el: Element, deep: boolean) => Element;
32
+ export declare const shouldReduceMotion: () => boolean;
31
33
  export {};
package/utils/dom.js CHANGED
@@ -122,6 +122,9 @@ export function getIntegerAttribute($element, attrName, defaultValue) {
122
122
  export const setClass = (elem, name, isSet) => {
123
123
  isSet ? elem.classList.add(name) : elem.classList.remove(name);
124
124
  };
125
+ export const hasClass = (elem, name) => {
126
+ return elem.classList.contains(name);
127
+ };
125
128
  export const getCssVar = (element, variableName) => {
126
129
  const result = getComputedStyle(element).getPropertyValue(variableName).trim();
127
130
  return result === '' ? null : result;
@@ -149,4 +152,5 @@ export const cloneNode = (el, deep) => {
149
152
  return cloned;
150
153
  }
151
154
  return el.cloneNode(deep);
152
- };
155
+ };
156
+ export const shouldReduceMotion = () => window.matchMedia('(prefers-reduced-motion: reduce)').matches;
package/utils/index.d.ts CHANGED
@@ -9,3 +9,4 @@ export * from './debounce';
9
9
  export * from './get-react-event-handler';
10
10
  export * from './markdown';
11
11
  export * from './event-target';
12
+ export * from './uid';
package/utils/index.js CHANGED
@@ -8,4 +8,5 @@ export * from './throttle';
8
8
  export * from './debounce';
9
9
  export * from './get-react-event-handler';
10
10
  export * from './markdown';
11
- export * from './event-target';
11
+ export * from './event-target';
12
+ export * from './uid';
package/utils/uid.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare const getUid: () => string;
package/utils/uid.js ADDED
@@ -0,0 +1,13 @@
1
+ export const getUid = () => crypto.getRandomValues(new Uint8Array(21)).reduce((id, byte) => {
2
+ const nextByte = byte & 63;
3
+ if (nextByte < 36) {
4
+ return id + nextByte.toString(36);
5
+ }
6
+ if (nextByte < 62) {
7
+ return id + (nextByte - 26).toString(36).toUpperCase();
8
+ }
9
+ if (nextByte > 62) {
10
+ return `${id}-`;
11
+ }
12
+ return `${id}_`;
13
+ }, '');