tiny-essentials 1.5.1 → 1.7.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.
- package/dist/TinyBasicsEs.js +59 -0
- package/dist/TinyBasicsEs.min.js +1 -1
- package/dist/TinyEssentials.js +145 -15
- package/dist/TinyEssentials.min.js +1 -1
- package/dist/TinyPromiseQueue.js +86 -15
- package/dist/TinyPromiseQueue.min.js +1 -1
- package/dist/aiMarker.css +4 -0
- package/dist/aiMarker.min.css +1 -0
- package/dist/v1/basics/index.cjs +1 -0
- package/dist/v1/basics/index.d.mts +2 -1
- package/dist/v1/basics/index.mjs +2 -2
- package/dist/v1/basics/text.cjs +59 -0
- package/dist/v1/basics/text.d.mts +14 -0
- package/dist/v1/basics/text.mjs +52 -0
- package/dist/v1/index.cjs +1 -0
- package/dist/v1/index.d.mts +2 -1
- package/dist/v1/index.mjs +2 -2
- package/dist/v1/libs/TinyPromiseQueue.cjs +86 -15
- package/dist/v1/libs/TinyPromiseQueue.d.mts +9 -0
- package/dist/v1/libs/TinyPromiseQueue.mjs +78 -15
- package/docs/basics/text.md +91 -0
- package/docs/libs/TinyPromiseQueue.md +95 -0
- package/package.json +5 -2
|
@@ -13,6 +13,7 @@ class TinyPromiseQueue {
|
|
|
13
13
|
* @property {(value: any) => any} resolve - The resolve function from the Promise.
|
|
14
14
|
* @property {(reason?: any) => any} reject - The reject function from the Promise.
|
|
15
15
|
* @property {string|undefined} [id] - Optional identifier for the task.
|
|
16
|
+
* @property {string|null|undefined} [marker] - Optional marker for the task.
|
|
16
17
|
* @property {number|null|undefined} [delay] - Optional delay (in ms) before the task is executed.
|
|
17
18
|
*/
|
|
18
19
|
/** @type {Array<QueuedTask>} */
|
|
@@ -31,22 +32,26 @@ class TinyPromiseQueue {
|
|
|
31
32
|
return this.#running;
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
|
-
* Processes the
|
|
35
|
-
*
|
|
35
|
+
* Processes the a normal task.
|
|
36
|
+
*
|
|
37
|
+
* @param {QueuedTask} data
|
|
36
38
|
*
|
|
37
39
|
* @returns {Promise<void>}
|
|
38
40
|
*/
|
|
39
|
-
async #
|
|
40
|
-
if (this.#running || this.#queue.length === 0)
|
|
41
|
-
return;
|
|
42
|
-
this.#running = true;
|
|
43
|
-
const data = this.#queue.shift();
|
|
41
|
+
async #normalProcessQueue(data) {
|
|
44
42
|
if (data &&
|
|
45
43
|
typeof data.task === 'function' &&
|
|
46
44
|
typeof data.resolve === 'function' &&
|
|
47
45
|
typeof data.reject === 'function') {
|
|
48
46
|
const { task, resolve, reject, delay, id } = data;
|
|
49
47
|
try {
|
|
48
|
+
if (id && this.#blacklist.has(id)) {
|
|
49
|
+
reject(new Error('The function was canceled on TinyPromiseQueue.'));
|
|
50
|
+
this.#blacklist.delete(id);
|
|
51
|
+
this.#running = false;
|
|
52
|
+
this.#processQueue();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
50
55
|
if (delay && id) {
|
|
51
56
|
await new Promise((resolveDelay) => {
|
|
52
57
|
const timeoutId = setTimeout(() => {
|
|
@@ -56,13 +61,6 @@ class TinyPromiseQueue {
|
|
|
56
61
|
this.#timeouts[id] = timeoutId;
|
|
57
62
|
});
|
|
58
63
|
}
|
|
59
|
-
if (id && this.#blacklist.has(id)) {
|
|
60
|
-
reject(new Error('The function was canceled on TinyPromiseQueue.'));
|
|
61
|
-
this.#blacklist.delete(id);
|
|
62
|
-
this.#running = false;
|
|
63
|
-
this.#processQueue();
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
64
|
const result = await task();
|
|
67
65
|
resolve(result);
|
|
68
66
|
}
|
|
@@ -75,6 +73,54 @@ class TinyPromiseQueue {
|
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Processes a group task.
|
|
78
|
+
*
|
|
79
|
+
* @returns {Promise<void>}
|
|
80
|
+
*/
|
|
81
|
+
async #groupProcessQueue() {
|
|
82
|
+
/** @type {Array<QueuedTask>} */
|
|
83
|
+
const grouped = [];
|
|
84
|
+
while (this.#queue.length && this.#queue[0]?.marker === 'POINT_MARKER') {
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
grouped.push(this.#queue.shift());
|
|
87
|
+
}
|
|
88
|
+
if (grouped.length === 0) {
|
|
89
|
+
this.#running = false;
|
|
90
|
+
this.#processQueue();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
await Promise.all(grouped.map(({ task, resolve, reject, id }) => new Promise(async (pResolve) => {
|
|
94
|
+
if (id && this.#blacklist.has(id)) {
|
|
95
|
+
this.#blacklist.delete(id);
|
|
96
|
+
reject(new Error('The function was canceled on TinyPromiseQueue.'));
|
|
97
|
+
pResolve(true);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
await task().then(resolve).catch(reject);
|
|
101
|
+
pResolve(true);
|
|
102
|
+
})));
|
|
103
|
+
this.#running = false;
|
|
104
|
+
this.#processQueue();
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Processes the next task in the queue if not already running.
|
|
108
|
+
* Ensures tasks are executed in order, one at a time.
|
|
109
|
+
*
|
|
110
|
+
* @returns {Promise<void>}
|
|
111
|
+
*/
|
|
112
|
+
async #processQueue() {
|
|
113
|
+
if (this.#running || this.#queue.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
this.#running = true;
|
|
116
|
+
if (typeof this.#queue[0]?.marker !== 'string' || this.#queue[0]?.marker !== 'POINT_MARKER') {
|
|
117
|
+
const data = this.#queue.shift();
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
this.#normalProcessQueue(data);
|
|
120
|
+
}
|
|
121
|
+
else
|
|
122
|
+
this.#groupProcessQueue();
|
|
123
|
+
}
|
|
78
124
|
/**
|
|
79
125
|
* Returns the index of a task by its ID.
|
|
80
126
|
*
|
|
@@ -112,6 +158,22 @@ class TinyPromiseQueue {
|
|
|
112
158
|
const [item] = this.#queue.splice(fromIndex, 1);
|
|
113
159
|
this.#queue.splice(toIndex, 0, item);
|
|
114
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Inserts a point in the queue where subsequent tasks will be grouped and executed together in a Promise.all.
|
|
163
|
+
* If the queue is currently empty, behaves like a regular promise.
|
|
164
|
+
*
|
|
165
|
+
* @param {(...args: any[]) => Promise<any>|Promise<any>} task A function that returns a Promise.
|
|
166
|
+
* @param {string} [id] Optional ID to identify the task in the queue.
|
|
167
|
+
* @returns {Promise<any>} A Promise that resolves or rejects with the result of the task once it's processed.
|
|
168
|
+
*/
|
|
169
|
+
async enqueuePoint(task, id) {
|
|
170
|
+
if (!this.#running)
|
|
171
|
+
return task();
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
this.#queue.push({ marker: 'POINT_MARKER', task, resolve, reject, id });
|
|
174
|
+
this.#processQueue();
|
|
175
|
+
});
|
|
176
|
+
}
|
|
115
177
|
/**
|
|
116
178
|
* Adds a new async task to the queue and ensures it runs in order after previous tasks.
|
|
117
179
|
* Optionally, a delay can be added before the task is executed.
|
|
@@ -148,7 +210,8 @@ class TinyPromiseQueue {
|
|
|
148
210
|
}
|
|
149
211
|
const index = this.getIndexById(id);
|
|
150
212
|
if (index !== -1) {
|
|
151
|
-
this.#queue.splice(index, 1);
|
|
213
|
+
const [removed] = this.#queue.splice(index, 1);
|
|
214
|
+
removed?.reject?.(new Error('The function was canceled on TinyPromiseQueue.'));
|
|
152
215
|
cancelled = true;
|
|
153
216
|
}
|
|
154
217
|
if (cancelled)
|
package/docs/basics/text.md
CHANGED
|
@@ -36,3 +36,94 @@ toTitleCase('hello world'); // → "Hello World"
|
|
|
36
36
|
```js
|
|
37
37
|
toTitleCaseLowerFirst('hello world'); // → "hello World"
|
|
38
38
|
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🎯 `addAiMarkerShortcut(key = 'a')`
|
|
43
|
+
|
|
44
|
+
Enables a keyboard shortcut (`Ctrl + Alt + [key]`) that toggles a CSS class on the `<body>` element. Useful for marking or highlighting AI-generated content dynamically.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 🔤 Syntax
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
addAiMarkerShortcut(key)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### 🧾 Parameters
|
|
57
|
+
|
|
58
|
+
| Name | Type | Default | Description |
|
|
59
|
+
| ----- | -------- | ------- | ---------------------------------------------------------------------------- |
|
|
60
|
+
| `key` | `string` | `'a'` | The character key to use in combination with `Ctrl + Alt`. Case-insensitive. |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### ⚙️ Behavior
|
|
65
|
+
|
|
66
|
+
* ⌨️ When the user presses `Ctrl + Alt + [key]`, the function toggles the CSS class `detect-made-by-ai` on the `<body>` element.
|
|
67
|
+
* 🧠 The shortcut only works in environments where the DOM is available (e.g., browsers).
|
|
68
|
+
* 🚫 If `document.body` is not available when the shortcut is used (e.g., if the DOM hasn't finished loading), a warning is logged and nothing happens.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### ❗ Error Handling
|
|
73
|
+
|
|
74
|
+
Two types of errors are handled:
|
|
75
|
+
|
|
76
|
+
1. 🧱 **Non-browser environment (e.g., Node.js):**
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
[AiMarkerShortcut] Environment does not support the DOM. This function must be run in a browser.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
2. 🕓 **DOM not fully loaded at the time of shortcut:**
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
[AiMarkerShortcut] <body> element not found. Cannot toggle class. Ensure the DOM is fully loaded when using the shortcut.
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### 🧪 Example
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
addAiMarkerShortcut(); // Uses default key 'a'
|
|
94
|
+
// Pressing Ctrl + Alt + A toggles the class "detect-made-by-ai" on <body>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### 🎨 CSS Integration Example
|
|
100
|
+
|
|
101
|
+
Define the class in your stylesheet to make the toggle visually meaningful:
|
|
102
|
+
|
|
103
|
+
```css
|
|
104
|
+
body.detect-made-by-ai .ai-content {
|
|
105
|
+
outline: 2px dashed red;
|
|
106
|
+
background-color: rgba(255, 0, 0, 0.05);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 💡 Tip
|
|
113
|
+
|
|
114
|
+
To avoid the `<body>` warning, make sure you only call the function after the DOM is ready:
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
118
|
+
addAiMarkerShortcut();
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 📂 CSS Templates
|
|
123
|
+
|
|
124
|
+
You can use a pre-built CSS template for the `detect-made-by-ai` class, available in the following files:
|
|
125
|
+
|
|
126
|
+
* `/dist/aiMarker.min.css` – A minified version of the CSS for production use.
|
|
127
|
+
* `/dist/aiMarker.css` – The non-minified version for easier readability and customization.
|
|
128
|
+
|
|
129
|
+
Simply include the appropriate file in your project to style the elements marked with the `detect-made-by-ai` class.
|
|
@@ -22,6 +22,8 @@ Returns whether the queue is currently processing a task.
|
|
|
22
22
|
#### Returns:
|
|
23
23
|
- `boolean`: `true` if the queue is processing a task, otherwise `false`.
|
|
24
24
|
|
|
25
|
+
---
|
|
26
|
+
|
|
25
27
|
### `getIndexById(id)` 🔍
|
|
26
28
|
|
|
27
29
|
Returns the index of a task in the queue by its ID.
|
|
@@ -32,6 +34,8 @@ Returns the index of a task in the queue by its ID.
|
|
|
32
34
|
#### Returns:
|
|
33
35
|
- `number`: The index of the task in the queue, or `-1` if not found.
|
|
34
36
|
|
|
37
|
+
---
|
|
38
|
+
|
|
35
39
|
### `getQueuedIds()` 📋
|
|
36
40
|
|
|
37
41
|
Returns a list of IDs for all tasks currently in the queue.
|
|
@@ -39,6 +43,8 @@ Returns a list of IDs for all tasks currently in the queue.
|
|
|
39
43
|
#### Returns:
|
|
40
44
|
- `Array<{ index: number, id: string }>`: An array of task IDs and their corresponding indices.
|
|
41
45
|
|
|
46
|
+
---
|
|
47
|
+
|
|
42
48
|
### `reorderQueue(fromIndex, toIndex)` 🔄
|
|
43
49
|
|
|
44
50
|
Reorders a task in the queue from one index to another.
|
|
@@ -50,6 +56,8 @@ Reorders a task in the queue from one index to another.
|
|
|
50
56
|
#### Returns:
|
|
51
57
|
- `void`: This method does not return anything.
|
|
52
58
|
|
|
59
|
+
---
|
|
60
|
+
|
|
53
61
|
### `enqueue(task, delay, id)` ⏳
|
|
54
62
|
|
|
55
63
|
Adds a new async task to the queue and ensures it runs in order after previous tasks. Optionally, a delay can be added before the task is executed.
|
|
@@ -65,6 +73,26 @@ If the task is canceled before execution, it will be rejected with the message:
|
|
|
65
73
|
#### Returns:
|
|
66
74
|
- `Promise<any>`: A promise that resolves or rejects with the result of the task once it's processed.
|
|
67
75
|
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### `enqueuePoint(task, id)` 🪢
|
|
79
|
+
|
|
80
|
+
Adds an async task to a parallel group in the queue. All tasks added with `enqueuePoint` before the next `enqueue` will be executed **simultaneously**, but only after all previous tasks in the queue have completed.
|
|
81
|
+
|
|
82
|
+
These grouped tasks share a "concurrent checkpoint" and will run using `Promise.all`. Each task resolves or rejects independently.
|
|
83
|
+
|
|
84
|
+
If a task is canceled before execution, it will be rejected with the message:
|
|
85
|
+
**"The function was canceled on TinyPromiseQueue."**
|
|
86
|
+
|
|
87
|
+
#### Parameters:
|
|
88
|
+
- `task` (`Function`): A function that returns a `Promise` to be executed sequentially.
|
|
89
|
+
- `id` (`string`): Optional ID to identify the task in the queue.
|
|
90
|
+
|
|
91
|
+
#### Returns:
|
|
92
|
+
- `Promise<any>`: A promise that resolves or rejects with the result of the task once it's processed.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
68
96
|
### `cancelTask(id)` ❌
|
|
69
97
|
|
|
70
98
|
Cancels a scheduled delay and removes the task from the queue. Adds the ID to a blacklist so the task is skipped if already being processed.
|
|
@@ -113,6 +141,73 @@ setTimeout(() => {
|
|
|
113
141
|
}, 60);
|
|
114
142
|
```
|
|
115
143
|
|
|
144
|
+
```js
|
|
145
|
+
import { TinyPromiseQueue } from './TinyPromiseQueue';
|
|
146
|
+
|
|
147
|
+
const queue = new TinyPromiseQueue();
|
|
148
|
+
await new Promise((resolve) => {
|
|
149
|
+
|
|
150
|
+
// Task generator with color-coded logs
|
|
151
|
+
function createTask(name, duration = 500) {
|
|
152
|
+
return () =>
|
|
153
|
+
new Promise((resolve) => {
|
|
154
|
+
console.log(`\x1b[34m[STARTED]\x1b[0m \x1b[36m${name}\x1b[0m`);
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
console.log(`\x1b[32m[FINISHED]\x1b[0m \x1b[36m${name}\x1b[0m`);
|
|
157
|
+
resolve(name);
|
|
158
|
+
}, duration);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Function to simulate a parallel group of enqueues
|
|
163
|
+
const parallelEnqueueGroup = (groupName, delayStart = 0) => {
|
|
164
|
+
const count = Math.floor(Math.random() * (15 - 1 + 1) + 1);
|
|
165
|
+
for (let i = 1; i <= count; i++) {
|
|
166
|
+
const taskName = `${groupName}-${i}`;
|
|
167
|
+
queue.enqueue(createTask(taskName, 300 + i * 50), delayStart, taskName);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Main enqueue block
|
|
172
|
+
queue.enqueue(createTask('Init-1', 400), 50, 'init-1');
|
|
173
|
+
queue.enqueue(createTask('Init-2', 400), 0, 'init-2');
|
|
174
|
+
|
|
175
|
+
// Simulate enqueues from other contexts "in parallel"
|
|
176
|
+
parallelEnqueueGroup('Alpha', 80); // Starts after 80ms
|
|
177
|
+
parallelEnqueueGroup('Beta', 120); // Starts after 120ms
|
|
178
|
+
parallelEnqueueGroup('Gamma', 250); // Starts after 250ms
|
|
179
|
+
parallelEnqueueGroup('Delta', 180); // Starts after 180ms
|
|
180
|
+
parallelEnqueueGroup('Epsilon', 300); // Starts after 300ms
|
|
181
|
+
parallelEnqueueGroup('Zeta', 160); // Starts after 160ms
|
|
182
|
+
parallelEnqueueGroup('Eta', 90); // Starts after 90ms
|
|
183
|
+
parallelEnqueueGroup('Theta', 220); // Starts after 220ms
|
|
184
|
+
parallelEnqueueGroup('Iota', 140); // Starts after 140ms
|
|
185
|
+
parallelEnqueueGroup('Kappa', 400); // Starts after 400ms
|
|
186
|
+
parallelEnqueueGroup('Lambda', 190); // Starts after 190ms
|
|
187
|
+
parallelEnqueueGroup('Mu', 260); // Starts after 260ms
|
|
188
|
+
parallelEnqueueGroup('Nu', 110); // Starts after 110ms
|
|
189
|
+
parallelEnqueueGroup('Xi', 330); // Starts after 330ms
|
|
190
|
+
parallelEnqueueGroup('Omicron', 170); // Starts after 170ms
|
|
191
|
+
parallelEnqueueGroup('Pi', 280); // Starts after 280ms
|
|
192
|
+
parallelEnqueueGroup('Rho', 70); // Starts after 70ms
|
|
193
|
+
parallelEnqueueGroup('Sigma', 360); // Starts after 360ms
|
|
194
|
+
parallelEnqueueGroup('Tau', 130); // Starts after 130ms
|
|
195
|
+
parallelEnqueueGroup('Upsilon', 240); // Starts after 240ms
|
|
196
|
+
parallelEnqueueGroup('Phi', 310); // Starts after 310ms
|
|
197
|
+
parallelEnqueueGroup('Chi', 100); // Starts after 100ms
|
|
198
|
+
parallelEnqueueGroup('Psi', 200); // Starts after 200ms
|
|
199
|
+
parallelEnqueueGroup('Omega', 50); // Starts after 50ms
|
|
200
|
+
|
|
201
|
+
// Final task to confirm everything executed
|
|
202
|
+
setTimeout(() => {
|
|
203
|
+
queue.enqueue(createTask('Finalizer', 500), 0, 'finalizer').then(() => {
|
|
204
|
+
console.log('\x1b[35m[QUEUE COMPLETE]\x1b[0m All tasks have been processed.');
|
|
205
|
+
resolve();
|
|
206
|
+
});
|
|
207
|
+
}, 250);
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
116
211
|
### Explanation 🧩:
|
|
117
212
|
1. **Task Creation**: Tasks are created with a name and an optional duration (in ms). The task logs its start and finish times 🕰️.
|
|
118
213
|
2. **Task Execution**: Tasks are enqueued one at a time, ensuring they run in the order they were added 🔁.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-essentials",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "npm run test:mjs && npm run test:cjs && npm run test:js",
|
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
"fix:prettier:rollup.config": "prettier --write ./rollup.config.mjs",
|
|
16
16
|
"fix:prettier:webpack.config": "prettier --write ./webpack.config.mjs",
|
|
17
17
|
"auto-build": "npm run build",
|
|
18
|
-
"build": "
|
|
18
|
+
"build": "npm run build:js && npm run build:css",
|
|
19
|
+
"build:js": "tsc -p tsconfig.json && rollup -c && webpack --mode production",
|
|
19
20
|
"build-clean": "npm run clean && npm run build",
|
|
20
21
|
"build-dist": "npm run build",
|
|
22
|
+
"build:css": "sass src/v1/scss/aiMarker.scss dist/aiMarker.css --no-source-map && sass src/v1/scss/aiMarker.scss dist/aiMarker.min.css --no-source-map --style=compressed",
|
|
21
23
|
"clean": "rm -rf dist",
|
|
22
24
|
"prepublishOnly": "npm run build"
|
|
23
25
|
},
|
|
@@ -80,6 +82,7 @@
|
|
|
80
82
|
"prettier": "3.5.3",
|
|
81
83
|
"rollup": "^4.40.0",
|
|
82
84
|
"rollup-preserve-directives": "^1.1.3",
|
|
85
|
+
"sass": "^1.87.0",
|
|
83
86
|
"tinycolor2": "^1.6.0",
|
|
84
87
|
"tslib": "^2.8.1",
|
|
85
88
|
"type-fest": "^4.40.0",
|