dockview
Version:
Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support
182 lines • 7.86 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isReactElement = exports.usePortalsLifecycle = exports.ReactPart = exports.ReactPartContext = void 0;
var React = __importStar(require("react"));
var ReactDOM = __importStar(require("react-dom"));
var math_1 = require("../math");
/**
* This component is intended to interface between vanilla-js and React hence we need to be
* creative in how we update props.
* A ref of the component is exposed with an update method; which when called stores the props
* as a ref within this component and forcefully triggers a re-render of the component using
* the ref of props we just set on the renderered component as the props passed to the inner
* component
*/
var ReactComponentBridge = function (props, ref) {
var _a = __read(React.useState(), 2), _ = _a[0], triggerRender = _a[1];
var _props = React.useRef(props.componentProps);
React.useImperativeHandle(ref, function () { return ({
update: function (componentProps) {
_props.current = __assign(__assign({}, _props.current), componentProps);
/**
* setting a arbitrary piece of state within this component will
* trigger a re-render.
* we use this rather than updating through a prop since we can
* pass a ref into the vanilla-js world.
*/
triggerRender(Date.now());
},
}); }, []);
return React.createElement(props.component, _props.current);
};
ReactComponentBridge.displayName = 'DockviewReactJsBridge';
/**
* Since we are storing the React.Portal references in a rendered array they
* require a key property like any other React element rendered in an array
* to prevent excessive re-rendering
*/
var uniquePortalKeyGenerator = (0, math_1.sequentialNumberGenerator)();
exports.ReactPartContext = React.createContext({});
var ReactPart = /** @class */ (function () {
function ReactPart(parent, portalStore, component, parameters, context) {
this.parent = parent;
this.portalStore = portalStore;
this.component = component;
this.parameters = parameters;
this.context = context;
this.disposed = false;
this.createPortal();
}
ReactPart.prototype.update = function (props) {
var _a;
if (this.disposed) {
throw new Error('invalid operation: resource is already disposed');
}
(_a = this.componentInstance) === null || _a === void 0 ? void 0 : _a.update(props);
};
ReactPart.prototype.createPortal = function () {
var _this = this;
if (this.disposed) {
throw new Error('invalid operation: resource is already disposed');
}
// TODO use a better check for isReactFunctionalComponent
if (typeof this.component !== 'function') {
/**
* we know this isn't a React.FunctionComponent so throw an error here.
* if we do not intercept this the React library will throw a very obsure error
* for the same reason, at least at this point we will emit a sensible stacktrace.
*/
throw new Error('invalid operation: only functional components are supported');
}
var bridgeComponent = React.createElement(React.forwardRef(ReactComponentBridge), {
component: this
.component,
componentProps: this.parameters,
ref: function (element) {
_this.componentInstance = element;
},
});
var node = this.context
? React.createElement(exports.ReactPartContext.Provider, { value: this.context }, bridgeComponent)
: bridgeComponent;
var portal = ReactDOM.createPortal(node, this.parent, uniquePortalKeyGenerator.next());
this.ref = {
portal: portal,
disposable: this.portalStore.addPortal(portal),
};
};
ReactPart.prototype.dispose = function () {
var _a;
(_a = this.ref) === null || _a === void 0 ? void 0 : _a.disposable.dispose();
this.disposed = true;
};
return ReactPart;
}());
exports.ReactPart = ReactPart;
/**
* A React Hook that returns an array of portals to be rendered by the user of this hook
* and a disposable function to add a portal. Calling dispose removes this portal from the
* portal array
*/
var usePortalsLifecycle = function () {
var _a = __read(React.useState([]), 2), portals = _a[0], setPortals = _a[1];
React.useDebugValue("Portal count: ".concat(portals.length));
var addPortal = React.useCallback(function (portal) {
setPortals(function (existingPortals) { return __spreadArray(__spreadArray([], __read(existingPortals), false), [portal], false); });
var disposed = false;
return {
dispose: function () {
if (disposed) {
throw new Error('invalid operation: resource already disposed');
}
disposed = true;
setPortals(function (existingPortals) {
return existingPortals.filter(function (p) { return p !== portal; });
});
},
};
}, []);
return [portals, addPortal];
};
exports.usePortalsLifecycle = usePortalsLifecycle;
// it does the job...
function isReactElement(element) {
return element === null || element === void 0 ? void 0 : element.type;
}
exports.isReactElement = isReactElement;
//# sourceMappingURL=react.js.map