@nectary/components 0.44.1 → 0.45.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 (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
package/pop/index.js CHANGED
@@ -1,5 +1,4 @@
1
- import dialogPolyfill from 'dialog-polyfill';
2
- import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, updateLiteralAttribute, getReactEventHandler, updateBooleanAttribute, NectaryElement, throttleAnimationFrame, isElementFocused, updateIntegerAttribute, getIntegerAttribute, getFirstFocusableElement, getFirstSlotElement, Context, dispatchContextConnectEvent, dispatchContextDisconnectEvent } from '../utils';
1
+ import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, updateLiteralAttribute, getReactEventHandler, updateBooleanAttribute, NectaryElement, throttleAnimationFrame, isElementFocused, updateIntegerAttribute, getIntegerAttribute, getFirstFocusableElement, getFirstSlotElement, Context, subscribeContext } from '../utils';
3
2
  const templateHTML = '<style>:host{display:contents;position:relative}dialog{position:fixed;left:0;top:0;margin:0;outline:0;padding:0;border:none;box-sizing:border-box;max-width:unset;max-height:unset;z-index:1;background:0 0;overflow:visible}dialog:not([open]){display:none}dialog::backdrop{background-color:transparent}dialog+.backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:transparent}dialog.fixed{position:fixed;top:50%;transform:translate(0,-50%)}._dialog_overlay{position:fixed;top:0;right:0;bottom:0;left:0}#content{position:relative;z-index:1}#target-open{display:flex;flex-direction:column;position:absolute;left:0;top:0}#focus{display:none;position:absolute;width:0;height:0}</style><slot id="target" aria-haspopup="dialog" aria-expanded="false" name="target"></slot><div id="focus" tabindex="-1"></div><dialog id="dialog"><div id="content"><slot name="content"></slot></div><div id="target-open"><slot name="target-open"></slot></div></dialog>';
4
3
  import { assertOrientation, disableScroll, enableScroll, orientationValues } from './utils';
5
4
  const template = document.createElement('template');
@@ -8,7 +7,6 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
8
7
  #$target;
9
8
  #$focus;
10
9
  #$dialog;
11
- #isConnected;
12
10
  #resizeThrottle;
13
11
  #$targetSlot;
14
12
  #$targetOpenSlot;
@@ -30,21 +28,18 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
30
28
  this.#$targetOpenSlot = shadowRoot.querySelector('slot[name="target-open"]');
31
29
  this.#$contentSlot = shadowRoot.querySelector('slot[name="content"]');
32
30
  this.#$targetOpenWrapper = shadowRoot.querySelector('#target-open');
33
- this.#isConnected = false;
34
31
  this.#resizeThrottle = throttleAnimationFrame(this.#updateOrientation);
35
32
  this.#keydownContext = new Context(this.#$contentSlot, 'keydown');
36
33
  this.#visibilityContext = new Context(this.#$contentSlot, 'visibility');
37
- dialogPolyfill.registerDialog(this.#$dialog);
38
-
39
- dialogPolyfill.dm.handleFocus_ = function () {};
40
34
  }
41
35
  connectedCallback() {
36
+ super.connectedCallback();
42
37
  this.#controller = new AbortController();
43
38
  const {
44
39
  signal
45
40
  } = this.#controller;
46
- this.#keydownContext.subscribe();
47
- this.#visibilityContext.subscribe();
41
+ this.#keydownContext.listen(signal);
42
+ this.#visibilityContext.listen(signal);
48
43
  this.setAttribute('role', 'dialog');
49
44
  this.#$dialog.addEventListener('cancel', this.#onCancel, {
50
45
  signal
@@ -55,22 +50,15 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
55
50
  this.addEventListener('-close', this.#onCloseReactHandler, {
56
51
  signal
57
52
  });
58
- this.addEventListener('-visibility', this.#onContextVisibility, {
59
- signal
60
- });
61
- dispatchContextConnectEvent(this, 'visibility');
62
- this.#isConnected = true;
53
+ subscribeContext(this, 'visibility', this.#onContextVisibility, signal);
63
54
  if (getBooleanAttribute(this, 'open')) {
64
55
  this.#onExpand();
65
56
  }
66
57
  }
67
58
  disconnectedCallback() {
59
+ super.disconnectedCallback();
68
60
  this.#controller.abort();
69
- this.#keydownContext.unsubscribe();
70
- this.#visibilityContext.unsubscribe();
71
- dispatchContextDisconnectEvent(this, 'visibility');
72
61
  this.#onCollapse();
73
- this.#isConnected = false;
74
62
  }
75
63
  static get observedAttributes() {
76
64
  return ['orientation', 'open'];
@@ -124,7 +112,9 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
124
112
  }
125
113
  case 'orientation':
126
114
  {
127
- assertOrientation(newVal);
115
+ if ('production' !== 'production') {
116
+ assertOrientation(newVal);
117
+ }
128
118
  if (this.#isOpen()) {
129
119
  this.#updateOrientation();
130
120
  }
@@ -153,7 +143,7 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
153
143
  return item;
154
144
  }
155
145
  #onExpand() {
156
- if (!this.#isConnected || this.#isOpen()) {
146
+ if (!this.isConnected || this.#isOpen()) {
157
147
  return;
158
148
  }
159
149
 
@@ -356,27 +346,15 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
356
346
  e.stopPropagation();
357
347
  };
358
348
  #dispatchContentVisibility(isVisible) {
359
- for (const $el of this.#visibilityContext.elements) {
360
- $el.dispatchEvent(new CustomEvent('-visibility', {
361
- detail: isVisible
362
- }));
363
- }
349
+ this.#visibilityContext.dispatch(isVisible);
364
350
  }
365
351
  #onTargetKeydown = e => {
366
- for (const $el of this.#keydownContext.elements) {
367
- let isPrevented = false;
368
- $el.dispatchEvent(new CustomEvent('-keydown', {
369
- detail: {
370
- code: e.code,
371
- preventDefault: () => {
372
- isPrevented = true;
373
- }
374
- }
375
- }));
376
- if (isPrevented) {
352
+ this.#keydownContext.dispatch({
353
+ code: e.code,
354
+ preventDefault: () => {
377
355
  e.preventDefault();
378
356
  }
379
- }
357
+ });
380
358
  };
381
359
  #onContextVisibility = e => {
