@nectary/components 1.1.0 → 1.1.2

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 '../icon-button';
2
2
  import '../icon';
3
3
  import '../text';
4
- import { defineCustomElement, getAttribute, getBooleanAttribute, getCssVars, getReactEventHandler, getRect, isAttrTrue, NectaryElement, packCsv, setClass, unpackCsv, updateAttribute, updateBooleanAttribute } from '../utils';
4
+ import { defineCustomElement, getAttribute, getBooleanAttribute, getCssVars, getReactEventHandler, getRect, getTargetAttribute, isAttrTrue, NectaryElement, packCsv, setClass, unpackCsv, updateAttribute, updateBooleanAttribute } from '../utils';
5
5
  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-s);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-tropical-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}.day.range{background-color:var(--sinch-color-tropical-100)}.day.selected{background-color:var(--sinch-color-tropical-500);color:var(--sinch-color-snow-100)}.day:hover:enabled:not(.selected){background-color:var(--sinch-color-tropical-200)}#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" size="s"><sinch-icon id="icon-prev-year" slot="icon"></sinch-icon></sinch-icon-button><sinch-icon-button id="prev-month" size="s"><sinch-icon id="icon-prev-month" slot="icon"></sinch-icon></sinch-icon-button><sinch-text id="date" type="m" emphasized aria-live="polite"></sinch-text><sinch-icon-button id="next-month" size="s"><sinch-icon id="icon-next-month" slot="icon"></sinch-icon></sinch-icon-button><sinch-icon-button id="next-year" size="s"><sinch-icon id="icon-next-year" slot="icon"></sinch-icon></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>';
6
6
  import { areDatesEqual, assertDate, assertLocale, assertMinMax, assertValue, canGoNextMonth, canGoNextYear, canGoPrevMonth, canGoPrevYear, clampMaxDate, clampMinDate, cloneDate, dateToIso, decMonth, decYear, getCalendarMonth, getDayNames, getMonthNames, incMonth, incYear, isDateBetween, isoToDate, isValidDate, sortDates, today } from './utils';
7
7
  const template = document.createElement('template');
