@jupyterlab/ui-components
Advanced tools
Comparing version 4.1.0-alpha.3 to 4.1.0-alpha.4
@@ -33,5 +33,5 @@ import { AccordionLayout, AccordionPanel, Title, Widget } from '@lumino/widgets'; | ||
* | ||
* Default titleSpace is 29 px (default var(--jp-private-toolbar-height) - but not styled) | ||
* Default titleSpace is 32 px (default var(--jp-private-toolbar-height) - but not styled) | ||
*/ | ||
function createLayout(options: AccordionPanel.IOptions): AccordionLayout; | ||
} |
@@ -214,3 +214,3 @@ // Copyright (c) Jupyter Development Team. | ||
* | ||
* Default titleSpace is 29 px (default var(--jp-private-toolbar-height) - but not styled) | ||
* Default titleSpace is 32 px (default var(--jp-private-toolbar-height) - but not styled) | ||
*/ | ||
@@ -225,3 +225,3 @@ function createLayout(options) { | ||
spacing: options.spacing, | ||
titleSpace: (_a = options.titleSpace) !== null && _a !== void 0 ? _a : 29 | ||
titleSpace: (_a = options.titleSpace) !== null && _a !== void 0 ? _a : 32 | ||
})); | ||
@@ -228,0 +228,0 @@ } |
@@ -14,2 +14,7 @@ // Copyright (c) Jupyter Development Team. | ||
}, className); | ||
// If the HTMLSelect is integrated to a toolbar, we avoid propagating the focus | ||
// to the element with tabindex=0. | ||
const handleFocus = (event) => { | ||
event.stopPropagation(); | ||
}; | ||
const optionChildren = options.map(option => { | ||
@@ -20,3 +25,3 @@ const props = typeof option === 'object' ? option : { value: option }; | ||
return (React.createElement("div", { className: cls }, | ||
React.createElement("select", { disabled: disabled, ref: elementRef, ...htmlProps, multiple: false }, | ||
React.createElement("select", { onFocus: handleFocus, disabled: disabled, ref: elementRef, ...htmlProps, multiple: false }, | ||
optionChildren, | ||
@@ -23,0 +28,0 @@ htmlProps.children), |
@@ -94,3 +94,2 @@ // Copyright (c) Jupyter Development Team. | ||
theToolbar.addClass('jp-SidePanel-toolbar'); | ||
theToolbar.node.setAttribute('role', 'navigation'); | ||
theToolbar.node.setAttribute('aria-label', this._trans.__('side panel actions')); | ||
@@ -97,0 +96,0 @@ this.layout.insertWidget(this.layout.widgets.length - 1, theToolbar); |
@@ -169,7 +169,12 @@ import { ITranslator } from '@jupyterlab/translation'; | ||
private _onResize; | ||
private _getWidgetsToRemove; | ||
private _saveWidgetWidth; | ||
private _getWidgetWidth; | ||
private _saveWidgetPosition; | ||
protected readonly popupOpener: ToolbarPopupOpener; | ||
private readonly _widgetWidths; | ||
private readonly _resizer; | ||
private _widgetPositions; | ||
private _zoom; | ||
private _zoomChanged; | ||
} | ||
@@ -409,2 +414,7 @@ /** | ||
/** | ||
* Insert widget to the popup. | ||
* @param widget the widget to add | ||
*/ | ||
insertWidget(index: number, widget: Widget): void; | ||
/** | ||
* Dispose of the widget and its descendant widgets. | ||
@@ -411,0 +421,0 @@ * |
// Copyright (c) Jupyter Development Team. | ||
// Distributed under the terms of the Modified BSD License. | ||
import { Button } from '@jupyter/react-components'; | ||
import { addJupyterLabThemeChangeListener, jpButton, jpToolbar, provideJupyterDesignSystem } from '@jupyter/web-components'; | ||
import { nullTranslator } from '@jupyterlab/translation'; | ||
@@ -11,6 +13,7 @@ import { find, map, some } from '@lumino/algorithm'; | ||
import * as React from 'react'; | ||
import { Button } from './button'; | ||
import { ellipsesIcon, LabIcon } from '../icon'; | ||
import { classes } from '../utils'; | ||
import { ReactWidget, UseSignal } from './vdom'; | ||
provideJupyterDesignSystem().register([jpButton(), jpToolbar()]); | ||
addJupyterLabThemeChangeListener(); | ||
/** | ||
@@ -151,3 +154,3 @@ * The class name added to toolbars. | ||
var _a; | ||
super(); | ||
super({ node: document.createElement('jp-toolbar') }); | ||
this.addClass(TOOLBAR_CLASS); | ||
@@ -328,5 +331,9 @@ this.layout = (_a = options.layout) !== null && _a !== void 0 ? _a : new ToolbarLayout(); | ||
this._widgetWidths = {}; | ||
this._widgetPositions = new Map(); | ||
this._zoomChanged = true; | ||
this.insertItem(0, TOOLBAR_OPENER_NAME, this.popupOpener); | ||
this.popupOpener.hide(); | ||
this._resizer = new Throttler(this._onResize.bind(this), 500); | ||
this._resizer = new Throttler(async () => { | ||
await this._onResize(); | ||
}, 300); | ||
} | ||
@@ -385,9 +392,15 @@ /** | ||
insertItem(index, name, widget) { | ||
let status; | ||
if (widget instanceof ToolbarPopupOpener) { | ||
return super.insertItem(index, name, widget); | ||
status = super.insertItem(index, name, widget); | ||
} | ||
else { | ||
const j = Math.max(0, Math.min(index, this.layout.widgets.length - 1)); | ||
return super.insertItem(j, name, widget); | ||
status = super.insertItem(j, name, widget); | ||
} | ||
// Save the widgets position when a new widget is inserted. | ||
if (this._widgetPositions.get(name) === undefined) { | ||
this._saveWidgetPosition(); | ||
} | ||
return status; | ||
} | ||
@@ -405,2 +418,8 @@ /** | ||
super.onResize(msg); | ||
// Check if the resize event is due to a zoom change. | ||
const zoom = Math.round((window.outerWidth / window.innerWidth) * 100); | ||
if (zoom !== this._zoom) { | ||
this._zoomChanged = true; | ||
this._zoom = zoom; | ||
} | ||
if (msg.width > 0 && this._resizer) { | ||
@@ -411,32 +430,23 @@ void this._resizer.invoke(); | ||
_onResize() { | ||
if (this.parent && this.parent.isAttached) { | ||
const toolbarWidth = this.node.clientWidth; | ||
const opener = this.popupOpener; | ||
const openerWidth = 30; | ||
const toolbarPadding = 2; | ||
const layout = this.layout; | ||
let width = opener.isHidden | ||
? toolbarPadding | ||
: toolbarPadding + openerWidth; | ||
let index = 0; | ||
const widgetsToRemove = []; | ||
const toIndex = layout.widgets.length - 1; | ||
while (index < toIndex) { | ||
const widget = layout.widgets[index]; | ||
this._saveWidgetWidth(widget); | ||
width += this._getWidgetWidth(widget); | ||
if (widgetsToRemove.length === 0 && | ||
opener.isHidden && | ||
width + openerWidth > toolbarWidth) { | ||
width += openerWidth; | ||
} | ||
if (width > toolbarWidth) { | ||
widgetsToRemove.push(widget); | ||
} | ||
index++; | ||
} | ||
if (!(this.parent && this.parent.isAttached)) { | ||
return; | ||
} | ||
const toolbarWidth = this.node.clientWidth; | ||
const opener = this.popupOpener; | ||
const openerWidth = 30; | ||
// left and right padding. | ||
const toolbarPadding = 2 + 5; | ||
let width = opener.isHidden ? toolbarPadding : toolbarPadding + openerWidth; | ||
this._getWidgetsToRemove(width, toolbarWidth, openerWidth) | ||
.then(values => { | ||
var _a, _b; | ||
let { width, widgetsToRemove } = values; | ||
while (widgetsToRemove.length > 0) { | ||
// Insert the widget in the right position in the opener popup. | ||
const widget = widgetsToRemove.pop(); | ||
width -= this._getWidgetWidth(widget); | ||
opener.addWidget(widget); | ||
const name = Private.nameProperty.get(widget); | ||
width -= this._widgetWidths[name]; | ||
const position = (_a = this._widgetPositions.get(name)) !== null && _a !== void 0 ? _a : 0; | ||
const index = opener.widgetCount() + position - this._widgetPositions.size; | ||
opener.insertWidget(index, widget); | ||
} | ||
@@ -464,4 +474,7 @@ if (opener.widgetCount() > 0) { | ||
while (widgetsToAdd.length > 0) { | ||
// Insert the widget in the right position in the toolbar. | ||
const widget = widgetsToAdd.shift(); | ||
this.addItem(Private.nameProperty.get(widget), widget); | ||
const name = Private.nameProperty.get(widget); | ||
const index = (_b = this._widgetPositions.get(name)) !== null && _b !== void 0 ? _b : 0; | ||
this.insertItem(index, name, widget); | ||
} | ||
@@ -476,9 +489,54 @@ } | ||
} | ||
}) | ||
.catch(msg => { | ||
console.error('Error while computing the ReactiveToolbar', msg); | ||
}); | ||
} | ||
async _getWidgetsToRemove(width, toolbarWidth, openerWidth) { | ||
var _a; | ||
const opener = this.popupOpener; | ||
const layout = this.layout; | ||
const toIndex = layout.widgets.length - 1; | ||
const widgetsToRemove = []; | ||
let index = 0; | ||
while (index < toIndex) { | ||
const widget = layout.widgets[index]; | ||
// Compute the widget size only if | ||
// - the zoom has changed. | ||
// - the widget size has not been computed yet. | ||
let widgetWidth; | ||
if (this._zoomChanged) { | ||
widgetWidth = await this._saveWidgetWidth(widget); | ||
} | ||
else { | ||
widgetWidth = | ||
(_a = this._getWidgetWidth(widget)) !== null && _a !== void 0 ? _a : (await this._saveWidgetWidth(widget)); | ||
} | ||
width += widgetWidth; | ||
if (widgetsToRemove.length === 0 && | ||
opener.isHidden && | ||
width + openerWidth > toolbarWidth) { | ||
width += openerWidth; | ||
} | ||
if (width > toolbarWidth) { | ||
widgetsToRemove.push(widget); | ||
} | ||
index++; | ||
} | ||
this._zoomChanged = false; | ||
return { | ||
width: width, | ||
widgetsToRemove: widgetsToRemove | ||
}; | ||
} | ||
_saveWidgetWidth(widget) { | ||
async _saveWidgetWidth(widget) { | ||
if (widget instanceof ReactWidget) { | ||
await widget.renderPromise; | ||
} | ||
const widgetName = Private.nameProperty.get(widget); | ||
this._widgetWidths[widgetName] = widget.hasClass(TOOLBAR_SPACER_CLASS) | ||
const widgetWidth = widget.hasClass(TOOLBAR_SPACER_CLASS) | ||
? 2 | ||
: widget.node.clientWidth; | ||
this._widgetWidths[widgetName] = widgetWidth; | ||
return widgetWidth; | ||
} | ||
@@ -489,2 +547,8 @@ _getWidgetWidth(widget) { | ||
} | ||
_saveWidgetPosition() { | ||
this._widgetPositions.clear(); | ||
this.layout.widgets.forEach((widget, index) => { | ||
this._widgetPositions.set(Private.nameProperty.get(widget), index); | ||
}); | ||
} | ||
} | ||
@@ -514,2 +578,3 @@ /** | ||
var _a, _b; | ||
const actualOnClick = (_a = props.actualOnClick) !== null && _a !== void 0 ? _a : false; | ||
// In some browsers, a button click event moves the focus from the main | ||
@@ -519,10 +584,23 @@ // content to the button (see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus). | ||
// we bind the button action to `mousedown`. | ||
const handleMouseDown = (event) => { | ||
var _a; | ||
// Fire action only when left button is pressed. | ||
if (event.button === 0) { | ||
event.preventDefault(); | ||
(_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props); | ||
const handleMouseDown = actualOnClick | ||
? undefined | ||
: (event) => { | ||
var _a; | ||
// Fire action only when left button is pressed. | ||
if (event.button === 0) { | ||
event.preventDefault(); | ||
(_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props); | ||
} | ||
}; | ||
const handleClick = actualOnClick | ||
? (event) => { | ||
var _a; | ||
if (event.button === 0) { | ||
(_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props); | ||
} | ||
} | ||
}; | ||
: (event) => { | ||
// Prevent the toolbar widget to steal focus | ||
event.stopPropagation(); | ||
}; | ||
const handleKeyDown = (event) => { | ||
@@ -535,8 +613,2 @@ var _a; | ||
}; | ||
const handleClick = (event) => { | ||
var _a; | ||
if (event.button === 0) { | ||
(_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props); | ||
} | ||
}; | ||
const getTooltip = () => { | ||
@@ -553,8 +625,8 @@ if (props.enabled === false && props.disabledTooltip) { | ||
}; | ||
return (React.createElement(Button, { className: props.className | ||
return (React.createElement(Button, { appearance: "stealth", className: props.className | ||
? props.className + ' jp-ToolbarButtonComponent' | ||
: 'jp-ToolbarButtonComponent', "aria-pressed": props.pressed, "aria-disabled": props.enabled === false, ...props.dataset, disabled: props.enabled === false, onClick: ((_a = props.actualOnClick) !== null && _a !== void 0 ? _a : false) ? handleClick : undefined, onMouseDown: !((_b = props.actualOnClick) !== null && _b !== void 0 ? _b : false) ? handleMouseDown : undefined, onKeyDown: handleKeyDown, title: getTooltip(), minimal: true }, | ||
(props.icon || props.iconClass) && (React.createElement(LabIcon.resolveReact, { icon: props.pressed ? props.pressedIcon : props.icon, iconClass: | ||
: 'jp-ToolbarButtonComponent', "aria-pressed": props.pressed, "aria-disabled": props.enabled === false, ...props.dataset, disabled: props.enabled === false, onClick: handleClick, onMouseDown: handleMouseDown, onKeyDown: handleKeyDown, title: getTooltip(), minimal: true }, | ||
(props.icon || props.iconClass) && (React.createElement(LabIcon.resolveReact, { icon: props.pressed ? (_b = props.pressedIcon) !== null && _b !== void 0 ? _b : props.icon : props.icon, iconClass: | ||
// add some extra classes for proper support of icons-as-css-background | ||
classes(props.iconClass, 'jp-Icon'), className: "jp-ToolbarButtonComponent-icon", tag: "span", stylesheet: "toolbarButton" })), | ||
classes(props.iconClass, 'jp-Icon'), tag: null })), | ||
props.label && (React.createElement("span", { className: "jp-ToolbarButtonComponent-label" }, props.label)))); | ||
@@ -650,3 +722,3 @@ } | ||
return (React.createElement(UseSignal, { signal: props.commands.commandChanged, shouldUpdate: (sender, args) => (args.id === props.id && args.type === 'changed') || | ||
args.type === 'many-changed' }, () => React.createElement(ToolbarButtonComponent, { ...Private.propsFromCommand(props) }))); | ||
args.type === 'many-changed' }, () => props.commands.listCommands().includes(props.id) ? (React.createElement(ToolbarButtonComponent, { ...Private.propsFromCommand(props) })) : null)); | ||
} | ||
@@ -688,4 +760,5 @@ /* | ||
constructor() { | ||
super(); | ||
super({ node: document.createElement('jp-toolbar') }); | ||
this.width = 0; | ||
this.addClass('jp-Toolbar'); | ||
this.addClass('jp-Toolbar-responsive-popup'); | ||
@@ -727,3 +800,3 @@ this.layout = new PanelLayout(); | ||
insertWidget(index, widget) { | ||
this.layout.insertWidget(0, widget); | ||
this.layout.insertWidget(index, widget); | ||
} | ||
@@ -773,2 +846,9 @@ /** | ||
/** | ||
* Insert widget to the popup. | ||
* @param widget the widget to add | ||
*/ | ||
insertWidget(index, widget) { | ||
this.popup.insertWidget(index, widget); | ||
} | ||
/** | ||
* Dispose of the widget and its descendant widgets. | ||
@@ -842,5 +922,9 @@ * | ||
let className = commands.className(id, args); | ||
// Add the boolean state classes. | ||
if (commands.isToggled(id, args)) { | ||
className += ' lm-mod-toggled'; | ||
// Add the boolean state classes and aria attributes. | ||
let pressed; | ||
if (commands.isToggleable(id, args)) { | ||
pressed = commands.isToggled(id, args); | ||
if (pressed) { | ||
className += ' lm-mod-toggled'; | ||
} | ||
} | ||
@@ -869,3 +953,4 @@ if (!commands.isVisible(id, args)) { | ||
enabled, | ||
label: (_c = options.label) !== null && _c !== void 0 ? _c : label | ||
label: (_c = options.label) !== null && _c !== void 0 ? _c : label, | ||
pressed | ||
}; | ||
@@ -872,0 +957,0 @@ } |
@@ -255,4 +255,8 @@ import { IRenderMime } from '@jupyterlab/rendermime-interfaces'; | ||
* if no container is passed in | ||
* | ||
* #### Notes | ||
* If `null` is provided and no container is defined, the icon SVG will return directly | ||
* ignoring all other attributes (label, title,...) | ||
*/ | ||
tag?: 'div' | 'span'; | ||
tag?: 'div' | 'span' | null; | ||
/** | ||
@@ -259,0 +263,0 @@ * Optional title that will be set on the icon's outermost container node |
@@ -280,3 +280,2 @@ // Copyright (c) Jupyter Development Team. | ||
} | ||
let returnSvgElement = true; | ||
if (container) { | ||
@@ -288,15 +287,25 @@ // take ownership by removing any existing children | ||
} | ||
else { | ||
else if (tag) { | ||
// create a container if needed | ||
container = document.createElement(tag); | ||
returnSvgElement = false; | ||
} | ||
const svgElement = this.svgElement.cloneNode(true); | ||
if (!container) { | ||
if (label) { | ||
console.warn(); | ||
} | ||
return svgElement; | ||
} | ||
if (label != null) { | ||
container.textContent = label; | ||
} | ||
Private.initContainer({ container, className, styleProps, title }); | ||
Private.initContainer({ | ||
container: container, | ||
className, | ||
styleProps, | ||
title | ||
}); | ||
// add the svg node to the container | ||
const svgElement = this.svgElement.cloneNode(true); | ||
container.appendChild(svgElement); | ||
return returnSvgElement ? svgElement : container; | ||
return container; | ||
} | ||
@@ -389,3 +398,3 @@ render(container, options) { | ||
// make it so that tag can be used as a jsx component | ||
const Tag = tag; | ||
const Tag = tag !== null && tag !== void 0 ? tag : React.Fragment; | ||
// ensure that svg html is valid | ||
@@ -404,5 +413,12 @@ if (!(this.svgInnerHTML && this.svgReactAttrs)) { | ||
else { | ||
return (React.createElement(Tag, { className: className || styleProps | ||
? classes(className, LabIconStyle.styleClass(styleProps)) | ||
: undefined, title: title }, | ||
let attributes = {}; | ||
if (Tag !== React.Fragment) { | ||
attributes = { | ||
className: className || styleProps | ||
? classes(className, LabIconStyle.styleClass(styleProps)) | ||
: undefined, | ||
title: title | ||
}; | ||
} | ||
return (React.createElement(Tag, { ...attributes }, | ||
svgComponent, | ||
@@ -462,3 +478,3 @@ label)); | ||
// create a container if needed | ||
container = document.createElement(tag); | ||
container = document.createElement(tag !== null && tag !== void 0 ? tag : 'div'); | ||
} | ||
@@ -474,3 +490,3 @@ if (label != null) { | ||
// make it so that tag can be used as a jsx component | ||
const Tag = tag; | ||
const Tag = tag !== null && tag !== void 0 ? tag : 'div'; | ||
if (container) { | ||
@@ -477,0 +493,0 @@ initContainer({ container, className, styleProps, title }); |
{ | ||
"name": "@jupyterlab/ui-components", | ||
"version": "4.1.0-alpha.3", | ||
"version": "4.1.0-alpha.4", | ||
"description": "JupyterLab - UI components written in React", | ||
@@ -44,8 +44,10 @@ "homepage": "https://github.com/jupyterlab/jupyterlab", | ||
"dependencies": { | ||
"@jupyterlab/coreutils": "^6.1.0-alpha.3", | ||
"@jupyterlab/observables": "^5.1.0-alpha.3", | ||
"@jupyterlab/rendermime-interfaces": "^3.9.0-alpha.2", | ||
"@jupyterlab/translation": "^4.1.0-alpha.3", | ||
"@jupyter/react-components": "^0.13.3", | ||
"@jupyter/web-components": "^0.13.3", | ||
"@jupyterlab/coreutils": "^6.1.0-alpha.4", | ||
"@jupyterlab/observables": "^5.1.0-alpha.4", | ||
"@jupyterlab/rendermime-interfaces": "^3.9.0-alpha.3", | ||
"@jupyterlab/translation": "^4.1.0-alpha.4", | ||
"@lumino/algorithm": "^2.0.1", | ||
"@lumino/commands": "^2.1.3", | ||
"@lumino/commands": "^2.2.0", | ||
"@lumino/coreutils": "^2.1.2", | ||
@@ -58,3 +60,3 @@ "@lumino/disposable": "^2.1.2", | ||
"@lumino/virtualdom": "^2.0.1", | ||
"@lumino/widgets": "^2.3.1-alpha.0", | ||
"@lumino/widgets": "^2.3.1", | ||
"@rjsf/core": "^5.13.2", | ||
@@ -67,3 +69,3 @@ "@rjsf/utils": "^5.13.2", | ||
"devDependencies": { | ||
"@jupyterlab/testing": "^4.1.0-alpha.3", | ||
"@jupyterlab/testing": "^4.1.0-alpha.4", | ||
"@types/jest": "^29.2.0", | ||
@@ -70,0 +72,0 @@ "@types/react": "^18.0.26", |
@@ -236,3 +236,3 @@ // Copyright (c) Jupyter Development Team. | ||
* | ||
* Default titleSpace is 29 px (default var(--jp-private-toolbar-height) - but not styled) | ||
* Default titleSpace is 32 px (default var(--jp-private-toolbar-height) - but not styled) | ||
*/ | ||
@@ -249,3 +249,3 @@ export function createLayout( | ||
spacing: options.spacing, | ||
titleSpace: options.titleSpace ?? 29 | ||
titleSpace: options.titleSpace ?? 32 | ||
}) | ||
@@ -252,0 +252,0 @@ ); |
@@ -115,3 +115,2 @@ // Copyright (c) Jupyter Development Team. | ||
theToolbar.addClass('jp-SidePanel-toolbar'); | ||
theToolbar.node.setAttribute('role', 'navigation'); | ||
theToolbar.node.setAttribute( | ||
@@ -118,0 +117,0 @@ 'aria-label', |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
871347
18688
22
+ Added@jupyter/react-components@0.13.3(transitive)
+ Added@jupyter/web-components@0.13.3(transitive)
+ Added@microsoft/fast-colors@5.3.1(transitive)
+ Added@microsoft/fast-components@2.30.6(transitive)
+ Added@microsoft/fast-element@1.13.0(transitive)
+ Added@microsoft/fast-foundation@2.49.6(transitive)
+ Added@microsoft/fast-react-wrapper@0.3.24(transitive)
+ Added@microsoft/fast-web-utilities@5.4.16.0.0(transitive)
+ Addedexenv-es6@1.1.1(transitive)
+ Addedtabbable@5.3.3(transitive)
+ Addedtslib@1.14.1(transitive)
Updated@lumino/commands@^2.2.0
Updated@lumino/widgets@^2.3.1