mirror of
https://github.com/mathuo/dockview
synced 2025-02-13 03:45:47 +00:00
bug: disable iframes within shadowdom during dnd
This commit is contained in:
parent
429177436e
commit
a4b9255f43
@ -112,8 +112,11 @@ export function isAncestor(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getElementsByTagName(tag: string): HTMLElement[] {
|
export function getElementsByTagName(
|
||||||
return Array.prototype.slice.call(document.getElementsByTagName(tag), 0);
|
tag: string,
|
||||||
|
document: ParentNode
|
||||||
|
): HTMLElement[] {
|
||||||
|
return Array.prototype.slice.call(document.querySelectorAll(tag), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFocusTracker extends IDisposable {
|
export interface IFocusTracker extends IDisposable {
|
||||||
@ -288,10 +291,29 @@ export function addTestId(element: HTMLElement, id: string): void {
|
|||||||
element.setAttribute('data-testid', id);
|
element.setAttribute('data-testid', id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function disableIframePointEvents() {
|
export function disableIframePointEvents(rootNode: ParentNode = document) {
|
||||||
|
const includeShadowDom = true;
|
||||||
|
|
||||||
|
const shadowRoots = [];
|
||||||
|
|
||||||
|
if (includeShadowDom) {
|
||||||
|
const items = rootNode.querySelectorAll('*');
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i];
|
||||||
|
if (item.shadowRoot) {
|
||||||
|
shadowRoots.push(item.shadowRoot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const iframes: HTMLElement[] = [
|
const iframes: HTMLElement[] = [
|
||||||
...getElementsByTagName('iframe'),
|
...getElementsByTagName('iframe', rootNode),
|
||||||
...getElementsByTagName('webview'),
|
...getElementsByTagName('webview', rootNode),
|
||||||
|
...shadowRoots.flatMap((root) => [
|
||||||
|
...getElementsByTagName('iframe', root),
|
||||||
|
...getElementsByTagName('webview', root),
|
||||||
|
]),
|
||||||
];
|
];
|
||||||
|
|
||||||
const original = new WeakMap<HTMLElement, string>(); // don't hold onto HTMLElement references longer than required
|
const original = new WeakMap<HTMLElement, string>(); // don't hold onto HTMLElement references longer than required
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
DockviewApi,
|
DockviewApi,
|
||||||
} from 'dockview';
|
} from 'dockview';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import * as ReactDOM from 'react-dom/client';
|
||||||
import './app.scss';
|
import './app.scss';
|
||||||
import { defaultConfig } from './defaultLayout';
|
import { defaultConfig } from './defaultLayout';
|
||||||
import { GridActions } from './gridActions';
|
import { GridActions } from './gridActions';
|
||||||
@ -30,6 +31,20 @@ const Option = (props: {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ShadowIframe = (props: IDockviewPanelProps) => {
|
||||||
|
return (
|
||||||
|
<iframe
|
||||||
|
onMouseDown={() => {
|
||||||
|
if (!props.api.isActive) {
|
||||||
|
props.api.setActive();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{ border: 'none', width: '100%', height: '100%' }}
|
||||||
|
src="https://dockview.dev"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
default: (props: IDockviewPanelProps) => {
|
default: (props: IDockviewPanelProps) => {
|
||||||
const isDebug = React.useContext(DebugContext);
|
const isDebug = React.useContext(DebugContext);
|
||||||
@ -105,6 +120,7 @@ const components = {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
|
border: 'none',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
}}
|
}}
|
||||||
@ -112,6 +128,33 @@ const components = {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
shadowDom: (props: IDockviewPanelProps) => {
|
||||||
|
const ref = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!ref.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shadow = ref.current.attachShadow({
|
||||||
|
mode: 'open',
|
||||||
|
});
|
||||||
|
|
||||||
|
const shadowRoot = document.createElement('div');
|
||||||
|
shadowRoot.style.height = '100%';
|
||||||
|
shadow.appendChild(shadowRoot);
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(shadowRoot);
|
||||||
|
|
||||||
|
root.render(<ShadowIframe {...props} />);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
root.unmount();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <div style={{ height: '100%' }} ref={ref}></div>;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const headerComponents = {
|
const headerComponents = {
|
||||||
@ -208,7 +251,7 @@ const DockviewDemo = (props: { theme?: string }) => {
|
|||||||
|
|
||||||
event.api.onDidMaximizedGroupChange((event) => {
|
event.api.onDidMaximizedGroupChange((event) => {
|
||||||
addLogLine(
|
addLogLine(
|
||||||
`Group Maximized Changed ${event.view.id} [${event.isMaximized}]`
|
`Group Maximized Changed ${event.group.id} [${event.isMaximized}]`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,7 +132,10 @@ export const GridActions = (props: {
|
|||||||
|
|
||||||
const popover = usePopover();
|
const popover = usePopover();
|
||||||
|
|
||||||
const onAddPanel = (options?: { advanced: boolean }) => {
|
const onAddPanel = (options?: {
|
||||||
|
advanced: boolean;
|
||||||
|
component?: string;
|
||||||
|
}) => {
|
||||||
if (options?.advanced) {
|
if (options?.advanced) {
|
||||||
popover.open(({ close }) => {
|
popover.open(({ close }) => {
|
||||||
return <PanelBuilder api={props.api!} done={close} />;
|
return <PanelBuilder api={props.api!} done={close} />;
|
||||||
@ -140,7 +143,7 @@ export const GridActions = (props: {
|
|||||||
} else {
|
} else {
|
||||||
props.api?.addPanel({
|
props.api?.addPanel({
|
||||||
id: `id_${Date.now().toString()}`,
|
id: `id_${Date.now().toString()}`,
|
||||||
component: 'default',
|
component: options?.component ?? 'default',
|
||||||
title: `Tab ${nextId()}`,
|
title: `Tab ${nextId()}`,
|
||||||
renderer: 'always',
|
renderer: 'always',
|
||||||
});
|
});
|
||||||
@ -170,6 +173,22 @@ export const GridActions = (props: {
|
|||||||
<span className="material-symbols-outlined">tune</span>
|
<span className="material-symbols-outlined">tune</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="button-group">
|
||||||
|
<button
|
||||||
|
className="text-button"
|
||||||
|
onClick={() =>
|
||||||
|
onAddPanel({ component: 'shadowDom', advanced: false })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Add Panel 2
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => onAddPanel({ advanced: true })}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">tune</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<button className="text-button" onClick={onAddGroup}>
|
<button className="text-button" onClick={onAddGroup}>
|
||||||
Add Group
|
Add Group
|
||||||
</button>
|
</button>
|
||||||
|
@ -75,9 +75,9 @@ const PanelAction = (props: {
|
|||||||
const panel = props.api.getPanel(props.panelId);
|
const panel = props.api.getPanel(props.panelId);
|
||||||
if (panel) {
|
if (panel) {
|
||||||
props.api.addFloatingGroup(panel, {
|
props.api.addFloatingGroup(panel, {
|
||||||
position: {
|
|
||||||
width: 400,
|
width: 400,
|
||||||
height: 300,
|
height: 300,
|
||||||
|
position: {
|
||||||
bottom: 50,
|
bottom: 50,
|
||||||
right: 50,
|
right: 50,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user