@baleada/logic 0.21.2 → 0.22.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.
package/lib/index.cjs CHANGED
@@ -291,16 +291,61 @@ const modifiersByAlias = {
291
291
  opt: "alt",
292
292
  option: "alt"
293
293
  };
294
- function createExceptAndOnlyEffect(effect, options) {
294
+ function createExceptAndOnlyEffect(type, effect, options) {
295
295
  const { except = [], only = [] } = options;
296
+ if (type === "keydown" || type === "keyup") {
297
+ return (event) => {
298
+ const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => lazyCollections.some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true], api = {
299
+ is: (keycombo) => eventMatchesKeycombo(event, ensureKeycombo(keycombo))
300
+ };
301
+ if (matchesOnly) {
302
+ effect(event, api);
303
+ return;
304
+ }
305
+ if (only.length === 0 && !matchesExcept) {
306
+ effect(event, api);
307
+ return;
308
+ }
309
+ };
310
+ }
311
+ if (type === "click" || type === "mousedown" || type === "mouseup" || type === "dblclick" || type === "contextmenu") {
312
+ return (event) => {
313
+ const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => lazyCollections.some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true], api = {
314
+ is: (clickcombo) => eventMatchesClickcombo(event, ensureClickcombo(clickcombo))
315
+ };
316
+ if (matchesOnly) {
317
+ effect(event, api);
318
+ return;
319
+ }
320
+ if (only.length === 0 && !matchesExcept) {
321
+ effect(event, api);
322
+ return;
323
+ }
324
+ };
325
+ }
326
+ if (type === "pointerdown" || type === "pointerup") {
327
+ return (event) => {
328
+ const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => lazyCollections.some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true], api = {
329
+ is: (pointercombo) => eventMatchesPointercombo(event, ensurePointercombo(pointercombo))
330
+ };
331
+ if (matchesOnly) {
332
+ effect(event, api);
333
+ return;
334
+ }
335
+ if (only.length === 0 && !matchesExcept) {
336
+ effect(event, api);
337
+ return;
338
+ }
339
+ };
340
+ }
296
341
  return (event) => {
297
342
  const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => lazyCollections.some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true];
298
343
  if (matchesOnly) {
299
- effect(event);
344
+ effect(event, {});
300
345
  return;
301
346
  }
302
347
  if (only.length === 0 && !matchesExcept) {
303
- effect(event);
348
+ effect(event, {});
304
349
  return;
305
350
  }
306
351
  };
