@petit-kit/scoped 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,534 @@
1
+ <br />
2
+
3
+ <p align="center">
4
+ <img src='https://github.com/petit-kit/scoped/blob/main/assets/logo.png?raw=true' width="400px" />
5
+ </p>
6
+ <br />
7
+ <br />
8
+
9
+ # Scoped - 0.0.1
10
+
11
+ ### A lightweight, framework-agnostic library for building web components with reactive state, bindings, lifecycle hooks, template-based rendering and plugins.
12
+
13
+ **4.1 Kb** Gzipped - **12.7kb** Minified
14
+
15
+ <br />
16
+
17
+ **Scoped** is a lightweight library designed to simplify the creation of web components.
18
+
19
+ Its main idea is to provide a minimal, framework-agnostic layer over the Custom Elements API, letting you build encapsulated, reusable UI components using a concise template syntax, reactive state, and straightforward binding mechanisms. With built-in lifecycle hooks and an extensible plugin system, Scoped empowers developers to efficiently build modern, reactive interfaces.
20
+
21
+ It encourages expressiveness and rapid prototyping, giving you fine-grained control and flexibility over your components without the overhead and complexity of traditional frameworks. Scoped lets you stay close to the platform while benefiting from reactivity, simple data flow, and composable patterns for creative and productive development.
22
+
23
+ <br />
24
+
25
+ - [Installation](#installation)
26
+ - [Getting started](#getting-started)
27
+ - [Component options](#component-options)
28
+ - [Setup function](#setup-function)
29
+ - [Templating](#templating)
30
+ - [State & Props](#state--props)
31
+ - [Effects](#effects)
32
+ - [Computed](#computed)
33
+ - [Custom events](#custom-events)
34
+ - [Event Delegation](#event-delegation)
35
+ - [Slots](#slots)
36
+ - [Lifecycle](#lifecycle)
37
+ - [Plugins](#plugins)
38
+
39
+ <br />
40
+ <br />
41
+
42
+ # Installation
43
+
44
+ ```bash
45
+ npm install @petit-kit/scoped
46
+ # or
47
+ yarn add @petit-kit/scoped
48
+ # or
49
+ pnpm install @petit-kit/scoped
50
+ ```
51
+
52
+ # Getting started
53
+
54
+ ```javascript
55
+ import { define } from '@petit-kit/scoped';
56
+
57
+ define(
58
+ 'c-slider',
59
+ {
60
+ props: { value: { type: Number, default: 0 } },
61
+ },
62
+ ({ link, emit, actions, host }) => {
63
+ link('value', 'value');
64
+
65
+ actions.handleChange = (event) => {
66
+ host.updateState({ value: event.target.valueAsNumber });
67
+ emit('on-change', { value: event.target.valueAsNumber });
68
+ };
69
+
70
+ return () => `
71
+ <div>
72
+ <input
73
+ type="range" min="0" max="100" step="1"
74
+ bind:value="value"
75
+ on:input="handleChange"
76
+ />
77
+ <c-number ref="number" bind:value="value"></c-number>
78
+ </div>
79
+ `;
80
+ }
81
+ );
82
+ ```
83
+
84
+ The `define()` function is used to declare a new component.
85
+
86
+ ```typescript
87
+ function define(
88
+ tagName: string,
89
+ options: ComponentOptions,
90
+ setup: SetupFunction
91
+ );
92
+ ```
93
+
94
+ It takes a `tagName` for naming the used tag, I recommend to prefix it with `c-` before.
95
+
96
+ ## Component options
97
+
98
+ For the `ComponentOptions` here the way to setup the component:
99
+
100
+ ```javascript
101
+ {
102
+ props: {
103
+ attributeName: {
104
+ type: Number|String|Boolean,
105
+ default: 0 // default value
106
+ }
107
+ },
108
+ styles: `c-slider { color: red; }`
109
+ plugins: [timerPlugin()], // an array of plugins
110
+ shadow: false // activate shadow DOM
111
+ }
112
+ ```
113
+
114
+ ## Setup function
115
+
116
+ The `SetupFunction` is run only once on mount and should return a function that return a template string.
117
+
118
+ ```typescript
119
+ ({ host, props, state, actions, refs, link }) => {
120
+ link('name', 'name)
121
+ host.setState('date', new Date())
122
+
123
+ actions.onMouseEnter = () => {
124
+ console.log('mouseEnter')
125
+ }
126
+
127
+ return () => `
128
+ <div
129
+ ref='container'
130
+ on:mouseEnter='onMouseEnter'
131
+ >
132
+ Hi ${props.name}, it's actually ${state.date}
133
+ </div>
134
+ `
135
+ }
136
+ ```
137
+
138
+ `host` is the component itself, it got those methods:
139
+
140
+ | Method | Description |
141
+ | --------------------------- | ------------------------------------------ |
142
+ | `host.setState(partial)` | Update state + full re-render |
143
+ | `host.updateState(partial)` | Update state, effects only (no re-render) |
144
+ | `host.setProps(partial)` | Update props programmatically |
145
+ | `host.scheduleUpdate()` | Schedule effects on next RAF |
146
+ | `host.update(fullRender)` | Force update (full or partial) |
147
+ | `host.forceRender()` | Force re-render even if template unchanged |
148
+ | `host.destroy()` | Clean up and run destroy callbacks |
149
+
150
+ ## Templating
151
+
152
+ Templates in this framework are just functions that return a string of HTML. Inside your setup function, you can return a function — known as the template function — that uses template literals for HTML generation.
153
+
154
+ ### Basic Example
155
+
156
+ ```typescript
157
+ return () => `
158
+ <div>
159
+ <h2>Hello, ${props.name}!</h2>
160
+ <button on:click="actions.addThing">Add thing</button>
161
+ </div>
162
+ `;
163
+ ```
164
+
165
+ ### Dynamic Content
166
+
167
+ Interpolation with `${...}` gives you access to state, props, or anything in closure:
168
+
169
+ ```typescript
170
+ return () => `
171
+ <ul>
172
+ ${state.items.map((item) => `<li>${item.title}</li>`).join('')}
173
+ </ul>
174
+ `;
175
+ ```
176
+
177
+ ### Event Handlers
178
+
179
+ Use `on:eventName="handler"` to bind events, where `handler` is a function from your `actions` object or setup context:
180
+
181
+ ```typescript
182
+ return () => `
183
+ <button on:click="actions.save">Save</button>
184
+ `;
185
+ ```
186
+
187
+ Arrow functions or direct expressions are not supported; you must use named action references.
188
+
189
+ ### Referencing DOM Elements
190
+
191
+ Use the `ref` attribute to assign references:
192
+
193
+ ```typescript
194
+ return () => `
195
+ <input ref="inputEl" type="text">
196
+ `;
197
+ ```
198
+
199
+ You can then access the element as `refs.inputEl` in your setup code or methods.
200
+
201
+ ### Bindings
202
+
203
+ Bindings let you connect the value of a DOM property or attribute to your component's state or props, making the element update reactively when the state changes, and optionally syncing changes back to your state.
204
+
205
+ #### Value Binding
206
+
207
+ For `<input>`, `<textarea>`, and `<select>`, use `bind:value="stateKey"` to bind the value to a property in your `state`. When the user edits the input, the component will automatically update that property.
208
+
209
+ ```typescript
210
+ return () => `
211
+ <input bind:value="message">
212
+ `;
213
+ ```
214
+
215
+ #### Supported Bindings
216
+
217
+ - `bind:text="stateKey"` - Binds textContent
218
+ - `bind:html="stateKey"` - Binds innerHTML
219
+ - `bind:value="stateKey"` — Binds the value property
220
+ - `bind:checked="isChecked"` — Binds the checked property of checkbox/radio
221
+ - `bind:prop="key"` — Generic property binding (any property, e.g. `bind:min`, `bind:max`)
222
+
223
+ #### Example: Checkbox
224
+
225
+ ```typescript
226
+ return () => `
227
+ <input type="checkbox" bind:checked="done">
228
+ <label>${state.done ? 'Complete' : 'Incomplete'}</label>
229
+ `;
230
+ ```
231
+
232
+ ## State & props
233
+
234
+ ### State
235
+
236
+ State is a plain object that belongs to your component instance. It is fully reactive and any time you update the state, your component can re-render or trigger effects.
237
+
238
+ You can update state in two main ways:
239
+
240
+ - `host.setState(partial)`: Merges the partial state and triggers a full re-render.
241
+ - `host.updateState(partial)`: Merges the partial state and only schedules effects/computed, but does NOT re-render the template.
242
+
243
+ ```typescript
244
+ // Initialize state in setup (optional)
245
+ host.setState({ count: 0, status: 'idle' });
246
+
247
+ // Update state & trigger re-render
248
+ actions.increment = () => {
249
+ host.setState({ count: state.count + 1 });
250
+ };
251
+
252
+ // Only update state silently without re-render
253
+ host.updateState({ status: 'busy' });
254
+ ```
255
+
256
+ State is always available via the `state` object you get in your setup function:
257
+
258
+ ```typescript
259
+ ({ state, host }) => {
260
+ // Access current state values
261
+ const current = state.count;
262
+ // Set state
263
+ host.setState({ count: current + 1 });
264
+ // ...
265
+ };
266
+ ```
267
+
268
+ ### Props
269
+
270
+ Props are values passed into your custom element as attributes or via programmatic updates. You define prop types/defaults in `props` on the component options.
271
+
272
+ Props are available as the `props` object in the setup function:
273
+
274
+ ```javascript
275
+ define(
276
+ 'c-my-thing',
277
+ {
278
+ props: {
279
+ value: { type: Number, default: 10 },
280
+ label: { type: String, default: 'Untitled' },
281
+ },
282
+ },
283
+ ({ props }) => {
284
+ return () => `
285
+ <p>Value: ${props.value}</p>
286
+ <span>${props.label}</span>
287
+ `;
288
+ }
289
+ );
290
+ ```
291
+
292
+ Props are always kept up to date with attribute changes, and updating props from the outside (or via `host.setProps(...)`) will trigger updates in your component.
293
+
294
+ **Two-way Binding:**
295
+
296
+ Scoped allows props <=> state syncing using the `link` helper:
297
+
298
+ ```typescript
299
+ ({ link }) => {
300
+ link('value', 'value'); // Binds prop 'value' with state 'value'
301
+ };
302
+ ```
303
+
304
+ This makes sure that when `props.value` changes from outside, your state updates, and when you change `state.value`, the prop and attribute reflect if configured.
305
+
306
+ **Programmatic prop updates:**
307
+
308
+ You can also change props from inside the component:
309
+
310
+ ```typescript
311
+ host.setProps({ value: 42 });
312
+ ```
313
+
314
+ This updates the prop, reflects it as an attribute if needed, and triggers all update lifecycle hooks.
315
+
316
+ Props are also automatically parsed from their attribute string values into the appropriate type, based on your definition (Number, Boolean, etc.), so you always work with type-safe values in your setup and template logic.
317
+
318
+ ## Effects
319
+
320
+ Effects are functions that run in response to reactive changes and can be used for side effects, subscriptions, or manual cleanup logic within your components.
321
+
322
+ ```typescript
323
+ // Run on every render
324
+ effect(() => console.log('Rendered'));
325
+
326
+ // Run once (empty deps)
327
+ effect(() => {
328
+ const sub = api.subscribe();
329
+ return () => sub.unsubscribe();
330
+ }, []);
331
+
332
+ // Run when deps change
333
+ effect(
334
+ (deps) => console.log('Count:', deps[0]),
335
+ () => [state.count]
336
+ );
337
+
338
+ // Manual cleanup
339
+ const cleanup = effect(() => {
340
+ /* ... */
341
+ });
342
+ cleanup();
343
+ ```
344
+
345
+ ## Computed
346
+
347
+ Computed values are memoized values used to derive data from state or props and automatically update when their dependencies change.
348
+
349
+ ```typescript
350
+ const fullName = computed(
351
+ () => `${state.firstName} ${state.lastName}`,
352
+ () => [state.firstName, state.lastName]
353
+ );
354
+ return () => `<p>Name: ${fullName()}</p>`;
355
+ ```
356
+
357
+ ## Custom events
358
+
359
+ ### Emit
360
+
361
+ To emit a custom event from your component, use `emit(name, detail?)`:
362
+
363
+ ```typescript
364
+ actions.handleButtonClick = () => {
365
+ host.emit('my-event', { message: 'Hello from the component!' });
366
+ };
367
+
368
+ return () => `<button on:click="handleButtonClick">Emit Event</button>`;
369
+ ```
370
+
371
+ **Listening to custom events in parent:**
372
+
373
+ ```javascript
374
+ <my-component id="c1"></my-component>
375
+ <script>
376
+ document.getElementById('c1').addEventListener('my-event', (e) => {
377
+ console.log('Received:', e.detail.message);
378
+ });
379
+ </script>
380
+ ```
381
+
382
+ ### Listen
383
+
384
+ You can use `listen` to subscribe to events on any EventTarget (automatically cleaned up on destroy):
385
+
386
+ ```typescript
387
+ onMount(() => {
388
+ // Listen to a custom event emitted by another component
389
+ listen(
390
+ someOtherElement, // can be `window`
391
+ 'my-event',
392
+ (e) => {
393
+ console.log('Got custom event with detail:', e.detail);
394
+ }
395
+ );
396
+ });
397
+ ```
398
+
399
+ ---
400
+
401
+ ### Event Delegation
402
+
403
+ `delegate` lets you efficiently handle events on descendants matching a selector:
404
+
405
+ ```typescript
406
+ onMount(() => {
407
+ delegate('click', '.item', (e, target) => {
408
+ console.log('Clicked item:', target.textContent);
409
+ target.classList.toggle('active');
410
+ });
411
+ });
412
+
413
+ return () => `
414
+ <ul>
415
+ <li class="item">Apple</li>
416
+ <li class="item">Banana</li>
417
+ <li class="item">Cherry</li>
418
+ </ul>
419
+ `;
420
+ ```
421
+
422
+ ## Slots
423
+
424
+ Slots allow you to render children inside your custom element, making it easy to compose interfaces or pass in dynamic content.
425
+
426
+ ### Basic Usage
427
+
428
+ By default, any child content placed inside your component tag will be rendered in the default slot:
429
+
430
+ ```html
431
+ <my-card>
432
+ <h2>Title goes here</h2>
433
+ <p>Some description or content.</p>
434
+ </my-card>
435
+ ```
436
+
437
+ In your component template, use:
438
+
439
+ ```typescript
440
+ return () => `
441
+ <div class="card">
442
+ <slot></slot> <!-- default slot -->
443
+ </div>
444
+ `;
445
+ ```
446
+
447
+ ### Named Slots
448
+
449
+ Named slots let your users provide content for specific areas:
450
+
451
+ ```html
452
+ <my-layout>
453
+ <div slot="sidebar">Sidebar content</div>
454
+ <div slot="main">Main content</div>
455
+ </my-layout>
456
+ ```
457
+
458
+ In your component:
459
+
460
+ ```typescript
461
+ return () => `
462
+ <aside><slot name="sidebar"></slot></aside>
463
+ <main><slot name="main"></slot></main>
464
+ `;
465
+ ```
466
+
467
+ ## Lifecycle
468
+
469
+ Lifecycle hooks let you run code at specific moments in the component's life, such as mount, update, or destruction.
470
+
471
+ | Method | Description |
472
+ | -------------------- | ------------------------ |
473
+ | `onMount(cb)` | After mount |
474
+ | `onDestroy(cb)` | On destroy |
475
+ | `onUpdate(cb)` | After each update |
476
+ | `onBeforeUpdate(cb)` | Before each update |
477
+ | `onFirstUpdate(cb)` | Once, after first render |
478
+ | `onPropsChanged(cb)` | When props change |
479
+
480
+ # Plugins
481
+
482
+ Scoped includes a set of optional plugins to extend or enhance component behavior. You can import any of these plugins and register them via the `plugins` option or the `use()` method.
483
+
484
+ **Available Plugins:**
485
+
486
+ - **morphPlugin**
487
+ Provides idiomorph-based DOM morphing for efficient, non-destructive updates.
488
+
489
+ - **devicePlugin**
490
+ Detects and reacts to device and input type changes (e.g., pointer type, hover support).
491
+
492
+ - **lenisPlugin**
493
+ Integrates the [Lenis](https://github.com/studio-freight/lenis) smooth scrolling library.
494
+
495
+ - **timerPlugin**
496
+ Adds easy interval, timeout, and requestAnimationFrame timers to your component logic.
497
+
498
+ - **windowPlugin**
499
+ Supplies window-level utilities such as window resize and scroll event listeners.
500
+
501
+ - **inViewPlugin**
502
+ Detects when an element is within the viewport and triggers handlers (uses IntersectionObserver).
503
+
504
+ - **mousePlugin**
505
+ Tracks mouse position, mouse events, and allows you to listen to wheel/pointer activity.
506
+
507
+ <!--
508
+ **(Commented-out/incomplete plugins):**
509
+ - contentPlugin
510
+ - lerpPlugin
511
+ - springPlugin
512
+ -->
513
+
514
+ **Usage Example:**
515
+
516
+ ```javascript
517
+ import { define } from '@petit-kit/scoped';
518
+ import { inViewPlugin, timerPlugin } from '@petit-kit/scoped/plugins';
519
+
520
+ define(
521
+ 'my-component',
522
+ {
523
+ plugins: [inViewPlugin(), timerPlugin()],
524
+ },
525
+ ({ inView, timer }) => {
526
+ // Use provided plugin APIs in your setup function
527
+ // ...
528
+ }
529
+ );
530
+ ```
531
+
532
+ All plugins are tree-shakeable—import only what you need.
533
+
534
+ See plugin API docs or source code for available methods and options for each plugin.
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";function t(t,e){if(!e||"object"!=typeof e||null==e.type)return null!=t?t:e;const{type:s,default:i}=e;if(null==t)return i;try{switch(s){case String:return String(t);case Number:{const e=Number(t);return Number.isNaN(e)?i:e}case Boolean:return""===t||"true"===t||"false"!==t&&"0"!==t&&null!=t;case Object:try{return"string"==typeof t?JSON.parse(t):t}catch{return i}case Array:try{return"string"==typeof t?JSON.parse(t):t}catch{return Array.isArray(i)?i:[]}default:return t}}catch{return i}}function e(t,e,s,i){if(!i||"object"!=typeof i||!i.reflect)return;let n=null;const o=i.type;if(o===Boolean)return s?void t.setAttribute(e,""):void t.removeAttribute(e);if(o===Object||o===Array)try{n=null==s?null:JSON.stringify(s)}catch{n=null}else n=null==s?null:String(s);null==n?t.removeAttribute(e):t.setAttribute(e,n)}const s="0.0.1",i=/\{([A-Za-z_$][\w$]*)\}/g;exports.SCOPE_VERSION=s,exports.define=function(n,o={},r){const{props:h={},shadow:c=!1,styles:f,plugins:u}=o,l=u??[],a=()=>{};class d extends HTMLElement{constructor(){super(),this.version=s,this.t={};for(const t of Object.keys(h)){const e=h[t];this.t[t]=e&&"object"==typeof e&&("type"in e||"default"in e)?e:{type:void 0,default:e,reflect:!1}}this.props={},this.state={},this.actions={},this.refs={},this.emit=this.emit.bind(this),this.listen=this.listen.bind(this),this.setState=this.setState.bind(this),this.updateState=this.updateState.bind(this),this.setProps=this.setProps.bind(this),this.scheduleUpdate=this.scheduleUpdate.bind(this),this.update=this.update.bind(this),this.forceRender=this.forceRender.bind(this),this.destroy=this.destroy.bind(this),this.i=null,this.o=null,this.h=!1,this.u=!1,this.l=c,this.p=c?this.attachShadow({mode:"open"}):this,this.m=null,this.S=[],this.v=[],this._=[],this.O=[],this.j=[],this.M=[],this.A=[],this.$=[],this.k=new Map,this.F=!1,this.T=!1,this.C={},this.H=!1,this.I=n,this.R=!1,this.U=new Set,this.q=!1,this.B=new Map,this.L=0,this.N=!1}V(t){const e=this.l?this.p.host:this;let s=t.parentElement;for(;s;){if(s===e)return!1;if(s.tagName.includes("-"))return!0;s=s.parentElement}return!1}static get observedAttributes(){return Object.keys(h)}attributeChangedCallback(e,s,i){if(s===i)return;const n=this.t[e],o=this.C[e],r=t(i,n);if(this.props[e]=r,this.F&&o!==r)for(const t of this.$)try{t(e,o,r)}catch(t){a(String(t?.message||t))}this.C[e]=r,this.U.has(e)?this.U.delete(e):this.i&&this.isConnected?this.q?this.R=!0:this.update(!0):this.R=!0}connectedCallback(){for(const e in this.t){if(!this.t.hasOwnProperty(e))continue;const s=t(this.getAttribute(e),this.t[e]);this.props[e]=s,this.C[e]=s}c||this.m||(this.m=this.J());let s=null;try{if(r){const t={props:this.props,state:this.state,actions:this.actions,refs:this.refs,emit:this.emit,listen:this.listen,updateState:this.updateState.bind(this),host:this,onMount:t=>this._.push(t),onDestroy:t=>this.O.push(t),onUpdate:t=>this.j.push(t),onBeforeUpdate:t=>this.M.push(t),onFirstUpdate:t=>this.A.push(t),onPropsChanged:t=>this.$.push(t),link:(t,s)=>{const i=s||t;this.state[i]=this.props[t],this.$.push((e,s,n)=>{e===t&&(Object.is(this.state[i],n)||(this.state[i]=n))});const n={fn:()=>{const s=this.state[i];if(Object.is(this.props[t],s))return;this.props[t]=s,this.C[t]=s;const n=this.t[t],o=n?{...n,reflect:!0}:n,r=this.getAttribute(t);this.U.add(t),e(this,t,s,o),r===this.getAttribute(t)&&this.U.delete(t)},deps:()=>[this.state[i]]};this.S.push(n)},computed:(t,e)=>{let s;if(void 0!==e)try{const t="function"==typeof e?e():e;Array.isArray(t)&&(s=t)}catch(t){String(t?.message||t)}const i={getter:t,deps:e,value:void 0!==e?t(s):t()};this.v.push(i);const n=()=>i.value;return n.P=i,this.W(n),n},effect:(t,e)=>{const s={fn:t,deps:e};return this.S.push(s),()=>this.D(s)},delegate:(t,e,s)=>(this.Z(t,e,s),()=>this.G(t,e,s))};for(const e of l)if(e)try{const s=e.extend(t,this);s&&"object"==typeof s&&Object.assign(t,s)}catch(t){a(String(t?.message||t))}s=r(t)}}catch(t){String(t?.message||t)}if(this.i="function"!=typeof s?()=>"":s,this.q=!0,this.update(!0),this.q=!1,this.R&&(this.R=!1,this.update(!0)),!this.F){this.F=!0;for(const t of this._)try{t()}catch(t){a(String(t?.message||t))}}}disconnectedCallback(){this.destroy()}remove(){super.remove()}destroy(){for(const t of this.O)try{t()}catch(t){a(String(t?.message||t))}for(const t of this.S)if(t.cleanup){try{t.cleanup()}catch(t){a(String(t?.message||t))}t.cleanup=void 0}for(const[,t]of this.k)try{this.p.removeEventListener(t.eventType,t.listener)}catch{}this.k.clear(),this.F=!1}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}listen(t,e,s,i){const n=s;t.addEventListener(e,n,i);const o=()=>{try{t.removeEventListener(e,n,i)}catch{}};return this.O.push(o),o}setState(t){let e=!1;const s=t,i=this.state;for(const t in s){if(!Object.prototype.hasOwnProperty.call(s,t))continue;const n=s[t];Object.is(i[t],n)||(i[t]=n,e=!0)}if(e)if(this.q||!this.F)this.update(!0);else{if(!this.i||!this.isConnected)return;if(this.h)return;this.h=!0,requestAnimationFrame(()=>{this.h=!1,this.i&&this.isConnected&&this.update(!0)})}}updateState(t){Object.assign(this.state,t),this.i&&this.isConnected&&this.K()}setProps(t){const s=Object.keys(t);if(0===s.length)return;const i=[];for(const n of s){const s=t[n],o=this.C[n];this.props[n]=s,this.F&&o!==s&&i.push(n);const r=this.t[n];r&&r.reflect&&e(this,n,s,r),this.F&&o===s||(this.C[n]=s)}if(this.F&&i.length>0)for(const e of i){const s=this.C[e],i=t[e];for(const t of this.$)try{t(e,s,i)}catch(t){a(String(t?.message||t))}}this.i&&this.isConnected?this.update(!0):this.R=!0}scheduleUpdate(){this.i&&this.isConnected&&this.K()}K(){this.u||this.h||(this.u=!0,("function"==typeof queueMicrotask?queueMicrotask:t=>Promise.resolve().then(t))(()=>{this.u=!1,this.i&&this.isConnected&&(this.h||this.update(!1))}))}update(t){if(this.i){if(t&&this.F)for(const t of this.M)try{t()}catch(t){a(String(t?.message||t))}if(t){this.X();let t="";try{t=this.i()}catch(e){String(e?.message||e),t=""}if("string"!=typeof t&&(t=null==t?"":String(t)),t=((t,e)=>{const s={...this.props,...e};return t.replace(i,(t,e)=>{const i=s[e];return null==i?"":String(i)})})(t,this.state),!this.l){const e=`data-scope-owner="${this.I}"`;t=t.replace(/<slot(?![^>]*data-scope-owner)(\s|>)/g,`<slot ${e}$1`)}this.N=!1;const e=null!==this.o&&Object.is(this.o,t);let s=!1;e&&this.F||(this.l,this.p.innerHTML=t,this.o=t,s=!0),this.q?(this.Y(),("function"==typeof requestAnimationFrame?requestAnimationFrame:t=>setTimeout(t,0))(()=>{this.i&&this.isConnected&&(s&&!c&&this.projectSlots(),s&&this.tt(),this.et(),this.st())})):(s&&!c&&this.projectSlots(),s&&this.it(),this.et(),this.st())}else this.N&&this.X(),this.et(),this.F&&this.st()}}forceRender(){this.o=null,this.i&&this.isConnected?this.q?this.R=!0:this.update(!0):this.R=!0}st(){if(!this.T){this.T=!0;for(const t of this.A)try{t()}catch(t){a(String(t?.message||t))}}for(const t of this.j)try{t()}catch(t){a(String(t?.message||t))}this.nt()}nt(){const t=(this.l?this.p:this).querySelectorAll("*"),e=Object.prototype.hasOwnProperty,s=this.state,i=this.props;this.actions;for(let n=0;n<t.length;n++){const o=t[n];if(this.V(o))continue;if(0===o.attributes.length)continue;const r=o.attributes;for(let t=r.length-1;t>=0;t--){const n=r[t];if(!n.name.startsWith("bind:"))continue;const h=n.name.slice(5),c=n.value,f=c?c.trim():"";let u,l=!1;if(f){const t=this.B.get(f);if(t){t.P&&(this.N=!0);try{u=t()}catch{}l=!0}}if(!l){const t=f||h,n=e.call(s,t),o=!n&&e.call(i,t);n?u=s[t]:o&&(u=i[t])}if("text"===h){const t=null==u?"":String(u);o.textContent!==t&&(o.textContent=t)}else if("html"===h){const t=null==u?"":String(u);o.innerHTML!==t&&(o.innerHTML=t)}else if(h in o){if(!Object.is(o[h],u))try{o[h]=u}catch{}if("value"===h)try{null==u?o.removeAttribute("value"):o.setAttribute("value",String(u))}catch{}}else if(null!=u)try{o.setAttribute(h,String(u))}catch{}const a=`__scopeBind_${h}`,d=o[a];if(d){const t=d.ot;t&&o.removeEventListener(t,d),delete o[a]}}}}X(){for(const t of this.v){let e,s=!0;if(void 0!==t.deps)try{const i="function"==typeof t.deps?t.deps():t.deps;if(Array.isArray(i)&&(e=i,t.prevDeps&&t.prevDeps.length===e.length)){s=!1;for(let i=0;i<e.length;i++)if(!Object.is(t.prevDeps[i],e[i])){s=!0;break}}}catch(t){a(String(t?.message||t)),s=!0,e=void 0}if(s){try{t.value=void 0!==t.deps?t.getter(e):t.getter()}catch(t){a(String(t?.message||t))}e&&(t.prevDeps=e.slice())}}}et(){for(const t of this.S){let e,s=!0;if(void 0!==t.deps)try{const i="function"==typeof t.deps?t.deps():t.deps;if(Array.isArray(i)&&(e=i,t.prevDeps&&t.prevDeps.length===e.length)){s=!1;for(let i=0;i<e.length;i++)if(!Object.is(t.prevDeps[i],e[i])){s=!0;break}}}catch(t){a(String(t?.message||t)),s=!0,e=void 0}if(s){if(t.cleanup){try{t.cleanup()}catch{}t.cleanup=void 0}try{const s=void 0!==t.deps?t.fn(e):t.fn();"function"==typeof s&&(t.cleanup=s)}catch{}e&&(t.prevDeps=e.slice())}}}D(t){const e=this.S.indexOf(t);if(-1!==e){if(t.cleanup)try{t.cleanup()}catch{}this.S.splice(e,1)}}W(t){const e=t.rt;if(e&&"string"==typeof e)return this.B.set(e,t),e;const s=`__scope_bind_${++this.L}__`;this.B.set(s,t);try{t.rt=s,t.toString=()=>s}catch{}return s}Y(){const t=(this.l?this.p:this).querySelectorAll("[ref]"),e=this.refs;for(const t in e)e.hasOwnProperty(t)&&delete e[t];if(0!==t.length)for(let s=0;s<t.length;s++){const i=t[s];if(this.V(i))continue;const n=i.getAttribute("ref");n&&(e[n]?Array.isArray(e[n])?e[n].push(i):e[n]=[e[n],i]:e[n]=i)}}tt(){const t=(this.l?this.p:this).querySelectorAll("*");for(let e=0;e<t.length;e++){const s=t[e];if(this.V(s))continue;if(0===s.attributes.length)continue;const i=s.attributes;for(let t=i.length-1;t>=0;t--){const e=i[t];if(!e.name.startsWith("on:"))continue;const n=e.name.slice(3),o=e.value,r=`__tinyHandler_${n}`,h=s[r];h&&s.removeEventListener(n,h),s.removeAttribute(e.name);const c=this.actions[o];if(c&&"function"==typeof c){const t=t=>{c.call(this.actions,t)};s[r]=t,s.addEventListener(n,t)}}}}it(){const t=(this.l?this.p:this).querySelectorAll("*"),e=this.refs;for(const t in e)e.hasOwnProperty(t)&&delete e[t];for(let s=0;s<t.length;s++){const i=t[s];if(this.V(i))continue;const n=i.getAttribute("ref");if(n&&(e[n]?Array.isArray(e[n])?e[n].push(i):e[n]=[e[n],i]:e[n]=i),i.attributes.length>0){const t=i.attributes;for(let e=t.length-1;e>=0;e--){const s=t[e];if(!s.name.startsWith("on:"))continue;const n=s.name.slice(3),o=s.value,r=`__tinyHandler_${n}`,h=i[r];h&&i.removeEventListener(n,h),i.removeAttribute(s.name);const c=this.actions[o];if(c&&"function"==typeof c){const t=t=>{c.call(this.actions,t)};i[r]=t,i.addEventListener(n,t)}}}}}J(){const t=new Map,e=this.childNodes,s=[];for(let t=0;t<e.length;t++)s.push(e[t]);for(let e=0;e<s.length;e++){const i=s[e];let n="";1===i.nodeType&&i.getAttribute&&(n=i.getAttribute("slot")||""),t.has(n)||t.set(n,[]),t.get(n).push(i)}for(let t=0;t<s.length;t++){const e=s[t];e.parentNode&&e.parentNode.removeChild(e)}return t}projectSlots(){const t=this.m||new Map,e=(this.l?this.p:this).querySelectorAll(`slot[data-scope-owner="${this.I}"]`);if(0!==e.length)for(let s=0;s<e.length;s++){const i=e[s],n=i.getAttribute("name")||"",o=t.get(n)||[];if(o.length){const t=document.createDocumentFragment();for(let e=0;e<o.length;e++){const s=o[e];let i;if(1===s.nodeType&&s.tagName.includes("-")&&s.m instanceof Map){const t=s,e=document.createElement(t.tagName.toLowerCase());for(let s=0;s<t.attributes.length;s++){const i=t.attributes[s];e.setAttribute(i.name,i.value)}for(const s of t.m.values())for(let t=0;t<s.length;t++)e.appendChild(s[t].cloneNode(!0));i=e}else i=s.cloneNode(!0);t.appendChild(i)}i.replaceWith(t)}else{const t=i.childNodes,e=[];for(let s=0;s<t.length;s++)e.push(t[s]);if(e.length>0){const t=document.createDocumentFragment();for(let s=0;s<e.length;s++)t.appendChild(e[s]);i.replaceWith(t)}}}}Z(t,e,s){const i=`${t}::${e}`;let n=this.k.get(i);if(!n){const s=t=>{const s=t.target&&t.target.closest?t.target.closest(e):null;if(s)for(const e of n.handlers)try{e(t,s)}catch{}};n={eventType:t,selector:e,listener:s,handlers:new Set},this.k.set(i,n),this.p.addEventListener(t,s)}n.handlers.add(s)}G(t,e,s){const i=`${t}::${e}`,n=this.k.get(i);if(n&&(n.handlers.delete(s),0===n.handlers.size)){try{this.p.removeEventListener(t,n.listener)}catch{}this.k.delete(i)}}}if(!customElements.get(n)){if(f&&"undefined"!=typeof document){const t=`scope-${n}-styles`;if(!document.getElementById(t)){const e=document.createElement("style");e.id=t,e.textContent=f,document.head.appendChild(e)}}try{customElements.define(n,d)}catch(t){String(t?.message||t)}}return d},exports.devicePlugin=()=>({name:"device",extend:t=>{const e=new Map;return t.onDestroy(()=>{for(const[t,s]of e)t.removeEventListener("change",s);e.clear()}),{onMediaQuery:(t,s,i={})=>{if("undefined"==typeof window||"undefined"==typeof matchMedia)return()=>{};const{immediate:n=!0}=i,o=matchMedia(t),r=t=>{s(t.matches,t)};return o.addEventListener("change",r),e.set(o,r),n&&s(o.matches,null),()=>{o.removeEventListener("change",r),e.delete(o)}}}}}),exports.inViewPlugin=()=>({name:"inview",extend:(t,e)=>{const s=new Set,i=(t,e,i={})=>{if("undefined"==typeof window||"undefined"==typeof IntersectionObserver)return()=>{};const{immediate:n=!0,...o}=i;let r=!n;const h=new IntersectionObserver(s=>{for(const i of s)i.target===t&&(r?r=!1:e(i.isIntersecting,i))},o);return h.observe(t),s.add(h),()=>{h.unobserve(t),h.disconnect(),s.delete(h)}};return t.onDestroy(()=>{for(const t of s)t.disconnect();s.clear()}),{onInView:(t,s)=>i(e,t,s),observeInView:(t,e,s)=>i(t,e,s)}}}),exports.lenisPlugin=t=>({name:"lenis",extend:e=>{const s=new Set;return e.onDestroy(()=>{for(const{lenis:t,handler:e}of s)"function"==typeof t.off&&t.off("scroll",e);s.clear()}),{onLenisScroll:e=>{const i=t();if(!i)return()=>{};const n=t=>{e(t)};i.on("scroll",n);const o={lenis:i,handler:n};return s.add(o),()=>{s.has(o)&&(s.delete(o),"function"==typeof i.off&&i.off("scroll",n))}}}}}),exports.morphPlugin=(t,e={})=>({name:"morph",extend:(s,i)=>{const{ignoreActiveValue:n=!0,callbacks:o}=e,r=t(),h=i,c=h.p,f=h.l?ShadowRoot.prototype:HTMLElement.prototype,u=Object.getOwnPropertyDescriptor(f,"innerHTML"),l=t=>{r.morph(c,t,{morphStyle:"innerHTML",ignoreActiveValue:n,callbacks:o})};let a=!0;return Object.defineProperty(c,"innerHTML",{set(t){a?(u.set.call(this,t),a=!1):l(t)},get(){return u.get.call(this)},configurable:!0}),s.onDestroy(()=>{delete c.innerHTML}),{morph:l}}}),exports.mousePlugin=()=>({name:"mouse",extend:t=>{const e=new Map,s=(t,s)=>{if("undefined"==typeof window)return()=>{};const i=t=>{const e=t;s(e.clientX,e.clientY,e)};window.addEventListener(t,i);let n=e.get(t);return n||(n=new Set,e.set(t,n)),n.add(i),()=>{window.removeEventListener(t,i),n?.delete(i)}};return t.onDestroy(()=>{if("undefined"!=typeof window){for(const[t,s]of e){for(const e of s)window.removeEventListener(t,e);s.clear()}e.clear()}}),{onMouseMove:t=>s("mousemove",t),onMouseDown:t=>s("mousedown",t),onMouseUp:t=>s("mouseup",t),onMouseWheel:t=>(t=>{if("undefined"==typeof window)return()=>{};const s=e=>{const s=e;t(s.clientX,s.clientY,s.deltaY,s)};window.addEventListener("wheel",s);let i=e.get("wheel");return i||(i=new Set,e.set("wheel",i)),i.add(s),()=>{window.removeEventListener("wheel",s),i?.delete(s)}})(t)}}}),exports.timerPlugin=()=>({name:"timer",extend:t=>{const e=new Set,s=new Set,i=new Set,n={setTimeout:(t,s,...i)=>{let n;return n=setTimeout((...s)=>{e.delete(n),t(...s)},s,...i),e.add(n),n},setInterval:(t,e,...i)=>{const n=setInterval(t,e,...i);return s.add(n),n},raf:(t,e)=>{let s=0,n=!0,o=0;const r="number"==typeof e&&e>0?1e3/e:0,h=e=>{if(i.delete(s),n){if(r){if(e-o>=r){const s=o?e-o:r;o=e,t(e,s)}}else{const s=o?e-o:0;o=e,t(e,s)}s=requestAnimationFrame(h),i.add(s)}};return s=requestAnimationFrame(h),i.add(s),()=>{n&&(n=!1,i.delete(s),cancelAnimationFrame(s))}}};return t.onDestroy(()=>{for(const t of e)clearTimeout(t);e.clear();for(const t of s)clearInterval(t);s.clear();for(const t of i)cancelAnimationFrame(t);i.clear()}),{timer:n}}}),exports.windowPlugin=()=>({name:"window",extend:t=>{const e=new Set,s=new Set,i=(t,s={})=>{if("undefined"==typeof window)return()=>{};const{immediate:i=!0}=s,n=e=>{t(window.innerWidth,window.innerHeight,e)};return window.addEventListener("resize",n),e.add(n),i&&n(new UIEvent("resize")),()=>{window.removeEventListener("resize",n),e.delete(n)}};return t.onDestroy(()=>{if("undefined"!=typeof window){for(const t of e)window.removeEventListener("resize",t);e.clear();for(const t of s)t.disconnect();s.clear()}}),{onViewportResize:i,onWindowResize:(t,e={})=>{if("undefined"==typeof window)return()=>{};if("undefined"==typeof ResizeObserver)return i((e,s,i)=>t(e,s,i),e);const{immediate:n=!0}=e,o=document.documentElement,r=new ResizeObserver(e=>{const s=e[0];if(!s)return;const{width:i,height:n}=s.contentRect;t(i,n,s)});if(r.observe(o),s.add(r),n){const e=o.getBoundingClientRect();t(e.width,e.height,new UIEvent("resize"))}return()=>{r.disconnect(),s.delete(r)}}}}});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}