UNPKG

@atlaskit/form

Version:

A form allows people to input information.

124 lines (110 loc) 5.13 kB
/* character-counter.tsx generated by @compiled/babel-plugin v0.39.1 */ import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import "./character-counter.compiled.css"; import * as React from 'react'; import { ax, ix } from "@compiled/react/runtime"; import { useContext, useEffect, useRef, useState } from 'react'; import ErrorIcon from '@atlaskit/icon/core/status-error'; import { Flex, Text } from '@atlaskit/primitives/compiled'; import VisuallyHidden from '@atlaskit/visually-hidden'; import { FieldId } from './field-id-context'; // Extracted styles for character counter message container var messageContainerStyles = { root: "_11c8wadc _syaze6sf _1pfh1b66" }; // Extracted styles for error icon wrapper, need to use css to override the default height var errorIconWrapperStyles = null; // Error icon with wrapper for character count violations var ErrorIconWithWrapper = function ErrorIconWithWrapper() { return /*#__PURE__*/React.createElement("span", { className: ax(["_1e0c1txw _4t3i7vkz _4cvr1h6o"]) }, /*#__PURE__*/React.createElement(ErrorIcon, { label: "error", size: "small" })); }; // Helper to pluralise "character(s)" var pluralize = function pluralize(count) { return "character".concat(count !== 1 ? 's' : ''); }; /** * __Character Counter__ * * A character counter component that displays remaining characters for text input. * Displays messages for over or under the maximum or minimum character limits. */ var CharacterCounter = function CharacterCounter(_ref) { var maxCharacters = _ref.maxCharacters, minCharacters = _ref.minCharacters, currentValue = _ref.currentValue, overMaximumMessage = _ref.overMaximumMessage, underMaximumMessage = _ref.underMaximumMessage, underMinimumMessage = _ref.underMinimumMessage, _ref$shouldShowAsErro = _ref.shouldShowAsError, shouldShowAsError = _ref$shouldShowAsErro === void 0 ? true : _ref$shouldShowAsErro, inputId = _ref.inputId, testId = _ref.testId; var _useState = useState(''), _useState2 = _slicedToArray(_useState, 2), announcementText = _useState2[0], setAnnouncementText = _useState2[1]; var debounceTimeoutRef = useRef(null); // Resolve the field ID from context (form use) or inputId prop (standalone use) var contextFieldId = useContext(FieldId); var resolvedFieldId = contextFieldId || inputId; var currentLength = (currentValue === null || currentValue === void 0 ? void 0 : currentValue.length) || 0; // Check if character count violates limits var isTooShort = minCharacters !== undefined && currentLength < minCharacters; var isTooLong = maxCharacters !== undefined && currentLength > maxCharacters; // Determine what to display based on the current value, the maximum and minimum character limits, and any custom messages var getMessage = function getMessage() { // Below minimum so show custom message or default if (isTooShort) { var needed = minCharacters - currentLength; return underMinimumMessage || "".concat(needed, " more ").concat(pluralize(needed), " needed"); } // Over maximum so show custom message or default if (isTooLong) { var over = currentLength - maxCharacters; return overMaximumMessage || "".concat(over, " ").concat(pluralize(over), " too many"); } // Within limits - show remaining count (if max is defined) if (maxCharacters) { var remaining = maxCharacters - currentLength; return underMaximumMessage || "".concat(remaining, " ").concat(pluralize(remaining), " remaining"); } // No message to show (min only limit satisfied) return null; }; var displayText = getMessage(); // Determine if the current character count violates limits var displayAsError = (isTooShort || isTooLong) && shouldShowAsError; // Debounce screen reader announcements so that it only reads the message when it input has settled useEffect(function () { // Debounce by 1 second to avoid announcing every keystroke debounceTimeoutRef.current = setTimeout(function () { setAnnouncementText(displayText || ''); }, 1000); // Cleanup function clears the timeout when displayText changes or component unmounts return function () { clearTimeout(debounceTimeoutRef.current); }; }, [displayText]); // Don't render if there's no message to display (min only limit satisfied) if (!displayText) { return null; } return /*#__PURE__*/React.createElement(Flex, { testId: testId }, /*#__PURE__*/React.createElement(Flex, { gap: "space.075", xcss: messageContainerStyles.root }, displayAsError && /*#__PURE__*/React.createElement(ErrorIconWithWrapper, null), /*#__PURE__*/React.createElement(Text, { color: displayAsError ? 'color.text.danger' : 'color.text.subtlest', size: "small", id: resolvedFieldId ? "".concat(resolvedFieldId, "-character-counter") : undefined }, displayText)), /*#__PURE__*/React.createElement(VisuallyHidden, null, /*#__PURE__*/React.createElement("div", { "aria-live": "polite" }, announcementText))); }; export default CharacterCounter;