@bquery/bquery 1.4.0 → 1.5.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 +139 -120
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/index.d.ts +2 -0
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/library.d.ts +34 -0
- package/dist/component/library.d.ts.map +1 -0
- package/dist/component/types.d.ts +10 -6
- package/dist/component/types.d.ts.map +1 -1
- package/dist/component-CY5MVoYN.js +531 -0
- package/dist/component-CY5MVoYN.js.map +1 -0
- package/dist/component.es.mjs +6 -184
- package/dist/config-DRmZZno3.js +40 -0
- package/dist/config-DRmZZno3.js.map +1 -0
- package/dist/core-CK2Mfpf4.js +648 -0
- package/dist/core-CK2Mfpf4.js.map +1 -0
- package/dist/core-DPdbItcq.js +112 -0
- package/dist/core-DPdbItcq.js.map +1 -0
- package/dist/core.es.mjs +45 -1261
- package/dist/full.d.ts +6 -6
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +98 -92
- package/dist/full.iife.js +173 -3
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +173 -3
- package/dist/full.umd.js.map +1 -1
- package/dist/index.es.mjs +143 -139
- package/dist/motion/transition.d.ts +1 -1
- package/dist/motion/transition.d.ts.map +1 -1
- package/dist/motion/types.d.ts +11 -1
- package/dist/motion/types.d.ts.map +1 -1
- package/dist/motion-C5DRdPnO.js +415 -0
- package/dist/motion-C5DRdPnO.js.map +1 -0
- package/dist/motion.es.mjs +25 -361
- package/dist/object-qGpWr6-J.js +38 -0
- package/dist/object-qGpWr6-J.js.map +1 -0
- package/dist/platform/announcer.d.ts +59 -0
- package/dist/platform/announcer.d.ts.map +1 -0
- package/dist/platform/config.d.ts +92 -0
- package/dist/platform/config.d.ts.map +1 -0
- package/dist/platform/cookies.d.ts +45 -0
- package/dist/platform/cookies.d.ts.map +1 -0
- package/dist/platform/index.d.ts +8 -0
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/meta.d.ts +62 -0
- package/dist/platform/meta.d.ts.map +1 -0
- package/dist/platform-B7JhGBc7.js +361 -0
- package/dist/platform-B7JhGBc7.js.map +1 -0
- package/dist/platform.es.mjs +11 -248
- package/dist/reactive/async-data.d.ts +114 -0
- package/dist/reactive/async-data.d.ts.map +1 -0
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/signal.d.ts +2 -0
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive-BDya-ia8.js +253 -0
- package/dist/reactive-BDya-ia8.js.map +1 -0
- package/dist/reactive.es.mjs +18 -34
- package/dist/router-CijiICxt.js +188 -0
- package/dist/router-CijiICxt.js.map +1 -0
- package/dist/router.es.mjs +11 -200
- package/dist/sanitize-jyJ2ryE2.js +302 -0
- package/dist/sanitize-jyJ2ryE2.js.map +1 -0
- package/dist/security/constants.d.ts.map +1 -1
- package/dist/security.es.mjs +10 -56
- package/dist/store-CPK9E62U.js +262 -0
- package/dist/store-CPK9E62U.js.map +1 -0
- package/dist/store.es.mjs +12 -25
- package/dist/view-Cdi0g-qo.js +396 -0
- package/dist/view-Cdi0g-qo.js.map +1 -0
- package/dist/view.es.mjs +10 -430
- package/package.json +15 -11
- package/src/component/component.ts +319 -289
- package/src/component/index.ts +42 -40
- package/src/component/library.ts +504 -0
- package/src/component/types.ts +91 -85
- package/src/core/collection.ts +628 -628
- package/src/core/element.ts +774 -774
- package/src/core/index.ts +48 -48
- package/src/core/utils/function.ts +151 -151
- package/src/full.ts +223 -187
- 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 +53 -7
- package/src/motion/types.ts +208 -198
- package/src/platform/announcer.ts +208 -0
- package/src/platform/config.ts +163 -0
- package/src/platform/cookies.ts +165 -0
- package/src/platform/index.ts +39 -18
- package/src/platform/meta.ts +168 -0
- package/src/platform/storage.ts +215 -215
- package/src/reactive/async-data.ts +486 -0
- package/src/reactive/core.ts +114 -114
- package/src/reactive/effect.ts +54 -54
- package/src/reactive/index.ts +37 -23
- package/src/reactive/internals.ts +122 -122
- package/src/reactive/signal.ts +29 -20
- package/src/security/constants.ts +211 -209
- package/src/security/sanitize-core.ts +364 -364
- package/src/view/evaluate.ts +290 -290
- package/dist/batch-x7b2eZST.js +0 -13
- package/dist/batch-x7b2eZST.js.map +0 -1
- package/dist/component.es.mjs.map +0 -1
- package/dist/core-BhpuvPhy.js +0 -170
- package/dist/core-BhpuvPhy.js.map +0 -1
- package/dist/core.es.mjs.map +0 -1
- package/dist/full.es.mjs.map +0 -1
- package/dist/index.es.mjs.map +0 -1
- package/dist/motion.es.mjs.map +0 -1
- package/dist/persisted-DHoi3uEs.js +0 -278
- package/dist/persisted-DHoi3uEs.js.map +0 -1
- package/dist/platform.es.mjs.map +0 -1
- package/dist/reactive.es.mjs.map +0 -1
- package/dist/router.es.mjs.map +0 -1
- package/dist/sanitize-Cxvxa-DX.js +0 -283
- package/dist/sanitize-Cxvxa-DX.js.map +0 -1
- package/dist/security.es.mjs.map +0 -1
- package/dist/store.es.mjs.map +0 -1
- package/dist/type-guards-BdKlYYlS.js +0 -32
- package/dist/type-guards-BdKlYYlS.js.map +0 -1
- package/dist/untrack-DNnnqdlR.js +0 -6
- package/dist/untrack-DNnnqdlR.js.map +0 -1
- package/dist/view.es.mjs.map +0 -1
- package/dist/watch-DXXv3iAI.js +0 -58
- package/dist/watch-DXXv3iAI.js.map +0 -1
package/README.md
CHANGED
|
@@ -16,17 +16,21 @@
|
|
|
16
16
|
[](https://www.codefactor.io/repository/github/bquery/bquery)
|
|
17
17
|
[](https://www.jsdelivr.com/package/npm/@bquery/bquery)
|
|
18
18
|
|
|
19
|
+
</p>
|
|
20
|
+
|
|
19
21
|
**The jQuery for the modern Web Platform.**
|
|
20
22
|
|
|
21
|
-
bQuery.js is a slim, TypeScript-first library that combines jQuery's direct DOM workflow with modern features like reactivity, Web Components,
|
|
23
|
+
bQuery.js is a slim, TypeScript-first library that combines jQuery's direct DOM workflow with modern features like reactivity, async data composables, Web Components, motion utilities, routing, stores, and declarative views — without a mandatory build step.
|
|
22
24
|
|
|
23
25
|
## Highlights
|
|
24
26
|
|
|
25
|
-
- **Zero
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
27
|
+
- **Zero-build capable**: runs directly in the browser; build tools are optional.
|
|
28
|
+
- **Async data built-in**: fetch and async state composables integrate directly with signals.
|
|
29
|
+
- **Security-focused**: DOM writes are sanitized by default; Trusted Types supported.
|
|
30
|
+
- **Modular**: the core stays small; extra modules are opt-in.
|
|
31
|
+
- **TypeScript-first**: clear types and strong IDE support.
|
|
29
32
|
- **Tree-shakeable**: import only what you need.
|
|
33
|
+
- **Storybook-ready**: default components can be previewed and developed in Storybook.
|
|
30
34
|
|
|
31
35
|
## Installation
|
|
32
36
|
|
|
@@ -76,11 +80,17 @@ pnpm add @bquery/bquery
|
|
|
76
80
|
</script>
|
|
77
81
|
```
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
## Import Strategies
|
|
80
84
|
|
|
81
85
|
```ts
|
|
82
86
|
// Full bundle (all modules)
|
|
83
|
-
import {
|
|
87
|
+
import {
|
|
88
|
+
$,
|
|
89
|
+
signal,
|
|
90
|
+
component,
|
|
91
|
+
registerDefaultComponents,
|
|
92
|
+
defineBqueryConfig,
|
|
93
|
+
} from '@bquery/bquery';
|
|
84
94
|
|
|
85
95
|
// Core only
|
|
86
96
|
import { $, $$ } from '@bquery/bquery/core';
|
|
@@ -88,12 +98,36 @@ import { $, $$ } from '@bquery/bquery/core';
|
|
|
88
98
|
// Core utilities (named exports, tree-shakeable)
|
|
89
99
|
import { debounce, merge, uid, once, utils } from '@bquery/bquery/core';
|
|
90
100
|
|
|
91
|
-
//
|
|
92
|
-
import {
|
|
93
|
-
|
|
101
|
+
// Reactive only
|
|
102
|
+
import {
|
|
103
|
+
signal,
|
|
104
|
+
computed,
|
|
105
|
+
effect,
|
|
106
|
+
linkedSignal,
|
|
107
|
+
persistedSignal,
|
|
108
|
+
useAsyncData,
|
|
109
|
+
useFetch,
|
|
110
|
+
createUseFetch,
|
|
111
|
+
} from '@bquery/bquery/reactive';
|
|
112
|
+
|
|
113
|
+
// Components only
|
|
114
|
+
import {
|
|
115
|
+
component,
|
|
116
|
+
defineComponent,
|
|
117
|
+
html,
|
|
118
|
+
registerDefaultComponents,
|
|
119
|
+
} from '@bquery/bquery/component';
|
|
120
|
+
|
|
121
|
+
// Motion only
|
|
94
122
|
import { transition, spring, animate, timeline } from '@bquery/bquery/motion';
|
|
123
|
+
|
|
124
|
+
// Security only
|
|
95
125
|
import { sanitize } from '@bquery/bquery/security';
|
|
96
|
-
|
|
126
|
+
|
|
127
|
+
// Platform only
|
|
128
|
+
import { storage, cache, useCookie, definePageMeta, useAnnouncer } from '@bquery/bquery/platform';
|
|
129
|
+
|
|
130
|
+
// Router, Store, View
|
|
97
131
|
import { createRouter, navigate } from '@bquery/bquery/router';
|
|
98
132
|
import { createStore, defineStore } from '@bquery/bquery/store';
|
|
99
133
|
import { mount, createTemplate } from '@bquery/bquery/view';
|
|
@@ -104,11 +138,11 @@ import { mount, createTemplate } from '@bquery/bquery/view';
|
|
|
104
138
|
| Module | Description | Size (gzip) |
|
|
105
139
|
| ------------- | -------------------------------------------------- | ----------- |
|
|
106
140
|
| **Core** | Selectors, DOM manipulation, events, utilities | ~11.3 KB |
|
|
107
|
-
| **Reactive** | `signal`, `computed`, `effect`,
|
|
108
|
-
| **Component** | Lightweight Web Components with props
|
|
141
|
+
| **Reactive** | `signal`, `computed`, `effect`, async data/fetch | ~0.3 KB |
|
|
142
|
+
| **Component** | Lightweight Web Components with props + defaults | ~1.9 KB |
|
|
109
143
|
| **Motion** | View transitions, FLIP, timelines, scroll, springs | ~4.0 KB |
|
|
110
144
|
| **Security** | HTML sanitizing, Trusted Types, CSP | ~0.7 KB |
|
|
111
|
-
| **Platform** | Storage, cache,
|
|
145
|
+
| **Platform** | Storage, cache, cookies, meta, announcers, config | ~2.2 KB |
|
|
112
146
|
| **Router** | SPA routing, navigation guards, history API | ~2.2 KB |
|
|
113
147
|
| **Store** | Signal-based state management, persistence | ~0.3 KB |
|
|
114
148
|
| **View** | Declarative DOM bindings, directives | ~4.3 KB |
|
|
@@ -120,45 +154,23 @@ import { mount, createTemplate } from '@bquery/bquery/view';
|
|
|
120
154
|
```ts
|
|
121
155
|
import { $, $$ } from '@bquery/bquery/core';
|
|
122
156
|
|
|
123
|
-
// jQuery-style selectors
|
|
124
157
|
$('#save').on('click', (event) => {
|
|
125
158
|
console.log('Saved', event.type);
|
|
126
159
|
});
|
|
127
160
|
|
|
128
|
-
// Event delegation for dynamic content
|
|
129
161
|
$('#list').delegate('click', '.item', (event, target) => {
|
|
130
162
|
console.log('Item clicked', target.textContent);
|
|
131
163
|
});
|
|
132
164
|
|
|
133
|
-
// Method chaining
|
|
134
165
|
$('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready');
|
|
135
166
|
|
|
136
|
-
|
|
137
|
-
const color = $('#box').css('color'); // Returns computed style value
|
|
167
|
+
const color = $('#box').css('color');
|
|
138
168
|
|
|
139
|
-
// Selector matching
|
|
140
169
|
if ($('#el').is('.active')) {
|
|
141
170
|
console.log('Element is active');
|
|
142
171
|
}
|
|
143
172
|
|
|
144
|
-
|
|
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
|
|
173
|
+
$$('.container').find('.item').addClass('found');
|
|
162
174
|
```
|
|
163
175
|
|
|
164
176
|
### Reactive – signals
|
|
@@ -181,24 +193,19 @@ effect(() => {
|
|
|
181
193
|
console.log('Count changed', count.value);
|
|
182
194
|
});
|
|
183
195
|
|
|
184
|
-
|
|
185
|
-
const stop = watch(count, (newVal, oldVal) => {
|
|
196
|
+
watch(count, (newVal, oldVal) => {
|
|
186
197
|
console.log(`Changed from ${oldVal} to ${newVal}`);
|
|
187
198
|
});
|
|
188
199
|
|
|
189
|
-
// Read-only signal wrapper
|
|
190
200
|
const readOnlyCount = readonly(count);
|
|
191
201
|
|
|
192
|
-
// Batch updates for performance
|
|
193
202
|
batch(() => {
|
|
194
203
|
count.value++;
|
|
195
204
|
count.value++;
|
|
196
205
|
});
|
|
197
206
|
|
|
198
|
-
// Dispose signal (remove all subscribers)
|
|
199
207
|
count.dispose();
|
|
200
208
|
|
|
201
|
-
// Writable computed (linked signal)
|
|
202
209
|
const first = signal('Ada');
|
|
203
210
|
const last = signal('Lovelace');
|
|
204
211
|
const fullName = linkedSignal(
|
|
@@ -213,17 +220,44 @@ const fullName = linkedSignal(
|
|
|
213
220
|
fullName.value = 'Grace Hopper';
|
|
214
221
|
```
|
|
215
222
|
|
|
223
|
+
### Reactive – async data & fetch
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { signal, useFetch, createUseFetch } from '@bquery/bquery/reactive';
|
|
227
|
+
|
|
228
|
+
const userId = signal(1);
|
|
229
|
+
|
|
230
|
+
const user = useFetch<{ id: number; name: string }>(() => `/users/${userId.value}`, {
|
|
231
|
+
baseUrl: 'https://api.example.com',
|
|
232
|
+
watch: [userId],
|
|
233
|
+
query: { include: 'profile' },
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const useApiFetch = createUseFetch({
|
|
237
|
+
baseUrl: 'https://api.example.com',
|
|
238
|
+
headers: { 'x-client': 'bquery-readme' },
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const settings = useApiFetch<{ theme: string }>('/settings');
|
|
242
|
+
|
|
243
|
+
console.log(user.pending.value, user.data.value, settings.error.value);
|
|
244
|
+
```
|
|
245
|
+
|
|
216
246
|
### Components – Web Components
|
|
217
247
|
|
|
218
248
|
```ts
|
|
219
|
-
import {
|
|
249
|
+
import {
|
|
250
|
+
component,
|
|
251
|
+
defineComponent,
|
|
252
|
+
html,
|
|
253
|
+
registerDefaultComponents,
|
|
254
|
+
} from '@bquery/bquery/component';
|
|
220
255
|
|
|
221
256
|
component('user-card', {
|
|
222
257
|
props: {
|
|
223
258
|
username: { type: String, required: true },
|
|
224
259
|
age: { type: Number, validator: (v) => v >= 0 && v <= 150 },
|
|
225
260
|
},
|
|
226
|
-
// Extended lifecycle hooks
|
|
227
261
|
beforeMount() {
|
|
228
262
|
console.log('About to mount');
|
|
229
263
|
},
|
|
@@ -231,7 +265,6 @@ component('user-card', {
|
|
|
231
265
|
console.log('Mounted');
|
|
232
266
|
},
|
|
233
267
|
beforeUpdate(props) {
|
|
234
|
-
// Return false to prevent update
|
|
235
268
|
return props.username !== '';
|
|
236
269
|
},
|
|
237
270
|
onError(error) {
|
|
@@ -242,12 +275,15 @@ component('user-card', {
|
|
|
242
275
|
},
|
|
243
276
|
});
|
|
244
277
|
|
|
245
|
-
// Optional: create the class without auto-registration
|
|
246
278
|
const UserCard = defineComponent('user-card', {
|
|
247
279
|
props: { username: { type: String, required: true } },
|
|
248
280
|
render: ({ props }) => html`<div>Hello ${props.username}</div>`,
|
|
249
281
|
});
|
|
282
|
+
|
|
250
283
|
customElements.define('user-card', UserCard);
|
|
284
|
+
|
|
285
|
+
const tags = registerDefaultComponents({ prefix: 'ui' });
|
|
286
|
+
console.log(tags.button); // ui-button
|
|
251
287
|
```
|
|
252
288
|
|
|
253
289
|
### Motion – animations
|
|
@@ -255,18 +291,20 @@ customElements.define('user-card', UserCard);
|
|
|
255
291
|
```ts
|
|
256
292
|
import { animate, keyframePresets, spring, transition } from '@bquery/bquery/motion';
|
|
257
293
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
294
|
+
await transition({
|
|
295
|
+
update: () => {
|
|
296
|
+
$('#content').text('Updated');
|
|
297
|
+
},
|
|
298
|
+
classes: ['page-transition'],
|
|
299
|
+
types: ['navigation'],
|
|
300
|
+
skipOnReducedMotion: true,
|
|
261
301
|
});
|
|
262
302
|
|
|
263
|
-
// Web Animations helper
|
|
264
303
|
await animate(card, {
|
|
265
304
|
keyframes: keyframePresets.pop(),
|
|
266
305
|
options: { duration: 240, easing: 'ease-out' },
|
|
267
306
|
});
|
|
268
307
|
|
|
269
|
-
// Spring physics
|
|
270
308
|
const x = spring(0, { stiffness: 120, damping: 14 });
|
|
271
309
|
x.onChange((value) => {
|
|
272
310
|
element.style.transform = `translateX(${value}px)`;
|
|
@@ -276,44 +314,47 @@ await x.to(100);
|
|
|
276
314
|
|
|
277
315
|
### Security – sanitizing
|
|
278
316
|
|
|
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
317
|
```ts
|
|
282
318
|
import { sanitize, escapeHtml } from '@bquery/bquery/security';
|
|
283
319
|
|
|
284
|
-
// Sanitize HTML (removes dangerous elements like script, iframe, svg)
|
|
285
320
|
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
|
|
321
|
+
const safe = sanitize('<form id="cookie">...</form>');
|
|
291
322
|
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
323
|
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)
|
|
324
|
+
const safeSrcset = sanitize('<img srcset="safe.jpg 1x, javascript:alert(1) 2x">');
|
|
300
325
|
const safeForm = sanitize('<form action="javascript:alert(1)">...</form>');
|
|
301
|
-
|
|
302
|
-
// Escape for text display
|
|
303
326
|
const escaped = escapeHtml('<script>alert(1)</script>');
|
|
304
327
|
```
|
|
305
328
|
|
|
306
|
-
### Platform –
|
|
329
|
+
### Platform – config, cookies & accessibility
|
|
307
330
|
|
|
308
331
|
```ts
|
|
309
|
-
import {
|
|
332
|
+
import {
|
|
333
|
+
defineBqueryConfig,
|
|
334
|
+
useCookie,
|
|
335
|
+
definePageMeta,
|
|
336
|
+
useAnnouncer,
|
|
337
|
+
storage,
|
|
338
|
+
notifications,
|
|
339
|
+
} from '@bquery/bquery/platform';
|
|
340
|
+
|
|
341
|
+
defineBqueryConfig({
|
|
342
|
+
fetch: { baseUrl: 'https://api.example.com' },
|
|
343
|
+
transitions: { skipOnReducedMotion: true, classes: ['page-transition'] },
|
|
344
|
+
components: { prefix: 'ui' },
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
const theme = useCookie<'light' | 'dark'>('theme', { defaultValue: 'light' });
|
|
348
|
+
const cleanupMeta = definePageMeta({ title: 'Dashboard' });
|
|
349
|
+
const announcer = useAnnouncer();
|
|
350
|
+
|
|
351
|
+
theme.value = 'dark';
|
|
352
|
+
announcer.announce('Preferences saved');
|
|
353
|
+
cleanupMeta();
|
|
310
354
|
|
|
311
|
-
// Unified storage API
|
|
312
355
|
const local = storage.local();
|
|
313
|
-
await local.set('theme',
|
|
314
|
-
const theme = await local.get<string>('theme');
|
|
356
|
+
await local.set('theme', theme.value);
|
|
315
357
|
|
|
316
|
-
// Notifications
|
|
317
358
|
const permission = await notifications.requestPermission();
|
|
318
359
|
if (permission === 'granted') {
|
|
319
360
|
notifications.send('Build complete', {
|
|
@@ -324,12 +365,10 @@ if (permission === 'granted') {
|
|
|
324
365
|
|
|
325
366
|
### Router – SPA navigation
|
|
326
367
|
|
|
327
|
-
Internally, the router has been split into focused submodules (matching, navigation, state, links, utilities) with no public API changes.
|
|
328
|
-
|
|
329
368
|
```ts
|
|
369
|
+
import { effect } from '@bquery/bquery/reactive';
|
|
330
370
|
import { createRouter, navigate, currentRoute } from '@bquery/bquery/router';
|
|
331
371
|
|
|
332
|
-
// Create router with routes
|
|
333
372
|
const router = createRouter({
|
|
334
373
|
routes: [
|
|
335
374
|
{ path: '/', name: 'home', component: HomePage },
|
|
@@ -338,20 +377,13 @@ const router = createRouter({
|
|
|
338
377
|
],
|
|
339
378
|
});
|
|
340
379
|
|
|
341
|
-
|
|
342
|
-
router.beforeEach(async (to, from) => {
|
|
380
|
+
router.beforeEach(async (to) => {
|
|
343
381
|
if (to.path === '/admin' && !isAuthenticated()) {
|
|
344
|
-
await navigate('/login');
|
|
345
|
-
return false;
|
|
382
|
+
await navigate('/login');
|
|
383
|
+
return false;
|
|
346
384
|
}
|
|
347
385
|
});
|
|
348
386
|
|
|
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
387
|
effect(() => {
|
|
356
388
|
console.log('Current path:', currentRoute.value.path);
|
|
357
389
|
});
|
|
@@ -360,9 +392,14 @@ effect(() => {
|
|
|
360
392
|
### Store – state management
|
|
361
393
|
|
|
362
394
|
```ts
|
|
363
|
-
import {
|
|
395
|
+
import {
|
|
396
|
+
createStore,
|
|
397
|
+
createPersistedStore,
|
|
398
|
+
defineStore,
|
|
399
|
+
mapGetters,
|
|
400
|
+
watchStore,
|
|
401
|
+
} from '@bquery/bquery/store';
|
|
364
402
|
|
|
365
|
-
// Create a store (returns the store instance directly)
|
|
366
403
|
const counterStore = createStore({
|
|
367
404
|
id: 'counter',
|
|
368
405
|
state: () => ({ count: 0, name: 'Counter' }),
|
|
@@ -373,25 +410,14 @@ const counterStore = createStore({
|
|
|
373
410
|
increment() {
|
|
374
411
|
this.count++;
|
|
375
412
|
},
|
|
376
|
-
async fetchCount() {
|
|
377
|
-
this.count = await api.getCount();
|
|
378
|
-
},
|
|
379
413
|
},
|
|
380
414
|
});
|
|
381
415
|
|
|
382
|
-
// Use the store
|
|
383
|
-
counterStore.increment();
|
|
384
|
-
console.log(counterStore.doubled); // Reactive getter
|
|
385
|
-
|
|
386
|
-
// Persisted store (localStorage)
|
|
387
416
|
const settingsStore = createPersistedStore({
|
|
388
417
|
id: 'settings',
|
|
389
418
|
state: () => ({ theme: 'dark', language: 'en' }),
|
|
390
419
|
});
|
|
391
420
|
|
|
392
|
-
// Factory-style store definition (Pinia-style)
|
|
393
|
-
import { defineStore, mapGetters, watchStore } from '@bquery/bquery/store';
|
|
394
|
-
|
|
395
421
|
const useCounter = defineStore('counter', {
|
|
396
422
|
state: () => ({ count: 0 }),
|
|
397
423
|
getters: {
|
|
@@ -418,29 +444,18 @@ watchStore(
|
|
|
418
444
|
|
|
419
445
|
### View – declarative bindings
|
|
420
446
|
|
|
421
|
-
Internally modularized into focused submodules; the public API remains unchanged.
|
|
422
|
-
|
|
423
447
|
```ts
|
|
424
448
|
import { mount, createTemplate } from '@bquery/bquery/view';
|
|
425
449
|
import { signal } from '@bquery/bquery/reactive';
|
|
426
450
|
|
|
427
|
-
// Mount reactive bindings to DOM
|
|
428
451
|
const count = signal(0);
|
|
429
452
|
const items = signal(['Apple', 'Banana', 'Cherry']);
|
|
430
453
|
|
|
431
|
-
|
|
454
|
+
mount('#app', {
|
|
432
455
|
count,
|
|
433
456
|
items,
|
|
434
457
|
increment: () => count.value++,
|
|
435
458
|
});
|
|
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
459
|
```
|
|
445
460
|
|
|
446
461
|
## Browser Support
|
|
@@ -477,8 +492,8 @@ bun install
|
|
|
477
492
|
# Start VitePress docs
|
|
478
493
|
bun run dev
|
|
479
494
|
|
|
480
|
-
# Run
|
|
481
|
-
bun run
|
|
495
|
+
# Run Storybook
|
|
496
|
+
bun run storybook
|
|
482
497
|
|
|
483
498
|
# Run tests
|
|
484
499
|
bun test
|
|
@@ -486,6 +501,9 @@ bun test
|
|
|
486
501
|
# Build library
|
|
487
502
|
bun run build
|
|
488
503
|
|
|
504
|
+
# Build docs
|
|
505
|
+
bun run build:docs
|
|
506
|
+
|
|
489
507
|
# Generate API documentation
|
|
490
508
|
bun run docs:api
|
|
491
509
|
```
|
|
@@ -496,16 +514,17 @@ bun run docs:api
|
|
|
496
514
|
bQuery.js
|
|
497
515
|
├── src/
|
|
498
516
|
│ ├── core/ # Selectors, DOM ops, events, utils
|
|
499
|
-
│ ├── reactive/ # Signals, computed, effects
|
|
500
|
-
│ ├── component/ # Web Components helper
|
|
517
|
+
│ ├── reactive/ # Signals, computed, effects, async data
|
|
518
|
+
│ ├── component/ # Web Components helper + default library
|
|
501
519
|
│ ├── motion/ # View transitions, FLIP, springs
|
|
502
520
|
│ ├── security/ # Sanitizer, CSP, Trusted Types
|
|
503
|
-
│ ├── platform/ # Storage, cache,
|
|
521
|
+
│ ├── platform/ # Storage, cache, cookies, meta, config
|
|
504
522
|
│ ├── router/ # SPA routing, navigation guards
|
|
505
523
|
│ ├── store/ # State management, persistence
|
|
506
524
|
│ └── view/ # Declarative DOM bindings
|
|
507
525
|
├── docs/ # VitePress documentation
|
|
508
|
-
├──
|
|
526
|
+
├── .storybook/ # Storybook config
|
|
527
|
+
├── stories/ # Component stories
|
|
509
528
|
├── tests/ # bun:test suites
|
|
510
529
|
└── dist/ # Built files (ESM, UMD, IIFE)
|
|
511
530
|
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/component/component.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,SAAS,CAAC;AAEnE;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,SAAS,MAAM,EACf,YAAY,mBAAmB,CAAC,MAAM,CAAC,KACtC,OAAO,
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/component/component.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,SAAS,CAAC;AAEnE;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,SAAS,MAAM,EACf,YAAY,mBAAmB,CAAC,MAAM,CAAC,KACtC,OAAO,WA0OT,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,SAAS,MAAM,EACf,YAAY,mBAAmB,CAAC,MAAM,CAAC,KACtC,IAMF,CAAC"}
|
|
@@ -36,5 +36,7 @@
|
|
|
36
36
|
*/
|
|
37
37
|
export { component, defineComponent } from './component';
|
|
38
38
|
export { html, safeHtml } from './html';
|
|
39
|
+
export { registerDefaultComponents } from './library';
|
|
40
|
+
export type { DefaultComponentLibraryOptions, RegisteredDefaultComponents } from './library';
|
|
39
41
|
export type { ComponentDefinition, ComponentRenderContext, PropDefinition } from './types';
|
|
40
42
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/component/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACxC,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/component/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AACtD,YAAY,EAAE,8BAA8B,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAC;AAC7F,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default component library based on native Web Components.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/component
|
|
5
|
+
*/
|
|
6
|
+
/** Options for registering the default component library. */
|
|
7
|
+
export interface DefaultComponentLibraryOptions {
|
|
8
|
+
/** Prefix used for all registered component tags. Defaults to `bq`. */
|
|
9
|
+
prefix?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Tag names returned by registerDefaultComponents(). */
|
|
12
|
+
export interface RegisteredDefaultComponents {
|
|
13
|
+
/** Button component tag name. */
|
|
14
|
+
button: string;
|
|
15
|
+
/** Card component tag name. */
|
|
16
|
+
card: string;
|
|
17
|
+
/** Input component tag name. */
|
|
18
|
+
input: string;
|
|
19
|
+
/** Textarea component tag name. */
|
|
20
|
+
textarea: string;
|
|
21
|
+
/** Checkbox component tag name. */
|
|
22
|
+
checkbox: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Register a default set of foundational UI components.
|
|
26
|
+
*
|
|
27
|
+
* The library is intentionally small and dependency-free, providing common
|
|
28
|
+
* primitives that can be themed via shadow parts and CSS custom properties.
|
|
29
|
+
*
|
|
30
|
+
* @param options - Optional registration settings such as a custom tag prefix
|
|
31
|
+
* @returns The registered tag names for each component
|
|
32
|
+
*/
|
|
33
|
+
export declare const registerDefaultComponents: (options?: DefaultComponentLibraryOptions) => RegisteredDefaultComponents;
|
|
34
|
+
//# sourceMappingURL=library.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../src/component/library.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,6DAA6D;AAC7D,MAAM,WAAW,8BAA8B;IAC7C,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,yDAAyD;AACzD,MAAM,WAAW,2BAA2B;IAC1C,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAwJD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAS,8BAAmC,KAC3C,2BAuTF,CAAC"}
|
|
@@ -52,6 +52,9 @@ export type ComponentRenderContext<TProps extends Record<string, unknown>> = {
|
|
|
52
52
|
*
|
|
53
53
|
* @template TProps - Type of the component's props
|
|
54
54
|
*/
|
|
55
|
+
type ComponentHook<TResult = void> = ((this: HTMLElement) => TResult) | (() => TResult);
|
|
56
|
+
type ComponentHookWithProps<TProps extends Record<string, unknown>, TResult = void> = ((this: HTMLElement, props: TProps) => TResult) | ((props: TProps) => TResult);
|
|
57
|
+
type ComponentErrorHook = ((this: HTMLElement, error: Error) => void) | ((error: Error) => void);
|
|
55
58
|
export type ComponentDefinition<TProps extends Record<string, unknown> = Record<string, unknown>> = {
|
|
56
59
|
/** Prop definitions with types and defaults */
|
|
57
60
|
props?: Record<keyof TProps, PropDefinition>;
|
|
@@ -60,18 +63,19 @@ export type ComponentDefinition<TProps extends Record<string, unknown> = Record<
|
|
|
60
63
|
/** CSS styles scoped to the component's shadow DOM */
|
|
61
64
|
styles?: string;
|
|
62
65
|
/** Lifecycle hook called before the component mounts (before first render) */
|
|
63
|
-
beforeMount?:
|
|
66
|
+
beforeMount?: ComponentHook;
|
|
64
67
|
/** Lifecycle hook called when component is added to DOM */
|
|
65
|
-
connected?:
|
|
68
|
+
connected?: ComponentHook;
|
|
66
69
|
/** Lifecycle hook called when component is removed from DOM */
|
|
67
|
-
disconnected?:
|
|
70
|
+
disconnected?: ComponentHook;
|
|
68
71
|
/** Lifecycle hook called before an update render; return false to prevent */
|
|
69
|
-
beforeUpdate?:
|
|
72
|
+
beforeUpdate?: ComponentHookWithProps<TProps, boolean | void>;
|
|
70
73
|
/** Lifecycle hook called after reactive updates trigger a render */
|
|
71
|
-
updated?:
|
|
74
|
+
updated?: ComponentHook;
|
|
72
75
|
/** Error handler for errors during rendering or lifecycle */
|
|
73
|
-
onError?:
|
|
76
|
+
onError?: ComponentErrorHook;
|
|
74
77
|
/** Render function returning HTML string */
|
|
75
78
|
render: (context: ComponentRenderContext<TProps>) => string;
|
|
76
79
|
};
|
|
80
|
+
export {};
|
|
77
81
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/component/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,IAAI;IACxC,0DAA0D;IAC1D,IAAI,EACA,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,iBAAiB,GACjB,gBAAgB,GAChB;QAAE,KAAK,KAAK,EAAE,OAAO,GAAG,CAAC,CAAA;KAAE,GAC3B,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,0DAA0D;IAC1D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAClC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC3E,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,6CAA6C;IAC7C,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAC9F;IACE,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,MAAM,EAAE,cAAc,CAAC,CAAC;IAC7C,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/component/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,IAAI;IACxC,0DAA0D;IAC1D,IAAI,EACA,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,iBAAiB,GACjB,gBAAgB,GAChB;QAAE,KAAK,KAAK,EAAE,OAAO,GAAG,CAAC,CAAA;KAAE,GAC3B,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,0DAA0D;IAC1D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAClC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC3E,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,6CAA6C;IAC7C,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF;;;;GAIG;AACH,KAAK,aAAa,CAAC,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;AACxF,KAAK,sBAAsB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,IAC9E,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAC/C,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AACjC,KAAK,kBAAkB,GAAG,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;AAEjG,MAAM,MAAM,mBAAmB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAC9F;IACE,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,MAAM,EAAE,cAAc,CAAC,CAAC;IAC7C,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,2DAA2D;IAC3D,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,+DAA+D;IAC/D,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,6EAA6E;IAC7E,YAAY,CAAC,EAAE,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;IAC9D,oEAAoE;IACpE,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,4CAA4C;IAC5C,MAAM,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC;CAC7D,CAAC"}
|