@@ -349,19 +394,13 @@ class Recognizeable {
349
394
  maxSequenceLength;
350
395
  effects;
351
396
  effectApi;
352
- toType;
353
- constructor(sequence, options = { effectsIncludeCombos: true }) {
397
+ constructor(sequence, options = {}) {
354
398
  const defaultOptions = {
355
399
  maxSequenceLength: true,
356
- effectsIncludeCombos: true,
357
400
  effects: {}
358
401
  };
359
402
  this.maxSequenceLength = options?.maxSequenceLength || defaultOptions.maxSequenceLength;
360
- this.effects = new Map(isFunction(options?.effects) ? options.effects(createDefineEffect()) : Object.entries(options?.effects || defaultOptions.effects));
361
- this.toType = createToType({
362
- effectsIncludeCombos: options.effectsIncludeCombos,
363
- effects: this.effects
364
- });
403
+ this.effects = new Map(Object.entries(options?.effects || defaultOptions.effects));
365
404
  this.resetComputedMetadata();
366
405
  this.setSequence(sequence);
367
406
  this.effectApi = {
@@ -404,14 +443,13 @@ class Recognizeable {
404
443
  this.computedSequence = sequence;
405
444
  return this;
406
445
  }
407
- recognize(sequenceItem, { onRecognized } = {}) {
446
+ recognize(sequenceItem, api, { onRecognized } = {}) {
408
447
  this.recognizing();
409
448
  const type = this.toType(sequenceItem), excess = isNumber(this.maxSequenceLength) ? Math.max(0, this.sequence.length - this.maxSequenceLength) : 0, newSequence = createConcat(createSlice(excess)(this.sequence), [sequenceItem])([]);
410
- this.effectApi.sequenceItem = sequenceItem;
411
449
  this.effectApi.getSequence = () => newSequence;
412
450
  this.effectApi.onRecognized = onRecognized || (() => {
413
451
  });
414
- this.effects.get(type)?.(this.effectApi);
452
+ this.effects.get(type)?.(sequenceItem, { ...api, ...this.effectApi });
415
453
  switch (this.status) {
416
454
  case "denied":
417
455
  this.resetComputedMetadata();
@@ -427,34 +465,7 @@ class Recognizeable {
427
465
  recognizing() {
428
466
  this.computedStatus = "recognizing";
429
467
  }
430
- }
431
- function createDefineEffect() {
432
- return (type, effect) => {
433
- return [type, effect];
434
- };
435
- }
436
- function createToType({
437
- effectsIncludeCombos,
438
- effects
439
- }) {
440
- const effectLeftclickcombos = [], effectRightclickcombos = [], effectKeycombos = [];
441
- if (effectsIncludeCombos) {
442
- for (const [effectKey] of effects) {
443
- const implementation = toImplementation(effectKey);
444
- switch (implementation) {
445
- case "leftclickcombo":
446
- effectLeftclickcombos.push(ensureClickcombo(effectKey));
447
- break;
448
- case "rightclickcombo":
449
- effectRightclickcombos.push(ensureClickcombo(effectKey));
450
- break;
451
- case "keycombo":
452
- effectKeycombos.push(ensureKeycombo(effectKey));
453
- break;
454
- }
455
- }
456
- }
457
- return function toType(sequenceItem) {
468
+ toType(sequenceItem) {
458
469
  if (isArray(sequenceItem)) {
459
470
  if (sequenceItem[0] instanceof IntersectionObserverEntry) {
460
471
  return "intersect";
@@ -472,38 +483,10 @@ function createToType({
472
483
  if ("didTimeout" in sequenceItem) {
473
484
  return "idle";
474
485
  }
475
- if (effectLeftclickcombos?.length > 0) {
476
- if (leftclickcomboEventTypes.has(sequenceItem.type)) {
477
- for (const clickcombo of effectLeftclickcombos) {
478
- if (eventMatchesClickcombo({ event: sequenceItem, clickcombo })) {
479
- return toJoinedClickcombo(clickcombo);
480
- }
481
- }
482
- }
483
- }
484
- if (effectRightclickcombos?.length > 0) {
485
- if (rightclickComboEventTypes.has(sequenceItem.type)) {
486
- for (const clickcombo of effectRightclickcombos) {
487
- if (eventMatchesClickcombo({ event: sequenceItem, clickcombo })) {
488
- return toJoinedClickcombo(clickcombo);
489
- }
490
- }
491
- }
492
- }
493
- if (effectKeycombos?.length > 0) {
494
- if (keycomboEventTypes.has(sequenceItem.type)) {
495
- for (const keycombo of effectKeycombos) {
496
- if (eventMatchesKeycombo({ event: sequenceItem, keycombo })) {
497
- return toJoinedKeycombo(keycombo);
498
- }
499
- }
500
- }
501
- }
502
486
  return sequenceItem.type;
503
487
  }
504
- };
488
+ }
505
489
  }
506
- const leftclickcomboEventTypes = /* @__PURE__ */ new Set(["click", "mousedown", "mouseup", "dblclick"]), rightclickComboEventTypes = /* @__PURE__ */ new Set(["contextmenu"]), keycomboEventTypes = /* @__PURE__ */ new Set(["keydown", "keyup"]), toJoinedClickcombo = lazyCollections.join("+"), toJoinedKeycombo = lazyCollections.pipe(lazyCollections.map(({ name }) => name), toJoinedClickcombo);
507
490
 
508
491
  class Listenable {
509
492
  computedRecognizeable;
@@ -511,15 +494,8 @@ class Listenable {
511
494
  computedActive;
512
495
  constructor(type, options) {
513
496
  if (type === "recognizeable") {
514
- const recognizeableOptions = {
515
- ...options?.recognizeable || {},
516
- effects: isFunction(options?.recognizeable?.effects) ? createReduce((effects, [type2, effect]) => {
517
- effects[type2] = effect;
518
- return effects;
519
- }, {})(options.recognizeable.effects(createDefineEffect())) : options?.recognizeable?.effects || {}
520
- };
521
- this.computedRecognizeable = new Recognizeable([], recognizeableOptions);
522
- this.recognizeableEffectsKeys = Object.keys(recognizeableOptions.effects);
497
+ this.computedRecognizeable = new Recognizeable([], options?.recognizeable || {});
498
+ this.recognizeableEffectsKeys = Object.keys(options?.recognizeable?.effects || {});
523
499
  }
524
500
  this.computedActive = /* @__PURE__ */ new Set();
525
501
  this.setType(type);
@@ -575,16 +551,6 @@ class Listenable {
575
551
  case "documentevent":
576
552
  this.documentEventListen(effect, options);
577
553
  break;
578
- case "keycombo":
579
- this.keycomboListen(effect, options);
580
- break;
581
- case "leftclickcombo":
582
- case "rightclickcombo":
583
- this.clickcomboListen(effect, options);
584
- break;
585
- case "pointercombo":
586
- this.pointercomboListen(effect, options);
587
- break;
588
554
  case "event":
589
555
  this.eventListen(effect, options);
590
556
  break;
@@ -612,18 +578,19 @@ class Listenable {
612
578
  if (isFunction(options.instantEffect)) {
613
579
  options.instantEffect(target);
614
580
  }
615
- target.addEventListener("change", effect);
616
- this.active.add({ target, id: ["change", effect] });
581
+ const withApi = (event) => effect(event, {});
582
+ target.addEventListener("change", withApi);
583
+ this.active.add({ target, id: ["change", withApi] });
617
584
  }
618
585
  idleListen(effect, options) {
619
- const { requestIdleCallback } = options, id = window.requestIdleCallback(effect, requestIdleCallback);
586
+ const { requestIdleCallback } = options, id = window.requestIdleCallback((deadline) => effect(deadline, {}), requestIdleCallback);
620
587
  this.active.add({ target: window, id });
621
588
  }
622
589
  recognizeableListen(effect, options) {
623
- const guardedEffect = (sequenceItem) => {
624
- this.recognizeable.recognize(sequenceItem, { onRecognized: effect });
590
+ const guardedEffect = (sequenceItem, api) => {
591
+ this.recognizeable.recognize(sequenceItem, api, { onRecognized: (sequenceItem2) => effect(sequenceItem2, api) });
625
592
  if (this.recognizeable.status === "recognized") {
626
- effect(sequenceItem);
593
+ effect(sequenceItem, api);
627
594
  }
628
595
  };
629
596
  for (const type of this.recognizeableEffectsKeys) {
@@ -639,44 +606,8 @@ class Listenable {
639
606
  };
640
607
  this.eventListen(effect, ensuredOptions);
641
608
  }
642
- pointercomboListen(effect, options) {
643
- const pointercombo = ensurePointercombo(this.type), guardedEffect = (event) => {
644
- if (eventMatchesPointercombo({ event, pointercombo })) {
645
- effect(event);
646
- }
647
- };
648
- this.eventListen(guardedEffect, options);
649
- }
650
- clickcomboListen(effect, options) {
651
- const clickcombo = ensureClickcombo(this.type), guardedEffect = (event) => {
652
- if (eventMatchesClickcombo({ event, clickcombo })) {
653
- effect(event);
654
- }
655
- };
656
- this.eventListen(guardedEffect, options);
657
- }
658
- keycomboListen(effect, options) {
659
- const keycombo = ensureKeycombo(this.type), guardedEffect = (event) => {
660
- if (eventMatchesKeycombo({ event, keycombo })) {
661
- effect(event);
662
- }
663
- };
664
- this.eventListen(guardedEffect, options);
665
- }
666
609
  eventListen(effect, options) {
667
- const type = (() => {
668
- switch (this.implementation) {
669
- case "keycombo":
670
- return `key${options.keyDirection || "down"}`;
671
- case "leftclickcombo":
672
- return this.type.match(/(\w+)$/)[1];
673
- case "rightclickcombo":
674
- return "contextmenu";
675
- default:
676
- return this.type;
677
- }
678
- })();
679
- const { exceptAndOnlyEffect, effectOptions } = toAddEventListenerParams(effect, options), eventListeners = [[type, exceptAndOnlyEffect, ...effectOptions]];
610
+ const { exceptAndOnlyEffect, effectOptions } = toAddEventListenerParams(this.type, effect, options), eventListeners = [[this.type, exceptAndOnlyEffect, ...effectOptions]];
680
611
  this.addEventListeners(eventListeners, options);
681
612
  }
682
613
  addEventListeners(eventListeners, options) {
@@ -767,22 +698,6 @@ const predicatesByImplementation = /* @__PURE__ */ new Map([
767
698
  "documentevent",
768
699
  (type) => documentEvents.has(type)
769
700
  ],
770
- [
771
- "keycombo",
772
- (type) => implementationREs.keycombo.test(type)
773
- ],
774
- [
775
- "leftclickcombo",
776
- (type) => implementationREs.leftclickcombo.test(type)
777
- ],
778
- [
779
- "rightclickcombo",
780
- (type) => implementationREs.rightclickcombo.test(type)
781
- ],
782
- [
783
- "pointercombo",
784
- (type) => implementationREs.pointercombo.test(type)
785
- ],
786
701
  [
787
702
  "event",
788
703
  () => true
@@ -797,17 +712,13 @@ const documentEvents = /* @__PURE__ */ new Set([
797
712
  "visibilitychange"
798
713
  ]);
799
714
  const implementationREs = {
800
- mediaquery: /^\(.+\)$/,
801
- keycombo: /^((!?([a-zA-Z0-9,<.>/?;:'"[{\]}\\|`~!@#$%^&*()-_=+]|tab|space|arrow|vertical|horizontal|up|right|down|left|enter|backspace|esc|home|end|pagedown|pageup|capslock|f[0-9]{1,2}|camera|delete|cmd|command|meta|shift|ctrl|control|alt|opt|option))\+)*(!?([a-zA-Z0-9,<.>/?;:'"[{\]}\\|`~!@#$%^&*()-_=+]|tab|space|arrow|vertical|horizontal|up|right|down|left|enter|backspace|esc|home|end|pagedown|pageup|capslock|f[0-9]{1,2}|camera|delete|cmd|command|meta|shift|ctrl|control|alt|opt|option))$/,
802
- leftclickcombo: /^(!?((cmd|command|meta|shift|ctrl|control|alt|opt|option))\+){0,4}!?(click|mousedown|mouseup|dblclick)$/,
803
- rightclickcombo: /^(!?((cmd|command|meta|shift|ctrl|control|alt|opt|option))\+){0,4}!?(rightclick|contextmenu)$/,
804
- pointercombo: /^(!?((cmd|command|meta|shift|ctrl|control|alt|opt|option))\+){0,4}!?(pointerdown|pointerup)$/
715
+ mediaquery: /^\(.+\)$/
805
716
  };
806
- function toAddEventListenerParams(effect, options) {
807
- const { addEventListener, useCapture } = options, exceptAndOnlyEffect = createExceptAndOnlyEffect(effect, options), effectOptions = [addEventListener || useCapture];
717
+ function toAddEventListenerParams(type, effect, options) {
718
+ const { addEventListener, useCapture } = options, exceptAndOnlyEffect = createExceptAndOnlyEffect(type, effect, options), effectOptions = [addEventListener || useCapture];
808
719
  return { exceptAndOnlyEffect, effectOptions };
809
720
  }
810
- function eventMatchesKeycombo({ event, keycombo }) {
721
+ function eventMatchesKeycombo(event, keycombo) {
811
722
  return lazyCollections.every(({ name, type }, index) => {
812
723
  switch (type) {
813
724
  case "singleCharacter":
@@ -891,10 +802,10 @@ const predicatesByArrow = /* @__PURE__ */ new Map([
891
802
  const arrows = /* @__PURE__ */ new Set(["arrowup", "arrowright", "arrowdown", "arrowleft"]);
892
803
  const verticalArrows = /* @__PURE__ */ new Set(["arrowup", "arrowdown"]);
893
804
  const horizontalArrows = /* @__PURE__ */ new Set(["arrowright", "arrowleft"]);
894
- function eventMatchesClickcombo({ event, clickcombo }) {
805
+ function eventMatchesClickcombo(event, clickcombo) {
895
806
  return lazyCollections.every((name) => fromComboItemNameToType(name) === "click" || name.startsWith("!") && !isModified({ alias: name.slice(1), event }) || !name.startsWith("!") && isModified({ alias: name, event }))(clickcombo);
896
807
  }
897
- function eventMatchesPointercombo({ event, pointercombo }) {
808
+ function eventMatchesPointercombo(event, pointercombo) {
898
809
  return lazyCollections.every((name) => fromComboItemNameToType(name) === "pointer" || name.startsWith("!") && !isModified({ alias: name.slice(1), event }) || !name.startsWith("!") && isModified({ alias: name, event }))(pointercombo);
899
810
  }
900
811
  const observerAssertionsByType = {
@@ -2753,8 +2664,9 @@ class Pickable {
2753
2664
  return this.toItems(this.picks);
2754
2665
  }
2755
2666
  toItems = createMap((index) => this.array[index]);
2667
+ computedMultiple;
2756
2668
  get multiple() {
2757
- return this.picks.length > 1;
2669
+ return this.computedMultiple;
2758
2670
  }
2759
2671
  toPossiblePicks;
2760
2672
  setArray(array) {
@@ -2801,6 +2713,7 @@ class Pickable {
2801
2713
  });
2802
2714
  this.computedFirst = Math.min(...this.picks);
2803
2715
  this.computedLast = Math.max(...this.picks);
2716
+ this.computedMultiple = toUnique(this.picks).length > 1;
2804
2717
  this.picked();
2805
2718
  return this;
2806
2719
  }
@@ -2812,6 +2725,7 @@ class Pickable {
2812
2725
  this.computedPicks = [];
2813
2726
  this.computedFirst = void 0;
2814
2727
  this.computedLast = void 0;
2728
+ this.computedMultiple = false;
2815
2729
  this.omitted();
2816
2730
  return this;
2817
2731
  }
@@ -2819,6 +2733,7 @@ class Pickable {
2819
2733
  this.computedPicks = createFilter((pick, index) => options.reference === "array" ? isUndefined(lazyCollections.find((omit) => pick === omit)(omits)) : isUndefined(lazyCollections.find((omit) => index === omit)(omits)))(this.computedPicks);
2820
2734
  this.computedFirst = Math.min(...this.picks);
2821
2735
  this.computedLast = Math.max(...this.picks);
2736
+ this.computedMultiple = toUnique(this.picks).length > 1;
2822
2737
  this.omitted();
2823
2738
  return this;
2824
2739
  }
@@ -3106,8 +3021,6 @@ exports.easingsNetOutExpo = easingsNetOutExpo;
3106
3021
  exports.easingsNetOutQuad = easingsNetOutQuad;
3107
3022
  exports.easingsNetOutQuint = easingsNetOutQuint;
3108
3023
  exports.easingsNetOutSine = easingsNetOutSine;
3109
- exports.ensureKeycombo = ensureKeycombo;
3110
- exports.eventMatchesKeycombo = eventMatchesKeycombo;
3111
3024
  exports.linear = linear;
3112
3025
  exports.materialAccelerated = materialAccelerated;
3113
3026
  exports.materialDecelerated = materialDecelerated;
package/lib/index.d.ts CHANGED
@@ -411,23 +411,21 @@ declare class Grantable<DescriptorType extends PermissionDescriptor> {
411
411
 
412
412
  declare type RecognizeableOptions<Type extends ListenableSupportedType, Metadata extends Record<any, any>> = {
413
413
  maxSequenceLength?: true | number;
414
- effectsIncludeCombos?: boolean;
415
414
  effects?: {
416
- [type in Type]?: (api: RecognizeableEffectApi<Type, Metadata>) => any;
417
- } | ((defineEffect: DefineEffect<Type, Metadata>) => [type: Type, effect: (api: RecognizeableEffectApi<Type, Metadata>) => any][]);
415
+ [type in Type]?: RecognizeableEffect<type, Metadata>;
416
+ };
418
417
  };
419
- declare type DefineEffect<Type extends ListenableSupportedType, Metadata extends Record<any, any>> = <EffectType extends Type>(type: EffectType, effect: (api: RecognizeableEffectApi<EffectType, Metadata>) => any) => [type: Type, effect: (api: RecognizeableEffectApi<Type, Metadata>) => any];
420
- declare type RecognizeableStatus = 'recognized' | 'recognizing' | 'denied' | 'ready';
418
+ declare type RecognizeableEffect<Type extends ListenableSupportedType, Metadata extends Record<any, any>> = (sequenceItem: ListenEffectParam<Type>, api: RecognizeableEffectApi<Type, Metadata>) => void;
421
419
  declare type RecognizeableEffectApi<Type extends ListenableSupportedType, Metadata extends Record<any, any>> = {
422
- getStatus: () => 'recognized' | 'recognizing' | 'denied' | 'ready';
420
+ getStatus: () => RecognizeableStatus;
423
421
  getMetadata: () => Metadata;
424
422
  setMetadata: (metadata: Metadata) => void;
425
423
  recognized: () => void;
426
424
  denied: () => void;
427
- sequenceItem: ListenEffectParam<Type>;
428
425
  getSequence: () => ListenEffectParam<Type>[];
429
426
  onRecognized: (sequenceItem: ListenEffectParam<Type>) => any;
430
- };
427
+ } & ListenEffectApi<Type>;
428
+ declare type RecognizeableStatus = 'recognized' | 'recognizing' | 'denied' | 'ready';
431
429
  declare type RecognizeOptions<Type extends ListenableSupportedType, Metadata extends Record<any, any>> = {
432
430
  onRecognized?: (sequenceItem: ListenEffectParam<Type>) => any;
433
431
  };
@@ -435,7 +433,6 @@ declare class Recognizeable<Type extends ListenableSupportedType, Metadata exten
435
433
  private maxSequenceLength;
436
434
  private effects;
437
435
  private effectApi;
438
- private toType;
439
436
  constructor(sequence: ListenEffectParam<Type>[], options?: RecognizeableOptions<Type, Metadata>);
440
437
  private computedMetadata;
441
438
  private resetComputedMetadata;
@@ -449,18 +446,12 @@ declare class Recognizeable<Type extends ListenableSupportedType, Metadata exten
449
446
  get metadata(): Metadata;
450
447
  private computedSequence;
451
448
  setSequence(sequence: ListenEffectParam<Type>[]): this;
452
- recognize(sequenceItem: ListenEffectParam<Type>, { onRecognized }?: RecognizeOptions<Type, Metadata>): this;
449
+ recognize(sequenceItem: ListenEffectParam<Type>, api: ListenEffectApi<Type>, { onRecognized }?: RecognizeOptions<Type, Metadata>): this;
453
450
  private recognizing;
451
+ private toType;
454
452
  }
455
453
 
456
- declare type ListenableKeycomboItem = {
457
- name: string;
458
- type: ListenableComboItemType | 'custom';
459
- };
460
- declare function ensureKeycombo(type: string): ListenableKeycomboItem[];
461
- declare type ListenableComboItemType = 'singleCharacter' | 'arrow' | 'other' | 'modifier' | 'click' | 'pointer';
462
-
463
- declare type ListenableSupportedType = 'recognizeable' | 'intersect' | 'mutate' | 'resize' | 'idle' | ListenableMediaQuery | ListenableClickcombo | ListenableLeftClick | ListenableRightClick | ListenablePointercombo | ListenableKeycombo | keyof Omit<HTMLElementEventMap, 'resize'> | keyof Omit<DocumentEventMap, 'resize'>;
454
+ declare type ListenableSupportedType = 'recognizeable' | 'intersect' | 'mutate' | 'resize' | 'idle' | ListenableMediaQuery | keyof Omit<HTMLElementEventMap, 'resize'> | keyof Omit<DocumentEventMap, 'resize'>;
464
455
  declare type ListenableMediaQuery = `(${string})`;
465
456
  declare type ListenableClickcombo = `${string}+${ListenableLeftClick | ListenableRightClick}`;
466
457
  declare type ListenableLeftClick = 'click' | 'mousedown' | 'mouseup' | 'dblclick';
@@ -468,12 +459,22 @@ declare type ListenableRightClick = 'rightclick' | 'contextmenu';
468
459
  declare type ListenablePointercombo = `${string}+${ListenablePointer}`;
469
460
  declare type ListenablePointer = 'pointerdown' | 'pointerup';
470
461
  declare type ListenableKeycombo = `${string}+${string}`;
471
- declare type ListenableSupportedEventType = ListenableClickcombo | ListenablePointercombo | ListenableKeycombo | keyof Omit<HTMLElementEventMap, 'resize'> | keyof Omit<DocumentEventMap, 'resize'>;
462
+ declare type ListenableSupportedEventType = keyof Omit<HTMLElementEventMap, 'resize'> | keyof Omit<DocumentEventMap, 'resize'>;
472
463
  declare type ListenableOptions<Type extends ListenableSupportedType, RecognizeableMetadata extends Record<any, any> = Record<any, any>> = {
473
464
  recognizeable?: RecognizeableOptions<Type, RecognizeableMetadata>;
474
465
  };
475
- declare type ListenEffect<Type extends ListenableSupportedType> = Type extends 'intersect' ? (entries: ListenEffectParam<Type>) => any : Type extends 'mutate' ? (records: ListenEffectParam<Type>) => any : Type extends 'resize' ? (entries: ListenEffectParam<Type>) => any : Type extends 'idle' ? (deadline: ListenEffectParam<Type>) => any : Type extends ListenableMediaQuery ? (event: ListenEffectParam<Type>) => any : Type extends ListenableClickcombo ? (event: ListenEffectParam<Type>) => any : Type extends ListenablePointercombo ? (event: ListenEffectParam<Type>) => any : Type extends ListenableKeycombo ? (event: ListenEffectParam<Type>) => any : Type extends keyof Omit<HTMLElementEventMap, 'resize'> ? (event: ListenEffectParam<Type>) => any : Type extends keyof Omit<DocumentEventMap, 'resize'> ? (event: ListenEffectParam<Type>) => any : never;
476
- declare type ListenEffectParam<Type extends ListenableSupportedType> = Type extends 'intersect' ? IntersectionObserverEntry[] : Type extends 'mutate' ? MutationRecord[] : Type extends 'resize' ? ResizeObserverEntry[] : Type extends 'idle' ? IdleDeadline : Type extends ListenableMediaQuery ? MediaQueryListEvent : Type extends ListenableClickcombo ? MouseEvent : Type extends ListenableLeftClick ? MouseEvent : Type extends ListenableRightClick ? MouseEvent : Type extends ListenablePointercombo ? PointerEvent : Type extends ListenableKeycombo ? KeyboardEvent : Type extends keyof Omit<HTMLElementEventMap, 'resize'> ? HTMLElementEventMap[Type] : Type extends keyof Omit<DocumentEventMap, 'resize'> ? DocumentEventMap[Type] : never;
466
+ declare type ListenEffect<Type extends ListenableSupportedType> = Type extends 'intersect' ? (entries: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends 'mutate' ? (records: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends 'resize' ? (entries: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends 'idle' ? (deadline: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends ListenableMediaQuery ? (event: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends (ListenableLeftClick | ListenableRightClick) ? (event: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends (ListenablePointer) ? (event: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends ('keydown' | 'keyup') ? (event: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends keyof Omit<HTMLElementEventMap, 'resize'> ? (event: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : Type extends keyof Omit<DocumentEventMap, 'resize'> ? (event: ListenEffectParam<Type>, api: ListenEffectApi<Type>) => any : never;
467
+ declare type ListenEffectParam<Type extends ListenableSupportedType> = Type extends 'intersect' ? IntersectionObserverEntry[] : Type extends 'mutate' ? MutationRecord[] : Type extends 'resize' ? ResizeObserverEntry[] : Type extends 'idle' ? IdleDeadline : Type extends ListenableMediaQuery ? MediaQueryListEvent : Type extends ListenableRightClick ? MouseEvent : Type extends keyof Omit<HTMLElementEventMap, 'resize'> ? HTMLElementEventMap[Type] : Type extends keyof Omit<DocumentEventMap, 'resize'> ? DocumentEventMap[Type] : never;
468
+ declare type ListenEffectApi<Type extends ListenableSupportedType> = Type extends 'intersect' ? Record<never, never> : Type extends 'mutate' ? Record<never, never> : Type extends 'resize' ? Record<never, never> : Type extends 'idle' ? Record<never, never> : Type extends ListenableMediaQuery ? Record<never, never> : Type extends (ListenableLeftClick | ListenableRightClick) ? MouseEventApi : Type extends (ListenablePointer) ? PointerEventApi : Type extends ('keydown' | 'keyup') ? KeyboardEventApi : Type extends keyof Omit<HTMLElementEventMap, 'resize'> ? Record<never, never> : Type extends keyof Omit<DocumentEventMap, 'resize'> ? Record<never, never> : never;
469
+ declare type MouseEventApi = {
470
+ is: (clickcombo: ListenableClickcombo) => boolean;
471
+ };
472
+ declare type PointerEventApi = {
473
+ is: (pointercombo: ListenablePointercombo) => boolean;
474
+ };
475
+ declare type KeyboardEventApi = {
476
+ is: (keycombo: ListenableKeycombo) => boolean;
477
+ };
477
478
  declare type ListenOptions<Type extends ListenableSupportedType> = Type extends 'intersect' ? {
478
479
  observer?: IntersectionObserverInit;
479
480
  } & ObservationListenOptions : Type extends 'mutate' ? {
@@ -484,9 +485,7 @@ declare type ListenOptions<Type extends ListenableSupportedType> = Type extends
484
485
  requestIdleCallback?: IdleRequestOptions;
485
486
  } : Type extends ListenableMediaQuery ? {
486
487
  instantEffect?: (list: MediaQueryList) => any;
487
- } : Type extends ListenableClickcombo ? EventListenOptions : Type extends ListenablePointercombo ? EventListenOptions : Type extends ListenableKeycombo ? {
488
- keyDirection?: 'up' | 'down';
489
- } & EventListenOptions : Type extends keyof Omit<HTMLElementEventMap, 'resize'> ? EventListenOptions : Type extends keyof Omit<DocumentEventMap, 'resize'> ? EventListenOptions : never;
488
+ } : Type extends keyof Omit<HTMLElementEventMap, 'resize'> ? EventListenOptions : Type extends keyof Omit<DocumentEventMap, 'resize'> ? EventListenOptions : never;
490
489
  declare type ObservationListenOptions = {
491
490
  target?: Element;
492
491
  };
@@ -511,7 +510,7 @@ declare type ListenableActive<Type extends ListenableSupportedType, Recognizeabl
511
510
  id: number;
512
511
  } : Type extends ListenableMediaQuery ? {
513
512
  target: MediaQueryList;
514
- id: [type: string, effect: ListenEffect<Type>];
513
+ id: [type: string, effect: (param: ListenEffectParam<Type>) => void];
515
514
  } : Type extends ListenableSupportedEventType ? {
516
515
  target: Element | Document;
517
516
  id: ListenableActiveEventId<Type>;
@@ -520,7 +519,7 @@ declare type ListenableActive<Type extends ListenableSupportedType, Recognizeabl
520
519
  };
521
520
  declare type ListenableActiveEventId<Type extends ListenableSupportedEventType> = [
522
521
  type: string,
523
- exceptAndOnlyEffect: ListenEffect<Type>,
522
+ exceptAndOnlyEffect: (param: ListenEffectParam<Type>) => void,
524
523
  optionsOrUseCapture: AddEventListenerOptions | boolean
525
524
  ];
526
525
  declare type ListenableStatus = 'ready' | 'listening' | 'stopped';
@@ -547,9 +546,6 @@ declare class Listenable<Type extends ListenableSupportedType, RecognizeableMeta
547
546
  private idleListen;
548
547
  private recognizeableListen;
549
548
  private documentEventListen;
550
- private pointercomboListen;
551
- private clickcomboListen;
552
- private keycomboListen;
553
549
  private eventListen;
554
550
  private addEventListeners;
555
551
  private listening;
@@ -558,10 +554,6 @@ declare class Listenable<Type extends ListenableSupportedType, RecognizeableMeta
558
554
  }): this;
559
555
  private stopped;
560
556
  }
561
- declare function eventMatchesKeycombo({ event, keycombo }: {
562
- event: KeyboardEvent;
563
- keycombo: ListenableKeycomboItem[];
564
- }): boolean;
565
557
 
566
558
  declare type NavigateableOptions = {
567
559
  initialLocation?: number;
@@ -630,6 +622,7 @@ declare class Pickable<Item> {
630
622
  get status(): PickableStatus;
631
623
  get items(): Item[];
632
624
  private toItems;
625
+ computedMultiple: boolean;
633
626
  get multiple(): boolean;
634
627
  private toPossiblePicks;
635
628
  setArray(array: Item[]): this;
@@ -755,4 +748,4 @@ declare class Pipeable {
755
748
  pipeAsync(...fns: ((...args: any[]) => Promise<any>)[]): Promise<any>;
756
749
  }
757
750
 
758
- export { AnimateFrame, AnimateFrameEffect, AnimateOptions, Animateable, AnimateableKeyframe, AnimateableOptions, AnimateableStatus, ArrayFunction, ArrayFunctionAsync, CompleteOptions, Completeable, CompleteableOptions, CompleteableStatus, Copyable, CopyableOptions, CopyableStatus, Delayable, DelayableEffect, DelayableOptions, DelayableStatus, Drawable, DrawableOptions, DrawableState, DrawableStatus, FetchOptions, FetchOptionsApi, Fetchable, FetchableOptions, FetchableStatus, Fullscreenable, FullscreenableGetElement, FullscreenableOptions, FullscreenableStatus, Grantable, GrantableOptions, GrantableStatus, ListenEffect, ListenEffectParam, ListenOptions, Listenable, ListenableActive, ListenableClickcombo, ListenableKeycombo, ListenableKeycomboItem, ListenableOptions, ListenablePointercombo, ListenableStatus, ListenableSupportedEventType, ListenableSupportedType, MapFunction, Navigateable, NavigateableOptions, NavigateableStatus, NumberFunction, ObjectFunction, Pickable, PickableOptions, PickableStatus, Pipeable, RecognizeOptions, Recognizeable, RecognizeableEffectApi, RecognizeableOptions, RecognizeableStatus, Resolveable, ResolveableGetPromise, ResolveableOptions, ResolveableStatus, Sanitizeable, SanitizeableOptions, SanitizeableStatus, Searchable, SearchableOptions, SearchableStatus, Storeable, StoreableOptions, StoreableStatus, StringFunction, createClamp, createClip, createConcat, createDelete, createDetermine, createFilter, createFilterAsync, createForEachAsync, createInsert, createMap, createMapAsync, createReduce, createReduceAsync, createRename, createReorder, createReplace, createReverse, createSlice, createSlug, createSort, createSwap, createToEntries, createUnique, easingsNetInBack, easingsNetInCirc, easingsNetInCubic, easingsNetInExpo, easingsNetInOutBack, easingsNetInOutCirc, easingsNetInOutCubic, easingsNetInOutExpo, easingsNetInOutQuad, easingsNetInOutQuint, easingsNetInOutSine, easingsNetInQuad, easingsNetInQuart, easingsNetInQuint, easingsNetInSine, easingsNetOutBack, easingsNetOutCirc, easingsNetOutCubic, easingsNetOutExpo, easingsNetOutQuad, easingsNetOutQuint, easingsNetOutSine, ensureKeycombo, eventMatchesKeycombo, linear, materialAccelerated, materialDecelerated, materialStandard, toD, toFlattenedD, verouEase, verouEaseIn, verouEaseInOut, verouEaseOut };
751
+ export { AnimateFrame, AnimateFrameEffect, AnimateOptions, Animateable, AnimateableKeyframe, AnimateableOptions, AnimateableStatus, ArrayFunction, ArrayFunctionAsync, CompleteOptions, Completeable, CompleteableOptions, CompleteableStatus, Copyable, CopyableOptions, CopyableStatus, Delayable, DelayableEffect, DelayableOptions, DelayableStatus, Drawable, DrawableOptions, DrawableState, DrawableStatus, FetchOptions, FetchOptionsApi, Fetchable, FetchableOptions, FetchableStatus, Fullscreenable, FullscreenableGetElement, FullscreenableOptions, FullscreenableStatus, Grantable, GrantableOptions, GrantableStatus, ListenEffect, ListenEffectParam, ListenOptions, Listenable, ListenableActive, ListenableClickcombo, ListenableKeycombo, ListenableOptions, ListenablePointercombo, ListenableStatus, ListenableSupportedEventType, ListenableSupportedType, MapFunction, Navigateable, NavigateableOptions, NavigateableStatus, NumberFunction, ObjectFunction, Pickable, PickableOptions, PickableStatus, Pipeable, RecognizeOptions, Recognizeable, RecognizeableEffect, RecognizeableOptions, RecognizeableStatus, Resolveable, ResolveableGetPromise, ResolveableOptions, ResolveableStatus, Sanitizeable, SanitizeableOptions, SanitizeableStatus, Searchable, SearchableOptions, SearchableStatus, Storeable, StoreableOptions, StoreableStatus, StringFunction, createClamp, createClip, createConcat, createDelete, createDetermine, createFilter, createFilterAsync, createForEachAsync, createInsert, createMap, createMapAsync, createReduce, createReduceAsync, createRename, createReorder, createReplace, createReverse, createSlice, createSlug, createSort, createSwap, createToEntries, createUnique, easingsNetInBack, easingsNetInCirc, easingsNetInCubic, easingsNetInExpo, easingsNetInOutBack, easingsNetInOutCirc, easingsNetInOutCubic, easingsNetInOutExpo, easingsNetInOutQuad, easingsNetInOutQuint, easingsNetInOutSine, easingsNetInQuad, easingsNetInQuart, easingsNetInQuint, easingsNetInSine, easingsNetOutBack, easingsNetOutCirc, easingsNetOutCubic, easingsNetOutExpo, easingsNetOutQuad, easingsNetOutQuint, easingsNetOutSine, linear, materialAccelerated, materialDecelerated, materialStandard, toD, toFlattenedD, verouEase, verouEaseIn, verouEaseInOut, verouEaseOut };
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { reduce, pipe, filter, toArray, slice, concat, unique, map, find, findIndex, some, join, every } from 'lazy-collections';
1
+ import { reduce, pipe, filter, toArray, slice, concat, unique, map, find, findIndex, some, every, join } from 'lazy-collections';
2
2
  import slugify from '@sindresorhus/slugify';
3
3
  import BezierEasing from 'bezier-easing';
4
4
  import { mix } from '@snigo.dev/color';
@@ -280,16 +280,61 @@ const modifiersByAlias = {
280
280
  opt: "alt",
281
281
  option: "alt"
282
282
  };
283
- function createExceptAndOnlyEffect(effect, options) {
283
+ function createExceptAndOnlyEffect(type, effect, options) {
284
284
  const { except = [], only = [] } = options;
285
+ if (type === "keydown" || type === "keyup") {
286
+ return (event) => {
287
+ const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true], api = {
288
+ is: (keycombo) => eventMatchesKeycombo(event, ensureKeycombo(keycombo))
289
+ };
290
+ if (matchesOnly) {
291
+ effect(event, api);
292
+ return;
293
+ }
294
+ if (only.length === 0 && !matchesExcept) {
295
+ effect(event, api);
296
+ return;
297
+ }
298
+ };
299
+ }
300
+ if (type === "click" || type === "mousedown" || type === "mouseup" || type === "dblclick" || type === "contextmenu") {
301
+ return (event) => {
302
+ const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true], api = {
303
+ is: (clickcombo) => eventMatchesClickcombo(event, ensureClickcombo(clickcombo))
304
+ };
305
+ if (matchesOnly) {
306
+ effect(event, api);
307
+ return;
308
+ }
309
+ if (only.length === 0 && !matchesExcept) {
310
+ effect(event, api);
311
+ return;
312
+ }
313
+ };
314
+ }
315
+ if (type === "pointerdown" || type === "pointerup") {
316
+ return (event) => {
317
+ const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true], api = {
318
+ is: (pointercombo) => eventMatchesPointercombo(event, ensurePointercombo(pointercombo))
319
+ };
320
+ if (matchesOnly) {
321
+ effect(event, api);
322
+ return;
323
+ }
324
+ if (only.length === 0 && !matchesExcept) {
325
+ effect(event, api);
326
+ return;
327
+ }
328
+ };
329
+ }
285
330
  return (event) => {
286
331
  const { target } = event, [matchesOnly, matchesExcept] = target instanceof Element ? createMap((selectors) => some((selector) => target.matches(selector))(selectors))([only, except]) : [false, true];
287
332
  if (matchesOnly) {
288
- effect(event);
333
+ effect(event, {});
289
334
  return;
290
335
  }
291
336
  if (only.length === 0 && !matchesExcept) {
292
- effect(event);
337
+ effect(event, {});
293
338
  return;
294
339
  }
295
340
  };
@@ -338,19 +383,13 @@ class Recognizeable {
338
383
  maxSequenceLength;
339
384
  effects;
340
385
  effectApi;
341
- toType;
342
- constructor(sequence, options = { effectsIncludeCombos: true }) {
386
+ constructor(sequence, options = {}) {
343
387
  const defaultOptions = {
344
388
  maxSequenceLength: true,
345
- effectsIncludeCombos: true,
346
389
  effects: {}
347
390
  };
348
391
  this.maxSequenceLength = options?.maxSequenceLength || defaultOptions.maxSequenceLength;
349
- this.effects = new Map(isFunction(options?.effects) ? options.effects(createDefineEffect()) : Object.entries(options?.effects || defaultOptions.effects));
350
- this.toType = createToType({
351
- effectsIncludeCombos: options.effectsIncludeCombos,
352
- effects: this.effects
353
- });
392
+ this.effects = new Map(Object.entries(options?.effects || defaultOptions.effects));
354
393
  this.resetComputedMetadata();
355
394
  this.setSequence(sequence);
356
395
  this.effectApi = {
@@ -393,14 +432,13 @@ class Recognizeable {
393
432
  this.computedSequence = sequence;
394
433
  return this;
395
434
  }
396
- recognize(sequenceItem, { onRecognized } = {}) {
435
+ recognize(sequenceItem, api, { onRecognized } = {}) {
397
436
  this.recognizing();
398
437
  const type = this.toType(sequenceItem), excess = isNumber(this.maxSequenceLength) ? Math.max(0, this.sequence.length - this.maxSequenceLength) : 0, newSequence = createConcat(createSlice(excess)(this.sequence), [sequenceItem])([]);
399
- this.effectApi.sequenceItem = sequenceItem;
400
438
  this.effectApi.getSequence = () => newSequence;
401
439
  this.effectApi.onRecognized = onRecognized || (() => {
402
440
  });
403
- this.effects.get(type)?.(this.effectApi);
441
+ this.effects.get(type)?.(sequenceItem, { ...api, ...this.effectApi });
404
442
  switch (this.status) {
405
443
  case "denied":
406
444
  this.resetComputedMetadata();
@@ -416,34 +454,7 @@ class Recognizeable {
416
454
  recognizing() {
417
455
  this.computedStatus = "recognizing";
418
456
  }
419
- }
420
- function createDefineEffect() {
421
- return (type, effect) => {
422
- return [type, effect];
423
- };
424
- }
425
- function createToType({
426
- effectsIncludeCombos,
427
- effects
428
- }) {
429
- const effectLeftclickcombos = [], effectRightclickcombos = [], effectKeycombos = [];
430
- if (effectsIncludeCombos) {
431
- for (const [effectKey] of effects) {
432
- const implementation = toImplementation(effectKey);
433
- switch (implementation) {
434
- case "leftclickcombo":
435
- effectLeftclickcombos.push(ensureClickcombo(effectKey));
436
- break;
437
- case "rightclickcombo":
438
- effectRightclickcombos.push(ensureClickcombo(effectKey));
439
- break;
440
- case "keycombo":
441
- effectKeycombos.push(ensureKeycombo(effectKey));
442
- break;
443
- }
444
- }
445
- }
446
- return function toType(sequenceItem) {
457
+ toType(sequenceItem) {
447
458
  if (isArray(sequenceItem)) {
448
459
  if (sequenceItem[0] instanceof IntersectionObserverEntry) {
449
460
  return "intersect";
@@ -461,38 +472,10 @@ function createToType({
461
472
  if ("didTimeout" in sequenceItem) {
462
473
  return "idle";
463
474
  }
464
- if (effectLeftclickcombos?.length > 0) {
465
- if (leftclickcomboEventTypes.has(sequenceItem.type)) {
466
- for (const clickcombo of effectLeftclickcombos) {
467
- if (eventMatchesClickcombo({ event: sequenceItem, clickcombo })) {
468
- return toJoinedClickcombo(clickcombo);
469
- }
470
- }
471
- }
472
- }
473
- if (effectRightclickcombos?.length > 0) {
474
- if (rightclickComboEventTypes.has(sequenceItem.type)) {
475
- for (const clickcombo of effectRightclickcombos) {
476
- if (eventMatchesClickcombo({ event: sequenceItem, clickcombo })) {
477
- return toJoinedClickcombo(clickcombo);
478
- }
479
- }
480
- }
481
- }
482
- if (effectKeycombos?.length > 0) {
483
- if (keycomboEventTypes.has(sequenceItem.type)) {
484
- for (const keycombo of effectKeycombos) {
485
- if (eventMatchesKeycombo({ event: sequenceItem, keycombo })) {
486
- return toJoinedKeycombo(keycombo);
487
- }
488
- }
489
- }
490
- }
491
475
  return sequenceItem.type;
492
476
  }
493
- };
477
+ }
494
478
  }
495
- const leftclickcomboEventTypes = /* @__PURE__ */ new Set(["click", "mousedown", "mouseup", "dblclick"]), rightclickComboEventTypes = /* @__PURE__ */ new Set(["contextmenu"]), keycomboEventTypes = /* @__PURE__ */ new Set(["keydown", "keyup"]), toJoinedClickcombo = join("+"), toJoinedKeycombo = pipe(map(({ name }) => name), toJoinedClickcombo);
496
479
 
497
480
  class Listenable {
498
481
  computedRecognizeable;
@@ -500,15 +483,8 @@ class Listenable {
500
483
  computedActive;
501
484
  constructor(type, options) {
502
485
  if (type === "recognizeable") {
503
- const recognizeableOptions = {
504
- ...options?.recognizeable || {},
505
- effects: isFunction(options?.recognizeable?.effects) ? createReduce((effects, [type2, effect]) => {
506
- effects[type2] = effect;
507
- return effects;
508
- }, {})(options.recognizeable.effects(createDefineEffect())) : options?.recognizeable?.effects || {}
509
- };
510
- this.computedRecognizeable = new Recognizeable([], recognizeableOptions);
511
- this.recognizeableEffectsKeys = Object.keys(recognizeableOptions.effects);
486
+ this.computedRecognizeable = new Recognizeable([], options?.recognizeable || {});
487
+ this.recognizeableEffectsKeys = Object.keys(options?.recognizeable?.effects || {});
512
488
  }
513
489
  this.computedActive = /* @__PURE__ */ new Set();
514
490
  this.setType(type);
@@ -564,16 +540,6 @@ class Listenable {
564
540
  case "documentevent":
565
541
  this.documentEventListen(effect, options);
566
542
  break;
567
- case "keycombo":
568
- this.keycomboListen(effect, options);
569
- break;
570
- case "leftclickcombo":
571
- case "rightclickcombo":
572
- this.clickcomboListen(effect, options);
573
- break;
574
- case "pointercombo":
575
- this.pointercomboListen(effect, options);
576
- break;
577
543
  case "event":
578
544
  this.eventListen(effect, options);
579
545
  break;
@@ -601,18 +567,19 @@ class Listenable {
601
567
  if (isFunction(options.instantEffect)) {
602
568
  options.instantEffect(target);
603
569
  }
604
- target.addEventListener("change", effect);
605
- this.active.add({ target, id: ["change", effect] });
570
+ const withApi = (event) => effect(event, {});
571
+ target.addEventListener("change", withApi);
572
+ this.active.add({ target, id: ["change", withApi] });
606
573
  }
607
574
  idleListen(effect, options) {
608
- const { requestIdleCallback } = options, id = window.requestIdleCallback(effect, requestIdleCallback);
575
+ const { requestIdleCallback } = options, id = window.requestIdleCallback((deadline) => effect(deadline, {}), requestIdleCallback);
609
576
  this.active.add({ target: window, id });
610
577
  }
611
578
  recognizeableListen(effect, options) {
612
- const guardedEffect = (sequenceItem) => {
613
- this.recognizeable.recognize(sequenceItem, { onRecognized: effect });
579
+ const guardedEffect = (sequenceItem, api) => {
580
+ this.recognizeable.recognize(sequenceItem, api, { onRecognized: (sequenceItem2) => effect(sequenceItem2, api) });
614
581
  if (this.recognizeable.status === "recognized") {
615
- effect(sequenceItem);
582
+ effect(sequenceItem, api);
616
583
  }
617
584
  };
618
585
  for (const type of this.recognizeableEffectsKeys) {
@@ -628,44 +595,8 @@ class Listenable {
628
595
  };
629
596
  this.eventListen(effect, ensuredOptions);
630
597
  }
631
- pointercomboListen(effect, options) {
632
- const pointercombo = ensurePointercombo(this.type), guardedEffect = (event) => {
633
- if (eventMatchesPointercombo({ event, pointercombo })) {
634
- effect(event);
635
- }
636
- };
637
- this.eventListen(guardedEffect, options);
638
- }
639
- clickcomboListen(effect, options) {
640
- const clickcombo = ensureClickcombo(this.type), guardedEffect = (event) => {
641
- if (eventMatchesClickcombo({ event, clickcombo })) {
642
- effect(event);
643
- }
644
- };
645
- this.eventListen(guardedEffect, options);
646
- }
647
- keycomboListen(effect, options) {
648
- const keycombo = ensureKeycombo(this.type), guardedEffect = (event) => {
649
- if (eventMatchesKeycombo({ event, keycombo })) {
650
- effect(event);
651
- }
652
- };
653
- this.eventListen(guardedEffect, options);
654
- }
655
598
  eventListen(effect, options) {
656
- const type = (() => {
657
- switch (this.implementation) {
658
- case "keycombo":
659
- return `key${options.keyDirection || "down"}`;
660
- case "leftclickcombo":
661
- return this.type.match(/(\w+)$/)[1];
662
- case "rightclickcombo":
663
- return "contextmenu";
664
- default:
665
- return this.type;
666
- }
667
- })();
668
- const { exceptAndOnlyEffect, effectOptions } = toAddEventListenerParams(effect, options), eventListeners = [[type, exceptAndOnlyEffect, ...effectOptions]];
599
+ const { exceptAndOnlyEffect, effectOptions } = toAddEventListenerParams(this.type, effect, options), eventListeners = [[this.type, exceptAndOnlyEffect, ...effectOptions]];
669
600
  this.addEventListeners(eventListeners, options);
670
601
  }
671
602
  addEventListeners(eventListeners, options) {
@@ -756,22 +687,6 @@ const predicatesByImplementation = /* @__PURE__ */ new Map([
756
687
  "documentevent",
757
688
  (type) => documentEvents.has(type)
758
689
  ],
759
- [
760
- "keycombo",
761
- (type) => implementationREs.keycombo.test(type)
762
- ],
763
- [
764
- "leftclickcombo",
765
- (type) => implementationREs.leftclickcombo.test(type)
766
- ],
767
- [
768
- "rightclickcombo",
769
- (type) => implementationREs.rightclickcombo.test(type)
770
- ],
771
- [
772
- "pointercombo",
773
- (type) => implementationREs.pointercombo.test(type)
774
- ],
775
690
  [
776
691
  "event",
777
692
  () => true
@@ -786,17 +701,13 @@ const documentEvents = /* @__PURE__ */ new Set([
786
701
  "visibilitychange"
787
702
  ]);
788
703
  const implementationREs = {
789
- mediaquery: /^\(.+\)$/,
790
- keycombo: /^((!?([a-zA-Z0-9,<.>/?;:'"[{\]}\\|`~!@#$%^&*()-_=+]|tab|space|arrow|vertical|horizontal|up|right|down|left|enter|backspace|esc|home|end|pagedown|pageup|capslock|f[0-9]{1,2}|camera|delete|cmd|command|meta|shift|ctrl|control|alt|opt|option))\+)*(!?([a-zA-Z0-9,<.>/?;:'"[{\]}\\|`~!@#$%^&*()-_=+]|tab|space|arrow|vertical|horizontal|up|right|down|left|enter|backspace|esc|home|end|pagedown|pageup|capslock|f[0-9]{1,2}|camera|delete|cmd|command|meta|shift|ctrl|control|alt|opt|option))$/,
791
- leftclickcombo: /^(!?((cmd|command|meta|shift|ctrl|control|alt|opt|option))\+){0,4}!?(click|mousedown|mouseup|dblclick)$/,
792
- rightclickcombo: /^(!?((cmd|command|meta|shift|ctrl|control|alt|opt|option))\+){0,4}!?(rightclick|contextmenu)$/,
793
- pointercombo: /^(!?((cmd|command|meta|shift|ctrl|control|alt|opt|option))\+){0,4}!?(pointerdown|pointerup)$/
704
+ mediaquery: /^\(.+\)$/
794
705
  };
795
- function toAddEventListenerParams(effect, options) {
796
- const { addEventListener, useCapture } = options, exceptAndOnlyEffect = createExceptAndOnlyEffect(effect, options), effectOptions = [addEventListener || useCapture];
706
+ function toAddEventListenerParams(type, effect, options) {
707
+ const { addEventListener, useCapture } = options, exceptAndOnlyEffect = createExceptAndOnlyEffect(type, effect, options), effectOptions = [addEventListener || useCapture];
797
708
  return { exceptAndOnlyEffect, effectOptions };
798
709
  }
799
- function eventMatchesKeycombo({ event, keycombo }) {
710
+ function eventMatchesKeycombo(event, keycombo) {
800
711
  return every(({ name, type }, index) => {
801
712
  switch (type) {
802
713
  case "singleCharacter":
@@ -880,10 +791,10 @@ const predicatesByArrow = /* @__PURE__ */ new Map([
880
791
  const arrows = /* @__PURE__ */ new Set(["arrowup", "arrowright", "arrowdown", "arrowleft"]);
881
792
  const verticalArrows = /* @__PURE__ */ new Set(["arrowup", "arrowdown"]);
882
793
  const horizontalArrows = /* @__PURE__ */ new Set(["arrowright", "arrowleft"]);
883
- function eventMatchesClickcombo({ event, clickcombo }) {
794
+ function eventMatchesClickcombo(event, clickcombo) {
884
795
  return every((name) => fromComboItemNameToType(name) === "click" || name.startsWith("!") && !isModified({ alias: name.slice(1), event }) || !name.startsWith("!") && isModified({ alias: name, event }))(clickcombo);
885
796
  }
886
- function eventMatchesPointercombo({ event, pointercombo }) {
797
+ function eventMatchesPointercombo(event, pointercombo) {
887
798
  return every((name) => fromComboItemNameToType(name) === "pointer" || name.startsWith("!") && !isModified({ alias: name.slice(1), event }) || !name.startsWith("!") && isModified({ alias: name, event }))(pointercombo);
888
799
  }
889
800
  const observerAssertionsByType = {
@@ -2742,8 +2653,9 @@ class Pickable {
2742
2653
  return this.toItems(this.picks);
2743
2654
  }
2744
2655
  toItems = createMap((index) => this.array[index]);
2656
+ computedMultiple;
2745
2657
  get multiple() {
2746
- return this.picks.length > 1;
2658
+ return this.computedMultiple;
2747
2659
  }
2748
2660
  toPossiblePicks;
2749
2661
  setArray(array) {
@@ -2790,6 +2702,7 @@ class Pickable {
2790
2702
  });
2791
2703
  this.computedFirst = Math.min(...this.picks);
2792
2704
  this.computedLast = Math.max(...this.picks);
2705
+ this.computedMultiple = toUnique(this.picks).length > 1;
2793
2706
  this.picked();
2794
2707
  return this;
2795
2708
  }
@@ -2801,6 +2714,7 @@ class Pickable {
2801
2714
  this.computedPicks = [];
2802
2715
  this.computedFirst = void 0;
2803
2716
  this.computedLast = void 0;
2717
+ this.computedMultiple = false;
2804
2718
  this.omitted();
2805
2719
  return this;
2806
2720
  }
@@ -2808,6 +2722,7 @@ class Pickable {
2808
2722
  this.computedPicks = createFilter((pick, index) => options.reference === "array" ? isUndefined(find((omit) => pick === omit)(omits)) : isUndefined(find((omit) => index === omit)(omits)))(this.computedPicks);
2809
2723
  this.computedFirst = Math.min(...this.picks);
2810
2724
  this.computedLast = Math.max(...this.picks);
2725
+ this.computedMultiple = toUnique(this.picks).length > 1;
2811
2726
  this.omitted();
2812
2727
  return this;
2813
2728
  }
@@ -3033,4 +2948,4 @@ class Storeable {
3033
2948
  }
3034
2949
  }
3035
2950
 
3036
- export { Animateable, Completeable, Copyable, Delayable, Drawable, Fetchable, Fullscreenable, Grantable, Listenable, Navigateable, Pickable, Pipeable, Recognizeable, Resolveable, Sanitizeable, Searchable, Storeable, createClamp, createClip, createConcat, createDelete, createDetermine, createFilter, createFilterAsync, createForEachAsync, createInsert, createMap, createMapAsync, createReduce, createReduceAsync, createRename, createReorder, createReplace, createReverse, createSlice, createSlug, createSort, createSwap, createToEntries, createUnique, easingsNetInBack, easingsNetInCirc, easingsNetInCubic, easingsNetInExpo, easingsNetInOutBack, easingsNetInOutCirc, easingsNetInOutCubic, easingsNetInOutExpo, easingsNetInOutQuad, easingsNetInOutQuint, easingsNetInOutSine, easingsNetInQuad, easingsNetInQuart, easingsNetInQuint, easingsNetInSine, easingsNetOutBack, easingsNetOutCirc, easingsNetOutCubic, easingsNetOutExpo, easingsNetOutQuad, easingsNetOutQuint, easingsNetOutSine, ensureKeycombo, eventMatchesKeycombo, linear, materialAccelerated, materialDecelerated, materialStandard, toD, toFlattenedD, verouEase, verouEaseIn, verouEaseInOut, verouEaseOut };
2951
+ export { Animateable, Completeable, Copyable, Delayable, Drawable, Fetchable, Fullscreenable, Grantable, Listenable, Navigateable, Pickable, Pipeable, Recognizeable, Resolveable, Sanitizeable, Searchable, Storeable, createClamp, createClip, createConcat, createDelete, createDetermine, createFilter, createFilterAsync, createForEachAsync, createInsert, createMap, createMapAsync, createReduce, createReduceAsync, createRename, createReorder, createReplace, createReverse, createSlice, createSlug, createSort, createSwap, createToEntries, createUnique, easingsNetInBack, easingsNetInCirc, easingsNetInCubic, easingsNetInExpo, easingsNetInOutBack, easingsNetInOutCirc, easingsNetInOutCubic, easingsNetInOutExpo, easingsNetInOutQuad, easingsNetInOutQuint, easingsNetInOutSine, easingsNetInQuad, easingsNetInQuart, easingsNetInQuint, easingsNetInSine, easingsNetOutBack, easingsNetOutCirc, easingsNetOutCubic, easingsNetOutExpo, easingsNetOutQuad, easingsNetOutQuint, easingsNetOutSine, linear, materialAccelerated, materialDecelerated, materialStandard, toD, toFlattenedD, verouEase, verouEaseIn, verouEaseInOut, verouEaseOut };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baleada/logic",
3
- "version": "0.21.2",
3
+ "version": "0.22.1",
4
4
  "description": "UI logic for the Baleada toolkit",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.js",