luxen-ui 0.9.1 → 0.9.2
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/cdn/custom-elements.json +197 -172
- package/cdn/elements/dropdown-item/dropdown-item.js +1 -1
- package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -1
- package/cdn/elements/tree/tree.d.ts +11 -1
- package/cdn/elements/tree/tree.d.ts.map +1 -1
- package/cdn/elements/tree/tree.js +1 -3
- package/cdn/elements/tree/tree.js.map +1 -1
- package/cdn/elements/tree-item/tree-item.d.ts +17 -1
- package/cdn/elements/tree-item/tree-item.d.ts.map +1 -1
- package/cdn/elements/tree-item/tree-item.js +2 -1
- package/cdn/elements/tree-item/tree-item.js.map +1 -1
- package/cdn/standalone.js +64 -16
- package/cdn/standalone.js.map +1 -1
- package/dist/custom-elements.json +197 -172
- package/dist/elements/dropdown-item/dropdown-item.css +1 -0
- package/dist/elements/tree/tree.d.ts +11 -1
- package/dist/elements/tree/tree.d.ts.map +1 -1
- package/dist/elements/tree/tree.js +37 -11
- package/dist/elements/tree-item/tree-item.d.ts +17 -1
- package/dist/elements/tree-item/tree-item.d.ts.map +1 -1
- package/dist/elements/tree-item/tree-item.js +51 -10
- package/dist/metadata/index.json +22 -3
- package/dist/metadata/tree-item.json +20 -1
- package/dist/metadata/tree.json +1 -1
- package/dist/templates/elements/tree.md +18 -0
- package/package.json +4 -2
package/cdn/custom-elements.json
CHANGED
|
@@ -172,127 +172,6 @@
|
|
|
172
172
|
}
|
|
173
173
|
]
|
|
174
174
|
},
|
|
175
|
-
{
|
|
176
|
-
"kind": "javascript-module",
|
|
177
|
-
"path": "src/html/elements/badge/badge.ts",
|
|
178
|
-
"declarations": [
|
|
179
|
-
{
|
|
180
|
-
"kind": "class",
|
|
181
|
-
"description": "",
|
|
182
|
-
"name": "Badge",
|
|
183
|
-
"members": [
|
|
184
|
-
{
|
|
185
|
-
"kind": "field",
|
|
186
|
-
"name": "variant",
|
|
187
|
-
"type": {
|
|
188
|
-
"text": "BadgeVariant | undefined"
|
|
189
|
-
},
|
|
190
|
-
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
191
|
-
"attribute": "variant",
|
|
192
|
-
"reflects": true
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
"kind": "field",
|
|
196
|
-
"name": "pill",
|
|
197
|
-
"type": {
|
|
198
|
-
"text": "boolean"
|
|
199
|
-
},
|
|
200
|
-
"default": "false",
|
|
201
|
-
"description": "Display as pill shape",
|
|
202
|
-
"attribute": "pill",
|
|
203
|
-
"reflects": true
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
"kind": "field",
|
|
207
|
-
"name": "size",
|
|
208
|
-
"type": {
|
|
209
|
-
"text": "BadgeSize | undefined"
|
|
210
|
-
},
|
|
211
|
-
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
212
|
-
"attribute": "size",
|
|
213
|
-
"reflects": true
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
"kind": "field",
|
|
217
|
-
"name": "appearance",
|
|
218
|
-
"type": {
|
|
219
|
-
"text": "BadgeAppearance | undefined"
|
|
220
|
-
},
|
|
221
|
-
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
222
|
-
"attribute": "appearance",
|
|
223
|
-
"reflects": true
|
|
224
|
-
}
|
|
225
|
-
],
|
|
226
|
-
"attributes": [
|
|
227
|
-
{
|
|
228
|
-
"name": "variant",
|
|
229
|
-
"type": {
|
|
230
|
-
"text": "BadgeVariant | undefined"
|
|
231
|
-
},
|
|
232
|
-
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
233
|
-
"fieldName": "variant"
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
"name": "pill",
|
|
237
|
-
"type": {
|
|
238
|
-
"text": "boolean"
|
|
239
|
-
},
|
|
240
|
-
"default": "false",
|
|
241
|
-
"description": "Display as pill shape",
|
|
242
|
-
"fieldName": "pill"
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
"name": "size",
|
|
246
|
-
"type": {
|
|
247
|
-
"text": "BadgeSize | undefined"
|
|
248
|
-
},
|
|
249
|
-
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
250
|
-
"fieldName": "size"
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
"name": "appearance",
|
|
254
|
-
"type": {
|
|
255
|
-
"text": "BadgeAppearance | undefined"
|
|
256
|
-
},
|
|
257
|
-
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
258
|
-
"fieldName": "appearance"
|
|
259
|
-
}
|
|
260
|
-
],
|
|
261
|
-
"superclass": {
|
|
262
|
-
"name": "LuxenElement",
|
|
263
|
-
"module": "/src/html/shared/luxen-element.js"
|
|
264
|
-
},
|
|
265
|
-
"tagName": "l-badge",
|
|
266
|
-
"customElement": true,
|
|
267
|
-
"summary": "A badge component for displaying small status indicators."
|
|
268
|
-
}
|
|
269
|
-
],
|
|
270
|
-
"exports": [
|
|
271
|
-
{
|
|
272
|
-
"kind": "js",
|
|
273
|
-
"name": "Badge",
|
|
274
|
-
"declaration": {
|
|
275
|
-
"name": "Badge",
|
|
276
|
-
"module": "src/html/elements/badge/badge.ts"
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
"kind": "javascript-module",
|
|
283
|
-
"path": "src/html/elements/badge/index.ts",
|
|
284
|
-
"declarations": [],
|
|
285
|
-
"exports": [
|
|
286
|
-
{
|
|
287
|
-
"kind": "js",
|
|
288
|
-
"name": "*",
|
|
289
|
-
"declaration": {
|
|
290
|
-
"name": "*",
|
|
291
|
-
"module": "src/html/elements/badge/badge.js"
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
]
|
|
295
|
-
},
|
|
296
175
|
{
|
|
297
176
|
"kind": "javascript-module",
|
|
298
177
|
"path": "src/html/elements/button/button.meta.ts",
|
|
@@ -446,6 +325,127 @@
|
|
|
446
325
|
}
|
|
447
326
|
]
|
|
448
327
|
},
|
|
328
|
+
{
|
|
329
|
+
"kind": "javascript-module",
|
|
330
|
+
"path": "src/html/elements/badge/badge.ts",
|
|
331
|
+
"declarations": [
|
|
332
|
+
{
|
|
333
|
+
"kind": "class",
|
|
334
|
+
"description": "",
|
|
335
|
+
"name": "Badge",
|
|
336
|
+
"members": [
|
|
337
|
+
{
|
|
338
|
+
"kind": "field",
|
|
339
|
+
"name": "variant",
|
|
340
|
+
"type": {
|
|
341
|
+
"text": "BadgeVariant | undefined"
|
|
342
|
+
},
|
|
343
|
+
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
344
|
+
"attribute": "variant",
|
|
345
|
+
"reflects": true
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"kind": "field",
|
|
349
|
+
"name": "pill",
|
|
350
|
+
"type": {
|
|
351
|
+
"text": "boolean"
|
|
352
|
+
},
|
|
353
|
+
"default": "false",
|
|
354
|
+
"description": "Display as pill shape",
|
|
355
|
+
"attribute": "pill",
|
|
356
|
+
"reflects": true
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"kind": "field",
|
|
360
|
+
"name": "size",
|
|
361
|
+
"type": {
|
|
362
|
+
"text": "BadgeSize | undefined"
|
|
363
|
+
},
|
|
364
|
+
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
365
|
+
"attribute": "size",
|
|
366
|
+
"reflects": true
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"kind": "field",
|
|
370
|
+
"name": "appearance",
|
|
371
|
+
"type": {
|
|
372
|
+
"text": "BadgeAppearance | undefined"
|
|
373
|
+
},
|
|
374
|
+
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
375
|
+
"attribute": "appearance",
|
|
376
|
+
"reflects": true
|
|
377
|
+
}
|
|
378
|
+
],
|
|
379
|
+
"attributes": [
|
|
380
|
+
{
|
|
381
|
+
"name": "variant",
|
|
382
|
+
"type": {
|
|
383
|
+
"text": "BadgeVariant | undefined"
|
|
384
|
+
},
|
|
385
|
+
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
386
|
+
"fieldName": "variant"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"name": "pill",
|
|
390
|
+
"type": {
|
|
391
|
+
"text": "boolean"
|
|
392
|
+
},
|
|
393
|
+
"default": "false",
|
|
394
|
+
"description": "Display as pill shape",
|
|
395
|
+
"fieldName": "pill"
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"name": "size",
|
|
399
|
+
"type": {
|
|
400
|
+
"text": "BadgeSize | undefined"
|
|
401
|
+
},
|
|
402
|
+
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
403
|
+
"fieldName": "size"
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"name": "appearance",
|
|
407
|
+
"type": {
|
|
408
|
+
"text": "BadgeAppearance | undefined"
|
|
409
|
+
},
|
|
410
|
+
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
411
|
+
"fieldName": "appearance"
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
"superclass": {
|
|
415
|
+
"name": "LuxenElement",
|
|
416
|
+
"module": "/src/html/shared/luxen-element.js"
|
|
417
|
+
},
|
|
418
|
+
"tagName": "l-badge",
|
|
419
|
+
"customElement": true,
|
|
420
|
+
"summary": "A badge component for displaying small status indicators."
|
|
421
|
+
}
|
|
422
|
+
],
|
|
423
|
+
"exports": [
|
|
424
|
+
{
|
|
425
|
+
"kind": "js",
|
|
426
|
+
"name": "Badge",
|
|
427
|
+
"declaration": {
|
|
428
|
+
"name": "Badge",
|
|
429
|
+
"module": "src/html/elements/badge/badge.ts"
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"kind": "javascript-module",
|
|
436
|
+
"path": "src/html/elements/badge/index.ts",
|
|
437
|
+
"declarations": [],
|
|
438
|
+
"exports": [
|
|
439
|
+
{
|
|
440
|
+
"kind": "js",
|
|
441
|
+
"name": "*",
|
|
442
|
+
"declaration": {
|
|
443
|
+
"name": "*",
|
|
444
|
+
"module": "src/html/elements/badge/badge.js"
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
]
|
|
448
|
+
},
|
|
449
449
|
{
|
|
450
450
|
"kind": "javascript-module",
|
|
451
451
|
"path": "src/html/elements/button-group/button-group.ts",
|
|
@@ -1144,55 +1144,6 @@
|
|
|
1144
1144
|
}
|
|
1145
1145
|
]
|
|
1146
1146
|
},
|
|
1147
|
-
{
|
|
1148
|
-
"kind": "javascript-module",
|
|
1149
|
-
"path": "src/html/elements/carousel-item/carousel-item.ts",
|
|
1150
|
-
"declarations": [
|
|
1151
|
-
{
|
|
1152
|
-
"kind": "class",
|
|
1153
|
-
"description": "A single slide inside an `<l-carousel>`.",
|
|
1154
|
-
"name": "CarouselItem",
|
|
1155
|
-
"cssProperties": [
|
|
1156
|
-
{
|
|
1157
|
-
"description": "Aspect ratio of the slide.",
|
|
1158
|
-
"name": "--aspect-ratio"
|
|
1159
|
-
}
|
|
1160
|
-
],
|
|
1161
|
-
"members": [],
|
|
1162
|
-
"superclass": {
|
|
1163
|
-
"name": "LuxenElement",
|
|
1164
|
-
"module": "/src/html/shared/luxen-element.js"
|
|
1165
|
-
},
|
|
1166
|
-
"tagName": "l-carousel-item",
|
|
1167
|
-
"customElement": true
|
|
1168
|
-
}
|
|
1169
|
-
],
|
|
1170
|
-
"exports": [
|
|
1171
|
-
{
|
|
1172
|
-
"kind": "js",
|
|
1173
|
-
"name": "CarouselItem",
|
|
1174
|
-
"declaration": {
|
|
1175
|
-
"name": "CarouselItem",
|
|
1176
|
-
"module": "src/html/elements/carousel-item/carousel-item.ts"
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
]
|
|
1180
|
-
},
|
|
1181
|
-
{
|
|
1182
|
-
"kind": "javascript-module",
|
|
1183
|
-
"path": "src/html/elements/carousel-item/index.ts",
|
|
1184
|
-
"declarations": [],
|
|
1185
|
-
"exports": [
|
|
1186
|
-
{
|
|
1187
|
-
"kind": "js",
|
|
1188
|
-
"name": "*",
|
|
1189
|
-
"declaration": {
|
|
1190
|
-
"name": "*",
|
|
1191
|
-
"module": "src/html/elements/carousel-item/carousel-item.js"
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
]
|
|
1195
|
-
},
|
|
1196
1147
|
{
|
|
1197
1148
|
"kind": "javascript-module",
|
|
1198
1149
|
"path": "src/html/elements/checkbox/checkbox.meta.ts",
|
|
@@ -1297,6 +1248,55 @@
|
|
|
1297
1248
|
}
|
|
1298
1249
|
]
|
|
1299
1250
|
},
|
|
1251
|
+
{
|
|
1252
|
+
"kind": "javascript-module",
|
|
1253
|
+
"path": "src/html/elements/carousel-item/carousel-item.ts",
|
|
1254
|
+
"declarations": [
|
|
1255
|
+
{
|
|
1256
|
+
"kind": "class",
|
|
1257
|
+
"description": "A single slide inside an `<l-carousel>`.",
|
|
1258
|
+
"name": "CarouselItem",
|
|
1259
|
+
"cssProperties": [
|
|
1260
|
+
{
|
|
1261
|
+
"description": "Aspect ratio of the slide.",
|
|
1262
|
+
"name": "--aspect-ratio"
|
|
1263
|
+
}
|
|
1264
|
+
],
|
|
1265
|
+
"members": [],
|
|
1266
|
+
"superclass": {
|
|
1267
|
+
"name": "LuxenElement",
|
|
1268
|
+
"module": "/src/html/shared/luxen-element.js"
|
|
1269
|
+
},
|
|
1270
|
+
"tagName": "l-carousel-item",
|
|
1271
|
+
"customElement": true
|
|
1272
|
+
}
|
|
1273
|
+
],
|
|
1274
|
+
"exports": [
|
|
1275
|
+
{
|
|
1276
|
+
"kind": "js",
|
|
1277
|
+
"name": "CarouselItem",
|
|
1278
|
+
"declaration": {
|
|
1279
|
+
"name": "CarouselItem",
|
|
1280
|
+
"module": "src/html/elements/carousel-item/carousel-item.ts"
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
]
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
"kind": "javascript-module",
|
|
1287
|
+
"path": "src/html/elements/carousel-item/index.ts",
|
|
1288
|
+
"declarations": [],
|
|
1289
|
+
"exports": [
|
|
1290
|
+
{
|
|
1291
|
+
"kind": "js",
|
|
1292
|
+
"name": "*",
|
|
1293
|
+
"declaration": {
|
|
1294
|
+
"name": "*",
|
|
1295
|
+
"module": "src/html/elements/carousel-item/carousel-item.js"
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
]
|
|
1299
|
+
},
|
|
1300
1300
|
{
|
|
1301
1301
|
"kind": "javascript-module",
|
|
1302
1302
|
"path": "src/html/elements/close-button/close-button.meta.ts",
|
|
@@ -6040,7 +6040,7 @@
|
|
|
6040
6040
|
"declarations": [
|
|
6041
6041
|
{
|
|
6042
6042
|
"kind": "class",
|
|
6043
|
-
"description": "A hierarchical tree view composed of `<l-tree-item>` children.",
|
|
6043
|
+
"description": "A hierarchical tree view composed of `<l-tree-item>` children.\n\nThe host carries `role=\"tree\"`, so give it an accessible name with\n`aria-label` or `aria-labelledby` (e.g. `<l-tree aria-label=\"Files\">`).",
|
|
6044
6044
|
"name": "Tree",
|
|
6045
6045
|
"cssProperties": [
|
|
6046
6046
|
{
|
|
@@ -6357,6 +6357,31 @@
|
|
|
6357
6357
|
"text": "number"
|
|
6358
6358
|
}
|
|
6359
6359
|
},
|
|
6360
|
+
{
|
|
6361
|
+
"kind": "method",
|
|
6362
|
+
"name": "setPosition",
|
|
6363
|
+
"parameters": [
|
|
6364
|
+
{
|
|
6365
|
+
"name": "level",
|
|
6366
|
+
"type": {
|
|
6367
|
+
"text": "number"
|
|
6368
|
+
}
|
|
6369
|
+
},
|
|
6370
|
+
{
|
|
6371
|
+
"name": "posInSet",
|
|
6372
|
+
"type": {
|
|
6373
|
+
"text": "number"
|
|
6374
|
+
}
|
|
6375
|
+
},
|
|
6376
|
+
{
|
|
6377
|
+
"name": "setSize",
|
|
6378
|
+
"type": {
|
|
6379
|
+
"text": "number"
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
],
|
|
6383
|
+
"description": "Set by `<l-tree>`: ARIA position within the tree. `level` is 1-based depth,\n`posInSet`/`setSize` describe the item's rank among its siblings. These let\nscreen readers announce \"level 2, 3 of 5\" even when `lazy` children keep the\nfull set out of the DOM."
|
|
6384
|
+
},
|
|
6360
6385
|
{
|
|
6361
6386
|
"kind": "field",
|
|
6362
6387
|
"name": "hasChildren",
|
|
@@ -6405,7 +6430,7 @@
|
|
|
6405
6430
|
{
|
|
6406
6431
|
"kind": "method",
|
|
6407
6432
|
"name": "toggle",
|
|
6408
|
-
"description": "Toggle expand state.
|
|
6433
|
+
"description": "Toggle expand state. Opening a `lazy` item emits `lazy-load` (via `updated`)."
|
|
6409
6434
|
}
|
|
6410
6435
|
],
|
|
6411
6436
|
"events": [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{i as e}from"../../chunks/lit.js";import{a as t,t as n}from"../../chunks/lit-html.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";var s=e(`:host{display:block}:host([disabled]){pointer-events:none;opacity:.5}.item{cursor:pointer;color:var(--l-color-text-primary,CanvasText);white-space:nowrap;border-radius:4px;outline:none;align-items:center;gap:8px;padding:.375rem .5rem;font-size:.875rem;line-height:1.5;display:flex}.item:focus-visible{background:var(--l-color-bg-state-hover)}@media (hover:hover){.item:hover{background:var(--l-color-bg-state-hover)}}.check{flex-shrink:0;width:16px;display:flex}:host(:not([checked])) .check svg{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0;display:flex}.label{flex:1}`),c=class extends r{static{this.styles=[o,s]}#e=``;get value(){return this.#e}set value(e){this.#e=e}#t=!1;get disabled(){return this.#t}set disabled(e){this.#t=e}#n=`normal`;get type(){return this.#n}set type(e){this.#n=e}#r=!1;get checked(){return this.#r}set checked(e){this.#r=e}getTextLabel(){return(this.textContent??``).trim()}render(){let e=this.type===`checkbox`;return t`
|
|
1
|
+
import{i as e}from"../../chunks/lit.js";import{a as t,t as n}from"../../chunks/lit-html.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";var s=e(`:host{display:block}:host([disabled]){pointer-events:none;opacity:.5}.item{cursor:pointer;color:var(--l-color-text-primary,CanvasText);white-space:nowrap;text-align:start;border-radius:4px;outline:none;align-items:center;gap:8px;padding:.375rem .5rem;font-size:.875rem;line-height:1.5;display:flex}.item:focus-visible{background:var(--l-color-bg-state-hover)}@media (hover:hover){.item:hover{background:var(--l-color-bg-state-hover)}}.check{flex-shrink:0;width:16px;display:flex}:host(:not([checked])) .check svg{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0;display:flex}.label{flex:1}`),c=class extends r{static{this.styles=[o,s]}#e=``;get value(){return this.#e}set value(e){this.#e=e}#t=!1;get disabled(){return this.#t}set disabled(e){this.#t=e}#n=`normal`;get type(){return this.#n}set type(e){this.#n=e}#r=!1;get checked(){return this.#r}set checked(e){this.#r=e}getTextLabel(){return(this.textContent??``).trim()}render(){let e=this.type===`checkbox`;return t`
|
|
2
2
|
<div
|
|
3
3
|
class="item"
|
|
4
4
|
role=${e?`menuitemcheckbox`:`menuitem`}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-item.js","names":[],"sources":["../../../src/html/elements/dropdown-item/dropdown-item.css?inline","../../../src/html/elements/dropdown-item/dropdown-item.ts"],"sourcesContent":[":host {\n display: block;\n}\n\n:host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0.375rem 0.5rem;\n cursor: pointer;\n outline: none;\n border-radius: 4px;\n font-size: 0.875rem;\n line-height: 1.5;\n color: var(--l-color-text-primary, CanvasText);\n white-space: nowrap;\n}\n\n.item:focus-visible {\n background: var(--l-color-bg-state-hover);\n}\n\n@media (hover: hover) {\n .item:hover {\n background: var(--l-color-bg-state-hover);\n }\n}\n\n.check {\n display: flex;\n width: 16px;\n flex-shrink: 0;\n}\n\n:host(:not([checked])) .check svg {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n display: flex;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1;\n}\n","import { html, nothing, unsafeCSS } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown-item.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A menu item for use inside `<l-dropdown>`.\n *\n * @slot - Label text.\n * @slot prefix - Leading content (e.g. icon).\n * @slot suffix - Trailing content.\n *\n * @cssproperty --color - Text color.\n *\n * @customElement l-dropdown-item\n */\nexport class DropdownItem extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n /** The value associated with this item. */\n @property()\n accessor value = '';\n\n /** Disables the item. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /** The type of item: `normal` or `checkbox`. */\n @property()\n accessor type: 'normal' | 'checkbox' = 'normal';\n\n /** Whether the checkbox item is checked. */\n @property({ type: Boolean, reflect: true })\n accessor checked = false;\n\n /** Returns the text label of this item. */\n getTextLabel(): string {\n return (this.textContent ?? '').trim();\n }\n\n override render() {\n const isCheckbox = this.type === 'checkbox';\n\n return html`\n <div\n class=\"item\"\n role=${isCheckbox ? 'menuitemcheckbox' : 'menuitem'}\n aria-checked=${isCheckbox ? String(this.checked) : nothing}\n aria-disabled=${this.disabled ? 'true' : nothing}\n tabindex=\"-1\"\n >\n ${isCheckbox\n ? html`\n <span\n class=\"check\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M3.5 8.5L6.5 11.5L12.5 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n `\n : html` <slot name=\"prefix\"></slot> `}\n <span class=\"label\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n </div>\n `;\n }\n}\n"],"mappings":"0PCMA,IAAM,EAAS,EAAU,
|
|
1
|
+
{"version":3,"file":"dropdown-item.js","names":[],"sources":["../../../src/html/elements/dropdown-item/dropdown-item.css?inline","../../../src/html/elements/dropdown-item/dropdown-item.ts"],"sourcesContent":[":host {\n display: block;\n}\n\n:host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0.375rem 0.5rem;\n cursor: pointer;\n outline: none;\n border-radius: 4px;\n font-size: 0.875rem;\n line-height: 1.5;\n color: var(--l-color-text-primary, CanvasText);\n white-space: nowrap;\n text-align: start;\n}\n\n.item:focus-visible {\n background: var(--l-color-bg-state-hover);\n}\n\n@media (hover: hover) {\n .item:hover {\n background: var(--l-color-bg-state-hover);\n }\n}\n\n.check {\n display: flex;\n width: 16px;\n flex-shrink: 0;\n}\n\n:host(:not([checked])) .check svg {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n display: flex;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1;\n}\n","import { html, nothing, unsafeCSS } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown-item.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A menu item for use inside `<l-dropdown>`.\n *\n * @slot - Label text.\n * @slot prefix - Leading content (e.g. icon).\n * @slot suffix - Trailing content.\n *\n * @cssproperty --color - Text color.\n *\n * @customElement l-dropdown-item\n */\nexport class DropdownItem extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n /** The value associated with this item. */\n @property()\n accessor value = '';\n\n /** Disables the item. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /** The type of item: `normal` or `checkbox`. */\n @property()\n accessor type: 'normal' | 'checkbox' = 'normal';\n\n /** Whether the checkbox item is checked. */\n @property({ type: Boolean, reflect: true })\n accessor checked = false;\n\n /** Returns the text label of this item. */\n getTextLabel(): string {\n return (this.textContent ?? '').trim();\n }\n\n override render() {\n const isCheckbox = this.type === 'checkbox';\n\n return html`\n <div\n class=\"item\"\n role=${isCheckbox ? 'menuitemcheckbox' : 'menuitem'}\n aria-checked=${isCheckbox ? String(this.checked) : nothing}\n aria-disabled=${this.disabled ? 'true' : nothing}\n tabindex=\"-1\"\n >\n ${isCheckbox\n ? html`\n <span\n class=\"check\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M3.5 8.5L6.5 11.5L12.5 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n `\n : html` <slot name=\"prefix\"></slot> `}\n <span class=\"label\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n </div>\n `;\n }\n}\n"],"mappings":"0PCMA,IAAM,EAAS,EAAU,inBAAU,CAatB,EAAb,cAAkC,CAAa,oBACpB,CAAC,EAAY,EAAO,IAI5B,OAAR,OAAA,0CAIW,OAAX,UAAA,6CAI8B,aAA9B,MAAA,yCAIU,OAAV,SAAA,yCAGT,cAAuB,CACrB,OAAQ,KAAK,aAAe,IAAI,MAAM,CAGxC,QAAkB,CAChB,IAAM,EAAa,KAAK,OAAS,WAEjC,MAAO,EAAI;;;eAGA,EAAa,mBAAqB,WAAW;uBACrC,EAAa,OAAO,KAAK,QAAQ,CAAG,EAAQ;wBAC3C,KAAK,SAAW,OAAS,EAAQ;;;UAG/C,EACE,CAAI;;;;;;;;;;;;;;;;;;;;cAqBJ,CAAI,gCAAgC;;;;WArD7C,GAAU,CAAA,CAAA,EAAA,UAAA,QAAA,KAAA,IAIV,EAAS,CAAE,KAAM,QAAS,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,WAAA,KAAA,IAI1C,GAAU,CAAA,CAAA,EAAA,UAAA,OAAA,KAAA,IAIV,EAAS,CAAE,KAAM,QAAS,QAAS,GAAM,CAAC,CAAA,CAAA,EAAA,UAAA,UAAA,KAAA"}
|
|
@@ -5,6 +5,9 @@ export type TreeSelection = 'single' | 'multiple' | 'leaf' | 'none';
|
|
|
5
5
|
/**
|
|
6
6
|
* A hierarchical tree view composed of `<l-tree-item>` children.
|
|
7
7
|
*
|
|
8
|
+
* The host carries `role="tree"`, so give it an accessible name with
|
|
9
|
+
* `aria-label` or `aria-labelledby` (e.g. `<l-tree aria-label="Files">`).
|
|
10
|
+
*
|
|
8
11
|
* @slot - One or more `l-tree-item` elements.
|
|
9
12
|
*
|
|
10
13
|
* @csspart base - The root tree container.
|
|
@@ -24,6 +27,7 @@ export type TreeSelection = 'single' | 'multiple' | 'leaf' | 'none';
|
|
|
24
27
|
*/
|
|
25
28
|
export declare class Tree extends LuxenElement {
|
|
26
29
|
static styles: import('lit').CSSResult[];
|
|
30
|
+
private _internals;
|
|
27
31
|
private _mutationObserver?;
|
|
28
32
|
private _lastFocusedItem;
|
|
29
33
|
/**
|
|
@@ -54,7 +58,13 @@ export declare class Tree extends LuxenElement {
|
|
|
54
58
|
/** Collapses every item. */
|
|
55
59
|
collapseAll(): void;
|
|
56
60
|
private _syncAll;
|
|
57
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Sync depth, checkbox visibility and ARIA position for a sibling group, then
|
|
63
|
+
* recurse. `aria-level`/`aria-setsize`/`aria-posinset` let screen readers
|
|
64
|
+
* announce "level N, M of K" — valuable here because `lazy` items mean the
|
|
65
|
+
* full set isn't always in the DOM (see WAI-ARIA Tree View pattern).
|
|
66
|
+
*/
|
|
67
|
+
private _syncLevel;
|
|
58
68
|
private _canShowCheckboxOn;
|
|
59
69
|
private _rootItems;
|
|
60
70
|
private _ensureTabStop;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tree/tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAM1D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpE
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tree/tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAM1D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,IAAK,SAAQ,YAAY;IACpC,OAAgB,MAAM,4BAAwB;IAE9C,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,iBAAiB,CAAC,CAAmB;IAC7C,OAAO,CAAC,gBAAgB,CAAyB;IAEjD;;;;;;OAMG;IAEH,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAY;IAE7C;;;;OAIG;IAEH,QAAQ,CAAC,WAAW,UAAS;IAEpB,iBAAiB;IAgBjB,oBAAoB;IAMpB,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAe9C,yEAAyE;IACzE,WAAW,CAAC,EAAE,eAAsB,EAAE;;KAAK,GAAG,QAAQ,EAAE;IAOxD,wCAAwC;IACxC,YAAY,IAAI,QAAQ,EAAE;IAI1B,4CAA4C;IAC5C,SAAS;IAMT,4BAA4B;IAC5B,WAAW;IAQX,OAAO,CAAC,QAAQ;IAoBhB;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,cAAc;IAUtB,2DAA2D;IAC3D,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,aAAa,CAGnB;IAEF,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,oBAAoB;IAS5B,0EAA0E;IAC1E,OAAO,CAAC,mBAAmB;IA6B3B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,QAAQ,CAqDd;IAEF,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,UAAU,CAMhB;IAEF,OAAO,CAAC,UAAU,CAqEhB;IAEO,MAAM;CAahB"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import{tagName as e}from"../../registry.js";import{i as t}from"../../chunks/lit.js";import{a as n}from"../../chunks/lit-html.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";var s=t(`:host{--indent-size:1rem;--indent-guide-width:1px;--indent-guide-style:solid;--indent-guide-color:var(--l-color-border-interactive,var(--lightningcss-light,#d1d5db)var(--lightningcss-dark,#3a4048));--row-height:1.75rem;--row-padding-inline:.25rem;--chevron-size:1.125rem;--item-gap:.375rem;color:var(--l-color-text-primary,CanvasText);font-family:inherit;line-height:1.5;display:block}.tree{outline:none;display:block}.tree:focus-visible{outline:2px solid var(--l-focus-ring);outline-offset:2px;border-radius:.375rem}`),c=class extends r{constructor(...t){super(...t),this._lastFocusedItem=null,this.#e=`single`,this.#t=!1,this._onItemToggle=e=>{let{item:t,checked:n}=e.detail;this._selectItem(t,n)},this._onClick=e=>{let t=this._itemFromEvent(e);if(!t||t.disabled)return;let n=e.composedPath();if(n.some(e=>e instanceof HTMLInputElement&&e.type===`checkbox`))return;let r=new Set([`BUTTON`,`A`,`INPUT`,`SELECT`,`TEXTAREA`]),i=new Set([`button`,`link`,`menuitem`,`menuitemcheckbox`]);if(n.some(e=>{if(!(e instanceof HTMLElement)||e===t||e.getAttribute?.(`part`)===`expand-button`||e instanceof HTMLInputElement&&e.type===`checkbox`)return!1;if(r.has(e.tagName))return!0;let n=e.getAttribute?.(`role`);return n!==null&&i.has(n)}))return;let a=n.some(e=>e instanceof HTMLElement&&e.getAttribute?.(`part`)===`expand-button`);if(this._focusItem(t),a){t.toggle();return}switch(this.selection){case`single`:this._setSingleSelection(t),t.isLeaf()||t.toggle();break;case`leaf`:t.isLeaf()?this._setSingleSelection(t):t.toggle();break;case`multiple`:this._selectItem(t,!t.selected);break;case`none`:t.toggle();break}},this._onFocusIn=t=>{let n=t.target;if(n instanceof HTMLElement){let t=n.closest(e(`tree-item`));t&&(this._lastFocusedItem=t)}},this._onKeyDown=t=>{let n=this._lastFocusedItem??this._visibleItems()[0];if(!n)return;let r=this._visibleItems(),i=r.indexOf(n);switch(t.key){case`ArrowDown`:{t.preventDefault();let e=r[Math.min(i+1,r.length-1)];e&&this._focusItem(e);break}case`ArrowUp`:{t.preventDefault();let e=r[Math.max(i-1,0)];e&&this._focusItem(e);break}case`ArrowRight`:if(t.preventDefault(),!n.isLeaf()&&!n.expanded)n.expanded=!0;else if(n.expanded){let e=n.getChildrenItems()[0];e&&this._focusItem(e)}break;case`ArrowLeft`:if(t.preventDefault(),n.expanded&&!n.isLeaf())n.expanded=!1;else{let t=n.parentElement?.closest(e(`tree-item`));t&&this._focusItem(t)}break;case`Home`:t.preventDefault(),r[0]&&this._focusItem(r[0]);break;case`End`:{t.preventDefault();let e=r[r.length-1];e&&this._focusItem(e);break}case`Enter`:case` `:t.preventDefault(),this._handleRowActivate(n);break;case`*`:{t.preventDefault();let r=(n.parentElement?Array.from(n.parentElement.children):[]).filter(t=>t.tagName===e(`tree-item`).toUpperCase());for(let e of r)e.isLeaf()||(e.expanded=!0);break}}}}static{this.styles=[o,s]}#e;get selection(){return this.#e}set selection(e){this.#e=e}#t;get independent(){return this.#t}set independent(e){this.#t=e}connectedCallback(){super.connectedCallback(),this._mutationObserver=new MutationObserver(()=>this._syncAll()),this._mutationObserver.observe(this,{childList:!0,subtree:!0}),this.addEventListener(`l-tree-item-toggle`,this._onItemToggle),queueMicrotask(()=>this._syncAll())}disconnectedCallback(){super.disconnectedCallback(),this._mutationObserver?.disconnect(),this.removeEventListener(`l-tree-item-toggle`,this._onItemToggle)}updated(e){(e.has(`selection`)||e.has(`independent`))&&this._syncAll()}getAllItems({includeDisabled:t=!0}={}){let n=e(`tree-item`);return Array.from(this.querySelectorAll(n)).filter(e=>t||!e.disabled)}getSelection(){return this.getAllItems().filter(e=>e.selected)}expandAll(){for(let e of this.getAllItems())e.isLeaf()||(e.expanded=!0)}collapseAll(){for(let e of this.getAllItems())e.expanded=!1}_syncAll(){customElements.upgrade(this);let t=e(`tree-item`),n=this._rootItems();if(n.some(e=>typeof e.getChildrenItems!=`function`)){customElements.whenDefined(t).then(()=>this._syncAll());return}let r=this.selection===`multiple`;
|
|
1
|
+
import{tagName as e}from"../../registry.js";import{i as t}from"../../chunks/lit.js";import{a as n}from"../../chunks/lit-html.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";var s=t(`:host{--indent-size:1rem;--indent-guide-width:1px;--indent-guide-style:solid;--indent-guide-color:var(--l-color-border-interactive,var(--lightningcss-light,#d1d5db)var(--lightningcss-dark,#3a4048));--row-height:1.75rem;--row-padding-inline:.25rem;--chevron-size:1.125rem;--item-gap:.375rem;color:var(--l-color-text-primary,CanvasText);font-family:inherit;line-height:1.5;display:block}.tree{outline:none;display:block}.tree:focus-visible{outline:2px solid var(--l-focus-ring);outline-offset:2px;border-radius:.375rem}`),c=class extends r{constructor(...t){super(...t),this._internals=this.attachInternals(),this._lastFocusedItem=null,this.#e=`single`,this.#t=!1,this._onItemToggle=e=>{let{item:t,checked:n}=e.detail;this._selectItem(t,n)},this._onClick=e=>{let t=this._itemFromEvent(e);if(!t||t.disabled)return;let n=e.composedPath();if(n.some(e=>e instanceof HTMLInputElement&&e.type===`checkbox`))return;let r=new Set([`BUTTON`,`A`,`INPUT`,`SELECT`,`TEXTAREA`]),i=new Set([`button`,`link`,`menuitem`,`menuitemcheckbox`]);if(n.some(e=>{if(!(e instanceof HTMLElement)||e===t||e.getAttribute?.(`part`)===`expand-button`||e instanceof HTMLInputElement&&e.type===`checkbox`)return!1;if(r.has(e.tagName))return!0;let n=e.getAttribute?.(`role`);return n!==null&&i.has(n)}))return;let a=n.some(e=>e instanceof HTMLElement&&e.getAttribute?.(`part`)===`expand-button`);if(this._focusItem(t),a){t.toggle();return}switch(this.selection){case`single`:this._setSingleSelection(t),t.isLeaf()||t.toggle();break;case`leaf`:t.isLeaf()?this._setSingleSelection(t):t.toggle();break;case`multiple`:this._selectItem(t,!t.selected);break;case`none`:t.toggle();break}},this._onFocusIn=t=>{let n=t.target;if(n instanceof HTMLElement){let t=n.closest(e(`tree-item`));t&&(this._lastFocusedItem=t)}},this._onKeyDown=t=>{let n=this._lastFocusedItem??this._visibleItems()[0];if(!n)return;let r=this._visibleItems(),i=r.indexOf(n);switch(t.key){case`ArrowDown`:{t.preventDefault();let e=r[Math.min(i+1,r.length-1)];e&&this._focusItem(e);break}case`ArrowUp`:{t.preventDefault();let e=r[Math.max(i-1,0)];e&&this._focusItem(e);break}case`ArrowRight`:if(t.preventDefault(),!n.isLeaf()&&!n.expanded)n.expanded=!0;else if(n.expanded){let e=n.getChildrenItems()[0];e&&this._focusItem(e)}break;case`ArrowLeft`:if(t.preventDefault(),n.expanded&&!n.isLeaf())n.expanded=!1;else{let t=n.parentElement?.closest(e(`tree-item`));t&&this._focusItem(t)}break;case`Home`:t.preventDefault(),r[0]&&this._focusItem(r[0]);break;case`End`:{t.preventDefault();let e=r[r.length-1];e&&this._focusItem(e);break}case`Enter`:case` `:t.preventDefault(),this._handleRowActivate(n);break;case`*`:{t.preventDefault();let r=(n.parentElement?Array.from(n.parentElement.children):[]).filter(t=>t.tagName===e(`tree-item`).toUpperCase());for(let e of r)e.isLeaf()||(e.expanded=!0);break}}}}static{this.styles=[o,s]}#e;get selection(){return this.#e}set selection(e){this.#e=e}#t;get independent(){return this.#t}set independent(e){this.#t=e}connectedCallback(){super.connectedCallback(),this._internals.role=`tree`,this.hasAttribute(`role`)||this.setAttribute(`role`,`tree`),this._mutationObserver=new MutationObserver(()=>this._syncAll()),this._mutationObserver.observe(this,{childList:!0,subtree:!0}),this.addEventListener(`l-tree-item-toggle`,this._onItemToggle),queueMicrotask(()=>this._syncAll())}disconnectedCallback(){super.disconnectedCallback(),this._mutationObserver?.disconnect(),this.removeEventListener(`l-tree-item-toggle`,this._onItemToggle)}updated(e){if(e.has(`selection`)){let e=this.selection===`multiple`?`true`:`false`;this._internals.ariaMultiSelectable=e,this.setAttribute(`aria-multiselectable`,e)}(e.has(`selection`)||e.has(`independent`))&&this._syncAll()}getAllItems({includeDisabled:t=!0}={}){let n=e(`tree-item`);return Array.from(this.querySelectorAll(n)).filter(e=>t||!e.disabled)}getSelection(){return this.getAllItems().filter(e=>e.selected)}expandAll(){for(let e of this.getAllItems())e.isLeaf()||(e.expanded=!0)}collapseAll(){for(let e of this.getAllItems())e.expanded=!1}_syncAll(){customElements.upgrade(this);let t=e(`tree-item`),n=this._rootItems();if(n.some(e=>typeof e.getChildrenItems!=`function`)){customElements.whenDefined(t).then(()=>this._syncAll());return}let r=this.selection===`multiple`;this._syncLevel(n,0,r),this._updateBranchStates(),this._ensureTabStop()}_syncLevel(e,t,n){let r=e.length;e.forEach((e,i)=>{e.depth=t,e.showCheckbox=n&&this._canShowCheckboxOn(e),e.setPosition(t+1,i+1,r),this._syncLevel(e.getChildrenItems(),t+1,n)})}_canShowCheckboxOn(e){return this.selection===`multiple`}_rootItems(){let t=e(`tree-item`).toUpperCase();return Array.from(this.children).filter(e=>e.tagName===t)}_ensureTabStop(){let e=this._visibleItems();if(e.length!==0&&!e.some(e=>e.tabIndex===0)){for(let t of e)t.tabIndex=-1;e[0].tabIndex=0}}_visibleItems(){let e=[],t=n=>{for(let r of n)e.push(r),r.expanded&&t(r.getChildrenItems())};return t(this._rootItems()),e}_handleRowActivate(e){if(!e.disabled)switch(this.selection){case`single`:this._setSingleSelection(e),e.isLeaf()||e.toggle();break;case`leaf`:e.isLeaf()?this._setSingleSelection(e):e.toggle();break;case`multiple`:this._selectItem(e,!e.selected);break;case`none`:e.toggle();break}}_setSingleSelection(e){for(let t of this.getAllItems())t!==e&&t.selected&&(t.selected=!1);e.selected=!0,this._emitSelectionChange()}_selectItem(e,t){e.disabled||(e.selected=t,this.selection===`multiple`&&!this.independent&&this._setSubtreeSelection(e,t),e.indeterminate=!1,this._updateBranchStates(),this._emitSelectionChange())}_setSubtreeSelection(e,t){for(let n of e.getChildrenItems())n.disabled||(n.selected=t,n.indeterminate=!1,this._setSubtreeSelection(n,t))}_updateBranchStates(){if(this.selection!==`multiple`||this.independent){for(let e of this.getAllItems())e.indeterminate=!1;return}let e=t=>{let n=t.getChildrenItems({includeDisabled:!1});if(n.length===0)return{all:t.selected,any:t.selected};let r=!0,i=!1;for(let t of n){let n=e(t);n.all||(r=!1),n.any&&(i=!0)}return t.selected=r,t.indeterminate=!r&&i,{all:r&&(t.getChildrenItems().length>0?r:t.selected),any:i}};for(let t of this._rootItems())e(t)}_emitSelectionChange(){this.emit(`selection-change`,{detail:{selection:this.getSelection()}})}_itemFromEvent(t){let n=e(`tree-item`),r=t.composedPath();for(let e of r)if(e instanceof HTMLElement&&e.matches?.(n))return e;return null}_focusItem(e){let t=this._visibleItems();for(let e of t)e.tabIndex=-1;e.tabIndex=0,e.focus(),this._lastFocusedItem=e}render(){return n`
|
|
2
2
|
<div
|
|
3
3
|
class="tree"
|
|
4
4
|
part="base"
|
|
5
|
-
role="tree"
|
|
6
|
-
aria-multiselectable=${this.selection===`multiple`?`true`:`false`}
|
|
7
5
|
@click=${this._onClick}
|
|
8
6
|
@keydown=${this._onKeyDown}
|
|
9
7
|
@focusin=${this._onFocusIn}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.js","names":[],"sources":["../../../src/html/elements/tree/tree.css?inline","../../../src/html/elements/tree/tree.ts"],"sourcesContent":[":host {\n --indent-size: 1rem;\n --indent-guide-width: 1px;\n --indent-guide-style: solid;\n --indent-guide-color: var(--l-color-border-interactive, light-dark(#d1d5db, #3a4048));\n --row-height: 1.75rem;\n --row-padding-inline: 0.25rem;\n --chevron-size: 1.125rem;\n --item-gap: 0.375rem;\n\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-family: inherit;\n line-height: 1.5;\n}\n\n.tree {\n display: block;\n outline: none;\n}\n\n.tree:focus-visible {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 2px;\n border-radius: 0.375rem;\n}\n","import { html, unsafeCSS, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { tagName } from '../../registry.js';\nimport type { TreeItem } from '../tree-item/tree-item.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './tree.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\nexport type TreeSelection = 'single' | 'multiple' | 'leaf' | 'none';\n\n/**\n * A hierarchical tree view composed of `<l-tree-item>` children.\n *\n * @slot - One or more `l-tree-item` elements.\n *\n * @csspart base - The root tree container.\n *\n * @cssproperty --indent-size - Horizontal indent per depth level. Default `1rem`.\n * @cssproperty --indent-guide-width - Thickness of the vertical guide line between a parent and its children. Default `1px`. Set to `0` to hide guides.\n * @cssproperty --indent-guide-style - Line style of the guide (`solid`, `dashed`, `dotted`, `double`…). Default `solid`.\n * @cssproperty --indent-guide-color - Color of the guide line.\n * @cssproperty --row-height - Minimum row height. Default `1.75rem`.\n * @cssproperty --row-padding-inline - Inner inline padding of the row; also drives the content slot left indent and the indent guide column. Default `0.25rem`.\n * @cssproperty --chevron-size - Size of the expand/collapse chevron box. Default `1.125rem`.\n * @cssproperty --item-gap - Horizontal gap between chevron, prefix, label and suffix on the row; also drives the content slot left indent. Default `0.375rem`.\n *\n * @event selection-change - Fired when the selected items change. Detail: `{ selection: TreeItem[] }`.\n *\n * @customElement l-tree\n */\nexport class Tree extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _mutationObserver?: MutationObserver;\n private _lastFocusedItem: TreeItem | null = null;\n\n /**\n * Selection behaviour:\n * - `single` (default): at most one item selected via `aria-selected`.\n * - `multiple`: any number of items selected. Checkboxes are rendered.\n * - `leaf`: only leaf items can be selected (single). Branches just toggle.\n * - `none`: purely navigable, no selection state.\n */\n @property({ reflect: true })\n accessor selection: TreeSelection = 'single';\n\n /**\n * When set with `selection=\"multiple\"`, parent and children selection are decoupled:\n * toggling a parent does NOT toggle its descendants and vice versa.\n * Without it, selection cascades both ways and branches may become indeterminate.\n */\n @property({ type: Boolean, reflect: true })\n accessor independent = false;\n\n override connectedCallback() {\n super.connectedCallback();\n this._mutationObserver = new MutationObserver(() => this._syncAll());\n this._mutationObserver.observe(this, { childList: true, subtree: true });\n this.addEventListener('l-tree-item-toggle', this._onItemToggle as EventListener);\n\n // Defer sync to let light DOM upgrade.\n queueMicrotask(() => this._syncAll());\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._mutationObserver?.disconnect();\n this.removeEventListener('l-tree-item-toggle', this._onItemToggle as EventListener);\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('selection') || changed.has('independent')) {\n this._syncAll();\n }\n }\n\n // --- Public API ---\n\n /** Returns all items in document (flat) order, including nested ones. */\n getAllItems({ includeDisabled = true } = {}): TreeItem[] {\n const tag = tagName('tree-item');\n return Array.from(this.querySelectorAll<TreeItem>(tag)).filter(\n (item) => includeDisabled || !item.disabled,\n );\n }\n\n /** Returns currently selected items. */\n getSelection(): TreeItem[] {\n return this.getAllItems().filter((i) => i.selected);\n }\n\n /** Expands every item that has children. */\n expandAll() {\n for (const item of this.getAllItems()) {\n if (!item.isLeaf()) item.expanded = true;\n }\n }\n\n /** Collapses every item. */\n collapseAll() {\n for (const item of this.getAllItems()) {\n item.expanded = false;\n }\n }\n\n // --- Sync / ARIA / depth / checkbox visibility ---\n\n private _syncAll() {\n // `_syncAll()` may run from `updated()` before `<l-tree-item>` is registered\n // (e.g. when the tree module is imported before tree-item, or in async chunks).\n // Force-upgrade any pending custom elements in our subtree, then bail and retry\n // once the registration completes if any item is still un-upgraded.\n customElements.upgrade(this);\n const itemTag = tagName('tree-item');\n const roots = this._rootItems();\n if (roots.some((r) => typeof r.getChildrenItems !== 'function')) {\n void customElements.whenDefined(itemTag).then(() => this._syncAll());\n return;\n }\n\n const showCheckbox = this.selection === 'multiple';\n for (const root of roots) {\n this._syncSubtree(root, 0, showCheckbox);\n }\n this._updateBranchStates();\n // Ensure at least one item is tabbable.\n this._ensureTabStop();\n }\n\n private _syncSubtree(item: TreeItem, depth: number, showCheckbox: boolean) {\n item.depth = depth;\n item.showCheckbox = showCheckbox && this._canShowCheckboxOn(item);\n for (const child of item.getChildrenItems()) {\n this._syncSubtree(child, depth + 1, showCheckbox);\n }\n }\n\n private _canShowCheckboxOn(_item: TreeItem): boolean {\n if (this.selection !== 'multiple') return false;\n // In cascade mode, branches get a checkbox too so you can bulk-toggle children.\n // In leaf-only selection, hidden here because selection !== 'multiple'.\n return true;\n }\n\n private _rootItems(): TreeItem[] {\n const tag = tagName('tree-item').toUpperCase();\n return (Array.from(this.children) as TreeItem[]).filter((el) => el.tagName === tag);\n }\n\n private _ensureTabStop() {\n const items = this._visibleItems();\n if (items.length === 0) return;\n const hasTabStop = items.some((i) => i.tabIndex === 0);\n if (!hasTabStop) {\n for (const i of items) i.tabIndex = -1;\n items[0].tabIndex = 0;\n }\n }\n\n /** Items currently visible (parent chain all expanded). */\n private _visibleItems(): TreeItem[] {\n const out: TreeItem[] = [];\n const walk = (items: TreeItem[]) => {\n for (const i of items) {\n out.push(i);\n if (i.expanded) walk(i.getChildrenItems());\n }\n };\n walk(this._rootItems());\n return out;\n }\n\n // --- Selection handling ---\n\n private _onItemToggle = (event: CustomEvent<{ item: TreeItem; checked: boolean }>) => {\n const { item, checked } = event.detail;\n this._selectItem(item, checked);\n };\n\n private _handleRowActivate(item: TreeItem) {\n if (item.disabled) return;\n\n switch (this.selection) {\n case 'single':\n this._setSingleSelection(item);\n break;\n case 'leaf':\n if (item.isLeaf()) this._setSingleSelection(item);\n else item.toggle();\n break;\n case 'multiple':\n this._selectItem(item, !item.selected);\n break;\n case 'none':\n item.toggle();\n break;\n }\n }\n\n private _setSingleSelection(item: TreeItem) {\n for (const i of this.getAllItems()) {\n if (i !== item && i.selected) i.selected = false;\n }\n item.selected = true;\n this._emitSelectionChange();\n }\n\n private _selectItem(item: TreeItem, value: boolean) {\n if (item.disabled) return;\n item.selected = value;\n\n if (this.selection === 'multiple' && !this.independent) {\n // Cascade DOWN: toggling a branch toggles all descendants.\n this._setSubtreeSelection(item, value);\n }\n\n item.indeterminate = false;\n this._updateBranchStates();\n this._emitSelectionChange();\n }\n\n private _setSubtreeSelection(item: TreeItem, value: boolean) {\n for (const child of item.getChildrenItems()) {\n if (child.disabled) continue;\n child.selected = value;\n child.indeterminate = false;\n this._setSubtreeSelection(child, value);\n }\n }\n\n /** Propagate child state UP to parents (indeterminate / auto-checked). */\n private _updateBranchStates() {\n if (this.selection !== 'multiple' || this.independent) {\n // In independent or non-multiple modes, clear any indeterminate flags.\n for (const i of this.getAllItems()) i.indeterminate = false;\n return;\n }\n\n const recompute = (item: TreeItem): { all: boolean; any: boolean } => {\n const children = item.getChildrenItems({ includeDisabled: false });\n if (children.length === 0) {\n return { all: item.selected, any: item.selected };\n }\n\n let all = true;\n let any = false;\n for (const child of children) {\n const state = recompute(child);\n if (!state.all) all = false;\n if (state.any) any = true;\n }\n\n item.selected = all;\n item.indeterminate = !all && any;\n return { all: all && (item.getChildrenItems().length > 0 ? all : item.selected), any };\n };\n\n for (const root of this._rootItems()) recompute(root);\n }\n\n private _emitSelectionChange() {\n this.emit('selection-change', { detail: { selection: this.getSelection() } });\n }\n\n // --- Keyboard / focus ---\n\n private _onClick = (event: MouseEvent) => {\n const item = this._itemFromEvent(event);\n if (!item || item.disabled) return;\n\n const path = event.composedPath();\n const onCheckbox = path.some((n) => n instanceof HTMLInputElement && n.type === 'checkbox');\n if (onCheckbox) return; // handled via change event\n\n // Clicks on consumer-provided interactive elements (buttons, links, form\n // controls, menu items…) must not toggle the row — the consumer owns that\n // interaction. Works regardless of which slot the element was placed in.\n const INTERACTIVE_TAGS = new Set(['BUTTON', 'A', 'INPUT', 'SELECT', 'TEXTAREA']);\n const INTERACTIVE_ROLES = new Set(['button', 'link', 'menuitem', 'menuitemcheckbox']);\n const onInteractive = path.some((n) => {\n if (!(n instanceof HTMLElement) || n === item) return false;\n if (n.getAttribute?.('part') === 'expand-button') return false;\n if (n instanceof HTMLInputElement && n.type === 'checkbox') return false;\n if (INTERACTIVE_TAGS.has(n.tagName)) return true;\n const role = n.getAttribute?.('role');\n return role !== null && INTERACTIVE_ROLES.has(role);\n });\n if (onInteractive) return;\n\n const onExpand = path.some(\n (n) => n instanceof HTMLElement && n.getAttribute?.('part') === 'expand-button',\n );\n\n this._focusItem(item);\n\n if (onExpand) {\n item.toggle();\n return;\n }\n\n // Row click (label area): mode-dependent behaviour.\n switch (this.selection) {\n case 'single':\n this._setSingleSelection(item);\n if (!item.isLeaf()) item.toggle();\n break;\n case 'leaf':\n if (item.isLeaf()) this._setSingleSelection(item);\n else item.toggle();\n break;\n case 'multiple':\n // The whole row acts like a <label> for the checkbox: clicking anywhere\n // on it toggles selection. Use the chevron to expand/collapse branches.\n this._selectItem(item, !item.selected);\n break;\n case 'none':\n item.toggle();\n break;\n }\n };\n\n private _itemFromEvent(event: Event): TreeItem | null {\n const tag = tagName('tree-item');\n const path = event.composedPath();\n for (const node of path) {\n if (node instanceof HTMLElement && node.matches?.(tag)) {\n return node as TreeItem;\n }\n }\n return null;\n }\n\n private _focusItem(item: TreeItem) {\n const visible = this._visibleItems();\n for (const i of visible) i.tabIndex = -1;\n item.tabIndex = 0;\n item.focus();\n this._lastFocusedItem = item;\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n const target = event.target;\n if (target instanceof HTMLElement) {\n const item = target.closest<TreeItem>(tagName('tree-item'));\n if (item) this._lastFocusedItem = item;\n }\n };\n\n private _onKeyDown = (event: KeyboardEvent) => {\n const current = this._lastFocusedItem ?? this._visibleItems()[0];\n if (!current) return;\n\n const visible = this._visibleItems();\n const index = visible.indexOf(current);\n\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault();\n const next = visible[Math.min(index + 1, visible.length - 1)];\n if (next) this._focusItem(next);\n break;\n }\n case 'ArrowUp': {\n event.preventDefault();\n const prev = visible[Math.max(index - 1, 0)];\n if (prev) this._focusItem(prev);\n break;\n }\n case 'ArrowRight': {\n event.preventDefault();\n if (!current.isLeaf() && !current.expanded) {\n current.expanded = true;\n } else if (current.expanded) {\n const first = current.getChildrenItems()[0];\n if (first) this._focusItem(first);\n }\n break;\n }\n case 'ArrowLeft': {\n event.preventDefault();\n if (current.expanded && !current.isLeaf()) {\n current.expanded = false;\n } else {\n const parent = current.parentElement?.closest(tagName('tree-item')) as TreeItem | null;\n if (parent) this._focusItem(parent);\n }\n break;\n }\n case 'Home': {\n event.preventDefault();\n if (visible[0]) this._focusItem(visible[0]);\n break;\n }\n case 'End': {\n event.preventDefault();\n const last = visible[visible.length - 1];\n if (last) this._focusItem(last);\n break;\n }\n case 'Enter':\n case ' ': {\n event.preventDefault();\n this._handleRowActivate(current);\n break;\n }\n case '*': {\n event.preventDefault();\n // Expand all siblings of the current item.\n const siblings = (\n current.parentElement ? (Array.from(current.parentElement.children) as TreeItem[]) : []\n ).filter((el) => el.tagName === tagName('tree-item').toUpperCase());\n for (const sib of siblings) {\n if (!sib.isLeaf()) sib.expanded = true;\n }\n break;\n }\n }\n };\n\n override render() {\n return html`\n <div\n class=\"tree\"\n part=\"base\"\n role=\"tree\"\n aria-multiselectable=${this.selection === 'multiple' ? 'true' : 'false'}\n @click=${this._onClick}\n @keydown=${this._onKeyDown}\n @focusin=${this._onFocusIn}\n >\n <slot></slot>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tree.js","names":[],"sources":["../../../src/html/elements/tree/tree.css?inline","../../../src/html/elements/tree/tree.ts"],"sourcesContent":[":host {\n --indent-size: 1rem;\n --indent-guide-width: 1px;\n --indent-guide-style: solid;\n --indent-guide-color: var(--l-color-border-interactive, light-dark(#d1d5db, #3a4048));\n --row-height: 1.75rem;\n --row-padding-inline: 0.25rem;\n --chevron-size: 1.125rem;\n --item-gap: 0.375rem;\n\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-family: inherit;\n line-height: 1.5;\n}\n\n.tree {\n display: block;\n outline: none;\n}\n\n.tree:focus-visible {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 2px;\n border-radius: 0.375rem;\n}\n","import { html, unsafeCSS, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { tagName } from '../../registry.js';\nimport type { TreeItem } from '../tree-item/tree-item.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './tree.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\nexport type TreeSelection = 'single' | 'multiple' | 'leaf' | 'none';\n\n/**\n * A hierarchical tree view composed of `<l-tree-item>` children.\n *\n * The host carries `role=\"tree\"`, so give it an accessible name with\n * `aria-label` or `aria-labelledby` (e.g. `<l-tree aria-label=\"Files\">`).\n *\n * @slot - One or more `l-tree-item` elements.\n *\n * @csspart base - The root tree container.\n *\n * @cssproperty --indent-size - Horizontal indent per depth level. Default `1rem`.\n * @cssproperty --indent-guide-width - Thickness of the vertical guide line between a parent and its children. Default `1px`. Set to `0` to hide guides.\n * @cssproperty --indent-guide-style - Line style of the guide (`solid`, `dashed`, `dotted`, `double`…). Default `solid`.\n * @cssproperty --indent-guide-color - Color of the guide line.\n * @cssproperty --row-height - Minimum row height. Default `1.75rem`.\n * @cssproperty --row-padding-inline - Inner inline padding of the row; also drives the content slot left indent and the indent guide column. Default `0.25rem`.\n * @cssproperty --chevron-size - Size of the expand/collapse chevron box. Default `1.125rem`.\n * @cssproperty --item-gap - Horizontal gap between chevron, prefix, label and suffix on the row; also drives the content slot left indent. Default `0.375rem`.\n *\n * @event selection-change - Fired when the selected items change. Detail: `{ selection: TreeItem[] }`.\n *\n * @customElement l-tree\n */\nexport class Tree extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _internals = this.attachInternals();\n private _mutationObserver?: MutationObserver;\n private _lastFocusedItem: TreeItem | null = null;\n\n /**\n * Selection behaviour:\n * - `single` (default): at most one item selected via `aria-selected`.\n * - `multiple`: any number of items selected. Checkboxes are rendered.\n * - `leaf`: only leaf items can be selected (single). Branches just toggle.\n * - `none`: purely navigable, no selection state.\n */\n @property({ reflect: true })\n accessor selection: TreeSelection = 'single';\n\n /**\n * When set with `selection=\"multiple\"`, parent and children selection are decoupled:\n * toggling a parent does NOT toggle its descendants and vice versa.\n * Without it, selection cascades both ways and branches may become indeterminate.\n */\n @property({ type: Boolean, reflect: true })\n accessor independent = false;\n\n override connectedCallback() {\n super.connectedCallback();\n this._internals.role = 'tree';\n // Mirror the role to a DOM attribute too. The ElementInternals role alone is\n // not `[role]`-selectable (CSS, querySelector, Cypress/Playwright CSS), which\n // silently breaks consumers migrating from libraries that expose an attribute\n // role. Respect an author-provided role if one is already set.\n if (!this.hasAttribute('role')) this.setAttribute('role', 'tree');\n this._mutationObserver = new MutationObserver(() => this._syncAll());\n this._mutationObserver.observe(this, { childList: true, subtree: true });\n this.addEventListener('l-tree-item-toggle', this._onItemToggle as EventListener);\n\n // Defer sync to let light DOM upgrade.\n queueMicrotask(() => this._syncAll());\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._mutationObserver?.disconnect();\n this.removeEventListener('l-tree-item-toggle', this._onItemToggle as EventListener);\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('selection')) {\n // Mirror to ElementInternals (a11y tree) and a content attribute, so\n // `[aria-multiselectable]` selectors keep matching — see tree-item `_aria`.\n const multiselectable = this.selection === 'multiple' ? 'true' : 'false';\n this._internals.ariaMultiSelectable = multiselectable;\n this.setAttribute('aria-multiselectable', multiselectable);\n }\n if (changed.has('selection') || changed.has('independent')) {\n this._syncAll();\n }\n }\n\n // --- Public API ---\n\n /** Returns all items in document (flat) order, including nested ones. */\n getAllItems({ includeDisabled = true } = {}): TreeItem[] {\n const tag = tagName('tree-item');\n return Array.from(this.querySelectorAll<TreeItem>(tag)).filter(\n (item) => includeDisabled || !item.disabled,\n );\n }\n\n /** Returns currently selected items. */\n getSelection(): TreeItem[] {\n return this.getAllItems().filter((i) => i.selected);\n }\n\n /** Expands every item that has children. */\n expandAll() {\n for (const item of this.getAllItems()) {\n if (!item.isLeaf()) item.expanded = true;\n }\n }\n\n /** Collapses every item. */\n collapseAll() {\n for (const item of this.getAllItems()) {\n item.expanded = false;\n }\n }\n\n // --- Sync / ARIA / depth / checkbox visibility ---\n\n private _syncAll() {\n // `_syncAll()` may run from `updated()` before `<l-tree-item>` is registered\n // (e.g. when the tree module is imported before tree-item, or in async chunks).\n // Force-upgrade any pending custom elements in our subtree, then bail and retry\n // once the registration completes if any item is still un-upgraded.\n customElements.upgrade(this);\n const itemTag = tagName('tree-item');\n const roots = this._rootItems();\n if (roots.some((r) => typeof r.getChildrenItems !== 'function')) {\n void customElements.whenDefined(itemTag).then(() => this._syncAll());\n return;\n }\n\n const showCheckbox = this.selection === 'multiple';\n this._syncLevel(roots, 0, showCheckbox);\n this._updateBranchStates();\n // Ensure at least one item is tabbable.\n this._ensureTabStop();\n }\n\n /**\n * Sync depth, checkbox visibility and ARIA position for a sibling group, then\n * recurse. `aria-level`/`aria-setsize`/`aria-posinset` let screen readers\n * announce \"level N, M of K\" — valuable here because `lazy` items mean the\n * full set isn't always in the DOM (see WAI-ARIA Tree View pattern).\n */\n private _syncLevel(items: TreeItem[], depth: number, showCheckbox: boolean) {\n const setSize = items.length;\n items.forEach((item, index) => {\n item.depth = depth;\n item.showCheckbox = showCheckbox && this._canShowCheckboxOn(item);\n item.setPosition(depth + 1, index + 1, setSize);\n this._syncLevel(item.getChildrenItems(), depth + 1, showCheckbox);\n });\n }\n\n private _canShowCheckboxOn(_item: TreeItem): boolean {\n if (this.selection !== 'multiple') return false;\n // In cascade mode, branches get a checkbox too so you can bulk-toggle children.\n // In leaf-only selection, hidden here because selection !== 'multiple'.\n return true;\n }\n\n private _rootItems(): TreeItem[] {\n const tag = tagName('tree-item').toUpperCase();\n return (Array.from(this.children) as TreeItem[]).filter((el) => el.tagName === tag);\n }\n\n private _ensureTabStop() {\n const items = this._visibleItems();\n if (items.length === 0) return;\n const hasTabStop = items.some((i) => i.tabIndex === 0);\n if (!hasTabStop) {\n for (const i of items) i.tabIndex = -1;\n items[0].tabIndex = 0;\n }\n }\n\n /** Items currently visible (parent chain all expanded). */\n private _visibleItems(): TreeItem[] {\n const out: TreeItem[] = [];\n const walk = (items: TreeItem[]) => {\n for (const i of items) {\n out.push(i);\n if (i.expanded) walk(i.getChildrenItems());\n }\n };\n walk(this._rootItems());\n return out;\n }\n\n // --- Selection handling ---\n\n private _onItemToggle = (event: CustomEvent<{ item: TreeItem; checked: boolean }>) => {\n const { item, checked } = event.detail;\n this._selectItem(item, checked);\n };\n\n private _handleRowActivate(item: TreeItem) {\n if (item.disabled) return;\n\n switch (this.selection) {\n case 'single':\n this._setSingleSelection(item);\n // Mirror the row-click behaviour: activating a branch also toggles it,\n // so keyboard users expand lazy branches (and trigger their fetch) too.\n if (!item.isLeaf()) item.toggle();\n break;\n case 'leaf':\n if (item.isLeaf()) this._setSingleSelection(item);\n else item.toggle();\n break;\n case 'multiple':\n this._selectItem(item, !item.selected);\n break;\n case 'none':\n item.toggle();\n break;\n }\n }\n\n private _setSingleSelection(item: TreeItem) {\n for (const i of this.getAllItems()) {\n if (i !== item && i.selected) i.selected = false;\n }\n item.selected = true;\n this._emitSelectionChange();\n }\n\n private _selectItem(item: TreeItem, value: boolean) {\n if (item.disabled) return;\n item.selected = value;\n\n if (this.selection === 'multiple' && !this.independent) {\n // Cascade DOWN: toggling a branch toggles all descendants.\n this._setSubtreeSelection(item, value);\n }\n\n item.indeterminate = false;\n this._updateBranchStates();\n this._emitSelectionChange();\n }\n\n private _setSubtreeSelection(item: TreeItem, value: boolean) {\n for (const child of item.getChildrenItems()) {\n if (child.disabled) continue;\n child.selected = value;\n child.indeterminate = false;\n this._setSubtreeSelection(child, value);\n }\n }\n\n /** Propagate child state UP to parents (indeterminate / auto-checked). */\n private _updateBranchStates() {\n if (this.selection !== 'multiple' || this.independent) {\n // In independent or non-multiple modes, clear any indeterminate flags.\n for (const i of this.getAllItems()) i.indeterminate = false;\n return;\n }\n\n const recompute = (item: TreeItem): { all: boolean; any: boolean } => {\n const children = item.getChildrenItems({ includeDisabled: false });\n if (children.length === 0) {\n return { all: item.selected, any: item.selected };\n }\n\n let all = true;\n let any = false;\n for (const child of children) {\n const state = recompute(child);\n if (!state.all) all = false;\n if (state.any) any = true;\n }\n\n item.selected = all;\n item.indeterminate = !all && any;\n return { all: all && (item.getChildrenItems().length > 0 ? all : item.selected), any };\n };\n\n for (const root of this._rootItems()) recompute(root);\n }\n\n private _emitSelectionChange() {\n this.emit('selection-change', { detail: { selection: this.getSelection() } });\n }\n\n // --- Keyboard / focus ---\n\n private _onClick = (event: MouseEvent) => {\n const item = this._itemFromEvent(event);\n if (!item || item.disabled) return;\n\n const path = event.composedPath();\n const onCheckbox = path.some((n) => n instanceof HTMLInputElement && n.type === 'checkbox');\n if (onCheckbox) return; // handled via change event\n\n // Clicks on consumer-provided interactive elements (buttons, links, form\n // controls, menu items…) must not toggle the row — the consumer owns that\n // interaction. Works regardless of which slot the element was placed in.\n const INTERACTIVE_TAGS = new Set(['BUTTON', 'A', 'INPUT', 'SELECT', 'TEXTAREA']);\n const INTERACTIVE_ROLES = new Set(['button', 'link', 'menuitem', 'menuitemcheckbox']);\n const onInteractive = path.some((n) => {\n if (!(n instanceof HTMLElement) || n === item) return false;\n if (n.getAttribute?.('part') === 'expand-button') return false;\n if (n instanceof HTMLInputElement && n.type === 'checkbox') return false;\n if (INTERACTIVE_TAGS.has(n.tagName)) return true;\n const role = n.getAttribute?.('role');\n return role !== null && INTERACTIVE_ROLES.has(role);\n });\n if (onInteractive) return;\n\n const onExpand = path.some(\n (n) => n instanceof HTMLElement && n.getAttribute?.('part') === 'expand-button',\n );\n\n this._focusItem(item);\n\n if (onExpand) {\n item.toggle();\n return;\n }\n\n // Row click (label area): mode-dependent behaviour.\n switch (this.selection) {\n case 'single':\n this._setSingleSelection(item);\n if (!item.isLeaf()) item.toggle();\n break;\n case 'leaf':\n if (item.isLeaf()) this._setSingleSelection(item);\n else item.toggle();\n break;\n case 'multiple':\n // The whole row acts like a <label> for the checkbox: clicking anywhere\n // on it toggles selection. Use the chevron to expand/collapse branches.\n this._selectItem(item, !item.selected);\n break;\n case 'none':\n item.toggle();\n break;\n }\n };\n\n private _itemFromEvent(event: Event): TreeItem | null {\n const tag = tagName('tree-item');\n const path = event.composedPath();\n for (const node of path) {\n if (node instanceof HTMLElement && node.matches?.(tag)) {\n return node as TreeItem;\n }\n }\n return null;\n }\n\n private _focusItem(item: TreeItem) {\n const visible = this._visibleItems();\n for (const i of visible) i.tabIndex = -1;\n item.tabIndex = 0;\n item.focus();\n this._lastFocusedItem = item;\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n const target = event.target;\n if (target instanceof HTMLElement) {\n const item = target.closest<TreeItem>(tagName('tree-item'));\n if (item) this._lastFocusedItem = item;\n }\n };\n\n private _onKeyDown = (event: KeyboardEvent) => {\n const current = this._lastFocusedItem ?? this._visibleItems()[0];\n if (!current) return;\n\n const visible = this._visibleItems();\n const index = visible.indexOf(current);\n\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault();\n const next = visible[Math.min(index + 1, visible.length - 1)];\n if (next) this._focusItem(next);\n break;\n }\n case 'ArrowUp': {\n event.preventDefault();\n const prev = visible[Math.max(index - 1, 0)];\n if (prev) this._focusItem(prev);\n break;\n }\n case 'ArrowRight': {\n event.preventDefault();\n if (!current.isLeaf() && !current.expanded) {\n current.expanded = true;\n } else if (current.expanded) {\n const first = current.getChildrenItems()[0];\n if (first) this._focusItem(first);\n }\n break;\n }\n case 'ArrowLeft': {\n event.preventDefault();\n if (current.expanded && !current.isLeaf()) {\n current.expanded = false;\n } else {\n const parent = current.parentElement?.closest(tagName('tree-item')) as TreeItem | null;\n if (parent) this._focusItem(parent);\n }\n break;\n }\n case 'Home': {\n event.preventDefault();\n if (visible[0]) this._focusItem(visible[0]);\n break;\n }\n case 'End': {\n event.preventDefault();\n const last = visible[visible.length - 1];\n if (last) this._focusItem(last);\n break;\n }\n case 'Enter':\n case ' ': {\n event.preventDefault();\n this._handleRowActivate(current);\n break;\n }\n case '*': {\n event.preventDefault();\n // Expand all siblings of the current item.\n const siblings = (\n current.parentElement ? (Array.from(current.parentElement.children) as TreeItem[]) : []\n ).filter((el) => el.tagName === tagName('tree-item').toUpperCase());\n for (const sib of siblings) {\n if (!sib.isLeaf()) sib.expanded = true;\n }\n break;\n }\n }\n };\n\n override render() {\n return html`\n <div\n class=\"tree\"\n part=\"base\"\n @click=${this._onClick}\n @keydown=${this._onKeyDown}\n @focusin=${this._onFocusIn}\n >\n <slot></slot>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|