From ee5f202f35ab227fdcfddd3c46965ee294e6ac3e Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 11 Apr 2024 08:07:00 -0600 Subject: [PATCH] Et2VfsPath: Better overflow handling, including arrow buttons when needed --- api/js/etemplate/Et2Vfs/Et2VfsPath.styles.ts | 32 +++++++--- api/js/etemplate/Et2Vfs/Et2VfsPath.ts | 65 ++++++++++++++++++-- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/api/js/etemplate/Et2Vfs/Et2VfsPath.styles.ts b/api/js/etemplate/Et2Vfs/Et2VfsPath.styles.ts index 6a355a73f3..e996535470 100644 --- a/api/js/etemplate/Et2Vfs/Et2VfsPath.styles.ts +++ b/api/js/etemplate/Et2Vfs/Et2VfsPath.styles.ts @@ -3,6 +3,7 @@ import {css} from 'lit'; export default css` .form-control-input { + position: relative; min-width: 15em; flex: 1; @@ -61,14 +62,31 @@ export default css` visibility: visible; } - /* Breadcrumb directories */ - - sl-breadcrumb { + .vfs-path__scroll { flex: 1 1 auto; overflow: hidden; min-width: 10em; } + .form-control-input sl-icon-button[name*="caret"] { + display: none; + position: absolute; + background: var(--sl-input-background-color); + } + + .form-control-input sl-icon-button[name*="caret"]:last-of-type { + right: 2em; + } + + :host(:hover) .form-control-input.vfs-path__overflow sl-icon-button[name*="caret"] { + display: initial; + } + + /* Breadcrumb directories */ + + sl-breadcrumb { + } + et2-image { flex: none; height: 1.5em; @@ -76,8 +94,6 @@ export default css` sl-breadcrumb::part(base) { flex-wrap: nowrap; - flex-direction: row-reverse; - justify-content: flex-start; } sl-breadcrumb-item::part(base) { @@ -95,15 +111,15 @@ export default css` } sl-breadcrumb-item:first-of-type { - margin-right: auto; } sl-breadcrumb-item:first-of-type::part(separator) { - display: none; + display: initial; } sl-breadcrumb-item:last-of-type::part(separator) { - display: initial; + /* Trailing / */ + display: none; } /* Sizes */ diff --git a/api/js/etemplate/Et2Vfs/Et2VfsPath.ts b/api/js/etemplate/Et2Vfs/Et2VfsPath.ts index 4fed5970c6..50cefb824f 100644 --- a/api/js/etemplate/Et2Vfs/Et2VfsPath.ts +++ b/api/js/etemplate/Et2Vfs/Et2VfsPath.ts @@ -8,7 +8,7 @@ */ import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; -import {html, LitElement, nothing, TemplateResult} from "lit"; +import {html, LitElement, nothing, PropertyValues, TemplateResult} from "lit"; import shoelace from "../Styles/shoelace"; import styles from "./Et2VfsPath.styles"; import {property} from "lit/decorators/property.js"; @@ -71,6 +71,13 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) this.handlePathClick = this.handlePathClick.bind(this); } + updated(changedProperties : PropertyValues) + { + super.updated(changedProperties); + + this.checkPathOverflow(); + } + @property() set value(_value : string) { @@ -138,6 +145,30 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) }) } + protected checkPathOverflow() + { + const wrapper = this.shadowRoot.querySelector(".vfs-path__scroll"); + const path = wrapper?.querySelector("sl-breadcrumb"); + const scroll = path?.shadowRoot.querySelector("nav"); + if(!wrapper || !scroll) + { + return; + } + path.updateComplete.then(() => + { + if(wrapper.clientWidth < scroll.scrollWidth) + { + // Too small + wrapper.scrollLeft = scroll.scrollWidth - wrapper.clientWidth; + wrapper.parentElement.classList.add("vfs-path__overflow"); + } + else + { + wrapper.parentElement.classList.remove("vfs-path__overflow"); + } + }); + } + protected handleLabelClick() { this.edit(); @@ -185,7 +216,7 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) event.preventDefault(); event.stopPropagation(); - const dirs = Array.from(target.parentElement.querySelectorAll('sl-breadcrumb-item')).reverse() ?? []; + const dirs = Array.from(target.parentElement.querySelectorAll('sl-breadcrumb-item')) ?? []; let stopIndex = dirs.indexOf(target) + 1; let newPath = dirs.slice(0, stopIndex) // Strip out any extra space @@ -228,7 +259,7 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) protected handleScroll(event : WheelEvent) { - this.shadowRoot.querySelector("sl-breadcrumb").scrollLeft += event.deltaY; + this.shadowRoot.querySelector(".vfs-path__scroll").scrollLeft += event.deltaY; } protected _getIcon(pathParts) @@ -242,9 +273,8 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) return image; } - protected pathPartTemplate(pathParts, path, i) + protected pathPartTemplate(pathParts, path, index) { - let index = pathParts.length - 1 - i; let pathName : string | TemplateResult<1> = path.trim(); if(pathParts.length > 1 && pathParts[1] == "apps") { @@ -310,6 +340,13 @@ export class Et2VfsPath extends Et2InputWidget(LitElement)
this.focus()} + @mouseout=${(e) => + { + if(e.target.classList.contains("form-control-input")) + { + this.checkPathOverflow(); + } + }} > ${icon ? html` @@ -334,14 +371,30 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) @keydown=${this.handleKeyDown} />
` : html` + + { + e.stopPropagation(); + this.handleScroll({deltaY: -20}) + }}> +
/ - ${repeat(pathParts.toReversed(), (part, i) => this.pathPartTemplate(pathParts, part, i))} + ${repeat(pathParts, (part, i) => this.pathPartTemplate(pathParts, part, i))} +
+ + { + e.stopPropagation(); + this.handleScroll({deltaY: 20}) + }}> ${!isEditable ? nothing : html`