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/**/*.d.ts
src/components/**/*.js src/components/**/*.js
src/components/**/*.js.map src/components/**/*.js.map
src/widgets/**/*.js
src/lib/**/*.d.ts src/lib/**/*.d.ts
src/lib/**/*.js src/lib/**/*.js
src/lib/**/*.js.map 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() { get order() {
return Array.from(this.manager.container.children).indexOf(this.master) return Array.from(this.manager.children).indexOf(this.master)
} }
synchroniseContainer() { 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 {customElement, query} from 'lit/decorators.js'
import DockChild from './dock-child' import DockChild from './dock-child'
import customStyle from './style' import customStyle from './style'
import dockStyle from './dock-styles'
import slotStyleHandler from './SlotStyleHandler'
interface DragAndDrop { interface DragAndDrop {
// Whether drag-and-drop is enabled // Whether drag-and-drop is enabled
enabled: boolean enabled: boolean
@ -65,6 +68,7 @@ const STATE_CHANGE_TIMEOUT = 100
export default class StarDock extends LitElement { export default class StarDock extends LitElement {
@query('#container') container!: HTMLElement @query('#container') container!: HTMLElement
name: string = 'star-dock'
_children: DockChild[] = [] _children: DockChild[] = []
_sortMode: Boolean = false _sortMode: Boolean = false
_dragInElement: HTMLElement | undefined _dragInElement: HTMLElement | undefined
@ -120,7 +124,7 @@ export default class StarDock extends LitElement {
const child = const child =
this.getChildByElement(element) || new DockChild(element, this) this.getChildByElement(element) || new DockChild(element, this)
this._children.push(child) this._children.push(child)
this.container.appendChild(child.master) this.appendChild(child.master)
if (typeof order == 'number') { if (typeof order == 'number') {
child.order = order child.order = order
} }
@ -141,15 +145,15 @@ export default class StarDock extends LitElement {
realInsertBefore = (element: HTMLElement, reference: HTMLElement) => { realInsertBefore = (element: HTMLElement, reference: HTMLElement) => {
element.style.order = reference.style.order element.style.order = reference.style.order
this.container.insertBefore(element, reference) this.insertBefore(element, reference)
} }
realInsertAfter = (element: HTMLElement, reference: HTMLElement) => { realInsertAfter = (element: HTMLElement, reference: HTMLElement) => {
element.style.order = reference.style.order element.style.order = reference.style.order
if (reference.nextSibling) { if (reference.nextSibling) {
this.container.insertBefore(element, reference.nextElementSibling) this.insertBefore(element, reference.nextElementSibling)
} else { } else {
this.container.appendChild(element) this.appendChild(element)
} }
return element return element
} }
@ -164,24 +168,28 @@ export default class StarDock extends LitElement {
child.master.style.order = String(child.order) child.master.style.order = String(child.order)
} else if (+child.master.style.order !== child.order) { } else if (+child.master.style.order !== child.order) {
const insertedMaster = const insertedMaster =
this.container.children[+child.master.style.order] this.children[+child.master.style.order]
if (insertedMaster) { if (insertedMaster) {
this.container.insertBefore(child.master, insertedMaster) this.insertBefore(child.master, insertedMaster)
} }
} }
child.synchroniseContainer() child.synchroniseContainer()
} }
this.reorderChild() this.recorderChild()
if (this._children.length) { if (this._children.length) {
this._gridSize = this._children[0].master.offsetWidth this._gridSize = this._children[0].master.offsetWidth
} }
} }
reorderChild() { recorderChild() {
let children: DockChild[] = [] let children: DockChild[] = []
let _children = [...this._children] let _children = [...this._children]
const childrenElements = [...this.container.children] const childrenElements = [...this.children]
if (!_children.length || !childrenElements.length) {
return
}
for (const childElement of childrenElements) { for (const childElement of childrenElements) {
let child!: DockChild let child!: DockChild
_children = _children.filter((item) => { _children = _children.filter((item) => {
@ -191,8 +199,7 @@ export default class StarDock extends LitElement {
} }
return true return true
}) })
child && children.push(child)
children.push(child)
} }
this._children = children this._children = children
@ -406,6 +413,7 @@ export default class StarDock extends LitElement {
'px)' 'px)'
if (!dropChild) { if (!dropChild) {
// this._children.pop()
return false return false
} }
@ -418,19 +426,17 @@ export default class StarDock extends LitElement {
} }
} else if (dropChild === this.container) { } else if (dropChild === this.container) {
if (this._children.length && this._children[0].center.x > centerX) { if (this._children.length && this._children[0].center.x > centerX) {
if (this.container.firstElementChild == this._dragChild!.master) if (this.firstElementChild == this._dragChild!.master) return true
return true
this.realInsertBefore( this.realInsertBefore(
this._dragChild?.master!, this._dragChild?.master!,
this._children[0].master this._children[0].master
) )
} else { } else {
if (this.container.lastElementChild == this._dragChild!.master) if (this.lastElementChild == this._dragChild!.master) return true
return true
this._dragChild!.order = this._children.length 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 { protected firstUpdated(): void {
this.container.addEventListener('touchstart', this) slotStyleHandler.injectGlobalCss(this, dockStyle.cssText, this.name)
this.container.addEventListener('click', this) this.addEventListener('touchstart', this)
this.container.addEventListener('touchmove', this) this.addEventListener('click', this)
this.container.addEventListener('touchend', this) this.addEventListener('touchmove', this)
this.container.addEventListener('touchcancel', this) this.addEventListener('touchend', this)
this.addEventListener('touchcancel', this)
this.resize() this.resize()
} }
@ -667,7 +674,7 @@ export default class StarDock extends LitElement {
child.container.addEventListener('animationstart', animStart) child.container.addEventListener('animationstart', animStart)
child.container.classList.add(state) child.container.classList.add(state)
child[state] = window.window.setTimeout(() => { child[state] = window.setTimeout(() => {
delete child[state] delete child[state]
child.container.removeEventListener('animationstart', animStart) child.container.removeEventListener('animationstart', animStart)
child.container.classList.remove(state) child.container.classList.remove(state)
@ -679,52 +686,12 @@ export default class StarDock extends LitElement {
protected render() { protected render() {
return html` return html`
<div id="container"></div> <div id="container">
<slot></slot>
</div>
` `
} }
static styles?: CSSResultGroup | undefined = [ static styles = [customStyle, dockStyle]
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;
}
`,
]
} }
declare global { declare global {

View File

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

View File

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