@mustib/web-components 0.0.0-alpha.4 → 0.0.0-alpha.6

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.
@@ -23,7 +23,10 @@ type Elements = [
23
23
  'mu-range-fill',
24
24
  'mu-range-thumb',
25
25
  'mu-range-thumb-value',
26
- 'mu-icon'
26
+ 'mu-icon',
27
+ 'mu-sortable',
28
+ 'mu-sortable-item',
29
+ 'mu-sortable-trigger'
27
30
  ];
28
31
  declare abstract class MuElement extends LitElement {
29
32
  #private;
@@ -1,3 +1,3 @@
1
- export { M as MuElement } from '../mu-element-C36Rgp-m.js';
1
+ export { M as MuElement } from '../mu-element-CEvBHYiI.js';
2
2
  import 'lit';
3
3
  import 'lit/decorators.js';
@@ -16,6 +16,7 @@ declare class MuIcon extends MuElement {
16
16
  close: any;
17
17
  closeLine: any;
18
18
  noImage: any;
19
+ dragVertical: any;
19
20
  };
20
21
  name?: keyof typeof MuIcon.icons;
21
22
  protected firstUpdated(_changedProperties: PropertyValues): void;
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
 
@@ -61,6 +61,9 @@ MuIcon.icons = {
61
61
  noImage: html `
62
62
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 115.19 123.38" style="enable-background:new 0 0 115.19 123.38" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-miterlimit:2.6131;}</style><g><path class="st0" d="M93.13,79.5c12.05,0,21.82,9.77,21.82,21.82c0,12.05-9.77,21.82-21.82,21.82c-12.05,0-21.82-9.77-21.82-21.82 C71.31,89.27,81.08,79.5,93.13,79.5L93.13,79.5z M8.08,0.25h95.28c2.17,0,4.11,0.89,5.53,2.3c1.42,1.42,2.3,3.39,2.3,5.53v70.01 c-2.46-1.91-5.24-3.44-8.25-4.48V9.98c0-0.43-0.16-0.79-0.46-1.05c-0.26-0.26-0.66-0.46-1.05-0.46H9.94 c-0.43,0-0.79,0.16-1.05,0.46C8.63,9.19,8.43,9.58,8.43,9.98v70.02h0.03l31.97-30.61c1.28-1.18,3.29-1.05,4.44,0.23 c0.03,0.03,0.03,0.07,0.07,0.07l26.88,31.8c-4.73,5.18-7.62,12.08-7.62,19.65c0,3.29,0.55,6.45,1.55,9.4H8.08 c-2.17,0-4.11-0.89-5.53-2.3s-2.3-3.39-2.3-5.53V8.08c0-2.17,0.89-4.11,2.3-5.53S5.94,0.25,8.08,0.25L8.08,0.25z M73.98,79.35 l3.71-22.79c0.3-1.71,1.91-2.9,3.62-2.6c0.66,0.1,1.25,0.43,1.71,0.86l17.1,17.97c-2.18-0.52-4.44-0.79-6.78-0.79 C85.91,71.99,79.13,74.77,73.98,79.35L73.98,79.35z M81.98,18.19c3.13,0,5.99,1.28,8.03,3.32c2.07,2.07,3.32,4.9,3.32,8.03 c0,3.13-1.28,5.99-3.32,8.03c-2.07,2.07-4.9,3.32-8.03,3.32c-3.13,0-5.99-1.28-8.03-3.32c-2.07-2.07-3.32-4.9-3.32-8.03 c0-3.13,1.28-5.99,3.32-8.03C76.02,19.44,78.86,18.19,81.98,18.19L81.98,18.19z M85.82,88.05l19.96,21.6 c1.58-2.39,2.5-5.25,2.5-8.33c0-8.36-6.78-15.14-15.14-15.14C90.48,86.17,87.99,86.85,85.82,88.05L85.82,88.05z M100.44,114.58 l-19.96-21.6c-1.58,2.39-2.5,5.25-2.5,8.33c0,8.36,6.78,15.14,15.14,15.14C95.78,116.46,98.27,115.78,100.44,114.58L100.44,114.58z"/></g></svg>
63
63
  `,
64
+ dragVertical: html `
65
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="var(--icon-fill)" stroke-width="3"><circle cx="8" cy="4" r="1"/><circle cx="16" cy="4" r="1"/><circle cx="8" cy="12" r="1"/><circle cx="16" cy="12" r="1"/><circle cx="8" cy="20" r="1"/><circle cx="16" cy="20" r="1"/></svg>
66
+ `,
64
67
  };
65
68
  __decorate([
66
69
  property()
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property, query } from 'lit/decorators.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property, query } from 'lit/decorators.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate, g as getElementBoundaries } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate, g as getElementBoundaries } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { state, property, query } from 'lit/decorators.js';
4
4
  import { MuTransparent } from './mu-transparent.js';
@@ -29,6 +29,24 @@ type RangeFill = {
29
29
  };
30
30
  type ChangeEventSrc = 'pointerdown' | 'pointerup' | 'pointermove' | 'keydown' | 'insert';
31
31
  type Events = {
32
+ /**
33
+ * Emitted before change event
34
+ */
35
+ 'mu-range-start': CustomEvent<{
36
+ /**
37
+ * The source of start event
38
+ */
39
+ src: 'pointerdown' | 'keydown';
40
+ }>;
41
+ /**
42
+ * Emitted at the end of change event
43
+ */
44
+ 'mu-range-end': CustomEvent<{
45
+ /**
46
+ * The source of end event
47
+ */
48
+ src: 'pointerup' | 'keyup';
49
+ }>;
32
50
  /**
33
51
  * Emitted when pointerdown on a non-thumb element and empty-area attribute has a value of "dispatch".
34
52
  *
@@ -45,6 +63,9 @@ type Events = {
45
63
  name: string;
46
64
  value: number;
47
65
  }[];
66
+ /**
67
+ * The source of change event
68
+ */
48
69
  src: ChangeEventSrc;
49
70
  }>;
50
71
  /**
@@ -132,11 +153,28 @@ declare class MuRange extends MuElement {
132
153
  /**
133
154
  * this is used to prevent focus listener from running when the pointer is down otherwise active thumb will gain focus when the pointer is down
134
155
  */
135
- protected _isPointerDown: boolean;
156
+ protected get _isPointerDownStart(): boolean;
157
+ protected get _isKeyDownStart(): boolean;
158
+ /**
159
+ * the event that started change event
160
+ */
161
+ protected _startEvent?: 'pointerdown' | 'keydown';
162
+ protected get _hasStarted(): boolean;
136
163
  set activeThumb(thumb: RangeThumb | undefined);
