tiny-essentials 1.26.3 → 1.27.0

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.
Files changed (128) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/README.md +0 -1
  3. package/changelog/1/26/4.md +10 -0
  4. package/changelog/1/27/0.md +24 -0
  5. package/dist/v1/ColorSafeStringify.min.js +1 -1
  6. package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
  7. package/dist/v1/TinyAfterScrollWatcher.min.js +1 -1
  8. package/dist/v1/TinyAnalogClock.min.js +1 -1
  9. package/dist/v1/TinyArrayComparator.min.js +1 -1
  10. package/dist/v1/TinyArrayPaginator.min.js +1 -1
  11. package/dist/v1/TinyBasicsEs.min.js +1 -1
  12. package/dist/v1/TinyClassManager.min.js +1 -1
  13. package/dist/v1/TinyClipboard.min.js +1 -1
  14. package/dist/v1/TinyColorConverter.min.js +1 -1
  15. package/dist/v1/TinyColorValidator.min.js +1 -1
  16. package/dist/v1/TinyCookieConsent.min.js +1 -1
  17. package/dist/v1/TinyDayNightCycle.min.js +1 -1
  18. package/dist/v1/TinyDomReadyManager.min.js +1 -1
  19. package/dist/v1/TinyDragDropDetector.min.js +1 -1
  20. package/dist/v1/TinyDragger.min.js +1 -1
  21. package/dist/v1/TinyElementObserver.min.js +1 -1
  22. package/dist/v1/TinyEssentials.min.js +1 -1
  23. package/dist/v1/TinyEvents.min.js +1 -1
  24. package/dist/v1/TinyGamepad.min.js +1 -1
  25. package/dist/v1/TinyHtml.min.js +1 -1
  26. package/dist/v1/TinyI18.min.js +1 -1
  27. package/dist/v1/TinyIframeEvents.min.js +1 -1
  28. package/dist/v1/TinyInventory.min.js +1 -1
  29. package/dist/v1/TinyInventoryTrader.min.js +1 -1
  30. package/dist/v1/TinyLevelUp.min.js +1 -1
  31. package/dist/v1/TinyLoadingScreen.min.js +1 -1
  32. package/dist/v1/TinyLocalStorage.min.js +1 -1
  33. package/dist/v1/TinyMaInSys.min.js +1 -1
  34. package/dist/v1/TinyMediaPlayer.min.js +1 -0
  35. package/dist/v1/TinyNeedBar.min.js +1 -1
  36. package/dist/v1/TinyNewWinEvents.min.js +1 -1
  37. package/dist/v1/TinyNotifications.min.js +1 -1
  38. package/dist/v1/TinyNotifyCenter.min.js +1 -1
  39. package/dist/v1/TinyPromiseQueue.min.js +1 -1
  40. package/dist/v1/TinyRadioFm.min.js +1 -0
  41. package/dist/v1/TinyRateLimiter.min.js +1 -1
  42. package/dist/v1/TinySimpleDice.min.js +1 -1
  43. package/dist/v1/TinySmartScroller.min.js +1 -1
  44. package/dist/v1/TinyTextDiffer.min.js +1 -1
  45. package/dist/v1/TinyTextRangeEditor.min.js +1 -1
  46. package/dist/v1/TinyTextarea.min.js +1 -1
  47. package/dist/v1/TinyTimeout.min.js +1 -1
  48. package/dist/v1/TinyToastNotify.min.js +1 -1
  49. package/dist/v1/TinyUploadClicker.min.js +1 -1
  50. package/dist/v1/UltraRandomMsgGen.min.js +1 -1
  51. package/dist/v1/basics/index.cjs +5 -0
  52. package/dist/v1/basics/index.d.mts +5 -1
  53. package/dist/v1/basics/index.mjs +2 -1
  54. package/dist/v1/basics/mediaContent.cjs +644 -0
  55. package/dist/v1/basics/mediaContent.d.mts +296 -0
  56. package/dist/v1/basics/mediaContent.mjs +557 -0
  57. package/dist/v1/build/TinyMediaPlayer.cjs +7 -0
  58. package/dist/v1/build/TinyMediaPlayer.d.mts +3 -0
  59. package/dist/v1/build/TinyMediaPlayer.mjs +2 -0
  60. package/dist/v1/build/TinyRadioFm.cjs +7 -0
  61. package/dist/v1/build/TinyRadioFm.d.mts +3 -0
  62. package/dist/v1/build/TinyRadioFm.mjs +2 -0
  63. package/dist/v1/index.cjs +9 -0
  64. package/dist/v1/index.d.mts +7 -1
  65. package/dist/v1/index.mjs +5 -2
  66. package/dist/v1/libs/ColorSafeStringify.d.mts +1 -1
  67. package/dist/v1/libs/TinyAfterScrollWatcher.cjs +16 -3
  68. package/dist/v1/libs/TinyAfterScrollWatcher.d.mts +7 -3
  69. package/dist/v1/libs/TinyAfterScrollWatcher.mjs +13 -3
  70. package/dist/v1/libs/TinyArrayComparator.cjs +14 -11
  71. package/dist/v1/libs/TinyArrayComparator.d.mts +22 -19
  72. package/dist/v1/libs/TinyArrayComparator.mjs +14 -11
  73. package/dist/v1/libs/TinyArrayPaginator.cjs +23 -16
  74. package/dist/v1/libs/TinyArrayPaginator.d.mts +57 -30
  75. package/dist/v1/libs/TinyArrayPaginator.mjs +22 -16
  76. package/dist/v1/libs/TinyClassManager/TinyPluginInliner.cjs +265 -0
  77. package/dist/v1/libs/TinyClassManager/TinyPluginInliner.d.mts +92 -0
  78. package/dist/v1/libs/TinyClassManager/TinyPluginInliner.mjs +223 -0
  79. package/dist/v1/libs/TinyClassManager.cjs +124 -23
  80. package/dist/v1/libs/TinyClassManager.d.mts +33 -13
  81. package/dist/v1/libs/TinyClassManager.mjs +108 -23
  82. package/dist/v1/libs/TinyColorValidator.d.mts +16 -16
  83. package/dist/v1/libs/TinyDragDropDetector.cjs +9 -34
  84. package/dist/v1/libs/TinyDragDropDetector.d.mts +7 -21
  85. package/dist/v1/libs/TinyDragDropDetector.mjs +9 -24
  86. package/dist/v1/libs/TinyDragger.cjs +5 -5
  87. package/dist/v1/libs/TinyDragger.d.mts +4 -3
  88. package/dist/v1/libs/TinyDragger.mjs +5 -5
  89. package/dist/v1/libs/TinyElementObserver.cjs +6 -21
  90. package/dist/v1/libs/TinyElementObserver.d.mts +6 -15
  91. package/dist/v1/libs/TinyElementObserver.mjs +6 -20
  92. package/dist/v1/libs/TinyEvents.cjs +7 -0
  93. package/dist/v1/libs/TinyEvents.d.mts +4 -0
  94. package/dist/v1/libs/TinyEvents.mjs +6 -0
  95. package/dist/v1/libs/TinyGamepad.cjs +4 -6
  96. package/dist/v1/libs/TinyGamepad.d.mts +1 -1
  97. package/dist/v1/libs/TinyHtml/TinyHtmlIcon.d.mts +1 -1
  98. package/dist/v1/libs/TinyHtml/TinyHtmlTemplate.d.mts +1 -1
  99. package/dist/v1/libs/TinyHtml/TinyHtmlTextarea.d.mts +1 -1
  100. package/dist/v1/libs/TinyHtml/index.d.mts +1 -1
  101. package/dist/v1/libs/TinyHtml.cjs +72 -98
  102. package/dist/v1/libs/TinyHtml.d.mts +15 -32
  103. package/dist/v1/libs/TinyHtml.mjs +53 -77
  104. package/dist/v1/libs/TinyInventory.d.mts +1 -1
  105. package/dist/v1/libs/TinyMediaPlayer.cjs +844 -0
  106. package/dist/v1/libs/TinyMediaPlayer.d.mts +306 -0
  107. package/dist/v1/libs/TinyMediaPlayer.mjs +755 -0
  108. package/dist/v1/libs/TinyRadioFm.cjs +1378 -0
  109. package/dist/v1/libs/TinyRadioFm.d.mts +554 -0
  110. package/dist/v1/libs/TinyRadioFm.mjs +1137 -0
  111. package/dist/v1/libs/TinySmartScroller.cjs +39 -26
  112. package/dist/v1/libs/TinySmartScroller.d.mts +16 -62
  113. package/dist/v1/libs/TinySmartScroller.mjs +35 -26
  114. package/dist/v1/libs/UltraRandomMsgGen.d.mts +7 -7
  115. package/dist/v1/libs/examples/TinyClassManager.cjs +43 -41
  116. package/dist/v1/libs/examples/TinyClassManager.mjs +37 -37
  117. package/docs/v1/README.md +6 -0
  118. package/docs/v1/basics/mediaContent.md +131 -0
  119. package/docs/v1/libs/TinyClassManager/TinyPluginInliner.md +107 -0
  120. package/docs/v1/libs/TinyClassManager.md +69 -70
  121. package/docs/v1/libs/TinyDragDropDetector.md +5 -9
  122. package/docs/v1/libs/TinyElementObserver.md +3 -6
  123. package/docs/v1/libs/TinyEvents.md +1 -1
  124. package/docs/v1/libs/TinyHtml.md +0 -29
  125. package/docs/v1/libs/TinyMediaPlayer.md +100 -0
  126. package/docs/v1/libs/TinyRadioFm.md +141 -0
  127. package/docs/v1/libs/TinySmartScroller.md +3 -3
  128. package/package.json +40 -22
