TASK: #109666 - fix bug of container

This commit is contained in:
luojiahao 2022-10-05 13:53:51 +08:00
parent a4727b4a79
commit dc18d4783d
7 changed files with 197 additions and 78 deletions

1
.gitignore vendored
View File

@ -28,6 +28,7 @@ types/
src/components/**/*.d.ts
src/components/**/*.js
src/components/**/*.js.map
src/widgets/**/*.js
src/lib/**/*.d.ts
src/lib/**/*.js
src/lib/**/*.js.map

View File

@ -0,0 +1,102 @@
class SlotStyleHandler {
regex: {[regStr: string]: RegExp} = {
slottedCss: /(?:\:\:slotted\(.*\))[^{]+\{[^}]*\}/g,
'::slotted()': /\:\:slotted\(([^\(]+)\)/g,
keyframes: /@keyframes[^{]+\{([^{]+\{[^}]*\})*\D*\}/g,
}
head!: HTMLElement
headFirstElement!: ChildNode | null
headStyle!: HTMLElement
shouldRefresh: boolean = false
styles: {[styleName: string]: string} = new Proxy(
{},
{
set: (
target: {[styleName: string]: string},
prop: string,
value: string
) => {
if (!target[prop] || target[prop] !== value) {
target[prop] = value
this.shouldRefresh = true
}
return true
},
}
)
processCss(style: string, name: string) {
let globalCss = ''
style.replace(this.regex.keyframes, (match) => {
globalCss += match
return ''
})
style = style.replace(this.regex.slottedCss, (match) => {
globalCss += match.replace(this.regex['::slotted()'], name + ' $1')
return ''
})
return globalCss
}
/**
* CSS注入头部<style></style>
*
* @param {String} style
* @param {String} name
* @returns
*/
injectGlobalCss(
component: HTMLElement,
style: string,
name: string,
subName = ''
) {
if (!style) return
const styleName = subName ? `${name}-${subName}` : name
let css = this.processCss(style, name)
this.styles[styleName] = css
if (this.shouldRefresh) {
if (!this.head || !this.headFirstElement) {
this.head = document.head
this.headFirstElement = this.head.firstChild
}
if (!this.headStyle) {
this.headStyle = document.createElement('style')
if (this.headFirstElement) {
this.head.insertBefore(this.headStyle, this.headFirstElement)
} else {
this.head.appendChild(this.headStyle)
}
}
// 当父节点也是 Web Component时防止全局注册的 Style 被父节点的
// ShadowRoot 隔离,需要再在父节点中插入一份样式
if (
component.parentNode &&
(Object.prototype.toString
.call(component.parentNode)
.includes('DocumentFragment') ||
Object.prototype.toString
.call(component.parentNode)
.includes('ShadowRoot'))
) {
let scoped = document.createElement('style')
scoped.innerHTML = css.trim()
component.parentNode.appendChild(scoped)
}
let style = ''
for (const styleName in this.styles) {
const content = this.styles[styleName]
style += content
}
this.headStyle.innerHTML = style
this.shouldRefresh = false
}
}
}
export default new SlotStyleHandler()

View File

@ -70,7 +70,7 @@ export default class DockChild {
}
get order() {
return Array.from(this.manager.container.children).indexOf(this.master)
return Array.from(this.manager.children).indexOf(this.master)
}
synchroniseContainer() {

View File

@ -0,0 +1,42 @@
import {css} from 'lit'
export default css`
:host {
// position: relative;
display: flex;
flex: 1;
margin-bottom: var(--dock-margin-bottom);
width: 100%;
height: var(--dock-container-height);
}
#container {
display: flex;
justify-content: center;
margin: auto auto 0;
min-width: var(--dock-min-width, 100%);
max-width: 100%;
height: var(--dock-container-height);
}
::slotted(.dock-child-master) {
max-width: var(--dock-grid-width, 92px);
max-height: var(--dock-grid-width, 92px);
flex: 1;
}
::slotted(.dock-child-container) {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: var(--icon-size);
height: var(--icon-size);
}
::slotted(.dock-child-container):not(.dragging):not(.added) {
transition: transform 0.2s;
}
::slotted(.dock-child-container).dragging {
z-index: 1;
}
`

View File

@ -1,7 +1,10 @@
import {html, css, LitElement, CSSResultGroup} from 'lit'
import {html, LitElement} from 'lit'
import {customElement, query} from 'lit/decorators.js'
import DockChild from './dock-child'
import customStyle from './style'
import dockStyle from './dock-styles'
import slotStyleHandler from './SlotStyleHandler'
interface DragAndDrop {
// Whether drag-and-drop is enabled
enabled: boolean
@ -65,6 +68,7 @@ const STATE_CHANGE_TIMEOUT = 100
export default class StarDock extends LitElement {
@query('#container') container!: HTMLElement
name: string = 'star-dock'
_children: DockChild[] = []
_sortMode: Boolean = false
_dragInElement: HTMLElement | undefined
@ -120,7 +124,7 @@ export default class StarDock extends LitElement {
const child =
this.getChildByElement(element) || new DockChild(element, this)
this._children.push(child)
this.container.appendChild(child.master)
this.appendChild(child.master)
if (typeof order == 'number') {
child.order = order
}
@ -141,15 +145,15 @@ export default class StarDock extends LitElement {
realInsertBefore = (element: HTMLElement, reference: HTMLElement) => {
element.style.order = reference.style.order
this.container.insertBefore(element, reference)
this.insertBefore(element, reference)
}
realInsertAfter = (element: HTMLElement, reference: HTMLElement) => {
element.style.order = reference.style.order
if (reference.nextSibling) {
this.container.insertBefore(element, reference.nextElementSibling)
this.insertBefore(element, reference.nextElementSibling)
} else {
this.container.appendChild(element)
this.appendChild(element)
}
return element
}
@ -164,24 +168,28 @@ export default class StarDock extends LitElement {
child.master.style.order = String(child.order)
} else if (+child.master.style.order !== child.order) {
const insertedMaster =
this.container.children[+child.master.style.order]
this.children[+child.master.style.order]
if (insertedMaster) {
this.container.insertBefore(child.master, insertedMaster)
this.insertBefore(child.master, insertedMaster)
}
}
child.synchroniseContainer()
}
this.reorderChild()
this.recorderChild()
if (this._children.length) {
this._gridSize = this._children[0].master.offsetWidth
}
}
reorderChild() {
recorderChild() {
let children: DockChild[] = []
let _children = [...this._children]
const childrenElements = [...this.container.children]
const childrenElements = [...this.children]
if (!_children.length || !childrenElements.length) {
return
}
for (const childElement of childrenElements) {
let child!: DockChild
_children = _children.filter((item) => {
@ -191,8 +199,7 @@ export default class StarDock extends LitElement {
}
return true
})
children.push(child)
child && children.push(child)
}
this._children = children
@ -406,6 +413,7 @@ export default class StarDock extends LitElement {
'px)'
if (!dropChild) {
// this._children.pop()
return false
}
@ -418,19 +426,17 @@ export default class StarDock extends LitElement {
}
} else if (dropChild === this.container) {
if (this._children.length && this._children[0].center.x > centerX) {
if (this.container.firstElementChild == this._dragChild!.master)
return true
if (this.firstElementChild == this._dragChild!.master) return true
this.realInsertBefore(
this._dragChild?.master!,
this._children[0].master
)
} else {
if (this.container.lastElementChild == this._dragChild!.master)
return true
if (this.lastElementChild == this._dragChild!.master) return true
this._dragChild!.order = this._children.length
this.container.appendChild(this._dragChild?.master!)
this.appendChild(this._dragChild?.master!)
}
}
@ -612,11 +618,12 @@ export default class StarDock extends LitElement {
}
protected firstUpdated(): void {
this.container.addEventListener('touchstart', this)
this.container.addEventListener('click', this)
this.container.addEventListener('touchmove', this)
this.container.addEventListener('touchend', this)
this.container.addEventListener('touchcancel', this)
slotStyleHandler.injectGlobalCss(this, dockStyle.cssText, this.name)
this.addEventListener('touchstart', this)
this.addEventListener('click', this)
this.addEventListener('touchmove', this)
this.addEventListener('touchend', this)
this.addEventListener('touchcancel', this)
this.resize()
}
@ -667,7 +674,7 @@ export default class StarDock extends LitElement {
child.container.addEventListener('animationstart', animStart)
child.container.classList.add(state)
child[state] = window.window.setTimeout(() => {
child[state] = window.setTimeout(() => {
delete child[state]
child.container.removeEventListener('animationstart', animStart)
child.container.classList.remove(state)
@ -679,52 +686,12 @@ export default class StarDock extends LitElement {
protected render() {
return html`
<div id="container"></div>
<div id="container">
<slot></slot>
</div>
`
}
static styles?: CSSResultGroup | undefined = [
customStyle,
css`
:host {
// position: relative;
display: flex;
flex: 1;
margin-bottom: var(--dock-margin-bottom);
width: 100%;
height: var(--dock-container-height);
}
#container {
display: flex;
justify-content: center;
margin: auto auto 0;
min-width: var(--dock-min-width, 100%);
max-width: 100%;
height: var(--dock-container-height);
}
.dock-child-master {
max-width: var(--dock-grid-width, 92px);
max-height: var(--dock-grid-width, 92px);
flex: 1;
}
.dock-child-container {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: var(--icon-size);
height: var(--icon-size);
}
.dock-child-container:not(.dragging):not(.added) {
transition: transform 0.2s;
}
.dock-child-container.dragging {
z-index: 1;
}
`,
]
static styles = [customStyle, dockStyle]
}
declare global {

View File

@ -803,12 +803,14 @@ class GaiaContainer extends StarBaseElement {
* @param {Object} options
*/
appendContainerChild(element: HTMLElement, options?: ChildElementInfo) {
if (element.tagName === 'GAIA-WIDGET') {
if (element.tagName.split('-').length > 1) {
let obj: ChildElementInfo = options
? {...options}
: ({} as ChildElementInfo)
if ((element as any).size) {
obj.row = (element as any).size[0]
obj.column = (element as any).size[1]
}
this.insertContainerBefore(element, null, obj)
} else {
this.insertContainerBefore(element, null, options)
@ -1239,10 +1241,10 @@ class GaiaContainer extends StarBaseElement {
cancelDrag() {
this.dataset.dragging = 'false'
if (this._dnd.timeout !== null) {
/* if (this._dnd.timeout !== null) {
clearTimeout(this._dnd.timeout)
this._dnd.timeout = undefined
}
} */
if (this._dnd.moveTimeout !== null) {
clearTimeout(this._dnd.moveTimeout)
@ -1861,14 +1863,14 @@ class GaiaContainer extends StarBaseElement {
composed: true,
})
)
} else if (this._dnd.timeout !== null && this._dnd.child?.isFolder) {
} else if (/* this._dnd.timeout !== null && */ this._dnd.child?.isFolder) {
this._dnd.child.open()
} else if (
!(
this.status & // 不处于四种状态的任何一种时,才可以发送 activate 事件
(STATUS.DRAG | STATUS.SWIPE | STATUS.TURN | STATUS.SORT)
) &&
this._dnd.timeout !== null &&
// this._dnd.timeout !== null &&
this._dnd.child?.element
) {
let handled = !this.dispatchEvent(
@ -1910,7 +1912,7 @@ class GaiaContainer extends StarBaseElement {
// 拖拽节点所处位置
dragPosition: 'inner' | 'outter' = 'inner'
// 翻页控制事件
turnEvent: 'holdmove' | 'panmove' | undefined
turnEvent: string | undefined
handleEvent(event: CustomEvent) {
switch (event.type) {
case 'touchstart':
@ -2128,7 +2130,7 @@ class GaiaContainer extends StarBaseElement {
handleMove(event: CustomEvent) {
if (!this.turnEvent || this.turnEvent == event.type) {
this.turnEvent = (event.type as 'holdmove' | 'panmove')
this.turnEvent = event.type
} else {
return
}
@ -2170,7 +2172,7 @@ class GaiaContainer extends StarBaseElement {
}
handleEnd(event: CustomEvent) {
if (this.turnEvent == event.type) {
if (this.turnEvent?.replace('move', 'end') == event.type) {
this.turnEvent = undefined
} else {
return

View File

@ -236,14 +236,13 @@ export class PanelContainer extends LitElement {
// 此时的拖拽进 container 组件的标志才意味着是否成功放置成功
if (this.dragInContainer) {
this.dock.removeContainerChild(evt.detail.target)
if (this.container._dnd.child) {
this.container._dnd.child.element = evt.detail.target
this.container._dnd.child.container.classList.remove('dragging')
this.container._dnd.child = undefined
this.container.synchronise()
}
this.dock.removeContainerChild(evt.detail.target)
} else {
this.container.removeContainerChild(this.elementPlaceholder)
}
@ -409,6 +408,12 @@ export class PanelContainer extends LitElement {
height: 2px;
background-color: pink;
}
star-dock .dock-child-container {
position: absolute;
top: 0;
left: 0;
}
`,
homescreenStyle,
]