@bquery/bquery 1.3.0 → 1.4.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/README.md +527 -501
- package/dist/{batch-4LAvfLE7.js → batch-x7b2eZST.js} +2 -2
- package/dist/{batch-4LAvfLE7.js.map → batch-x7b2eZST.js.map} +1 -1
- package/dist/component.es.mjs +1 -1
- package/dist/core/collection.d.ts +19 -3
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +23 -4
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/utils/function.d.ts +21 -4
- package/dist/core/utils/function.d.ts.map +1 -1
- package/dist/{core-COenAZjD.js → core-BhpuvPhy.js} +62 -37
- package/dist/core-BhpuvPhy.js.map +1 -0
- package/dist/core.es.mjs +174 -131
- package/dist/core.es.mjs.map +1 -1
- package/dist/full.es.mjs +7 -7
- package/dist/full.iife.js +2 -2
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +2 -2
- package/dist/full.umd.js.map +1 -1
- package/dist/index.es.mjs +7 -7
- package/dist/motion.es.mjs.map +1 -1
- package/dist/{persisted-Dz_ryNuC.js → persisted-DHoi3uEs.js} +4 -4
- package/dist/{persisted-Dz_ryNuC.js.map → persisted-DHoi3uEs.js.map} +1 -1
- package/dist/platform/storage.d.ts.map +1 -1
- package/dist/platform.es.mjs +12 -7
- package/dist/platform.es.mjs.map +1 -1
- package/dist/reactive/core.d.ts +12 -0
- package/dist/reactive/core.d.ts.map +1 -1
- package/dist/reactive/effect.d.ts.map +1 -1
- package/dist/reactive/internals.d.ts +6 -0
- package/dist/reactive/internals.d.ts.map +1 -1
- package/dist/reactive.es.mjs +6 -6
- package/dist/router.es.mjs +1 -1
- package/dist/{sanitize-1FBEPAFH.js → sanitize-Cxvxa-DX.js} +50 -39
- package/dist/sanitize-Cxvxa-DX.js.map +1 -0
- package/dist/security/sanitize-core.d.ts.map +1 -1
- package/dist/security.es.mjs +2 -2
- package/dist/store.es.mjs +2 -2
- package/dist/type-guards-BdKlYYlS.js +32 -0
- package/dist/type-guards-BdKlYYlS.js.map +1 -0
- package/dist/untrack-DNnnqdlR.js +6 -0
- package/dist/{untrack-BuEQKH7_.js.map → untrack-DNnnqdlR.js.map} +1 -1
- package/dist/view/evaluate.d.ts.map +1 -1
- package/dist/view.es.mjs +157 -151
- package/dist/view.es.mjs.map +1 -1
- package/dist/{watch-CXyaBC_9.js → watch-DXXv3iAI.js} +3 -3
- package/dist/{watch-CXyaBC_9.js.map → watch-DXXv3iAI.js.map} +1 -1
- package/package.json +132 -132
- package/src/core/collection.ts +628 -588
- package/src/core/element.ts +774 -746
- package/src/core/index.ts +48 -47
- package/src/core/utils/function.ts +151 -110
- package/src/motion/animate.ts +113 -113
- package/src/motion/flip.ts +176 -176
- package/src/motion/scroll.ts +57 -57
- package/src/motion/spring.ts +150 -150
- package/src/motion/timeline.ts +246 -246
- package/src/motion/transition.ts +51 -51
- package/src/platform/storage.ts +215 -208
- package/src/reactive/core.ts +114 -93
- package/src/reactive/effect.ts +54 -43
- package/src/reactive/internals.ts +122 -105
- package/src/security/sanitize-core.ts +364 -343
- package/src/view/evaluate.ts +290 -274
- package/dist/core-COenAZjD.js.map +0 -1
- package/dist/sanitize-1FBEPAFH.js.map +0 -1
- package/dist/type-guards-DRma3-Kc.js +0 -16
- package/dist/type-guards-DRma3-Kc.js.map +0 -1
- package/dist/untrack-BuEQKH7_.js +0 -6
package/README.md
CHANGED
|
@@ -1,501 +1,527 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="assets/bquerry-logo.svg" alt="bQuery.js Logo" width="120" />
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<h1 align="center">bQuery.js</h1>
|
|
6
|
-
|
|
7
|
-
<p align="center">
|
|
8
|
-
|
|
9
|
-
[](https://github.com/bQuery/bQuery)
|
|
10
|
-
[](https://github.com/bQuery/bQuery/stargazers)
|
|
11
|
-
[](https://github.com/bQuery/bQuery/issues)
|
|
12
|
-
[](https://github.com/bQuery/bQuery/blob/main/LICENSE.md)
|
|
13
|
-
[](https://www.npmjs.com/package/@bquery/bquery)
|
|
14
|
-
[](https://bundlephobia.com/package/@bquery/bquery)
|
|
15
|
-
[](https://unpkg.com/@bquery/bquery)
|
|
16
|
-
[](https://www.codefactor.io/repository/github/bquery/bquery)
|
|
17
|
-
[](https://www.jsdelivr.com/package/npm/@bquery/bquery)
|
|
18
|
-
|
|
19
|
-
**The jQuery for the modern Web Platform.**
|
|
20
|
-
|
|
21
|
-
bQuery.js is a slim, TypeScript-first library that combines jQuery's direct DOM workflow with modern features like reactivity, Web Components, and motion utilities — without a mandatory build step.
|
|
22
|
-
|
|
23
|
-
## Highlights
|
|
24
|
-
|
|
25
|
-
- **Zero‑build capable**: runs directly in the browser; build tools are optional.
|
|
26
|
-
- **Security‑focused**: DOM writes are sanitized by default; Trusted Types supported.
|
|
27
|
-
- **Modular**: the core stays small; extra modules are opt‑in.
|
|
28
|
-
- **TypeScript‑first**: clear types and strong IDE support.
|
|
29
|
-
- **Tree-shakeable**: import only what you need.
|
|
30
|
-
|
|
31
|
-
## Installation
|
|
32
|
-
|
|
33
|
-
### Via npm/bun/pnpm
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# npm
|
|
37
|
-
npm install @bquery/bquery
|
|
38
|
-
|
|
39
|
-
# bun
|
|
40
|
-
bun add @bquery/bquery
|
|
41
|
-
|
|
42
|
-
# pnpm
|
|
43
|
-
pnpm add @bquery/bquery
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Via CDN (Zero-build)
|
|
47
|
-
|
|
48
|
-
#### ES Modules (recommended)
|
|
49
|
-
|
|
50
|
-
```html
|
|
51
|
-
<script type="module">
|
|
52
|
-
import { $, signal } from 'https://unpkg.com/@bquery/bquery@1/dist/full.es.mjs';
|
|
53
|
-
|
|
54
|
-
const count = signal(0);
|
|
55
|
-
$('#counter').text(`Count: ${count.value}`);
|
|
56
|
-
</script>
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
#### UMD (global variable)
|
|
60
|
-
|
|
61
|
-
```html
|
|
62
|
-
<script src="https://unpkg.com/@bquery/bquery@1/dist/full.umd.js"></script>
|
|
63
|
-
<script>
|
|
64
|
-
const { $, signal } = bQuery;
|
|
65
|
-
const count = signal(0);
|
|
66
|
-
</script>
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
#### IIFE (self-executing)
|
|
70
|
-
|
|
71
|
-
```html
|
|
72
|
-
<script src="https://unpkg.com/@bquery/bquery@1/dist/full.iife.js"></script>
|
|
73
|
-
<script>
|
|
74
|
-
const { $, $$ } = bQuery;
|
|
75
|
-
$$('.items').addClass('loaded');
|
|
76
|
-
</script>
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Import Strategies
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
// Full bundle (all modules)
|
|
83
|
-
import { $, signal, component } from '@bquery/bquery';
|
|
84
|
-
|
|
85
|
-
// Core only
|
|
86
|
-
import { $, $$ } from '@bquery/bquery/core';
|
|
87
|
-
|
|
88
|
-
// Core utilities (named exports, tree-shakeable)
|
|
89
|
-
import { debounce, merge, uid, once, utils } from '@bquery/bquery/core';
|
|
90
|
-
|
|
91
|
-
// À la carte (individual modules)
|
|
92
|
-
import { signal, computed, effect, linkedSignal, persistedSignal } from '@bquery/bquery/reactive';
|
|
93
|
-
import { component, defineComponent, html } from '@bquery/bquery/component';
|
|
94
|
-
import { transition, spring, animate, timeline } from '@bquery/bquery/motion';
|
|
95
|
-
import { sanitize } from '@bquery/bquery/security';
|
|
96
|
-
import { storage, cache } from '@bquery/bquery/platform';
|
|
97
|
-
import { createRouter, navigate } from '@bquery/bquery/router';
|
|
98
|
-
import { createStore, defineStore } from '@bquery/bquery/store';
|
|
99
|
-
import { mount, createTemplate } from '@bquery/bquery/view';
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Modules at a glance
|
|
103
|
-
|
|
104
|
-
| Module | Description | Size (gzip) |
|
|
105
|
-
| ------------- | -------------------------------------------------- | ----------- |
|
|
106
|
-
| **Core** | Selectors, DOM manipulation, events, utilities | ~11.3 KB |
|
|
107
|
-
| **Reactive** | `signal`, `computed`, `effect`, `batch` | ~0.3 KB |
|
|
108
|
-
| **Component** | Lightweight Web Components with props | ~1.9 KB |
|
|
109
|
-
| **Motion** | View transitions, FLIP, timelines, scroll, springs | ~4.0 KB |
|
|
110
|
-
| **Security** | HTML sanitizing, Trusted Types, CSP | ~0.7 KB |
|
|
111
|
-
| **Platform** | Storage, cache, notifications, buckets | ~2.2 KB |
|
|
112
|
-
| **Router** | SPA routing, navigation guards, history API | ~2.2 KB |
|
|
113
|
-
| **Store** | Signal-based state management, persistence | ~0.3 KB |
|
|
114
|
-
| **View** | Declarative DOM bindings, directives | ~4.3 KB |
|
|
115
|
-
|
|
116
|
-
## Quick examples
|
|
117
|
-
|
|
118
|
-
### Core – DOM & events
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
import { $, $$ } from '@bquery/bquery/core';
|
|
122
|
-
|
|
123
|
-
// jQuery-style selectors
|
|
124
|
-
$('#save').on('click', (event) => {
|
|
125
|
-
console.log('Saved', event.type);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Event delegation for dynamic content
|
|
129
|
-
$('#list').delegate('click', '.item', (event, target) => {
|
|
130
|
-
console.log('Item clicked', target.textContent);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Method chaining
|
|
134
|
-
$('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready');
|
|
135
|
-
|
|
136
|
-
//
|
|
137
|
-
$('#
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
//
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
//
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
-
|
|
442
|
-
-
|
|
443
|
-
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/bquerry-logo.svg" alt="bQuery.js Logo" width="120" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">bQuery.js</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
|
|
9
|
+
[](https://github.com/bQuery/bQuery)
|
|
10
|
+
[](https://github.com/bQuery/bQuery/stargazers)
|
|
11
|
+
[](https://github.com/bQuery/bQuery/issues)
|
|
12
|
+
[](https://github.com/bQuery/bQuery/blob/main/LICENSE.md)
|
|
13
|
+
[](https://www.npmjs.com/package/@bquery/bquery)
|
|
14
|
+
[](https://bundlephobia.com/package/@bquery/bquery)
|
|
15
|
+
[](https://unpkg.com/@bquery/bquery)
|
|
16
|
+
[](https://www.codefactor.io/repository/github/bquery/bquery)
|
|
17
|
+
[](https://www.jsdelivr.com/package/npm/@bquery/bquery)
|
|
18
|
+
|
|
19
|
+
**The jQuery for the modern Web Platform.**
|
|
20
|
+
|
|
21
|
+
bQuery.js is a slim, TypeScript-first library that combines jQuery's direct DOM workflow with modern features like reactivity, Web Components, and motion utilities — without a mandatory build step.
|
|
22
|
+
|
|
23
|
+
## Highlights
|
|
24
|
+
|
|
25
|
+
- **Zero‑build capable**: runs directly in the browser; build tools are optional.
|
|
26
|
+
- **Security‑focused**: DOM writes are sanitized by default; Trusted Types supported.
|
|
27
|
+
- **Modular**: the core stays small; extra modules are opt‑in.
|
|
28
|
+
- **TypeScript‑first**: clear types and strong IDE support.
|
|
29
|
+
- **Tree-shakeable**: import only what you need.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
### Via npm/bun/pnpm
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# npm
|
|
37
|
+
npm install @bquery/bquery
|
|
38
|
+
|
|
39
|
+
# bun
|
|
40
|
+
bun add @bquery/bquery
|
|
41
|
+
|
|
42
|
+
# pnpm
|
|
43
|
+
pnpm add @bquery/bquery
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Via CDN (Zero-build)
|
|
47
|
+
|
|
48
|
+
#### ES Modules (recommended)
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<script type="module">
|
|
52
|
+
import { $, signal } from 'https://unpkg.com/@bquery/bquery@1/dist/full.es.mjs';
|
|
53
|
+
|
|
54
|
+
const count = signal(0);
|
|
55
|
+
$('#counter').text(`Count: ${count.value}`);
|
|
56
|
+
</script>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### UMD (global variable)
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<script src="https://unpkg.com/@bquery/bquery@1/dist/full.umd.js"></script>
|
|
63
|
+
<script>
|
|
64
|
+
const { $, signal } = bQuery;
|
|
65
|
+
const count = signal(0);
|
|
66
|
+
</script>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### IIFE (self-executing)
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<script src="https://unpkg.com/@bquery/bquery@1/dist/full.iife.js"></script>
|
|
73
|
+
<script>
|
|
74
|
+
const { $, $$ } = bQuery;
|
|
75
|
+
$$('.items').addClass('loaded');
|
|
76
|
+
</script>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Import Strategies
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// Full bundle (all modules)
|
|
83
|
+
import { $, signal, component } from '@bquery/bquery';
|
|
84
|
+
|
|
85
|
+
// Core only
|
|
86
|
+
import { $, $$ } from '@bquery/bquery/core';
|
|
87
|
+
|
|
88
|
+
// Core utilities (named exports, tree-shakeable)
|
|
89
|
+
import { debounce, merge, uid, once, utils } from '@bquery/bquery/core';
|
|
90
|
+
|
|
91
|
+
// À la carte (individual modules)
|
|
92
|
+
import { signal, computed, effect, linkedSignal, persistedSignal } from '@bquery/bquery/reactive';
|
|
93
|
+
import { component, defineComponent, html } from '@bquery/bquery/component';
|
|
94
|
+
import { transition, spring, animate, timeline } from '@bquery/bquery/motion';
|
|
95
|
+
import { sanitize } from '@bquery/bquery/security';
|
|
96
|
+
import { storage, cache } from '@bquery/bquery/platform';
|
|
97
|
+
import { createRouter, navigate } from '@bquery/bquery/router';
|
|
98
|
+
import { createStore, defineStore } from '@bquery/bquery/store';
|
|
99
|
+
import { mount, createTemplate } from '@bquery/bquery/view';
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Modules at a glance
|
|
103
|
+
|
|
104
|
+
| Module | Description | Size (gzip) |
|
|
105
|
+
| ------------- | -------------------------------------------------- | ----------- |
|
|
106
|
+
| **Core** | Selectors, DOM manipulation, events, utilities | ~11.3 KB |
|
|
107
|
+
| **Reactive** | `signal`, `computed`, `effect`, `batch` | ~0.3 KB |
|
|
108
|
+
| **Component** | Lightweight Web Components with props | ~1.9 KB |
|
|
109
|
+
| **Motion** | View transitions, FLIP, timelines, scroll, springs | ~4.0 KB |
|
|
110
|
+
| **Security** | HTML sanitizing, Trusted Types, CSP | ~0.7 KB |
|
|
111
|
+
| **Platform** | Storage, cache, notifications, buckets | ~2.2 KB |
|
|
112
|
+
| **Router** | SPA routing, navigation guards, history API | ~2.2 KB |
|
|
113
|
+
| **Store** | Signal-based state management, persistence | ~0.3 KB |
|
|
114
|
+
| **View** | Declarative DOM bindings, directives | ~4.3 KB |
|
|
115
|
+
|
|
116
|
+
## Quick examples
|
|
117
|
+
|
|
118
|
+
### Core – DOM & events
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { $, $$ } from '@bquery/bquery/core';
|
|
122
|
+
|
|
123
|
+
// jQuery-style selectors
|
|
124
|
+
$('#save').on('click', (event) => {
|
|
125
|
+
console.log('Saved', event.type);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Event delegation for dynamic content
|
|
129
|
+
$('#list').delegate('click', '.item', (event, target) => {
|
|
130
|
+
console.log('Item clicked', target.textContent);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Method chaining
|
|
134
|
+
$('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready');
|
|
135
|
+
|
|
136
|
+
// CSS getter (computed style)
|
|
137
|
+
const color = $('#box').css('color'); // Returns computed style value
|
|
138
|
+
|
|
139
|
+
// Selector matching
|
|
140
|
+
if ($('#el').is('.active')) {
|
|
141
|
+
console.log('Element is active');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// DOM manipulation
|
|
145
|
+
$('#content').wrap('div');
|
|
146
|
+
$('#content').unwrap(); // Remove parent wrapper
|
|
147
|
+
|
|
148
|
+
// Attribute helpers
|
|
149
|
+
$('#dialog').toggleAttr('open');
|
|
150
|
+
|
|
151
|
+
// Smooth scrolling
|
|
152
|
+
$('#section').scrollTo({ behavior: 'smooth' });
|
|
153
|
+
|
|
154
|
+
// Form serialization
|
|
155
|
+
const formData = $('form').serialize(); // Returns object
|
|
156
|
+
const queryString = $('form').serializeString(); // Returns URL-encoded string
|
|
157
|
+
|
|
158
|
+
// Collections
|
|
159
|
+
$$('.items').addClass('highlight');
|
|
160
|
+
$$('.items').append('<li class="item">New</li>');
|
|
161
|
+
$$('.container').find('.item').addClass('found'); // Find descendants across collection
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Reactive – signals
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import {
|
|
168
|
+
signal,
|
|
169
|
+
computed,
|
|
170
|
+
effect,
|
|
171
|
+
batch,
|
|
172
|
+
watch,
|
|
173
|
+
readonly,
|
|
174
|
+
linkedSignal,
|
|
175
|
+
} from '@bquery/bquery/reactive';
|
|
176
|
+
|
|
177
|
+
const count = signal(0);
|
|
178
|
+
const doubled = computed(() => count.value * 2);
|
|
179
|
+
|
|
180
|
+
effect(() => {
|
|
181
|
+
console.log('Count changed', count.value);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Watch with cleanup support
|
|
185
|
+
const stop = watch(count, (newVal, oldVal) => {
|
|
186
|
+
console.log(`Changed from ${oldVal} to ${newVal}`);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Read-only signal wrapper
|
|
190
|
+
const readOnlyCount = readonly(count);
|
|
191
|
+
|
|
192
|
+
// Batch updates for performance
|
|
193
|
+
batch(() => {
|
|
194
|
+
count.value++;
|
|
195
|
+
count.value++;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Dispose signal (remove all subscribers)
|
|
199
|
+
count.dispose();
|
|
200
|
+
|
|
201
|
+
// Writable computed (linked signal)
|
|
202
|
+
const first = signal('Ada');
|
|
203
|
+
const last = signal('Lovelace');
|
|
204
|
+
const fullName = linkedSignal(
|
|
205
|
+
() => `${first.value} ${last.value}`,
|
|
206
|
+
(next) => {
|
|
207
|
+
const [nextFirst, nextLast] = next.split(' ');
|
|
208
|
+
first.value = nextFirst ?? '';
|
|
209
|
+
last.value = nextLast ?? '';
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
fullName.value = 'Grace Hopper';
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Components – Web Components
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { component, defineComponent, html } from '@bquery/bquery/component';
|
|
220
|
+
|
|
221
|
+
component('user-card', {
|
|
222
|
+
props: {
|
|
223
|
+
username: { type: String, required: true },
|
|
224
|
+
age: { type: Number, validator: (v) => v >= 0 && v <= 150 },
|
|
225
|
+
},
|
|
226
|
+
// Extended lifecycle hooks
|
|
227
|
+
beforeMount() {
|
|
228
|
+
console.log('About to mount');
|
|
229
|
+
},
|
|
230
|
+
connected() {
|
|
231
|
+
console.log('Mounted');
|
|
232
|
+
},
|
|
233
|
+
beforeUpdate(props) {
|
|
234
|
+
// Return false to prevent update
|
|
235
|
+
return props.username !== '';
|
|
236
|
+
},
|
|
237
|
+
onError(error) {
|
|
238
|
+
console.error('Component error:', error);
|
|
239
|
+
},
|
|
240
|
+
render({ props }) {
|
|
241
|
+
return html`<div>Hello ${props.username}</div>`;
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Optional: create the class without auto-registration
|
|
246
|
+
const UserCard = defineComponent('user-card', {
|
|
247
|
+
props: { username: { type: String, required: true } },
|
|
248
|
+
render: ({ props }) => html`<div>Hello ${props.username}</div>`,
|
|
249
|
+
});
|
|
250
|
+
customElements.define('user-card', UserCard);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Motion – animations
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
import { animate, keyframePresets, spring, transition } from '@bquery/bquery/motion';
|
|
257
|
+
|
|
258
|
+
// View transitions (with fallback)
|
|
259
|
+
await transition(() => {
|
|
260
|
+
$('#content').text('Updated');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Web Animations helper
|
|
264
|
+
await animate(card, {
|
|
265
|
+
keyframes: keyframePresets.pop(),
|
|
266
|
+
options: { duration: 240, easing: 'ease-out' },
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Spring physics
|
|
270
|
+
const x = spring(0, { stiffness: 120, damping: 14 });
|
|
271
|
+
x.onChange((value) => {
|
|
272
|
+
element.style.transform = `translateX(${value}px)`;
|
|
273
|
+
});
|
|
274
|
+
await x.to(100);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Security – sanitizing
|
|
278
|
+
|
|
279
|
+
Internally modularized (sanitize core, Trusted Types, CSP helpers) — the public API remains unchanged. For legacy deep imports, `@bquery/bquery/security/sanitize` also re-exports `generateNonce()` and `isTrustedTypesSupported()`.
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import { sanitize, escapeHtml } from '@bquery/bquery/security';
|
|
283
|
+
|
|
284
|
+
// Sanitize HTML (removes dangerous elements like script, iframe, svg)
|
|
285
|
+
const safeHtml = sanitize(userInput);
|
|
286
|
+
|
|
287
|
+
// DOM clobbering protection (reserved IDs are blocked)
|
|
288
|
+
const safe = sanitize('<form id="cookie">...</form>'); // id stripped
|
|
289
|
+
|
|
290
|
+
// Unicode bypass protection in URLs
|
|
291
|
+
const urlSafe = sanitize('<a href="java\u200Bscript:alert(1)">click</a>');
|
|
292
|
+
|
|
293
|
+
// Automatic link security (adds rel="noopener noreferrer" to external/target="_blank" links)
|
|
294
|
+
const secureLink = sanitize('<a href="https://external.com" target="_blank">Link</a>');
|
|
295
|
+
|
|
296
|
+
// srcset validation (per-URL; entire attribute removed if any entry is unsafe)
|
|
297
|
+
const safeSrcset = sanitize('<img srcset="safe.jpg 1x, javascript:alert(1) 2x">'); // <img>
|
|
298
|
+
|
|
299
|
+
// Form action validation (blocks javascript: protocol)
|
|
300
|
+
const safeForm = sanitize('<form action="javascript:alert(1)">...</form>');
|
|
301
|
+
|
|
302
|
+
// Escape for text display
|
|
303
|
+
const escaped = escapeHtml('<script>alert(1)</script>');
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Platform – storage & APIs
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
import { storage, notifications } from '@bquery/bquery/platform';
|
|
310
|
+
|
|
311
|
+
// Unified storage API
|
|
312
|
+
const local = storage.local();
|
|
313
|
+
await local.set('theme', 'dark');
|
|
314
|
+
const theme = await local.get<string>('theme');
|
|
315
|
+
|
|
316
|
+
// Notifications
|
|
317
|
+
const permission = await notifications.requestPermission();
|
|
318
|
+
if (permission === 'granted') {
|
|
319
|
+
notifications.send('Build complete', {
|
|
320
|
+
body: 'Your docs are ready.',
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Router – SPA navigation
|
|
326
|
+
|
|
327
|
+
Internally, the router has been split into focused submodules (matching, navigation, state, links, utilities) with no public API changes.
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
import { createRouter, navigate, currentRoute } from '@bquery/bquery/router';
|
|
331
|
+
|
|
332
|
+
// Create router with routes
|
|
333
|
+
const router = createRouter({
|
|
334
|
+
routes: [
|
|
335
|
+
{ path: '/', name: 'home', component: HomePage },
|
|
336
|
+
{ path: '/user/:id', name: 'user', component: UserPage },
|
|
337
|
+
{ path: '*', component: NotFound },
|
|
338
|
+
],
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Navigation guards
|
|
342
|
+
router.beforeEach(async (to, from) => {
|
|
343
|
+
if (to.path === '/admin' && !isAuthenticated()) {
|
|
344
|
+
await navigate('/login'); // Redirect
|
|
345
|
+
return false; // Cancel original navigation
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Navigate programmatically
|
|
350
|
+
await navigate('/user/42');
|
|
351
|
+
await navigate('/search?q=bquery'); // Query params in path
|
|
352
|
+
await navigate('/login', { replace: true }); // Replace history entry
|
|
353
|
+
|
|
354
|
+
// Reactive current route
|
|
355
|
+
effect(() => {
|
|
356
|
+
console.log('Current path:', currentRoute.value.path);
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Store – state management
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
import { createStore, createPersistedStore } from '@bquery/bquery/store';
|
|
364
|
+
|
|
365
|
+
// Create a store (returns the store instance directly)
|
|
366
|
+
const counterStore = createStore({
|
|
367
|
+
id: 'counter',
|
|
368
|
+
state: () => ({ count: 0, name: 'Counter' }),
|
|
369
|
+
getters: {
|
|
370
|
+
doubled: (state) => state.count * 2,
|
|
371
|
+
},
|
|
372
|
+
actions: {
|
|
373
|
+
increment() {
|
|
374
|
+
this.count++;
|
|
375
|
+
},
|
|
376
|
+
async fetchCount() {
|
|
377
|
+
this.count = await api.getCount();
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Use the store
|
|
383
|
+
counterStore.increment();
|
|
384
|
+
console.log(counterStore.doubled); // Reactive getter
|
|
385
|
+
|
|
386
|
+
// Persisted store (localStorage)
|
|
387
|
+
const settingsStore = createPersistedStore({
|
|
388
|
+
id: 'settings',
|
|
389
|
+
state: () => ({ theme: 'dark', language: 'en' }),
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Factory-style store definition (Pinia-style)
|
|
393
|
+
import { defineStore, mapGetters, watchStore } from '@bquery/bquery/store';
|
|
394
|
+
|
|
395
|
+
const useCounter = defineStore('counter', {
|
|
396
|
+
state: () => ({ count: 0 }),
|
|
397
|
+
getters: {
|
|
398
|
+
doubled: (state) => state.count * 2,
|
|
399
|
+
},
|
|
400
|
+
actions: {
|
|
401
|
+
increment() {
|
|
402
|
+
this.count++;
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
const counter = useCounter();
|
|
408
|
+
const getters = mapGetters(counter, ['doubled']);
|
|
409
|
+
|
|
410
|
+
watchStore(
|
|
411
|
+
counter,
|
|
412
|
+
(state) => state.count,
|
|
413
|
+
(value) => {
|
|
414
|
+
console.log('Count changed:', value, getters.doubled);
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### View – declarative bindings
|
|
420
|
+
|
|
421
|
+
Internally modularized into focused submodules; the public API remains unchanged.
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
import { mount, createTemplate } from '@bquery/bquery/view';
|
|
425
|
+
import { signal } from '@bquery/bquery/reactive';
|
|
426
|
+
|
|
427
|
+
// Mount reactive bindings to DOM
|
|
428
|
+
const count = signal(0);
|
|
429
|
+
const items = signal(['Apple', 'Banana', 'Cherry']);
|
|
430
|
+
|
|
431
|
+
const app = mount('#app', {
|
|
432
|
+
count,
|
|
433
|
+
items,
|
|
434
|
+
increment: () => count.value++,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// In HTML:
|
|
438
|
+
// <p bq-text="count"></p>
|
|
439
|
+
// <button bq-on:click="increment">+1</button>
|
|
440
|
+
// <ul><li bq-for="item in items" bq-text="item"></li></ul>
|
|
441
|
+
// <input bq-model="count" type="number" />
|
|
442
|
+
// <div bq-if="count > 5">Count is high!</div>
|
|
443
|
+
// <div bq-class="{ active: count > 0 }"></div>
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Browser Support
|
|
447
|
+
|
|
448
|
+
| Browser | Version | Support |
|
|
449
|
+
| ------- | ------- | ------- |
|
|
450
|
+
| Chrome | 90+ | ✅ Full |
|
|
451
|
+
| Firefox | 90+ | ✅ Full |
|
|
452
|
+
| Safari | 15+ | ✅ Full |
|
|
453
|
+
| Edge | 90+ | ✅ Full |
|
|
454
|
+
|
|
455
|
+
> **No IE support** by design.
|
|
456
|
+
|
|
457
|
+
## Documentation
|
|
458
|
+
|
|
459
|
+
- **Getting Started**: [docs/guide/getting-started.md](docs/guide/getting-started.md)
|
|
460
|
+
- **Core API**: [docs/guide/api-core.md](docs/guide/api-core.md)
|
|
461
|
+
- **Agents**: [docs/guide/agents.md](docs/guide/agents.md)
|
|
462
|
+
- **Components**: [docs/guide/components.md](docs/guide/components.md)
|
|
463
|
+
- **Reactivity**: [docs/guide/reactive.md](docs/guide/reactive.md)
|
|
464
|
+
- **Motion**: [docs/guide/motion.md](docs/guide/motion.md)
|
|
465
|
+
- **Security**: [docs/guide/security.md](docs/guide/security.md)
|
|
466
|
+
- **Platform**: [docs/guide/platform.md](docs/guide/platform.md)
|
|
467
|
+
- **Router**: [docs/guide/router.md](docs/guide/router.md)
|
|
468
|
+
- **Store**: [docs/guide/store.md](docs/guide/store.md)
|
|
469
|
+
- **View**: [docs/guide/view.md](docs/guide/view.md)
|
|
470
|
+
|
|
471
|
+
## Local Development
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
# Install dependencies
|
|
475
|
+
bun install
|
|
476
|
+
|
|
477
|
+
# Start VitePress docs
|
|
478
|
+
bun run dev
|
|
479
|
+
|
|
480
|
+
# Run Vite playground
|
|
481
|
+
bun run playground
|
|
482
|
+
|
|
483
|
+
# Run tests
|
|
484
|
+
bun test
|
|
485
|
+
|
|
486
|
+
# Build library
|
|
487
|
+
bun run build
|
|
488
|
+
|
|
489
|
+
# Generate API documentation
|
|
490
|
+
bun run docs:api
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## Project Structure
|
|
494
|
+
|
|
495
|
+
```text
|
|
496
|
+
bQuery.js
|
|
497
|
+
├── src/
|
|
498
|
+
│ ├── core/ # Selectors, DOM ops, events, utils
|
|
499
|
+
│ ├── reactive/ # Signals, computed, effects
|
|
500
|
+
│ ├── component/ # Web Components helper
|
|
501
|
+
│ ├── motion/ # View transitions, FLIP, springs
|
|
502
|
+
│ ├── security/ # Sanitizer, CSP, Trusted Types
|
|
503
|
+
│ ├── platform/ # Storage, cache, notifications
|
|
504
|
+
│ ├── router/ # SPA routing, navigation guards
|
|
505
|
+
│ ├── store/ # State management, persistence
|
|
506
|
+
│ └── view/ # Declarative DOM bindings
|
|
507
|
+
├── docs/ # VitePress documentation
|
|
508
|
+
├── playground/ # Vite demo app
|
|
509
|
+
├── tests/ # bun:test suites
|
|
510
|
+
└── dist/ # Built files (ESM, UMD, IIFE)
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
## Contributing
|
|
514
|
+
|
|
515
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
516
|
+
|
|
517
|
+
## AI Agent Support
|
|
518
|
+
|
|
519
|
+
This project provides dedicated context files for AI coding agents:
|
|
520
|
+
|
|
521
|
+
- **[AGENT.md](AGENT.md)** — Architecture, module API reference, coding conventions, common tasks
|
|
522
|
+
- **[llms.txt](llms.txt)** — Compact LLM-optimized project summary
|
|
523
|
+
- **[.github/copilot-instructions.md](.github/copilot-instructions.md)** — GitHub Copilot context
|
|
524
|
+
|
|
525
|
+
## License
|
|
526
|
+
|
|
527
|
+
MIT – See [LICENSE.md](LICENSE.md) for details.
|