UNPKG

survey-react-ui

Version:

survey.js is a JavaScript Survey Library. It is a modern way to add a survey to your website. It uses JSON for survey metadata and results.

1,393 lines (1,370 loc) 332 kB
/*! * surveyjs - Survey JavaScript library v2.0.4 * Copyright (c) 2015-2025 Devsoft Baltic OÜ - http://surveyjs.io/ * License: MIT (http://www.opensource.org/licenses/mit-license.php) */ import { SurveyModel, Helpers, createSvg, createPopupViewModel, CssClassBuilder, ActionDropdownViewModel, RendererFactory, doKey2ClickUp, Question, SvgRegistry, settings, createPopupModalViewModel, ScrollViewModel, doKey2ClickBlur, doKey2ClickDown, addIconsToThemeSet, SurveyProgressModel, ProgressButtonsResponsivityManager, PopupSurveyModel, ButtonGroupItemModel, LocalizableString, checkLibraryVersion } from 'survey-core'; export { SurveyModel as Model, SurveyModel, SurveyWindowModel, settings, surveyLocalization, surveyStrings } from 'survey-core'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { createPortal } from 'react-dom'; class ReactElementFactory { constructor() { this.creatorHash = {}; } registerElement(elementType, elementCreator) { this.creatorHash[elementType] = elementCreator; } getAllTypes() { var result = new Array(); for (var key in this.creatorHash) { result.push(key); } return result.sort(); } isElementRegistered(elementType) { return !!this.creatorHash[elementType]; } createElement(elementType, params) { var creator = this.creatorHash[elementType]; if (creator == null) return null; return creator(params); } } ReactElementFactory.Instance = new ReactElementFactory(); class ReactSurveyElementsWrapper { static wrapRow(survey, element, row) { const componentName = survey.getRowWrapperComponentName(row); const componentData = survey.getRowWrapperComponentData(row); return ReactElementFactory.Instance.createElement(componentName, { element, row, componentData, }); } static wrapElement(survey, element, question) { const componentName = survey.getElementWrapperComponentName(question); const componentData = survey.getElementWrapperComponentData(question); return ReactElementFactory.Instance.createElement(componentName, { element, question, componentData, }); } static wrapQuestionContent(survey, element, question) { const componentName = survey.getQuestionContentWrapperComponentName(question); const componentData = survey.getElementWrapperComponentData(question); return ReactElementFactory.Instance.createElement(componentName, { element, question, componentData, }); } static wrapItemValue(survey, element, question, item) { const componentName = survey.getItemValueWrapperComponentName(item, question); const componentData = survey.getItemValueWrapperComponentData(item, question); return ReactElementFactory.Instance.createElement(componentName, { key: element === null || element === void 0 ? void 0 : element.key, element, question, item, componentData, }); } static wrapMatrixCell(survey, element, cell, reason = "cell") { const componentName = survey.getElementWrapperComponentName(cell, reason); const componentData = survey.getElementWrapperComponentData(cell, reason); return ReactElementFactory.Instance.createElement(componentName, { element, cell, componentData, }); } } SurveyModel.platform = "react"; class SurveyElementBase extends React.Component { static renderLocString(locStr, style = null, key) { return ReactElementFactory.Instance.createElement(locStr.renderAs, { locStr: locStr.renderAsData, style: style, key: key, }); } static renderQuestionDescription(question) { var descriptionText = SurveyElementBase.renderLocString(question.locDescription); return React.createElement("div", { style: question.hasDescription ? undefined : { display: "none" }, id: question.ariaDescriptionId, className: question.cssDescription }, descriptionText); } constructor(props) { super(props); this._allowComponentUpdate = true; this.prevStateElements = []; this.propertyValueChangedHandler = (hash, key, val) => { if (hash[key] !== val) { hash[key] = val; if (!this.canUsePropInState(key)) return; if (this.isRendering) return; this.changedStatePropNameValue = key; this.setState((state) => { var newState = {}; newState[key] = val; return newState; }); } }; } componentDidMount() { this.makeBaseElementsReact(); } componentWillUnmount() { this.unMakeBaseElementsReact(); this.disableStateElementsRerenderEvent(this.getStateElements()); } componentDidUpdate(prevProps, prevState) { var _a; this.makeBaseElementsReact(); const stateElements = this.getStateElements(); this.disableStateElementsRerenderEvent(((_a = this.prevStateElements) !== null && _a !== void 0 ? _a : []).filter(el => !stateElements.find(stateElement => stateElement == el))); this.prevStateElements = []; this.getStateElements().forEach((el) => { el.afterRerender(); }); } allowComponentUpdate() { this._allowComponentUpdate = true; this.forceUpdate(); } denyComponentUpdate() { this._allowComponentUpdate = false; } shouldComponentUpdate(nextProps, nextState) { if (this._allowComponentUpdate) { this.unMakeBaseElementsReact(); this.prevStateElements = this.getStateElements(); } return this._allowComponentUpdate; } render() { if (!this.canRender()) { return null; } this.startEndRendering(1); var res = this.renderElement(); this.startEndRendering(-1); if (!!res) { res = this.wrapElement(res); } this.changedStatePropNameValue = undefined; return res; } wrapElement(element) { return element; } get isRendering() { var stateEls = this.getRenderedElements(); for (let stateEl of stateEls) { if (stateEl.reactRendering > 0) return true; } return false; } getRenderedElements() { return this.getStateElements(); } startEndRendering(val) { var stateEls = this.getRenderedElements(); for (let stateEl of stateEls) { if (!stateEl.reactRendering) stateEl.reactRendering = 0; stateEl.reactRendering += val; } } canRender() { return true; } renderElement() { return null; } get changedStatePropName() { return this.changedStatePropNameValue; } makeBaseElementsReact() { var els = this.getStateElements(); for (var i = 0; i < els.length; i++) { els[i].enableOnElementRerenderedEvent(); this.makeBaseElementReact(els[i]); } } unMakeBaseElementsReact() { var els = this.getStateElements(); this.unMakeBaseElementsReactive(els); } unMakeBaseElementsReactive(els) { for (var i = 0; i < els.length; i++) { this.unMakeBaseElementReact(els[i]); } } disableStateElementsRerenderEvent(els) { els.forEach(el => { el.disableOnElementRerenderedEvent(); }); } getStateElements() { var el = this.getStateElement(); return !!el ? [el] : []; } getStateElement() { return null; } get isDisplayMode() { const props = this.props; return props.isDisplayMode || false; } renderLocString(locStr, style = null, key) { return SurveyElementBase.renderLocString(locStr, style, key); } canMakeReact(stateElement) { return !!stateElement && !!stateElement.iteratePropertiesHash; } isCurrentStateElement(stateElement) { return !!stateElement && !!stateElement.setPropertyValueCoreHandler && stateElement.setPropertyValueCoreHandler === this.propertyValueChangedHandler; } makeBaseElementReact(stateElement) { if (!this.canMakeReact(stateElement)) return; stateElement.iteratePropertiesHash((hash, key) => { if (!this.canUsePropInState(key)) return; var val = hash[key]; if (Array.isArray(val)) { var val = val; val["onArrayChanged"] = (arrayChanges) => { if (this.isRendering) return; this.changedStatePropNameValue = key; this.setState((state) => { var newState = {}; newState[key] = val; return newState; }); }; } }); stateElement.setPropertyValueCoreHandler = this.propertyValueChangedHandler; } canUsePropInState(key) { return true; } unMakeBaseElementReact(stateElement) { if (!this.canMakeReact(stateElement)) return; if (!this.isCurrentStateElement(stateElement)) ; stateElement.setPropertyValueCoreHandler = undefined; stateElement.iteratePropertiesHash((hash, key) => { var val = hash[key]; if (Array.isArray(val)) { var val = val; val["onArrayChanged"] = () => { }; } }); } } class ReactSurveyElement extends SurveyElementBase { constructor(props) { super(props); } get cssClasses() { return this.props.cssClasses; } } class SurveyQuestionElementBase extends SurveyElementBase { constructor(props) { super(props); } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); this.updateDomElement(); } componentDidMount() { super.componentDidMount(); this.updateDomElement(); } componentWillUnmount() { super.componentWillUnmount(); if (!!this.questionBase) { const contentElement = this.content || this.control; this.questionBase.beforeDestroyQuestionElement(contentElement); if (!!contentElement) { contentElement.removeAttribute("data-rendered"); } } } updateDomElement() { const contentElement = this.content || this.control; if (!!contentElement) { if (contentElement.getAttribute("data-rendered") !== "r") { contentElement.setAttribute("data-rendered", "r"); this.questionBase.afterRenderQuestionElement(contentElement); } } } get questionBase() { return this.props.question; } getRenderedElements() { return [this.questionBase]; } get creator() { return this.props.creator; } canRender() { return !!this.questionBase && !!this.creator; } shouldComponentUpdate(nextProps, nextState) { if (!super.shouldComponentUpdate(nextProps, nextState)) return false; return (!this.questionBase.customWidget || !!this.questionBase.customWidgetData.isNeedRender || !!this.questionBase.customWidget.widgetJson.isDefaultRender || !!this.questionBase.customWidget.widgetJson.render); } get isDisplayMode() { const props = this.props; return (props.isDisplayMode || (!!this.questionBase && this.questionBase.isInputReadOnly) || false); } wrapCell(cell, element, reason) { if (!reason) { return element; } const survey = this.questionBase .survey; let wrapper = null; if (survey) { wrapper = ReactSurveyElementsWrapper.wrapMatrixCell(survey, element, cell, reason); } return wrapper !== null && wrapper !== void 0 ? wrapper : element; } setControl(element) { if (!!element) { this.control = element; } } setContent(element) { if (!!element) { this.content = element; } } } class SurveyQuestionUncontrolledElement extends SurveyQuestionElementBase { constructor(props) { super(props); this.updateValueOnEvent = (event) => { if (!Helpers.isTwoValueEquals(this.questionBase.value, event.target.value, false, true, false)) { this.setValueCore(event.target.value); } }; this.updateValueOnEvent = this.updateValueOnEvent.bind(this); } get question() { return this.questionBase; } setValueCore(newValue) { this.questionBase.value = newValue; } getValueCore() { return this.questionBase.value; } updateDomElement() { if (!!this.control) { const control = this.control; const newValue = this.getValueCore(); if (!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)) { control.value = this.getValue(newValue); } } super.updateDomElement(); } getValue(val) { if (Helpers.isValueEmpty(val)) return ""; return val; } } class SurveyRowElement extends SurveyElementBase { constructor(props) { super(props); this.element.cssClasses; this.rootRef = React.createRef(); } getStateElement() { return this.element; } get element() { return this.props.element; } get index() { return this.props.index; } get row() { return this.props.row; } get survey() { return this.props.survey; } get creator() { return this.props.creator; } get css() { return this.props.css; } componentDidMount() { super.componentDidMount(); if (this.rootRef.current) { (this.element).setWrapperElement(this.rootRef.current); } } componentWillUnmount() { super.componentWillUnmount(); this.element.setWrapperElement(undefined); } shouldComponentUpdate(nextProps, nextState) { if (!super.shouldComponentUpdate(nextProps, nextState)) return false; if (nextProps.element !== this.element) { if (nextProps.element) { nextProps.element.setWrapperElement(this.rootRef.current); } if (this.element) { this.element.setWrapperElement(undefined); } } this.element.cssClasses; return true; } renderElement() { const element = this.element; const innerElement = this.createElement(element, this.index); const css = element.cssClassesValue; const focusIn = () => { const el = element; if (el && el.isQuestion) { el.focusIn(); } }; return (React.createElement("div", { className: css.questionWrapper, style: element.rootStyle, "data-key": element.name + this.index, onFocus: focusIn, ref: this.rootRef }, innerElement)); } createElement(element, elementIndex) { if (!this.row.isNeedRender) { return ReactElementFactory.Instance.createElement(element.skeletonComponentName, { element: element, css: this.css, }); } let elementType = element.getTemplate(); if (!ReactElementFactory.Instance.isElementRegistered(elementType)) { elementType = "question"; } return ReactElementFactory.Instance.createElement(elementType, { element: element, creator: this.creator, survey: this.survey, css: this.css, }); } } class SurveyRow extends SurveyElementBase { constructor(props) { super(props); this.rootRef = React.createRef(); this.recalculateCss(); } recalculateCss() { this.row.visibleElements.map(element => element.cssClasses); } getStateElement() { return this.row; } get row() { return this.props.row; } get survey() { return this.props.survey; } get creator() { return this.props.creator; } get css() { return this.props.css; } canRender() { return !!this.row && !!this.survey && !!this.creator; } renderElementContent() { const elements = this.row.visibleElements.map((element, elementIndex) => { return (React.createElement(SurveyRowElement, { element: element, index: elementIndex, row: this.row, survey: this.survey, creator: this.creator, css: this.css, key: element.id })); }); return (React.createElement("div", { ref: this.rootRef, className: this.row.getRowCss() }, elements)); } renderElement() { const survey = this.survey; const content = this.renderElementContent(); const wrapper = ReactSurveyElementsWrapper.wrapRow(survey, content, this.row); return wrapper || content; } componentDidMount() { super.componentDidMount(); var el = this.rootRef.current; if (this.rootRef.current) { this.row.setRootElement(this.rootRef.current); } if (!!el && !this.row.isNeedRender) { var rowContainerDiv = el; setTimeout(() => { this.row.startLazyRendering(rowContainerDiv); }, 10); } } shouldComponentUpdate(nextProps, nextState) { if (!super.shouldComponentUpdate(nextProps, nextState)) return false; if (nextProps.row !== this.row) { nextProps.row.isNeedRender = this.row.isNeedRender; nextProps.row.setRootElement(this.rootRef.current); this.row.setRootElement(undefined); this.stopLazyRendering(); } this.recalculateCss(); return true; } stopLazyRendering() { this.row.stopLazyRendering(); this.row.isNeedRender = !this.row.isLazyRendering(); } componentWillUnmount() { super.componentWillUnmount(); if (this.isCurrentStateElement(this.getStateElement())) { this.row.setRootElement(undefined); this.stopLazyRendering(); } } createElement(element, elementIndex) { const index = elementIndex ? "-" + elementIndex : 0; var elementType = element.getType(); if (!ReactElementFactory.Instance.isElementRegistered(elementType)) { elementType = "question"; } return ReactElementFactory.Instance.createElement(elementType, { key: element.name + index, element: element, creator: this.creator, survey: this.survey, css: this.css, }); } } class SurveyPanelBase extends SurveyElementBase { constructor(props) { super(props); this.rootRef = React.createRef(); } getStateElement() { return this.panelBase; } canUsePropInState(key) { return key !== "elements" && super.canUsePropInState(key); } get survey() { return this.getSurvey(); } get creator() { return this.props.creator; } get css() { return this.getCss(); } get panelBase() { return this.getPanelBase(); } getPanelBase() { return this.props.element || this.props.question; } getSurvey() { return (this.props.survey || (!!this.panelBase ? this.panelBase.survey : null)); } getCss() { return this.props.css; } componentDidMount() { super.componentDidMount(); this.doAfterRender(); } componentWillUnmount() { super.componentWillUnmount(); var el = this.rootRef.current; if (!!el) { el.removeAttribute("data-rendered"); } } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); if (!!prevProps.page && !!this.survey && !!this.survey.activePage && prevProps.page.id === this.survey.activePage.id) return; this.doAfterRender(); } doAfterRender() { var el = this.rootRef.current; if (el && this.survey) { if (this.panelBase.isPanel) { this.panelBase.afterRender(el); } else { this.survey.afterRenderPage(el); } } } getIsVisible() { return this.panelBase.isVisible; } canRender() { return (super.canRender() && !!this.survey && !!this.panelBase && !!this.panelBase.survey && this.getIsVisible()); } renderRows(css) { return this.panelBase.visibleRows.map((row) => this.createRow(row, css)); } createRow(row, css) { return (React.createElement(SurveyRow, { key: row.id, row: row, survey: this.survey, creator: this.creator, css: css })); } } class SvgIcon extends React.Component { constructor(props) { super(props); this.svgIconRef = React.createRef(); } updateSvg() { if (this.props.iconName) createSvg(this.props.size, this.props.width, this.props.height, this.props.iconName, this.svgIconRef.current, this.props.title); } componentDidUpdate() { this.updateSvg(); } render() { let className = "sv-svg-icon"; if (this.props.className) { className += " " + this.props.className; } return (this.props.iconName ? React.createElement("svg", { className: className, style: this.props.style, onClick: this.props.onClick, ref: this.svgIconRef, role: "presentation" }, React.createElement("use", null)) : null); } componentDidMount() { this.updateSvg(); } } ReactElementFactory.Instance.registerElement("sv-svg-icon", (props) => { return React.createElement(SvgIcon, props); }); class SurveyActionBarSeparator extends React.Component { constructor(props) { super(props); } render() { var className = `sv-action-bar-separator ${this.props.cssClasses}`; return React.createElement("div", { className: className }); } } ReactElementFactory.Instance.registerElement("sv-action-bar-separator", (props) => { return React.createElement(SurveyActionBarSeparator, props); }); class SurveyAction extends SurveyElementBase { constructor(props) { super(props); this.ref = React.createRef(); } get item() { return this.props.item; } getStateElement() { return this.item; } renderElement() { //refactor const itemClass = this.item.getActionRootCss(); const separator = this.item.needSeparator ? (React.createElement(SurveyActionBarSeparator, null)) : null; const itemComponent = ReactElementFactory.Instance.createElement(this.item.component || "sv-action-bar-item", { item: this.item, }); return (React.createElement("div", { className: itemClass, id: this.item.id, ref: this.ref }, React.createElement("div", { className: "sv-action__content" }, separator, itemComponent))); } componentWillUnmount() { super.componentWillUnmount(); this.item.updateModeCallback = undefined; } componentDidMount() { super.componentDidMount(); this.item.updateModeCallback = (mode, callback) => { queueMicrotask(() => { if (ReactDOM["flushSync"]) { ReactDOM["flushSync"](() => { this.item.mode = mode; }); } else { this.item.mode = mode; } queueMicrotask(() => { callback(mode, this.ref.current); }); }); }; this.item.afterRender(); } } class SurveyActionBarItem extends SurveyElementBase { get item() { return this.props.item; } getStateElement() { return this.item; } renderElement() { return React.createElement(React.Fragment, null, this.renderInnerButton()); } renderText() { if (!this.item.hasTitle) return null; const titleClass = this.item.getActionBarItemTitleCss(); return React.createElement("span", { className: titleClass }, this.item.title); } renderButtonContent() { const text = this.renderText(); const svgIcon = !!this.item.iconName ? (React.createElement(SvgIcon, { className: this.item.cssClasses.itemIcon, size: this.item.iconSize, iconName: this.item.iconName, title: this.item.tooltip || this.item.title })) : null; return (React.createElement(React.Fragment, null, svgIcon, text)); } renderInnerButton() { const className = this.item.getActionBarItemCss(); const title = this.item.tooltip || this.item.title; const buttonContent = this.renderButtonContent(); const tabIndex = this.item.disableTabStop ? -1 : undefined; const button = attachKey2click(React.createElement("button", { className: className, type: "button", disabled: this.item.disabled, onMouseDown: (args) => this.item.doMouseDown(args), onFocus: (args) => this.item.doFocus(args), onClick: (args) => this.item.doAction(args), title: title, tabIndex: tabIndex, "aria-checked": this.item.ariaChecked, "aria-expanded": this.item.ariaExpanded, role: this.item.ariaRole }, buttonContent), this.item, { processEsc: false }); return button; } } ReactElementFactory.Instance.registerElement("sv-action-bar-item", (props) => { return React.createElement(SurveyActionBarItem, props); }); class Popup extends SurveyElementBase { constructor(props) { super(props); this.containerRef = React.createRef(); this.createModel(); } get model() { return this.props.model; } getStateElement() { return this.model; } createModel() { this.popup = createPopupViewModel(this.props.model); } setTargetElement() { const container = this.containerRef.current; this.popup.setComponentElement(container); } componentDidMount() { super.componentDidMount(); this.setTargetElement(); } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); this.setTargetElement(); } componentWillUnmount() { super.componentWillUnmount(); this.popup.resetComponentElement(); } shouldComponentUpdate(nextProps, nextState) { var _a; if (!super.shouldComponentUpdate(nextProps, nextState)) return false; const isNeedUpdate = nextProps.model !== this.popup.model; if (isNeedUpdate) { (_a = this.popup) === null || _a === void 0 ? void 0 : _a.dispose(); this.createModel(); } return isNeedUpdate; } render() { this.popup.model = this.model; let popupContainer; if (this.model.isModal) { popupContainer = React.createElement(PopupContainer, { model: this.popup }); } else { popupContainer = React.createElement(PopupDropdownContainer, { model: this.popup }); } return React.createElement("div", { ref: this.containerRef }, popupContainer); } } ReactElementFactory.Instance.registerElement("sv-popup", (props) => { return React.createElement(Popup, props); }); class PopupContainer extends SurveyElementBase { constructor(props) { super(props); this.handleKeydown = (event) => { this.model.onKeyDown(event); }; this.clickInside = (ev) => { ev.stopPropagation(); }; } get model() { return this.props.model; } getStateElement() { return this.model; } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); if (!this.model.isPositionSet && this.model.isVisible) { this.model.updateOnShowing(); } } renderContainer(popupBaseViewModel) { const headerPopup = popupBaseViewModel.showHeader ? this.renderHeaderPopup(popupBaseViewModel) : null; const headerContent = !!popupBaseViewModel.title ? this.renderHeaderContent() : null; const content = this.renderContent(); const footerContent = popupBaseViewModel.showFooter ? this.renderFooter(this.model) : null; return (React.createElement("div", { className: "sv-popup__container", style: { left: popupBaseViewModel.left, top: popupBaseViewModel.top, height: popupBaseViewModel.height, width: popupBaseViewModel.width, minWidth: popupBaseViewModel.minWidth, }, onClick: (ev) => { this.clickInside(ev); } }, headerPopup, React.createElement("div", { className: "sv-popup__body-content" }, headerContent, React.createElement("div", { className: "sv-popup__scrolling-content" }, content), footerContent))); } renderHeaderContent() { return React.createElement("div", { className: "sv-popup__body-header" }, this.model.title); } renderContent() { const contentComponent = ReactElementFactory.Instance.createElement(this.model.contentComponentName, this.model.contentComponentData); return React.createElement("div", { className: "sv-popup__content" }, contentComponent); } renderHeaderPopup(popupModel) { return null; } renderFooter(popuModel) { return (React.createElement("div", { className: "sv-popup__body-footer" }, React.createElement(SurveyActionBar, { model: popuModel.footerToolbar }))); } render() { const container = this.renderContainer(this.model); const className = new CssClassBuilder() .append("sv-popup") .append(this.model.styleClass) .toString(); const style = { display: this.model.isVisible ? "" : "none", }; return (React.createElement("div", { tabIndex: -1, className: className, style: style, onClick: (e) => { this.model.clickOutside(e); }, onKeyDown: this.handleKeydown }, container)); } componentDidMount() { super.componentDidMount(); if (this.model.isVisible) { this.model.updateOnShowing(); } } } class PopupDropdownContainer extends PopupContainer { renderHeaderPopup(popupModel) { const popupDropdownModel = popupModel; if (!popupDropdownModel) return null; return (React.createElement("span", { style: { left: popupDropdownModel.pointerTarget.left, top: popupDropdownModel.pointerTarget.top, }, className: "sv-popup__pointer" })); } } class SurveyActionBarItemDropdown extends SurveyActionBarItem { constructor(props) { super(props); } renderInnerButton() { const button = super.renderInnerButton(); return (React.createElement(React.Fragment, null, button, React.createElement(Popup, { model: this.item.popupModel }))); } componentDidMount() { this.viewModel = new ActionDropdownViewModel(this.item); } componentWillUnmount() { super.componentWillUnmount(); this.viewModel.dispose(); } } ReactElementFactory.Instance.registerElement("sv-action-bar-item-dropdown", (props) => { return React.createElement(SurveyActionBarItemDropdown, props); }); class SurveyActionBar extends SurveyElementBase { constructor(props) { super(props); this.rootRef = React.createRef(); } get handleClick() { return this.props.handleClick !== undefined ? this.props.handleClick : true; } get model() { return this.props.model; } componentDidMount() { super.componentDidMount(); if (!this.model.hasActions) return; const container = this.rootRef.current; if (!!container) { this.model.initResponsivityManager(container, (callback) => { setTimeout(callback, 100); }); } } componentWillUnmount() { super.componentWillUnmount(); this.model.resetResponsivityManager(); } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); if (prevProps.model != this.props.model) { prevProps.model.resetResponsivityManager(); } if (!!this.model.hasActions) { const container = this.rootRef.current; if (!!container) { this.model.initResponsivityManager(container, (callback) => { setTimeout(callback, 100); }); } } } getStateElement() { return this.model; } renderElement() { if (!this.model.hasActions) return null; const items = this.renderItems(); return (React.createElement("div", { ref: this.rootRef, className: this.model.getRootCss(), onClick: this.handleClick ? function (event) { event.stopPropagation(); } : undefined }, items)); } renderItems() { return this.model.renderedActions.concat([]).map((item, itemIndex) => { return (React.createElement(SurveyAction, { item: item, key: item.renderedId })); }); } } ReactElementFactory.Instance.registerElement("sv-action-bar", (props) => { return React.createElement(SurveyActionBar, props); }); class TitleContent extends React.Component { constructor(props) { super(props); } get cssClasses() { return this.props.cssClasses; } get element() { return this.props.element; } render() { if (this.element.isTitleRenderedAsString) return SurveyElementBase.renderLocString(this.element.locTitle); var spans = this.renderTitleSpans(this.element.getTitleOwner(), this.cssClasses); return React.createElement(React.Fragment, null, spans); } renderTitleSpans(element, cssClasses) { var getSpaceSpan = (key) => { return (React.createElement("span", { "data-key": key, key: key }, "\u00A0")); }; var spans = []; if (element.isRequireTextOnStart) { spans.push(this.renderRequireText(element)); spans.push(getSpaceSpan("req-sp")); } var questionNumber = element.no; if (questionNumber) { spans.push(React.createElement("span", { "data-key": "q_num", key: "q_num", className: element.cssTitleNumber, style: { position: "static" }, "aria-hidden": true }, questionNumber)); spans.push(getSpaceSpan("num-sp")); } if (element.isRequireTextBeforeTitle) { spans.push(this.renderRequireText(element)); spans.push(getSpaceSpan("req-sp")); } spans.push(SurveyElementBase.renderLocString(element.locTitle, null, "q_title")); if (element.isRequireTextAfterTitle) { spans.push(getSpaceSpan("req-sp")); spans.push(this.renderRequireText(element)); } return spans; } renderRequireText(element) { return (React.createElement("span", { "data-key": "req-text", key: "req-text", className: element.cssRequiredMark, "aria-hidden": true }, element.requiredMark)); } } class TitleActions extends React.Component { get cssClasses() { return this.props.cssClasses; } get element() { return this.props.element; } render() { const titleContent = React.createElement(TitleContent, { element: this.element, cssClasses: this.cssClasses }); if (!this.element.hasTitleActions) return titleContent; return (React.createElement("div", { className: "sv-title-actions" }, React.createElement("span", { className: "sv-title-actions__title" }, titleContent), React.createElement(SurveyActionBar, { model: this.element.getTitleToolbar() }))); } } RendererFactory.Instance.registerRenderer("element", "title-actions", "sv-title-actions"); ReactElementFactory.Instance.registerElement("sv-title-actions", (props) => { return React.createElement(TitleActions, props); }); class TitleElement extends React.Component { constructor(props) { super(props); } get element() { return this.props.element; } renderTitleExpandableSvg() { if (!this.element.getCssTitleExpandableSvg()) return null; let iconName = this.element.isExpanded ? "icon-collapse-16x16" : "icon-expand-16x16"; return React.createElement(SvgIcon, { className: this.element.getCssTitleExpandableSvg(), iconName: iconName, size: "auto" }); } render() { const element = this.element; if (!element || !element.hasTitle) return null; const ariaLabel = element.titleAriaLabel || undefined; const titleExpandableSvg = this.renderTitleExpandableSvg(); const titleContent = (React.createElement(TitleActions, { element: element, cssClasses: element.cssClasses })); let onClick = undefined; let onKeyUp = undefined; if (element.hasTitleEvents) { onKeyUp = (evt) => { doKey2ClickUp(evt.nativeEvent); }; } const CustomTag = element.titleTagName; return (React.createElement(CustomTag, { className: element.cssTitle, id: element.ariaTitleId, "aria-label": ariaLabel, tabIndex: element.titleTabIndex, "aria-expanded": element.titleAriaExpanded, role: element.titleAriaRole, onClick: onClick, onKeyUp: onKeyUp }, titleExpandableSvg, titleContent)); } } class ReactQuestionFactory { constructor() { this.creatorHash = {}; } registerQuestion(questionType, questionCreator) { this.creatorHash[questionType] = questionCreator; } getAllTypes() { var result = new Array(); for (var key in this.creatorHash) { result.push(key); } return result.sort(); } createQuestion(questionType, params) { var creator = this.creatorHash[questionType]; if (creator == null) return null; return creator(params); } } ReactQuestionFactory.Instance = new ReactQuestionFactory(); class CharacterCounterComponent extends SurveyElementBase { getStateElement() { return this.props.counter; } renderElement() { return (React.createElement("div", { className: this.props.remainingCharacterCounter }, this.props.counter.remainingCharacterCounter)); } } ReactElementFactory.Instance.registerElement("sv-character-counter", (props) => { return React.createElement(CharacterCounterComponent, props); }); class TextAreaComponent extends SurveyElementBase { constructor(props) { super(props); this.initialValue = this.viewModel.getTextValue() || ""; this.textareaRef = React.createRef(); } get viewModel() { return this.props.viewModel; } canRender() { return !!this.viewModel.question; } componentDidMount() { super.componentDidMount(); let el = this.textareaRef.current; if (!!el) { this.viewModel.setElement(el); } } componentWillUnmount() { super.componentWillUnmount(); this.viewModel.resetElement(); } renderElement() { return (React.createElement("textarea", { id: this.viewModel.id, className: this.viewModel.className, ref: this.textareaRef, disabled: this.viewModel.isDisabledAttr, readOnly: this.viewModel.isReadOnlyAttr, rows: this.viewModel.rows, cols: this.viewModel.cols, placeholder: this.viewModel.placeholder, maxLength: this.viewModel.maxLength, defaultValue: this.initialValue, onChange: (event) => { this.viewModel.onTextAreaInput(event); }, onFocus: (event) => { this.viewModel.onTextAreaFocus(event); }, onBlur: (event) => { this.viewModel.onTextAreaBlur(event); }, onKeyDown: (event) => { this.viewModel.onTextAreaKeyDown(event); }, "aria-required": this.viewModel.ariaRequired, "aria-label": this.viewModel.ariaLabel, "aria-labelledby": this.viewModel.ariaLabelledBy, "aria-describedby": this.viewModel.ariaDescribedBy, "aria-invalid": this.viewModel.ariaInvalid, "aria-errormessage": this.viewModel.ariaErrormessage, style: { resize: this.viewModel.question.resizeStyle } })); } } ReactElementFactory.Instance.registerElement("sv-text-area", (props) => { return React.createElement(TextAreaComponent, props); }); class SurveyQuestionComment extends SurveyQuestionUncontrolledElement { renderCharacterCounter() { let counter = null; if (!!this.question.getMaxLength()) { counter = React.createElement(CharacterCounterComponent, { counter: this.question.characterCounter, remainingCharacterCounter: this.question.cssClasses.remainingCharacterCounter }); } return counter; } constructor(props) { super(props); } renderElement() { if (this.question.isReadOnlyRenderDiv()) { return React.createElement("div", null, this.question.value); } const counter = this.renderCharacterCounter(); const textAreaModel = this.props.question.textAreaModel; return (React.createElement(React.Fragment, null, React.createElement(TextAreaComponent, { viewModel: textAreaModel }), counter)); } } class SurveyQuestionCommentItem extends ReactSurveyElement { constructor(props) { super(props); this.textAreaModel = this.getTextAreaModel(); } canRender() { return !!this.props.question; } getTextAreaModel() { return this.props.question.commentTextAreaModel; } renderElement() { const question = this.props.question; if (question.isReadOnlyRenderDiv()) { const comment = this.textAreaModel.getTextValue() || ""; return React.createElement("div", null, comment); } return (React.createElement(TextAreaComponent, { viewModel: this.textAreaModel })); } } class SurveyQuestionOtherValueItem extends SurveyQuestionCommentItem { getTextAreaModel() { return this.props.question.otherTextAreaModel; } } ReactQuestionFactory.Instance.registerQuestion("comment", (props) => { return React.createElement(SurveyQuestionComment, props); }); class SurveyCustomWidget extends SurveyQuestionElementBase { constructor(props) { super(props); this.widgetRef = React.createRef(); } _afterRender() { if (this.questionBase.customWidget) { let el = this.widgetRef.current; if (!!el) { this.questionBase.customWidget.afterRender(this.questionBase, el); this.questionBase.customWidgetData.isNeedRender = false; } } } componentDidMount() { super.componentDidMount(); if (this.questionBase) { this._afterRender(); } } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); var isDefaultRender = !!this.questionBase.customWidget && this.questionBase.customWidget.isDefaultRender; if (this.questionBase && !isDefaultRender) { this._afterRender(); } } componentWillUnmount() { super.componentWillUnmount(); if (this.questionBase.customWidget) { let el = this.widgetRef.current; if (!!el) { this.questionBase.customWidget.willUnmount(this.questionBase, el); } } } canRender() { return super.canRender() && this.questionBase.visible; } renderElement() { let customWidget = this.questionBase.customWidget; if (customWidget.isDefaultRender) { return (React.createElement("div", { ref: this.widgetRef }, this.creator.createQuestionElement(this.questionBase))); } let widget = null; if (customWidget.widgetJson.render) { widget = customWidget.widgetJson.render(this.questionBase); } else { if (customWidget.htmlTemplate) { let htmlValue = { __html: customWidget.htmlTemplate }; return React.createElement("div", { ref: this.widgetRef, dangerouslySetInnerHTML: htmlValue }); } } return React.createElement("div", { ref: this.widgetRef }, widget); } } class SurveyElementHeader extends SurveyElementBase { get element() { return this.props.element; } getRenderedElements() { return [this.element]; } renderElement() { const element = this.element; const title = element.hasTitle ? (React.createElement(TitleElement, { element: element })) : null; const description = element.hasDescriptionUnderTitle ? SurveyElementBase.renderQuestionDescription(this.element) : null; const additionalTitleToolbarElement = element.hasAdditionalTitleToolbar ? React.createElement(SurveyActionBar, { model: element.additionalTitleToolbar }) : null; const headerStyle = { width: undefined }; if (element instanceof Question) { headerStyle.width = element.titleWidth; } return (React.createElement("div", { className: element.cssHeader, onClick: (e) => element.clickTitleFunction && element.clickTitleFunction(e.nativeEvent), style: headerStyle }, title, description, additionalTitleToolbarElement)); } } class SurveyQuestion extends SurveyElementBase { static renderQuestionBody(creator, question) { // if (!question.isVisible) return null; var customWidget = question.customWidget; if (!customWidget) { return creator.createQuestionElement(question); } return React.createElement(SurveyCustomWidget, { creator: creator, question: question }); } constructor(props) { super(props); this.isNeedFocus = false; this.rootRef = React.createRef(); } getStateElement() { return this.question; } get question() { return this.props.element; } get creator() { return this.props.creator; } componentDidMount() { super.componentDidMount(); if (!!this.question) { this.question["react"] = this; } this.doAfterRender(); } componentWillUnmount() { super.componentWillUnmount(); if (!!this.question) { this.question["react"] = null; } const el = this.rootRef.current; if (!!el) { el.removeAttribute("data-rendered"); } } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); this.doAfterRender(); } doAfterRender() { if (this.isNeedFocus) { if (!this.question.isCollapsed) { this.question.clickTitleFunction(); } this.isNeedFocus = false; } if (this.question) { var el = this.rootRef.current; if (el && el.getAttribute("data-rendered") !== "r") { el.setAttribute("data-rendered", "r"); if (this.question.afterRender) { this.question.afterRender(el); } } } } canRender() { return (super.canRender() && !!this.question && !!this.creator); } renderQuestionContent() { let question = this.question; var contentStyle = { display: this.question.renderedIsExpanded ? "" : "none", }; var cssClasses = question.cssClasses; var questionRender = this.renderQuestion(); var errorsTop = this.question.showErrorOnTop ? this.renderErrors(cssClasses, "top") : null; var errorsBottom = this.question.showErrorOnBottom ? this.renderErrors(cssClasses, "bottom") : null; var comment = question && question.hasComment ? this.renderComment(cssClasses) : null; var descriptionUnderInput = question.hasDescriptionUnderInput ? this.renderDescription() : null; return (React.createElement("div", { className: question.cssContent || undefined, style: contentStyle, role: "presentation" }, errorsTop, questionRender, comment, errorsBottom, descriptionUnderInput)); } renderElement() { var question = this.question; var cssClasses = question.cssClasses; var header = this.renderHeader(question); var headerTop = question.hasTitleOnLeftTop ? heade