@mulsense/xnew 0.5.2 → 0.5.4

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/dist/xnew.mjs CHANGED
@@ -137,11 +137,11 @@ class Timer {
137
137
  else if (this.options.easing === 'ease-in') {
138
138
  p = Math.pow((1.0 - Math.pow((1.0 - p), 0.5)), 2.0);
139
139
  }
140
- else if (this.options.easing === 'ease') {
141
- p = (1.0 - Math.cos(p * Math.PI)) / 2.0; // todo
142
- }
143
- else if (this.options.easing === 'ease-in-out') {
144
- p = (1.0 - Math.cos(p * Math.PI)) / 2.0;
140
+ else if (this.options.easing === 'ease' || this.options.easing === 'ease-in-out') {
141
+ // p = (1.0 - Math.cos(p * Math.PI)) / 2.0;
142
+ const bias = (this.options.easing === 'ease') ? 0.7 : 1.0;
143
+ const s = Math.pow(p, bias);
144
+ p = s * s * (3 - 2 * s);
145
145
  }
146
146
  (_b = (_a = this.options).transition) === null || _b === void 0 ? void 0 : _b.call(_a, p);
147
147
  });
@@ -199,7 +199,7 @@ class Timer {
199
199
  }
200
200
  }
201
201
 
202
- class EventManager {
202
+ class Eventor {
203
203
  constructor() {
204
204
  this.map = new MapMap();
205
205
  }
@@ -519,12 +519,93 @@ function pointer(element, event) {
519
519
  // utils
520
520
  //----------------------------------------------------------------------------------------------------
521
521
  const SYSTEM_EVENTS = ['start', 'update', 'render', 'stop', 'finalize'];
522
+ class UnitPromise {
523
+ constructor(promise, component) {
524
+ this.promise = promise;
525
+ this.component = component;
526
+ }
527
+ then(callback) {
528
+ const snapshot = Unit.snapshot(Unit.currentUnit);
529
+ this.promise = this.promise.then((...args) => Unit.scope(snapshot, callback, ...args));
530
+ return this;
531
+ }
532
+ catch(callback) {
533
+ const snapshot = Unit.snapshot(Unit.currentUnit);
534
+ this.promise = this.promise.catch((...args) => Unit.scope(snapshot, callback, ...args));
535
+ return this;
536
+ }
537
+ finally(callback) {
538
+ const snapshot = Unit.snapshot(Unit.currentUnit);
539
+ this.promise = this.promise.finally(() => Unit.scope(snapshot, callback));
540
+ return this;
541
+ }
542
+ }
543
+ class UnitTimer {
544
+ constructor(options) {
545
+ this.stack = [];
546
+ this.unit = new Unit(Unit.currentUnit, null, UnitTimer.Component, { options, snapshot: Unit.snapshot(Unit.currentUnit) });
547
+ }
548
+ clear() {
549
+ this.stack = [];
550
+ this.unit.finalize();
551
+ }
552
+ timeout(timeout, duration = 0) {
553
+ UnitTimer.execute(this, { timeout, duration, iterations: 1 });
554
+ return this;
555
+ }
556
+ iteration(timeout, duration = 0, iterations = -1) {
557
+ UnitTimer.execute(this, { timeout, duration, iterations });
558
+ return this;
559
+ }
560
+ transition(transition, duration = 0, easing) {
561
+ UnitTimer.execute(this, { transition, duration, iterations: 1, easing });
562
+ return this;
563
+ }
564
+ static execute(timer, options) {
565
+ if (timer.unit._.state === 'finalized') {
566
+ timer.unit = new Unit(Unit.currentUnit, null, UnitTimer.Component, { options, snapshot: Unit.snapshot(Unit.currentUnit) });
567
+ }
568
+ else if (timer.stack.length === 0) {
569
+ timer.stack.push({ options, snapshot: Unit.snapshot(Unit.currentUnit) });
570
+ timer.unit.on('finalize', () => UnitTimer.next(timer));
571
+ }
572
+ else {
573
+ timer.stack.push({ options, snapshot: Unit.snapshot(Unit.currentUnit) });
574
+ }
575
+ }
576
+ static next(timer) {
577
+ if (timer.stack.length > 0) {
578
+ timer.unit = new Unit(Unit.currentUnit, null, UnitTimer.Component, timer.stack.shift());
579
+ timer.unit.on('finalize', () => UnitTimer.next(timer));
580
+ }
581
+ }
582
+ static Component(unit, { options, snapshot }) {
583
+ let counter = 0;
584
+ const timer = new Timer({
585
+ transition: (p) => {
586
+ if (options.transition)
587
+ Unit.scope(snapshot, options.transition, p);
588
+ },
589
+ timeout: () => {
590
+ if (options.transition)
591
+ Unit.scope(snapshot, options.transition, 1.0);
592
+ if (options.timeout)
593
+ Unit.scope(snapshot, options.timeout);
594
+ if (options.iterations && counter >= options.iterations - 1) {
595
+ unit.finalize();
596
+ }
597
+ counter++;
598
+ }, duration: options.duration, iterations: options.iterations, easing: options.easing
599
+ });
600
+ unit.on('finalize', () => timer.clear());
601
+ }
602
+ }
522
603
  //----------------------------------------------------------------------------------------------------
523
604
  // unit
524
605
  //----------------------------------------------------------------------------------------------------
525
606
  class Unit {
526
- constructor(parent, target, component, props, config) {
527
- var _a, _b;
607
+ constructor(parent, target, component, props) {
608
+ var _a;
528
609
  let baseElement;
529
610
  if (target instanceof HTMLElement || target instanceof SVGElement) {
530
611
  baseElement = target;
@@ -539,15 +620,14 @@ class Unit {
539
620
  if (typeof component === 'function') {
540
621
  baseComponent = component;
541
622
  }
542
- else if (typeof component === 'string') {
543
- baseComponent = (unit) => { unit.element.textContent = component; };
623
+ else if (component !== undefined) {
624
+ baseComponent = (unit) => { unit.element.textContent = component.toString(); };
544
625
  }
545
626
  else {
546
627
  baseComponent = (unit) => { };
547
628
  }
548
629
  const baseContext = (_a = parent === null || parent === void 0 ? void 0 : parent._.currentContext) !== null && _a !== void 0 ? _a : { stack: null };
549
- const protect = (_b = config === null || config === void 0 ? void 0 : config.protect) !== null && _b !== void 0 ? _b : false;
550
- this._ = { parent, target, baseElement, baseContext, baseComponent, props, config: { protect } };
630
+ this._ = { parent, target, baseElement, baseContext, baseComponent, props };
551
631
  parent === null || parent === void 0 ? void 0 : parent._.children.push(this);
552
632
  Unit.initialize(this, null);
553
633
  }
@@ -576,7 +656,6 @@ class Unit {
576
656
  Unit.initialize(this, anchor);
577
657
  }
578
658
  static initialize(unit, anchor) {
579
- var _a, _b;
580
659
  const backup = Unit.currentUnit;
581
660
  Unit.currentUnit = unit;
582
661
  unit._ = Object.assign(unit._, {
@@ -586,15 +665,16 @@ class Unit {
586
665
  anchor,
587
666
  state: 'invoked',
588
667
  tostart: true,
589
- ancestors: [...(unit._.parent ? [unit._.parent] : []), ...((_b = (_a = unit._.parent) === null || _a === void 0 ? void 0 : _a._.ancestors) !== null && _b !== void 0 ? _b : [])],
668
+ protected: false,
669
+ ancestors: unit._.parent ? [unit._.parent, ...unit._.parent._.ancestors] : [],
590
670
  children: [],
591
671
  elements: [],
592
672
  promises: [],
593
- components: [],
673
+ extends: [],
594
674
  listeners: new MapMap(),
595
675
  defines: {},
596
676
  systems: { start: [], update: [], render: [], stop: [], finalize: [] },
597
- eventManager: new EventManager(),
677
+ eventor: new Eventor(),
598
678
  });
599
679
  // nest html element
600
680
  if (typeof unit._.target === 'string') {
@@ -612,26 +692,21 @@ class Unit {
612
692
  unit._.children.forEach((child) => child.finalize());
613
693
  unit._.systems.finalize.forEach(({ execute }) => execute());
614
694
  unit.off();
615
- unit._.components.forEach((component) => Unit.component2units.delete(component, unit));
695
+ unit._.extends.forEach(({ component }) => Unit.component2units.delete(component, unit));
616
696
  if (unit._.elements.length > 0) {
617
697
  unit._.baseElement.removeChild(unit._.elements[0]);
618
698
  unit._.currentElement = unit._.baseElement;
619
699
  }
620
700
  // reset defines
621
701
  Object.keys(unit._.defines).forEach((key) => {
622
- if (SYSTEM_EVENTS.includes(key) === false) {
623
- delete unit[key];
624
- }
702
+ delete unit[key];
625
703
  });
626
704
  unit._.defines = {};
627
705
  unit._.state = 'finalized';
628
706
  }
629
707
  }
630
- static nest(unit, htmlString, textContent) {
631
- if (unit._.state !== 'invoked') {
632
- throw new Error('This function can not be called after initialized.');
633
- }
634
- const match = htmlString.match(/<((\w+)[^>]*?)\/?>/);
708
+ static nest(unit, tag, textContent) {
709
+ const match = tag.match(/<((\w+)[^>]*?)\/?>/);
635
710
  if (match !== null) {
636
711
  let element;
637
712
  if (unit._.anchor !== null) {
@@ -645,47 +720,53 @@ class Unit {
645
720
  }
646
721
  unit._.currentElement = element;
647
722
  if (textContent !== undefined) {
648
- element.textContent = textContent;
723
+ element.textContent = textContent.toString();
649
724
  }
650
725
  unit._.elements.push(element);
651
726
  return element;
652
727
  }
653
728
  else {
654
- throw new Error(`Invalid html string: ${htmlString}`);
729
+ throw new Error(`xnew.nest: invalid html string [${tag}]`);
655
730
  }
656
731
  }
657
732
  static extend(unit, component, props) {
658
733
  var _a;
659
- if (unit._.state !== 'invoked') {
660
- throw new Error('This function can not be called after initialized.');
661
- }
662
- unit._.components.push(component);
663
- Unit.component2units.add(component, unit);
664
- const backupComponent = unit._.currentComponent;
665
- unit._.currentComponent = component;
666
- const defines = (_a = component(unit, props)) !== null && _a !== void 0 ? _a : {};
667
- unit._.currentComponent = backupComponent;
668
- Object.keys(defines).forEach((key) => {
669
- if (unit[key] !== undefined && unit._.defines[key] === undefined) {
670
- throw new Error(`The property "${key}" already exists.`);
671
- }
672
- const descriptor = Object.getOwnPropertyDescriptor(defines, key);
673
- const wrapper = { configurable: true, enumerable: true };
674
- if (descriptor === null || descriptor === void 0 ? void 0 : descriptor.get)
675
- wrapper.get = Unit.wrap(unit, descriptor.get);
676
- if (descriptor === null || descriptor === void 0 ? void 0 : descriptor.set)
677
- wrapper.set = Unit.wrap(unit, descriptor.set);
678
- if (typeof (descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) === 'function') {
679
- wrapper.value = Unit.wrap(unit, descriptor.value);
680
- }
681
- else if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) !== undefined) {
682
- wrapper.writable = true;
683
- wrapper.value = descriptor.value;
684
- }
685
- Object.defineProperty(unit._.defines, key, wrapper);
686
- Object.defineProperty(unit, key, wrapper);
687
- });
688
- return Object.assign({}, unit._.defines);
734
+ const find = unit._.extends.find(({ component: c }) => c === component);
735
+ if (find !== undefined) {
736
+ throw new Error(`The component is already extended.`);
737
+ }
738
+ else {
739
+ const backupComponent = unit._.currentComponent;
740
+ unit._.currentComponent = component;
741
+ const defines = (_a = component(unit, props)) !== null && _a !== void 0 ? _a : {};
742
+ unit._.currentComponent = backupComponent;
743
+ Object.keys(defines).forEach((key) => {
744
+ if (unit[key] !== undefined && unit._.defines[key] === undefined) {
745
+ throw new Error(`The property "${key}" already exists.`);
746
+ }
747
+ const descriptor = Object.getOwnPropertyDescriptor(defines, key);
748
+ const wrapper = { configurable: true, enumerable: true };
749
+ const snapshot = Unit.snapshot(unit);
750
+ if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.get) || (descriptor === null || descriptor === void 0 ? void 0 : descriptor.set)) {
751
+ if (descriptor === null || descriptor === void 0 ? void 0 : descriptor.get)
752
+ wrapper.get = (...args) => Unit.scope(snapshot, descriptor.get, ...args);
753
+ if (descriptor === null || descriptor === void 0 ? void 0 : descriptor.set)
754
+ wrapper.set = (...args) => Unit.scope(snapshot, descriptor.set, ...args);
755
+ }
756
+ else if (typeof (descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) === 'function') {
757
+ wrapper.value = (...args) => Unit.scope(snapshot, descriptor.value, ...args);
758
+ }
759
+ else if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) !== undefined) {
760
+ wrapper.get = () => defines[key];
761
+ wrapper.set = (value) => defines[key] = value;
762
+ }
763
+ Object.defineProperty(unit._.defines, key, wrapper);
764
+ Object.defineProperty(unit, key, wrapper);
765
+ });
766
+ Unit.component2units.add(component, unit);
767
+ unit._.extends.push({ component, defines });
768
+ return defines;
769
+ }
689
770
  }
690
771
  static start(unit) {
691
772
  if (unit._.tostart === false)
@@ -729,10 +810,6 @@ class Unit {
729
810
  });
730
811
  Unit.rootUnit.on('finalize', () => ticker.clear());
731
812
  }
732
- static wrap(unit, listener) {
733
- const snapshot = Unit.snapshot(unit);
734
- return (...args) => Unit.scope(snapshot, listener, ...args);
735
- }
736
813
  static scope(snapshot, func, ...args) {
737
814
  if (snapshot.unit._.state === 'finalized') {
738
815
  return;
@@ -783,15 +860,16 @@ class Unit {
783
860
  types.forEach((type) => Unit.off(this, type, listener));
784
861
  }
785
862
  static on(unit, type, listener, options) {
863
+ const snapshot = Unit.snapshot(Unit.currentUnit);
864
+ const execute = (...args) => Unit.scope(snapshot, listener, ...args);
786
865
  if (SYSTEM_EVENTS.includes(type)) {
787
- unit._.systems[type].push({ listener, execute: Unit.wrap(Unit.currentUnit, listener) });
866
+ unit._.systems[type].push({ listener, execute });
788
867
  }
789
868
  if (unit._.listeners.has(type, listener) === false) {
790
- const execute = Unit.wrap(Unit.currentUnit, listener);
791
869
  unit._.listeners.set(type, listener, { element: unit.element, component: unit._.currentComponent, execute });
792
870
  Unit.type2units.add(type, unit);
793
871
  if (/^[A-Za-z]/.test(type)) {
794
- unit._.eventManager.add(unit.element, type, execute, options);
872
+ unit._.eventor.add(unit.element, type, execute, options);
795
873
  }
796
874
  }
797
875
  }
@@ -805,7 +883,7 @@ class Unit {
805
883
  return;
806
884
  unit._.listeners.delete(type, listener);
807
885
  if (/^[A-Za-z]/.test(type)) {
808
- unit._.eventManager.remove(type, item.execute);
886
+ unit._.eventor.remove(type, item.execute);
809
887
  }
810
888
  });
811
889
  if (unit._.listeners.has(type) === false) {
@@ -818,7 +896,7 @@ class Unit {
818
896
  if (type[0] === '+') {
819
897
  (_a = Unit.type2units.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((unit) => {
820
898
  var _a;
821
- const find = [unit, ...unit._.ancestors].find(u => u._.config.protect === true);
899
+ const find = [unit, ...unit._.ancestors].find(u => u._.protected === true);
822
900
  if (find === undefined || current._.ancestors.includes(find) === true || current === find) {
823
901
  (_a = unit._.listeners.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((item) => item.execute(...args));
824
902
  }
@@ -835,92 +913,10 @@ Unit.component2units = new MapSet();
835
913
  // event
836
914
  //----------------------------------------------------------------------------------------------------
837
915
  Unit.type2units = new MapSet();
838
- //----------------------------------------------------------------------------------------------------
839
- // unit promise
840
- //----------------------------------------------------------------------------------------------------
841
- class UnitPromise {
842
- constructor(promise, component) {
843
- this.promise = promise;
844
- this.component = component;
845
- }
846
- then(callback) {
847
- this.promise = this.promise.then(Unit.wrap(Unit.currentUnit, callback));
848
- return this;
849
- }
850
- catch(callback) {
851
- this.promise = this.promise.catch(Unit.wrap(Unit.currentUnit, callback));
852
- return this;
853
- }
854
- finally(callback) {
855
- this.promise = this.promise.finally(Unit.wrap(Unit.currentUnit, callback));
856
- return this;
857
- }
858
- }
859
- //----------------------------------------------------------------------------------------------------
860
- // unit timer
861
- //----------------------------------------------------------------------------------------------------
862
- class UnitTimer {
863
- constructor(options) {
864
- this.stack = [];
865
- this.unit = new Unit(Unit.currentUnit, null, UnitTimer.Component, Object.assign({ snapshot: Unit.snapshot(Unit.currentUnit) }, options));
866
- }
867
- clear() {
868
- this.stack = [];
869
- this.unit.finalize();
870
- }
871
- timeout(timeout, duration = 0) {
872
- UnitTimer.execute(this, { timeout, duration, iterations: 1 });
873
- return this;
874
- }
875
- iteration(timeout, duration = 0, iterations = -1) {
876
- UnitTimer.execute(this, { timeout, duration, iterations });
877
- return this;
878
- }
879
- transition(transition, duration = 0, easing) {
880
- UnitTimer.execute(this, { transition, duration, iterations: 1, easing });
881
- return this;
882
- }
883
- static execute(timer, options) {
884
- if (timer.unit._.state === 'finalized') {
885
- timer.unit = new Unit(Unit.currentUnit, null, UnitTimer.Component, Object.assign({ snapshot: Unit.snapshot(Unit.currentUnit) }, options));
886
- }
887
- else if (timer.stack.length === 0) {
888
- timer.stack.push(Object.assign({ snapshot: Unit.snapshot(Unit.currentUnit) }, options));
889
- timer.unit.on('finalize', () => { UnitTimer.next(timer); });
890
- }
891
- else {
892
- timer.stack.push(Object.assign({ snapshot: Unit.snapshot(Unit.currentUnit) }, options));
893
- }
894
- }
895
- static next(timer) {
896
- if (timer.stack.length > 0) {
897
- timer.unit = new Unit(Unit.currentUnit, null, UnitTimer.Component, timer.stack.shift());
898
- timer.unit.on('finalize', () => { UnitTimer.next(timer); });
899
- }
900
- }
901
- static Component(unit, options) {
902
- let counter = 0;
903
- const timer = new Timer({
904
- transition: (p) => {
905
- if (options.transition)
906
- Unit.scope(options.snapshot, options.transition, p);
907
- },
908
- timeout: () => {
909
- if (options.transition)
910
- Unit.scope(options.snapshot, options.transition, 1.0);
911
- if (options.timeout)
912
- Unit.scope(options.snapshot, options.timeout);
913
- if (options.iterations && counter >= options.iterations - 1) {
914
- unit.finalize();
915
- }
916
- counter++;
917
- }, duration: options.duration, iterations: options.iterations, easing: options.easing
918
- });
919
- unit.on('finalize', () => timer.clear());
920
- }
921
- }
922
916
 
923
- function parseArguments(...args) {
917
+ const xnew$1 = Object.assign(function (...args) {
918
+ if (Unit.rootUnit === undefined)
919
+ Unit.reset();
924
920
  let target;
925
921
  if (args[0] instanceof HTMLElement || args[0] instanceof SVGElement) {
926
922
  target = args.shift(); // an existing html element
@@ -933,29 +929,26 @@ function parseArguments(...args) {
933
929
  }
934
930
  const component = args.shift();
935
931
  const props = args.shift();
936
- return { target, component, props };
937
- }
938
- const xnew$1 = Object.assign(function (...args) {
939
- if (Unit.rootUnit === undefined)
940
- Unit.reset();
941
- const { target, component, props } = parseArguments(...args);
942
- return new Unit(Unit.currentUnit, target, component, props, { protect: false });
932
+ return new Unit(Unit.currentUnit, target, component, props);
943
933
  }, {
944
934
  /**
945
935
  * Creates a nested HTML/SVG element within the current component
946
- * @param htmlString - HTML or SVG tag name (e.g., '<div>', '<span>', '<svg>')
936
+ * @param tag - HTML or SVG tag name (e.g., '<div>', '<span>', '<svg>')
947
937
  * @returns The created HTML/SVG element
948
938
  * @throws Error if called after component initialization
949
939
  * @example
950
940
  * const div = xnew.nest('<div>')
951
941
  * div.textContent = 'Hello'
952
942
  */
953
- nest(htmlString, textContent) {
943
+ nest(tag, textContent) {
954
944
  try {
955
- return Unit.nest(Unit.currentUnit, htmlString, textContent);
945
+ if (Unit.currentUnit._.state !== 'invoked') {
946
+ throw new Error('xnew.nest can not be called after initialized.');
947
+ }
948
+ return Unit.nest(Unit.currentUnit, tag, textContent);
956
949
  }
957
950
  catch (error) {
958
- console.error('xnew.nest(htmlString: string): ', error);
951
+ console.error('xnew.nest(tag: string): ', error);
959
952
  throw error;
960
953
  }
961
954
  },
@@ -963,13 +956,16 @@ const xnew$1 = Object.assign(function (...args) {
963
956
  * Extends the current component with another component's functionality
964
957
  * @param component - Component function to extend with
965
958
  * @param props - Optional properties to pass to the extended component
966
- * @returns The extended component's return value
959
+ * @returns defines returned by the extended component
967
960
  * @throws Error if called after component initialization
968
961
  * @example
969
962
  * const api = xnew.extend(BaseComponent, { data: {} })
970
963
  */
971
964
  extend(component, props) {
972
965
  try {
966
+ if (Unit.currentUnit._.state !== 'invoked') {
967
+ throw new Error('xnew.extend can not be called after initialized.');
968
+ }
973
969
  return Unit.extend(Unit.currentUnit, component, props);
974
970
  }
975
971
  catch (error) {
@@ -1104,6 +1100,15 @@ const xnew$1 = Object.assign(function (...args) {
1104
1100
  throw error;
1105
1101
  }
1106
1102
  },
1103
+ /**
1104
+ * Emits a custom event to components
1105
+ * @param type - Event type to emit (prefix with '+' for global events, '-' for local events)
1106
+ * @param args - Additional arguments to pass to event listeners
1107
+ * @returns void
1108
+ * @example
1109
+ * xnew.emit('+globalevent', { data: 123 }); // Global event
1110
+ * xnew.emit('-localevent', { data: 123 }); // Local event
1111
+ */
1107
1112
  emit(type, ...args) {
1108
1113
  try {
1109
1114
  return Unit.emit(type, ...args);
@@ -1153,100 +1158,111 @@ const xnew$1 = Object.assign(function (...args) {
1153
1158
  transition(transition, duration = 0, easing = 'linear') {
1154
1159
  return new UnitTimer({ transition, duration, easing, iterations: 1 });
1155
1160
  },
1156
- protect(...args) {
1157
- if (Unit.rootUnit === undefined)
1158
- Unit.reset();
1159
- const { target, component, props } = parseArguments(...args);
1160
- return new Unit(Unit.currentUnit, target, component, props, { protect: true });
1161
+ /**
1162
+ * Call this method within a component function to enable protection.
1163
+ * Protected components will not respond to global events emitted via xnew.emit,
1164
+ * and will be excluded from xnew.find searches.
1165
+ * @example
1166
+ * function MyComponent(unit) {
1167
+ * xnew.protect();
1168
+ * // Component logic here
1169
+ * }
1170
+ */
1171
+ protect() {
1172
+ Unit.currentUnit._.protected = true;
1161
1173
  },
1162
1174
  });
1163
1175
 
1164
- function Accordion(unit, { open = false, duration = 200, easing = 'ease' } = {}) {
1165
- xnew$1.context('xnew.accordion', unit);
1166
- unit.on('-transition', ({ state }) => unit.state = state);
1167
- xnew$1.timeout(() => xnew$1.emit('-transition', { state: open ? 1.0 : 0.0 }));
1176
+ function OpenAndClose(unit, { state: initialState = 0.0 } = {}) {
1177
+ let state = Math.max(0.0, Math.min(1.0, initialState));
1178
+ let direction = state === 1.0 ? +1 : (state === 0.0 ? -1 : null);
1179
+ let timer = xnew$1.timeout(() => xnew$1.emit('-transition', { state }));
1168
1180
  return {
1169
- state: open ? 1.0 : 0.0,
1170
- toggle() {
1171
- if (unit.state === 1.0) {
1172
- unit.close();
1181
+ toggle(duration = 200, easing = 'ease') {
1182
+ if (direction === null || direction < 0) {
1183
+ unit.open(duration, easing);
1173
1184
  }
1174
- else if (unit.state === 0.0) {
1175
- unit.open();
1185
+ else {
1186
+ unit.close(duration, easing);
1176
1187
  }
1177
1188
  },
1178
- open() {
1179
- if (unit.state === 0.0) {
1180
- xnew$1.transition((x) => xnew$1.emit('-transition', { state: x }), duration, easing);
1189
+ open(duration = 200, easing = 'ease') {
1190
+ if (direction === null || direction < 0) {
1191
+ direction = +1;
1192
+ const d = 1 - state;
1193
+ timer === null || timer === void 0 ? void 0 : timer.clear();
1194
+ timer = xnew$1.transition((x) => {
1195
+ const y = x < 1.0 ? (1 - x) * d : 0.0;
1196
+ state = 1.0 - y;
1197
+ xnew$1.emit('-transition', { state, type: '-transition' });
1198
+ }, duration * d, easing)
1199
+ .timeout(() => {
1200
+ xnew$1.emit('-opened', { state, type: '-opened' });
1201
+ });
1181
1202
  }
1182
1203
  },
1183
- close() {
1184
- if (unit.state === 1.0) {
1185
- xnew$1.transition((x) => xnew$1.emit('-transition', { state: 1.0 - x }), duration, easing);
1204
+ close(duration = 200, easing = 'ease') {
1205
+ if (direction === null || direction > 0) {
1206
+ direction = -1;
1207
+ const d = state;
1208
+ timer === null || timer === void 0 ? void 0 : timer.clear();
1209
+ timer = xnew$1.transition((x) => {
1210
+ const y = x < 1.0 ? (1 - x) * d : 0.0;
1211
+ state = y;
1212
+ xnew$1.emit('-transition', { state, type: '-transition' });
1213
+ }, duration * d, easing)
1214
+ .timeout(() => {
1215
+ xnew$1.emit('-closed', { state, type: '-closed' });
1216
+ });
1186
1217
  }
1187
- }
1218
+ },
1188
1219
  };
1189
1220
  }
1190
1221
 
1191
- function Screen(unit, { width = 640, height = 480, fit = 'contain' } = {}) {
1192
- const size = { width, height };
1193
- const wrapper = xnew$1.nest('<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">');
1194
- unit.on('resize', resize);
1222
+ function Screen(unit, { width, height, fit = 'contain' } = {}) {
1223
+ const size = { width: width !== null && width !== void 0 ? width : 800, height: height !== null && height !== void 0 ? height : 600 };
1224
+ const outer = xnew$1.nest('<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">');
1225
+ xnew$1().on('resize', resize);
1195
1226
  const absolute = xnew$1.nest('<div style="position: absolute; margin: auto; container-type: size; overflow: hidden;">');
1196
- const canvas = xnew$1(`<canvas width="${width}" height="${height}" style="width: 100%; height: 100%; vertical-align: bottom; user-select: none; user-drag: none; pointer-events: auto;">`);
1227
+ const canvas = xnew$1(`<canvas width="${size.width}" height="${size.height}" style="width: 100%; height: 100%; vertical-align: bottom; user-select: none; user-drag: none; pointer-events: auto;">`);
1197
1228
  resize();
1198
1229
  function resize() {
1199
- const aspect = size.width / size.height;
1200
1230
  const style = { width: '100%', height: '100%', top: 0, left: 0, bottom: 0, right: 0 };
1201
1231
  if (fit === 'contain') {
1202
- if (wrapper.clientWidth < wrapper.clientHeight * aspect) {
1203
- style.height = Math.floor(wrapper.clientWidth / aspect) + 'px';
1232
+ const aspect = size.width / size.height;
1233
+ if (outer.clientWidth < outer.clientHeight * aspect) {
1234
+ style.height = Math.floor(outer.clientWidth / aspect) + 'px';
1204
1235
  }
1205
1236
  else {
1206
- style.width = Math.floor(wrapper.clientHeight * aspect) + 'px';
1237
+ style.width = Math.floor(outer.clientHeight * aspect) + 'px';
1207
1238
  }
1208
1239
  }
1209
1240
  else if (fit === 'cover') {
1210
- if (wrapper.clientWidth < wrapper.clientHeight * aspect) {
1211
- style.width = Math.floor(wrapper.clientHeight * aspect) + 'px';
1212
- style.left = Math.floor((wrapper.clientWidth - wrapper.clientHeight * aspect) / 2) + 'px';
1241
+ const aspect = size.width / size.height;
1242
+ if (outer.clientWidth < outer.clientHeight * aspect) {
1243
+ style.width = Math.floor(outer.clientHeight * aspect) + 'px';
1244
+ style.left = Math.floor((outer.clientWidth - outer.clientHeight * aspect) / 2) + 'px';
1213
1245
  style.right = 'auto';
1214
1246
  }
1215
1247
  else {
1216
- style.height = Math.floor(wrapper.clientWidth / aspect) + 'px';
1217
- style.top = Math.floor((wrapper.clientHeight - wrapper.clientWidth / aspect) / 2) + 'px';
1248
+ style.height = Math.floor(outer.clientWidth / aspect) + 'px';
1249
+ style.top = Math.floor((outer.clientHeight - outer.clientWidth / aspect) / 2) + 'px';
1218
1250
  style.bottom = 'auto';
1219
1251
  }
1220
1252
  }
1221
- else ;
1253
+ else if (fit === 'resize') {
1254
+ size.width = outer.clientWidth > 0 ? outer.clientWidth : size.width;
1255
+ size.height = outer.clientHeight > 0 ? outer.clientHeight : size.height;
1256
+ console.log(size);
1257
+ canvas.element.setAttribute('width', size.width + 'px');
1258
+ canvas.element.setAttribute('height', size.height + 'px');
1259
+ }
1222
1260
  Object.assign(absolute.style, style);
1223
1261
  }
1224
1262
  return {
1225
1263
  get canvas() {
1226
1264
  return canvas.element;
1227
1265
  },
1228
- resize(width, height) {
1229
- size.width = width;
1230
- size.height = height;
1231
- canvas.element.setAttribute('width', width + 'px');
1232
- canvas.element.setAttribute('height', height + 'px');
1233
- resize();
1234
- },
1235
- };
1236
- }
1237
-
1238
- function Modal(unit, { duration = 200, easing = 'ease' } = {}) {
1239
- xnew$1.context('xnew.modalframe', unit);
1240
- xnew$1.nest('<div style="position: fixed; inset: 0; z-index: 1000;">');
1241
- unit.on('click', ({ event }) => unit.close());
1242
- unit.on('-transition', ({ state }) => unit.state = state);
1243
- xnew$1.transition((x) => xnew$1.emit('-transition', { state: x }), duration, easing);
1244
- return {
1245
- state: 0.0,
1246
- close() {
1247
- xnew$1.transition((x) => xnew$1.emit('-transition', { state: 1.0 - x }), duration, easing)
1248
- .timeout(() => unit.finalize());
1249
- }
1250
1266
  };
1251
1267
  }
1252
1268
 
@@ -1301,7 +1317,7 @@ function AnalogStick(unit, { stroke = 'currentColor', strokeOpacity = 0.8, strok
1301
1317
  xnew$1.emit('-up', { type: '-up', vector });
1302
1318
  });
1303
1319
  }
1304
- function DirectionalPad(unit, { diagonal = true, stroke = 'currentColor', strokeOpacity = 0.8, strokeWidth = 2, strokeLinejoin = 'round', fill = '#FFF', fillOpacity = 0.8 } = {}) {
1320
+ function DPad(unit, { diagonal = true, stroke = 'currentColor', strokeOpacity = 0.8, strokeWidth = 2, strokeLinejoin = 'round', fill = '#FFF', fillOpacity = 0.8 } = {}) {
1305
1321
  const outer = xnew$1.nest(`<div style="position: relative; width: 100%; height: 100%;">`);
1306
1322
  let newsize = Math.min(outer.clientWidth, outer.clientHeight);
1307
1323
  const inner = xnew$1.nest(`<div style="position: absolute; width: ${newsize}px; height: ${newsize}px; margin: auto; inset: 0; cursor: pointer; pointer-select: none; pointer-events: auto; overflow: hidden;">`);
@@ -1594,10 +1610,9 @@ class Synthesizer {
1594
1610
 
1595
1611
  const basics = {
1596
1612
  Screen,
1597
- Modal,
1598
- Accordion,
1613
+ OpenAndClose,
1599
1614
  AnalogStick,
1600
- DirectionalPad,
1615
+ DPad,
1601
1616
  };
1602
1617
  const audio = {
1603
1618
  load(path) {