@ape-egg/vibe 1.0.5 → 1.1.2

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +228 -23
  3. package/compiler/bin/vibe-compile.js +109 -0
  4. package/compiler/native/.gitkeep +0 -0
  5. package/compiler/native/vibe-compiler-darwin-arm64 +0 -0
  6. package/compiler/src/Cargo.lock +1885 -0
  7. package/compiler/src/Cargo.toml +29 -0
  8. package/compiler/src/compiler/compile.rs +1209 -0
  9. package/compiler/src/compiler/mod.rs +5 -0
  10. package/compiler/src/config.rs +184 -0
  11. package/compiler/src/main.rs +284 -0
  12. package/compiler/src/parser/element.rs +96 -0
  13. package/compiler/src/parser/html.rs +335 -0
  14. package/compiler/src/parser/mod.rs +8 -0
  15. package/index.js +2 -248
  16. package/package.json +26 -3
  17. package/{affected.js → runtime/affected.js} +64 -4
  18. package/runtime/cleanup.js +59 -0
  19. package/runtime/component.js +116 -0
  20. package/{conditionals.js → runtime/conditionals.js} +25 -11
  21. package/{constants.js → runtime/constants.js} +23 -3
  22. package/runtime/debug.js +91 -0
  23. package/{hydrate.js → runtime/hydrate.js} +57 -7
  24. package/runtime/index.js +614 -0
  25. package/{iterate.js → runtime/iterate.js} +53 -45
  26. package/{iteration-utils.js → runtime/iteration-utils.js} +11 -1
  27. package/{parse.js → runtime/parse.js} +37 -7
  28. package/runtime/state.js +52 -0
  29. package/ROADMAP.md +0 -289
  30. package/llms.txt +0 -279
  31. package/state.js +0 -26
  32. /package/{_vibe-compiled-iteration-batch.js → runtime/_vibe-compiled-iteration-batch.js} +0 -0
  33. /package/{link.js → runtime/manifest.js} +0 -0
  34. /package/{utils.js → runtime/utils.js} +0 -0
  35. /package/{vibe.css → runtime/vibe.css} +0 -0
