spikijs 1.1.24 → 1.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,526 +1,307 @@
1
- # Spikijs
1
+ # SpikiJS
2
2
 
3
- Spikijs is a lightweight (~5KB), high-performance JavaScript framework for building interactive interfaces. It works directly with your HTML (no build step required) and uses ES6 Proxies for reactive state management.
3
+ SpikiJS is a lightweight (~5KB), high-performance JavaScript framework for building reactive web applications directly in your HTML without build tools. It utilizes ES6 Proxies for fine-grained reactivity and adheres to a strict Content Security Policy (CSP).
4
4
 
5
- It is designed to be simple, secure (CSP Compliant), and fast.
5
+ ---
6
6
 
7
7
  ## Key Features
8
8
 
9
- * **Tiny Footprint:** Around 5KB gzip. No complex bundlers needed.
10
- * **Zero Inline Logic:** You cannot write JavaScript logic in HTML attributes (e.g., `count++` is forbidden). This enforces clean separation of concerns and complies with strict Content Security Policies (CSP).
11
- * **Deep Reactivity:** Automatically tracks changes in nested objects and arrays using Proxies.
12
- * **Memory Safe:** Explicit `mount()` and `unmount()` methods prevent memory leaks in Single Page Applications.
9
+ - **Tiny Footprint:** Only ~5KB gzip. Works directly in HTML without build tools.
10
+ - **100% CSP Secure:** Safe execution without `eval()` or inline expression vulnerabilities.
11
+ - **Deep Reactivity:** Automatic tracking for nested objects & arrays using ES6 Proxies.
12
+ - **Full SVG Support:** Dynamic attributes and `:class` binding work seamlessly on HTML and SVG.
13
+ - **Auto Loop Context:** `s-for` automatically provides `this.item` and `this.index` in event handlers.
14
+ - **Global Store + `init()`:** Shared state store that automatically runs an `init()` method on registration.
15
+ - **Memory Safe:** Built-in `mount()` and `unmount()` methods to prevent SPA memory leaks.
13
16
 
14
17
  ---
15
18
 
16
- ## Installation
19
+ ## Directive Rules & CSP Security
17
20
 
18
- ### CDN (Browser)
19
- Simply add the script tag to your HTML. Spiki will automatically attach to `window.spiki`.
21
+ SpikiJS enforces strict security and architectural separation of concerns:
20
22
 
21
- ```html
22
- <script src="https://unpkg.com/spikijs"></script>
23
+ 1. **No Inline JS Code:** HTML attributes cannot contain JavaScript code, expressions, or operators (e.g. `count++` or `a + b` are invalid).
24
+ - **Allowed Exception:** Boolean directives (`s-if`, `:hidden`, `:disabled`, `:checked`) evaluate state property names directly or with a logical NOT (`!`) operator (e.g. `s-if="isReady"` or `:hidden="!isVisible"`).
23
25
 
24
- ```
26
+ 2. **No Attribute Parameters:** Function parameters are not supported inside HTML attributes (e.g. `s-click="save(item)"` is invalid).
27
+ - **Correct Pattern:** Bind only the method name (`s-click="save"`). Inside loop templates, Spiki automatically injects context variables directly into `this` (e.g. `this.item`, `this.index`).
25
28
 
26
- ### NPM (Module)
27
-
28
- Install via package manager.
29
-
30
- ```bash
31
- npm install spikijs
32
-
33
- ```
29
+ 3. **State Access via `this`:** All data reading and state mutations must be performed inside component methods using the `this` context (e.g. `this.count++`).
34
30
 
35
31
  ---
36
32
 
37
- ## Usage Strategies
38
-
39
- Choose the initialization method that fits your architecture.
40
-
41
- ### Automatic
42
-
43
- Best for simple websites. Spiki scans the entire document for `s-data` attributes.
44
-
45
- **HTML:**
46
-
47
- ```html
48
- <div s-data="counterApp">
49
- Count: <span s-text="count"></span>
50
- <button s-click="increment">+</button>
51
- </div>
52
-
53
- ```
54
-
55
- **JavaScript:**
56
-
57
- ```javascript
58
- import spiki from 'spikijs';
59
-
60
- // 1. Register Component
61
- spiki.data('counterApp', () => ({
62
- count: 0,
63
- increment() {
64
- this.count++;
65
- }
66
- }));
67
-
68
- // 2. Start Engine (Scans the whole body)
69
- spiki.start();
70
-
71
- ```
72
-
73
- ### Manual Mount
74
-
75
- You control exactly *when* and *where* Spiki starts, and crucially, when it stops to free memory.
33
+ ## Installation
76
34
 
77
- **HTML:**
35
+ ### CDN (Browser)
36
+ Include SpikiJS via script tag. Spiki automatically exposes `window.spiki`:
78
37
 
79
38
  ```html
80
- <div id="my-widget" s-data="counterApp">
81
- Count: <span s-text="count"></span>
82
- <button s-click="increment">+</button>
83
- </div>
84
-
39
+ <script src="https://unpkg.com/spikijs"></script>
85
40
  ```
86
41
 
87
- **JavaScript:**
42
+ ### ESM Module (Modern Browsers / NPM)
43
+ Import SpikiJS directly as an ES module:
88
44
 
89
45
  ```javascript
90
- import spiki from 'spikijs';
91
-
92
- // 1. Register Component logic
93
- spiki.data('counterApp', () => ({
94
- count: 0,
95
- increment() {
96
- this.count++;
97
- }
98
- }));
99
-
100
- // 2. Select the DOM element
101
- const myWidget = document.getElementById('my-widget');
102
-
103
- // 3. Mount Spiki to this specific element
104
- const counterApp = spiki.mount(myWidget);
105
-
106
- // ... later when removing the element or changing pages ...
107
- // 4. Unmount to free memory (Stop watchers and event listeners)
108
- // counterApp.unmount();
109
-
46
+ import spiki from './spikijs/spiki.esm.js';
110
47
  ```
111
48
 
112
49
  ---
113
50
 
114
- ## Quick Start
115
-
116
- 1. **Define HTML**: Add `s-data` to a container.
117
- 2. **Define Logic**: Use `spiki.data()`.
118
- 3. **Start Engine**: Call `spiki.start()`.
119
-
120
- ```html
121
- <div s-data="counterApp">
122
- <h1>Count: <span s-text="count"></span></h1>
123
- <button s-click="increment">Add +1</button>
124
- <button s-click="decrement">Del -1</button>
125
- </div>
126
-
127
- <script src="https://unpkg.com/spikijs"></script>
128
- <script>
129
- // 1. Register Component
130
- spiki.data('counterApp', () => ({
131
- count: 0,
132
- increment() {
133
- this.count++;
134
- },
135
- decrement() {
136
- this.count--;
137
- }
138
- }));
139
-
140
- // 2. Start Spiki
141
- document.addEventListener('DOMContentLoaded', () => {
142
- spiki.start();
143
- });
144
- </script>
145
-
146
- ```
51
+ ## Directives & API Reference
52
+
53
+ | Directive / API | Description | Example |
54
+ | :--- | :--- | :--- |
55
+ | **`s-data`** | Defines component state scope. | `<div s-data="myApp">` |
56
+ | **`s-text`** | Sets safe text content. | `<span s-text="username"></span>` |
57
+ | **`s-html`** | Sets inner HTML (XSS caution). | `<div s-html="richText"></div>` |
58
+ | **`s-if`** | Conditionally mounts/unmounts DOM nodes (supports `!`). | `<div s-if="!isOnline">Offline</div>` |
59
+ | **`:hidden`** | Toggles native `hidden` visibility (replaces `s-show`, supports `!`). | `<div hidden :hidden="!isVisible">Content</div>` |
60
+ | **`s-for`** | Loops array items inside `<template>` tags. | `<template s-for="(item, idx) in list" s-key="id">` |
61
+ | **`s-key`** | Unique key tracking for list items. | `<template ... s-key="id">` |
62
+ | **`s-model`** | Two-way input data binding. | `<input s-model="query">` |
63
+ | **`s-value`** | One-way value binding. | `<input s-value="formattedText" readonly>` |
64
+ | **`s-effect`** | Automatic reactive watcher (runs on state mutations). | `<div s-effect="saveToStorage">` |
65
+ | **`s-ref`** | Registers DOM element reference in `this.$refs`. | `<input s-ref="textInput">` |
66
+ | **`s-init`** | Executes hook on component mount. | `<div s-init="onMount">` |
67
+ | **`s-destroy`** | Executes hook on component unmount. | `<div s-destroy="onUnmount">` |
68
+ | **`s-ignore`** | Skips DOM compilation for static blocks. | `<div s-ignore>` |
69
+ | **`:[attr]`** | Binds dynamic attributes (HTML & SVG). | `<img :src="userAvatar">` |
70
+ | **`:class`** | Binds dynamic classes (HTML & SVG). | `<div :class="activeClass">` |
71
+ | **`s-[event]`** | Attaches event listener (`s-click`, `s-keyup`, etc.). | `<button s-click="submitForm">` |
72
+ | **`this.$root`** | Accesses component's root container element. | `this.$root.classList.add('active');` |
73
+ | **`this.$refs`** | Object containing all `s-ref` DOM elements. | `this.$refs.textInput.focus();` |
74
+ | **`this.$store`** | Accesses registered global stores. | `this.$store.settings.theme` |
75
+ | **`spiki.store()`** | Registers global store (runs `init()` automatically if present). | `spiki.store('settings', { theme: 'dark', init() {} })` |
76
+ | **`spiki.raw()`** | Unwraps Spiki Proxy to a plain JavaScript object. | `const plainObj = spiki.raw(this.user);` |
147
77
 
148
78
  ---
149
79
 
150
- ## Directives Reference
151
-
152
- | Directive | Description | Example |
153
- | --- | --- | --- |
154
- | **`s-data`** | Defines component scope. | `<div s-data="app">` |
155
- | **`s-text`** | Sets text content (Safe). | `<span s-text="msg">` |
156
- | **`s-html`** | Sets innerHTML (Use carefully). | `<div s-html="htmlContent">` |
157
- | **`s-if`** | Conditional rendering. | `<p s-if="showMe">` |
158
- | **`s-for`** | Loops content (requires `<template>`). | `<template s-for="item in list">` |
159
- | **`s-key`** | Unique key for loops (Performance). | `<template ... s-key="id">` |
160
- | **`s-model`** | Two-way binding (Inputs). | `<input s-model="text">` |
161
- | **`s-value`** | One-way value binding. | `<input s-value="text">` |
162
- | **`s-effect`** | Runs function on data change. | `<div s-effect="autoSave">` |
163
- | **`s-ref`** | Stores DOM reference in `$refs`. | `<input s-ref="myInput">` |
164
- | **`s-init`** | Runs on mount. | `<div s-init="onLoad">` |
165
- | **`s-destroy`** | Runs on unmount. | `<div s-destroy="onRemove">` |
166
- | **`s-ignore`** | Skips compilation (Static content). | `<div s-ignore>` |
167
- | **`:[attr]`** | Dynamic attribute binding. | `<img :src="imgUrl">` |
168
- | **`:class`** | Dynamic class toggling. | `<div :class="classConfig">` |
169
- | **`s-[event]`** | Event listener. | `<button s-click="save">` |
170
- | **`this.$root`** | Access the root elm. | `this.$root.classList.add('loaded');` |
171
- | **`this.$store`** | Access the global store. | `this.$store.theme` |
172
- | **`spiki.store()`** | Get or set global store. | `spiki.store('theme', 'dark')` |
173
- | **`spiki.raw()`** | Proxy to original object. | `spiki.raw(this.users)` |
80
+ ## Detailed Feature Documentation
174
81
 
