pulse-js-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +182 -0
- package/cli/build.js +199 -0
- package/cli/dev.js +225 -0
- package/cli/index.js +324 -0
- package/compiler/index.js +65 -0
- package/compiler/lexer.js +581 -0
- package/compiler/parser.js +900 -0
- package/compiler/transformer.js +552 -0
- package/index.js +19 -0
- package/loader/vite-plugin.js +160 -0
- package/package.json +58 -0
- package/runtime/dom.js +484 -0
- package/runtime/index.js +13 -0
- package/runtime/pulse.js +339 -0
- package/runtime/router.js +392 -0
- package/runtime/store.js +301 -0
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pulse-js-framework",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A declarative DOM framework with CSS selector-based structure and reactive pulsations",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"pulse": "cli/index.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./index.js",
|
|
12
|
+
"./runtime": "./runtime/index.js",
|
|
13
|
+
"./runtime/*": "./runtime/*.js",
|
|
14
|
+
"./compiler": "./compiler/index.js",
|
|
15
|
+
"./vite": "./loader/vite-plugin.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"index.js",
|
|
19
|
+
"cli/",
|
|
20
|
+
"runtime/",
|
|
21
|
+
"compiler/",
|
|
22
|
+
"loader/",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"test": "node --test test/*.js"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"framework",
|
|
31
|
+
"frontend",
|
|
32
|
+
"reactive",
|
|
33
|
+
"declarative",
|
|
34
|
+
"dom",
|
|
35
|
+
"pulse",
|
|
36
|
+
"css-selectors",
|
|
37
|
+
"dsl",
|
|
38
|
+
"ui",
|
|
39
|
+
"javascript",
|
|
40
|
+
"spa",
|
|
41
|
+
"signals"
|
|
42
|
+
],
|
|
43
|
+
"author": "Your Name <your.email@example.com>",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/your-username/pulse-framework.git"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/your-username/pulse-framework#readme",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/your-username/pulse-framework/issues"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {},
|
|
57
|
+
"devDependencies": {}
|
|
58
|
+
}
|
package/runtime/dom.js
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse DOM - Declarative DOM manipulation
|
|
3
|
+
*
|
|
4
|
+
* Creates DOM elements using CSS selector-like syntax
|
|
5
|
+
* and provides reactive bindings
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { effect, pulse, batch } from './pulse.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse a CSS selector-like string into element configuration
|
|
12
|
+
* Supports: tag, #id, .class, [attr=value]
|
|
13
|
+
*
|
|
14
|
+
* Examples:
|
|
15
|
+
* "div" -> { tag: "div" }
|
|
16
|
+
* "#app" -> { tag: "div", id: "app" }
|
|
17
|
+
* ".container" -> { tag: "div", classes: ["container"] }
|
|
18
|
+
* "button.primary.large" -> { tag: "button", classes: ["primary", "large"] }
|
|
19
|
+
* "input[type=text][placeholder=Name]" -> { tag: "input", attrs: { type: "text", placeholder: "Name" } }
|
|
20
|
+
*/
|
|
21
|
+
function parseSelector(selector) {
|
|
22
|
+
const config = {
|
|
23
|
+
tag: 'div',
|
|
24
|
+
id: null,
|
|
25
|
+
classes: [],
|
|
26
|
+
attrs: {}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (!selector || selector === '') return config;
|
|
30
|
+
|
|
31
|
+
// Match tag name at the start
|
|
32
|
+
const tagMatch = selector.match(/^([a-zA-Z][a-zA-Z0-9-]*)/);
|
|
33
|
+
if (tagMatch) {
|
|
34
|
+
config.tag = tagMatch[1];
|
|
35
|
+
selector = selector.slice(tagMatch[0].length);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Match ID
|
|
39
|
+
const idMatch = selector.match(/#([a-zA-Z][a-zA-Z0-9-_]*)/);
|
|
40
|
+
if (idMatch) {
|
|
41
|
+
config.id = idMatch[1];
|
|
42
|
+
selector = selector.replace(idMatch[0], '');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Match classes
|
|
46
|
+
const classMatches = selector.matchAll(/\.([a-zA-Z][a-zA-Z0-9-_]*)/g);
|
|
47
|
+
for (const match of classMatches) {
|
|
48
|
+
config.classes.push(match[1]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Match attributes
|
|
52
|
+
const attrMatches = selector.matchAll(/\[([a-zA-Z][a-zA-Z0-9-_]*)(?:=([^\]]+))?\]/g);
|
|
53
|
+
for (const match of attrMatches) {
|
|
54
|
+
const key = match[1];
|
|
55
|
+
let value = match[2] || '';
|
|
56
|
+
// Remove quotes if present
|
|
57
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
58
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
59
|
+
value = value.slice(1, -1);
|
|
60
|
+
}
|
|
61
|
+
config.attrs[key] = value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return config;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Create a DOM element from a selector
|
|
69
|
+
*/
|
|
70
|
+
export function el(selector, ...children) {
|
|
71
|
+
const config = parseSelector(selector);
|
|
72
|
+
const element = document.createElement(config.tag);
|
|
73
|
+
|
|
74
|
+
if (config.id) {
|
|
75
|
+
element.id = config.id;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (config.classes.length > 0) {
|
|
79
|
+
element.className = config.classes.join(' ');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const [key, value] of Object.entries(config.attrs)) {
|
|
83
|
+
element.setAttribute(key, value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Process children
|
|
87
|
+
for (const child of children) {
|
|
88
|
+
appendChild(element, child);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return element;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Append a child to an element, handling various types
|
|
96
|
+
*/
|
|
97
|
+
function appendChild(parent, child) {
|
|
98
|
+
if (child == null || child === false) return;
|
|
99
|
+
|
|
100
|
+
if (typeof child === 'string' || typeof child === 'number') {
|
|
101
|
+
parent.appendChild(document.createTextNode(String(child)));
|
|
102
|
+
} else if (child instanceof Node) {
|
|
103
|
+
parent.appendChild(child);
|
|
104
|
+
} else if (Array.isArray(child)) {
|
|
105
|
+
for (const c of child) {
|
|
106
|
+
appendChild(parent, c);
|
|
107
|
+
}
|
|
108
|
+
} else if (typeof child === 'function') {
|
|
109
|
+
// Reactive child - create a placeholder and update it
|
|
110
|
+
const placeholder = document.createComment('pulse');
|
|
111
|
+
parent.appendChild(placeholder);
|
|
112
|
+
let currentNodes = [];
|
|
113
|
+
|
|
114
|
+
effect(() => {
|
|
115
|
+
const result = child();
|
|
116
|
+
|
|
117
|
+
// Remove old nodes
|
|
118
|
+
for (const node of currentNodes) {
|
|
119
|
+
node.remove();
|
|
120
|
+
}
|
|
121
|
+
currentNodes = [];
|
|
122
|
+
|
|
123
|
+
// Add new nodes
|
|
124
|
+
if (result != null && result !== false) {
|
|
125
|
+
const fragment = document.createDocumentFragment();
|
|
126
|
+
if (typeof result === 'string' || typeof result === 'number') {
|
|
127
|
+
const textNode = document.createTextNode(String(result));
|
|
128
|
+
fragment.appendChild(textNode);
|
|
129
|
+
currentNodes.push(textNode);
|
|
130
|
+
} else if (result instanceof Node) {
|
|
131
|
+
fragment.appendChild(result);
|
|
132
|
+
currentNodes.push(result);
|
|
133
|
+
} else if (Array.isArray(result)) {
|
|
134
|
+
for (const r of result) {
|
|
135
|
+
if (r instanceof Node) {
|
|
136
|
+
fragment.appendChild(r);
|
|
137
|
+
currentNodes.push(r);
|
|
138
|
+
} else if (r != null && r !== false) {
|
|
139
|
+
const textNode = document.createTextNode(String(r));
|
|
140
|
+
fragment.appendChild(textNode);
|
|
141
|
+
currentNodes.push(textNode);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
placeholder.parentNode.insertBefore(fragment, placeholder.nextSibling);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create a reactive text node
|
|
153
|
+
*/
|
|
154
|
+
export function text(getValue) {
|
|
155
|
+
if (typeof getValue === 'function') {
|
|
156
|
+
const node = document.createTextNode('');
|
|
157
|
+
effect(() => {
|
|
158
|
+
node.textContent = String(getValue());
|
|
159
|
+
});
|
|
160
|
+
return node;
|
|
161
|
+
}
|
|
162
|
+
return document.createTextNode(String(getValue));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Bind an attribute reactively
|
|
167
|
+
*/
|
|
168
|
+
export function bind(element, attr, getValue) {
|
|
169
|
+
if (typeof getValue === 'function') {
|
|
170
|
+
effect(() => {
|
|
171
|
+
const value = getValue();
|
|
172
|
+
if (value == null || value === false) {
|
|
173
|
+
element.removeAttribute(attr);
|
|
174
|
+
} else if (value === true) {
|
|
175
|
+
element.setAttribute(attr, '');
|
|
176
|
+
} else {
|
|
177
|
+
element.setAttribute(attr, String(value));
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
element.setAttribute(attr, String(getValue));
|
|
182
|
+
}
|
|
183
|
+
return element;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Bind a property reactively
|
|
188
|
+
*/
|
|
189
|
+
export function prop(element, propName, getValue) {
|
|
190
|
+
if (typeof getValue === 'function') {
|
|
191
|
+
effect(() => {
|
|
192
|
+
element[propName] = getValue();
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
element[propName] = getValue;
|
|
196
|
+
}
|
|
197
|
+
return element;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Bind CSS class reactively
|
|
202
|
+
*/
|
|
203
|
+
export function cls(element, className, condition) {
|
|
204
|
+
if (typeof condition === 'function') {
|
|
205
|
+
effect(() => {
|
|
206
|
+
if (condition()) {
|
|
207
|
+
element.classList.add(className);
|
|
208
|
+
} else {
|
|
209
|
+
element.classList.remove(className);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
} else if (condition) {
|
|
213
|
+
element.classList.add(className);
|
|
214
|
+
}
|
|
215
|
+
return element;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Bind style property reactively
|
|
220
|
+
*/
|
|
221
|
+
export function style(element, prop, getValue) {
|
|
222
|
+
if (typeof getValue === 'function') {
|
|
223
|
+
effect(() => {
|
|
224
|
+
element.style[prop] = getValue();
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
element.style[prop] = getValue;
|
|
228
|
+
}
|
|
229
|
+
return element;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Attach an event listener
|
|
234
|
+
*/
|
|
235
|
+
export function on(element, event, handler, options) {
|
|
236
|
+
element.addEventListener(event, handler, options);
|
|
237
|
+
return element;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Create a reactive list
|
|
242
|
+
*/
|
|
243
|
+
export function list(getItems, template, keyFn = (item, i) => i) {
|
|
244
|
+
const container = document.createDocumentFragment();
|
|
245
|
+
const startMarker = document.createComment('list-start');
|
|
246
|
+
const endMarker = document.createComment('list-end');
|
|
247
|
+
|
|
248
|
+
container.appendChild(startMarker);
|
|
249
|
+
container.appendChild(endMarker);
|
|
250
|
+
|
|
251
|
+
let itemNodes = new Map(); // key -> { nodes: Node[], cleanup: Function }
|
|
252
|
+
|
|
253
|
+
effect(() => {
|
|
254
|
+
const items = typeof getItems === 'function' ? getItems() : getItems.get();
|
|
255
|
+
const newKeys = new Set();
|
|
256
|
+
|
|
257
|
+
// Build new list
|
|
258
|
+
const fragment = document.createDocumentFragment();
|
|
259
|
+
const newItemNodes = new Map();
|
|
260
|
+
|
|
261
|
+
items.forEach((item, index) => {
|
|
262
|
+
const key = keyFn(item, index);
|
|
263
|
+
newKeys.add(key);
|
|
264
|
+
|
|
265
|
+
if (itemNodes.has(key)) {
|
|
266
|
+
// Reuse existing nodes
|
|
267
|
+
const existing = itemNodes.get(key);
|
|
268
|
+
for (const node of existing.nodes) {
|
|
269
|
+
fragment.appendChild(node);
|
|
270
|
+
}
|
|
271
|
+
newItemNodes.set(key, existing);
|
|
272
|
+
} else {
|
|
273
|
+
// Create new nodes
|
|
274
|
+
const result = template(item, index);
|
|
275
|
+
const nodes = Array.isArray(result) ? result : [result];
|
|
276
|
+
for (const node of nodes) {
|
|
277
|
+
fragment.appendChild(node);
|
|
278
|
+
}
|
|
279
|
+
newItemNodes.set(key, { nodes, cleanup: null });
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Remove old items
|
|
284
|
+
for (const [key, entry] of itemNodes) {
|
|
285
|
+
if (!newKeys.has(key)) {
|
|
286
|
+
for (const node of entry.nodes) {
|
|
287
|
+
node.remove();
|
|
288
|
+
}
|
|
289
|
+
if (entry.cleanup) entry.cleanup();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Clear between markers
|
|
294
|
+
let current = startMarker.nextSibling;
|
|
295
|
+
while (current && current !== endMarker) {
|
|
296
|
+
const next = current.nextSibling;
|
|
297
|
+
current.remove();
|
|
298
|
+
current = next;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Insert new fragment
|
|
302
|
+
endMarker.parentNode?.insertBefore(fragment, endMarker);
|
|
303
|
+
itemNodes = newItemNodes;
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return container;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Conditional rendering
|
|
311
|
+
*/
|
|
312
|
+
export function when(condition, thenTemplate, elseTemplate = null) {
|
|
313
|
+
const container = document.createDocumentFragment();
|
|
314
|
+
const marker = document.createComment('when');
|
|
315
|
+
container.appendChild(marker);
|
|
316
|
+
|
|
317
|
+
let currentNodes = [];
|
|
318
|
+
let currentCleanup = null;
|
|
319
|
+
|
|
320
|
+
effect(() => {
|
|
321
|
+
const show = typeof condition === 'function' ? condition() : condition.get();
|
|
322
|
+
|
|
323
|
+
// Cleanup previous
|
|
324
|
+
for (const node of currentNodes) {
|
|
325
|
+
node.remove();
|
|
326
|
+
}
|
|
327
|
+
if (currentCleanup) currentCleanup();
|
|
328
|
+
currentNodes = [];
|
|
329
|
+
currentCleanup = null;
|
|
330
|
+
|
|
331
|
+
// Render new
|
|
332
|
+
const template = show ? thenTemplate : elseTemplate;
|
|
333
|
+
if (template) {
|
|
334
|
+
const result = typeof template === 'function' ? template() : template;
|
|
335
|
+
if (result) {
|
|
336
|
+
const nodes = Array.isArray(result) ? result : [result];
|
|
337
|
+
const fragment = document.createDocumentFragment();
|
|
338
|
+
for (const node of nodes) {
|
|
339
|
+
if (node instanceof Node) {
|
|
340
|
+
fragment.appendChild(node);
|
|
341
|
+
currentNodes.push(node);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
marker.parentNode?.insertBefore(fragment, marker.nextSibling);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
return container;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Switch/case rendering
|
|
354
|
+
*/
|
|
355
|
+
export function match(getValue, cases) {
|
|
356
|
+
const marker = document.createComment('match');
|
|
357
|
+
let currentNodes = [];
|
|
358
|
+
|
|
359
|
+
effect(() => {
|
|
360
|
+
const value = typeof getValue === 'function' ? getValue() : getValue.get();
|
|
361
|
+
|
|
362
|
+
// Remove old nodes
|
|
363
|
+
for (const node of currentNodes) {
|
|
364
|
+
node.remove();
|
|
365
|
+
}
|
|
366
|
+
currentNodes = [];
|
|
367
|
+
|
|
368
|
+
// Find matching case
|
|
369
|
+
const template = cases[value] ?? cases.default;
|
|
370
|
+
if (template) {
|
|
371
|
+
const result = typeof template === 'function' ? template() : template;
|
|
372
|
+
if (result) {
|
|
373
|
+
const nodes = Array.isArray(result) ? result : [result];
|
|
374
|
+
const fragment = document.createDocumentFragment();
|
|
375
|
+
for (const node of nodes) {
|
|
376
|
+
if (node instanceof Node) {
|
|
377
|
+
fragment.appendChild(node);
|
|
378
|
+
currentNodes.push(node);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
marker.parentNode?.insertBefore(fragment, marker.nextSibling);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
return marker;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Two-way binding for form inputs
|
|
391
|
+
*/
|
|
392
|
+
export function model(element, pulseValue) {
|
|
393
|
+
const tagName = element.tagName.toLowerCase();
|
|
394
|
+
const type = element.type?.toLowerCase();
|
|
395
|
+
|
|
396
|
+
if (tagName === 'input' && (type === 'checkbox' || type === 'radio')) {
|
|
397
|
+
// Checkbox/Radio
|
|
398
|
+
effect(() => {
|
|
399
|
+
element.checked = pulseValue.get();
|
|
400
|
+
});
|
|
401
|
+
element.addEventListener('change', () => {
|
|
402
|
+
pulseValue.set(element.checked);
|
|
403
|
+
});
|
|
404
|
+
} else if (tagName === 'select') {
|
|
405
|
+
// Select
|
|
406
|
+
effect(() => {
|
|
407
|
+
element.value = pulseValue.get();
|
|
408
|
+
});
|
|
409
|
+
element.addEventListener('change', () => {
|
|
410
|
+
pulseValue.set(element.value);
|
|
411
|
+
});
|
|
412
|
+
} else {
|
|
413
|
+
// Text input, textarea, etc.
|
|
414
|
+
effect(() => {
|
|
415
|
+
if (element.value !== pulseValue.get()) {
|
|
416
|
+
element.value = pulseValue.get();
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
element.addEventListener('input', () => {
|
|
420
|
+
pulseValue.set(element.value);
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return element;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Mount an element to a target
|
|
429
|
+
*/
|
|
430
|
+
export function mount(target, element) {
|
|
431
|
+
if (typeof target === 'string') {
|
|
432
|
+
target = document.querySelector(target);
|
|
433
|
+
}
|
|
434
|
+
if (!target) {
|
|
435
|
+
throw new Error('Mount target not found');
|
|
436
|
+
}
|
|
437
|
+
target.appendChild(element);
|
|
438
|
+
return () => {
|
|
439
|
+
element.remove();
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Create a component factory
|
|
445
|
+
*/
|
|
446
|
+
export function component(setup) {
|
|
447
|
+
return (props = {}) => {
|
|
448
|
+
const state = {};
|
|
449
|
+
const methods = {};
|
|
450
|
+
|
|
451
|
+
const ctx = {
|
|
452
|
+
state,
|
|
453
|
+
methods,
|
|
454
|
+
props,
|
|
455
|
+
pulse,
|
|
456
|
+
el,
|
|
457
|
+
text,
|
|
458
|
+
list,
|
|
459
|
+
when,
|
|
460
|
+
on,
|
|
461
|
+
bind,
|
|
462
|
+
model
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
return setup(ctx);
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export default {
|
|
470
|
+
el,
|
|
471
|
+
text,
|
|
472
|
+
bind,
|
|
473
|
+
prop,
|
|
474
|
+
cls,
|
|
475
|
+
style,
|
|
476
|
+
on,
|
|
477
|
+
list,
|
|
478
|
+
when,
|
|
479
|
+
match,
|
|
480
|
+
model,
|
|
481
|
+
mount,
|
|
482
|
+
component,
|
|
483
|
+
parseSelector
|
|
484
|
+
};
|
package/runtime/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse Runtime - Main exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export * from './pulse.js';
|
|
6
|
+
export * from './dom.js';
|
|
7
|
+
export * from './router.js';
|
|
8
|
+
export * from './store.js';
|
|
9
|
+
|
|
10
|
+
export { default as PulseCore } from './pulse.js';
|
|
11
|
+
export { default as PulseDOM } from './dom.js';
|
|
12
|
+
export { default as PulseRouter } from './router.js';
|
|
13
|
+
export { default as PulseStore } from './store.js';
|