@thyn/core 0.0.39 → 0.0.41

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/tests/element.js DELETED
@@ -1,587 +0,0 @@
1
- import { component, element, first, list, show } from "/element.js";
2
- import { effect, signal } from "/signals.js";
3
- import { assertEqual, it, mount, wait } from "/tests/test.js";
4
-
5
- it("creates element", () => {
6
- const p = element("p", { slot: ["foo"] });
7
- mount(p);
8
- assertEqual(p.textContent, "foo");
9
- });
10
-
11
- it("button disabled", async () => {
12
- const [count, setCount] = signal(0);
13
- const btn = element("button", {
14
- disabled: true,
15
- onclick: () => setCount(c => c + 1),
16
- slot: [count],
17
- });
18
- mount(btn);
19
- assertEqual(btn.textContent, "0");
20
- btn.click();
21
- await wait();
22
- assertEqual(btn.textContent, "0");
23
- });
24
-
25
- it("sets aria- attributes", () => {
26
- const btn = element("button", { "aria-label": "foo" });
27
- mount(btn);
28
- assertEqual(btn.getAttribute("aria-label"), "foo");
29
- });
30
-
31
- it("sets aria- properties", () => {
32
- const btn = element("button", { ariaLabel: "foo" });
33
- mount(btn);
34
- assertEqual(btn.getAttribute("aria-label"), "foo");
35
- });
36
-
37
- it("sets aria- attributes", () => {
38
- const btn = element("button", { ariaLabel: "foo" });
39
- mount(btn);
40
- assertEqual(btn.getAttribute("aria-label"), "foo");
41
- });
42
-
43
- it("sets data- attributes", () => {
44
- const btn = element("button", { "data-foo": "foo" });
45
- mount(btn);
46
- assertEqual(btn.dataset.foo, "foo");
47
- });
48
-
49
- it("set class name", () => {
50
- const btn = element("button", { class: "foo" });
51
- mount(btn);
52
- assertEqual(btn.classList.contains("foo"), true);
53
- });
54
-
55
- it("don't set class name if undefined", () => {
56
- const btn = element("button", { class: undefined });
57
- mount(btn);
58
- assertEqual(btn.classList.length, 0);
59
- });
60
-
61
- it("don't set class name if null", () => {
62
- const btn = element("button", { class: false });
63
- mount(btn);
64
- assertEqual(btn.classList.length, 0);
65
- });
66
-
67
- it("remove class name if changed to undefined", async () => {
68
- const [className, setClassName] = signal("foo")
69
- const btn = element("button", { class: className, onclick: () => setClassName(n => n ? undefined : "foo") });
70
- mount(btn);
71
- assertEqual(btn.classList.contains("foo"), true);
72
- btn.click();
73
- await wait();
74
- assertEqual(btn.classList.length, 0);
75
- });
76
-
77
- it("creates component", () => {
78
- const p = props => element("p", { slot: [props.text] });
79
- const div = element("div", {
80
- slot: [component(p, { text: "foo" })],
81
- });
82
- mount(div);
83
- assertEqual(div.textContent, "foo");
84
- });
85
-
86
- it("first with no default first component", () => {
87
- const div = element("div", {
88
- slot: [component(first, {
89
- cases: [],
90
- })],
91
- });
92
- mount(div);
93
- assertEqual(div.textContent, "");
94
- });
95
-
96
- it("first with default first component", () => {
97
- const div = element("div", {
98
- slot: [component(first, {
99
- cases: [],
100
- default: () => element("p", { slot: ["foo"] }),
101
- })],
102
- });
103
- mount(div);
104
- assertEqual(div.textContent, "foo");
105
- });
106
-
107
- it("show then to empty", async () => {
108
- const [vis, setVis] = signal(true);
109
- const div = element("div", {
110
- slot: [component(show, {
111
- if: vis,
112
- then: () => element("p", { slot: ["foo"] }),
113
- })],
114
- onclick: () => setVis(v => !v),
115
- });
116
- mount(div);
117
- assertEqual(div.textContent, "foo");
118
- div.click();
119
- await wait();
120
- assertEqual(div.textContent, "");
121
- div.click();
122
- await wait();
123
- assertEqual(div.textContent, "foo");
124
- });
125
-
126
- it("show empty to then", async () => {
127
- const [vis, setVis] = signal(false);
128
- const div = element("div", {
129
- slot: [component(show, {
130
- if: vis,
131
- then: () => element("p", { slot: ["foo"] }),
132
- })],
133
- onclick: () => setVis(v => !v),
134
- });
135
- mount(div);
136
- assertEqual(div.textContent, "");
137
- div.click();
138
- await wait();
139
- assertEqual(div.textContent, "foo");
140
- div.click();
141
- await wait();
142
- assertEqual(div.textContent, "");
143
- });
144
-
145
- it("show true to else", async () => {
146
- const [vis, setVis] = signal(true);
147
- const div = element("div", {
148
- slot: [component(show, {
149
- if: vis,
150
- then: () => element("p", { slot: ["foo"] }),
151
- else: () => element("p", { slot: ["bar"] }),
152
- })],
153
- onclick: () => setVis(v => !v),
154
- });
155
- mount(div);
156
- assertEqual(div.textContent, "foo");
157
- div.click();
158
- await wait();
159
- assertEqual(div.textContent, "bar");
160
- div.click();
161
- await wait();
162
- assertEqual(div.textContent, "foo");
163
- });
164
-
165
- it("responds to signal in slot", async () => {
166
- const [count, setCount] = signal(0);
167
- const p = element("p", {
168
- slot: [count],
169
- onclick: () => setCount(c => c + 1),
170
- });
171
- mount(p);
172
- assertEqual(p.textContent, "0");
173
- p.click();
174
- await wait();
175
- assertEqual(p.textContent, "1");
176
- });
177
-
178
- it("responds to signal in class name", async () => {
179
- const [name, setName] = signal("foo");
180
- const p = element("p", {
181
- class: name,
182
- onclick: () => setName("bar"),
183
- });
184
- mount(p);
185
- assertEqual(p.className, "foo");
186
- p.click();
187
- await wait();
188
- assertEqual(p.className, "bar");
189
- });
190
-
191
- it("responds to computed signal", async () => {
192
- const [count, setCount] = signal(0);
193
- const double = () => count() * 2;
194
- const p = element("p", {
195
- slot: [double],
196
- onclick: () => setCount(c => c + 1),
197
- });
198
- mount(p);
199
- assertEqual(p.textContent, "0");
200
- p.click();
201
- await wait();
202
- assertEqual(p.textContent, "2");
203
- p.click();
204
- await wait();
205
- assertEqual(p.textContent, "4");
206
- });
207
-
208
- it("list: siblings - append to empty", async () => {
209
- const [nums, setNums] = signal([]);
210
- const div = element("div", {
211
- slot: [
212
- element("p", { slot: ["foo"] }),
213
- component(list, {
214
- items: nums,
215
- key: n => n,
216
- render: n => element("p", { slot: [n] }),
217
- }),
218
- element("p", { slot: ["bar"] }),
219
- ],
220
- onclick: () => setNums(old => [...old, old.length]),
221
- });
222
- mount(div);
223
- assertEqual(div.textContent, "foobar");
224
- div.click();
225
- await wait();
226
- assertEqual(div.textContent, "foo0bar");
227
- div.click();
228
- await wait();
229
- assertEqual(div.textContent, "foo01bar");
230
- });
231
-
232
- it("list: siblings - modify", async () => {
233
- const [nums, setNums] = signal([0, 1]);
234
- const div = element("div", {
235
- slot: [
236
- element("p", { slot: ["foo"] }),
237
- component(list, {
238
- items: nums,
239
- key: n => n,
240
- render: n => element("p", { slot: [n] }),
241
- }),
242
- element("p", { slot: ["bar"] }),
243
- ],
244
- onclick: () => setNums([2, 3]),
245
- });
246
- mount(div);
247
- assertEqual(div.textContent, "foo01bar");
248
- div.click();
249
- await wait();
250
- assertEqual(div.textContent, "foo23bar");
251
- });
252
-
253
- it("list: append to empty", async () => {
254
- const [nums, setNums] = signal([]);
255
- const div = element("div", {
256
- slot: [component(list, {
257
-
258
- items: nums,
259
- key: n => n,
260
- render: n => element("p", { slot: [n] }),
261
- })],
262
- onclick: () => setNums(old => [...old, old.length]),
263
- });
264
- mount(div);
265
- assertEqual(div.textContent, "");
266
- div.click();
267
- await wait();
268
- assertEqual(div.textContent, "0");
269
- div.click();
270
- await wait();
271
- assertEqual(div.textContent, "01");
272
- });
273
-
274
- it("list: reverse 2", async () => {
275
- const [nums, setNums] = signal([0, 1]);
276
- const div = element("div", {
277
- slot: [component(list, {
278
-
279
- items: nums,
280
- key: n => n,
281
- render: n => element("p", { slot: [n] }),
282
- })],
283
- onclick: () => setNums(ns => {
284
- const nns = [...ns];
285
- nns.reverse();
286
- return nns;
287
- }),
288
- });
289
- mount(div);
290
- assertEqual(div.textContent, "01");
291
- div.click();
292
- await wait();
293
- assertEqual(div.textContent, "10");
294
- div.click();
295
- await wait();
296
- assertEqual(div.textContent, "01");
297
- });
298
-
299
- it("list: reverse 3", async () => {
300
- const [nums, setNums] = signal([0, 1, 2]);
301
- const div = element("div", {
302
- slot: [component(list, {
303
-
304
- items: nums,
305
- key: n => n,
306
- render: n => element("p", { slot: [n] }),
307
- })],
308
- onclick: () => setNums(ns => {
309
- const nns = [...ns];
310
- nns.reverse();
311
- return nns;
312
- }),
313
- });
314
- mount(div);
315
- assertEqual(div.textContent, "012");
316
- div.click();
317
- await wait();
318
- assertEqual(div.textContent, "210");
319
- div.click();
320
- await wait();
321
- assertEqual(div.textContent, "012");
322
- });
323
-
324
- it("list: reverse 4", async () => {
325
- const [nums, setNums] = signal([0, 1, 2, 3]);
326
- const div = element("div", {
327
- slot: [component(list, {
328
-
329
- items: nums,
330
- key: n => n,
331
- render: n => element("p", { slot: [n] }),
332
- })],
333
- onclick: () => setNums(ns => {
334
- const nns = [...ns];
335
- nns.reverse();
336
- return nns;
337
- }),
338
- });
339
- mount(div);
340
- assertEqual(div.textContent, "0123");
341
- div.click();
342
- await wait();
343
- assertEqual(div.textContent, "3210");
344
- div.click();
345
- await wait();
346
- assertEqual(div.textContent, "0123");
347
- });
348
-
349
- it("list: sort", async () => {
350
- const [nums, setNums] = signal([2, 3, 1, 0, 8, 4, 5, 6, 7]);
351
- const div = element("div", {
352
- slot: [component(list, {
353
-
354
- items: nums,
355
- key: n => n,
356
- render: n => element("p", { slot: [n] }),
357
- })],
358
- onclick: () => setNums(ns => {
359
- const nns = [...ns];
360
- nns.sort();
361
- return nns;
362
- }),
363
- });
364
- mount(div);
365
- assertEqual(div.textContent, "231084567");
366
- div.click();
367
- await wait();
368
- assertEqual(div.textContent, "012345678");
369
- });
370
-
371
- it("list: append", async () => {
372
- const [nums, setNums] = signal([0, 1]);
373
- const div = element("div", {
374
- slot: [component(list, {
375
-
376
- items: nums,
377
- key: n => n,
378
- render: n => element("p", { slot: [n] }),
379
- })],
380
- onclick: () => setNums(ns => [...ns, ns.length]),
381
- });
382
- mount(div);
383
- assertEqual(div.textContent, "01");
384
- div.click();
385
- await wait();
386
- assertEqual(div.textContent, "012");
387
- div.click();
388
- await wait();
389
- assertEqual(div.textContent, "0123");
390
- });
391
-
392
- it("list: replace all", async () => {
393
- const [nums, setNums] = signal([0, 1]);
394
- const div = element("div", {
395
- slot: [component(list, {
396
-
397
- items: nums,
398
- key: n => n,
399
- render: n => element("p", { slot: [n] }),
400
- })],
401
- onclick: () => setNums(() => [2, 3]),
402
- });
403
- mount(div);
404
- assertEqual(div.textContent, "01");
405
- div.click();
406
- await wait();
407
- assertEqual(div.textContent, "23");
408
- });
409
-
410
- it("list: splice", async () => {
411
- const [nums, setNums] = signal([0, 1]);
412
- const div = element("div", {
413
- slot: [component(list, {
414
-
415
- items: nums,
416
- key: n => n,
417
- render: n => element("p", { slot: [n] }),
418
- })],
419
- onclick: () => setNums(() => [0, 2, 1]),
420
- });
421
- mount(div);
422
- assertEqual(div.textContent, "01");
423
- div.click();
424
- await wait();
425
- assertEqual(div.textContent, "021");
426
- });
427
-
428
- it("list: prepend", async () => {
429
- const [nums, setNums] = signal([0]);
430
- const div = element("div", {
431
- slot: [component(list, {
432
-
433
- items: nums,
434
- key: n => n,
435
- render: n => element("p", { slot: [n] }),
436
- })],
437
- onclick: () => setNums(ns => [ns.length, ...ns]),
438
- });
439
- mount(div);
440
- assertEqual(div.textContent, "0");
441
- div.click();
442
- await wait();
443
- assertEqual(div.textContent, "10");
444
- div.click();
445
- await wait();
446
- assertEqual(div.textContent, "210");
447
- });
448
-
449
- it("list: truncate", async () => {
450
- const [nums, setNums] = signal([0, 1, 2, 3]);
451
- const div = element("div", {
452
- slot: [component(list, {
453
-
454
- items: nums,
455
- key: n => n,
456
- render: n => element("p", { slot: [n] }),
457
- })],
458
- onclick: () => setNums(ns => ns.slice(0, -1)),
459
- });
460
- mount(div);
461
- assertEqual(div.textContent, "0123");
462
- div.click();
463
- await wait();
464
- assertEqual(div.textContent, "012");
465
- div.click();
466
- await wait();
467
- assertEqual(div.textContent, "01");
468
- });
469
-
470
- it("list: remove from middle", async () => {
471
- const [nums, setNums] = signal([0, 1, 2, 3]);
472
- const div = element("div", {
473
- slot: [component(list, {
474
-
475
- items: nums,
476
- key: n => n,
477
- render: n => element("p", { slot: [n] }),
478
- })],
479
- onclick: () => setNums(ns => ns.filter((_, i) => i !== 1)),
480
- });
481
- mount(div);
482
- assertEqual(div.textContent, "0123");
483
- div.click();
484
- await wait();
485
- assertEqual(div.textContent, "023");
486
- div.click();
487
- await wait();
488
- assertEqual(div.textContent, "03");
489
- });
490
-
491
- it("list: insert into middle", async () => {
492
- const [nums, setNums] = signal([0, 1, 2, 3]);
493
- const div = element("div", {
494
- slot: [component(list, {
495
-
496
- items: nums,
497
- key: n => n,
498
- render: n => element("p", { slot: [n] }),
499
- })],
500
- onclick: () => setNums(ns => [...ns.slice(0, 1), ns.length, ...ns.slice(1)]),
501
- });
502
- mount(div);
503
- assertEqual(div.textContent, "0123");
504
- div.click();
505
- await wait();
506
- assertEqual(div.textContent, "04123");
507
- div.click();
508
- await wait();
509
- assertEqual(div.textContent, "054123");
510
- });
511
-
512
- it("list: new content", async () => {
513
- const [foos, setFoos] = signal([
514
- { id: 1, foo: "bar" },
515
- { id: 2, foo: "baz" },
516
- ]);
517
- const div = element("div", {
518
- slot: [component(list, {
519
-
520
- items: foos,
521
- key: foo => foo.id,
522
- render: foo => element("p", { slot: foo.foo }),
523
- })],
524
- onclick: () => setFoos(ns => ns.map(f => f.id === 1 ? { id: 1, foo: "bat" } : f)),
525
- });
526
- mount(div);
527
- assertEqual(div.textContent, "barbaz");
528
- div.click();
529
- await wait();
530
- assertEqual(div.textContent, "batbaz");
531
- });
532
-
533
- it("list: new item refs memo no change", async () => {
534
- const renderCnt = { value: 0 };
535
- const getFoos = () => [
536
- { id: 1, foo: "bar" },
537
- { id: 2, foo: "baz" },
538
- ];
539
- const [foos, setFoos] = signal(getFoos());
540
- const div = element("div", {
541
- slot: [component(list, {
542
-
543
- items: foos,
544
- key: foo => foo.id,
545
- memo: foo => [foo.id],
546
- render: foo => {
547
- renderCnt.value++;
548
- return element("p", { slot: foo.foo });
549
- },
550
- })],
551
- onclick: () => setFoos(getFoos()),
552
- });
553
- mount(div);
554
- assertEqual(div.textContent, "barbaz");
555
- assertEqual(renderCnt.value, 2);
556
- div.click();
557
- await wait();
558
- assertEqual(div.textContent, "barbaz");
559
- assertEqual(renderCnt.value, 2);
560
- });
561
-
562
- it("unmount component", async () => {
563
- const unmounted = { value: false };
564
- const foo = () => {
565
- effect(() => () => unmounted.value = true);
566
- return element("p", { slot: ["foo"] });
567
- };
568
- const [show, setShow] = signal(true);
569
- const div = element("div", {
570
- slot: [
571
- element("button", {
572
- slot: "remove",
573
- onclick: () => setShow(s => !s),
574
- }),
575
- component(first, {
576
- cases: [{ condition: show, element: () => component(foo) }],
577
- }),
578
- ],
579
- });
580
- mount(div);
581
- assertEqual(div.textContent, "removefoo");
582
- const btn = div.querySelector("button");
583
- btn.click();
584
- await wait();
585
- assertEqual(div.textContent, "remove");
586
- assertEqual(unmounted.value, true);
587
- });
package/tests/index.html DELETED
@@ -1,54 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
-
4
- <head>
5
- <title>Tests</title>
6
- <style>
7
- body {
8
- background: #333;
9
- color: #fff;
10
- margin: 0;
11
- padding: 20px;
12
- }
13
-
14
- h2 {
15
- margin-top: 0;
16
- }
17
-
18
- .test-result {
19
- margin: 0;
20
- margin-bottom: 5px;
21
- padding: 5px 20px;
22
- border-left: 5px solid;
23
- border-radius: 3px;
24
- }
25
-
26
- .success {
27
- border-color: #393;
28
- background-color: #252;
29
- }
30
-
31
- .failure {
32
- border-color: #933;
33
- background-color: #533;
34
- }
35
-
36
- pre {
37
- margin: 0;
38
- margin-top: 10px;
39
- padding: 10px;
40
- border-radius: 3px;
41
- overflow-x: auto;
42
- background: rgba(0, 0, 0, 0.25);
43
- }
44
- </style>
45
- </head>
46
-
47
- <body>
48
- <div id="test-results">
49
- <h2 id="results-summary"></h2>
50
- </div>
51
- <script src="/tests/test.js" type="module"></script>
52
- </body>
53
-
54
- </html>
package/tests/test.js DELETED
@@ -1,70 +0,0 @@
1
- const resultsContainer = document.getElementById('test-results');
2
-
3
- function createResultElement(description, isSuccess, error = null) {
4
- const p = document.createElement('p');
5
- p.classList.add('test-result');
6
- if (isSuccess) {
7
- p.classList.add('success');
8
- p.innerHTML = `&#10004;&nbsp;&nbsp;&nbsp;${description}`;
9
- p.title = 'Passed';
10
- window.dispatchEvent(new CustomEvent("test-result", { detail: { pass: true } }));
11
- } else {
12
- p.classList.add('failure');
13
- p.innerHTML = `&#10006;&nbsp;&nbsp;&nbsp;${description}`;
14
- p.title = 'Failed';
15
- if (error) {
16
- const pre = document.createElement('pre');
17
- pre.textContent = error.stack || error.message;
18
- p.appendChild(pre);
19
- }
20
- window.dispatchEvent(new CustomEvent("test-result", { detail: { pass: false } }));
21
- }
22
- resultsContainer.appendChild(p);
23
- }
24
-
25
- const root = document.createElement("div");
26
- document.body.appendChild(root);
27
-
28
- export async function it(description, testFunction) {
29
- try {
30
- await testFunction();
31
- createResultElement(description, true);
32
- } catch (e) {
33
- createResultElement(description, false, e);
34
- } finally {
35
- root.innerText = "";
36
- }
37
- }
38
-
39
- export function assertEqual(actual, expected) {
40
- if (actual !== expected) {
41
- throw new Error(`Expected ${expected} but got ${actual}`);
42
- }
43
- }
44
-
45
- export function mount(el) {
46
- root.appendChild(el);
47
- }
48
-
49
-
50
- export function wait() {
51
- return new Promise(r => setTimeout(r, 10));
52
- }
53
-
54
- let totalTests = 0;
55
- let passedTests = 0;
56
- const resultsSummary = document.querySelector("#results-summary");
57
- window.addEventListener("test-result", e => {
58
- if (e.detail.pass) {
59
- passedTests++;
60
- }
61
- totalTests++;
62
- resultsSummary.textContent = `Tests completed: ${passedTests} / ${totalTests} passed.`;
63
- if (passedTests === totalTests) {
64
- resultsSummary.style.color = 'green';
65
- } else {
66
- resultsSummary.style.color = 'red';
67
- }
68
- });
69
-
70
- import("/tests/element.js");