175
- ---
82
+ ### 1. Conditional Rendering (`s-if`) & Visibility (`:hidden`)
176
83
 
177
- ## Detailed Usage Examples
84
+ SpikiJS provides two ways to control element display:
178
85
 
179
- ### 1. Displaying Data (`s-text`)
86
+ - **`s-if`**: Completely mounts or unmounts the element from the DOM tree. Supports negation (`!`).
87
+ - **`:hidden`**: Replaces traditional `s-show` by toggling the native `hidden` DOM attribute. Supports negation (`!`).
180
88
 
181
- Updates the `textContent` of an element. This is safe and prevents XSS attacks.
89
+ > **Pro Tip (Prevent FOUC Glitch):** Add the static `hidden` attribute to elements in HTML (`<div hidden :hidden="show">`) so they remain hidden during page load before JS initializes.
182
90
 
183
91
  ```html
184
- <div s-data="textApp">
185
- <p>Message: <span s-text="msg"></span></p>
186
-
187
- <p>Formatted: <span s-text="formatMsg"></span></p>
92
+ <div s-data="visibilityDemo">
93
+ <button s-click="toggle">Toggle Visibility</button>
94
+
95
+ <!-- s-if (Mount/Unmount) -->
96
+ <div s-if="isOnline">Status: Online</div>
97
+ <div s-if="!isOnline">Status: Disconnected (Negation Example)</div>
98
+
99
+ <!-- :hidden (Visibility Toggle with static hidden attribute to prevent flicker) -->
100
+ <div hidden :hidden="!isVisible">Visible Content</div>
188
101
  </div>
189
102
 
190
103
  <script>
191
- spiki.data('textApp', () => ({
192
- msg: 'hello world',
193
-
194
- // Function receives the element as argument
195
- formatMsg(el) {
196
- // You can manipulate 'el' if needed, but return value is used for text
197
- return this.msg.toUpperCase();
104
+ spiki.data('visibilityDemo', () => ({
105
+ isOnline: true,
106
+ isVisible: true,
107
+ toggle() {
108
+ this.isOnline = !this.isOnline;
109
+ this.isVisible = !this.isVisible;
198
110
  }
199
111
  }));
200
112
  </script>
201
-
202
113
  ```
203
114
 
204
- > **Note:** If you bind a function to `s-text`, that function receives the DOM element (`el`) as its first argument.
115
+ ---
205
116
 
206
- ### 2. Inner HTML (`s-html`)
117
+ ### 2. SVG & HTML Dynamic Class Binding (`:class`)
207
118
 
208
- Updates the `innerHTML`. Only use this if you trust the content source.
119
+ Dynamic class binding works seamlessly on both HTML and SVG elements (preventing `SVGAnimatedString` class errors):
209
120
 
210
121
  ```html
211
- <div s-data="htmlApp">
212
- <div s-html="rawHtml"></div>
213
- </div>
122
+ <div s-data="themeApp">
123
+ <!-- HTML Element -->
124
+ <div :class="statusClass">Component Active</div>
214
125
 
215
- <script>
216
- spiki.data('htmlApp', () => ({
217
- rawHtml: '<b>Bold Text</b> and <i>Italic</i>'
218
- }));
219
- </script>
126
+ <!-- SVG Element -->
127
+ <svg :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor">
128
+ <circle cx="12" cy="12" r="10"></circle>
129
+ </svg>
220
130
 
221
- ```
222
-
223
- > **Note:** Just like `s-text`, if you use a function here, it receives the DOM element (`el`) as an argument.
224
-
225
- ### 3. Dynamic Attributes (`:[attribute]`)
226
-
227
- You can bind ANY HTML attribute to a variable by adding a colon `:` before the attribute name.
228
-
229
- ```html
230
- <div s-data="attrApp">
231
- <img :src="avatarUrl" :alt="avatarAlt">
232
- <a :href="profileLink">View Profile</a>
233
-
234
- <button :disabled="checkStatus">Submit</button>
131
+ <button s-click="toggleStatus">Toggle Theme</button>
235
132
  </div>
236
133
 
237
134
  <script>
238
- spiki.data('attrApp', () => ({
239
- avatarUrl: 'https://via.placeholder.com/150',
240
- avatarAlt: 'User Avatar',
241
- profileLink: '/profile/user1',
242
- isLoading: true,
243
-
244
- checkStatus(el) {
245
- // 'el' is the button element
246
- if (this.isLoading) {
247
- el.style.opacity = '0.5'; // You can touch DOM directly
248
- return true; // Return value sets the attribute
249
- }
250
- el.style.opacity = '1';
251
- return false;
135
+ spiki.data('themeApp', () => ({
136
+ isActive: false,
137
+ toggleStatus() {
138
+ this.isActive = !this.isActive;
139
+ },
140
+ get statusClass() {
141
+ return this.isActive ? 'bg-indigo-600 text-white' : 'bg-slate-200 text-slate-700';
142
+ },
143
+ get iconClass() {
144
+ return this.isActive ? 'stroke-indigo-500 text-indigo-500' : 'stroke-slate-400 text-slate-400';
252
145
  }
253
146
  }));
254
147
  </script>
255
-
256
148
  ```
257
149
 
258
- > **Note:** The function receives the DOM element (`el`) as an argument. You can use this to perform direct DOM manipulation alongside setting the attribute.
150
+ ---
259
151
 
260
- ### 4. Initialization (`s-init`)
152
+ ### 3. List Rendering & Scope Auto-Injection (`s-for`)
261
153
 
262
- Runs a function immediately when the component is mounted. This is the perfect place for API calls or setting up 3rd party libraries.
154
+ Inside `<template s-for="(child, index) in children">`, event handlers do **NOT** require parameters. Spiki automatically injects `this.child` (current item) and `this.index` (current loop index) directly into method execution context:
263
155
 
264
156
  ```html
265
- <div s-data="usersApp" s-init="loadUsers">
266
- <p s-if="isLoading">Loading...</p>
157
+ <div s-data="todoApp">
158
+ <input s-model="newItem" s-keyup="checkAdd" placeholder="Add fruit (e.g. Mango)...">
159
+ <button s-click="addItem">Add</button>
160
+
267
161
  <ul>
268
- <template s-for="user in users" s-key="id">
269
- <li><span s-text="user.name"></span></li>
162
+ <template s-for="(fruit, idx) in fruits" s-key="id">
163
+ <li>
164
+ #<span s-text="idx"></span>: <span s-text="fruit.name"></span>
165
+ <!-- No parameters needed! this.fruit and this.idx are auto-injected -->
166
+ <button s-click="removeItem">Delete</button>
167
+ </li>
270
168
  </template>
271
169
  </ul>
272
170
  </div>
273
171
 
274
172
  <script>
275
- spiki.data('usersApp', () => ({
276
- isLoading: true,
277
- users: [],
278
-
279
- loadUsers(el) {
280
- // 'el' is the div containing s-init
281
- console.log("Component mounted on:", el);
282
-
283
- var self = this;
284
- fetch('https://jsonplaceholder.typicode.com/users')
285
- .then(function(r) { return r.json() })
286
- .then(function(data) {
287
- self.users = data;
288
- self.isLoading = false;
289
- });
173
+ spiki.data('todoApp', () => ({
174
+ newItem: 'Mango',
175
+ fruits: [
176
+ { id: 1, name: 'Apple' },
177
+ { id: 2, name: 'Banana' }
178
+ ],
179
+ checkAdd(e) {
180
+ if (e.key === 'Enter') this.addItem();
181
+ },
182
+ addItem() {
183
+ if (!this.newItem.trim()) return;
184
+ this.fruits.push({ id: Date.now(), name: this.newItem.trim() });
185
+ this.newItem = '';
186
+ },
187
+ removeItem() {
188
+ // Automatically reads this.idx auto-injected by Spiki loop scope
189
+ if (typeof this.idx === 'number') {
190
+ this.fruits.splice(this.idx, 1);
191
+ }
290
192
  }
291
193
  }));
292
194
  </script>
293
-
294
195
  ```
295
196
 
296
- > **Note:** The function receives the element (`el`) where the directive is placed.
197
+ ---
297
198
 
298
- ### 5. Event Listeners (`s-[event]`)
199
+ ### 4. Instance API: `this.$refs` & `this.$root`
299
200
 
300
- Listen to any DOM event using the `s-` prefix.
201
+ Access raw DOM nodes without query selectors using `this.$refs` and `this.$root`:
301
202
 
302
203
  ```html
303
- <div s-data="eventApp">
304
- <button s-click="handleClick">Click Me</button>
204
+ <div s-data="refDemo">
205
+ <input s-ref="textInput" type="text" value="Spiki Ref Input">
206
+ <button s-click="focusInput">Focus</button>
207
+ <button s-click="highlightContainer">Highlight Container</button>
305
208
  </div>
306
209
 
307
210
  <script>
308
- spiki.data('eventApp', () => ({
309
- handleClick(e) {
310
- // 'e' is the standard Native Event Object
311
- // 'e.target' gives you the element
312
- e.preventDefault();
313
- alert('Button Clicked!');
211
+ spiki.data('refDemo', () => ({
212
+ focusInput() {
213
+ // Access raw HTMLInputElement directly
214
+ this.$refs.textInput.focus();
215
+ this.$refs.textInput.select();
216
+ },
217
+ highlightContainer() {
218
+ // Manipulate component container directly
219
+ this.$root.classList.toggle('ring-2');
314
220
  }
315
221
  }));
316
222
  </script>
317
-
318
223
  ```
319
224
 
320
- > **Note:** Events receive the native Event Object (`e`). You can access the element via `e.target` or `e.currentTarget`.
321
-
322
- ### 6. Side Effects (`s-effect`)
225
+ ---
323
226
 
