@etsoo/shared 1.1.25 → 1.1.28

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.
@@ -0,0 +1,69 @@
1
+ import { EventBase, EventClass } from './EventClass';
2
+ /**
3
+ * ETSOO Extended history event type
4
+ */
5
+ export declare type EHistoryEventType = 'navigate' | 'push' | 'replace' | 'clear';
6
+ /**
7
+ * ETSOO Extended history event data
8
+ */
9
+ export interface EHistoryEventData {
10
+ /**
11
+ * Current index
12
+ */
13
+ index: number;
14
+ }
15
+ /**
16
+ * ETSOO Extended abstract history class
17
+ */
18
+ export declare abstract class EHistory<T, D extends EHistoryEventData> extends EventClass<EHistoryEventType, D> {
19
+ private _index;
20
+ /**
21
+ * States
22
+ */
23
+ readonly states: T[];
24
+ /**
25
+ * States length
26
+ */
27
+ get length(): number;
28
+ /**
29
+ * Get current state index
30
+ */
31
+ get index(): number;
32
+ /**
33
+ * Get current state
34
+ */
35
+ get state(): T | undefined;
36
+ /**
37
+ * Back to the previous state
38
+ */
39
+ back(): void;
40
+ /**
41
+ * Clear all states but keep event listeners
42
+ */
43
+ clear(): void;
44
+ /**
45
+ * Create event
46
+ * @param type Type
47
+ * @param index Current index
48
+ */
49
+ protected abstract createEvent(type: EHistoryEventType, index: number): EventBase<EHistoryEventType, D>;
50
+ /**
51
+ * Forward to the next state
52
+ */
53
+ forward(): void;
54
+ /**
55
+ * Go to the specific state
56
+ * @param delta A negative value moves backwards, a positive value moves forwards
57
+ */
58
+ go(delta: number): undefined;
59
+ /**
60
+ * Adds an entry to the history stack
61
+ * @param state State
62
+ */
63
+ pushState(state: T): void;
64
+ /**
65
+ * Modifies the current history entry
66
+ * @param state State
67
+ */
68
+ replaceState(state: T): void;
69
+ }
@@ -0,0 +1,97 @@
1
+ import { EventClass } from './EventClass';
2
+ /**
3
+ * ETSOO Extended abstract history class
4
+ */
5
+ export class EHistory extends EventClass {
6
+ constructor() {
7
+ super(...arguments);
8
+ // Index
9
+ this._index = -1;
10
+ /**
11
+ * States
12
+ */
13
+ this.states = [];
14
+ }
15
+ /**
16
+ * States length
17
+ */
18
+ get length() {
19
+ return this.states.length;
20
+ }
21
+ /**
22
+ * Get current state index
23
+ */
24
+ get index() {
25
+ return this._index;
26
+ }
27
+ /**
28
+ * Get current state
29
+ */
30
+ get state() {
31
+ if (this._index === -1)
32
+ return undefined;
33
+ return this.states[this._index];
34
+ }
35
+ /**
36
+ * Back to the previous state
37
+ */
38
+ back() {
39
+ this.go(-1);
40
+ }
41
+ /**
42
+ * Clear all states but keep event listeners
43
+ */
44
+ clear() {
45
+ // https://stackoverflow.com/questions/1232040/how-do-i-empty-an-array-in-javascript
46
+ this.states.length = 0;
47
+ this._index = -1;
48
+ this.trigger(this.createEvent('clear', this._index));
49
+ }
50
+ /**
51
+ * Forward to the next state
52
+ */
53
+ forward() {
54
+ this.go(1);
55
+ }
56
+ /**
57
+ * Go to the specific state
58
+ * @param delta A negative value moves backwards, a positive value moves forwards
59
+ */
60
+ go(delta) {
61
+ // No data
62
+ if (this._index === -1)
63
+ return undefined;
64
+ // New index
65
+ const newIndex = this._index + delta;
66
+ // Not in the range
67
+ if (newIndex < 0 || newIndex >= this.length)
68
+ return undefined;
69
+ // Update the index
70
+ this._index = newIndex;
71
+ // Trigger event
72
+ this.trigger(this.createEvent('navigate', newIndex));
73
+ }
74
+ /**
75
+ * Adds an entry to the history stack
76
+ * @param state State
77
+ */
78
+ pushState(state) {
79
+ if (this._index >= 0) {
80
+ // Remove states after the index
81
+ this.states.splice(this._index + 1);
82
+ }
83
+ this.states.push(state);
84
+ this._index++;
85
+ this.trigger(this.createEvent('push', this._index));
86
+ }
87
+ /**
88
+ * Modifies the current history entry
89
+ * @param state State
90
+ */
91
+ replaceState(state) {
92
+ if (this._index === -1)
93
+ return;
94
+ this.states[this._index] = state;
95
+ this.trigger(this.createEvent('replace', this._index));
96
+ }
97
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Abstract event base class
3
+ * T for type
4
+ * D for data
5
+ */
6
+ export declare abstract class EventBase<T extends string, D> {
7
+ readonly target: EventClass<T, D>;
8
+ readonly type: T;
9
+ readonly data: D;
10
+ private _propagationStopped;
11
+ /**
12
+ * stopImmediatePropagation called
13
+ */
14
+ get propagationStopped(): boolean;
15
+ private _timeStamp;
16
+ /**
17
+ * Time stamp
18
+ */
19
+ get timeStamp(): number;
20
+ /**
21
+ * Constructor
22
+ * @param type Type
23
+ */
24
+ constructor(target: EventClass<T, D>, type: T, data: D);
25
+ /**
26
+ * Prevent all other listeners from being called
27
+ */
28
+ stopImmediatePropagation(): void;
29
+ }
30
+ /**
31
+ * Event options
32
+ */
33
+ interface EventOptions {
34
+ /**
35
+ * A boolean value indicating that events of this type will be dispatched first
36
+ */
37
+ capture?: boolean;
38
+ /**
39
+ * A boolean value indicating that the listener should be invoked at most once after being added
40
+ */
41
+ once?: boolean;
42
+ }
43
+ /**
44
+ * Event class callback
45
+ * T for type
46
+ * D for data
47
+ */
48
+ export declare type EventClassCallback<T extends string, D> = (event: EventBase<T, D>) => void;
49
+ /**
50
+ * Event class collection definition
51
+ * T for type
52
+ * D for data
53
+ */
54
+ export declare type EventClassCollection<T extends string, D> = {
55
+ [key in T]?: EventClassCallback<T, D>;
56
+ };
57
+ /**
58
+ * Event class
59
+ * T for type
60
+ * D for data
61
+ */
62
+ export declare abstract class EventClass<T extends string, D> {
63
+ private readonly listeners;
64
+ /**
65
+ * Has specific type events
66
+ * @param type Type
67
+ */
68
+ hasEvents(type: T): boolean;
69
+ /**
70
+ * Has specific type and callback events
71
+ * @param type Type
72
+ * @param callback Callback
73
+ */
74
+ hasEvents(type: T, callback: EventClassCallback<T, D>): boolean;
75
+ /**
76
+ * Remove all specific type events
77
+ * @param type Type
78
+ */
79
+ off(type: T): void;
80
+ /**
81
+ * Remove specific type and callback event
82
+ * @param type Type
83
+ * @param callback Callback
84
+ */
85
+ off(type: T, callback: EventClassCallback<T, D>): void;
86
+ /**
87
+ * Add event listeners
88
+ * @param collection Collection of events
89
+ */
90
+ on(collection: EventClassCollection<T, D>): void;
91
+ /**
92
+ * Add event listener
93
+ * @param type Type
94
+ * @param callback Callback
95
+ * @param options Options
96
+ */
97
+ on(type: T, callback: EventClassCallback<T, D>, options?: EventOptions): void;
98
+ /**
99
+ * Trigger event
100
+ * @param event Event
101
+ */
102
+ trigger(event: EventBase<T, D>): void;
103
+ }
104
+ export {};
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Abstract event base class
3
+ * T for type
4
+ * D for data
5
+ */
6
+ export class EventBase {
7
+ /**
8
+ * Constructor
9
+ * @param type Type
10
+ */
11
+ constructor(target, type, data) {
12
+ this.target = target;
13
+ this.type = type;
14
+ this.data = data;
15
+ this._propagationStopped = false;
16
+ this._timeStamp = Date.now();
17
+ }
18
+ /**
19
+ * stopImmediatePropagation called
20
+ */
21
+ get propagationStopped() {
22
+ return this._propagationStopped;
23
+ }
24
+ /**
25
+ * Time stamp
26
+ */
27
+ get timeStamp() {
28
+ return this._timeStamp;
29
+ }
30
+ /**
31
+ * Prevent all other listeners from being called
32
+ */
33
+ stopImmediatePropagation() {
34
+ this._propagationStopped = true;
35
+ }
36
+ }
37
+ /**
38
+ * Event class
39
+ * T for type
40
+ * D for data
41
+ */
42
+ export class EventClass {
43
+ constructor() {
44
+ // Listeners
45
+ this.listeners = new Map();
46
+ }
47
+ /**
48
+ * Has specific type and callback events
49
+ * @param type Type
50
+ * @param callback Callback
51
+ * @returns Result
52
+ */
53
+ hasEvents(type, callback) {
54
+ const items = this.listeners.get(type);
55
+ if (items == null || items.length === 0)
56
+ return false;
57
+ if (callback) {
58
+ return items.some((item) => item[0] == callback);
59
+ }
60
+ return true;
61
+ }
62
+ /**
63
+ * Remove specific type and callback event
64
+ * @param type Type
65
+ * @param callback Callback
66
+ */
67
+ off(type, callback) {
68
+ if (callback == null) {
69
+ this.listeners.delete(type);
70
+ return;
71
+ }
72
+ const items = this.listeners.get(type);
73
+ if (items == null)
74
+ return;
75
+ for (let i = items.length - 1; i >= 0; i--) {
76
+ if (items[i][0] == callback) {
77
+ items.splice(i, 1);
78
+ }
79
+ }
80
+ }
81
+ /**
82
+ * Add events
83
+ * @param type Type
84
+ * @param callback Callback
85
+ * @param options Options
86
+ */
87
+ on(type, callback, options) {
88
+ var _a, _b;
89
+ if (typeof type === 'object') {
90
+ for (const key in type) {
91
+ const item = key;
92
+ const itemCallback = (_a = type[item]) !== null && _a !== void 0 ? _a : callback;
93
+ if (itemCallback)
94
+ this.on(item, itemCallback, options);
95
+ }
96
+ return;
97
+ }
98
+ if (callback == null)
99
+ return;
100
+ this.listeners.has(type) || this.listeners.set(type, []);
101
+ (_b = this.listeners.get(type)) === null || _b === void 0 ? void 0 : _b.push([callback, options]);
102
+ }
103
+ /**
104
+ * Trigger event
105
+ * @param event Event
106
+ */
107
+ trigger(event) {
108
+ const items = this.listeners.get(event.type);
109
+ if (items == null)
110
+ return;
111
+ // Len
112
+ const len = items.length;
113
+ if (len === 0)
114
+ return;
115
+ // Need to be removed indicies
116
+ const indicies = [];
117
+ // Capture items first
118
+ let stopped = false;
119
+ for (let c = 0; c < len; c++) {
120
+ const item = items[c];
121
+ const [callback, options] = item;
122
+ if (options == null || !options.capture)
123
+ continue;
124
+ callback(event);
125
+ if (options.once) {
126
+ indicies.push(c);
127
+ }
128
+ if (event.propagationStopped) {
129
+ stopped = true;
130
+ break;
131
+ }
132
+ }
133
+ if (!stopped) {
134
+ for (let c = 0; c < len; c++) {
135
+ const item = items[c];
136
+ const [callback, options] = item;
137
+ if (options === null || options === void 0 ? void 0 : options.capture)
138
+ continue;
139
+ callback(event);
140
+ if (options === null || options === void 0 ? void 0 : options.once) {
141
+ indicies.push(c);
142
+ }
143
+ if (event.propagationStopped) {
144
+ stopped = true;
145
+ break;
146
+ }
147
+ }
148
+ }
149
+ // Remove all once handlers
150
+ for (let i = indicies.length - 1; i >= 0; i--) {
151
+ items.splice(indicies[i], 1);
152
+ }
153
+ }
154
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/shared",
3
- "version": "1.1.25",
3
+ "version": "1.1.28",
4
4
  "description": "TypeScript shared utilities and functions",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -15,6 +15,25 @@ export class EColor {
15
15
  return value;
16
16
  }
17
17
 
18
+ /**
19
+ * Format color
20
+ * @param input Input color text
21
+ * @param hexColor Format as Hex color
22
+ * @returns Result
23
+ */
24
+ static format(input: string | undefined | null, hexColor?: boolean) {
25
+ // Null
26
+ if (input == null) return undefined;
27
+
28
+ // Like transparent, black, red
29
+ if (/^[a-zA-Z]+$/gi.test(input)) return input.toLowerCase();
30
+
31
+ const color = EColor.parse(input);
32
+ if (color == null) return undefined;
33
+
34
+ return hexColor ? color.toHEXColor() : color.toRGBColor();
35
+ }
36
+
18
37
  /**
19
38
  * HEX string to integer value
20
39
  * @param hex HEX string
@@ -0,0 +1,134 @@
1
+ import { EventBase, EventClass } from './EventClass';
2
+
3
+ /**
4
+ * ETSOO Extended history event type
5
+ */
6
+ export type EHistoryEventType = 'navigate' | 'push' | 'replace' | 'clear';
7
+
8
+ /**
9
+ * ETSOO Extended history event data
10
+ */
11
+ export interface EHistoryEventData {
12
+ /**
13
+ * Current index
14
+ */
15
+ index: number;
16
+ }
17
+
18
+ /**
19
+ * ETSOO Extended abstract history class
20
+ */
21
+ export abstract class EHistory<
22
+ T,
23
+ D extends EHistoryEventData
24
+ > extends EventClass<EHistoryEventType, D> {
25
+ // Index
26
+ private _index: number = -1;
27
+
28
+ /**
29
+ * States
30
+ */
31
+ readonly states: T[] = [];
32
+
33
+ /**
34
+ * States length
35
+ */
36
+ get length() {
37
+ return this.states.length;
38
+ }
39
+
40
+ /**
41
+ * Get current state index
42
+ */
43
+ get index() {
44
+ return this._index;
45
+ }
46
+
47
+ /**
48
+ * Get current state
49
+ */
50
+ get state() {
51
+ if (this._index === -1) return undefined;
52
+ return this.states[this._index];
53
+ }
54
+
55
+ /**
56
+ * Back to the previous state
57
+ */
58
+ back() {
59
+ this.go(-1);
60
+ }
61
+
62
+ /**
63
+ * Clear all states but keep event listeners
64
+ */
65
+ clear() {
66
+ // https://stackoverflow.com/questions/1232040/how-do-i-empty-an-array-in-javascript
67
+ this.states.length = 0;
68
+ this._index = -1;
69
+ this.trigger(this.createEvent('clear', this._index));
70
+ }
71
+
72
+ /**
73
+ * Create event
74
+ * @param type Type
75
+ * @param index Current index
76
+ */
77
+ protected abstract createEvent(
78
+ type: EHistoryEventType,
79
+ index: number
80
+ ): EventBase<EHistoryEventType, D>;
81
+
82
+ /**
83
+ * Forward to the next state
84
+ */
85
+ forward() {
86
+ this.go(1);
87
+ }
88
+
89
+ /**
90
+ * Go to the specific state
91
+ * @param delta A negative value moves backwards, a positive value moves forwards
92
+ */
93
+ go(delta: number) {
94
+ // No data
95
+ if (this._index === -1) return undefined;
96
+
97
+ // New index
98
+ const newIndex = this._index + delta;
99
+
100
+ // Not in the range
101
+ if (newIndex < 0 || newIndex >= this.length) return undefined;
102
+
103
+ // Update the index
104
+ this._index = newIndex;
105
+
106
+ // Trigger event
107
+ this.trigger(this.createEvent('navigate', newIndex));
108
+ }
109
+
110
+ /**
111
+ * Adds an entry to the history stack
112
+ * @param state State
113
+ */
114
+ pushState(state: T) {
115
+ if (this._index >= 0) {
116
+ // Remove states after the index
117
+ this.states.splice(this._index + 1);
118
+ }
119
+
120
+ this.states.push(state);
121
+ this._index++;
122
+ this.trigger(this.createEvent('push', this._index));
123
+ }
124
+
125
+ /**
126
+ * Modifies the current history entry
127
+ * @param state State
128
+ */
129
+ replaceState(state: T) {
130
+ if (this._index === -1) return;
131
+ this.states[this._index] = state;
132
+ this.trigger(this.createEvent('replace', this._index));
133
+ }
134
+ }