@nectary/components 0.40.0 → 0.41.1

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 (74) hide show
  1. package/accordion-item/index.js +4 -0
  2. package/action-menu/index.js +11 -13
  3. package/action-menu-option/index.js +2 -1
  4. package/button/index.js +5 -1
  5. package/button/types.d.ts +1 -1
  6. package/checkbox/index.js +4 -0
  7. package/chip/index.js +18 -15
  8. package/chip/types.d.ts +3 -4
  9. package/color-menu/index.d.ts +1 -0
  10. package/color-menu/index.js +37 -51
  11. package/color-menu/types.d.ts +5 -6
  12. package/color-menu/utils.d.ts +1 -0
  13. package/color-menu/utils.js +15 -0
  14. package/color-swatch/index.js +8 -7
  15. package/color-swatch/types.d.ts +3 -4
  16. package/colors.json +14 -10
  17. package/date-picker/index.js +1 -1
  18. package/field/index.js +22 -5
  19. package/file-drop/index.js +1 -1
  20. package/file-picker/index.js +1 -1
  21. package/help-tooltip/index.js +10 -27
  22. package/icon-button/index.d.ts +1 -0
  23. package/icon-button/index.js +26 -15
  24. package/icon-button/types.d.ts +16 -2
  25. package/input/index.js +4 -0
  26. package/link/index.js +5 -1
  27. package/package.json +1 -1
  28. package/pagination/index.js +4 -0
  29. package/pop/index.d.ts +11 -0
  30. package/pop/index.js +429 -0
  31. package/pop/types.d.ts +35 -0
  32. package/pop/utils.d.ts +7 -0
  33. package/pop/utils.js +18 -0
  34. package/popover/index.d.ts +1 -0
  35. package/popover/index.js +91 -230
  36. package/popover/types.d.ts +8 -1
  37. package/popover/utils.d.ts +5 -0
  38. package/popover/utils.js +17 -1
  39. package/radio-option/index.js +4 -0
  40. package/segment-collapse/index.js +4 -0
  41. package/segmented-control-option/index.js +5 -1
  42. package/segmented-icon-control-option/index.js +5 -1
  43. package/select-button/index.js +6 -1
  44. package/select-menu/index.js +12 -13
  45. package/tabs-option/index.js +4 -0
  46. package/tag/index.js +13 -15
  47. package/tag/types.d.ts +3 -4
  48. package/textarea/index.js +4 -0
  49. package/theme.css +76 -10
  50. package/tile-control-option/index.js +5 -1
  51. package/time-picker/index.js +1 -1
  52. package/toggle/index.js +5 -1
  53. package/tooltip/index.d.ts +2 -0
  54. package/tooltip/index.js +160 -17
  55. package/tooltip/types.d.ts +13 -0
  56. package/tooltip/utils.d.ts +5 -0
  57. package/tooltip/utils.js +25 -1
  58. package/types.d.ts +0 -7
  59. package/utils/animation.d.ts +17 -0
  60. package/utils/animation.js +142 -0
  61. package/utils/colors.d.ts +4 -9
  62. package/utils/colors.js +4 -120
  63. package/utils/context.d.ts +15 -0
  64. package/utils/context.js +57 -0
  65. package/utils/index.d.ts +5 -9
  66. package/utils/index.js +49 -50
  67. package/dropdown-checkbox-option/index.d.ts +0 -11
  68. package/dropdown-checkbox-option/index.js +0 -74
  69. package/dropdown-checkbox-option/types.d.ts +0 -15
  70. package/dropdown-radio-option/index.d.ts +0 -11
  71. package/dropdown-radio-option/index.js +0 -74
  72. package/dropdown-radio-option/types.d.ts +0 -15
  73. package/dropdown-radio-option/types.js +0 -1
  74. /package/{dropdown-checkbox-option → pop}/types.js +0 -0
@@ -7,7 +7,7 @@ import '../icons/delete-outline';
7
7
  import '../icons/today';
8
8
  import '../text';
9
9
  import { defineCustomElement, getAttribute, getReactEventHandler, getRect, NectaryElement, setClass, updateAttribute, updateBooleanAttribute } from '../utils';
