@nectary/components 0.32.0 → 0.33.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.
@@ -1,7 +1,7 @@
1
1
  import _classPrivateFieldGet from '@babel/runtime/helpers/classPrivateFieldGet';
2
2
  import _classPrivateFieldSet from '@babel/runtime/helpers/classPrivateFieldSet';
3
3
 
4
- var _$optionSlot, _$listbox, _$popover, _onListboxKeyDown, _getFirstOption, _getLastOption, _getNextOption, _getPrevOption, _selectOption, _getOptionElements, _findSelectedOption, _getEnabledOptionElements, _onOpen, _onClose, _onReactClose;
4
+ var _$optionSlot, _$listbox, _$popover, _onListboxKeyDown, _getFirstOption, _getLastOption, _getNextOption, _getPrevOption, _selectOption, _getOptionElements, _findSelectedOption, _getEnabledOptionElements, _onClose, _onReactClose;
5
5
 
6
6
  function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
7
7
 
@@ -14,16 +14,14 @@ function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(
14
14
  import { orientationValues } from '../popover/utils';
15
15
  import '../popover';
16
16
  import { attrValueToPixels, defineCustomElement, getBooleanAttribute, getIntegerAttribute, getLiteralAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateIntegerAttribute, updateLiteralAttribute } from '../utils';
17
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}sinch-popover{width:100%}</style><sinch-popover><slot name="target" slot="target"></slot><div id="listbox" slot="content"><slot name="option"></slot></div></sinch-popover>';
17
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{width:100%;--sinch-popover-shape-radius:var(--sinch-shape-radius-s)}#listbox{overflow-y:auto}</style><sinch-popover id="wrapper"><slot name="target" slot="target"></slot><div id="listbox" slot="content"><slot name="option"></slot></div></sinch-popover>';
18
18
  const ITEM_HEIGHT = 40;
19
19
  const template = document.createElement('template');
20
20
  template.innerHTML = templateHTML;
