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