import PropTypes from 'prop-types';
import DashLuminoComponent from '../component.js'
import { components } from '../registry.js';
import {
TabPanel as l_TabPanel
} from '@lumino/widgets';
/**
* A widget which combines a TabBar and a StackedPanel.
* {@link https://jupyterlab.github.io/lumino/widgets/classes/tabpanel.html}
*
* This is a simple panel which handles the common case of a tab bar placed
* next to a content area. The selected tab controls the widget which is
* shown in the content area.
* For use cases which require more control than is provided by this panel,
* the TabBar widget may be used independently.
* @hideconstructor
*
* @example
* //Python:
* import dash
* import dash_lumino_components as dlc
* import dash_html_components as html
* import dash_bootstrap_components as dbc
*
* tabPanel = dlc.TabPanel(
* [
* dlc.Panel(
* html.Div([
* dbc.Button("Open Plot",
* id="button2",
* style={"width": "100%"})
* ]),
* id="tab-panel-A"
* label="Plots",
* icon="fa fa-bar-chart")
* ],
* id='tab-panel-left')
*/
class TabPanel extends DashLuminoComponent {
constructor(props) {
super(props);
// register a new TabPanel
let luminoComponent = super.register(new l_TabPanel({
tabPlacement: props.tabPlacement,
tabsMovable: props.tabsMovable,
}), props.addToDom);
// set additional properties
luminoComponent.tabBar.allowDeselect = props.allowDeselect;
luminoComponent.currentIndex = props.currentIndex;
if (props.allowDeselect) {
// if the user is allow to deselect items, panel should hide if nothing is selected
// this is handeled by the _onTabIndexChanged callback
luminoComponent.currentChanged.connect(
this._onTabIndexChanged,
this
);
setTimeout(this._onTabIndexChanged, 100);
}
if (props.currentIndex == -1) {
// set the current index if it is not -1 after the component is created
function setIndex() {
luminoComponent.currentIndex = -1;
}
setTimeout(setIndex, 10);
setTimeout(setIndex, 20);
setTimeout(setIndex, 50);
setTimeout(setIndex, 100);
}
// we need to update the tabpanel width once the user resizes the window
let that = this;
let st_panel = luminoComponent.stackedPanel;
luminoComponent.stackedPanel.onResize = (msg) => {
const { setProps } = that.props;
try
{
let rel_sizes = st_panel.parent.relativeSizes();
let idx = st_panel.parent.widgets.indexOf(st_panel);
if (idx != -1) {
setProps({ width: rel_sizes[idx] * window.innerWidth });
}
} catch (e) {
}
};
//add the children of the component to the widgets of the panel
if (this.props.children) {
super.parseChildrenToArray().forEach(el => {
super.applyAfterLuminoChildCreation(el, (target, child) => {
target.lumino.addWidget(child.lumino);
target.lumino.currentIndex = target.dash.props.currentIndex;
});
})
}
}
/**
* this callback hids the stackedpanel if no tab is selected
* to make everything seamless, the resizing is handeled here
* @private
*/
_onTabIndexChanged() {
if (components[this.id] == null)
return;
let tabBar = components[this.id].lumino.tabBar;
let stackedPanel = components[this.id].lumino.stackedPanel;
if (tabBar != null && stackedPanel != null) {
let { setProps } = components[this.id].dash.props;
setProps({ currentIndex: tabBar.currentIndex });
if (tabBar.currentIndex == -1) {
let sizes = stackedPanel.parent.relativeSizes();
stackedPanel.hide();
} else {
stackedPanel.show();
}
try {
components[stackedPanel.parent.id].dash.updateSizes();
} catch (e) {}
} else {
return;
}
}
render() {
if (components[this.id]) {
components[this.id].lumino.currentIndex = this.props.currentIndex;
}
return super.render();
}
}
TabPanel.defaultProps = {
tabPlacement: 'top',
tabsMovable: false,
allowDeselect: false,
addToDom: false,
width: 250,
currentIndex: -1
};
/**
* @typedef
* @enum {}
*/
TabPanel.propTypes = {
/**
* ID of the widget
* @type {string}
*/
id: PropTypes.string.isRequired,
/**
* the placement of the tab bar relative to the content. ("left" | "right" | "top" | "bottom")
* @type {string}
*/
tabPlacement: PropTypes.string,
/**
* whether the tabs are movable by the user
* @type {boolean}
*/
tabsMovable: PropTypes.bool,
/**
* bool if all tabs can be deselected
* @type {boolean}
*/
allowDeselect: PropTypes.bool,
/**
* the default width or height of the tab panel content
* @type {number}
*/
width: PropTypes.number,
/**
* bool if the object has to be added to the dom directly
* @type {boolean}
*/
addToDom: PropTypes.bool,
/**
* The widgets
* @type {Panel[]}
*/
children: PropTypes.node,
/**
* Get the index of the currently selected tab. It will be -1 if no tab is selected.
* @type {number}
*/
currentIndex: PropTypes.number,
/**
* Dash-assigned callback that should be called to report property changes
* to Dash, to make them available for callbacks.
* @private
*/
setProps: PropTypes.func
};
/**
* @private
*/
export default TabPanel;