324
- Use `s-effect` to run a function automatically whenever its dependencies change.
227
+ ### 5. Global Store (`spiki.store()`) with Auto `init()` Execution
325
228
 
326
- ```html
327
- <div s-data="saveApp" s-effect="autoSave">
328
- <textarea s-model="note"></textarea>
329
- <span s-text="status"></span>
330
- </div>
229
+ Register shared global state with `spiki.store('name', stateObject)`. If your store defines an `init()` method, Spiki executes `store.init.call(store)` automatically upon registration:
331
230
 
332
- <script>
333
- spiki.data('saveApp', () => ({
334
- note: localStorage.getItem('note') || '',
335
- status: '',
336
-
337
- autoSave() {
338
- localStorage.setItem('note', this.note);
339
- this.status = 'Saved!';
231
+ ```javascript
232
+ // 1. Register store with automatic init hook
233
+ spiki.store('settings', {
234
+ theme: 'dark',
235
+ initialized: false,
236
+ init() {
237
+ // Runs automatically when store is registered!
238
+ this.theme = localStorage.getItem('theme') || 'dark';
239
+ this.initialized = true;
340
240
  }
341
- }));
342
- </script>
343
-
344
- ```
345
-
346
- > **Note:** The function receives the element (`el`) as an argument. Useful if you need to update something visual on the container when data changes.
347
-
348
- ### 7. Form Inputs (`s-model` vs `s-value`)
349
-
350
- * **`s-model` (Two-Way):** Updates data when user types, and updates input when data changes.
351
- * **`s-value` (One-Way):** Only updates the input when data changes.
352
-
353
- ```html
354
- <div s-data="formApp">
355
- <input type="text" s-model="username">
356
-
357
- <input type="text" s-value="previewName" readonly>
358
- </div>
241
+ });
359
242
 
