@simplysm/core-browser 13.0.85 → 13.0.87
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/README.md +298 -16
- package/dist/extensions/element-ext.js +2 -2
- package/dist/extensions/element-ext.js.map +1 -1
- package/dist/utils/IndexedDbStore.d.ts +5 -0
- package/dist/utils/IndexedDbStore.d.ts.map +1 -1
- package/dist/utils/IndexedDbStore.js +77 -49
- package/dist/utils/IndexedDbStore.js.map +1 -1
- package/dist/utils/IndexedDbVirtualFs.js +2 -2
- package/dist/utils/IndexedDbVirtualFs.js.map +1 -1
- package/package.json +3 -3
- package/src/extensions/element-ext.ts +2 -2
- package/src/utils/IndexedDbStore.ts +87 -53
- package/src/utils/IndexedDbVirtualFs.ts +2 -2
- package/tests/extensions/element-ext.spec.ts +34 -0
- package/tests/utils/IndexedDbStore.spec.ts +103 -0
- package/tests/utils/IndexedDbVirtualFs.spec.ts +171 -0
- package/tests/utils/fetch.spec.ts +154 -0
- package/docs/element-extensions.md +0 -151
- package/docs/html-element-extensions.md +0 -86
- package/docs/indexed-db.md +0 -193
- package/docs/utilities.md +0 -94
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# Element Extensions
|
|
2
|
-
|
|
3
|
-
Side-effect module that extends `Element.prototype` with DOM traversal, focus management, and visibility helpers. Also exports standalone functions for clipboard operations and element bounds measurement.
|
|
4
|
-
|
|
5
|
-
## Prototype Methods
|
|
6
|
-
|
|
7
|
-
### Element.findAll
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
findAll<TEl extends Element = Element>(selector: string): TEl[]
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Find all child elements matching a CSS selector. Returns an empty array if the selector is empty.
|
|
14
|
-
|
|
15
|
-
### Element.findFirst
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
findFirst<TEl extends Element = Element>(selector: string): TEl | undefined
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Find the first child element matching a CSS selector. Returns `undefined` if the selector is empty or no match is found.
|
|
22
|
-
|
|
23
|
-
### Element.prependChild
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
prependChild<TEl extends Element>(child: TEl): TEl
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Insert an element as the first child. Returns the inserted child element.
|
|
30
|
-
|
|
31
|
-
### Element.getParents
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
getParents(): Element[]
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Get all parent elements ordered from closest to farthest (up to the root).
|
|
38
|
-
|
|
39
|
-
### Element.findFocusableParent
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
findFocusableParent(): HTMLElement | undefined
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Find the nearest focusable ancestor element. Uses the `tabbable` library to determine focusability.
|
|
46
|
-
|
|
47
|
-
### Element.findFirstFocusableChild
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
findFirstFocusableChild(): HTMLElement | undefined
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Find the first focusable descendant element using a tree walker. Uses the `tabbable` library to determine focusability.
|
|
54
|
-
|
|
55
|
-
### Element.isOffsetElement
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
isOffsetElement(): boolean
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Check whether the element is an offset parent. Returns `true` if the computed `position` is `relative`, `absolute`, `fixed`, or `sticky`.
|
|
62
|
-
|
|
63
|
-
### Element.isVisible
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
isVisible(): boolean
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Check whether the element is visible on screen. Checks for the existence of client rects, `visibility: hidden`, and `opacity: 0`.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## Exported Interfaces
|
|
74
|
-
|
|
75
|
-
### ElementBounds
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
interface ElementBounds {
|
|
79
|
-
target: Element;
|
|
80
|
-
top: number;
|
|
81
|
-
left: number;
|
|
82
|
-
width: number;
|
|
83
|
-
height: number;
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Bounds information for an element, with positions relative to the viewport.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Exported Functions
|
|
92
|
-
|
|
93
|
-
### copyElement
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
function copyElement(event: ClipboardEvent): void
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Copy element content to clipboard. Intended for use as a `copy` event handler. Finds the first `input` or `textarea` within the event target and writes its value to the clipboard.
|
|
100
|
-
|
|
101
|
-
### pasteToElement
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
function pasteToElement(event: ClipboardEvent): void
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Paste clipboard content into an element. Intended for use as a `paste` event handler. Finds the first `input` or `textarea` within the event target and replaces its value with clipboard text, dispatching an `input` event afterward.
|
|
108
|
-
|
|
109
|
-
### getBounds
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
function getBounds(els: Element[], timeout?: number): Promise<ElementBounds[]>
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
Get bounds information for multiple elements using `IntersectionObserver`. Results are returned in the same order as the input array, with duplicates removed.
|
|
116
|
-
|
|
117
|
-
| Parameter | Type | Default | Description |
|
|
118
|
-
|-----------|------|---------|-------------|
|
|
119
|
-
| `els` | `Element[]` | -- | Target elements |
|
|
120
|
-
| `timeout` | `number` | `5000` | Timeout in milliseconds |
|
|
121
|
-
|
|
122
|
-
Throws `TimeoutError` (from `@simplysm/core-common`) if the observer does not respond within the timeout duration.
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Usage Examples
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
import "@simplysm/core-browser"; // activate side effects
|
|
130
|
-
|
|
131
|
-
// Find elements
|
|
132
|
-
const buttons = container.findAll<HTMLButtonElement>("button.primary");
|
|
133
|
-
const firstInput = form.findFirst<HTMLInputElement>("input[type=text]");
|
|
134
|
-
|
|
135
|
-
// DOM traversal
|
|
136
|
-
const parents = element.getParents();
|
|
137
|
-
const focusable = element.findFirstFocusableChild();
|
|
138
|
-
|
|
139
|
-
// Visibility check
|
|
140
|
-
if (element.isVisible()) {
|
|
141
|
-
// element is rendered and visible
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Clipboard handlers
|
|
145
|
-
document.addEventListener("copy", copyElement);
|
|
146
|
-
document.addEventListener("paste", pasteToElement);
|
|
147
|
-
|
|
148
|
-
// Measure element bounds
|
|
149
|
-
const bounds = await getBounds([el1, el2, el3]);
|
|
150
|
-
// bounds[0].top, bounds[0].left, bounds[0].width, bounds[0].height
|
|
151
|
-
```
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# HTMLElement Extensions
|
|
2
|
-
|
|
3
|
-
Side-effect module that extends `HTMLElement.prototype` with layout and scrolling utilities.
|
|
4
|
-
|
|
5
|
-
## Prototype Methods
|
|
6
|
-
|
|
7
|
-
### HTMLElement.repaint
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
repaint(): void
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Force a synchronous repaint by triggering a reflow. Internally accesses `offsetHeight` to flush pending style changes.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
### HTMLElement.getRelativeOffset
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
getRelativeOffset(parent: HTMLElement | string): { top: number; left: number }
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Calculate the element's position relative to a parent element, returning document-based coordinates suitable for CSS `top`/`left` properties.
|
|
24
|
-
|
|
25
|
-
| Parameter | Type | Description |
|
|
26
|
-
|-----------|------|-------------|
|
|
27
|
-
| `parent` | `HTMLElement \| string` | Parent element or CSS selector to use as reference |
|
|
28
|
-
|
|
29
|
-
**Returns:** `{ top: number; left: number }` -- coordinates usable in CSS positioning.
|
|
30
|
-
|
|
31
|
-
**Throws:** `ArgumentError` (from `@simplysm/core-common`) if the parent element cannot be found.
|
|
32
|
-
|
|
33
|
-
The calculation accounts for:
|
|
34
|
-
- Viewport-relative position (`getBoundingClientRect`)
|
|
35
|
-
- Document scroll position (`window.scrollX/Y`)
|
|
36
|
-
- Parent element internal scroll (`parentEl.scrollTop/Left`)
|
|
37
|
-
- Border thickness of intermediate elements
|
|
38
|
-
- CSS `transform` transformations
|
|
39
|
-
|
|
40
|
-
Common use cases include positioning dropdowns and popups after appending them to `document.body`.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
### HTMLElement.scrollIntoViewIfNeeded
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
scrollIntoViewIfNeeded(
|
|
48
|
-
target: { top: number; left: number },
|
|
49
|
-
offset?: { top: number; left: number },
|
|
50
|
-
): void
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Scroll the element so that a target position is not obscured by a fixed offset area (e.g., a sticky header or fixed column).
|
|
54
|
-
|
|
55
|
-
| Parameter | Type | Default | Description |
|
|
56
|
-
|-----------|------|---------|-------------|
|
|
57
|
-
| `target` | `{ top: number; left: number }` | -- | Target position within the container (`offsetTop`, `offsetLeft`) |
|
|
58
|
-
| `offset` | `{ top: number; left: number }` | `{ top: 0, left: 0 }` | Size of the area that must remain unobscured |
|
|
59
|
-
|
|
60
|
-
Only handles cases where the target extends beyond the top/left boundaries of the scroll area. For downward/rightward scrolling, the browser's default focus scroll behavior is relied upon. Typically used with focus events on tables that have fixed headers or columns.
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Usage Examples
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
import "@simplysm/core-browser"; // activate side effects
|
|
68
|
-
|
|
69
|
-
// Force repaint after style changes
|
|
70
|
-
element.style.transform = "scale(1.1)";
|
|
71
|
-
element.repaint();
|
|
72
|
-
|
|
73
|
-
// Position a dropdown relative to document.body
|
|
74
|
-
const pos = trigger.getRelativeOffset(document.body);
|
|
75
|
-
dropdown.style.top = `${pos.top + trigger.offsetHeight}px`;
|
|
76
|
-
dropdown.style.left = `${pos.left}px`;
|
|
77
|
-
|
|
78
|
-
// Position relative to a container found by selector
|
|
79
|
-
const pos2 = cell.getRelativeOffset(".scroll-container");
|
|
80
|
-
|
|
81
|
-
// Scroll table so focused cell is visible past fixed header
|
|
82
|
-
tableContainer.scrollIntoViewIfNeeded(
|
|
83
|
-
{ top: cell.offsetTop, left: cell.offsetLeft },
|
|
84
|
-
{ top: headerHeight, left: fixedColumnWidth },
|
|
85
|
-
);
|
|
86
|
-
```
|
package/docs/indexed-db.md
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
# IndexedDB
|
|
2
|
-
|
|
3
|
-
Lightweight wrappers around the browser IndexedDB API. `IndexedDbStore` provides a simplified interface for opening databases and performing CRUD operations. `IndexedDbVirtualFs` builds on top of it to implement a virtual filesystem stored in IndexedDB.
|
|
4
|
-
|
|
5
|
-
## IndexedDbStore
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
class IndexedDbStore {
|
|
9
|
-
constructor(dbName: string, dbVersion: number, storeConfigs: StoreConfig[]);
|
|
10
|
-
}
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
A wrapper that manages an IndexedDB database with automatic store creation on version upgrades.
|
|
14
|
-
|
|
15
|
-
| Parameter | Type | Description |
|
|
16
|
-
|-----------|------|-------------|
|
|
17
|
-
| `dbName` | `string` | Database name |
|
|
18
|
-
| `dbVersion` | `number` | Database version (triggers `onupgradeneeded` when increased) |
|
|
19
|
-
| `storeConfigs` | `StoreConfig[]` | Object store definitions |
|
|
20
|
-
|
|
21
|
-
### StoreConfig
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
interface StoreConfig {
|
|
25
|
-
name: string;
|
|
26
|
-
keyPath: string;
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Methods
|
|
31
|
-
|
|
32
|
-
#### open
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
open(): Promise<IDBDatabase>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Open the database, creating any missing object stores defined in `storeConfigs`. Rejects if the database is blocked by another connection.
|
|
39
|
-
|
|
40
|
-
#### withStore
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
withStore<TResult>(
|
|
44
|
-
storeName: string,
|
|
45
|
-
mode: IDBTransactionMode,
|
|
46
|
-
fn: (store: IDBObjectStore) => Promise<TResult>,
|
|
47
|
-
): Promise<TResult>
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Execute a callback within a transaction on the specified store. The database connection is automatically opened and closed. If the callback throws, the transaction is aborted.
|
|
51
|
-
|
|
52
|
-
#### get
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
get<TValue>(storeName: string, key: IDBValidKey): Promise<TValue | undefined>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Retrieve a single record by key. Returns `undefined` if not found.
|
|
59
|
-
|
|
60
|
-
#### put
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
put(storeName: string, value: unknown): Promise<void>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Insert or update a record. The key is extracted from the value using the store's `keyPath`.
|
|
67
|
-
|
|
68
|
-
#### getAll
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
getAll<TItem>(storeName: string): Promise<TItem[]>
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Retrieve all records from a store.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## IndexedDbVirtualFs
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
class IndexedDbVirtualFs {
|
|
82
|
-
constructor(db: IndexedDbStore, storeName: string, keyField: string);
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
A virtual filesystem built on `IndexedDbStore`. Each entry is stored as a record with a full path key, a kind (`"file"` or `"dir"`), and optional Base64-encoded data.
|
|
87
|
-
|
|
88
|
-
| Parameter | Type | Description |
|
|
89
|
-
|-----------|------|-------------|
|
|
90
|
-
| `db` | `IndexedDbStore` | The underlying IndexedDB store instance |
|
|
91
|
-
| `storeName` | `string` | Name of the object store to use |
|
|
92
|
-
| `keyField` | `string` | The key property name in stored records |
|
|
93
|
-
|
|
94
|
-
### VirtualFsEntry
|
|
95
|
-
|
|
96
|
-
```typescript
|
|
97
|
-
interface VirtualFsEntry {
|
|
98
|
-
kind: "file" | "dir";
|
|
99
|
-
dataBase64?: string;
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Methods
|
|
104
|
-
|
|
105
|
-
#### getEntry
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
getEntry(fullKey: string): Promise<VirtualFsEntry | undefined>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Get a single filesystem entry by its full key path.
|
|
112
|
-
|
|
113
|
-
#### putEntry
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
putEntry(fullKey: string, kind: "file" | "dir", dataBase64?: string): Promise<void>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Create or update a filesystem entry.
|
|
120
|
-
|
|
121
|
-
#### deleteByPrefix
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
deleteByPrefix(keyPrefix: string): Promise<boolean>
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Delete all entries whose key matches the prefix or starts with `prefix + "/"`. Returns `true` if any entries were deleted.
|
|
128
|
-
|
|
129
|
-
#### listChildren
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
listChildren(prefix: string): Promise<{ name: string; isDirectory: boolean }[]>
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
List immediate children under a path prefix. Returns each child's name and whether it is a directory.
|
|
136
|
-
|
|
137
|
-
#### ensureDir
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
ensureDir(
|
|
141
|
-
fullKeyBuilder: (path: string) => string,
|
|
142
|
-
dirPath: string,
|
|
143
|
-
): Promise<void>
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Ensure that a directory and all its ancestor directories exist. Walks through each segment of `dirPath` and creates missing directory entries.
|
|
147
|
-
|
|
148
|
-
| Parameter | Type | Description |
|
|
149
|
-
|-----------|------|-------------|
|
|
150
|
-
| `fullKeyBuilder` | `(path: string) => string` | Function to convert a path into a full key |
|
|
151
|
-
| `dirPath` | `string` | Directory path to ensure (e.g., `"/data/images"`) |
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## Usage Examples
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
import { IndexedDbStore, IndexedDbVirtualFs } from "@simplysm/core-browser";
|
|
159
|
-
|
|
160
|
-
// Set up a database with one store
|
|
161
|
-
const store = new IndexedDbStore("my-app-db", 1, [
|
|
162
|
-
{ name: "files", keyPath: "path" },
|
|
163
|
-
]);
|
|
164
|
-
|
|
165
|
-
// Basic CRUD
|
|
166
|
-
await store.put("files", { path: "/config.json", data: "{}" });
|
|
167
|
-
const record = await store.get<{ path: string; data: string }>("files", "/config.json");
|
|
168
|
-
const allRecords = await store.getAll("files");
|
|
169
|
-
|
|
170
|
-
// Use withStore for custom transactions
|
|
171
|
-
await store.withStore("files", "readwrite", async (objStore) => {
|
|
172
|
-
return new Promise((resolve, reject) => {
|
|
173
|
-
const req = objStore.delete("/old-file.txt");
|
|
174
|
-
req.onsuccess = () => resolve(undefined);
|
|
175
|
-
req.onerror = () => reject(req.error);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// Virtual filesystem
|
|
180
|
-
const vfs = new IndexedDbVirtualFs(store, "files", "path");
|
|
181
|
-
|
|
182
|
-
await vfs.ensureDir((p) => p, "/data/images");
|
|
183
|
-
await vfs.putEntry("/data/images/photo.png", "file", btoa("...binary data..."));
|
|
184
|
-
|
|
185
|
-
const children = await vfs.listChildren("/data/");
|
|
186
|
-
// [{ name: "images", isDirectory: true }]
|
|
187
|
-
|
|
188
|
-
const entry = await vfs.getEntry("/data/images/photo.png");
|
|
189
|
-
// { kind: "file", dataBase64: "..." }
|
|
190
|
-
|
|
191
|
-
const deleted = await vfs.deleteByPrefix("/data/images");
|
|
192
|
-
// true
|
|
193
|
-
```
|
package/docs/utilities.md
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# Utilities
|
|
2
|
-
|
|
3
|
-
Standalone utility functions for file downloads, HTTP fetching with progress tracking, and programmatic file selection dialogs.
|
|
4
|
-
|
|
5
|
-
## downloadBlob
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
function downloadBlob(blob: Blob, fileName: string): void
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Download a Blob as a file. Creates a temporary object URL, triggers a download via an anchor click, and revokes the URL after 1 second.
|
|
12
|
-
|
|
13
|
-
| Parameter | Type | Description |
|
|
14
|
-
|-----------|------|-------------|
|
|
15
|
-
| `blob` | `Blob` | Blob object to download |
|
|
16
|
-
| `fileName` | `string` | File name for the downloaded file |
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## fetchUrlBytes
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
function fetchUrlBytes(
|
|
24
|
-
url: string,
|
|
25
|
-
options?: { onProgress?: (progress: DownloadProgress) => void },
|
|
26
|
-
): Promise<Uint8Array>
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Download binary data from a URL as a `Uint8Array`, with optional progress reporting.
|
|
30
|
-
|
|
31
|
-
| Parameter | Type | Description |
|
|
32
|
-
|-----------|------|-------------|
|
|
33
|
-
| `url` | `string` | URL to download from |
|
|
34
|
-
| `options.onProgress` | `(progress: DownloadProgress) => void` | Callback invoked as chunks are received |
|
|
35
|
-
|
|
36
|
-
When the server provides a `Content-Length` header, memory is pre-allocated for efficiency. For chunked transfers without `Content-Length`, chunks are collected and concatenated at the end.
|
|
37
|
-
|
|
38
|
-
Throws an `Error` if the response status is not OK or the response body is not readable.
|
|
39
|
-
|
|
40
|
-
### DownloadProgress
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
interface DownloadProgress {
|
|
44
|
-
receivedLength: number;
|
|
45
|
-
contentLength: number;
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## openFileDialog
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
function openFileDialog(options?: {
|
|
55
|
-
accept?: string;
|
|
56
|
-
multiple?: boolean;
|
|
57
|
-
}): Promise<File[] | undefined>
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Programmatically open a file selection dialog without requiring a visible `<input type="file">` in the DOM.
|
|
61
|
-
|
|
62
|
-
| Parameter | Type | Default | Description |
|
|
63
|
-
|-----------|------|---------|-------------|
|
|
64
|
-
| `options.accept` | `string` | -- | Accepted file types (e.g., `".png,.jpg"`, `"image/*"`) |
|
|
65
|
-
| `options.multiple` | `boolean` | `false` | Allow selecting multiple files |
|
|
66
|
-
|
|
67
|
-
**Returns:** A `File[]` if the user selected files, or `undefined` if the dialog was cancelled.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Usage Examples
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { downloadBlob, fetchUrlBytes, openFileDialog } from "@simplysm/core-browser";
|
|
75
|
-
|
|
76
|
-
// Download a text file
|
|
77
|
-
const blob = new Blob(["Hello, world!"], { type: "text/plain" });
|
|
78
|
-
downloadBlob(blob, "hello.txt");
|
|
79
|
-
|
|
80
|
-
// Fetch binary data with progress
|
|
81
|
-
const data = await fetchUrlBytes("https://example.com/archive.zip", {
|
|
82
|
-
onProgress: ({ receivedLength, contentLength }) => {
|
|
83
|
-
console.log(`${Math.round((receivedLength / contentLength) * 100)}%`);
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Open file dialog for images
|
|
88
|
-
const files = await openFileDialog({ accept: "image/*", multiple: true });
|
|
89
|
-
if (files) {
|
|
90
|
-
for (const file of files) {
|
|
91
|
-
// process each selected file
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|