tiny-essentials 1.26.4 โ 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.
- package/.github/workflows/node.js.yml +1 -1
- package/README.md +0 -1
- package/changelog/1/27/0.md +24 -0
- package/dist/v1/ColorSafeStringify.min.js +1 -1
- package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
- package/dist/v1/TinyAfterScrollWatcher.min.js +1 -1
- package/dist/v1/TinyAnalogClock.min.js +1 -1
- package/dist/v1/TinyArrayComparator.min.js +1 -1
- package/dist/v1/TinyArrayPaginator.min.js +1 -1
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyClassManager.min.js +1 -1
- package/dist/v1/TinyClipboard.min.js +1 -1
- package/dist/v1/TinyColorConverter.min.js +1 -1
- package/dist/v1/TinyColorValidator.min.js +1 -1
- package/dist/v1/TinyCookieConsent.min.js +1 -1
- package/dist/v1/TinyDayNightCycle.min.js +1 -1
- package/dist/v1/TinyDomReadyManager.min.js +1 -1
- package/dist/v1/TinyDragDropDetector.min.js +1 -1
- package/dist/v1/TinyDragger.min.js +1 -1
- package/dist/v1/TinyElementObserver.min.js +1 -1
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyEvents.min.js +1 -1
- package/dist/v1/TinyGamepad.min.js +1 -1
- package/dist/v1/TinyHtml.min.js +1 -1
- package/dist/v1/TinyI18.min.js +1 -1
- package/dist/v1/TinyIframeEvents.min.js +1 -1
- package/dist/v1/TinyInventory.min.js +1 -1
- package/dist/v1/TinyInventoryTrader.min.js +1 -1
- package/dist/v1/TinyLevelUp.min.js +1 -1
- package/dist/v1/TinyLoadingScreen.min.js +1 -1
- package/dist/v1/TinyLocalStorage.min.js +1 -1
- package/dist/v1/TinyMaInSys.min.js +1 -1
- package/dist/v1/TinyMediaPlayer.min.js +1 -0
- package/dist/v1/TinyNeedBar.min.js +1 -1
- package/dist/v1/TinyNewWinEvents.min.js +1 -1
- package/dist/v1/TinyNotifications.min.js +1 -1
- package/dist/v1/TinyNotifyCenter.min.js +1 -1
- package/dist/v1/TinyPromiseQueue.min.js +1 -1
- package/dist/v1/TinyRadioFm.min.js +1 -0
- package/dist/v1/TinyRateLimiter.min.js +1 -1
- package/dist/v1/TinySimpleDice.min.js +1 -1
- package/dist/v1/TinySmartScroller.min.js +1 -1
- package/dist/v1/TinyTextDiffer.min.js +1 -1
- package/dist/v1/TinyTextRangeEditor.min.js +1 -1
- package/dist/v1/TinyTextarea.min.js +1 -1
- package/dist/v1/TinyTimeout.min.js +1 -1
- package/dist/v1/TinyToastNotify.min.js +1 -1
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/UltraRandomMsgGen.min.js +1 -1
- package/dist/v1/basics/index.cjs +5 -0
- package/dist/v1/basics/index.d.mts +5 -1
- package/dist/v1/basics/index.mjs +2 -1
- package/dist/v1/basics/mediaContent.cjs +644 -0
- package/dist/v1/basics/mediaContent.d.mts +296 -0
- package/dist/v1/basics/mediaContent.mjs +557 -0
- package/dist/v1/build/TinyMediaPlayer.cjs +7 -0
- package/dist/v1/build/TinyMediaPlayer.d.mts +3 -0
- package/dist/v1/build/TinyMediaPlayer.mjs +2 -0
- package/dist/v1/build/TinyRadioFm.cjs +7 -0
- package/dist/v1/build/TinyRadioFm.d.mts +3 -0
- package/dist/v1/build/TinyRadioFm.mjs +2 -0
- package/dist/v1/index.cjs +9 -0
- package/dist/v1/index.d.mts +7 -1
- package/dist/v1/index.mjs +5 -2
- package/dist/v1/libs/ColorSafeStringify.d.mts +1 -1
- package/dist/v1/libs/TinyAfterScrollWatcher.cjs +16 -3
- package/dist/v1/libs/TinyAfterScrollWatcher.d.mts +7 -3
- package/dist/v1/libs/TinyAfterScrollWatcher.mjs +13 -3
- package/dist/v1/libs/TinyArrayComparator.cjs +14 -11
- package/dist/v1/libs/TinyArrayComparator.d.mts +22 -19
- package/dist/v1/libs/TinyArrayComparator.mjs +14 -11
- package/dist/v1/libs/TinyArrayPaginator.cjs +23 -16
- package/dist/v1/libs/TinyArrayPaginator.d.mts +57 -30
- package/dist/v1/libs/TinyArrayPaginator.mjs +22 -16
- package/dist/v1/libs/TinyClassManager/TinyPluginInliner.cjs +265 -0
- package/dist/v1/libs/TinyClassManager/TinyPluginInliner.d.mts +92 -0
- package/dist/v1/libs/TinyClassManager/TinyPluginInliner.mjs +223 -0
- package/dist/v1/libs/TinyClassManager.cjs +52 -22
- package/dist/v1/libs/TinyClassManager.d.mts +26 -16
- package/dist/v1/libs/TinyClassManager.mjs +50 -21
- package/dist/v1/libs/TinyColorValidator.d.mts +16 -16
- package/dist/v1/libs/TinyDragDropDetector.cjs +9 -34
- package/dist/v1/libs/TinyDragDropDetector.d.mts +7 -21
- package/dist/v1/libs/TinyDragDropDetector.mjs +9 -24
- package/dist/v1/libs/TinyDragger.cjs +5 -5
- package/dist/v1/libs/TinyDragger.d.mts +4 -3
- package/dist/v1/libs/TinyDragger.mjs +5 -5
- package/dist/v1/libs/TinyElementObserver.cjs +6 -21
- package/dist/v1/libs/TinyElementObserver.d.mts +6 -15
- package/dist/v1/libs/TinyElementObserver.mjs +6 -20
- package/dist/v1/libs/TinyGamepad.cjs +4 -6
- package/dist/v1/libs/TinyGamepad.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlIcon.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlTemplate.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlTextarea.d.mts +1 -1
- package/dist/v1/libs/TinyHtml/index.d.mts +1 -1
- package/dist/v1/libs/TinyHtml.cjs +72 -98
- package/dist/v1/libs/TinyHtml.d.mts +15 -32
- package/dist/v1/libs/TinyHtml.mjs +53 -77
- package/dist/v1/libs/TinyInventory.d.mts +1 -1
- package/dist/v1/libs/TinyMediaPlayer.cjs +844 -0
- package/dist/v1/libs/TinyMediaPlayer.d.mts +306 -0
- package/dist/v1/libs/TinyMediaPlayer.mjs +755 -0
- package/dist/v1/libs/TinyRadioFm.cjs +1378 -0
- package/dist/v1/libs/TinyRadioFm.d.mts +554 -0
- package/dist/v1/libs/TinyRadioFm.mjs +1137 -0
- package/dist/v1/libs/TinySmartScroller.cjs +39 -26
- package/dist/v1/libs/TinySmartScroller.d.mts +16 -62
- package/dist/v1/libs/TinySmartScroller.mjs +35 -26
- package/dist/v1/libs/UltraRandomMsgGen.d.mts +7 -7
- package/docs/v1/README.md +6 -0
- package/docs/v1/basics/mediaContent.md +131 -0
- package/docs/v1/libs/TinyClassManager/TinyPluginInliner.md +107 -0
- package/docs/v1/libs/TinyDragDropDetector.md +5 -9
- package/docs/v1/libs/TinyElementObserver.md +3 -6
- package/docs/v1/libs/TinyHtml.md +0 -29
- package/docs/v1/libs/TinyMediaPlayer.md +100 -0
- package/docs/v1/libs/TinyRadioFm.md +141 -0
- package/docs/v1/libs/TinySmartScroller.md +3 -3
- package/package.json +40 -22
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# ๐ต Media Content Module
|
|
2
|
+
|
|
3
|
+
Welcome to the documentation for the media content module! This module is the heart of the media processing pipeline, responsible for downloading audio, extracting rich metadata (ID3 tags), managing memory for image blobs, and preparing finalized `MediaContent` objects for the radio system. ๐
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ๐ฆ Data Structures & Types
|
|
8
|
+
|
|
9
|
+
These definitions ensure type safety and provide a clear blueprint for how media information is structured throughout the application.
|
|
10
|
+
|
|
11
|
+
### ๐ผ Core Metadata Types
|
|
12
|
+
|
|
13
|
+
| Type | Description |
|
|
14
|
+
| :--- | :--- |
|
|
15
|
+
| `MediaContent` | **The Final Object.** A combination of `MediaContentBase` and `MediaContentMetadata`. This is what the system uses for playback. |
|
|
16
|
+
| `MediaContentBase` | The essential properties: `id`, `title`, `artist`, `duration`, `url`, and `weight`. |
|
|
17
|
+
| `MediaContentMetadata` | Rich metadata modeled after `music-metadata`. Includes `album`, `genre`, `year`, `track` info, etc. |
|
|
18
|
+
| `MediaNumber` | A structure for indexing: `{ no: number \| null, of: number \| null }`. |
|
|
19
|
+
| `UnknownArtistGetter` | A type that can be a `string` or a function returning a `string`. |
|
|
20
|
+
|
|
21
|
+
### ๐ผ๏ธ Image & Picture Types
|
|
22
|
+
|
|
23
|
+
| Type | Description |
|
|
24
|
+
| :--- | :--- |
|
|
25
|
+
| `IPicture` | Represents an image attachment (like album art). |
|
|
26
|
+
| `IPictureTemplate<T>` | A generic template for pictures, where `T` is the data type (`Uint8Array` or `string`). |
|
|
27
|
+
|
|
28
|
+
### ๐ฆ Progress & Error Types
|
|
29
|
+
|
|
30
|
+
| Type | Description |
|
|
31
|
+
| :--- | :--- |
|
|
32
|
+
| `LoadingMediaProgress` | Tracks the current state: `status` ('loading' or 'success'), `stage`, and the `url`. |
|
|
33
|
+
| `LoadingProgressStage` | Stages: `INITIALIZING` โก๏ธ `DOWNLOADING` โก๏ธ `METADATA_LOADED` โก๏ธ `EXTRACTING_ID3` โก๏ธ `COMPLETE`. |
|
|
34
|
+
| `LoadingErrorStage` | Error stages: `INITIALIZING`, `DOWNLOADING`, `METADATA`, `ID3`, or `UNKNOWN`. |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## โ Custom Errors
|
|
39
|
+
|
|
40
|
+
### `MediaLoadingError`
|
|
41
|
+
Used to provide specific context when something goes wrong during the media preparation lifecycle.
|
|
42
|
+
|
|
43
|
+
* **Properties:**
|
|
44
|
+
* `message`: Human-readable error description.
|
|
45
|
+
* `url`: The URL that caused the failure.
|
|
46
|
+
* `stage`: The `LoadingErrorStage` where the error occurred.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## ๐ ๏ธ Utility Functions
|
|
51
|
+
|
|
52
|
+
### Factory & Validation
|
|
53
|
+
|
|
54
|
+
| Function | Description |
|
|
55
|
+
| :--- | :--- |
|
|
56
|
+
| `getMediaContentBase` | Returns a fresh, empty `MediaContentBase` object. |
|
|
57
|
+
| `getMediaContentMetadata` | Returns a fresh, empty `MediaContentMetadata` object. |
|
|
58
|
+
| `valMediaContentMetadata` | Performs strict validation on a full `MediaContentMetadata` object. |
|
|
59
|
+
| `valMediaContentMetadataPartial` | Performs validation on a partial metadata object (useful for patches/updates). |
|
|
60
|
+
|
|
61
|
+
### Data & Memory Management
|
|
62
|
+
|
|
63
|
+
| Function | Description |
|
|
64
|
+
| :--- | :--- |
|
|
65
|
+
| `generateSimpleHash` | Generates a deterministic 8-character ID from a string using SHA-1. |
|
|
66
|
+
| `convertToBlobUrl` | Converts `Uint8Array` or Base64 strings into high-performance Blob URLs. It also tracks usage to prevent memory leaks. |
|
|
67
|
+
| `blobUrlToBase64` | Converts a `blob:` URL back into a Base64 Data URL. Useful for exporting data. |
|
|
68
|
+
| `revokeContentUrls` | Safely cleans up memory by revoking Blob URLs associated with a `MediaContent` object. **Call this when media is no longer needed!** ๐งน |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## ๐ Main Operations
|
|
73
|
+
|
|
74
|
+
### `extractMediaId3Tags`
|
|
75
|
+
Downloads an audio file and uses a provided parser to extract its internal metadata.
|
|
76
|
+
|
|
77
|
+
* **Parameters:**
|
|
78
|
+
* `url` (string): The full URL of the audio file.
|
|
79
|
+
* `parseFile` (Function): A callback that accepts a `Blob` and returns a promise with metadata.
|
|
80
|
+
* **Returns:** `Promise<MediaContentMetadata>`
|
|
81
|
+
* **Throws:** `TypeError` for invalid arguments or `Error` for network/parsing failures.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### `parseMediaMetadata`
|
|
86
|
+
**The Primary Factory Method.** This is the main entry point for turning a URL or an Audio element into a fully prepared `MediaContent` object. It handles the heavy lifting: downloading, metadata extraction, fallback logic, and progress reporting.
|
|
87
|
+
|
|
88
|
+
#### ๐ Parameters
|
|
89
|
+
|
|
90
|
+
| Parameter | Type | Description |
|
|
91
|
+
| :--- | :--- | :--- |
|
|
92
|
+
| `source` | `string \| HTMLMediaElement` | The audio source (URL or Audio object). |
|
|
93
|
+
| `defaultMetadata` | `Partial<MediaContent>` | Default data for the metadata. |
|
|
94
|
+
| `metadata` | `Partial<MediaContent>` | Manual overrides for the metadata (highest priority). |
|
|
95
|
+
| `parseFile` | `ParseMediaContentMetadata` | The library function used to parse the file. |
|
|
96
|
+
| `callbacks` | `Object` | Contains `onProgress` and `onError` listeners. |
|
|
97
|
+
| `unknownArtist` | `UnknownArtistGetter` | Logic to determine the artist if none is found. |
|
|
98
|
+
|
|
99
|
+
#### ๐ก Usage Examples
|
|
100
|
+
|
|
101
|
+
**1. Using a simple URL with manual overrides:**
|
|
102
|
+
```javascript
|
|
103
|
+
import { parseMediaMetadata } from './mediaContent.mjs';
|
|
104
|
+
import { parseBlob } from 'music-metadata';
|
|
105
|
+
|
|
106
|
+
// Note: We pass empty objects for default/manual if we want to jump straight to the parser
|
|
107
|
+
const track = await parseMediaMetadata(
|
|
108
|
+
'/assets/song.mp3',
|
|
109
|
+
{},
|
|
110
|
+
{ title: 'Manual Override' },
|
|
111
|
+
parseBlob
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
console.log(track.title); // "Manual Override"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**2. Using an existing Audio object with progress tracking:**
|
|
118
|
+
```javascript
|
|
119
|
+
const audio = new Audio('/assets/song.mp3');
|
|
120
|
+
|
|
121
|
+
const track = await parseMediaMetadata(
|
|
122
|
+
audio,
|
|
123
|
+
{},
|
|
124
|
+
{},
|
|
125
|
+
parseBlob,
|
|
126
|
+
{
|
|
127
|
+
onProgress: (p) => console.log(`[${p.stage}] ${p.status}`),
|
|
128
|
+
onError: (e) => console.error(`Error at ${e.stage}: ${e.error.message}`)
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
```
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# ๐ ๏ธ TinyPluginInliner
|
|
2
|
+
|
|
3
|
+
`TinyPluginInliner` is a powerful **build-time utility** designed specifically to complement the `TinyClassManager`.
|
|
4
|
+
|
|
5
|
+
When using `TinyClassManager`, you compose classes using a mixin pattern via the `.insert()` method. While this is incredibly flexible for development, it creates a challenge for deployment: you end up with many small, interconnected files and complex import paths.
|
|
6
|
+
|
|
7
|
+
**`TinyPluginInliner` solves this by "inlining" your plugins directly into a single, self-contained bundle.** It automates the process of fetching plugin code, rewriting their internal import paths, and hoisting dependencies to the top of your final file. ๐
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## โจ Key Features
|
|
12
|
+
|
|
13
|
+
* **๐ฆ Automatic Inlining:** It scans your entry file for `.insert(PluginName)` calls and replaces them with the actual source code of the plugin.
|
|
14
|
+
* **๐ Smart Path Rewriting:** It automatically corrects `import` statements inside your plugins so they point to the correct relative locations in your `dist` folder.
|
|
15
|
+
* **๐ JSDoc Support:** It doesn't just fix code; it also rewrites `import()` calls and `@typedef` paths inside JSDoc comments, ensuring your IDE (like VS Code) keeps providing perfect autocomplete in the bundled version.
|
|
16
|
+
* **๐ NPM Integration:** It can reach into your `node_modules`, grab an NPM package used by a plugin, and inline it into your bundle, even fixing that package's internal relative paths!
|
|
17
|
+
* **๐ Root Remapping:** Through `rootReplacement`, you can tell the inliner to automatically swap directory names (e.g., changing all `src/` imports to `dist/` imports).
|
|
18
|
+
* **๐ Dependency Hoisting:** It collects all necessary imports and type definitions from all plugins and moves them to the very top of the generated file for a clean, valid structure.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## โ๏ธ Configuration
|
|
23
|
+
|
|
24
|
+
When creating an instance of `TinyPluginInliner`, you provide an `InlinerConfig` object:
|
|
25
|
+
|
|
26
|
+
| Property | Type | Description |
|
|
27
|
+
| :--- | :--- | :--- |
|
|
28
|
+
| `entryPoint` | `string` | The absolute or relative path to your main file (where you call `.insert()`). |
|
|
29
|
+
| `outDir` | `string` | The directory where the final bundle will be saved. |
|
|
30
|
+
| `outFileName` | `string` | The name of the generated bundle file (e.g., `bundle.mjs`). |
|
|
31
|
+
| `rootReplacement` | `Object` | *(Optional)* An object `{ from: string, to: string }` to remap project roots. |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ๐ How to Use
|
|
36
|
+
|
|
37
|
+
### 1. Develop your Plugins
|
|
38
|
+
Your plugins must follow the `TinyClassManager` requirement of having static properties for identification.
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
// src/plugins/LoggerPlugin.mjs
|
|
42
|
+
export class LoggerPlugin {
|
|
43
|
+
static _tinyDepName = 'Logger';
|
|
44
|
+
static _tinyDeps = [];
|
|
45
|
+
|
|
46
|
+
constructor(Base) {
|
|
47
|
+
super();
|
|
48
|
+
this.log = (msg) => console.log(`[LOG]: ${msg}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Create your Entry Point
|
|
54
|
+
This is the file that uses the `TinyClassManager` to compose your final class.
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// src/main.mjs
|
|
58
|
+
import TinyClassManager from './libs/TinyClassManager.mjs';
|
|
59
|
+
import { LoggerPlugin } from './plugins/LoggerPlugin.mjs';
|
|
60
|
+
|
|
61
|
+
class BaseUser {}
|
|
62
|
+
|
|
63
|
+
// The Inliner will look for this specific pattern!
|
|
64
|
+
const User = new TinyClassManager(BaseUser)
|
|
65
|
+
.insert(LoggerPlugin)
|
|
66
|
+
.build();
|
|
67
|
+
|
|
68
|
+
export default User;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. Run the Inliner
|
|
72
|
+
Create a build script (e.g., `build.mjs`) to trigger the process.
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
import TinyPluginInliner from './libs/TinyClassManager/TinyPluginInliner.mjs';
|
|
76
|
+
|
|
77
|
+
const builder = new TinyPluginInliner({
|
|
78
|
+
entryPoint: 'src/main.mjs',
|
|
79
|
+
outDir: 'dist',
|
|
80
|
+
outFileName: 'app.bundle.mjs',
|
|
81
|
+
// This ensures that if a plugin imports from 'src/utils',
|
|
82
|
+
// it will be rewritten to 'dist/utils' in the bundle.
|
|
83
|
+
rootReplacement: {
|
|
84
|
+
from: 'src',
|
|
85
|
+
to: 'dist',
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
builder.build();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## ๐ Before vs. After
|
|
95
|
+
|
|
96
|
+
### ๐ Before (Development)
|
|
97
|
+
Your project is a web of files:
|
|
98
|
+
* `src/main.mjs` $\rightarrow$ imports `LoggerPlugin`
|
|
99
|
+
* `src/plugins/LoggerPlugin.mjs` $\rightarrow$ imports `src/utils/helper.mjs`
|
|
100
|
+
|
|
101
|
+
### ๐ฆ After (Production Bundle)
|
|
102
|
+
The `dist/app.bundle.mjs` is a single, massive, but perfectly valid file:
|
|
103
|
+
1. **Top:** All imports from `main.mjs`, `LoggerPlugin.mjs`, and `helper.mjs` are hoisted here.
|
|
104
|
+
2. **Middle:** All `@typedef` definitions are gathered here.
|
|
105
|
+
3. **Bottom:** The logic of `main.mjs` runs, but the `.insert(LoggerPlugin)` call has been replaced by the actual code of the `LoggerPlugin` class, which now correctly references the hoisted helper functions.
|
|
106
|
+
|
|
107
|
+
**Everything is ready to be shipped!** ๐ข๐จ
|
|
@@ -21,7 +21,6 @@ A lightweight JavaScript utility for detecting drag-and-drop file operations on
|
|
|
21
21
|
import TinyDragDropDetector from './TinyDragDropDetector.js';
|
|
22
22
|
|
|
23
23
|
const dnd = new TinyDragDropDetector({
|
|
24
|
-
fullscreen: false,
|
|
25
24
|
target: document.getElementById('drop-area'),
|
|
26
25
|
hoverClass: 'hover-effect',
|
|
27
26
|
onDrop: (files, event) => {
|
|
@@ -50,19 +49,19 @@ A drag-and-drop detector instance.
|
|
|
50
49
|
### Constructor
|
|
51
50
|
|
|
52
51
|
```javascript
|
|
53
|
-
new TinyDragDropDetector(options)
|
|
52
|
+
new TinyDragDropDetector(target, options)
|
|
54
53
|
```
|
|
55
54
|
|
|
56
55
|
#### Parameters:
|
|
57
56
|
|
|
58
|
-
| Name | Type |
|
|
59
|
-
| --------- | ------------------------------------------- |
|
|
60
|
-
| `
|
|
57
|
+
| Name | Type | Description |
|
|
58
|
+
| --------- | ------------------------------------------- | ------------------------------------------------------- |
|
|
59
|
+
| `target` | `HTMLElement` | The DOM element where drag listeners will be attached. |
|
|
60
|
+
| `options` | [`DragAndDropOptions`](#draganddropoptions) | Configuration object. |
|
|
61
61
|
|
|
62
62
|
#### Throws:
|
|
63
63
|
|
|
64
64
|
* `TypeError` if `target` is not an `HTMLElement`.
|
|
65
|
-
* `TypeError` if `fullscreen` is not a boolean.
|
|
66
65
|
* `TypeError` if `hoverClass` is not a string.
|
|
67
66
|
* `TypeError` if `onDrop` is not a function.
|
|
68
67
|
* `TypeError` if `onEnter` is defined but not a function.
|
|
@@ -76,7 +75,6 @@ new TinyDragDropDetector(options)
|
|
|
76
75
|
| ----------------- | ------------- | ------------------------------------------------------------------------ |
|
|
77
76
|
| `getTarget()` | `HTMLElement` | Returns the DOM element where listeners are attached. |
|
|
78
77
|
| `getHoverClass()` | `string` | Returns the CSS class applied during drag hover. |
|
|
79
|
-
| `isFullScreen()` | `boolean` | Indicates whether the detector is in fullscreen mode (`document.body`). |
|
|
80
78
|
| `isDragging()` | `boolean` | Returns whether a drag operation is currently active over the target. |
|
|
81
79
|
| `bound()` | `boolean` | Returns whether the event listeners are currently bound to the target. |
|
|
82
80
|
| `destroy()` | `void` | Destroys the detector, unbinding all events and cleaning up CSS classes. |
|
|
@@ -98,8 +96,6 @@ new TinyDragDropDetector(options)
|
|
|
98
96
|
```javascript
|
|
99
97
|
/**
|
|
100
98
|
* @typedef {Object} DragAndDropOptions
|
|
101
|
-
* @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.
|
|
102
|
-
* @property {boolean} [fullscreen=true] - If true, listeners are attached to the entire page (`document.body`). If false, the `target` must be specified.
|
|
103
99
|
* @property {string} [hoverClass="dnd-hover"] - CSS class applied to the target element while files are being dragged over it.
|
|
104
100
|
* @property {(files: FileList, event: DragEvent) => void} onDrop - Callback function executed when files are dropped onto the target.
|
|
105
101
|
* @property {(event: DragEvent) => void} [onEnter] - Optional callback triggered when dragging enters the target area.
|
|
@@ -22,14 +22,13 @@ type ElementDetectorsFn = (
|
|
|
22
22
|
## ๐น Constructor
|
|
23
23
|
|
|
24
24
|
```ts
|
|
25
|
-
new TinyElementObserver({
|
|
26
|
-
el?: Element,
|
|
25
|
+
new TinyElementObserver(el, {
|
|
27
26
|
initDetectors?: Array<[string, ElementDetectorsFn]>,
|
|
28
27
|
initCfg?: MutationObserverInit
|
|
29
28
|
})
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
* **`el`**
|
|
31
|
+
* **`el`** โ Initial element to observe ๐ท๏ธ
|
|
33
32
|
* **`initDetectors`** *(optional)* โ Array of detectors to register on creation ๐๏ธ
|
|
34
33
|
* **`initCfg`** *(optional)* โ Initial `MutationObserverInit` configuration โ๏ธ
|
|
35
34
|
|
|
@@ -39,7 +38,6 @@ new TinyElementObserver({
|
|
|
39
38
|
|
|
40
39
|
| Property | Type | Description |
|
|
41
40
|
| ----------- | ------------------------------------- | --------------------------------------------------------- |
|
|
42
|
-
| `el` | `Element \| undefined` | The DOM element being observed. Can only be set once. ๐๏ธ |
|
|
43
41
|
| `settings` | `MutationObserverInit` | Observer configuration object. ๐ง |
|
|
44
42
|
| `observer` | `MutationObserver \| null` | Internal observer instance. |
|
|
45
43
|
| `detectors` | `Array<[string, ElementDetectorsFn]>` | List of registered detectors. |
|
|
@@ -85,8 +83,7 @@ const logDetector = (mutation, index, mutations) => {
|
|
|
85
83
|
};
|
|
86
84
|
|
|
87
85
|
// Create instance
|
|
88
|
-
const observer = new TinyElementObserver({
|
|
89
|
-
el: document.querySelector('#target'),
|
|
86
|
+
const observer = new TinyElementObserver(document.querySelector('#target'), {
|
|
90
87
|
initDetectors: [['logger', logDetector]],
|
|
91
88
|
initCfg: { childList: true, subtree: true }
|
|
92
89
|
});
|
package/docs/v1/libs/TinyHtml.md
CHANGED
|
@@ -767,32 +767,6 @@ Finds elements by tag name in a namespace (defaults to XHTML).
|
|
|
767
767
|
|
|
768
768
|
## ๐ Element Observer
|
|
769
769
|
|
|
770
|
-
### โก `autoStartElemObserver`
|
|
771
|
-
|
|
772
|
-
A **flag** that determines whether the internal element observer should automatically start when some library code initializes.
|
|
773
|
-
|
|
774
|
-
* **Type** ๐ โ `boolean`
|
|
775
|
-
* **Default** ๐ โ `true`
|
|
776
|
-
|
|
777
|
-
#### ๐ฅ Getter
|
|
778
|
-
|
|
779
|
-
```js
|
|
780
|
-
TinyHtml.autoStartElemObserver; // returns true or false
|
|
781
|
-
```
|
|
782
|
-
|
|
783
|
-
Returns the current state of the auto-start flag.
|
|
784
|
-
|
|
785
|
-
#### ๐ค Setter
|
|
786
|
-
|
|
787
|
-
```js
|
|
788
|
-
TinyHtml.autoStartElemObserver = false;
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
Updates the flag.
|
|
792
|
-
โ ๏ธ Throws a `TypeError` if the value is not a boolean.
|
|
793
|
-
|
|
794
|
-
---
|
|
795
|
-
|
|
796
770
|
### ๐ `tinyObserver`
|
|
797
771
|
|
|
798
772
|
The internal **[`TinyElementObserver`](./TinyElementObserver.md)** instance used by TinyHtml to track DOM changes.
|
|
@@ -857,9 +831,6 @@ document.addEventListener('tinyhtml.classchanged', (e) => {
|
|
|
857
831
|
console.log('๐ท๏ธ Class changed:', e.detail);
|
|
858
832
|
});
|
|
859
833
|
|
|
860
|
-
// Disable auto-start (if needed)
|
|
861
|
-
TinyHtml.autoStartElemObserver = false;
|
|
862
|
-
|
|
863
834
|
// Manually start the observer
|
|
864
835
|
TinyHtml.tinyObserver.start();
|
|
865
836
|
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# ๐ง TinyMediaPlayer Documentation
|
|
2
|
+
|
|
3
|
+
`TinyMediaPlayer` is a robust, universal media player manager designed to orchestrate playback across multiple different media providers (such as YouTube, Spotify, etc.) using an **Adapter Pattern**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ๐งฉ Core Architecture: The Adapter Pattern
|
|
8
|
+
|
|
9
|
+
To support different media platforms, `TinyMediaPlayer` relies on **Adapters**. You must create a class that extends `BaseMediaAdapter` for every new service you wish to support.
|
|
10
|
+
|
|
11
|
+
### ๐ ๏ธ `BaseMediaAdapter` (Abstract Class)
|
|
12
|
+
*This class cannot be instantiated directly. It serves as an interface.*
|
|
13
|
+
|
|
14
|
+
| Method | Description | Parameters | Returns |
|
|
15
|
+
| :--- | :--- | :--- | :--- |
|
|
16
|
+
| `canHandle` | Checks if the adapter supports a specific content item. | `content: MediaContent` | `boolean` |
|
|
17
|
+
| `play` | Starts or resumes playback. | `content: MediaContent` | `Promise<void>` |
|
|
18
|
+
| `pause` | Pauses the current playback. | None | `Promise<void>` |
|
|
19
|
+
| `stop` | Stops playback and resets the platform state. | None | `Promise<void>` |
|
|
20
|
+
| `seek` | Jumps to a specific time. | `timeMs: number` | `Promise<void>` |
|
|
21
|
+
| `getCurrentTime` | Gets the current playback position. | None | `number` (ms) |
|
|
22
|
+
| `setVolume` | Sets the volume level. | `volume: number` (0.0 to 1.0) | `void` |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ๐ `TinyMediaPlayer` Class
|
|
27
|
+
|
|
28
|
+
The main controller for managing playlists, playback state, and adapters.
|
|
29
|
+
|
|
30
|
+
### โ๏ธ Configuration (Constructor Options)
|
|
31
|
+
When initializing `new TinyMediaPlayer(options)`, you can pass the following:
|
|
32
|
+
|
|
33
|
+
* **`persistVolume`** (`boolean`): If `true`, the volume level is automatically saved to and loaded from `localStorage`. (Default: `false`).
|
|
34
|
+
* **`volumeStorageKey`** (`string`): The key name used in `localStorage` to store the volume. (Default: `'tiny_media_player_volume'`).
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
### ๐๏ธ Static Members
|
|
39
|
+
|
|
40
|
+
#### Properties
|
|
41
|
+
* **`unknownArtist`**: A global setting for when an artist's name is unavailable.
|
|
42
|
+
* **Type**: `string` | `function` (returns a string).
|
|
43
|
+
* **Getter/Setter**: Allows you to define a custom string or a logic-based function.
|
|
44
|
+
|
|
45
|
+
#### Methods
|
|
46
|
+
* **`parseContent(source, defaultMetadata, metadata, parseFile, callbacks)`**:
|
|
47
|
+
* A static factory method to prepare a `MediaContent` object by extracting metadata from a URL or HTMLMediaElement.
|
|
48
|
+
* **Returns**: `Promise<MediaContent>`.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### ๐ Instance Properties (Getters & Setters)
|
|
53
|
+
|
|
54
|
+
| Property | Type | Description |
|
|
55
|
+
| :--- | :--- | :--- |
|
|
56
|
+
| `playlist` | `MediaContent[]` | Returns a shallow copy of the current playlist. |
|
|
57
|
+
| `currentIndex` | `number` | The index of the currently playing track. |
|
|
58
|
+
| `loopMode` | `'NONE' \| 'TRACK' \| 'PLAYLIST'` | Defines how the player behaves at the end of a track. |
|
|
59
|
+
| `isRandom` | `boolean` | Enables or disables shuffle mode. |
|
|
60
|
+
| `isPlaying` | `boolean` | Indicates if media is currently playing. |
|
|
61
|
+
| `volume` | `number` | The current volume (constrained between `0.0` and `1.0`). |
|
|
62
|
+
| `persistVolume` | `boolean` | Enables/disables volume saving to `localStorage`. |
|
|
63
|
+
| `volumeStorageKey`| `string` | The key used for volume persistence. |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### ๐น๏ธ Methods
|
|
68
|
+
|
|
69
|
+
#### ๐ Adapter Management
|
|
70
|
+
* **`registerAdapter(id, adapter)`**: Registers a new provider.
|
|
71
|
+
* `id`: A unique string (e.g., `'youtube'`).
|
|
72
|
+
* `adapter`: An instance of a class extending `BaseMediaAdapter`.
|
|
73
|
+
|
|
74
|
+
#### ๐ Playlist Management
|
|
75
|
+
* **`addTrack(content)`**: Adds a new `MediaContent` object to the end of the playlist.
|
|
76
|
+
* **`existsTrack(index)`**: Returns `true` if a track exists at the given index.
|
|
77
|
+
* **`getTrack(index)`**: Retrieves the track at the specified index.
|
|
78
|
+
* **`removeTrack(index)`**: Removes a track. If the current track is removed, playback stops or adjusts.
|
|
79
|
+
* **`searchTrack(query)`**: Searches the playlist.
|
|
80
|
+
* `query`: A `string` (searches title, artist, or album) or a `function` (custom logic).
|
|
81
|
+
* **Returns**: `SearchResult[]` (array of objects containing the track and its index).
|
|
82
|
+
* **`clearPlaylist()`**: Stops playback and empties the playlist.
|
|
83
|
+
|
|
84
|
+
#### โฏ๏ธ Playback Controls
|
|
85
|
+
* **`play()`**: Starts playback of the current track.
|
|
86
|
+
* **`pause()`**: Pauses the current track.
|
|
87
|
+
* **`stop()`**: Stops the current track completely.
|
|
88
|
+
* **`next()`**: Advances to the next track (respects `loopMode` and `isRandom`).
|
|
89
|
+
* **`prev()`**: Returns to the previous track (respects `loopMode` and `isRandom`).
|
|
90
|
+
* **`seek(timeMs)`**: Jumps to a specific millisecond in the current track.
|
|
91
|
+
* **`step(stepMs)`**: Moves the timeline forward (positive) or backward (negative) by a specific amount.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## โ ๏ธ Error Handling
|
|
96
|
+
|
|
97
|
+
The class uses strict validation. The following errors may be thrown:
|
|
98
|
+
* **`TypeError`**: Thrown when an argument is of the wrong type (e.g., passing a string to `volume`).
|
|
99
|
+
* **`RangeError`**: Thrown when a number is out of allowed bounds (e.g., an index that doesn't exist or volume > 1.0).
|
|
100
|
+
* **`Error`**: Thrown if no compatible adapter is found for the current content.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# ๐ป TinyRadioFm Documentation
|
|
2
|
+
|
|
3
|
+
`TinyRadioFm` is a powerful, deterministic, and seed-based radio management system. It is designed to handle complex playback sequences, including music and voice playlists, scheduled timeline mutations, and custom content injections, all while maintaining absolute reproducibility through a mathematical seed. ๐ฏ
|
|
4
|
+
|
|
5
|
+
> **Beta Status:** This engine is currently in beta.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## โจ Key Features
|
|
10
|
+
|
|
11
|
+
* **๐ฏ Deterministic Playback:** Uses a `Mulberry32` PRNG to ensure that the same seed always produces the exact same radio sequence.
|
|
12
|
+
* **๐ต Dual-Stream Logic:** Manages separate playlists for `music` and `voice`, with configurable interaction rules (e.g., playing voices after music).
|
|
13
|
+
* **๐
Scheduled Mutations:** Schedule tasks to `add`, `remove`, or `move` items in the playlist at specific future timestamps.
|
|
14
|
+
* **โก Custom Injections:** Inject "Custom Positions" into the timeline that interrupt the standard cycle.
|
|
15
|
+
* **๐ง Smart Queuing:** Intelligent logic to prevent audio overlaps by automatically adjusting timestamps to the end of currently playing content.
|
|
16
|
+
* **๐พ State Persistence:** Full export/import capabilities, including automatic conversion of Blob URLs to Base64 for easy storage.
|
|
17
|
+
* **๐งน Memory Management:** Proactive cleanup of Blob URLs and event listeners to prevent memory leaks.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## โ๏ธ Configuration
|
|
22
|
+
|
|
23
|
+
The behavior of the engine is controlled via the `RadioConfig` object.
|
|
24
|
+
|
|
25
|
+
| Property | Type | Default | Description |
|
|
26
|
+
| :--- | :--- | :--- | :--- |
|
|
27
|
+
| `mode` | `'playlist' \| 'random'` | `'playlist'` | Sequence logic for the music playlist. |
|
|
28
|
+
| `voiceMode` | `'playlist' \| 'random'` | `'playlist'` | Sequence logic for the voice playlist. |
|
|
29
|
+
| `silenceDuration` | `number` | `0` | Gap in milliseconds between tracks. |
|
|
30
|
+
| `queryLimit` | `number` | `100000` | Safety lock for maximum items processed during queries. |
|
|
31
|
+
| `voiceAfterMusic` | `boolean` | `true` | If `true`, voice messages play after music tracks. |
|
|
32
|
+
| `voiceMin` | `number` | `0` | Minimum number of voice messages to play in a cycle. |
|
|
33
|
+
| `voiceMax` | `number` | `1` | Maximum number of voice messages to play in a cycle. |
|
|
34
|
+
| `musicMaxConsecutive`| `number` | `0` | Max consecutive music repeats (`-1` = unlimited, `0` = no repeats). |
|
|
35
|
+
| `voiceMaxConsecutive`| `number` | `0` | Max consecutive voice repeats (`-1` = unlimited, `0` = no repeats). |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## ๐ ๏ธ Core API Reference
|
|
40
|
+
|
|
41
|
+
### ๐๏ธ Static Methods
|
|
42
|
+
|
|
43
|
+
#### `static parseContent(source, defaultMetadata, metadata, parseFile, callbacks)`
|
|
44
|
+
Prepares a `MediaContent` object by extracting metadata from an audio source.
|
|
45
|
+
* **Parameters:**
|
|
46
|
+
* `source`: A URL string or an existing `HTMLMediaElement`.
|
|
47
|
+
* `defaultMetadata`: Optional base metadata.
|
|
48
|
+
* `metadata`: Optional manual overrides.
|
|
49
|
+
* `parseFile`: Internal helper for file parsing.
|
|
50
|
+
* `callbacks`: Object containing `onProgress` and `onError` handlers.
|
|
51
|
+
* **Returns:** `Promise<MediaContent>`
|
|
52
|
+
* **Throws:** `MediaLoadingError`
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### ๐ฅ Content Management
|
|
57
|
+
|
|
58
|
+
#### `add(type, data, smartQueue = true)`
|
|
59
|
+
Adds new content to the engine immediately.
|
|
60
|
+
* **Parameters:**
|
|
61
|
+
* `type`: `'music' | 'voice' | 'custom'`.
|
|
62
|
+
* `data`: The `MediaContent` object (must include `id` and `duration`).
|
|
63
|
+
* `smartQueue`: If `true`, delays insertion until the current content ends (primarily for `custom`).
|
|
64
|
+
* **Emits:** `contentAdded`
|
|
65
|
+
|
|
66
|
+
#### `remove(id)`
|
|
67
|
+
Instantly removes content by its unique ID across all lists, custom positions, and pending tasks. It also revokes associated Blob URLs.
|
|
68
|
+
* **Parameters:** `id` (string)
|
|
69
|
+
* **Emits:** `contentRemoved`
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### ๐
Task & Config Management
|
|
74
|
+
|
|
75
|
+
#### `scheduleTask(timestamp, action, type, payload, smartQueue = true)`
|
|
76
|
+
Schedules a modification to the playlists at a specific point in time.
|
|
77
|
+
* **Parameters:**
|
|
78
|
+
* `timestamp`: Target epoch timestamp (ms).
|
|
79
|
+
* `action`: `'add' | 'remove' | 'move'`.
|
|
80
|
+
* `type`: `'music' | 'voice'`.
|
|
81
|
+
* `payload`: Data required for the action (`MediaContent` for add, `string` for remove, or `ScheduledMovePayload` for move).
|
|
82
|
+
* `smartQueue`: If `true`, aligns the task to the end of the current event.
|
|
83
|
+
* **Emits:** `taskScheduled`
|
|
84
|
+
|
|
85
|
+
#### `setConfig(config)`
|
|
86
|
+
Performs a partial or full update of the engine configuration.
|
|
87
|
+
* **Parameters:** `config` (Partial or full `RadioConfig` object).
|
|
88
|
+
* **Emits:** `configChanged`
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### ๐ Timeline & Querying
|
|
93
|
+
|
|
94
|
+
#### `getCurrentEvent()`
|
|
95
|
+
Retrieves the exact event currently playing at the system's current time.
|
|
96
|
+
* **Returns:** `RadioEvent | null`
|
|
97
|
+
|
|
98
|
+
#### `queryTimeline(targetDate, limit = 10)`
|
|
99
|
+
Predicts upcoming events from a specific date forward using a virtual sandbox to prevent state mutation.
|
|
100
|
+
* **Parameters:**
|
|
101
|
+
* `targetDate`: Starting epoch timestamp.
|
|
102
|
+
* `limit`: Maximum number of events to return.
|
|
103
|
+
* **Returns:** `RadioEvent[]`
|
|
104
|
+
* **Throws:** `TypeError` or `RangeError` if limit is invalid.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### ๐พ Persistence & Lifecycle
|
|
109
|
+
|
|
110
|
+
#### `async exportState()`
|
|
111
|
+
Exports the entire radio state (playlists, tasks, seed, config) as a JSON string. Automatically converts all image Blob URLs to **Base64** for portability.
|
|
112
|
+
* **Returns:** `Promise<string>`
|
|
113
|
+
|
|
114
|
+
#### `importState(json)`
|
|
115
|
+
Hydrates the engine with a previously exported state.
|
|
116
|
+
* **Parameters:** `json` (A JSON string or a state object).
|
|
117
|
+
* **Emits:** `stateImported`
|
|
118
|
+
|
|
119
|
+
#### `destroy(destroyThumbs = true)`
|
|
120
|
+
Performs a complete cleanup. It wipes all lists, clears the cache, removes all listeners, and revokes all Blob URLs to free up system memory.
|
|
121
|
+
* **Parameters:** `destroyThumbs` (boolean) - Whether to revoke image Blob URLs.
|
|
122
|
+
* **Emits:** `destroyed`
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## ๐ Data Models (Summary)
|
|
127
|
+
|
|
128
|
+
### `RadioEvent` ๐ก
|
|
129
|
+
The standardized object returned when querying the timeline.
|
|
130
|
+
* `id`, `title`, `artist`, `url`, `duration`
|
|
131
|
+
* `absoluteStart`, `absoluteEnd`
|
|
132
|
+
* `elapsedTime`, `remainingTime`
|
|
133
|
+
* `progress` (0 to 1)
|
|
134
|
+
* `isCustom` (boolean)
|
|
135
|
+
|
|
136
|
+
### `ScheduledTask` ๐
|
|
137
|
+
An instruction to change the radio state.
|
|
138
|
+
* `timestamp`: Execution time.
|
|
139
|
+
* `action`: `'add' | 'remove' | 'move'`.
|
|
140
|
+
* `type`: `'music' | 'voice'`.
|
|
141
|
+
* `payload`: Action-specific data.
|
|
@@ -358,15 +358,15 @@ scroller._listenLoadEvents(imgElement);
|
|
|
358
358
|
|
|
359
359
|
## ๐งฑ DOM and Element Accessors
|
|
360
360
|
|
|
361
|
-
### ๐ฏ `
|
|
361
|
+
### ๐ฏ `targetElement`
|
|
362
362
|
|
|
363
363
|
Returns the internal scroll container element being monitored.
|
|
364
364
|
|
|
365
365
|
```js
|
|
366
|
-
const container = scroller.
|
|
366
|
+
const container = scroller.targetElement;
|
|
367
367
|
```
|
|
368
368
|
|
|
369
|
-
* ๐ Returns the target DOM element
|
|
369
|
+
* ๐ Returns the target DOM element.
|
|
370
370
|
|
|
371
371
|
### ๐ต๏ธโโ๏ธ `getOldSize(el)`
|
|
372
372
|
|