Compare commits

...

4 Commits

Author SHA1 Message Date
8c60d3bea3 v3.5.1
Some checks failed
Default (tags) / security (push) Failing after 14s
Default (tags) / test (push) Failing after 15s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-01-04 11:31:02 +00:00
9ed614994f fix(sidebar): disable frame CSS transition while user is resizing the sidebar to prevent janky animations 2026-01-04 11:31:02 +00:00
61b79aa4dc update 2026-01-04 11:29:19 +00:00
1134cba575 update 2026-01-04 10:57:45 +00:00
9 changed files with 157 additions and 22 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -1,5 +1,13 @@
# Changelog
## 2026-01-04 - 3.5.1 - fix(sidebar)
disable frame CSS transition while user is resizing the sidebar to prevent janky animations
- Added isResizing boolean property to wcc-frame to toggle transitions during resize
- Set frame.isResizing = true at resize start and false on mouseup to re-enable transitions
- Updated CSS to skip transition while isResizing is true
- Files changed: ts_web/elements/wcc-frame.ts, ts_web/elements/wcc-sidebar.ts
## 2026-01-04 - 3.5.0 - feat(wcctools)
add context menu and pinning support, persist pinned state in URL, and add grouped demo test elements

View File

@@ -1,6 +1,6 @@
{
"name": "@design.estate/dees-wcctools",
"version": "3.5.0",
"version": "3.5.1",
"private": false,
"description": "A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.",
"exports": {

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@design.estate/dees-wcctools',
version: '3.5.0',
version: '3.5.1',
description: 'A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.'
}

View File

@@ -66,6 +66,10 @@ export class WccDashboard extends DeesElement {
@property({ attribute: false })
accessor pinnedItems: Set<string> = new Set();
// Sidebar width (resizable)
@property({ type: Number })
accessor sidebarWidth: number = 200;
// Derived from selectedViewport - no need for separate property
public get isNative(): boolean {
return this.selectedViewport === 'native';
@@ -127,6 +131,7 @@ export class WccDashboard extends DeesElement {
.selectedItem=${this.selectedItem}
.searchQuery=${this.searchQuery}
.pinnedItems=${this.pinnedItems}
.sidebarWidth=${this.sidebarWidth}
.isNative=${this.isNative}
@selectedType=${(eventArg) => {
this.selectedType = eventArg.detail;
@@ -145,6 +150,15 @@ export class WccDashboard extends DeesElement {
this.pinnedItems = eventArg.detail;
this.updateUrlWithScrollState();
}}
@widthChanged=${async (eventArg: CustomEvent) => {
this.sidebarWidth = eventArg.detail;
this.updateUrlWithScrollState();
const frame = await this.wccFrame;
if (frame) {
frame.sidebarWidth = eventArg.detail;
frame.requestUpdate();
}
}}
></wcc-sidebar>
<wcc-properties
.dashboardRef=${this}
@@ -153,6 +167,7 @@ export class WccDashboard extends DeesElement {
.selectedViewport=${this.selectedViewport}
.selectedTheme=${this.selectedTheme}
.isNative=${this.isNative}
.sidebarWidth=${this.sidebarWidth}
@selectedViewport=${(eventArg) => {
this.selectedViewport = eventArg.detail;
this.scheduleUpdate();
@@ -171,7 +186,7 @@ export class WccDashboard extends DeesElement {
this.toggleNative();
}}
></wcc-properties>
<wcc-frame id="wccFrame" viewport=${this.selectedViewport} .isNative=${this.isNative}>
<wcc-frame id="wccFrame" viewport=${this.selectedViewport} .isNative=${this.isNative} .sidebarWidth=${this.sidebarWidth}>
</wcc-frame>
`;
}
@@ -247,6 +262,7 @@ export class WccDashboard extends DeesElement {
const frameScrollY = routeInfo.queryParams.frameScrollY;
const sidebarScrollY = routeInfo.queryParams.sidebarScrollY;
const pinned = routeInfo.queryParams.pinned;
const sidebarWidth = routeInfo.queryParams.sidebarWidth;
if (search) {
this.searchQuery = search;
@@ -269,10 +285,19 @@ export class WccDashboard extends DeesElement {
} else if (this.pinnedItems.size > 0) {
this.pinnedItems = new Set();
}
if (sidebarWidth) {
this.sidebarWidth = parseInt(sidebarWidth, 10);
}
// Apply scroll positions after a short delay to ensure DOM is ready
setTimeout(() => {
// Apply scroll positions and update frame after a short delay to ensure DOM is ready
setTimeout(async () => {
this.applyScrollPositions();
// Ensure frame gets the sidebarWidth
const frame = await this.wccFrame;
if (frame) {
frame.sidebarWidth = this.sidebarWidth;
frame.requestUpdate();
}
}, 100);
} else {
this.searchQuery = '';
@@ -326,6 +351,7 @@ export class WccDashboard extends DeesElement {
const frameScrollY = routeInfo.queryParams.frameScrollY;
const sidebarScrollY = routeInfo.queryParams.sidebarScrollY;
const pinned = routeInfo.queryParams.pinned;
const sidebarWidth = routeInfo.queryParams.sidebarWidth;
if (search) {
this.searchQuery = search;
@@ -348,6 +374,9 @@ export class WccDashboard extends DeesElement {
} else if (this.pinnedItems.size > 0) {
this.pinnedItems = new Set();
}
if (sidebarWidth) {
this.sidebarWidth = parseInt(sidebarWidth, 10);
}
// Apply scroll positions after a short delay to ensure DOM is ready
setTimeout(() => {
@@ -444,6 +473,9 @@ export class WccDashboard extends DeesElement {
if (this.pinnedItems.size > 0) {
queryParams.set('pinned', Array.from(this.pinnedItems).join(','));
}
if (this.sidebarWidth !== 200) {
queryParams.set('sidebarWidth', this.sidebarWidth.toString());
}
const queryString = queryParams.toString();
const fullUrl = queryString ? `${baseUrl}?${queryString}` : baseUrl;
@@ -507,6 +539,9 @@ export class WccDashboard extends DeesElement {
if (this.pinnedItems.size > 0) {
queryParams.set('pinned', Array.from(this.pinnedItems).join(','));
}
if (this.sidebarWidth !== 200) {
queryParams.set('sidebarWidth', this.sidebarWidth.toString());
}
const queryString = queryParams.toString();
const fullUrl = queryString ? `${baseUrl}?${queryString}` : baseUrl;

View File

@@ -19,13 +19,18 @@ export class WccFrame extends DeesElement {
@property({ type: Boolean })
accessor isNative: boolean = false;
@property({ type: Number })
accessor sidebarWidth: number = 200;
@property({ type: Boolean })
accessor isResizing: boolean = false;
public static styles = [
css`
:host {
border: 10px solid #ffaeaf;
position: absolute;
background: ${cssManager.bdTheme('#333', '#000')};
left: 200px;
right: 0px;
top: 0px;
overflow-y: auto;
@@ -55,9 +60,9 @@ export class WccFrame extends DeesElement {
` : `
bottom: ${this.advancedEditorOpen ? '400px' : '100px'};
border: 10px solid #ffaeaf;
left: 200px;
left: ${this.sidebarWidth}px;
`}
transition: all 0.3s ease;
transition: ${this.isResizing ? 'none' : 'all 0.3s ease'};
${this.isNative ? 'padding: 0px;' : (() => {
switch (this.viewport) {
case 'desktop':
@@ -67,19 +72,19 @@ export class WccFrame extends DeesElement {
case 'tablet':
return `
padding: 0px ${
(document.body.clientWidth - 200 - domtools.breakpoints.tablet) / 2
(document.body.clientWidth - this.sidebarWidth - domtools.breakpoints.tablet) / 2
}px;
`;
case 'phablet':
return `
padding: 0px ${
(document.body.clientWidth - 200 - domtools.breakpoints.phablet) / 2
(document.body.clientWidth - this.sidebarWidth - domtools.breakpoints.phablet) / 2
}px;
`;
case 'phone':
return `
padding: 0px ${
(document.body.clientWidth - 200 - domtools.breakpoints.phone) / 2
(document.body.clientWidth - this.sidebarWidth - domtools.breakpoints.phone) / 2
}px;
`;
}

View File

@@ -37,6 +37,9 @@ export class WccProperties extends DeesElement {
@property()
accessor isNative: boolean = false;
@property({ type: Number })
accessor sidebarWidth: number = 200;
@state()
accessor propertyContent: TemplateResult[] = [];
@@ -89,7 +92,7 @@ export class WccProperties extends DeesElement {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
box-sizing: border-box;
position: absolute;
left: 200px;
left: ${this.sidebarWidth}px;
height: ${this.editingProperties.length > 0 ? 100 + this.editorHeight : 100}px;
bottom: 0px;
right: 0px;

View File

@@ -36,6 +36,14 @@ export class WccSidebar extends DeesElement {
@property({ attribute: false })
accessor pinnedItems: Set<string> = new Set();
// Sidebar width (resizable)
@property({ type: Number })
accessor sidebarWidth: number = 200;
// Track if currently resizing
@state()
accessor isResizing: boolean = false;
private sectionsInitialized = false;
public render(): TemplateResult {
@@ -66,7 +74,7 @@ export class WccSidebar extends DeesElement {
box-sizing: border-box;
position: absolute;
left: 0px;
width: 200px;
width: ${this.sidebarWidth}px;
top: 0px;
bottom: 0px;
overflow-y: auto;
@@ -167,6 +175,10 @@ export class WccSidebar extends DeesElement {
grid-template-columns: 16px 1fr;
}
.selectOption.folder .text {
margin-left: 4px;
}
.selectOption .expand-icon {
font-size: 14px;
opacity: 0.5;
@@ -321,13 +333,17 @@ export class WccSidebar extends DeesElement {
opacity: 0.8;
}
/* Section tag for pinned items */
/* Section tag pill for pinned items */
.section-tag {
font-size: 0.55rem;
color: #555;
font-size: 0.5rem;
color: #888;
margin-left: auto;
text-transform: uppercase;
letter-spacing: 0.03em;
letter-spacing: 0.02em;
background: rgba(255, 255, 255, 0.06);
padding: 0.15rem 0.4rem;
border-radius: 9999px;
white-space: nowrap;
}
/* Group container */
@@ -352,6 +368,27 @@ export class WccSidebar extends DeesElement {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
/* Resize handle */
.resize-handle {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 4px;
cursor: col-resize;
background: transparent;
transition: background 0.15s ease;
z-index: 10;
}
.resize-handle:hover {
background: rgba(59, 130, 246, 0.3);
}
.resize-handle.active {
background: var(--primary);
}
</style>
<div class="search-container">
<input
@@ -366,6 +403,10 @@ export class WccSidebar extends DeesElement {
${this.renderPinnedSection()}
${this.renderSections()}
</div>
<div
class="resize-handle ${this.isResizing ? 'active' : ''}"
@mousedown=${this.startResize}
></div>
`;
}
@@ -429,6 +470,7 @@ export class WccSidebar extends DeesElement {
const isCollapsed = this.collapsedSections.has('__pinned__');
// Collect pinned items with their original section info
// Pinned items are NOT filtered by search - they always remain visible
const pinnedEntries: Array<{ sectionName: string; itemName: string; item: any; section: IWccSection }> = [];
for (const key of this.pinnedItems) {
@@ -443,10 +485,7 @@ export class WccSidebar extends DeesElement {
}
}
// Filter by search
const filteredEntries = pinnedEntries.filter(e => this.matchesSearch(e.itemName));
if (filteredEntries.length === 0 && this.searchQuery) {
if (pinnedEntries.length === 0) {
return null;
}
@@ -460,7 +499,7 @@ export class WccSidebar extends DeesElement {
<span>Pinned</span>
</div>
<div class="section-content ${isCollapsed ? 'collapsed' : ''}">
${filteredEntries.map(({ sectionName, itemName, item, section }) => {
${pinnedEntries.map(({ sectionName, itemName, item, section }) => {
const isSelected = this.selectedItem === item;
const type = section.type === 'elements' ? 'element' : 'page';
const icon = section.type === 'elements' ? 'featured_video' : 'insert_drive_file';
@@ -717,6 +756,51 @@ export class WccSidebar extends DeesElement {
}
}
// ============ Resize functionality ============
private startResize = (e: MouseEvent) => {
e.preventDefault();
this.isResizing = true;
const startX = e.clientX;
const startWidth = this.sidebarWidth;
// Cache references once at start
const frame = this.dashboardRef?.shadowRoot?.querySelector('wcc-frame') as any;
const properties = this.dashboardRef?.shadowRoot?.querySelector('wcc-properties') as any;
// Disable frame transition during resize
if (frame) {
frame.isResizing = true;
}
const onMouseMove = (e: MouseEvent) => {
const newWidth = Math.min(400, Math.max(150, startWidth + (e.clientX - startX)));
this.sidebarWidth = newWidth;
// Update frame and properties directly
if (frame) {
frame.sidebarWidth = newWidth;
}
if (properties) {
properties.sidebarWidth = newWidth;
}
};
const onMouseUp = () => {
this.isResizing = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
// Re-enable frame transition
if (frame) {
frame.isResizing = false;
}
// Dispatch event on release for URL persistence
this.dispatchEvent(new CustomEvent('widthChanged', { detail: this.sidebarWidth }));
};
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
public selectItem(
typeArg: TElementType,
itemNameArg: string,