diff --git a/@plotly/dash-test-components/src/components/AddPropsComponent.js b/@plotly/dash-test-components/src/components/AddPropsComponent.js index c4f8af1ea7..c4b94b6e49 100644 --- a/@plotly/dash-test-components/src/components/AddPropsComponent.js +++ b/@plotly/dash-test-components/src/components/AddPropsComponent.js @@ -7,9 +7,8 @@ const AddPropsComponent = (props) => { return (
- {React.cloneElement(children, { + {React.cloneElement(children, { receive: `Element #${id} pass`, - id: id, })}
); diff --git a/components/dash-core-components/src/components/Checklist.react.js b/components/dash-core-components/src/components/Checklist.react.js index 784d8fc596..dbe8580b27 100644 --- a/components/dash-core-components/src/components/Checklist.react.js +++ b/components/dash-core-components/src/components/Checklist.react.js @@ -1,7 +1,9 @@ import PropTypes from 'prop-types'; import {append, includes, without} from 'ramda'; import React, {Component} from 'react'; + import {sanitizeOptions} from '../utils/optionTypes'; +import LoadingElement from '../utils/LoadingElement'; /** * Checklist is a component that encapsulates several checkboxes. @@ -21,19 +23,11 @@ export default class Checklist extends Component { options, setProps, style, - loading_state, value, inline, } = this.props; return ( -
+ {sanitizeOptions(options).map(option => { return (
+ ); } } @@ -192,24 +186,6 @@ Checklist.propTypes = { */ setProps: PropTypes.func, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/Clipboard.react.js b/components/dash-core-components/src/components/Clipboard.react.js index c7bf1a2592..72d94c8199 100644 --- a/components/dash-core-components/src/components/Clipboard.react.js +++ b/components/dash-core-components/src/components/Clipboard.react.js @@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faCopy, faCheckCircle} from '@fortawesome/free-regular-svg-icons'; +import LoadingElement from '../utils/LoadingElement'; + const clipboardAPI = navigator.clipboard; function wait(ms) { @@ -14,6 +16,8 @@ function wait(ms) { */ export default class Clipboard extends React.Component { + static contextType = window.dash_component_api.DashContext; + constructor(props) { super(props); this.copyToClipboard = this.copyToClipboard.bind(this); @@ -96,7 +100,7 @@ export default class Clipboard extends React.Component { } async loading() { - while (this.props.loading_state?.is_loading) { + while (this.context.isLoading()) { await wait(100); } } @@ -124,24 +128,21 @@ export default class Clipboard extends React.Component { } render() { - const {id, title, className, style, loading_state} = this.props; + const {id, title, className, style} = this.props; const copyIcon = ; const copiedIcon = ; const btnIcon = this.state.copied ? copiedIcon : copyIcon; return clipboardAPI ? ( -
{btnIcon} -
+ ) : null; } } @@ -196,24 +197,6 @@ Clipboard.propTypes = { */ className: PropTypes.string, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Dash-assigned callback that gets fired when the value changes. */ diff --git a/components/dash-core-components/src/components/ConfirmDialogProvider.react.js b/components/dash-core-components/src/components/ConfirmDialogProvider.react.js index c4e82f6a0d..3c6499cf4d 100644 --- a/components/dash-core-components/src/components/ConfirmDialogProvider.react.js +++ b/components/dash-core-components/src/components/ConfirmDialogProvider.react.js @@ -1,8 +1,8 @@ -import {clone} from 'ramda'; import React from 'react'; import PropTypes from 'prop-types'; import ConfirmDialog from './ConfirmDialog.react'; +import LoadingElement from '../utils/LoadingElement'; /** * A wrapper component that will display a confirmation dialog @@ -18,30 +18,21 @@ import ConfirmDialog from './ConfirmDialog.react'; */ export default class ConfirmDialogProvider extends React.Component { render() { - const {displayed, id, setProps, children, loading_state} = this.props; + const {displayed, id, setProps, children} = this.props; // Will lose the previous onClick of the child - const wrapClick = child => { - const props = clone(child.props); - props._dashprivate_layout.props.onClick = () => { - setProps({displayed: true}); - }; - - return React.cloneElement(child, props); - }; + const wrapClick = child => + React.cloneElement(child, { + onClick: () => setProps({displayed: true}), + }); return ( -
+ {Array.isArray(children) ? children.map(wrapClick) : wrapClick(children)} -
+ ); } } @@ -94,22 +85,4 @@ ConfirmDialogProvider.propTypes = { * The children to hijack clicks from and display the popup. */ children: PropTypes.any, - - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), }; diff --git a/components/dash-core-components/src/components/DatePickerRange.react.js b/components/dash-core-components/src/components/DatePickerRange.react.js index e9bcdebd5b..3cdfe83551 100644 --- a/components/dash-core-components/src/components/DatePickerRange.react.js +++ b/components/dash-core-components/src/components/DatePickerRange.react.js @@ -222,24 +222,6 @@ DatePickerRange.propTypes = { */ setProps: PropTypes.func, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/DatePickerSingle.react.js b/components/dash-core-components/src/components/DatePickerSingle.react.js index 792e9f6b75..1c35fa8505 100644 --- a/components/dash-core-components/src/components/DatePickerSingle.react.js +++ b/components/dash-core-components/src/components/DatePickerSingle.react.js @@ -181,24 +181,6 @@ DatePickerSingle.propTypes = { */ setProps: PropTypes.func, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/Dropdown.react.js b/components/dash-core-components/src/components/Dropdown.react.js index 37111fc338..d0a10fd2a7 100644 --- a/components/dash-core-components/src/components/Dropdown.react.js +++ b/components/dash-core-components/src/components/Dropdown.react.js @@ -177,24 +177,6 @@ Dropdown.propTypes = { */ setProps: PropTypes.func, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/Graph.react.js b/components/dash-core-components/src/components/Graph.react.js index ff326b6b0c..770c9defd6 100644 --- a/components/dash-core-components/src/components/Graph.react.js +++ b/components/dash-core-components/src/components/Graph.react.js @@ -556,24 +556,6 @@ PlotlyGraph.propTypes = { * Function that updates the state tree. */ setProps: PropTypes.func, - - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), }; ControlledPlotlyGraph.propTypes = PlotlyGraph.propTypes; diff --git a/components/dash-core-components/src/components/Input.react.js b/components/dash-core-components/src/components/Input.react.js index d4656fddae..16fa7e611d 100644 --- a/components/dash-core-components/src/components/Input.react.js +++ b/components/dash-core-components/src/components/Input.react.js @@ -3,6 +3,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import isNumeric from 'fast-isnumeric'; import './css/input.css'; +import LoadingElement from '../utils/LoadingElement'; // eslint-disable-next-line no-implicit-coercion const convert = val => (isNumeric(val) ? +val : NaN); @@ -94,14 +95,11 @@ export default class Input extends PureComponent { render() { const valprops = this.props.type === 'number' ? {} : {value: this.state.value}; - const {loading_state} = this.props; let {className} = this.props; className = 'dash-input' + (className ? ` ${className}` : ''); return ( - { - const { - className, - style, - id, - href, - loading_state, - children, - title, - target, - setProps, - } = props; + const {className, style, id, href, children, title, target, setProps} = + props; const cleanUrl = window.dash_clientside.clean_url; const sanitizedUrl = useMemo(() => { return href ? cleanUrl(href) : undefined; }, [href]); + const ctx = window.dash_component_api.useDashContext(); + const loading = ctx.useLoading(); + const updateLocation = e => { const hasModifiers = e.metaKey || e.shiftKey || e.altKey || e.ctrlKey; @@ -80,9 +74,7 @@ const Link = ({refresh = false, ...props}) => { return ( spinnerComponentOptions[spinnerType] || DefaultSpinner; -/** - * A Loading component that wraps any other component and displays a spinner until the wrapped component has rendered. - */ -const Loading = ({ +const coveringSpinner = { + visibility: 'visible', + position: 'absolute', + top: '0', + height: '100%', + width: '100%', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}; + +const loadingSelector = (componentPath, targetComponents) => state => { + let stringPath = JSON.stringify(componentPath); + // Remove the last ] for easy match + stringPath = stringPath.substring(0, stringPath.length - 1); + const loadingChildren = toPairs(state.loading).reduce( + (acc, [path, load]) => { + if (path.startsWith(stringPath) && load.length) { + if ( + targetComponents && + !any(l => { + const target = targetComponents[l.id]; + if (!target) { + return false; + } + if (Array.isArray(target)) { + return includes(l.property, target); + } + return l.property === target; + }, load) + ) { + return acc; + } + return concat(acc, load); + } + return acc; + }, + [] + ); + if (loadingChildren.length) { + return loadingChildren; + } + return null; +}; + +function Loading({ children, - loading_state, display = 'auto', color = '#119DFF', id, @@ -38,91 +81,60 @@ const Loading = ({ delay_show = 0, target_components, custom_spinner, -}) => { - const coveringSpinner = { - visibility: 'visible', - position: 'absolute', - top: '0', - height: '100%', - width: '100%', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - }; - - /* Overrides default Loading behavior if target_components is set. By default, - * Loading fires when any recursive child enters loading state. This makes loading - * opt-in: Loading animation only enabled when one of target components enters loading state. - */ - const isTarget = () => { - if (!target_components) { - return true; - } - const isMatchingComponent = () => { - return Object.entries(target_components).some( - ([component_name, prop_names]) => { - // Convert prop_names to an array if it's not already - const prop_names_array = Array.isArray(prop_names) - ? prop_names - : [prop_names]; - - return ( - loading_state.component_name === component_name && - (prop_names_array.includes('*') || - prop_names_array.some( - prop_name => - loading_state.prop_name === prop_name - )) - ); - } - ); - }; - return isMatchingComponent; - }; +}) { + const ctx = window.dash_component_api.useDashContext(); + const loading = ctx.useSelector( + loadingSelector(ctx.componentPath, target_components), + equals + ); const [showSpinner, setShowSpinner] = useState(show_initially); const dismissTimer = useRef(); const showTimer = useRef(); - // delay_hide and delay_show is from dash-bootstrap-components dbc.Spinner + const containerStyle = useMemo(() => { + if (showSpinner) { + return {visibility: 'hidden', ...overlay_style, ...parent_style}; + } + return parent_style; + }, [showSpinner, parent_style]); + useEffect(() => { if (display === 'show' || display === 'hide') { setShowSpinner(display === 'show'); return; } - if (loading_state) { - if (loading_state.is_loading) { - // if component is currently loading and there's a dismiss timer active - // we need to clear it. - if (dismissTimer.current) { - dismissTimer.current = clearTimeout(dismissTimer.current); - } - // if component is currently loading but the spinner is not showing and - // there is no timer set to show, then set a timeout to show - if (!showSpinner && !showTimer.current) { - showTimer.current = setTimeout(() => { - setShowSpinner(isTarget()); - showTimer.current = null; - }, delay_show); - } - } else { - // if component is not currently loading and there's a show timer - // active we need to clear it - if (showTimer.current) { - showTimer.current = clearTimeout(showTimer.current); - } - // if component is not currently loading and the spinner is showing and - // there's no timer set to dismiss it, then set a timeout to hide it - if (showSpinner && !dismissTimer.current) { - dismissTimer.current = setTimeout(() => { - setShowSpinner(false); - dismissTimer.current = null; - }, delay_hide); - } + if (loading) { + // if component is currently loading and there's a dismiss timer active + // we need to clear it. + if (dismissTimer.current) { + dismissTimer.current = clearTimeout(dismissTimer.current); + } + // if component is currently loading but the spinner is not showing and + // there is no timer set to show, then set a timeout to show + if (!showSpinner && !showTimer.current) { + showTimer.current = setTimeout(() => { + setShowSpinner(true); + showTimer.current = null; + }, delay_show); + } + } else { + // if component is not currently loading and there's a show timer + // active we need to clear it + if (showTimer.current) { + showTimer.current = clearTimeout(showTimer.current); + } + // if component is not currently loading and the spinner is showing and + // there's no timer set to dismiss it, then set a timeout to hide it + if (showSpinner && !dismissTimer.current) { + dismissTimer.current = setTimeout(() => { + setShowSpinner(false); + dismissTimer.current = null; + }, delay_hide); } } - }, [delay_hide, delay_show, loading_state, display, showSpinner]); + }, [delay_hide, delay_show, loading, display, showSpinner]); const Spinner = showSpinner && getSpinner(spinnerType); @@ -131,18 +143,7 @@ const Loading = ({ style={{position: 'relative', ...parent_style}} className={parent_className} > -
+
{children}
@@ -151,7 +152,7 @@ const Loading = ({
); -}; - -Loading._dashprivate_isLoadingComponent = true; +} Loading.propTypes = { /** @@ -227,24 +226,6 @@ Loading.propTypes = { */ color: PropTypes.string, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Setting display to "show" or "hide" will override the loading state coming from dash-renderer */ diff --git a/components/dash-core-components/src/components/Markdown.react.js b/components/dash-core-components/src/components/Markdown.react.js index 322c9d68b8..a2daa0538d 100644 --- a/components/dash-core-components/src/components/Markdown.react.js +++ b/components/dash-core-components/src/components/Markdown.react.js @@ -84,24 +84,6 @@ DashMarkdown.propTypes = { theme: PropTypes.oneOf(['dark', 'light']), }), - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * User-defined inline styles for the rendered Markdown */ diff --git a/components/dash-core-components/src/components/RadioItems.react.js b/components/dash-core-components/src/components/RadioItems.react.js index a62e2293ff..f7b263d92d 100644 --- a/components/dash-core-components/src/components/RadioItems.react.js +++ b/components/dash-core-components/src/components/RadioItems.react.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, {Component} from 'react'; import './css/react-select@1.0.0-rc.3.min.css'; import {sanitizeOptions} from '../utils/optionTypes'; +import LoadingElement from '../utils/LoadingElement'; /** * RadioItems is a component that encapsulates several radio item inputs. @@ -22,7 +23,6 @@ export default class RadioItems extends Component { labelStyle, options, setProps, - loading_state, value, inline, } = this.props; @@ -32,14 +32,7 @@ export default class RadioItems extends Component { ids = {id, key: id}; } return ( -
+ {sanitizeOptions(options).map(option => (
+ ); } } @@ -185,24 +178,6 @@ RadioItems.propTypes = { */ setProps: PropTypes.func, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/RangeSlider.react.js b/components/dash-core-components/src/components/RangeSlider.react.js index 93dbf015d6..0fe3341379 100644 --- a/components/dash-core-components/src/components/RangeSlider.react.js +++ b/components/dash-core-components/src/components/RangeSlider.react.js @@ -190,24 +190,6 @@ RangeSlider.propTypes = { */ setProps: PropTypes.func, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/Slider.react.js b/components/dash-core-components/src/components/Slider.react.js index 7e642591c2..2bdfb8e958 100644 --- a/components/dash-core-components/src/components/Slider.react.js +++ b/components/dash-core-components/src/components/Slider.react.js @@ -173,24 +173,6 @@ Slider.propTypes = { */ setProps: PropTypes.func, - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/Tab.react.js b/components/dash-core-components/src/components/Tab.react.js index 1985b884c7..273ea16286 100644 --- a/components/dash-core-components/src/components/Tab.react.js +++ b/components/dash-core-components/src/components/Tab.react.js @@ -74,24 +74,6 @@ Tab.propTypes = { * Overrides the default (inline) styles for the Tab component when it is selected. */ selected_style: PropTypes.object, - - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), }; export default Tab; diff --git a/components/dash-core-components/src/components/Tabs.react.js b/components/dash-core-components/src/components/Tabs.react.js index 0857ed1c12..994d1bd410 100644 --- a/components/dash-core-components/src/components/Tabs.react.js +++ b/components/dash-core-components/src/components/Tabs.react.js @@ -6,6 +6,7 @@ import {has, is, isNil} from 'ramda'; // some weird interaction btwn styled-jsx 3.4 and babel // see https://github.com/vercel/styled-jsx/pull/716 import _JSXStyle from 'styled-jsx/style'; // eslint-disable-line no-unused-vars +import LoadingElement from '../utils/LoadingElement'; // EnhancedTab is defined here instead of in Tab.react.js because if exported there, // it will mess up the Python imports and metadata.json @@ -135,8 +136,6 @@ export default class Tabs extends Component { super(props); this.selectHandler = this.selectHandler.bind(this); - this.parseChildrenToArray = this.parseChildrenToArray.bind(this); - this.valueOrDefault = this.valueOrDefault.bind(this); if (!has('value', this.props)) { this.props.setProps({ @@ -150,8 +149,13 @@ export default class Tabs extends Component { return this.props.value; } const children = this.parseChildrenToArray(); - if (children && children[0].props.children) { - return children[0].props.children.props.value || 'tab-1'; + if (children && children.length) { + const firstChildren = window.dash_clientside.get_layout([ + ...children[0].props.componentPath, + 'props', + 'value', + ]); + return firstChildren || 'tab-1'; } return 'tab-1'; } @@ -173,6 +177,8 @@ export default class Tabs extends Component { let EnhancedTabs; let selectedTab; + const value = this.valueOrDefault(); + if (this.props.children) { const children = this.parseChildrenToArray(); @@ -183,20 +189,14 @@ export default class Tabs extends Component { // enhance Tab components coming from Dash (as dcc.Tab) with methods needed for handling logic let childProps; - if ( - // disabled is a defaultProp (so it's always set) - // meaning that if it's not set on child.props, the actual - // props we want are lying a bit deeper - which means they - // are coming from Dash - isNil(child.props.disabled) && - child.props._dashprivate_layout && - child.props._dashprivate_layout.props - ) { - // props are coming from Dash - childProps = child.props._dashprivate_layout.props; + if (React.isValidElement(child)) { + childProps = window.dash_clientside.get_layout([ + ...child.props.componentPath, + 'props', + ]); } else { - // else props are coming from React (Demo.react.js, or Tabs.test.js) - childProps = child.props; + // In case the selected tab is a string. + childProps = {}; } if (!childProps.value) { @@ -204,7 +204,7 @@ export default class Tabs extends Component { } // check if this child/Tab is currently selected - if (childProps.value === this.valueOrDefault()) { + if (childProps.value === value) { selectedTab = child; } @@ -213,7 +213,7 @@ export default class Tabs extends Component { key={index} id={childProps.id} label={childProps.label} - selected={this.valueOrDefault() === childProps.value} + selected={value === childProps.value} selectHandler={this.selectHandler} className={childProps.className} style={childProps.style} @@ -248,12 +248,7 @@ export default class Tabs extends Component { : 'tab-parent'; return ( -
-
+ ); } } @@ -412,24 +407,6 @@ Tabs.propTypes = { background: PropTypes.string, }), - /** - * Object that holds the loading state object coming from dash-renderer - */ - loading_state: PropTypes.shape({ - /** - * Determines if the component is loading or not - */ - is_loading: PropTypes.bool, - /** - * Holds which property is loading - */ - prop_name: PropTypes.string, - /** - * Holds the name of the component that is loading - */ - component_name: PropTypes.string, - }), - /** * Used to allow user interactions in this component to be persisted when * the component - or the page - is refreshed. If `persisted` is truthy and diff --git a/components/dash-core-components/src/components/Tooltip.react.js b/components/dash-core-components/src/components/Tooltip.react.js index 1d2fcb7b0c..3c5505df43 100644 --- a/components/dash-core-components/src/components/Tooltip.react.js +++ b/components/dash-core-components/src/components/Tooltip.react.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import _JSXStyle from 'styled-jsx/style'; // eslint-disable-line no-unused-vars +import LoadingElement from '../utils/LoadingElement'; /** * A tooltip with an absolute position. @@ -17,15 +18,17 @@ const Tooltip = ({ loading_text = 'Loading...', ...props }) => { - const {bbox, id, loading_state} = props; - const is_loading = loading_state?.is_loading; + const {bbox, id} = props; const show_tooltip = show && bbox; + const ctx = window.dash_component_api.useDashContext(); + const is_loading = ctx.useLoading(); + return ( <>
- - +