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,391 lines (1,367 loc) • 328 kB
JavaScript
/*!
* surveyjs - Survey JavaScript library v2.0.5
* 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 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" },
questionRender,
comment,
descriptionUnderInput));
}
renderElement() {
var question = this.question;
var cssClasses = question.cssClasses;
var header = this.renderHeader(question);
var headerTop = question.hasTitleOnLeftTop ? header : null;
var headerBottom = question.hasTitleOnBottom ? header : null;
const errorsAboveQuestion = this.question.showErrorsAboveQuestion
? this.renderErrors(cssClasses, "")
: null;
const errorsBelowQuestion = this.question.showErrorsBelowQuestion