dalila 1.3.2 → 1.4.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/README.md +87 -611
- package/dist/context/auto-scope.d.ts +65 -0
- package/dist/context/auto-scope.js +28 -0
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/raw.d.ts +1 -1
- package/dist/context/raw.js +1 -1
- package/dist/core/dev.d.ts +5 -0
- package/dist/core/dev.js +7 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/persist.d.ts +63 -0
- package/dist/core/persist.js +371 -0
- package/dist/core/scope.d.ts +17 -0
- package/dist/core/scope.js +29 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/runtime/bind.d.ts +59 -0
- package/dist/runtime/bind.js +336 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.js +9 -0
- package/package.json +18 -1
- package/dist/compiler/dalila-lang.d.ts +0 -85
- package/dist/compiler/dalila-lang.js +0 -442
- package/dist/dom/elements.d.ts +0 -15
- package/dist/dom/elements.js +0 -100
- package/dist/dom/events.d.ts +0 -7
- package/dist/dom/events.js +0 -47
- package/dist/dom/index.d.ts +0 -2
- package/dist/dom/index.js +0 -2
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
// dalila Template Language Compiler v0.1
|
|
2
|
-
// SPEC Implementation
|
|
3
|
-
export function isElementNode(node) {
|
|
4
|
-
return node.type === 'element';
|
|
5
|
-
}
|
|
6
|
-
export function isTextNode(node) {
|
|
7
|
-
return node.type === 'text';
|
|
8
|
-
}
|
|
9
|
-
export function isInterpolationNode(node) {
|
|
10
|
-
return node.type === 'interpolation';
|
|
11
|
-
}
|
|
12
|
-
// Parser
|
|
13
|
-
export class DalilaParser {
|
|
14
|
-
constructor(input) {
|
|
15
|
-
this.position = 0;
|
|
16
|
-
this.line = 1;
|
|
17
|
-
this.column = 1;
|
|
18
|
-
this.rawTextTags = new Set(['pre', 'code']);
|
|
19
|
-
this.input = input;
|
|
20
|
-
}
|
|
21
|
-
parse() {
|
|
22
|
-
const diagnostics = [];
|
|
23
|
-
const ast = [];
|
|
24
|
-
try {
|
|
25
|
-
while (!this.isAtEnd()) {
|
|
26
|
-
this.skipWhitespace();
|
|
27
|
-
if (this.isAtEnd())
|
|
28
|
-
break;
|
|
29
|
-
if (this.peek() === '<') {
|
|
30
|
-
const element = this.parseElement();
|
|
31
|
-
if (element) {
|
|
32
|
-
ast.push(element);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
// Parse text content
|
|
37
|
-
const text = this.parseText(true);
|
|
38
|
-
if (text) {
|
|
39
|
-
if (isTextNode(text)) {
|
|
40
|
-
ast.push(text);
|
|
41
|
-
}
|
|
42
|
-
else if (isInterpolationNode(text)) {
|
|
43
|
-
ast.push(text);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
51
|
-
diagnostics.push({
|
|
52
|
-
message: `Parse error: ${errorMessage}`,
|
|
53
|
-
line: this.line,
|
|
54
|
-
column: this.column,
|
|
55
|
-
severity: 'error'
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
return { ast, diagnostics };
|
|
59
|
-
}
|
|
60
|
-
parseElement() {
|
|
61
|
-
if (!this.match('<'))
|
|
62
|
-
return null;
|
|
63
|
-
const startLocation = this.currentLocation();
|
|
64
|
-
// Parse tag name
|
|
65
|
-
const tagName = this.parseTagName();
|
|
66
|
-
if (!tagName) {
|
|
67
|
-
throw new Error('Expected tag name after <');
|
|
68
|
-
}
|
|
69
|
-
// Parse attributes
|
|
70
|
-
const attributes = this.parseAttributes();
|
|
71
|
-
// Check if self-closing
|
|
72
|
-
const selfClosing = this.match('/>');
|
|
73
|
-
let children = [];
|
|
74
|
-
if (!selfClosing) {
|
|
75
|
-
if (!this.match('>')) {
|
|
76
|
-
throw new Error('Expected > after tag attributes');
|
|
77
|
-
}
|
|
78
|
-
// Parse children until closing tag
|
|
79
|
-
children = [];
|
|
80
|
-
const allowInterpolation = !this.rawTextTags.has(tagName);
|
|
81
|
-
while (!this.isAtEnd() && !this.lookingAt(`</${tagName}`)) {
|
|
82
|
-
this.skipWhitespace();
|
|
83
|
-
if (this.lookingAt(`</${tagName}`))
|
|
84
|
-
break;
|
|
85
|
-
if (this.peek() === '<') {
|
|
86
|
-
const childElement = this.parseElement();
|
|
87
|
-
if (childElement) {
|
|
88
|
-
children.push(childElement);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
const text = this.parseText(allowInterpolation);
|
|
93
|
-
if (text) {
|
|
94
|
-
children.push(text);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
// Parse closing tag
|
|
99
|
-
if (!this.match(`</${tagName}>`)) {
|
|
100
|
-
throw new Error(`Expected closing tag </${tagName}>`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return {
|
|
104
|
-
type: 'element',
|
|
105
|
-
tagName,
|
|
106
|
-
attributes,
|
|
107
|
-
children,
|
|
108
|
-
selfClosing,
|
|
109
|
-
location: startLocation
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
parseTagName() {
|
|
113
|
-
let name = '';
|
|
114
|
-
while (!this.isAtEnd() && /[a-zA-Z0-9\-_]/.test(this.peek())) {
|
|
115
|
-
name += this.advance();
|
|
116
|
-
}
|
|
117
|
-
return name || null;
|
|
118
|
-
}
|
|
119
|
-
parseAttributes() {
|
|
120
|
-
const attributes = [];
|
|
121
|
-
while (!this.isAtEnd() && !['>', '/>'].includes(this.peek(2))) {
|
|
122
|
-
this.skipWhitespace();
|
|
123
|
-
if (['>', '/>'].includes(this.peek(2)))
|
|
124
|
-
break;
|
|
125
|
-
const attr = this.parseAttribute();
|
|
126
|
-
if (attr) {
|
|
127
|
-
attributes.push(attr);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return attributes;
|
|
131
|
-
}
|
|
132
|
-
parseAttribute() {
|
|
133
|
-
const startLocation = this.currentLocation();
|
|
134
|
-
// Parse attribute name
|
|
135
|
-
let name = '';
|
|
136
|
-
while (!this.isAtEnd() && /[a-zA-Z0-9\-_:]/.test(this.peek())) {
|
|
137
|
-
name += this.advance();
|
|
138
|
-
}
|
|
139
|
-
if (!name)
|
|
140
|
-
return null;
|
|
141
|
-
this.skipWhitespace();
|
|
142
|
-
let value = null;
|
|
143
|
-
if (this.match('=')) {
|
|
144
|
-
this.skipWhitespace();
|
|
145
|
-
if (this.match('"')) {
|
|
146
|
-
// Parse string literal or interpolation
|
|
147
|
-
if (this.peek() === '{') {
|
|
148
|
-
const interpolation = this.parseInterpolation();
|
|
149
|
-
if (interpolation) {
|
|
150
|
-
value = interpolation;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
// Parse string literal
|
|
155
|
-
let str = '';
|
|
156
|
-
while (!this.isAtEnd() && this.peek() !== '"') {
|
|
157
|
-
str += this.advance();
|
|
158
|
-
}
|
|
159
|
-
value = str;
|
|
160
|
-
}
|
|
161
|
-
this.match('"'); // consume closing quote
|
|
162
|
-
}
|
|
163
|
-
else if (this.peek() === '{') {
|
|
164
|
-
value = this.parseInterpolation();
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return {
|
|
168
|
-
name,
|
|
169
|
-
value,
|
|
170
|
-
location: startLocation
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
parseInterpolation() {
|
|
174
|
-
if (!this.match('{'))
|
|
175
|
-
return null;
|
|
176
|
-
const startLocation = this.currentLocation();
|
|
177
|
-
this.skipWhitespace();
|
|
178
|
-
// Parse identifier
|
|
179
|
-
let identifier = '';
|
|
180
|
-
while (!this.isAtEnd() && /[a-zA-Z_$][a-zA-Z0-9_$]*/.test(this.peek())) {
|
|
181
|
-
identifier += this.advance();
|
|
182
|
-
}
|
|
183
|
-
this.skipWhitespace();
|
|
184
|
-
if (!this.match('}')) {
|
|
185
|
-
throw new Error('Expected } to close interpolation');
|
|
186
|
-
}
|
|
187
|
-
if (!identifier) {
|
|
188
|
-
throw new Error('Expected identifier in interpolation');
|
|
189
|
-
}
|
|
190
|
-
return {
|
|
191
|
-
type: 'interpolation',
|
|
192
|
-
identifier,
|
|
193
|
-
location: startLocation
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
parseText(allowInterpolation) {
|
|
197
|
-
const startLocation = this.currentLocation();
|
|
198
|
-
let content = '';
|
|
199
|
-
while (!this.isAtEnd() && this.peek() !== '<') {
|
|
200
|
-
if (allowInterpolation && this.peek() === '{') {
|
|
201
|
-
// Found interpolation in text
|
|
202
|
-
if (content) {
|
|
203
|
-
// Return text node up to interpolation
|
|
204
|
-
this.backup(content.length);
|
|
205
|
-
return {
|
|
206
|
-
type: 'text',
|
|
207
|
-
content,
|
|
208
|
-
location: startLocation
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
// Parse interpolation
|
|
212
|
-
const interpolation = this.parseInterpolation();
|
|
213
|
-
if (interpolation) {
|
|
214
|
-
return interpolation;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
content += this.advance();
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (!content.trim())
|
|
222
|
-
return null;
|
|
223
|
-
return {
|
|
224
|
-
type: 'text',
|
|
225
|
-
content,
|
|
226
|
-
location: startLocation
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
skipWhitespace() {
|
|
230
|
-
while (!this.isAtEnd() && /\s/.test(this.peek())) {
|
|
231
|
-
if (this.peek() === '\n') {
|
|
232
|
-
this.line++;
|
|
233
|
-
this.column = 1;
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
this.column++;
|
|
237
|
-
}
|
|
238
|
-
this.position++;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
match(expected) {
|
|
242
|
-
if (this.lookingAt(expected)) {
|
|
243
|
-
for (let i = 0; i < expected.length; i++) {
|
|
244
|
-
if (expected[i] === '\n') {
|
|
245
|
-
this.line++;
|
|
246
|
-
this.column = 1;
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
this.column++;
|
|
250
|
-
}
|
|
251
|
-
this.position++;
|
|
252
|
-
}
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
return false;
|
|
256
|
-
}
|
|
257
|
-
lookingAt(expected) {
|
|
258
|
-
for (let i = 0; i < expected.length; i++) {
|
|
259
|
-
if (this.position + i >= this.input.length ||
|
|
260
|
-
this.input[this.position + i] !== expected[i]) {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return true;
|
|
265
|
-
}
|
|
266
|
-
peek(n = 1) {
|
|
267
|
-
const start = this.position;
|
|
268
|
-
return this.input.slice(start, start + n);
|
|
269
|
-
}
|
|
270
|
-
advance() {
|
|
271
|
-
if (this.isAtEnd())
|
|
272
|
-
return '\0';
|
|
273
|
-
const char = this.input[this.position++];
|
|
274
|
-
if (char === '\n') {
|
|
275
|
-
this.line++;
|
|
276
|
-
this.column = 1;
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
this.column++;
|
|
280
|
-
}
|
|
281
|
-
return char;
|
|
282
|
-
}
|
|
283
|
-
backup(count) {
|
|
284
|
-
for (let i = 0; i < count; i++) {
|
|
285
|
-
this.position--;
|
|
286
|
-
const char = this.input[this.position];
|
|
287
|
-
if (char === '\n') {
|
|
288
|
-
this.line--;
|
|
289
|
-
// Note: column would need more complex tracking
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
this.column--;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
isAtEnd() {
|
|
297
|
-
return this.position >= this.input.length;
|
|
298
|
-
}
|
|
299
|
-
currentLocation() {
|
|
300
|
-
return {
|
|
301
|
-
line: this.line,
|
|
302
|
-
column: this.column,
|
|
303
|
-
offset: this.position
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
// Code Generator
|
|
308
|
-
export class DalilaCodeGenerator {
|
|
309
|
-
constructor() {
|
|
310
|
-
this.indentLevel = 0;
|
|
311
|
-
this.output = [];
|
|
312
|
-
}
|
|
313
|
-
generate(ast, componentName) {
|
|
314
|
-
this.output = [];
|
|
315
|
-
const diagnostics = [];
|
|
316
|
-
this.emit(`import { watch } from '../core/watch.js';`);
|
|
317
|
-
this.emit('');
|
|
318
|
-
this.emit(`export function render${componentName}(ctx: any): Node {`);
|
|
319
|
-
this.indentLevel++;
|
|
320
|
-
// Generate root fragment or single element
|
|
321
|
-
if (ast.length === 1 && ast[0].type === 'element') {
|
|
322
|
-
this.generateElement(ast[0], 'root');
|
|
323
|
-
}
|
|
324
|
-
else {
|
|
325
|
-
this.emit('const root = document.createDocumentFragment();');
|
|
326
|
-
for (let i = 0; i < ast.length; i++) {
|
|
327
|
-
const node = ast[i];
|
|
328
|
-
const varName = `node_${i}`;
|
|
329
|
-
if (node.type === 'element') {
|
|
330
|
-
this.generateElement(node, varName);
|
|
331
|
-
}
|
|
332
|
-
else if (node.type === 'text') {
|
|
333
|
-
this.emit(`const ${varName} = document.createTextNode(${JSON.stringify(node.content)});`);
|
|
334
|
-
}
|
|
335
|
-
else if (node.type === 'interpolation') {
|
|
336
|
-
this.generateTextInterpolation(node, varName);
|
|
337
|
-
}
|
|
338
|
-
this.emit(`root.append(${varName});`);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
this.emit('return root;');
|
|
342
|
-
this.indentLevel--;
|
|
343
|
-
this.emit('}');
|
|
344
|
-
// Generate type definition (simplified)
|
|
345
|
-
const typeDef = this.generateTypeDefinition(componentName, ast);
|
|
346
|
-
return {
|
|
347
|
-
source: this.output.join('\n'),
|
|
348
|
-
typeDefinition: typeDef,
|
|
349
|
-
diagnostics
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
generateElement(node, varName) {
|
|
353
|
-
this.emit(`const ${varName} = document.createElement(${JSON.stringify(node.tagName)});`);
|
|
354
|
-
// Generate attributes
|
|
355
|
-
for (const attr of node.attributes) {
|
|
356
|
-
this.generateAttribute(varName, attr);
|
|
357
|
-
}
|
|
358
|
-
// Generate children
|
|
359
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
360
|
-
const child = node.children[i];
|
|
361
|
-
const childVar = `${varName}_child_${i}`;
|
|
362
|
-
if (child.type === 'element') {
|
|
363
|
-
this.generateElement(child, childVar);
|
|
364
|
-
this.emit(`${varName}.append(${childVar});`);
|
|
365
|
-
}
|
|
366
|
-
else if (child.type === 'text') {
|
|
367
|
-
this.emit(`${varName}.append(${JSON.stringify(child.content)});`);
|
|
368
|
-
}
|
|
369
|
-
else if (child.type === 'interpolation') {
|
|
370
|
-
this.generateTextInterpolation(child, childVar);
|
|
371
|
-
this.emit(`${varName}.append(${childVar});`);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
generateAttribute(elementVar, attr) {
|
|
376
|
-
const attrName = attr.name;
|
|
377
|
-
if (attr.value === null) {
|
|
378
|
-
// Boolean attribute
|
|
379
|
-
this.emit(`${elementVar}.setAttribute(${JSON.stringify(attrName)}, '');`);
|
|
380
|
-
}
|
|
381
|
-
else if (typeof attr.value === 'string') {
|
|
382
|
-
// String literal
|
|
383
|
-
this.emit(`${elementVar}.setAttribute(${JSON.stringify(attrName)}, ${JSON.stringify(attr.value)});`);
|
|
384
|
-
}
|
|
385
|
-
else if (attr.value.type === 'interpolation') {
|
|
386
|
-
// Dynamic attribute
|
|
387
|
-
if (attrName.startsWith('on:')) {
|
|
388
|
-
// Event handler
|
|
389
|
-
const eventName = attrName.slice(3); // remove 'on:'
|
|
390
|
-
this.emit(`${elementVar}.addEventListener(${JSON.stringify(eventName)}, ctx.${attr.value.identifier});`);
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
// Attribute binding
|
|
394
|
-
const watchFn = `() => {
|
|
395
|
-
const value = ctx.${attr.value.identifier}();
|
|
396
|
-
if (value == null || value === false) {
|
|
397
|
-
${elementVar}.removeAttribute(${JSON.stringify(attrName)});
|
|
398
|
-
} else {
|
|
399
|
-
${elementVar}.setAttribute(${JSON.stringify(attrName)}, String(value));
|
|
400
|
-
}
|
|
401
|
-
}`;
|
|
402
|
-
this.emit(`watch(${elementVar}, ${watchFn});`);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
generateTextInterpolation(node, varName) {
|
|
407
|
-
this.emit(`const ${varName} = document.createTextNode('');`);
|
|
408
|
-
const watchFn = `() => {
|
|
409
|
-
${varName}.data = String(ctx.${node.identifier}() ?? '');
|
|
410
|
-
}`;
|
|
411
|
-
this.emit(`watch(${varName}, ${watchFn});`);
|
|
412
|
-
}
|
|
413
|
-
generateTypeDefinition(componentName, ast) {
|
|
414
|
-
// Simplified type generation - in a real implementation this would analyze all usages
|
|
415
|
-
return `export interface ${componentName}Ctx {
|
|
416
|
-
// Type definition would be inferred from template usage
|
|
417
|
-
[key: string]: any;
|
|
418
|
-
}`;
|
|
419
|
-
}
|
|
420
|
-
emit(line) {
|
|
421
|
-
const indent = ' '.repeat(this.indentLevel);
|
|
422
|
-
this.output.push(indent + line);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
// Main Compiler
|
|
426
|
-
export function compileDalilaTemplate(template) {
|
|
427
|
-
const parser = new DalilaParser(template.content);
|
|
428
|
-
const { ast, diagnostics } = parser.parse();
|
|
429
|
-
if (diagnostics.some(d => d.severity === 'error')) {
|
|
430
|
-
return {
|
|
431
|
-
source: '',
|
|
432
|
-
typeDefinition: '',
|
|
433
|
-
diagnostics
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
const generator = new DalilaCodeGenerator();
|
|
437
|
-
const result = generator.generate(ast, template.componentName);
|
|
438
|
-
return {
|
|
439
|
-
...result,
|
|
440
|
-
diagnostics: [...diagnostics, ...result.diagnostics]
|
|
441
|
-
};
|
|
442
|
-
}
|
package/dist/dom/elements.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare function div(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLDivElement;
|
|
2
|
-
export declare function span(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLSpanElement;
|
|
3
|
-
export declare function p(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLParagraphElement;
|
|
4
|
-
export declare function h1(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLHeadingElement;
|
|
5
|
-
export declare function h2(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLHeadingElement;
|
|
6
|
-
export declare function h3(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLHeadingElement;
|
|
7
|
-
export declare function button(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLButtonElement;
|
|
8
|
-
export declare function input(attrs?: Record<string, any>): HTMLInputElement;
|
|
9
|
-
export declare function a(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLAnchorElement;
|
|
10
|
-
export declare function ul(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLUListElement;
|
|
11
|
-
export declare function li(children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLLIElement;
|
|
12
|
-
export declare function createElement<K extends keyof HTMLElementTagNameMap>(tag: K, children?: Node | Node[] | string, attrs?: Record<string, any>): HTMLElementTagNameMap[K];
|
|
13
|
-
export declare function fragment(...children: Node[]): DocumentFragment;
|
|
14
|
-
import { Signal } from '../core/signal.js';
|
|
15
|
-
export declare function text(content: string | Signal<any>): Text;
|
package/dist/dom/elements.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// DOM element creation utilities
|
|
2
|
-
export function div(children, attrs) {
|
|
3
|
-
return createElement('div', children, attrs);
|
|
4
|
-
}
|
|
5
|
-
export function span(children, attrs) {
|
|
6
|
-
return createElement('span', children, attrs);
|
|
7
|
-
}
|
|
8
|
-
export function p(children, attrs) {
|
|
9
|
-
return createElement('p', children, attrs);
|
|
10
|
-
}
|
|
11
|
-
export function h1(children, attrs) {
|
|
12
|
-
return createElement('h1', children, attrs);
|
|
13
|
-
}
|
|
14
|
-
export function h2(children, attrs) {
|
|
15
|
-
return createElement('h2', children, attrs);
|
|
16
|
-
}
|
|
17
|
-
export function h3(children, attrs) {
|
|
18
|
-
return createElement('h3', children, attrs);
|
|
19
|
-
}
|
|
20
|
-
export function button(children, attrs) {
|
|
21
|
-
return createElement('button', children, attrs);
|
|
22
|
-
}
|
|
23
|
-
export function input(attrs) {
|
|
24
|
-
return createElement('input', undefined, attrs);
|
|
25
|
-
}
|
|
26
|
-
export function a(children, attrs) {
|
|
27
|
-
return createElement('a', children, attrs);
|
|
28
|
-
}
|
|
29
|
-
export function ul(children, attrs) {
|
|
30
|
-
return createElement('ul', children, attrs);
|
|
31
|
-
}
|
|
32
|
-
export function li(children, attrs) {
|
|
33
|
-
return createElement('li', children, attrs);
|
|
34
|
-
}
|
|
35
|
-
export function createElement(tag, children, attrs) {
|
|
36
|
-
const element = document.createElement(tag);
|
|
37
|
-
let resolvedChildren = children;
|
|
38
|
-
let resolvedAttrs = attrs;
|
|
39
|
-
const isAttrsObject = (value) => value !== null &&
|
|
40
|
-
typeof value === 'object' &&
|
|
41
|
-
!Array.isArray(value) &&
|
|
42
|
-
!(value instanceof Node);
|
|
43
|
-
const isChildValue = (value) => value === undefined ||
|
|
44
|
-
typeof value === 'string' ||
|
|
45
|
-
value instanceof Node ||
|
|
46
|
-
Array.isArray(value);
|
|
47
|
-
if (isAttrsObject(children) && (attrs === undefined || isChildValue(attrs))) {
|
|
48
|
-
resolvedAttrs = children;
|
|
49
|
-
resolvedChildren = attrs;
|
|
50
|
-
}
|
|
51
|
-
// Set attributes
|
|
52
|
-
if (resolvedAttrs) {
|
|
53
|
-
Object.entries(resolvedAttrs).forEach(([key, value]) => {
|
|
54
|
-
if (key === 'class') {
|
|
55
|
-
element.className = value;
|
|
56
|
-
}
|
|
57
|
-
else if (key === 'style' && typeof value === 'object') {
|
|
58
|
-
Object.assign(element.style, value);
|
|
59
|
-
}
|
|
60
|
-
else if (key.startsWith('on') && typeof value === 'function') {
|
|
61
|
-
const eventName = key.slice(2).toLowerCase();
|
|
62
|
-
element.addEventListener(eventName, value);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
element.setAttribute(key, String(value));
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
// Add children
|
|
70
|
-
if (resolvedChildren !== undefined) {
|
|
71
|
-
if (typeof resolvedChildren === 'string') {
|
|
72
|
-
element.textContent = resolvedChildren;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
const nodes = Array.isArray(resolvedChildren) ? resolvedChildren : [resolvedChildren];
|
|
76
|
-
element.append(...nodes);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return element;
|
|
80
|
-
}
|
|
81
|
-
// Fragment utility
|
|
82
|
-
export function fragment(...children) {
|
|
83
|
-
const frag = document.createDocumentFragment();
|
|
84
|
-
frag.append(...children);
|
|
85
|
-
return frag;
|
|
86
|
-
}
|
|
87
|
-
// Reactive text binding
|
|
88
|
-
import { effect } from '../core/signal.js';
|
|
89
|
-
export function text(content) {
|
|
90
|
-
const textNode = document.createTextNode('');
|
|
91
|
-
if (typeof content === 'string') {
|
|
92
|
-
textNode.textContent = content;
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
effect(() => {
|
|
96
|
-
textNode.textContent = String(content());
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return textNode;
|
|
100
|
-
}
|
package/dist/dom/events.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export type EventHandler<T extends Event = Event> = (event: T) => void;
|
|
2
|
-
export declare function on<K extends keyof HTMLElementEventMap>(element: Element, event: K, handler: EventHandler<HTMLElementEventMap[K]>): () => void;
|
|
3
|
-
export declare function once<K extends keyof HTMLElementEventMap>(element: Element, event: K, handler: EventHandler<HTMLElementEventMap[K]>): () => void;
|
|
4
|
-
export declare function preventDefault<T extends Event>(handler: EventHandler<T>): EventHandler<T>;
|
|
5
|
-
export declare function stopPropagation<T extends Event>(handler: EventHandler<T>): EventHandler<T>;
|
|
6
|
-
export declare function debounce<T extends Event>(handler: EventHandler<T>, delay: number): EventHandler<T>;
|
|
7
|
-
export declare function throttle<T extends Event>(handler: EventHandler<T>, delay: number): EventHandler<T>;
|
package/dist/dom/events.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export function on(element, event, handler) {
|
|
2
|
-
element.addEventListener(event, handler);
|
|
3
|
-
return () => element.removeEventListener(event, handler);
|
|
4
|
-
}
|
|
5
|
-
export function once(element, event, handler) {
|
|
6
|
-
const onceHandler = (e) => {
|
|
7
|
-
handler(e);
|
|
8
|
-
element.removeEventListener(event, onceHandler);
|
|
9
|
-
};
|
|
10
|
-
element.addEventListener(event, onceHandler);
|
|
11
|
-
return () => element.removeEventListener(event, onceHandler);
|
|
12
|
-
}
|
|
13
|
-
// Prevent default utility
|
|
14
|
-
export function preventDefault(handler) {
|
|
15
|
-
return (event) => {
|
|
16
|
-
event.preventDefault();
|
|
17
|
-
handler(event);
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
// Stop propagation utility
|
|
21
|
-
export function stopPropagation(handler) {
|
|
22
|
-
return (event) => {
|
|
23
|
-
event.stopPropagation();
|
|
24
|
-
handler(event);
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
// Debounce utility for events
|
|
28
|
-
export function debounce(handler, delay) {
|
|
29
|
-
let timeoutId = null;
|
|
30
|
-
return (event) => {
|
|
31
|
-
if (timeoutId !== null) {
|
|
32
|
-
clearTimeout(timeoutId);
|
|
33
|
-
}
|
|
34
|
-
timeoutId = window.setTimeout(() => handler(event), delay);
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
// Throttle utility for events
|
|
38
|
-
export function throttle(handler, delay) {
|
|
39
|
-
let lastCall = 0;
|
|
40
|
-
return (event) => {
|
|
41
|
-
const now = Date.now();
|
|
42
|
-
if (now - lastCall >= delay) {
|
|
43
|
-
lastCall = now;
|
|
44
|
-
handler(event);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
}
|
package/dist/dom/index.d.ts
DELETED
package/dist/dom/index.js
DELETED