tiny-essentials 1.10.2 → 1.12.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 (106) hide show
  1. package/README.md +13 -4
  2. package/dist/node_modules/firebase-functions/lib/common/trace.cjs +82 -0
  3. package/dist/node_modules/firebase-functions/lib/logger/common.cjs +57 -0
  4. package/dist/node_modules/firebase-functions/lib/logger/index.cjs +158 -0
  5. package/dist/{TinyEssentials.js → v1/TinyBasicsEs.js} +1726 -1362
  6. package/dist/v1/TinyBasicsEs.min.js +2 -0
  7. package/dist/v1/TinyDragDropDetector.js +307 -0
  8. package/dist/v1/TinyDragDropDetector.min.js +1 -0
  9. package/dist/{TinyBasicsEs.js → v1/TinyDragger.js} +1004 -506
  10. package/dist/v1/TinyDragger.min.js +2 -0
  11. package/dist/v1/TinyEssentials.js +7938 -0
  12. package/dist/v1/TinyEssentials.min.js +2 -0
  13. package/dist/v1/TinyEssentials.min.js.LICENSE.txt +8 -0
  14. package/dist/v1/TinyNotifyCenter.js +493 -0
  15. package/dist/v1/TinyNotifyCenter.min.js +1 -0
  16. package/dist/v1/TinyToastNotify.js +441 -0
  17. package/dist/v1/TinyToastNotify.min.js +1 -0
  18. package/dist/v1/TinyUploadClicker.js +5235 -0
  19. package/dist/v1/TinyUploadClicker.min.js +2 -0
  20. package/dist/v1/TinyUploadClicker.min.js.LICENSE.txt +8 -0
  21. package/dist/v1/basics/fileManager.cjs +524 -0
  22. package/dist/v1/basics/fileManager.d.mts +209 -0
  23. package/dist/v1/basics/fileManager.mjs +443 -0
  24. package/dist/v1/basics/fullScreen.cjs +134 -0
  25. package/dist/v1/basics/fullScreen.d.mts +8 -0
  26. package/dist/v1/basics/fullScreen.mjs +121 -0
  27. package/dist/v1/basics/html.cjs +262 -0
  28. package/dist/v1/basics/html.d.mts +63 -0
  29. package/dist/v1/basics/html.mjs +208 -0
  30. package/dist/v1/basics/index.cjs +40 -0
  31. package/dist/v1/basics/index.d.mts +38 -1
  32. package/dist/v1/basics/index.mjs +4 -1
  33. package/dist/v1/build/TinyDragDropDetector.cjs +7 -0
  34. package/dist/v1/build/TinyDragDropDetector.d.mts +3 -0
  35. package/dist/v1/build/TinyDragDropDetector.mjs +2 -0
  36. package/dist/v1/build/TinyDragger.cjs +7 -0
  37. package/dist/v1/build/TinyDragger.d.mts +3 -0
  38. package/dist/v1/build/TinyDragger.mjs +2 -0
  39. package/dist/v1/build/TinyNotifyCenter.cjs +7 -0
  40. package/dist/v1/build/TinyNotifyCenter.d.mts +3 -0
  41. package/dist/v1/build/TinyNotifyCenter.mjs +2 -0
  42. package/dist/v1/build/TinyToastNotify.cjs +7 -0
  43. package/dist/v1/build/TinyToastNotify.d.mts +3 -0
  44. package/dist/v1/build/TinyToastNotify.mjs +2 -0
  45. package/dist/v1/build/TinyUploadClicker.cjs +7 -0
  46. package/dist/v1/build/TinyUploadClicker.d.mts +3 -0
  47. package/dist/v1/build/TinyUploadClicker.mjs +2 -0
  48. package/dist/v1/css/TinyDraggerExample.css +21 -0
  49. package/dist/v1/css/TinyDraggerExample.min.css +1 -0
  50. package/dist/v1/css/TinyNotify.css +350 -0
  51. package/dist/v1/css/TinyNotify.min.css +1 -0
  52. package/dist/v1/index.cjs +48 -0
  53. package/dist/v1/index.d.mts +42 -1
  54. package/dist/v1/index.mjs +8 -1
  55. package/dist/v1/libs/TinyDragDropDetector.cjs +268 -0
  56. package/dist/v1/libs/TinyDragDropDetector.d.mts +123 -0
  57. package/dist/v1/libs/TinyDragDropDetector.mjs +228 -0
  58. package/dist/v1/libs/TinyDragger.cjs +801 -0
  59. package/dist/v1/libs/TinyDragger.d.mts +300 -0
  60. package/dist/v1/libs/TinyDragger.mjs +689 -0
  61. package/dist/v1/libs/TinyNotifyCenter.cjs +454 -0
  62. package/dist/v1/libs/TinyNotifyCenter.d.mts +175 -0
  63. package/dist/v1/libs/TinyNotifyCenter.mjs +413 -0
  64. package/dist/v1/libs/TinyToastNotify.cjs +402 -0
  65. package/dist/v1/libs/TinyToastNotify.d.mts +165 -0
  66. package/dist/v1/libs/TinyToastNotify.mjs +352 -0
  67. package/dist/v1/libs/TinyUploadClicker.cjs +223 -0
  68. package/dist/v1/libs/TinyUploadClicker.d.mts +80 -0
  69. package/dist/v1/libs/TinyUploadClicker.mjs +182 -0
  70. package/docs/{README.md → v1/README.md} +8 -0
  71. package/docs/v1/basics/fileManager.md +222 -0
  72. package/docs/v1/basics/fullScreen.md +183 -0
  73. package/docs/v1/basics/html.md +243 -0
  74. package/docs/{basics → v1/basics}/text.md +2 -2
  75. package/docs/v1/libs/TinyDragDropDetector.md +143 -0
  76. package/docs/v1/libs/TinyDragger.md +415 -0
  77. package/docs/{libs → v1/libs}/TinyLevelUp.md +1 -1
  78. package/docs/v1/libs/TinyNotifyCenter.md +311 -0
  79. package/docs/v1/libs/TinyToastNotify.md +309 -0
  80. package/docs/v1/libs/TinyUploadClicker.md +108 -0
  81. package/package.json +14 -2
  82. package/dist/TinyBasicsEs.min.js +0 -2
  83. package/dist/TinyEssentials.min.js +0 -2
  84. package/dist/v1/libs/TinyRateLimit.cjs +0 -196
  85. package/dist/v1/libs/TinyRateLimit.d.mts +0 -86
  86. package/dist/v1/libs/TinyRateLimit.mjs +0 -171
  87. /package/dist/{ColorSafeStringify.js → v1/ColorSafeStringify.js} +0 -0
  88. /package/dist/{ColorSafeStringify.min.js → v1/ColorSafeStringify.min.js} +0 -0
  89. /package/dist/{TinyBasicsEs.min.js.LICENSE.txt → v1/TinyBasicsEs.min.js.LICENSE.txt} +0 -0
  90. /package/dist/{TinyEssentials.min.js.LICENSE.txt → v1/TinyDragger.min.js.LICENSE.txt} +0 -0
  91. /package/dist/{TinyLevelUp.js → v1/TinyLevelUp.js} +0 -0
  92. /package/dist/{TinyLevelUp.min.js → v1/TinyLevelUp.min.js} +0 -0
  93. /package/dist/{TinyPromiseQueue.js → v1/TinyPromiseQueue.js} +0 -0
  94. /package/dist/{TinyPromiseQueue.min.js → v1/TinyPromiseQueue.min.js} +0 -0
  95. /package/dist/{TinyRateLimiter.js → v1/TinyRateLimiter.js} +0 -0
  96. /package/dist/{TinyRateLimiter.min.js → v1/TinyRateLimiter.min.js} +0 -0
  97. /package/dist/{aiMarker.css → v1/css/aiMarker.css} +0 -0
  98. /package/dist/{aiMarker.min.css → v1/css/aiMarker.min.css} +0 -0
  99. /package/docs/{basics → v1/basics}/array.md +0 -0
  100. /package/docs/{basics → v1/basics}/asyncReplace.md +0 -0
  101. /package/docs/{basics → v1/basics}/clock.md +0 -0
  102. /package/docs/{basics → v1/basics}/objFilter.md +0 -0
  103. /package/docs/{basics → v1/basics}/simpleMath.md +0 -0
  104. /package/docs/{libs → v1/libs}/ColorSafeStringify.md +0 -0
  105. /package/docs/{libs → v1/libs}/TinyPromiseQueue.md +0 -0
  106. /package/docs/{libs → v1/libs}/TinyRateLimiter.md +0 -0
