UNPKG

dockview

Version:

Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support

1,326 lines (1,312 loc) 283 kB
/** * dockview * @version 1.0.0 * @link https://github.com/mathuo/dockview * @license MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('react-dom')) : typeof define === 'function' && define.amd ? define(['exports', 'react', 'react-dom'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.dockview = {}, global.React, global.ReactDOM)); })(this, (function (exports, React, ReactDOM) { 'use strict'; function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespace(React); var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM); function runFootnote() { var _a, _b; const DOCKVIEW_SUPPRESS_WATERMARK = 'DOCKVIEW_WATERMARK_SUPPRESSED'; const isTest = ((_b = (_a = window.process) === null || _a === void 0 ? void 0 : _a.env) === null || _b === void 0 ? void 0 : _b.NODE_ENV) === 'test'; if (isTest) { return; // don't spam people tests } const isSuppressed = !!window[DOCKVIEW_SUPPRESS_WATERMARK]; if (!isSuppressed) { console.log([ 'dockview: https://github.com/mathuo/dockview for examples and documentation', 'dockview: https://www.npmjs.com/package/dockview', `dockview: To suppress this message set window.${DOCKVIEW_SUPPRESS_WATERMARK}=1 before importing the dockview package`, '', ].join('\n')); } } runFootnote(); exports.Event = void 0; (function (Event) { Event.any = (...children) => { return (listener) => { const disposables = children.map((child) => child(listener)); return { dispose: () => { disposables.forEach((d) => { d.dispose(); }); }, }; }; }; })(exports.Event || (exports.Event = {})); // dumb event emitter with better typings than nodes event emitter // https://github.com/microsoft/vscode/blob/master/src/vs/base/common/event.ts class Emitter { constructor(options) { this.options = options; this._listeners = []; this._disposed = false; } get event() { if (!this._event) { this._event = (listener) => { var _a; if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.replay) && this._last !== undefined) { listener(this._last); } this._listeners.length === 0; this._listeners.push(listener); return { dispose: () => { const index = this._listeners.indexOf(listener); if (index > -1) { this._listeners.splice(index, 1); } }, }; }; } return this._event; } fire(e) { this._last = e; this._listeners.forEach((listener) => { listener(e); }); } dispose() { this._listeners = []; this._disposed = true; } } function addDisposableWindowListener(element, type, listener, options) { element.addEventListener(type, listener, options); return { dispose: () => { element.removeEventListener(type, listener); }, }; } function addDisposableListener(element, type, listener, options) { element.addEventListener(type, listener, options); return { dispose: () => { element.removeEventListener(type, listener); }, }; } exports.Disposable = void 0; (function (Disposable) { Disposable.NONE = { dispose: () => { // noop }, }; })(exports.Disposable || (exports.Disposable = {})); class CompositeDisposable { constructor(...args) { this.disposables = args; } static from(...args) { return new CompositeDisposable(...args); } addDisposables(...args) { args === null || args === void 0 ? void 0 : args.forEach((arg) => this.disposables.push(arg)); } dispose() { this.disposables.forEach((arg) => arg.dispose()); } } class MutableDisposable { constructor() { this._disposable = exports.Disposable.NONE; } set value(disposable) { if (this._disposable) { this._disposable.dispose(); } this._disposable = disposable; } dispose() { if (this._disposable) { this._disposable.dispose(); } } } function tryParseJSON(text, reviver) { try { return JSON.parse(text, reviver); } catch (err) { console.warn('failed to parse JSON'); return undefined; } } class TransferObject { constructor() { // } } class PanelTransfer extends TransferObject { constructor(viewId, groupId, panelId) { super(); this.viewId = viewId; this.groupId = groupId; this.panelId = panelId; } } class PaneTransfer extends TransferObject { constructor(viewId, paneId) { super(); this.viewId = viewId; this.paneId = paneId; } } const DATA_KEY = 'splitview/transfer'; const isPanelTransferEvent = (event) => { if (!event.dataTransfer) { return false; } return event.dataTransfer.types.includes(DATA_KEY); }; exports.DragType = void 0; (function (DragType) { DragType["DOCKVIEW_TAB"] = "dockview_tab"; DragType["EXTERNAL"] = "external_group_drag"; })(exports.DragType || (exports.DragType = {})); /** * Determine whether this data belong to that of an event that was started by * dragging a tab component */ const isTabDragEvent = (data) => { return data.type === exports.DragType.DOCKVIEW_TAB; }; /** * Determine whether this data belong to that of an event that was started by * a custom drag-enable component */ const isCustomDragEvent = (data) => { return data.type === exports.DragType.EXTERNAL; }; const extractData = (event) => { if (!event.dataTransfer) { return null; } const data = tryParseJSON(event.dataTransfer.getData(DATA_KEY)); if (!data) { console.warn(`[dragEvent] ${DATA_KEY} data is missing`); } if (typeof data.type !== 'string') { console.warn(`[dragEvent] invalid type ${data.type}`); } return data; }; /** * A singleton to store transfer data during drag & drop operations that are only valid within the application. */ class LocalSelectionTransfer { constructor() { // protect against external instantiation } static getInstance() { return LocalSelectionTransfer.INSTANCE; } hasData(proto) { return proto && proto === this.proto; } clearData(proto) { if (this.hasData(proto)) { this.proto = undefined; this.data = undefined; } } getData(proto) { if (this.hasData(proto)) { return this.data; } return undefined; } setData(data, proto) { if (proto) { this.data = data; this.proto = proto; } } } LocalSelectionTransfer.INSTANCE = new LocalSelectionTransfer(); function getPanelData() { const panelTransfer = LocalSelectionTransfer.getInstance(); const isPanelEvent = panelTransfer.hasData(PanelTransfer.prototype); if (!isPanelEvent) { return undefined; } return panelTransfer.getData(PanelTransfer.prototype)[0]; } function getPaneData() { const paneTransfer = LocalSelectionTransfer.getInstance(); const isPanelEvent = paneTransfer.hasData(PaneTransfer.prototype); if (!isPanelEvent) { return undefined; } return paneTransfer.getData(PaneTransfer.prototype)[0]; } class SplitviewApi { constructor(component) { this.component = component; } get minimumSize() { return this.component.minimumSize; } get maximumSize() { return this.component.maximumSize; } get height() { return this.component.height; } get width() { return this.component.width; } get length() { return this.component.length; } get onDidLayoutChange() { return this.component.onDidLayoutChange; } get orientation() { return this.component.orientation; } updateOptions(options) { this.component.updateOptions(options); } removePanel(panel, sizing) { this.component.removePanel(panel, sizing); } setVisible(panel, isVisible) { this.component.setVisible(panel, isVisible); } getPanels() { return this.component.getPanels(); } focus() { this.component.focus(); } getPanel(id) { return this.component.getPanel(id); } setActive(panel) { this.component.setActive(panel); } layout(width, height) { return this.component.layout(width, height); } addPanel(options) { this.component.addPanel(options); } resizeToFit() { this.component.resizeToFit(); } movePanel(from, to) { this.component.movePanel(from, to); } fromJSON(data, deferComponentLayout) { this.component.fromJSON(data, deferComponentLayout); } toJSON() { return this.component.toJSON(); } } class PaneviewApi { constructor(component) { this.component = component; } get width() { return this.component.width; } get height() { return this.component.height; } get minimumSize() { return this.component.minimumSize; } get maximumSize() { return this.component.maximumSize; } get onDidLayoutChange() { return this.component.onDidLayoutChange; } getPanels() { return this.component.getPanels(); } removePanel(panel) { this.component.removePanel(panel); } getPanel(id) { return this.component.getPanel(id); } movePanel(from, to) { this.component.movePanel(from, to); } focus() { this.component.focus(); } layout(width, height) { this.component.layout(width, height); } addPanel(options) { return this.component.addPanel(options); } resizeToFit() { this.component.resizeToFit(); } fromJSON(data, deferComponentLayout) { this.component.fromJSON(data, deferComponentLayout); } toJSON() { return this.component.toJSON(); } } class GridviewApi { constructor(component) { this.component = component; } get width() { return this.component.width; } get height() { return this.component.height; } get minimumHeight() { return this.component.minimumHeight; } get maximumHeight() { return this.component.maximumHeight; } get minimumWidth() { return this.component.minimumWidth; } get maximumWidth() { return this.component.maximumWidth; } get onGridEvent() { return this.component.onGridEvent; } get onDidLayoutChange() { return this.component.onDidLayoutChange; } get panels() { return this.component.groups; } get orientation() { return this.component.orientation; } set orientation(value) { this.component.updateOptions({ orientation: value }); } focus() { this.component.focus(); } layout(width, height, force = false) { this.component.layout(width, height, force); } addPanel(options) { this.component.addPanel(options); } removePanel(panel, sizing) { this.component.removePanel(panel, sizing); } movePanel(panel, options) { this.component.movePanel(panel, options); } resizeToFit() { this.component.resizeToFit(); } getPanel(id) { return this.component.getPanel(id); } toggleVisibility(panel) { this.component.toggleVisibility(panel); } setVisible(panel, visible) { this.component.setVisible(panel, visible); } setActive(panel) { this.component.setActive(panel); } fromJSON(data, deferComponentLayout) { return this.component.fromJSON(data, deferComponentLayout); } toJSON() { return this.component.toJSON(); } } class DockviewApi { constructor(component) { this.component = component; } get width() { return this.component.width; } get height() { return this.component.height; } get minimumHeight() { return this.component.minimumHeight; } get maximumHeight() { return this.component.maximumHeight; } get minimumWidth() { return this.component.minimumWidth; } get maximumWidth() { return this.component.maximumWidth; } get size() { return this.component.size; } get totalPanels() { return this.component.totalPanels; } get onGridEvent() { return this.component.onGridEvent; } get onDidLayoutChange() { return this.component.onDidLayoutChange; } get panels() { return this.component.panels; } get groups() { return this.component.groups; } get activePanel() { return this.component.activePanel; } get activeGroup() { return this.component.activeGroup; } getTabHeight() { return this.component.tabHeight; } setTabHeight(height) { this.component.tabHeight = height; } focus() { this.component.focus(); } getPanel(id) { return this.component.getGroupPanel(id); } setActivePanel(panel) { this.component.setActivePanel(panel); } layout(width, height, force = false) { this.component.layout(width, height, force); } addPanel(options) { return this.component.addPanel(options); } removePanel(panel) { this.component.removePanel(panel); } addEmptyGroup(options) { this.component.addEmptyGroup(options); } moveToNext(options) { this.component.moveToNext(options); } moveToPrevious(options) { this.component.moveToPrevious(options); } closeAllGroups() { return this.component.closeAllGroups(); } removeGroup(group) { this.component.removeGroup(group); } resizeToFit() { return this.component.resizeToFit(); } getGroup(id) { return this.component.getPanel(id); } fromJSON(data) { this.component.fromJSON(data); } toJSON() { return this.component.toJSON(); } } function watchElementResize(element, cb) { const observer = new ResizeObserver((entires) => { const firstEntry = entires[0]; cb(firstEntry); }); observer.observe(element); return { dispose: () => { observer.unobserve(element); observer.disconnect(); }, }; } const removeClasses = (element, ...classes) => { for (const classname of classes) { if (element.classList.contains(classname)) { element.classList.remove(classname); } } }; const addClasses = (element, ...classes) => { for (const classname of classes) { if (!element.classList.contains(classname)) { element.classList.add(classname); } } }; const toggleClass = (element, className, isToggled) => { const hasClass = element.classList.contains(className); if (isToggled && !hasClass) { element.classList.add(className); } if (!isToggled && hasClass) { element.classList.remove(className); } }; function isAncestor(testChild, testAncestor) { while (testChild) { if (testChild === testAncestor) { return true; } testChild = testChild.parentNode; } return false; } function getElementsByTagName(tag) { return Array.prototype.slice.call(document.getElementsByTagName(tag), 0); } function trackFocus(element) { return new FocusTracker(element); } /** * Track focus on an element. Ensure tabIndex is set when an HTMLElement is not focusable by default */ class FocusTracker extends CompositeDisposable { constructor(element) { super(); this._onDidFocus = new Emitter(); this.onDidFocus = this._onDidFocus.event; this._onDidBlur = new Emitter(); this.onDidBlur = this._onDidBlur.event; let hasFocus = isAncestor(document.activeElement, element); let loosingFocus = false; const onFocus = () => { loosingFocus = false; if (!hasFocus) { hasFocus = true; this._onDidFocus.fire(); } }; const onBlur = () => { if (hasFocus) { loosingFocus = true; window.setTimeout(() => { if (loosingFocus) { loosingFocus = false; hasFocus = false; this._onDidBlur.fire(); } }, 0); } }; this._refreshStateHandler = () => { const currentNodeHasFocus = isAncestor(document.activeElement, element); if (currentNodeHasFocus !== hasFocus) { if (hasFocus) { onBlur(); } else { onFocus(); } } }; if (element instanceof HTMLElement) { this.addDisposables(addDisposableListener(element, 'focus', onFocus, true)); this.addDisposables(addDisposableListener(element, 'blur', onBlur, true)); } else { this.addDisposables(addDisposableWindowListener(element, 'focus', onFocus, true)); this.addDisposables(addDisposableWindowListener(element, 'blur', onBlur, true)); } } refreshState() { this._refreshStateHandler(); } dispose() { super.dispose(); this._onDidBlur.dispose(); this._onDidFocus.dispose(); } } const clamp = (value, min, max) => { if (min > max) { throw new Error(`${min} > ${max} is an invalid condition`); } return Math.min(max, Math.max(value, min)); }; const sequentialNumberGenerator = () => { let value = 1; return { next: () => (value++).toString() }; }; function tail(arr) { if (arr.length === 0) { throw new Error('Invalid tail call'); } return [arr.slice(0, arr.length - 1), arr[arr.length - 1]]; } function last(arr) { return arr.length > 0 ? arr[arr.length - 1] : undefined; } function sequenceEquals(arr1, arr2) { if (arr1.length !== arr2.length) { return false; } for (let i = 0; i < arr1.length; i++) { if (arr1[i] !== arr2[i]) { return false; } } return true; } /** * Pushes an element to the start of the array, if found. */ function pushToStart(arr, value) { const index = arr.indexOf(value); if (index > -1) { arr.splice(index, 1); arr.unshift(value); } } /** * Pushes an element to the end of the array, if found. */ function pushToEnd(arr, value) { const index = arr.indexOf(value); if (index > -1) { arr.splice(index, 1); arr.push(value); } } const range = (from, to) => { const result = []; if (typeof to !== 'number') { to = from; from = 0; } if (from <= to) { for (let i = from; i < to; i++) { result.push(i); } } else { for (let i = from; i > to; i--) { result.push(i); } } return result; }; function firstIndex(array, fn) { for (let i = 0; i < array.length; i++) { const element = array[i]; if (fn(element)) { return i; } } return -1; } class ViewItem { constructor(container, view, size, disposable) { this.container = container; this.view = view; this.disposable = disposable; this._cachedVisibleSize = undefined; if (typeof size === 'number') { this._size = size; this._cachedVisibleSize = undefined; container.classList.add('visible'); } else { this._size = 0; this._cachedVisibleSize = size.cachedVisibleSize; } } set size(size) { this._size = size; } get size() { return this._size; } get cachedVisibleSize() { return this._cachedVisibleSize; } get visible() { return typeof this._cachedVisibleSize === 'undefined'; } setVisible(visible, size) { var _a; if (visible === this.visible) { return; } if (visible) { this.size = clamp((_a = this._cachedVisibleSize) !== null && _a !== void 0 ? _a : 0, this.viewMinimumSize, this.viewMaximumSize); this._cachedVisibleSize = undefined; } else { this._cachedVisibleSize = typeof size === 'number' ? size : this.size; this.size = 0; } this.container.classList.toggle('visible', visible); if (this.view.setVisible) { this.view.setVisible(visible); } } get minimumSize() { return this.visible ? this.view.minimumSize : 0; } get viewMinimumSize() { return this.view.minimumSize; } get maximumSize() { return this.visible ? this.view.maximumSize : 0; } get viewMaximumSize() { return this.view.maximumSize; } get priority() { return this.view.priority; } get snap() { return !!this.view.snap; } set enabled(enabled) { this.container.style.pointerEvents = enabled ? '' : 'none'; } // layout(offset: number, layoutContext: TLayoutContext | undefined): void { // this.layoutContainer(offset); // this.view.layout(this.size, offset, layoutContext); // } // abstract layoutContainer(offset: number): void; dispose() { this.disposable.dispose(); return this.view; } } /*--------------------------------------------------------------------------------------------- * Accreditation: This file is largly based upon the MIT licenced VSCode sourcecode found at: * https://github.com/microsoft/vscode/tree/main/src/vs/base/browser/ui/splitview *--------------------------------------------------------------------------------------------*/ exports.Orientation = void 0; (function (Orientation) { Orientation["HORIZONTAL"] = "HORIZONTAL"; Orientation["VERTICAL"] = "VERTICAL"; })(exports.Orientation || (exports.Orientation = {})); exports.SashState = void 0; (function (SashState) { SashState[SashState["MAXIMUM"] = 0] = "MAXIMUM"; SashState[SashState["MINIMUM"] = 1] = "MINIMUM"; SashState[SashState["DISABLED"] = 2] = "DISABLED"; SashState[SashState["ENABLED"] = 3] = "ENABLED"; })(exports.SashState || (exports.SashState = {})); exports.LayoutPriority = void 0; (function (LayoutPriority) { LayoutPriority["Low"] = "low"; LayoutPriority["High"] = "high"; LayoutPriority["Normal"] = "normal"; })(exports.LayoutPriority || (exports.LayoutPriority = {})); exports.Sizing = void 0; (function (Sizing) { Sizing.Distribute = { type: 'distribute' }; function Split(index) { return { type: 'split', index }; } Sizing.Split = Split; function Invisible(cachedVisibleSize) { return { type: 'invisible', cachedVisibleSize }; } Sizing.Invisible = Invisible; })(exports.Sizing || (exports.Sizing = {})); class Splitview { constructor(container, options) { this.container = container; this.views = []; this.sashes = []; this._size = 0; this._orthogonalSize = 0; this.contentSize = 0; this._proportions = undefined; this._onDidSashEnd = new Emitter(); this.onDidSashEnd = this._onDidSashEnd.event; this._onDidAddView = new Emitter(); this.onDidAddView = this._onDidAddView.event; this._onDidRemoveView = new Emitter(); this.onDidRemoveView = this._onDidAddView.event; this._startSnappingEnabled = true; this._endSnappingEnabled = true; this.resize = (index, delta, sizes = this.views.map((x) => x.size), lowPriorityIndexes, highPriorityIndexes, overloadMinDelta = Number.NEGATIVE_INFINITY, overloadMaxDelta = Number.POSITIVE_INFINITY, snapBefore, snapAfter) => { if (index < 0 || index > this.views.length) { return 0; } const upIndexes = range(index, -1); const downIndexes = range(index + 1, this.views.length); // if (highPriorityIndexes) { for (const i of highPriorityIndexes) { pushToStart(upIndexes, i); pushToStart(downIndexes, i); } } if (lowPriorityIndexes) { for (const i of lowPriorityIndexes) { pushToEnd(upIndexes, i); pushToEnd(downIndexes, i); } } // const upItems = upIndexes.map((i) => this.views[i]); const upSizes = upIndexes.map((i) => sizes[i]); // const downItems = downIndexes.map((i) => this.views[i]); const downSizes = downIndexes.map((i) => sizes[i]); // const minDeltaUp = upIndexes.reduce((_, i) => _ + this.views[i].minimumSize - sizes[i], 0); const maxDeltaUp = upIndexes.reduce((_, i) => _ + this.views[i].maximumSize - sizes[i], 0); // const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((_, i) => _ + sizes[i] - this.views[i].minimumSize, 0); const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((_, i) => _ + sizes[i] - this.views[i].maximumSize, 0); // const minDelta = Math.max(minDeltaUp, minDeltaDown); const maxDelta = Math.min(maxDeltaDown, maxDeltaUp); // let snapped = false; if (snapBefore) { const snapView = this.views[snapBefore.index]; const visible = delta >= snapBefore.limitDelta; snapped = visible !== snapView.visible; snapView.setVisible(visible, snapBefore.size); } if (!snapped && snapAfter) { const snapView = this.views[snapAfter.index]; const visible = delta < snapAfter.limitDelta; snapped = visible !== snapView.visible; snapView.setVisible(visible, snapAfter.size); } if (snapped) { return this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta); } // const tentativeDelta = clamp(delta, minDelta, maxDelta); let actualDelta = 0; // let deltaUp = tentativeDelta; for (let i = 0; i < upItems.length; i++) { const item = upItems[i]; const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize); const viewDelta = size - upSizes[i]; actualDelta += viewDelta; deltaUp -= viewDelta; item.size = size; } // let deltaDown = actualDelta; for (let i = 0; i < downItems.length; i++) { const item = downItems[i]; const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize); const viewDelta = size - downSizes[i]; deltaDown += viewDelta; item.size = size; } // return delta; }; this._orientation = options.orientation; this.element = this.createContainer(); this.proportionalLayout = options.proportionalLayout === undefined ? true : !!options.proportionalLayout; this.viewContainer = this.createViewContainer(); this.sashContainer = this.createSashContainer(); this.element.appendChild(this.sashContainer); this.element.appendChild(this.viewContainer); this.container.appendChild(this.element); this.style(options.styles); // We have an existing set of view, add them now if (options.descriptor) { this._size = options.descriptor.size; options.descriptor.views.forEach((viewDescriptor, index) => { const sizing = viewDescriptor.visible === undefined || viewDescriptor.visible ? viewDescriptor.size : { type: 'invisible', cachedVisibleSize: viewDescriptor.size, }; const view = viewDescriptor.view; this.addView(view, sizing, index, true // true skip layout ); }); // Initialize content size and proportions for first layout this.contentSize = this.views.reduce((r, i) => r + i.size, 0); this.saveProportions(); } } get size() { return this._size; } set size(value) { this._size = value; } get orthogonalSize() { return this._orthogonalSize; } set orthogonalSize(value) { this._orthogonalSize = value; } get length() { return this.views.length; } get proportions() { return this._proportions ? [...this._proportions] : undefined; } get orientation() { return this._orientation; } set orientation(value) { this._orientation = value; const tmp = this.size; this.size = this.orthogonalSize; this.orthogonalSize = tmp; removeClasses(this.element, 'horizontal', 'vertical'); this.element.classList.add(this.orientation == exports.Orientation.HORIZONTAL ? 'horizontal' : 'vertical'); } get minimumSize() { return this.views.reduce((r, item) => r + item.minimumSize, 0); } get maximumSize() { return this.length === 0 ? Number.POSITIVE_INFINITY : this.views.reduce((r, item) => r + item.maximumSize, 0); } get startSnappingEnabled() { return this._startSnappingEnabled; } set startSnappingEnabled(startSnappingEnabled) { if (this._startSnappingEnabled === startSnappingEnabled) { return; } this._startSnappingEnabled = startSnappingEnabled; this.updateSashEnablement(); } get endSnappingEnabled() { return this._endSnappingEnabled; } set endSnappingEnabled(endSnappingEnabled) { if (this._endSnappingEnabled === endSnappingEnabled) { return; } this._endSnappingEnabled = endSnappingEnabled; this.updateSashEnablement(); } style(styles) { if ((styles === null || styles === void 0 ? void 0 : styles.separatorBorder) === 'transparent') { removeClasses(this.element, 'separator-border'); this.element.style.removeProperty('--dv-separator-border'); } else { addClasses(this.element, 'separator-border'); if (styles === null || styles === void 0 ? void 0 : styles.separatorBorder) { this.element.style.setProperty('--dv-separator-border', styles.separatorBorder); } } } isViewVisible(index) { if (index < 0 || index >= this.views.length) { throw new Error('Index out of bounds'); } const viewItem = this.views[index]; return viewItem.visible; } setViewVisible(index, visible) { if (index < 0 || index >= this.views.length) { throw new Error('Index out of bounds'); } toggleClass(this.container, 'visible', visible); const viewItem = this.views[index]; toggleClass(this.container, 'visible', visible); viewItem.setVisible(visible, viewItem.size); this.distributeEmptySpace(index); this.layoutViews(); this.saveProportions(); } getViewSize(index) { if (index < 0 || index >= this.views.length) { return -1; } return this.views[index].size; } resizeView(index, size) { if (index < 0 || index >= this.views.length) { return; } const indexes = range(this.views.length).filter((i) => i !== index); const lowPriorityIndexes = [ ...indexes.filter((i) => this.views[i].priority === exports.LayoutPriority.Low), index, ]; const highPriorityIndexes = indexes.filter((i) => this.views[i].priority === exports.LayoutPriority.High); const item = this.views[index]; size = Math.round(size); size = clamp(size, item.minimumSize, Math.min(item.maximumSize, this._size)); item.size = size; this.relayout(lowPriorityIndexes, highPriorityIndexes); } getViews() { return this.views.map((x) => x.view); } onDidChange(item, size) { const index = this.views.indexOf(item); if (index < 0 || index >= this.views.length) { return; } size = typeof size === 'number' ? size : item.size; size = clamp(size, item.minimumSize, item.maximumSize); item.size = size; this.relayout([index]); } addView(view, size = { type: 'distribute' }, index = this.views.length, skipLayout) { const container = document.createElement('div'); container.className = 'view'; container.appendChild(view.element); let viewSize; if (typeof size === 'number') { viewSize = size; } else if (size.type === 'split') { viewSize = this.getViewSize(size.index) / 2; } else if (size.type === 'invisible') { viewSize = { cachedVisibleSize: size.cachedVisibleSize }; } else { viewSize = view.minimumSize; } const disposable = view.onDidChange((newSize) => this.onDidChange(viewItem, newSize)); const dispose = () => { disposable === null || disposable === void 0 ? void 0 : disposable.dispose(); this.viewContainer.removeChild(container); }; const viewItem = new ViewItem(container, view, viewSize, { dispose }); if (index === this.views.length) { this.viewContainer.appendChild(container); } else { this.viewContainer.insertBefore(container, this.viewContainer.children.item(index)); } this.views.splice(index, 0, viewItem); if (this.views.length > 1) { //add sash const sash = document.createElement('div'); sash.className = 'sash'; const onStart = (event) => { for (const item of this.views) { item.enabled = false; } const iframes = [ ...getElementsByTagName('iframe'), ...getElementsByTagName('webview'), ]; for (const iframe of iframes) { iframe.style.pointerEvents = 'none'; } const start = this._orientation === exports.Orientation.HORIZONTAL ? event.clientX : event.clientY; const sashIndex = firstIndex(this.sashes, (s) => s.container === sash); // const sizes = this.views.map((x) => x.size); // let snapBefore; let snapAfter; const upIndexes = range(sashIndex, -1); const downIndexes = range(sashIndex + 1, this.views.length); const minDeltaUp = upIndexes.reduce((r, i) => r + (this.views[i].minimumSize - sizes[i]), 0); const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.views[i].viewMaximumSize - sizes[i]), 0); const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.views[i].minimumSize), 0); const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.views[i].viewMaximumSize), 0); const minDelta = Math.max(minDeltaUp, minDeltaDown); const maxDelta = Math.min(maxDeltaDown, maxDeltaUp); const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); const snapAfterIndex = this.findFirstSnapIndex(downIndexes); if (typeof snapBeforeIndex === 'number') { const snappedViewItem = this.views[snapBeforeIndex]; const halfSize = Math.floor(snappedViewItem.viewMinimumSize / 2); snapBefore = { index: snapBeforeIndex, limitDelta: snappedViewItem.visible ? minDelta - halfSize : minDelta + halfSize, size: snappedViewItem.size, }; } if (typeof snapAfterIndex === 'number') { const snappedViewItem = this.views[snapAfterIndex]; const halfSize = Math.floor(snappedViewItem.viewMinimumSize / 2); snapAfter = { index: snapAfterIndex, limitDelta: snappedViewItem.visible ? maxDelta + halfSize : maxDelta - halfSize, size: snappedViewItem.size, }; } // const mousemove = (mousemoveEvent) => { const current = this._orientation === exports.Orientation.HORIZONTAL ? mousemoveEvent.clientX : mousemoveEvent.clientY; const delta = current - start; this.resize(sashIndex, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter); this.distributeEmptySpace(); this.layoutViews(); }; const end = () => { for (const item of this.views) { item.enabled = true; } for (const iframe of iframes) { iframe.style.pointerEvents = 'auto'; } this.saveProportions(); document.removeEventListener('mousemove', mousemove); document.removeEventListener('mouseup', end); document.removeEventListener('mouseend', end); this._onDidSashEnd.fire(undefined); }; document.addEventListener('mousemove', mousemove); document.addEventListener('mouseup', end); document.addEventListener('mouseend', end); }; sash.addEventListener('mousedown', onStart); const sashItem = { container: sash, disposable: () => { sash.removeEventListener('mousedown', onStart); this.sashContainer.removeChild(sash); }, }; this.sashContainer.appendChild(sash); this.sashes.push(sashItem); } if (!skipLayout) { this.relayout([index]); } if (!skipLayout && typeof size !== 'number' && size.type === 'distribute') { this.distributeViewSizes(); } this._onDidAddView.fire(view); } distributeViewSizes() { const flexibleViewItems = []; let flexibleSize = 0; for (const item of this.views) { if (item.maximumSize - item.minimumSize > 0) { flexibleViewItems.push(item); flexibleSize += item.size; } } const size = Math.floor(flexibleSize / flexibleViewItems.length); for (const item of flexibleViewItems) { item.size = clamp(size, item.minimumSize, item.maximumSize); } const indexes = range(this.views.length); const lowPriorityIndexes = indexes.filter((i) => this.views[i].priority === exports.LayoutPriority.Low); const highPriorityIndexes = indexes.filter((i) => this.views[i].priority === exports.LayoutPriority.High); this.relayout(lowPriorityIndexes, highPriorityIndexes); } removeView(index, sizing, skipLayout = false) { // Remove view const viewItem = this.views.splice(index, 1)[0]; viewItem.dispose(); // Remove sash if (this.views.length >= 1) { const sashIndex = Math.max(index - 1, 0); const sashItem = this.sashes.splice(sashIndex, 1)[0]; sashItem.disposable(); } if (!skipLayout) { this.relayout(); } if (sizing && sizing.type === 'distribute') { this.distributeViewSizes(); } this._onDidRemoveView.fire(viewItem.view); return viewItem.view; } getViewCachedVisibleSize(index) { if (index < 0 || index >= this.views.length) { throw new Error('Index out of bounds'); } const viewItem = this.views[index]; return viewItem.cachedVisibleSize; } moveView(from, to) { const cachedVisibleSize = this.getViewCachedVisibleSize(from); const sizing = typeof cachedVisibleSize === 'undefined' ? this.getViewSize(from) : exports.Sizing.Invisible(cachedVisibleSize); const view = this.removeView(from, undefined, true); this.addView(view, sizing, to); } layout(size, orthogonalSize) { const previousSize = Math.max(this.size, this.contentSize); this.size = size; this.orthogonalSize = orthogonalSize; if (!this.proportions) {