b0nes
Version:
Zero-dependency component library and SSR/SSG framework
89 lines (86 loc) • 3.51 kB
JavaScript
import { normalizeClasses } from '../../utils/normalizeClasses.js';
import { validateProps, validatePropTypes, createComponentError } from '../../utils/componentError.js';
import { escapeHtml } from '../../utils/escapeHtml.js';
import { escapeAttr } from '../../utils/escapeAttr.js';
/**
* Textarea component - An HTML textarea element for multi-line text input
*
* Renders an HTML textarea element with validation, accessibility features,
* and customizable styling. Supports multi-line text input with optional
* rows/cols sizing, character limits, and form integration.
*
* @param {Object} props - Component properties
* @param {string} [props.attrs=''] - Additional HTML attributes (e.g., 'rows="5" cols="40" maxlength="500"')
* @param {string} [props.className=''] - Additional CSS classes to apply
*
* @returns {string} Rendered HTML textarea element
*
* @throws {createComponentError} If prop types are invalid
*
* @example
* // Basic textarea
* textarea({
* attrs: 'name="message" placeholder="Enter your message here..."'
* })
* // Returns: '<textarea class="textarea" name="message" placeholder="Enter your message here..."/>'
*
* @example
* // Textarea with dimensions and character limit
* textarea({
* attrs: 'name="bio" id="user-bio" rows="5" cols="50" maxlength="500" placeholder="Tell us about yourself..."'
* })
* // Returns: '<textarea class="textarea" name="bio" id="user-bio" rows="5" cols="50" maxlength="500" placeholder="Tell us about yourself..."/>'
*
* @example
* // Textarea with default value (pre-filled)
* textarea({
* attrs: 'name="comment" rows="3" value="This is my initial comment"'
* })
* // Returns: '<textarea class="textarea" name="comment" rows="3" value="This is my initial comment"/>'
*
* @example
* // Required textarea with custom class
* textarea({
* className: 'feedback-box large',
* attrs: 'name="feedback" required data-required="true"'
* })
* // Returns: '<textarea class="textarea feedback-box large" name="feedback" required data-required="true"/>'
*
* @example
* // Disabled textarea (read-only display)
* textarea({
* attrs: 'name="terms" rows="10" disabled value="Terms and conditions text here..."'
* })
* // Returns: '<textarea class="textarea" name="terms" rows="10" disabled value="Terms and conditions text here..."/>'
*
* @example
* // Accessible textarea with ARIA
* textarea({
* attrs: 'name="notes" aria-label="Additional notes" aria-describedby="notes-help" spellcheck="true"'
* })
* // Returns: '<textarea class="textarea" name="notes" aria-label="Additional notes" aria-describedby="notes-help" spellcheck="true"/>'
*/
export const textarea = ({
attrs = '',
className = ''
}) => {
// Validate prop types
validatePropTypes(
{ attrs, className },
{
attrs: 'string',
className: 'string',
},
{ componentName: 'textarea', componentType: 'atom' }
);
// Process attributes
attrs = attrs ? ` ${attrs}` : '';
// Normalize and escape classes
const classes = normalizeClasses(['textarea', className]);
// TODO: TO VALIDATE YET --
// Escape the value content (this goes inside the textarea tags)
// Important: textarea content must be HTML-escaped to prevent XSS
// const escapedValue = escapeHtml(value);
//return `<textarea class="${classes}"${attrs}>${escapedValue}</textarea>`;
return `<textarea class="${classes}"${attrs}/>`;
};