id-dom 0.0.4 → 0.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 CHANGED
@@ -1,296 +1,295 @@
1
- # id-dom
2
-
3
- [![npm version](https://img.shields.io/npm/v/id-dom.svg)](https://www.npmjs.com/package/id-dom)
4
- [![npm downloads](https://img.shields.io/npm/dm/id-dom.svg)](https://www.npmjs.com/package/id-dom)
5
- [![GitHub stars](https://img.shields.io/github/stars/iWhatty/id-dom.svg?style=social)](https://github.com/iWhatty/id-dom)
6
- [![License](https://img.shields.io/github/license/iWhatty/id-dom.svg)](https://github.com/iWhatty/id-dom/blob/main/LICENSE)
7
-
8
- **Deterministic DOM element getters by ID — typed, tiny, modern.**
9
-
10
- `id-dom` is a small utility for grabbing DOM references safely **by `id`**, with predictable behavior:
11
-
12
- * **Typed getters** like `button('saveBtn')`, `input('nameInput')`, `svg('icon')`
13
- * **Strict or optional** mode (`throw` vs `null`)
14
- * **Short optional alias** via `.opt`
15
- * **Scoped lookups** for `document`, `ShadowRoot`, `DocumentFragment`, or an `Element`
16
- * **Centralized error handling** with `onError` and optional `warn`
17
- * **Zero deps**
18
-
19
- This is deliberately **not** a selector framework. It is a tiny, ID-first primitive for safe DOM wiring.
20
-
21
- ---
22
-
23
- ## Install
24
-
25
- ```bash
26
- npm install id-dom
27
- ```
28
-
29
- ---
30
-
31
- ## Quick Start
32
-
33
- ```js
34
- import dom from 'id-dom'
35
-
36
- const saveBtn = dom.button('saveBtn')
37
- saveBtn.addEventListener('click', save)
38
- ```
39
-
40
- Optional access never throws for missing or wrong-type elements:
41
-
42
- ```js
43
- const debug = dom.div.optional('debugPanel')
44
- debug?.append('hello')
45
-
46
- const maybeCanvas = dom.canvas.opt('game')
47
- ```
48
-
49
- ---
50
-
51
- ## Why ID-first?
52
-
53
- Using `getElementById` is:
54
-
55
- * fast
56
- * unambiguous
57
- * easy to reason about
58
-
59
- And with typed getters, you immediately know whether you got a `HTMLButtonElement`, `HTMLInputElement`, `SVGSVGElement`, and so on.
60
-
61
- When scoped roots do not support `getElementById`, `id-dom` falls back to `querySelector(#id)` and safely escapes edge-case IDs.
62
-
63
- ---
64
-
65
- ## API
66
-
67
- ### Default export: `dom`
68
-
69
- The default export is a scoped instance using `document` (when available) with **strict** behavior:
70
-
71
- * missing element → **throws**
72
- * wrong type or wrong tag **throws**
73
- * invalid input → **throws**
74
-
75
- ```js
76
- import dom from 'id-dom'
77
-
78
- const name = dom.input('nameInput')
79
- const submit = dom.button('submitBtn')
80
- ```
81
-
82
- ---
83
-
84
- ### `createDom(root, config?)`
85
-
86
- Create a scoped instance that searches within a specific root:
87
-
88
- * `document` → uses `getElementById`
89
- * `ShadowRoot`, `DocumentFragment`, or `Element` → uses `querySelector(#id)` fallback
90
-
91
- ```js
92
- import { createDom } from 'id-dom'
93
-
94
- const d = createDom(document, { mode: 'null', warn: true })
95
- const sidebar = d.div('sidebar')
96
- ```
97
-
98
- #### Config
99
-
100
- ```ts
101
- type DomMode = 'throw' | 'null'
102
-
103
- {
104
- mode?: DomMode
105
- warn?: boolean
106
- onError?: (err: Error, ctx: any) => void
107
- }
108
- ```
109
-
110
- ---
111
-
112
- ### `byId(id, Type, config?)`
113
-
114
- Generic typed lookup:
115
-
116
- ```js
117
- import { byId } from 'id-dom'
118
-
119
- const btn = byId('saveBtn', HTMLButtonElement)
120
- ```
121
-
122
- Optional variants:
123
-
124
- ```js
125
- const maybeBtn = byId.optional('saveBtn', HTMLButtonElement)
126
- const maybeBtn2 = byId.opt('saveBtn', HTMLButtonElement)
127
- ```
128
-
129
- #### Behavior
130
-
131
- * valid match → returns the element
132
- * missing element → throws or returns `null`
133
- * wrong type → throws or returns `null`
134
- * invalid `id` → throws or returns `null`
135
- * invalid `Type` → throws or returns `null`
136
-
137
- ---
138
-
139
- ### `tag(id, tagName, config?)`
140
-
141
- Tag-based validation when constructor checks are not the right fit:
142
-
143
- ```js
144
- import { tag } from 'id-dom'
145
-
146
- const main = tag('appMain', 'main')
147
- const icon = tag('icon', 'svg', { root: container })
148
- ```
149
-
150
- Optional variants:
151
-
152
- ```js
153
- const maybeMain = tag.optional('appMain', 'main')
154
- const maybeMain2 = tag.opt('appMain', 'main')
155
- ```
156
-
157
- #### Behavior
158
-
159
- * valid tag match → returns the element
160
- * missing element → throws or returns `null`
161
- * wrong tag → throws or returns `null`
162
- * invalid `id` → throws or returns `null`
163
- * invalid `tagName` → throws or returns `null`
164
-
165
- ---
166
-
167
- ## Built-in Getters
168
-
169
- ### Typed getters
170
-
171
- Available on `dom` and on any `createDom()` instance:
172
-
173
- * `el(id)` → `HTMLElement`
174
- * `input(id)` → `HTMLInputElement`
175
- * `button(id)` → `HTMLButtonElement`
176
- * `textarea(id)` → `HTMLTextAreaElement`
177
- * `select(id)` → `HTMLSelectElement`
178
- * `form(id)` → `HTMLFormElement`
179
- * `div(id)` → `HTMLDivElement`
180
- * `span(id)` `HTMLSpanElement`
181
- * `label(id)` → `HTMLLabelElement`
182
- * `canvas(id)` → `HTMLCanvasElement`
183
- * `template(id)` → `HTMLTemplateElement`
184
- * `svg(id)` → `SVGSVGElement`
185
- * `body(id)` → `HTMLBodyElement`
186
-
187
- Each getter also has:
188
-
189
- ```js
190
- dom.canvas.optional('game')
191
- dom.canvas.opt('game')
192
- ```
193
-
194
- ### Common tag helpers
195
-
196
- * `main(id)` → validates `<main>`
197
- * `section(id)` → validates `<section>`
198
- * `small(id)` → validates `<small>`
199
-
200
- Each also supports `.optional` and `.opt`.
201
-
202
- ---
203
-
204
- ## Error Handling
205
-
206
- ### Throwing mode
207
-
208
- ```js
209
- import dom from 'id-dom'
210
-
211
- dom.button('missing') // throws
212
- ```
213
-
214
- ### Null-returning mode
215
-
216
- ```js
217
- import { createDom } from 'id-dom'
218
-
219
- const d = createDom(document, { mode: 'null' })
220
- d.button('missing') // null
221
- ```
222
-
223
- ### Central reporting
224
-
225
- ```js
226
- const d = createDom(document, {
227
- mode: 'null',
228
- onError: (err, ctx) => {
229
- // sendToSentry({ err, ctx })
230
- },
231
- })
232
- ```
233
-
234
- Enable console warnings too:
235
-
236
- ```js
237
- createDom(document, { mode: 'null', warn: true })
238
- ```
239
-
240
- ---
241
-
242
- ## Scoped Roots
243
-
244
- ### Shadow DOM
245
-
246
- ```js
247
- import { createDom } from 'id-dom'
248
-
249
- const host = document.querySelector('#widget')
250
- const shadow = host.attachShadow({ mode: 'open' })
251
- shadow.innerHTML = `<button id="shadowBtn">Click</button>`
252
-
253
- const d = createDom(shadow)
254
- const btn = d.button('shadowBtn')
255
- ```
256
-
257
- ### Element root
258
-
259
- ```js
260
- const container = document.querySelector('#settings-panel')
261
- const d = createDom(container)
262
- const input = d.input('emailInput')
263
- ```
264
-
265
- ### SVG in scoped roots
266
-
267
- ```js
268
- const container = document.querySelector('#icons')
269
- const d = createDom(container)
270
- const icon = d.svg('logoMark')
271
- ```
272
-
273
- ---
274
-
275
- ## Notes
276
-
277
- * `el(id)` is specifically for `HTMLElement`, not every possible DOM `Element`.
278
- * `body(id)` looks up a `<body>` **by ID**. This library stays ID-first on purpose.
279
- * `tag()` can validate non-HTML tags too, such as `svg`, when used against supported scoped roots.
280
-
281
- ---
282
-
283
- ## Browser Support
284
-
285
- Modern browsers supporting:
286
-
287
- * `getElementById`
288
- * `querySelector`
289
-
290
- `CSS.escape` is used when available. A safe internal fallback is included for environments such as some jsdom builds where it may be missing.
291
-
292
- ---
293
-
294
- ## License
295
-
296
- See `LICENSE`.
1
+ # id-dom
2
+
3
+ [![npm](https://img.shields.io/npm/v/id-dom)](https://www.npmjs.com/package/id-dom)
4
+ [![downloads](https://img.shields.io/npm/dm/id-dom)](https://www.npmjs.com/package/id-dom)
5
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/id-dom)](https://bundlephobia.com/package/id-dom)
6
+ [![license](https://img.shields.io/npm/l/id-dom)](https://github.com/iWhatty/id-dom/blob/main/LICENSE)
7
+ [![stars](https://img.shields.io/github/stars/iWhatty/id-dom?style=social)](https://github.com/iWhatty/id-dom)
8
+
9
+ Deterministic DOM element getters by ID. Typed, tiny, modern. A small utility for grabbing DOM references safely by `id`, with predictable behavior.
10
+
11
+ ## Features
12
+
13
+ - Typed getters like `button('saveBtn')`, `input('nameInput')`, `svg('icon')`
14
+ - Strict or optional mode (`throw` vs `null`)
15
+ - Short optional alias via `.opt`
16
+ - Scoped lookups for `document`, `ShadowRoot`, `DocumentFragment`, or an `Element`
17
+ - Centralized error handling with `onError` and optional `warn`
18
+ - Zero dependencies
19
+
20
+ This is deliberately **not** a selector framework. It is a tiny, ID-first primitive for safe DOM wiring.
21
+
22
+ ---
23
+
24
+ ## Install
25
+
26
+ ```sh
27
+ pnpm add id-dom
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Quick start
33
+
34
+ Two import styles, same root, same behavior. Pick by preference:
35
+
36
+ ```js
37
+ // Default-object style. Every typed helper lives under one namespace.
38
+ import dom from 'id-dom'
39
+
40
+ const saveBtn = dom.button('saveBtn')
41
+ saveBtn.addEventListener('click', save)
42
+ ```
43
+
44
+ ```js
45
+ // Named-import style, added in 0.0.5. Makes the dependency surface explicit
46
+ // in the import declaration. Tree-shaken identically by modern bundlers
47
+ // (esbuild, vite, rollup, webpack 5) since the package ships
48
+ // `sideEffects: false`.
49
+ import { button, input, div } from 'id-dom'
50
+
51
+ const saveBtn = button('saveBtn')
52
+ const email = input('email')
53
+ const panel = div('mainPanel')
54
+ ```
55
+
56
+ Optional access never throws for missing or wrong-type elements:
57
+
58
+ ```js
59
+ const debug = dom.div.optional('debugPanel') // default-object style
60
+ debug?.append('hello')
61
+
62
+ import { canvas } from 'id-dom'
63
+ const maybeCanvas = canvas.opt('game') // named style
64
+ ```
65
+
66
+ ---
67
+
68
+ ## API
69
+
70
+ ### Default export: `dom`
71
+
72
+ The default export is a scoped instance using `document` (when available) with **strict** behavior:
73
+
74
+ - missing element → **throws**
75
+ - wrong type or wrong tag → **throws**
76
+ - invalid input → **throws**
77
+
78
+ ```js
79
+ import dom from 'id-dom'
80
+
81
+ const name = dom.input('nameInput')
82
+ const submit = dom.button('submitBtn')
83
+ ```
84
+
85
+ ### `createDom(root, config?)`
86
+
87
+ Create a scoped instance that searches within a specific root:
88
+
89
+ - `document` → uses `getElementById`
90
+ - `ShadowRoot`, `DocumentFragment`, or `Element` → uses `querySelector(#id)` fallback
91
+
92
+ ```js
93
+ import { createDom } from 'id-dom'
94
+
95
+ const d = createDom(document, { mode: 'null', warn: true })
96
+ const sidebar = d.div('sidebar')
97
+ ```
98
+
99
+ **Config:**
100
+
101
+ ```ts
102
+ type DomMode = 'throw' | 'null'
103
+
104
+ {
105
+ mode?: DomMode
106
+ warn?: boolean
107
+ onError?: (err: Error, ctx: any) => void
108
+ }
109
+ ```
110
+
111
+ ### `byId(id, Type, config?)`
112
+
113
+ Generic typed lookup:
114
+
115
+ ```js
116
+ import { byId } from 'id-dom'
117
+
118
+ const btn = byId('saveBtn', HTMLButtonElement)
119
+ ```
120
+
121
+ Optional variants:
122
+
123
+ ```js
124
+ const maybeBtn = byId.optional('saveBtn', HTMLButtonElement)
125
+ const maybeBtn2 = byId.opt('saveBtn', HTMLButtonElement)
126
+ ```
127
+
128
+ Behavior:
129
+
130
+ - valid match → returns the element
131
+ - missing elementthrows or returns `null`
132
+ - wrong type → throws or returns `null`
133
+ - invalid `id` → throws or returns `null`
134
+ - invalid `Type` → throws or returns `null`
135
+
136
+ ### `tag(id, tagName, config?)`
137
+
138
+ Tag-based validation when constructor checks are not the right fit:
139
+
140
+ ```js
141
+ import { tag } from 'id-dom'
142
+
143
+ const main = tag('appMain', 'main')
144
+ const icon = tag('icon', 'svg', { root: container })
145
+ ```
146
+
147
+ Optional variants:
148
+
149
+ ```js
150
+ const maybeMain = tag.optional('appMain', 'main')
151
+ const maybeMain2 = tag.opt('appMain', 'main')
152
+ ```
153
+
154
+ Behavior:
155
+
156
+ - valid tag match → returns the element
157
+ - missing element → throws or returns `null`
158
+ - wrong tag → throws or returns `null`
159
+ - invalid `id`throws or returns `null`
160
+ - invalid `tagName` → throws or returns `null`
161
+
162
+ ### Built-in getters
163
+
164
+ Typed getters available on `dom` and on any `createDom()` instance:
165
+
166
+ - `el(id)` → `HTMLElement`
167
+ - `input(id)` → `HTMLInputElement`
168
+ - `button(id)` → `HTMLButtonElement`
169
+ - `textarea(id)` → `HTMLTextAreaElement`
170
+ - `select(id)` → `HTMLSelectElement`
171
+ - `form(id)` `HTMLFormElement`
172
+ - `div(id)` → `HTMLDivElement`
173
+ - `span(id)` → `HTMLSpanElement`
174
+ - `label(id)` → `HTMLLabelElement`
175
+ - `canvas(id)` → `HTMLCanvasElement`
176
+ - `template(id)` → `HTMLTemplateElement`
177
+ - `svg(id)` → `SVGSVGElement`
178
+ - `body(id)` → `HTMLBodyElement`
179
+
180
+ Each getter also has `.optional` and `.opt` variants:
181
+
182
+ ```js
183
+ dom.canvas.optional('game')
184
+ dom.canvas.opt('game')
185
+ ```
186
+
187
+ Common tag helpers:
188
+
189
+ - `main(id)` → validates `<main>`
190
+ - `section(id)` → validates `<section>`
191
+ - `small(id)` → validates `<small>`
192
+
193
+ Each also supports `.optional` and `.opt`.
194
+
195
+ ### Error handling
196
+
197
+ **Throwing mode:**
198
+
199
+ ```js
200
+ import dom from 'id-dom'
201
+
202
+ dom.button('missing') // throws
203
+ ```
204
+
205
+ **Null-returning mode:**
206
+
207
+ ```js
208
+ import { createDom } from 'id-dom'
209
+
210
+ const d = createDom(document, { mode: 'null' })
211
+ d.button('missing') // null
212
+ ```
213
+
214
+ **Central reporting:**
215
+
216
+ ```js
217
+ const d = createDom(document, {
218
+ mode: 'null',
219
+ onError: (err, ctx) => {
220
+ // sendToSentry({ err, ctx })
221
+ },
222
+ })
223
+ ```
224
+
225
+ Enable console warnings too:
226
+
227
+ ```js
228
+ createDom(document, { mode: 'null', warn: true })
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Notes
234
+
235
+ ### Why id-first?
236
+
237
+ Using `getElementById` is fast, unambiguous, and easy to reason about. With typed getters, you immediately know whether you got a `HTMLButtonElement`, `HTMLInputElement`, `SVGSVGElement`, and so on.
238
+
239
+ When scoped roots do not support `getElementById`, id-dom falls back to `querySelector(#id)` and safely escapes edge-case IDs.
240
+
241
+ ### Bundle-size note
242
+
243
+ The shared lookup machinery (validation, CSS-escape fallback, error policy, root resolution) is the bulk of the package, roughly 1.9 KB gzipped in a modern bundler. Importing 4 helpers vs 1 vs the full default object lands in the same ballpark. The named-import style is recommended for readability and explicit-surface clarity, not for size.
244
+
245
+ ### Scoped roots
246
+
247
+ **Shadow DOM:**
248
+
249
+ ```js
250
+ import { createDom } from 'id-dom'
251
+
252
+ const host = document.querySelector('#widget')
253
+ const shadow = host.attachShadow({ mode: 'open' })
254
+ shadow.innerHTML = `<button id="shadowBtn">Click</button>`
255
+
256
+ const d = createDom(shadow)
257
+ const btn = d.button('shadowBtn')
258
+ ```
259
+
260
+ **Element root:**
261
+
262
+ ```js
263
+ const container = document.querySelector('#settings-panel')
264
+ const d = createDom(container)
265
+ const input = d.input('emailInput')
266
+ ```
267
+
268
+ **SVG in scoped roots:**
269
+
270
+ ```js
271
+ const container = document.querySelector('#icons')
272
+ const d = createDom(container)
273
+ const icon = d.svg('logoMark')
274
+ ```
275
+
276
+ ### Misc
277
+
278
+ - `el(id)` is specifically for `HTMLElement`, not every possible DOM `Element`.
279
+ - `body(id)` looks up a `<body>` **by ID**. This library stays ID-first on purpose.
280
+ - `tag()` can validate non-HTML tags too, such as `svg`, when used against supported scoped roots.
281
+
282
+ ### Browser support
283
+
284
+ Modern browsers supporting:
285
+
286
+ - `getElementById`
287
+ - `querySelector`
288
+
289
+ `CSS.escape` is used when available. A safe internal fallback is included for environments such as some jsdom builds where it may be missing.
290
+
291
+ ---
292
+
293
+ ## License
294
+
295
+ Licensed under AGPL-3.0 with WATT3D Additional Terms. See [LICENSE](./LICENSE) and [ADDITIONAL_TERMS.md](./ADDITIONAL_TERMS.md). Commercial AI/model-training use requires compliance with those terms or a separate WATT3D license. © WATT3D.