10
- const templateHTML = '<style>:host{display:block;outline:0}#content{width:fit-content;box-sizing:border-box;padding:16px;display:flex;flex-direction:column;gap:8px}#month{display:flex;flex-direction:column;row-gap:8px}.week{display:flex;flex-direction:row;column-gap:8px}.week.empty{display:none}.day{all:initial;font:var(--sinch-font-text-xs);color:var(--sinch-color-text-default);text-align:center;border-radius:var(--sinch-shape-radius-m);width:24px;height:24px;line-height:22px;cursor:pointer;border:1px solid transparent;background-color:transparent;box-sizing:border-box;user-select:none}.day.today{border:1px solid var(--sinch-color-stormy-500)}.day:disabled{cursor:initial;color:var(--sinch-color-snow-700)}.day:focus-visible{outline:1px solid var(--sinch-color-aqua-400);outline-offset:1px}@supports not selector(:focus-visible){.day:focus{outline:1px solid var(--sinch-color-aqua-400);outline-offset:1px}}.day.selected{background-color:var(--sinch-color-stormy-500);color:var(--sinch-color-snow-100)}.day:hover:not(:disabled):not(.selected){background-color:var(--sinch-color-snow-600)}#week-day-names{display:flex;flex-direction:row;gap:8px;height:24px}.week-day-name{font:var(--sinch-font-text-xs);font-weight:var(--sinch-font-weight-emphasized);color:var(--sinch-color-text-default);text-align:center;width:24px;height:24px;line-height:24px;user-select:none;text-transform:uppercase}#content-header{display:flex;flex-direction:row;height:32px;align-items:center}#date{flex:1;text-align:center;text-transform:capitalize}#prev-year{margin-left:-4px}#next-year{margin-right:-4px}</style><div id="content"><div id="content-header"><sinch-icon-button id="prev-year" small><sinch-icon-keyboard-double-arrow-left slot="icon"></sinch-icon-keyboard-double-arrow-left></sinch-icon-button><sinch-icon-button id="prev-month" small><sinch-icon-keyboard-arrow-left slot="icon"></sinch-icon-keyboard-arrow-left></sinch-icon-button><sinch-text id="date" type="m" emphasized aria-live="polite"></sinch-text><sinch-icon-button id="next-month" small><sinch-icon-keyboard-arrow-right slot="icon"></sinch-icon-keyboard-arrow-right></sinch-icon-button><sinch-icon-button id="next-year" small><sinch-icon-keyboard-double-arrow-right slot="icon"></sinch-icon-keyboard-double-arrow-right></sinch-icon-button></div><div id="week-day-names"><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div></div><div id="month"><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div></div></div>';
10
+ const templateHTML = '<style>:host{display:block;outline:0}#content{width:fit-content;box-sizing:border-box;padding:16px;display:flex;flex-direction:column;gap:8px}#month{display:flex;flex-direction:column;row-gap:8px}.week{display:flex;flex-direction:row;column-gap:8px}.week.empty{display:none}.day{all:initial;font:var(--sinch-font-text-xs);color:var(--sinch-color-text-default);text-align:center;border-radius:var(--sinch-shape-radius-m);width:24px;height:24px;line-height:22px;cursor:pointer;border:1px solid transparent;background-color:transparent;box-sizing:border-box;user-select:none}.day.today{border:1px solid var(--sinch-color-stormy-500)}.day:disabled{cursor:initial;color:var(--sinch-color-snow-700)}.day:focus-visible{outline:1px solid var(--sinch-color-border-focus);outline-offset:1px}@supports not selector(:focus-visible){.day:focus{outline:1px solid var(--sinch-color-border-focus);outline-offset:1px}}.day.selected{background-color:var(--sinch-color-stormy-500);color:var(--sinch-color-snow-100)}.day:hover:not(:disabled):not(.selected){background-color:var(--sinch-color-snow-600)}#week-day-names{display:flex;flex-direction:row;gap:8px;height:24px}.week-day-name{font:var(--sinch-font-text-xs);font-weight:var(--sinch-font-weight-emphasized);color:var(--sinch-color-text-default);text-align:center;width:24px;height:24px;line-height:24px;user-select:none;text-transform:uppercase}#content-header{display:flex;flex-direction:row;height:32px;align-items:center}#date{flex:1;text-align:center;text-transform:capitalize}#prev-year{margin-left:-4px}#next-year{margin-right:-4px}</style><div id="content"><div id="content-header"><sinch-icon-button id="prev-year" small><sinch-icon-keyboard-double-arrow-left slot="icon"></sinch-icon-keyboard-double-arrow-left></sinch-icon-button><sinch-icon-button id="prev-month" small><sinch-icon-keyboard-arrow-left slot="icon"></sinch-icon-keyboard-arrow-left></sinch-icon-button><sinch-text id="date" type="m" emphasized aria-live="polite"></sinch-text><sinch-icon-button id="next-month" small><sinch-icon-keyboard-arrow-right slot="icon"></sinch-icon-keyboard-arrow-right></sinch-icon-button><sinch-icon-button id="next-year" small><sinch-icon-keyboard-double-arrow-right slot="icon"></sinch-icon-keyboard-double-arrow-right></sinch-icon-button></div><div id="week-day-names"><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div><div class="week-day-name"></div></div><div id="month"><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div><div class="week"><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button><button class="day"></button></div></div></div>';
11
11
  import { areDatesEqual, assertDate, assertLocale, assertMinMax, assertValue, canGoNextMonth, canGoNextYear, canGoPrevMonth, canGoPrevYear, clampMaxDate, clampMinDate, dateToIso, decMonth, decYear, getCalendarMonth, getDayNames, getMonthNames, incMonth, incYear, isDateBetween, isoToDate, isValidDate, today } from './utils';
