@mulsense/xnew 0.1.9 → 0.1.11

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
@@ -1,99 +1,3 @@
1
- //----------------------------------------------------------------------------------------------------
2
- // ticker
3
- //----------------------------------------------------------------------------------------------------
4
- class Ticker {
5
- constructor(callback) {
6
- const self = this;
7
- this.id = null;
8
- let previous = 0;
9
- ticker();
10
- function ticker() {
11
- const time = Date.now();
12
- const interval = 1000 / 60;
13
- if (time - previous > interval * 0.9) {
14
- callback(time);
15
- previous = time;
16
- }
17
- self.id = requestAnimationFrame(ticker);
18
- }
19
- }
20
- clear() {
21
- if (this.id !== null) {
22
- cancelAnimationFrame(this.id);
23
- this.id = null;
24
- }
25
- }
26
- }
27
- //----------------------------------------------------------------------------------------------------
28
- // timer
29
- //----------------------------------------------------------------------------------------------------
30
- class Timer {
31
- constructor(timeout, transition, delay, loop = false) {
32
- var _a;
33
- this.timeout = timeout;
34
- this.transition = transition;
35
- this.delay = delay;
36
- this.loop = loop;
37
- this.id = null;
38
- this.time = 0.0;
39
- this.offset = 0.0;
40
- this.status = 0;
41
- this.ticker = new Ticker((time) => { var _a; return (_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, this.elapsed() / this.delay); });
42
- this.visibilitychange = () => document.hidden === false ? this._start() : this._stop();
43
- document.addEventListener('visibilitychange', this.visibilitychange);
44
- if (this.delay > 0.0) {
45
- (_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, 0.0);
46
- }
47
- this.start();
48
- }
49
- clear() {
50
- if (this.id !== null) {
51
- clearTimeout(this.id);
52
- this.id = null;
53
- }
54
- document.removeEventListener('visibilitychange', this.visibilitychange);
55
- this.ticker.clear();
56
- }
57
- elapsed() {
58
- return this.offset + (this.id !== null ? (Date.now() - this.time) : 0);
59
- }
60
- start() {
61
- this.status = 1;
62
- this._start();
63
- }
64
- stop() {
65
- this._stop();
66
- this.status = 0;
67
- }
68
- _start() {
69
- if (this.status === 1 && this.id === null) {
70
- this.id = setTimeout(() => {
71
- var _a;
72
- this.timeout();
73
- (_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, 1.0);
74
- this.id = null;
75
- this.time = 0.0;
76
- this.offset = 0.0;
77
- if (this.loop) {
78
- this.start();
79
- }
80
- else {
81
- this.clear();
82
- }
83
- }, this.delay - this.offset);
84
- this.time = Date.now();
85
- }
86
- }
87
- _stop() {
88
- if (this.status === 1 && this.id !== null) {
89
- this.offset = this.offset + Date.now() - this.time;
90
- clearTimeout(this.id);
91
- this.id = null;
92
- this.time = 0.0;
93
- }
94
- }
95
- }
96
-
97
1
  //----------------------------------------------------------------------------------------------------
98
2
  // map set
99
3
  //----------------------------------------------------------------------------------------------------
@@ -192,24 +96,117 @@ class MapMap extends Map {
192
96
  }
193
97
 
194
98
  //----------------------------------------------------------------------------------------------------
195
- // utils
99
+ // ticker
196
100
  //----------------------------------------------------------------------------------------------------