382
360
  if (!e.detail) {
package/popover/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import '../pop';
2
- import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, updateLiteralAttribute, updateBooleanAttribute, NectaryElement, updateAttribute, getReactEventHandler, isAttrTrue, setClass, rectOverlap, dispatchContextConnectEvent, dispatchContextDisconnectEvent } from '../utils';
3
- const templateHTML = '<style>:host{display:contents}#content-wrapper{position:relative;padding-top:4px}#content{font:var(--sinch-font-body);color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-100);border:1px solid var(--sinch-color-snow-500);border-radius:var(--sinch-shape-radius-m);box-shadow:var(--sinch-elevation-level-2);overflow:hidden}#tip{position:absolute;left:50%;top:13px;transform:translateX(-50%) rotate(180deg);transform-origin:top center;fill:var(--sinch-color-snow-100);stroke:var(--sinch-color-snow-500);stroke-linecap:square;pointer-events:none;display:none}:host([orientation^=top]) #tip{transform:translateX(-50%) rotate(0);top:calc(100% - 13px)}:host([tip]) #tip:not(.hidden){display:block}:host([tip]) #content{box-shadow:none}:host([tip]) #content-wrapper{padding-top:12px;filter:drop-shadow(var(--sinch-elevation-level-2))}:host([orientation^=top]) #content-wrapper{padding-top:0;padding-bottom:4px}:host([orientation^=top][tip]) #content-wrapper{padding-top:0;padding-bottom:12px}</style><sinch-pop id="pop" inset="4"><slot name="target" slot="target"></slot><div id="content-wrapper" slot="content"><div id="content"><slot name="content"></slot></div><svg id="tip" width="16" height="9" aria-hidden="true"><path d="m0 0 8 8 8 -8"/></svg></div></sinch-pop>';
2
+ import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, updateLiteralAttribute, updateBooleanAttribute, NectaryElement, updateAttribute, getReactEventHandler, isAttrTrue, setClass, rectOverlap, subscribeContext } from '../utils';
3
+ const templateHTML = '<style>:host{display:contents}#content-wrapper{position:relative;padding-top:4px}#content{font:var(--sinch-font-text-m);color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-100);border:1px solid var(--sinch-color-snow-500);border-radius:var(--sinch-shape-radius-m);box-shadow:var(--sinch-elevation-level-2);overflow:hidden}#tip{position:absolute;left:50%;top:13px;transform:translateX(-50%) rotate(180deg);transform-origin:top center;fill:var(--sinch-color-snow-100);stroke:var(--sinch-color-snow-500);stroke-linecap:square;pointer-events:none;display:none}:host([orientation^=top]) #tip{transform:translateX(-50%) rotate(0);top:calc(100% - 13px)}:host([tip]) #tip:not(.hidden){display:block}:host([tip]) #content{box-shadow:none}:host([tip]) #content-wrapper{padding-top:12px;filter:drop-shadow(var(--sinch-elevation-level-2))}:host([orientation^=top]) #content-wrapper{padding-top:0;padding-bottom:4px}:host([orientation^=top][tip]) #content-wrapper{padding-top:0;padding-bottom:12px}</style><sinch-pop id="pop" inset="4"><slot name="target" slot="target"></slot><div id="content-wrapper" slot="content"><div id="content"><slot name="content"></slot></div><svg id="tip" width="16" height="9" aria-hidden="true"><path d="m0 0 8 8 8 -8"/></svg></div></sinch-pop>';
4
4
  import { assertOrientation, getPopOrientation, orientationValues } from './utils';
5
5
  const TIP_SIZE = 16;
6
6
  const template = document.createElement('template');
@@ -29,14 +29,10 @@ defineCustomElement('sinch-popover', class extends NectaryElement {
29
29
  this.#$pop.addEventListener('-close', this.#onPopClose, {
30
30
  signal
31
31
  });
