Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add soft_max_length warnings for text/textarea widget @Tishasoumya-02
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tishasoumya-02 @iFlameing this is no longer a customization, so we don't need the comments.

* OVERRIDE TextWidget.jsx
* REASON: Add softMaxLength warning for TextWidget.
* FILE: https://github.com/plone/volto/blob/ede0335834445988dd0639ab2361180251c97e4e/packages/volto/src/components/manage/Widgets/TextWidget.jsx
* FILE VERSION: Volto 19.0.0-alpha.20
* DATE: 2025-12-16
* DEVELOPER: @Tishasoumya-02
*/
import { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Input, Label } from 'semantic-ui-react';
import Icon from '@plone/volto/components/theme/Icon/Icon';
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
const SoftTextWidget = (props) => {
const {
id,
value,
onChange,
onBlur,
onClick,
icon,
iconAction,
minLength,
maxLength,
softMaxLength,
placeholder,
isDisabled,
focus,
} = props;
const ref = useRef();
const [softLengthWarning, setSoftLengthWarning] = useState('');
useEffect(() => {
if (focus) {
ref.current.focus();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// START CUSTOMIZATION
const handleChange = (id, newValue) => {
if (softMaxLength && newValue?.length) {
const remaining = softMaxLength - newValue.length;
if (remaining < 0) {
setSoftLengthWarning(
`You have exceeded the recommended limit by ${Math.abs(remaining)}`,
);
} else {
setSoftLengthWarning('');
}
}
onChange(id, newValue);
};
// END CUSTOMIZATION
return (
<FormFieldWrapper {...props} className="text">
<Input
id={`field-${id}`}
name={id}
value={value || ''}
disabled={isDisabled}
icon={icon || null}
placeholder={placeholder}
// START CUSTOMIZATION
onChange={({ target }) =>
handleChange(id, target.value === '' ? undefined : target.value)
}
// END CUSTOMIZATION
ref={ref}
onBlur={({ target }) =>
onBlur(id, target.value === '' ? undefined : target.value)
}
onClick={() => onClick()}
minLength={minLength || null}
maxLength={maxLength || null}
/>
{/* START CUSTOMIZATION */}
{softLengthWarning.length > 0 && (
<Label key={softLengthWarning} basic color="yellow" pointing>
{softLengthWarning}
</Label>
)}
{/* END CUSTOMIZATION */}
{icon && iconAction && (
<button className={`field-${id}-action-button`} onClick={iconAction}>
<Icon name={icon} size="18px" />
</button>
)}
</FormFieldWrapper>
);
};
export default SoftTextWidget;
SoftTextWidget.propTypes = {
id: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
description: PropTypes.string,
required: PropTypes.bool,
error: PropTypes.arrayOf(PropTypes.string),
value: PropTypes.string,
focus: PropTypes.bool,
onChange: PropTypes.func,
onBlur: PropTypes.func,
onClick: PropTypes.func,
onEdit: PropTypes.func,
onDelete: PropTypes.func,
icon: PropTypes.shape({
xmlns: PropTypes.string,
viewBox: PropTypes.string,
content: PropTypes.string,
}),
iconAction: PropTypes.func,
minLength: PropTypes.number,
maxLength: PropTypes.number,
// START CUSTOMIZATION
softMaxLength: PropTypes.number,
// END CUSTOMIZATION
wrapped: PropTypes.bool,
placeholder: PropTypes.string,
};
SoftTextWidget.defaultProps = {
description: null,
required: false,
error: [],
value: null,
onChange: () => {},
onBlur: () => {},
onClick: () => {},
onEdit: null,
onDelete: null,
focus: false,
icon: null,
iconAction: null,
minLength: null,
maxLength: null,
// START CUSTOMIZATION
softMaxLength: null,
// END CUSTOMIZATION
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* OVERRIDE TextareaWidget.jsx
* REASON: Add softMaxLength warning for TextareaWidget.
* FILE: https://github.com/plone/volto/blob/ede0335834445988dd0639ab2361180251c97e4e/packages/volto/src/components/manage/Widgets/TextareaWidget.jsx
* FILE VERSION: Volto 19.0.0-alpha.20
* DATE: 2025-12-16
* DEVELOPER: @Tishasoumya-02
*/
import { useState } from 'react';
import PropTypes from 'prop-types';
import { Label, TextArea } from 'semantic-ui-react';
import { injectIntl } from 'react-intl';
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
/**
* TextareaWidget, a widget for multiple lines text
*
* To use it, in schema properties, declare a field like:
*
* ```jsx
* {
* title: "Text",
* widget: 'textarea',
* }
* ```
*/
const SoftTextareaWidget = (props) => {
const {
id,
maxLength,
value,
onChange,
placeholder,
isDisabled,
softMaxLength,
} = props;
const [lengthError, setlengthError] = useState('');
const [softLengthWarning, setSoftLengthWarning] = useState('');
const onhandleChange = (id, value) => {
if (maxLength && value?.length) {
let remlength = maxLength - value.length;
if (remlength < 0) {
setlengthError(
`You have exceeded word limit by ${Math.abs(remlength)}`,
);
} else {
setlengthError('');
}
}
//START CUSTOMIZATION
if (softMaxLength && value?.length) {
let remaining = softMaxLength - value.length;
if (remaining < 0) {
setSoftLengthWarning(
`You have exceeded the recommended limit by ${Math.abs(remaining)}`,
);
} else {
setSoftLengthWarning('');
}
}
//END CUSTOMIZATION
onChange(id, value);
};
return (
<FormFieldWrapper {...props} className="textarea">
<TextArea
id={`field-${id}`}
name={id}
value={value || ''}
disabled={isDisabled}
placeholder={placeholder}
onChange={({ target }) =>
onhandleChange(id, target.value === '' ? undefined : target.value)
}
/>
{/* START CUSTOMIZATION */}
{softLengthWarning.length > 0 && (
<Label key={softLengthWarning} basic color="yellow" pointing>
{softLengthWarning}
</Label>
)}
{/* END CUSTOMIZATION */}
{lengthError.length > 0 && (
<Label key={lengthError} basic color="red" pointing>
{lengthError}
</Label>
)}
</FormFieldWrapper>
);
};
/**
* Property types.
* @property {Object} propTypes Property types.
* @static
*/
SoftTextareaWidget.propTypes = {
id: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
description: PropTypes.string,
maxLength: PropTypes.number,
softMaxLength: PropTypes.number,
required: PropTypes.bool,
error: PropTypes.arrayOf(PropTypes.string),
value: PropTypes.string,
onChange: PropTypes.func,
onEdit: PropTypes.func,
onDelete: PropTypes.func,
wrapped: PropTypes.bool,
placeholder: PropTypes.string,
};
/**
* Default properties.
* @property {Object} defaultProps Default properties.
* @static
*/
SoftTextareaWidget.defaultProps = {
description: null,
maxLength: null,
softMaxLength: null,
required: false,
error: [],
value: null,
onChange: null,
onEdit: null,
onDelete: null,
};
export default injectIntl(SoftTextareaWidget);
4 changes: 4 additions & 0 deletions frontend/packages/volto-light-theme/src/config/widgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { footerLogosSchema } from '../components/Widgets/schema/footerLogosSchem
import { footerLinksSchema } from '../components/Widgets/schema/footerLinksSchema';
import { iconLinkListSchema } from '../components/Widgets/schema/iconLinkListSchema';
import ModalJSONEditor from '../components/Widgets/ModalJSONEditor';
import SoftTextWidget from '../components/Widgets/SoftTextWidget';
import SoftTextareaWidget from '../components/Widgets/SoftTextareaWidget';

export default function install(config: ConfigType) {
// Color picker widget override - use our own non-semanticUI widget
Expand All @@ -27,6 +29,8 @@ export default function install(config: ConfigType) {

config.widgets.widget.colorPicker = ColorPicker;
config.widgets.widget.themeColorSwatch = ThemeColorSwatch;
config.widgets.widget.soft_text_widget = SoftTextWidget;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know the pickyness, but in VLT we are using camelCase widget names.

config.widgets.widget.soft_text_area_widget = SoftTextareaWidget;

config.widgets.widget.modalJSONEditor = ModalJSONEditor;

Expand Down