197
- const SYSTEM_EVENTS = ['start', 'update', 'stop', 'finalize'];
198
- class UnitPromise {
199
- constructor(promise) { this.promise = promise; }
200
- then(callback) {
201
- this.promise = this.promise.then(Unit.wrap(Unit.current, callback));
202
- return this;
101
+ class Ticker {
102
+ constructor(callback) {
103
+ const self = this;
104
+ this.id = null;
105
+ let previous = 0;
106
+ ticker();
107
+ function ticker() {
108
+ const time = Date.now();
109
+ const fps = 60;
110
+ if (time - previous > (1000 / fps) * 0.9) {
111
+ callback(time);
112
+ previous = time;
113
+ }
114
+ self.id = requestAnimationFrame(ticker);
115
+ }
203
116
  }
204
- catch(callback) {
205
- this.promise = this.promise.catch(Unit.wrap(Unit.current, callback));
206
- return this;
117
+ clear() {
118
+ if (this.id !== null) {
119
+ cancelAnimationFrame(this.id);
120
+ this.id = null;
121
+ }
207
122
  }
208
- finally(callback) {
209
- this.promise = this.promise.finally(Unit.wrap(Unit.current, callback));
210
- return this;
123
+ }
124
+ //----------------------------------------------------------------------------------------------------
125
+ // timer
126
+ //----------------------------------------------------------------------------------------------------
127
+ class Timer {
128
+ constructor(transition, timeout, duration, { loop = false, easing = 'linear' } = {}) {
129
+ var _a;
130
+ this.transition = transition;
131
+ this.timeout = timeout;
132
+ this.duration = duration !== null && duration !== void 0 ? duration : 0;
133
+ this.loop = loop;
134
+ this.easing = easing;
135
+ this.id = null;
136
+ this.time = 0.0;
137
+ this.offset = 0.0;
138
+ this.status = 0;
139
+ this.ticker = new Ticker((time) => {
140
+ var _a;
141
+ let p = Math.min(this.elapsed() / this.duration, 1.0);
142
+ if (easing === 'ease-out') {
143
+ p = Math.pow((1.0 - Math.pow((1.0 - p), 2.0)), 0.5);
144
+ }
145
+ else if (easing === 'ease-in') {
146
+ p = Math.pow((1.0 - Math.pow((1.0 - p), 0.5)), 2.0);
147
+ }
148
+ else if (easing === 'ease') {
149
+ p = (1.0 - Math.cos(p * Math.PI)) / 2.0;
150
+ }
151
+ else if (easing === 'ease-in-out') {
152
+ p = (1.0 - Math.cos(p * Math.PI)) / 2.0;
153
+ }
154
+ (_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, p);
155
+ });
156
+ this.visibilitychange = () => document.hidden === false ? this._start() : this._stop();
157
+ document.addEventListener('visibilitychange', this.visibilitychange);
158
+ if (this.duration > 0.0) {
159
+ (_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, 0.0);
160
+ }
161
+ this.start();
162
+ }
163
+ clear() {
164
+ if (this.id !== null) {
165
+ clearTimeout(this.id);
166
+ this.id = null;
167
+ }
168
+ document.removeEventListener('visibilitychange', this.visibilitychange);
169
+ this.ticker.clear();
170
+ }
171
+ elapsed() {
172
+ return this.offset + (this.id !== null ? (Date.now() - this.time) : 0);
173
+ }
174
+ start() {
175
+ this.status = 1;
176
+ this._start();
177
+ }
178
+ stop() {
179
+ this._stop();
180
+ this.status = 0;
181
+ }
182
+ _start() {
183
+ if (this.status === 1 && this.id === null) {
184
+ this.id = setTimeout(() => {
185
+ var _a, _b;
186
+ (_a = this.timeout) === null || _a === void 0 ? void 0 : _a.call(this);
187
+ (_b = this.transition) === null || _b === void 0 ? void 0 : _b.call(this, 1.0);
188
+ this.id = null;
189
+ this.time = 0.0;
190
+ this.offset = 0.0;
191
+ this.loop ? this.start() : this.clear();
192
+ }, this.duration - this.offset);
193
+ this.time = Date.now();
194
+ }
195
+ }
196
+ _stop() {
197
+ if (this.status === 1 && this.id !== null) {
198
+ this.offset = this.offset + Date.now() - this.time;
199
+ clearTimeout(this.id);
200
+ this.id = null;
201
+ this.time = 0.0;
202
+ }
211
203
  }
212
204
  }
205
+
206
+ //----------------------------------------------------------------------------------------------------
207
+ // utils
208
+ //----------------------------------------------------------------------------------------------------
209
+ const SYSTEM_EVENTS = ['start', 'update', 'stop', 'finalize'];
213
210
  //----------------------------------------------------------------------------------------------------
214
211
  // unit
215
212
  //----------------------------------------------------------------------------------------------------
@@ -301,7 +298,6 @@ class Unit {
301
298
  children: [],
302
299
  elements: [],
303
300
  promises: [],
304
- captures: [],
305
301
  components: [],
306
302
  listeners1: new MapMap(),
307
303
  listeners2: new MapMap(),
@@ -316,11 +312,6 @@ class Unit {
316
312
  Unit.extend(unit, unit._.baseComponent, unit._.props);
317
313
  // whether the unit promise was resolved
318
314
  Promise.all(unit._.promises).then(() => unit._.state = 'initialized');
319
- // setup capture
320
- for (let current = unit; current !== null; current = current._.parent) {
321
- if (current._.captures.find((capture) => capture(unit)) !== undefined)
322
- break;
323
- }
324
315
  Unit.current = backup;
325
316
  }
326
317
  static finalize(unit) {
@@ -468,15 +459,13 @@ class Unit {
468
459
  return [...((_a = Unit.component2units.get(component)) !== null && _a !== void 0 ? _a : [])];
469
460
  }
470
461
  on(type, listener, options) {
471
- if (this._.state === 'finalized')
472
- return;
473
462
  type.trim().split(/\s+/).forEach((type) => {
474
463
  if (SYSTEM_EVENTS.includes(type)) {
475
464
  this._.systems[type].push(listener);
476
465
  }
477
466
  if (this._.listeners1.has(type, listener) === false) {
478
467
  const execute = Unit.wrap(Unit.current, listener);
479
- this._.listeners1.set(type, listener, [this.element, execute]);
468
+ this._.listeners1.set(type, listener, { element: this.element, execute });
480
469
  Unit.type2units.add(type, this);
481
470
  if (/^[A-Za-z]/.test(type)) {
482
471
  this.element.addEventListener(type, execute, options);
@@ -490,13 +479,12 @@ class Unit {
490
479
  if (SYSTEM_EVENTS.includes(type)) {
491
480
  this._.systems[type] = this._.systems[type].filter((lis) => listener ? lis !== listener : false);
492
481
  }
493
- (listener ? [listener] : [...this._.listeners1.keys(type)]).forEach((lis) => {
494
- const tuple = this._.listeners1.get(type, lis);
495
- if (tuple !== undefined) {
496
- const [target, execute] = tuple;
497
- this._.listeners1.delete(type, lis);
482
+ (listener ? [listener] : [...this._.listeners1.keys(type)]).forEach((listener) => {
483
+ const item = this._.listeners1.get(type, listener);
484
+ if (item !== undefined) {
485
+ this._.listeners1.delete(type, listener);
498
486
  if (/^[A-Za-z]/.test(type)) {
499
- target.removeEventListener(type, execute);
487
+ item.element.removeEventListener(type, item.execute);
500
488
  }
501
489
  }
502
490
  });
@@ -507,23 +495,21 @@ class Unit {
507
495
  }
508
496
  emit(type, ...args) {
509
497
  var _a, _b;
510
- if (this._.state === 'finalized')
511
- return;
512
498
  if (type[0] === '+') {
513
499
  (_a = Unit.type2units.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((unit) => {
514
500
  var _a;
515
- (_a = unit._.listeners1.get(type)) === null || _a === void 0 ? void 0 : _a.forEach(([_, execute]) => execute(...args));
501
+ (_a = unit._.listeners1.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((item) => item.execute(...args));
516
502
  });
517
503
  }
518
504
  else if (type[0] === '-') {
519
- (_b = this._.listeners1.get(type)) === null || _b === void 0 ? void 0 : _b.forEach(([_, execute]) => execute(...args));
505
+ (_b = this._.listeners1.get(type)) === null || _b === void 0 ? void 0 : _b.forEach((item) => item.execute(...args));
520
506
  }
521
507
  }
522
508
  static subon(unit, target, type, listener, options) {
523
509
  type.trim().split(/\s+/).forEach((type) => {
524
510
  if (unit._.listeners2.has(type, listener) === false) {
525
511
  const execute = Unit.wrap(unit, listener);
526
- unit._.listeners2.set(type, listener, [target, execute]);
512
+ unit._.listeners2.set(type, listener, { element: target, execute });
527
513
  target.addEventListener(type, execute, options);
528
514
  }
529
515
  });
@@ -531,14 +517,11 @@ class Unit {
531
517
  static suboff(unit, target, type, listener) {
532
518
  const types = typeof type === 'string' ? type.trim().split(/\s+/) : [...unit._.listeners2.keys()];
533
519
  types.forEach((type) => {
534
- (listener ? [listener] : [...unit._.listeners2.keys(type)]).forEach((lis) => {
535
- const tuple = unit._.listeners2.get(type, lis);
536
- if (tuple !== undefined) {
537
- const [element, execute] = tuple;
538
- if (target === null || target === element) {
539
- unit._.listeners2.delete(type, lis);
540
- element.removeEventListener(type, execute);
541
- }
520
+ (listener ? [listener] : [...unit._.listeners2.keys(type)]).forEach((listener) => {
521
+ const item = unit._.listeners2.get(type, listener);
522
+ if (item !== undefined && (target === null || target === item.element)) {
523
+ unit._.listeners2.delete(type, listener);
524
+ item.element.removeEventListener(type, item.execute);
542
525
  }
543
526
  });
544
527
  });
@@ -549,6 +532,78 @@ Unit.component2units = new MapSet();
549
532
  // event
550
533
  //----------------------------------------------------------------------------------------------------
551
534
  Unit.type2units = new MapSet();
535
+ //----------------------------------------------------------------------------------------------------
536
+ // unit promise
537
+ //----------------------------------------------------------------------------------------------------
538
+ class UnitPromise {
539
+ constructor(promise) { this.promise = promise; }
540
+ then(callback) {
541
+ this.promise = this.promise.then(Unit.wrap(Unit.current, callback));
542
+ return this;
543
+ }
544
+ catch(callback) {
545
+ this.promise = this.promise.catch(Unit.wrap(Unit.current, callback));
546
+ return this;
547
+ }
548
+ finally(callback) {
549
+ this.promise = this.promise.finally(Unit.wrap(Unit.current, callback));
550
+ return this;
551
+ }
552
+ }
553
+ //----------------------------------------------------------------------------------------------------
554
+ // unit timer
555
+ //----------------------------------------------------------------------------------------------------
556
+ class UnitTimer {
557
+ constructor({ transition, timeout, duration, easing, loop }) {
558
+ this.stack = [];
559
+ this.unit = new Unit(Unit.current, UnitTimer.Component, { snapshot: Unit.snapshot(Unit.current), transition, timeout, duration, easing, loop });
560
+ }
561
+ clear() {
562
+ this.stack = [];
563
+ this.unit.finalize();
564
+ }
565
+ timeout(timeout, duration = 0) {
566
+ UnitTimer.execute(this, { timeout, duration });
567
+ return this;
568
+ }
569
+ transition(transition, duration = 0, easing = 'linear') {
570
+ UnitTimer.execute(this, { transition, duration, easing });
571
+ return this;
572
+ }
573
+ static execute(timer, { transition, timeout, duration, easing, loop }) {
574
+ if (timer.unit._.state === 'finalized') {
575
+ timer.unit = new Unit(Unit.current, UnitTimer.Component, { snapshot: Unit.snapshot(Unit.current), transition, timeout, duration, easing, loop });
576
+ }
577
+ else if (timer.stack.length === 0) {
578
+ timer.stack.push({ snapshot: Unit.snapshot(Unit.current), transition, timeout, duration, easing, loop });
579
+ timer.unit.on('finalize', () => { UnitTimer.next(timer); });
580
+ }
581
+ else {
582
+ timer.stack.push({ snapshot: Unit.snapshot(Unit.current), transition, timeout, duration, easing, loop });
583
+ }
584
+ }
585
+ static next(timer) {
586
+ if (timer.stack.length > 0) {
587
+ timer.unit = new Unit(Unit.current, UnitTimer.Component, timer.stack.shift());
588
+ timer.unit.on('finalize', () => { UnitTimer.next(timer); });
589
+ }
590
+ }
591
+ static Component(unit, { snapshot, transition, timeout, duration, loop, easing }) {
592
+ const timer = new Timer((x) => {
593
+ if (transition !== undefined)
594
+ Unit.scope(snapshot, transition, x);
595
+ }, () => {
596
+ if (transition !== undefined)
597
+ Unit.scope(snapshot, transition, 1.0);
598
+ if (timeout !== undefined)
599
+ Unit.scope(snapshot, timeout);
600
+ if (loop === false) {
601
+ unit.finalize();
602
+ }
603
+ }, duration, { loop, easing });
604
+ unit.on('finalize', () => timer.clear());
605
+ }
606
+ }
552
607
 
553
608
  const xnew$1 = Object.assign(function (...args) {
554
609
  if (Unit.root === undefined) {
@@ -729,105 +784,43 @@ const xnew$1 = Object.assign(function (...args) {
729
784
  },
730
785
  /**
731
786
  * Executes a callback once after a delay, managed by component lifecycle
732
- * @param callback - Function to execute after delay
733
- * @param delay - Delay in milliseconds
787
+ * @param timeout - Function to execute after Duration
788
+ * @param duration - Duration in milliseconds
734
789
  * @returns Object with clear() method to cancel the timeout
735
790
  * @example
736
791
  * const timer = xnew.timeout(() => console.log('Delayed'), 1000)
737
792
  * // Cancel if needed: timer.clear()
738
793
  */
739
- timeout(callback, delay = 0) {
740
- const snapshot = Unit.snapshot(Unit.current);
741
- const unit = xnew$1((self) => {
742
- const timer = new Timer(() => {
743
- Unit.scope(snapshot, callback);
744
- self.finalize();
745
- }, null, delay, false);
746
- self.on('finalize', () => timer.clear());
747
- });
748
- return { clear: () => unit.finalize() };
794
+ timeout(timeout, duration = 0) {
795
+ return new UnitTimer({ timeout, duration });
749
796
  },
750
797
  /**
751
798
  * Executes a callback repeatedly at specified intervals, managed by component lifecycle
752
- * @param callback - Function to execute at each interval
753
- * @param delay - Interval duration in milliseconds
799
+ * @param timeout - Function to execute at each duration
800
+ * @param duration - Duration in milliseconds
754
801
  * @returns Object with clear() method to stop the interval
755
802
  * @example
756
803
  * const timer = xnew.interval(() => console.log('Tick'), 1000)
757
804
  * // Stop when needed: timer.clear()
758
805
  */
759
- interval(callback, delay) {
760
- const snapshot = Unit.snapshot(Unit.current);
761
- const unit = xnew$1((self) => {
762
- const timer = new Timer(() => {
763
- Unit.scope(snapshot, callback);
764
- }, null, delay, true);
765
- self.on('finalize', () => timer.clear());
766
- });
767
- return { clear: () => unit.finalize() };
806
+ interval(timeout, duration) {
807
+ return new UnitTimer({ timeout, duration, loop: true });
768
808
  },
769
809
  /**
770
810
  * Creates a transition animation with easing, executing callback with progress values
771
811
  * @param callback - Function called with progress value (0.0 to 1.0)
772
- * @param interval - Duration of transition in milliseconds
812
+ * @param duration - Duration of transition in milliseconds
773
813
  * @param easing - Easing function: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out' (default: 'linear')
774
814
  * @returns Object with clear() and next() methods for controlling transitions
775
815
  * @example
776
- * xnew.transition(progress => {
777
- * element.style.opacity = progress
778
- * }, 500, 'ease-out').next(progress => {
779
- * element.style.transform = `scale(${progress})`
816
+ * xnew.transition(p => {
817
+ * element.style.opacity = p
818
+ * }, 500, 'ease-out').transition(p => {
819
+ * element.style.transform = `scale(${p})`
780
820
  * }, 300)
781
821
  */
782
- transition(callback, interval, easing = 'linear') {
783
- const snapshot = Unit.snapshot(Unit.current);
784
- let stacks = [];
785
- let unit = xnew$1(Local, { callback, interval, easing });
786
- let isRunning = true;
787
- const timer = { clear, next };
788
- return timer;
789
- function execute() {
790
- if (isRunning === false && stacks.length > 0) {
791
- unit = xnew$1(Local, stacks.shift());
792
- isRunning = true;
793
- }
794
- }
795
- function clear() {
796
- stacks = [];
797
- unit.finalize();
798
- }
799
- function next(callback, interval = 0, easing = 'linear') {
800
- stacks.push({ callback, interval, easing });
801
- execute();
802
- return timer;
803
- }
804
- function Local(self, { callback, interval, easing }) {
805
- const timer = new Timer(() => {
806
- Unit.scope(snapshot, callback, 1.0);
807
- self.finalize();
808
- }, (x) => {
809
- if (x < 1.0) {
810
- if (easing === 'ease-out') {
811
- x = Math.pow((1.0 - Math.pow((1.0 - x), 2.0)), 0.5);
812
- }
813
- else if (easing === 'ease-in') {
814
- x = Math.pow((1.0 - Math.pow((1.0 - x), 0.5)), 2.0);
815
- }
816
- else if (easing === 'ease') {
817
- x = (1.0 - Math.cos(x * Math.PI)) / 2.0;
818
- }
819
- else if (easing === 'ease-in-out') {
820
- x = (1.0 - Math.cos(x * Math.PI)) / 2.0;
821
- }
822
- Unit.scope(snapshot, callback, x);
823
- }
824
- }, interval);
825
- self.on('finalize', () => {
826
- timer.clear();
827
- isRunning = false;
828
- execute();
829
- });
830
- }
822
+ transition(transition, duration = 0, easing = 'linear') {
823
+ return new UnitTimer({ transition, duration, easing });
831
824
  },
832
825
  /**
833
826
  * Creates an event listener manager for a target element with automatic cleanup
@@ -848,20 +841,86 @@ const xnew$1 = Object.assign(function (...args) {
848
841
  }
849
842
  };
850
843
  },
851
- /**
852
- * Registers a capture function that can intercept and handle child component events
853
- * @param execute - Function that receives child unit and returns boolean (true to stop propagation)
854
- * @example
855
- * xnew.capture((childUnit) => {
856
- * console.log('Child component created:', childUnit)
857
- * return false // Continue propagation
858
- * })
859
- */
860
- capture(execute) {
861
- Unit.current._.captures.push(Unit.wrap(Unit.current, (unit) => execute(unit)));
862
- },
863
844
  });
864
845
 
846
+ function AccordionFrame(frame, { open = false, duration = 200, easing = 'ease' } = {}) {
847
+ const internal = xnew$1((internal) => {
848
+ return { frame, open, rate: 0.0, };
849
+ });
850
+ xnew$1.context('xnew.accordionframe', internal);
851
+ internal.on('-transition', ({ rate }) => internal.rate = rate);
852
+ internal.emit('-transition', { rate: open ? 1.0 : 0.0 });
853
+ return {
854
+ toggle() {
855
+ if (internal.rate === 1.0) {
856
+ frame.close();
857
+ }
858
+ else if (internal.rate === 0.0) {
859
+ frame.open();
860
+ }
861
+ },
862
+ open() {
863
+ if (internal.rate === 0.0) {
864
+ xnew$1.transition((x) => internal.emit('-transition', { rate: x }), duration, easing);
865
+ }
866
+ },
867
+ close() {
868
+ if (internal.rate === 1.0) {
869
+ xnew$1.transition((x) => internal.emit('-transition', { rate: 1.0 - x }), duration, easing);
870
+ }
871
+ }
872
+ };
873
+ }
874
+ function AccordionHeader(header, {} = {}) {
875
+ const internal = xnew$1.context('xnew.accordionframe');
876
+ xnew$1.nest('<button style="display: flex; align-items: center; margin: 0; padding: 0; width: 100%; text-align: left; border: none; font: inherit; color: inherit; background: none; cursor: pointer;">');
877
+ header.on('click', () => internal.frame.toggle());
878
+ }
879
+ function AccordionBullet(bullet, { type = 'arrow' } = {}) {
880
+ const internal = xnew$1.context('xnew.accordionframe');
881
+ xnew$1.nest('<div style="display:inline-block; position: relative; width: 0.55em; margin: 0 0.3em;">');
882
+ if (type === 'arrow') {
883
+ const arrow = xnew$1(`<div style="width: 100%; height: 0.55em; border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
884
+ arrow.element.style.transform = `rotate(${internal.rate * 90 - 45}deg)`;
885
+ internal.on('-transition', ({ rate }) => {
886
+ arrow.element.style.transform = `rotate(${rate * 90 - 45}deg)`;
887
+ });
888
+ }
889
+ else if (type === 'plusminus') {
890
+ const line1 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
891
+ const line2 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
892
+ line2.element.style.transform = `rotate(90deg)`;
893
+ line2.element.style.opacity = `${1.0 - internal.rate}`;
894
+ internal.on('-transition', ({ rate }) => {
895
+ line1.element.style.transform = `rotate(${90 + rate * 90}deg)`;
896
+ line2.element.style.transform = `rotate(${rate * 180}deg)`;
897
+ });
898
+ }
899
+ }
900
+ function AccordionContent(content, {} = {}) {
901
+ const internal = xnew$1.context('xnew.accordionframe');
902
+ xnew$1.nest(`<div style="display: ${internal.open ? 'block' : 'none'};">`);
903
+ xnew$1.nest('<div style="padding: 0; display: flex; flex-direction: column; box-sizing: border-box;">');
904
+ internal.on('-transition', ({ rate }) => {
905
+ content.transition({ element: content.element, rate });
906
+ });
907
+ return {
908
+ transition({ element, rate }) {
909
+ const wrapper = element.parentElement;
910
+ wrapper.style.display = 'block';
911
+ if (rate === 0.0) {
912
+ wrapper.style.display = 'none';
913
+ }
914
+ else if (rate < 1.0) {
915
+ Object.assign(wrapper.style, { height: element.offsetHeight * rate + 'px', overflow: 'hidden', opacity: rate });
916
+ }
917
+ else {
918
+ Object.assign(wrapper.style, { height: 'auto', overflow: 'visible', opacity: 1.0 });
919
+ }
920
+ }
921
+ };
922
+ }
923
+
865
924
  function ResizeEvent(resize) {
866
925
  const observer = new ResizeObserver((entries) => {
867
926
  for (const entry of entries) {
@@ -878,7 +937,29 @@ function ResizeEvent(resize) {
878
937
  }
879
938
  });
880
939
  }
881
-
940
+ function KeyboardEvent(unit) {
941
+ const state = {};
942
+ xnew$1.listener(window).on('keydown', (event) => {
943
+ state[event.code] = 1;
944
+ unit.emit('-keydown', { event, type: '-keydown', code: event.code });
945
+ });
946
+ xnew$1.listener(window).on('keyup', (event) => {
947
+ state[event.code] = 0;
948
+ unit.emit('-keyup', { event, type: '-keyup', code: event.code });
949
+ });
950
+ xnew$1.listener(window).on('keydown', (event) => {
951
+ unit.emit('-arrowkeydown', { event, type: '-arrowkeydown', code: event.code, vector: getVector() });
952
+ });
953
+ xnew$1.listener(window).on('keyup', (event) => {
954
+ unit.emit('-arrowkeyup', { event, type: '-arrowkeyup', code: event.code, vector: getVector() });
955
+ });
956
+ function getVector() {
957
+ return {
958
+ x: (state['ArrowLeft'] ? -1 : 0) + (state['ArrowRight'] ? +1 : 0),
959
+ y: (state['ArrowUp'] ? -1 : 0) + (state['ArrowDown'] ? +1 : 0)
960
+ };
961
+ }
962
+ }
882
963
  function PointerEvent(unit) {
883
964
  const internal = xnew$1();
884
965
  internal.on('pointerdown', (event) => unit.emit('-pointerdown', { event, position: getPosition(unit.element, event) }));
@@ -995,30 +1076,6 @@ function getPosition(element, event) {
995
1076
  return { x: event.clientX - rect.left, y: event.clientY - rect.top };
996
1077
  }
997
1078
 
998
- function KeyboardEvent(unit) {
999
- const state = {};
1000
- xnew$1.listener(window).on('keydown', (event) => {
1001
- state[event.code] = 1;
1002
- unit.emit('-keydown', { event, type: '-keydown', code: event.code });
1003
- });
1004
- xnew$1.listener(window).on('keyup', (event) => {
1005
- state[event.code] = 0;
1006
- unit.emit('-keyup', { event, type: '-keyup', code: event.code });
1007
- });
1008
- xnew$1.listener(window).on('keydown', (event) => {
1009
- unit.emit('-arrowkeydown', { event, type: '-arrowkeydown', code: event.code, vector: getVector() });
1010
- });
1011
- xnew$1.listener(window).on('keyup', (event) => {
1012
- unit.emit('-arrowkeyup', { event, type: '-arrowkeyup', code: event.code, vector: getVector() });
1013
- });
1014
- function getVector() {
1015
- return {
1016
- x: (state['ArrowLeft'] ? -1 : 0) + (state['ArrowRight'] ? +1 : 0),
1017
- y: (state['ArrowUp'] ? -1 : 0) + (state['ArrowDown'] ? +1 : 0)
1018
- };
1019
- }
1020
- }
1021
-
1022
1079
  function Screen(screen, { width = 640, height = 480, fit = 'contain' } = {}) {
1023
1080
  const size = { width, height };
1024
1081
  const wrapper = xnew$1.nest('<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">');
@@ -1066,25 +1123,6 @@ function Screen(screen, { width = 640, height = 480, fit = 'contain' } = {}) {
1066
1123
  };
1067
1124
  }
1068
1125
 
1069
- function InputFrame(frame, {} = {}) {
1070
- xnew$1.nest('<div>');
1071
- xnew$1.capture((unit) => {
1072
- if (unit.element.tagName.toLowerCase() === 'input') {
1073
- const element = unit.element;
1074
- xnew$1.listener(element).on('input', (event) => {
1075
- frame.emit('-input', { event });
1076
- });
1077
- xnew$1.listener(element).on('change', (event) => {
1078
- frame.emit('-change', { event });
1079
- });
1080
- xnew$1.listener(element).on('click', (event) => {
1081
- frame.emit('-click', { event });
1082
- });
1083
- return true;
1084
- }
1085
- });
1086
- }
1087
-
1088
1126
  function ModalFrame(frame, { duration = 200, easing = 'ease' } = {}) {
1089
1127
  const internal = xnew$1((internal) => {
1090
1128
  return {};
@@ -1175,84 +1213,6 @@ function TabContent(content, { key } = {}) {
1175
1213
  };
1176
1214
  }
1177
1215
 
1178
- function AccordionFrame(frame, { open = false, duration = 200, easing = 'ease' } = {}) {
1179
- const internal = xnew$1((internal) => {
1180
- return { frame, open, rate: 0.0, };
1181
- });
1182
- xnew$1.context('xnew.accordionframe', internal);
1183
- internal.on('-transition', ({ rate }) => internal.rate = rate);
1184
- internal.emit('-transition', { rate: open ? 1.0 : 0.0 });
1185
- return {
1186
- toggle() {
1187
- if (internal.rate === 1.0) {
1188
- frame.close();
1189
- }
1190
- else if (internal.rate === 0.0) {
1191
- frame.open();
1192
- }
1193
- },
1194
- open() {
1195
- if (internal.rate === 0.0) {
1196
- xnew$1.transition((x) => internal.emit('-transition', { rate: x }), duration, easing);
1197
- }
1198
- },
1199
- close() {
1200
- if (internal.rate === 1.0) {
1201
- xnew$1.transition((x) => internal.emit('-transition', { rate: 1.0 - x }), duration, easing);
1202
- }
1203
- }
1204
- };
1205
- }
1206
- function AccordionHeader(header, {} = {}) {
1207
- const internal = xnew$1.context('xnew.accordionframe');
1208
- xnew$1.nest('<button style="display: flex; align-items: center; margin: 0; padding: 0; width: 100%; text-align: left; border: none; font: inherit; color: inherit; background: none; cursor: pointer;">');
1209
- header.on('click', () => internal.frame.toggle());
1210
- }
1211
- function AccordionBullet(bullet, { type = 'arrow' } = {}) {
1212
- const internal = xnew$1.context('xnew.accordionframe');
1213
- xnew$1.nest('<div style="display:inline-block; position: relative; width: 0.55em; margin: 0 0.3em;">');
1214
- if (type === 'arrow') {
1215
- const arrow = xnew$1(`<div style="width: 100%; height: 0.55em; border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1216
- arrow.element.style.transform = `rotate(${internal.rate * 90 - 45}deg)`;
1217
- internal.on('-transition', ({ rate }) => {
1218
- arrow.element.style.transform = `rotate(${rate * 90 - 45}deg)`;
1219
- });
1220
- }
1221
- else if (type === 'plusminus') {
1222
- const line1 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1223
- const line2 = xnew$1(`<div style="position: absolute; width: 100%; border-top: 0.06em solid currentColor; border-bottom: 0.06em solid currentColor; box-sizing: border-box; transform-origin: center;">`);
1224
- line2.element.style.transform = `rotate(90deg)`;
1225
- line2.element.style.opacity = `${1.0 - internal.rate}`;
1226
- internal.on('-transition', ({ rate }) => {
1227
- line1.element.style.transform = `rotate(${90 + rate * 90}deg)`;
1228
- line2.element.style.transform = `rotate(${rate * 180}deg)`;
1229
- });
1230
- }
1231
- }
1232
- function AccordionContent(content, {} = {}) {
1233
- const internal = xnew$1.context('xnew.accordionframe');
1234
- xnew$1.nest(`<div style="display: ${internal.open ? 'block' : 'none'};">`);
1235
- xnew$1.nest('<div style="padding: 0; display: flex; flex-direction: column; box-sizing: border-box;">');
1236
- internal.on('-transition', ({ rate }) => {
1237
- content.transition({ element: content.element, rate });
1238
- });
1239
- return {
1240
- transition({ element, rate }) {
1241
- const wrapper = element.parentElement;
1242
- wrapper.style.display = 'block';
1243
- if (rate === 0.0) {
1244
- wrapper.style.display = 'none';
1245
- }
1246
- else if (rate < 1.0) {
1247
- Object.assign(wrapper.style, { height: element.offsetHeight * rate + 'px', overflow: 'hidden', opacity: rate });
1248
- }
1249
- else {
1250
- Object.assign(wrapper.style, { height: 'auto', overflow: 'visible', opacity: 1.0 });
1251
- }
1252
- }
1253
- };
1254
- }
1255
-
1256
1216
  function DragFrame(frame, { x = 0, y = 0 } = {}) {
1257
1217
  const absolute = xnew$1.nest(`<div style="position: absolute; top: ${y}px; left: ${x}px;">`);
1258
1218
  xnew$1.context('xnew.dragframe', { frame, absolute });
@@ -1676,7 +1636,6 @@ const basics = {
1676
1636
  TabFrame,
1677
1637
  TabButton,
1678
1638
  TabContent,
1679
- InputFrame,
1680
1639
  DragFrame,
1681
1640
  DragTarget,
1682
1641
  AnalogStick,