32
- this.#$content.addEventListener('-visibility', this.#onContextVisibility, {
33
- signal
34
- });
35
- dispatchContextConnectEvent(this.#$content, 'visibility');
32
+ subscribeContext(this, 'visibility', this.#onContextVisibility, signal);
36
33
  updateAttribute(this.#$pop, 'orientation', getPopOrientation(this.orientation));
37
34
  }
38
35
  disconnectedCallback() {
39
- dispatchContextDisconnectEvent(this.#$content, 'visibility');
40
36
  this.#controller.abort();
41
37
  }
42
38
  #onPopClose = () => {
@@ -89,8 +85,10 @@ defineCustomElement('sinch-popover', class extends NectaryElement {
89
85
  switch (name) {
90
86
  case 'orientation':
91
87
  {
92
- assertOrientation(newVal);
93
- updateAttribute(this.#$pop, 'orientation', getPopOrientation(newVal));
88
+ if ('production' !== 'production') {
89
+ assertOrientation(newVal);
90
+ }
91
+ updateAttribute(this.#$pop, 'orientation', getPopOrientation(this.orientation));
94
92
  if (this.#isOpen()) {
95
93
  this.#updateTipOrientation();
96
94
  }
@@ -1,5 +1,5 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{--sinch-color-radio-outer-circle:var(--sinch-color-transparent);--sinch-color-radio-background:var(--sinch-color-snow-100);--sinch-color-radio-border:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-checked:var(--sinch-color-transparent);--sinch-color-radio-border-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-hover:var(--sinch-color-snow-500);--sinch-color-radio-border-hover:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-hover-checked:var(--sinch-color-tropical-100);--sinch-color-radio-border-hover-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-focus:var(--sinch-color-snow-700);--sinch-color-radio-border-focus:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-focus-checked:var(--sinch-color-tropical-200);--sinch-color-radio-border-focus-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-active:var(--sinch-color-stormy-100);--sinch-color-radio-border-active:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-active-checked:var(--sinch-color-tropical-300);--sinch-color-radio-border-active-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-disabled:var(--sinch-color-transparent);--sinch-color-radio-border-disabled:var(--sinch-color-stormy-100);--sinch-color-radio-outer-circle-disabled-checked:var(--sinch-color-transparent);--sinch-color-radio-border-disabled-checked:var(--sinch-color-stormy-100);display:block;outline:0}#wrapper{display:flex;height:32px;box-sizing:border-box;width:100%}#input{all:initial;display:block;width:32px;height:32px;cursor:pointer}#input:disabled{cursor:initial}#icon-container{position:relative;width:32px;height:32px}#input::before{content:"";position:absolute;top:0;left:0;width:32px;height:32px;border-radius:50%;pointer-events:none;background-color:var(--sinch-color-radio-outer-circle);transition:background-color .1s linear}#input::after{content:"";position:absolute;top:6px;left:6px;width:20px;height:20px;border-radius:50%;pointer-events:none;background-color:var(--sinch-color-radio-background);border:2px solid var(--sinch-color-radio-border);transition:background-color .1s linear;box-sizing:border-box}#icon-knob{position:absolute;left:11px;top:11px;width:10px;height:10px;border-radius:50%;transition:opacity .1s linear;opacity:0;background-color:var(--sinch-color-radio-border);pointer-events:none}@media (prefers-reduced-motion){#icon-knob,#input::after,#input::before{transition:none}}#label{align-self:center;flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding-left:8px;font:var(--sinch-font-body);color:var(--sinch-color-text-default)}:host([disabled]:not([disabled=false])) #label{color:var(--sinch-color-stormy-200)}#input:checked::before{background-color:var(--sinch-color-radio-outer-circle-checked)}#input:checked::after{border-color:var(--sinch-color-radio-border-checked)}#input:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-checked)}#input:focus::before{background-color:var(--sinch-color-radio-outer-circle-focus)}#input:focus::after{border-color:var(--sinch-color-radio-border-focus)}#input:focus~#icon-knob{background-color:var(--sinch-color-radio-border-focus)}#input:hover::before{background-color:var(--sinch-color-radio-outer-circle-hover)}#input:hover::after{border-color:var(--sinch-color-radio-border-hover)}#input:hover~#icon-knob{background-color:var(--sinch-color-radio-border-hover)}#input:active::before{background-color:var(--sinch-color-radio-outer-circle-active)}#input:active::after{border-color:var(--sinch-color-radio-border-active)}#input:active~#icon-knob{background-color:var(--sinch-color-radio-border-active)}#input:disabled::before{background-color:var(--sinch-color-radio-outer-circle-disabled)}#input:disabled::after{border-color:var(--sinch-color-radio-border-disabled)}#input:disabled~#icon-knob{background-color:var(--sinch-color-radio-border-disabled)}#input:focus:checked::before{background-color:var(--sinch-color-radio-outer-circle-focus-checked)}#input:focus:checked::after{border-color:var(--sinch-color-radio-border-focus-checked)}#input:focus:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-focus-checked)}#input:hover:checked::before{background-color:var(--sinch-color-radio-outer-circle-hover-checked)}#input:hover:checked::after{border-color:var(--sinch-color-radio-border-hover-checked)}#input:hover:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-hover-checked)}#input:active:checked::before{background-color:var(--sinch-color-radio-outer-circle-active-checked)}#input:active:checked::after{border-color:var(--sinch-color-radio-border-active-checked)}#input:active:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-active-checked)}#input:disabled:checked::before{background-color:var(--sinch-color-radio-outer-circle-disabled-checked)}#input:disabled:checked::after{border-color:var(--sinch-color-radio-border-disabled-checked)}#input:disabled:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-disabled-checked)}</style><div id="wrapper"><div id="icon-container"><input id="input" type="radio"/><div id="icon-knob"></div></div><label for="input" id="label"></label></div>';
2
+ const templateHTML = '<style>:host{--sinch-color-radio-outer-circle:var(--sinch-color-transparent);--sinch-color-radio-background:var(--sinch-color-snow-100);--sinch-color-radio-border:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-checked:var(--sinch-color-transparent);--sinch-color-radio-border-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-hover:var(--sinch-color-snow-500);--sinch-color-radio-border-hover:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-hover-checked:var(--sinch-color-tropical-100);--sinch-color-radio-border-hover-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-focus:var(--sinch-color-snow-700);--sinch-color-radio-border-focus:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-focus-checked:var(--sinch-color-tropical-200);--sinch-color-radio-border-focus-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-active:var(--sinch-color-stormy-100);--sinch-color-radio-border-active:var(--sinch-color-stormy-300);--sinch-color-radio-outer-circle-active-checked:var(--sinch-color-tropical-300);--sinch-color-radio-border-active-checked:var(--sinch-color-tropical-500);--sinch-color-radio-outer-circle-disabled:var(--sinch-color-transparent);--sinch-color-radio-border-disabled:var(--sinch-color-stormy-100);--sinch-color-radio-outer-circle-disabled-checked:var(--sinch-color-transparent);--sinch-color-radio-border-disabled-checked:var(--sinch-color-stormy-100);display:block;outline:0}#wrapper{display:flex;height:32px;box-sizing:border-box;width:100%}#input{all:initial;display:block;width:32px;height:32px;cursor:pointer}#input:disabled{cursor:initial}#icon-container{position:relative;width:32px;height:32px}#input::before{content:"";position:absolute;top:0;left:0;width:32px;height:32px;border-radius:50%;pointer-events:none;background-color:var(--sinch-color-radio-outer-circle);transition:background-color .1s linear}#input::after{content:"";position:absolute;top:6px;left:6px;width:20px;height:20px;border-radius:50%;pointer-events:none;background-color:var(--sinch-color-radio-background);border:2px solid var(--sinch-color-radio-border);transition:background-color .1s linear;box-sizing:border-box}#icon-knob{position:absolute;left:11px;top:11px;width:10px;height:10px;border-radius:50%;transition:opacity .1s linear;opacity:0;background-color:var(--sinch-color-radio-border);pointer-events:none}@media (prefers-reduced-motion){#icon-knob,#input::after,#input::before{transition:none}}#label{align-self:center;flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding-left:8px;font:var(--sinch-font-text-m);color:var(--sinch-color-text-default)}:host([disabled]:not([disabled=false])) #label{color:var(--sinch-color-stormy-200)}#input:checked::before{background-color:var(--sinch-color-radio-outer-circle-checked)}#input:checked::after{border-color:var(--sinch-color-radio-border-checked)}#input:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-checked)}#input:focus::before{background-color:var(--sinch-color-radio-outer-circle-focus)}#input:focus::after{border-color:var(--sinch-color-radio-border-focus)}#input:focus~#icon-knob{background-color:var(--sinch-color-radio-border-focus)}#input:hover::before{background-color:var(--sinch-color-radio-outer-circle-hover)}#input:hover::after{border-color:var(--sinch-color-radio-border-hover)}#input:hover~#icon-knob{background-color:var(--sinch-color-radio-border-hover)}#input:active::before{background-color:var(--sinch-color-radio-outer-circle-active)}#input:active::after{border-color:var(--sinch-color-radio-border-active)}#input:active~#icon-knob{background-color:var(--sinch-color-radio-border-active)}#input:disabled::before{background-color:var(--sinch-color-radio-outer-circle-disabled)}#input:disabled::after{border-color:var(--sinch-color-radio-border-disabled)}#input:disabled~#icon-knob{background-color:var(--sinch-color-radio-border-disabled)}#input:focus:checked::before{background-color:var(--sinch-color-radio-outer-circle-focus-checked)}#input:focus:checked::after{border-color:var(--sinch-color-radio-border-focus-checked)}#input:focus:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-focus-checked)}#input:hover:checked::before{background-color:var(--sinch-color-radio-outer-circle-hover-checked)}#input:hover:checked::after{border-color:var(--sinch-color-radio-border-hover-checked)}#input:hover:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-hover-checked)}#input:active:checked::before{background-color:var(--sinch-color-radio-outer-circle-active-checked)}#input:active:checked::after{border-color:var(--sinch-color-radio-border-active-checked)}#input:active:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-active-checked)}#input:disabled:checked::before{background-color:var(--sinch-color-radio-outer-circle-disabled-checked)}#input:disabled:checked::after{border-color:var(--sinch-color-radio-border-disabled-checked)}#input:disabled:checked~#icon-knob{opacity:1;background-color:var(--sinch-color-radio-border-disabled-checked)}</style><div id="wrapper"><div id="icon-container"><input id="input" type="radio"/><div id="icon-knob"></div></div><label for="input" id="label"></label></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-radio-option', class extends NectaryElement {
package/segment/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import '../title';
2
2
  import { getTitleLevelFromType } from '../title/utils';
3
3
  import { defineCustomElement, getAttribute, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, NectaryElement, setClass, updateAttribute, updateBooleanAttribute, updateLiteralAttribute } from '../utils';
4
- const templateHTML = '<style>:host{display:block}#wrapper{display:flex;flex-direction:column;gap:12px;width:100%;height:100%;border:1px solid var(--sinch-color-snow-700);border-radius:var(--sinch-shape-radius-l);box-sizing:border-box;background-color:var(--sinch-color-snow-100);color:var(--sinch-color-text-default);font:var(--sinch-font-body);box-shadow:var(--sinch-elevation-level-2);padding:8px 0 16px}#header{display:flex;flex-direction:row;align-items:center;height:48px;gap:8px;padding:0 24px;--sinch-size-icon:32px}#caption{color:var(--sinch-color-text-default);min-width:1em}#info{display:flex;flex-direction:row;align-items:center;gap:8px;margin-left:auto;align-self:stretch}#info.empty{display:none}#preview{flex:1;flex-basis:auto;height:48px;min-width:0;overflow:hidden;margin-left:24px}#preview.empty{display:none}#info.empty+#collapse{margin-left:auto}#collapse.empty{display:none}#preview:not(.empty)+#info.empty+#collapse:not(.empty),#preview:not(.empty)+#info:not(.empty){margin-left:24px}#content-wrapper{flex:1;min-height:0;overflow-y:auto;padding:4px 24px}#action{display:flex;flex-direction:row;justify-content:flex-end;gap:16px;padding:0 24px}#action.empty{display:none}:host([collapsed]:not([collapsed=false])) :is(#content-wrapper,#action){display:none}:host([collapsed]:not([collapsed=false])) #wrapper{padding-bottom:8px}::slotted([slot=icon]){margin-right:8px}</style><div id="wrapper"><div id="header"><slot name="icon"></slot><sinch-title id="caption" level="3" type="m" ellipsis></sinch-title><div id="preview"><slot name="preview"></slot></div><div id="info"><slot name="info"></slot></div><div id="collapse"><slot name="collapse"></slot></div></div><div id="content-wrapper"><slot name="content"></slot></div><div id="action"><slot name="action"></slot></div></div>';
5
- import { assertSize, sizeValues } from './utils';
4
+ import { assertSize, DEFAULT_SIZE, sizeValues } from '../utils/size';
5
+ const templateHTML = '<style>:host{display:block}#wrapper{display:flex;flex-direction:column;gap:12px;width:100%;height:100%;border:1px solid var(--sinch-color-snow-700);border-radius:var(--sinch-shape-radius-l);box-sizing:border-box;background-color:var(--sinch-color-snow-100);color:var(--sinch-color-text-default);font:var(--sinch-font-text-m);padding:8px 0 16px}#header{display:flex;flex-direction:row;align-items:center;height:48px;gap:8px;padding:0 24px;--sinch-size-icon:32px}#caption{color:var(--sinch-color-text-default);min-width:1em}#info{display:flex;flex-direction:row;align-items:center;gap:8px;margin-left:auto;align-self:stretch}#info.empty{display:none}#preview{flex:1;flex-basis:auto;height:48px;min-width:0;overflow:hidden;margin-left:24px}#preview.empty{display:none}#info.empty+#collapse{margin-left:auto}#collapse.empty{display:none}#preview:not(.empty)+#info.empty+#collapse:not(.empty),#preview:not(.empty)+#info:not(.empty){margin-left:24px}#content-wrapper{flex:1;min-height:0;overflow-y:auto;padding:4px 24px}#action{display:flex;flex-direction:row;justify-content:flex-end;gap:16px;padding:0 24px}#action.empty{display:none}:host([collapsed]:not([collapsed=false])) :is(#content-wrapper,#action){display:none}:host([collapsed]:not([collapsed=false])) #wrapper{padding-bottom:8px}::slotted([slot=icon]){margin-right:8px}</style><div id="wrapper"><div id="header"><slot name="icon"></slot><sinch-title id="caption" level="3" type="m" ellipsis></sinch-title><div id="preview"><slot name="preview"></slot></div><div id="info"><slot name="info"></slot></div><div id="collapse"><slot name="collapse"></slot></div></div><div id="content-wrapper"><slot name="content"></slot></div><div id="action"><slot name="action"></slot></div></div>';
6
+ import { getTitleTypeFromSize } from './utils';
6
7
  const template = document.createElement('template');
7
8
  template.innerHTML = templateHTML;
8
9
  defineCustomElement('sinch-segment', class extends NectaryElement {
@@ -62,9 +63,12 @@ defineCustomElement('sinch-segment', class extends NectaryElement {
62
63
  }
63
64
  case 'size':
64
65
  {
65
- assertSize(newVal);
66
- updateAttribute(this.#$caption, 'type', newVal);
67
- updateAttribute(this.#$caption, 'level', getTitleLevelFromType(newVal));
66
+ if ('production' !== 'production') {
67
+ assertSize(newVal, 'sinch-segment');
68
+ }
69
+ const titleType = getTitleTypeFromSize(this.size);
70
+ updateAttribute(this.#$caption, 'type', titleType);
71
+ updateAttribute(this.#$caption, 'level', getTitleLevelFromType(titleType));
68
72
  break;
69
73
  }
70
74
  }
@@ -82,7 +86,7 @@ defineCustomElement('sinch-segment', class extends NectaryElement {
82
86
  return getBooleanAttribute(this, 'collapsed');
83
87
  }
84
88
  get size() {
85
- return getLiteralAttribute(this, sizeValues, 'size', 'm');
89
+ return getLiteralAttribute(this, sizeValues, 'size', DEFAULT_SIZE);
86
90
  }
87
91
  set size(value) {
88
92
  updateLiteralAttribute(this, sizeValues, 'size', value);
@@ -1,16 +1,16 @@
1
1
  import type { TRect, TSinchElementReact } from '../types';
2
- export declare type TSinchSegmentSize = 'l' | 'm' | 's';
2
+ import type { TSinchSize } from '../utils/size';
3
3
  export declare type TSinchSegmentElement = HTMLElement & {
4
4
  caption: string;
5
5
  collapsed: boolean;
6
- size: TSinchSegmentSize;
6
+ size: TSinchSize;
7
7
  readonly collapseButtonRect: TRect | null;
8
8
  setAttribute(name: 'caption', value: string): void;
9
9
  setAttribute(name: 'collapsed', value: ''): void;
10
- setAttribute(name: 'size', value: TSinchSegmentSize): void;
10
+ setAttribute(name: 'size', value: TSinchSize): void;
11
11
  };
12
12
  export declare type TSinchSegmentReact = TSinchElementReact<TSinchSegmentElement> & {
13
13
  caption: string;
14
14
  collapsed?: boolean;
15
- size?: TSinchSegmentSize;
15
+ size?: TSinchSize;
16
16
  };
@@ -1,5 +1,3 @@
1
- import type { TSinchSegmentSize } from './types';
2
- export declare const sizeValues: readonly TSinchSegmentSize[];
3
- declare type TAssertSize = (value: string | null) => asserts value is TSinchSegmentSize;
4
- export declare const assertSize: TAssertSize;
5
- export {};
1
+ import type { TSinchTitleType } from '../title/types';
2
+ import type { TSinchSize } from '../utils/size';
3
+ export declare const getTitleTypeFromSize: (size: TSinchSize) => TSinchTitleType;
package/segment/utils.js CHANGED
@@ -1,6 +1,16 @@
1
- export const sizeValues = ['l', 'm', 's'];
2
- export const assertSize = value => {
3
- if (value === null || !sizeValues.includes(value)) {
4
- throw new Error(`sinch-segment: invalid size attribute: ${value}`);
1
+ export const getTitleTypeFromSize = size => {
2
+ switch (size) {
3
+ case 'l':
4
+ {
5
+ return 'l';
6
+ }
7
+ case 's':
8
+ {
9
+ return 's';
10
+ }
11
+ default:
12
+ {
13
+ return 'm';
14
+ }
5
15
  }
6
16
  };
@@ -2,7 +2,7 @@ import '../icons/expand-less';
2
2
  import '../icons/expand-more';
3
3
  import '../icon-button';
4
4
  import { defineCustomElement, getBooleanAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
5
- const templateHTML = '<style>:host{display:block;--sinch-size-icon:32px}#up{display:block}#down{display:none}:host([value]:not([value=false])) #up{display:none}:host([value]:not([value=false])) #down{display:block}</style><sinch-icon-button id="button" small><sinch-icon-expand-less id="up" slot="icon"></sinch-icon-expand-less><sinch-icon-expand-more id="down" slot="icon"></sinch-icon-expand-more></sinch-icon-button>';
5
+ const templateHTML = '<style>:host{display:block;--sinch-size-icon:32px}#up{display:block}#down{display:none}:host([value]:not([value=false])) #up{display:none}:host([value]:not([value=false])) #down{display:block}</style><sinch-icon-button id="button" size="s"><sinch-icon-expand-less id="up" slot="icon"></sinch-icon-expand-less><sinch-icon-expand-more id="down" slot="icon"></sinch-icon-expand-more></sinch-icon-button>';
6
6
  const template = document.createElement('template');
7
7
  template.innerHTML = templateHTML;
8
8
  defineCustomElement('sinch-segment-collapse', class extends NectaryElement {
@@ -1,5 +1,5 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:block;outline:0}#wrapper{display:flex;position:relative;flex-direction:row;align-items:center;gap:12px;width:100%;height:32px;padding:0 16px;box-sizing:border-box;border:1px solid var(--sinch-color-snow-600);border-left-width:0;border-right-width:0;color:var(--sinch-color-stormy-500);background-color:var(--sinch-color-snow-100);--sinch-color-icon:var(--sinch-color-stormy-500);--sinch-size-icon:16px}#wrapper:hover{background-color:var(--sinch-color-snow-400)}:host(:first-child) #wrapper{border-left-width:1px;border-top-left-radius:4px;border-bottom-left-radius:4px}:host(:last-child) #wrapper{border-right-width:1px;border-top-right-radius:4px;border-bottom-right-radius:4px}#content{font:var(--sinch-font-title-s);flex-shrink:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host([data-checked]) #wrapper{border-color:var(--sinch-color-stormy-500)}:host([data-checked]:not(:first-child)) #wrapper::before{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;left:0;top:-1px;bottom:-1px}:host([data-checked]:not(:last-child)) #wrapper::after{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;right:0;top:-1px;bottom:-1px}#button{all:initial;position:absolute;left:0;top:0;box-sizing:border-box;width:100%;height:100%;cursor:pointer;z-index:1}#button:disabled{cursor:unset}#button:focus::before{content:"";position:absolute;left:-3px;right:-3px;top:-4px;bottom:-4px;border-style:solid;border-color:var(--sinch-color-border-focus);border-width:0}#button:focus-visible::before{border-width:2px}:host(:first-child) #button:focus::before{left:-4px;border-top-left-radius:6px;border-bottom-left-radius:6px}:host(:last-child) #button:focus::before{right:-4px;border-top-right-radius:6px;border-bottom-right-radius:6px}@supports not selector(:focus-visible){#button:focus::before{border-width:2px}}:host([disabled]:not([disabled=false])) #wrapper{background-color:var(--sinch-color-snow-100);color:var(--sinch-color-stormy-100);--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><slot name="icon"></slot><label for="button" id="content"></label><button id="button"></button></div>';
2
+ const templateHTML = '<style>:host{display:block;outline:0}#wrapper{display:flex;position:relative;flex-direction:row;align-items:center;gap:12px;width:100%;height:32px;padding:0 16px;box-sizing:border-box;border:1px solid var(--sinch-color-snow-600);border-left-width:0;border-right-width:0;color:var(--sinch-color-stormy-500);background-color:var(--sinch-color-snow-100);--sinch-color-icon:var(--sinch-color-stormy-500);--sinch-size-icon:16px}#wrapper:hover{background-color:var(--sinch-color-snow-400)}:host(:first-child) #wrapper{border-left-width:1px;border-top-left-radius:4px;border-bottom-left-radius:4px}:host(:last-child) #wrapper{border-right-width:1px;border-top-right-radius:4px;border-bottom-right-radius:4px}#content{font:var(--sinch-font-title-s);flex-shrink:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host([data-checked]) #wrapper{border-color:var(--sinch-color-stormy-500)}:host([data-checked]:not(:first-child)) #wrapper::before{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;left:0;top:-1px;bottom:-1px}:host([data-checked]:not(:last-child)) #wrapper::after{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;right:0;top:-1px;bottom:-1px}#button{all:initial;position:absolute;left:0;top:0;box-sizing:border-box;width:100%;height:100%;cursor:pointer;z-index:1}#button:disabled{cursor:unset}#button:focus::before{content:"";position:absolute;left:-3px;right:-3px;top:-4px;bottom:-4px;border-style:solid;border-color:var(--sinch-color-border-focus);border-width:0}#button:focus-visible::before{border-width:2px}:host(:first-child) #button:focus::before{left:-4px;border-top-left-radius:6px;border-bottom-left-radius:6px}:host(:last-child) #button:focus::before{right:-4px;border-top-right-radius:6px;border-bottom-right-radius:6px}:host([disabled]:not([disabled=false])) #wrapper{background-color:var(--sinch-color-snow-100);color:var(--sinch-color-stormy-100);--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><slot name="icon"></slot><label for="button" id="content"></label><button id="button"></button></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-segmented-control-option', class extends NectaryElement {
@@ -1,5 +1,5 @@
1
1
  import { defineCustomElement, getAttribute, getBooleanAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:block;outline:0}#wrapper{position:relative;width:56px;height:32px;padding:3px 16px;box-sizing:border-box;border:1px solid var(--sinch-color-snow-600);border-left-width:0;border-right-width:0;color:var(--sinch-color-stormy-500);background-color:var(--sinch-color-snow-100);--sinch-color-icon:var(--sinch-color-stormy-500);--sinch-size-icon:24px}#wrapper:hover{background-color:var(--sinch-color-snow-400)}:host(:first-child) #wrapper{border-left-width:1px;border-top-left-radius:4px;border-bottom-left-radius:4px}:host(:last-child) #wrapper{border-right-width:1px;border-top-right-radius:4px;border-bottom-right-radius:4px}:host([data-checked]) #wrapper{border-color:var(--sinch-color-stormy-500)}:host([data-checked]:not(:first-child)) #wrapper::before{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;left:-1px;top:-1px;bottom:-1px}:host([data-checked]:not(:last-child)) #wrapper::after{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;right:0;top:-1px;bottom:-1px}#button{all:initial;position:absolute;left:0;top:0;box-sizing:border-box;width:100%;height:100%;cursor:pointer;z-index:1}#button:disabled{cursor:unset}#button:focus::before{content:"";position:absolute;left:-4px;right:-3px;top:-4px;bottom:-4px;border-style:solid;border-color:var(--sinch-color-border-focus);border-width:0}#button:focus-visible::before{border-width:2px}:host(:first-child) #button:focus::before{left:-4px;border-top-left-radius:6px;border-bottom-left-radius:6px}:host(:last-child) #button:focus::before{right:-4px;border-top-right-radius:6px;border-bottom-right-radius:6px}@supports not selector(:focus-visible){#button:focus::before{border-width:2px}}:host([disabled]:not([disabled=false])) #wrapper{background-color:var(--sinch-color-snow-100);color:var(--sinch-color-stormy-100);--sinch-color-icon:var(--sinch-color-stormy-100)}::slotted(*){display:block}</style><div id="wrapper"><slot name="icon"></slot><button id="button"></button></div>';
2
+ const templateHTML = '<style>:host{display:block;outline:0}#wrapper{position:relative;width:56px;height:32px;padding:3px 16px;box-sizing:border-box;border:1px solid var(--sinch-color-snow-600);border-left-width:0;border-right-width:0;color:var(--sinch-color-stormy-500);background-color:var(--sinch-color-snow-100);--sinch-color-icon:var(--sinch-color-stormy-500);--sinch-size-icon:24px}#wrapper:hover{background-color:var(--sinch-color-snow-400)}:host(:first-child) #wrapper{border-left-width:1px;border-top-left-radius:4px;border-bottom-left-radius:4px}:host(:last-child) #wrapper{border-right-width:1px;border-top-right-radius:4px;border-bottom-right-radius:4px}:host([data-checked]) #wrapper{border-color:var(--sinch-color-stormy-500)}:host([data-checked]:not(:first-child)) #wrapper::before{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;left:-1px;top:-1px;bottom:-1px}:host([data-checked]:not(:last-child)) #wrapper::after{content:"";width:1px;background-color:var(--sinch-color-stormy-500);position:absolute;right:0;top:-1px;bottom:-1px}#button{all:initial;position:absolute;left:0;top:0;box-sizing:border-box;width:100%;height:100%;cursor:pointer;z-index:1}#button:disabled{cursor:unset}#button:focus::before{content:"";position:absolute;left:-4px;right:-3px;top:-4px;bottom:-4px;border-style:solid;border-color:var(--sinch-color-border-focus);border-width:0}#button:focus-visible::before{border-width:2px}:host(:first-child) #button:focus::before{left:-4px;border-top-left-radius:6px;border-bottom-left-radius:6px}:host(:last-child) #button:focus::before{right:-4px;border-top-right-radius:6px;border-bottom-right-radius:6px}:host([disabled]:not([disabled=false])) #wrapper{background-color:var(--sinch-color-snow-100);color:var(--sinch-color-stormy-100);--sinch-color-icon:var(--sinch-color-stormy-100)}::slotted(*){display:block}</style><div id="wrapper"><slot name="icon"></slot><button id="button"></button></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-segmented-icon-control-option', class extends NectaryElement {
@@ -1,21 +1,33 @@
1
1
  import '../text';
2
2
  import '../icons/keyboard-arrow-down';
3
- import { defineCustomElement, getAttribute, getBooleanAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
4
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle}#wrapper{position:relative;display:flex;flex-direction:row;align-items:center;gap:8px;box-sizing:border-box;width:100%;height:48px;padding:0 12px;background-color:var(--sinch-color-snow-100);border-radius:var(--sinch-shape-radius-s);--sinch-size-icon:24px;--sinch-color-icon:var(--sinch-color-stormy-500)}#button{all:initial;cursor:pointer;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1;border-radius:var(--sinch-shape-radius-s);border:1px solid var(--sinch-color-stormy-200);box-sizing:border-box}#text{flex:1;min-width:0;color:var(--sinch-color-text-muted)}:host([text]:not([text=""])) #text{color:var(--sinch-color-text-default)}#button:disabled{border-color:var(--sinch-color-snow-500);cursor:initial}#button:focus-visible{border-color:var(--sinch-color-stormy-600)}@supports not selector(:focus-visible){#button:focus{border-color:var(--sinch-color-stormy-600)}}:host([invalid]) #button:enabled{border-color:var(--sinch-color-text-invalid)}#button:disabled~#text{color:var(--sinch-color-stormy-100)}:host([disabled]) #wrapper{--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><button id="button"></button><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text><sinch-icon-keyboard-arrow-down></sinch-icon-keyboard-arrow-down></div>';
3
+ import { defineCustomElement, getAttribute, getBooleanAttribute, getLiteralAttribute, getReactEventHandler, isAttrTrue, NectaryElement, setClass, subscribeContext, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateLiteralAttribute, Context } from '../utils';
4
+ import { assertSize, DEFAULT_SIZE, sizeValues } from '../utils/size';
5
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0;--sinch-size:var(--sinch-size-m);--sinch-size-icon:var(--sinch-select-button-icon-size-m);--sinch-shape-radius:var(--sinch-shape-radius-m)}:host([data-size="l"]){--sinch-size:var(--sinch-size-l);--sinch-size-icon:var(--sinch-select-button-icon-size-l);--sinch-shape-radius:var(--sinch-shape-radius-l)}:host([data-size="m"]){--sinch-size:var(--sinch-size-m);--sinch-size-icon:var(--sinch-select-button-icon-size-m);--sinch-shape-radius:var(--sinch-shape-radius-m)}:host([data-size="s"]){--sinch-size:var(--sinch-size-s);--sinch-size-icon:var(--sinch-select-button-icon-size-s);--sinch-shape-radius:var(--sinch-shape-radius-s)}#wrapper{position:relative;display:flex;flex-direction:row;align-items:center;gap:8px;box-sizing:border-box;width:100%;height:var(--sinch-size);padding:0 8px 0 12px;background-color:var(--sinch-color-bg-primary-light);border-radius:var(--sinch-shape-radius);--sinch-color-icon:var(--sinch-color-stormy-500)}:host([disabled]:not([disabled=false])) #wrapper{--sinch-color-icon:var(--sinch-color-text-disabled)}:host([data-size="l"]) #wrapper{padding:0 12px}:host([data-size="m"]) #wrapper{padding:0 8px 0 12px}:host([data-size="s"]) #wrapper{padding:0 4px 0 12px}#button{all:initial;cursor:pointer;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}#border{position:absolute;border:1px solid var(--sinch-color-border-dark);border-radius:var(--sinch-shape-radius);inset:0;pointer-events:none}#text{flex:1;min-width:0;color:var(--sinch-color-text-muted)}:host([text]:not([text=""])) #text{color:var(--sinch-color-text-default)}#button:disabled{cursor:initial}#button:disabled+#border{border-color:var(--sinch-color-border-disabled)}#button:focus-visible+#border{border-color:var(--sinch-color-border-focus);border-width:2px}:host([invalid]) #button:enabled+#border{border-color:var(--sinch-color-text-invalid)}#button:disabled~#text{color:var(--sinch-color-text-disabled)}#left{display:flex;flex-direction:row;align-self:stretch;align-items:center;gap:4px;margin-left:-4px}#left.empty{display:none}#dropdown-icon{margin-left:-4px}</style><div id="wrapper"><button id="button"></button><div id="border"></div><div id="left"><slot name="left"></slot></div><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text><sinch-icon-keyboard-arrow-down id="dropdown-icon"></sinch-icon-keyboard-arrow-down></div>';
5
6
  const template = document.createElement('template');
6
7
  template.innerHTML = templateHTML;
7
8
  defineCustomElement('sinch-select-button', class extends NectaryElement {
8
9
  #$button;
9
10
  #$text;
11
+ #$leftSlot;
12
+ #$leftWrapper;
13
+ #$wrapper;
10
14
  #controller = null;
15
+ #sizeContext;
11
16
  constructor() {
12
17
  super();
13
- const shadowRoot = this.attachShadow();
18
+ const shadowRoot = this.attachShadow({
19
+ delegatesFocus: true
20
+ });
14
21
  shadowRoot.appendChild(template.content.cloneNode(true));
15
22
  this.#$button = shadowRoot.querySelector('#button');
16
23
  this.#$text = shadowRoot.querySelector('#text');
24
+ this.#$leftSlot = shadowRoot.querySelector('slot[name="left"]');
25
+ this.#$leftWrapper = shadowRoot.querySelector('#left');
26
+ this.#$wrapper = shadowRoot.querySelector('#wrapper');
27
+ this.#sizeContext = new Context(this.#$wrapper, 'size');
17
28
  }
18
29
  connectedCallback() {
30
+ super.connectedCallback();
19
31
  this.#controller = new AbortController();
20
32
  const {
21
33
  signal
@@ -39,36 +51,20 @@ defineCustomElement('sinch-select-button', class extends NectaryElement {
39
51
  this.addEventListener('-blur', this.#onBlurReactHandler, {
40
52
  signal
41
53
  });
54
+ this.#$leftSlot.addEventListener('slotchange', this.#onLeftSlotChange, {
55
+ signal
56
+ });
57
+ this.#sizeContext.listen(this.#controller.signal);
58
+ subscribeContext(this, 'size', this.#onContextSize, signal);
59
+ this.#onLeftSlotChange();
60
+ this.#onSizeUpdate();
42
61
  }
43
62
  disconnectedCallback() {
63
+ super.disconnectedCallback();
44
64
  this.#controller.abort();
45
65
  }
46
66
  static get observedAttributes() {
47
- return ['text', 'placeholder', 'invalid', 'disabled'];
48
- }
49
- set text(value) {
50
- updateAttribute(this, 'text', value);
51
- }
52
- get text() {
53
- return getAttribute(this, 'text', '');
54
- }
55
- set placeholder(value) {
56
- updateAttribute(this, 'placeholder', value);
57
- }
58
- get placeholder() {
59
- return getAttribute(this, 'placeholder');
60
- }
61
- set invalid(isInvalid) {
62
- updateBooleanAttribute(this, 'invalid', isInvalid);
63
- }
64
- get invalid() {
65
- return getBooleanAttribute(this, 'invalid');
66
- }
67
- set disabled(isDisabled) {
68
- updateBooleanAttribute(this, 'disabled', isDisabled);
69
- }
70
- get disabled() {
71
- return getBooleanAttribute(this, 'disabled');
67
+ return ['text', 'placeholder', 'invalid', 'disabled', 'size', 'data-size'];
72
68
  }
73
69
  attributeChangedCallback(name, oldVal, newVal) {
74
70
  if (oldVal === newVal) {
@@ -103,8 +99,51 @@ defineCustomElement('sinch-select-button', class extends NectaryElement {
103
99
  updateBooleanAttribute(this, 'disabled', isDisabled);
104
100
  break;
105
101
  }
102
+ case 'size':
103
+ {
104
+ updateAttribute(this, 'data-size', newVal);
105
+ break;
106
+ }
107
+ case 'data-size':
108
+ {
109
+ if ('production' !== 'production') {
110
+ assertSize(newVal, 'sinch-select-button');
111
+ }
112
+ this.#onSizeUpdate();
113
+ break;
114
+ }
106
115
  }
107
116
  }
117
+ set text(value) {
118
+ updateAttribute(this, 'text', value);
119
+ }
120
+ get text() {
121
+ return getAttribute(this, 'text', '');
122
+ }
123
+ set placeholder(value) {
124
+ updateAttribute(this, 'placeholder', value);
125
+ }
126
+ get placeholder() {
127
+ return getAttribute(this, 'placeholder');
128
+ }
129
+ set invalid(isInvalid) {
130
+ updateBooleanAttribute(this, 'invalid', isInvalid);
131
+ }
132
+ get invalid() {
133
+ return getBooleanAttribute(this, 'invalid');
134
+ }
135
+ set disabled(isDisabled) {
136
+ updateBooleanAttribute(this, 'disabled', isDisabled);
137
+ }
138
+ get disabled() {
139
+ return getBooleanAttribute(this, 'disabled');
140
+ }
141
+ set size(size) {
142
+ updateLiteralAttribute(this, sizeValues, 'size', size);
143
+ }
144
+ get size() {
145
+ return getLiteralAttribute(this, sizeValues, 'size', DEFAULT_SIZE);
146
+ }
108
147
  get focusable() {
109
148
  return true;
110
149
  }
@@ -114,6 +153,32 @@ defineCustomElement('sinch-select-button', class extends NectaryElement {
114
153
  blur() {
115
154
  this.#$button.blur();
116
155
  }
156
+ #onContextSize = e => {
157
+ if (this.hasAttribute('size')) {
158
+ return;
159
+ }
160
+ switch (e.detail) {
161
+ case 'l':
162
+ {
163
+ this.setAttribute('data-size', 'm');
164
+ break;
165
+ }
166
+ default:
167
+ {
168
+ this.setAttribute('data-size', 's');
169
+ }
170
+ }
171
+ };
172
+ #onSizeUpdate() {
173
+ if (!this.isConnected) {
174
+ return;
175
+ }
176
+ const size = this.getAttribute('data-size') ?? DEFAULT_SIZE;
177
+ this.#sizeContext.dispatch(size);
178
+ }
179
+ #onLeftSlotChange = () => {
180
+ setClass(this.#$leftWrapper, 'empty', this.#$leftSlot.assignedElements().length === 0);
181
+ };
117
182
  #onButtonFocus = () => {
118
183
  this.dispatchEvent(new CustomEvent('-focus'));
119
184
  };
@@ -1,4 +1,5 @@
1
1
  import type { TSinchElementReact } from '../types';
2
+ import type { TSinchSize } from '../utils/size';
2
3
  export declare type TSinchSelectButtonElement = HTMLElement & {
3
4
  /** Text */
4
5
  text: string;
@@ -8,6 +9,8 @@ export declare type TSinchSelectButtonElement = HTMLElement & {
8
9
  invalid: boolean;
9
10
  /** Disabled */
10
11
  disabled: boolean;
12
+ /** Size, `m` by default */
13
+ size: TSinchSize;
11
14
  /** Click event */
12
15
  addEventListener(type: '-click', listener: (e: CustomEvent<void>) => void): void;
13
16
  /** Focus event */
@@ -22,6 +25,8 @@ export declare type TSinchSelectButtonElement = HTMLElement & {
22
25
  setAttribute(name: 'invalid', value: ''): void;
23
26
  /** Disabled */
24
27
  setAttribute(name: 'disabled', value: ''): void;
28
+ /** Size, `m` by default */
29
+ setAttribute(name: 'size', value: TSinchSize): void;
25
30
  };
26
31
  export declare type TSinchSelectButtonReact = TSinchElementReact<TSinchSelectButtonElement> & {
27
32
  /** Text */
@@ -34,8 +39,10 @@ export declare type TSinchSelectButtonReact = TSinchElementReact<TSinchSelectBut
34
39
  invalid?: boolean;
35
40
  /** Disabled */
36
41
  disabled?: boolean;
42
+ /** Size, `m` by default */
43
+ size?: TSinchSize;
37
44
  /** Click handler */
38
- 'on-click'?: (e: CustomEvent<void>) => void;
45
+ 'on-click': (e: CustomEvent<void>) => void;
39
46
  /** Focus handler */
40
47
  'on-focus'?: (e: CustomEvent<void>) => void;
41
48
  /** Blur handler */
@@ -1,3 +1,8 @@
1
+ import '../input';
2
+ import '../icon-button';
3
+ import '../icons/search';
4
+ import '../icons/close';
5
+ import '../text';
1
6
  import type { TSinchSelectMenuElement, TSinchSelectMenuReact } from './types';
2
7
  declare global {
3
8
  namespace JSX {