@simplysm/core-browser 13.0.78 → 13.0.80

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.
@@ -79,7 +79,7 @@ async function getBounds(els, timeout = 5e3) {
79
79
  if (indexMap.size === 0) {
80
80
  return [];
81
81
  }
82
- const sortIndexMap = new Map(els.map((el, i) => [el, i]));
82
+ const remaining = new Set(indexMap.keys());
83
83
  let observer;
84
84
  try {
85
85
  return await Promise.race([
@@ -88,8 +88,8 @@ async function getBounds(els, timeout = 5e3) {
88
88
  observer = new IntersectionObserver((entries) => {
89
89
  for (const entry of entries) {
90
90
  const target = entry.target;
91
- if (indexMap.has(target)) {
92
- indexMap.delete(target);
91
+ if (remaining.has(target)) {
92
+ remaining.delete(target);
93
93
  results.push({
94
94
  target,
95
95
  top: entry.boundingClientRect.top,
@@ -99,10 +99,10 @@ async function getBounds(els, timeout = 5e3) {
99
99
  });
100
100
  }
101
101
  }
102
- if (indexMap.size === 0) {
102
+ if (remaining.size === 0) {
103
103
  observer == null ? void 0 : observer.disconnect();
104
104
  resolve(
105
- results.sort((a, b) => sortIndexMap.get(a.target) - sortIndexMap.get(b.target))
105
+ results.sort((a, b) => indexMap.get(a.target) - indexMap.get(b.target))
106
106
  );
107
107
  }
108
108
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/extensions/element-ext.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": []
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["..\\..\\src\\utils\\fetch.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAE,GAC9D,OAAO,CAAC,UAAU,CAAC,CAsDrB"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["..\\..\\src\\utils\\fetch.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAE,GAC9D,OAAO,CAAC,UAAU,CAAC,CA4CrB"}
@@ -1,3 +1,4 @@
1
+ import { bytes } from "@simplysm/core-common";
1
2
  async function fetchUrlBytes(url, options) {
2
3
  var _a, _b;
3
4
  const response = await fetch(url);
@@ -11,32 +12,24 @@ async function fetchUrlBytes(url, options) {
11
12
  }
12
13
  try {
13
14
  if (contentLength > 0) {
14
- const result2 = new Uint8Array(contentLength);
15
- let receivedLength2 = 0;
15
+ const result = new Uint8Array(contentLength);
16
+ let receivedLength = 0;
16
17
  while (true) {
17
18
  const { done, value } = await reader.read();
18
19
  if (done) break;
19
- result2.set(value, receivedLength2);
20
- receivedLength2 += value.length;
21
- (_b = options == null ? void 0 : options.onProgress) == null ? void 0 : _b.call(options, { receivedLength: receivedLength2, contentLength });
20
+ result.set(value, receivedLength);
21
+ receivedLength += value.length;
22
+ (_b = options == null ? void 0 : options.onProgress) == null ? void 0 : _b.call(options, { receivedLength, contentLength });
22
23
  }
23
- return result2;
24
+ return result;
24
25
  }
25
26
  const chunks = [];
26
- let receivedLength = 0;
27
27
  while (true) {
28
28
  const { done, value } = await reader.read();
29
29
  if (done) break;
30
30
  chunks.push(value);
31
- receivedLength += value.length;
32
31
  }
33
- const result = new Uint8Array(receivedLength);
34
- let position = 0;
35
- for (const chunk of chunks) {
36
- result.set(chunk, position);
37
- position += chunk.length;
38
- }
39
- return result;
32
+ return bytes.concat(chunks);
40
33
  } finally {
41
34
  reader.releaseLock();
42
35
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/fetch.ts"],
4
- "mappings": "AAQA,eAAsB,cACpB,KACA,SACqB;AAXvB;AAYE,QAAM,WAAW,MAAM,MAAM,GAAG;AAChC,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,oBAAoB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,EAC9E;AAEA,QAAM,gBAAgB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AACxE,QAAM,UAAS,cAAS,SAAT,mBAAe;AAC9B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,MAAI;AAEF,QAAI,gBAAgB,GAAG;AACrB,YAAMA,UAAS,IAAI,WAAW,aAAa;AAC3C,UAAIC,kBAAiB;AAErB,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,QAAAD,QAAO,IAAI,OAAOC,eAAc;AAChC,QAAAA,mBAAkB,MAAM;AACxB,iDAAS,eAAT,iCAAsB,EAAE,gBAAAA,iBAAgB,cAAc;AAAA,MACxD;AAEA,aAAOD;AAAA,IACT;AAGA,UAAM,SAAuB,CAAC;AAC9B,QAAI,iBAAiB;AAErB,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AAEV,aAAO,KAAK,KAAK;AACjB,wBAAkB,MAAM;AAAA,IAC1B;AAGA,UAAM,SAAS,IAAI,WAAW,cAAc;AAC5C,QAAI,WAAW;AACf,eAAW,SAAS,QAAQ;AAC1B,aAAO,IAAI,OAAO,QAAQ;AAC1B,kBAAY,MAAM;AAAA,IACpB;AAEA,WAAO;AAAA,EACT,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;",
5
- "names": ["result", "receivedLength"]
4
+ "mappings": "AAAA,SAAS,aAAa;AAUtB,eAAsB,cACpB,KACA,SACqB;AAbvB;AAcE,QAAM,WAAW,MAAM,MAAM,GAAG;AAChC,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,oBAAoB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,EAC9E;AAEA,QAAM,gBAAgB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AACxE,QAAM,UAAS,cAAS,SAAT,mBAAe;AAC9B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,MAAI;AAEF,QAAI,gBAAgB,GAAG;AACrB,YAAM,SAAS,IAAI,WAAW,aAAa;AAC3C,UAAI,iBAAiB;AAErB,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,eAAO,IAAI,OAAO,cAAc;AAChC,0BAAkB,MAAM;AACxB,iDAAS,eAAT,iCAAsB,EAAE,gBAAgB,cAAc;AAAA,MACxD;AAEA,aAAO;AAAA,IACT;AAGA,UAAM,SAAuB,CAAC;AAE9B,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AAEV,aAAO,KAAK,KAAK;AAAA,IACnB;AAEA,WAAO,MAAM,OAAO,MAAM;AAAA,EAC5B,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;",
5
+ "names": []
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-dialog.d.ts","sourceRoot":"","sources":["..\\..\\src\\utils\\file-dialog.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,CAa9B"}
1
+ {"version":3,"file":"file-dialog.d.ts","sourceRoot":"","sources":["..\\..\\src\\utils\\file-dialog.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,CAgB9B"}
@@ -9,6 +9,9 @@ function openFileDialog(options) {
9
9
  input.onchange = () => {
10
10
  resolve(input.files != null && input.files.length > 0 ? [...input.files] : void 0);
11
11
  };
12
+ input.addEventListener("cancel", () => {
13
+ resolve(void 0);
14
+ });
12
15
  input.click();
13
16
  });
14
17
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/file-dialog.ts"],
4
- "mappings": "AAGO,SAAS,eAAe,SAGC;AAC9B,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,OAAO;AACb,UAAM,YAAW,mCAAS,aAAY;AACtC,SAAI,mCAAS,WAAU,MAAM;AAC3B,YAAM,SAAS,QAAQ;AAAA,IACzB;AACA,UAAM,WAAW,MAAM;AACrB,cAAQ,MAAM,SAAS,QAAQ,MAAM,MAAM,SAAS,IAAI,CAAC,GAAG,MAAM,KAAK,IAAI,MAAS;AAAA,IACtF;AACA,UAAM,MAAM;AAAA,EACd,CAAC;AACH;",
4
+ "mappings": "AAGO,SAAS,eAAe,SAGC;AAC9B,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,OAAO;AACb,UAAM,YAAW,mCAAS,aAAY;AACtC,SAAI,mCAAS,WAAU,MAAM;AAC3B,YAAM,SAAS,QAAQ;AAAA,IACzB;AACA,UAAM,WAAW,MAAM;AACrB,cAAQ,MAAM,SAAS,QAAQ,MAAM,MAAM,SAAS,IAAI,CAAC,GAAG,MAAM,KAAK,IAAI,MAAS;AAAA,IACtF;AACA,UAAM,iBAAiB,UAAU,MAAM;AACrC,cAAQ,MAAS;AAAA,IACnB,CAAC;AACD,UAAM,MAAM;AAAA,EACd,CAAC;AACH;",
5
5
  "names": []
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/core-browser",
3
- "version": "13.0.78",
3
+ "version": "13.0.80",
4
4
  "description": "Simplysm package - Core module (browser)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -14,6 +14,7 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "files": [
16
16
  "dist",
17
+ "docs",
17
18
  "src",
18
19
  "tests"
19
20
  ],
@@ -23,7 +24,7 @@
23
24
  ],
24
25
  "dependencies": {
25
26
  "tabbable": "^6.4.0",
26
- "@simplysm/core-common": "13.0.78"
27
+ "@simplysm/core-common": "13.0.80"
27
28
  },
28
29
  "devDependencies": {
29
30
  "happy-dom": "^20.8.3"
@@ -204,8 +204,8 @@ export async function getBounds(els: Element[], timeout: number = 5000): Promise
204
204
  return [];
205
205
  }
206
206
 
207
- // Index map for sorting performance optimization
208
- const sortIndexMap = new Map(els.map((el, i) => [el, i] as const));
207
+ // Set to track remaining elements
208
+ const remaining = new Set(indexMap.keys());
209
209
 
210
210
  let observer: IntersectionObserver | undefined;
211
211
 
@@ -217,8 +217,8 @@ export async function getBounds(els: Element[], timeout: number = 5000): Promise
217
217
  observer = new IntersectionObserver((entries) => {
218
218
  for (const entry of entries) {
219
219
  const target = entry.target;
220
- if (indexMap.has(target)) {
221
- indexMap.delete(target);
220
+ if (remaining.has(target)) {
221
+ remaining.delete(target);
222
222
  results.push({
223
223
  target,
224
224
  top: entry.boundingClientRect.top,
@@ -229,11 +229,11 @@ export async function getBounds(els: Element[], timeout: number = 5000): Promise
229
229
  }
230
230
  }
231
231
 
232
- if (indexMap.size === 0) {
232
+ if (remaining.size === 0) {
233
233
  observer?.disconnect();
234
234
  // Sort in input order
235
235
  resolve(
236
- results.sort((a, b) => sortIndexMap.get(a.target)! - sortIndexMap.get(b.target)!),
236
+ results.sort((a, b) => indexMap.get(a.target)! - indexMap.get(b.target)!),
237
237
  );
238
238
  }
239
239
  });
@@ -1,3 +1,5 @@
1
+ import { bytes } from "@simplysm/core-common";
2
+
1
3
  export interface DownloadProgress {
2
4
  receivedLength: number;
3
5
  contentLength: number;
@@ -41,25 +43,15 @@ export async function fetchUrlBytes(
41
43
 
42
44
  // If Content-Length is unknown, collect chunks then merge (chunked encoding)
43
45
  const chunks: Uint8Array[] = [];
44
- let receivedLength = 0;
45
46
 
46
47
  while (true) {
47
48
  const { done, value } = await reader.read();
48
49
  if (done) break;
49
50
 
50
51
  chunks.push(value);
51
- receivedLength += value.length;
52
- }
53
-
54
- // Merge chunks
55
- const result = new Uint8Array(receivedLength);
56
- let position = 0;
57
- for (const chunk of chunks) {
58
- result.set(chunk, position);
59
- position += chunk.length;
60
52
  }
61
53
 
62
- return result;
54
+ return bytes.concat(chunks);
63
55
  } finally {
64
56
  reader.releaseLock();
65
57
  }
@@ -15,6 +15,9 @@ export function openFileDialog(options?: {
15
15
  input.onchange = () => {
16
16
  resolve(input.files != null && input.files.length > 0 ? [...input.files] : undefined);
17
17
  };
18
+ input.addEventListener("cancel", () => {
19
+ resolve(undefined);
20
+ });
18
21
  input.click();
19
22
  });
20
23
  }
package/README.md DELETED
@@ -1,606 +0,0 @@
1
- # @simplysm/core-browser
2
-
3
- Simplysm package - Core module (browser)
4
-
5
- Browser-only utilities including DOM element extensions, file download helpers, fetch utilities, file dialog helpers, and IndexedDB wrappers.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- pnpm add @simplysm/core-browser
11
- ```
12
-
13
- Import the package to activate side-effect extensions on `Element` and `HTMLElement`:
14
-
15
- ```ts
16
- import "@simplysm/core-browser";
17
- ```
18
-
19
- ---
20
-
21
- ## Element Extensions
22
-
23
- Extends the global `Element` interface with utility methods. These are activated as side effects when the package is imported.
24
-
25
- ### `element.findAll<TEl>(selector)`
26
-
27
- Finds all child elements matching a CSS selector.
28
-
29
- - Returns an empty array if the selector is empty.
30
-
31
- ```ts
32
- import "@simplysm/core-browser";
33
-
34
- const items = containerEl.findAll<HTMLLIElement>("li.active");
35
- ```
36
-
37
- **Signature:**
38
-
39
- ```ts
40
- findAll<TEl extends Element = Element>(selector: string): TEl[]
41
- ```
42
-
43
- ---
44
-
45
- ### `element.findFirst<TEl>(selector)`
46
-
47
- Finds the first child element matching a CSS selector.
48
-
49
- - Returns `undefined` if the selector is empty or no match is found.
50
-
51
- ```ts
52
- import "@simplysm/core-browser";
53
-
54
- const input = formEl.findFirst<HTMLInputElement>("input[name='email']");
55
- ```
56
-
57
- **Signature:**
58
-
59
- ```ts
60
- findFirst<TEl extends Element = Element>(selector: string): TEl | undefined
61
- ```
62
-
63
- ---
64
-
65
- ### `element.prependChild<TEl>(child)`
66
-
67
- Inserts a child element as the first child of the element.
68
-
69
- ```ts
70
- import "@simplysm/core-browser";
71
-
72
- const newEl = document.createElement("div");
73
- containerEl.prependChild(newEl);
74
- ```
75
-
76
- **Signature:**
77
-
78
- ```ts
79
- prependChild<TEl extends Element>(child: TEl): TEl
80
- ```
81
-
82
- ---
83
-
84
- ### `element.getParents()`
85
-
86
- Returns all ancestor elements in order from closest to farthest.
87
-
88
- ```ts
89
- import "@simplysm/core-browser";
90
-
91
- const parents = someEl.getParents();
92
- // parents[0] is the immediate parent, parents[n-1] is the farthest ancestor
93
- ```
94
-
95
- **Signature:**
96
-
97
- ```ts
98
- getParents(): Element[]
99
- ```
100
-
101
- ---
102
-
103
- ### `element.findFocusableParent()`
104
-
105
- Finds the first focusable ancestor element using the `tabbable` library's focusability check.
106
-
107
- - Returns `undefined` if no focusable parent is found.
108
-
109
- ```ts
110
- import "@simplysm/core-browser";
111
-
112
- const focusableParent = someEl.findFocusableParent();
113
- focusableParent?.focus();
114
- ```
115
-
116
- **Signature:**
117
-
118
- ```ts
119
- findFocusableParent(): HTMLElement | undefined
120
- ```
121
-
122
- ---
123
-
124
- ### `element.findFirstFocusableChild()`
125
-
126
- Finds the first focusable descendant element using a `TreeWalker` and the `tabbable` library's focusability check.
127
-
128
- - Returns `undefined` if no focusable child is found.
129
-
130
- ```ts
131
- import "@simplysm/core-browser";
132
-
133
- const firstFocusable = dialogEl.findFirstFocusableChild();
134
- firstFocusable?.focus();
135
- ```
136
-
137
- **Signature:**
138
-
139
- ```ts
140
- findFirstFocusableChild(): HTMLElement | undefined
141
- ```
142
-
143
- ---
144
-
145
- ### `element.isOffsetElement()`
146
-
147
- Checks whether the element has a CSS `position` of `relative`, `absolute`, `fixed`, or `sticky`.
148
-
149
- ```ts
150
- import "@simplysm/core-browser";
151
-
152
- if (someEl.isOffsetElement()) {
153
- // element is a positioning context
154
- }
155
- ```
156
-
157
- **Signature:**
158
-
159
- ```ts
160
- isOffsetElement(): boolean
161
- ```
162
-
163
- ---
164
-
165
- ### `element.isVisible()`
166
-
167
- Checks whether the element is visible on screen.
168
-
169
- Considers:
170
- - Presence of client rects (`getClientRects().length > 0`)
171
- - `visibility: hidden`
172
- - `opacity: 0`
173
-
174
- ```ts
175
- import "@simplysm/core-browser";
176
-
177
- if (someEl.isVisible()) {
178
- // element is visible
179
- }
180
- ```
181
-
182
- **Signature:**
183
-
184
- ```ts
185
- isVisible(): boolean
186
- ```
187
-
188
- ---
189
-
190
- ## HTMLElement Extensions
191
-
192
- Extends the global `HTMLElement` interface with utility methods. These are activated as side effects when the package is imported.
193
-
194
- ### `htmlElement.repaint()`
195
-
196
- Forces a browser repaint by triggering a synchronous reflow.
197
-
198
- Accessing `offsetHeight` forces the browser to flush pending style changes immediately.
199
-
200
- ```ts
201
- import "@simplysm/core-browser";
202
-
203
- el.classList.add("animate");
204
- el.repaint(); // flush styles
205
- el.classList.add("animate-active");
206
- ```
207
-
208
- **Signature:**
209
-
210
- ```ts
211
- repaint(): void
212
- ```
213
-
214
- ---
215
-
216
- ### `htmlElement.getRelativeOffset(parent)`
217
-
218
- Calculates the element's position relative to a parent element, returning coordinates suitable for use directly in CSS `top`/`left` properties.
219
-
220
- Accounts for:
221
- - Viewport-relative position (`getBoundingClientRect`)
222
- - Document scroll position (`window.scrollX/Y`)
223
- - Parent element internal scroll (`scrollTop/Left`)
224
- - Border widths of intermediate elements
225
- - CSS `transform` on element and parent
226
-
227
- Typical use: positioning dropdowns or popups appended to `document.body`.
228
-
229
- - `parent` — a reference `HTMLElement` or a CSS selector string (resolved via `closest`)
230
- - Throws `ArgumentError` if the parent element cannot be found.
231
-
232
- ```ts
233
- import "@simplysm/core-browser";
234
-
235
- const popup = document.createElement("div");
236
- document.body.appendChild(popup);
237
- const { top, left } = triggerEl.getRelativeOffset(document.body);
238
- popup.style.top = `${top}px`;
239
- popup.style.left = `${left}px`;
240
- ```
241
-
242
- **Signature:**
243
-
244
- ```ts
245
- getRelativeOffset(parent: HTMLElement | string): { top: number; left: number }
246
- ```
247
-
248
- ---
249
-
250
- ### `htmlElement.scrollIntoViewIfNeeded(target, offset?)`
251
-
252
- Scrolls the element so that a target position becomes visible, but only if the target is hidden behind an offset area (e.g., a fixed header or fixed column).
253
-
254
- - Only handles cases where the target is obscured from the top or left. Downward/rightward scrolling relies on the browser's default focus behavior.
255
- - Typically used with focus events on tables with fixed headers or columns.
256
-
257
- ```ts
258
- import "@simplysm/core-browser";
259
-
260
- tableEl.scrollIntoViewIfNeeded(
261
- { top: row.offsetTop, left: row.offsetLeft },
262
- { top: 48, left: 120 }, // fixed header height and fixed column width
263
- );
264
- ```
265
-
266
- **Signature:**
267
-
268
- ```ts
269
- scrollIntoViewIfNeeded(
270
- target: { top: number; left: number },
271
- offset?: { top: number; left: number },
272
- ): void
273
- ```
274
-
275
- ---
276
-
277
- ## Static Element Utilities
278
-
279
- Standalone functions exported from `element-ext`.
280
-
281
- ### `copyElement(event)`
282
-
283
- Copies the value of the first `input` or `textarea` inside the event target element to the clipboard.
284
-
285
- Intended for use as a `copy` event handler.
286
-
287
- ```ts
288
- import { copyElement } from "@simplysm/core-browser";
289
-
290
- someEl.addEventListener("copy", copyElement);
291
- ```
292
-
293
- **Signature:**
294
-
295
- ```ts
296
- function copyElement(event: ClipboardEvent): void
297
- ```
298
-
299
- ---
300
-
301
- ### `pasteToElement(event)`
302
-
303
- Pastes plain-text clipboard content into the first `input` or `textarea` inside the event target element, replacing its entire value.
304
-
305
- Intended for use as a `paste` event handler. Does not consider cursor position or selection.
306
-
307
- ```ts
308
- import { pasteToElement } from "@simplysm/core-browser";
309
-
310
- someEl.addEventListener("paste", pasteToElement);
311
- ```
312
-
313
- **Signature:**
314
-
315
- ```ts
316
- function pasteToElement(event: ClipboardEvent): void
317
- ```
318
-
319
- ---
320
-
321
- ### `getBounds(els, timeout?)`
322
-
323
- Retrieves bounding box information for multiple elements using `IntersectionObserver`. Results are returned in the same order as the input array.
324
-
325
- - Deduplicates elements internally.
326
- - Returns an empty array if `els` is empty.
327
- - Throws `TimeoutError` if results are not received within `timeout` milliseconds (default: `5000`).
328
-
329
- ```ts
330
- import { getBounds } from "@simplysm/core-browser";
331
-
332
- const bounds = await getBounds([el1, el2]);
333
- for (const { target, top, left, width, height } of bounds) {
334
- console.log(target, top, left, width, height);
335
- }
336
- ```
337
-
338
- **Signature:**
339
-
340
- ```ts
341
- function getBounds(els: Element[], timeout?: number): Promise<ElementBounds[]>
342
- ```
343
-
344
- ---
345
-
346
- ## Download Utilities
347
-
348
- ### `downloadBlob(blob, fileName)`
349
-
350
- Triggers a file download in the browser for a given `Blob` object.
351
-
352
- Creates a temporary object URL, simulates an anchor click, and revokes the URL after 1 second.
353
-
354
- ```ts
355
- import { downloadBlob } from "@simplysm/core-browser";
356
-
357
- const blob = new Blob(["hello"], { type: "text/plain" });
358
- downloadBlob(blob, "hello.txt");
359
- ```
360
-
361
- **Signature:**
362
-
363
- ```ts
364
- function downloadBlob(blob: Blob, fileName: string): void
365
- ```
366
-
367
- ---
368
-
369
- ## Fetch Utilities
370
-
371
- ### `fetchUrlBytes(url, options?)`
372
-
373
- Downloads binary data from a URL and returns it as a `Uint8Array`, with optional progress reporting.
374
-
375
- - When `Content-Length` is known, pre-allocates memory for efficiency.
376
- - When `Content-Length` is unknown (chunked transfer encoding), collects chunks then merges.
377
- - Throws an `Error` if the response is not OK or the body is not readable.
378
-
379
- ```ts
380
- import { fetchUrlBytes } from "@simplysm/core-browser";
381
-
382
- const bytes = await fetchUrlBytes("https://example.com/file.bin", {
383
- onProgress: ({ receivedLength, contentLength }) => {
384
- console.log(`${receivedLength} / ${contentLength}`);
385
- },
386
- });
387
- ```
388
-
389
- **Signature:**
390
-
391
- ```ts
392
- function fetchUrlBytes(
393
- url: string,
394
- options?: { onProgress?: (progress: DownloadProgress) => void },
395
- ): Promise<Uint8Array>
396
- ```
397
-
398
- ---
399
-
400
- ## File Dialog Utilities
401
-
402
- ### `openFileDialog(options?)`
403
-
404
- Programmatically opens a browser file selection dialog and returns the selected files.
405
-
406
- - Returns `undefined` if the user cancels or selects no files.
407
- - `options.accept` — MIME type or file extension filter (e.g., `"image/*"`, `".pdf"`)
408
- - `options.multiple` — allow selecting multiple files (default: `false`)
409
-
410
- ```ts
411
- import { openFileDialog } from "@simplysm/core-browser";
412
-
413
- const files = await openFileDialog({ accept: ".csv", multiple: true });
414
- if (files) {
415
- for (const file of files) {
416
- console.log(file.name);
417
- }
418
- }
419
- ```
420
-
421
- **Signature:**
422
-
423
- ```ts
424
- function openFileDialog(options?: {
425
- accept?: string;
426
- multiple?: boolean;
427
- }): Promise<File[] | undefined>
428
- ```
429
-
430
- ---
431
-
432
- ## IndexedDB Store
433
-
434
- ### `IndexedDbStore`
435
-
436
- A thin wrapper around the browser `IndexedDB` API for typed key-value object stores. Opens a versioned database, auto-creates stores on upgrade, and closes the connection after each operation.
437
-
438
- ```ts
439
- import { IndexedDbStore } from "@simplysm/core-browser";
440
-
441
- const db = new IndexedDbStore("my-db", 1, [
442
- { name: "users", keyPath: "id" },
443
- ]);
444
-
445
- await db.put("users", { id: 1, name: "Alice" });
446
- const user = await db.get<{ id: number; name: string }>("users", 1);
447
- const all = await db.getAll<{ id: number; name: string }>("users");
448
- ```
449
-
450
- **Constructor:**
451
-
452
- ```ts
453
- new IndexedDbStore(
454
- dbName: string,
455
- dbVersion: number,
456
- storeConfigs: StoreConfig[],
457
- )
458
- ```
459
-
460
- **Methods:**
461
-
462
- ```ts
463
- open(): Promise<IDBDatabase>
464
-
465
- withStore<TResult>(
466
- storeName: string,
467
- mode: IDBTransactionMode,
468
- fn: (store: IDBObjectStore) => Promise<TResult>,
469
- ): Promise<TResult>
470
-
471
- get<TValue>(storeName: string, key: IDBValidKey): Promise<TValue | undefined>
472
-
473
- put(storeName: string, value: unknown): Promise<void>
474
-
475
- getAll<TItem>(storeName: string): Promise<TItem[]>
476
- ```
477
-
478
- - `open()` — opens the database and returns the raw `IDBDatabase`. Creates missing object stores declared in `storeConfigs`. Rejects if the connection is blocked.
479
- - `withStore()` — executes `fn` inside a single transaction on `storeName`. Aborts the transaction if `fn` throws. Closes the database when the transaction completes.
480
- - `get()` — retrieves one record by `key` from `storeName`. Returns `undefined` if not found.
481
- - `put()` — inserts or updates a record in `storeName`.
482
- - `getAll()` — retrieves all records from `storeName`.
483
-
484
- ---
485
-
486
- ## IndexedDB Virtual Filesystem
487
-
488
- ### `IndexedDbVirtualFs`
489
-
490
- A virtual filesystem built on top of `IndexedDbStore`. Each entry is stored as a flat key (slash-separated path string) with a kind (`"file"` or `"dir"`) and optional base64 data payload.
491
-
492
- ```ts
493
- import { IndexedDbStore, IndexedDbVirtualFs } from "@simplysm/core-browser";
494
-
495
- const db = new IndexedDbStore("my-fs-db", 1, [
496
- { name: "fs", keyPath: "fullKey" },
497
- ]);
498
- const vfs = new IndexedDbVirtualFs(db, "fs", "fullKey");
499
-
500
- await vfs.putEntry("/docs/readme.txt", "file", btoa("hello"));
501
- const entry = await vfs.getEntry("/docs/readme.txt");
502
- const children = await vfs.listChildren("/docs/");
503
- await vfs.deleteByPrefix("/docs");
504
- ```
505
-
506
- **Constructor:**
507
-
508
- ```ts
509
- new IndexedDbVirtualFs(
510
- db: IndexedDbStore,
511
- storeName: string,
512
- keyField: string,
513
- )
514
- ```
515
-
516
- - `db` — an `IndexedDbStore` instance to use for persistence.
517
- - `storeName` — the object store name within the database.
518
- - `keyField` — the field name used as the primary key in stored records.
519
-
520
- **Methods:**
521
-
522
- ```ts
523
- getEntry(fullKey: string): Promise<VirtualFsEntry | undefined>
524
-
525
- putEntry(fullKey: string, kind: "file" | "dir", dataBase64?: string): Promise<void>
526
-
527
- deleteByPrefix(keyPrefix: string): Promise<boolean>
528
-
529
- listChildren(prefix: string): Promise<{ name: string; isDirectory: boolean }[]>
530
-
531
- ensureDir(fullKeyBuilder: (path: string) => string, dirPath: string): Promise<void>
532
- ```
533
-
534
- - `getEntry()` — retrieves the entry for `fullKey`. Returns `undefined` if not found.
535
- - `putEntry()` — writes or overwrites an entry with the given `kind` and optional base64 data.
536
- - `deleteByPrefix()` — deletes all entries whose key equals `keyPrefix` or starts with `keyPrefix + "/"`. Returns `true` if at least one entry was deleted.
537
- - `listChildren()` — lists the immediate children under `prefix`. Each result includes `name` (the path segment) and `isDirectory`.
538
- - `ensureDir()` — creates directory entries for every path segment in `dirPath` if they do not already exist. `fullKeyBuilder` maps a path string to the full store key.
539
-
540
- ---
541
-
542
- ## Types
543
-
544
- ### `ElementBounds`
545
-
546
- Bounding box information for an element, returned by `getBounds`.
547
-
548
- ```ts
549
- interface ElementBounds {
550
- /** Element that was measured */
551
- target: Element;
552
- /** Top position relative to the viewport */
553
- top: number;
554
- /** Left position relative to the viewport */
555
- left: number;
556
- /** Element width */
557
- width: number;
558
- /** Element height */
559
- height: number;
560
- }
561
- ```
562
-
563
- ---
564
-
565
- ### `DownloadProgress`
566
-
567
- Progress information passed to the `onProgress` callback of `fetchUrlBytes`.
568
-
569
- ```ts
570
- interface DownloadProgress {
571
- /** Number of bytes received so far */
572
- receivedLength: number;
573
- /** Total content length in bytes (0 if unknown) */
574
- contentLength: number;
575
- }
576
- ```
577
-
578
- ---
579
-
580
- ### `StoreConfig`
581
-
582
- Configuration for a single object store within an `IndexedDbStore`.
583
-
584
- ```ts
585
- interface StoreConfig {
586
- /** Object store name */
587
- name: string;
588
- /** Primary key field path */
589
- keyPath: string;
590
- }
591
- ```
592
-
593
- ---
594
-
595
- ### `VirtualFsEntry`
596
-
597
- A single entry stored in the `IndexedDbVirtualFs`.
598
-
599
- ```ts
600
- interface VirtualFsEntry {
601
- /** Entry kind: "file" or "dir" */
602
- kind: "file" | "dir";
603
- /** File contents encoded as base64 (only present for file entries) */
604
- dataBase64?: string;
605
- }
606
- ```