UNPKG

survey-creator-react

Version:

A white-label drag-and-drop form builder for React that lets you design complex, interactive forms and surveys without writing code. It generates JSON schemas used by the SurveyJS Form Library to render dynamic forms in your React app.

1,103 lines (1,078 loc) 144 kB
/*! * SurveyJS Creator React v2.5.4 * (c) 2015-2025 Devsoft Baltic OÜ - http://surveyjs.io/ * Github: https://github.com/surveyjs/survey-creator * License: https://surveyjs.io/Licenses#SurveyCreator */ import * as React from 'react'; import { createElement, Fragment } from 'react'; import { ReactElementFactory, SurveyElementBase, attachKey2click, SvgIcon, Survey, ReactQuestionFactory, SurveyLocStringViewer, SvgBundleComponent, PopupModal, SurveyActionBar, NotifierComponent, TitleElement, ReactSurveyElementsWrapper, LoadingIndicatorComponent, SurveyPage, Popup, LogoImage, SurveyQuestionElementBase, SurveyQuestion, SurveyPanel, Scroll, CharacterCounterComponent, SurveyQuestionDropdown, SurveyHeader, List, SurveyQuestionText } from 'survey-react-ui'; import { SurveyCreatorModel, assign, RowViewModel, QuestionAdornerViewModel, QuestionDropdownAdornerViewModel, QuestionImageAdornerViewModel, QuestionRatingAdornerViewModel, PageAdorner, LogoImageViewModel, editorLocalization, ItemValueWrapperViewModel, ImageItemValueWrapperViewModel, MatrixCellWrapperViewModel, SurveyResultsModel, ToolboxToolViewModel, editableStringRendererName, StringEditorViewModelBase, initLogicOperator, PageNavigatorViewModel } from 'survey-creator-core'; export { PropertyGridEditorCollection, SurveyLogic, SurveyLogicUI, SurveyQuestionEditorDefinition, ToolboxToolViewModel, editorLocalization, localization, settings, svgBundle } from 'survey-creator-core'; import * as ReactDOM from 'react-dom'; import { CssClassBuilder, settings, RendererFactory, unwrap, checkLibraryVersion } from 'survey-core'; class TabbedMenuComponent extends SurveyElementBase { get model() { return this.props.model; } getStateElement() { return this.model; } constructor(props) { super(props); this.rootRef = React.createRef(); } renderElement() { const items = this.model.renderedActions.map((item) => React.createElement(TabbedMenuItemWrapper, { item: item, key: item.renderedId })); return (React.createElement("div", { ref: this.rootRef, className: "svc-tabbed-menu", role: "tablist", style: this.model.getRootStyle() }, items)); } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); const container = this.rootRef.current; if (!container) return; this.model.initResponsivityManager(container); } componentDidMount() { super.componentDidMount(); const container = this.rootRef.current; if (!container) return; this.model.initResponsivityManager(container); } componentWillUnmount() { this.model.resetResponsivityManager(); super.componentWillUnmount(); } } class TabbedMenuItemWrapper extends SurveyElementBase { constructor(props) { super(props); this.ref = React.createRef(); this.state = { changed: 0 }; } get item() { return this.props.item; } getStateElement() { return this.item; } renderElement() { let css = "svc-tabbed-menu-item-container"; if (this.item.css) { css += " " + this.item.css; } css += (!this.item.isVisible ? " sv-action--hidden" : ""); const component = ReactElementFactory.Instance.createElement(this.item.component || "svc-tabbed-menu-item", { item: this.item }); return (React.createElement("span", { key: this.item.id, className: css, ref: this.ref }, React.createElement("div", { className: "sv-action__content" }, component))); } componentDidMount() { super.componentDidMount(); this.item.updateModeCallback = (mode, callback) => { const update = () => { if (this.item.mode == mode) { this.setState({ changed: this.state.changed + 1 }); } else { this.item.mode = mode; } }; queueMicrotask(() => { if (ReactDOM["flushSync"]) { ReactDOM["flushSync"](() => { update(); }); } else { update(); } queueMicrotask(() => { callback(mode, this.ref.current); }); }); }; this.item.afterRender(); } componentWillUnmount() { super.componentWillUnmount(); this.item.updateModeCallback = undefined; } } class TabbedMenuItemComponent extends SurveyElementBase { get item() { return this.props.item; } getStateElement() { return this.item; } render() { const item = this.item; return (attachKey2click(React.createElement("div", { role: "tab", id: "tab-" + item.id, "aria-selected": item.active, "aria-controls": "scrollableDiv-" + item.id, className: item.getRootCss(), onClick: () => item.doAction() }, item.hasTitle ? React.createElement("span", { className: item.getTitleCss() }, item.title) : null, item.hasIcon ? React.createElement(SvgIcon, { iconName: item.iconName, className: item.getIconCss(), size: "auto", title: item.tooltip || item.title }) : null))); } } ReactElementFactory.Instance.registerElement("svc-tabbed-menu-item", (props) => { return React.createElement(TabbedMenuItemComponent, props); }); class SurveyCreatorComponent extends SurveyElementBase { constructor(props) { super(props); this.rootNode = React.createRef(); } get creator() { return this.props.creator; } getStateElement() { return this.creator; } get style() { return this.props.style; } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); if (this.creator !== prevProps.creator) { if (prevProps.creator) { prevProps.creator.unsubscribeRootElement(); } if (this.creator && this.rootNode.current) { this.creator.setRootElement(this.rootNode.current); } } } componentDidMount() { super.componentDidMount(); this.creator.setRootElement(this.rootNode.current); } componentWillUnmount() { super.componentWillUnmount(); this.creator.unsubscribeRootElement(); } renderElement() { const creator = this.props.creator; if (creator.isCreatorDisposed) return null; const areaClassName = "svc-full-container svc-creator__area svc-flex-column" + (this.props.creator.haveCommercialLicense ? "" : " svc-creator__area--with-banner"); const contentWrapperClassName = "svc-creator__content-wrapper svc-flex-row" + (this.props.creator.isMobileView ? " svc-creator__content-wrapper--footer-toolbar" : ""); const fullContainerClassName = "svc-flex-row svc-full-container" + (" svc-creator__side-bar--" + this.creator.sidebarLocation); const creatorStyles = {}; assign(creatorStyles, this.style, this.props.creator.themeVariables); let licenseBanner = null; if (!this.props.creator.haveCommercialLicense) { const htmlValue = { __html: this.props.creator.licenseText }; licenseBanner = (React.createElement("div", { className: "svc-creator__banner" }, React.createElement("span", { className: "svc-creator__non-commercial-text", dangerouslySetInnerHTML: htmlValue }))); } //AM: width unrecognized by react return (React.createElement("div", { className: this.creator.getRootCss(), ref: this.rootNode, style: creatorStyles }, React.createElement(SvgBundleComponent, null), React.createElement(PopupModal, null), React.createElement("div", { className: areaClassName }, React.createElement("div", { className: fullContainerClassName }, React.createElement("div", { className: "svc-flex-column svc-flex-row__element svc-flex-row__element--growing" }, React.createElement("div", { className: "svc-top-bar" }, (creator.showTabs ? React.createElement("div", { className: "svc-tabbed-menu-wrapper" }, React.createElement(TabbedMenuComponent, { model: creator.tabbedMenu })) : null), (creator.showToolbar ? React.createElement("div", { className: "svc-toolbar-wrapper" }, React.createElement(SurveyActionBar, { model: creator.toolbar })) : null)), React.createElement("div", { className: contentWrapperClassName }, React.createElement("div", { className: "svc-creator__content-holder svc-flex-column" }, this.renderActiveTab())), React.createElement("div", { className: "svc-footer-bar" }, (creator.isMobileView ? React.createElement("div", { className: "svc-toolbar-wrapper" }, React.createElement(SurveyActionBar, { model: creator.footerToolbar })) : null))), this.renderSidebar()), licenseBanner, React.createElement(NotifierComponent, { notifier: creator.notifier })))); } renderActiveTab() { const creator = this.props.creator; for (var i = 0; i < creator.tabs.length; i++) { if (creator.tabs[i].id === creator.activeTab) { return this.renderCreatorTab(creator.tabs[i]); } } return null; } renderCreatorTab(tab) { if (tab.visible === false) { return null; } const creator = this.props.creator; const component = !!tab.renderTab ? tab.renderTab() : ReactElementFactory.Instance.createElement(tab.componentContent, { creator: creator, survey: creator.survey, data: tab.data.model }); const className = "svc-creator-tab" + (creator.toolboxLocation == "right" ? " svc-creator__toolbox--right" : ""); return (React.createElement("div", { role: "tabpanel", key: tab.id, id: "scrollableDiv-" + tab.id, "aria-labelledby": "tab-" + tab.id, className: className }, component)); } renderSidebar() { if (!!this.creator.isSidebarVisible) { return ReactElementFactory.Instance.createElement("svc-side-bar", { model: this.creator.sidebar }); } else { return null; } } } class SurveyCreator extends SurveyCreatorModel { constructor(options = {}, options2) { super(options, options2); } render(target) { // eslint-disable-next-line no-console console.error("The render method is deprecated. Use SurveyCreatorComponent instead."); } //ISurveyCreator createQuestionElement(question) { return ReactQuestionFactory.Instance.createQuestion(question.isDefaultRendering() ? question.getTemplate() : question.getComponentName(), { question: question, isDisplayMode: question.isReadOnly, creator: this }); } renderError(key, error, cssClasses) { return (React.createElement("div", { key: key }, React.createElement("span", { className: cssClasses.error.icon, "aria-hidden": "true" }), React.createElement("span", { className: cssClasses.error.item }, React.createElement(SurveyLocStringViewer, { locStr: error.locText })))); } questionTitleLocation() { return this.survey.questionTitleLocation; } questionErrorLocation() { return this.survey.questionErrorLocation; } } ReactElementFactory.Instance.registerElement("survey-widget", (props) => { return React.createElement(Survey, props); }); class CreatorModelElement extends SurveyElementBase { constructor(props) { super(props); this.createModel(props); } shouldComponentUpdate(nextProps, nextState) { const result = super.shouldComponentUpdate(nextProps, nextState); if (result) { if (this.needUpdateModel(nextProps)) { this.createModel(nextProps); } } return result; } createModel(props) { } needUpdateModel(nextProps) { const names = this.getUpdatedModelProps(); if (!Array.isArray(names)) return true; for (var i = 0; i < names.length; i++) { const key = names[i]; if (typeof key === "object") { const currentProp = this.props[key.name]; const nextProp = nextProps[key.name]; if (key.deepEqual) { if (this.props[key.name] === nextProps[key.name]) return false; const currentPropKeys = Object.keys(currentProp || {}); if (currentPropKeys.length !== Object.keys(nextProp || {}).length) return true; return currentPropKeys.some(key => currentProp[key] != nextProp[key]); } else { return currentProp !== nextProp; } } else { if (this.props[key] !== nextProps[key]) return true; } } return false; } getUpdatedModelProps() { return undefined; } } class RowWrapper extends CreatorModelElement { constructor(props) { super(props); } createModel(props) { if (!!this.model) { this.model.dispose(); } this.model = new RowViewModel(props.componentData.creator, props.row, null); } getUpdatedModelProps() { return ["row", { name: "componentData", deepEqual: true }]; } getStateElement() { return this.model; } componentDidMount() { super.componentDidMount(); this.model.subscribeElementChanges(); } componentWillUnmount() { this.model.unsubscribeElementChanges(); super.componentWillUnmount(); } render() { return (React.createElement("div", { key: "svc-row-" + this.props.row.id, className: this.model.cssClasses }, React.createElement("div", { className: "svc-row__drop-indicator svc-row__drop-indicator--top" }), React.createElement("div", { className: "svc-row__drop-indicator svc-row__drop-indicator--bottom" }), this.props.element)); } } ReactElementFactory.Instance.registerElement("svc-row", (props) => { return React.createElement(RowWrapper, props); }); class ReactMouseEvent { constructor(event) { this.event = event; } stopPropagation() { this.event.stopPropagation(); //this.event.nativeEvent.stopPropagation(); //this.event.nativeEvent.stopImmediatePropagation(); } preventDefault() { this.event.preventDefault(); //this.event.nativeEvent.preventDefault(); } get cancelBubble() { //return this.event.cancelBubble; return false; } set cancelBubble(value) { //this.event.cancelBubble = value; } get target() { return this.event.target; } get currentTarget() { return this.event.currentTarget; } get clientX() { return this.event.clientX; } get clientY() { return this.event.clientY; } get offsetX() { return this.event.nativeEvent.offsetX; } get offsetY() { return this.event.nativeEvent.offsetY; } } class ReactDragEvent extends ReactMouseEvent { constructor(event) { super(event); this.event = event; } get dataTransfer() { return this.event.dataTransfer; } } function QuestionElementContentFunc(props) { return props.element; } const QuestionElementContent = React.memo(QuestionElementContentFunc); QuestionElementContent.displayName = "QuestionElementContent"; class QuestionAdornerComponent extends CreatorModelElement { constructor(props) { super(props); this.rootRef = React.createRef(); } createModel(props) { if (this.model) { this.model.attachToUI(props.question, this.rootRef.current); } else { this.modelValue = this.createQuestionViewModel(props); } } createQuestionViewModel(props) { return new QuestionAdornerViewModel(props.componentData, props.question, null); } getUpdatedModelProps() { return ["question", "componentData"]; } get model() { return this.modelValue; } getStateElement() { return this.model; } renderElement() { const allowInteractions = this.model.element .isInteractiveDesignElement; const titleForCollapsedState = this.renderQuestionTitle(); const content = this.renderContent(allowInteractions); return (React.createElement("div", { ref: this.rootRef, "data-sv-drop-target-survey-element": this.model.element.name || null, className: this.model.rootCss(), onDoubleClick: e => { allowInteractions && this.model.dblclick(e.nativeEvent); e.stopPropagation(); }, onMouseLeave: e => allowInteractions && this.model.hover(e.nativeEvent, e.currentTarget), onMouseOver: e => allowInteractions && this.model.hover(e.nativeEvent, e.currentTarget) }, titleForCollapsedState, content)); } disableTabStop() { return true; } renderContent(allowInteractions) { var content = this.model.needToRenderContent ? this.renderElementContent() : null; //if (!allowInteractions) return <>{content}{this.renderFooter()}</>; return attachKey2click(React.createElement("div", { className: this.model.css(), onClick: (e) => this.model.select(this.model, new ReactMouseEvent(e)) }, React.createElement("div", { className: "svc-question__drop-indicator svc-question__drop-indicator--left" }), React.createElement("div", { className: "svc-question__drop-indicator svc-question__drop-indicator--right" }), React.createElement("div", { className: "svc-question__drop-indicator svc-question__drop-indicator--top" }), React.createElement("div", { className: "svc-question__drop-indicator svc-question__drop-indicator--bottom" }), allowInteractions ? this.renderHeader() : null, content, this.model.needToRenderContent ? this.renderFooter() : null), undefined, { disableTabStop: this.disableTabStop() }); } renderHeader() { return ReactElementFactory.Instance.createElement("svc-question-header", { model: this.model }); } renderFooter() { const allowInteractions = this.model.element .isInteractiveDesignElement; return allowInteractions ? ReactElementFactory.Instance.createElement("svc-question-footer", { className: "svc-question__content-actions", model: this.model }) : null; } renderCarryForwardBanner() { if (!this.model.isBannerShowing) return null; return ReactElementFactory.Instance.createElement("svc-question-banner", this.model.createBannerParams()); } renderQuestionTitle() { if (!this.model.showHiddenTitle) return null; const element = this.model.element; return (React.createElement("div", { ref: node => node && (!this.model.renderedCollapsed ? node.setAttribute("inert", "") : node.removeAttribute("inert")), className: this.model.cssCollapsedHiddenHeader }, (element.hasTitle ? React.createElement(TitleElement, { element: element, renderActions: false }) : React.createElement("div", { className: this.model.cssCollapsedHiddenTitle }, React.createElement("span", { className: "svc-fake-title" }, element.name))))); } renderElementContent() { return (React.createElement(React.Fragment, null, React.createElement(QuestionElementContent, { element: this.props.element }), this.renderElementPlaceholder(), this.renderCarryForwardBanner())); } componentDidMount() { super.componentDidMount(); this.model.attachToUI(this.props.question, this.rootRef.current); } renderElementPlaceholder() { if (!this.model.isEmptyElement) { return null; } return (React.createElement("div", { className: "svc-panel__placeholder_frame-wrapper" }, React.createElement("div", { className: "svc-panel__placeholder_frame" }, React.createElement("div", { className: "svc-panel__placeholder" }, this.model.placeholderText)))); } componentWillUnmount() { super.componentWillUnmount(); this.model.detachFromUI(); } } ReactElementFactory.Instance.registerElement("svc-question", (props) => { return React.createElement(QuestionAdornerComponent, props); }); class QuestionWrapperHeader extends React.Component { render() { if (!this.props.model.allowDragging) return null; return (React.createElement("div", { className: "svc-question__drag-area", onPointerDown: (event) => this.props.model.onPointerDown(event) }, React.createElement(SvgIcon, { className: "svc-question__drag-element", size: "auto", iconName: "icon-drag-area-indicator_24x16" }), React.createElement("div", { className: "svc-question__top-actions" }, React.createElement(SurveyActionBar, { model: this.props.model.topActionContainer, handleClick: false })))); } } ReactElementFactory.Instance.registerElement("svc-question-header", (props) => { return React.createElement(QuestionWrapperHeader, props); }); class QuestionWrapperFooter extends React.Component { render() { return (React.createElement("div", { className: this.props.className, onFocus: (e) => this.props.model.select(this.props.model, new ReactMouseEvent(e)) }, React.createElement(SurveyActionBar, { model: this.props.model.actionContainer, handleClick: false }))); } } ReactElementFactory.Instance.registerElement("svc-question-footer", (props) => { return React.createElement(QuestionWrapperFooter, props); }); class ActionButton extends SurveyElementBase { renderElement() { const classes = new CssClassBuilder() .append(this.props.classes) .append("svc-action-button") .append("svc-action-button--selected", !!this.props.selected) .append("svc-action-button--disabled", !!this.props.disabled) .toString(); if (this.props.iconName) { return this.renderIcon(classes); } return this.renderButtonText(classes); } renderButtonText(classes) { if (this.props.disabled) { return React.createElement("span", { className: classes }, this.props.text); } return (React.createElement(React.Fragment, null, attachKey2click(React.createElement("span", { role: "button", className: classes, onClick: (e) => { if (!this.props.allowBubble) { e.stopPropagation(); } this.props.click(); }, title: this.props.title }, this.props.text)))); } renderIcon(classes) { classes += " svc-action-button--icon"; if (this.props.disabled) { return React.createElement("span", { className: classes }, React.createElement(SvgIcon, { size: "auto", iconName: this.props.iconName })); } return (React.createElement(React.Fragment, null, attachKey2click(React.createElement("span", { className: classes, onClick: (e) => { if (!this.props.allowBubble) { e.stopPropagation(); } this.props.click(); }, title: this.props.title }, React.createElement(SvgIcon, { size: "auto", iconName: this.props.iconName }))))); } } ReactElementFactory.Instance.registerElement("svc-action-button", (props) => { return React.createElement(ActionButton, props); }); class QuestionBanner extends React.Component { render() { return (React.createElement("div", { className: "svc-carry-forward-panel-wrapper" }, React.createElement("div", { className: "svc-carry-forward-panel" }, React.createElement("span", null, this.props.text, " "), React.createElement("span", { className: "svc-carry-forward-panel__link" }, React.createElement(ActionButton, { click: () => this.props.onClick(), text: this.props.actionText }))))); } } ReactElementFactory.Instance.registerElement("svc-question-banner", (props) => { return React.createElement(QuestionBanner, props); }); class QuestionDropdownAdornerComponent extends QuestionAdornerComponent { constructor(props) { super(props); } createQuestionViewModel(props) { return new QuestionDropdownAdornerViewModel(props.componentData, props.question, null); } get dropdownModel() { return this.model; } get question() { return this.dropdownModel.question; } renderElementPlaceholder() { const textStyle = this.question.textStyle; return (React.createElement("div", { className: "svc-question__dropdown-choices--wrapper" }, React.createElement("div", null, React.createElement("div", { className: "svc-question__dropdown-choices" }, (this.dropdownModel.getRenderedItems() || []).map((item, index) => (React.createElement("div", { className: this.dropdownModel.getChoiceCss(), key: `editable_choice_${index}` }, ReactSurveyElementsWrapper.wrapItemValue(this.question.survey, ReactElementFactory.Instance.createElement(this.dropdownModel.itemComponent, { key: item.value, question: this.question, cssClasses: this.question.cssClasses, isDisplayMode: true, item: item, textStyle: textStyle, index: index, isChecked: this.question.value === item.value }), this.question, item))))), this.dropdownModel.needToCollapse ? React.createElement(ActionButton, { click: this.dropdownModel.switchCollapse, text: this.dropdownModel.getButtonText(), allowBubble: true }) : null))); } } ReactElementFactory.Instance.registerElement("svc-dropdown-question", (props) => { return React.createElement(QuestionDropdownAdornerComponent, props); }); class QuestionImageAdornerComponent extends QuestionAdornerComponent { createQuestionViewModel(props) { return new QuestionImageAdornerViewModel(props.componentData, props.question, null); } get imageModel() { return this.model; } renderHeader() { return (React.createElement(React.Fragment, null, React.createElement("input", { type: "file", "aria-hidden": "true", tabIndex: -1, accept: this.imageModel.acceptedTypes, className: "svc-choose-file-input", style: { position: "absolute", opacity: 0, width: "1px", height: "1px", overflow: "hidden" } }), super.renderHeader())); } renderLoadingPlaceholder() { return (React.createElement("div", { className: "svc-image-question__loading-placeholder" }, React.createElement("div", { className: "svc-image-question__loading" }, React.createElement(LoadingIndicatorComponent, null)))); } renderChooseButton() { return (React.createElement("div", { className: "svc-image-question-controls" }, this.model.allowEdit ? attachKey2click(React.createElement("span", { className: "svc-context-button", onClick: () => this.imageModel.chooseFile(this.imageModel) }, React.createElement(SvgIcon, { size: "auto", iconName: "icon-choosefile" }))) : null)); } renderElementPlaceholder() { return this.imageModel.isUploading ? this.renderLoadingPlaceholder() : this.renderChooseButton(); } getStateElements() { return [this.model, this.imageModel.filePresentationModel]; } renderElementContent() { if (this.imageModel.isEmptyElement) { const fileQuestion = ReactQuestionFactory.Instance.createQuestion("file", { creator: this.imageModel.question.survey, isDisplayMode: false, question: this.imageModel.filePresentationModel }); return (React.createElement(React.Fragment, null, fileQuestion)); } else { return (React.createElement(React.Fragment, null, this.props.element, this.renderElementPlaceholder())); } } } ReactElementFactory.Instance.registerElement("svc-image-question", (props) => { return React.createElement(QuestionImageAdornerComponent, props); }); class QuestionRatingAdornerComponent extends CreatorModelElement { createModel(props) { this.modelValue = this.createQuestionViewModel(props); } createQuestionViewModel(props) { return new QuestionRatingAdornerViewModel(props.componentData, props.question, null); } getUpdatedModelProps() { return ["question", "componentData"]; } get ratingModel() { return this.model; } get model() { return this.modelValue; } getStateElement() { return this.model; } renderElement() { const model = this.ratingModel; return (React.createElement(React.Fragment, null, React.createElement("div", { className: "svc-rating-question-content" }, React.createElement("div", { className: model.controlsClassNames }, model.allowRemove ? attachKey2click(React.createElement("span", { role: "button", className: model.removeClassNames, "aria-label": model.removeTooltip, onClick: () => model.removeItem(model) }, React.createElement(SvgIcon, { size: "auto", iconName: "icon-remove_16x16", title: model.removeTooltip }))) : null, model.allowAdd ? attachKey2click(React.createElement("span", { role: "button", className: model.addClassNames, "aria-label": model.addTooltip, onClick: () => model.addItem(model) }, React.createElement(SvgIcon, { size: "auto", iconName: "icon-add_16x16", title: model.addTooltip }))) : null), this.props.element))); } } ReactElementFactory.Instance.registerElement("svc-rating-question", (props) => { return React.createElement(QuestionRatingAdornerComponent, props); }); ReactElementFactory.Instance.registerElement("svc-rating-question-content", (props) => { return React.createElement(QuestionRatingAdornerComponent, props); }); class QuestionWidgetAdornerComponent extends QuestionAdornerComponent { createQuestionViewModel(props) { return new QuestionAdornerViewModel(props.componentData, props.question, null); } get widgetModel() { return this.model; } renderElementContent() { return (React.createElement("div", { className: "svc-widget__content" }, this.props.element)); } } ReactElementFactory.Instance.registerElement("svc-widget-question", (props) => { return React.createElement(QuestionWidgetAdornerComponent, props); }); class CellQuestionAdornerComponent extends CreatorModelElement { createModel(props) { this.model = new QuestionAdornerViewModel(props.componentData, props.question, null); } getStateElement() { return this.model; } getUpdatedModelProps() { return ["question", "componentData"]; } render() { return (React.createElement(React.Fragment, null, React.createElement("div", { "data-sv-drop-target-survey-element": this.model.element.name, className: "svc-question__adorner" }, React.createElement("div", { className: " svc-question__content--in-popup svc-question__content" }, this.props.element)))); } } ReactElementFactory.Instance.registerElement("svc-cell-question", (props) => { return React.createElement(CellQuestionAdornerComponent, props); }); class CellQuestionDropdownAdornerComponent extends CreatorModelElement { createModel(props) { this.model = new QuestionAdornerViewModel(props.componentData, props.question, null); } getUpdatedModelProps() { return ["question", "componentData"]; } getStateElement() { return this.model; } render() { const question = this.props.question; const textStyle = this.props.question.textStyle; return (React.createElement(React.Fragment, null, React.createElement("div", { "data-sv-drop-target-survey-element": this.model.element.name, className: "svc-question__adorner" }, React.createElement("div", { className: " svc-question__content--in-popup svc-question__content" }, this.props.element, React.createElement("div", { className: "svc-question__dropdown-choices" }, question.visibleChoices.map((item, index) => (React.createElement("div", { className: "svc-question__dropdown-choice", key: `editable_choice_${index}` }, ReactSurveyElementsWrapper.wrapItemValue(question.survey, ReactElementFactory.Instance.createElement("survey-radiogroup-item", { question: question, cssClasses: question.cssClasses, isDisplayMode: true, item: item, textStyle: textStyle, index: index, isChecked: question.value === item.value }), question, item))))))))); } } ReactElementFactory.Instance.registerElement("svc-cell-dropdown-question", (props) => { return React.createElement(CellQuestionDropdownAdornerComponent, props); }); const PageElementContent = React.memo(({ page, survey, creator }) => { return React.createElement(SurveyPage, { page: page, survey: survey, creator: creator }); }); PageElementContent.displayName = "PageElementContent"; class CreatorSurveyPageComponent extends CreatorModelElement { constructor(props) { super(props); this.rootRef = React.createRef(); } createModel(props) { if (this.model) { this.model.attachToUI(props.page, this.rootRef.current); } this.model = this.createPageAdorner(props.creator, props.page); this.model.isGhost = this.props.isGhost; } createPageAdorner(creator, page) { return new PageAdorner(creator, page); } shouldComponentUpdate(nextProps, nextState) { const res = super.shouldComponentUpdate(nextProps, nextState); if (this.model) { this.model.isGhost = this.props.isGhost; } return res; } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); } getUpdatedModelProps() { return ["creator", "page"]; } getStateElement() { return this.model; } componentDidMount() { super.componentDidMount(); this.model.attachToUI(this.props.page, this.rootRef.current); this.model.isGhost = this.props.isGhost; } componentWillUnmount() { super.componentWillUnmount(); this.model.detachFromUI(); } canRender() { return super.canRender(); } renderElement() { if (!this.props.page) return null; return (attachKey2click(React.createElement("div", { ref: this.rootRef, id: this.props.page.id, "data-sv-drop-target-survey-page": this.model.dropTargetName, className: "svc-page__content " + this.model.css, onClick: (e) => { return this.model.select(this.model, new ReactMouseEvent(e)); }, onDoubleClick: e => this.model.dblclick(e.nativeEvent), onMouseLeave: (e) => this.model.hover(e.nativeEvent, e.currentTarget), onMouseOver: (e) => this.model.hover(e.nativeEvent, e.currentTarget) }, React.createElement("div", { className: "svc-question__drop-indicator svc-question__drop-indicator--top" }), React.createElement("div", { className: "svc-question__drop-indicator svc-question__drop-indicator--bottom" }), this.renderContent(), this.renderPlaceholder(), this.renderHeader(), this.renderFooter()))); } renderPlaceholder() { if (!this.model.showPlaceholder) return null; return (React.createElement("div", { className: "svc-page__placeholder_frame" }, React.createElement("div", { className: "svc-panel__placeholder_frame" }, React.createElement("div", { className: "svc-panel__placeholder" }, this.model.placeholderText)))); } renderContent() { if (!this.model.needRenderContent) { return React.createElement("div", { className: "svc-page__loading-content" }, React.createElement(LoadingIndicatorComponent, null)); } return (React.createElement(PageElementContent, { page: this.props.page, survey: this.props.survey, creator: this.props.creator })); } renderHeader() { const actions = (React.createElement("div", { className: "svc-page__content-actions" }, React.createElement(SurveyActionBar, { model: this.model.actionContainer }), (this.model.topActionContainer.hasActions ? React.createElement(SurveyActionBar, { model: this.model.topActionContainer }) : null))); if (this.model.isGhost || !this.model.allowDragging) { return actions; } return (React.createElement("div", { className: "svc-question__drag-area", onPointerDown: (event) => this.model.onPointerDown(event) }, React.createElement(SvgIcon, { className: "svc-question__drag-element", size: "auto", iconName: "icon-drag-area-indicator_24x16" }), actions)); } renderFooter() { return React.createElement(SurveyActionBar, { model: this.model.footerActionsBar }); } } ReactElementFactory.Instance.registerElement("svc-page", (props) => { return React.createElement(CreatorSurveyPageComponent, props); }); class AddQuestionButtonComponent extends SurveyElementBase { get model() { return this.props.item.data; } renderTypeSelector() { const questionTypeSelectorModel = this.model.questionTypeSelectorModel; return attachKey2click(React.createElement("button", { type: "button", onClick: (e) => { e.stopPropagation(); questionTypeSelectorModel.action(); }, className: "svc-element__question-type-selector", title: this.model.addNewQuestionText, role: "button" }, React.createElement("span", { className: "svc-element__question-type-selector-icon" }, React.createElement(SvgIcon, { iconName: questionTypeSelectorModel.iconName, size: "auto", title: this.model.addNewQuestionText })), this.props.renderPopup === undefined || this.props.renderPopup ? React.createElement(Popup, { model: questionTypeSelectorModel.popupModel }) : null)); } renderElement() { const addButtonClass = this.props.buttonClass || "svc-btn"; return React.createElement(React.Fragment, null, attachKey2click(React.createElement("div", { className: "svc-element__add-new-question " + addButtonClass, onClick: (e) => { e.stopPropagation(); this.model.addNewQuestion(this.model, new ReactMouseEvent(e)); }, onMouseOver: (e) => this.model.hoverStopper && this.model.hoverStopper(e.nativeEvent, e.currentTarget) }, React.createElement(SvgIcon, { className: "svc-panel__add-new-question-icon", iconName: "icon-add_24x24", size: "auto" }), React.createElement("span", { className: "svc-add-new-item-button__text" }, this.model.addNewQuestionText), this.props.renderPopup !== false ? this.renderTypeSelector() : null)), this.props.renderPopup === false ? this.renderTypeSelector() : null); } } ReactElementFactory.Instance.registerElement("svc-add-new-question-btn", (props) => { return React.createElement(AddQuestionButtonComponent, props); }); class PanelAdornerComponent extends QuestionAdornerComponent { renderElementPlaceholder() { if (!this.model.isEmptyElement) { return null; } return (React.createElement("div", { className: "svc-panel__placeholder_frame-wrapper" }, React.createElement("div", { className: "svc-panel__placeholder_frame" }, React.createElement("div", { className: "svc-panel__placeholder" }, this.model.placeholderText), this.model.showAddQuestionButton ? attachKey2click(React.createElement("div", { className: "svc-panel__add-new-question svc-action-button", onClick: (e) => { e.stopPropagation(); this.model.addNewQuestion(); } }, React.createElement(SvgIcon, { className: "svc-panel__add-new-question-icon", iconName: "icon-add_24x24", size: "auto" }), React.createElement("span", { className: "svc-add-new-item-button__text" }, this.model.addNewQuestionText))) : null))); } disableTabStop() { return true; } renderFooter() { return (React.createElement(React.Fragment, null, !this.model.isEmptyElement && this.model.element.isPanel && this.model.showAddQuestionButton ? (React.createElement("div", { className: "svc-panel__add-new-question-container" }, React.createElement("div", { className: "svc-panel__question-type-selector-popup" }, React.createElement(Popup, { model: this.model.questionTypeSelectorModel.popupModel })), React.createElement("div", { className: "svc-panel__add-new-question-wrapper" }, React.createElement(AddQuestionButtonComponent, { item: { data: this.model }, buttonClass: "svc-action-button", renderPopup: false })))) : null, super.renderFooter())); } } ReactElementFactory.Instance.registerElement("svc-panel", (props) => { return React.createElement(PanelAdornerComponent, props); }); class LogoImageComponent extends CreatorModelElement { constructor(props) { super(props); this.rootRef = React.createRef(); } createModel(props) { let prevRoot = null; if (!!this.model) { prevRoot = this.model.root; } this.model = new LogoImageViewModel(props.data, prevRoot); } getUpdatedModelProps() { return ["data"]; } getStateElement() { return this.model; } componentDidMount() { super.componentDidMount(); this.model.root = this.rootRef.current; } renderChooseButton() { return attachKey2click(React.createElement("span", { className: "svc-context-button", onClick: () => this.model.chooseFile(this.model) }, React.createElement(SvgIcon, { size: "auto", iconName: "icon-choosefile" }))); } renderClearButton() { return attachKey2click(React.createElement("span", { className: "svc-context-button svc-context-button--danger", onClick: () => this.model.remove(this.model) }, React.createElement(SvgIcon, { size: "auto", iconName: "icon-clear" }))); } renderButtons() { return (React.createElement("div", { className: "svc-context-container svc-logo-image-controls" }, this.renderChooseButton(), this.renderClearButton())); } renderImage() { return React.createElement("div", { className: this.model.containerCss }, this.renderButtons(), React.createElement(LogoImage, { data: this.props.data.survey })); } renderPlaceHolder() { return this.model.allowEdit && !this.model.isUploading ? attachKey2click(React.createElement("div", { className: "svc-logo-image-placeholder", onClick: () => this.model.chooseFile(this.model) }, React.createElement("svg", null, React.createElement("use", { xlinkHref: "#icon-image-48x48" })))) : null; } renderInput() { return React.createElement("input", { "aria-hidden": "true", type: "file", tabIndex: -1, accept: this.model.acceptedTypes, className: "svc-choose-file-input" }); } renderLoadingIndicator() { return React.createElement("div", { className: "svc-logo-image__loading" }, React.createElement(LoadingIndicatorComponent, null)); } render() { let content = null; if (this.model.survey.locLogo.renderedHtml && !this.model.isUploading) { content = this.renderImage(); } else if (this.model.isUploading) { content = this.renderLoadingIndicator(); } else { content = this.renderPlaceHolder(); } return (React.createElement("div", { ref: this.rootRef, className: "svc-logo-image" }, this.renderInput(), content)); } } ReactElementFactory.Instance.registerElement("svc-logo-image", (props) => { return React.createElement(LogoImageComponent, props); }); class SurveyQuestionLinkValue extends SurveyQuestionElementBase { get question() { return this.questionBase; } renderClear() { const showClear = this.questionBase.showClear; if (!this.questionBase.isReadOnly && showClear) { return (React.createElement(ActionButton, { classes: this.question.linkClearButtonCssClasses, click: () => this.question.doClearClick(), text: editorLocalization.getString("pe.clear") })); } else { return null; } } renderElement() { return (React.createElement(React.Fragment, null, React.createElement(ActionButton, { classes: this.question.linkSetButtonCssClasses, click: () => this.question.doLinkClick(), selected: this.question.isSelected, disabled: !this.question.isClickable, text: this.question.linkValueText, title: this.question.tooltip, iconName: this.question.iconName }), this.renderClear())); } } ReactQuestionFactory.Instance.registerQuestion("linkvalue", (props) => { return React.createElement(SurveyQuestionLinkValue, props); }); class SurveyElementEmbeddedSurvey extends SurveyQuestionElementBase { get embeddedSurvey() { return (this.props.element || this.props.question); } get creator() { return this.props.creator; } render() { if (!this.embeddedSurvey) return null; const survey = this.embeddedSurvey.embeddedSurvey; if (!survey || !survey.currentPage) return null; return React.createElement(SurveyPage, { survey: survey, page: survey.currentPage, css: survey.css, creator: this.creator }); } } ReactQuestionFactory.Instance.registerQuestion("embeddedsurvey", (props) => { return React.createElement(SurveyElementEmbeddedSurvey, props); }); class QuestionEditorContentComponent extends React.Component { get survey() { return this.props.survey; } createQuestionElement(question) { return ReactQuestionFactory.Instance.createQuestion(!question.isDefaultRendering || question.isDefaultRendering() ? question.getTemplate() : question.getComponentName(), { question: question, isDisplayMode: question.isInputReadOnly, creator: this, }); } questionTitleLocation() { return this.survey.questionTitleLocation; } questionErrorLocation() { return this.survey.questionErrorLocation; } renderError(key, error, cssClasses) { return null; } render() { const question = this.survey.getAllQuestions()[0]; return (React.createElement("div", { style: this.props.style }, React.createElement(SurveyQuestion, { creator: this, element: question }))); } } ReactElementFactory.Instance.registerElement("svc-question-editor-content", (props) => { return React.createElement(QuestionEditorContentComponent, props); }); class ItemValueAdornerComponent extends CreatorModelElement { constructor(props) { super(props); this.onBlur = (event) => { this.model.onFocusOut(event.nativeEvent); }; this.rootRef = React.createRef(); } createModel(props) { this.model = new ItemValueWrapperViewModel(props.componentData.creator, props.question, props.item); } getUpdatedModelProps() { return ["question", "item"]; } getStateElement() { return this.model; } componentDidUpdate(prevProps, prevState) { super.componentDidUpdate(prevProps, prevState); this.props.item.setRootElement(this.rootRef.current); if (prevProps.item !== this.props.item && prevProps.item) { prevProps.item.setRootElement(undefined); } } componentDidMount() { super.compone