package/llms.txt DELETED
@@ -1,279 +0,0 @@
1
- # Vibe - Complete Documentation
2
-
3
- > Runtime-first reactivity. No virtual DOM. No build step.
4
-
5
- ## Overview
6
-
7
- Vibe is a lightweight reactive library that uses Proxy-based state and MutationObserver for fine-grained DOM updates. It works directly in the browser with zero compilation required.
8
-
9
- **Key characteristics:**
10
- - Proxy-based reactive state (`window.$`)
11
- - Surgical DOM updates (only affected elements re-render)
12
- - MutationObserver for dynamic element tracking
13
- - Works with vanilla HTML - no special file format
14
-
15
- ## Installation
16
-
17
- ```bash
18
- npm install @ape-egg/vibe
19
- ```
20
-
21
- ## Quick Start
22
-
23
- ```html
24
- <script type="module">
25
- import state from "@ape-egg/vibe";
26
- window.$ = state({ name: "World", count: 0 });
27
- </script>
28
-
29
- <h1>Hello, @[name]!</h1>
30
- <button onclick="$.count++">Clicked @[count] times</button>
31
- ```
32
-
33
- ## Core Syntax
34
-
35
- ### Reactive Bindings
36
-
37
- Use `@[property]` syntax anywhere in HTML or CSS:
38
-
39
- ```html
40
- <!-- Text content -->
41
- <div>@[firstName]</div>
42
-
43
- <!-- Expressions -->
44
- <div>@[firstName + ' ' + lastName]</div>
45
- <div>@[count * 2]</div>
46
-
47
- <!-- Attributes -->
48
- <input value="@[inputValue]">
49
- <button disabled="@[isLoading]">Submit</button>
50
-
51
- <!-- CSS -->
52
- <style>
53
- .box { background: @[themeColor]; }
54
- </style>
55
- ```
56
-
57
- ⚠️ **Important**: Bindings are evaluated using `new Function()`. Do not bind untrusted user input.
58
-
59
- ### State Access
60
-
61
- State is accessed globally via `window.$`:
62
-
63
- ```javascript
64
- // Read
65
- console.log($.firstName);
66
-
67
- // Write (triggers re-render)
68
- $.firstName = "John";
69
-
70
- // Increment
71
- $.count++;
72
- ```
73
-
74
- ## Control Flow
75
-
76
- ### Iteration
77
-
78
- ```html
79
- <!-- each items as item -->
80
- <li>@[item]</li>
81
- <!-- /each -->
82
- ```
83
-
84
- With index:
85
-
86
- ```html
87
- <!-- each items as item, index -->
88
- <li>@[index]: @[item]</li>
89
- <!-- /each -->
90
- ```
91
-
92
- ### Nested Iteration
93
-
94
- Use dot paths for nested arrays:
95
-
96
- ```html
97
- <!-- each categories as category -->
98
- <h2>@[category.name]</h2>
99
- <!-- each category.items as item -->
100
- <span>@[item.name]</span>
101
- <!-- /each -->
102
- <!-- /each -->
103
- ```
104
-
105
- ### Conditionals
106
-
107
- ```html
108
- <!-- if isLoggedIn -->
109
- <span>Welcome, @[username]!</span>
110
- <!-- else -->
111
- <span>Please log in</span>
112
- <!-- /if -->
113
- ```
114
-
115
- Conditionals can be nested inside iterations and vice versa.
116
-
117
- ## Special Attributes
118
-
119
- ### Dehydrate
120
-
121
- Skip reactive processing for an element and its children:
122
-
123
- ```html
124
- <code dehydrate>@[this] displays literally, not parsed</code>
125
- ```
126
-
127
- Use cases:
128
- - Displaying `@[...]` syntax in documentation
129
- - Static content that shouldn't be reactive
130
- - Performance optimization for large static sections
131
-
132
- ### Boolean Attributes
133
-
134
- Attributes not in the value whitelist are removed when falsy:
135
-
136
- ```html
137
- <button disabled="@[isLoading]">Submit</button>
138
- <!-- When isLoading is false, disabled attribute is removed entirely -->
139
- ```
140
-
141
- ## Events
142
-
143
- Use standard inline event handlers:
144
-
145
- ```html
146
- <button onclick="$.count++">Increment</button>
147
- <input oninput="$.text = this.value">
148
- <form onsubmit="event.preventDefault(); handleSubmit()">
149
- ```
150
-
151
- ## Styling
152
-
153
- ### CSS Bindings
154
-
155
- Reactive values work inside `<style>` tags:
156
-
157
- ```html
158
- <style>
159
- .box {
160
- background: @[backgroundColor];
161
- color: @[textColor];
162
- width: @[width]px;
163
- }
164
- </style>
165
- ```
166
-
167
- ### Preventing FOUC
168
-
169
- Hide content until hydration completes:
170
-
171
- ```html
172
- <body style="visibility: hidden;">
173
- ```
174
-
175
- Or use the included CSS:
176
-
177
- ```html
178
- <link rel="stylesheet" href="@ape-egg/vibe/vibe.css">
179
- <body vibe>
180
- ```
181
-
182
- ## Dynamic Elements
183
-
184
- Elements added via JavaScript are automatically hydrated through MutationObserver:
185
-
186
- ```javascript
187
- const div = document.createElement('div');
188
- div.innerHTML = '<span>Hello, @[name]!</span>';
189
- document.body.appendChild(div);
190
- // Automatically becomes reactive
191
- ```
192
-
193
- ## API Reference
194
-
195
- ### `state(initialState, afterUpdate?)`
196
-
197
- Creates reactive state and initializes the framework.
198
-
199
- ```javascript
200
- import state from "@ape-egg/vibe";
201
-
202
- window.$ = state(
203
- { count: 0, user: { name: "Alice" } },
204
- (newState, oldState) => {
205
- console.log("State updated:", newState);
206
- }
207
- );
208
- ```
209
-
210
- **Parameters:**
211
- - `initialState` - Object containing initial state values
212
- - `afterUpdate` - Optional callback after each state change (receives read-only snapshots)
213
-
214
- **Returns:** Proxy object for reactive state access
215
-
216
- ## Scoped Variables
217
-
218
- Inside `<!-- each -->` blocks, these variables are available:
219
- - `item` (or custom name) - current array element
220
- - `index` (or custom name) - current index
221
- - Parent state remains accessible via `$`
222
-
223
- ```html
224
- <!-- each users as user, i -->
225
- <div>@[i]: @[user.name] (total: @[users.length])</div>
226
- <!-- /each -->
227
- ```
228
-
229
- ## Architecture
230
-
231
- Vibe consists of these core modules:
232
-
233
- - **state.js** - Proxy-based reactive state container
234
- - **parse.js** - DOM parser that finds `@[...]` bindings
235
- - **link.js** - Maps elements to parsed tree nodes
236
- - **hydrate.js** - Updates DOM with current state values
237
- - **affected.js** - Determines which elements need updating
238
- - **iterate.js** - Array rendering with efficient diffing
239
- - **conditionals.js** - Conditional block rendering
240
-
241
- ## How It Works
242
-
243
- ```
244
- 1. state() initializes the Proxy and framework
245
- 2. parse.js scans DOM for @[...], <!-- each -->, <!-- if -->
246
- 3. link.js maps elements to the parsed tree
247
- 4. hydrate.js replaces bindings with values
248
- 5. iterate.js renders <!-- each --> loops
249
- 6. conditionals.js renders <!-- if --> blocks
250
- 7. MutationObserver watches for new elements
251
- 8. On state change: affected.js finds changed elements → hydrate.js updates them
252
- ```
253
-
254
- ## Current Limitations
255
-
256
- - **Top-level reactivity only**: `$.nested.prop = value` doesn't trigger updates (must replace parent object)
257
- - **No computed values**: Derived state must be calculated manually
258
- - **No two-way binding sugar**: Must wire input events manually
259
- - **Expression security**: `new Function()` evaluation - don't bind untrusted input
260
-
261
- ## Best Practices
262
-
263
- 1. **Initialize state before DOM**: Place `<script>` in `<head>` or before reactive elements
264
- 2. **Use dehydrate for docs**: When showing `@[...]` syntax examples
265
- 3. **Prevent FOUC**: Use `visibility: hidden` on body until hydration
266
- 4. **Keep expressions simple**: Complex logic belongs in JavaScript, not templates
267
- 5. **Replace objects for deep updates**: `$.user = { ...$.user, name: "New" }`
268
-
269
- ## Browser Support
270
-
271
- Modern browsers with:
272
- - Proxy (ES6)
273
- - MutationObserver
274
- - ES Modules
275
-
276
- ## Resources
277
-
278
- - **Homepage**: https://vibe.korte.kim
279
- - **npm**: https://www.npmjs.com/package/@ape-egg/vibe
package/state.js DELETED
@@ -1,26 +0,0 @@
1
- export default (state, rerender) =>
2
- new Proxy(state, {
3
- set(obj, prop, value) {
4
- const ref = Reflect.set(...arguments);
5
- rerender({
6
- [prop]: value,
7
- });
8
- // console.info("state change", { obj, prop, value });
9
- return ref;
10
- },
11
- get(target, prop) {
12
- // if (typeof target[prop] === 'function') {
13
- // const inputString = target[prop].toString();
14
- // const regex = /\$\.\w+/g;
15
- // let match;
16
- // while ((match = regex.exec(inputString))) {
17
- // const varName = match[0].split('.')[1];
18
- // console.log(varName, state[varName]);
19
- // }
20
- // console.log(arguments)
21
-
22
- // }
23
-
24
- return Reflect.get(...arguments);
25
- },
26
- });
File without changes
File without changes
File without changes