360
- <script>
361
- spiki.data('formApp', () => ({
362
- username: 'john_doe',
363
-
364
- get previewName() {
365
- return this.username.toUpperCase();
243
+ // 2. Consume store inside any component
244
+ spiki.data('headerApp', () => ({
245
+ get currentTheme() {
246
+ return this.$store.settings.theme; // Reactive store subscription!
247
+ },
248
+ toggleTheme() {
249
+ this.$store.settings.theme = this.$store.settings.theme === 'dark' ? 'light' : 'dark';
366
250
  }
367
251
  }));
368
- </script>
369
-
370
252
  ```
371
253
 
372
254
  ---
373
255
 
374
- ## Mastering Lists (`s-for`)
375
-
376
- ### 1. Basic Loop Requirement
377
-
378
- You **MUST** use the `<template>` tag. Spiki uses the template to stamp out copies of your HTML.
379
-
380
- ```html
381
- <ul>
382
- <template s-for="user in users" s-key="id">
383
- <li><span s-text="user.name"></span></li>
384
- </template>
385
- </ul>
386
-
387
- ```
388
-
389
- ### 2. Accessing Data Inside Loop (`this.item`)
390
-
391
- When you trigger an event inside a loop, Spiki automatically injects the current item into `this`. The property name matches your loop alias.
392
-
393
- ```html
394
- <div s-data="shopApp">
395
- <ul>
396
- <template s-for="product in products" s-key="id">
397
- <li>
398
- <span s-text="product.name"></span>
399
- <button s-click="selectProduct">Select</button>
400
- </li>
401
- </template>
402
- </ul>
403
- </div>
404
-
405
- <script>
406
- spiki.data('shopApp', () => ({
407
- products: [
408
- { id: 1, name: 'Laptop' },
409
- { id: 2, name: 'Phone' }
410
- ],
411
- selectProduct() {
412
- // 'this.product' is automatically available
413
- console.log('You selected:', this.product.name);
414
- }
415
- }));
416
- </script>
417
-
418
- ```
419
-
420
- ### 3. Accessing Index
256
+ ### 6. Unwrapping Reactive Proxies (`spiki.raw()`)
421
257
 
422
- You can get the current index by using parentheses: `(item, index) in array`.
258
+ Spiki wraps state objects in ES6 Proxies. Use `spiki.raw(proxy)` to unwrap state back into plain JavaScript objects before calling `JSON.stringify()`, logging, or sending network payloads:
423
259
 
424
- ```html
425
- <template s-for="(item, i) in list" s-key="id">
426
- <button s-click="remove">
427
- Remove Index <span s-text="i"></span>
428
- </button>
429
- </template>
430
-
431
- <script>
432
- spiki.data('listApp', () => ({
433
- list: ['A', 'B', 'C'],
434
- remove() {
435
- // 'this.i' is automatically available
436
- this.list.splice(this.i, 1);
260
+ ```javascript
261
+ spiki.data('userProfile', () => ({
262
+ user: { name: 'Alice', role: 'Admin' },
263
+
264
+ saveUser() {
265
+ // Extract raw, un-proxied JS object
266
+ const plainData = spiki.raw(this.user);
267
+
268
+ fetch('/api/user', {
269
+ method: 'POST',
270
+ headers: { 'Content-Type': 'application/json' },
271
+ body: JSON.stringify(plainData)
272
+ });
437
273
  }
438
274
  }));
439
- </script>
440
-
441
275
  ```
442
276
 
443
277
  ---
444
278
 
445
- ## Advanced Features
279
+ ### 7. Reactive Side Effects (`s-effect`)
446
280
 
447
- ### DOM References (`s-ref`)
281
+ Use `s-effect="handler"` to run automatic reactive watchers.
448
282
 
449
- Sometimes you need to access the raw DOM element (e.g., to focus an input or play a video).
283
+ > **Warning:** Do **NOT** mutate component state properties inside `s-effect` methods (e.g. `this.runs++`), as modifying state read inside an effect causes an infinite loop. Use `s-effect` strictly for external side effects like `localStorage`, network calls, or direct DOM updates.
450
284
 
451
285
  ```html
452
- <div s-data="refApp">
453
- <input s-ref="myInput" type="text">
454
- <button s-click="focusMe">Focus Input</button>
286
+ <div s-data="noteApp" s-effect="autoSave">
287
+ <input type="text" s-model="note">
455
288
  </div>
456
289
 
457
290
  <script>
458
- spiki.data('refApp', () => ({
459
- focusMe() {
460
- // Access DOM element via this.$refs
461
- this.$refs.myInput.focus();
291
+ spiki.data('noteApp', () => ({
292
+ note: 'Hello Spiki',
293
+ autoSave() {
294
+ // Pure side effect: read state and write to localStorage
295
+ try {
296
+ localStorage.setItem('user_note', this.note);
297
+ } catch(e) {}
462
298
  }
463
299
  }));
464
300
  </script>
465
-
466
301
  ```
467
302
 
468
303
  ---
469
304
 
470
- ## Core Concepts
471
-
472
- ### Component Instance (`this`)
473
-
474
- Inside your functions, `this` refers to your component state.
475
-
476
- > **Warning:** Do not use arrow functions for methods (`func: () => {}`) if you need `this`. Use method shorthand (`func() {}`) instead.
477
-
478
- Spiki injects helper properties:
479
-
480
- * **`this.$root`**: The HTML element containing the component.
481
- * **`this.$refs`**: Access elements marked with `s-ref`.
482
- * **`this.$store`**: Access the global store.
483
- * **`this.$parent`**: Access the parent component.
484
-
485
- ### Global Store
486
-
487
- Share state across multiple components.
488
-
489
- ```javascript
490
- // 1. Define Store
491
- spiki.store('user', {
492
- name: 'John Doe',
493
- isLoggedIn: true
494
- });
495
-
496
- // 2. Use in Component
497
- spiki.data('profile', () => ({
498
- get userName() {
499
- return this.$store.user.name; // Reactive!
500
- }
501
- }));
502
-
503
- ```
504
-
505
- ### `spiki.raw(proxy)`
506
-
507
- Get the original object from a Spiki proxy. Useful for console logging or API calls.
508
-
509
- ```javascript
510
- const cleanData = spiki.raw(this.myData);
511
- console.log(cleanData);
512
-
513
- ```
514
-
515
- ---
516
-
517
- ## Browser Support
518
-
519
- Spiki requires a browser that supports **ES6 Proxy**.
520
-
521
- * **Supported:** Chrome, Firefox, Edge, Safari (Modern versions).
522
- * **Not Supported:** Internet Explorer 11.
523
-
524
305
  ## License
525
306
 
526
307
  MIT License.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "spikijs",
3
3
  "license": "MIT",
4
- "version": "1.1.24",
4
+ "version": "1.1.26",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
package/spiki.esm.js CHANGED
@@ -160,7 +160,7 @@ var spiki = (() => {
160
160
  while (proto && proto !== Object.prototype) {
161
161
  if (Object.prototype.hasOwnProperty.call(proto, key)) {
162
162
  var res = Reflect.set(proto, key, val);
163
- if (!pauseTracking && val !== old) trigger(target, key);
163
+ if (!pauseTracking && (val !== old || (val && typeof val === 'object'))) trigger(target, key);
164
164
  return res;
165
165
  }
166
166
  proto = Object.getPrototypeOf(proto);
@@ -169,7 +169,7 @@ var spiki = (() => {
169
169
 
170
170
  var res = Reflect.set(target, key, val, receiver);
171
171
  if (!pauseTracking && res) {
172
- if (!hadKey || val !== old) {
172
+ if (!hadKey || val !== old || (val && typeof val === 'object')) {
173
173
  trigger(target, key);
174
174
  if (isArr) trigger(target, 'length');
175
175
  else if (!hadKey) trigger(target, '_k');
@@ -233,7 +233,7 @@ var spiki = (() => {
233
233
  for (var k in val) val[k] ? (obj[k] = 1) : delete obj[k];
234
234
  }
235
235
  var res = Object.keys(obj).join(' ');
236
- if (el.className !== res) el.className = res;
236
+ if ((el.getAttribute('class') || '') !== res) el.setAttribute('class', res);
237
237
  };
238
238
 
239
239
  var mount = (rootElement, parentScope) => {
@@ -328,7 +328,7 @@ var spiki = (() => {
328
328
  var directiveFor = !directiveIf && el.tagName === 'TEMPLATE' && el.getAttribute('s-for');
329
329
  var bindings = [];
330
330
 
331
- if (el.hasAttribute('class') && !el._n) el._n = el.className;
331
+ if (el.hasAttribute('class') && !el._n) el._n = el.getAttribute('class');
332
332
 
333
333
  if (directiveIf) {
334
334
  var end = document.createTextNode('');
package/spiki.esm.min.js CHANGED
@@ -1 +1 @@
1
- var spiki=(()=>{var r,e=Object,t=Array,a=Reflect,n=Promise,o=Node,i=document,l=console,v="length",f="value",s="push",u="forEach",p="indexOf",c="split",_="slice",d="call",y="keys",h="get",m="prototype",g="hasOwnProperty",b="getPrototypeOf",x="defineProperty",P="create",k="isArray",A="getAttribute",N="removeAttribute",w="hasAttribute",E="tagName",S="type",T="name",$="checked",O="parentNode",j="nextSibling",C="textContent",L="innerHTML",q="replaceWith",M="insertBefore",D="cloneNode",F="remove",K="createTextNode",B="addEventListener",H="input",R="checkbox",W="function",z="radio",G="class",I="model",J="object",Q="unshift",U="scope",V="trim",X="cleanups",Y="nodes",Z="deps",rr="className",er="destroy",tr="init",ar="charCodeAt",nr="sched",or="string",ir="unmount",lr="attr",vr="s-data",fr="s-if",sr=e[P](null),ur=[],pr=!1,cr=null,_r=!1,dr=n.resolve(),yr={blur:1,focus:1,scroll:1,load:1,error:1,mouseenter:1,mouseleave:1,toggle:1},hr=r=>{r._q||(r._q=!0,ur[s](r),pr||(pr=!0,dr.then(()=>{var r=ur;ur=[],pr=!1;for(var e=r[v];e--;)r[e]._q=!1,r[e]()})))},mr=(r,e)=>{var a,n=r;if(typeof e===or)a=r?r[e]:void 0;else{for(var o=0,i=e[v];o<i-1&&n;)n=n[e[o++]];a=n?n[e[i-1]]:void 0}if(void 0===a){var f=t[k](e)?e.join("."):e;l.warn("[spikijs] Property undefined: "+f)}return{ctx:n,val:a}},gr={};[s,"pop","shift",Q,"splice","sort","reverse"][u](r=>{gr[r]=function(...e){_r=!0;try{return t[m][r].apply(this,e)}finally{_r=!1,xr(this,v)}}});var br=(r,t)=>{if(cr){var a=r._d||(e[x](r,"_d",{value:e[P](null),writable:!0}),r._d),n=a[t]||(a[t]=[]);-1===n[p](cr)&&(n[s](cr),cr[Z][s](n))}},xr=(r,e)=>{if(!_r&&r._d&&r._d[e])for(var t=r._d[e][_](),a=0,n=t[v];a<n;a++){var o=t[a];o[nr]?o[nr](o):o()}},Pr=r=>{for(var e=r[Z][v];e--;){var t=r[Z][e],a=t[p](r);-1!==a&&(t[a]=t[t[v]-1],t.pop())}r[Z]=[]},kr=(r,e)=>{var t=()=>{Pr(t);var e=cr;cr=t;try{r()}finally{cr=e}};return t[Z]=[],t[nr]=e,t(),()=>Pr(t)},Ar=r=>{if(!r||typeof r!==J||r._y||r instanceof o)return r;if(e[m][g][d](r,"_p"))return r._p;var n=new Proxy(r,{get:(r,n,i)=>{if("_y"===n)return i===r._p;if("_t"===n)return r;if("_d"===n)return r._d;if("_i"===n)return r._i;if(t[k](r)&&gr[g](n))return gr[n];var l=e.getOwnPropertyDescriptor(r,n);if(l&&l[h]){var v="_"+n;return v in r||kr(()=>i[v]=l[h][d](i)),i[v]}br(r,n);var f=a[h](r,n,i);return!f||typeof f!==J||f instanceof o?f:Ar(f)},set:(r,n,o,i)=>{var l=r[n],f=t[k](r),s=f?Number(n)<r[v]:e[m][g][d](r,n);if(r._i&&!s)for(var u=e[b](r);u&&u!==e[m];){if(e[m][g][d](u,n)){var p=a.set(u,n,o);return _r||o===l||xr(r,n),p}u=e[b](u)}return p=a.set(r,n,o,i),!_r&&p&&(s&&o===l||(xr(r,n),f?xr(r,v):s||xr(r,"_k"))),p},deleteProperty:(r,n)=>{var o=e[m][g][d](r,n),i=a.deleteProperty(r,n);return i&&o&&(xr(r,n),t[k](r)?xr(r,v):xr(r,"_k")),i},ownKeys:r=>(br(r,"_k"),a.ownKeys(r))});return e[x](r,"_p",{value:n}),n};r=Ar({});var Nr=e[P](null);Nr.text=(r,e)=>{e=null==e?"":e,r[C]!==String(e)&&(r[C]=e)},Nr.html=(r,e)=>{r[L]!=e&&(r[L]=null==e?"":e)},Nr[f]=(r,e)=>{r[S]===R?r[$]=!!e:r[S]===z?r[$]=r[f]==e:r[f]!=e&&(r[f]=null==e?"":e)},Nr[lr]=(r,e,t)=>{if(null==e||!1===e)r[N](t);else{var a=!0===e?"":String(e);r[A](t)!==a&&r.setAttribute(t,a)}},Nr[G]=(r,t)=>{var a=r._n||"",n=e[P](null);if(a[c](/\s+/)[u](r=>r&&(n[r]=1)),typeof t===or)t[c](/\s+/)[u](r=>r&&(n[r]=1));else if(t)for(var o in t)t[o]?n[o]=1:delete n[o];var i=e[y](n).join(" ");r[rr]!==i&&(r[rr]=i)};var wr=(a,n)=>{if(a._m)return a._m;var o=a[A](vr);if(sr[o]){var l=sr[o]();n&&e.setPrototypeOf(l,n);var h=Ar(l);h.$refs={},h.$root=a,h.$store=r,h.$parent=n;var g=[],b=e[P](null),C=r=>{var t=r.target;if(r[S]!==H||!t._c)for(var n=a[O],o=r[S];t&&t!==n;){var i=t._h&&t._h[o];if(i){var l=t._s;if(!l||l.$root!==h.$root){t=t[O];continue}for(var s=i[v];s--;){var u=i[s],p=u.p;if(u[I]){var c=t[S]===R?t[$]:t[f];if(typeof c===or){var _=c[V]();_&&isFinite(_)&&(48===_[ar](0)&&1!==_[v]&&46!==_[ar](1)||(c=Number(_)))}if(typeof p===or)l&&(l[p]=c);else{for(var y=l,m=0,g=p[v]-1;m<g&&y;)y=y[p[m++]];y&&(y[p[g]]=c)}}else{var b=mr(l,p);typeof b.val===W&&(e[x](r,"currentTarget",{configurable:!0,value:t}),b.val[d](b.ctx,r))}}}t=t[O]}},L=r=>{b[r]||(b[r]=!0,a[B](r,C,!!yr[r]))},Z=(r,n,o)=>{if(1===r.nodeType&&!r[w]("s-ignore"))if(r!==a&&r[w](vr)){var l=wr(r,n);l&&o[s](l[ir])}else{var g=r[A](fr),b=!g&&"TEMPLATE"===r[E]&&r[A]("s-for"),$=[];if(r[w](G)&&!r._n&&(r._n=r[rr]),g){var nr=i[K](""),or=null,sr=[];r[q](nr);var ur="!"===g[0],pr=ur?g[_](1):g,cr=-1===pr[p](".")?pr:pr[c](".");return o[s](()=>{for(var r=sr[v];r--;)sr[r]()}),o[s](kr(()=>{var e=mr(n,cr).val;if(ur&&(e=!e),e)or||((or=r[D](!0))[N](fr),Z(or,n,sr),nr[O][M](or,nr));else if(or){for(var t=sr[v];t--;)sr[t]();sr=[],or[F](),or=null}},hr))}if(b){var _r=b[p](" in ");if(-1!==_r){var dr,yr=b[_](0,_r)[V](),gr=b[_](_r+4)[V](),xr=yr.replace(/[()]/g,"")[c](","),Pr=xr[0][V](),Er=xr[1]?xr[1][V]():null,Sr=-1===gr[p](".")?gr:gr[c]("."),Tr=r[A]("s-key"),$r=Tr?-1===Tr[p](".")?Tr:Tr[c]("."):null,Or=(nr=i[K](""),e[P](null));return r[q](nr),o[s](()=>{for(var r in Or)Or[r][X][u](r=>r())}),o[s](kr(()=>{var a=mr(n,Sr).val||[];"number"==typeof a&&(a=t.from({length:Math.max(0,Math.floor(a))},(r,e)=>e+1)),t[k](a)&&br(a,v);var o=i.createDocumentFragment(),l=nr;dr=e[P](null);for(var f=t[k](a),s=f?a:e[y](a),p=f?a[v]:s[v],c=0;c<p;c++){var h,g=f?c:s[c],b=f?a[c]:a[g];h=null==b||typeof b!==J?String(b):$r?mr(b,$r).val:String(g)+"_o",dr[h]&&(h+="_"+c);var A=Or[h];if(A)A[U][Pr]=b,Er&&(A[U][Er]=g);else{var N=r.content[D](!0),w=e[P](n);e[x](w,"_i",{value:!0});var E=Ar(w);E[Pr]=b,Er&&(E[Er]=g);for(var S=t[m][_][d](N.childNodes),T=[],$=0;$<S[v];$++)Z(S[$],E,T);A={nodes:t[m][_][d](N.childNodes),scope:E,cleanups:T},Or[h]=A}if(A[Y][0]!==l[j]){for($=0;$<A[Y][v];$++)o.appendChild(A[Y][$]);l[O][M](o,l[j])}l=A[Y][A[Y][v]-1],dr[h]=!0}for(var C in Or)dr[C]||(Or[C][X][u](r=>r()),Or[C][Y][u](r=>r[F]()),delete Or[C])},hr))}}if(r.hasAttributes())for(var jr=r.attributes,Cr=jr[v];Cr--;){var Lr=jr[Cr],qr=Lr[T],Mr=Lr[f];if(58===qr[ar](0)){var Dr=qr[_](1),Fr=33===Mr[ar](0),Kr=Fr?Mr[_](1):Mr;cr=-1===Kr[p](".")?Kr:Kr[c]("."),$[s]({type:lr,name:Dr,path:cr,neg:Fr})}else if(115===qr[ar](0)&&45===qr[ar](1)){let e=qr[_](2),t=-1===Mr[p](".")?Mr:Mr[c](".");if(e===tr||e===er)((e,t)=>{var a=mr(n,t);typeof a.val===W&&(e===tr?hr(()=>{var e=a.val[d](a.ctx,r);typeof e===W&&o[s](e)}):o[s](()=>a.val[d](a.ctx,r)))})(e,t);else if("effect"===e)o[s](kr(()=>{var e=mr(n,t);typeof e.val===W&&e.val[d](e.ctx,r)},hr));else if(e===I){$[s]({type:f,path:t}),r._s=n,r._h=r._h||{};var Br=r[S]===R||r[S]===z||"SELECT"===r[E]?"change":H;Br===H&&(r[B]("compositionstart",()=>r._c=!0),r[B]("compositionend",()=>{r._c=!1,C({target:r,type:H})})),(r._h[Br]=r._h[Br]||[])[s]({model:!0,p:t}),L(Br)}else"ref"===e?h.$refs[Mr]=r:Nr[e]?$[s]({type:e,path:t}):(r._s=n,r._h=r._h||{},(r._h[e]=r._h[e]||[])[Q]({p:t}),L(e))}}$[v]&&o[s](kr(()=>{for(var e=$[v];e--;){var t=$[e],a=mr(n,t.path),o=typeof a.val===W?a.val[d](a.ctx,r):a.val;t[S]===lr?(t.neg&&(o=!o),t[T]===G?Nr[G](r,o):Nr[lr](r,o,t[T])):Nr[t[S]](r,o)}},hr));for(var Hr=r.firstChild;Hr;){var Rr=Hr[j];Z(Hr,n,o),Hr=Rr}}};Z(a,h,g),h[tr]&&h[tr]();var nr={unmount:()=>{h[er]&&h[er][d](h);for(var r=g[v];r--;)g[r]();for(var e in b)a.removeEventListener(e,C);a._m=null}};return a._m=nr,nr}},Er=r=>{if(!r||typeof r!==J)return r;var e=r._t||r;if(t[k](e))return e.map(r=>Er(r));var a={};for(var n in e)a[n]=Er(e[n]);return a};return{data:(r,e)=>{sr[r]=e},start:()=>{for(var r=i.querySelectorAll("[s-data]"),e=r[v];e--;)wr(r[e])},store:(e,t)=>{if(void 0===t)return r[e];r[e]=t;var a=r[e];return a&&typeof a[tr]===W&&a[tr][d](a),a},raw:Er,mount:r=>wr(r),unmount:r=>{r&&r._m&&r._m[ir]()}}})();export default spiki;
1
+ var spiki=(()=>{var r,e=Object,t=Array,a=Reflect,n=Promise,o=Node,i=document,l=console,f="length",v="value",s="push",u="forEach",p="indexOf",c="split",_="slice",d="call",y="keys",h="get",m="prototype",g="hasOwnProperty",b="getPrototypeOf",x="defineProperty",P="create",k="isArray",A="getAttribute",N="setAttribute",w="removeAttribute",E="hasAttribute",S="tagName",T="type",$="name",O="checked",j="parentNode",C="nextSibling",L="textContent",q="innerHTML",M="replaceWith",D="insertBefore",F="cloneNode",K="remove",B="createTextNode",H="addEventListener",R="input",W="checkbox",z="function",G="radio",I="class",J="model",Q="object",U="unshift",V="scope",X="trim",Y="cleanups",Z="nodes",rr="deps",er="destroy",tr="init",ar="charCodeAt",nr="sched",or="string",ir="unmount",lr="attr",fr="s-data",vr="s-if",sr=e[P](null),ur=[],pr=!1,cr=null,_r=!1,dr=n.resolve(),yr={blur:1,focus:1,scroll:1,load:1,error:1,mouseenter:1,mouseleave:1,toggle:1},hr=r=>{r._q||(r._q=!0,ur[s](r),pr||(pr=!0,dr.then(()=>{var r=ur;ur=[],pr=!1;for(var e=r[f];e--;)r[e]._q=!1,r[e]()})))},mr=(r,e)=>{var a,n=r;if(typeof e===or)a=r?r[e]:void 0;else{for(var o=0,i=e[f];o<i-1&&n;)n=n[e[o++]];a=n?n[e[i-1]]:void 0}if(void 0===a){var v=t[k](e)?e.join("."):e;l.warn("[spikijs] Property undefined: "+v)}return{ctx:n,val:a}},gr={};[s,"pop","shift",U,"splice","sort","reverse"][u](r=>{gr[r]=function(...e){_r=!0;try{return t[m][r].apply(this,e)}finally{_r=!1,xr(this,f)}}});var br=(r,t)=>{if(cr){var a=r._d||(e[x](r,"_d",{value:e[P](null),writable:!0}),r._d),n=a[t]||(a[t]=[]);-1===n[p](cr)&&(n[s](cr),cr[rr][s](n))}},xr=(r,e)=>{if(!_r&&r._d&&r._d[e])for(var t=r._d[e][_](),a=0,n=t[f];a<n;a++){var o=t[a];o[nr]?o[nr](o):o()}},Pr=r=>{for(var e=r[rr][f];e--;){var t=r[rr][e],a=t[p](r);-1!==a&&(t[a]=t[t[f]-1],t.pop())}r[rr]=[]},kr=(r,e)=>{var t=()=>{Pr(t);var e=cr;cr=t;try{r()}finally{cr=e}};return t[rr]=[],t[nr]=e,t(),()=>Pr(t)},Ar=r=>{if(!r||typeof r!==Q||r._y||r instanceof o)return r;if(e[m][g][d](r,"_p"))return r._p;var n=new Proxy(r,{get:(r,n,i)=>{if("_y"===n)return i===r._p;if("_t"===n)return r;if("_d"===n)return r._d;if("_i"===n)return r._i;if(t[k](r)&&gr[g](n))return gr[n];var l=e.getOwnPropertyDescriptor(r,n);if(l&&l[h]){var f="_"+n;return f in r||kr(()=>i[f]=l[h][d](i)),i[f]}br(r,n);var v=a[h](r,n,i);return!v||typeof v!==Q||v instanceof o?v:Ar(v)},set:(r,n,o,i)=>{var l=r[n],v=t[k](r),s=v?Number(n)<r[f]:e[m][g][d](r,n);if(r._i&&!s)for(var u=e[b](r);u&&u!==e[m];){if(e[m][g][d](u,n)){var p=a.set(u,n,o);return!_r&&(o!==l||o&&typeof o===Q)&&xr(r,n),p}u=e[b](u)}return p=a.set(r,n,o,i),!_r&&p&&(!s||o!==l||o&&typeof o===Q)&&(xr(r,n),v?xr(r,f):s||xr(r,"_k")),p},deleteProperty:(r,n)=>{var o=e[m][g][d](r,n),i=a.deleteProperty(r,n);return i&&o&&(xr(r,n),t[k](r)?xr(r,f):xr(r,"_k")),i},ownKeys:r=>(br(r,"_k"),a.ownKeys(r))});return e[x](r,"_p",{value:n}),n};r=Ar({});var Nr=e[P](null);Nr.text=(r,e)=>{e=null==e?"":e,r[L]!==String(e)&&(r[L]=e)},Nr.html=(r,e)=>{r[q]!=e&&(r[q]=null==e?"":e)},Nr[v]=(r,e)=>{r[T]===W?r[O]=!!e:r[T]===G?r[O]=r[v]==e:r[v]!=e&&(r[v]=null==e?"":e)},Nr[lr]=(r,e,t)=>{if(null==e||!1===e)r[w](t);else{var a=!0===e?"":String(e);r[A](t)!==a&&r[N](t,a)}},Nr[I]=(r,t)=>{var a=r._n||"",n=e[P](null);if(a[c](/\s+/)[u](r=>r&&(n[r]=1)),typeof t===or)t[c](/\s+/)[u](r=>r&&(n[r]=1));else if(t)for(var o in t)t[o]?n[o]=1:delete n[o];var i=e[y](n).join(" ");(r[A](I)||"")!==i&&r[N](I,i)};var wr=(a,n)=>{if(a._m)return a._m;var o=a[A](fr);if(sr[o]){var l=sr[o]();n&&e.setPrototypeOf(l,n);var h=Ar(l);h.$refs={},h.$root=a,h.$store=r,h.$parent=n;var g=[],b=e[P](null),N=r=>{var t=r.target;if(r[T]!==R||!t._c)for(var n=a[j],o=r[T];t&&t!==n;){var i=t._h&&t._h[o];if(i){var l=t._s;if(!l||l.$root!==h.$root){t=t[j];continue}for(var s=i[f];s--;){var u=i[s],p=u.p;if(u[J]){var c=t[T]===W?t[O]:t[v];if(typeof c===or){var _=c[X]();_&&isFinite(_)&&(48===_[ar](0)&&1!==_[f]&&46!==_[ar](1)||(c=Number(_)))}if(typeof p===or)l&&(l[p]=c);else{for(var y=l,m=0,g=p[f]-1;m<g&&y;)y=y[p[m++]];y&&(y[p[g]]=c)}}else{var b=mr(l,p);typeof b.val===z&&(e[x](r,"currentTarget",{configurable:!0,value:t}),b.val[d](b.ctx,r))}}}t=t[j]}},L=r=>{b[r]||(b[r]=!0,a[H](r,N,!!yr[r]))},q=(r,n,o)=>{if(1===r.nodeType&&!r[E]("s-ignore"))if(r!==a&&r[E](fr)){var l=wr(r,n);l&&o[s](l[ir])}else{var g=r[A](vr),b=!g&&"TEMPLATE"===r[S]&&r[A]("s-for"),O=[];if(r[E](I)&&!r._n&&(r._n=r[A](I)),g){var rr=i[B](""),nr=null,or=[];r[M](rr);var sr="!"===g[0],ur=sr?g[_](1):g,pr=-1===ur[p](".")?ur:ur[c](".");return o[s](()=>{for(var r=or[f];r--;)or[r]()}),o[s](kr(()=>{var e=mr(n,pr).val;if(sr&&(e=!e),e)nr||((nr=r[F](!0))[w](vr),q(nr,n,or),rr[j][D](nr,rr));else if(nr){for(var t=or[f];t--;)or[t]();or=[],nr[K](),nr=null}},hr))}if(b){var cr=b[p](" in ");if(-1!==cr){var _r,dr=b[_](0,cr)[X](),yr=b[_](cr+4)[X](),gr=dr.replace(/[()]/g,"")[c](","),xr=gr[0][X](),Pr=gr[1]?gr[1][X]():null,Er=-1===yr[p](".")?yr:yr[c]("."),Sr=r[A]("s-key"),Tr=Sr?-1===Sr[p](".")?Sr:Sr[c]("."):null,$r=(rr=i[B](""),e[P](null));return r[M](rr),o[s](()=>{for(var r in $r)$r[r][Y][u](r=>r())}),o[s](kr(()=>{var a=mr(n,Er).val||[];"number"==typeof a&&(a=t.from({length:Math.max(0,Math.floor(a))},(r,e)=>e+1)),t[k](a)&&br(a,f);var o=i.createDocumentFragment(),l=rr;_r=e[P](null);for(var v=t[k](a),s=v?a:e[y](a),p=v?a[f]:s[f],c=0;c<p;c++){var h,g=v?c:s[c],b=v?a[c]:a[g];h=null==b||typeof b!==Q?String(b):Tr?mr(b,Tr).val:String(g)+"_o",_r[h]&&(h+="_"+c);var A=$r[h];if(A)A[V][xr]=b,Pr&&(A[V][Pr]=g);else{var N=r.content[F](!0),w=e[P](n);e[x](w,"_i",{value:!0});var E=Ar(w);E[xr]=b,Pr&&(E[Pr]=g);for(var S=t[m][_][d](N.childNodes),T=[],$=0;$<S[f];$++)q(S[$],E,T);A={nodes:t[m][_][d](N.childNodes),scope:E,cleanups:T},$r[h]=A}if(A[Z][0]!==l[C]){for($=0;$<A[Z][f];$++)o.appendChild(A[Z][$]);l[j][D](o,l[C])}l=A[Z][A[Z][f]-1],_r[h]=!0}for(var O in $r)_r[O]||($r[O][Y][u](r=>r()),$r[O][Z][u](r=>r[K]()),delete $r[O])},hr))}}if(r.hasAttributes())for(var Or=r.attributes,jr=Or[f];jr--;){var Cr=Or[jr],Lr=Cr[$],qr=Cr[v];if(58===Lr[ar](0)){var Mr=Lr[_](1),Dr=33===qr[ar](0),Fr=Dr?qr[_](1):qr;pr=-1===Fr[p](".")?Fr:Fr[c]("."),O[s]({type:lr,name:Mr,path:pr,neg:Dr})}else if(115===Lr[ar](0)&&45===Lr[ar](1)){let e=Lr[_](2),t=-1===qr[p](".")?qr:qr[c](".");if(e===tr||e===er)((e,t)=>{var a=mr(n,t);typeof a.val===z&&(e===tr?hr(()=>{var e=a.val[d](a.ctx,r);typeof e===z&&o[s](e)}):o[s](()=>a.val[d](a.ctx,r)))})(e,t);else if("effect"===e)o[s](kr(()=>{var e=mr(n,t);typeof e.val===z&&e.val[d](e.ctx,r)},hr));else if(e===J){O[s]({type:v,path:t}),r._s=n,r._h=r._h||{};var Kr=r[T]===W||r[T]===G||"SELECT"===r[S]?"change":R;Kr===R&&(r[H]("compositionstart",()=>r._c=!0),r[H]("compositionend",()=>{r._c=!1,N({target:r,type:R})})),(r._h[Kr]=r._h[Kr]||[])[s]({model:!0,p:t}),L(Kr)}else"ref"===e?h.$refs[qr]=r:Nr[e]?O[s]({type:e,path:t}):(r._s=n,r._h=r._h||{},(r._h[e]=r._h[e]||[])[U]({p:t}),L(e))}}O[f]&&o[s](kr(()=>{for(var e=O[f];e--;){var t=O[e],a=mr(n,t.path),o=typeof a.val===z?a.val[d](a.ctx,r):a.val;t[T]===lr?(t.neg&&(o=!o),t[$]===I?Nr[I](r,o):Nr[lr](r,o,t[$])):Nr[t[T]](r,o)}},hr));for(var Br=r.firstChild;Br;){var Hr=Br[C];q(Br,n,o),Br=Hr}}};q(a,h,g),h[tr]&&h[tr]();var rr={unmount:()=>{h[er]&&h[er][d](h);for(var r=g[f];r--;)g[r]();for(var e in b)a.removeEventListener(e,N);a._m=null}};return a._m=rr,rr}},Er=r=>{if(!r||typeof r!==Q)return r;var e=r._t||r;if(t[k](e))return e.map(r=>Er(r));var a={};for(var n in e)a[n]=Er(e[n]);return a};return{data:(r,e)=>{sr[r]=e},start:()=>{for(var r=i.querySelectorAll("[s-data]"),e=r[f];e--;)wr(r[e])},store:(e,t)=>{if(void 0===t)return r[e];r[e]=t;var a=r[e];return a&&typeof a[tr]===z&&a[tr][d](a),a},raw:Er,mount:r=>wr(r),unmount:r=>{r&&r._m&&r._m[ir]()}}})();export default spiki;
package/spiki.js CHANGED
@@ -163,7 +163,7 @@ var spiki = (() => {
163
163
  while (proto && proto !== Object.prototype) {
164
164
  if (Object.prototype.hasOwnProperty.call(proto, key)) {
165
165
  var res = Reflect.set(proto, key, val);
166
- if (!pauseTracking && val !== old) trigger(target, key);
166
+ if (!pauseTracking && (val !== old || (val && typeof val === 'object'))) trigger(target, key);
167
167
  return res;
168
168
  }
169
169
  proto = Object.getPrototypeOf(proto);
@@ -172,7 +172,7 @@ var spiki = (() => {
172
172
 
173
173
  var res = Reflect.set(target, key, val, receiver);
174
174
  if (!pauseTracking && res) {
175
- if (!hadKey || val !== old) {
175
+ if (!hadKey || val !== old || (val && typeof val === 'object')) {
176
176
  trigger(target, key);
177
177
  if (isArr) trigger(target, 'length');
178
178
  else if (!hadKey) trigger(target, '_k');
@@ -236,7 +236,7 @@ var spiki = (() => {
236
236
  for (var k in val) val[k] ? (obj[k] = 1) : delete obj[k];
237
237
  }
238
238
  var res = Object.keys(obj).join(' ');
239
- if (el.className !== res) el.className = res;
239
+ if ((el.getAttribute('class') || '') !== res) el.setAttribute('class', res);
240
240
  };
241
241
 
242
242
  var mount = (rootElement, parentScope) => {
@@ -331,7 +331,7 @@ var spiki = (() => {
331
331
  var directiveFor = !directiveIf && el.tagName === 'TEMPLATE' && el.getAttribute('s-for');
332
332
  var bindings = [];
333
333
 
334
- if (el.hasAttribute('class') && !el._n) el._n = el.className;
334
+ if (el.hasAttribute('class') && !el._n) el._n = el.getAttribute('class');
335
335
 
336
336
  if (directiveIf) {
337
337
  var end = document.createTextNode('');
package/spiki.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{"use strict";var spiki=(()=>{var r,e=Object,t=Array,a=Reflect,n=Promise,o=Node,i=document,l=console,v="length",f="value",s="push",u="forEach",p="indexOf",c="split",_="slice",d="call",y="keys",h="get",m="prototype",g="hasOwnProperty",b="getPrototypeOf",x="defineProperty",P="create",k="isArray",A="getAttribute",N="removeAttribute",w="hasAttribute",E="tagName",S="type",T="name",$="checked",O="parentNode",j="nextSibling",C="textContent",L="innerHTML",q="replaceWith",M="insertBefore",D="cloneNode",F="remove",K="createTextNode",B="addEventListener",H="input",R="checkbox",W="function",z="radio",G="class",I="model",J="object",Q="unshift",U="scope",V="trim",X="cleanups",Y="nodes",Z="deps",rr="className",er="destroy",tr="init",ar="charCodeAt",nr="sched",or="string",ir="unmount",lr="attr",vr="s-data",fr="s-if",sr=e[P](null),ur=[],pr=!1,cr=null,_r=!1,dr=n.resolve(),yr={blur:1,focus:1,scroll:1,load:1,error:1,mouseenter:1,mouseleave:1,toggle:1},hr=r=>{r._q||(r._q=!0,ur[s](r),pr||(pr=!0,dr.then(()=>{var r=ur;ur=[],pr=!1;for(var e=r[v];e--;)r[e]._q=!1,r[e]()})))},mr=(r,e)=>{var a,n=r;if(typeof e===or)a=r?r[e]:void 0;else{for(var o=0,i=e[v];o<i-1&&n;)n=n[e[o++]];a=n?n[e[i-1]]:void 0}if(void 0===a){var f=t[k](e)?e.join("."):e;l.warn("[spikijs] Property undefined: "+f)}return{ctx:n,val:a}},gr={};[s,"pop","shift",Q,"splice","sort","reverse"][u](r=>{gr[r]=function(...e){_r=!0;try{return t[m][r].apply(this,e)}finally{_r=!1,xr(this,v)}}});var br=(r,t)=>{if(cr){var a=r._d||(e[x](r,"_d",{value:e[P](null),writable:!0}),r._d),n=a[t]||(a[t]=[]);-1===n[p](cr)&&(n[s](cr),cr[Z][s](n))}},xr=(r,e)=>{if(!_r&&r._d&&r._d[e])for(var t=r._d[e][_](),a=0,n=t[v];a<n;a++){var o=t[a];o[nr]?o[nr](o):o()}},Pr=r=>{for(var e=r[Z][v];e--;){var t=r[Z][e],a=t[p](r);-1!==a&&(t[a]=t[t[v]-1],t.pop())}r[Z]=[]},kr=(r,e)=>{var t=()=>{Pr(t);var e=cr;cr=t;try{r()}finally{cr=e}};return t[Z]=[],t[nr]=e,t(),()=>Pr(t)},Ar=r=>{if(!r||typeof r!==J||r._y||r instanceof o)return r;if(e[m][g][d](r,"_p"))return r._p;var n=new Proxy(r,{get:(r,n,i)=>{if("_y"===n)return i===r._p;if("_t"===n)return r;if("_d"===n)return r._d;if("_i"===n)return r._i;if(t[k](r)&&gr[g](n))return gr[n];var l=e.getOwnPropertyDescriptor(r,n);if(l&&l[h]){var v="_"+n;return v in r||kr(()=>i[v]=l[h][d](i)),i[v]}br(r,n);var f=a[h](r,n,i);return!f||typeof f!==J||f instanceof o?f:Ar(f)},set:(r,n,o,i)=>{var l=r[n],f=t[k](r),s=f?Number(n)<r[v]:e[m][g][d](r,n);if(r._i&&!s)for(var u=e[b](r);u&&u!==e[m];){if(e[m][g][d](u,n)){var p=a.set(u,n,o);return _r||o===l||xr(r,n),p}u=e[b](u)}return p=a.set(r,n,o,i),!_r&&p&&(s&&o===l||(xr(r,n),f?xr(r,v):s||xr(r,"_k"))),p},deleteProperty:(r,n)=>{var o=e[m][g][d](r,n),i=a.deleteProperty(r,n);return i&&o&&(xr(r,n),t[k](r)?xr(r,v):xr(r,"_k")),i},ownKeys:r=>(br(r,"_k"),a.ownKeys(r))});return e[x](r,"_p",{value:n}),n};r=Ar({});var Nr=e[P](null);Nr.text=(r,e)=>{e=null==e?"":e,r[C]!==String(e)&&(r[C]=e)},Nr.html=(r,e)=>{r[L]!=e&&(r[L]=null==e?"":e)},Nr[f]=(r,e)=>{r[S]===R?r[$]=!!e:r[S]===z?r[$]=r[f]==e:r[f]!=e&&(r[f]=null==e?"":e)},Nr[lr]=(r,e,t)=>{if(null==e||!1===e)r[N](t);else{var a=!0===e?"":String(e);r[A](t)!==a&&r.setAttribute(t,a)}},Nr[G]=(r,t)=>{var a=r._n||"",n=e[P](null);if(a[c](/\s+/)[u](r=>r&&(n[r]=1)),typeof t===or)t[c](/\s+/)[u](r=>r&&(n[r]=1));else if(t)for(var o in t)t[o]?n[o]=1:delete n[o];var i=e[y](n).join(" ");r[rr]!==i&&(r[rr]=i)};var wr=(a,n)=>{if(a._m)return a._m;var o=a[A](vr);if(sr[o]){var l=sr[o]();n&&e.setPrototypeOf(l,n);var h=Ar(l);h.$refs={},h.$root=a,h.$store=r,h.$parent=n;var g=[],b=e[P](null),C=r=>{var t=r.target;if(r[S]!==H||!t._c)for(var n=a[O],o=r[S];t&&t!==n;){var i=t._h&&t._h[o];if(i){var l=t._s;if(!l||l.$root!==h.$root){t=t[O];continue}for(var s=i[v];s--;){var u=i[s],p=u.p;if(u[I]){var c=t[S]===R?t[$]:t[f];if(typeof c===or){var _=c[V]();_&&isFinite(_)&&(48===_[ar](0)&&1!==_[v]&&46!==_[ar](1)||(c=Number(_)))}if(typeof p===or)l&&(l[p]=c);else{for(var y=l,m=0,g=p[v]-1;m<g&&y;)y=y[p[m++]];y&&(y[p[g]]=c)}}else{var b=mr(l,p);typeof b.val===W&&(e[x](r,"currentTarget",{configurable:!0,value:t}),b.val[d](b.ctx,r))}}}t=t[O]}},L=r=>{b[r]||(b[r]=!0,a[B](r,C,!!yr[r]))},Z=(r,n,o)=>{if(1===r.nodeType&&!r[w]("s-ignore"))if(r!==a&&r[w](vr)){var l=wr(r,n);l&&o[s](l[ir])}else{var g=r[A](fr),b=!g&&"TEMPLATE"===r[E]&&r[A]("s-for"),$=[];if(r[w](G)&&!r._n&&(r._n=r[rr]),g){var nr=i[K](""),or=null,sr=[];r[q](nr);var ur="!"===g[0],pr=ur?g[_](1):g,cr=-1===pr[p](".")?pr:pr[c](".");return o[s](()=>{for(var r=sr[v];r--;)sr[r]()}),o[s](kr(()=>{var e=mr(n,cr).val;if(ur&&(e=!e),e)or||((or=r[D](!0))[N](fr),Z(or,n,sr),nr[O][M](or,nr));else if(or){for(var t=sr[v];t--;)sr[t]();sr=[],or[F](),or=null}},hr))}if(b){var _r=b[p](" in ");if(-1!==_r){var dr,yr=b[_](0,_r)[V](),gr=b[_](_r+4)[V](),xr=yr.replace(/[()]/g,"")[c](","),Pr=xr[0][V](),Er=xr[1]?xr[1][V]():null,Sr=-1===gr[p](".")?gr:gr[c]("."),Tr=r[A]("s-key"),$r=Tr?-1===Tr[p](".")?Tr:Tr[c]("."):null,Or=(nr=i[K](""),e[P](null));return r[q](nr),o[s](()=>{for(var r in Or)Or[r][X][u](r=>r())}),o[s](kr(()=>{var a=mr(n,Sr).val||[];"number"==typeof a&&(a=t.from({length:Math.max(0,Math.floor(a))},(r,e)=>e+1)),t[k](a)&&br(a,v);var o=i.createDocumentFragment(),l=nr;dr=e[P](null);for(var f=t[k](a),s=f?a:e[y](a),p=f?a[v]:s[v],c=0;c<p;c++){var h,g=f?c:s[c],b=f?a[c]:a[g];h=null==b||typeof b!==J?String(b):$r?mr(b,$r).val:String(g)+"_o",dr[h]&&(h+="_"+c);var A=Or[h];if(A)A[U][Pr]=b,Er&&(A[U][Er]=g);else{var N=r.content[D](!0),w=e[P](n);e[x](w,"_i",{value:!0});var E=Ar(w);E[Pr]=b,Er&&(E[Er]=g);for(var S=t[m][_][d](N.childNodes),T=[],$=0;$<S[v];$++)Z(S[$],E,T);A={nodes:t[m][_][d](N.childNodes),scope:E,cleanups:T},Or[h]=A}if(A[Y][0]!==l[j]){for($=0;$<A[Y][v];$++)o.appendChild(A[Y][$]);l[O][M](o,l[j])}l=A[Y][A[Y][v]-1],dr[h]=!0}for(var C in Or)dr[C]||(Or[C][X][u](r=>r()),Or[C][Y][u](r=>r[F]()),delete Or[C])},hr))}}if(r.hasAttributes())for(var jr=r.attributes,Cr=jr[v];Cr--;){var Lr=jr[Cr],qr=Lr[T],Mr=Lr[f];if(58===qr[ar](0)){var Dr=qr[_](1),Fr=33===Mr[ar](0),Kr=Fr?Mr[_](1):Mr;cr=-1===Kr[p](".")?Kr:Kr[c]("."),$[s]({type:lr,name:Dr,path:cr,neg:Fr})}else if(115===qr[ar](0)&&45===qr[ar](1)){let e=qr[_](2),t=-1===Mr[p](".")?Mr:Mr[c](".");if(e===tr||e===er)((e,t)=>{var a=mr(n,t);typeof a.val===W&&(e===tr?hr(()=>{var e=a.val[d](a.ctx,r);typeof e===W&&o[s](e)}):o[s](()=>a.val[d](a.ctx,r)))})(e,t);else if("effect"===e)o[s](kr(()=>{var e=mr(n,t);typeof e.val===W&&e.val[d](e.ctx,r)},hr));else if(e===I){$[s]({type:f,path:t}),r._s=n,r._h=r._h||{};var Br=r[S]===R||r[S]===z||"SELECT"===r[E]?"change":H;Br===H&&(r[B]("compositionstart",()=>r._c=!0),r[B]("compositionend",()=>{r._c=!1,C({target:r,type:H})})),(r._h[Br]=r._h[Br]||[])[s]({model:!0,p:t}),L(Br)}else"ref"===e?h.$refs[Mr]=r:Nr[e]?$[s]({type:e,path:t}):(r._s=n,r._h=r._h||{},(r._h[e]=r._h[e]||[])[Q]({p:t}),L(e))}}$[v]&&o[s](kr(()=>{for(var e=$[v];e--;){var t=$[e],a=mr(n,t.path),o=typeof a.val===W?a.val[d](a.ctx,r):a.val;t[S]===lr?(t.neg&&(o=!o),t[T]===G?Nr[G](r,o):Nr[lr](r,o,t[T])):Nr[t[S]](r,o)}},hr));for(var Hr=r.firstChild;Hr;){var Rr=Hr[j];Z(Hr,n,o),Hr=Rr}}};Z(a,h,g),h[tr]&&h[tr]();var nr={unmount:()=>{h[er]&&h[er][d](h);for(var r=g[v];r--;)g[r]();for(var e in b)a.removeEventListener(e,C);a._m=null}};return a._m=nr,nr}},Er=r=>{if(!r||typeof r!==J)return r;var e=r._t||r;if(t[k](e))return e.map(r=>Er(r));var a={};for(var n in e)a[n]=Er(e[n]);return a};return{data:(r,e)=>{sr[r]=e},start:()=>{for(var r=i.querySelectorAll("[s-data]"),e=r[v];e--;)wr(r[e])},store:(e,t)=>{if(void 0===t)return r[e];r[e]=t;var a=r[e];return a&&typeof a[tr]===W&&a[tr][d](a),a},raw:Er,mount:r=>wr(r),unmount:r=>{r&&r._m&&r._m[ir]()}}})();window.spiki=spiki})();
1
+ (()=>{"use strict";var spiki=(()=>{var r,e=Object,t=Array,a=Reflect,n=Promise,o=Node,i=document,l=console,f="length",v="value",s="push",u="forEach",p="indexOf",c="split",_="slice",d="call",y="keys",h="get",m="prototype",g="hasOwnProperty",b="getPrototypeOf",x="defineProperty",P="create",k="isArray",A="getAttribute",N="setAttribute",w="removeAttribute",E="hasAttribute",S="tagName",T="type",$="name",O="checked",j="parentNode",C="nextSibling",L="textContent",q="innerHTML",M="replaceWith",D="insertBefore",F="cloneNode",K="remove",B="createTextNode",H="addEventListener",R="input",W="checkbox",z="function",G="radio",I="class",J="model",Q="object",U="unshift",V="scope",X="trim",Y="cleanups",Z="nodes",rr="deps",er="destroy",tr="init",ar="charCodeAt",nr="sched",or="string",ir="unmount",lr="attr",fr="s-data",vr="s-if",sr=e[P](null),ur=[],pr=!1,cr=null,_r=!1,dr=n.resolve(),yr={blur:1,focus:1,scroll:1,load:1,error:1,mouseenter:1,mouseleave:1,toggle:1},hr=r=>{r._q||(r._q=!0,ur[s](r),pr||(pr=!0,dr.then(()=>{var r=ur;ur=[],pr=!1;for(var e=r[f];e--;)r[e]._q=!1,r[e]()})))},mr=(r,e)=>{var a,n=r;if(typeof e===or)a=r?r[e]:void 0;else{for(var o=0,i=e[f];o<i-1&&n;)n=n[e[o++]];a=n?n[e[i-1]]:void 0}if(void 0===a){var v=t[k](e)?e.join("."):e;l.warn("[spikijs] Property undefined: "+v)}return{ctx:n,val:a}},gr={};[s,"pop","shift",U,"splice","sort","reverse"][u](r=>{gr[r]=function(...e){_r=!0;try{return t[m][r].apply(this,e)}finally{_r=!1,xr(this,f)}}});var br=(r,t)=>{if(cr){var a=r._d||(e[x](r,"_d",{value:e[P](null),writable:!0}),r._d),n=a[t]||(a[t]=[]);-1===n[p](cr)&&(n[s](cr),cr[rr][s](n))}},xr=(r,e)=>{if(!_r&&r._d&&r._d[e])for(var t=r._d[e][_](),a=0,n=t[f];a<n;a++){var o=t[a];o[nr]?o[nr](o):o()}},Pr=r=>{for(var e=r[rr][f];e--;){var t=r[rr][e],a=t[p](r);-1!==a&&(t[a]=t[t[f]-1],t.pop())}r[rr]=[]},kr=(r,e)=>{var t=()=>{Pr(t);var e=cr;cr=t;try{r()}finally{cr=e}};return t[rr]=[],t[nr]=e,t(),()=>Pr(t)},Ar=r=>{if(!r||typeof r!==Q||r._y||r instanceof o)return r;if(e[m][g][d](r,"_p"))return r._p;var n=new Proxy(r,{get:(r,n,i)=>{if("_y"===n)return i===r._p;if("_t"===n)return r;if("_d"===n)return r._d;if("_i"===n)return r._i;if(t[k](r)&&gr[g](n))return gr[n];var l=e.getOwnPropertyDescriptor(r,n);if(l&&l[h]){var f="_"+n;return f in r||kr(()=>i[f]=l[h][d](i)),i[f]}br(r,n);var v=a[h](r,n,i);return!v||typeof v!==Q||v instanceof o?v:Ar(v)},set:(r,n,o,i)=>{var l=r[n],v=t[k](r),s=v?Number(n)<r[f]:e[m][g][d](r,n);if(r._i&&!s)for(var u=e[b](r);u&&u!==e[m];){if(e[m][g][d](u,n)){var p=a.set(u,n,o);return!_r&&(o!==l||o&&typeof o===Q)&&xr(r,n),p}u=e[b](u)}return p=a.set(r,n,o,i),!_r&&p&&(!s||o!==l||o&&typeof o===Q)&&(xr(r,n),v?xr(r,f):s||xr(r,"_k")),p},deleteProperty:(r,n)=>{var o=e[m][g][d](r,n),i=a.deleteProperty(r,n);return i&&o&&(xr(r,n),t[k](r)?xr(r,f):xr(r,"_k")),i},ownKeys:r=>(br(r,"_k"),a.ownKeys(r))});return e[x](r,"_p",{value:n}),n};r=Ar({});var Nr=e[P](null);Nr.text=(r,e)=>{e=null==e?"":e,r[L]!==String(e)&&(r[L]=e)},Nr.html=(r,e)=>{r[q]!=e&&(r[q]=null==e?"":e)},Nr[v]=(r,e)=>{r[T]===W?r[O]=!!e:r[T]===G?r[O]=r[v]==e:r[v]!=e&&(r[v]=null==e?"":e)},Nr[lr]=(r,e,t)=>{if(null==e||!1===e)r[w](t);else{var a=!0===e?"":String(e);r[A](t)!==a&&r[N](t,a)}},Nr[I]=(r,t)=>{var a=r._n||"",n=e[P](null);if(a[c](/\s+/)[u](r=>r&&(n[r]=1)),typeof t===or)t[c](/\s+/)[u](r=>r&&(n[r]=1));else if(t)for(var o in t)t[o]?n[o]=1:delete n[o];var i=e[y](n).join(" ");(r[A](I)||"")!==i&&r[N](I,i)};var wr=(a,n)=>{if(a._m)return a._m;var o=a[A](fr);if(sr[o]){var l=sr[o]();n&&e.setPrototypeOf(l,n);var h=Ar(l);h.$refs={},h.$root=a,h.$store=r,h.$parent=n;var g=[],b=e[P](null),N=r=>{var t=r.target;if(r[T]!==R||!t._c)for(var n=a[j],o=r[T];t&&t!==n;){var i=t._h&&t._h[o];if(i){var l=t._s;if(!l||l.$root!==h.$root){t=t[j];continue}for(var s=i[f];s--;){var u=i[s],p=u.p;if(u[J]){var c=t[T]===W?t[O]:t[v];if(typeof c===or){var _=c[X]();_&&isFinite(_)&&(48===_[ar](0)&&1!==_[f]&&46!==_[ar](1)||(c=Number(_)))}if(typeof p===or)l&&(l[p]=c);else{for(var y=l,m=0,g=p[f]-1;m<g&&y;)y=y[p[m++]];y&&(y[p[g]]=c)}}else{var b=mr(l,p);typeof b.val===z&&(e[x](r,"currentTarget",{configurable:!0,value:t}),b.val[d](b.ctx,r))}}}t=t[j]}},L=r=>{b[r]||(b[r]=!0,a[H](r,N,!!yr[r]))},q=(r,n,o)=>{if(1===r.nodeType&&!r[E]("s-ignore"))if(r!==a&&r[E](fr)){var l=wr(r,n);l&&o[s](l[ir])}else{var g=r[A](vr),b=!g&&"TEMPLATE"===r[S]&&r[A]("s-for"),O=[];if(r[E](I)&&!r._n&&(r._n=r[A](I)),g){var rr=i[B](""),nr=null,or=[];r[M](rr);var sr="!"===g[0],ur=sr?g[_](1):g,pr=-1===ur[p](".")?ur:ur[c](".");return o[s](()=>{for(var r=or[f];r--;)or[r]()}),o[s](kr(()=>{var e=mr(n,pr).val;if(sr&&(e=!e),e)nr||((nr=r[F](!0))[w](vr),q(nr,n,or),rr[j][D](nr,rr));else if(nr){for(var t=or[f];t--;)or[t]();or=[],nr[K](),nr=null}},hr))}if(b){var cr=b[p](" in ");if(-1!==cr){var _r,dr=b[_](0,cr)[X](),yr=b[_](cr+4)[X](),gr=dr.replace(/[()]/g,"")[c](","),xr=gr[0][X](),Pr=gr[1]?gr[1][X]():null,Er=-1===yr[p](".")?yr:yr[c]("."),Sr=r[A]("s-key"),Tr=Sr?-1===Sr[p](".")?Sr:Sr[c]("."):null,$r=(rr=i[B](""),e[P](null));return r[M](rr),o[s](()=>{for(var r in $r)$r[r][Y][u](r=>r())}),o[s](kr(()=>{var a=mr(n,Er).val||[];"number"==typeof a&&(a=t.from({length:Math.max(0,Math.floor(a))},(r,e)=>e+1)),t[k](a)&&br(a,f);var o=i.createDocumentFragment(),l=rr;_r=e[P](null);for(var v=t[k](a),s=v?a:e[y](a),p=v?a[f]:s[f],c=0;c<p;c++){var h,g=v?c:s[c],b=v?a[c]:a[g];h=null==b||typeof b!==Q?String(b):Tr?mr(b,Tr).val:String(g)+"_o",_r[h]&&(h+="_"+c);var A=$r[h];if(A)A[V][xr]=b,Pr&&(A[V][Pr]=g);else{var N=r.content[F](!0),w=e[P](n);e[x](w,"_i",{value:!0});var E=Ar(w);E[xr]=b,Pr&&(E[Pr]=g);for(var S=t[m][_][d](N.childNodes),T=[],$=0;$<S[f];$++)q(S[$],E,T);A={nodes:t[m][_][d](N.childNodes),scope:E,cleanups:T},$r[h]=A}if(A[Z][0]!==l[C]){for($=0;$<A[Z][f];$++)o.appendChild(A[Z][$]);l[j][D](o,l[C])}l=A[Z][A[Z][f]-1],_r[h]=!0}for(var O in $r)_r[O]||($r[O][Y][u](r=>r()),$r[O][Z][u](r=>r[K]()),delete $r[O])},hr))}}if(r.hasAttributes())for(var Or=r.attributes,jr=Or[f];jr--;){var Cr=Or[jr],Lr=Cr[$],qr=Cr[v];if(58===Lr[ar](0)){var Mr=Lr[_](1),Dr=33===qr[ar](0),Fr=Dr?qr[_](1):qr;pr=-1===Fr[p](".")?Fr:Fr[c]("."),O[s]({type:lr,name:Mr,path:pr,neg:Dr})}else if(115===Lr[ar](0)&&45===Lr[ar](1)){let e=Lr[_](2),t=-1===qr[p](".")?qr:qr[c](".");if(e===tr||e===er)((e,t)=>{var a=mr(n,t);typeof a.val===z&&(e===tr?hr(()=>{var e=a.val[d](a.ctx,r);typeof e===z&&o[s](e)}):o[s](()=>a.val[d](a.ctx,r)))})(e,t);else if("effect"===e)o[s](kr(()=>{var e=mr(n,t);typeof e.val===z&&e.val[d](e.ctx,r)},hr));else if(e===J){O[s]({type:v,path:t}),r._s=n,r._h=r._h||{};var Kr=r[T]===W||r[T]===G||"SELECT"===r[S]?"change":R;Kr===R&&(r[H]("compositionstart",()=>r._c=!0),r[H]("compositionend",()=>{r._c=!1,N({target:r,type:R})})),(r._h[Kr]=r._h[Kr]||[])[s]({model:!0,p:t}),L(Kr)}else"ref"===e?h.$refs[qr]=r:Nr[e]?O[s]({type:e,path:t}):(r._s=n,r._h=r._h||{},(r._h[e]=r._h[e]||[])[U]({p:t}),L(e))}}O[f]&&o[s](kr(()=>{for(var e=O[f];e--;){var t=O[e],a=mr(n,t.path),o=typeof a.val===z?a.val[d](a.ctx,r):a.val;t[T]===lr?(t.neg&&(o=!o),t[$]===I?Nr[I](r,o):Nr[lr](r,o,t[$])):Nr[t[T]](r,o)}},hr));for(var Br=r.firstChild;Br;){var Hr=Br[C];q(Br,n,o),Br=Hr}}};q(a,h,g),h[tr]&&h[tr]();var rr={unmount:()=>{h[er]&&h[er][d](h);for(var r=g[f];r--;)g[r]();for(var e in b)a.removeEventListener(e,N);a._m=null}};return a._m=rr,rr}},Er=r=>{if(!r||typeof r!==Q)return r;var e=r._t||r;if(t[k](e))return e.map(r=>Er(r));var a={};for(var n in e)a[n]=Er(e[n]);return a};return{data:(r,e)=>{sr[r]=e},start:()=>{for(var r=i.querySelectorAll("[s-data]"),e=r[f];e--;)wr(r[e])},store:(e,t)=>{if(void 0===t)return r[e];r[e]=t;var a=r[e];return a&&typeof a[tr]===z&&a[tr][d](a),a},raw:Er,mount:r=>wr(r),unmount:r=>{r&&r._m&&r._m[ir]()}}})();window.spiki=spiki})();