137
164
  get activeThumb(): RangeThumb | undefined;
138
165
  constructor();
139
166
  disconnectedCallback(): void;
167
+ /**
168
+ * start thumb move
169
+ */
170
+ protected _start(data: {
171
+ activeThumb?: RangeThumb;
172
+ src: 'pointerdown' | 'keydown';
173
+ }): void;
174
+ /**
175
+ * end thumb move
176
+ */
177
+ protected _end(): void;
140
178
  /**
141
179
  *
142
180
  * @returns an array of objects containing the name and value of each thumb
@@ -153,6 +191,12 @@ declare class MuRange extends MuElement {
153
191
  * Switches the active thumb for keyboard navigation
154
192
  */
155
193
  switchNavigationActiveItem(direction: 'next' | 'prev'): boolean;
194
+ dispatchStartEvent(data: {
195
+ src: Events['mu-range-start']['detail']['src'];
196
+ }): void;
197
+ dispatchEndEvent(data: {
198
+ src: Events['mu-range-end']['detail']['src'];
199
+ }): void;
156
200
  dispatchChangeEvent(thumbs: {
157
201
  name: string;
158
202
  value: number;
@@ -202,6 +246,7 @@ declare class MuRange extends MuElement {
202
246
  */
203
247
  setValueFromString(valueString: string): Promise<void>;
204
248
  _keydownHandler: (e: KeyboardEvent) => void;
249
+ _documentKeyupHandler: () => void;
205
250
  _pointerdownHandler: (e: PointerEvent) => void;
206
251
  _documentPointerupHandler: (e: PointerEvent) => void;
207
252
  _pointermoveHandler: (e: PointerEvent) => void;
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate, t as throttle, d as debounce, w as wait, g as getElementBoundaries } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate, t as throttle, d as debounce, w as wait, g as getElementBoundaries } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { MuTransparent } from './mu-transparent.js';
@@ -10,6 +10,18 @@ class MuRange extends MuElement {
10
10
  get isControlled() {
11
11
  return this.value !== undefined;
12
12
  }
13
+ /**
14
+ * this is used to prevent focus listener from running when the pointer is down otherwise active thumb will gain focus when the pointer is down
15
+ */
16
+ get _isPointerDownStart() {
17
+ return this._startEvent === 'pointerdown';
18
+ }
19
+ get _isKeyDownStart() {
20
+ return this._startEvent === 'keydown';
21
+ }
22
+ get _hasStarted() {
23
+ return this._startEvent !== undefined;
24
+ }
13
25
  set activeThumb(thumb) {
14
26
  if (thumb &&
15
27
  (thumb.element.transparent ||
@@ -64,10 +76,6 @@ class MuRange extends MuElement {
64
76
  this._thumbs = [];
65
77
  this._thumbsElementsMap = new Map();
66
78
  this._thumbsNamesMap = new Map();
67
- /**
68
- * this is used to prevent focus listener from running when the pointer is down otherwise active thumb will gain focus when the pointer is down
69
- */
70
- this._isPointerDown = false;
71
79
  this._slotChangeHandler = async () => {
72
80
  const previousThumbsElementsMap = new Map(this._thumbsElementsMap);
73
81
  this._thumbs = [];
@@ -188,6 +196,7 @@ class MuRange extends MuElement {
188
196
  const thumb = this.activeThumb;
189
197
  if (this.disabled || this.readonly || !thumb || e.defaultPrevented)
190
198
  return;
199
+ this.dispatchStartEvent({ src: 'keydown' });
191
200
  let increaseKey = 'ArrowRight';
192
201
  let decreaseKey = 'ArrowLeft';
193
202
  switch (this.axis) {
@@ -212,7 +221,15 @@ class MuRange extends MuElement {
212
221
  break;
213
222
  }
214
223
  const setValue = (value) => {
224
+ if (this._hasStarted && !this._isKeyDownStart)
225
+ return;
215
226
  e.preventDefault();
227
+ if (!this._isKeyDownStart) {
228
+ this._start({
229
+ activeThumb: thumb,
230
+ src: 'keydown',
231
+ });
232
+ }
216
233
  this.focus();
217
234
  thumb.element.focused = true;
218
235
  this._setThumbValue({ thumb, value, src: 'keydown' });
@@ -246,19 +263,25 @@ class MuRange extends MuElement {
246
263
  break;
247
264
  }
248
265
  };
266
+ this._documentKeyupHandler = () => {
267
+ this._end();
268
+ };
249
269
  this._pointerdownHandler = (e) => {
250
- if (this.disabled || this.readonly || e.defaultPrevented)
270
+ if (this.disabled ||
271
+ this.readonly ||
272
+ e.defaultPrevented ||
273
+ this._hasStarted)
251
274
  return;
252
- this._isPointerDown = true;
253
- document.addEventListener('pointermove', this._documentPointermoveHandler);
254
- document.addEventListener('pointerup', this._documentPointerupHandler);
255
275
  const thumbEl = MuElement.closestPierce('mu-range-thumb', e.target);
256
276
  if ((thumbEl && (thumbEl.disabled || thumbEl.readonly)) ||
257
277
  this.emptyArea === 'prevent')
258
278
  return;
259
279
  if (thumbEl && !thumbEl.transparent) {
260
280
  const activeThumb = this._thumbsElementsMap.get(thumbEl);
261
- this.activeThumb = activeThumb;
281
+ this._start({
282
+ activeThumb,
283
+ src: 'pointerdown',
284
+ });
262
285
  return;
263
286
  }
264
287
  if (this.emptyArea === 'dispatch') {
@@ -317,18 +340,19 @@ class MuRange extends MuElement {
317
340
  : rightThumb;
318
341
  }
319
342
  if (candidateThumb) {
343
+ this._start({
344
+ activeThumb: candidateThumb,
345
+ src: 'pointerdown',
346
+ });
320
347
  this._setThumbValue({ thumb: candidateThumb, value, src: 'pointerdown' });
321
- this.activeThumb = candidateThumb;
322
348
  }
323
349
  };
324
350
  this._documentPointerupHandler = (e) => {
325
- this._isPointerDown = false;
326
- document.removeEventListener('pointermove', this._documentPointermoveHandler);
327
- document.removeEventListener('pointerup', this._documentPointerupHandler);
328
- if (!this.activeThumb)
329
- return;
330
- const { value } = this._getValuesFromEvent(e);
331
- this._setThumbValue({ thumb: this.activeThumb, value, src: 'pointerup' });
351
+ if (this.activeThumb) {
352
+ const { value } = this._getValuesFromEvent(e);
353
+ this._setThumbValue({ thumb: this.activeThumb, value, src: 'pointerup' });
354
+ }
355
+ this._end();
332
356
  };
333
357
  this._pointermoveHandler = (e) => {
334
358
  if (!this.activeThumb)
@@ -349,7 +373,7 @@ class MuRange extends MuElement {
349
373
  }
350
374
  });
351
375
  this.addEventListener('focus', (e) => {
352
- if (this._isPointerDown ||
376
+ if (this._isPointerDownStart ||
353
377
  this.disabled ||
354
378
  this.readonly ||
355
379
  e.defaultPrevented)
@@ -369,6 +393,41 @@ class MuRange extends MuElement {
369
393
  disconnectedCallback() {
370
394
  document.removeEventListener('pointermove', this._documentPointermoveHandler);
371
395
  document.removeEventListener('pointerup', this._documentPointerupHandler);
396
+ document.removeEventListener('keyup', this._documentKeyupHandler);
397
+ }
398
+ /**
399
+ * start thumb move
400
+ */
401
+ _start(data) {
402
+ if (this._hasStarted)
403
+ return;
404
+ this._activeThumb = data.activeThumb;
405
+ if (!data.activeThumb)
406
+ return;
407
+ this._startEvent = data.src;
408
+ this.dispatchStartEvent({ src: data.src });
409
+ if (data.src === 'pointerdown') {
410
+ document.addEventListener('pointermove', this._documentPointermoveHandler);
411
+ document.addEventListener('pointerup', this._documentPointerupHandler);
412
+ }
413
+ if (data.src === 'keydown') {
414
+ document.addEventListener('keyup', this._documentKeyupHandler);
415
+ }
416
+ }
417
+ /**
418
+ * end thumb move
419
+ */
420
+ _end() {
421
+ document.removeEventListener('pointermove', this._documentPointermoveHandler);
422
+ document.removeEventListener('pointerup', this._documentPointerupHandler);
423
+ document.removeEventListener('keyup', this._documentKeyupHandler);
424
+ if (this._startEvent === 'pointerdown') {
425
+ this.dispatchEndEvent({ src: 'pointerup' });
426
+ }
427
+ if (this._startEvent === 'keydown') {
428
+ this.dispatchEndEvent({ src: 'keyup' });
429
+ }
430
+ this._startEvent = undefined;
372
431
  }
373
432
  /**
374
433
  *
@@ -414,6 +473,24 @@ class MuRange extends MuElement {
414
473
  navigationThumb.element.focused = true;
415
474
  return true;
416
475
  }
476
+ dispatchStartEvent(data) {
477
+ const eventName = 'mu-range-start';
478
+ this.dispatchEvent(new CustomEvent(eventName, {
479
+ bubbles: true,
480
+ composed: true,
481
+ cancelable: true,
482
+ detail: data,
483
+ }));
484
+ }
485
+ dispatchEndEvent(data) {
486
+ const eventName = 'mu-range-end';
487
+ this.dispatchEvent(new CustomEvent(eventName, {
488
+ bubbles: true,
489
+ composed: true,
490
+ cancelable: true,
491
+ detail: data,
492
+ }));
493
+ }
417
494
  dispatchChangeEvent(thumbs = this._thumbs, src) {
418
495
  const eventName = 'mu-range-change';
419
496
  const data = thumbs.map((thumb) => ({ name: thumb.name, value: thumb.value }));
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { M as MuElement, E as EventAction, _ as __decorate, g as getElementBoundaries, d as debounce, a as disableElementScroll, e as enableElementScroll } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, E as EventAction, _ as __decorate, g as getElementBoundaries, d as debounce, a as disableElementScroll, e as enableElementScroll } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { MuTransparent } from './mu-transparent.js';
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, nothing, html } from 'lit';
3
3
  import { property, state } from 'lit/decorators.js';
4
4
  import { repeat } from 'lit/directives/repeat.js';
@@ -36,7 +36,7 @@ declare class MuSelectLabel extends MuElement {
36
36
  setActiveDescendantId(id?: string): void;
37
37
  connectedCallback(): void;
38
38
  protected _assignLabelAndValueTypes(): void;
39
- get comboboxElement(): HTMLElement | MuSelectLabelContent | null | undefined;
39
+ get comboboxElement(): MuSelectLabelContent | HTMLElement | null | undefined;
40
40
  focus(options?: FocusOptions): void;
41
41
  protected _slotChangeHandler: () => void;
42
42
  protected firstUpdated(_changedProperties: PropertyValues): void;
@@ -1,4 +1,4 @@
1
- import { M as MuElement, _ as __decorate } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html, nothing } from 'lit';
3
3
  import './mu-trigger.js';
4
4
  import { property, state } from 'lit/decorators.js';
@@ -1,4 +1,4 @@
1
- import { M as MuElement, E as EventAction, _ as __decorate } from '../mu-element-C36Rgp-m.js';
1
+ import { M as MuElement, E as EventAction, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property, queryAssignedElements } from 'lit/decorators.js';
4
4
  import { MuTransparent } from './mu-transparent.js';
@@ -0,0 +1,34 @@
1
+ import { CSSResultGroup } from 'lit';
2
+ import { MuElement, MuElementComponent } from './mu-element.js';
3
+ import '@mustib/utils/browser';
4
+
5
+ type MuSortableItemComponent = MuElementComponent['attributes'] & {
6
+ attributes: {
7
+ name: string;
8
+ };
9
+ };
10
+ declare class MuSortableItem extends MuElement {
11
+ static styles?: CSSResultGroup | undefined;
12
+ _addEventActionAttributes: undefined;
13
+ eventActionData: undefined;
14
+ name: string;
15
+ connectedCallback(): void;
16
+ /**
17
+ * Used to notify the item whether or not it is being sorted and is moving
18
+ */
19
+ setIsMoving(value: boolean): void;
20
+ /**
21
+ * Used to notify the item whether or not it is added to be sorted
22
+ */
23
+ setAdded(value: boolean): void;
24
+ protected _slotChangeHandler: () => void;
25
+ protected render(): unknown;
26
+ }
27
+ declare global {
28
+ interface HTMLElementTagNameMap {
29
+ 'mu-sortable-item': MuSortableItem;
30
+ }
31
+ }
32
+
33
+ export { MuSortableItem };
34
+ export type { MuSortableItemComponent };
@@ -0,0 +1,95 @@
1
+ import { M as MuElement, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
+ import { css, html } from 'lit';
3
+ import { property } from 'lit/decorators.js';
4
+ import { MuTransparent } from './mu-transparent.js';
5
+ import { MuSortableTrigger } from './mu-sortable-trigger.js';
6
+ import './mu-icon.js';
7
+
8
+ class MuSortableItem extends MuElement {
9
+ constructor() {
10
+ super(...arguments);
11
+ this._slotChangeHandler = () => {
12
+ const triggers = [];
13
+ const addElement = (element) => {
14
+ if (element instanceof MuSortableTrigger) {
15
+ triggers.push(element);
16
+ }
17
+ };
18
+ this.renderRoot
19
+ .querySelector('slot')
20
+ ?.assignedElements({ flatten: true })
21
+ .forEach((el) => {
22
+ if (el instanceof MuTransparent)
23
+ el.contents.forEach(addElement);
24
+ else
25
+ addElement(el);
26
+ });
27
+ if (!triggers.length) {
28
+ console.warn(`mu-sortable-item does not have any triggers`, this);
29
+ }
30
+ triggers.forEach((trigger) => {
31
+ trigger.for = this.name;
32
+ });
33
+ };
34
+ }
35
+ connectedCallback() {
36
+ super.connectedCallback();
37
+ this.addEventListener('mu-transparent-slotchange', this._slotChangeHandler);
38
+ this.renderRoot.addEventListener('slotchange', this._slotChangeHandler);
39
+ if (!this.name) {
40
+ this.updateComplete.then(() => {
41
+ console.warn(`mu-sortable-item does not has a name, it will be assigned this default one (${this.muId})`, this);
42
+ });
43
+ this.name = this.muId;
44
+ }
45
+ }
46
+ /**
47
+ * Used to notify the item whether or not it is being sorted and is moving
48
+ */
49
+ setIsMoving(value) {
50
+ value ? this.setAttribute('moving', '') : this.removeAttribute('moving');
51
+ }
52
+ /**
53
+ * Used to notify the item whether or not it is added to be sorted
54
+ */
55
+ setAdded(value) {
56
+ value ? this.setAttribute('added', '') : this.removeAttribute('added');
57
+ }
58
+ render() {
59
+ return html `
60
+ <slot></slot>
61
+ `;
62
+ }
63
+ }
64
+ MuSortableItem.styles = [
65
+ MuElement.cssBase,
66
+ css `
67
+ :host([added]) {
68
+ outline: 1px dashed;
69
+ }
70
+
71
+ :host([moving]) {
72
+ user-select: none;
73
+ cursor: grabbing;
74
+ opacity: 0.5;
75
+ }
76
+
77
+ :host {
78
+ animation: flip 150ms 100ms ease-out forwards;
79
+ transform: scaleY(-0.75);
80
+ transition: opacity 150ms;
81
+ }
82
+
83
+ @keyframes flip {
84
+ 100% {
85
+ transform: none;
86
+ }
87
+ }
88
+ `,
89
+ ];
90
+ __decorate([
91
+ property()
92
+ ], MuSortableItem.prototype, "name", void 0);
93
+ MuSortableItem.register('mu-sortable-item');
94
+
95
+ export { MuSortableItem };
@@ -0,0 +1,22 @@
1
+ import { CSSResultGroup } from 'lit';
2
+ import { MuElement } from './mu-element.js';
3
+ import './mu-icon.js';
4
+ import '@mustib/utils/browser';
5
+
6
+ declare class MuSortableTrigger extends MuElement {
7
+ static styles?: CSSResultGroup | undefined;
8
+ eventActionData: undefined;
9
+ /**
10
+ * The associated item name
11
+ */
12
+ for: string;
13
+ protected _addEventActionAttributes(): Promise<void>;
14
+ protected render(): unknown;
15
+ }
16
+ declare global {
17
+ interface HTMLElementTagNameMap {
18
+ 'mu-sortable-trigger': MuSortableTrigger;
19
+ }
20
+ }
21
+
22
+ export { MuSortableTrigger };
@@ -0,0 +1,61 @@
1
+ import { css, html } from 'lit';
2
+ import { M as MuElement } from '../mu-element-CEvBHYiI.js';
3
+ import './mu-icon.js';
4
+ import 'lit/decorators.js';
5
+
6
+ class MuSortableTrigger extends MuElement {
7
+ constructor() {
8
+ super(...arguments);
9
+ /**
10
+ * The associated item name
11
+ */
12
+ this.for = '';
13
+ }
14
+ async _addEventActionAttributes() {
15
+ await this.updateComplete;
16
+ /**
17
+ * mouse events
18
+ */
19
+ this.setAttribute('mu-sortable-pointerdown', JSON.stringify([
20
+ 'prepared? ||#prevent',
21
+ '#modifier:Control? ||toggle',
22
+ ['add', this.for],
23
+ '||prepare',
24
+ ]));
25
+ /**
26
+ * keyboard events
27
+ */
28
+ this.setAttribute('mu-sortable-keydown', JSON.stringify([
29
+ 'prepared? ||#prevent',
30
+ '#key:Enter,Space?#modifier:Control? ||toggle',
31
+ ['add', this.for, '#key:Enter,Space'],
32
+ '#key:Enter,Space? ||prepare',
33
+ ]));
34
+ }
35
+ render() {
36
+ return html `
37
+ <div id='container' tabindex='0' part='container'>
38
+ <slot>
39
+ <mu-icon name='dragVertical'></mu-icon>
40
+ </slot>
41
+ </div>
42
+ `;
43
+ }
44
+ }
45
+ MuSortableTrigger.styles = [
46
+ MuElement.cssBase,
47
+ css `
48
+ #container {
49
+ display: grid;
50
+ cursor: grab;
51
+ user-select: none;
52
+ }
53
+
54
+ #container:focus-visible {
55
+ outline: 1px solid;
56
+ }
57
+ `,
58
+ ];
59
+ MuSortableTrigger.register('mu-sortable-trigger');
60
+
61
+ export { MuSortableTrigger };
@@ -0,0 +1,97 @@
1
+ import { EventAction, GenerateData } from '@mustib/utils/browser';
2
+ import { CSSResultGroup, PropertyValues } from 'lit';
3
+ import { MuElement, MuElementComponent } from './mu-element.js';
4
+ import { MuSortableItem } from './mu-sortable-item.js';
5
+
6
+ type MuSortableComponent = {
7
+ attributes: MuElementComponent['attributes'] & {
8
+ multiple: MuSortable['multiple'];
9
+ throttle: MuSortable['throttle'];
10
+ };
11
+ events: Events;
12
+ };
13
+ type Events = {
14
+ 'mu-sortable-change': CustomEvent<{
15
+ /**
16
+ * items names order before sorting
17
+ */
18
+ from: string[];
19
+ /**
20
+ * items names order after sorting
21
+ */
22
+ to: string[];
23
+ /**
24
+ * item name that started prepare action
25
+ */
26
+ startItem: string;
27
+ /**
28
+ * selected items names
29
+ */
30
+ selected: string[];
31
+ }>;
32
+ };
33
+ type SortableItem = {
34
+ element: MuSortableItem;
35
+ index: number;
36
+ name: string;
37
+ };
38
+ declare class MuSortable extends MuElement {
39
+ static styles?: CSSResultGroup | undefined;
40
+ static globalEventActionEvents: string[];
41
+ static eventAction: EventAction<GenerateData<MuSortable>>;
42
+ _addEventActionAttributes: undefined;
43
+ eventActionData: {
44
+ eventAction: EventAction<GenerateData<MuSortable>>;
45
+ events: string[];
46
+ };
47
+ /**
48
+ * a boolean indicates if multiple items can be sorted at the same time
49
+ *
50
+ * @default false
51
+ */
52
+ multiple: boolean;
53
+ /**
54
+ * pointer move throttle in ms
55
+ *
56
+ * @default 50
57
+ */
58
+ throttle: number;
59
+ protected _sortableItemsNamesMap: Map<string, SortableItem>;
60
+ protected _sortableItemsElementsMap: Map<MuSortableItem, SortableItem>;
61
+ protected _sortableItems: SortableItem[];
62
+ protected _overSortableItem?: SortableItem;
63
+ protected _toBeSortedItems: Set<SortableItem>;
64
+ protected _moveActionAnimationFrameId?: number;
65
+ protected _hasStartedMovingItems: boolean;
66
+ protected _prepareData?: {
67
+ /**
68
+ * The item that triggered prepare action regardless if there are multiple items to be sorted
69
+ */
70
+ movingItem: SortableItem;
71
+ type: 'keyboard' | 'pointer';
72
+ /**
73
+ * Initial items order before any sorting
74
+ */
75
+ initialItems: SortableItem[];
76
+ };
77
+ protected _changeSortState(data: GenerateData<MuSortable>): void;
78
+ protected _getItemFromEventAction(data: GenerateData<MuSortable>): SortableItem;
79
+ protected _endSortingHandler: () => void;
80
+ protected _throttledGlobalPointerMoveHandler?: typeof this._globalPointerMoveHandler;
81
+ protected _moveItems(overItem: SortableItem | undefined): void;
82
+ protected _globalKeydownHandler: (event: KeyboardEvent) => void;
83
+ protected _globalPointerMoveHandler(event: PointerEvent): void;
84
+ protected _slotChangeHandler: () => Promise<void>;
85
+ protected firstUpdated(_changedProperties: PropertyValues): Promise<void>;
86
+ protected render(): unknown;
87
+ }
88
+ declare global {
89
+ interface HTMLElementTagNameMap {
90
+ 'mu-sortable': MuSortable;
91
+ }
92
+ interface GlobalEventHandlersEventMap extends Events {
93
+ }
94
+ }
95
+
96
+ export { MuSortable };
97
+ export type { MuSortableComponent };
@@ -0,0 +1,308 @@
1
+ import { M as MuElement, E as EventAction, t as throttle, _ as __decorate } from '../mu-element-CEvBHYiI.js';
2
+ import { html } from 'lit';
3
+ import { property } from 'lit/decorators.js';
4
+ import { MuTransparent } from './mu-transparent.js';
5
+ import { MuSortableItem } from './mu-sortable-item.js';
6
+ import { MuSortableTrigger } from './mu-sortable-trigger.js';
7
+ import './mu-icon.js';
8
+
9
+ class MuSortable extends MuElement {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.eventActionData = {
13
+ eventAction: MuSortable.eventAction,
14
+ events: ['pointerdown', 'click', 'keydown'],
15
+ };
16
+ /**
17
+ * a boolean indicates if multiple items can be sorted at the same time
18
+ *
19
+ * @default false
20
+ */
21
+ this.multiple = false;
22
+ /**
23
+ * pointer move throttle in ms
24
+ *
25
+ * @default 50
26
+ */
27
+ this.throttle = 50;
28
+ this._sortableItemsNamesMap = new Map();
29
+ this._sortableItemsElementsMap = new Map();
30
+ this._sortableItems = [];
31
+ this._toBeSortedItems = new Set();
32
+ this._hasStartedMovingItems = false;
33
+ this._endSortingHandler = () => {
34
+ if (this._moveActionAnimationFrameId) {
35
+ cancelAnimationFrame(this._moveActionAnimationFrameId);
36
+ this._moveActionAnimationFrameId = undefined;
37
+ }
38
+ const prepareData = this._prepareData;
39
+ if (!prepareData) {
40
+ throw new Error('internal mu-sortable error (_prepareData) is undefined in end handler');
41
+ }
42
+ const selected = [];
43
+ const startItem = prepareData.movingItem.name;
44
+ const from = prepareData.initialItems.map((item) => item.name);
45
+ const to = this._sortableItems.map((item) => item.name);
46
+ if (this._throttledGlobalPointerMoveHandler)
47
+ document.removeEventListener('pointermove', this._throttledGlobalPointerMoveHandler);
48
+ document.removeEventListener('keydown', this._globalKeydownHandler);
49
+ document.removeEventListener('pointerup', this._endSortingHandler);
50
+ const eventName = 'mu-sortable-change';
51
+ const event = new CustomEvent(eventName, {
52
+ bubbles: true,
53
+ composed: true,
54
+ detail: { from, to, selected, startItem },
55
+ });
56
+ this._toBeSortedItems.forEach((item) => {
57
+ selected.push(item.name);
58
+ item.element.setAdded(false);
59
+ item.element.setIsMoving(false);
60
+ });
61
+ this._toBeSortedItems.clear();
62
+ this._hasStartedMovingItems = false;
63
+ this._prepareData = undefined;
64
+ this.dispatchEvent(event);
65
+ };
66
+ this._globalKeydownHandler = (event) => {
67
+ if (event.key === 'Enter' || event.key === ' ') {
68
+ this._endSortingHandler();
69
+ return;
70
+ }
71
+ let direction;
72
+ if (event.key === 'ArrowUp') {
73
+ direction = 'prev';
74
+ }
75
+ else if (event.key === 'ArrowDown')
76
+ direction = 'next';
77
+ if (!direction)
78
+ return;
79
+ const overItem = this.getNavigationItem({
80
+ direction,
81
+ items: this._sortableItems,
82
+ fromIndex: this._prepareData?.movingItem.index,
83
+ isNavigable: (item) => {
84
+ return !this._toBeSortedItems.has(item);
85
+ },
86
+ });
87
+ this._moveItems(overItem);
88
+ };
89
+ this._slotChangeHandler = async () => {
90
+ const toBeSortedNames = new Set([...this._toBeSortedItems].map((item) => item.name));
91
+ this._toBeSortedItems.clear();
92
+ this._sortableItems = [];
93
+ this._sortableItemsNamesMap.clear();
94
+ this._sortableItemsElementsMap.clear();
95
+ const addElement = (element) => {
96
+ if (element instanceof MuSortableItem) {
97
+ const name = element.name;
98
+ if (this._sortableItemsNamesMap.has(name)) {
99
+ console.warn('duplicated mu-sortable-item name', element);
100
+ return;
101
+ }
102
+ const item = {
103
+ element,
104
+ index: this._sortableItems.length,
105
+ name,
106
+ };
107
+ this._sortableItems.push(item);
108
+ this._sortableItemsElementsMap.set(element, item);
109
+ this._sortableItemsNamesMap.set(name, item);
110
+ if (this._prepareData?.movingItem.name === name) {
111
+ this._prepareData.movingItem = item;
112
+ }
113
+ if (toBeSortedNames.has(name)) {
114
+ this._toBeSortedItems.add(item);
115
+ }
116
+ }
117
+ };
118
+ this.renderRoot.querySelectorAll('slot').forEach((slot) => {
119
+ slot.assignedElements({ flatten: true }).forEach((el) => {
120
+ if (el instanceof MuTransparent)
121
+ el.contents.forEach(addElement);
122
+ else
123
+ addElement(el);
124
+ });
125
+ });
126
+ };
127
+ }
128
+ _changeSortState(data) {
129
+ const actionName = data._parsedAction.name;
130
+ if (this._hasStartedMovingItems) {
131
+ console.warn(`cannot use (${actionName}) action in mu-sortable when there is active sorting`, data);
132
+ return;
133
+ }
134
+ const item = this._getItemFromEventAction(data);
135
+ let operation;
136
+ if (actionName === 'toggle') {
137
+ operation = this._toBeSortedItems.has(item) ? 'delete' : 'add';
138
+ }
139
+ else
140
+ operation = actionName;
141
+ switch (operation) {
142
+ case 'add':
143
+ if (!this.multiple) {
144
+ this._toBeSortedItems.forEach((item) => {
145
+ item.element.setAdded(false);
146
+ });
147
+ this._toBeSortedItems.clear();
148
+ }
149
+ item.element.setAdded(true);
150
+ this._toBeSortedItems.add(item);
151
+ break;
152
+ case 'delete':
153
+ item.element.setAdded(false);
154
+ this._toBeSortedItems.delete(item);
155
+ break;
156
+ default:
157
+ console.warn(`unsupported action name (${actionName}) cannot change select state for mu-sortable`, data);
158
+ break;
159
+ }
160
+ }
161
+ _getItemFromEventAction(data) {
162
+ const actionName = data._parsedAction.name;
163
+ let itemName;
164
+ if (typeof data.actionParam === 'string' && data.actionParam !== '')
165
+ itemName = data.actionParam;
166
+ else if (data.matchedTarget instanceof MuSortableItem)
167
+ itemName = data.matchedTarget.name;
168
+ else if (data.matchedTarget instanceof MuSortableTrigger)
169
+ itemName = data.matchedTarget.for;
170
+ else {
171
+ throw new Error(`cannot get mu-sortable-item name for (${actionName}) action because it is not passed as action param or the element which dispatched the action is not the item itself or it's trigger`);
172
+ }
173
+ const item = this._sortableItemsNamesMap.get(itemName);
174
+ if (!item) {
175
+ throw new Error(`(${itemName}) is not recognized mu-sortable-item name`);
176
+ }
177
+ return item;
178
+ }
179
+ _moveItems(overItem) {
180
+ if (!this._toBeSortedItems.size)
181
+ return;
182
+ const lastAnimationFrameId = this._moveActionAnimationFrameId;
183
+ if (lastAnimationFrameId !== undefined)
184
+ cancelAnimationFrame(lastAnimationFrameId);
185
+ this._moveActionAnimationFrameId = requestAnimationFrame(() => {
186
+ const prepareData = this._prepareData;
187
+ if (!prepareData) {
188
+ throw new Error('internal mu-sortable error, (_prepareData) is undefined');
189
+ }
190
+ /**
191
+ * Notify sortable item of being moved
192
+ */
193
+ if (!this._hasStartedMovingItems) {
194
+ this._toBeSortedItems.forEach((item) => {
195
+ item.element.setIsMoving(true);
196
+ });
197
+ this._hasStartedMovingItems = true;
198
+ }
199
+ this._overSortableItem = overItem;
200
+ if (overItem) {
201
+ const preparedItem = prepareData.movingItem;
202
+ const isMovingBackward = preparedItem.index > overItem.index;
203
+ [...this._toBeSortedItems]
204
+ .sort((a, b) => isMovingBackward ? a.index - b.index : b.index - a.index)
205
+ .forEach((toBeSortedItem) => {
206
+ overItem.element.parentElement?.insertBefore(toBeSortedItem.element, isMovingBackward
207
+ ? overItem.element
208
+ : overItem.element.nextElementSibling);
209
+ });
210
+ }
211
+ });
212
+ }
213
+ _globalPointerMoveHandler(event) {
214
+ const overItemElement = document
215
+ .elementsFromPoint(event.clientX, event.clientY)
216
+ .find((el) => {
217
+ if (!(el instanceof MuSortableItem))
218
+ return false;
219
+ const sortableItem = this._sortableItemsElementsMap.get(el);
220
+ return sortableItem && !this._toBeSortedItems.has(sortableItem);
221
+ });
222
+ const overItem = overItemElement
223
+ ? this._sortableItemsElementsMap.get(overItemElement)
224
+ : undefined;
225
+ this._moveItems(overItem);
226
+ }
227
+ async firstUpdated(_changedProperties) {
228
+ this._slotChangeHandler();
229
+ await this.updateComplete;
230
+ this.addEventListener('mu-transparent-slotchange', this._slotChangeHandler);
231
+ this.renderRoot.addEventListener('slotchange', this._slotChangeHandler);
232
+ }
233
+ render() {
234
+ return html `
235
+ <slot></slot>
236
+ `;
237
+ }
238
+ }
239
+ MuSortable.styles = [MuElement.cssBase];
240
+ MuSortable.globalEventActionEvents = ['pointermove', 'pointerup'];
241
+ MuSortable.eventAction = new EventAction({
242
+ currTargetSelector: 'mu-sortable',
243
+ getEventAttributeName(eventName) {
244
+ return `mu-sortable-${eventName}`;
245
+ },
246
+ actions: {
247
+ toggle(data) {
248
+ data.event.currentTarget._changeSortState(data);
249
+ },
250
+ delete(data) {
251
+ data.event.currentTarget._changeSortState(data);
252
+ },
253
+ add(data) {
254
+ data.event.currentTarget._changeSortState(data);
255
+ },
256
+ prepare(data) {
257
+ const sortable = data.event.currentTarget;
258
+ if (sortable._prepareData) {
259
+ console.warn('cannot use prepare action for mu-sortable before current prepare ends', data);
260
+ return;
261
+ }
262
+ const movingItem = sortable._getItemFromEventAction(data);
263
+ let type;
264
+ if (data.actionParam === 'pointer' || data.actionParam === 'keyboard')
265
+ type = data.actionParam;
266
+ else if (data.event instanceof PointerEvent)
267
+ type = 'pointer';
268
+ else if (data.event instanceof KeyboardEvent)
269
+ type = 'keyboard';
270
+ else {
271
+ console.warn('cannot get prepare action type for mu-sortable', data);
272
+ return;
273
+ }
274
+ sortable._prepareData = {
275
+ movingItem,
276
+ initialItems: sortable._sortableItems,
277
+ type,
278
+ };
279
+ // need to defer so events not fire immediately
280
+ setTimeout(() => {
281
+ if (type === 'pointer') {
282
+ const handler = throttle(sortable._globalPointerMoveHandler.bind(sortable), sortable.throttle);
283
+ sortable._throttledGlobalPointerMoveHandler = handler;
284
+ document.addEventListener('pointermove', handler);
285
+ document.addEventListener('pointerup', sortable._endSortingHandler, { once: true });
286
+ }
287
+ else {
288
+ document.addEventListener('keydown', sortable._globalKeydownHandler);
289
+ }
290
+ }, 0);
291
+ },
292
+ },
293
+ switches: {
294
+ prepared(data) {
295
+ const sortable = data.event.currentTarget;
296
+ return sortable._prepareData !== undefined;
297
+ },
298
+ },
299
+ });
300
+ __decorate([
301
+ property({ type: Boolean })
302
+ ], MuSortable.prototype, "multiple", void 0);
303
+ __decorate([
304
+ property({ type: Number })
305
+ ], MuSortable.prototype, "throttle", void 0);
306
+ MuSortable.register('mu-sortable');
307
+
308
+ export { MuSortable };
@@ -1,4 +1,4 @@
1
- import { _ as __decorate, M as MuElement } from '../mu-element-C36Rgp-m.js';
1
+ import { _ as __decorate, M as MuElement } from '../mu-element-CEvBHYiI.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { _ as __decorate, p as parseJson } from '../mu-element-C36Rgp-m.js';
1
+ import { _ as __decorate, p as parseJson } from '../mu-element-CEvBHYiI.js';
2
2
  import { property } from 'lit/decorators.js';
3
3
  import { MuTransparent } from './mu-transparent.js';
4
4
  import 'lit';
package/index.d.ts CHANGED
@@ -18,6 +18,9 @@ import { MuSelectLabelComponent } from './components/mu-select-label.js';
18
18
  export { MuSelectLabel } from './components/mu-select-label.js';
19
19
  import { MuSelectLabelContentComponent } from './components/mu-select-label-content.js';
20
20
  export { MuSelectLabelContent } from './components/mu-select-label-content.js';
21
+ import { MuSortableComponent } from './components/mu-sortable.js';
22
+ import { MuSortableItemComponent } from './components/mu-sortable-item.js';
23
+ import './components/mu-sortable-trigger.js';
21
24
  import { MuTransparentComponent } from './components/mu-transparent.js';
22
25
  export { MuTransparent } from './components/mu-transparent.js';
23
26
  import { MuTriggerComponent } from './components/mu-trigger.js';
@@ -39,6 +42,8 @@ type ComponentsAttributes = {
39
42
  'mu-icon': MuIconComponent['attributes'];
40
43
  'mu-transparent': MuTransparentComponent['attributes'];
41
44
  'mu-trigger': MuTriggerComponent['attributes'];
45
+ 'mu-sortable': MuSortableComponent['attributes'];
46
+ 'mu-sortable-item': MuSortableItemComponent['attributes'];
42
47
  };
43
48
  type MuComponentsAttributes<GlobalAttributes = Record<string, any>> = {
44
49
  [key in keyof ComponentsAttributes]: Partial<ComponentsAttributes[key]> & GlobalAttributes;
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { M as MuElement } from './mu-element-C36Rgp-m.js';
1
+ export { M as MuElement } from './mu-element-CEvBHYiI.js';
2
2
  export { MuIcon } from './components/mu-icon.js';
3
3
  export { MuRange } from './components/mu-range.js';
4
4
  export { MuRangeFill } from './components/mu-range-fill.js';
@@ -458,6 +458,22 @@ class EventAction {
458
458
  },
459
459
  overridable: false,
460
460
  dynamic: false
461
+ },
462
+ '#modifier': {
463
+ handler(data) {
464
+ let modifiers;
465
+ const { event, switchParam } = data;
466
+ if (typeof switchParam === 'string')
467
+ modifiers = switchParam.split(',');
468
+ else if (Array.isArray(switchParam))
469
+ modifiers = switchParam;
470
+ if (!modifiers || modifiers.length === 0 || !(event instanceof PointerEvent || event instanceof KeyboardEvent)) {
471
+ return false;
472
+ }
473
+ return modifiers.some(modifier => event.getModifierState(modifier));
474
+ },
475
+ overridable: true,
476
+ dynamic: true
461
477
  }
462
478
  };
463
479
  /**
@@ -518,7 +534,7 @@ class EventAction {
518
534
  /**
519
535
  * Parse an action name and returns an object with the following properties:
520
536
  * - name: The name of the action.
521
- * - hasOr: A boolean indicating whether the action name starts with "||".
537
+ * - hasOr: A boolean indicating whether the action name starts with `||`.
522
538
  *
523
539
  * @param name - The name of the action to parse.
524
540
  */
@@ -527,6 +543,21 @@ class EventAction {
527
543
  const hasOr = trimmedName.startsWith('||');
528
544
  return { name: hasOr ? trimmedName.slice(2) : trimmedName, hasOr };
529
545
  }
546
+ /**
547
+ * Parse a switch name and returns an object with the following properties:
548
+ * - name: The name of the switch.
549
+ * - isNegated: A boolean indicating whether the switch name starts with `!`.
550
+ *
551
+ * @param name - The name of the switch to parse.
552
+ */
553
+ static parseSwitchName(name) {
554
+ const trimmedName = name.trim();
555
+ const isNegated = trimmedName.startsWith('!');
556
+ return {
557
+ name: isNegated ? trimmedName.slice(1) : trimmedName,
558
+ isNegated
559
+ };
560
+ }
530
561
  /**
531
562
  * Parse an action string and returns a {@link ParsedAction parsed action}.
532
563
  *
@@ -564,7 +595,7 @@ class EventAction {
564
595
  const hasSwitchParam = switchParamIndex !== -1;
565
596
  const switchName = hasSwitchParam ? switchString.slice(0, switchParamIndex) : switchString;
566
597
  const switchParam = hasSwitchParam ? switchString.slice(switchParamIndex + 1) : '';
567
- return { name: switchName.trim(), param: switchParam.trim() };
598
+ return { param: switchParam.trim(), ...this.parseSwitchName(switchName) };
568
599
  });
569
600
  }
570
601
  return { param: param.trim(), switches, ...EventAction.parseActionName(name) };
@@ -658,7 +689,15 @@ class EventAction {
658
689
  console.warn(`Switch named (${name}) is already registered and need (override) option to be true to be overridden`);
659
690
  continue;
660
691
  }
661
- this.switches[name] = switchData;
692
+ const parsedSwitchName = EventAction.parseSwitchName(name);
693
+ if (parsedSwitchName.isNegated) {
694
+ console.warn(`Switch name must not start with (!) as it is used to negate switches, add your logic once with the name (${parsedSwitchName.name}) and negate the switch name in the attribute instead, Please note that your switch handler will be wrapped in a negated one, and the name will be converted to (${parsedSwitchName.name}) if you omit this warning`);
695
+ const originalHandler = switchData.handler;
696
+ switchData.handler = (...args) => {
697
+ return !originalHandler(...args);
698
+ };
699
+ }
700
+ this.switches[parsedSwitchName.name] = switchData;
662
701
  }
663
702
  return this;
664
703
  }
@@ -695,7 +734,11 @@ class EventAction {
695
734
  console.warn(`Action named (${name}) is already registered and need (override) option to be true to be overridden`);
696
735
  continue;
697
736
  }
698
- this.actions[name] = actionData;
737
+ const parsedActionName = EventAction.parseActionName(name);
738
+ if (parsedActionName.hasOr) {
739
+ console.warn(`Action name cannot start with (||), as it is used to detect if the action hasOr, which is used as an indicator to not run other actions if this one gets executed, Please not that the action name will be converted to (${parsedActionName.name}) if you omit this warning`);
740
+ }
741
+ this.actions[parsedActionName.name] = actionData;
699
742
  }
700
743
  return this;
701
744
  }
@@ -729,8 +772,8 @@ class EventAction {
729
772
  switches: actionData.slice(2).map(switchData => {
730
773
  const [name = '', param = ''] = Array.isArray(switchData) ? switchData : switchData.split(':');
731
774
  return {
732
- name,
733
- param
775
+ param,
776
+ ...EventAction.parseSwitchName(name)
734
777
  };
735
778
  }),
736
779
  ...EventAction.parseActionName(actionData[0])
@@ -746,7 +789,7 @@ class EventAction {
746
789
  }
747
790
  return attributeString
748
791
  .split('&&')
749
- .map(EventAction.parseActionString);
792
+ .map(EventAction.parseActionString.bind(EventAction));
750
793
  }
751
794
  /**
752
795
  * for internal use
@@ -798,7 +841,7 @@ class EventAction {
798
841
  const checkSwitches = parsedAction.switches.length === 0 ? true : parsedAction.switches.every(switchData => {
799
842
  const staticValue = staticSwitches[switchData.name]?.get(switchData.param);
800
843
  if (staticValue !== undefined)
801
- return staticValue;
844
+ return switchData.isNegated ? !staticValue : staticValue;
802
845
  const switchAction = this.switches[switchData.name];
803
846
  if (!switchAction) {
804
847
  console.warn(`There is no registered switch with the name (${switchData.name}) for the event (${eventName})`, matchedTarget);
@@ -817,7 +860,7 @@ class EventAction {
817
860
  const map = staticSwitches[switchData.name] ||= new Map();
818
861
  map.set(switchData.param, value);
819
862
  }
820
- return value;
863
+ return switchData.isNegated ? !value : value;
821
864
  });
822
865
  if (!checkSwitches)
823
866
  continue;
package/package.json CHANGED
@@ -3,9 +3,12 @@
3
3
  "type": "module",
4
4
  "description": "A customizable web-components library with lit",
5
5
  "private": false,
6
- "version": "0.0.0-alpha.4",
6
+ "version": "0.0.0-alpha.6",
7
+ "lint-staged": {
8
+ "*.{js,ts,astro}": "biome check --write"
9
+ },
7
10
  "dependencies": {
8
- "@mustib/utils": "2.7.0"
11
+ "@mustib/utils": "2.8.1"
9
12
  },
10
13
  "peerDependencies": {
11
14
  "lit": "^3.3.1"
@@ -18,6 +21,8 @@
18
21
  "@tailwindcss/vite": "^4.1.12",
19
22
  "@types/node": "^24.9.2",
20
23
  "astro": "^5.12.8",
24
+ "husky": "^9.1.7",
25
+ "lint-staged": "^16.2.7",
21
26
  "rollup": "^4.52.5",
22
27
  "rollup-plugin-dts": "^6.2.3",
23
28
  "tailwindcss": "^4.1.12",