@@ -0,0 +1,182 @@
1
+ /**
2
+ * @typedef {Object} UploaderConfig
3
+ *
4
+ * @property {string | HTMLElement | Array<string | HTMLElement>} triggers -
5
+ * Single or multiple elements (or selectors) that will act as upload triggers.
6
+ *
7
+ * @property {boolean} [multiple=false] -
8
+ * Whether to allow selection of multiple files.
9
+ *
10
+ * @property {string|string[]} [accept=""] -
11
+ * A comma-separated list of accepted file types (e.g., ".png,.jpg" or "image/*").
12
+ *
13
+ * @property {Record<string, string>} [inputAttributes={}] -
14
+ * Additional attributes to apply to the created `<input type="file">`.
15
+ *
16
+ * @property {Partial<CSSStyleDeclaration>} [inputStyles={ display: 'none' }] -
17
+ * Inline CSS styles to apply to the hidden input. Default hides the element.
18
+ *
19
+ * @property {((triggerElement: HTMLElement) => void)|null} [onClick=null] -
20
+ * Callback executed when a trigger is clicked (before the file dialog opens).
21
+ *
22
+ * @property {((files: FileList, triggerElement: HTMLElement) => void)|null} [onFileLoad=null] -
23
+ * Callback executed when files are selected through the file input.
24
+ */
25
+ import { isJsonObject } from '../index.mjs';
26
+ /**
27
+ * TinyUploadClicker is a lightweight utility class for attaching custom clickable elements
28
+ * (like buttons, divs, icons, etc.) that trigger hidden file input elements.
29
+ *
30
+ * It provides full control over the input file element without needing to display it,
31
+ * and allows per-trigger customization, style injection, and event handling.
32
+ *
33
+ * Each trigger element creates its own associated hidden file input, enabling multiple
34
+ * upload zones with different behaviors. You can handle `onClick` and `onFileLoad` callbacks,
35
+ * define accepted file types, allow multiple selections, and cleanly destroy everything via `destroy()`.
36
+ *
37
+ * Designed for maximum flexibility in pure JavaScript environments, including dynamic UI rendering.
38
+ *
39
+ * @example
40
+ * const uploader = new TinyUploadClicker({
41
+ * triggers: '#uploadBtn',
42
+ * accept: ['.png', '.jpg'],
43
+ * multiple: true,
44
+ * inputAttributes: { 'data-tracker': 'upload' },
45
+ * inputStyles: { display: 'none' },
46
+ * onClick: (el) => console.log('Trigger clicked:', el),
47
+ * onFileLoad: (files, el) => console.log('Files selected:', files)
48
+ * });
49
+ *
50
+ * // Later, if needed:
51
+ * uploader.destroy();
52
+ */
53
+ class TinyUploadClicker {
54
+ /** @type {UploaderConfig} */
55
+ #config;
56
+ /** @type {Array<HTMLElement|Element|null>} */
57
+ #triggerElements = [];
58
+ /** @type {WeakMap<HTMLElement, HTMLInputElement>} */
59
+ #inputs = new WeakMap();
60
+ /** @type {(ev: MouseEvent) => void} */
61
+ #boundClick;
62
+ /**
63
+ * Creates a new instance of TinyUploadClicker.
64
+ *
65
+ * @param {UploaderConfig} options - Configuration object for customizing the uploader behavior and appearance.
66
+ * @throws {TypeError} If the config is invalid or required options are missing.
67
+ */
68
+ constructor(options) {
69
+ if (!isJsonObject(options))
70
+ throw new TypeError('TinyUploadClicker: "options" must be a valid object.');
71
+ this.#config = {
72
+ multiple: false,
73
+ accept: '',
74
+ inputAttributes: {},
75
+ inputStyles: { display: 'none' },
76
+ onClick: null,
77
+ onFileLoad: null,
78
+ ...options,
79
+ };
80
+ const { triggers } = options;
81
+ if (!Array.isArray(triggers) &&
82
+ typeof triggers !== 'string' &&
83
+ !(triggers instanceof HTMLElement))
84
+ throw new TypeError('TinyUploadClicker: "triggers" is required and must be a string, HTMLElement, or an array of them.');
85
+ const triggerList = Array.isArray(this.#config.triggers)
86
+ ? this.#config.triggers
87
+ : [this.#config.triggers];
88
+ const resolvedTriggers = triggerList.map((ref) => {
89
+ if (typeof ref === 'string') {
90
+ const el = document.querySelector(ref);
91
+ if (!el) {
92
+ throw new Error(`TinyUploadClicker: No element found for selector "${ref}".`);
93
+ }
94
+ return el;
95
+ }
96
+ if (!(ref instanceof HTMLElement))
97
+ throw new TypeError('TinyUploadClicker: All triggers must be either strings (selectors) or HTMLElements.');
98
+ return ref;
99
+ });
100
+ // Validate optional values
101
+ if (options.accept !== undefined &&
102
+ typeof options.accept !== 'string' &&
103
+ !Array.isArray(options.accept))
104
+ throw new TypeError('TinyUploadClicker: "accept" must be a string or an array of strings.');
105
+ if (options.onClick !== undefined &&
106
+ typeof options.onClick !== 'function' &&
107
+ options.onClick !== null)
108
+ throw new TypeError('TinyUploadClicker: "onClick" must be a function or null.');
109
+ if (options.onFileLoad !== undefined &&
110
+ typeof options.onFileLoad !== 'function' &&
111
+ options.onFileLoad !== null)
112
+ throw new TypeError('TinyUploadClicker: "onFileLoad" must be a function or null.');
113
+ if (options.inputAttributes !== undefined && !isJsonObject(options.inputAttributes))
114
+ throw new TypeError('TinyUploadClicker: "inputAttributes" must be an object.');
115
+ if (options.inputStyles !== undefined && !isJsonObject(options.inputStyles))
116
+ throw new TypeError('TinyUploadClicker: "inputStyles" must be an object.');
117
+ this.#boundClick = this.#handleClick.bind(this);
118
+ this.#triggerElements = resolvedTriggers;
119
+ this.#triggerElements.forEach((trigger) => {
120
+ if (!(trigger instanceof HTMLElement))
121
+ return;
122
+ const input = document.createElement('input');
123
+ input.type = 'file';
124
+ if (this.#config.multiple)
125
+ input.multiple = true;
126
+ if (typeof this.#config.accept === 'string')
127
+ input.accept = this.#config.accept;
128
+ else if (Array.isArray(this.#config.accept))
129
+ input.accept = this.#config.accept.join(',');
130
+ // Apply attributes
131
+ const attr = this.#config.inputAttributes;
132
+ if (attr && typeof attr === 'object') {
133
+ for (const [key, value] of Object.entries(attr)) {
134
+ input.setAttribute(key, value);
135
+ }
136
+ }
137
+ // Apply styles
138
+ Object.assign(input.style, this.#config.inputStyles || { display: 'none' });
139
+ // Listen for file changes
140
+ input.addEventListener('change', () => {
141
+ if (input.files && typeof this.#config.onFileLoad === 'function')
142
+ this.#config.onFileLoad(input.files, trigger);
143
+ input.value = ''; // reset so same file can be reselected
144
+ });
145
+ document.body.appendChild(input);
146
+ this.#inputs.set(trigger, input);
147
+ trigger.addEventListener('click', this.#boundClick);
148
+ });
149
+ }
150
+ /**
151
+ * Handles the click on a trigger element and forwards it to the associated file input.
152
+ *
153
+ * @param {MouseEvent} event - The click event object.
154
+ */
155
+ #handleClick(event) {
156
+ const trigger = event.currentTarget;
157
+ if (!(trigger instanceof HTMLElement))
158
+ return;
159
+ const input = this.#inputs.get(trigger);
160
+ if (!input)
161
+ return;
162
+ if (typeof this.#config.onClick === 'function')
163
+ this.#config.onClick(trigger);
164
+ input.click();
165
+ }
166
+ /**
167
+ * Cleans up all internal elements and event listeners, removing created inputs and breaking references.
168
+ */
169
+ destroy() {
170
+ for (const trigger of this.#triggerElements) {
171
+ if (!(trigger instanceof HTMLElement))
172
+ return;
173
+ trigger.removeEventListener('click', this.#boundClick);
174
+ const input = this.#inputs.get(trigger);
175
+ if (input && input.parentNode)
176
+ input.remove();
177
+ this.#inputs.delete(trigger);
178
+ }
179
+ this.#triggerElements = [];
180
+ }
181
+ }
182
+ export default TinyUploadClicker;
@@ -18,12 +18,20 @@ This folder contains the core scripts we have worked on so far. Each file is a m
18
18
  - 🔢 **[simpleMath](./basics/simpleMath.md)** — A collection of simple math utilities for calculations like the Rule of Three and percentages.
19
19
  - ✍️ **[text](./basics/text.md)** — A utility for transforming text into title case formats, with multiple options for capitalization.
20
20
  - 🔄 **[asyncReplace](./basics/asyncReplace.md)** — Asynchronously replaces matches in a string using a regex and an async function.
21
+ - 🖼️ **[html](./basics/html.md)** — Utilities for handling DOM element interactions like collision detection and basic element manipulation.
22
+ - 📺 **[fullScreen](./basics/fullScreen.md)** — A complete fullscreen API manager with detection, event handling, and cross-browser compatibility.
23
+ * 📁 **[fileManager](./basics/fileManager.mjs.md)** — A Node.js file/directory utility module with support for JSON, backups, renaming, size analysis, and more.
21
24
 
22
25
  ### 2. **`libs/`**
23
26
  - 🗂️ **[TinyPromiseQueue](./libs/TinyPromiseQueue.md)** — A class that allows sequential execution of asynchronous tasks, supporting task delays, cancellation, and queue management.
24
27
  - 🏅 **[TinyLevelUp](./libs/TinyLevelUp.md)** — A class to manage user level-up logic based on experience points, providing methods for experience validation, addition, removal, and calculation.
25
28
  - 🎨 **[ColorSafeStringify](./libs/ColorSafeStringify.md)** — A utility for applying customizable ANSI colors to JSON strings in terminal outputs, supporting presets and fine-grained type-based highlighting.
26
29
  - 🚦 **[TinyRateLimiter](./libs/TinyRateLimiter.md)** — A flexible per-user rate limiter supporting time windows, hit caps, and automatic cleanup of inactive users.
30
+ - 🔔 **[TinyNotifyCenter](./libs/TinyNotifyCenter.md)** — A dynamic notification center class to display, manage, and interact with notifications, supporting avatars, clickable items, HTML/text modes, and clean UI controls.
31
+ - 🍞 **[TinyToastNotify](./libs/TinyToastNotify.md)** — A lightweight toast notification system supporting positioning, timing customization, avatars, click actions, and fade-out animations.
32
+ - 📥 **[TinyDragDropDetector](./libs/TinyDragDropDetector.md)** — A lightweight drag-and-drop detector for files, handling the full drag lifecycle (`enter`, `over`, `leave`, `drop`) with CSS hover management and safe event handling on any DOM element or the full page.
33
+ * 📂 **[TinyUploadClicker](./libs/TinyUploadClicker.md)** — A minimal utility to bind any clickable element to a hidden file input, offering full control over styling, behavior, and upload event hooks.
34
+ * 🧲 **[TinyDragger](./libs/TinyDragger.md)** — A flexible drag-and-drop manager with collision detection, jail constraints, vibration feedback, visual proxies, revert-on-drop, and full custom event support.
27
35
 
28
36
  ---
29
37
 
@@ -0,0 +1,222 @@
1
+ # 📁 Node.js File & Directory Utilities
2
+
3
+ A powerful and flexible utility toolkit for managing files and directories in Node.js using `fs` and `path`. Includes support for JSON operations, text handling, backups, renaming strategies, and more!
4
+
5
+ ---
6
+
7
+ ## 📦 JSON Operations
8
+
9
+ ### `readJsonFile(filePath: string): any`
10
+
11
+ 📖 Reads and parses a JSON file.
12
+
13
+ * Throws an error if the file doesn't exist or contains invalid JSON.
14
+ * Async version: `readJsonFileAsync`.
15
+
16
+ ### `writeJsonFile(filePath: string, data: any, spaces: number = 2): void`
17
+
18
+ 💾 Saves a JavaScript object as a formatted JSON file.
19
+
20
+ * Automatically creates the directory if it doesn't exist.
21
+ * Async version: `writeJsonFileAsync`.
22
+
23
+ ---
24
+
25
+ ## 📂 Directory Management
26
+
27
+ ### `ensureDirectory(dirPath: string): void`
28
+
29
+ 🛠️ Ensures a directory exists. Creates it recursively if needed.
30
+
31
+ ### `clearDirectory(dirPath: string): void`
32
+
33
+ 🧹 Deletes all contents inside a directory while keeping the directory itself.
34
+
35
+ ---
36
+
37
+ ## 🧪 File Checks
38
+
39
+ ### `fileExists(filePath: string): boolean`
40
+
41
+ 🔎 Checks if a file exists.
42
+
43
+ ### `dirExists(dirPath: string): boolean`
44
+
45
+ 🏢 Checks if a directory exists.
46
+
47
+ ### `isDirEmpty(dirPath: string): boolean`
48
+
49
+ 📭 Checks if a directory is empty.
50
+
51
+ ---
52
+
53
+ ## 📄 File Operations
54
+
55
+ ### `ensureCopyFile(src: string, dest: string): void`
56
+
57
+ 📋 Copies a file from `src` to `dest`, ensuring the destination directory exists.
58
+
59
+ * Async version: `ensureCopyFileAsync`.
60
+
61
+ ### `tryDeleteFile(filePath: string): boolean`
62
+
63
+ 🗑️ Tries to delete a file if it exists. Returns `true` if deleted.
64
+
65
+ * Async version: `tryDeleteFileAsync`.
66
+
67
+ ---
68
+
69
+ ## 📝 Text Operations
70
+
71
+ ### `writeTextFile(filePath: string, content: string, ops?: fs.WriteFileOptions): void`
72
+
73
+ ✍️ Writes text content to a file. Ensures the directory exists before writing.
74
+
75
+ * Async version: `writeTextFileAsync`.
76
+
77
+ ---
78
+
79
+ ## 🧾 Directory Listings
80
+
81
+ ### `listFiles(dirPath: string, recursive?: boolean): string[]`
82
+
83
+ 📃 Lists all files and dirs in a directory. Can be recursive.
84
+
85
+ ### `listDirs(dirPath: string, recursive?: boolean): string[]`
86
+
87
+ 📁 Lists all directories in a directory. Can be recursive.
88
+
89
+ ---
90
+
91
+ ## 📏 File Info
92
+
93
+ ### `fileSize(filePath: string): number`
94
+
95
+ ⚖️ Gets the size of a single file in bytes.
96
+
97
+ ### `dirSize(dirPath: string): number`
98
+
99
+ 📦 Gets the total size of all files inside a directory (recursive).
100
+
101
+ ---
102
+
103
+ ## 💾 Backup Utilities
104
+
105
+ ### `backupFile(filePath: string, ext: string = 'bak'): void`
106
+
107
+ 🛟 Creates a timestamped `.bak` copy of the file.
108
+
109
+ * Async version: `backupFileAsync`.
110
+
111
+ ### `getLatestBackupPath(filePath: string, ext: string = 'bak'): void`
112
+
113
+ 📦 Returns the **most recent backup file path** for a given file, without modifying anything. Useful for checking which backup would be restored.
114
+
115
+ ### `restoreLatestBackup(filePath: string, ext: string = 'bak'): void`
116
+
117
+ ♻️ Restores the most recent backup for the file.
118
+
119
+ Output: `/home/yasmin/notes.txt.bak.20250625T153000`
120
+
121
+ ```
122
+ <file name>.<ext>.<timestamp>
123
+ ```
124
+
125
+ * Async version: `restoreLatestBackupAsync`.
126
+
127
+ ---
128
+
129
+ ## 🔄 Rename Utilities
130
+
131
+ ### `renameFileBatch(dirPath, renameFn, extensions?)`
132
+
133
+ 🧠 Renames all files using a custom renaming function.
134
+
135
+ * Only affects files with the specified extensions (if any).
136
+
137
+ ### `renameFileRegex(dirPath, pattern, replacement, extensions?)`
138
+
139
+ 🔡 Renames files using a regex pattern and replacement string.
140
+
141
+ ### `renameFileAddPrefixSuffix(dirPath, { prefix, suffix }, extensions?)`
142
+
143
+ 🔠 Adds a prefix and/or suffix to each filename.
144
+
145
+ ### `renameFileNormalizeCase(dirPath, mode, extensions?, normalizeExt: boolean = false)`
146
+
147
+ 🆎 Converts filenames to lowercase or uppercase.
148
+
149
+ * `mode`: `'lower'` or `'upper'`.
150
+
151
+ ### `renameFilePadNumbers(dirPath, totalDigits, extensions?)`
152
+
153
+ 🔢 Pads the first numeric sequence in a filename with leading zeros.
154
+
155
+ ---
156
+
157
+ ## 🔡 `renameFileNormalizeCase(dirPath, mode = 'lower', extensions = [])`
158
+
159
+ Normalizes all filenames in a directory to lowercase or uppercase.
160
+
161
+ ### 📥 Parameters:
162
+
163
+ * `dirPath` *(string)*: Path to the target directory.
164
+ * `mode` *(`'lower' | 'upper'`)*: Case conversion mode.
165
+
166
+ * `'lower'`: Converts filenames to lowercase.
167
+ * `'upper'`: Converts filenames to uppercase.
168
+ * `extensions` *(string\[])* *(optional)*: List of file extensions to filter. If provided, only files with these extensions will be renamed.
169
+
170
+ ### 🎯 Example:
171
+
172
+ ```js
173
+ renameFileNormalizeCase('./images', 'lower', ['.jpg', '.png']);
174
+ ```
175
+
176
+ 🔁 **Effect**:
177
+ `Photo01.JPG` → `photo01.jpg`
178
+ `Logo.PNG` → `logo.png`
179
+
180
+ ---
181
+
182
+ ## 🔢 `renameFilePadNumbers(dirPath, totalDigits = 3, extensions = [])`
183
+
184
+ Pads the first numeric sequence found in each filename to a specified number of digits.
185
+
186
+ ### 📥 Parameters:
187
+
188
+ * `dirPath` *(string)*: Path to the target directory.
189
+ * `totalDigits` *(number)*: Minimum number of digits. Numbers will be padded with leading zeros.
190
+ * `extensions` *(string\[])* *(optional)*: Only rename files with matching extensions.
191
+
192
+ ### 🎯 Example:
193
+
194
+ ```js
195
+ renameFilePadNumbers('./screenshots', 4, ['.jpg']);
196
+ ```
197
+
198
+ 🔁 **Effect**:
199
+ `screenshot1.jpg` → `screenshot0001.jpg`
200
+ `photo23.jpg` → `photo0023.jpg`
201
+
202
+ ### 🧠 Notes:
203
+
204
+ * Only the **first** number in the filename is affected.
205
+ * If a filename has no digits, it will not be changed.
206
+
207
+ ---
208
+
209
+ ## 📦 More Example Use
210
+
211
+ ```js
212
+ import { readJsonFile, writeJsonFile, listFiles, backupFile } from './utils/files.js';
213
+
214
+ const data = readJsonFile('./config/settings.json');
215
+ data.debug = false;
216
+ writeJsonFile('./config/settings.json', data);
217
+
218
+ const files = listFiles('./src/assets', true);
219
+ console.log('Found files:', files);
220
+
221
+ backupFile('./config/settings.json');
222
+ ```
@@ -0,0 +1,183 @@
1
+ # 📺 Fullscreen Utility API
2
+
3
+ A lightweight JavaScript utility to manage fullscreen behavior easily with cross-browser support! 🚀
4
+
5
+ ---
6
+
7
+ ## 🧠 Features
8
+
9
+ * ✅ Check if fullscreen is active
10
+ * ✅ Check if the screen is completely filled
11
+ * ✅ Enter fullscreen mode (with legacy browser support)
12
+ * ✅ Exit fullscreen mode (with legacy browser support)
13
+ * ✅ Listen to fullscreen change events
14
+ * ✅ Remove fullscreen change listeners
15
+
16
+ ---
17
+
18
+ ## 🚀 Functions
19
+
20
+ ---
21
+
22
+ ### 🔍 `documentIsFullScreen()`
23
+
24
+ Checks if the **document** is currently in fullscreen mode.
25
+
26
+ ```js
27
+ documentIsFullScreen();
28
+ ```
29
+
30
+ #### ✅ Returns
31
+
32
+ * `boolean` → `true` if the document is in fullscreen, `false` otherwise.
33
+
34
+ ---
35
+
36
+ ### 🔍 `isScreenFilled()`
37
+
38
+ Checks if the **window is filling the entire screen**, based on window dimensions.
39
+
40
+ ```js
41
+ isScreenFilled();
42
+ ```
43
+
44
+ #### ✅ Returns
45
+
46
+ * `boolean` → `true` if the window occupies the full screen (matching `screen.width` and `screen.height`), otherwise `false`.
47
+
48
+ ---
49
+
50
+ ### 🔍 `isFullScreenMode()`
51
+
52
+ Checks whether fullscreen mode is active **by API** (`documentIsFullScreen`) **or by matching window dimensions** (`isScreenFilled`).
53
+
54
+ ```js
55
+ isFullScreenMode();
56
+ ```
57
+
58
+ #### ✅ Returns
59
+
60
+ * `boolean` → `true` if fullscreen mode is detected by either method.
61
+
62
+ ---
63
+
64
+ ### 🖥️ `requestFullScreen(ops?)`
65
+
66
+ Requests fullscreen mode for the entire document.
67
+
68
+ ```js
69
+ await requestFullScreen();
70
+ ```
71
+
72
+ #### 🔧 Parameters
73
+
74
+ | Name | Type | Description |
75
+ | ---- | -------------------- | ------------------ |
76
+ | ops | `FullscreenOptions?` | Optional settings. |
77
+
78
+ #### ✅ Returns
79
+
80
+ * `Promise<void>` → Resolves when fullscreen mode is successfully entered.
81
+
82
+ #### ⚠️ Notes
83
+
84
+ * Fully supports modern and legacy browsers (`moz`, `webkit`, `ms` prefixes).
85
+
86
+ ---
87
+
88
+ ### 🖥️ `exitFullScreen()`
89
+
90
+ Exits fullscreen mode.
91
+
92
+ ```js
93
+ await exitFullScreen();
94
+ ```
95
+
96
+ #### ✅ Returns
97
+
98
+ * `Promise<void>` → Resolves when fullscreen mode is successfully exited.
99
+
100
+ #### ⚠️ Notes
101
+
102
+ * Fully supports modern and legacy browsers (`moz`, `webkit`, `ms` prefixes).
103
+
104
+ ---
105
+
106
+ ### 🔔 `onFullScreenChange(listener, ops?)`
107
+
108
+ Attaches a listener for fullscreen change events.
109
+
110
+ ```js
111
+ onFullScreenChange((event) => {
112
+ console.log('Fullscreen changed!', event);
113
+ });
114
+ ```
115
+
116
+ #### 🔧 Parameters
117
+
118
+ | Name | Type | Description |
119
+ | -------- | ------------------------------------------- | ------------------ |
120
+ | listener | `EventListenerOrEventListenerObject` | Callback function. |
121
+ | ops | `boolean \| AddEventListenerOptions` (opt.) | Optional options. |
122
+
123
+ #### ✅ Returns
124
+
125
+ * `void`
126
+
127
+ ---
128
+
129
+ ### 🔕 `offFullScreenChange(listener, ops?)`
130
+
131
+ Removes a listener from fullscreen change events.
132
+
133
+ ```js
134
+ offFullScreenChange(myListener);
135
+ ```
136
+
137
+ #### 🔧 Parameters
138
+
139
+ | Name | Type | Description |
140
+ | -------- | ------------------------------------------- | ------------------ |
141
+ | listener | `EventListenerOrEventListenerObject` | Callback function. |
142
+ | ops | `boolean \| AddEventListenerOptions` (opt.) | Optional options. |
143
+
144
+ #### ✅ Returns
145
+
146
+ * `void`
147
+
148
+ ---
149
+
150
+ ## 📜 Fullscreen Events Supported
151
+
152
+ The following events are internally used for compatibility:
153
+
154
+ * `'fullscreenchange'`
155
+ * `'webkitfullscreenchange'`
156
+ * `'mozfullscreenchange'`
157
+ * `'MSFullscreenChange'`
158
+
159
+ ---
160
+
161
+ ## 💡 Example Usage
162
+
163
+ ```js
164
+ import {
165
+ requestFullScreen,
166
+ exitFullScreen,
167
+ isFullScreenMode,
168
+ onFullScreenChange,
169
+ offFullScreenChange,
170
+ } from './fullScreen';
171
+
172
+ async function toggleFullscreen() {
173
+ if (isFullScreenMode()) {
174
+ await exitFullScreen();
175
+ } else {
176
+ await requestFullScreen();
177
+ }
178
+ }
179
+
180
+ onFullScreenChange(() => {
181
+ console.log('Fullscreen mode changed!');
182
+ });
183
+ ```