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