12
12
  const template = document.createElement('template');
13
13
  template.innerHTML = templateHTML;
package/field/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { defineCustomElement, getAttribute, getBooleanAttribute, NectaryElement, updateAttribute, updateBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle}#wrapper{display:flex;flex-direction:column;width:100%}#bottom,#top{display:flex;align-items:baseline}#top{height:24px;margin-bottom:2px;--sinch-color-icon:var(--sinch-color-stormy-500)}#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])) #top{--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><slot name="input"></slot><div id="bottom"><div id="invalid"></div><div id="additional"></div></div></div>';
1
+ import { defineCustomElement, getAttribute, getBooleanAttribute, getFirstSlotElement, NectaryElement, setClass, updateAttribute, updateBooleanAttribute } from '../utils';
2
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle}#wrapper{display:flex;flex-direction:column;width:100%}#bottom,#top{display:flex;align-items:baseline}#top{height:24px;margin-bottom:2px;--sinch-color-icon:var(--sinch-color-stormy-500)}#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}#tooltip{align-self:center;margin:0 8px;display:flex}#tooltip.empty{display:none}:host([disabled]:not([disabled=false])) :is(#label,#additional,#optional,#invalid){color:var(--sinch-color-stormy-100)}:host([disabled]:not([disabled=false])) #top{--sinch-color-icon:var(--sinch-color-stormy-100)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><div id="tooltip"><slot name="tooltip"></slot></div><span id="optional"></span></div><slot name="input"></slot><div id="bottom"><div id="invalid"></div><div id="additional"></div></div></div>';
3
3
  const template = document.createElement('template');
4
4
  template.innerHTML = templateHTML;
