@design.estate/wcctools 5.1.0 → 6.1.0
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/.smartconfig.json +7 -3
- package/changelog.md +28 -0
- package/cli.js +3 -0
- package/dist_shell/bundle.js +2970 -0
- package/dist_shell/bundle.js.map +1 -0
- package/dist_shell/bundle.js.third-party-notices.json +1722 -0
- package/dist_shell/bundle.js.third-party-notices.txt +4195 -0
- package/dist_shell/index.html +21 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.devapi.d.ts +11 -0
- package/dist_ts/classes.devapi.js +21 -0
- package/dist_ts/classes.devserver.d.ts +49 -0
- package/dist_ts/classes.devserver.js +142 -0
- package/dist_ts/cli.d.ts +6 -0
- package/dist_ts/cli.js +51 -0
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +4 -0
- package/dist_ts/paths.d.ts +4 -0
- package/dist_ts/paths.js +6 -0
- package/dist_ts/plugins.d.ts +20 -0
- package/dist_ts/plugins.js +27 -0
- package/dist_ts/shellcontent.d.ts +9 -0
- package/dist_ts/shellcontent.js +42 -0
- package/dist_ts/standards/baselines.d.ts +27 -0
- package/dist_ts/standards/baselines.js +83 -0
- package/dist_ts/standards/checker.d.ts +21 -0
- package/dist_ts/standards/checker.js +88 -0
- package/dist_ts/standards/classes.gitrepo.d.ts +13 -0
- package/dist_ts/standards/classes.gitrepo.js +43 -0
- package/dist_ts/standards/classes.sourceedits.d.ts +15 -0
- package/dist_ts/standards/classes.sourceedits.js +54 -0
- package/dist_ts/standards/classes.standardfixer.d.ts +40 -0
- package/dist_ts/standards/classes.standardfixer.js +210 -0
- package/dist_ts/standards/classes.standardproject.d.ts +80 -0
- package/dist_ts/standards/classes.standardproject.js +195 -0
- package/dist_ts/standards/classes.standardtree.d.ts +56 -0
- package/dist_ts/standards/classes.standardtree.js +207 -0
- package/dist_ts/standards/cli.d.ts +7 -0
- package/dist_ts/standards/cli.js +89 -0
- package/dist_ts/standards/config.d.ts +33 -0
- package/dist_ts/standards/config.js +139 -0
- package/dist_ts/standards/errors.d.ts +9 -0
- package/dist_ts/standards/errors.js +17 -0
- package/dist_ts/standards/helpers.ast.d.ts +56 -0
- package/dist_ts/standards/helpers.ast.js +172 -0
- package/dist_ts/standards/helpers.paths.d.ts +36 -0
- package/dist_ts/standards/helpers.paths.js +86 -0
- package/dist_ts/standards/index.d.ts +14 -0
- package/dist_ts/standards/index.js +15 -0
- package/dist_ts/standards/output.d.ts +7 -0
- package/dist_ts/standards/output.js +57 -0
- package/dist_ts/standards/ratchet.d.ts +15 -0
- package/dist_ts/standards/ratchet.js +45 -0
- package/dist_ts/standards/rule.d.ts +50 -0
- package/dist_ts/standards/rule.js +9 -0
- package/dist_ts/standards/rules/barrel.element-index.d.ts +7 -0
- package/dist_ts/standards/rules/barrel.element-index.js +108 -0
- package/dist_ts/standards/rules/barrel.no-demo-export.d.ts +3 -0
- package/dist_ts/standards/rules/barrel.no-demo-export.js +29 -0
- package/dist_ts/standards/rules/demo.fixture-not-exported.d.ts +3 -0
- package/dist_ts/standards/rules/demo.fixture-not-exported.js +29 -0
- package/dist_ts/standards/rules/demo.groups.d.ts +6 -0
- package/dist_ts/standards/rules/demo.groups.js +72 -0
- package/dist_ts/standards/rules/demo.required.d.ts +3 -0
- package/dist_ts/standards/rules/demo.required.js +48 -0
- package/dist_ts/standards/rules/demo.separate-file.d.ts +3 -0
- package/dist_ts/standards/rules/demo.separate-file.js +38 -0
- package/dist_ts/standards/rules/demo.shape.d.ts +3 -0
- package/dist_ts/standards/rules/demo.shape.js +38 -0
- package/dist_ts/standards/rules/docs.component-index.d.ts +8 -0
- package/dist_ts/standards/rules/docs.component-index.js +84 -0
- package/dist_ts/standards/rules/element.exported.d.ts +3 -0
- package/dist_ts/standards/rules/element.exported.js +33 -0
- package/dist_ts/standards/rules/element.literal-tag.d.ts +3 -0
- package/dist_ts/standards/rules/element.literal-tag.js +30 -0
- package/dist_ts/standards/rules/element.reachable.d.ts +3 -0
- package/dist_ts/standards/rules/element.reachable.js +48 -0
- package/dist_ts/standards/rules/element.tag-map.d.ts +3 -0
- package/dist_ts/standards/rules/element.tag-map.js +83 -0
- package/dist_ts/standards/rules/i18n.literals.d.ts +3 -0
- package/dist_ts/standards/rules/i18n.literals.js +52 -0
- package/dist_ts/standards/rules/index.d.ts +12 -0
- package/dist_ts/standards/rules/index.js +83 -0
- package/dist_ts/standards/rules/layout.element-folder.d.ts +3 -0
- package/dist_ts/standards/rules/layout.element-folder.js +47 -0
- package/dist_ts/standards/rules/layout.entry-file-name.d.ts +3 -0
- package/dist_ts/standards/rules/layout.entry-file-name.js +71 -0
- package/dist_ts/standards/rules/layout.entry.d.ts +3 -0
- package/dist_ts/standards/rules/layout.entry.js +38 -0
- package/dist_ts/standards/rules/layout.group-folder.d.ts +3 -0
- package/dist_ts/standards/rules/layout.group-folder.js +22 -0
- package/dist_ts/standards/rules/layout.shared-00.d.ts +3 -0
- package/dist_ts/standards/rules/layout.shared-00.js +36 -0
- package/dist_ts/standards/rules/naming.class-matches-tag.d.ts +3 -0
- package/dist_ts/standards/rules/naming.class-matches-tag.js +26 -0
- package/dist_ts/standards/rules/naming.lowercase-files.d.ts +3 -0
- package/dist_ts/standards/rules/naming.lowercase-files.js +26 -0
- package/dist_ts/standards/rules/naming.tag-prefix.d.ts +3 -0
- package/dist_ts/standards/rules/naming.tag-prefix.js +23 -0
- package/dist_ts/standards/rules/props.accessor.d.ts +3 -0
- package/dist_ts/standards/rules/props.accessor.js +35 -0
- package/dist_ts/standards/rules/props.object-no-attribute.d.ts +3 -0
- package/dist_ts/standards/rules/props.object-no-attribute.js +42 -0
- package/dist_ts/standards/rules/props.reflect-primitive.d.ts +5 -0
- package/dist_ts/standards/rules/props.reflect-primitive.js +41 -0
- package/dist_ts/standards/rules/props.typed.d.ts +6 -0
- package/dist_ts/standards/rules/props.typed.js +64 -0
- package/dist_ts/standards/rules/shared.d.ts +38 -0
- package/dist_ts/standards/rules/shared.js +103 -0
- package/dist_ts/standards/rules/style.bdtheme.d.ts +5 -0
- package/dist_ts/standards/rules/style.bdtheme.js +28 -0
- package/dist_ts_interfaces/bridge.d.ts +88 -0
- package/dist_ts_interfaces/bridge.js +2 -0
- package/dist_ts_interfaces/catalog.d.ts +32 -0
- package/dist_ts_interfaces/catalog.js +6 -0
- package/dist_ts_interfaces/index.d.ts +4 -0
- package/dist_ts_interfaces/index.js +5 -0
- package/dist_ts_interfaces/plugins.d.ts +2 -0
- package/dist_ts_interfaces/plugins.js +3 -0
- package/dist_ts_interfaces/requests.d.ts +15 -0
- package/dist_ts_interfaces/requests.js +2 -0
- package/dist_ts_interfaces/standard.d.ts +93 -0
- package/dist_ts_interfaces/standard.js +6 -0
- package/dist_ts_shared/index.d.ts +1 -0
- package/dist_ts_shared/index.js +2 -0
- package/dist_ts_shared/plugins.d.ts +2 -0
- package/dist_ts_shared/plugins.js +3 -0
- package/dist_ts_shared/previewroute.d.ts +18 -0
- package/dist_ts_shared/previewroute.js +47 -0
- package/{dist_ts_web → dist_ts_shell}/elements/wcc-contextmenu.js +1 -1
- package/dist_ts_shell/elements/wcc-preview-frame.d.ts +23 -0
- package/dist_ts_shell/elements/wcc-preview-frame.js +197 -0
- package/dist_ts_shell/elements/wcc-properties.d.ts +49 -0
- package/{dist_ts_web → dist_ts_shell}/elements/wcc-properties.js +149 -216
- package/{dist_ts_web → dist_ts_shell}/elements/wcc-record-button.js +1 -1
- package/{dist_ts_web → dist_ts_shell}/elements/wcc-recording-panel.d.ts +2 -2
- package/{dist_ts_web → dist_ts_shell}/elements/wcc-recording-panel.js +12 -16
- package/dist_ts_shell/elements/wcc-shell.d.ts +87 -0
- package/dist_ts_shell/elements/wcc-shell.js +524 -0
- package/{dist_ts_web → dist_ts_shell}/elements/wcc-sidebar.d.ts +12 -10
- package/{dist_ts_web → dist_ts_shell}/elements/wcc-sidebar.js +137 -183
- package/dist_ts_shell/index.d.ts +4 -0
- package/dist_ts_shell/index.js +5 -0
- package/dist_ts_shell/plugins.d.ts +4 -0
- package/dist_ts_shell/plugins.js +5 -0
- package/dist_ts_shell/previewconnection.d.ts +30 -0
- package/dist_ts_shell/previewconnection.js +86 -0
- package/dist_ts_shell/services/recorder.service.js +353 -0
- package/dist_ts_web/00_commitinfo_data.js +2 -2
- package/dist_ts_web/catalog.d.ts +45 -0
- package/dist_ts_web/catalog.js +153 -0
- package/dist_ts_web/elementproperties.d.ts +15 -0
- package/dist_ts_web/elementproperties.js +89 -0
- package/dist_ts_web/elements/wcc-preview.d.ts +19 -0
- package/dist_ts_web/elements/wcc-preview.js +164 -0
- package/dist_ts_web/elements/wcc-standalone-notice.d.ts +14 -0
- package/dist_ts_web/elements/wcc-standalone-notice.js +110 -0
- package/dist_ts_web/elements/wcctools.helpers.d.ts +2 -6
- package/dist_ts_web/elements/wcctools.helpers.js +1 -7
- package/dist_ts_web/index.d.ts +2 -5
- package/dist_ts_web/index.js +38 -17
- package/dist_ts_web/previewbridge.d.ts +39 -0
- package/dist_ts_web/previewbridge.js +153 -0
- package/dist_ts_web/renderedtree.d.ts +5 -0
- package/dist_ts_web/renderedtree.js +37 -0
- package/dist_ts_web/wcctools.interfaces.d.ts +3 -6
- package/dist_ts_web/wcctools.interfaces.js +1 -1
- package/dist_ts_web/wcctools.plugins.d.ts +3 -1
- package/dist_ts_web/wcctools.plugins.js +4 -2
- package/package.json +17 -7
- package/readme.md +93 -28
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.devapi.ts +25 -0
- package/ts/classes.devserver.ts +161 -0
- package/ts/cli.ts +53 -0
- package/ts/index.ts +3 -0
- package/ts/paths.ts +7 -0
- package/ts/plugins.ts +37 -0
- package/ts/shellcontent.ts +42 -0
- package/ts/standards/baselines.ts +100 -0
- package/ts/standards/checker.ts +114 -0
- package/ts/standards/classes.gitrepo.ts +48 -0
- package/ts/standards/classes.sourceedits.ts +58 -0
- package/ts/standards/classes.standardfixer.ts +234 -0
- package/ts/standards/classes.standardproject.ts +250 -0
- package/ts/standards/classes.standardtree.ts +220 -0
- package/ts/standards/cli.ts +86 -0
- package/ts/standards/config.ts +160 -0
- package/ts/standards/errors.ts +18 -0
- package/ts/standards/helpers.ast.ts +208 -0
- package/ts/standards/helpers.paths.ts +119 -0
- package/ts/standards/index.ts +22 -0
- package/ts/standards/output.ts +65 -0
- package/ts/standards/ratchet.ts +63 -0
- package/ts/standards/rule.ts +58 -0
- package/ts/standards/rules/barrel.element-index.ts +112 -0
- package/ts/standards/rules/barrel.no-demo-export.ts +30 -0
- package/ts/standards/rules/demo.fixture-not-exported.ts +30 -0
- package/ts/standards/rules/demo.groups.ts +74 -0
- package/ts/standards/rules/demo.required.ts +49 -0
- package/ts/standards/rules/demo.separate-file.ts +40 -0
- package/ts/standards/rules/demo.shape.ts +42 -0
- package/ts/standards/rules/docs.component-index.ts +88 -0
- package/ts/standards/rules/element.exported.ts +35 -0
- package/ts/standards/rules/element.literal-tag.ts +30 -0
- package/ts/standards/rules/element.reachable.ts +49 -0
- package/ts/standards/rules/element.tag-map.ts +87 -0
- package/ts/standards/rules/i18n.literals.ts +58 -0
- package/ts/standards/rules/index.ts +87 -0
- package/ts/standards/rules/layout.element-folder.ts +49 -0
- package/ts/standards/rules/layout.entry-file-name.ts +73 -0
- package/ts/standards/rules/layout.entry.ts +40 -0
- package/ts/standards/rules/layout.group-folder.ts +23 -0
- package/ts/standards/rules/layout.shared-00.ts +37 -0
- package/ts/standards/rules/naming.class-matches-tag.ts +27 -0
- package/ts/standards/rules/naming.lowercase-files.ts +27 -0
- package/ts/standards/rules/naming.tag-prefix.ts +24 -0
- package/ts/standards/rules/props.accessor.ts +37 -0
- package/ts/standards/rules/props.object-no-attribute.ts +45 -0
- package/ts/standards/rules/props.reflect-primitive.ts +44 -0
- package/ts/standards/rules/props.typed.ts +70 -0
- package/ts/standards/rules/shared.ts +127 -0
- package/ts/standards/rules/style.bdtheme.ts +31 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/catalog.ts +194 -0
- package/ts_web/elementproperties.ts +96 -0
- package/ts_web/elements/wcc-preview.ts +111 -0
- package/ts_web/elements/wcc-standalone-notice.ts +65 -0
- package/ts_web/elements/wcctools.helpers.ts +2 -10
- package/ts_web/index.ts +38 -19
- package/ts_web/previewbridge.ts +189 -0
- package/ts_web/readme.md +26 -85
- package/ts_web/renderedtree.ts +43 -0
- package/ts_web/wcctools.interfaces.ts +4 -7
- package/ts_web/wcctools.plugins.ts +6 -1
- package/dist_bundle/bundle.js +0 -92419
- package/dist_bundle/bundle.js.map +0 -1
- package/dist_ts_web/elements/wcc-dashboard.d.ts +0 -119
- package/dist_ts_web/elements/wcc-dashboard.js +0 -700
- package/dist_ts_web/elements/wcc-frame.d.ts +0 -22
- package/dist_ts_web/elements/wcc-frame.js +0 -256
- package/dist_ts_web/elements/wcc-properties.d.ts +0 -43
- package/dist_ts_web/pages/index.d.ts +0 -1
- package/dist_ts_web/pages/index.js +0 -2
- package/dist_ts_web/services/recorder.service.js +0 -353
- package/ts_web/elements/wcc-contextmenu.ts +0 -291
- package/ts_web/elements/wcc-dashboard.ts +0 -672
- package/ts_web/elements/wcc-frame.ts +0 -189
- package/ts_web/elements/wcc-properties.ts +0 -1089
- package/ts_web/elements/wcc-record-button.ts +0 -108
- package/ts_web/elements/wcc-recording-panel.ts +0 -1010
- package/ts_web/elements/wcc-sidebar.ts +0 -1470
- package/ts_web/pages/index.ts +0 -1
- package/ts_web/services/recorder.service.ts +0 -451
- package/ts_web/types/dom-mediacapture-stub/index.d.ts +0 -12
- package/ts_web/types/dom-mediacapture-stub/package.json +0 -6
- package/ts_web/types/dom-webcodecs-stub/index.d.ts +0 -2
- package/ts_web/types/dom-webcodecs-stub/package.json +0 -6
- /package/{dist_ts_web → dist_ts_shell}/elements/wcc-contextmenu.d.ts +0 -0
- /package/{dist_ts_web → dist_ts_shell}/elements/wcc-record-button.d.ts +0 -0
- /package/{dist_ts_web → dist_ts_shell}/services/recorder.service.d.ts +0 -0
|
@@ -1,672 +0,0 @@
|
|
|
1
|
-
import { DeesElement, property, state, html, customElement, type TemplateResult, queryAsync, render } from '@design.estate/dees-element';
|
|
2
|
-
import {
|
|
3
|
-
classifyCatalogEntry,
|
|
4
|
-
getDemoAtIndex,
|
|
5
|
-
getDemoCount,
|
|
6
|
-
getElementTagName,
|
|
7
|
-
isElementConstructor,
|
|
8
|
-
resolveTemplateFactory,
|
|
9
|
-
} from './wcctools.helpers.js';
|
|
10
|
-
import type { TTemplateFactory } from './wcctools.helpers.js';
|
|
11
|
-
import type { IWccConfig, IWccSection, TElementType } from '../wcctools.interfaces.js';
|
|
12
|
-
|
|
13
|
-
import * as plugins from '../wcctools.plugins.js';
|
|
14
|
-
|
|
15
|
-
// wcc tools
|
|
16
|
-
import './wcc-frame.js';
|
|
17
|
-
import './wcc-sidebar.js';
|
|
18
|
-
import './wcc-properties.js';
|
|
19
|
-
import { type TTheme } from './wcc-properties.js';
|
|
20
|
-
import { breakpoints } from '@design.estate/dees-domtools';
|
|
21
|
-
import { WccFrame, type IWccEmptyState } from './wcc-frame.js';
|
|
22
|
-
import { WccSidebar } from './wcc-sidebar.js';
|
|
23
|
-
|
|
24
|
-
type TSectionEntry = [string, any];
|
|
25
|
-
|
|
26
|
-
const applySectionFilterAndSort = (
|
|
27
|
-
section: IWccSection,
|
|
28
|
-
entries: TSectionEntry[],
|
|
29
|
-
fallbackSort?: (a: TSectionEntry, b: TSectionEntry) => number
|
|
30
|
-
): TSectionEntry[] => {
|
|
31
|
-
let result = entries;
|
|
32
|
-
if (section.filter) {
|
|
33
|
-
const filterFn = section.filter;
|
|
34
|
-
result = result.filter(([name, item]) => filterFn(name, item));
|
|
35
|
-
}
|
|
36
|
-
const sortFn = section.sort ?? fallbackSort;
|
|
37
|
-
if (sortFn) {
|
|
38
|
-
result = [...result].sort(sortFn);
|
|
39
|
-
}
|
|
40
|
-
return result;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The navigable entries of a section, after classification and the section's own filter and sort.
|
|
45
|
-
* Elements sections keep only custom element classes with a usable static `demo`;
|
|
46
|
-
* pages sections keep only template factories.
|
|
47
|
-
*/
|
|
48
|
-
export const getSectionItems = (section: IWccSection): TSectionEntry[] => {
|
|
49
|
-
const entries = Object.entries(section.items).filter(([, item]) =>
|
|
50
|
-
section.type === 'elements'
|
|
51
|
-
? classifyCatalogEntry(item) === 'demo'
|
|
52
|
-
: typeof item === 'function'
|
|
53
|
-
);
|
|
54
|
-
return applySectionFilterAndSort(section, entries);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Registered custom elements of an elements section that have no usable demo.
|
|
59
|
-
* They are listed (not navigable) in the sidebar's "Without demo" group.
|
|
60
|
-
*/
|
|
61
|
-
export const getSectionItemsWithoutDemo = (section: IWccSection): TSectionEntry[] => {
|
|
62
|
-
if (section.type !== 'elements') {
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
65
|
-
const entries = Object.entries(section.items).filter(([, item]) => classifyCatalogEntry(item) === 'no-demo');
|
|
66
|
-
return applySectionFilterAndSort(section, entries, ([a], [b]) => a.localeCompare(b));
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/** An addressed entry the dashboard cannot preview. */
|
|
70
|
-
export interface IWccUnavailableEntry {
|
|
71
|
-
kind: 'no-demo' | 'ignored' | 'missing';
|
|
72
|
-
sectionName: string;
|
|
73
|
-
itemName: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Parameters of a `/wcctools-route/...` URL. */
|
|
77
|
-
export interface IWccRouteParams {
|
|
78
|
-
sectionName: string;
|
|
79
|
-
itemName: string;
|
|
80
|
-
demoIndex?: string;
|
|
81
|
-
viewport: string;
|
|
82
|
-
theme: string;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
type TResolvedEntry =
|
|
86
|
-
| { kind: 'listed'; section: IWccSection; item: unknown }
|
|
87
|
-
| { kind: IWccUnavailableEntry['kind']; section: IWccSection | null };
|
|
88
|
-
|
|
89
|
-
interface IRenderedSelection {
|
|
90
|
-
item: unknown;
|
|
91
|
-
demoIndex: number;
|
|
92
|
-
type: TElementType;
|
|
93
|
-
unavailable: IWccUnavailableEntry | null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@customElement('wcc-dashboard')
|
|
97
|
-
export class WccDashboard extends DeesElement {
|
|
98
|
-
|
|
99
|
-
@property()
|
|
100
|
-
accessor sections: IWccSection[] = [];
|
|
101
|
-
|
|
102
|
-
@property()
|
|
103
|
-
accessor selectedSection: IWccSection | null = null;
|
|
104
|
-
|
|
105
|
-
@property()
|
|
106
|
-
accessor selectedType: TElementType = 'element';
|
|
107
|
-
|
|
108
|
-
@property()
|
|
109
|
-
accessor selectedItemName: string = '';
|
|
110
|
-
|
|
111
|
-
@property()
|
|
112
|
-
accessor selectedItem: TTemplateFactory | DeesElement | null = null;
|
|
113
|
-
|
|
114
|
-
@property({ type: Number })
|
|
115
|
-
accessor selectedDemoIndex: number = 0;
|
|
116
|
-
|
|
117
|
-
@property()
|
|
118
|
-
accessor selectedViewport: plugins.deesDomtools.breakpoints.TViewport = 'desktop';
|
|
119
|
-
|
|
120
|
-
@property()
|
|
121
|
-
accessor selectedTheme: TTheme = 'dark';
|
|
122
|
-
|
|
123
|
-
@property()
|
|
124
|
-
accessor searchQuery: string = '';
|
|
125
|
-
|
|
126
|
-
// Pinned items as Set of "sectionName::itemName"
|
|
127
|
-
@property({ attribute: false })
|
|
128
|
-
accessor pinnedItems: Set<string> = new Set();
|
|
129
|
-
|
|
130
|
-
// Sidebar width (resizable)
|
|
131
|
-
@property({ type: Number })
|
|
132
|
-
accessor sidebarWidth: number = 200;
|
|
133
|
-
|
|
134
|
-
/** Set when the route addresses an entry that cannot be previewed. */
|
|
135
|
-
@state()
|
|
136
|
-
accessor unavailableEntry: IWccUnavailableEntry | null = null;
|
|
137
|
-
|
|
138
|
-
/** What the frame shows instead of a demo, if anything. */
|
|
139
|
-
@state()
|
|
140
|
-
accessor emptyState: IWccEmptyState | null = null;
|
|
141
|
-
|
|
142
|
-
// Derived from selectedViewport - no need for separate property
|
|
143
|
-
public get isNative(): boolean {
|
|
144
|
-
return this.selectedViewport === 'native';
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
private frameScrollY: number = 0;
|
|
148
|
-
private sidebarScrollY: number = 0;
|
|
149
|
-
private scrollPositionsApplied: boolean = false;
|
|
150
|
-
|
|
151
|
-
private renderedSelection: IRenderedSelection | null = null;
|
|
152
|
-
private renderGeneration = 0;
|
|
153
|
-
private routeDisposers: Array<() => void> = [];
|
|
154
|
-
private scrollDisposers: Array<() => void> = [];
|
|
155
|
-
private scrollSetupTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
156
|
-
private routeSettleTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
157
|
-
private scrollUpdateTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
158
|
-
|
|
159
|
-
@queryAsync('wcc-frame')
|
|
160
|
-
accessor wccFrame: Promise<WccFrame>;
|
|
161
|
-
|
|
162
|
-
constructor(config?: IWccConfig) {
|
|
163
|
-
super();
|
|
164
|
-
if (config && config.sections) {
|
|
165
|
-
this.sections = config.sections;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Find a listed item by name across all sections, returns the item and its section
|
|
171
|
-
*/
|
|
172
|
-
public findItemByName(name: string): { item: any; section: IWccSection } | null {
|
|
173
|
-
for (const section of this.sections) {
|
|
174
|
-
const found = getSectionItems(section).find(([itemName]) => itemName === name);
|
|
175
|
-
if (found) {
|
|
176
|
-
return { item: found[1], section };
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Find a section by name (URL-decoded)
|
|
184
|
-
*/
|
|
185
|
-
public findSectionByName(name: string): IWccSection | null {
|
|
186
|
-
return this.sections.find(s => s.name === name) || null;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
public render(): TemplateResult {
|
|
190
|
-
return html`
|
|
191
|
-
<style>
|
|
192
|
-
:host {
|
|
193
|
-
background: #fcfcfc;
|
|
194
|
-
display: block;
|
|
195
|
-
box-sizing: border-box;
|
|
196
|
-
position: fixed;
|
|
197
|
-
inset: 0;
|
|
198
|
-
min-width: 0;
|
|
199
|
-
overflow: hidden;
|
|
200
|
-
container-type: inline-size;
|
|
201
|
-
container-name: wccDashboard;
|
|
202
|
-
}
|
|
203
|
-
:host([hidden]) {
|
|
204
|
-
display: none;
|
|
205
|
-
}
|
|
206
|
-
</style>
|
|
207
|
-
<wcc-sidebar
|
|
208
|
-
.dashboardRef=${this}
|
|
209
|
-
.selectedItem=${this.selectedItem}
|
|
210
|
-
.searchQuery=${this.searchQuery}
|
|
211
|
-
.pinnedItems=${this.pinnedItems}
|
|
212
|
-
.sidebarWidth=${this.sidebarWidth}
|
|
213
|
-
.isNative=${this.isNative}
|
|
214
|
-
@selectedType=${(eventArg) => {
|
|
215
|
-
this.selectedType = eventArg.detail;
|
|
216
|
-
}}
|
|
217
|
-
@selectedItemName=${(eventArg) => {
|
|
218
|
-
this.selectedItemName = eventArg.detail;
|
|
219
|
-
}}
|
|
220
|
-
@selectedItem=${(eventArg) => {
|
|
221
|
-
this.unavailableEntry = null;
|
|
222
|
-
this.selectedItem = eventArg.detail;
|
|
223
|
-
}}
|
|
224
|
-
@searchChanged=${(eventArg: CustomEvent) => {
|
|
225
|
-
this.searchQuery = eventArg.detail;
|
|
226
|
-
this.updateUrlWithScrollState();
|
|
227
|
-
}}
|
|
228
|
-
@pinnedChanged=${(eventArg: CustomEvent) => {
|
|
229
|
-
this.pinnedItems = eventArg.detail;
|
|
230
|
-
this.updateUrlWithScrollState();
|
|
231
|
-
}}
|
|
232
|
-
@widthChanged=${async (eventArg: CustomEvent) => {
|
|
233
|
-
this.sidebarWidth = eventArg.detail;
|
|
234
|
-
this.updateUrlWithScrollState();
|
|
235
|
-
const frame = await this.wccFrame;
|
|
236
|
-
if (frame) {
|
|
237
|
-
frame.sidebarWidth = eventArg.detail;
|
|
238
|
-
frame.requestUpdate();
|
|
239
|
-
}
|
|
240
|
-
}}
|
|
241
|
-
></wcc-sidebar>
|
|
242
|
-
<wcc-properties
|
|
243
|
-
role="region"
|
|
244
|
-
aria-label="Properties and preview controls"
|
|
245
|
-
.dashboardRef=${this}
|
|
246
|
-
.selectedItem=${this.selectedItem}
|
|
247
|
-
.selectedViewport=${this.selectedViewport}
|
|
248
|
-
.selectedTheme=${this.selectedTheme}
|
|
249
|
-
.isNative=${this.isNative}
|
|
250
|
-
.sidebarWidth=${this.sidebarWidth}
|
|
251
|
-
@selectedViewport=${(eventArg) => {
|
|
252
|
-
this.selectedViewport = eventArg.detail;
|
|
253
|
-
}}
|
|
254
|
-
@selectedTheme=${(eventArg) => {
|
|
255
|
-
this.selectedTheme = eventArg.detail;
|
|
256
|
-
}}
|
|
257
|
-
@editorStateChanged=${async (eventArg) => {
|
|
258
|
-
const frame = await this.wccFrame;
|
|
259
|
-
if (frame) {
|
|
260
|
-
frame.advancedEditorOpen = eventArg.detail.isOpen;
|
|
261
|
-
frame.requestUpdate();
|
|
262
|
-
}
|
|
263
|
-
}}
|
|
264
|
-
@toggleNative=${() => {
|
|
265
|
-
this.toggleNative();
|
|
266
|
-
}}
|
|
267
|
-
></wcc-properties>
|
|
268
|
-
<wcc-frame
|
|
269
|
-
id="wccFrame"
|
|
270
|
-
role="main"
|
|
271
|
-
aria-label="Preview"
|
|
272
|
-
viewport=${this.selectedViewport}
|
|
273
|
-
.isNative=${this.isNative}
|
|
274
|
-
.sidebarWidth=${this.sidebarWidth}
|
|
275
|
-
.emptyState=${this.emptyState}
|
|
276
|
-
>
|
|
277
|
-
</wcc-frame>
|
|
278
|
-
`;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
public toggleNative() {
|
|
282
|
-
// Toggle between 'native' and 'desktop' viewports
|
|
283
|
-
this.selectedViewport = this.selectedViewport === 'native' ? 'desktop' : 'native';
|
|
284
|
-
this.buildUrl();
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
private handleDocumentKeydown = (event: KeyboardEvent) => {
|
|
288
|
-
if (event.key === 'Escape' && this.isNative) {
|
|
289
|
-
this.selectedViewport = 'desktop';
|
|
290
|
-
this.buildUrl();
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
public async connectedCallback() {
|
|
295
|
-
const connected = super.connectedCallback();
|
|
296
|
-
document.addEventListener('keydown', this.handleDocumentKeydown);
|
|
297
|
-
// On a reconnect firstUpdated does not run again
|
|
298
|
-
if (this.hasUpdated) {
|
|
299
|
-
this.scheduleScrollListeners();
|
|
300
|
-
}
|
|
301
|
-
await this.connectRoutes();
|
|
302
|
-
return connected;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
public async disconnectedCallback() {
|
|
306
|
-
const disconnected = super.disconnectedCallback();
|
|
307
|
-
document.removeEventListener('keydown', this.handleDocumentKeydown);
|
|
308
|
-
for (const dispose of this.routeDisposers) {
|
|
309
|
-
dispose();
|
|
310
|
-
}
|
|
311
|
-
this.routeDisposers = [];
|
|
312
|
-
for (const dispose of this.scrollDisposers) {
|
|
313
|
-
dispose();
|
|
314
|
-
}
|
|
315
|
-
this.scrollDisposers = [];
|
|
316
|
-
clearTimeout(this.scrollSetupTimeout);
|
|
317
|
-
clearTimeout(this.routeSettleTimeout);
|
|
318
|
-
clearTimeout(this.scrollUpdateTimeout);
|
|
319
|
-
return disconnected;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
private async connectRoutes() {
|
|
323
|
-
const domtools = await this.domtoolsPromise;
|
|
324
|
-
if (!this.isConnected || this.routeDisposers.length > 0) {
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
this.domtools = domtools;
|
|
328
|
-
const handleRoute = async (routeInfo: { params: Record<string, string>; queryParams: Record<string, string> }) => {
|
|
329
|
-
const { sectionName, itemName, demoIndex, viewport, theme } = routeInfo.params;
|
|
330
|
-
await this.applyRoute({ sectionName, itemName, demoIndex, viewport, theme }, routeInfo.queryParams);
|
|
331
|
-
};
|
|
332
|
-
this.routeDisposers = [
|
|
333
|
-
domtools.router.on('/wcctools-route/:sectionName/:itemName/:demoIndex/:viewport/:theme', handleRoute),
|
|
334
|
-
// Route without demo index (kept for existing links)
|
|
335
|
-
domtools.router.on('/wcctools-route/:sectionName/:itemName/:viewport/:theme', handleRoute),
|
|
336
|
-
];
|
|
337
|
-
await domtools.router._handleRouteState();
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
public async firstUpdated() {
|
|
341
|
-
this.scheduleScrollListeners();
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
private scheduleScrollListeners() {
|
|
345
|
-
// Set up scroll listeners after DOM is ready
|
|
346
|
-
clearTimeout(this.scrollSetupTimeout);
|
|
347
|
-
this.scrollSetupTimeout = setTimeout(() => {
|
|
348
|
-
this.setupScrollListeners();
|
|
349
|
-
}, 500);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Resolve a section/item pair to a listed entry, or to the reason it cannot be previewed.
|
|
354
|
-
* The legacy section names `element` and `page` search every section.
|
|
355
|
-
*/
|
|
356
|
-
public resolveEntry(sectionNameArg: string, itemNameArg: string): TResolvedEntry {
|
|
357
|
-
const section = this.findSectionByName(sectionNameArg);
|
|
358
|
-
const isLegacyName = !section && (sectionNameArg === 'element' || sectionNameArg === 'page');
|
|
359
|
-
const candidates = section ? [section] : isLegacyName ? this.sections : [];
|
|
360
|
-
|
|
361
|
-
for (const candidate of candidates) {
|
|
362
|
-
const listed = getSectionItems(candidate).find(([name]) => name === itemNameArg);
|
|
363
|
-
if (listed) {
|
|
364
|
-
return { kind: 'listed', section: candidate, item: listed[1] };
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
for (const candidate of candidates) {
|
|
368
|
-
if (getSectionItemsWithoutDemo(candidate).some(([name]) => name === itemNameArg)) {
|
|
369
|
-
return { kind: 'no-demo', section: candidate };
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
for (const candidate of candidates) {
|
|
373
|
-
if (Object.prototype.hasOwnProperty.call(candidate.items, itemNameArg)) {
|
|
374
|
-
const item = candidate.items[itemNameArg];
|
|
375
|
-
const notDemoable = candidate.type === 'elements'
|
|
376
|
-
? classifyCatalogEntry(item) === 'ignored'
|
|
377
|
-
: typeof item !== 'function';
|
|
378
|
-
return { kind: notDemoable ? 'ignored' : 'missing', section: candidate };
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
return { kind: 'missing', section };
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Apply a `/wcctools-route/...` location to the dashboard state.
|
|
386
|
-
*/
|
|
387
|
-
public async applyRoute(routeArg: IWccRouteParams, queryParamsArg?: Record<string, string>) {
|
|
388
|
-
const sectionName = decodeURIComponent(routeArg.sectionName);
|
|
389
|
-
const itemName = routeArg.itemName;
|
|
390
|
-
this.selectedItemName = itemName;
|
|
391
|
-
this.selectedDemoIndex = parseInt(routeArg.demoIndex ?? '0', 10) || 0;
|
|
392
|
-
this.selectedViewport = routeArg.viewport as breakpoints.TViewport;
|
|
393
|
-
this.selectedTheme = routeArg.theme as TTheme;
|
|
394
|
-
|
|
395
|
-
const resolved = this.resolveEntry(sectionName, itemName);
|
|
396
|
-
if (resolved.kind === 'listed') {
|
|
397
|
-
this.selectedSection = resolved.section;
|
|
398
|
-
this.selectedType = resolved.section.type === 'elements' ? 'element' : 'page';
|
|
399
|
-
this.selectedItem = resolved.item as TTemplateFactory | DeesElement;
|
|
400
|
-
this.unavailableEntry = null;
|
|
401
|
-
} else {
|
|
402
|
-
this.selectedSection = resolved.section;
|
|
403
|
-
this.selectedType = resolved.section?.type === 'pages' ? 'page' : 'element';
|
|
404
|
-
this.selectedItem = null;
|
|
405
|
-
this.unavailableEntry = { kind: resolved.kind, sectionName, itemName };
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Restore state from query parameters
|
|
409
|
-
const queryParams = queryParamsArg ?? {};
|
|
410
|
-
this.searchQuery = queryParams.search || '';
|
|
411
|
-
if (queryParams.frameScrollY) {
|
|
412
|
-
this.frameScrollY = parseInt(queryParams.frameScrollY, 10);
|
|
413
|
-
}
|
|
414
|
-
if (queryParams.sidebarScrollY) {
|
|
415
|
-
this.sidebarScrollY = parseInt(queryParams.sidebarScrollY, 10);
|
|
416
|
-
}
|
|
417
|
-
if (queryParams.pinned) {
|
|
418
|
-
const newPinned = new Set(queryParams.pinned.split(',').filter(Boolean));
|
|
419
|
-
// Only update if actually different to avoid update loops
|
|
420
|
-
if (this.pinnedItems.size !== newPinned.size ||
|
|
421
|
-
![...newPinned].every(k => this.pinnedItems.has(k))) {
|
|
422
|
-
this.pinnedItems = newPinned;
|
|
423
|
-
}
|
|
424
|
-
} else if (this.pinnedItems.size > 0) {
|
|
425
|
-
this.pinnedItems = new Set();
|
|
426
|
-
}
|
|
427
|
-
if (queryParams.sidebarWidth) {
|
|
428
|
-
this.sidebarWidth = parseInt(queryParams.sidebarWidth, 10);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Apply scroll positions and update frame after a short delay to ensure DOM is ready
|
|
432
|
-
clearTimeout(this.routeSettleTimeout);
|
|
433
|
-
this.routeSettleTimeout = setTimeout(async () => {
|
|
434
|
-
this.applyScrollPositions();
|
|
435
|
-
const frame = await this.wccFrame;
|
|
436
|
-
if (!this.isConnected) {
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
if (frame) {
|
|
440
|
-
frame.sidebarWidth = this.sidebarWidth;
|
|
441
|
-
frame.requestUpdate();
|
|
442
|
-
}
|
|
443
|
-
}, 100);
|
|
444
|
-
|
|
445
|
-
const domtoolsInstance = await plugins.deesDomtools.elementBasic.setup();
|
|
446
|
-
this.selectedTheme === 'bright'
|
|
447
|
-
? domtoolsInstance.themeManager.goBright()
|
|
448
|
-
: domtoolsInstance.themeManager.goDark();
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
public async updated(changedPropertiesArg: Map<string, any>) {
|
|
452
|
-
super.updated(changedPropertiesArg);
|
|
453
|
-
if (changedPropertiesArg.has('selectedItemName') && this.selectedItemName) {
|
|
454
|
-
document.title = this.selectedItemName;
|
|
455
|
-
}
|
|
456
|
-
await this.renderSelection();
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Render the selected demo or page into the frame. Only a change of the selected item,
|
|
461
|
-
* demo index, type or unavailable entry re-renders; theme, viewport, search, pins and
|
|
462
|
-
* sidebar width leave the rendered demo (and its internal state) untouched.
|
|
463
|
-
*/
|
|
464
|
-
private async renderSelection() {
|
|
465
|
-
const selection: IRenderedSelection = {
|
|
466
|
-
item: this.selectedItem,
|
|
467
|
-
demoIndex: this.selectedDemoIndex,
|
|
468
|
-
type: this.selectedType,
|
|
469
|
-
unavailable: this.unavailableEntry,
|
|
470
|
-
};
|
|
471
|
-
const previous = this.renderedSelection;
|
|
472
|
-
if (
|
|
473
|
-
previous &&
|
|
474
|
-
previous.item === selection.item &&
|
|
475
|
-
previous.demoIndex === selection.demoIndex &&
|
|
476
|
-
previous.type === selection.type &&
|
|
477
|
-
previous.unavailable === selection.unavailable
|
|
478
|
-
) {
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
this.renderedSelection = selection;
|
|
482
|
-
const generation = ++this.renderGeneration;
|
|
483
|
-
|
|
484
|
-
const frame = await this.wccFrame;
|
|
485
|
-
const viewport = await frame.getViewportElement();
|
|
486
|
-
if (generation !== this.renderGeneration) {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const target = this.resolveRenderTarget();
|
|
491
|
-
if ('emptyState' in target) {
|
|
492
|
-
render(html``, viewport);
|
|
493
|
-
this.emptyState = target.emptyState;
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
try {
|
|
498
|
-
const template = await resolveTemplateFactory(target.factory);
|
|
499
|
-
if (generation !== this.renderGeneration) {
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
render(template, viewport);
|
|
503
|
-
this.emptyState = null;
|
|
504
|
-
} catch (error) {
|
|
505
|
-
if (generation !== this.renderGeneration) {
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
console.error(`wcctools: rendering "${this.selectedItemName}" failed`, error);
|
|
509
|
-
render(html``, viewport);
|
|
510
|
-
this.emptyState = {
|
|
511
|
-
title: `${this.selectedItemName} failed to render`,
|
|
512
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
private resolveRenderTarget(): { factory: TTemplateFactory } | { emptyState: IWccEmptyState } {
|
|
518
|
-
const unavailable = this.unavailableEntry;
|
|
519
|
-
if (unavailable) {
|
|
520
|
-
return { emptyState: this.getUnavailableEmptyState(unavailable) };
|
|
521
|
-
}
|
|
522
|
-
const item = this.selectedItem;
|
|
523
|
-
if (!item) {
|
|
524
|
-
return {
|
|
525
|
-
emptyState: {
|
|
526
|
-
title: 'Nothing selected',
|
|
527
|
-
detail: 'Choose an element or page in the sidebar to preview it here.',
|
|
528
|
-
},
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
if (this.selectedType === 'page') {
|
|
532
|
-
return { factory: item as TTemplateFactory };
|
|
533
|
-
}
|
|
534
|
-
const demo = isElementConstructor(item) ? item.demo : undefined;
|
|
535
|
-
const demoFactory = demo ? getDemoAtIndex(demo as TTemplateFactory | TTemplateFactory[], this.selectedDemoIndex) : null;
|
|
536
|
-
if (!demoFactory) {
|
|
537
|
-
const count = demo ? getDemoCount(demo as TTemplateFactory | TTemplateFactory[]) : 0;
|
|
538
|
-
return {
|
|
539
|
-
emptyState: {
|
|
540
|
-
title: `${this.selectedItemName} has no demo ${this.selectedDemoIndex + 1}`,
|
|
541
|
-
detail: `This element defines ${count} ${count === 1 ? 'demo' : 'demos'}.`,
|
|
542
|
-
},
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
return { factory: demoFactory };
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
private getUnavailableEmptyState(entryArg: IWccUnavailableEntry): IWccEmptyState {
|
|
549
|
-
switch (entryArg.kind) {
|
|
550
|
-
case 'no-demo': {
|
|
551
|
-
const section = this.findSectionByName(entryArg.sectionName);
|
|
552
|
-
const item = section?.items[entryArg.itemName]
|
|
553
|
-
?? this.sections.map((s) => s.items[entryArg.itemName]).find((i) => i !== undefined);
|
|
554
|
-
const tagName = getElementTagName(item);
|
|
555
|
-
return {
|
|
556
|
-
title: `${entryArg.itemName} has no demo`,
|
|
557
|
-
detail: `${tagName ? `<${tagName}>` : 'This element'} is a registered custom element without a static demo. It is listed under "Without demo".`,
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
case 'ignored':
|
|
561
|
-
return {
|
|
562
|
-
title: `${entryArg.itemName} cannot be previewed`,
|
|
563
|
-
detail: 'This export is not a custom element with a demo, so the catalog does not list it.',
|
|
564
|
-
};
|
|
565
|
-
case 'missing':
|
|
566
|
-
return {
|
|
567
|
-
title: `${entryArg.itemName} was not found`,
|
|
568
|
-
detail: `No entry with this name exists in "${entryArg.sectionName}".`,
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
private getRouteUrl(): string {
|
|
574
|
-
const sectionName = this.selectedSection
|
|
575
|
-
? encodeURIComponent(this.selectedSection.name)
|
|
576
|
-
: this.selectedType; // Fallback for legacy
|
|
577
|
-
const baseUrl = `/wcctools-route/${sectionName}/${this.selectedItemName}/${this.selectedDemoIndex}/${this.selectedViewport}/${this.selectedTheme}`;
|
|
578
|
-
const queryParams = new URLSearchParams();
|
|
579
|
-
|
|
580
|
-
if (this.searchQuery) {
|
|
581
|
-
queryParams.set('search', this.searchQuery);
|
|
582
|
-
}
|
|
583
|
-
if (this.frameScrollY > 0) {
|
|
584
|
-
queryParams.set('frameScrollY', this.frameScrollY.toString());
|
|
585
|
-
}
|
|
586
|
-
if (this.sidebarScrollY > 0) {
|
|
587
|
-
queryParams.set('sidebarScrollY', this.sidebarScrollY.toString());
|
|
588
|
-
}
|
|
589
|
-
if (this.pinnedItems.size > 0) {
|
|
590
|
-
queryParams.set('pinned', Array.from(this.pinnedItems).join(','));
|
|
591
|
-
}
|
|
592
|
-
if (this.sidebarWidth !== 200) {
|
|
593
|
-
queryParams.set('sidebarWidth', this.sidebarWidth.toString());
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const queryString = queryParams.toString();
|
|
597
|
-
return queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
public buildUrl() {
|
|
601
|
-
this.domtools.router.pushUrl(this.getRouteUrl());
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
private handleFrameScroll = (event: Event) => {
|
|
605
|
-
this.frameScrollY = (event.currentTarget as HTMLElement).scrollTop;
|
|
606
|
-
this.debouncedScrollUpdate();
|
|
607
|
-
};
|
|
608
|
-
|
|
609
|
-
private handleSidebarScroll = (event: Event) => {
|
|
610
|
-
this.sidebarScrollY = (event.currentTarget as HTMLElement).scrollTop;
|
|
611
|
-
this.debouncedScrollUpdate();
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
public async setupScrollListeners() {
|
|
615
|
-
const wccFrame = await this.wccFrame;
|
|
616
|
-
// Prevent duplicate listeners and listeners on a removed dashboard
|
|
617
|
-
if (!this.isConnected || this.scrollDisposers.length > 0) {
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
const wccSidebar = this.shadowRoot.querySelector('wcc-sidebar') as WccSidebar | null;
|
|
621
|
-
|
|
622
|
-
if (wccFrame) {
|
|
623
|
-
// The frame element itself is the scrollable container
|
|
624
|
-
wccFrame.addEventListener('scroll', this.handleFrameScroll);
|
|
625
|
-
this.scrollDisposers.push(() => wccFrame.removeEventListener('scroll', this.handleFrameScroll));
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// Use the sidebar's scrollable container (.menu element)
|
|
629
|
-
const scrollContainer = wccSidebar?.scrollableContainer;
|
|
630
|
-
if (scrollContainer) {
|
|
631
|
-
scrollContainer.addEventListener('scroll', this.handleSidebarScroll);
|
|
632
|
-
this.scrollDisposers.push(() => scrollContainer.removeEventListener('scroll', this.handleSidebarScroll));
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
private debouncedScrollUpdate() {
|
|
637
|
-
clearTimeout(this.scrollUpdateTimeout);
|
|
638
|
-
this.scrollUpdateTimeout = setTimeout(() => {
|
|
639
|
-
this.updateUrlWithScrollState();
|
|
640
|
-
}, 300);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
private updateUrlWithScrollState() {
|
|
644
|
-
// Use replaceState to update URL without navigation
|
|
645
|
-
window.history.replaceState(null, '', this.getRouteUrl());
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
public async applyScrollPositions() {
|
|
649
|
-
// Only apply scroll positions once to avoid interfering with user scrolling
|
|
650
|
-
if (this.scrollPositionsApplied) {
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
const wccFrame = await this.wccFrame;
|
|
655
|
-
const wccSidebar = this.shadowRoot.querySelector('wcc-sidebar') as WccSidebar | null;
|
|
656
|
-
|
|
657
|
-
if (wccFrame && this.frameScrollY > 0) {
|
|
658
|
-
// The frame element itself is the scrollable container
|
|
659
|
-
wccFrame.scrollTop = this.frameScrollY;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
if (wccSidebar && this.sidebarScrollY > 0) {
|
|
663
|
-
// Use the sidebar's scrollable container (.menu element)
|
|
664
|
-
const scrollContainer = wccSidebar.scrollableContainer;
|
|
665
|
-
if (scrollContainer) {
|
|
666
|
-
scrollContainer.scrollTop = this.sidebarScrollY;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
this.scrollPositionsApplied = true;
|
|
671
|
-
}
|
|
672
|
-
}
|