UNPKG

@progress/sitefinity-nextjs-sdk

Version:

Provides OOB widgets developed using the Next.js framework, which includes an abstraction layer for Sitefinity communication. Additionally, it offers an expanded API, typings, and tools for further development and integration.

122 lines (121 loc) 7.21 kB
'use client'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import React, { useContext, useState } from 'react'; import { VisibilityStyle } from '../../styling/visibility-style'; import { StylingConfig } from '../../styling/styling-config'; import { classNames } from '../../../editor/utils/classNames'; import { FormContext } from '../../form/form-context'; import { getUniqueId } from '../../../editor/utils/getUniqueId'; export function MultipleChoiceClient(props) { const multipleChoiceUniqueId = props.widgetContext.model.Properties.SfFieldName; const inputMultipleChoiceUniqueId = getUniqueId(multipleChoiceUniqueId, props.widgetContext.model.Id); const otherChoiceOptionId = getUniqueId(`choiceOption-other-${multipleChoiceUniqueId}`, props.widgetContext.model.Id); let layoutClass = ''; let innerColumnClass = ''; const parsed = parseInt(props.widgetContext.model.Properties.ColumnsNumber.toString(), 10); switch (parsed) { case 0: layoutClass = 'd-flex flex-wrap'; innerColumnClass = 'me-2'; break; case 2: layoutClass = 'row m-0'; innerColumnClass = 'col-6'; break; case 3: layoutClass = 'row m-0'; innerColumnClass = 'col-4'; break; default: break; } const [inputValues, setInputValues] = React.useState(props.choices); const otherChoiceInputRef = React.useRef(null); const { formViewProps, sfFormValueChanged, dispatchValidity, hiddenInputs, skippedInputs, formSubmitted } = useContext(FormContext); const isHidden = hiddenInputs[multipleChoiceUniqueId]; const isSkipped = skippedInputs[multipleChoiceUniqueId]; const [errorMessageText, setErrorMessageText] = useState(''); const [otherInputText, setOtherInputText] = useState(''); const [showOtherInput, setShowOtherInput] = useState(false); let delayTimer; function dispatchValueChanged() { clearTimeout(delayTimer); delayTimer = setTimeout(function () { sfFormValueChanged(); }, 300); } function clearErrorMessage() { setErrorMessageText(''); } const handleChange = (event) => { clearErrorMessage(); const newInputValues = [...inputValues].map((input) => { return { ...input, Selected: event.target.value.toString() === input.Value?.toString() }; }); setInputValues(newInputValues); setShowOtherInput(false); dispatchValueChanged(); }; function handleOtherChange(event) { const newInputValues = [...inputValues].map(input => { return { ...input, Selected: false }; }); setInputValues(newInputValues); setShowOtherInput(true); dispatchValueChanged(); } function handleOtherInputChange(event) { if (event.target.value) { clearErrorMessage(); } else { setErrorMessageText(props.requiredErrorMessage.replace('{0}', props.label)); } dispatchValueChanged(); } function handleOtherInputInput(event) { setOtherInputText(event.target.value); } const hasValueSelected = React.useMemo(() => { return inputValues.some((i) => i.Selected); }, [inputValues]); const handleChoiceValidation = () => { const otherChoiceInput = otherChoiceInputRef.current; if ((props.required && !hasValueSelected) && !(otherChoiceInput && otherChoiceInput.required)) { setErrorMessageText(props.requiredErrorMessage.replace('{0}', props.label)); return false; } if (otherChoiceInput && otherChoiceInput.required && otherChoiceInput.validity.valueMissing) { setErrorMessageText(props.requiredErrorMessage.replace('{0}', props.label)); return false; } clearErrorMessage(); return true; }; React.useEffect(() => { let isValid = false; if (formSubmitted) { isValid = handleChoiceValidation(); } dispatchValidity(multipleChoiceUniqueId, isValid); // eslint-disable-next-line react-hooks/exhaustive-deps }, [formSubmitted]); return (_jsxs("fieldset", { "data-sf-role": "multiple-choice-field-container", className: classNames('mb-3', props.cssClass, isHidden ? StylingConfig.VisibilityClasses[VisibilityStyle.Hidden] : StylingConfig.VisibilityClasses[VisibilityStyle.Visible]), "aria-labelledby": `choice-field-label-${multipleChoiceUniqueId} choice-field-description-${multipleChoiceUniqueId}`, children: [_jsx("input", { type: "hidden", "data-sf-role": "required-validator", value: props.required.toString() }), _jsx("legend", { className: "h6", id: `choice-field-label-${multipleChoiceUniqueId}`, children: props.label }), props.instructionalText && _jsx("p", { className: "text-muted small", id: `choice-field-description-${multipleChoiceUniqueId}`, children: props.instructionalText }), _jsxs("div", { className: layoutClass, children: [inputValues.map((choiceOption, idx) => { const choiceOptionId = `choiceOption-${idx}-${inputMultipleChoiceUniqueId}`; return (_jsxs("div", { className: `form-check ${innerColumnClass}`, children: [_jsx("input", { className: "form-check-input", type: "radio", name: multipleChoiceUniqueId, id: choiceOptionId, value: choiceOption.Value || '', "data-sf-role": "multiple-choice-field-input", required: props.required && !hasValueSelected, checked: choiceOption.Selected || false, disabled: isHidden || isSkipped, onChange: handleChange }), _jsx("label", { className: "form-check-label", htmlFor: choiceOptionId, children: choiceOption.Name })] }, idx)); }), props.hasAdditionalChoice && _jsxs("div", { className: `form-check ${innerColumnClass}`, children: [_jsx("input", { className: "form-check-input mt-1", type: "radio", name: multipleChoiceUniqueId, id: otherChoiceOptionId, "data-sf-role": "multiple-choice-field-input", required: props.required && !hasValueSelected, checked: showOtherInput, value: otherInputText, onChange: handleOtherChange }), _jsx("label", { className: "form-check-label", htmlFor: otherChoiceOptionId, children: "Other" }), showOtherInput && _jsx("input", { type: "text", ref: otherChoiceInputRef, className: classNames('form-control', { [formViewProps.invalidClass]: formViewProps.invalidClass && props.required && !otherInputText }), "data-sf-role": "choice-other-input", value: otherInputText, required: props.required, onChange: handleOtherInputChange, onInput: handleOtherInputInput })] })] }), props.required && errorMessageText && _jsx("div", { "data-sf-role": "error-message", role: "alert", "aria-live": "assertive", className: classNames('invalid-feedback', { [StylingConfig.VisibilityClasses[VisibilityStyle.Visible]]: true }), children: errorMessageText })] })); }