@@ -257,7 +257,7 @@ defineCustomElement('sinch-date-picker', class extends NectaryElement {
257
257
  };
258
258
  #onDateMouseEnter = e => {
259
259
  if (this.#date1 !== null && this.#date2 === null) {
260
- const hoverDateIso = e.target.getAttribute('data-date');
260
+ const hoverDateIso = getTargetAttribute(e, 'data-date');
261
261
  if (hoverDateIso === null) {
262
262
  return;
263
263
  }
@@ -276,7 +276,7 @@ defineCustomElement('sinch-date-picker', class extends NectaryElement {
276
276
  };
277
277
  #onDateClick = e => {
278
278
  e.stopPropagation();
279
- const dateIso = e.target.getAttribute('data-date');
279
+ const dateIso = getTargetAttribute(e, 'data-date');
280
280
  if (dateIso === null || dateIso.length === 0) {
281
281
  return;
282
282
  }
package/dialog/index.js CHANGED
@@ -2,8 +2,9 @@ import '../icon-button';
2
2
  import '../icon';
3
3
  import '../stop-events';
4
4
  import '../title';
5
- import { defineCustomElement, getAttribute, getBooleanAttribute, getRect, isAttrTrue, updateAttribute, getReactEventHandler, NectaryElement, updateBooleanAttribute, getCssVar } from '../utils';
6
- const templateHTML = '<style>:host{display:block}dialog{position:fixed;left:0;right:0;margin:auto;display:flex;flex-direction:column;padding:24px 0;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-text-m);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:12px;padding:0 24px}#caption{color:var(--sinch-color-text-default)}#content{min-height:0;overflow:auto;max-height:var(--sinch-dialog-max-height,50vh);padding:4px 24px}#buttons{display:flex;flex-direction:row;justify-content:flex-end;gap:16px;margin-top:20px;padding:0 24px}#close{transform:translate(4px,-4px)}</style><dialog><div id="header"><sinch-title id="caption" type="m" level="3" ellipsis></sinch-title><sinch-icon-button id="close" size="s" tabindex="0"><sinch-icon id="icon-close" slot="icon"></sinch-icon></sinch-icon-button></div><div id="content"><sinch-stop-events events="close"><slot name="content"></slot></sinch-stop-events></div><div id="buttons"><sinch-stop-events events="close"><slot name="buttons"></slot></sinch-stop-events></div></dialog>';
5
+ import { disableScroll, enableScroll } from '../pop/utils';
6
+ import { defineCustomElement, getAttribute, getBooleanAttribute, getRect, isAttrTrue, updateAttribute, getReactEventHandler, NectaryElement, updateBooleanAttribute, getCssVar, setClass, isTargetEqual } from '../utils';
7
+ const templateHTML = '<style>:host{display:contents}#dialog{position:fixed;left:0;right:0;margin:auto;display:flex;flex-direction:column;padding:24px 0;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-text-m);border:none;box-shadow:var(--sinch-elevation-level-3)}#dialog:not([open]){display:none}dialog::backdrop{background-color:#000;opacity:.55}#header{display:flex;flex-direction:row;justify-content:space-between;align-items:flex-start;margin-bottom:12px;padding:0 24px}#caption{color:var(--sinch-color-text-default)}#content{min-height:0;overflow:auto;max-height:var(--sinch-dialog-max-height,50vh);padding:4px 24px}#action{display:flex;flex-direction:row;justify-content:flex-end;gap:16px;margin-top:20px;padding:0 24px}#action.empty{display:none}#close{transform:translate(4px,-4px)}</style><dialog id="dialog"><div id="header"><sinch-title id="caption" type="m" level="3" ellipsis></sinch-title><sinch-icon-button id="close" size="s" tabindex="0"><sinch-icon id="icon-close" slot="icon"></sinch-icon></sinch-icon-button></div><div id="content"><sinch-stop-events events="close"><slot name="content"></slot></sinch-stop-events></div><div id="action"><sinch-stop-events events="close"><slot name="buttons"></slot></sinch-stop-events></div></dialog>';
7
8
  const template = document.createElement('template');
8
9
  template.innerHTML = templateHTML;
9
10
  defineCustomElement('sinch-dialog', class extends NectaryElement {
@@ -11,16 +12,19 @@ defineCustomElement('sinch-dialog', class extends NectaryElement {
11
12
  #$dialog;
12
13
  #$closeButton;
13
14
  #$caption;
15
+ #$actionWrapper;
16
+ #$actionSlot;
14
17
  #controller = null;
15
- #prevOverflowValue = '';
16
18
  constructor() {
17
19
  super();
18
20
  const shadowRoot = this.attachShadow();
19
21
  shadowRoot.appendChild(template.content.cloneNode(true));
20
- this.#$dialog = shadowRoot.querySelector('dialog');
22
+ this.#$dialog = shadowRoot.querySelector('#dialog');
21
23
  this.#$closeButton = shadowRoot.querySelector('#close');
22
24
  this.#$caption = shadowRoot.querySelector('#caption');
23
25
  this.#$iconClose = shadowRoot.querySelector('#icon-close');
26
+ this.#$actionWrapper = shadowRoot.querySelector('#action');
27
+ this.#$actionSlot = shadowRoot.querySelector('slot[name="buttons"]');
24
28
  }
25
29
  connectedCallback() {
26
30
  super.connectedCallback();
@@ -30,16 +34,20 @@ defineCustomElement('sinch-dialog', class extends NectaryElement {
30
34
  signal: this.#controller.signal
31
35
  };
32
36
  this.#$closeButton.addEventListener('click', this.#onCloseClick, options);
33
- this.#$dialog.addEventListener('mousedown', this.#onBackdropClick, options);
37
+ this.#$dialog.addEventListener('mousedown', this.#onBackdropMouseDown, options);
34
38
  this.#$dialog.addEventListener('cancel', this.#onCancel, options);
39
+ this.#$actionSlot.addEventListener('slotchange', this.#onActionSlotChange, options);
35
40
  this.addEventListener('-close', this.#onCloseReactHandler, options);
36
41
  updateAttribute(this.#$iconClose, 'name', getCssVar(this, '--sinch-dialog-icon-close'));
37
- this.#setOpen(getBooleanAttribute(this, 'open'));
42
+ this.#onActionSlotChange();
43
+ if (getBooleanAttribute(this, 'open')) {
44
+ this.#onExpand();
45
+ }
38
46
  }
39
47
  disconnectedCallback() {
40
48
  super.disconnectedCallback();
41
49
  this.#controller.abort();
42
- this.#setOpen(false);
50
+ this.#onCollapse();
43
51
  }
44
52
  static get observedAttributes() {
45
53
  return ['caption', 'open', 'close-aria-label'];
@@ -54,7 +62,13 @@ defineCustomElement('sinch-dialog', class extends NectaryElement {
54
62
  case 'open':
55
63
  {
56
64
  const shouldOpen = isAttrTrue(newVal);
57
- this.#setOpen(shouldOpen);
65
+ if (shouldOpen) {
66
+ requestAnimationFrame(() => {
67
+ this.#onExpand();
68
+ });
69
+ } else {
70
+ this.#onCollapse();
71
+ }
58
72
  updateBooleanAttribute(this, 'open', shouldOpen);
59
73
  break;
60
74
  }
@@ -71,21 +85,28 @@ defineCustomElement('sinch-dialog', class extends NectaryElement {
71
85
  get caption() {
72
86
  return getAttribute(this, 'caption', '');
73
87
  }
88
+ get dialogRect() {
89
+ return getRect(this.#$dialog);
90
+ }
91
+ get closeButtonRect() {
92
+ return getRect(this.#$closeButton);
93
+ }
74
94
  #onCancel = e => {
75
95
  e.preventDefault();
96
+ e.stopPropagation();
76
97
  this.#dispatchCloseEvent('escape');
77
98
  };
78
99
  #onCloseClick = () => {
79
100
  this.#dispatchCloseEvent('close');
80
101
  };
81
- #onBackdropClick = e => {
82
- if (e.target !== this.#$dialog) {
83
- return;
84
- }
85
- const rect = this.dialogRect;
86
- const isInside = e.x >= rect.x && e.x < rect.x + rect.width && e.y >= rect.y && e.y < rect.y + rect.height;
87
- if (!isInside) {
88
- this.#dispatchCloseEvent('backdrop');
102
+ #onBackdropMouseDown = e => {
103
+ if (isTargetEqual(e, this.#$dialog)) {
104
+ const rect = this.dialogRect;
105
+ const isInside = e.x >= rect.x && e.x < rect.x + rect.width && e.y >= rect.y && e.y < rect.y + rect.height;
106
+ if (!isInside) {
107
+ e.stopPropagation();
108
+ this.#dispatchCloseEvent('backdrop');
109
+ }
89
110
  }
90
111
  };
91
112
  #onCloseReactHandler = e => {
@@ -97,22 +118,24 @@ defineCustomElement('sinch-dialog', class extends NectaryElement {
97
118
  detail
98
119
  }));
99
120
  }
100
- #setOpen(shouldOpen) {
101
- if (shouldOpen) {
102
- if (this.isConnected && !getBooleanAttribute(this.#$dialog, 'open')) {
103
- this.#prevOverflowValue = document.body.style.overflow;
104
- document.body.style.overflow = 'hidden';
105
- this.#$dialog.showModal();
106
- }
107
- } else {
108
- this.#$dialog.close?.();
109
- document.body.style.overflow = this.#prevOverflowValue;
121
+ #onExpand() {
122
+ if (!this.isConnected || this.#isOpen()) {
123
+ return;
110
124
  }
125
+ this.#$dialog.showModal();
126
+ disableScroll();
111
127
  }
112
- get dialogRect() {
113
- return getRect(this.#$dialog);
128
+ #onCollapse() {
129
+ if (!this.#isOpen()) {
130
+ return;
131
+ }
132
+ this.#$dialog.close?.();
133
+ enableScroll();
114
134
  }
115
- get closeButtonRect() {
116
- return getRect(this.#$closeButton);
135
+ #isOpen() {
136
+ return getBooleanAttribute(this.#$dialog, 'open');
117
137
  }
138
+ #onActionSlotChange = () => {
139
+ setClass(this.#$actionWrapper, 'empty', this.#$actionSlot.assignedElements().length === 0);
140
+ };
118
141
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "files": [
5
5
  "**/*/*.css",
6
6
  "**/*/*.json",
@@ -1,5 +1,5 @@
1
1
  import '../icon';
2
- import { defineCustomElement, updateAttribute, getIntegerAttribute, setClass, NectaryElement, getRect, getReactEventHandler, getCssVars } from '../utils';
2
+ import { defineCustomElement, updateAttribute, getIntegerAttribute, setClass, NectaryElement, getRect, getReactEventHandler, getCssVars, isTargetEqual, getTargetIndexInParent } from '../utils';
3
3
  const templateHTML = '<style>:host{display:inline-block;vertical-align:middle;outline:0}#wrapper{display:flex;justify-content:center;gap:8px;width:100%;box-sizing:border-box}button{all:initial;width:28px;height:28px;box-sizing:border-box;cursor:pointer;text-align:center;contain:strict;--sinch-color-icon:var(--sinch-color-stormy-500)}button:disabled{--sinch-color-icon:var(--sinch-color-stormy-100);cursor:initial}button>*{pointer-events:none}.page{border-radius:50%;font:var(--sinch-font-text-m);color:var(--sinch-color-stormy-500)}.page.dots>span{display:none}.page.dots::after{content:"..."}.page.active{font-weight:var(--sinch-font-weight-emphasized);background-color:var(--sinch-color-snow-600);pointer-events:none;cursor:initial}.page.hidden{display:none}#left,#right{display:flex;padding:2px;--sinch-icon-size:24px}</style><div id="wrapper"><button id="left"><sinch-icon id="icon-left"></sinch-icon></button><button class="page"><span>1</span></button><button class="page active"><span>2</span></button><button class="page"><span>3</span></button><button class="page"><span>4</span></button><button class="page"><span>5</span></button><button class="page dots"><span>6</span></button><button class="page"><span>20</span></button><button id="right"><sinch-icon id="icon-right"></sinch-icon></button></div>';
4
4
  const NUM_BUTTONS = 7;
5
5
  const MIDDLE_BTN_INDEX = Math.floor(NUM_BUTTONS / 2);
@@ -99,13 +99,13 @@ defineCustomElement('sinch-pagination', class extends NectaryElement {
99
99
  e.stopPropagation();
100
100
  const value = getIntegerAttribute(this, 'value', 0) - 1;
101
101
  const max = Math.max(0, getIntegerAttribute(this, 'max', 0));
102
- if (e.target === this.#$left) {
102
+ if (isTargetEqual(e, this.#$left)) {
103
103
  return this.#dispatchChangeEvent(value - 1);
104
104
  }
105
- if (e.target === this.#$right) {
105
+ if (isTargetEqual(e, this.#$right)) {
106
106
  return this.#dispatchChangeEvent(value + 1);
107
107
  }
108
- const btnIndex = Array.prototype.indexOf.call(this.#$wrapper.children, e.target) - 1;
108
+ const btnIndex = getTargetIndexInParent(e, this.#$wrapper) - 1;
109
109
  if (btnIndex >= 0 && btnIndex < this.#$buttons.length) {
110
110
  if (btnIndex === FIRST_BTN_INDEX) {
111
111
  return this.#dispatchChangeEvent(0);
package/pop/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, updateLiteralAttribute, getReactEventHandler, updateBooleanAttribute, NectaryElement, throttleAnimationFrame, isElementFocused, updateIntegerAttribute, getIntegerAttribute, getFirstFocusableElement, getFirstSlotElement, Context, subscribeContext } from '../utils';
2
- const templateHTML = '<style>:host{display:contents;position:relative}dialog{position:fixed;left:0;top:0;margin:0;outline:0;padding:0;border:none;box-sizing:border-box;max-width:unset;max-height:unset;z-index:1;background:0 0;overflow:visible}dialog:not([open]){display:none}dialog::backdrop{background-color:transparent}dialog+.backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:transparent}dialog.fixed{position:fixed;top:50%;transform:translate(0,-50%)}._dialog_overlay{position:fixed;top:0;right:0;bottom:0;left:0}#content{position:relative;z-index:1}#target-open{display:flex;flex-direction:column;position:absolute;left:0;top:0}#focus{display:none;position:absolute;width:0;height:0}</style><slot id="target" aria-haspopup="dialog" aria-expanded="false" name="target"></slot><div id="focus" tabindex="-1"></div><dialog id="dialog"><div id="content"><slot name="content"></slot></div><div id="target-open"><slot name="target-open"></slot></div></dialog>';
1
+ import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, updateLiteralAttribute, getReactEventHandler, updateBooleanAttribute, NectaryElement, throttleAnimationFrame, isElementFocused, updateIntegerAttribute, getIntegerAttribute, getFirstFocusableElement, getFirstSlotElement, Context, subscribeContext, isTargetEqual } from '../utils';
2
+ const templateHTML = '<style>:host{display:contents;position:relative}dialog{position:fixed;left:0;top:0;margin:0;outline:0;padding:0;border:none;box-sizing:border-box;max-width:unset;max-height:unset;z-index:1;background:0 0;overflow:visible}dialog:not([open]){display:none}dialog::backdrop{background-color:transparent}#content{position:relative;z-index:1}#target-open{display:flex;flex-direction:column;position:absolute;left:0;top:0}#focus{display:none;position:absolute;width:0;height:0}</style><slot id="target" name="target" aria-haspopup="dialog" aria-expanded="false"></slot><div id="focus" tabindex="-1"></div><dialog id="dialog"><div id="content"><slot name="content"></slot></div><div id="target-open"><slot name="target-open"></slot></div></dialog>';
3
3
  import { assertOrientation, disableScroll, enableScroll, orientationValues } from './utils';
4
4
  const template = document.createElement('template');
5
5
  template.innerHTML = templateHTML;
@@ -195,6 +195,11 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
195
195
  }
196
196
  disableScroll();
197
197
  window.addEventListener('resize', this.#onResize);
198
+ requestAnimationFrame(() => {
199
+ if (this.#isOpen()) {
200
+ this.#$contentSlot.addEventListener('slotchange', this.#onContentSlotChange);
201
+ }
202
+ });
198
203
  this.#dispatchContentVisibility(true);
199
204
  }
200
205
  #onCollapse() {
@@ -244,6 +249,7 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
244
249
  enableScroll();
245
250
  this.#resizeThrottle.cancel();
246
251
  window.removeEventListener('resize', this.#onResize);
252
+ this.#$contentSlot.removeEventListener('slotchange', this.#onContentSlotChange);
247
253
  }
248
254
  #isOpen() {
249
255
  return getBooleanAttribute(this.#$dialog, 'open');
@@ -299,17 +305,18 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
299
305
  }
300
306
  };
301
307
  #onBackdropMouseDown = e => {
302
- if (e.target !== this.#$dialog) {
303
- return;
304
- }
305
- const rect = this.popoverRect;
306
- const isInside = e.x >= rect.x && e.x < rect.x + rect.width && e.y >= rect.y && e.y < rect.y + rect.height;
307
- if (!isInside) {
308
- this.#dispatchCloseEvent();
308
+ if (isTargetEqual(e, this.#$dialog)) {
309
+ const rect = this.popoverRect;
310
+ const isInside = e.x >= rect.x && e.x < rect.x + rect.width && e.y >= rect.y && e.y < rect.y + rect.height;
311
+ if (!isInside) {
312
+ e.stopPropagation();
313
+ this.#dispatchCloseEvent();
314
+ }
309
315
  }
310
316
  };
311
317
  #onCancel = e => {
312
318
  e.preventDefault();
319
+ e.stopPropagation();
313
320
  this.#dispatchCloseEvent();
314
321
  };
315
322
  #onCloseReactHandler = e => {
@@ -345,4 +352,10 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
345
352
  this.#dispatchCloseEvent();
346
353
  }
347
354
  };
355
+ #onContentSlotChange = e => {
356
+ e.stopPropagation();
357
+ if (this.#isOpen()) {
358
+ this.#updateOrientation();
359
+ }
360
+ };
348
361
  });
@@ -0,0 +1,3 @@
1
+ export declare const isTargetEqual: (e: Event, $elem: HTMLElement) => boolean;
2
+ export declare const getTargetAttribute: (e: Event, attr: string) => string | null;
3
+ export declare const getTargetIndexInParent: (e: Event, parent: Element) => number;
@@ -0,0 +1,17 @@
1
+ export const isTargetEqual = (e, $elem) => {
2
+ return e.target === $elem || e.originalTarget === $elem;
3
+ };
4
+ export const getTargetAttribute = (e, attr) => {
5
+ return e.target.getAttribute(attr) ?? e.originalTarget?.getAttribute(attr) ?? null;
6
+ };
7
+ export const getTargetIndexInParent = (e, parent) => {
8
+ const indexOf = Array.prototype.indexOf.call(parent.children, e.target);
9
+ if (indexOf >= 0) {
10
+ return indexOf;
11
+ }
12
+ const origTgt = e.originalTarget;
13
+ if (origTgt != null) {
14
+ return Array.prototype.indexOf.call(parent.children, origTgt);
15
+ }
16
+ return -1;
17
+ };
package/utils/index.d.ts CHANGED
@@ -8,3 +8,4 @@ export * from './throttle';
8
8
  export * from './debounce';
9
9
  export * from './get-react-event-handler';
10
10
  export * from './markdown';
11
+ export * from './event-target';
package/utils/index.js CHANGED
@@ -7,4 +7,5 @@ export * from './slot';
7
7
  export * from './throttle';
8
8
  export * from './debounce';
9
9
  export * from './get-react-event-handler';
10
- export * from './markdown';
10
+ export * from './markdown';
11
+ export * from './event-target';