5
5
  defineCustomElement('sinch-field', class extends NectaryElement {
@@ -8,6 +8,9 @@ defineCustomElement('sinch-field', class extends NectaryElement {
8
8
  #$additionalText;
9
9
  #$invalidText;
10
10
  #$inputSlot;
11
+ #$tooltipWrapper;
12
+ #$tooltipSlot;
13
+ #controller = null;
11
14
 
12
15
  constructor() {
13
16
  super();
@@ -18,14 +21,25 @@ defineCustomElement('sinch-field', class extends NectaryElement {
18
21
  this.#$additionalText = shadowRoot.querySelector('#additional');
19
22
  this.#$invalidText = shadowRoot.querySelector('#invalid');
20
23
  this.#$inputSlot = shadowRoot.querySelector('slot[name="input"]');
24
+ this.#$tooltipSlot = shadowRoot.querySelector('slot[name="tooltip"]');
25
+ this.#$tooltipWrapper = shadowRoot.querySelector('#tooltip');
21
26
  }
22
27
 
23
28
  connectedCallback() {
24
- this.#$label.addEventListener('click', this.#onLabelClick);
29
+ this.#controller = new AbortController();
30
+ const {
31
+ signal
32
+ } = this.#controller;
33
+ this.#$label.addEventListener('click', this.#onLabelClick, {
34
+ signal
35
+ });
36
+ this.#$tooltipSlot.addEventListener('slotchange', this.#onTooltipSlotChange, {
37
+ signal
38
+ });
25
39
  }
26
40
 
27
41
  disconnectedCallback() {
28
- this.#$label.removeEventListener('click', this.#onLabelClick);
42
+ this.#controller.abort();
29
43
  }
30
44
 
31
45
  static get observedAttributes() {
@@ -101,6 +115,9 @@ defineCustomElement('sinch-field', class extends NectaryElement {
101
115
  }
102
116
 
103
117
  #onLabelClick = () => {
104
- this.#$inputSlot.assignedElements()[0]?.focus?.();
118
+ getFirstSlotElement(this.#$inputSlot)?.focus?.();
119
+ };
120
+ #onTooltipSlotChange = () => {
121
+ setClass(this.#$tooltipWrapper, 'empty', this.#$tooltipSlot.assignedElements().length === 0);
105
122
  };
106
123
  });
@@ -1,7 +1,7 @@
1
1
  import '../text';
2
2
  import '../file-picker';
3
3
  import { defineCustomElement, getAttribute, getBooleanAttribute, getIntegerAttribute, getReactEventHandler, isAttrTrue, NectaryElement, setClass, updateAttribute, updateBooleanAttribute } from '../utils';
4
- const templateHTML = '<style>:host{display:block}#wrapper{position:relative;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;align-content:center;gap:8px;height:148px;min-width:148px;box-sizing:border-box;padding:16px;border-radius:var(--sinch-shape-radius-m);background-color:var(--sinch-color-bg-primary-contrast)}#wrapper.drop.valid{background-color:var(--sinch-color-bg-comp-blue)}#wrapper::after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;border:1px dashed var(--sinch-color-stormy-100);border-radius:var(--sinch-shape-radius-m);pointer-events:none}#placeholder{align-self:center;text-align:center}:host([invalid]) #wrapper::after{border-color:var(--sinch-color-text-invalid);border-width:1px}#wrapper.drop::after{pointer-events:all}#wrapper.drop.valid::after{border-color:var(--sinch-color-aqua-400);border-width:2px}#wrapper.drop #placeholder{color:var(--sinch-color-text-muted)}:host([disabled]) #wrapper #placeholder{color:var(--sinch-color-stormy-100)}:host([disabled]) #wrapper{background-color:var(--sinch-color-snow-100)}:host([disabled]) #wrapper::after{border-color:var(--sinch-color-stormy-100);border-width:1px}</style><div id="wrapper"><sinch-text id="placeholder" type="m" aria-hidden="true"></sinch-text><sinch-file-picker id="file-picker"><slot></slot></sinch-file-picker></div>';
4
+ const templateHTML = '<style>:host{display:block}#wrapper{position:relative;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;align-content:center;gap:8px;height:148px;min-width:148px;box-sizing:border-box;padding:16px;border-radius:var(--sinch-shape-radius-m);background-color:var(--sinch-color-bg-primary-contrast)}#wrapper.drop.valid{background-color:var(--sinch-color-bg-comp-blue)}#wrapper::after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;border:1px dashed var(--sinch-color-stormy-100);border-radius:var(--sinch-shape-radius-m);pointer-events:none}#placeholder{align-self:center;text-align:center}:host([invalid]) #wrapper::after{border-color:var(--sinch-color-text-invalid);border-width:1px}#wrapper.drop::after{pointer-events:all}#wrapper.drop.valid::after{border-color:var(--sinch-color-border-focus);border-width:2px}#wrapper.drop #placeholder{color:var(--sinch-color-text-muted)}:host([disabled]) #wrapper #placeholder{color:var(--sinch-color-stormy-100)}:host([disabled]) #wrapper{background-color:var(--sinch-color-snow-100)}:host([disabled]) #wrapper::after{border-color:var(--sinch-color-stormy-100);border-width:1px}</style><div id="wrapper"><sinch-text id="placeholder" type="m" aria-hidden="true"></sinch-text><sinch-file-picker id="file-picker"><slot></slot></sinch-file-picker></div>';
5
5
  import { areFilesAccepted, doFilesSatisfySize } from './utils';
6
6
  const template = document.createElement('template');
7
7
  template.innerHTML = templateHTML;
@@ -84,7 +84,7 @@ defineCustomElement('sinch-file-picker', class extends NectaryElement {
84
84
 
85
85
  #onTargetSlotChange = () => {
86
86
  this.#$target?.removeEventListener('-click', this.#onTargetClick);
87
- this.#$target = getFirstSlotElement(this.#$targetSlot);
87
+ this.#$target = getFirstSlotElement(this.#$targetSlot, true);
88
88
  this.#$target?.addEventListener('-click', this.#onTargetClick);
89
89
  };
90
90
  #onTargetClick = () => {
@@ -1,15 +1,17 @@
1
1
  import '../tooltip';
2
2
  import '../icons/help-outline';
3
3
  import { defineCustomElement, getAttribute, getBooleanAttribute, getIntegerAttribute, NectaryElement, updateAttribute, updateBooleanAttribute, updateIntegerAttribute } from '../utils';
4
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;--sinch-size-icon:18px}sinch-tooltip{display:block}</style><sinch-tooltip><sinch-icon-help-outline></sinch-icon-help-outline></sinch-tooltip>';
4
+ const templateHTML = '<style>:host{display:contents}#icon{--sinch-size-icon:18px}</style><sinch-tooltip><sinch-icon-help-outline id="icon"></sinch-icon-help-outline></sinch-tooltip>';
5
5
  const template = document.createElement('template');
6
6
  template.innerHTML = templateHTML;
7
7
  defineCustomElement('sinch-help-tooltip', class extends NectaryElement {
8
+ #$tooltip;
9
+
8
10
  constructor() {
9
11
  super();
10
12
  const shadowRoot = this.attachShadow();
11
13
  shadowRoot.appendChild(template.content.cloneNode(true));
12
- this.$tooltip = shadowRoot.querySelector('sinch-tooltip');
14
+ this.#$tooltip = shadowRoot.querySelector('sinch-tooltip');
13
15
  }
14
16
 
15
17
  static get observedAttributes() {
@@ -48,35 +50,16 @@ defineCustomElement('sinch-help-tooltip', class extends NectaryElement {
48
50
  updateAttribute(this, 'orientation', value);
49
51
  }
50
52
 
53
+ get footprintRect() {
54
+ return this.#$tooltip.footprintRect;
55
+ }
56
+
51
57
  get tooltipRect() {
52
- return this.$tooltip.tooltipRect;
58
+ return this.#$tooltip.tooltipRect;
53
59
  }
54
60
 
55
61
  attributeChangedCallback(name, _, newVal) {
56
- switch (name) {
57
- case 'text':
58
- {
59
- updateAttribute(this.$tooltip, 'text', newVal);
60
- break;
61
- }
62
-
63
- case 'width':
64
- {
65
- updateAttribute(this.$tooltip, 'width', newVal);
66
- break;
67
- }
68
-
69
- case 'inverted':
70
- {
71
- updateAttribute(this.$tooltip, 'inverted', newVal);
72
- break;
73
- }
74
-
75
- case 'orientation':
76
- {
77
- updateAttribute(this.$tooltip, 'orientation', newVal);
78
- }
79
- }
62
+ updateAttribute(this.#$tooltip, name, newVal);
80
63
  }
81
64
 
82
65
  });
@@ -1,3 +1,4 @@
1
+ import '../tooltip';
1
2
  import type { TSinchIconButtonElement, TSinchIconButtonReact } from './types';
2
3
  declare global {
3
4
  namespace JSX {
@@ -1,34 +1,37 @@
1
+ import '../tooltip';
1
2
  import { defineCustomElement, getBooleanAttribute, getReactEventHandler, isAttrTrue, NectaryElement, updateAttribute, updateBooleanAttribute } from '../utils';
2
- const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;width:48px;height:48px;cursor:pointer;contain:size;--sinch-size-icon:24px;--sinch-color-icon:var(--sinch-icon-button-color, var(--sinch-color-stormy-500));--sinch-icon-button-shape-radius:var(--sinch-shape-radius-l)}button::before{content:"";position:absolute;left:0;top:0;width:100%;height:100%;border-radius:var(--sinch-icon-button-shape-radius);pointer-events:none;box-sizing:border-box;border:1px solid transparent;background-color:transparent;mix-blend-mode:multiply}button:focus-visible::after{position:absolute;content:"";left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;padding:2px;border:2px solid var(--sinch-color-aqua-400);border-radius:calc(var(--sinch-icon-button-shape-radius) + 4px);pointer-events:none}@supports not selector(:focus-visible){button:focus::after{position:absolute;content:"";left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;padding:2px;border:2px solid var(--sinch-color-aqua-400);border-radius:calc(var(--sinch-icon-button-shape-radius) + 4px);pointer-events:none}}button:enabled:hover::before{background-color:#f1f2f4}button:enabled:active::before{background-color:#e3e6e8}button:disabled{background-color:transparent;cursor:initial;--sinch-color-spinner-bg:var(--sinch-color-snow-200);--sinch-color-spinner-fg:var(--sinch-color-stormy-200);--sinch-color-icon:var(--sinch-color-stormy-100)}:host([small]:not([small=false]))>button{width:32px;height:32px;--sinch-icon-button-shape-radius:var(--sinch-shape-radius-m)}button>*{pointer-events:none}</style><button><slot name="icon"></slot></button>';
3
+ const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;width:48px;height:48px;cursor:pointer;contain:size;--sinch-size-icon:24px;--sinch-color-icon:var(--sinch-icon-button-color, var(--sinch-color-stormy-500));--sinch-icon-button-shape-radius:var(--sinch-shape-radius-l)}button::before{content:"";position:absolute;left:0;top:0;width:100%;height:100%;border-radius:var(--sinch-icon-button-shape-radius);pointer-events:none;box-sizing:border-box;border:1px solid transparent;background-color:transparent;mix-blend-mode:multiply}button:focus-visible::after{position:absolute;content:"";left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;padding:2px;border:2px solid var(--sinch-color-border-focus);border-radius:calc(var(--sinch-icon-button-shape-radius) + 4px);pointer-events:none}@supports not selector(:focus-visible){button:focus::after{position:absolute;content:"";left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;padding:2px;border:2px solid var(--sinch-color-border-focus);border-radius:calc(var(--sinch-icon-button-shape-radius) + 4px);pointer-events:none}}button:enabled:hover::before{background-color:#f1f2f4}button:enabled:active::before{background-color:#e3e6e8}button:disabled{background-color:transparent;cursor:initial;--sinch-color-spinner-bg:var(--sinch-color-snow-200);--sinch-color-spinner-fg:var(--sinch-color-stormy-200);--sinch-color-icon:var(--sinch-color-stormy-100)}:host([small]:not([small=false])) #button{width:32px;height:32px;--sinch-icon-button-shape-radius:var(--sinch-shape-radius-m)}button>*{pointer-events:none}</style><sinch-tooltip id="tooltip"><button id="button"><slot name="icon"></slot></button></sinch-tooltip>';
3
4
  const template = document.createElement('template');
4
5
  template.innerHTML = templateHTML;
5
6
  defineCustomElement('sinch-icon-button', class extends NectaryElement {
6
7
  #$button;
8
+ #$tooltip;
9
+ #controller = null;
7
10
 
8
11
  constructor() {
9
12
  super();
10
13
  const shadowRoot = this.attachShadow();
11
14
  shadowRoot.appendChild(template.content.cloneNode(true));
12
- this.#$button = shadowRoot.querySelector('button');
15
+ this.#$button = shadowRoot.querySelector('#button');
16
+ this.#$tooltip = shadowRoot.querySelector('#tooltip');
13
17
  }
14
18
 
15
19
  connectedCallback() {
20
+ this.#controller = new AbortController();
21
+ const options = {
22
+ signal: this.#controller.signal
23
+ };
16
24
  this.setAttribute('role', 'button');
17
- this.#$button.addEventListener('click', this.#onButtonClick);
18
- this.#$button.addEventListener('focus', this.#onButtonFocus);
19
- this.#$button.addEventListener('blur', this.#onButtonBlur);
20
- this.addEventListener('-click', this.#onClickReactHandler);
21
- this.addEventListener('-focus', this.#onFocusReactHandler);
22
- this.addEventListener('-blur', this.#onBlurReactHandler);
25
+ this.#$button.addEventListener('click', this.#onButtonClick, options);
26
+ this.#$button.addEventListener('focus', this.#onButtonFocus, options);
27
+ this.#$button.addEventListener('blur', this.#onButtonBlur, options);
28
+ this.addEventListener('-click', this.#onClickReactHandler, options);
29
+ this.addEventListener('-focus', this.#onFocusReactHandler, options);
30
+ this.addEventListener('-blur', this.#onBlurReactHandler, options);
23
31
  }
24
32
 
25
33
  disconnectedCallback() {
26
- this.#$button.removeEventListener('click', this.#onButtonClick);
27
- this.#$button.removeEventListener('focus', this.#onButtonFocus);
28
- this.#$button.removeEventListener('blur', this.#onButtonBlur);
29
- this.removeEventListener('-click', this.#onClickReactHandler);
30
- this.removeEventListener('-focus', this.#onFocusReactHandler);
31
- this.removeEventListener('-blur', this.#onBlurReactHandler);
34
+ this.#controller.abort();
32
35
  }
33
36
 
34
37
  static get observedAttributes() {
@@ -47,7 +50,7 @@ defineCustomElement('sinch-icon-button', class extends NectaryElement {
47
50
 
48
51
  case 'aria-label':
49
52
  {
50
- updateAttribute(this, 'title', newVal);
53
+ updateAttribute(this.#$tooltip, 'text', newVal);
51
54
  break;
52
55
  }
53
56
  }
@@ -69,6 +72,14 @@ defineCustomElement('sinch-icon-button', class extends NectaryElement {
69
72
  return getBooleanAttribute(this, 'small');
70
73
  }
71
74
 
75
+ get tooltipRect() {
76
+ return this.#$tooltip.tooltipRect;
77
+ }
78
+
79
+ get focusable() {
80
+ return true;
81
+ }
82
+
72
83
  focus() {
73
84
  this.#$button.focus();
74
85
  }
@@ -1,18 +1,32 @@
1
- import type { TSinchElementReact } from '../types';
1
+ import type { TRect, TSinchElementReact } from '../types';
2
2
  export declare type TSinchIconButtonElement = HTMLElement & {
3
+ /** Disabled */
3
4
  disabled: boolean;
5
+ /** Small */
4
6
  small: boolean;
7
+ readonly tooltipRect: TRect;
8
+ /** Click event */
5
9
  addEventListener(type: '-click', listener: (e: CustomEvent<void>) => void): void;
10
+ /** Focus event */
6
11
  addEventListener(type: '-focus', listener: (e: CustomEvent<void>) => void): void;
12
+ /** Blur event */
7
13
  addEventListener(type: '-blur', listener: (e: CustomEvent<void>) => void): void;
14
+ /** Disabled */
8
15
  setAttribute(name: 'disabled', value: ''): void;
16
+ /** Small */
9
17
  setAttribute(name: 'small', value: ''): void;
10
18
  };
11
19
  export declare type TSinchIconButtonReact = TSinchElementReact<TSinchIconButtonElement> & {
12
- 'aria-label': string;
20
+ /** Disabled */
13
21
  disabled?: boolean;
22
+ /** Small */
14
23
  small?: boolean;
24
+ /** Label that is used for a11y */
25
+ 'aria-label': string;
26
+ /** Click event handler */
15
27
  'on-click'?: (e: CustomEvent<void>) => void;
28
+ /** Focus event handler */
16
29
  'on-focus'?: (e: CustomEvent<void>) => void;
30
+ /** Blur event handler */
17
31
  'on-blur'?: (e: CustomEvent<void>) => void;
18
32
  };
package/input/index.js CHANGED
@@ -175,6 +175,10 @@ defineCustomElement('sinch-input', class extends NectaryElement {
175
175
  }
176
176
  }
177
177
 
178
+ get focusable() {
179
+ return true;
180
+ }
181
+
178
182
  focus() {
179
183
  this.#$input.focus();
180
184
  }
package/link/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import '../icons/open-in-new';
2
2
  import '../icons/arrow-forward';
3
3
  import { defineCustomElement, getBooleanAttribute, getAttribute, updateBooleanAttribute, updateAttribute, NectaryElement, isAttrTrue, getReactEventHandler } from '../utils';
4
- const templateHTML = '<style>:host{display:inline}a{font:var(--sinch-font-text-m);font-size:inherit;line-height:inherit;color:var(--sinch-color-tropical-500);border-radius:.5em;--sinch-size-icon:1em;--sinch-color-icon:var(--sinch-color-tropical-500)}a:hover{color:var(--sinch-color-tropical-600);--sinch-color-icon:var(--sinch-color-tropical-600)}a:focus-visible{outline:2px solid var(--sinch-color-aqua-400);outline-offset:2px}@supports not selector(:focus-visible){a:focus{outline:2px solid var(--sinch-color-aqua-400);outline-offset:2px}}#external-icon{display:none;margin-right:.2em;vertical-align:-.2em}#standalone-icon{display:none}:host([external]:not([external=false])) #external-icon{display:inline-block}:host([standalone]:not([standalone=false])){display:block}:host([standalone]:not([standalone=false])) a{display:block;font:var(--sinch-font-text-m);font-weight:var(--sinch-font-weight-emphasized);text-decoration:none;border-radius:var(--sinch-shape-radius-m);width:fit-content;--sinch-size-icon:24px}:host([standalone]:not([standalone=false])) #external-icon{margin-right:8px;vertical-align:-7px}:host([standalone]:not([standalone=false]):is([external=false],:not([external]))) #standalone-icon{display:inline-block;vertical-align:-7px;margin-left:8px}:host([disabled]:not([disabled=false])) a{color:var(--sinch-color-tropical-200);pointer-events:none;cursor:initial;--sinch-color-icon:var(--sinch-color-tropical-200)}</style><a referrerpolicy="no-referer" aria-hidden="true"><sinch-icon-open-in-new id="external-icon"></sinch-icon-open-in-new><span id="content"></span><sinch-icon-arrow-forward id="standalone-icon"></sinch-icon-arrow-forward></a>';
4
+ const templateHTML = '<style>:host{display:inline}a{font:var(--sinch-font-text-m);font-size:inherit;line-height:inherit;color:var(--sinch-color-tropical-500);border-radius:.5em;--sinch-size-icon:1em;--sinch-color-icon:var(--sinch-color-tropical-500)}a:hover{color:var(--sinch-color-tropical-600);--sinch-color-icon:var(--sinch-color-tropical-600)}a:focus-visible{outline:2px solid var(--sinch-color-border-focus);outline-offset:2px}@supports not selector(:focus-visible){a:focus{outline:2px solid var(--sinch-color-border-focus);outline-offset:2px}}#external-icon{display:none;margin-right:.2em;vertical-align:-.2em}#standalone-icon{display:none}:host([external]:not([external=false])) #external-icon{display:inline-block}:host([standalone]:not([standalone=false])){display:block}:host([standalone]:not([standalone=false])) a{display:block;font:var(--sinch-font-text-m);font-weight:var(--sinch-font-weight-emphasized);text-decoration:none;border-radius:var(--sinch-shape-radius-m);width:fit-content;--sinch-size-icon:24px}:host([standalone]:not([standalone=false])) #external-icon{margin-right:8px;vertical-align:-7px}:host([standalone]:not([standalone=false]):is([external=false],:not([external]))) #standalone-icon{display:inline-block;vertical-align:-7px;margin-left:8px}:host([disabled]:not([disabled=false])) a{color:var(--sinch-color-tropical-200);pointer-events:none;cursor:initial;--sinch-color-icon:var(--sinch-color-tropical-200)}</style><a referrerpolicy="no-referer" aria-hidden="true"><sinch-icon-open-in-new id="external-icon"></sinch-icon-open-in-new><span id="content"></span><sinch-icon-arrow-forward id="standalone-icon"></sinch-icon-arrow-forward></a>';
5
5
  const template = document.createElement('template');
6
6
  template.innerHTML = templateHTML;
7
7
  defineCustomElement('sinch-link', class extends NectaryElement {
@@ -113,6 +113,10 @@ defineCustomElement('sinch-link', class extends NectaryElement {
113
113
  }
114
114
  }
115
115
 
116
+ get focusable() {
117
+ return true;
118
+ }
119
+
116
120
  focus() {
117
121
  this.#$anchor.focus();
118
122
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "0.40.0",
3
+ "version": "0.41.1",
4
4
  "files": [
5
5
  "theme.css",
6
6
  "**/*/*.js",
@@ -166,6 +166,10 @@ defineCustomElement('sinch-pagination', class extends NectaryElement {
166
166
  getReactEventHandler(this, 'on-change')?.(e);
167
167
  };
168
168
 
169
+ get focusable() {
170
+ return true;
171
+ }
172
+
169
173
  focus() {
170
174
  this.#$left.focus();
171
175
  }
package/pop/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { TSinchPopElement, TSinchPopReact } from './types';
2
+ declare global {
3
+ namespace JSX {
4
+ interface IntrinsicElements {
5
+ 'sinch-pop': TSinchPopReact;
6
+ }
7
+ }
8
+ interface HTMLElementTagNameMap {
9
+ 'sinch-pop': TSinchPopElement;
10
+ }
11
+ }