@bquery/bquery 1.0.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/LICENSE.md +21 -0
- package/README.md +266 -0
- package/dist/component/index.d.ts +155 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component.es.mjs +128 -0
- package/dist/component.es.mjs.map +1 -0
- package/dist/core/collection.d.ts +198 -0
- package/dist/core/collection.d.ts.map +1 -0
- package/dist/core/element.d.ts +301 -0
- package/dist/core/element.d.ts.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/selector.d.ts +11 -0
- package/dist/core/selector.d.ts.map +1 -0
- package/dist/core/shared.d.ts +7 -0
- package/dist/core/shared.d.ts.map +1 -0
- package/dist/core/utils.d.ts +300 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core.es.mjs +1015 -0
- package/dist/core.es.mjs.map +1 -0
- package/dist/full.d.ts +48 -0
- package/dist/full.d.ts.map +1 -0
- package/dist/full.es.mjs +43 -0
- package/dist/full.es.mjs.map +1 -0
- package/dist/full.iife.js +2 -0
- package/dist/full.iife.js.map +1 -0
- package/dist/full.umd.js +2 -0
- package/dist/full.umd.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.es.mjs +43 -0
- package/dist/index.es.mjs.map +1 -0
- package/dist/motion/index.d.ts +145 -0
- package/dist/motion/index.d.ts.map +1 -0
- package/dist/motion.es.mjs +104 -0
- package/dist/motion.es.mjs.map +1 -0
- package/dist/platform/buckets.d.ts +44 -0
- package/dist/platform/buckets.d.ts.map +1 -0
- package/dist/platform/cache.d.ts +71 -0
- package/dist/platform/cache.d.ts.map +1 -0
- package/dist/platform/index.d.ts +15 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/notifications.d.ts +52 -0
- package/dist/platform/notifications.d.ts.map +1 -0
- package/dist/platform/storage.d.ts +69 -0
- package/dist/platform/storage.d.ts.map +1 -0
- package/dist/platform.es.mjs +245 -0
- package/dist/platform.es.mjs.map +1 -0
- package/dist/reactive/index.d.ts +8 -0
- package/dist/reactive/index.d.ts.map +1 -0
- package/dist/reactive/signal.d.ts +204 -0
- package/dist/reactive/signal.d.ts.map +1 -0
- package/dist/reactive.es.mjs +123 -0
- package/dist/reactive.es.mjs.map +1 -0
- package/dist/security/index.d.ts +8 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/sanitize.d.ts +99 -0
- package/dist/security/sanitize.d.ts.map +1 -0
- package/dist/security.es.mjs +194 -0
- package/dist/security.es.mjs.map +1 -0
- package/package.json +120 -0
- package/src/component/index.ts +360 -0
- package/src/core/collection.ts +339 -0
- package/src/core/element.ts +493 -0
- package/src/core/index.ts +4 -0
- package/src/core/selector.ts +29 -0
- package/src/core/shared.ts +13 -0
- package/src/core/utils.ts +425 -0
- package/src/full.ts +101 -0
- package/src/index.ts +27 -0
- package/src/motion/index.ts +365 -0
- package/src/platform/buckets.ts +115 -0
- package/src/platform/cache.ts +130 -0
- package/src/platform/index.ts +18 -0
- package/src/platform/notifications.ts +87 -0
- package/src/platform/storage.ts +208 -0
- package/src/reactive/index.ts +9 -0
- package/src/reactive/signal.ts +347 -0
- package/src/security/index.ts +18 -0
- package/src/security/sanitize.ts +446 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 @bQuery / Jonas Pfalzgraf
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# bQuery.js
|
|
2
|
+
|
|
3
|
+
[](https://github.com/bquery/bquery)
|
|
4
|
+
[](https://github.com/bquery/bquery/stargazers)
|
|
5
|
+
[](https://github.com/bquery/bquery/issues)
|
|
6
|
+
[](https://github.com/bquery/bquery/blob/main/LICENSE.md)
|
|
7
|
+
[](https://www.npmjs.com/package/bquery)
|
|
8
|
+
[](https://bundlephobia.com/package/bquery)
|
|
9
|
+
[](https://unpkg.com/bquery/)
|
|
10
|
+
|
|
11
|
+
**The jQuery for the modern Web Platform.**
|
|
12
|
+
|
|
13
|
+
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.
|
|
14
|
+
|
|
15
|
+
## Highlights
|
|
16
|
+
|
|
17
|
+
- **Zero‑build capable**: runs directly in the browser; build tools are optional.
|
|
18
|
+
- **Security‑focused**: DOM writes are sanitized by default; Trusted Types supported.
|
|
19
|
+
- **Modular**: the core stays small; extra modules are opt‑in.
|
|
20
|
+
- **TypeScript‑first**: clear types and strong IDE support.
|
|
21
|
+
- **Tree-shakeable**: import only what you need.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
### Via npm/bun/pnpm
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# npm
|
|
29
|
+
npm install bquery
|
|
30
|
+
|
|
31
|
+
# bun
|
|
32
|
+
bun add bquery
|
|
33
|
+
|
|
34
|
+
# pnpm
|
|
35
|
+
pnpm add bquery
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Via CDN (Zero-build)
|
|
39
|
+
|
|
40
|
+
#### ES Modules (recommended)
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<script type="module">
|
|
44
|
+
import { $, signal } from 'https://unpkg.com/bquery@1/dist/full.es.mjs';
|
|
45
|
+
|
|
46
|
+
const count = signal(0);
|
|
47
|
+
$('#counter').text(`Count: ${count.value}`);
|
|
48
|
+
</script>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### UMD (global variable)
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<script src="https://unpkg.com/bquery@1/dist/full.umd.js"></script>
|
|
55
|
+
<script>
|
|
56
|
+
const { $, signal } = bQuery;
|
|
57
|
+
const count = signal(0);
|
|
58
|
+
</script>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### IIFE (self-executing)
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<script src="https://unpkg.com/bquery@1/dist/full.iife.js"></script>
|
|
65
|
+
<script>
|
|
66
|
+
const { $, $$ } = bQuery;
|
|
67
|
+
$$('.items').addClass('loaded');
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Import Strategies
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// Full bundle (all modules)
|
|
75
|
+
import { $, signal, component } from 'bquery';
|
|
76
|
+
|
|
77
|
+
// Core only
|
|
78
|
+
import { $, $$ } from 'bquery/core';
|
|
79
|
+
|
|
80
|
+
// À la carte (individual modules)
|
|
81
|
+
import { signal, computed, effect } from 'bquery/reactive';
|
|
82
|
+
import { component, html } from 'bquery/component';
|
|
83
|
+
import { transition, spring } from 'bquery/motion';
|
|
84
|
+
import { sanitize } from 'bquery/security';
|
|
85
|
+
import { storage, cache } from 'bquery/platform';
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Modules at a glance
|
|
89
|
+
|
|
90
|
+
| Module | Description | Size (gzip) |
|
|
91
|
+
| ------------- | ---------------------------------------------- | ----------- |
|
|
92
|
+
| **Core** | Selectors, DOM manipulation, events, utilities | ~6 KB |
|
|
93
|
+
| **Reactive** | `signal`, `computed`, `effect`, `batch` | ~1 KB |
|
|
94
|
+
| **Component** | Lightweight Web Components with props | ~1.3 KB |
|
|
95
|
+
| **Motion** | View transitions, FLIP animations, springs | ~1.2 KB |
|
|
96
|
+
| **Security** | HTML sanitizing, Trusted Types, CSP | ~1.6 KB |
|
|
97
|
+
| **Platform** | Storage, cache, notifications, buckets | ~1.7 KB |
|
|
98
|
+
|
|
99
|
+
## Quick examples
|
|
100
|
+
|
|
101
|
+
### Core – DOM & events
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { $, $$ } from 'bquery/core';
|
|
105
|
+
|
|
106
|
+
// jQuery-style selectors
|
|
107
|
+
$('#save').on('click', (event) => {
|
|
108
|
+
console.log('Saved', event.type);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Method chaining
|
|
112
|
+
$('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready');
|
|
113
|
+
|
|
114
|
+
// Collections
|
|
115
|
+
$$('.items').addClass('highlight');
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Reactive – signals
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { signal, computed, effect, batch } from 'bquery/reactive';
|
|
122
|
+
|
|
123
|
+
const count = signal(0);
|
|
124
|
+
const doubled = computed(() => count.value * 2);
|
|
125
|
+
|
|
126
|
+
effect(() => {
|
|
127
|
+
console.log('Count changed', count.value);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Batch updates for performance
|
|
131
|
+
batch(() => {
|
|
132
|
+
count.value++;
|
|
133
|
+
count.value++;
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Components – Web Components
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { component, html } from 'bquery/component';
|
|
141
|
+
|
|
142
|
+
component('user-card', {
|
|
143
|
+
props: {
|
|
144
|
+
username: { type: String, required: true },
|
|
145
|
+
},
|
|
146
|
+
render({ props }) {
|
|
147
|
+
return html`<div>Hello ${props.username}</div>`;
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Motion – animations
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { transition, spring } from 'bquery/motion';
|
|
156
|
+
|
|
157
|
+
// View transitions (with fallback)
|
|
158
|
+
await transition(() => {
|
|
159
|
+
$('#content').text('Updated');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Spring physics
|
|
163
|
+
const x = spring(0, { stiffness: 120, damping: 14 });
|
|
164
|
+
x.onChange((value) => {
|
|
165
|
+
element.style.transform = `translateX(${value}px)`;
|
|
166
|
+
});
|
|
167
|
+
await x.to(100);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Security – sanitizing
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { sanitize, escapeHtml } from 'bquery/security';
|
|
174
|
+
|
|
175
|
+
// Sanitize HTML (removes dangerous elements)
|
|
176
|
+
const safeHtml = sanitize(userInput);
|
|
177
|
+
|
|
178
|
+
// Escape for text display
|
|
179
|
+
const escaped = escapeHtml('<script>alert(1)</script>');
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Platform – storage & APIs
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import { storage, notifications } from 'bquery/platform';
|
|
186
|
+
|
|
187
|
+
// Unified storage API
|
|
188
|
+
const local = storage.local();
|
|
189
|
+
await local.set('theme', 'dark');
|
|
190
|
+
const theme = await local.get<string>('theme');
|
|
191
|
+
|
|
192
|
+
// Notifications
|
|
193
|
+
const permission = await notifications.requestPermission();
|
|
194
|
+
if (permission === 'granted') {
|
|
195
|
+
notifications.send('Build complete', {
|
|
196
|
+
body: 'Your docs are ready.',
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Browser Support
|
|
202
|
+
|
|
203
|
+
| Browser | Version | Support |
|
|
204
|
+
| ------- | ------- | ------- |
|
|
205
|
+
| Chrome | 90+ | ✅ Full |
|
|
206
|
+
| Firefox | 90+ | ✅ Full |
|
|
207
|
+
| Safari | 15+ | ✅ Full |
|
|
208
|
+
| Edge | 90+ | ✅ Full |
|
|
209
|
+
|
|
210
|
+
> **No IE support** by design.
|
|
211
|
+
|
|
212
|
+
## Documentation
|
|
213
|
+
|
|
214
|
+
- **Getting Started**: [docs/guide/getting-started.md](docs/guide/getting-started.md)
|
|
215
|
+
- **Core API**: [docs/guide/api-core.md](docs/guide/api-core.md)
|
|
216
|
+
- **Components**: [docs/guide/components.md](docs/guide/components.md)
|
|
217
|
+
- **Reactivity**: [docs/guide/reactive.md](docs/guide/reactive.md)
|
|
218
|
+
- **Motion**: [docs/guide/motion.md](docs/guide/motion.md)
|
|
219
|
+
- **Security**: [docs/guide/security.md](docs/guide/security.md)
|
|
220
|
+
|
|
221
|
+
## Local Development
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Install dependencies
|
|
225
|
+
bun install
|
|
226
|
+
|
|
227
|
+
# Start VitePress docs
|
|
228
|
+
bun run dev
|
|
229
|
+
|
|
230
|
+
# Run Vite playground
|
|
231
|
+
bun run playground
|
|
232
|
+
|
|
233
|
+
# Run tests
|
|
234
|
+
bun test
|
|
235
|
+
|
|
236
|
+
# Build library
|
|
237
|
+
bun run build
|
|
238
|
+
|
|
239
|
+
# Generate API documentation
|
|
240
|
+
bun run docs:api
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Project Structure
|
|
244
|
+
|
|
245
|
+
```text
|
|
246
|
+
bQuery.js
|
|
247
|
+
├── src/
|
|
248
|
+
│ ├── core/ # Selectors, DOM ops, events, utils
|
|
249
|
+
│ ├── reactive/ # Signals, computed, effects
|
|
250
|
+
│ ├── component/ # Web Components helper
|
|
251
|
+
│ ├── motion/ # View transitions, FLIP, springs
|
|
252
|
+
│ ├── security/ # Sanitizer, CSP, Trusted Types
|
|
253
|
+
│ └── platform/ # Storage, cache, notifications
|
|
254
|
+
├── docs/ # VitePress documentation
|
|
255
|
+
├── playground/ # Vite demo app
|
|
256
|
+
├── tests/ # bun:test suites
|
|
257
|
+
└── dist/ # Built files (ESM, UMD, IIFE)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Contributing
|
|
261
|
+
|
|
262
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
MIT – See [LICENSE.md](LICENSE.md) for details.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Web Component helper for building custom elements.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a declarative API for defining Web Components
|
|
5
|
+
* without complex build steps. Features include:
|
|
6
|
+
* - Type-safe props with automatic attribute coercion
|
|
7
|
+
* - Reactive state management
|
|
8
|
+
* - Shadow DOM encapsulation with scoped styles
|
|
9
|
+
* - Lifecycle hooks (connected, disconnected)
|
|
10
|
+
* - Event emission helpers
|
|
11
|
+
*
|
|
12
|
+
* @module bquery/component
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { component, html } from 'bquery/component';
|
|
17
|
+
*
|
|
18
|
+
* component('user-card', {
|
|
19
|
+
* props: {
|
|
20
|
+
* username: { type: String, required: true },
|
|
21
|
+
* avatar: { type: String, default: '/default-avatar.png' },
|
|
22
|
+
* },
|
|
23
|
+
* styles: `
|
|
24
|
+
* .card { padding: 1rem; border: 1px solid #ccc; }
|
|
25
|
+
* `,
|
|
26
|
+
* render({ props }) {
|
|
27
|
+
* return html`
|
|
28
|
+
* <div class="card">
|
|
29
|
+
* <img src="${props.avatar}" alt="${props.username}" />
|
|
30
|
+
* <h3>${props.username}</h3>
|
|
31
|
+
* </div>
|
|
32
|
+
* `;
|
|
33
|
+
* },
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Defines a single prop's type and configuration.
|
|
39
|
+
*
|
|
40
|
+
* @template T - The TypeScript type of the prop value
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const myProp: PropDefinition<number> = {
|
|
45
|
+
* type: Number,
|
|
46
|
+
* required: false,
|
|
47
|
+
* default: 0,
|
|
48
|
+
* };
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export type PropDefinition<T = unknown> = {
|
|
52
|
+
/** Constructor or converter function for the prop type */
|
|
53
|
+
type: StringConstructor | NumberConstructor | BooleanConstructor | ObjectConstructor | ArrayConstructor | {
|
|
54
|
+
new (value: unknown): T;
|
|
55
|
+
} | ((value: unknown) => T);
|
|
56
|
+
/** Whether the prop must be provided */
|
|
57
|
+
required?: boolean;
|
|
58
|
+
/** Default value when prop is not provided */
|
|
59
|
+
default?: T;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Complete component definition including props, state, styles, and lifecycle.
|
|
63
|
+
*
|
|
64
|
+
* @template TProps - Type of the component's props
|
|
65
|
+
*/
|
|
66
|
+
export type ComponentDefinition<TProps extends Record<string, unknown> = Record<string, unknown>> = {
|
|
67
|
+
/** Prop definitions with types and defaults */
|
|
68
|
+
props?: Record<keyof TProps, PropDefinition>;
|
|
69
|
+
/** Initial internal state */
|
|
70
|
+
state?: Record<string, unknown>;
|
|
71
|
+
/** CSS styles scoped to the component's shadow DOM */
|
|
72
|
+
styles?: string;
|
|
73
|
+
/** Lifecycle hook called when component is added to DOM */
|
|
74
|
+
connected?: () => void;
|
|
75
|
+
/** Lifecycle hook called when component is removed from DOM */
|
|
76
|
+
disconnected?: () => void;
|
|
77
|
+
/** Lifecycle hook called after reactive updates trigger a render */
|
|
78
|
+
updated?: () => void;
|
|
79
|
+
/** Render function returning HTML string */
|
|
80
|
+
render: (context: {
|
|
81
|
+
props: TProps;
|
|
82
|
+
state: Record<string, unknown>;
|
|
83
|
+
emit: (event: string, detail?: unknown) => void;
|
|
84
|
+
}) => string;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Tagged template literal for creating HTML strings.
|
|
88
|
+
*
|
|
89
|
+
* This function handles interpolation of values into HTML templates,
|
|
90
|
+
* converting null/undefined to empty strings.
|
|
91
|
+
*
|
|
92
|
+
* @param strings - Template literal string parts
|
|
93
|
+
* @param values - Interpolated values
|
|
94
|
+
* @returns Combined HTML string
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const name = 'World';
|
|
99
|
+
* const greeting = html`<h1>Hello, ${name}!</h1>`;
|
|
100
|
+
* // Result: '<h1>Hello, World!</h1>'
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => string;
|
|
104
|
+
/**
|
|
105
|
+
* Escapes HTML entities in interpolated values for XSS prevention.
|
|
106
|
+
* Use this when you need to safely embed user content in templates.
|
|
107
|
+
*
|
|
108
|
+
* @param strings - Template literal string parts
|
|
109
|
+
* @param values - Interpolated values to escape
|
|
110
|
+
* @returns Combined HTML string with escaped values
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const userInput = '<script>alert("xss")</script>';
|
|
115
|
+
* const safe = safeHtml`<div>${userInput}</div>`;
|
|
116
|
+
* // Result: '<div><script>alert("xss")</script></div>'
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export declare const safeHtml: (strings: TemplateStringsArray, ...values: unknown[]) => string;
|
|
120
|
+
/**
|
|
121
|
+
* Defines and registers a custom Web Component.
|
|
122
|
+
*
|
|
123
|
+
* This function creates a new custom element with the given tag name
|
|
124
|
+
* and configuration. The component uses Shadow DOM for encapsulation
|
|
125
|
+
* and automatically re-renders when observed attributes change.
|
|
126
|
+
*
|
|
127
|
+
* @template TProps - Type of the component's props
|
|
128
|
+
* @param tagName - The custom element tag name (must contain a hyphen)
|
|
129
|
+
* @param definition - The component configuration
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* component('counter-button', {
|
|
134
|
+
* props: {
|
|
135
|
+
* start: { type: Number, default: 0 },
|
|
136
|
+
* },
|
|
137
|
+
* state: { count: 0 },
|
|
138
|
+
* styles: `
|
|
139
|
+
* button { padding: 0.5rem 1rem; }
|
|
140
|
+
* `,
|
|
141
|
+
* connected() {
|
|
142
|
+
* console.log('Counter mounted');
|
|
143
|
+
* },
|
|
144
|
+
* render({ props, state, emit }) {
|
|
145
|
+
* return html`
|
|
146
|
+
* <button onclick="this.getRootNode().host.increment()">
|
|
147
|
+
* Count: ${state.count}
|
|
148
|
+
* </button>
|
|
149
|
+
* `;
|
|
150
|
+
* },
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export declare const component: <TProps extends Record<string, unknown>>(tagName: string, definition: ComponentDefinition<TProps>) => void;
|
|
155
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/component/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;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;CACb,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,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,4CAA4C;IAC5C,MAAM,EAAE,CAAC,OAAO,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;KACjD,KAAK,MAAM,CAAC;CACd,CAAC;AAsDJ;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,IAAI,GAAI,SAAS,oBAAoB,EAAE,GAAG,QAAQ,OAAO,EAAE,KAAG,MAE1E,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,GAAI,SAAS,oBAAoB,EAAE,GAAG,QAAQ,OAAO,EAAE,KAAG,MAgB9E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,SAAS,MAAM,EACf,YAAY,mBAAmB,CAAC,MAAM,CAAC,KACtC,IA0HF,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const i = (t, e) => {
|
|
2
|
+
const { type: o } = e;
|
|
3
|
+
if (o === String) return t;
|
|
4
|
+
if (o === Number) {
|
|
5
|
+
const s = Number(t);
|
|
6
|
+
return Number.isNaN(s) ? t : s;
|
|
7
|
+
}
|
|
8
|
+
if (o === Boolean) {
|
|
9
|
+
const s = t.trim().toLowerCase();
|
|
10
|
+
return s === "" || s === "true" || s === "1" ? !0 : s === "false" || s === "0" ? !1 : !!t;
|
|
11
|
+
}
|
|
12
|
+
if (o === Object || o === Array)
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(t);
|
|
15
|
+
} catch {
|
|
16
|
+
return t;
|
|
17
|
+
}
|
|
18
|
+
if (typeof o == "function") {
|
|
19
|
+
const s = o, r = o;
|
|
20
|
+
try {
|
|
21
|
+
return s(t);
|
|
22
|
+
} catch {
|
|
23
|
+
return new r(t);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return t;
|
|
27
|
+
}, l = (t, ...e) => t.reduce((o, s, r) => `${o}${s}${e[r] ?? ""}`, ""), h = (t, ...e) => {
|
|
28
|
+
const o = {
|
|
29
|
+
"&": "&",
|
|
30
|
+
"<": "<",
|
|
31
|
+
">": ">",
|
|
32
|
+
'"': """,
|
|
33
|
+
"'": "'",
|
|
34
|
+
"`": "`"
|
|
35
|
+
}, s = (r) => String(r ?? "").replace(/[&<>"'`]/g, (c) => o[c]);
|
|
36
|
+
return t.reduce((r, n, c) => `${r}${n}${s(e[c])}`, "");
|
|
37
|
+
}, d = (t, e) => {
|
|
38
|
+
class o extends HTMLElement {
|
|
39
|
+
constructor() {
|
|
40
|
+
super(), this.state = { ...e.state ?? {} }, this.props = {}, this.attachShadow({ mode: "open" }), this.syncProps();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns the list of attributes to observe for changes.
|
|
44
|
+
*/
|
|
45
|
+
static get observedAttributes() {
|
|
46
|
+
return Object.keys(e.props ?? {});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Called when the element is added to the DOM.
|
|
50
|
+
*/
|
|
51
|
+
connectedCallback() {
|
|
52
|
+
e.connected?.call(this), this.render();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Called when the element is removed from the DOM.
|
|
56
|
+
*/
|
|
57
|
+
disconnectedCallback() {
|
|
58
|
+
e.disconnected?.call(this);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Called when an observed attribute changes.
|
|
62
|
+
*/
|
|
63
|
+
attributeChangedCallback() {
|
|
64
|
+
this.syncProps(), this.render(!0);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Updates a state property and triggers a re-render.
|
|
68
|
+
*
|
|
69
|
+
* @param key - The state property key
|
|
70
|
+
* @param value - The new value
|
|
71
|
+
*/
|
|
72
|
+
setState(r, n) {
|
|
73
|
+
this.state[r] = n, this.render(!0);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Gets a state property value.
|
|
77
|
+
*
|
|
78
|
+
* @param key - The state property key
|
|
79
|
+
* @returns The current value
|
|
80
|
+
*/
|
|
81
|
+
getState(r) {
|
|
82
|
+
return this.state[r];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Synchronizes props from attributes.
|
|
86
|
+
* @internal
|
|
87
|
+
*/
|
|
88
|
+
syncProps() {
|
|
89
|
+
const r = e.props ?? {};
|
|
90
|
+
for (const [n, c] of Object.entries(r)) {
|
|
91
|
+
const u = this.getAttribute(n);
|
|
92
|
+
if (u == null) {
|
|
93
|
+
if (c.required && c.default === void 0)
|
|
94
|
+
throw new Error(`bQuery component: missing required prop "${n}"`);
|
|
95
|
+
this.props[n] = c.default ?? void 0;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
this.props[n] = i(
|
|
99
|
+
u,
|
|
100
|
+
c
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Renders the component to its shadow root.
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
render(r = !1) {
|
|
109
|
+
const n = (p, a) => {
|
|
110
|
+
this.dispatchEvent(new CustomEvent(p, { detail: a, bubbles: !0, composed: !0 }));
|
|
111
|
+
};
|
|
112
|
+
if (!this.shadowRoot) return;
|
|
113
|
+
const c = e.render({
|
|
114
|
+
props: this.props,
|
|
115
|
+
state: this.state,
|
|
116
|
+
emit: n
|
|
117
|
+
}), u = e.styles ? `<style>${e.styles}</style>` : "";
|
|
118
|
+
this.shadowRoot.innerHTML = `${u}${c}`, r && e.updated?.call(this);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
customElements.get(t) || customElements.define(t, o);
|
|
122
|
+
};
|
|
123
|
+
export {
|
|
124
|
+
d as component,
|
|
125
|
+
l as html,
|
|
126
|
+
h as safeHtml
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=component.es.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.es.mjs","sources":["../src/component/index.ts"],"sourcesContent":["/**\n * Minimal Web Component helper for building custom elements.\n *\n * This module provides a declarative API for defining Web Components\n * without complex build steps. Features include:\n * - Type-safe props with automatic attribute coercion\n * - Reactive state management\n * - Shadow DOM encapsulation with scoped styles\n * - Lifecycle hooks (connected, disconnected)\n * - Event emission helpers\n *\n * @module bquery/component\n *\n * @example\n * ```ts\n * import { component, html } from 'bquery/component';\n *\n * component('user-card', {\n * props: {\n * username: { type: String, required: true },\n * avatar: { type: String, default: '/default-avatar.png' },\n * },\n * styles: `\n * .card { padding: 1rem; border: 1px solid #ccc; }\n * `,\n * render({ props }) {\n * return html`\n * <div class=\"card\">\n * <img src=\"${props.avatar}\" alt=\"${props.username}\" />\n * <h3>${props.username}</h3>\n * </div>\n * `;\n * },\n * });\n * ```\n */\n\n/**\n * Defines a single prop's type and configuration.\n *\n * @template T - The TypeScript type of the prop value\n *\n * @example\n * ```ts\n * const myProp: PropDefinition<number> = {\n * type: Number,\n * required: false,\n * default: 0,\n * };\n * ```\n */\nexport type PropDefinition<T = unknown> = {\n /** Constructor or converter function for the prop type */\n type:\n | StringConstructor\n | NumberConstructor\n | BooleanConstructor\n | ObjectConstructor\n | ArrayConstructor\n | { new (value: unknown): T }\n | ((value: unknown) => T);\n /** Whether the prop must be provided */\n required?: boolean;\n /** Default value when prop is not provided */\n default?: T;\n};\n\n/**\n * Complete component definition including props, state, styles, and lifecycle.\n *\n * @template TProps - Type of the component's props\n */\nexport type ComponentDefinition<TProps extends Record<string, unknown> = Record<string, unknown>> =\n {\n /** Prop definitions with types and defaults */\n props?: Record<keyof TProps, PropDefinition>;\n /** Initial internal state */\n state?: Record<string, unknown>;\n /** CSS styles scoped to the component's shadow DOM */\n styles?: string;\n /** Lifecycle hook called when component is added to DOM */\n connected?: () => void;\n /** Lifecycle hook called when component is removed from DOM */\n disconnected?: () => void;\n /** Lifecycle hook called after reactive updates trigger a render */\n updated?: () => void;\n /** Render function returning HTML string */\n render: (context: {\n props: TProps;\n state: Record<string, unknown>;\n emit: (event: string, detail?: unknown) => void;\n }) => string;\n };\n\n/**\n * Coerces a string attribute value into a typed prop value.\n * Supports String, Number, Boolean, Object, Array, and custom converters.\n *\n * @internal\n * @template T - The target type\n * @param rawValue - The raw string value from the attribute\n * @param config - The prop definition with type information\n * @returns The coerced value of type T\n */\nconst coercePropValue = <T>(rawValue: string, config: PropDefinition<T>): T => {\n const { type } = config;\n\n if (type === String) return rawValue as T;\n\n if (type === Number) {\n const parsed = Number(rawValue);\n return (Number.isNaN(parsed) ? rawValue : parsed) as T;\n }\n\n if (type === Boolean) {\n const normalized = rawValue.trim().toLowerCase();\n if (normalized === '' || normalized === 'true' || normalized === '1') {\n return true as T;\n }\n if (normalized === 'false' || normalized === '0') {\n return false as T;\n }\n return Boolean(rawValue) as T;\n }\n\n if (type === Object || type === Array) {\n try {\n return JSON.parse(rawValue) as T;\n } catch {\n return rawValue as T;\n }\n }\n\n if (typeof type === 'function') {\n const callable = type as (value: unknown) => T;\n const constructable = type as new (value: unknown) => T;\n try {\n return callable(rawValue);\n } catch {\n return new constructable(rawValue);\n }\n }\n\n return rawValue as T;\n};\n\n/**\n * Tagged template literal for creating HTML strings.\n *\n * This function handles interpolation of values into HTML templates,\n * converting null/undefined to empty strings.\n *\n * @param strings - Template literal string parts\n * @param values - Interpolated values\n * @returns Combined HTML string\n *\n * @example\n * ```ts\n * const name = 'World';\n * const greeting = html`<h1>Hello, ${name}!</h1>`;\n * // Result: '<h1>Hello, World!</h1>'\n * ```\n */\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): string => {\n return strings.reduce((acc, part, index) => `${acc}${part}${values[index] ?? ''}`, '');\n};\n\n/**\n * Escapes HTML entities in interpolated values for XSS prevention.\n * Use this when you need to safely embed user content in templates.\n *\n * @param strings - Template literal string parts\n * @param values - Interpolated values to escape\n * @returns Combined HTML string with escaped values\n *\n * @example\n * ```ts\n * const userInput = '<script>alert(\"xss\")</script>';\n * const safe = safeHtml`<div>${userInput}</div>`;\n * // Result: '<div><script>alert(\"xss\")</script></div>'\n * ```\n */\nexport const safeHtml = (strings: TemplateStringsArray, ...values: unknown[]): string => {\n const escapeMap: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '`': '`',\n };\n\n const escape = (value: unknown): string => {\n const str = String(value ?? '');\n return str.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\n };\n\n return strings.reduce((acc, part, index) => `${acc}${part}${escape(values[index])}`, '');\n};\n\n/**\n * Defines and registers a custom Web Component.\n *\n * This function creates a new custom element with the given tag name\n * and configuration. The component uses Shadow DOM for encapsulation\n * and automatically re-renders when observed attributes change.\n *\n * @template TProps - Type of the component's props\n * @param tagName - The custom element tag name (must contain a hyphen)\n * @param definition - The component configuration\n *\n * @example\n * ```ts\n * component('counter-button', {\n * props: {\n * start: { type: Number, default: 0 },\n * },\n * state: { count: 0 },\n * styles: `\n * button { padding: 0.5rem 1rem; }\n * `,\n * connected() {\n * console.log('Counter mounted');\n * },\n * render({ props, state, emit }) {\n * return html`\n * <button onclick=\"this.getRootNode().host.increment()\">\n * Count: ${state.count}\n * </button>\n * `;\n * },\n * });\n * ```\n */\nexport const component = <TProps extends Record<string, unknown>>(\n tagName: string,\n definition: ComponentDefinition<TProps>\n): void => {\n /**\n * Internal Web Component class created for each component definition.\n * @internal\n */\n class BQueryComponent extends HTMLElement {\n /** Internal state object for the component */\n private readonly state = { ...(definition.state ?? {}) };\n /** Typed props object populated from attributes */\n private props = {} as TProps;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n this.syncProps();\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n */\n static get observedAttributes(): string[] {\n return Object.keys(definition.props ?? {});\n }\n\n /**\n * Called when the element is added to the DOM.\n */\n connectedCallback(): void {\n definition.connected?.call(this);\n this.render();\n }\n\n /**\n * Called when the element is removed from the DOM.\n */\n disconnectedCallback(): void {\n definition.disconnected?.call(this);\n }\n\n /**\n * Called when an observed attribute changes.\n */\n attributeChangedCallback(): void {\n this.syncProps();\n this.render(true);\n }\n\n /**\n * Updates a state property and triggers a re-render.\n *\n * @param key - The state property key\n * @param value - The new value\n */\n setState(key: string, value: unknown): void {\n this.state[key] = value;\n this.render(true);\n }\n\n /**\n * Gets a state property value.\n *\n * @param key - The state property key\n * @returns The current value\n */\n getState<T = unknown>(key: string): T {\n return this.state[key] as T;\n }\n\n /**\n * Synchronizes props from attributes.\n * @internal\n */\n private syncProps(): void {\n const props = definition.props ?? {};\n for (const [key, config] of Object.entries(props) as [string, PropDefinition][]) {\n const attrValue = this.getAttribute(key);\n if (attrValue == null) {\n if (config.required && config.default === undefined) {\n throw new Error(`bQuery component: missing required prop \"${key}\"`);\n }\n (this.props as Record<string, unknown>)[key] = config.default ?? undefined;\n continue;\n }\n (this.props as Record<string, unknown>)[key] = coercePropValue(\n attrValue,\n config\n ) as TProps[keyof TProps];\n }\n }\n\n /**\n * Renders the component to its shadow root.\n * @internal\n */\n private render(triggerUpdated = false): void {\n /**\n * Emits a custom event from the component.\n */\n const emit = (event: string, detail?: unknown): void => {\n this.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, composed: true }));\n };\n\n if (!this.shadowRoot) return;\n\n const markup = definition.render({\n props: this.props,\n state: this.state,\n emit,\n });\n\n const styles = definition.styles ? `<style>${definition.styles}</style>` : '';\n this.shadowRoot.innerHTML = `${styles}${markup}`;\n\n if (triggerUpdated) {\n definition.updated?.call(this);\n }\n }\n }\n\n if (!customElements.get(tagName)) {\n customElements.define(tagName, BQueryComponent);\n }\n};\n"],"names":["coercePropValue","rawValue","config","type","parsed","normalized","callable","constructable","html","strings","values","acc","part","index","safeHtml","escapeMap","escape","value","char","component","tagName","definition","BQueryComponent","key","props","attrValue","triggerUpdated","emit","event","detail","markup","styles"],"mappings":"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"}
|