@@ -1,19 +1,25 @@
1
1
  'use strict';
2
2
 
3
+ /** @typedef {new (...args: any[]) => any} NewTinyClass */
4
+
3
5
  /**
4
- * @template {new (...args: any[]) => any} TBase
5
- * @template {new (...args: any[]) => any} TExtended
6
+ * @template {NewTinyClass} TBase
7
+ * @template {NewTinyClass} TExtended
8
+ * @template {NewTinyClass[]} AppliedPluginClasses
6
9
  * @typedef {Object} PluginDefinition
7
10
  * @property {string} name - The unique identifier for the plugin.
8
11
  * @property {string[]} [dependencies] - Array of plugin names required before applying this one.
9
- * @property {function(TBase): TExtended} apply - Function that receives the base class and returns the extended class.
12
+ * @property {function(TBase, AppliedPluginClasses): TExtended} apply - Function that receives the base class and returns the extended class.
10
13
  */
11
14
 
12
15
  /**
13
16
  * Manages the composition of a base class with multiple optional plugins (Mixins).
14
- * @template {new (...args: any[]) => any} T
17
+ * @template {NewTinyClass} T
18
+ * @template {T|NewTinyClass} oldT
15
19
  */
16
20
  class TinyClassManager {
21
+ /** @typedef {[...oldT[], T]} AppliedPluginClasses */
22
+
17
23
  /**
18
24
  * @type {Set<string>}
19
25
  * Tracks the names of successfully applied plugins to prevent duplication and check dependencies.
@@ -25,15 +31,33 @@ class TinyClassManager {
25
31
  * @returns {string[]} Array of applied plugin names.
26
32
  */
27
33
  get appliedPlugins() {
34
+ if (this.#used) throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
28
35
  return [...this.#appliedPlugins];
29
36
  }
30
37
 
38
+ /**
39
+ * @type {AppliedPluginClasses}
40
+ * Tracks the classes of successfully applied plugins to prevent duplication and check dependencies.
41
+ */
42
+ // @ts-ignore
43
+ #appliedPluginClasses = [];
44
+
45
+ /**
46
+ * Gets the list of plugin classes currently applied to this instance.
47
+ * @returns {AppliedPluginClasses} Array of applied plugin classes.
48
+ */
49
+ get appliedPluginClasses() {
50
+ if (this.#used) throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
51
+ return [...this.#appliedPluginClasses];
52
+ }
53
+
31
54
  /**
32
55
  * Gets the total size of the current class chain hierarchy.
33
56
  * @returns {number} The count of applied plugins plus the core base.
34
57
  */
35
58
  get size() {
36
- return this.#appliedPlugins.size + 1;
59
+ if (this.#used) throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
60
+ return this.#appliedPluginClasses.length;
37
61
  }
38
62
 
39
63
  /**
@@ -46,6 +70,7 @@ class TinyClassManager {
46
70
  * Holds the current state of the class chain.
47
71
  */
48
72
  get currentClass() {
73
+ if (this.#used) throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
49
74
  return this.#currentClass;
50
75
  }
51
76
 
@@ -64,46 +89,120 @@ class TinyClassManager {
64
89
  /**
65
90
  * Initializes the manager with a core class.
66
91
  * @param {T} coreClass - The foundational class to be extended.
92
+ * @param {oldT[]} [oldClasses=[]]
67
93
  */
68
- constructor(coreClass) {
94
+ constructor(
95
+ coreClass,
96
+ // @ts-ignore
97
+ oldClasses = [],
98
+ ) {
69
99
  this.#currentClass = coreClass;
100
+ this.#appliedPluginClasses = [...oldClasses, coreClass];
70
101
  }
71
102
 
72
103
  /**
73
- * Applies a plugin to the class chain if all conditions are met.
74
- * @template {new (...args: any[]) => any} R
75
- * @param {PluginDefinition<T, R>} plugin - The plugin module to be integrated.
76
- * @returns {TinyClassManager<R>} A new manager instance holding the extended class chain.
77
- * @throws {Error} Throws if instance is already consumed, plugin is duplicate, or dependencies are missing.
104
+ * Internal helper to validate dependencies, check conflicts, and transition state.
105
+ * @template {NewTinyClass} R
106
+ * @param {string} name - The plugin name.
107
+ * @param {string[]} deps - The plugin dependencies.
108
+ * @param {R} ExtendedClass - The newly extended class returned by the apply function.
109
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance.
78
110
  */
79
- use(plugin) {
111
+ #validateAndTransition(name, deps, ExtendedClass) {
112
+ // Verifies if the current manager has already been consumed to prevent branching.
80
113
  if (this.#used) throw new Error(`[TinyClassManager] Cannot reuse a consumed manager instance.`);
81
- if (this.#appliedPlugins.has(plugin.name))
82
- throw new Error(`[TinyClassManager] Plugin conflict: "${plugin.name}" is already installed.`);
83
114
 
84
- /**
85
- * @type {string[]}
86
- * Extracted dependencies array with fallback for undefined properties.
87
- */
88
- const deps = plugin.dependencies || [];
115
+ // Checks if the plugin being inserted is already in the applied list.
116
+ if (this.#appliedPlugins.has(name))
117
+ throw new Error(`[TinyClassManager] Plugin conflict: "${name}" is already installed.`);
89
118
 
90
119
  for (const dep of deps) {
91
120
  if (!this.#appliedPlugins.has(dep)) {
92
121
  throw new Error(
93
- `[TinyClassManager] Missing Dependency: "${plugin.name}" requires "${dep}" to be installed first.`,
122
+ `[TinyClassManager] Missing Dependency: "${name}" requires "${dep}" to be installed first.`,
94
123
  );
95
124
  }
96
125
  }
97
126
 
98
- const newClassManager = new TinyClassManager(plugin.apply(this.#currentClass));
99
- this.#appliedPlugins.forEach((name) => newClassManager.#appliedPlugins.add(name));
100
- newClassManager.#appliedPlugins.add(plugin.name);
127
+ const newClassManager = new TinyClassManager(ExtendedClass, this.#appliedPluginClasses);
128
+ this.#appliedPlugins.forEach((appliedName) => newClassManager.#appliedPlugins.add(appliedName));
129
+ newClassManager.#appliedPlugins.add(name);
101
130
 
102
131
  this.#used = true;
103
132
  this.#appliedPlugins.clear();
133
+ // @ts-ignore
134
+ this.#appliedPluginClasses = [];
135
+
104
136
  return newClassManager;
105
137
  }
106
138
 
139
+ /**
140
+ * Applies a plugin to the class chain using a definition object.
141
+ * @deprecated Use {@link insert} instead.
142
+ * @template {NewTinyClass} R
143
+ * @param {PluginDefinition<T, R, AppliedPluginClasses>} plugin - The plugin module to be integrated.
144
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance holding the extended class chain.
145
+ * @throws {Error} Throws if instance is already consumed, plugin is duplicate, or dependencies are missing.
146
+ */
147
+ use(plugin) {
148
+ /**
149
+ * @type {string[]}
150
+ * Extracted dependencies array with fallback for undefined properties.
151
+ */
152
+ const deps = plugin.dependencies || [];
153
+
154
+ /**
155
+ * @type {R}
156
+ * The new class generated by the old object-style apply wrapper.
157
+ */
158
+ const ExtendedClass = plugin.apply(this.#currentClass, this.appliedPluginClasses);
159
+
160
+ return this.#validateAndTransition(plugin.name, deps, ExtendedClass);
161
+ }
162
+
163
+ /**
164
+ * Inserts a plugin directly by passing its apply function.
165
+ * It reads `_tinyDepName` and `_tinyDeps` statically from the returned class.
166
+ * @template {NewTinyClass} R
167
+ * @param {function(T, AppliedPluginClasses): R} applyFn - Function that receives the base class and returns the extended class.
168
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance holding the extended class chain.
169
+ * @throws {Error} Throws if static properties are missing, instance is consumed, or validation fails.
170
+ */
171
+ insert(applyFn) {
172
+ /** * @type {R}
173
+ * The extended class returned directly from the provided function.
174
+ */
175
+ const ExtendedClass = applyFn(this.#currentClass, this.appliedPluginClasses);
176
+
177
+ /**
178
+ * @type {string}
179
+ * The plugin name extracted from the static property.
180
+ */
181
+ // @ts-ignore
182
+ const pluginName = ExtendedClass._tinyDepName;
183
+
184
+ if (!pluginName) {
185
+ throw new Error(
186
+ `[TinyClassManager] Plugin class must define a static '_tinyDepName' property.`,
187
+ );
188
+ }
189
+
190
+ /**
191
+ * @type {string[]}
192
+ * The dependencies extracted from the static property, defaulting to an empty array.
193
+ */
194
+ // @ts-ignore
195
+ const deps = ExtendedClass._tinyDeps ?? [];
196
+
197
+ if (!Array.isArray(deps) || !deps.every((name) => typeof name === 'string')) {
198
+ throw new Error(
199
+ `[TinyClassManager] Plugin class must define a static array of strings in '_tinyDepName' property.`,
200
+ );
201
+ }
202
+
203
+ return this.#validateAndTransition(pluginName, deps, ExtendedClass);
204
+ }
205
+
107
206
  /**
108
207
  * Finalizes the composition and returns the fully built class.
109
208
  * @returns {T} The final class representing the last extended version in the chain.
@@ -114,6 +213,8 @@ class TinyClassManager {
114
213
  throw new Error(`[TinyClassManager] Cannot build from an already finalized manager.`);
115
214
  this.#used = true;
116
215
  this.#appliedPlugins.clear();
216
+ // @ts-ignore
217
+ this.#appliedPluginClasses = [];
117
218
  return this.#currentClass;
118
219
  }
119
220
  }
@@ -1,5 +1,6 @@
1
1
  export default TinyClassManager;
2
- export type PluginDefinition<TBase extends new (...args: any[]) => any, TExtended extends new (...args: any[]) => any> = {
2
+ export type NewTinyClass = new (...args: any[]) => any;
3
+ export type PluginDefinition<TBase extends NewTinyClass, TExtended extends NewTinyClass, AppliedPluginClasses extends NewTinyClass[]> = {
3
4
  /**
4
5
  * - The unique identifier for the plugin.
5
6
  */
@@ -11,31 +12,40 @@ export type PluginDefinition<TBase extends new (...args: any[]) => any, TExtende
11
12
  /**
12
13
  * - Function that receives the base class and returns the extended class.
13
14
  */
14
- apply: (arg0: TBase) => TExtended;
15
+ apply: (arg0: TBase, arg1: AppliedPluginClasses) => TExtended;
15
16
  };
17
+ /** @typedef {new (...args: any[]) => any} NewTinyClass */
16
18
  /**
17
- * @template {new (...args: any[]) => any} TBase
18
- * @template {new (...args: any[]) => any} TExtended
19
+ * @template {NewTinyClass} TBase
20
+ * @template {NewTinyClass} TExtended
21
+ * @template {NewTinyClass[]} AppliedPluginClasses
19
22
  * @typedef {Object} PluginDefinition
20
23
  * @property {string} name - The unique identifier for the plugin.
21
24
  * @property {string[]} [dependencies] - Array of plugin names required before applying this one.
22
- * @property {function(TBase): TExtended} apply - Function that receives the base class and returns the extended class.
25
+ * @property {function(TBase, AppliedPluginClasses): TExtended} apply - Function that receives the base class and returns the extended class.
23
26
  */
24
27
  /**
25
28
  * Manages the composition of a base class with multiple optional plugins (Mixins).
26
- * @template {new (...args: any[]) => any} T
29
+ * @template {NewTinyClass} T
30
+ * @template {T|NewTinyClass} oldT
27
31
  */
28
- declare class TinyClassManager<T extends new (...args: any[]) => any> {
32
+ declare class TinyClassManager<T extends NewTinyClass, oldT extends T | NewTinyClass> {
29
33
  /**
30
34
  * Initializes the manager with a core class.
31
35
  * @param {T} coreClass - The foundational class to be extended.
36
+ * @param {oldT[]} [oldClasses=[]]
32
37
  */
33
- constructor(coreClass: T);
38
+ constructor(coreClass: T, oldClasses?: oldT[]);
34
39
  /**
35
40
  * Gets the list of plugins currently applied to this instance.
36
41
  * @returns {string[]} Array of applied plugin names.
37
42
  */
38
43
  get appliedPlugins(): string[];
44
+ /**
45
+ * Gets the list of plugin classes currently applied to this instance.
46
+ * @returns {AppliedPluginClasses} Array of applied plugin classes.
47
+ */
48
+ get appliedPluginClasses(): [...oldT[], T];
39
49
  /**
40
50
  * Gets the total size of the current class chain hierarchy.
41
51
  * @returns {number} The count of applied plugins plus the core base.
@@ -50,13 +60,23 @@ declare class TinyClassManager<T extends new (...args: any[]) => any> {
50
60
  */
51
61
  get used(): boolean;
52
62
  /**
53
- * Applies a plugin to the class chain if all conditions are met.
54
- * @template {new (...args: any[]) => any} R
55
- * @param {PluginDefinition<T, R>} plugin - The plugin module to be integrated.
56
- * @returns {TinyClassManager<R>} A new manager instance holding the extended class chain.
63
+ * Applies a plugin to the class chain using a definition object.
64
+ * @deprecated Use {@link insert} instead.
65
+ * @template {NewTinyClass} R
66
+ * @param {PluginDefinition<T, R, AppliedPluginClasses>} plugin - The plugin module to be integrated.
67
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance holding the extended class chain.
57
68
  * @throws {Error} Throws if instance is already consumed, plugin is duplicate, or dependencies are missing.
58
69
  */
59
- use<R extends new (...args: any[]) => any>(plugin: PluginDefinition<T, R>): TinyClassManager<R>;
70
+ use<R extends NewTinyClass>(plugin: PluginDefinition<T, R, [...oldT[], T]>): TinyClassManager<R, T | oldT>;
71
+ /**
72
+ * Inserts a plugin directly by passing its apply function.
73
+ * It reads `_tinyDepName` and `_tinyDeps` statically from the returned class.
74
+ * @template {NewTinyClass} R
75
+ * @param {function(T, AppliedPluginClasses): R} applyFn - Function that receives the base class and returns the extended class.
76
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance holding the extended class chain.
77
+ * @throws {Error} Throws if static properties are missing, instance is consumed, or validation fails.
78
+ */
79
+ insert<R extends NewTinyClass>(applyFn: (arg0: T, arg1: [...oldT[], T]) => R): TinyClassManager<R, T | oldT>;
60
80
  /**
61
81
  * Finalizes the composition and returns the fully built class.
62
82
  * @returns {T} The final class representing the last extended version in the chain.
@@ -1,16 +1,20 @@
1
+ /** @typedef {new (...args: any[]) => any} NewTinyClass */
1
2
  /**
2
- * @template {new (...args: any[]) => any} TBase
3
- * @template {new (...args: any[]) => any} TExtended
3
+ * @template {NewTinyClass} TBase
4
+ * @template {NewTinyClass} TExtended
5
+ * @template {NewTinyClass[]} AppliedPluginClasses
4
6
  * @typedef {Object} PluginDefinition
5
7
  * @property {string} name - The unique identifier for the plugin.
6
8
  * @property {string[]} [dependencies] - Array of plugin names required before applying this one.
7
- * @property {function(TBase): TExtended} apply - Function that receives the base class and returns the extended class.
9
+ * @property {function(TBase, AppliedPluginClasses): TExtended} apply - Function that receives the base class and returns the extended class.
8
10
  */
9
11
  /**
10
12
  * Manages the composition of a base class with multiple optional plugins (Mixins).
11
- * @template {new (...args: any[]) => any} T
13
+ * @template {NewTinyClass} T
14
+ * @template {T|NewTinyClass} oldT
12
15
  */
13
16
  class TinyClassManager {
17
+ /** @typedef {[...oldT[], T]} AppliedPluginClasses */
14
18
  /**
15
19
  * @type {Set<string>}
16
20
  * Tracks the names of successfully applied plugins to prevent duplication and check dependencies.
@@ -21,14 +25,33 @@ class TinyClassManager {
21
25
  * @returns {string[]} Array of applied plugin names.
22
26
  */
23
27
  get appliedPlugins() {
28
+ if (this.#used)
29
+ throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
24
30
  return [...this.#appliedPlugins];
25
31
  }
32
+ /**
33
+ * @type {AppliedPluginClasses}
34
+ * Tracks the classes of successfully applied plugins to prevent duplication and check dependencies.
35
+ */
36
+ // @ts-ignore
37
+ #appliedPluginClasses = [];
38
+ /**
39
+ * Gets the list of plugin classes currently applied to this instance.
40
+ * @returns {AppliedPluginClasses} Array of applied plugin classes.
41
+ */
42
+ get appliedPluginClasses() {
43
+ if (this.#used)
44
+ throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
45
+ return [...this.#appliedPluginClasses];
46
+ }
26
47
  /**
27
48
  * Gets the total size of the current class chain hierarchy.
28
49
  * @returns {number} The count of applied plugins plus the core base.
29
50
  */
30
51
  get size() {
31
- return this.#appliedPlugins.size + 1;
52
+ if (this.#used)
53
+ throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
54
+ return this.#appliedPluginClasses.length;
32
55
  }
33
56
  /**
34
57
  * @type {T}
@@ -39,6 +62,8 @@ class TinyClassManager {
39
62
  * Holds the current state of the class chain.
40
63
  */
41
64
  get currentClass() {
65
+ if (this.#used)
66
+ throw new Error(`[TinyClassManager] Cannot get a consumed manager instance.`);
42
67
  return this.#currentClass;
43
68
  }
44
69
  /**
@@ -54,39 +79,97 @@ class TinyClassManager {
54
79
  /**
55
80
  * Initializes the manager with a core class.
56
81
  * @param {T} coreClass - The foundational class to be extended.
82
+ * @param {oldT[]} [oldClasses=[]]
57
83
  */
58
- constructor(coreClass) {
84
+ constructor(coreClass,
85
+ // @ts-ignore
86
+ oldClasses = []) {
59
87
  this.#currentClass = coreClass;
88
+ this.#appliedPluginClasses = [...oldClasses, coreClass];
60
89
  }
61
90
  /**
62
- * Applies a plugin to the class chain if all conditions are met.
63
- * @template {new (...args: any[]) => any} R
64
- * @param {PluginDefinition<T, R>} plugin - The plugin module to be integrated.
65
- * @returns {TinyClassManager<R>} A new manager instance holding the extended class chain.
66
- * @throws {Error} Throws if instance is already consumed, plugin is duplicate, or dependencies are missing.
91
+ * Internal helper to validate dependencies, check conflicts, and transition state.
92
+ * @template {NewTinyClass} R
93
+ * @param {string} name - The plugin name.
94
+ * @param {string[]} deps - The plugin dependencies.
95
+ * @param {R} ExtendedClass - The newly extended class returned by the apply function.
96
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance.
67
97
  */
68
- use(plugin) {
98
+ #validateAndTransition(name, deps, ExtendedClass) {
99
+ // Verifies if the current manager has already been consumed to prevent branching.
69
100
  if (this.#used)
70
101
  throw new Error(`[TinyClassManager] Cannot reuse a consumed manager instance.`);
71
- if (this.#appliedPlugins.has(plugin.name))
72
- throw new Error(`[TinyClassManager] Plugin conflict: "${plugin.name}" is already installed.`);
73
- /**
74
- * @type {string[]}
75
- * Extracted dependencies array with fallback for undefined properties.
76
- */
77
- const deps = plugin.dependencies || [];
102
+ // Checks if the plugin being inserted is already in the applied list.
103
+ if (this.#appliedPlugins.has(name))
104
+ throw new Error(`[TinyClassManager] Plugin conflict: "${name}" is already installed.`);
78
105
  for (const dep of deps) {
79
106
  if (!this.#appliedPlugins.has(dep)) {
80
- throw new Error(`[TinyClassManager] Missing Dependency: "${plugin.name}" requires "${dep}" to be installed first.`);
107
+ throw new Error(`[TinyClassManager] Missing Dependency: "${name}" requires "${dep}" to be installed first.`);
81
108
  }
82
109
  }
83
- const newClassManager = new TinyClassManager(plugin.apply(this.#currentClass));
84
- this.#appliedPlugins.forEach((name) => newClassManager.#appliedPlugins.add(name));
85
- newClassManager.#appliedPlugins.add(plugin.name);
110
+ const newClassManager = new TinyClassManager(ExtendedClass, this.#appliedPluginClasses);
111
+ this.#appliedPlugins.forEach((appliedName) => newClassManager.#appliedPlugins.add(appliedName));
112
+ newClassManager.#appliedPlugins.add(name);
86
113
  this.#used = true;
87
114
  this.#appliedPlugins.clear();
115
+ // @ts-ignore
116
+ this.#appliedPluginClasses = [];
88
117
  return newClassManager;
89
118
  }
119
+ /**
120
+ * Applies a plugin to the class chain using a definition object.
121
+ * @deprecated Use {@link insert} instead.
122
+ * @template {NewTinyClass} R
123
+ * @param {PluginDefinition<T, R, AppliedPluginClasses>} plugin - The plugin module to be integrated.
124
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance holding the extended class chain.
125
+ * @throws {Error} Throws if instance is already consumed, plugin is duplicate, or dependencies are missing.
126
+ */
127
+ use(plugin) {
128
+ /**
129
+ * @type {string[]}
130
+ * Extracted dependencies array with fallback for undefined properties.
131
+ */
132
+ const deps = plugin.dependencies || [];
133
+ /**
134
+ * @type {R}
135
+ * The new class generated by the old object-style apply wrapper.
136
+ */
137
+ const ExtendedClass = plugin.apply(this.#currentClass, this.appliedPluginClasses);
138
+ return this.#validateAndTransition(plugin.name, deps, ExtendedClass);
139
+ }
140
+ /**
141
+ * Inserts a plugin directly by passing its apply function.
142
+ * It reads `_tinyDepName` and `_tinyDeps` statically from the returned class.
143
+ * @template {NewTinyClass} R
144
+ * @param {function(T, AppliedPluginClasses): R} applyFn - Function that receives the base class and returns the extended class.
145
+ * @returns {TinyClassManager<R, T | oldT>} A new manager instance holding the extended class chain.
146
+ * @throws {Error} Throws if static properties are missing, instance is consumed, or validation fails.
147
+ */
148
+ insert(applyFn) {
149
+ /** * @type {R}
150
+ * The extended class returned directly from the provided function.
151
+ */
152
+ const ExtendedClass = applyFn(this.#currentClass, this.appliedPluginClasses);
153
+ /**
154
+ * @type {string}
155
+ * The plugin name extracted from the static property.
156
+ */
157
+ // @ts-ignore
158
+ const pluginName = ExtendedClass._tinyDepName;
159
+ if (!pluginName) {
160
+ throw new Error(`[TinyClassManager] Plugin class must define a static '_tinyDepName' property.`);
161
+ }
162
+ /**
163
+ * @type {string[]}
164
+ * The dependencies extracted from the static property, defaulting to an empty array.
165
+ */
166
+ // @ts-ignore
167
+ const deps = ExtendedClass._tinyDeps ?? [];
168
+ if (!Array.isArray(deps) || !deps.every((name) => typeof name === 'string')) {
169
+ throw new Error(`[TinyClassManager] Plugin class must define a static array of strings in '_tinyDepName' property.`);
170
+ }
171
+ return this.#validateAndTransition(pluginName, deps, ExtendedClass);
172
+ }
90
173
  /**
91
174
  * Finalizes the composition and returns the fully built class.
92
175
  * @returns {T} The final class representing the last extended version in the chain.
@@ -97,6 +180,8 @@ class TinyClassManager {
97
180
  throw new Error(`[TinyClassManager] Cannot build from an already finalized manager.`);
98
181
  this.#used = true;
99
182
  this.#appliedPlugins.clear();
183
+ // @ts-ignore
184
+ this.#appliedPluginClasses = [];
100
185
  return this.#currentClass;
101
186
  }
102
187
  }
@@ -80,22 +80,22 @@ export type ColorTypes = "hex" | "hexa" | "rgb" | "rgba" | "hsl" | "hsla" | "hwb
80
80
  * @template {string} TinyColorValidatorT
81
81
  */
82
82
  declare class TinyColorValidator<TinyColorValidatorT extends string> {
83
- static "__#private@#HEX_REGEX": RegExp;
84
- static "__#private@#HEXA_REGEX": RegExp;
85
- static "__#private@#ALPHA": string;
86
- static "__#private@#NUM_0_255": string;
87
- static "__#private@#NUM_0_360": string;
88
- static "__#private@#NUM_0_100": string;
89
- static "__#private@#RGB_REGEX": RegExp;
90
- static "__#private@#RGBA_REGEX": RegExp;
91
- static "__#private@#HSL_REGEX": RegExp;
92
- static "__#private@#HSLA_REGEX": RegExp;
93
- static "__#private@#HWB_REGEX": RegExp;
94
- static "__#private@#LAB_AB": string;
95
- static "__#private@#LAB_REGEX": RegExp;
96
- static "__#private@#LCH_REGEX": RegExp;
97
- static "__#private@#HTML_COLOR_NAMES": Set<string>;
98
- static "__#private@#SPECIAL_COLOR_NAMES": Set<string>;
83
+ static #HEX_REGEX: RegExp;
84
+ static #HEXA_REGEX: RegExp;
85
+ static #ALPHA: string;
86
+ static #NUM_0_255: string;
87
+ static #NUM_0_360: string;
88
+ static #NUM_0_100: string;
89
+ static #RGB_REGEX: RegExp;
90
+ static #RGBA_REGEX: RegExp;
91
+ static #HSL_REGEX: RegExp;
92
+ static #HSLA_REGEX: RegExp;
93
+ static #HWB_REGEX: RegExp;
94
+ static #LAB_AB: string;
95
+ static #LAB_REGEX: RegExp;
96
+ static #LCH_REGEX: RegExp;
97
+ static #HTML_COLOR_NAMES: Set<string>;
98
+ static #SPECIAL_COLOR_NAMES: Set<string>;
99
99
  /**
100
100
  * Returns all HTML color names as an array.
101
101
  * @returns {string[]}
@@ -2,8 +2,6 @@
2
2
 
3
3
  /**
4
4
  * @typedef {Object} DragAndDropOptions
5
- * @property {HTMLElement} [target=document.body] - The DOM element where drag listeners will be attached. Defaults to `document.body` if `fullscreen` is true or no target is provided.
6
- * @property {boolean} [fullscreen=true] - If true, listeners are attached to the entire page (`document.body`). If false, the `target` must be specified.
7
5
  * @property {string} [hoverClass="dnd-hover"] - CSS class applied to the target element while files are being dragged over it.
8
6
  * @property {(files: FileList, event: DragEvent) => void} [onDrop] - Callback function executed when files are dropped onto the target.
9
7
  * @property {(event: DragEvent) => void} [onEnter] - Optional callback triggered when dragging enters the target area.
@@ -17,14 +15,12 @@
17
15
  * It handles the drag lifecycle (enter, over, leave, drop) and provides hooks for developers to handle file uploads or UI changes.
18
16
  *
19
17
  * @class
18
+ * @template {HTMLElement} HTMLTarget
20
19
  */
21
20
  class TinyDragDropDetector {
22
- /** @type {HTMLElement} */
21
+ /** @type {HTMLTarget} */
23
22
  #target;
24
23
 
25
- /** @type {boolean} */
26
- #fullscreen;
27
-
28
24
  /** @type {string} */
29
25
  #hoverClass;
30
26
 
@@ -46,31 +42,19 @@ class TinyDragDropDetector {
46
42
  /**
47
43
  * Creates a new instance of TinyDragDropDetector to handle drag-and-drop file detection.
48
44
  *
49
- * @param {DragAndDropOptions} [options={}] - Configuration options for the detector.
45
+ * @param {HTMLTarget} target - The DOM element where drag listeners will be attached.
46
+ * @param {DragAndDropOptions} options - Configuration options for the detector.
50
47
  * @throws {TypeError} If `target` is not an HTMLElement.
51
- * @throws {TypeError} If `fullscreen` is not a boolean.
52
48
  * @throws {TypeError} If `hoverClass` is not a string.
53
49
  * @throws {TypeError} If `onDrop` is defined but not a function.
54
50
  * @throws {TypeError} If `onEnter` is defined but not a function.
55
51
  * @throws {TypeError} If `onLeave` is defined but not a function.
56
52
  */
57
- constructor(options = {}) {
58
- const {
59
- target,
60
- fullscreen = true,
61
- hoverClass = 'dnd-hover',
62
- onDrop,
63
- onEnter,
64
- onLeave,
65
- } = options;
66
-
67
- // Validate fullscreen
68
- if (typeof fullscreen !== 'boolean')
69
- throw new TypeError('The "fullscreen" option must be a boolean.');
53
+ constructor(target, options) {
54
+ const { hoverClass = 'dnd-hover', onDrop, onEnter, onLeave } = options;
70
55
 
71
56
  // Validate target
72
- const resolvedTarget = fullscreen ? document.body : target || document.body;
73
- if (!(resolvedTarget instanceof HTMLElement))
57
+ if (!(target instanceof HTMLElement))
74
58
  throw new TypeError('The "target" option must be an instance of HTMLElement.');
75
59
 
76
60
  // Validate hoverClass
@@ -90,8 +74,7 @@ class TinyDragDropDetector {
90
74
  throw new TypeError('The "onLeave" option must be a function.');
91
75
 
92
76
  // Store properties
93
- this.#target = resolvedTarget;
94
- this.#fullscreen = fullscreen;
77
+ this.#target = target;
95
78
  this.#hoverClass = hoverClass;
96
79
 
97
80
  this.#onDropCallback = onDrop || (() => {});
@@ -112,7 +95,7 @@ class TinyDragDropDetector {
112
95
 
113
96
  /**
114
97
  * Returns the current target DOM element where the listeners are attached.
115
- * @returns {HTMLElement}
98
+ * @returns {HTMLTarget}
116
99
  */
117
100
  getTarget() {
118
101
  return this.#target;
@@ -126,14 +109,6 @@ class TinyDragDropDetector {
126
109
  return this.#hoverClass;
127
110
  }
128
111
 
129
- /**
130
- * Indicates whether the detector is operating in fullscreen mode.
131
- * @returns {boolean}
132
- */
133
- isFullScreen() {
134
- return this.#fullscreen;
135
- }
136
-
137
112
  /**
138
113
  * Returns whether a drag operation is currently active over the target.
139
114
  * @returns {boolean}