@inglorious/web 4.0.6 → 4.0.8
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 +356 -15
- package/package.json +4 -1
- package/src/index.js +1 -1
- package/src/list/index.js +30 -19
- package/src/select/rendering.js +2 -2
- package/src/table/rendering.js +20 -11
- package/src/test.js +2 -0
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ It's that simple — and surprisingly fast in practice.
|
|
|
89
89
|
|
|
90
90
|
This framework is ideal for both small apps and large business UIs.
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
---
|
|
93
93
|
|
|
94
94
|
## When NOT to Use Inglorious Web
|
|
95
95
|
|
|
@@ -125,7 +125,7 @@ These systems are powerful but introduce:
|
|
|
125
125
|
✔ **Every UI update is a full diff pass**
|
|
126
126
|
✔ **Every part of the system is just JavaScript**
|
|
127
127
|
✔ **No special lifecycle**
|
|
128
|
-
✔ **No subscriptions needed**
|
|
128
|
+
✔ **No subscriptions needed**
|
|
129
129
|
✔ **No signals**
|
|
130
130
|
✔ **No cleanup**
|
|
131
131
|
✔ **No surprises**
|
|
@@ -139,13 +139,13 @@ This makes it especially suitable for:
|
|
|
139
139
|
|
|
140
140
|
---
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
## Comparison with Other Frameworks
|
|
143
143
|
|
|
144
144
|
Here's how @inglorious/web compares to the major players:
|
|
145
145
|
|
|
146
146
|
---
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
### **React**
|
|
149
149
|
|
|
150
150
|
| Feature | React | Inglorious Web |
|
|
151
151
|
| ------------------------- | ----------------------------- | ---------------------------------- |
|
|
@@ -162,7 +162,7 @@ React is powerful but complicated. Inglorious Web is simpler, lighter, and close
|
|
|
162
162
|
|
|
163
163
|
---
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
### **Vue (3)**
|
|
166
166
|
|
|
167
167
|
| Feature | Vue | Inglorious Web |
|
|
168
168
|
| --------------- | -------------------------- | ----------------------------------- |
|
|
@@ -176,7 +176,7 @@ Vue reactivity is elegant but complex. Inglorious Web avoids proxies and keeps e
|
|
|
176
176
|
|
|
177
177
|
---
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
### **Svelte**
|
|
180
180
|
|
|
181
181
|
| Feature | Svelte | Inglorious Web |
|
|
182
182
|
| -------------- | --------------------------- | ------------------ |
|
|
@@ -189,7 +189,7 @@ Svelte is magic; Inglorious Web is explicit.
|
|
|
189
189
|
|
|
190
190
|
---
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
### **SolidJS**
|
|
193
193
|
|
|
194
194
|
| Feature | Solid | Inglorious Web |
|
|
195
195
|
| ---------- | -------------------- | ------------------ |
|
|
@@ -198,12 +198,12 @@ Svelte is magic; Inglorious Web is explicit.
|
|
|
198
198
|
| Cleanup | Required | None |
|
|
199
199
|
| Behavior | Highly optimized | Highly predictable |
|
|
200
200
|
|
|
201
|
-
Solid is extremely fast but requires a mental model.
|
|
201
|
+
Solid is extremely fast but requires a mental model shift.
|
|
202
202
|
Inglorious Web trades peak performance for simplicity and zero overhead.
|
|
203
203
|
|
|
204
204
|
---
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
### **Qwik**
|
|
207
207
|
|
|
208
208
|
| Feature | Qwik | Inglorious Web |
|
|
209
209
|
| -------------------- | -------------------- | -------------- |
|
|
@@ -216,13 +216,13 @@ Inglorious Web is minimal, predictable, and tiny.
|
|
|
216
216
|
|
|
217
217
|
---
|
|
218
218
|
|
|
219
|
-
|
|
219
|
+
### **HTMX / Alpine / Vanilla DOM**
|
|
220
220
|
|
|
221
221
|
Inglorious Web is closer philosophically to **HTMX** and **vanilla JS**, but with a declarative rendering model and entity-based state.
|
|
222
222
|
|
|
223
223
|
---
|
|
224
224
|
|
|
225
|
-
|
|
225
|
+
## Why Choose Inglorious Web
|
|
226
226
|
|
|
227
227
|
- Minimalistic
|
|
228
228
|
- Pure JavaScript
|
|
@@ -260,8 +260,7 @@ import { createStore, html } from "@inglorious/web"
|
|
|
260
260
|
|
|
261
261
|
const types = {
|
|
262
262
|
counter: {
|
|
263
|
-
increment(entity
|
|
264
|
-
if (entity.id !== id) return
|
|
263
|
+
increment(entity) {
|
|
265
264
|
entity.value++
|
|
266
265
|
},
|
|
267
266
|
|
|
@@ -270,7 +269,9 @@ const types = {
|
|
|
270
269
|
return html`
|
|
271
270
|
<div>
|
|
272
271
|
<span>Count: ${entity.value}</span>
|
|
273
|
-
<button @click=${() => api.notify(
|
|
272
|
+
<button @click=${() => api.notify(`#${entity.id}:increment`)}>
|
|
273
|
+
+1
|
|
274
|
+
</button>
|
|
274
275
|
</div>
|
|
275
276
|
`
|
|
276
277
|
},
|
|
@@ -312,6 +313,346 @@ The `mount` function subscribes to the store and automatically re-renders your t
|
|
|
312
313
|
|
|
313
314
|
---
|
|
314
315
|
|
|
316
|
+
## Testing
|
|
317
|
+
|
|
318
|
+
One of Inglorious Web's greatest strengths is **testability**. Entity handlers are pure functions (via Mutative.js), and render functions return simple templates. No special testing libraries, no complex setup, no mocking hell.
|
|
319
|
+
|
|
320
|
+
### Testing Utilities
|
|
321
|
+
|
|
322
|
+
Inglorious Web provides two simple utilities for testing via `@inglorious/web/test`:
|
|
323
|
+
|
|
324
|
+
#### `trigger(entity, handler, payload?, api?)`
|
|
325
|
+
|
|
326
|
+
Execute an entity handler and get back the new state plus any events dispatched. Handlers are wrapped in Mutative.js, so they return new immutable state even though you write mutable-looking code.
|
|
327
|
+
|
|
328
|
+
```javascript
|
|
329
|
+
import { trigger } from "@inglorious/web/test"
|
|
330
|
+
import { counter } from "./types/counter.js"
|
|
331
|
+
|
|
332
|
+
test("increment adds to value", () => {
|
|
333
|
+
const { entity, events } = trigger(
|
|
334
|
+
{ type: "counter", id: "counter1", value: 10 },
|
|
335
|
+
counter.increment,
|
|
336
|
+
{ amount: 5 },
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
expect(entity.value).toBe(15)
|
|
340
|
+
expect(events).toEqual([]) // No events dispatched
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
test("increment dispatches overflow event", () => {
|
|
344
|
+
const { entity, events } = trigger(
|
|
345
|
+
{ type: "counter", id: "counter1", value: 99 },
|
|
346
|
+
counter.increment,
|
|
347
|
+
{ amount: 5 },
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
expect(entity.value).toBe(104)
|
|
351
|
+
expect(events).toEqual([{ type: "overflow", payload: { id: "counter1" } }])
|
|
352
|
+
})
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
#### `render(template)`
|
|
356
|
+
|
|
357
|
+
Render a lit-html template to an HTML string for testing. Perfect for testing render output with simple string assertions.
|
|
358
|
+
|
|
359
|
+
```javascript
|
|
360
|
+
import { render } from "@inglorious/web/test"
|
|
361
|
+
import { counter } from "./types/counter.js"
|
|
362
|
+
|
|
363
|
+
test("counter renders correctly", () => {
|
|
364
|
+
const entity = {
|
|
365
|
+
type: "counter",
|
|
366
|
+
id: "counter1",
|
|
367
|
+
value: 42,
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const mockApi = {
|
|
371
|
+
notify: jest.fn(),
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const template = counter.render(entity, mockApi)
|
|
375
|
+
const html = render(template)
|
|
376
|
+
|
|
377
|
+
expect(html).toContain("Count: 42")
|
|
378
|
+
expect(html).toContain("button")
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
test("counter button has click handler", () => {
|
|
382
|
+
const entity = { type: "counter", id: "counter1", value: 10 }
|
|
383
|
+
const mockApi = { notify: jest.fn() }
|
|
384
|
+
|
|
385
|
+
const template = counter.render(entity, mockApi)
|
|
386
|
+
const html = render(template)
|
|
387
|
+
|
|
388
|
+
expect(html).toContain("onclick")
|
|
389
|
+
})
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Why Testing is Easy
|
|
393
|
+
|
|
394
|
+
**No special setup required:**
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
npm install --save-dev vitest # or jest, or node:test
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
That's it. No `@testing-library/react`, no `renderHook`, no `act()` wrappers.
|
|
401
|
+
|
|
402
|
+
**Pure functions everywhere:**
|
|
403
|
+
|
|
404
|
+
- Entity handlers are pure (thanks to Mutative.js)
|
|
405
|
+
- Render functions are pure (they return templates)
|
|
406
|
+
- No lifecycle hooks to manage
|
|
407
|
+
- No async state updates to wrangle
|
|
408
|
+
|
|
409
|
+
**Simple assertions:**
|
|
410
|
+
|
|
411
|
+
- Test handlers: `expect(entity.value).toBe(15)`
|
|
412
|
+
- Test renders: `expect(html).toContain('expected text')`
|
|
413
|
+
- Test events: `expect(events).toHaveLength(1)`
|
|
414
|
+
|
|
415
|
+
### Testing Patterns
|
|
416
|
+
|
|
417
|
+
#### Unit Test: Handler Logic
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
import { trigger } from "@inglorious/web/test"
|
|
421
|
+
import { todo } from "./types/todo.js"
|
|
422
|
+
|
|
423
|
+
test("toggle changes completed status", () => {
|
|
424
|
+
const { entity } = trigger(
|
|
425
|
+
{ type: "todo", id: "todo1", text: "Buy milk", completed: false },
|
|
426
|
+
todo.toggle,
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
expect(entity.completed).toBe(true)
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
test("delete dispatches remove event", () => {
|
|
433
|
+
const { events } = trigger(
|
|
434
|
+
{ type: "todo", id: "todo1", text: "Buy milk" },
|
|
435
|
+
todo.delete,
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
expect(events).toEqual([{ type: "#todoList:removeTodo", payload: "todo1" }])
|
|
439
|
+
})
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
#### Unit Test: Render Output
|
|
443
|
+
|
|
444
|
+
```javascript
|
|
445
|
+
import { render } from "@inglorious/web/test"
|
|
446
|
+
import { todo } from "./types/todo.js"
|
|
447
|
+
|
|
448
|
+
test("todo renders text and status", () => {
|
|
449
|
+
const entity = {
|
|
450
|
+
type: "todo",
|
|
451
|
+
id: "todo1",
|
|
452
|
+
text: "Buy milk",
|
|
453
|
+
completed: false,
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const html = render(todo.render(entity, { notify: jest.fn() }))
|
|
457
|
+
|
|
458
|
+
expect(html).toContain("Buy milk")
|
|
459
|
+
expect(html).not.toContain("completed")
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
test("completed todo has completed class", () => {
|
|
463
|
+
const entity = {
|
|
464
|
+
type: "todo",
|
|
465
|
+
id: "todo1",
|
|
466
|
+
text: "Buy milk",
|
|
467
|
+
completed: true,
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const html = render(todo.render(entity, { notify: jest.fn() }))
|
|
471
|
+
|
|
472
|
+
expect(html).toContain("completed")
|
|
473
|
+
})
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
#### Integration Test: Full Store
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
import { createStore } from "@inglorious/web"
|
|
480
|
+
import { counter } from "./types/counter.js"
|
|
481
|
+
|
|
482
|
+
test("full user interaction flow", () => {
|
|
483
|
+
const store = createStore({
|
|
484
|
+
types: { counter },
|
|
485
|
+
entities: {
|
|
486
|
+
counter1: { type: "counter", id: "counter1", value: 0 },
|
|
487
|
+
},
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
// User clicks increment
|
|
491
|
+
store.notify("#counter1:increment", { amount: 5 })
|
|
492
|
+
expect(store.entities.counter1.value).toBe(5)
|
|
493
|
+
|
|
494
|
+
// User clicks increment again
|
|
495
|
+
store.notify("#counter1:increment", { amount: 3 })
|
|
496
|
+
expect(store.entities.counter1.value).toBe(8)
|
|
497
|
+
})
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
#### Testing Computed State
|
|
501
|
+
|
|
502
|
+
```javascript
|
|
503
|
+
import { createSelector } from "@inglorious/store"
|
|
504
|
+
|
|
505
|
+
test("filtered todos excludes completed", () => {
|
|
506
|
+
const todos = [
|
|
507
|
+
{ id: 1, text: "Buy milk", completed: false },
|
|
508
|
+
{ id: 2, text: "Walk dog", completed: true },
|
|
509
|
+
{ id: 3, text: "Write tests", completed: false },
|
|
510
|
+
]
|
|
511
|
+
|
|
512
|
+
const getActiveTodos = createSelector([() => todos], (todos) =>
|
|
513
|
+
todos.filter((t) => !t.completed),
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
const result = getActiveTodos()
|
|
517
|
+
|
|
518
|
+
expect(result).toHaveLength(2)
|
|
519
|
+
expect(result[0].text).toBe("Buy milk")
|
|
520
|
+
expect(result[1].text).toBe("Write tests")
|
|
521
|
+
})
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Comparison with React Testing
|
|
525
|
+
|
|
526
|
+
**React (with hooks):**
|
|
527
|
+
|
|
528
|
+
```javascript
|
|
529
|
+
import { renderHook, act } from "@testing-library/react"
|
|
530
|
+
|
|
531
|
+
test("counter increments", () => {
|
|
532
|
+
const { result } = renderHook(() => useCounter())
|
|
533
|
+
|
|
534
|
+
act(() => {
|
|
535
|
+
result.current.increment()
|
|
536
|
+
})
|
|
537
|
+
|
|
538
|
+
expect(result.current.count).toBe(1)
|
|
539
|
+
})
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
**Inglorious Web:**
|
|
543
|
+
|
|
544
|
+
```javascript
|
|
545
|
+
import { trigger } from "@inglorious/web/test"
|
|
546
|
+
|
|
547
|
+
test("counter increments", () => {
|
|
548
|
+
const { entity } = trigger({ value: 0 }, counter.increment)
|
|
549
|
+
|
|
550
|
+
expect(entity.value).toBe(1)
|
|
551
|
+
})
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
**The difference:**
|
|
555
|
+
|
|
556
|
+
- ❌ React requires `renderHook`, `act()`, special testing library
|
|
557
|
+
- ✅ Inglorious just calls the function directly
|
|
558
|
+
- ❌ React hooks can't be tested in isolation
|
|
559
|
+
- ✅ Inglorious handlers are just functions
|
|
560
|
+
- ❌ React has async timing issues
|
|
561
|
+
- ✅ Inglorious is synchronous and predictable
|
|
562
|
+
|
|
563
|
+
### Testing Type Composition
|
|
564
|
+
|
|
565
|
+
Type composition (like route guards) is also easy to test:
|
|
566
|
+
|
|
567
|
+
```javascript
|
|
568
|
+
import { trigger } from "@inglorious/web/test"
|
|
569
|
+
import { requireAuth } from "./guards/require-auth.js"
|
|
570
|
+
import { adminPage } from "./pages/admin.js"
|
|
571
|
+
|
|
572
|
+
test("requireAuth blocks unauthenticated access", () => {
|
|
573
|
+
// Compose the guard with the page type
|
|
574
|
+
const guardedPage = requireAuth(adminPage)
|
|
575
|
+
|
|
576
|
+
// Mock localStorage.getItem to return null (not logged in)
|
|
577
|
+
const mockApi = {
|
|
578
|
+
notify: jest.fn(),
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const { events } = trigger(
|
|
582
|
+
{ type: "adminPage", id: "admin" },
|
|
583
|
+
guardedPage.routeChange,
|
|
584
|
+
{ route: "adminPage" },
|
|
585
|
+
mockApi,
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
// Should redirect to login
|
|
589
|
+
expect(events).toContainEqual(
|
|
590
|
+
expect.objectContaining({
|
|
591
|
+
type: "navigate",
|
|
592
|
+
payload: expect.objectContaining({ to: "/login" }),
|
|
593
|
+
}),
|
|
594
|
+
)
|
|
595
|
+
})
|
|
596
|
+
|
|
597
|
+
test("requireAuth allows authenticated access", () => {
|
|
598
|
+
// Mock localStorage.getItem to return user data
|
|
599
|
+
localStorage.setItem("user", JSON.stringify({ id: 1 }))
|
|
600
|
+
|
|
601
|
+
const guardedPage = requireAuth(adminPage)
|
|
602
|
+
const mockApi = { notify: jest.fn() }
|
|
603
|
+
|
|
604
|
+
const { events } = trigger(
|
|
605
|
+
{ type: "adminPage", id: "admin" },
|
|
606
|
+
guardedPage.routeChange,
|
|
607
|
+
{ route: "adminPage" },
|
|
608
|
+
mockApi,
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
// Should NOT redirect
|
|
612
|
+
expect(events).toEqual([])
|
|
613
|
+
|
|
614
|
+
// Cleanup
|
|
615
|
+
localStorage.removeItem("user")
|
|
616
|
+
})
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Fast Test Execution
|
|
620
|
+
|
|
621
|
+
Because Inglorious tests don't mount components or manipulate the DOM, they're extremely fast:
|
|
622
|
+
|
|
623
|
+
```bash
|
|
624
|
+
# Typical test suite times
|
|
625
|
+
React: 30-60 seconds for 100 tests
|
|
626
|
+
Inglorious: 1-3 seconds for 100 tests
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
This makes TDD (Test-Driven Development) actually enjoyable. Fast feedback loops mean you'll actually run tests while coding.
|
|
630
|
+
|
|
631
|
+
### Best Practices
|
|
632
|
+
|
|
633
|
+
1. **Test handlers separately from renders** - Unit test logic, integration test UI
|
|
634
|
+
2. **Use descriptive test names** - "increment adds to value" not "test increment"
|
|
635
|
+
3. **Test edge cases** - Empty states, max values, null checks
|
|
636
|
+
4. **Keep tests simple** - One assertion per test when possible
|
|
637
|
+
5. **Don't over-mock** - Only mock what you must (usually just `api.notify`)
|
|
638
|
+
|
|
639
|
+
### When to Write Tests
|
|
640
|
+
|
|
641
|
+
- ✅ **Always test:** Complex business logic, calculations, validations
|
|
642
|
+
- ✅ **Often test:** Event handlers, state transitions, conditional renders
|
|
643
|
+
- ⚠️ **Sometimes test:** Simple getters, trivial renders
|
|
644
|
+
- ❌ **Rarely test:** Third-party components, framework internals
|
|
645
|
+
|
|
646
|
+
### The Bottom Line
|
|
647
|
+
|
|
648
|
+
If your framework makes testing painful, developers won't test. If testing is trivial, they will.
|
|
649
|
+
|
|
650
|
+
**Inglorious Web makes testing so easy that you'll actually write tests.**
|
|
651
|
+
|
|
652
|
+
No special libraries, no complex setup, just pure functions and simple assertions. Testing becomes a natural part of your workflow, not a chore you avoid.
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
315
656
|
## JSX Support
|
|
316
657
|
|
|
317
658
|
If you prefer JSX syntax over template literals, you can use **[`@inglorious/vite-plugin-jsx`](https://www.npmjs.com/package/@inglorious/vite-plugin-jsx)**.
|
|
@@ -1064,7 +1405,6 @@ import {
|
|
|
1064
1405
|
// from lit-html
|
|
1065
1406
|
mount,
|
|
1066
1407
|
html,
|
|
1067
|
-
render,
|
|
1068
1408
|
svg,
|
|
1069
1409
|
// lit-html directives
|
|
1070
1410
|
choose,
|
|
@@ -1086,6 +1426,7 @@ import {
|
|
|
1086
1426
|
import { list } from "@inglorious/web/list"
|
|
1087
1427
|
import { router } from "@inglorious/web/router"
|
|
1088
1428
|
import { select } from "@inglorious/web/select"
|
|
1429
|
+
import { render, trigger } from "@inglorious/web/test"
|
|
1089
1430
|
import { table } from "@inglorious/web/table"
|
|
1090
1431
|
```
|
|
1091
1432
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/web",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.8",
|
|
4
4
|
"description": "A new web framework that leverages the power of the Inglorious Store combined with the performance and simplicity of lit-html.",
|
|
5
5
|
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,6 +46,9 @@
|
|
|
46
46
|
"types": "./types/table.d.ts",
|
|
47
47
|
"import": "./src/table/index.js"
|
|
48
48
|
},
|
|
49
|
+
"./test": {
|
|
50
|
+
"import": "./src/test.js"
|
|
51
|
+
},
|
|
49
52
|
"./table/base.css": "./src/table/base.css",
|
|
50
53
|
"./table/theme.css": "./src/table/theme.css",
|
|
51
54
|
"./select/base.css": "./src/select/base.css",
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { createStore } from "@inglorious/store"
|
|
|
3
3
|
export { createDevtools } from "@inglorious/store/client/devtools.js"
|
|
4
4
|
export { createSelector } from "@inglorious/store/select.js"
|
|
5
5
|
export { trigger } from "@inglorious/store/test.js"
|
|
6
|
-
export { html,
|
|
6
|
+
export { html, svg } from "lit-html"
|
|
7
7
|
export { choose } from "lit-html/directives/choose.js"
|
|
8
8
|
export { classMap } from "lit-html/directives/class-map.js"
|
|
9
9
|
export { ref } from "lit-html/directives/ref.js"
|
package/src/list/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { html } from "lit-html"
|
|
2
2
|
import { ref } from "lit-html/directives/ref.js"
|
|
3
|
+
import { repeat } from "lit-html/directives/repeat.js"
|
|
3
4
|
import { styleMap } from "lit-html/directives/style-map.js"
|
|
4
5
|
|
|
5
6
|
const LIST_START = 0
|
|
@@ -108,23 +109,31 @@ export const list = {
|
|
|
108
109
|
position: "relative",
|
|
109
110
|
})}
|
|
110
111
|
>
|
|
111
|
-
${
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
112
|
+
${repeat(
|
|
113
|
+
visibleItems,
|
|
114
|
+
(item) => item.id,
|
|
115
|
+
(item, index) => {
|
|
116
|
+
const absoluteIndex = visibleRange.start + index
|
|
117
|
+
const top = absoluteIndex * height
|
|
118
|
+
|
|
119
|
+
return html`
|
|
120
|
+
<div
|
|
121
|
+
style=${styleMap({
|
|
122
|
+
position: "absolute",
|
|
123
|
+
top: `${top}px`,
|
|
124
|
+
width: "100%",
|
|
125
|
+
})}
|
|
126
|
+
data-index=${absoluteIndex}
|
|
127
|
+
>
|
|
128
|
+
${type.renderItem(
|
|
129
|
+
entity,
|
|
130
|
+
{ item, index: absoluteIndex },
|
|
131
|
+
api,
|
|
132
|
+
)}
|
|
133
|
+
</div>
|
|
134
|
+
`
|
|
135
|
+
},
|
|
136
|
+
)}
|
|
128
137
|
</div>
|
|
129
138
|
</div>
|
|
130
139
|
`
|
|
@@ -138,8 +147,10 @@ export const list = {
|
|
|
138
147
|
* @returns {TemplateResult}
|
|
139
148
|
*/
|
|
140
149
|
// eslint-disable-next-line no-unused-vars
|
|
141
|
-
renderItem(item, index, api) {
|
|
142
|
-
return html`<div
|
|
150
|
+
renderItem(entity, { item, index }, api) {
|
|
151
|
+
return html`<div class="iw-list-item">
|
|
152
|
+
${index + PRETTY_INDEX}. ${JSON.stringify(item)}
|
|
153
|
+
</div>`
|
|
143
154
|
},
|
|
144
155
|
}
|
|
145
156
|
|
package/src/select/rendering.js
CHANGED
|
@@ -226,7 +226,7 @@ export const rendering = {
|
|
|
226
226
|
${repeat(
|
|
227
227
|
filteredOptions,
|
|
228
228
|
(option) => getOptionValue(option),
|
|
229
|
-
(option, index) => type.renderOption(entity, option, index, api),
|
|
229
|
+
(option, index) => type.renderOption(entity, { option, index }, api),
|
|
230
230
|
)}
|
|
231
231
|
</div>`
|
|
232
232
|
},
|
|
@@ -239,7 +239,7 @@ export const rendering = {
|
|
|
239
239
|
* @param {Api} api
|
|
240
240
|
* @returns {TemplateResult}
|
|
241
241
|
*/
|
|
242
|
-
renderOption(entity, option, index, api) {
|
|
242
|
+
renderOption(entity, { option, index }, api) {
|
|
243
243
|
const optionLabel = getOptionLabel(option)
|
|
244
244
|
const isSelected = isOptionSelected(
|
|
245
245
|
option,
|
package/src/table/rendering.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { html } from "lit-html"
|
|
2
2
|
import { classMap } from "lit-html/directives/class-map.js"
|
|
3
3
|
import { ref } from "lit-html/directives/ref.js"
|
|
4
|
+
import { repeat } from "lit-html/directives/repeat.js"
|
|
4
5
|
|
|
5
6
|
import { filters } from "./filters.js"
|
|
6
7
|
import { getPaginationInfo, getRows, getSortDirection } from "./logic.js"
|
|
@@ -45,8 +46,11 @@ export const rendering = {
|
|
|
45
46
|
}
|
|
46
47
|
})}
|
|
47
48
|
>
|
|
48
|
-
${
|
|
49
|
-
|
|
49
|
+
${repeat(
|
|
50
|
+
entity.columns,
|
|
51
|
+
(column) => column.id,
|
|
52
|
+
(column, index) =>
|
|
53
|
+
type.renderHeaderColumn(entity, { column, index }, api),
|
|
50
54
|
)}
|
|
51
55
|
</div>
|
|
52
56
|
|
|
@@ -54,7 +58,7 @@ export const rendering = {
|
|
|
54
58
|
</div>`
|
|
55
59
|
},
|
|
56
60
|
|
|
57
|
-
renderHeaderColumn(entity, column, api) {
|
|
61
|
+
renderHeaderColumn(entity, { column }, api) {
|
|
58
62
|
return html`<div
|
|
59
63
|
class="iw-table-header-column"
|
|
60
64
|
style=${getColumnStyle(column)}
|
|
@@ -88,13 +92,15 @@ export const rendering = {
|
|
|
88
92
|
const type = api.getType(entity.type)
|
|
89
93
|
|
|
90
94
|
return html`<div class="iw-table-body">
|
|
91
|
-
${
|
|
92
|
-
|
|
95
|
+
${repeat(
|
|
96
|
+
getRows(entity),
|
|
97
|
+
(row) => row.id,
|
|
98
|
+
(row, index) => type.renderRow(entity, { row, index }, api),
|
|
93
99
|
)}
|
|
94
100
|
</div>`
|
|
95
101
|
},
|
|
96
102
|
|
|
97
|
-
renderRow(entity, row, index, api) {
|
|
103
|
+
renderRow(entity, { row, index }, api) {
|
|
98
104
|
const type = api.getType(entity.type)
|
|
99
105
|
const rowId = row[entity.rowId ?? "id"]
|
|
100
106
|
|
|
@@ -105,13 +111,16 @@ export const rendering = {
|
|
|
105
111
|
"iw-table-row-selected": entity.selection?.includes(rowId),
|
|
106
112
|
})}"
|
|
107
113
|
>
|
|
108
|
-
${
|
|
109
|
-
|
|
114
|
+
${repeat(
|
|
115
|
+
entity.columns,
|
|
116
|
+
(column) => column.id,
|
|
117
|
+
(column, index) =>
|
|
118
|
+
type.renderCell(entity, { cell: row[column.id], index }, api),
|
|
110
119
|
)}
|
|
111
120
|
</div>`
|
|
112
121
|
},
|
|
113
122
|
|
|
114
|
-
renderCell(entity, cell, index, api) {
|
|
123
|
+
renderCell(entity, { cell, index }, api) {
|
|
115
124
|
const type = api.getType(entity.type)
|
|
116
125
|
const column = entity.columns[index]
|
|
117
126
|
|
|
@@ -123,11 +132,11 @@ export const rendering = {
|
|
|
123
132
|
})}"
|
|
124
133
|
style=${getColumnStyle(column)}
|
|
125
134
|
>
|
|
126
|
-
${type.renderValue(cell, column, api)}
|
|
135
|
+
${type.renderValue(entity, { value: cell, column, index }, api)}
|
|
127
136
|
</div>`
|
|
128
137
|
},
|
|
129
138
|
|
|
130
|
-
renderValue(value) {
|
|
139
|
+
renderValue(_, { value }) {
|
|
131
140
|
return value
|
|
132
141
|
},
|
|
133
142
|
|
package/src/test.js
ADDED