@design.estate/dees-wcctools 3.7.1 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{npmextra.json → .smartconfig.json} +13 -0
- package/dist_bundle/bundle.js +10565 -3101
- package/dist_bundle/bundle.js.map +3 -3
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/wcc-dashboard.d.ts +2 -2
- package/dist_ts_web/elements/wcc-dashboard.js +6 -5
- package/dist_ts_web/elements/wcc-sidebar.d.ts +4 -0
- package/dist_ts_web/elements/wcc-sidebar.js +111 -16
- package/dist_watch/bundle.js +140 -27
- package/dist_watch/bundle.js.map +3 -3
- package/license +1 -1
- package/package.json +14 -14
- package/readme.hints.md +40 -0
- package/readme.md +20 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/wcc-dashboard.ts +6 -5
- package/ts_web/elements/wcc-sidebar.ts +116 -16
package/license
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2020
|
|
1
|
+
Copyright (c) 2020 Task Venture Capital GmbH (hello@task.vc)
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@design.estate/dees-wcctools",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.",
|
|
6
6
|
"exports": {
|
|
@@ -10,27 +10,27 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"scripts": {
|
|
12
12
|
"test": "(npm run build)",
|
|
13
|
-
"build": "(tsbuild tsfolders --allowimplicitany && tsbundle
|
|
14
|
-
"watch": "tswatch
|
|
13
|
+
"build": "(tsbuild tsfolders --allowimplicitany && tsbundle)",
|
|
14
|
+
"watch": "tswatch",
|
|
15
15
|
"buildDocs": "tsdoc"
|
|
16
16
|
},
|
|
17
17
|
"author": "Lossless GmbH",
|
|
18
18
|
"license": "UNLICENSED",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@design.estate/dees-domtools": "^2.
|
|
21
|
-
"@design.estate/dees-element": "^2.
|
|
20
|
+
"@design.estate/dees-domtools": "^2.5.4",
|
|
21
|
+
"@design.estate/dees-element": "^2.2.4",
|
|
22
22
|
"@push.rocks/smartdelay": "^3.0.5",
|
|
23
23
|
"lit": "^3.3.2"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@api.global/typedserver": "^8.
|
|
27
|
-
"@git.zone/tsbuild": "^4.0
|
|
28
|
-
"@git.zone/tsbundle": "^2.
|
|
29
|
-
"@git.zone/tsrun": "^2.0.
|
|
30
|
-
"@git.zone/tstest": "^3.
|
|
31
|
-
"@git.zone/tswatch": "^
|
|
32
|
-
"@push.rocks/projectinfo": "^5.0
|
|
33
|
-
"@types/node": "^25.0
|
|
26
|
+
"@api.global/typedserver": "^8.4.6",
|
|
27
|
+
"@git.zone/tsbuild": "^4.4.0",
|
|
28
|
+
"@git.zone/tsbundle": "^2.10.0",
|
|
29
|
+
"@git.zone/tsrun": "^2.0.2",
|
|
30
|
+
"@git.zone/tstest": "^3.6.3",
|
|
31
|
+
"@git.zone/tswatch": "^3.3.2",
|
|
32
|
+
"@push.rocks/projectinfo": "^5.1.0",
|
|
33
|
+
"@types/node": "^25.6.0"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"ts/**/*",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"dist_ts_web/**/*",
|
|
42
42
|
"assets/**/*",
|
|
43
43
|
"cli.js",
|
|
44
|
-
"
|
|
44
|
+
".smartconfig.json",
|
|
45
45
|
"readme.md"
|
|
46
46
|
],
|
|
47
47
|
"browserslist": [
|
package/readme.hints.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Project Hints and Findings
|
|
2
2
|
|
|
3
|
+
## TypeScript 6.0 & Build Tooling (2026-04-12)
|
|
4
|
+
|
|
5
|
+
### TypeScript 6.0 Strict Defaults
|
|
6
|
+
TypeScript 6.0.2 (shipped with tsbuild 4.4.0) changes `strict` to `true` by default. The project explicitly sets `"strict": false` in tsconfig.json to preserve pre-TS6 behavior. Also added `"types": ["node"]` since TS6 changed `@types/*` auto-discovery.
|
|
7
|
+
|
|
8
|
+
### Config Migration: npmextra.json → .smartconfig.json
|
|
9
|
+
Build tools (tsbundle 2.10.0, tswatch 3.3.2) now use `@push.rocks/smartconfig` which reads `.smartconfig.json` (with leading dot). The old `npmextra.json` was renamed.
|
|
10
|
+
|
|
11
|
+
### tsbundle Configuration
|
|
12
|
+
The `tsbundle element` subcommand no longer exists. Instead, bundle configuration lives in `.smartconfig.json` under `"@git.zone/tsbundle"` with a `bundles` array. Entry point is `./html/index.ts` → `./dist_bundle/bundle.js`.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
3
16
|
## Section-based Configuration API (2025-12-27)
|
|
4
17
|
|
|
5
18
|
### Overview
|
|
@@ -62,6 +75,33 @@ Section names are URL-encoded. Legacy routes (`element`/`page` as section name)
|
|
|
62
75
|
|
|
63
76
|
---
|
|
64
77
|
|
|
78
|
+
## Element Demo Groups (2026-01-27)
|
|
79
|
+
|
|
80
|
+
### Overview
|
|
81
|
+
Elements can declare `demoGroups` (renamed from `demoGroup`) as a static property to appear grouped in the sidebar. Supports `string | string[]` — elements with an array appear in multiple groups simultaneously.
|
|
82
|
+
|
|
83
|
+
### Usage
|
|
84
|
+
```typescript
|
|
85
|
+
// Single group
|
|
86
|
+
public static demoGroups = 'Buttons';
|
|
87
|
+
|
|
88
|
+
// Multiple groups — element appears in both
|
|
89
|
+
public static demoGroups = ['Buttons', 'Form Controls'];
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Features
|
|
93
|
+
- Search matches group names (searching "Buttons" shows all elements in that group)
|
|
94
|
+
- Groups sorted alphabetically by group name
|
|
95
|
+
- Multi-group elements show `library_books` icon instead of `featured_video`
|
|
96
|
+
- Context menu shows "Show in Group:" with clickable group entries that scroll to and highlight the group
|
|
97
|
+
- `data-group` attribute on `.item-group` containers for DOM querying
|
|
98
|
+
|
|
99
|
+
### Files Changed
|
|
100
|
+
- `ts_web/elements/wcc-sidebar.ts` — grouping logic, search filter, sort key, icon, context menu, scrollToGroup
|
|
101
|
+
- `test/elements/test-button-*.ts`, `test/elements/test-input-*.ts` — renamed `demoGroup` → `demoGroups`
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
65
105
|
## UI Redesign with Shadcn-like Styles (2025-06-27)
|
|
66
106
|
|
|
67
107
|
### Changes Made
|
package/readme.md
CHANGED
|
@@ -293,6 +293,25 @@ export class MyButton extends DeesElement {
|
|
|
293
293
|
|
|
294
294
|
Each demo appears as a numbered item in an expandable folder in the sidebar.
|
|
295
295
|
|
|
296
|
+
### 🗂️ Demo Groups
|
|
297
|
+
|
|
298
|
+
Organize elements into groups within a section for better discoverability:
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
@customElement('my-input')
|
|
302
|
+
export class MyInput extends DeesElement {
|
|
303
|
+
// Single group
|
|
304
|
+
public static demoGroups = 'Form Controls';
|
|
305
|
+
|
|
306
|
+
// Or multiple groups — element appears in each
|
|
307
|
+
public static demoGroups = ['Form Controls', 'Inputs'];
|
|
308
|
+
|
|
309
|
+
public static demo = () => html`<my-input></my-input>`;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Groups appear as collapsible headers in the sidebar, sorted alphabetically. Searching matches group names too — searching "Form Controls" shows all elements in that group.
|
|
314
|
+
|
|
296
315
|
### ⏳ Async Demos
|
|
297
316
|
|
|
298
317
|
Return a `Promise` from `demo` for async setup:
|
|
@@ -462,7 +481,7 @@ my-component-library/
|
|
|
462
481
|
|
|
463
482
|
## License and Legal Information
|
|
464
483
|
|
|
465
|
-
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [
|
|
484
|
+
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license](./license) file.
|
|
466
485
|
|
|
467
486
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
468
487
|
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-wcctools',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.8.1',
|
|
7
7
|
description: 'A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.'
|
|
8
8
|
}
|
|
@@ -22,7 +22,8 @@ export const getSectionItems = (section: IWccSection): Array<[string, any]> => {
|
|
|
22
22
|
|
|
23
23
|
// Apply filter if provided
|
|
24
24
|
if (section.filter) {
|
|
25
|
-
|
|
25
|
+
const filterFn = section.filter;
|
|
26
|
+
entries = entries.filter(([name, item]) => filterFn(name, item));
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
// Apply sort if provided
|
|
@@ -43,13 +44,13 @@ export class WccDashboard extends DeesElement {
|
|
|
43
44
|
accessor selectedSection: IWccSection | null = null;
|
|
44
45
|
|
|
45
46
|
@property()
|
|
46
|
-
accessor selectedType: TElementType;
|
|
47
|
+
accessor selectedType: TElementType = 'element';
|
|
47
48
|
|
|
48
49
|
@property()
|
|
49
|
-
accessor selectedItemName: string;
|
|
50
|
+
accessor selectedItemName: string = '';
|
|
50
51
|
|
|
51
52
|
@property()
|
|
52
|
-
accessor selectedItem: TTemplateFactory | DeesElement;
|
|
53
|
+
accessor selectedItem: TTemplateFactory | DeesElement | null = null;
|
|
53
54
|
|
|
54
55
|
@property({ type: Number })
|
|
55
56
|
accessor selectedDemoIndex: number = 0;
|
|
@@ -77,7 +78,7 @@ export class WccDashboard extends DeesElement {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
@property()
|
|
80
|
-
accessor warning: string = null;
|
|
81
|
+
accessor warning: string | null = null;
|
|
81
82
|
|
|
82
83
|
private frameScrollY: number = 0;
|
|
83
84
|
private sidebarScrollY: number = 0;
|
|
@@ -4,7 +4,7 @@ import { WccDashboard, getSectionItems } from './wcc-dashboard.js';
|
|
|
4
4
|
import type { TTemplateFactory } from './wcctools.helpers.js';
|
|
5
5
|
import { getDemoCount, hasMultipleDemos } from './wcctools.helpers.js';
|
|
6
6
|
import type { IWccSection, TElementType } from '../wcctools.interfaces.js';
|
|
7
|
-
import { WccContextmenu } from './wcc-contextmenu.js';
|
|
7
|
+
import { WccContextmenu, type IContextMenuItem } from './wcc-contextmenu.js';
|
|
8
8
|
|
|
9
9
|
@customElement('wcc-sidebar')
|
|
10
10
|
export class WccSidebar extends DeesElement {
|
|
@@ -422,6 +422,7 @@ export class WccSidebar extends DeesElement {
|
|
|
422
422
|
color: #555;
|
|
423
423
|
padding: 0.125rem 0.625rem 0.25rem;
|
|
424
424
|
display: block;
|
|
425
|
+
cursor: context-menu;
|
|
425
426
|
}
|
|
426
427
|
|
|
427
428
|
.item-group .selectOption {
|
|
@@ -429,6 +430,15 @@ export class WccSidebar extends DeesElement {
|
|
|
429
430
|
margin-right: 0.25rem;
|
|
430
431
|
}
|
|
431
432
|
|
|
433
|
+
.item-group.group-highlight {
|
|
434
|
+
background: rgba(59, 130, 246, 0.15);
|
|
435
|
+
transition: background 0.3s ease;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.item-group.group-filter-match {
|
|
439
|
+
border-color: rgba(245, 158, 11, 0.5);
|
|
440
|
+
}
|
|
441
|
+
|
|
432
442
|
/* Resize handle */
|
|
433
443
|
.resize-handle {
|
|
434
444
|
position: absolute;
|
|
@@ -517,12 +527,49 @@ export class WccSidebar extends DeesElement {
|
|
|
517
527
|
|
|
518
528
|
private showContextMenu(e: MouseEvent, sectionName: string, itemName: string) {
|
|
519
529
|
const isPinned = this.isPinned(sectionName, itemName);
|
|
520
|
-
|
|
530
|
+
const section = this.dashboardRef?.sections?.find(s => s.name === sectionName);
|
|
531
|
+
const sectionEntries = section ? getSectionItems(section) : [];
|
|
532
|
+
const foundEntry = sectionEntries.find(([name]) => name === itemName);
|
|
533
|
+
const item = foundEntry?.[1];
|
|
534
|
+
const groups = item ? this.getElementGroups(item) : [];
|
|
535
|
+
|
|
536
|
+
const menuItems: IContextMenuItem[] = [
|
|
521
537
|
{
|
|
522
538
|
name: isPinned ? 'Unpin' : 'Pin',
|
|
523
539
|
iconName: isPinned ? 'push_pin' : 'push_pin',
|
|
524
540
|
action: () => this.togglePin(sectionName, itemName),
|
|
525
541
|
},
|
|
542
|
+
];
|
|
543
|
+
|
|
544
|
+
if (groups.length > 0) {
|
|
545
|
+
menuItems.push({
|
|
546
|
+
name: 'Show in Group:',
|
|
547
|
+
iconName: 'folder',
|
|
548
|
+
action: () => {},
|
|
549
|
+
disabled: true,
|
|
550
|
+
});
|
|
551
|
+
for (const groupName of groups) {
|
|
552
|
+
menuItems.push({
|
|
553
|
+
name: groupName,
|
|
554
|
+
iconName: 'label',
|
|
555
|
+
action: () => this.scrollToGroup(sectionName, groupName),
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
WccContextmenu.show(e, menuItems);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private showGroupContextMenu(e: MouseEvent, groupName: string) {
|
|
564
|
+
WccContextmenu.show(e, [
|
|
565
|
+
{
|
|
566
|
+
name: `Show "${groupName}"`,
|
|
567
|
+
iconName: 'filter_alt',
|
|
568
|
+
action: () => {
|
|
569
|
+
this.searchQuery = groupName;
|
|
570
|
+
this.dispatchEvent(new CustomEvent('searchChanged', { detail: this.searchQuery }));
|
|
571
|
+
},
|
|
572
|
+
},
|
|
526
573
|
]);
|
|
527
574
|
}
|
|
528
575
|
|
|
@@ -569,7 +616,9 @@ export class WccSidebar extends DeesElement {
|
|
|
569
616
|
${pinnedEntries.map(({ sectionName, itemName, item, section }) => {
|
|
570
617
|
const isSelected = this.selectedItem === item;
|
|
571
618
|
const type = section.type === 'elements' ? 'element' : 'page';
|
|
572
|
-
const icon = section.type === 'elements'
|
|
619
|
+
const icon = section.type === 'elements'
|
|
620
|
+
? (this.getElementGroups(item).length > 1 ? 'library_books' : 'featured_video')
|
|
621
|
+
: 'insert_drive_file';
|
|
573
622
|
|
|
574
623
|
return html`
|
|
575
624
|
<div
|
|
@@ -603,7 +652,13 @@ export class WccSidebar extends DeesElement {
|
|
|
603
652
|
return this.dashboardRef.sections.map((section) => {
|
|
604
653
|
// Check if section has any matching items
|
|
605
654
|
const entries = getSectionItems(section);
|
|
606
|
-
const filteredEntries = entries.filter(([name]) =>
|
|
655
|
+
const filteredEntries = entries.filter(([name, item]) => {
|
|
656
|
+
if (this.matchesSearch(name)) return true;
|
|
657
|
+
const rawGroups = (item as any).demoGroups;
|
|
658
|
+
if (!rawGroups) return false;
|
|
659
|
+
const groups: string[] = Array.isArray(rawGroups) ? rawGroups : [rawGroups];
|
|
660
|
+
return groups.some(g => this.matchesSearch(g));
|
|
661
|
+
});
|
|
607
662
|
|
|
608
663
|
// Hide section if no items match the search
|
|
609
664
|
if (filteredEntries.length === 0 && this.searchQuery) {
|
|
@@ -635,7 +690,13 @@ export class WccSidebar extends DeesElement {
|
|
|
635
690
|
private renderSectionItems(section: IWccSection) {
|
|
636
691
|
const entries = getSectionItems(section);
|
|
637
692
|
// Filter entries by search query
|
|
638
|
-
const filteredEntries = entries.filter(([name]) =>
|
|
693
|
+
const filteredEntries = entries.filter(([name, item]) => {
|
|
694
|
+
if (this.matchesSearch(name)) return true;
|
|
695
|
+
const rawGroups = (item as any).demoGroups;
|
|
696
|
+
if (!rawGroups) return false;
|
|
697
|
+
const groups: string[] = Array.isArray(rawGroups) ? rawGroups : [rawGroups];
|
|
698
|
+
return groups.some(g => this.matchesSearch(g));
|
|
699
|
+
});
|
|
639
700
|
|
|
640
701
|
if (section.type === 'pages') {
|
|
641
702
|
return filteredEntries.map(([pageName, item]) => {
|
|
@@ -655,16 +716,21 @@ export class WccSidebar extends DeesElement {
|
|
|
655
716
|
`;
|
|
656
717
|
});
|
|
657
718
|
} else {
|
|
658
|
-
// type === 'elements' - group by
|
|
719
|
+
// type === 'elements' - group by demoGroups (supports string | string[])
|
|
659
720
|
const groupedItems = new Map<string | null, Array<[string, any]>>();
|
|
660
721
|
|
|
661
722
|
for (const entry of filteredEntries) {
|
|
662
723
|
const [, item] = entry;
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
724
|
+
const rawGroups = (item as any).demoGroups;
|
|
725
|
+
const groups: Array<string | null> = rawGroups
|
|
726
|
+
? (Array.isArray(rawGroups) ? rawGroups : [rawGroups])
|
|
727
|
+
: [null];
|
|
728
|
+
for (const group of groups) {
|
|
729
|
+
if (!groupedItems.has(group)) {
|
|
730
|
+
groupedItems.set(group, []);
|
|
731
|
+
}
|
|
732
|
+
groupedItems.get(group)!.push(entry);
|
|
666
733
|
}
|
|
667
|
-
groupedItems.get(group)!.push(entry);
|
|
668
734
|
}
|
|
669
735
|
|
|
670
736
|
// Build a unified list of render items (ungrouped elements and groups)
|
|
@@ -681,11 +747,10 @@ export class WccSidebar extends DeesElement {
|
|
|
681
747
|
renderItems.push({ type: 'element', entry, sortKey: entry[0].toLowerCase() });
|
|
682
748
|
}
|
|
683
749
|
|
|
684
|
-
// Add groups (sorted by
|
|
750
|
+
// Add groups (sorted by group name)
|
|
685
751
|
for (const [groupName, items] of groupedItems) {
|
|
686
752
|
if (groupName === null) continue;
|
|
687
|
-
|
|
688
|
-
renderItems.push({ type: 'group', groupName, items, sortKey: firstElementName.toLowerCase() });
|
|
753
|
+
renderItems.push({ type: 'group', groupName, items, sortKey: groupName.toLowerCase() });
|
|
689
754
|
}
|
|
690
755
|
|
|
691
756
|
// Sort all items alphabetically by sortKey
|
|
@@ -697,8 +762,11 @@ export class WccSidebar extends DeesElement {
|
|
|
697
762
|
return this.renderElementItem(item.entry, section);
|
|
698
763
|
} else {
|
|
699
764
|
return html`
|
|
700
|
-
<div class="item-group">
|
|
701
|
-
<span
|
|
765
|
+
<div class="item-group ${this.isGroupFilterMatch(item.groupName) ? 'group-filter-match' : ''}" data-group="${item.groupName}">
|
|
766
|
+
<span
|
|
767
|
+
class="item-group-legend"
|
|
768
|
+
@contextmenu=${(e: MouseEvent) => this.showGroupContextMenu(e, item.groupName)}
|
|
769
|
+
>${item.groupName}</span>
|
|
702
770
|
${item.items.map((entry) => this.renderElementItem(entry, section))}
|
|
703
771
|
</div>
|
|
704
772
|
`;
|
|
@@ -753,6 +821,7 @@ export class WccSidebar extends DeesElement {
|
|
|
753
821
|
`;
|
|
754
822
|
} else {
|
|
755
823
|
// Single demo element
|
|
824
|
+
const icon = this.getElementGroups(item).length > 1 ? 'library_books' : 'featured_video';
|
|
756
825
|
return html`
|
|
757
826
|
<div
|
|
758
827
|
class="selectOption ${isSelected ? 'selected' : ''} ${isPinned ? 'pinned' : ''}"
|
|
@@ -762,7 +831,7 @@ export class WccSidebar extends DeesElement {
|
|
|
762
831
|
}}
|
|
763
832
|
@contextmenu=${(e: MouseEvent) => this.showContextMenu(e, section.name, elementName)}
|
|
764
833
|
>
|
|
765
|
-
<i class="material-symbols-outlined"
|
|
834
|
+
<i class="material-symbols-outlined">${icon}</i>
|
|
766
835
|
<div class="text">${this.highlightMatch(elementName)}</div>
|
|
767
836
|
</div>
|
|
768
837
|
`;
|
|
@@ -810,6 +879,37 @@ export class WccSidebar extends DeesElement {
|
|
|
810
879
|
return name.toLowerCase().includes(this.searchQuery.toLowerCase());
|
|
811
880
|
}
|
|
812
881
|
|
|
882
|
+
private isGroupFilterMatch(groupName: string): boolean {
|
|
883
|
+
return !!this.searchQuery && groupName.toLowerCase() === this.searchQuery.toLowerCase();
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
private getElementGroups(item: any): string[] {
|
|
887
|
+
const raw = item?.demoGroups;
|
|
888
|
+
if (!raw) return [];
|
|
889
|
+
return Array.isArray(raw) ? raw : [raw];
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
private scrollToGroup(sectionName: string, groupName: string) {
|
|
893
|
+
// Ensure the section is not collapsed
|
|
894
|
+
this.collapsedSections.delete(sectionName);
|
|
895
|
+
// Clear any active search so all groups are visible
|
|
896
|
+
this.searchQuery = '';
|
|
897
|
+
this.requestUpdate();
|
|
898
|
+
|
|
899
|
+
// After render, scroll to the group element
|
|
900
|
+
this.updateComplete.then(() => {
|
|
901
|
+
const groupEl = this.shadowRoot?.querySelector(
|
|
902
|
+
`.item-group[data-group="${groupName}"]`
|
|
903
|
+
);
|
|
904
|
+
if (groupEl) {
|
|
905
|
+
groupEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
906
|
+
// Brief highlight flash
|
|
907
|
+
groupEl.classList.add('group-highlight');
|
|
908
|
+
setTimeout(() => groupEl.classList.remove('group-highlight'), 1500);
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
|
|
813
913
|
private highlightMatch(text: string): TemplateResult {
|
|
814
914
|
if (!this.searchQuery) return html`${text}`;
|
|
815
915
|
const lowerText = text.toLowerCase();
|