luxen-ui 0.9.2 → 0.9.3
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 +170 -170
- package/cdn/elements/tree-item/tree-item.js +1 -1
- package/cdn/elements/tree-item/tree-item.js.map +1 -1
- package/cdn/standalone.js +1 -1
- package/cdn/standalone.js.map +1 -1
- package/dist/custom-elements.json +170 -170
- package/dist/elements/tree-item/tree-item.css +7 -1
- package/dist/metadata/index.json +1 -1
- package/package.json +1 -1
package/cdn/custom-elements.json
CHANGED
|
@@ -172,6 +172,127 @@
|
|
|
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
|
+
},
|
|
175
296
|
{
|
|
176
297
|
"kind": "javascript-module",
|
|
177
298
|
"path": "src/html/elements/button/button.meta.ts",
|
|
@@ -325,127 +446,6 @@
|
|
|
325
446
|
}
|
|
326
447
|
]
|
|
327
448
|
},
|
|
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,6 +1144,55 @@
|
|
|
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
|
+
},
|
|
1147
1196
|
{
|
|
1148
1197
|
"kind": "javascript-module",
|
|
1149
1198
|
"path": "src/html/elements/checkbox/checkbox.meta.ts",
|
|
@@ -1248,55 +1297,6 @@
|
|
|
1248
1297
|
}
|
|
1249
1298
|
]
|
|
1250
1299
|
},
|
|
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",
|
|
@@ -1,4 +1,4 @@
|
|
|
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";import s from"../../shared/styles/checkbox-appearance.styles.js";var c=t(`:host{color:var(--l-color-text-primary,CanvasText);outline:none;font-size:.875rem;line-height:1.5;display:block}:host([disabled]){opacity:.4}:host([disabled]) .item{cursor:not-allowed}.item{align-items:center;gap:var(--item-gap);min-block-size:var(--row-height);padding-inline:var(--row-padding-inline);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:.375rem;padding-inline-start:calc(var(--indent-size) * var(--_depth,0) + var(--row-padding-inline));transition:background-color .12s,color .12s;display:flex;position:relative}.item:focus-visible,:host(:focus-visible) .item{outline:2px solid var(--l-focus-ring);outline-offset:1px}@media (hover:hover){:host(:not([disabled])) .item:hover{background-color:var(--l-color-bg-state-hover)}}:host([selected]:not([disabled])) .item{background-color:var(--l-color-bg-state-selected)}.expand{inline-size:var(--chevron-size);block-size:var(--chevron-size);color:var(--l-color-text-secondary,CanvasText);cursor:pointer;border-radius:3px;flex:none;place-items:center;display:grid}:host(:not(:state(has-children)):not([lazy])) .expand>slot>svg{display:none}.expand svg{width:100%;height:100%;display:block}:host(:not(:state(checkbox))) .checkbox{display:none}.label{text-overflow:ellipsis;white-space:nowrap;flex:1;align-items:center;gap:.375rem;min-inline-size:0;display:flex;overflow:
|
|
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";import s from"../../shared/styles/checkbox-appearance.styles.js";var c=t(`:host{color:var(--l-color-text-primary,CanvasText);outline:none;font-size:.875rem;line-height:1.5;display:block}:host([disabled]){opacity:.4}:host([disabled]) .item{cursor:not-allowed}.item{align-items:center;gap:var(--item-gap);min-block-size:var(--row-height);padding-inline:var(--row-padding-inline);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:.375rem;padding-inline-start:calc(var(--indent-size) * var(--_depth,0) + var(--row-padding-inline));transition:background-color .12s,color .12s;display:flex;position:relative}.item:focus-visible,:host(:focus-visible) .item{outline:2px solid var(--l-focus-ring);outline-offset:1px}@media (hover:hover){:host(:not([disabled])) .item:hover{background-color:var(--l-color-bg-state-hover)}}:host([selected]:not([disabled])) .item{background-color:var(--l-color-bg-state-selected)}.expand{inline-size:var(--chevron-size);block-size:var(--chevron-size);color:var(--l-color-text-secondary,CanvasText);cursor:pointer;border-radius:3px;flex:none;place-items:center;display:grid}:host(:not(:state(has-children)):not([lazy])) .expand>slot>svg{display:none}.expand svg{width:100%;height:100%;display:block}:host(:not(:state(checkbox))) .checkbox{display:none}.label{overflow-clip-margin:.375rem;text-overflow:ellipsis;white-space:nowrap;flex:1;align-items:center;gap:.375rem;min-inline-size:0;display:flex;overflow:clip}.label ::slotted(*){min-inline-size:0}.branch{position:relative}.content{padding-inline-start:calc(var(--indent-size) * var(--_depth,0) + var(--row-padding-inline) + var(--chevron-size) + var(--item-gap));padding-inline-end:var(--row-padding-inline);display:block}:host(:state(has-children):not([expanded])) .content,.children{display:none}:host([expanded]) .children{display:block}.branch:before{content:"";border-inline-start:var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color);pointer-events:none;inline-size:0;position:absolute;inset-block:0;inset-inline-start:calc(var(--indent-size) * var(--_depth,0) + var(--row-padding-inline) + (var(--chevron-size) / 2) - (var(--indent-guide-width) / 2))}:host(:not([expanded])) .branch:before,:host(:not(:state(has-children))) .branch:before{display:none}.spinner{border:2px solid var(--l-color-border,currentColor);border-block-start-color:#0000;border-radius:50%;block-size:.875rem;inline-size:.875rem;animation:.7s linear infinite spin}@media (prefers-reduced-motion:reduce){.spinner{animation:none}}@keyframes spin{to{transform:rotate(360deg)}}`),l=class extends r{constructor(...e){super(...e),this._internals=this.attachInternals(),this.#e=!1,this.#t=!1,this.#n=!1,this.#r=!1,this.#i=!1,this.#a=!1,this._showCheckbox=!1,this._depth=0,this._hasChildren=!1,this._onCheckboxChange=e=>{e.stopPropagation();let t=e.target;this.dispatchEvent(new CustomEvent(`l-tree-item-toggle`,{bubbles:!0,composed:!0,detail:{item:this,checked:t.checked}}))}}static{this.styles=[o,s,c]}#e;get expanded(){return this.#e}set expanded(e){this.#e=e}#t;get selected(){return this.#t}set selected(e){this.#t=e}#n;get indeterminate(){return this.#n}set indeterminate(e){this.#n=e}#r;get disabled(){return this.#r}set disabled(e){this.#r=e}#i;get lazy(){return this.#i}set lazy(e){this.#i=e}#a;get loading(){return this.#a}set loading(e){this.#a=e}set showCheckbox(e){this._showCheckbox=e,this._setState(`checkbox`,e)}get showCheckbox(){return this._showCheckbox}set depth(e){this._depth=e,this.style.setProperty(`--_depth`,String(e))}get depth(){return this._depth}setPosition(e,t,n){this._aria(`ariaLevel`,`aria-level`,String(e)),this._aria(`ariaPosInSet`,`aria-posinset`,String(t)),this._aria(`ariaSetSize`,`aria-setsize`,String(n))}get hasChildren(){return this._hasChildren}getChildrenItems({includeDisabled:t=!0}={}){let n=e(`tree-item`).toUpperCase();return Array.from(this.children).filter(e=>e.tagName===n&&(t||!e.disabled))}isLeaf(){return!this.lazy&&this.getChildrenItems().length===0}getTextLabel(){let e=this.shadowRoot?.querySelector(`slot:not([name])`);return e?e.assignedNodes({flatten:!0}).map(e=>e.textContent??``).join(``).trim():(this.textContent??``).trim()}connectedCallback(){super.connectedCallback(),this._internals.role=`treeitem`,this.hasAttribute(`role`)||this.setAttribute(`role`,`treeitem`),this._childObserver=new MutationObserver(()=>this._syncChildren()),this._childObserver.observe(this,{childList:!0}),this._syncChildren()}disconnectedCallback(){super.disconnectedCallback(),this._childObserver?.disconnect()}updated(e){e.has(`expanded`)&&(this._reflectExpanded(),this.expanded&&this.lazy&&this.emit(`lazy-load`),this.emit(this.expanded?`expand`:`collapse`)),e.has(`selected`)&&this._aria(`ariaSelected`,`aria-selected`,String(this.selected)),e.has(`disabled`)&&this._aria(`ariaDisabled`,`aria-disabled`,this.disabled?`true`:null),e.has(`loading`)&&this._aria(`ariaBusy`,`aria-busy`,this.loading?`true`:null)}_reflectExpanded(){this._aria(`ariaExpanded`,`aria-expanded`,this.isLeaf()?null:String(this.expanded))}_aria(e,t,n){this._internals[e]=n,n===null?this.removeAttribute(t):this.setAttribute(t,n)}_setState(e,t){this._internals.states&&(t?this._internals.states.add(e):this._internals.states.delete(e))}_syncChildren(){let t=e(`tree-item`).toUpperCase(),n=0;for(let e of Array.from(this.children))e.tagName===t&&(n++,e.slot!==`children`&&(e.slot=`children`));this._hasChildren=n>0,this._setState(`has-children`,this._hasChildren),!this._hasChildren&&!this.lazy&&this.expanded&&(this.expanded=!1),this._reflectExpanded()}toggle(){this.isLeaf()&&!this.lazy||(this.expanded=!this.expanded)}render(){return n`
|
|
2
2
|
<div
|
|
3
3
|
class="item"
|
|
4
4
|
part="base"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-item.js","names":[],"sources":["../../../src/html/elements/tree-item/tree-item.css?inline","../../../src/html/elements/tree-item/tree-item.ts"],"sourcesContent":[":host {\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-size: 0.875rem;\n line-height: 1.5;\n /* The host is the roving-tabindex focus target, but the visible ring is drawn\n on the inner `.item` row. Suppress the host's UA outline so it doesn't paint\n a second ring around the whole subtree (row + children). */\n outline: none;\n}\n\n:host([disabled]) {\n opacity: 0.4;\n}\n\n:host([disabled]) .item {\n cursor: not-allowed;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--item-gap);\n min-block-size: var(--row-height);\n padding-inline: var(--row-padding-inline);\n padding-inline-start: calc(var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline));\n border-radius: 0.375rem;\n cursor: pointer;\n user-select: none;\n transition:\n background-color 120ms ease,\n color 120ms ease;\n position: relative;\n}\n\n.item:focus-visible,\n:host(:focus-visible) .item {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 1px;\n}\n\n@media (hover: hover) {\n :host(:not([disabled])) .item:hover {\n background-color: var(--l-color-bg-state-hover);\n }\n}\n\n:host([selected]:not([disabled])) .item {\n background-color: var(--l-color-bg-state-selected);\n}\n\n.expand {\n inline-size: var(--chevron-size);\n block-size: var(--chevron-size);\n display: grid;\n place-items: center;\n flex: none;\n color: var(--l-color-text-secondary, CanvasText);\n border-radius: 3px;\n cursor: pointer;\n}\n\n/* Hide the DEFAULT fallback chevron SVG on a leaf — slotted content\n (user-provided icon, avatar, etc.) remains visible because it lives outside\n the slot in the DOM tree. The `.expand` span keeps its fixed --chevron-size\n so leaf rows stay aligned with branches. */\n:host(:not(:state(has-children)):not([lazy])) .expand > slot > svg {\n display: none;\n}\n\n.expand svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* The checkbox appearance comes from the shared `.l-checkbox` skin imported\n above; this rule only governs visibility. */\n:host(:not(:state(checkbox))) .checkbox {\n display: none;\n}\n\n.label {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.label ::slotted(*) {\n min-inline-size: 0;\n}\n\n/* Wrapper around the content slot + children — anchor for the indent guide. */\n.branch {\n position: relative;\n}\n\n/* Content slot — block area between the row and the children.\n Aligned under the label text: same left offset as the row's label\n (depth indent + row padding + chevron + gap). Visible for leaves (no\n children) and for expanded branches; hidden when a branch is collapsed\n (mirrors the children visibility). */\n.content {\n display: block;\n padding-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + var(--chevron-size) +\n var(--item-gap)\n );\n padding-inline-end: var(--row-padding-inline);\n}\n\n:host(:state(has-children):not([expanded])) .content {\n display: none;\n}\n\n.children {\n display: none;\n}\n\n:host([expanded]) .children {\n display: block;\n}\n\n/* Vertical indent guide — spans the content + children block, starting\n right below the row so it never overlaps the chevron/avatar.\n The guide's visual centre sits exactly on the parent chevron's centre. */\n.branch::before {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + (var(--chevron-size) / 2) -\n (var(--indent-guide-width) / 2)\n );\n inline-size: 0;\n border-inline-start: var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color);\n pointer-events: none;\n}\n\n/* Only render the guide for open branches that have children. */\n:host(:not([expanded])) .branch::before,\n:host(:not(:state(has-children))) .branch::before {\n display: none;\n}\n\n.spinner {\n inline-size: 0.875rem;\n block-size: 0.875rem;\n border-radius: 50%;\n border: 2px solid var(--l-color-border, currentColor);\n border-block-start-color: transparent;\n animation: spin 700ms linear infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .spinner {\n animation: none;\n }\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\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 hostStyles from '../../shared/styles/host.styles.js';\nimport checkboxAppearance from '../../shared/styles/checkbox-appearance.styles.js';\nimport rawStyles from './tree-item.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A node inside `<l-tree>`. Nested `<l-tree-item>` children become sub-nodes.\n *\n * @slot - Label content (kept to a single row).\n * @slot prefix - Leading content before the label (e.g. icon).\n * @slot suffix - Trailing content.\n * @slot expand-icon - Icon shown when the item is collapsed.\n * @slot collapse-icon - Icon shown when the item is expanded.\n * @slot content - Block content that belongs to the item but not to its header row (e.g. comment body, action bar). Hidden when a branch is collapsed.\n *\n * @csspart base - The item row.\n * @csspart expand-button - The chevron toggle area.\n * @csspart checkbox - The native checkbox input.\n * @csspart label - The label container.\n * @csspart branch - Wrapper around the content and children slots; carries the indent guide.\n * @csspart content - The content slot wrapper (block area between the row and the children).\n * @csspart children - The nested items container.\n *\n * @cssproperty [--_depth] - Internal depth index driving indentation. Set by `<l-tree>`.\n *\n * Layout tokens (`--chevron-size`, `--row-height`, `--row-padding-inline`, `--item-gap`) live on `<l-tree>` and cascade down — see its CSS custom properties.\n *\n * @event expand - Fired when the item is expanded.\n * @event collapse - Fired when the item is collapsed.\n * @event lazy-load - Fired when a lazy item is expanded for the first time. Consumers should append children and set `lazy=false`.\n *\n * @customElement l-tree-item\n */\nexport class TreeItem extends LuxenElement {\n static override styles = [hostStyles, checkboxAppearance, styles];\n\n private _internals = this.attachInternals();\n private _childObserver?: MutationObserver;\n\n /** Whether the item is expanded. */\n @property({ type: Boolean, reflect: true })\n accessor expanded = false;\n\n /** Whether the item is selected. */\n @property({ type: Boolean, reflect: true })\n accessor selected = false;\n\n /** Whether the checkbox is indeterminate (some descendants selected). */\n @property({ type: Boolean, reflect: true })\n accessor indeterminate = false;\n\n /** Whether the item is disabled. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /** Marks this item as having children that will be loaded on first expand. */\n @property({ type: Boolean, reflect: true })\n accessor lazy = false;\n\n /** Whether the item is currently loading (shows a spinner). */\n @property({ type: Boolean, reflect: true })\n accessor loading = false;\n\n /** Set by `<l-tree>`: whether a checkbox is shown. */\n set showCheckbox(value: boolean) {\n this._showCheckbox = value;\n this._setState('checkbox', value);\n }\n get showCheckbox(): boolean {\n return this._showCheckbox;\n }\n private _showCheckbox = false;\n\n /** Set by `<l-tree>`: depth of the item in the tree (0 = root). */\n set depth(value: number) {\n this._depth = value;\n this.style.setProperty('--_depth', String(value));\n }\n get depth(): number {\n return this._depth;\n }\n private _depth = 0;\n\n /**\n * 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\n * screen readers announce \"level 2, 3 of 5\" even when `lazy` children keep the\n * full set out of the DOM.\n */\n setPosition(level: number, posInSet: number, setSize: number) {\n this._aria('ariaLevel', 'aria-level', String(level));\n this._aria('ariaPosInSet', 'aria-posinset', String(posInSet));\n this._aria('ariaSetSize', 'aria-setsize', String(setSize));\n }\n\n /** Whether this item has nested tree-item children. */\n get hasChildren(): boolean {\n return this._hasChildren;\n }\n private _hasChildren = false;\n\n /** Returns the child `<l-tree-item>` elements directly under this one. */\n getChildrenItems({ includeDisabled = true } = {}): TreeItem[] {\n const childTag = tagName('tree-item').toUpperCase();\n return (Array.from(this.children) as TreeItem[]).filter(\n (el) => el.tagName === childTag && (includeDisabled || !el.disabled),\n );\n }\n\n /** Returns true if this item has no expandable children. */\n isLeaf(): boolean {\n return !this.lazy && this.getChildrenItems().length === 0;\n }\n\n /** Returns the text label of this item. */\n getTextLabel(): string {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!slot) return (this.textContent ?? '').trim();\n return slot\n .assignedNodes({ flatten: true })\n .map((n) => n.textContent ?? '')\n .join('')\n .trim();\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this._internals.role = 'treeitem';\n // Mirror the role to a DOM attribute too, so `[role=\"treeitem\"]` selectors\n // (CSS, querySelector, Cypress/Playwright CSS) keep matching — the\n // ElementInternals role alone is not attribute-selectable. ARIA states are\n // mirrored the same way in `_aria()` (aria-expanded/selected/disabled/…).\n if (!this.hasAttribute('role')) this.setAttribute('role', 'treeitem');\n this._childObserver = new MutationObserver(() => this._syncChildren());\n this._childObserver.observe(this, { childList: true });\n this._syncChildren();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._childObserver?.disconnect();\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('expanded')) {\n this._reflectExpanded();\n // Emit lazy-load for ANY transition to expanded (keyboard, chevron,\n // `expandAll()`…), not just `toggle()` — otherwise keyboard users expand a\n // lazy branch with no children and no fetch. Fires while still `lazy`; the\n // consumer appends children and clears `lazy`, so it won't re-fire.\n if (this.expanded && this.lazy) this.emit('lazy-load');\n this.emit(this.expanded ? 'expand' : 'collapse');\n }\n\n if (changed.has('selected')) {\n this._aria('ariaSelected', 'aria-selected', String(this.selected));\n }\n\n if (changed.has('disabled')) {\n this._aria('ariaDisabled', 'aria-disabled', this.disabled ? 'true' : null);\n }\n\n if (changed.has('loading')) {\n this._aria('ariaBusy', 'aria-busy', this.loading ? 'true' : null);\n }\n }\n\n /** Leaf items omit `aria-expanded` entirely; branches reflect their state. */\n private _reflectExpanded() {\n this._aria('ariaExpanded', 'aria-expanded', this.isLeaf() ? null : String(this.expanded));\n }\n\n /**\n * Write an ARIA state to BOTH ElementInternals (the semantic source, in the\n * accessibility tree) and a content attribute (so `[aria-*]` CSS / query / test\n * selectors keep matching — same belt-and-suspenders as the mirrored `role`).\n * A `null` value clears both.\n */\n private _aria(key: keyof ElementInternals, attr: string, value: string | null) {\n (this._internals as unknown as Record<string, string | null>)[key] = value;\n if (value === null) this.removeAttribute(attr);\n else this.setAttribute(attr, value);\n }\n\n private _setState(name: string, on: boolean) {\n if (!this._internals.states) return;\n if (on) this._internals.states.add(name);\n else this._internals.states.delete(name);\n }\n\n private _syncChildren() {\n // Auto-slot nested tree-items into the `children` slot so they render in the group container,\n // while label text/elements remain in the default slot.\n const childTag = tagName('tree-item').toUpperCase();\n let count = 0;\n for (const child of Array.from(this.children) as HTMLElement[]) {\n if (child.tagName === childTag) {\n count++;\n if (child.slot !== 'children') child.slot = 'children';\n }\n }\n this._hasChildren = count > 0;\n this._setState('has-children', this._hasChildren);\n if (!this._hasChildren && !this.lazy && this.expanded) {\n this.expanded = false;\n }\n this._reflectExpanded();\n }\n\n /** Toggle expand state. Opening a `lazy` item emits `lazy-load` (via `updated`). */\n toggle() {\n if (this.isLeaf() && !this.lazy) return;\n // lazy-load is emitted centrally from `updated()` on the expand transition.\n this.expanded = !this.expanded;\n }\n\n private _onCheckboxChange = (event: Event) => {\n event.stopPropagation();\n const input = event.target as HTMLInputElement;\n this.dispatchEvent(\n new CustomEvent('l-tree-item-toggle', {\n bubbles: true,\n composed: true,\n detail: { item: this, checked: input.checked },\n }),\n );\n };\n\n override render() {\n return html`\n <div\n class=\"item\"\n part=\"base\"\n >\n <span\n class=\"expand\"\n part=\"expand-button\"\n aria-hidden=\"true\"\n >\n ${this.loading\n ? html`<span\n class=\"spinner\"\n role=\"status\"\n ></span>`\n : this.expanded || this.isLeaf()\n ? html`<slot name=\"collapse-icon\">\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M3.5 6l4.5 5 4.5-5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </slot>`\n : html`<slot name=\"expand-icon\">\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M6 3.5l5 4.5-5 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </slot>`}\n </span>\n\n <input\n class=\"checkbox l-checkbox\"\n part=\"checkbox\"\n type=\"checkbox\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n .checked=${this.selected}\n .indeterminate=${this.indeterminate}\n ?disabled=${this.disabled}\n @click=${(e: Event) => e.stopPropagation()}\n @change=${this._onCheckboxChange}\n />\n\n <slot name=\"prefix\"></slot>\n <span\n class=\"label\"\n part=\"label\"\n ><slot></slot\n ></span>\n <slot name=\"suffix\"></slot>\n </div>\n\n <div\n class=\"branch\"\n part=\"branch\"\n >\n <div\n class=\"content\"\n part=\"content\"\n >\n <slot name=\"content\"></slot>\n </div>\n <div\n class=\"children\"\n part=\"children\"\n role=\"group\"\n >\n <slot name=\"children\"></slot>\n </div>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tree-item.js","names":[],"sources":["../../../src/html/elements/tree-item/tree-item.css?inline","../../../src/html/elements/tree-item/tree-item.ts"],"sourcesContent":[":host {\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-size: 0.875rem;\n line-height: 1.5;\n /* The host is the roving-tabindex focus target, but the visible ring is drawn\n on the inner `.item` row. Suppress the host's UA outline so it doesn't paint\n a second ring around the whole subtree (row + children). */\n outline: none;\n}\n\n:host([disabled]) {\n opacity: 0.4;\n}\n\n:host([disabled]) .item {\n cursor: not-allowed;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--item-gap);\n min-block-size: var(--row-height);\n padding-inline: var(--row-padding-inline);\n padding-inline-start: calc(var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline));\n border-radius: 0.375rem;\n cursor: pointer;\n user-select: none;\n transition:\n background-color 120ms ease,\n color 120ms ease;\n position: relative;\n}\n\n.item:focus-visible,\n:host(:focus-visible) .item {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 1px;\n}\n\n@media (hover: hover) {\n :host(:not([disabled])) .item:hover {\n background-color: var(--l-color-bg-state-hover);\n }\n}\n\n:host([selected]:not([disabled])) .item {\n background-color: var(--l-color-bg-state-selected);\n}\n\n.expand {\n inline-size: var(--chevron-size);\n block-size: var(--chevron-size);\n display: grid;\n place-items: center;\n flex: none;\n color: var(--l-color-text-secondary, CanvasText);\n border-radius: 3px;\n cursor: pointer;\n}\n\n/* Hide the DEFAULT fallback chevron SVG on a leaf — slotted content\n (user-provided icon, avatar, etc.) remains visible because it lives outside\n the slot in the DOM tree. The `.expand` span keeps its fixed --chevron-size\n so leaf rows stay aligned with branches. */\n:host(:not(:state(has-children)):not([lazy])) .expand > slot > svg {\n display: none;\n}\n\n.expand svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* The checkbox appearance comes from the shared `.l-checkbox` skin imported\n above; this rule only governs visibility. */\n:host(:not(:state(checkbox))) .checkbox {\n display: none;\n}\n\n.label {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n /* `clip` (not `hidden`) so the label still truncates long text to an ellipsis\n while `overflow-clip-margin` lets a slotted interactive control's hover/focus\n decoration (a row-action button, an `<l-dropdown>` trigger) bleed past the\n row-height label box instead of being cut on its top/bottom/left edges. The\n margin is kept small so the bleed stays imperceptible for text. */\n overflow: clip;\n overflow-clip-margin: 0.375rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.label ::slotted(*) {\n min-inline-size: 0;\n}\n\n/* Wrapper around the content slot + children — anchor for the indent guide. */\n.branch {\n position: relative;\n}\n\n/* Content slot — block area between the row and the children.\n Aligned under the label text: same left offset as the row's label\n (depth indent + row padding + chevron + gap). Visible for leaves (no\n children) and for expanded branches; hidden when a branch is collapsed\n (mirrors the children visibility). */\n.content {\n display: block;\n padding-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + var(--chevron-size) +\n var(--item-gap)\n );\n padding-inline-end: var(--row-padding-inline);\n}\n\n:host(:state(has-children):not([expanded])) .content {\n display: none;\n}\n\n.children {\n display: none;\n}\n\n:host([expanded]) .children {\n display: block;\n}\n\n/* Vertical indent guide — spans the content + children block, starting\n right below the row so it never overlaps the chevron/avatar.\n The guide's visual centre sits exactly on the parent chevron's centre. */\n.branch::before {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + (var(--chevron-size) / 2) -\n (var(--indent-guide-width) / 2)\n );\n inline-size: 0;\n border-inline-start: var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color);\n pointer-events: none;\n}\n\n/* Only render the guide for open branches that have children. */\n:host(:not([expanded])) .branch::before,\n:host(:not(:state(has-children))) .branch::before {\n display: none;\n}\n\n.spinner {\n inline-size: 0.875rem;\n block-size: 0.875rem;\n border-radius: 50%;\n border: 2px solid var(--l-color-border, currentColor);\n border-block-start-color: transparent;\n animation: spin 700ms linear infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .spinner {\n animation: none;\n }\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\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 hostStyles from '../../shared/styles/host.styles.js';\nimport checkboxAppearance from '../../shared/styles/checkbox-appearance.styles.js';\nimport rawStyles from './tree-item.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * A node inside `<l-tree>`. Nested `<l-tree-item>` children become sub-nodes.\n *\n * @slot - Label content (kept to a single row).\n * @slot prefix - Leading content before the label (e.g. icon).\n * @slot suffix - Trailing content.\n * @slot expand-icon - Icon shown when the item is collapsed.\n * @slot collapse-icon - Icon shown when the item is expanded.\n * @slot content - Block content that belongs to the item but not to its header row (e.g. comment body, action bar). Hidden when a branch is collapsed.\n *\n * @csspart base - The item row.\n * @csspart expand-button - The chevron toggle area.\n * @csspart checkbox - The native checkbox input.\n * @csspart label - The label container.\n * @csspart branch - Wrapper around the content and children slots; carries the indent guide.\n * @csspart content - The content slot wrapper (block area between the row and the children).\n * @csspart children - The nested items container.\n *\n * @cssproperty [--_depth] - Internal depth index driving indentation. Set by `<l-tree>`.\n *\n * Layout tokens (`--chevron-size`, `--row-height`, `--row-padding-inline`, `--item-gap`) live on `<l-tree>` and cascade down — see its CSS custom properties.\n *\n * @event expand - Fired when the item is expanded.\n * @event collapse - Fired when the item is collapsed.\n * @event lazy-load - Fired when a lazy item is expanded for the first time. Consumers should append children and set `lazy=false`.\n *\n * @customElement l-tree-item\n */\nexport class TreeItem extends LuxenElement {\n static override styles = [hostStyles, checkboxAppearance, styles];\n\n private _internals = this.attachInternals();\n private _childObserver?: MutationObserver;\n\n /** Whether the item is expanded. */\n @property({ type: Boolean, reflect: true })\n accessor expanded = false;\n\n /** Whether the item is selected. */\n @property({ type: Boolean, reflect: true })\n accessor selected = false;\n\n /** Whether the checkbox is indeterminate (some descendants selected). */\n @property({ type: Boolean, reflect: true })\n accessor indeterminate = false;\n\n /** Whether the item is disabled. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /** Marks this item as having children that will be loaded on first expand. */\n @property({ type: Boolean, reflect: true })\n accessor lazy = false;\n\n /** Whether the item is currently loading (shows a spinner). */\n @property({ type: Boolean, reflect: true })\n accessor loading = false;\n\n /** Set by `<l-tree>`: whether a checkbox is shown. */\n set showCheckbox(value: boolean) {\n this._showCheckbox = value;\n this._setState('checkbox', value);\n }\n get showCheckbox(): boolean {\n return this._showCheckbox;\n }\n private _showCheckbox = false;\n\n /** Set by `<l-tree>`: depth of the item in the tree (0 = root). */\n set depth(value: number) {\n this._depth = value;\n this.style.setProperty('--_depth', String(value));\n }\n get depth(): number {\n return this._depth;\n }\n private _depth = 0;\n\n /**\n * 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\n * screen readers announce \"level 2, 3 of 5\" even when `lazy` children keep the\n * full set out of the DOM.\n */\n setPosition(level: number, posInSet: number, setSize: number) {\n this._aria('ariaLevel', 'aria-level', String(level));\n this._aria('ariaPosInSet', 'aria-posinset', String(posInSet));\n this._aria('ariaSetSize', 'aria-setsize', String(setSize));\n }\n\n /** Whether this item has nested tree-item children. */\n get hasChildren(): boolean {\n return this._hasChildren;\n }\n private _hasChildren = false;\n\n /** Returns the child `<l-tree-item>` elements directly under this one. */\n getChildrenItems({ includeDisabled = true } = {}): TreeItem[] {\n const childTag = tagName('tree-item').toUpperCase();\n return (Array.from(this.children) as TreeItem[]).filter(\n (el) => el.tagName === childTag && (includeDisabled || !el.disabled),\n );\n }\n\n /** Returns true if this item has no expandable children. */\n isLeaf(): boolean {\n return !this.lazy && this.getChildrenItems().length === 0;\n }\n\n /** Returns the text label of this item. */\n getTextLabel(): string {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!slot) return (this.textContent ?? '').trim();\n return slot\n .assignedNodes({ flatten: true })\n .map((n) => n.textContent ?? '')\n .join('')\n .trim();\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this._internals.role = 'treeitem';\n // Mirror the role to a DOM attribute too, so `[role=\"treeitem\"]` selectors\n // (CSS, querySelector, Cypress/Playwright CSS) keep matching — the\n // ElementInternals role alone is not attribute-selectable. ARIA states are\n // mirrored the same way in `_aria()` (aria-expanded/selected/disabled/…).\n if (!this.hasAttribute('role')) this.setAttribute('role', 'treeitem');\n this._childObserver = new MutationObserver(() => this._syncChildren());\n this._childObserver.observe(this, { childList: true });\n this._syncChildren();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._childObserver?.disconnect();\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('expanded')) {\n this._reflectExpanded();\n // Emit lazy-load for ANY transition to expanded (keyboard, chevron,\n // `expandAll()`…), not just `toggle()` — otherwise keyboard users expand a\n // lazy branch with no children and no fetch. Fires while still `lazy`; the\n // consumer appends children and clears `lazy`, so it won't re-fire.\n if (this.expanded && this.lazy) this.emit('lazy-load');\n this.emit(this.expanded ? 'expand' : 'collapse');\n }\n\n if (changed.has('selected')) {\n this._aria('ariaSelected', 'aria-selected', String(this.selected));\n }\n\n if (changed.has('disabled')) {\n this._aria('ariaDisabled', 'aria-disabled', this.disabled ? 'true' : null);\n }\n\n if (changed.has('loading')) {\n this._aria('ariaBusy', 'aria-busy', this.loading ? 'true' : null);\n }\n }\n\n /** Leaf items omit `aria-expanded` entirely; branches reflect their state. */\n private _reflectExpanded() {\n this._aria('ariaExpanded', 'aria-expanded', this.isLeaf() ? null : String(this.expanded));\n }\n\n /**\n * Write an ARIA state to BOTH ElementInternals (the semantic source, in the\n * accessibility tree) and a content attribute (so `[aria-*]` CSS / query / test\n * selectors keep matching — same belt-and-suspenders as the mirrored `role`).\n * A `null` value clears both.\n */\n private _aria(key: keyof ElementInternals, attr: string, value: string | null) {\n (this._internals as unknown as Record<string, string | null>)[key] = value;\n if (value === null) this.removeAttribute(attr);\n else this.setAttribute(attr, value);\n }\n\n private _setState(name: string, on: boolean) {\n if (!this._internals.states) return;\n if (on) this._internals.states.add(name);\n else this._internals.states.delete(name);\n }\n\n private _syncChildren() {\n // Auto-slot nested tree-items into the `children` slot so they render in the group container,\n // while label text/elements remain in the default slot.\n const childTag = tagName('tree-item').toUpperCase();\n let count = 0;\n for (const child of Array.from(this.children) as HTMLElement[]) {\n if (child.tagName === childTag) {\n count++;\n if (child.slot !== 'children') child.slot = 'children';\n }\n }\n this._hasChildren = count > 0;\n this._setState('has-children', this._hasChildren);\n if (!this._hasChildren && !this.lazy && this.expanded) {\n this.expanded = false;\n }\n this._reflectExpanded();\n }\n\n /** Toggle expand state. Opening a `lazy` item emits `lazy-load` (via `updated`). */\n toggle() {\n if (this.isLeaf() && !this.lazy) return;\n // lazy-load is emitted centrally from `updated()` on the expand transition.\n this.expanded = !this.expanded;\n }\n\n private _onCheckboxChange = (event: Event) => {\n event.stopPropagation();\n const input = event.target as HTMLInputElement;\n this.dispatchEvent(\n new CustomEvent('l-tree-item-toggle', {\n bubbles: true,\n composed: true,\n detail: { item: this, checked: input.checked },\n }),\n );\n };\n\n override render() {\n return html`\n <div\n class=\"item\"\n part=\"base\"\n >\n <span\n class=\"expand\"\n part=\"expand-button\"\n aria-hidden=\"true\"\n >\n ${this.loading\n ? html`<span\n class=\"spinner\"\n role=\"status\"\n ></span>`\n : this.expanded || this.isLeaf()\n ? html`<slot name=\"collapse-icon\">\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M3.5 6l4.5 5 4.5-5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </slot>`\n : html`<slot name=\"expand-icon\">\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M6 3.5l5 4.5-5 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </slot>`}\n </span>\n\n <input\n class=\"checkbox l-checkbox\"\n part=\"checkbox\"\n type=\"checkbox\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n .checked=${this.selected}\n .indeterminate=${this.indeterminate}\n ?disabled=${this.disabled}\n @click=${(e: Event) => e.stopPropagation()}\n @change=${this._onCheckboxChange}\n />\n\n <slot name=\"prefix\"></slot>\n <span\n class=\"label\"\n part=\"label\"\n ><slot></slot\n ></span>\n <slot name=\"suffix\"></slot>\n </div>\n\n <div\n class=\"branch\"\n part=\"branch\"\n >\n <div\n class=\"content\"\n part=\"content\"\n >\n <slot name=\"content\"></slot>\n </div>\n <div\n class=\"children\"\n part=\"children\"\n role=\"group\"\n >\n <slot name=\"children\"></slot>\n </div>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|
package/cdn/standalone.js
CHANGED
|
@@ -34915,7 +34915,7 @@ define("tree", Tree);
|
|
|
34915
34915
|
var checkbox_appearance_styles_default = r$6("/* Shared checkbox appearance — the visual skin behind `.l-checkbox`.\n\n Colocated with its `checkbox-appearance.styles.ts` wrapper so Shadow-DOM\n elements that render their own native checkbox (e.g. `<l-tree-item>` in\n `selection=\"multiple\"`) can pull in the exact same look via `static styles`.\n The global light-DOM `checkbox.css` primitive `@import`s this file too, so\n both surfaces stay in sync. The global `.l-checkbox` class cannot pierce a\n shadow boundary, but the `--l-form-control-*` tokens this rule relies on DO\n inherit across shadow roots.\n\n The checkmark / indeterminate dash are drawn with a `background-image` SVG on\n the input itself — `::before`/`::after` do not paint on replaced elements\n like `<input>`. `background-image` can't read the host's `currentColor`, so\n the glyph color is baked white. This stays legible because the accent\n (`--l-form-control-activated-color`) is a stable color that does not invert\n between light and dark. Override `--checkmark` to swap the icon. */\n\n@layer components {\n .l-checkbox,\n :where(l-form-field:not([unstyled])) > input[type='checkbox']:not([role='switch']) {\n /* Public knobs */\n --size: var(--l-form-control-toggle-size);\n --accent: var(--l-form-control-activated-color);\n --checkmark: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>');\n --_dash: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>');\n\n box-sizing: border-box;\n flex: 0 0 auto;\n inline-size: var(--size);\n block-size: var(--size);\n margin: 0;\n padding: 0;\n appearance: none;\n border: var(--l-form-control-border-width) solid var(--l-form-control-border-color);\n border-radius: calc(var(--size) * 0.2);\n background-color: var(--l-form-control-background-color);\n background-repeat: no-repeat;\n background-position: center;\n background-size: 75%;\n vertical-align: middle;\n cursor: pointer;\n transition-property: background-color, border-color;\n transition-duration: 150ms;\n\n &:checked,\n &:indeterminate {\n border-color: var(--accent);\n background-color: var(--accent);\n }\n\n &:checked {\n background-image: var(--checkmark);\n }\n\n &:indeterminate {\n background-image: var(--_dash);\n }\n\n @media (hover: hover) {\n &:hover:not(:disabled) {\n border-color: var(--l-form-control-border-color-hover);\n }\n }\n\n &:focus-visible {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 2px;\n }\n\n /* Invalid: only after interaction (`:user-invalid`), or forced via\n `aria-invalid` (set by `l-form-field` / server-side validation).\n Overriding `--accent` makes a checked invalid box fill with the error\n color too (not just the border). */\n &:user-invalid,\n &[aria-invalid='true'] {\n --accent: var(--l-form-control-border-color-invalid);\n border-color: var(--l-form-control-border-color-invalid);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .l-checkbox,\n :where(l-form-field:not([unstyled])) > input[type='checkbox']:not([role='switch']) {\n transition-duration: 0ms;\n }\n }\n}\n");
|
|
34916
34916
|
//#endregion
|
|
34917
34917
|
//#region src/html/elements/tree-item/tree-item.ts
|
|
34918
|
-
var styles = r$6(":host {\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-size: 0.875rem;\n line-height: 1.5;\n /* The host is the roving-tabindex focus target, but the visible ring is drawn\n on the inner `.item` row. Suppress the host's UA outline so it doesn't paint\n a second ring around the whole subtree (row + children). */\n outline: none;\n}\n\n:host([disabled]) {\n opacity: 0.4;\n}\n\n:host([disabled]) .item {\n cursor: not-allowed;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--item-gap);\n min-block-size: var(--row-height);\n padding-inline: var(--row-padding-inline);\n padding-inline-start: calc(var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline));\n border-radius: 0.375rem;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n transition:\n background-color 120ms ease,\n color 120ms ease;\n position: relative;\n}\n\n.item:focus-visible,\n:host(:focus-visible) .item {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 1px;\n}\n\n@media (hover: hover) {\n :host(:not([disabled])) .item:hover {\n background-color: var(--l-color-bg-state-hover);\n }\n}\n\n:host([selected]:not([disabled])) .item {\n background-color: var(--l-color-bg-state-selected);\n}\n\n.expand {\n inline-size: var(--chevron-size);\n block-size: var(--chevron-size);\n display: grid;\n place-items: center;\n flex: none;\n color: var(--l-color-text-secondary, CanvasText);\n border-radius: 3px;\n cursor: pointer;\n}\n\n/* Hide the DEFAULT fallback chevron SVG on a leaf — slotted content\n (user-provided icon, avatar, etc.) remains visible because it lives outside\n the slot in the DOM tree. The `.expand` span keeps its fixed --chevron-size\n so leaf rows stay aligned with branches. */\n\n:host(:not(:state(has-children)):not([lazy])) .expand > slot > svg {\n display: none;\n}\n\n.expand svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* The checkbox appearance comes from the shared `.l-checkbox` skin imported\n above; this rule only governs visibility. */\n\n:host(:not(:state(checkbox))) .checkbox {\n display: none;\n}\n\n.label {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n overflow:
|
|
34918
|
+
var styles = r$6(":host {\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-size: 0.875rem;\n line-height: 1.5;\n /* The host is the roving-tabindex focus target, but the visible ring is drawn\n on the inner `.item` row. Suppress the host's UA outline so it doesn't paint\n a second ring around the whole subtree (row + children). */\n outline: none;\n}\n\n:host([disabled]) {\n opacity: 0.4;\n}\n\n:host([disabled]) .item {\n cursor: not-allowed;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--item-gap);\n min-block-size: var(--row-height);\n padding-inline: var(--row-padding-inline);\n padding-inline-start: calc(var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline));\n border-radius: 0.375rem;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n transition:\n background-color 120ms ease,\n color 120ms ease;\n position: relative;\n}\n\n.item:focus-visible,\n:host(:focus-visible) .item {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 1px;\n}\n\n@media (hover: hover) {\n :host(:not([disabled])) .item:hover {\n background-color: var(--l-color-bg-state-hover);\n }\n}\n\n:host([selected]:not([disabled])) .item {\n background-color: var(--l-color-bg-state-selected);\n}\n\n.expand {\n inline-size: var(--chevron-size);\n block-size: var(--chevron-size);\n display: grid;\n place-items: center;\n flex: none;\n color: var(--l-color-text-secondary, CanvasText);\n border-radius: 3px;\n cursor: pointer;\n}\n\n/* Hide the DEFAULT fallback chevron SVG on a leaf — slotted content\n (user-provided icon, avatar, etc.) remains visible because it lives outside\n the slot in the DOM tree. The `.expand` span keeps its fixed --chevron-size\n so leaf rows stay aligned with branches. */\n\n:host(:not(:state(has-children)):not([lazy])) .expand > slot > svg {\n display: none;\n}\n\n.expand svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* The checkbox appearance comes from the shared `.l-checkbox` skin imported\n above; this rule only governs visibility. */\n\n:host(:not(:state(checkbox))) .checkbox {\n display: none;\n}\n\n.label {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n /* `clip` (not `hidden`) so the label still truncates long text to an ellipsis\n while `overflow-clip-margin` lets a slotted interactive control's hover/focus\n decoration (a row-action button, an `<l-dropdown>` trigger) bleed past the\n row-height label box instead of being cut on its top/bottom/left edges. The\n margin is kept small so the bleed stays imperceptible for text. */\n overflow: clip;\n overflow-clip-margin: 0.375rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.label ::slotted(*) {\n min-inline-size: 0;\n}\n\n/* Wrapper around the content slot + children — anchor for the indent guide. */\n\n.branch {\n position: relative;\n}\n\n/* Content slot — block area between the row and the children.\n Aligned under the label text: same left offset as the row's label\n (depth indent + row padding + chevron + gap). Visible for leaves (no\n children) and for expanded branches; hidden when a branch is collapsed\n (mirrors the children visibility). */\n\n.content {\n display: block;\n padding-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + var(--chevron-size) +\n var(--item-gap)\n );\n padding-inline-end: var(--row-padding-inline);\n}\n\n:host(:state(has-children):not([expanded])) .content {\n display: none;\n}\n\n.children {\n display: none;\n}\n\n:host([expanded]) .children {\n display: block;\n}\n\n/* Vertical indent guide — spans the content + children block, starting\n right below the row so it never overlaps the chevron/avatar.\n The guide's visual centre sits exactly on the parent chevron's centre. */\n\n.branch::before {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + (var(--chevron-size) / 2) -\n (var(--indent-guide-width) / 2)\n );\n inline-size: 0;\n border-inline-start: var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color);\n pointer-events: none;\n}\n\n/* Only render the guide for open branches that have children. */\n\n:host(:not([expanded])) .branch::before,\n:host(:not(:state(has-children))) .branch::before {\n display: none;\n}\n\n.spinner {\n inline-size: 0.875rem;\n block-size: 0.875rem;\n border-radius: 50%;\n border: 2px solid var(--l-color-border, currentColor);\n border-block-start-color: transparent;\n animation: spin 700ms linear infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .spinner {\n animation: none;\n }\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n");
|
|
34919
34919
|
/**
|
|
34920
34920
|
* A node inside `<l-tree>`. Nested `<l-tree-item>` children become sub-nodes.
|
|
34921
34921
|
*
|