diff --git a/index.json b/index.json index 0400cd4..cd1d70d 100644 --- a/index.json +++ b/index.json @@ -91,7 +91,7 @@ }, "dom-viewer": { "icon": true, - "version": "1.3.0", + "version": "1.4.0", "style": true, "test": true, "install": false, diff --git a/src/dom-viewer/CHANGELOG.md b/src/dom-viewer/CHANGELOG.md index cfcb6f4..84078e4 100644 --- a/src/dom-viewer/CHANGELOG.md +++ b/src/dom-viewer/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.0 (27 Sep 2024) + +* feat: shadow root support + ## 1.3.0 (25 Dec 2023) * feat: hotkey for navigation diff --git a/src/dom-viewer/index.ts b/src/dom-viewer/index.ts index 4a09b6e..a4ad60f 100644 --- a/src/dom-viewer/index.ts +++ b/src/dom-viewer/index.ts @@ -56,6 +56,7 @@ export default class DomViewer extends Component { private $tag: $.$ private $children: $.$ private observer: MutationObserver + private isShadowRoot: boolean constructor(container: HTMLElement, options: IOptions = {}) { super(container, { compName: 'dom-viewer' }, options) @@ -69,6 +70,8 @@ export default class DomViewer extends Component { hotkey: true, }) + this.isShadowRoot = isShadowRoot(this.options.node) + this.initTpl() this.bindEvent() if (!this.options.isEndTag) { @@ -177,13 +180,15 @@ export default class DomViewer extends Component { const { $tag, c } = this const { node } = this.options - $tag.html( - this.renderHtmlTag({ - ...getHtmlTagData(node as HTMLElement), - hasTail: false, - hasToggleButton: true, - }) - ) + if (!this.isShadowRoot) { + $tag.html( + this.renderHtmlTag({ + ...getHtmlTagData(node as HTMLElement), + hasTail: false, + hasToggleButton: true, + }) + ) + } $tag.addClass(c('expanded')) this.$children.rmClass(c('hidden')) } @@ -192,13 +197,15 @@ export default class DomViewer extends Component { const { node } = this.options this.$children.addClass(c('hidden')) - this.$tag.html( - this.renderHtmlTag({ - ...getHtmlTagData(node as HTMLElement), - hasTail: true, - hasToggleButton: true, - }) - ) + if (!this.isShadowRoot) { + this.$tag.html( + this.renderHtmlTag({ + ...getHtmlTagData(node as HTMLElement), + hasTail: true, + hasToggleButton: true, + }) + ) + } $tag.rmClass(c('expanded')) } private initObserver() { @@ -232,12 +239,17 @@ export default class DomViewer extends Component { this.isExpanded ? this.renderExpandTag() : this.renderCollapseTag() } else { this.$children.addClass(c('hidden')) - $tag.html( - this.renderHtmlTag({ - ...getHtmlTagData(node as HTMLElement), - hasTail: false, - }) - ) + this.isExpanded = false + if (this.isShadowRoot) { + $tag.html(this.renderShadowRoot(false)) + } else { + $tag.html( + this.renderHtmlTag({ + ...getHtmlTagData(node as HTMLElement), + hasTail: false, + }) + ) + } } } else if (mutation.type === 'characterData') { if (node.nodeType === Node.TEXT_NODE) { @@ -251,7 +263,7 @@ export default class DomViewer extends Component { const { c, $tag } = this const { node } = this.options - if (node.nodeType === Node.ELEMENT_NODE) { + if (node.nodeType === Node.ELEMENT_NODE || this.isShadowRoot) { $tag.on('click', c('.toggle'), (e: any) => { e.stopPropagation() this.toggle() @@ -353,9 +365,11 @@ export default class DomViewer extends Component { private isExpandable() { const { node } = this.options - return ( - node.nodeType === Node.ELEMENT_NODE && this.getChildNodes().length > 0 - ) + if (node.nodeType !== Node.ELEMENT_NODE && !this.isShadowRoot) { + return false + } + + return this.getChildNodes().length > 0 } private getChildNodes() { const { rootContainer, ignore } = this.options @@ -373,6 +387,11 @@ export default class DomViewer extends Component { } return child !== rootContainer && !ignore(child) }) + if (node.shadowRoot) { + childNodes.unshift(node.shadowRoot) + } else if ((node as any).chobitsuShadowRoot) { + childNodes.unshift((node as any).chobitsuShadowRoot) + } return childNodes } private initTpl() { @@ -399,6 +418,9 @@ export default class DomViewer extends Component { hasToggleButton: isExpandable, } $tag.html(this.renderHtmlTag(data)) + } else if (isShadowRoot(node)) { + const isExpandable = this.isExpandable() + $tag.html(this.renderShadowRoot(isExpandable)) } else if (node.nodeType === Node.TEXT_NODE) { $tag.html(this.renderTextNode(node)) } else if (node.nodeType === Node.COMMENT_NODE) { @@ -412,7 +434,7 @@ export default class DomViewer extends Component { container.appendChild($tag.get(0)) - if (node.nodeType === node.ELEMENT_NODE) { + if (node.nodeType === node.ELEMENT_NODE || this.isShadowRoot) { const $children = $(h('ul')) $children.addClass([c('children'), c('hidden')]) container.appendChild($children.get(0)) @@ -465,7 +487,7 @@ export default class DomViewer extends Component { } }) - if (node) { + if (node && !this.isShadowRoot) { if (this.endTagDomViewer) { this.endTagDomViewer.attach() } else { @@ -506,15 +528,11 @@ export default class DomViewer extends Component { tail = `</${data.tagName}>` } - let toggle = '' - if (data.hasToggleButton) { - toggle = - '
' - } - return this.c(stripIndent` - ${toggle} - <${data.tagName}${attributes}>${tail} + ${data.hasToggleButton ? this.renderToggle() : ''} + <${ + data.tagName + }${attributes}>${tail} `) } private renderTextNode(node: ChildNode) { @@ -553,6 +571,17 @@ export default class DomViewer extends Component { )} -->` ) } + private renderShadowRoot(hasToggle: boolean) { + const { node } = this.options + + return this.c(stripIndent` + ${hasToggle ? this.renderToggle() : ''} + #shadow-root (${(node as any).mode}) + `) + } + private renderToggle() { + return '
' + } } interface IAttribute { @@ -611,6 +640,14 @@ function isUrlAttribute(el: HTMLElement, name: string) { return false } +function isShadowRoot(node: any) { + if (window.ShadowRoot) { + return node instanceof ShadowRoot + } + + return false +} + if (typeof module !== 'undefined') { exportCjs(module, DomViewer) } diff --git a/src/dom-viewer/package.json b/src/dom-viewer/package.json index 1f89375..010a31e 100644 --- a/src/dom-viewer/package.json +++ b/src/dom-viewer/package.json @@ -1,6 +1,6 @@ { "name": "dom-viewer", - "version": "1.3.0", + "version": "1.4.0", "description": "Dom tree navigator", "luna": { "icon": true diff --git a/src/dom-viewer/story.js b/src/dom-viewer/story.js index 780569a..9e5bcff 100644 --- a/src/dom-viewer/story.js +++ b/src/dom-viewer/story.js @@ -1,4 +1,5 @@ import 'luna-dom-viewer.css' +import h from 'licia/h' import DomViewer from 'luna-dom-viewer.js' import story from '../share/story' import readme from './README.md' @@ -6,7 +7,12 @@ import changelog from './CHANGELOG.md' const def = story( 'dom-viewer', - (container) => { + (wrapper) => { + const test = h('div') + const root = test.attachShadow({ mode: 'open' }) + root.innerHTML = `Shadow DOM` + + const container = h('div') const domViewer = new DomViewer(container, { ignore(node) { if (node.tagName === 'STYLE') { @@ -17,6 +23,9 @@ const def = story( }) domViewer.expand() + wrapper.appendChild(test) + wrapper.appendChild(container) + return domViewer }, {