"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useExpressionRenderer = useExpressionRenderer; var _react = require("react"); var _operators = require("rxjs/operators"); var _useUpdateEffect = _interopRequireDefault(require("react-use/lib/useUpdateEffect")); var _common = require("../../common"); var _loader = require("../loader"); var _use_debounced_value = require("./use_debounced_value"); var _use_shallow_memo = require("./use_shallow_memo"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ function useExpressionRenderer(nodeRef, { debounce, expression, hasCustomErrorRenderer, onData$, onEvent, onRender$, reload$, ...loaderParams }) { const [{ error, isEmpty, isLoading }, setState] = (0, _react.useReducer)((currentState, newState) => ({ ...currentState, ...newState }), { isEmpty: true, isLoading: false, error: null }); const memoizedOptions = (0, _use_shallow_memo.useShallowMemo)({ expression, params: (0, _use_shallow_memo.useShallowMemo)(loaderParams) }); const [{ expression: debouncedExpression, params: debouncedLoaderParams }, isDebounced] = (0, _use_debounced_value.useDebouncedValue)(memoizedOptions, debounce); const expressionLoaderRef = (0, _react.useRef)(null); // flag to skip next render$ notification, // because of just handled error const hasHandledErrorRef = (0, _react.useRef)(false); // will call done() in LayoutEffect when done with rendering custom error state const errorRenderHandlerRef = (0, _react.useRef)(null); /* eslint-disable react-hooks/exhaustive-deps */ // OK to ignore react-hooks/exhaustive-deps because options update is handled by calling .update() (0, _react.useEffect)(() => { var _expressionLoaderRef$; expressionLoaderRef.current = nodeRef.current && new _loader.ExpressionLoader(nodeRef.current, debouncedExpression, { ...debouncedLoaderParams, // react component wrapper provides different // error handling api which is easier to work with from react // if custom renderError is not provided then we fallback to default error handling from ExpressionLoader onRenderError: (domNode, newError, handlers) => { var _debouncedLoaderParam; errorRenderHandlerRef.current = handlers; setState({ error: newError, isEmpty: false, isLoading: false }); return (_debouncedLoaderParam = debouncedLoaderParams.onRenderError) === null || _debouncedLoaderParam === void 0 ? void 0 : _debouncedLoaderParam.call(debouncedLoaderParams, domNode, newError, handlers); } }); const subscription = (_expressionLoaderRef$ = expressionLoaderRef.current) === null || _expressionLoaderRef$ === void 0 ? void 0 : _expressionLoaderRef$.loading$.subscribe(() => { hasHandledErrorRef.current = false; setState({ isLoading: true }); }); return () => { var _expressionLoaderRef$2; subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe(); (_expressionLoaderRef$2 = expressionLoaderRef.current) === null || _expressionLoaderRef$2 === void 0 ? void 0 : _expressionLoaderRef$2.destroy(); expressionLoaderRef.current = null; errorRenderHandlerRef.current = null; }; }, [debouncedLoaderParams.onRenderError, debouncedLoaderParams.interactive, debouncedLoaderParams.renderMode, debouncedLoaderParams.syncColors, debouncedLoaderParams.syncTooltips, debouncedLoaderParams.syncCursor]); (0, _react.useEffect)(() => { var _expressionLoaderRef$3; const subscription = onEvent && ((_expressionLoaderRef$3 = expressionLoaderRef.current) === null || _expressionLoaderRef$3 === void 0 ? void 0 : _expressionLoaderRef$3.events$.subscribe(onEvent)); return () => subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe(); }, [expressionLoaderRef.current, onEvent]); (0, _react.useEffect)(() => { var _expressionLoaderRef$4; const subscription = (_expressionLoaderRef$4 = expressionLoaderRef.current) === null || _expressionLoaderRef$4 === void 0 ? void 0 : _expressionLoaderRef$4.data$.subscribe(({ partial, result }) => { var _expressionLoaderRef$5; setState({ isEmpty: false, ...(!(0, _common.isExpressionValueError)(result) ? { error: null } : {}) }); onData$ === null || onData$ === void 0 ? void 0 : onData$(result, (_expressionLoaderRef$5 = expressionLoaderRef.current) === null || _expressionLoaderRef$5 === void 0 ? void 0 : _expressionLoaderRef$5.inspect(), partial); }); return () => subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe(); }, [expressionLoaderRef.current, onData$]); (0, _react.useEffect)(() => { var _expressionLoaderRef$6; const subscription = (_expressionLoaderRef$6 = expressionLoaderRef.current) === null || _expressionLoaderRef$6 === void 0 ? void 0 : _expressionLoaderRef$6.render$.pipe((0, _operators.filter)(() => !hasHandledErrorRef.current)).subscribe(item => { setState({ error: null, isEmpty: false, isLoading: false }); onRender$ === null || onRender$ === void 0 ? void 0 : onRender$(item); }); return () => { subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe(); }; }, [expressionLoaderRef.current, onRender$]); /* eslint-enable react-hooks/exhaustive-deps */ (0, _react.useEffect)(() => { const subscription = reload$ === null || reload$ === void 0 ? void 0 : reload$.subscribe(() => { var _expressionLoaderRef$7; (_expressionLoaderRef$7 = expressionLoaderRef.current) === null || _expressionLoaderRef$7 === void 0 ? void 0 : _expressionLoaderRef$7.update(debouncedExpression, debouncedLoaderParams); }); return () => subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe(); }, [reload$, debouncedExpression, debouncedLoaderParams]); (0, _useUpdateEffect.default)(() => { var _expressionLoaderRef$8; (_expressionLoaderRef$8 = expressionLoaderRef.current) === null || _expressionLoaderRef$8 === void 0 ? void 0 : _expressionLoaderRef$8.update(debouncedExpression, debouncedLoaderParams); }, [debouncedExpression, debouncedLoaderParams]); // call expression loader's done() handler when finished rendering custom error state (0, _react.useLayoutEffect)(() => { if (error && hasCustomErrorRenderer) { var _errorRenderHandlerRe; hasHandledErrorRef.current = true; (_errorRenderHandlerRe = errorRenderHandlerRef.current) === null || _errorRenderHandlerRe === void 0 ? void 0 : _errorRenderHandlerRe.done(); } errorRenderHandlerRef.current = null; }, [error, hasCustomErrorRenderer]); return { error, isEmpty, isLoading: isLoading || isDebounced }; }