tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
446 lines (303 loc) β’ 13.5 kB
Markdown
### π `readBase64Blob(file: File, isDataUrl?: boolean | string): Promise<string>`
Reads a file and returns its Base64 content using the FileReader API, with optional formatting as a full Data URL.
#### π₯ Parameters
* `file` *(File)*: The file object selected by the user (e.g., from an `<input type="file">` element).
* `isDataUrl` *(boolean | string, optional)*:
* If `false` *(default)*: returns only the Base64 portion.
* If `true`: returns the original Data URL string from `FileReader`.
* If a string: treated as a custom MIME type for building a new Data URL.
#### π€ Returns
* `Promise<string>`: Resolves with either the Base64 string or a complete Data URL, depending on `isDataUrl`.
#### β οΈ Throws
* `TypeError` if:
* The result is not a string.
* The `isDataUrl` argument is not a boolean or a string.
* `Error` if:
* The string is not a valid Base64 or Data URL format.
* The MIME string format is invalid.
* `DOMException` if the file cannot be read by `FileReader`.
#### π§ͺ Example
```js
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async () => {
try {
const base64 = await readBase64Blob(input.files[0], false);
console.log(base64); // Logs only the Base64 string
} catch (err) {
console.error('Error reading file:', err.message);
}
});
```
---
### π `readFileBlob(file: File, method: 'readAsArrayBuffer' | 'readAsDataURL' | 'readAsText' | 'readAsBinaryString'): Promise<any>`
Reads the contents of a file using a specified FileReader method.
#### π₯ Parameters
* `file` *(File)*: The file object selected by the user (e.g., from an `<input type="file">` element).
* `method` *(string)*: The FileReader method to use:
* `'readAsArrayBuffer'` β for binary buffers
* `'readAsDataURL'` β for Base64 encoded data URLs
* `'readAsText'` β for plain text
* `'readAsBinaryString'` β for legacy binary string output
#### π€ Returns
* `Promise<any>`: Resolves with the file content, depending on the method used.
#### β οΈ Throws
* `Error` if an unexpected error occurs while resolving the result.
* `DOMException` if `FileReader` encounters a failure during the read process.
#### π§ͺ Example
```js
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async () => {
try {
const text = await readFileBlob(input.files[0], 'readAsText');
console.log(text); // Logs the file content as plain text
} catch (err) {
console.error('Error reading file:', err.message);
}
});
```
---
### π `readJsonBlob(file: File): Promise<any>`
Reads and parses a JSON file using the FileReader API.
#### π₯ Parameters
* `file` *(File)*: The file object selected by the user (e.g., from an `<input type="file">` element).
#### π€ Returns
* `Promise<any>`: Resolves with the parsed JSON object, or rejects with an error if the content is invalid.
#### β οΈ Throws
* An error if the content is not valid JSON.
* An error if the file can't be read.
#### π§ͺ Example
```js
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async () => {
try {
const result = await readJsonBlob(input.files[0]);
console.log(result);
} catch (err) {
alert(err.message);
}
});
```
---
### πΎ `saveJsonFile(filename: string, data: any, spaces: number = 2): void`
Converts a JavaScript object to JSON and triggers a download in the browser.
#### π₯ Parameters
* `filename` *(string)*: The name of the file to save (e.g., `"data.json"`).
* `data` *(any)*: The JavaScript object to convert to JSON.
* `spaces` *(number)* *(optional)*: Indentation level for formatting the JSON string. Default is `2`.
#### π€ Returns
* `void`
#### π Behavior
Creates a temporary `<a>` element, downloads the file, and cleans up the URL.
#### π§ͺ Example
```js
const data = { name: 'Yasmin', type: 'dev' };
saveJsonFile('yasmin.json', data);
```
### π `fetchTemplate(...)`
Loads data from a remote URL using the Fetch API, with support for custom HTTP methods, retries, timeouts, headers, and even external abort controllers.
#### π₯ Parameters
* `url` *(string)*: The full URL to fetch from (must start with `http://`, `https://`, `/`, `./`, or `../`).
* `options` *(object)* *(optional)*:
* `signal` *(`AbortSignal` | `null`)*: Custom abort signal.
* `method` *(string)*: The HTTP method to use (e.g., `GET`, `POST`, `PUT`, `DELETE`, etc.).
* `timeout` *(number)*: Request timeout in milliseconds. Default is `0` (no timeout).
* `retries` *(number)*: Number of retry attempts if the request fails. Default is `0`.
* `headers` *(object)*: Additional headers to include in the request.
* `body` *(object)*: Request body. If the value is a plain object, it will be automatically stringified as JSON.
* `onProgress` *((loaded: number, total: number) => void)*: Track the load progress.
#### `trackFetchProgress(response, onProgress)`
Intercepts a standard Fetch API Response to track the download progress of its body stream.
* **Parameters**:
* `response` *(Response)*: The original response object to be tracked.
* `options` *(FetchOnProgressResult)*: The callback function to handle progress events (loaded and total numbers).
* **Returns**:
`Response` β A new Response object with the tracked stream.
---
#### `fetchJson(url, options?)`
Loads and parses a remote JSON file.
* **Parameters**:
* `url` *(string)*: URL to fetch the JSON from.
* `options` *(object)* *(optional)*: Same structure as `fetchTemplate`.
* **Returns**:
`Promise<any[] | Record<string | number | symbol, unknown>>` β The parsed JSON data.
* **Throws**:
* `Error` if the fetch fails, times out, or returns invalid JSON.
* `Error` if the `Content-Type` is not `application/json`.
---
#### `fetchBlob(url, allowedMimeTypes?, options?)`
Loads a remote file as a Blob object.
* **Parameters**:
* `url` *(string)*: URL of the remote file.
* `allowedMimeTypes` *(string\[])* *(optional)*: List of accepted MIME types.
* `options` *(object)* *(optional)*: Same structure as `fetchTemplate`.
* **Returns**:
`Promise<Blob>`
* **Throws**:
* `Error` if fetch fails or the MIME type is not allowed.
* `Error` if the response is not OK.
---
#### `fetchText(url, allowedMimeTypes?, options?)`
Loads a remote file as **plain text** using the Fetch API.
* **Parameters**:
* `url` *(string)*: Full URL of the file to fetch.
* `allowedMimeTypes` *(string\[])* *(optional)*: List of accepted MIME types (e.g., `['text/plain']`).
* `options` *(object)* *(optional)*: Same structure as `fetchTemplate`.
* **Returns**:
`Promise<string>` β The content of the file as a text string.
* **Throws**:
* `Error` if the fetch fails or the response is not OK.
* `Error` if the MIME type is not in the allowed list (when provided).
---
#### π€ Returns (for all helpers)
* `Promise<any>` β Depends on the function:
* `fetchJson`: Parsed JSON
* `fetchBlob`: File as a Blob
* `fetchText`: File as plain text
---
#### β οΈ Throws
All functions may throw the following:
* `Error` if the request fails or the response times out.
* `Error` if `Content-Type` does not match expected type (JSON, Blob, Text, etc).
* `Error` if response is malformed or rejected by MIME type filter.
---
#### π§ Tip
Using a custom `signal` disables both `timeout` and `retries`. This is useful when you want to handle cancellation yourself, like in user interfaces or abortable workflows.
#### π§ͺ Example
```js
const controller = new AbortController();
const data = await fetchJson('https://api.example.com/data', {
method: 'POST',
body: { name: 'Yasmin' },
headers: {
'Content-Type': 'application/json'
},
timeout: 5000,
retries: 2,
signal: controller.signal, // optional
});
```
```js
const text = await fetchText('/example.txt', ['text/plain'], {
timeout: 3000,
});
```
```js
const blob = await fetchBlob('/image.jpg', ['image/jpeg']);
```
---
### π¦ `HtmlElBoxSides` Type
```ts
type HtmlElBoxSides = {
x: number; // Total horizontal size (left + right)
y: number; // Total vertical size (top + bottom)
left: number;
right: number;
top: number;
bottom: number;
}
```
A common return format used to describe the box model dimensions (borders, padding, margin) of an HTML element.
---
### π `installWindowHiddenScript`
Automatically toggles CSS classes on a given element based on the browser window or tab **visibility** and **focus** state.
Perfect for UI states like dimming, pausing animations, or showing "away" statuses.
#### π§ Features
* β
Adds or removes custom CSS classes depending on page visibility or focus
* β
Supports modern and legacy browsers (including IE9)
* β
Automatically dispatches an initial state check on load
* β
Allows custom **callbacks** for visibility changes (`onVisible`, `onHidden`)
* β
Returns a cleanup function to remove all listeners
#### π§ͺ Usage
```js
import { installWindowHiddenScript } from 'tiny-essentials';
const uninstall = installWindowHiddenScript({
element: document.getElementById('app'),
hiddenClass: 'is-hidden',
visibleClass: 'is-visible',
onVisible: () => console.log('Window is now visible'),
onHidden: () => console.log('Window is now hidden'),
});
// To remove all listeners later
uninstall();
```
#### βοΈ Options
| Option | Type | Default | Description |
| -------------- | ------------- | ----------------- | ----------------------------------------------------------------- |
| `element` | `HTMLElement` | `document.body` | The element to which the visibility classes will be applied |
| `hiddenClass` | `string` | `'windowHidden'` | Class name to apply when the window is **not visible or blurred** |
| `visibleClass` | `string` | `'windowVisible'` | Class name to apply when the window is **visible or focused** |
| `onVisible` | `() => void` | `undefined` | Optional callback fired when the window becomes visible |
| `onHidden` | `() => void` | `undefined` | Optional callback fired when the window becomes hidden |
#### π Return Value
```ts
() => void
```
Returns a function that, when called, will:
* π§Ή Remove all attached event listeners
* β Remove both visibility classes from the target element
#### π¦ Events Supported
The script handles multiple events depending on browser support:
* `visibilitychange`, `webkitvisibilitychange`, `mozvisibilitychange`, `msvisibilitychange`
* `focus`, `blur`, `focusin`, `focusout`
* `pageshow`, `pagehide`
* IE fallback: `onfocusin`, `onfocusout`
#### π Initial Trigger
Immediately after installation, the script simulates a `focus` or `blur` event based on the current visibility state to **ensure the classes and callbacks are applied from the start**.
#### π§― Uninstalling
Donβt forget to call the returned function if you dynamically load/unload components or scripts:
```js
const stopWatching = installWindowHiddenScript(...);
stopWatching(); // later
```
#### π¨ CSS Example
```css
.windowVisible {
opacity: 1;
pointer-events: auto;
transition: opacity 0.3s ease;
}
.windowHidden {
opacity: 0.4;
pointer-events: none;
transition: opacity 0.3s ease;
}
```
---
### π `loadImage(options): Promise<object>`
A robust, asynchronous utility for loading images in the browser. It captures critical lifecycle events and provides a normalized result object, making it much easier to handle image loading states and performance metrics.
#### β¨ Features
* **Asynchronous:** Returns a clean `Promise`.
* **Performance Tracking:** Automatically calculates the time taken to load the image.
* **Memory Safe:** Includes a cleanup mechanism for event listeners.
* **Normalized Output:** Returns consistent data structures for both success and edge cases.
#### π₯ Parameters
| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `url` | `string` | **Required** | The source URL of the image. |
| `crossOrigin` | `string` | `'anonymous'` | The CORS policy for the request. |
| `onLoading` | `function` | `undefined` | Callback fired when the browser starts the network request. |
#### π€ Returns
The promise resolves to an object containing:
* **`element`**: `HTMLImageElement` - The actual image object.
* **`isSuccess`**: `boolean` - True if the image loaded correctly.
* **`event`**: `Event` - The raw event captured from the browser.
* **`status`**: `string` - `'loaded'` or `'aborted'`.
* **`loadTimeMs`**: `number` - Total duration of the request in milliseconds.
* **`dimensions`**: `Object` - Contains `width`, `height`, `naturalWidth`, and `naturalHeight`.
#### π§ͺ Example
```javascript
import { loadImage } from './html.mjs';
const handleLoading = (event, startTime) => {
console.log('Started loading at:', startTime);
};
const result = await loadImage({
url: 'https://example.com/image.png',
onLoading: handleLoading,
crossOrigin: 'anonymous'
});
if (result.isSuccess) {
console.log(`Image loaded in ${result.loadTimeMs.toFixed(2)}ms`);
document.body.appendChild(result.element);
}
```
> **Note:** The utility uses `performance.now()` for high-resolution timestamps, ensuring accurate performance monitoring of your assets.