@inglorious/web 2.5.0 → 2.6.1
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 +218 -6
- package/package.json +5 -3
- package/src/form.js +15 -11
- package/src/form.test.js +17 -17
- package/src/index.js +1 -0
- package/src/list.js +39 -5
- package/src/list.test.js +7 -7
- package/src/router.js +5 -0
- package/src/router.test.js +6 -14
- package/src/select/base.css +52 -0
- package/src/select/logic.js +332 -0
- package/src/select/rendering.js +352 -0
- package/src/select/theme.css +133 -0
- package/src/select.js +7 -0
- package/src/select.test.js +415 -0
- package/src/table/logic.js +177 -5
- package/src/table.test.js +24 -3
- package/types/form.d.ts +2 -12
- package/types/index.d.ts +4 -0
- package/types/list.d.ts +76 -0
- package/types/select.d.ts +136 -0
- package/types/table.d.ts +232 -0
package/src/table/logic.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
/* eslint-disable no-magic-numbers */
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import('../../types/table').TableEntity} TableEntity
|
|
5
|
+
* @typedef {import('../../types/table').TableColumn} TableColumn
|
|
6
|
+
*/
|
|
7
7
|
|
|
8
|
+
export const logic = {
|
|
9
|
+
/**
|
|
10
|
+
* Resets the table entity with default state.
|
|
11
|
+
* @param {TableEntity} entity
|
|
12
|
+
*/
|
|
8
13
|
create(entity) {
|
|
9
14
|
initTable(entity)
|
|
10
15
|
},
|
|
11
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Toggles sorting for a column.
|
|
19
|
+
* @param {TableEntity} entity
|
|
20
|
+
* @param {string} columnId
|
|
21
|
+
*/
|
|
12
22
|
sortChange(entity, columnId) {
|
|
13
23
|
const column = entity.columns.find((c) => c.id === columnId)
|
|
14
24
|
if (!column?.isSortable) return
|
|
@@ -34,10 +44,19 @@ export const logic = {
|
|
|
34
44
|
}
|
|
35
45
|
},
|
|
36
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Clears all sorts.
|
|
49
|
+
* @param {TableEntity} entity
|
|
50
|
+
*/
|
|
37
51
|
sortsClear(entity) {
|
|
38
52
|
entity.sorts = []
|
|
39
53
|
},
|
|
40
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Updates a filter value for a column.
|
|
57
|
+
* @param {TableEntity} entity
|
|
58
|
+
* @param {{ columnId: string, value: any }} payload
|
|
59
|
+
*/
|
|
41
60
|
filterChange(entity, { columnId, value }) {
|
|
42
61
|
if (value == null || value === "") {
|
|
43
62
|
delete entity.filters[columnId]
|
|
@@ -51,6 +70,10 @@ export const logic = {
|
|
|
51
70
|
}
|
|
52
71
|
},
|
|
53
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Clears all filters.
|
|
75
|
+
* @param {TableEntity} entity
|
|
76
|
+
*/
|
|
54
77
|
filtersClear(entity) {
|
|
55
78
|
entity.filters = {}
|
|
56
79
|
if (entity.pagination) {
|
|
@@ -58,10 +81,20 @@ export const logic = {
|
|
|
58
81
|
}
|
|
59
82
|
},
|
|
60
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Updates the search term.
|
|
86
|
+
* @param {TableEntity} entity
|
|
87
|
+
* @param {string} search
|
|
88
|
+
*/
|
|
61
89
|
searchChange(entity, search) {
|
|
62
90
|
entity.search.value = search
|
|
63
91
|
},
|
|
64
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Changes the current page.
|
|
95
|
+
* @param {TableEntity} entity
|
|
96
|
+
* @param {number} page
|
|
97
|
+
*/
|
|
65
98
|
pageChange(entity, page) {
|
|
66
99
|
if (!entity.pagination) return
|
|
67
100
|
|
|
@@ -71,6 +104,10 @@ export const logic = {
|
|
|
71
104
|
entity.pagination.page = Math.max(0, Math.min(page, totalPages - 1))
|
|
72
105
|
},
|
|
73
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Moves to the next page.
|
|
109
|
+
* @param {TableEntity} entity
|
|
110
|
+
*/
|
|
74
111
|
pageNext(entity) {
|
|
75
112
|
if (!entity.pagination) return
|
|
76
113
|
const totalPages = Math.ceil(
|
|
@@ -82,11 +119,20 @@ export const logic = {
|
|
|
82
119
|
)
|
|
83
120
|
},
|
|
84
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Moves to the previous page.
|
|
124
|
+
* @param {TableEntity} entity
|
|
125
|
+
*/
|
|
85
126
|
pagePrev(entity) {
|
|
86
127
|
if (!entity.pagination) return
|
|
87
128
|
entity.pagination.page = Math.max(entity.pagination.page - 1, 0)
|
|
88
129
|
},
|
|
89
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Changes the page size.
|
|
133
|
+
* @param {TableEntity} entity
|
|
134
|
+
* @param {number} pageSize
|
|
135
|
+
*/
|
|
90
136
|
pageSizeChange(entity, pageSize) {
|
|
91
137
|
if (!entity.pagination) return
|
|
92
138
|
|
|
@@ -94,6 +140,11 @@ export const logic = {
|
|
|
94
140
|
entity.pagination.page = 0
|
|
95
141
|
},
|
|
96
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Selects a row.
|
|
145
|
+
* @param {TableEntity} entity
|
|
146
|
+
* @param {string|number} rowId
|
|
147
|
+
*/
|
|
97
148
|
rowSelect(entity, rowId) {
|
|
98
149
|
if (!entity.isMultiSelect) {
|
|
99
150
|
entity.selection = []
|
|
@@ -104,6 +155,11 @@ export const logic = {
|
|
|
104
155
|
}
|
|
105
156
|
},
|
|
106
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Deselects a row.
|
|
160
|
+
* @param {TableEntity} entity
|
|
161
|
+
* @param {string|number} rowId
|
|
162
|
+
*/
|
|
107
163
|
rowDeselect(entity, rowId) {
|
|
108
164
|
const index = entity.selection.indexOf(rowId)
|
|
109
165
|
if (index !== -1) {
|
|
@@ -111,6 +167,11 @@ export const logic = {
|
|
|
111
167
|
}
|
|
112
168
|
},
|
|
113
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Toggles row selection.
|
|
172
|
+
* @param {TableEntity} entity
|
|
173
|
+
* @param {string|number} rowId
|
|
174
|
+
*/
|
|
114
175
|
rowToggle(entity, rowId) {
|
|
115
176
|
const index = entity.selection.indexOf(rowId)
|
|
116
177
|
|
|
@@ -125,6 +186,10 @@ export const logic = {
|
|
|
125
186
|
}
|
|
126
187
|
},
|
|
127
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Toggles selection of all currently visible rows.
|
|
191
|
+
* @param {TableEntity} entity
|
|
192
|
+
*/
|
|
128
193
|
rowsToggleAll(entity) {
|
|
129
194
|
const rows = getRows(entity)
|
|
130
195
|
const allSelected = rows.every((row) => entity.selection.includes(row.id))
|
|
@@ -145,6 +210,10 @@ export const logic = {
|
|
|
145
210
|
}
|
|
146
211
|
},
|
|
147
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Selects all currently visible rows.
|
|
215
|
+
* @param {TableEntity} entity
|
|
216
|
+
*/
|
|
148
217
|
rowsSelectAll(entity) {
|
|
149
218
|
const rows = getRows(entity)
|
|
150
219
|
rows.forEach((row) => {
|
|
@@ -154,13 +223,22 @@ export const logic = {
|
|
|
154
223
|
})
|
|
155
224
|
},
|
|
156
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Clears all row selections.
|
|
228
|
+
* @param {TableEntity} entity
|
|
229
|
+
*/
|
|
157
230
|
selectionClear(entity) {
|
|
158
231
|
entity.selection.length = 0
|
|
159
232
|
},
|
|
160
233
|
}
|
|
161
234
|
|
|
162
|
-
// Helper functions
|
|
235
|
+
// Helper functions
|
|
163
236
|
|
|
237
|
+
/**
|
|
238
|
+
* Gets the processed rows (filtered, searched, sorted, paginated).
|
|
239
|
+
* @param {TableEntity} entity
|
|
240
|
+
* @returns {any[]}
|
|
241
|
+
*/
|
|
164
242
|
export function getRows(entity) {
|
|
165
243
|
let rows = entity.data
|
|
166
244
|
rows = applyFilters(entity, rows)
|
|
@@ -171,6 +249,11 @@ export function getRows(entity) {
|
|
|
171
249
|
return rows
|
|
172
250
|
}
|
|
173
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Gets the total number of rows after filtering and searching.
|
|
254
|
+
* @param {TableEntity} entity
|
|
255
|
+
* @returns {number}
|
|
256
|
+
*/
|
|
174
257
|
export function getTotalRows(entity) {
|
|
175
258
|
let rows = entity.data
|
|
176
259
|
rows = applyFilters(entity, rows)
|
|
@@ -178,6 +261,11 @@ export function getTotalRows(entity) {
|
|
|
178
261
|
return rows.length
|
|
179
262
|
}
|
|
180
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Gets pagination information.
|
|
266
|
+
* @param {TableEntity} entity
|
|
267
|
+
* @returns {object|null}
|
|
268
|
+
*/
|
|
181
269
|
export function getPaginationInfo(entity) {
|
|
182
270
|
if (!entity.pagination) return null
|
|
183
271
|
|
|
@@ -199,28 +287,62 @@ export function getPaginationInfo(entity) {
|
|
|
199
287
|
}
|
|
200
288
|
}
|
|
201
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Gets the sort direction for a column.
|
|
292
|
+
* @param {TableEntity} entity
|
|
293
|
+
* @param {string} columnId
|
|
294
|
+
* @returns {"asc"|"desc"|null}
|
|
295
|
+
*/
|
|
202
296
|
export function getSortDirection(entity, columnId) {
|
|
203
297
|
const sort = entity.sorts.find((s) => s.column === columnId)
|
|
204
298
|
return sort?.direction || null
|
|
205
299
|
}
|
|
206
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Gets the sort index (priority) for a column.
|
|
303
|
+
* @param {TableEntity} entity
|
|
304
|
+
* @param {string} columnId
|
|
305
|
+
* @returns {number}
|
|
306
|
+
*/
|
|
207
307
|
export function getSortIndex(entity, columnId) {
|
|
208
308
|
return entity.sorts.findIndex((s) => s.column === columnId)
|
|
209
309
|
}
|
|
210
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Gets the filter value for a column.
|
|
313
|
+
* @param {TableEntity} entity
|
|
314
|
+
* @param {string} columnId
|
|
315
|
+
* @returns {any}
|
|
316
|
+
*/
|
|
211
317
|
export function getFilter(entity, columnId) {
|
|
212
318
|
return entity.filters[columnId]
|
|
213
319
|
}
|
|
214
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Checks if a row is selected.
|
|
323
|
+
* @param {TableEntity} entity
|
|
324
|
+
* @param {string|number} rowId
|
|
325
|
+
* @returns {boolean}
|
|
326
|
+
*/
|
|
215
327
|
export function isRowSelected(entity, rowId) {
|
|
216
328
|
return entity.selection.includes(rowId)
|
|
217
329
|
}
|
|
218
330
|
|
|
331
|
+
/**
|
|
332
|
+
* Checks if all visible rows are selected.
|
|
333
|
+
* @param {TableEntity} entity
|
|
334
|
+
* @returns {boolean}
|
|
335
|
+
*/
|
|
219
336
|
export function isAllSelected(entity) {
|
|
220
337
|
const rows = getRows(entity)
|
|
221
338
|
return rows.length && rows.every((row) => entity.selection.includes(row.id))
|
|
222
339
|
}
|
|
223
340
|
|
|
341
|
+
/**
|
|
342
|
+
* Checks if some (but not all) visible rows are selected.
|
|
343
|
+
* @param {TableEntity} entity
|
|
344
|
+
* @returns {boolean}
|
|
345
|
+
*/
|
|
224
346
|
export function isSomeSelected(entity) {
|
|
225
347
|
const rows = getRows(entity)
|
|
226
348
|
const selectedCount = rows.filter((row) =>
|
|
@@ -229,6 +351,12 @@ export function isSomeSelected(entity) {
|
|
|
229
351
|
return selectedCount && selectedCount < rows.length
|
|
230
352
|
}
|
|
231
353
|
|
|
354
|
+
// Private helper functions
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Initializes the table state.
|
|
358
|
+
* @param {TableEntity} entity
|
|
359
|
+
*/
|
|
232
360
|
function initTable(entity) {
|
|
233
361
|
entity.data ??= []
|
|
234
362
|
|
|
@@ -276,6 +404,11 @@ function initTable(entity) {
|
|
|
276
404
|
}
|
|
277
405
|
}
|
|
278
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Infers the column type from a value.
|
|
409
|
+
* @param {any} value
|
|
410
|
+
* @returns {string}
|
|
411
|
+
*/
|
|
279
412
|
function getDefaultColumnType(value) {
|
|
280
413
|
if (typeof value === "number") return "number"
|
|
281
414
|
if (typeof value === "boolean") return "boolean"
|
|
@@ -283,6 +416,11 @@ function getDefaultColumnType(value) {
|
|
|
283
416
|
return "string"
|
|
284
417
|
}
|
|
285
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Gets the default filter configuration for a column type.
|
|
421
|
+
* @param {string} type
|
|
422
|
+
* @returns {object}
|
|
423
|
+
*/
|
|
286
424
|
function getDefaultColumnFilter(type) {
|
|
287
425
|
if (type === "number") return { type: "range" }
|
|
288
426
|
if (type === "boolean")
|
|
@@ -291,6 +429,11 @@ function getDefaultColumnFilter(type) {
|
|
|
291
429
|
return { type: "text" }
|
|
292
430
|
}
|
|
293
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Gets the default column width based on filter type.
|
|
434
|
+
* @param {string} filterType
|
|
435
|
+
* @returns {number}
|
|
436
|
+
*/
|
|
294
437
|
function getDefaultColumnWidth(filterType) {
|
|
295
438
|
if (filterType === "number") return 70
|
|
296
439
|
if (filterType === "range") return 100
|
|
@@ -301,6 +444,12 @@ function getDefaultColumnWidth(filterType) {
|
|
|
301
444
|
return 200
|
|
302
445
|
}
|
|
303
446
|
|
|
447
|
+
/**
|
|
448
|
+
* Applies filters to the data.
|
|
449
|
+
* @param {TableEntity} entity
|
|
450
|
+
* @param {any[]} rows
|
|
451
|
+
* @returns {any[]}
|
|
452
|
+
*/
|
|
304
453
|
function applyFilters(entity, rows) {
|
|
305
454
|
if (!Object.keys(entity.filters).length) {
|
|
306
455
|
return rows
|
|
@@ -338,6 +487,12 @@ function applyFilters(entity, rows) {
|
|
|
338
487
|
})
|
|
339
488
|
}
|
|
340
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Applies search to the data.
|
|
492
|
+
* @param {TableEntity} entity
|
|
493
|
+
* @param {any[]} rows
|
|
494
|
+
* @returns {any[]}
|
|
495
|
+
*/
|
|
341
496
|
function applySearch(entity, rows) {
|
|
342
497
|
if (!entity.search?.value) {
|
|
343
498
|
return rows
|
|
@@ -354,6 +509,12 @@ function applySearch(entity, rows) {
|
|
|
354
509
|
)
|
|
355
510
|
}
|
|
356
511
|
|
|
512
|
+
/**
|
|
513
|
+
* Applies sorting to the data.
|
|
514
|
+
* @param {TableEntity} entity
|
|
515
|
+
* @param {any[]} rows
|
|
516
|
+
* @returns {any[]}
|
|
517
|
+
*/
|
|
357
518
|
function applySorts(entity, rows) {
|
|
358
519
|
if (!entity.sorts.length) {
|
|
359
520
|
return rows
|
|
@@ -385,6 +546,12 @@ function applySorts(entity, rows) {
|
|
|
385
546
|
})
|
|
386
547
|
}
|
|
387
548
|
|
|
549
|
+
/**
|
|
550
|
+
* Applies pagination to the data.
|
|
551
|
+
* @param {TableEntity} entity
|
|
552
|
+
* @param {any[]} rows
|
|
553
|
+
* @returns {any[]}
|
|
554
|
+
*/
|
|
388
555
|
function applyPagination(entity, rows) {
|
|
389
556
|
if (!entity.pagination) {
|
|
390
557
|
return rows
|
|
@@ -395,6 +562,11 @@ function applyPagination(entity, rows) {
|
|
|
395
562
|
return rows.slice(start, start + pageSize)
|
|
396
563
|
}
|
|
397
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Capitalizes the first letter of a string.
|
|
567
|
+
* @param {string} str
|
|
568
|
+
* @returns {string}
|
|
569
|
+
*/
|
|
398
570
|
function capitalize(str) {
|
|
399
571
|
const [firstChar, ...rest] = str
|
|
400
572
|
return [firstChar.toUpperCase(), ...rest].join("")
|
package/src/table.test.js
CHANGED
|
@@ -61,14 +61,13 @@ describe("table", () => {
|
|
|
61
61
|
pagination: { page: 0, pageSize: 2 },
|
|
62
62
|
search: { value: "" },
|
|
63
63
|
}
|
|
64
|
-
table.init(entity)
|
|
65
64
|
})
|
|
66
65
|
|
|
67
66
|
describe("logic", () => {
|
|
68
|
-
describe("
|
|
67
|
+
describe("create()", () => {
|
|
69
68
|
it("should initialize with default state", () => {
|
|
70
69
|
const newEntity = { data: [{ id: 1, name: "Test" }] }
|
|
71
|
-
table.
|
|
70
|
+
table.create(newEntity)
|
|
72
71
|
expect(newEntity.sorts).toEqual([])
|
|
73
72
|
expect(newEntity.filters).toEqual({})
|
|
74
73
|
expect(newEntity.selection).toEqual([])
|
|
@@ -79,6 +78,10 @@ describe("table", () => {
|
|
|
79
78
|
})
|
|
80
79
|
|
|
81
80
|
describe("sortChange()", () => {
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
table.create(entity)
|
|
83
|
+
})
|
|
84
|
+
|
|
82
85
|
it("should add a new sort", () => {
|
|
83
86
|
table.sortChange(entity, "name")
|
|
84
87
|
expect(entity.sorts).toEqual([{ column: "name", direction: "asc" }])
|
|
@@ -105,6 +108,10 @@ describe("table", () => {
|
|
|
105
108
|
})
|
|
106
109
|
|
|
107
110
|
describe("filterChange()", () => {
|
|
111
|
+
beforeEach(() => {
|
|
112
|
+
table.create(entity)
|
|
113
|
+
})
|
|
114
|
+
|
|
108
115
|
it("should add a filter", () => {
|
|
109
116
|
table.filterChange(entity, { columnId: "name", value: "Alice" })
|
|
110
117
|
expect(entity.filters.name).toBe("Alice")
|
|
@@ -124,6 +131,10 @@ describe("table", () => {
|
|
|
124
131
|
})
|
|
125
132
|
|
|
126
133
|
describe("pagination", () => {
|
|
134
|
+
beforeEach(() => {
|
|
135
|
+
table.create(entity)
|
|
136
|
+
})
|
|
137
|
+
|
|
127
138
|
it("pageNext: should go to the next page", () => {
|
|
128
139
|
table.pageNext(entity)
|
|
129
140
|
expect(entity.pagination.page).toBe(1)
|
|
@@ -155,6 +166,10 @@ describe("table", () => {
|
|
|
155
166
|
})
|
|
156
167
|
|
|
157
168
|
describe("selection", () => {
|
|
169
|
+
beforeEach(() => {
|
|
170
|
+
table.create(entity)
|
|
171
|
+
})
|
|
172
|
+
|
|
158
173
|
it("rowToggle: should select an unselected row", () => {
|
|
159
174
|
table.rowToggle(entity, 1)
|
|
160
175
|
expect(entity.selection).toContain(1)
|
|
@@ -189,6 +204,10 @@ describe("table", () => {
|
|
|
189
204
|
})
|
|
190
205
|
|
|
191
206
|
describe("getters and selectors", () => {
|
|
207
|
+
beforeEach(() => {
|
|
208
|
+
table.create(entity)
|
|
209
|
+
})
|
|
210
|
+
|
|
192
211
|
it("getRows: should return sorted, filtered, and paginated rows", () => {
|
|
193
212
|
// Sort by age descending
|
|
194
213
|
table.sortChange(entity, "age")
|
|
@@ -256,6 +275,8 @@ describe("table", () => {
|
|
|
256
275
|
renderFooter: vi.fn(() => html`<div>Footer</div>`),
|
|
257
276
|
}),
|
|
258
277
|
}
|
|
278
|
+
|
|
279
|
+
table.create(entity)
|
|
259
280
|
})
|
|
260
281
|
|
|
261
282
|
it("render: should call sub-renderers", () => {
|
package/types/form.d.ts
CHANGED
|
@@ -191,20 +191,10 @@ export interface FormValidationErrorPayload {
|
|
|
191
191
|
*/
|
|
192
192
|
export declare const form: {
|
|
193
193
|
/**
|
|
194
|
-
* Initializes the form entity
|
|
194
|
+
* Initializes the form entity with default state.
|
|
195
195
|
* @param entity The form entity.
|
|
196
196
|
*/
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Resets the form entity when a 'create' event payload matches its ID.
|
|
201
|
-
* @param entity The form entity.
|
|
202
|
-
* @param entityId The entity ID from the create event, used to target a specific form.
|
|
203
|
-
*/
|
|
204
|
-
create<T extends FormValues>(
|
|
205
|
-
entity: FormEntity<T>,
|
|
206
|
-
entityId: string | number,
|
|
207
|
-
): void
|
|
197
|
+
create<T extends FormValues>(entity: FormEntity<T>): void
|
|
208
198
|
|
|
209
199
|
/**
|
|
210
200
|
* Appends an item to a field array.
|
package/types/index.d.ts
CHANGED
package/types/list.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { TemplateResult } from "lit-html"
|
|
2
|
+
import type { Api } from "./mount"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents the visible range of items in the list.
|
|
6
|
+
*/
|
|
7
|
+
export interface VisibleRange {
|
|
8
|
+
start: number
|
|
9
|
+
end: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Represents the state of a list entity.
|
|
14
|
+
*/
|
|
15
|
+
export interface ListEntity<T = any> {
|
|
16
|
+
/** A unique identifier for the list entity. */
|
|
17
|
+
id: string | number
|
|
18
|
+
/** The entity type (usually 'list'). */
|
|
19
|
+
type: string
|
|
20
|
+
/** The array of items to render. */
|
|
21
|
+
items: T[]
|
|
22
|
+
/** The current scroll position of the list container. */
|
|
23
|
+
scrollTop: number
|
|
24
|
+
/** The range of items currently visible (plus buffer). */
|
|
25
|
+
visibleRange: VisibleRange
|
|
26
|
+
/** The height of the viewport in pixels. */
|
|
27
|
+
viewportHeight: number
|
|
28
|
+
/** The number of extra items to render above and below the visible range. */
|
|
29
|
+
bufferSize: number
|
|
30
|
+
/** The fixed height of each item in pixels, or null if measuring. */
|
|
31
|
+
itemHeight: number | null
|
|
32
|
+
/** The estimated height of an item, used before measurement. */
|
|
33
|
+
estimatedHeight: number
|
|
34
|
+
/** Any other custom properties. */
|
|
35
|
+
[key: string]: any
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The list type implementation.
|
|
40
|
+
*/
|
|
41
|
+
export declare const list: {
|
|
42
|
+
/**
|
|
43
|
+
* Initializes the list entity with default state.
|
|
44
|
+
* @param entity The list entity.
|
|
45
|
+
*/
|
|
46
|
+
create(entity: ListEntity): void
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Handles the scroll event to update the visible range.
|
|
50
|
+
* @param entity The list entity.
|
|
51
|
+
* @param containerEl The scrolling container element.
|
|
52
|
+
*/
|
|
53
|
+
scroll(entity: ListEntity, containerEl: HTMLElement): void
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Mounts the list, measuring the first item to determine item height.
|
|
57
|
+
* @param entity The list entity.
|
|
58
|
+
* @param containerEl The scrolling container element.
|
|
59
|
+
*/
|
|
60
|
+
mount(entity: ListEntity, containerEl: HTMLElement): void
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Renders the virtualized list component.
|
|
64
|
+
* @param entity The list entity.
|
|
65
|
+
* @param api The store API.
|
|
66
|
+
*/
|
|
67
|
+
render(entity: ListEntity, api: Api): TemplateResult
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Default item renderer.
|
|
71
|
+
* @param item The item to render.
|
|
72
|
+
* @param index The index of the item.
|
|
73
|
+
* @param api The store API.
|
|
74
|
+
*/
|
|
75
|
+
renderItem(item: any, index: number, api: Api): TemplateResult
|
|
76
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { TemplateResult } from "lit-html"
|
|
2
|
+
import type { Api } from "./mount"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents an option in the select component.
|
|
6
|
+
* Can be a simple string/number or an object with value and label.
|
|
7
|
+
*/
|
|
8
|
+
export type SelectOption =
|
|
9
|
+
| string
|
|
10
|
+
| number
|
|
11
|
+
| {
|
|
12
|
+
value: string | number
|
|
13
|
+
label?: string
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
[key: string]: any
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Represents the state of a select entity.
|
|
20
|
+
*/
|
|
21
|
+
export interface SelectEntity {
|
|
22
|
+
/** A unique identifier for the select entity. */
|
|
23
|
+
id: string | number
|
|
24
|
+
/** The entity type (usually 'select'). */
|
|
25
|
+
type: string
|
|
26
|
+
/** The list of options available for selection. */
|
|
27
|
+
options: SelectOption[]
|
|
28
|
+
/** Whether the dropdown is currently open. */
|
|
29
|
+
isOpen: boolean
|
|
30
|
+
/** The current search term entered by the user. */
|
|
31
|
+
searchTerm: string
|
|
32
|
+
/** The index of the currently focused option (for keyboard navigation). */
|
|
33
|
+
focusedIndex: number
|
|
34
|
+
/** Whether multiple options can be selected. */
|
|
35
|
+
isMulti: boolean
|
|
36
|
+
/** The currently selected value(s). */
|
|
37
|
+
selectedValue: string | number | (string | number)[] | null
|
|
38
|
+
/** Whether the options are currently loading. */
|
|
39
|
+
isLoading: boolean
|
|
40
|
+
/** Whether the select component is disabled. */
|
|
41
|
+
isDisabled: boolean
|
|
42
|
+
/** Whether the user can search through options. */
|
|
43
|
+
isSearchable: boolean
|
|
44
|
+
/** Whether the selection can be cleared. */
|
|
45
|
+
isClearable: boolean
|
|
46
|
+
/** Whether new options can be created by the user. */
|
|
47
|
+
isCreatable: boolean
|
|
48
|
+
/** Placeholder text to display when no value is selected. */
|
|
49
|
+
placeholder: string
|
|
50
|
+
/** Message to display when no options match the search term. */
|
|
51
|
+
noOptionsMessage: string
|
|
52
|
+
/** Message to display while options are loading. */
|
|
53
|
+
loadingMessage: string
|
|
54
|
+
/** Property name to group options by. */
|
|
55
|
+
groupBy: string | null
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The select type implementation.
|
|
60
|
+
*/
|
|
61
|
+
export declare const select: {
|
|
62
|
+
/**
|
|
63
|
+
* Initializes the select entity with default state.
|
|
64
|
+
* @param {SelectEntity} entity
|
|
65
|
+
*/
|
|
66
|
+
create(entity: SelectEntity): void
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Renders the select component.
|
|
70
|
+
* @param entity The select entity.
|
|
71
|
+
* @param api The store API.
|
|
72
|
+
*/
|
|
73
|
+
render(entity: SelectEntity, api: Api): TemplateResult
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Opens the select dropdown.
|
|
77
|
+
* @param entity The select entity.
|
|
78
|
+
*/
|
|
79
|
+
open(entity: SelectEntity): void
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Closes the select dropdown.
|
|
83
|
+
* @param entity The select entity.
|
|
84
|
+
*/
|
|
85
|
+
close(entity: SelectEntity): void
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Toggles the select dropdown open/closed state.
|
|
89
|
+
* @param entity The select entity.
|
|
90
|
+
*/
|
|
91
|
+
toggle(entity: SelectEntity): void
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Selects an option.
|
|
95
|
+
* @param entity The select entity.
|
|
96
|
+
* @param option The option to select.
|
|
97
|
+
*/
|
|
98
|
+
optionSelect(entity: SelectEntity, option: SelectOption): void
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Clears the current selection.
|
|
102
|
+
* @param entity The select entity.
|
|
103
|
+
*/
|
|
104
|
+
clear(entity: SelectEntity): void
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Updates the search term and filters options.
|
|
108
|
+
* @param entity The select entity.
|
|
109
|
+
* @param term The new search term.
|
|
110
|
+
*/
|
|
111
|
+
searchChange(entity: SelectEntity, term: string): void
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Moves focus to the next option.
|
|
115
|
+
* @param entity The select entity.
|
|
116
|
+
*/
|
|
117
|
+
focusNext(entity: SelectEntity): void
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Moves focus to the previous option.
|
|
121
|
+
* @param entity The select entity.
|
|
122
|
+
*/
|
|
123
|
+
focusPrev(entity: SelectEntity): void
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Moves focus to the first option.
|
|
127
|
+
* @param entity The select entity.
|
|
128
|
+
*/
|
|
129
|
+
focusFirst(entity: SelectEntity): void
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Moves focus to the last option.
|
|
133
|
+
* @param entity The select entity.
|
|
134
|
+
*/
|
|
135
|
+
focusLast(entity: SelectEntity): void
|
|
136
|
+
}
|