@simplysm/core-browser 14.0.1 → 14.0.5

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 ADDED
@@ -0,0 +1,151 @@
1
+ # @simplysm/core-browser
2
+
3
+ Browser-specific core utilities for the Simplysm framework. Provides DOM element extensions, download/fetch helpers, file dialog, and IndexedDB abstractions.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @simplysm/core-browser
9
+ ```
10
+
11
+ ## API Overview
12
+
13
+ ### Element Extensions
14
+
15
+ | API | Type | Description |
16
+ |-----|------|-------------|
17
+ | `ElementBounds` | interface | Bounding rect info for an element |
18
+ | `Element.prototype.findAll` | method | Find all descendant elements matching a CSS selector |
19
+ | `Element.prototype.findFirst` | method | Find the first descendant element matching a CSS selector |
20
+ | `Element.prototype.prependChild` | method | Insert a child as the first element child |
21
+ | `Element.prototype.getParents` | method | Get all ancestor elements (nearest first) |
22
+ | `Element.prototype.findFocusableParent` | method | Find the nearest focusable ancestor |
23
+ | `Element.prototype.findFirstFocusableChild` | method | Find the first focusable descendant |
24
+ | `Element.prototype.isOffsetElement` | method | Check if element is an offset parent |
25
+ | `Element.prototype.isVisible` | method | Check if element is visible on screen |
26
+ | `copyElement` | function | Copy element content to clipboard via ClipboardEvent |
27
+ | `pasteToElement` | function | Paste clipboard content into element via ClipboardEvent |
28
+ | `getBounds` | function | Get bounding info for multiple elements using IntersectionObserver |
29
+
30
+ > See [docs/element-extensions.md](./docs/element-extensions.md) for details.
31
+
32
+ ### HTML Element Extensions
33
+
34
+ | API | Type | Description |
35
+ |-----|------|-------------|
36
+ | `HTMLElement.prototype.repaint` | method | Force a synchronous repaint |
37
+ | `HTMLElement.prototype.getRelativeOffset` | method | Calculate position relative to a parent element |
38
+ | `HTMLElement.prototype.scrollIntoViewIfNeeded` | method | Scroll container so target is not hidden by offset areas |
39
+
40
+ > See [docs/html-element-extensions.md](./docs/html-element-extensions.md) for details.
41
+
42
+ ### Download
43
+
44
+ | API | Type | Description |
45
+ |-----|------|-------------|
46
+ | `downloadBlob` | function | Download a Blob as a file |
47
+
48
+ > See [docs/download.md](./docs/download.md) for details.
49
+
50
+ ### Fetch
51
+
52
+ | API | Type | Description |
53
+ |-----|------|-------------|
54
+ | `DownloadProgress` | interface | Progress info for fetch downloads |
55
+ | `fetchUrlBytes` | function | Download binary data from a URL with progress callback |
56
+
57
+ > See [docs/fetch.md](./docs/fetch.md) for details.
58
+
59
+ ### File Dialog
60
+
61
+ | API | Type | Description |
62
+ |-----|------|-------------|
63
+ | `openFileDialog` | function | Programmatically open a file picker dialog |
64
+
65
+ > See [docs/file-dialog.md](./docs/file-dialog.md) for details.
66
+
67
+ ### IndexedDB Store
68
+
69
+ | API | Type | Description |
70
+ |-----|------|-------------|
71
+ | `StoreConfig` | interface | Configuration for an IndexedDB object store |
72
+ | `IndexedDbStore` | class | Generic IndexedDB wrapper with CRUD operations |
73
+
74
+ > See [docs/indexed-db-store.md](./docs/indexed-db-store.md) for details.
75
+
76
+ ### IndexedDB Virtual FS
77
+
78
+ | API | Type | Description |
79
+ |-----|------|-------------|
80
+ | `VirtualFsEntry` | interface | Entry representing a file or directory in the virtual FS |
81
+ | `IndexedDbVirtualFs` | class | Virtual file system backed by IndexedDB |
82
+
83
+ > See [docs/indexed-db-virtual-fs.md](./docs/indexed-db-virtual-fs.md) for details.
84
+
85
+ ## Usage Examples
86
+
87
+ ### Copy/Paste with ClipboardEvent
88
+
89
+ ```typescript
90
+ import { copyElement, pasteToElement } from "@simplysm/core-browser";
91
+
92
+ document.addEventListener("copy", (event) => copyElement(event));
93
+ document.addEventListener("paste", (event) => pasteToElement(event));
94
+ ```
95
+
96
+ ### Download a Blob
97
+
98
+ ```typescript
99
+ import { downloadBlob } from "@simplysm/core-browser";
100
+
101
+ const blob = new Blob(["hello"], { type: "text/plain" });
102
+ downloadBlob(blob, "hello.txt");
103
+ ```
104
+
105
+ ### Fetch binary data with progress
106
+
107
+ ```typescript
108
+ import { fetchUrlBytes } from "@simplysm/core-browser";
109
+
110
+ const data = await fetchUrlBytes("/api/file.bin", {
111
+ onProgress: ({ receivedLength, contentLength }) => {
112
+ console.log(`${receivedLength} / ${contentLength}`);
113
+ },
114
+ });
115
+ ```
116
+
117
+ ### Open a file dialog
118
+
119
+ ```typescript
120
+ import { openFileDialog } from "@simplysm/core-browser";
121
+
122
+ const files = await openFileDialog({ accept: ".csv", multiple: true });
123
+ if (files) {
124
+ for (const file of files) {
125
+ console.log(file.name);
126
+ }
127
+ }
128
+ ```
129
+
130
+ ### IndexedDB Store
131
+
132
+ ```typescript
133
+ import { IndexedDbStore } from "@simplysm/core-browser";
134
+
135
+ const store = new IndexedDbStore("myDb", 1, [{ name: "items", keyPath: "id" }]);
136
+ await store.put("items", { id: "1", value: "hello" });
137
+ const item = await store.get<{ id: string; value: string }>("items", "1");
138
+ store.close();
139
+ ```
140
+
141
+ ### Get element bounds
142
+
143
+ ```typescript
144
+ import { getBounds } from "@simplysm/core-browser";
145
+
146
+ const elements = document.querySelectorAll(".card");
147
+ const bounds = await getBounds([...elements]);
148
+ for (const b of bounds) {
149
+ console.log(`${b.target.tagName}: ${b.top}, ${b.left}, ${b.width}x${b.height}`);
150
+ }
151
+ ```
@@ -0,0 +1,16 @@
1
+ # Download
2
+
3
+ Utility for triggering file downloads in the browser.
4
+
5
+ ## `downloadBlob`
6
+
7
+ Download a `Blob` as a file by creating a temporary object URL and clicking a hidden anchor element. The object URL is revoked after 1 second.
8
+
9
+ ```typescript
10
+ function downloadBlob(blob: Blob, fileName: string): void
11
+ ```
12
+
13
+ | Parameter | Type | Description |
14
+ |-----------|------|-------------|
15
+ | `blob` | `Blob` | The Blob to download |
16
+ | `fileName` | `string` | File name for the download |
@@ -0,0 +1,158 @@
1
+ # Element Extensions
2
+
3
+ Side-effect import that extends the global `Element` prototype with DOM utility methods, plus standalone clipboard and bounds functions.
4
+
5
+ ## `ElementBounds`
6
+
7
+ Bounding rectangle information for an element, returned by `getBounds`.
8
+
9
+ ```typescript
10
+ interface ElementBounds {
11
+ target: Element;
12
+ top: number;
13
+ left: number;
14
+ width: number;
15
+ height: number;
16
+ }
17
+ ```
18
+
19
+ | Field | Type | Description |
20
+ |-------|------|-------------|
21
+ | `target` | `Element` | The measured element |
22
+ | `top` | `number` | Top position relative to viewport |
23
+ | `left` | `number` | Left position relative to viewport |
24
+ | `width` | `number` | Element width |
25
+ | `height` | `number` | Element height |
26
+
27
+ ## `Element.prototype.findAll`
28
+
29
+ Find all descendant elements matching a CSS selector.
30
+
31
+ ```typescript
32
+ findAll<TEl extends Element = Element>(selector: string): TEl[]
33
+ ```
34
+
35
+ | Parameter | Type | Description |
36
+ |-----------|------|-------------|
37
+ | `selector` | `string` | CSS selector. Returns empty array if empty string. |
38
+
39
+ **Returns:** `TEl[]` -- Array of matching elements.
40
+
41
+ ## `Element.prototype.findFirst`
42
+
43
+ Find the first descendant element matching a CSS selector.
44
+
45
+ ```typescript
46
+ findFirst<TEl extends Element = Element>(selector: string): TEl | undefined
47
+ ```
48
+
49
+ | Parameter | Type | Description |
50
+ |-----------|------|-------------|
51
+ | `selector` | `string` | CSS selector. Returns `undefined` if empty string. |
52
+
53
+ **Returns:** `TEl | undefined` -- First matching element or `undefined`.
54
+
55
+ ## `Element.prototype.prependChild`
56
+
57
+ Insert a child element as the first child.
58
+
59
+ ```typescript
60
+ prependChild<TEl extends Element>(child: TEl): TEl
61
+ ```
62
+
63
+ | Parameter | Type | Description |
64
+ |-----------|------|-------------|
65
+ | `child` | `TEl` | Element to insert |
66
+
67
+ **Returns:** `TEl` -- The inserted child element.
68
+
69
+ ## `Element.prototype.getParents`
70
+
71
+ Get all ancestor elements, ordered from nearest to farthest.
72
+
73
+ ```typescript
74
+ getParents(): Element[]
75
+ ```
76
+
77
+ **Returns:** `Element[]` -- Array of parent elements (nearest first).
78
+
79
+ ## `Element.prototype.findFocusableParent`
80
+
81
+ Find the nearest focusable ancestor element (uses `tabbable` library).
82
+
83
+ ```typescript
84
+ findFocusableParent(): HTMLElement | undefined
85
+ ```
86
+
87
+ **Returns:** `HTMLElement | undefined` -- First focusable parent or `undefined`.
88
+
89
+ ## `Element.prototype.findFirstFocusableChild`
90
+
91
+ Find the first focusable descendant element (uses `tabbable` library).
92
+
93
+ ```typescript
94
+ findFirstFocusableChild(): HTMLElement | undefined
95
+ ```
96
+
97
+ **Returns:** `HTMLElement | undefined` -- First focusable child or `undefined`.
98
+
99
+ ## `Element.prototype.isOffsetElement`
100
+
101
+ Check whether the element is an offset parent (`position: relative | absolute | fixed | sticky`).
102
+
103
+ ```typescript
104
+ isOffsetElement(): boolean
105
+ ```
106
+
107
+ **Returns:** `boolean` -- `true` if element has a positioning CSS property.
108
+
109
+ ## `Element.prototype.isVisible`
110
+
111
+ Check whether the element is visible on screen. Checks `getClientRects()`, `visibility`, and `opacity`.
112
+
113
+ ```typescript
114
+ isVisible(): boolean
115
+ ```
116
+
117
+ **Returns:** `boolean` -- `true` if the element is visible.
118
+
119
+ ## `copyElement`
120
+
121
+ Copy element content to the clipboard. Intended for use as a `copy` event handler. Finds the first `input` or `textarea` within the event target and copies its value.
122
+
123
+ ```typescript
124
+ function copyElement(event: ClipboardEvent): void
125
+ ```
126
+
127
+ | Parameter | Type | Description |
128
+ |-----------|------|-------------|
129
+ | `event` | `ClipboardEvent` | The copy event object |
130
+
131
+ ## `pasteToElement`
132
+
133
+ 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 entire value with the clipboard text.
134
+
135
+ ```typescript
136
+ function pasteToElement(event: ClipboardEvent): void
137
+ ```
138
+
139
+ | Parameter | Type | Description |
140
+ |-----------|------|-------------|
141
+ | `event` | `ClipboardEvent` | The paste event object |
142
+
143
+ ## `getBounds`
144
+
145
+ Get bounding rectangle information for multiple elements using `IntersectionObserver`. Results are returned in the same order as the input array. Duplicate elements are deduplicated.
146
+
147
+ ```typescript
148
+ async function getBounds(els: Element[], timeout?: number): Promise<ElementBounds[]>
149
+ ```
150
+
151
+ | Parameter | Type | Default | Description |
152
+ |-----------|------|---------|-------------|
153
+ | `els` | `Element[]` | | Target elements |
154
+ | `timeout` | `number` | `5000` | Timeout in milliseconds |
155
+
156
+ **Returns:** `Promise<ElementBounds[]>` -- Bounding info sorted by input order.
157
+
158
+ **Throws:** `TimeoutError` if the observer does not respond within the timeout.
package/docs/fetch.md ADDED
@@ -0,0 +1,39 @@
1
+ # Fetch
2
+
3
+ Utility for downloading binary data from a URL with optional progress tracking.
4
+
5
+ ## `DownloadProgress`
6
+
7
+ Progress information emitted during a fetch download.
8
+
9
+ ```typescript
10
+ interface DownloadProgress {
11
+ receivedLength: number;
12
+ contentLength: number;
13
+ }
14
+ ```
15
+
16
+ | Field | Type | Description |
17
+ |-------|------|-------------|
18
+ | `receivedLength` | `number` | Bytes received so far |
19
+ | `contentLength` | `number` | Total content length from the `Content-Length` header |
20
+
21
+ ## `fetchUrlBytes`
22
+
23
+ Download binary data from a URL. Supports progress callbacks via `ReadableStream` reader. When the `Content-Length` header is available, the result buffer is pre-allocated for efficiency. When unavailable (chunked encoding), chunks are collected and concatenated.
24
+
25
+ ```typescript
26
+ async function fetchUrlBytes(
27
+ url: string,
28
+ options?: { onProgress?: (progress: DownloadProgress) => void },
29
+ ): Promise<Uint8Array>
30
+ ```
31
+
32
+ | Parameter | Type | Description |
33
+ |-----------|------|-------------|
34
+ | `url` | `string` | URL to fetch |
35
+ | `options.onProgress` | `(progress: DownloadProgress) => void` | Optional progress callback |
36
+
37
+ **Returns:** `Promise<Uint8Array>` -- The downloaded binary data.
38
+
39
+ **Throws:** `Error` if the response is not OK or the body cannot be read.
@@ -0,0 +1,21 @@
1
+ # File Dialog
2
+
3
+ Utility for programmatically opening a native file picker dialog.
4
+
5
+ ## `openFileDialog`
6
+
7
+ Open a file selection dialog by creating and clicking a hidden `<input type="file">` element. Returns the selected files or `undefined` if the dialog is cancelled.
8
+
9
+ ```typescript
10
+ function openFileDialog(options?: {
11
+ accept?: string;
12
+ multiple?: boolean;
13
+ }): Promise<File[] | undefined>
14
+ ```
15
+
16
+ | Parameter | Type | Default | Description |
17
+ |-----------|------|---------|-------------|
18
+ | `options.accept` | `string` | `undefined` | File type filter (e.g., `".csv"`, `"image/*"`) |
19
+ | `options.multiple` | `boolean` | `false` | Allow selecting multiple files |
20
+
21
+ **Returns:** `Promise<File[] | undefined>` -- Selected files array, or `undefined` if cancelled or no files selected.
@@ -0,0 +1,50 @@
1
+ # HTML Element Extensions
2
+
3
+ Side-effect import that extends the global `HTMLElement` prototype with layout and scroll utility methods.
4
+
5
+ ## `HTMLElement.prototype.repaint`
6
+
7
+ Force a synchronous repaint by triggering a reflow (reads `offsetHeight`).
8
+
9
+ ```typescript
10
+ repaint(): void
11
+ ```
12
+
13
+ ## `HTMLElement.prototype.getRelativeOffset`
14
+
15
+ Calculate the element's position relative to a parent element. Returns document-based coordinates (including `window.scrollX/Y`) suitable for CSS `top`/`left` properties.
16
+
17
+ The calculation accounts for:
18
+ - Viewport position (`getBoundingClientRect`)
19
+ - Document scroll (`window.scrollX/Y`)
20
+ - Parent internal scroll (`parentEl.scrollTop/Left`)
21
+ - Intermediate element border widths
22
+ - CSS `transform`
23
+
24
+ ```typescript
25
+ getRelativeOffset(parent: HTMLElement | string): { top: number; left: number }
26
+ ```
27
+
28
+ | Parameter | Type | Description |
29
+ |-----------|------|-------------|
30
+ | `parent` | `HTMLElement \| string` | Parent element or CSS selector to match via `closest()` |
31
+
32
+ **Returns:** `{ top: number; left: number }` -- Coordinates usable for CSS `top`/`left`.
33
+
34
+ **Throws:** `ArgumentError` if the parent element cannot be found.
35
+
36
+ ## `HTMLElement.prototype.scrollIntoViewIfNeeded`
37
+
38
+ Scroll the container so that the target position is not obscured by fixed offset areas (e.g., sticky headers or fixed columns). Only handles cases where the target is above or to the left of the visible area; downward/rightward scrolling relies on the browser's default focus scroll behavior.
39
+
40
+ ```typescript
41
+ scrollIntoViewIfNeeded(
42
+ target: { top: number; left: number },
43
+ offset?: { top: number; left: number },
44
+ ): void
45
+ ```
46
+
47
+ | Parameter | Type | Default | Description |
48
+ |-----------|------|---------|-------------|
49
+ | `target` | `{ top: number; left: number }` | | Target position within the container (`offsetTop`, `offsetLeft`) |
50
+ | `offset` | `{ top: number; left: number }` | `{ top: 0, left: 0 }` | Size of the offset area that must not obscure the target (e.g., fixed header height) |
@@ -0,0 +1,103 @@
1
+ # IndexedDB Store
2
+
3
+ Generic IndexedDB wrapper providing typed CRUD operations and transaction management.
4
+
5
+ ## `StoreConfig`
6
+
7
+ Configuration for an IndexedDB object store, used when opening the database.
8
+
9
+ ```typescript
10
+ interface StoreConfig {
11
+ name: string;
12
+ keyPath: string;
13
+ }
14
+ ```
15
+
16
+ | Field | Type | Description |
17
+ |-------|------|-------------|
18
+ | `name` | `string` | Object store name |
19
+ | `keyPath` | `string` | Key path for the object store |
20
+
21
+ ## `IndexedDbStore`
22
+
23
+ A wrapper around the IndexedDB API with automatic database opening, version upgrade handling, and typed CRUD methods.
24
+
25
+ ```typescript
26
+ class IndexedDbStore {
27
+ constructor(dbName: string, dbVersion: number, storeConfigs: StoreConfig[]);
28
+ }
29
+ ```
30
+
31
+ | Constructor Parameter | Type | Description |
32
+ |----------------------|------|-------------|
33
+ | `dbName` | `string` | Database name |
34
+ | `dbVersion` | `number` | Database version (triggers `onupgradeneeded` when increased) |
35
+ | `storeConfigs` | `StoreConfig[]` | Object store configurations to create on upgrade |
36
+
37
+ ### Methods
38
+
39
+ #### `open`
40
+
41
+ Open the database (creates stores on version upgrade). Returns the existing connection if already open. Concurrent calls return the same pending promise.
42
+
43
+ ```typescript
44
+ async open(): Promise<IDBDatabase>
45
+ ```
46
+
47
+ #### `withStore`
48
+
49
+ Execute a function within a transaction on a specific store. Handles transaction commit/abort automatically.
50
+
51
+ ```typescript
52
+ async withStore<TResult>(
53
+ storeName: string,
54
+ mode: IDBTransactionMode,
55
+ fn: (store: IDBObjectStore) => Promise<TResult>,
56
+ ): Promise<TResult>
57
+ ```
58
+
59
+ | Parameter | Type | Description |
60
+ |-----------|------|-------------|
61
+ | `storeName` | `string` | Target object store name |
62
+ | `mode` | `IDBTransactionMode` | `"readonly"` or `"readwrite"` |
63
+ | `fn` | `(store: IDBObjectStore) => Promise<TResult>` | Function to execute within the transaction |
64
+
65
+ #### `get`
66
+
67
+ Get a single value by key.
68
+
69
+ ```typescript
70
+ async get<TValue>(storeName: string, key: IDBValidKey): Promise<TValue | undefined>
71
+ ```
72
+
73
+ #### `put`
74
+
75
+ Insert or update a value.
76
+
77
+ ```typescript
78
+ async put(storeName: string, value: unknown): Promise<void>
79
+ ```
80
+
81
+ #### `delete`
82
+
83
+ Delete a value by key.
84
+
85
+ ```typescript
86
+ async delete(storeName: string, key: IDBValidKey): Promise<void>
87
+ ```
88
+
89
+ #### `getAll`
90
+
91
+ Get all values from a store.
92
+
93
+ ```typescript
94
+ async getAll<TItem>(storeName: string): Promise<TItem[]>
95
+ ```
96
+
97
+ #### `close`
98
+
99
+ Close the database connection.
100
+
101
+ ```typescript
102
+ close(): void
103
+ ```
@@ -0,0 +1,107 @@
1
+ # IndexedDB Virtual FS
2
+
3
+ A virtual file system abstraction backed by IndexedDB, built on top of `IndexedDbStore`.
4
+
5
+ ## `VirtualFsEntry`
6
+
7
+ Represents a file or directory entry in the virtual file system.
8
+
9
+ ```typescript
10
+ interface VirtualFsEntry {
11
+ kind: "file" | "dir";
12
+ dataBase64?: string;
13
+ }
14
+ ```
15
+
16
+ | Field | Type | Description |
17
+ |-------|------|-------------|
18
+ | `kind` | `"file" \| "dir"` | Entry type |
19
+ | `dataBase64` | `string \| undefined` | Base64-encoded file data (only for files) |
20
+
21
+ ## `IndexedDbVirtualFs`
22
+
23
+ Virtual file system that stores entries in an `IndexedDbStore`. Supports hierarchical path-based operations including directory creation, prefix-based deletion, and child listing.
24
+
25
+ ```typescript
26
+ class IndexedDbVirtualFs {
27
+ constructor(db: IndexedDbStore, storeName: string, keyField: string);
28
+ }
29
+ ```
30
+
31
+ | Constructor Parameter | Type | Description |
32
+ |----------------------|------|-------------|
33
+ | `db` | `IndexedDbStore` | The IndexedDB store instance |
34
+ | `storeName` | `string` | Object store name to use |
35
+ | `keyField` | `string` | Field name used as the key in the store |
36
+
37
+ ### Methods
38
+
39
+ #### `getEntry`
40
+
41
+ Get a virtual FS entry by its full key.
42
+
43
+ ```typescript
44
+ async getEntry(fullKey: string): Promise<VirtualFsEntry | undefined>
45
+ ```
46
+
47
+ | Parameter | Type | Description |
48
+ |-----------|------|-------------|
49
+ | `fullKey` | `string` | Full key identifying the entry |
50
+
51
+ #### `putEntry`
52
+
53
+ Insert or update a virtual FS entry.
54
+
55
+ ```typescript
56
+ async putEntry(fullKey: string, kind: "file" | "dir", dataBase64?: string): Promise<void>
57
+ ```
58
+
59
+ | Parameter | Type | Description |
60
+ |-----------|------|-------------|
61
+ | `fullKey` | `string` | Full key for the entry |
62
+ | `kind` | `"file" \| "dir"` | Entry type |
63
+ | `dataBase64` | `string` | Optional base64-encoded data (for files) |
64
+
65
+ #### `deleteByPrefix`
66
+
67
+ Delete all entries whose key matches the given prefix or starts with `prefix + "/"`.
68
+
69
+ ```typescript
70
+ async deleteByPrefix(keyPrefix: string): Promise<boolean>
71
+ ```
72
+
73
+ | Parameter | Type | Description |
74
+ |-----------|------|-------------|
75
+ | `keyPrefix` | `string` | Key prefix to match |
76
+
77
+ **Returns:** `Promise<boolean>` -- `true` if at least one entry was deleted.
78
+
79
+ #### `listChildren`
80
+
81
+ List immediate children under a given prefix. Returns each child's name and whether it is a directory.
82
+
83
+ ```typescript
84
+ async listChildren(prefix: string): Promise<{ name: string; isDirectory: boolean }[]>
85
+ ```
86
+
87
+ | Parameter | Type | Description |
88
+ |-----------|------|-------------|
89
+ | `prefix` | `string` | Parent path prefix (e.g., `"/root/dir/"`) |
90
+
91
+ **Returns:** `Promise<{ name: string; isDirectory: boolean }[]>` -- Array of child entries.
92
+
93
+ #### `ensureDir`
94
+
95
+ Ensure all directories along a path exist, creating missing ones.
96
+
97
+ ```typescript
98
+ async ensureDir(
99
+ fullKeyBuilder: (path: string) => string,
100
+ dirPath: string,
101
+ ): Promise<void>
102
+ ```
103
+
104
+ | Parameter | Type | Description |
105
+ |-----------|------|-------------|
106
+ | `fullKeyBuilder` | `(path: string) => string` | Function to build the full key from a path segment |
107
+ | `dirPath` | `string` | Directory path to ensure (e.g., `"/a/b/c"`) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/core-browser",
3
- "version": "14.0.1",
3
+ "version": "14.0.5",
4
4
  "description": "심플리즘 패키지 - 코어 (browser)",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -14,7 +14,8 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "files": [
16
16
  "dist",
17
- "src"
17
+ "src",
18
+ "docs"
18
19
  ],
19
20
  "sideEffects": [
20
21
  "./src/extensions/element-ext.ts",
@@ -24,6 +25,6 @@
24
25
  ],
25
26
  "dependencies": {
26
27
  "tabbable": "^6.4.0",
27
- "@simplysm/core-common": "14.0.1"
28
+ "@simplysm/core-common": "14.0.5"
28
29
  }
29
30
  }