21
- defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbox = new WeakMap(), _$popover = new WeakMap(), _onListboxKeyDown = new WeakMap(), _getFirstOption = new WeakSet(), _getLastOption = new WeakSet(), _getNextOption = new WeakSet(), _getPrevOption = new WeakSet(), _selectOption = new WeakSet(), _getOptionElements = new WeakSet(), _findSelectedOption = new WeakSet(), _getEnabledOptionElements = new WeakSet(), _onOpen = new WeakSet(), _onClose = new WeakMap(), _onReactClose = new WeakMap(), class extends NectaryElement {
21
+ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbox = new WeakMap(), _$popover = new WeakMap(), _onListboxKeyDown = new WeakMap(), _getFirstOption = new WeakSet(), _getLastOption = new WeakSet(), _getNextOption = new WeakSet(), _getPrevOption = new WeakSet(), _selectOption = new WeakSet(), _getOptionElements = new WeakSet(), _findSelectedOption = new WeakSet(), _getEnabledOptionElements = new WeakSet(), _onClose = new WeakMap(), _onReactClose = new WeakMap(), class extends NectaryElement {
22
22
  constructor() {
23
23
  super();
24
24
 
25
- _classPrivateMethodInitSpec(this, _onOpen);
26
-
27
25
  _classPrivateMethodInitSpec(this, _getEnabledOptionElements);
28
26
 
29
27
  _classPrivateMethodInitSpec(this, _findSelectedOption);
@@ -59,8 +57,19 @@ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbo
59
57
  writable: true,
60
58
  value: e => {
61
59
  switch (e.code) {
60
+ case 'Enter':
61
+ {
62
+ const $opt = _classPrivateMethodGet(this, _findSelectedOption, _findSelectedOption2).call(this, _classPrivateMethodGet(this, _getEnabledOptionElements, _getEnabledOptionElements2).call(this));
63
+
64
+ if ($opt !== null) {
65
+ e.preventDefault();
66
+ $opt.click();
67
+ }
68
+
69
+ break;
70
+ }
71
+
62
72
  case 'ArrowUp':
63
- case 'ArrowLeft':
64
73
  {
65
74
  e.preventDefault();
66
75
 
@@ -70,7 +79,6 @@ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbo
70
79
  }
71
80
 
72
81
  case 'ArrowDown':
73
- case 'ArrowRight':
74
82
  {
75
83
  e.preventDefault();
76
84
 
@@ -118,7 +126,7 @@ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbo
118
126
  }
119
127
 
120
128
  static get observedAttributes() {
121
- return ['open', 'orientation', 'maxvisibleitems'];
129
+ return ['open', 'orientation', 'maxvisibleitems', 'modal'];
122
130
  }
123
131
 
124
132
  get nodeName() {
@@ -149,6 +157,14 @@ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbo
149
157
  return getBooleanAttribute(this, 'open');
150
158
  }
151
159
 
160
+ set modal(isModal) {
161
+ updateBooleanAttribute(this, 'modal', isModal);
162
+ }
163
+
164
+ get modal() {
165
+ return getBooleanAttribute(this, 'modal');
166
+ }
167
+
152
168
  get dropdownRect() {
153
169
  return _classPrivateFieldGet(this, _$popover).popoverRect;
154
170
  }
@@ -160,8 +176,6 @@ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbo
160
176
  updateAttribute(_classPrivateFieldGet(this, _$popover), 'open', newVal);
161
177
 
162
178
  if (isAttrTrue(newVal)) {
163
- _classPrivateMethodGet(this, _onOpen, _onOpen2).call(this);
164
-
165
179
  _classPrivateFieldGet(this, _$popover).addEventListener('keydown', _classPrivateFieldGet(this, _onListboxKeyDown));
166
180
 
167
181
  _classPrivateFieldGet(this, _$popover).addEventListener('close', _classPrivateFieldGet(this, _onClose));
@@ -169,6 +183,8 @@ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbo
169
183
  _classPrivateFieldGet(this, _$popover).removeEventListener('keydown', _classPrivateFieldGet(this, _onListboxKeyDown));
170
184
 
171
185
  _classPrivateFieldGet(this, _$popover).removeEventListener('close', _classPrivateFieldGet(this, _onClose));
186
+
187
+ _classPrivateMethodGet(this, _selectOption, _selectOption2).call(this, null);
172
188
  }
173
189
 
174
190
  break;
@@ -193,6 +209,12 @@ defineCustomElement('sinch-action-menu', (_$optionSlot = new WeakMap(), _$listbo
193
209
 
194
210
  break;
195
211
  }
212
+
213
+ case 'modal':
214
+ {
215
+ updateBooleanAttribute(_classPrivateFieldGet(this, _$popover), 'modal', isAttrTrue(newVal));
216
+ break;
217
+ }
196
218
  }
197
219
  }
198
220
 
@@ -235,12 +257,16 @@ function _getPrevOption2() {
235
257
  }
236
258
 
237
259
  function _selectOption2($option) {
260
+ const hasMaxVisibleItems = this.hasAttribute('maxvisibleitems');
261
+
238
262
  for (const $op of _classPrivateMethodGet(this, _getOptionElements, _getOptionElements2).call(this)) {
239
263
  const isSelected = $op === $option;
240
- updateBooleanAttribute($op, 'selected', isSelected);
264
+ updateBooleanAttribute($op, 'data-selected', isSelected);
241
265
 
242
- if (isSelected) {
243
- $op.focus();
266
+ if (isSelected && hasMaxVisibleItems) {
267
+ $op.scrollIntoView?.({
268
+ block: 'nearest'
269
+ });
244
270
  }
245
271
  }
246
272
  }
@@ -257,7 +283,7 @@ function _getOptionElements2() {
257
283
 
258
284
  function _findSelectedOption2(elements) {
259
285
  for (const el of elements) {
260
- if (getBooleanAttribute(el, 'selected')) {
286
+ if (getBooleanAttribute(el, 'data-selected')) {
261
287
  return el;
262
288
  }
263
289
  }
@@ -267,8 +293,4 @@ function _findSelectedOption2(elements) {
267
293
 
268
294
  function _getEnabledOptionElements2() {
269
295
  return _classPrivateMethodGet(this, _getOptionElements, _getOptionElements2).call(this).filter(opt => opt.disabled !== true);
270
- }
271
-
272
- function _onOpen2() {
273
- _classPrivateMethodGet(this, _selectOption, _selectOption2).call(this, _classPrivateMethodGet(this, _getFirstOption, _getFirstOption2).call(this));
274
296
  }
@@ -5,16 +5,19 @@ export declare type TSinchActionMenuElement = HTMLElement & {
5
5
  open: boolean;
6
6
  orientation: TSinchPopoverOrientation;
7
7
  maxVisibleItems: number | null;
8
+ modal: boolean;
8
9
  readonly dropdownRect: TRect;
9
10
  addEventListener(type: 'close', listener: (e: CustomEvent<void>) => void): void;
10
11
  setAttribute(name: 'open', value: ''): void;
11
12
  setAttribute(name: 'orientation', value: TSinchPopoverOrientation): void;
12
13
  setAttribute(name: 'maxvisibleitems', value: string): void;
14
+ setAttribute(name: 'modal', value: boolean): void;
13
15
  };
14
16
  export declare type TSinchActionMenuReact = TSinchElementReact<TSinchActionMenuElement> & {
15
17
  open: boolean;
16
18
  orientation?: TSinchPopoverOrientation;
17
19
  maxVisibleItems?: number;
20
+ modal?: boolean;
18
21
  'aria-label': string;
19
22
  onClose: (event: SyntheticEvent<TSinchActionMenuElement, CustomEvent<void>>) => void;
20
23
  };
@@ -1,21 +1,21 @@
1
1
  import _classPrivateFieldGet from '@babel/runtime/helpers/classPrivateFieldGet';
2
2
  import _classPrivateFieldSet from '@babel/runtime/helpers/classPrivateFieldSet';
3
3
 
4
- var _$button, _$content;
4
+ var _$wrapper, _$content, _onMouseDown;
5
5
 
6
6
  function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
7
7
 
8
8
  function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
9
9
 
10
10
  import { defineCustomElement, getAttribute, getBooleanAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute } from '../utils';
11
- const templateHTML = '<style>:host{display:block}#wrapper{all:initial;display:flex;position:relative;box-sizing:border-box;height:40px;width:100%;padding:8px 16px;align-items:center;gap:10px;user-select:none;cursor:pointer;font:inherit;color:inherit;--sinch-size-icon:24px}#content{flex-shrink:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}#wrapper:focus,:host(:hover)>#wrapper{background-color:var(--sinch-color-snow-500)}:host([disabled]:not([disabled=false]))>#wrapper{color:var(--sinch-color-stormy-100);cursor:initial;--sinch-color-icon:var(--sinch-color-stormy-100)}::slotted(*){margin-left:-6px}</style><button id="wrapper"><slot name="icon"></slot><span id="content"></span></button>';
11
+ const templateHTML = '<style>:host{display:block}#wrapper{all:initial;display:flex;position:relative;box-sizing:border-box;height:40px;width:100%;padding:8px 16px;align-items:center;gap:10px;user-select:none;cursor:pointer;font:inherit;color:inherit;--sinch-size-icon:24px}#content{flex-shrink:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host(:hover)>#wrapper,:host([data-selected])>#wrapper{background-color:var(--sinch-color-snow-500)}:host([disabled]:not([disabled=false]))>#wrapper{color:var(--sinch-color-stormy-100);cursor:initial;pointer-events:none;--sinch-color-icon:var(--sinch-color-stormy-100)}::slotted(*){margin-left:-6px}</style><div id="wrapper"><slot name="icon"></slot><span id="content"></span></div>';
12
12
  const template = document.createElement('template');
13
13
  template.innerHTML = templateHTML;
14
- defineCustomElement('sinch-action-menu-option', (_$button = new WeakMap(), _$content = new WeakMap(), class ActionMenuOption extends NectaryElement {
14
+ defineCustomElement('sinch-action-menu-option', (_$wrapper = new WeakMap(), _$content = new WeakMap(), _onMouseDown = new WeakMap(), class ActionMenuOption extends NectaryElement {
15
15
  constructor() {
16
16
  super();
17
17
 
18
- _classPrivateFieldInitSpec(this, _$button, {
18
+ _classPrivateFieldInitSpec(this, _$wrapper, {
19
19
  writable: true,
20
20
  value: void 0
21
21
  });
@@ -25,16 +25,31 @@ defineCustomElement('sinch-action-menu-option', (_$button = new WeakMap(), _$con
25
25
  value: void 0
26
26
  });
27
27
 
28
+ _classPrivateFieldInitSpec(this, _onMouseDown, {
29
+ writable: true,
30
+ value: e => {
31
+ e.preventDefault();
32
+ e.stopPropagation();
33
+ this.click();
34
+ }
35
+ });
36
+
28
37
  const shadowRoot = this.attachShadow();
29
38
  shadowRoot.appendChild(template.content.cloneNode(true));
30
39
 
31
- _classPrivateFieldSet(this, _$button, shadowRoot.querySelector('#wrapper'));
40
+ _classPrivateFieldSet(this, _$wrapper, shadowRoot.querySelector('#wrapper'));
32
41
 
33
42
  _classPrivateFieldSet(this, _$content, shadowRoot.querySelector('#content'));
34
43
  }
35
44
 
36
45
  connectedCallback() {
37
46
  this.setAttribute('role', 'option');
47
+
48
+ _classPrivateFieldGet(this, _$wrapper).addEventListener('mousedown', _classPrivateFieldGet(this, _onMouseDown));
49
+ }
50
+
51
+ disconnectedCallback() {
52
+ _classPrivateFieldGet(this, _$wrapper).removeEventListener('mousedown', _classPrivateFieldGet(this, _onMouseDown));
38
53
  }
39
54
 
40
55
  static get observedAttributes() {
@@ -55,7 +70,8 @@ defineCustomElement('sinch-action-menu-option', (_$button = new WeakMap(), _$con
55
70
 
56
71
  case 'disabled':
57
72
  {
58
- _classPrivateFieldGet(this, _$button).disabled = isAttrTrue(newVal);
73
+ updateBooleanAttribute(this, 'disabled', isAttrTrue(newVal));
74
+ break;
59
75
  }
60
76
  }
61
77
  }
@@ -76,12 +92,4 @@ defineCustomElement('sinch-action-menu-option', (_$button = new WeakMap(), _$con
76
92
  return getBooleanAttribute(this, 'disabled');
77
93
  }
78
94
 
79
- focus() {
80
- _classPrivateFieldGet(this, _$button).focus();
81
- }
82
-
83
- blur() {
84
- _classPrivateFieldGet(this, _$button).blur();
85
- }
86
-
87
95
  }));
package/dialog/index.js CHANGED
@@ -14,7 +14,7 @@ function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(
14
14
  import dialogPolyfill from 'dialog-polyfill';
15
15
  import '../icon-button';
16
16
  import '../icons/close';
17
- import { defineCustomElement, getAttribute, getBooleanAttribute, getRect, isAttrTrue, updateAttribute, getReactEventHandler, NectaryElement } from '../utils';
17
+ import { defineCustomElement, getAttribute, getBooleanAttribute, getRect, isAttrTrue, updateAttribute, getReactEventHandler, NectaryElement, updateBooleanAttribute } from '../utils';
18
18
  const templateHTML = '<style>dialog{position:fixed;left:0;right:0;margin:auto;display:flex;flex-direction:column;padding:24px;max-width:var(--sinch-dialog-max-width,512px);max-height:unset;border-radius:var(--sinch-shape-radius-l);box-sizing:border-box;contain:content;background-color:var(--sinch-color-snow-100);color:var(--sinch-color-text-default);font:var(--sinch-font-body);border:none;box-shadow:var(--sinch-elevation-level-3)}dialog:not([open]){display:none}dialog+.backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#000;opacity:.55}dialog::backdrop{background-color:#000;opacity:.55}._dialog_overlay{position:fixed;top:0;right:0;bottom:0;left:0}dialog.fixed{position:fixed;top:50%;transform:translate(0,-50%)}#header{display:flex;flex-direction:row;justify-content:space-between;align-items:flex-start;margin-bottom:16px}#caption{font:var(--sinch-font-title-m);color:var(--sinch-color-text-default);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}#content-wrapper{min-height:0;overflow:auto;max-height:var(--sinch-dialog-max-height,50vh)}#buttons{display:flex;flex-direction:row;justify-content:flex-end;gap:16px;margin-top:24px}sinch-icon-button{transform:translate(4px,-4px)}</style><dialog><div id="header"><span id="caption"></span><sinch-icon-button id="close" small tabindex="0"><sinch-icon-close slot="icon"></sinch-icon-close></sinch-icon-button></div><div id="content-wrapper"><slot name="content"></slot></div><div id="buttons"><slot name="buttons"></slot></div></dialog>';
19
19
  const template = document.createElement('template');
20
20
  template.innerHTML = templateHTML;
@@ -106,8 +106,38 @@ defineCustomElement('sinch-dialog', (_$dialog = new WeakMap(), _$closeButton = n
106
106
  dialogPolyfill.registerDialog(_classPrivateFieldGet(this, _$dialog));
107
107
  }
108
108
 
109
+ connectedCallback() {
110
+ this.setAttribute('role', 'dialog');
111
+
112
+ _classPrivateFieldGet(this, _$closeButton).addEventListener('click', _classPrivateFieldGet(this, _onCloseClick));
113
+
114
+ _classPrivateFieldGet(this, _$dialog).addEventListener('mousedown', _classPrivateFieldGet(this, _onBackdropClick));
115
+
116
+ _classPrivateFieldGet(this, _$dialog).addEventListener('cancel', _classPrivateFieldGet(this, _onCancel));
117
+
118
+ this.addEventListener('close', _classPrivateFieldGet(this, _onCloseReactHandler));
119
+
120
+ _classPrivateFieldSet(this, _isConnected, true);
121
+
122
+ _classPrivateMethodGet(this, _setOpen, _setOpen2).call(this, getBooleanAttribute(this, 'open'));
123
+ }
124
+
125
+ disconnectedCallback() {
126
+ _classPrivateFieldGet(this, _$closeButton).removeEventListener('click', _classPrivateFieldGet(this, _onCloseClick));
127
+
128
+ _classPrivateFieldGet(this, _$dialog).removeEventListener('mousedown', _classPrivateFieldGet(this, _onBackdropClick));
129
+
130
+ _classPrivateFieldGet(this, _$dialog).removeEventListener('cancel', _classPrivateFieldGet(this, _onCancel));
131
+
132
+ this.removeEventListener('close', _classPrivateFieldGet(this, _onCloseReactHandler));
133
+
134
+ _classPrivateMethodGet(this, _setOpen, _setOpen2).call(this, false);
135
+
136
+ _classPrivateFieldSet(this, _isConnected, false);
137
+ }
138
+
109
139
  static get observedAttributes() {
110
- return ['caption', 'open'];
140
+ return ['caption', 'open', 'close-aria-label'];
111
141
  }
112
142
 
113
143
  attributeChangedCallback(name, _, newVal) {
@@ -120,10 +150,17 @@ defineCustomElement('sinch-dialog', (_$dialog = new WeakMap(), _$closeButton = n
120
150
 
121
151
  case 'open':
122
152
  {
123
- if (_classPrivateFieldGet(this, _isConnected)) {
124
- _classPrivateMethodGet(this, _setOpen, _setOpen2).call(this, isAttrTrue(newVal));
125
- }
153
+ const shouldOpen = isAttrTrue(newVal);
154
+
155
+ _classPrivateMethodGet(this, _setOpen, _setOpen2).call(this, shouldOpen);
126
156
 
157
+ updateBooleanAttribute(this, 'open', shouldOpen);
158
+ break;
159
+ }
160
+
161
+ case 'close-aria-label':
162
+ {
163
+ updateAttribute(_classPrivateFieldGet(this, _$closeButton), 'aria-label', newVal);
127
164
  break;
128
165
  }
129
166
  }
@@ -137,36 +174,6 @@ defineCustomElement('sinch-dialog', (_$dialog = new WeakMap(), _$closeButton = n
137
174
  return getAttribute(this, 'caption', '');
138
175
  }
139
176
 
140
- connectedCallback() {
141
- this.setAttribute('role', 'dialog');
142
-
143
- _classPrivateFieldGet(this, _$closeButton).addEventListener('click', _classPrivateFieldGet(this, _onCloseClick));
144
-
145
- this.addEventListener('close', _classPrivateFieldGet(this, _onCloseReactHandler));
146
-
147
- _classPrivateFieldGet(this, _$dialog).addEventListener('mousedown', _classPrivateFieldGet(this, _onBackdropClick));
148
-
149
- _classPrivateFieldGet(this, _$dialog).addEventListener('cancel', _classPrivateFieldGet(this, _onCancel));
150
-
151
- _classPrivateFieldSet(this, _isConnected, true);
152
-
153
- if (getBooleanAttribute(this, 'open')) {
154
- _classPrivateMethodGet(this, _setOpen, _setOpen2).call(this, true);
155
- }
156
- }
157
-
158
- disconnectedCallback() {
159
- _classPrivateFieldGet(this, _$closeButton).removeEventListener('click', _classPrivateFieldGet(this, _onCloseClick));
160
-
161
- this.removeEventListener('close', _classPrivateFieldGet(this, _onCloseReactHandler));
162
-
163
- _classPrivateFieldGet(this, _$dialog).removeEventListener('mousedown', _classPrivateFieldGet(this, _onBackdropClick));
164
-
165
- _classPrivateFieldGet(this, _$dialog).removeEventListener('cancel', _classPrivateFieldGet(this, _onCancel));
166
-
167
- _classPrivateFieldSet(this, _isConnected, false);
168
- }
169
-
170
177
  get dialogRect() {
171
178
  return getRect(_classPrivateFieldGet(this, _$dialog));
172
179
  }
@@ -183,14 +190,14 @@ function _dispatchCloseEvent2() {
183
190
  }));
184
191
  }
185
192
 
186
- function _setOpen2(isOpen) {
187
- if (isOpen) {
188
- if (!getBooleanAttribute(_classPrivateFieldGet(this, _$dialog), 'open')) {
189
- _classPrivateFieldGet(this, _$dialog).showModal();
190
-
193
+ function _setOpen2(shouldOpen) {
194
+ if (shouldOpen) {
195
+ if (_classPrivateFieldGet(this, _isConnected) && !getBooleanAttribute(_classPrivateFieldGet(this, _$dialog), 'open')) {
191
196
  _classPrivateFieldSet(this, _prevOverflowValue, document.body.style.overflow);
192
197
 
193
198
  document.body.style.overflow = 'hidden';
199
+
200
+ _classPrivateFieldGet(this, _$dialog).showModal();
194
201
  }
195
202
  } else {
196
203
  _classPrivateFieldGet(this, _$dialog).close?.();
package/dialog/types.d.ts CHANGED
@@ -6,10 +6,12 @@ export declare type TSinchDialogElement = HTMLElement & {
6
6
  readonly closeButtonRect: TRect;
7
7
  addEventListener(type: 'close', listener: (e: CustomEvent<void>) => void): void;
8
8
  setAttribute(name: 'caption', value: string): void;
9
+ setAttribute(name: 'close-aria-label', value: string): void;
9
10
  };
10
11
  export declare type TSinchDialogReact = TSinchElementReact<TSinchDialogElement> & {
11
12
  open: boolean;
12
13
  caption: string;
13
14
  'aria-label': string;
15
+ 'close-aria-label': string;
14
16
  onClose: (event: SyntheticEvent<TSinchDialogElement, CustomEvent<void>>) => void;
15
17
  };
package/dropdown/index.js CHANGED
@@ -14,7 +14,7 @@ function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(
14
14
  import { orientationValues } from '../popover/utils';
15
15
  import '../popover';
16
16
  import { attrValueToPixels, defineCustomElement, getAttribute, getBooleanAttribute, getCsvSet, getFirstCsvValue, getIntegerAttribute, getLiteralAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateCsv, updateIntegerAttribute, updateLiteralAttribute } from '../utils';
17
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}sinch-popover{width:100%}</style><sinch-popover><slot name="target" slot="target"></slot><div id="listbox" slot="content"><slot name="option"></slot></div></sinch-popover>';
17
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{width:100%;--sinch-popover-shape-radius:var(--sinch-shape-radius-s)}#listbox{overflow-y:auto}</style><sinch-popover id="wrapper" modal><slot name="target" slot="target"></slot><div id="listbox" slot="content"><slot name="option"></slot></div></sinch-popover>';
18
18
  const ITEM_HEIGHT = 40;
19
19
  const template = document.createElement('template');
20
20
  template.innerHTML = templateHTML;
@@ -81,9 +81,13 @@ defineCustomElement('sinch-dropdown', (_$optionSlot = new WeakMap(), _$listbox =
81
81
  case 'Space':
82
82
  case 'Enter':
83
83
  {
84
- e.preventDefault();
84
+ const $option = _classPrivateMethodGet(this, _findSelectedOption, _findSelectedOption2).call(this, _classPrivateMethodGet(this, _getEnabledOptionElements, _getEnabledOptionElements2).call(this));
85
+
86
+ if ($option !== null) {
87
+ e.preventDefault();
85
88
 
86
- _classPrivateMethodGet(this, _dispatchChangeEvent, _dispatchChangeEvent2).call(this, _classPrivateMethodGet(this, _findSelectedOption, _findSelectedOption2).call(this, _classPrivateMethodGet(this, _getEnabledOptionElements, _getEnabledOptionElements2).call(this)));
89
+ _classPrivateMethodGet(this, _dispatchChangeEvent, _dispatchChangeEvent2).call(this, $option);
90
+ }
87
91
 
88
92
  break;
89
93
  }
@@ -323,11 +327,13 @@ function _getPrevOption2() {
323
327
  }
324
328
 
325
329
  function _selectOption2($option) {
330
+ const hasMaxVisibleItems = this.hasAttribute('maxvisibleitems');
331
+
326
332
  for (const $op of _classPrivateMethodGet(this, _getOptionElements, _getOptionElements2).call(this)) {
327
333
  const isSelected = $op === $option;
328
334
  updateBooleanAttribute($op, 'data-selected', isSelected);
329
335
 
330
- if (isSelected && this.maxVisibleItems !== null) {
336
+ if (isSelected && hasMaxVisibleItems) {
331
337
  $op.scrollIntoView?.({
332
338
  block: 'nearest'
333
339
  });
@@ -389,13 +395,5 @@ function _dispatchChangeEvent2($opt) {
389
395
  function _onOpen2() {
390
396
  const $opt = _classPrivateMethodGet(this, _getOptionWithValue, _getOptionWithValue2).call(this, getFirstCsvValue(this.value));
391
397
 
392
- if ($opt !== null) {
393
- _classPrivateMethodGet(this, _selectOption, _selectOption2).call(this, $opt);
394
-
395
- $opt.scrollIntoView?.({
396
- block: 'nearest'
397
- });
398
- } else {
399
- _classPrivateMethodGet(this, _selectOption, _selectOption2).call(this, _classPrivateMethodGet(this, _getFirstOption, _getFirstOption2).call(this));
400
- }
398
+ _classPrivateMethodGet(this, _selectOption, _selectOption2).call(this, $opt ?? _classPrivateMethodGet(this, _getFirstOption, _getFirstOption2).call(this));
401
399
  }
package/input/index.js CHANGED
@@ -1,18 +1,18 @@
1
1
  import _classPrivateFieldGet from '@babel/runtime/helpers/classPrivateFieldGet';
2
2
  import _classPrivateFieldSet from '@babel/runtime/helpers/classPrivateFieldSet';
3
3
 
4
- var _$input, _$label, _$optionalText, _$additionalText, _$invalidText, _selectionStart, _selectionEnd, _isPendingDk, _onCompositionStart, _onInput;
4
+ var _$input, _$label, _$optionalText, _$additionalText, _$invalidText, _$iconSlot, _$iconWrapper, _$rightSlot, _$rightWrapper, _cursorPos, _isPendingDk, _onCompositionStart, _onSelectionChange, _onInput, _onIconSlotChange, _onRightSlotChange, _onEventFilter;
5
5
 
6
6
  function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
7
7
 
8
8
  function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
9
9
 
10
- import { defineCustomElement, getAttribute, getBooleanAttribute, getLiteralAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateLiteralAttribute } from '../utils';
11
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0;--sinch-color-icon:var(--sinch-color-stormy-500)}#wrapper{width:100%;box-sizing:border-box}#input-wrapper{display:flex;flex-direction:row;align-items:center;gap:4px;border:1px solid var(--sinch-color-stormy-200);box-sizing:border-box;border-radius:var(--sinch-shape-radius-s);width:100%;height:48px;margin:2px 0;padding:0 8px;background-color:var(--sinch-color-snow-100)}#input{all:initial;flex:1;min-width:0;height:48px;padding:0 4px;font:var(--sinch-font-body);color:var(--sinch-color-text-default);caret-color:var(--sinch-caret-color,auto)}#input::placeholder{font:var(--sinch-font-body);color:var(--sinch-color-text-muted)}#input:disabled{border-color:var(--sinch-color-snow-500);color:var(--sinch-color-stormy-100)}#input:disabled::placeholder{color:var(--sinch-color-snow-500)}#input:focus{border-color:var(--sinch-color-stormy-600)}#input[type=password]{font-size:1.5em;letter-spacing:.1em}:host([invalidtext]:not([invalidtext=""]):not([disabled])) #input-wrapper{border-color:var(--sinch-color-text-invalid)}#bottom,#top{display:flex;align-items:baseline}#top{height:24px}#bottom{height:20px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-font-title-s);color:var(--sinch-color-text-default)}#optional{flex:1;text-align:right;font:var(--sinch-font-small-text);color:var(--sinch-color-text-muted)}#additional{flex:1;text-align:right;font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-muted)}#invalid{font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-invalid)}::slotted(sinch-help-tooltip){align-self:center;margin:0 8px}:host([disabled]:not([disabled=false])) :is(#label,#additional,#optional,#invalid){color:var(--sinch-color-stormy-100)}:host([disabled]:not([disabled=false])){--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><slot name="tooltip"></slot><span id="optional"></span></div><div id="input-wrapper"><input id="input" type="text"/><slot name="right"></slot></div><div id="bottom"><span id="invalid"></span> <span id="additional"></span></div></div>';
10
+ import { defineCustomElement, getAttribute, getBooleanAttribute, getLiteralAttribute, isAttrTrue, NectaryElement, setClass, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateLiteralAttribute } from '../utils';
11
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0;--sinch-color-icon:var(--sinch-color-stormy-500)}#wrapper{width:100%;box-sizing:border-box}#input-wrapper{position:relative;display:flex;flex-direction:row;align-items:center;box-sizing:border-box;border-radius:var(--sinch-shape-radius-s);width:100%;height:48px;background-color:var(--sinch-color-snow-100)}#input{all:initial;flex:1;min-width:0;height:48px;padding:0 12px 0 44px;font:var(--sinch-font-body);color:var(--sinch-color-text-default);caret-color:var(--sinch-caret-color,auto)}#input::placeholder{font:var(--sinch-font-body);color:var(--sinch-color-text-muted)}#border{position:absolute;border:1px solid var(--sinch-color-stormy-200);border-radius:var(--sinch-shape-radius-s);left:0;right:0;top:0;bottom:0;pointer-events:none}:host([invalidtext]:not([invalidtext=""]):not([disabled])) #border{border-color:var(--sinch-color-text-invalid)}#input:disabled{color:var(--sinch-color-stormy-100)}#input:disabled::placeholder{color:var(--sinch-color-snow-500)}#input:disabled+#border{border-color:var(--sinch-color-snow-500)}#input:focus+#border{border-color:var(--sinch-color-stormy-600)}#input[type=password]{font-size:1.5em;letter-spacing:.1em}#bottom,#top{display:flex;align-items:baseline}#top{height:24px;margin-bottom:2px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-font-title-s);color:var(--sinch-color-text-default)}#optional{flex:1;text-align:right;font:var(--sinch-font-small-text);color:var(--sinch-color-text-muted)}#additional{flex:1;text-align:right;font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-muted);line-height:20px;margin-top:2px}#additional:empty{display:none}#invalid{font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-invalid);line-height:20px;margin-top:2px}#invalid:empty{display:none}#icon{position:absolute;left:12px;top:12px;pointer-events:none;--sinch-icon-size:24px}#icon.empty{display:none}#icon.empty~#input{padding-left:12px}#right{display:flex;flex-direction:row;align-self:stretch;align-items:center;gap:4px;padding-right:8px}#right.empty{display:none}::slotted(sinch-help-tooltip){align-self:center;margin:0 8px}:host([disabled]:not([disabled=false])) :is(#label,#additional,#optional,#invalid){color:var(--sinch-color-stormy-100)}:host([disabled]:not([disabled=false])){--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><slot name="tooltip"></slot><span id="optional"></span></div><div id="input-wrapper"><div id="icon"><slot name="icon"></slot></div><input id="input" type="text"/><div id="border"></div><div id="right"><slot name="right"></slot></div></div><div id="bottom"><div id="invalid"></div><div id="additional"></div></div></div>';
12
12
  import { inputTypes } from './utils';
13
13
  const template = document.createElement('template');
14
14
  template.innerHTML = templateHTML;
15
- defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakMap(), _$optionalText = new WeakMap(), _$additionalText = new WeakMap(), _$invalidText = new WeakMap(), _selectionStart = new WeakMap(), _selectionEnd = new WeakMap(), _isPendingDk = new WeakMap(), _onCompositionStart = new WeakMap(), _onInput = new WeakMap(), class extends NectaryElement {
15
+ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakMap(), _$optionalText = new WeakMap(), _$additionalText = new WeakMap(), _$invalidText = new WeakMap(), _$iconSlot = new WeakMap(), _$iconWrapper = new WeakMap(), _$rightSlot = new WeakMap(), _$rightWrapper = new WeakMap(), _cursorPos = new WeakMap(), _isPendingDk = new WeakMap(), _onCompositionStart = new WeakMap(), _onSelectionChange = new WeakMap(), _onInput = new WeakMap(), _onIconSlotChange = new WeakMap(), _onRightSlotChange = new WeakMap(), _onEventFilter = new WeakMap(), class extends NectaryElement {
16
16
  constructor() {
17
17
  super();
18
18
 
@@ -41,12 +41,27 @@ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakM
41
41
  value: void 0
42
42
  });
43
43
 
44
- _classPrivateFieldInitSpec(this, _selectionStart, {
44
+ _classPrivateFieldInitSpec(this, _$iconSlot, {
45
45
  writable: true,
46
- value: null
46
+ value: void 0
47
47
  });
48
48
 
49
- _classPrivateFieldInitSpec(this, _selectionEnd, {
49
+ _classPrivateFieldInitSpec(this, _$iconWrapper, {
50
+ writable: true,
51
+ value: void 0
52
+ });
53
+
54
+ _classPrivateFieldInitSpec(this, _$rightSlot, {
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+
59
+ _classPrivateFieldInitSpec(this, _$rightWrapper, {
60
+ writable: true,
61
+ value: void 0
62
+ });
63
+
64
+ _classPrivateFieldInitSpec(this, _cursorPos, {
50
65
  writable: true,
51
66
  value: null
52
67
  });
@@ -63,6 +78,13 @@ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakM
63
78
  }
64
79
  });
65
80
 
81
+ _classPrivateFieldInitSpec(this, _onSelectionChange, {
82
+ writable: true,
83
+ value: () => {
84
+ _classPrivateFieldSet(this, _cursorPos, _classPrivateFieldGet(this, _$input).selectionEnd);
85
+ }
86
+ });
87
+
66
88
  _classPrivateFieldInitSpec(this, _onInput, {
67
89
  writable: true,
68
90
  value: e => {
@@ -73,29 +95,23 @@ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakM
73
95
  const prevValue = this.value;
74
96
 
75
97
  if (prevValue !== nextValue) {
76
- const nextSelectionStart = _classPrivateFieldGet(this, _$input).selectionStart;
77
-
78
- const nextSelectionEnd = _classPrivateFieldGet(this, _$input).selectionEnd;
79
-
80
- const prevSelectionStart = _classPrivateFieldGet(this, _selectionStart);
81
-
82
- const prevSelectionEnd = _classPrivateFieldGet(this, _selectionEnd);
83
-
84
- const isPrevCursorEnd = prevSelectionStart === prevSelectionEnd && prevSelectionStart === prevValue.length;
98
+ const nextCursorPos = _classPrivateFieldGet(this, _$input).selectionEnd;
85
99
 
86
100
  if (!_classPrivateFieldGet(this, _isPendingDk)) {
87
101
  _classPrivateFieldGet(this, _$input).value = prevValue;
88
- }
89
102
 
90
- _classPrivateFieldSet(this, _isPendingDk, false);
103
+ const prevCursorPos = _classPrivateFieldGet(this, _cursorPos);
104
+
105
+ const isPrevCursorEnd = prevCursorPos === null || prevCursorPos === prevValue.length;
91
106
 
92
- if (!isPrevCursorEnd) {
93
- _classPrivateFieldGet(this, _$input).setSelectionRange(prevSelectionStart, prevSelectionEnd);
107
+ if (!isPrevCursorEnd) {
108
+ _classPrivateFieldGet(this, _$input).setSelectionRange(prevCursorPos, prevCursorPos);
109
+ }
94
110
  }
95
111
 
96
- _classPrivateFieldSet(this, _selectionStart, nextSelectionStart);
112
+ _classPrivateFieldSet(this, _isPendingDk, false);
97
113
 
98
- _classPrivateFieldSet(this, _selectionEnd, nextSelectionEnd);
114
+ _classPrivateFieldSet(this, _cursorPos, nextCursorPos);
99
115
 
100
116
  this.dispatchEvent(new CustomEvent('change', {
101
117
  detail: nextValue,
@@ -105,6 +121,27 @@ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakM
105
121
  }
106
122
  });
107
123
 
124
+ _classPrivateFieldInitSpec(this, _onIconSlotChange, {
125
+ writable: true,
126
+ value: () => {
127
+ setClass(_classPrivateFieldGet(this, _$iconWrapper), 'empty', _classPrivateFieldGet(this, _$iconSlot).assignedElements().length === 0);
128
+ }
129
+ });
130
+
131
+ _classPrivateFieldInitSpec(this, _onRightSlotChange, {
132
+ writable: true,
133
+ value: () => {
134
+ setClass(_classPrivateFieldGet(this, _$rightWrapper), 'empty', _classPrivateFieldGet(this, _$rightSlot).assignedElements().length === 0);
135
+ }
136
+ });
137
+
138
+ _classPrivateFieldInitSpec(this, _onEventFilter, {
139
+ writable: true,
140
+ value: e => {
141
+ e.stopPropagation();
142
+ }
143
+ });
144
+
108
145
  const shadowRoot = this.attachShadow();
109
146
  shadowRoot.appendChild(template.content.cloneNode(true));
110
147
 
@@ -117,6 +154,14 @@ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakM
117
154
  _classPrivateFieldSet(this, _$additionalText, shadowRoot.querySelector('#additional'));
118
155
 
119
156
  _classPrivateFieldSet(this, _$invalidText, shadowRoot.querySelector('#invalid'));
157
+
158
+ _classPrivateFieldSet(this, _$iconSlot, shadowRoot.querySelector('slot[name="icon"]'));
159
+
160
+ _classPrivateFieldSet(this, _$iconWrapper, shadowRoot.querySelector('#icon'));
161
+
162
+ _classPrivateFieldSet(this, _$rightSlot, shadowRoot.querySelector('slot[name="right"]'));
163
+
164
+ _classPrivateFieldSet(this, _$rightWrapper, shadowRoot.querySelector('#right'));
120
165
  }
121
166
 
122
167
  connectedCallback() {
@@ -125,12 +170,48 @@ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakM
125
170
  _classPrivateFieldGet(this, _$input).addEventListener('input', _classPrivateFieldGet(this, _onInput));
126
171
 
127
172
  _classPrivateFieldGet(this, _$input).addEventListener('compositionstart', _classPrivateFieldGet(this, _onCompositionStart));
173
+
174
+ _classPrivateFieldGet(this, _$input).addEventListener('mousedown', _classPrivateFieldGet(this, _onSelectionChange));
175
+
176
+ _classPrivateFieldGet(this, _$input).addEventListener('keydown', _classPrivateFieldGet(this, _onSelectionChange));
177
+
178
+ _classPrivateFieldGet(this, _$iconSlot).addEventListener('slotchange', _classPrivateFieldGet(this, _onIconSlotChange));
179
+
180
+ _classPrivateFieldGet(this, _$rightSlot).addEventListener('slotchange', _classPrivateFieldGet(this, _onRightSlotChange));
181
+
182
+ _classPrivateFieldGet(this, _$rightSlot).addEventListener('input', _classPrivateFieldGet(this, _onEventFilter));
183
+
184
+ _classPrivateFieldGet(this, _$rightSlot).addEventListener('change', _classPrivateFieldGet(this, _onEventFilter));
185
+
186
+ _classPrivateFieldGet(this, _$rightSlot).addEventListener('focusin', _classPrivateFieldGet(this, _onEventFilter));
187
+
188
+ _classPrivateFieldGet(this, _$rightSlot).addEventListener('focusout', _classPrivateFieldGet(this, _onEventFilter));
189
+
190
+ _classPrivateFieldGet(this, _onIconSlotChange).call(this);
191
+
192
+ _classPrivateFieldGet(this, _onRightSlotChange).call(this);
128
193
  }
129
194
 
130
195
  disconnectedCallback() {
131
196
  _classPrivateFieldGet(this, _$input).removeEventListener('input', _classPrivateFieldGet(this, _onInput));
132
197
 
133
198
  _classPrivateFieldGet(this, _$input).removeEventListener('compositionstart', _classPrivateFieldGet(this, _onCompositionStart));
199
+
200
+ _classPrivateFieldGet(this, _$input).removeEventListener('mousedown', _classPrivateFieldGet(this, _onSelectionChange));
201
+
202
+ _classPrivateFieldGet(this, _$input).removeEventListener('keydown', _classPrivateFieldGet(this, _onSelectionChange));
203
+
204
+ _classPrivateFieldGet(this, _$iconSlot).removeEventListener('slotchange', _classPrivateFieldGet(this, _onIconSlotChange));
205
+
206
+ _classPrivateFieldGet(this, _$rightSlot).removeEventListener('slotchange', _classPrivateFieldGet(this, _onRightSlotChange));
207
+
208
+ _classPrivateFieldGet(this, _$rightSlot).removeEventListener('input', _classPrivateFieldGet(this, _onEventFilter));
209
+
210
+ _classPrivateFieldGet(this, _$rightSlot).removeEventListener('change', _classPrivateFieldGet(this, _onEventFilter));
211
+
212
+ _classPrivateFieldGet(this, _$rightSlot).removeEventListener('focusin', _classPrivateFieldGet(this, _onEventFilter));
213
+
214
+ _classPrivateFieldGet(this, _$rightSlot).removeEventListener('focusout', _classPrivateFieldGet(this, _onEventFilter));
134
215
  }
135
216
 
136
217
  static get observedAttributes() {
@@ -241,12 +322,16 @@ defineCustomElement('sinch-input', (_$input = new WeakMap(), _$label = new WeakM
241
322
  {
242
323
  const nextVal = newVal ?? '';
243
324
 
244
- if (nextVal !== _classPrivateFieldGet(this, _$input).value) {
325
+ const prevVal = _classPrivateFieldGet(this, _$input).value;
326
+
327
+ if (nextVal !== prevVal) {
328
+ const prevCursorPos = _classPrivateFieldGet(this, _$input).selectionEnd;
329
+
330
+ const isPrevCursorEnd = prevCursorPos === prevVal.length;
245
331
  _classPrivateFieldGet(this, _$input).value = nextVal;
246
- const isNextCursorEnd = _classPrivateFieldGet(this, _selectionStart) === _classPrivateFieldGet(this, _selectionEnd) && (_classPrivateFieldGet(this, _selectionStart) === null || _classPrivateFieldGet(this, _selectionStart) === nextVal.length);
247
332
 
248
- if (!isNextCursorEnd) {
249
- _classPrivateFieldGet(this, _$input).setSelectionRange(_classPrivateFieldGet(this, _selectionStart), _classPrivateFieldGet(this, _selectionEnd));
333
+ if (!isPrevCursorEnd) {
334
+ _classPrivateFieldGet(this, _$input).setSelectionRange(_classPrivateFieldGet(this, _cursorPos), _classPrivateFieldGet(this, _cursorPos));
250
335
  }
251
336
  }
252
337
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "files": [
5
5
  "theme.css",
6
6
  "**/*/*.js",
package/popover/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import _classPrivateFieldGet from '@babel/runtime/helpers/classPrivateFieldGet';
2
2
  import _classPrivateFieldSet from '@babel/runtime/helpers/classPrivateFieldSet';
3
3
 
4
- var _$target, _$dialog, _isConnected, _resizeThrottle, _prevOverflowValue, _onExpand, _onCollapse, _isOpen, _onResize, _updateOrientation, _onBackdropClick, _onCancel, _onCloseReactHandler, _dispatchCloseEvent;
4
+ var _$target, _$dialog, _isConnected, _resizeThrottle, _prevOverflowValue, _onExpand, _onCollapse, _isOpen, _onResize, _updateOrientation, _updateOrientationModal, _onBackdropClick, _onCancel, _onCloseReactHandler, _onTargetKeydown, _dispatchCloseEvent;
5
5
 
6
6
  function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
7
7
 
@@ -12,13 +12,13 @@ function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollect
12
12
  function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
13
13
 
14
14
  import dialogPolyfill from 'dialog-polyfill';
15
- import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, updateLiteralAttribute, getReactEventHandler, updateBooleanAttribute, NectaryElement, getCssVar, throttleAnimationFrame } from '../utils';
16
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{position:relative}dialog{position:fixed;top:0;left:0;margin:0;outline:0;font:var(--sinch-font-body);color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-100);box-shadow:var(--sinch-elevation-level-2);border:1px solid var(--sinch-color-snow-500);border-radius:var(--sinch-shape-radius-s);contain:content;padding:0;box-sizing:border-box;max-width:unset;max-height:unset}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}#target{display:flex;flex-direction:column}</style><div id="wrapper"><div id="target" aria-haspopup="dialog" aria-expanded="false"><slot name="target"></slot></div><dialog id="dialog" tabindex="-1"><slot name="content"></slot></dialog></div>';
15
+ import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, updateLiteralAttribute, getReactEventHandler, updateBooleanAttribute, NectaryElement, throttleAnimationFrame } from '../utils';
16
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{position:relative}dialog{position:fixed;top:0;left:0;margin:0;outline:0;font:var(--sinch-font-body);color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-100);box-shadow:var(--sinch-elevation-level-2);border:1px solid var(--sinch-color-snow-500);border-radius:var(--sinch-popover-shape-radius,var(--sinch-shape-radius-l));contain:content;padding:0;box-sizing:border-box;max-width:unset;max-height:unset;z-index:1}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}#target{display:flex;flex-direction:column}</style><div id="wrapper"><div id="target" aria-haspopup="dialog" aria-expanded="false"><slot name="target"></slot></div><dialog id="dialog" tabindex="-1"><slot name="content"></slot></dialog></div>';
17
17
  import { orientationValues } from './utils';
18
18
  const template = document.createElement('template');
19
19
  template.innerHTML = templateHTML;
20
20
  const POPOVER_OFFSET = 4;
21
- defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new WeakMap(), _isConnected = new WeakMap(), _resizeThrottle = new WeakMap(), _prevOverflowValue = new WeakMap(), _onExpand = new WeakSet(), _onCollapse = new WeakSet(), _isOpen = new WeakSet(), _onResize = new WeakMap(), _updateOrientation = new WeakMap(), _onBackdropClick = new WeakMap(), _onCancel = new WeakMap(), _onCloseReactHandler = new WeakMap(), _dispatchCloseEvent = new WeakSet(), class extends NectaryElement {
21
+ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new WeakMap(), _isConnected = new WeakMap(), _resizeThrottle = new WeakMap(), _prevOverflowValue = new WeakMap(), _onExpand = new WeakSet(), _onCollapse = new WeakSet(), _isOpen = new WeakSet(), _onResize = new WeakMap(), _updateOrientation = new WeakMap(), _updateOrientationModal = new WeakMap(), _onBackdropClick = new WeakMap(), _onCancel = new WeakMap(), _onCloseReactHandler = new WeakMap(), _onTargetKeydown = new WeakMap(), _dispatchCloseEvent = new WeakSet(), class extends NectaryElement {
22
22
  constructor() {
23
23
  super();
24
24
 
@@ -65,7 +65,7 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
65
65
  _classPrivateFieldInitSpec(this, _updateOrientation, {
66
66
  writable: true,
67
67
  value: () => {
68
- _classPrivateFieldGet(this, _$dialog).style.width = 'fit-content';
68
+ _classPrivateFieldGet(this, _$dialog).style.width = 'max-content';
69
69
 
70
70
  const targetRect = _classPrivateFieldGet(this, _$target).getBoundingClientRect();
71
71
 
@@ -74,11 +74,43 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
74
74
  let leftPos = 0;
75
75
  let topPos = 0;
76
76
  const orient = this.orientation;
77
- const shouldExpandWidthToTarget = getCssVar(this, '--sinch-popover-expand-width') !== null;
78
- const largestWidth = Math.max(modalRect.width, targetRect.width);
79
- const resultWidth = shouldExpandWidthToTarget ? largestWidth : modalRect.width;
77
+ const shouldExpandWidthToTarget = orient === 'top' || orient === 'bottom';
78
+ const resultWidth = shouldExpandWidthToTarget ? Math.max(modalRect.width, targetRect.width) : modalRect.width;
80
79
 
81
- if (orient === 'bottom-right' || orient === 'top-right') {
80
+ if (orient === 'bottom-left' || orient === 'top-left') {
81
+ leftPos = targetRect.width - resultWidth;
82
+ }
83
+
84
+ if (orient === 'bottom-left' || orient === 'bottom-right' || orient === 'bottom') {
85
+ topPos = targetRect.height + POPOVER_OFFSET;
86
+ }
87
+
88
+ if (orient === 'top-left' || orient === 'top-right' || orient === 'top') {
89
+ topPos = -(modalRect.height + POPOVER_OFFSET);
90
+ }
91
+
92
+ _classPrivateFieldGet(this, _$dialog).style.left = `${leftPos}px`;
93
+ _classPrivateFieldGet(this, _$dialog).style.top = `${topPos}px`;
94
+ _classPrivateFieldGet(this, _$dialog).style.width = `${resultWidth}px`;
95
+ }
96
+ });
97
+
98
+ _classPrivateFieldInitSpec(this, _updateOrientationModal, {
99
+ writable: true,
100
+ value: () => {
101
+ _classPrivateFieldGet(this, _$dialog).style.width = 'max-content';
102
+
103
+ const targetRect = _classPrivateFieldGet(this, _$target).getBoundingClientRect();
104
+
105
+ const modalRect = _classPrivateFieldGet(this, _$dialog).getBoundingClientRect();
106
+
107
+ let leftPos = 0;
108
+ let topPos = 0;
109
+ const orient = this.orientation;
110
+ const shouldExpandWidthToTarget = orient === 'top' || orient === 'bottom';
111
+ const resultWidth = shouldExpandWidthToTarget ? Math.max(modalRect.width, targetRect.width) : modalRect.width;
112
+
113
+ if (orient === 'bottom-right' || orient === 'top-right' || orient === 'top' || orient === 'bottom') {
82
114
  leftPos = Math.max(POPOVER_OFFSET, Math.min(targetRect.x, window.innerWidth - resultWidth - POPOVER_OFFSET));
83
115
  }
84
116
 
@@ -86,11 +118,11 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
86
118
  leftPos = Math.max(POPOVER_OFFSET, targetRect.right - resultWidth);
87
119
  }
88
120
 
89
- if (orient === 'bottom-left' || orient === 'bottom-right') {
121
+ if (orient === 'bottom-left' || orient === 'bottom-right' || orient === 'bottom') {
90
122
  topPos = Math.max(POPOVER_OFFSET, Math.min(targetRect.bottom + POPOVER_OFFSET, window.innerHeight - modalRect.height - POPOVER_OFFSET));
91
123
  }
92
124
 
93
- if (orient === 'top-left' || orient === 'top-right') {
125
+ if (orient === 'top-left' || orient === 'top-right' || orient === 'top') {
94
126
  topPos = Math.max(POPOVER_OFFSET, targetRect.top - POPOVER_OFFSET - modalRect.height);
95
127
  }
96
128
 
@@ -134,6 +166,22 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
134
166
  }
135
167
  });
136
168
 
169
+ _classPrivateFieldInitSpec(this, _onTargetKeydown, {
170
+ writable: true,
171
+ value: e => {
172
+ switch (e.key) {
173
+ case 'Escape':
174
+ {
175
+ e.preventDefault();
176
+
177
+ _classPrivateMethodGet(this, _dispatchCloseEvent, _dispatchCloseEvent2).call(this);
178
+
179
+ break;
180
+ }
181
+ }
182
+ }
183
+ });
184
+
137
185
  const shadowRoot = this.attachShadow();
138
186
  shadowRoot.appendChild(template.content.cloneNode(true));
139
187
 
@@ -143,7 +191,7 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
143
191
 
144
192
  _classPrivateFieldSet(this, _isConnected, false);
145
193
 
146
- _classPrivateFieldSet(this, _resizeThrottle, throttleAnimationFrame(_classPrivateFieldGet(this, _updateOrientation)));
194
+ _classPrivateFieldSet(this, _resizeThrottle, throttleAnimationFrame(_classPrivateFieldGet(this, _updateOrientationModal)));
147
195
 
148
196
  dialogPolyfill.registerDialog(_classPrivateFieldGet(this, _$dialog));
149
197
  }
@@ -173,11 +221,21 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
173
221
 
174
222
  this.removeEventListener('close', _classPrivateFieldGet(this, _onCloseReactHandler));
175
223
 
224
+ _classPrivateMethodGet(this, _onCollapse, _onCollapse2).call(this);
225
+
176
226
  _classPrivateFieldSet(this, _isConnected, false);
177
227
  }
178
228
 
179
229
  static get observedAttributes() {
180
- return ['open', 'orientation'];
230
+ return ['modal', 'orientation', 'open'];
231
+ }
232
+
233
+ set modal(isModal) {
234
+ updateBooleanAttribute(this, 'modal', isModal);
235
+ }
236
+
237
+ get modal() {
238
+ return getBooleanAttribute(this, 'modal');
181
239
  }
182
240
 
183
241
  set open(isOpen) {
@@ -189,7 +247,7 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
189
247
  }
190
248
 
191
249
  get orientation() {
192
- return getLiteralAttribute(this, orientationValues, 'orientation', 'bottom-right');
250
+ return getLiteralAttribute(this, orientationValues, 'orientation', 'bottom');
193
251
  }
194
252
 
195
253
  set orientation(value) {
@@ -201,48 +259,77 @@ defineCustomElement('sinch-popover', (_$target = new WeakMap(), _$dialog = new W
201
259
  }
202
260
 
203
261
  attributeChangedCallback(name, oldVal, newVal) {
262
+ if (oldVal === newVal) {
263
+ return;
264
+ }
265
+
204
266
  switch (name) {
205
267
  case 'open':
206
268
  {
207
- if (_classPrivateFieldGet(this, _isConnected)) {
208
- if (isAttrTrue(newVal)) {
209
- _classPrivateMethodGet(this, _onExpand, _onExpand2).call(this);
210
- } else {
211
- _classPrivateMethodGet(this, _onCollapse, _onCollapse2).call(this);
212
- }
269
+ if (isAttrTrue(newVal)) {
270
+ _classPrivateMethodGet(this, _onExpand, _onExpand2).call(this);
271
+ } else {
272
+ _classPrivateMethodGet(this, _onCollapse, _onCollapse2).call(this);
213
273
  }
214
274
 
275
+ updateBooleanAttribute(this, 'open', isAttrTrue(newVal));
215
276
  break;
216
277
  }
217
278
 
218
279
  case 'orientation':
219
280
  {
220
281
  if (_classPrivateMethodGet(this, _isOpen, _isOpen2).call(this)) {
221
- _classPrivateFieldGet(this, _updateOrientation).call(this);
282
+ if (this.modal) {
283
+ _classPrivateFieldGet(this, _updateOrientationModal).call(this);
284
+ } else {
285
+ _classPrivateFieldGet(this, _updateOrientation).call(this);
286
+ }
222
287
  }
223
288
 
224
289
  break;
225
290
  }
291
+
292
+ case 'modal':
293
+ {
294
+ if (_classPrivateMethodGet(this, _isOpen, _isOpen2).call(this)) {
295
+ _classPrivateMethodGet(this, _onCollapse, _onCollapse2).call(this);
296
+
297
+ _classPrivateMethodGet(this, _onExpand, _onExpand2).call(this);
298
+ }
299
+ }
226
300
  }
227
301
  }
228
302
 
229
303
  }));
230
304
 
231
305
  function _onExpand2() {
232
- if (_classPrivateMethodGet(this, _isOpen, _isOpen2).call(this)) {
306
+ if (!_classPrivateFieldGet(this, _isConnected) || _classPrivateMethodGet(this, _isOpen, _isOpen2).call(this)) {
233
307
  return;
234
308
  }
235
309
 
236
- _classPrivateFieldGet(this, _$target).setAttribute('aria-expanded', 'true');
310
+ if (this.modal) {
311
+ _classPrivateFieldGet(this, _$dialog).style.position = 'fixed';
312
+
313
+ _classPrivateFieldGet(this, _$dialog).showModal();
314
+
315
+ _classPrivateFieldGet(this, _updateOrientationModal).call(this);
316
+
317
+ _classPrivateFieldGet(this, _$target).setAttribute('aria-expanded', 'true');
237
318
 
238
- _classPrivateFieldGet(this, _$dialog).showModal();
319
+ _classPrivateFieldSet(this, _prevOverflowValue, document.body.style.overflow);
239
320
 
240
- _classPrivateFieldGet(this, _updateOrientation).call(this);
321
+ document.body.style.overflow = 'hidden';
322
+ window.addEventListener('resize', _classPrivateFieldGet(this, _onResize));
323
+ } else {
324
+ this.addEventListener('keydown', _classPrivateFieldGet(this, _onTargetKeydown));
325
+ _classPrivateFieldGet(this, _$dialog).style.position = 'absolute';
241
326
 
242
- _classPrivateFieldSet(this, _prevOverflowValue, document.body.style.overflow);
327
+ _classPrivateFieldGet(this, _$dialog).setAttribute('open', '');
243
328
 
244
- document.body.style.overflow = 'hidden';
245
- window.addEventListener('resize', _classPrivateFieldGet(this, _onResize));
329
+ _classPrivateFieldGet(this, _updateOrientation).call(this);
330
+
331
+ _classPrivateFieldGet(this, _$target).setAttribute('aria-expanded', 'true');
332
+ }
246
333
  }
247
334
 
248
335
  function _onCollapse2() {
@@ -250,17 +337,24 @@ function _onCollapse2() {
250
337
  return;
251
338
  }
252
339
 
340
+ if (this.modal) {
341
+ _classPrivateFieldGet(this, _$dialog).close?.();
342
+ } else {
343
+ _classPrivateFieldGet(this, _$dialog).removeAttribute('open');
344
+ }
345
+
253
346
  _classPrivateFieldGet(this, _$target).setAttribute('aria-expanded', 'false');
254
347
 
255
- _classPrivateFieldGet(this, _$dialog).close?.();
256
348
  document.body.style.overflow = _classPrivateFieldGet(this, _prevOverflowValue);
257
- window.removeEventListener('resize', _classPrivateFieldGet(this, _onResize));
258
349
 
259
350
  _classPrivateFieldGet(this, _resizeThrottle).cancel();
351
+
352
+ window.removeEventListener('resize', _classPrivateFieldGet(this, _onResize));
353
+ this.removeEventListener('keydown', _classPrivateFieldGet(this, _onTargetKeydown));
260
354
  }
261
355
 
262
356
  function _isOpen2() {
263
- return _classPrivateFieldGet(this, _isConnected) && getBooleanAttribute(_classPrivateFieldGet(this, _$dialog), 'open');
357
+ return getBooleanAttribute(_classPrivateFieldGet(this, _$dialog), 'open');
264
358
  }
265
359
 
266
360
  function _dispatchCloseEvent2() {
@@ -1,17 +1,32 @@
1
1
  import type { TRect, TSinchElementReact } from '../types';
2
2
  import type { SyntheticEvent } from 'react';
3
- export declare type TSinchPopoverOrientation = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
3
+ export declare type TSinchPopoverOrientation = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'bottom' | 'top';
4
4
  export declare type TSinchPopoverElement = HTMLElement & {
5
+ /** Open/close state */
5
6
  open: boolean;
7
+ /** Orientation, where it *points to* from origin */
6
8
  orientation: TSinchPopoverOrientation;
9
+ /** Modal/non-modal mode */
10
+ modal: boolean;
7
11
  readonly popoverRect: TRect;
12
+ /** Close event */
8
13
  addEventListener(type: 'close', listener: (e: CustomEvent<void>) => void): void;
14
+ /** Open/close state */
9
15
  setAttribute(name: 'open', value: ''): void;
16
+ /** Orientation, where it *points to* from origin */
10
17
  setAttribute(name: 'orientation', value: TSinchPopoverOrientation): void;
18
+ /** Modal/non-modal mode */
19
+ setAttribute(name: 'modal', value: boolean): void;
11
20
  };
12
21
  export declare type TSinchPopoverReact = TSinchElementReact<TSinchPopoverElement> & {
22
+ /** Open/close state */
13
23
  open: boolean;
24
+ /** Orientation, where it *points to* from origin */
14
25
  orientation?: TSinchPopoverOrientation;
26
+ /** Modal/non-modal mode */
27
+ modal?: boolean;
28
+ /** Label that is used for a11y */
15
29
  'aria-label': string;
16
- onClose: (event: SyntheticEvent<TSinchPopoverElement, CustomEvent<void>>) => void;
30
+ /** Close event handler */
31
+ onClose?: (event: SyntheticEvent<TSinchPopoverElement, CustomEvent<void>>) => void;
17
32
  };
package/popover/utils.js CHANGED
@@ -1 +1 @@
1
- export const orientationValues = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
1
+ export const orientationValues = ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'bottom', 'top'];
package/select/index.js CHANGED
@@ -13,7 +13,7 @@ function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(
13
13
 
14
14
  import '../dropdown';
15
15
  import { defineCustomElement, getAttribute, getBooleanAttribute, getIntegerAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute, updateIntegerAttribute } from '../utils';
16
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0;--sinch-color-icon:var(--sinch-color-stormy-500)}#wrapper{position:relative;--sinch-popover-expand-width:1}sinch-dropdown{display:block}#button{all:initial;display:flex;align-items:center;gap:8px;border:1px solid var(--sinch-color-stormy-200);border-radius:var(--sinch-shape-radius-s);box-sizing:border-box;width:100%;height:48px;margin:2px 0;padding:8px 12px;font:var(--sinch-font-body);color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-100);cursor:pointer}#button:focus{border-color:var(--sinch-color-stormy-600)}#dropdown-icon{fill:var(--sinch-color-stormy-500)}#button>*{pointer-events:none}#button[data-unselected]{color:var(--sinch-color-text-muted)}#button:disabled{border-color:var(--sinch-color-snow-500);color:var(--sinch-color-stormy-100);cursor:initial}#button:disabled #dropdown-icon{fill:var(--sinch-color-stormy-100)}:host([invalidtext]:not([invalidtext=""])) #button:not(:disabled){border-color:var(--sinch-color-text-invalid)}#content{flex:1;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}#bottom,#top{display:flex;align-items:baseline}#top{height:24px}#bottom{height:20px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-font-title-s);color:var(--sinch-color-text-default)}#optional{flex:1;text-align:right;font:var(--sinch-font-small-text);color:var(--sinch-color-text-muted)}#additional{flex:1;text-align:right;font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-muted)}#invalid{font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-invalid)}::slotted(sinch-help-tooltip){align-self:center;margin:0 8px}:host([disabled]:not([disabled=false])) :is(#label,#additional,#optional,#invalid){color:var(--sinch-color-stormy-100)}:host([disabled]:not([disabled=false])){--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><div id="top"><label id="label" for="button"></label><slot name="tooltip"></slot><span id="optional"></span></div><sinch-dropdown id="dropdown"><button slot="target" id="button"><span id="content"></span> <svg id="dropdown-icon" width="12" height="8" aria-hidden="true"><path d="M1.41.59 6 5.17 10.59.59 12 2 6 8 0 2 1.41.59Z"/></svg></button><slot name="option" slot="option"></slot></sinch-dropdown><div id="bottom"><span id="invalid"></span> <span id="additional"></span></div></div>';
16
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0;--sinch-color-icon:var(--sinch-color-stormy-500)}#wrapper{position:relative}sinch-dropdown{display:block}#button{all:initial;display:flex;align-items:center;gap:8px;border:1px solid var(--sinch-color-stormy-200);border-radius:var(--sinch-shape-radius-s);box-sizing:border-box;width:100%;height:48px;padding:8px 12px;font:var(--sinch-font-body);color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-100);cursor:pointer}#button:focus{border-color:var(--sinch-color-stormy-600)}#dropdown-icon{fill:var(--sinch-color-stormy-500)}#button>*{pointer-events:none}#button[data-unselected]{color:var(--sinch-color-text-muted)}#button:disabled{border-color:var(--sinch-color-snow-500);color:var(--sinch-color-stormy-100);cursor:initial}#button:disabled #dropdown-icon{fill:var(--sinch-color-stormy-100)}:host([invalidtext]:not([invalidtext=""])) #button:not(:disabled){border-color:var(--sinch-color-text-invalid)}#content{flex:1;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}#bottom,#top{display:flex;align-items:baseline}#top{height:24px;margin-bottom:2px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-font-title-s);color:var(--sinch-color-text-default)}#optional{flex:1;text-align:right;font:var(--sinch-font-small-text);color:var(--sinch-color-text-muted)}#additional{flex:1;text-align:right;font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-muted);line-height:20px;margin-top:2px}#additional:empty{display:none}#invalid{font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-invalid);line-height:20px;margin-top:2px}#invalid:empty{display:none}::slotted(sinch-help-tooltip){align-self:center;margin:0 8px}:host([disabled]:not([disabled=false])) :is(#label,#additional,#optional,#invalid){color:var(--sinch-color-stormy-100)}:host([disabled]:not([disabled=false])){--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><div id="top"><label id="label" for="button"></label><slot name="tooltip"></slot><span id="optional"></span></div><sinch-dropdown id="dropdown" modal orientation="bottom"><button slot="target" id="button"><span id="content"></span> <svg id="dropdown-icon" width="12" height="8" aria-hidden="true"><path d="M1.41.59 6 5.17 10.59.59 12 2 6 8 0 2 1.41.59Z"/></svg></button><slot name="option" slot="option"></slot></sinch-dropdown><div id="bottom"><span id="invalid"></span> <span id="additional"></span></div></div>';
17
17
  const template = document.createElement('template');
18
18
  template.innerHTML = templateHTML;
19
19
  defineCustomElement('sinch-select', (_$button = new WeakMap(), _$buttonContent = new WeakMap(), _$label = new WeakMap(), _$optionalText = new WeakMap(), _$additionalText = new WeakMap(), _$invalidText = new WeakMap(), _$dropdown = new WeakMap(), _$optionSlot = new WeakMap(), _$sh = new WeakMap(), _createElement = new WeakSet(), _updateButtonContent = new WeakSet(), _onValueChange = new WeakMap(), _getOptionWithValue = new WeakSet(), _onLabelClick = new WeakMap(), _onDropdownClick = new WeakMap(), _onDropdownClose = new WeakMap(), class extends NectaryElement {
package/textarea/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import _classPrivateFieldGet from '@babel/runtime/helpers/classPrivateFieldGet';
2
2
  import _classPrivateFieldSet from '@babel/runtime/helpers/classPrivateFieldSet';
3
3
 
4
- var _$input, _$label, _$optionalText, _$additionalText, _$invalidText, _selectionStart, _selectionEnd, _isPendingDk, _onCompositionStart, _onInput;
4
+ var _$input, _$label, _$optionalText, _$additionalText, _$invalidText, _cursorPos, _isPendingDk, _onCompositionStart, _onSelectionChange, _onInput;
5
5
 
6
6
  function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
7
7
 
8
8
  function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
9
9
 
10
10
  import { defineCustomElement, getAttribute, getBooleanAttribute, getIntegerAttribute, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute, updateExplicitBooleanAttribute } from '../utils';
11
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0;--sinch-color-icon:var(--sinch-color-stormy-500)}#wrapper{width:100%;box-sizing:border-box}#input{all:initial;border:1px solid var(--sinch-color-stormy-200);box-sizing:border-box;border-radius:var(--sinch-shape-radius-s);width:100%;margin:2px 0;padding:8px 12px;font:var(--sinch-font-body);color:var(--sinch-color-text-default);caret-color:var(--sinch-caret-color,auto);background-color:var(--sinch-color-snow-100);resize:none}#input::placeholder{font:var(--sinch-font-body);color:var(--sinch-color-text-muted)}#input:disabled{border-color:var(--sinch-color-snow-500);color:var(--sinch-color-stormy-100)}#input:disabled::placeholder{color:var(--sinch-color-snow-500)}#input:focus{border-color:var(--sinch-color-stormy-600)}:host([resizable]:not([resizable=false])) #input{resize:vertical}:host([invalidtext]:not([invalidtext=""])) #input:not(:disabled){border-color:var(--sinch-color-text-invalid)}#bottom,#top{display:flex;align-items:baseline}#top{height:24px}#bottom{height:20px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-font-title-s);color:var(--sinch-color-text-default)}#optional{flex:1;text-align:right;font:var(--sinch-font-small-text);color:var(--sinch-color-text-muted)}#additional{flex:1;text-align:right;font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-muted)}#invalid{font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-invalid)}::slotted(sinch-help-tooltip){align-self:center;margin:0 8px}:host([disabled]:not([disabled=false])) :is(#label,#additional,#optional,#invalid){color:var(--sinch-color-stormy-100)}:host([disabled]:not([disabled=false])){--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><slot name="tooltip"></slot><span id="optional"></span></div><textarea id="input"></textarea><div id="bottom"><span id="invalid"></span> <span id="additional"></span></div></div>';
11
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0;--sinch-color-icon:var(--sinch-color-stormy-500)}#wrapper{width:100%;box-sizing:border-box}#input{all:initial;border:1px solid var(--sinch-color-stormy-200);box-sizing:border-box;border-radius:var(--sinch-shape-radius-s);width:100%;padding:8px 12px;font:var(--sinch-font-body);color:var(--sinch-color-text-default);caret-color:var(--sinch-caret-color,auto);background-color:var(--sinch-color-snow-100);resize:none}#input::placeholder{font:var(--sinch-font-body);color:var(--sinch-color-text-muted)}#input:disabled{border-color:var(--sinch-color-snow-500);color:var(--sinch-color-stormy-100)}#input:disabled::placeholder{color:var(--sinch-color-snow-500)}#input:focus{border-color:var(--sinch-color-stormy-600)}:host([resizable]:not([resizable=false])) #input{resize:vertical}:host([invalidtext]:not([invalidtext=""])) #input:not(:disabled){border-color:var(--sinch-color-text-invalid)}#bottom,#top{display:flex;align-items:baseline}#top{height:24px;margin-bottom:2px}#additional,#invalid,#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-font-title-s);color:var(--sinch-color-text-default)}#optional{flex:1;text-align:right;font:var(--sinch-font-small-text);color:var(--sinch-color-text-muted)}#additional{flex:1;text-align:right;font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-muted);line-height:20px;margin-top:2px}#additional:empty{display:none}#invalid{font:var(--sinch-font-extra-small-text);color:var(--sinch-color-text-invalid);line-height:20px;margin-top:2px}#invalid:empty{display:none}::slotted(sinch-help-tooltip){align-self:center;margin:0 8px}:host([disabled]:not([disabled=false])) :is(#label,#additional,#optional,#invalid){color:var(--sinch-color-stormy-100)}:host([disabled]:not([disabled=false])){--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><slot name="tooltip"></slot><span id="optional"></span></div><textarea id="input"></textarea><div id="bottom"><span id="invalid"></span> <span id="additional"></span></div></div>';
12
12
  const template = document.createElement('template');
13
13
  template.innerHTML = templateHTML;
14
- defineCustomElement('sinch-textarea', (_$input = new WeakMap(), _$label = new WeakMap(), _$optionalText = new WeakMap(), _$additionalText = new WeakMap(), _$invalidText = new WeakMap(), _selectionStart = new WeakMap(), _selectionEnd = new WeakMap(), _isPendingDk = new WeakMap(), _onCompositionStart = new WeakMap(), _onInput = new WeakMap(), class extends NectaryElement {
14
+ defineCustomElement('sinch-textarea', (_$input = new WeakMap(), _$label = new WeakMap(), _$optionalText = new WeakMap(), _$additionalText = new WeakMap(), _$invalidText = new WeakMap(), _cursorPos = new WeakMap(), _isPendingDk = new WeakMap(), _onCompositionStart = new WeakMap(), _onSelectionChange = new WeakMap(), _onInput = new WeakMap(), class extends NectaryElement {
15
15
  constructor() {
16
16
  super();
17
17
 
@@ -40,12 +40,7 @@ defineCustomElement('sinch-textarea', (_$input = new WeakMap(), _$label = new We
40
40
  value: void 0
41
41
  });
42
42
 
43
- _classPrivateFieldInitSpec(this, _selectionStart, {
44
- writable: true,
45
- value: null
46
- });
47
-
48
- _classPrivateFieldInitSpec(this, _selectionEnd, {
43
+ _classPrivateFieldInitSpec(this, _cursorPos, {
49
44
  writable: true,
50
45
  value: null
51
46
  });
@@ -62,6 +57,13 @@ defineCustomElement('sinch-textarea', (_$input = new WeakMap(), _$label = new We
62
57
  }
63
58
  });
64
59
 
60
+ _classPrivateFieldInitSpec(this, _onSelectionChange, {
61
+ writable: true,
62
+ value: () => {
63
+ _classPrivateFieldSet(this, _cursorPos, _classPrivateFieldGet(this, _$input).selectionEnd);
64
+ }
65
+ });
66
+
65
67
  _classPrivateFieldInitSpec(this, _onInput, {
66
68
  writable: true,
67
69
  value: e => {
@@ -72,29 +74,23 @@ defineCustomElement('sinch-textarea', (_$input = new WeakMap(), _$label = new We
72
74
  const prevValue = this.value;
73
75
 
74
76
  if (prevValue !== nextValue) {
75
- const nextSelectionStart = _classPrivateFieldGet(this, _$input).selectionStart;
76
-
77
- const nextSelectionEnd = _classPrivateFieldGet(this, _$input).selectionEnd;
78
-
79
- const prevSelectionStart = _classPrivateFieldGet(this, _selectionStart);
80
-
81
- const prevSelectionEnd = _classPrivateFieldGet(this, _selectionEnd);
82
-
83
- const isPrevCursorEnd = prevSelectionStart === prevSelectionEnd && prevSelectionStart === prevValue.length;
77
+ const nextCursorPos = _classPrivateFieldGet(this, _$input).selectionEnd;
84
78
 
85
79
  if (!_classPrivateFieldGet(this, _isPendingDk)) {
86
80
  _classPrivateFieldGet(this, _$input).value = prevValue;
87
- }
88
81
 
89
- _classPrivateFieldSet(this, _isPendingDk, false);
82
+ const prevCursorPos = _classPrivateFieldGet(this, _cursorPos);
90
83
 
91
- if (!isPrevCursorEnd) {
92
- _classPrivateFieldGet(this, _$input).setSelectionRange(prevSelectionStart, prevSelectionEnd);
84
+ const isPrevCursorEnd = prevCursorPos === null || prevCursorPos === prevValue.length;
85
+
86
+ if (!isPrevCursorEnd) {
87
+ _classPrivateFieldGet(this, _$input).setSelectionRange(prevCursorPos, prevCursorPos);
88
+ }
93
89
  }
94
90
 
95
- _classPrivateFieldSet(this, _selectionStart, nextSelectionStart);
91
+ _classPrivateFieldSet(this, _isPendingDk, false);
96
92
 
97
- _classPrivateFieldSet(this, _selectionEnd, nextSelectionEnd);
93
+ _classPrivateFieldSet(this, _cursorPos, nextCursorPos);
98
94
 
99
95
  this.dispatchEvent(new CustomEvent('change', {
100
96
  detail: nextValue,
@@ -125,12 +121,20 @@ defineCustomElement('sinch-textarea', (_$input = new WeakMap(), _$label = new We
125
121
  _classPrivateFieldGet(this, _$input).addEventListener('input', _classPrivateFieldGet(this, _onInput));
126
122
 
127
123
  _classPrivateFieldGet(this, _$input).addEventListener('compositionstart', _classPrivateFieldGet(this, _onCompositionStart));
124
+
125
+ _classPrivateFieldGet(this, _$input).addEventListener('mousedown', _classPrivateFieldGet(this, _onSelectionChange));
126
+
127
+ _classPrivateFieldGet(this, _$input).addEventListener('keydown', _classPrivateFieldGet(this, _onSelectionChange));
128
128
  }
129
129
 
130
130
  disconnectedCallback() {
131
131
  _classPrivateFieldGet(this, _$input).removeEventListener('input', _classPrivateFieldGet(this, _onInput));
132
132
 
133
133
  _classPrivateFieldGet(this, _$input).removeEventListener('compositionstart', _classPrivateFieldGet(this, _onCompositionStart));
134
+
135
+ _classPrivateFieldGet(this, _$input).removeEventListener('mousedown', _classPrivateFieldGet(this, _onSelectionChange));
136
+
137
+ _classPrivateFieldGet(this, _$input).removeEventListener('keydown', _classPrivateFieldGet(this, _onSelectionChange));
134
138
  }
135
139
 
136
140
  static get observedAttributes() {
@@ -143,12 +147,16 @@ defineCustomElement('sinch-textarea', (_$input = new WeakMap(), _$label = new We
143
147
  {
144
148
  const nextVal = newVal ?? '';
145
149
 
146
- if (nextVal !== _classPrivateFieldGet(this, _$input).value) {
150
+ const prevVal = _classPrivateFieldGet(this, _$input).value;
151
+
152
+ if (nextVal !== prevVal) {
153
+ const prevCursorPos = _classPrivateFieldGet(this, _$input).selectionEnd;
154
+
155
+ const isPrevCursorEnd = prevCursorPos === prevVal.length;
147
156
  _classPrivateFieldGet(this, _$input).value = nextVal;
148
- const isNextCursorEnd = _classPrivateFieldGet(this, _selectionStart) === _classPrivateFieldGet(this, _selectionEnd) && (_classPrivateFieldGet(this, _selectionStart) === null || _classPrivateFieldGet(this, _selectionStart) === nextVal.length);
149
157
 
150
- if (!isNextCursorEnd) {
151
- _classPrivateFieldGet(this, _$input).setSelectionRange(_classPrivateFieldGet(this, _selectionStart), _classPrivateFieldGet(this, _selectionEnd));
158
+ if (!isPrevCursorEnd) {
159
+ _classPrivateFieldGet(this, _$input).setSelectionRange(_classPrivateFieldGet(this, _cursorPos), _classPrivateFieldGet(this, _cursorPos));
152
160
  }
153
161
  }
154
162