@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/types/basics/Event.d.ts +4 -3
- package/dist/types/core/time.d.ts +6 -2
- package/dist/types/core/unit.d.ts +45 -10
- package/dist/types/core/xnew.d.ts +12 -22
- package/dist/types/index.d.ts +2 -6
- package/dist/xnew.d.ts +48 -58
- package/dist/xnew.js +308 -349
- package/dist/xnew.mjs +308 -349
- package/package.json +1 -1
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
|
-
//
|
|
105
|
+
// ticker
|
|
202
106
|
//----------------------------------------------------------------------------------------------------
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
211
|
-
this.
|
|
212
|
-
|
|
123
|
+
clear() {
|
|
124
|
+
if (this.id !== null) {
|
|
125
|
+
cancelAnimationFrame(this.id);
|
|
126
|
+
this.id = null;
|
|
127
|
+
}
|
|
213
128
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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,
|
|
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((
|
|
500
|
-
const
|
|
501
|
-
if (
|
|
502
|
-
|
|
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
|
-
|
|
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((
|
|
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((
|
|
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,
|
|
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((
|
|
541
|
-
const
|
|
542
|
-
if (
|
|
543
|
-
|
|
544
|
-
|
|
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
|
|
739
|
-
* @param
|
|
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(
|
|
746
|
-
|
|
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
|
|
759
|
-
* @param
|
|
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(
|
|
766
|
-
|
|
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
|
|
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(
|
|
783
|
-
* element.style.opacity =
|
|
784
|
-
* }, 500, 'ease-out').
|
|
785
|
-
* element.style.transform = `scale(${
|
|
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(
|
|
789
|
-
|
|
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,
|