@atlaskit/form
Version:
A form allows people to input information.
132 lines (118 loc) • 6.26 kB
JavaScript
/* character-counter.tsx generated by @compiled/babel-plugin v0.39.1 */
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("./character-counter.compiled.css");
var _react = _interopRequireWildcard(require("react"));
var React = _react;
var _runtime = require("@compiled/react/runtime");
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _statusError = _interopRequireDefault(require("@atlaskit/icon/core/status-error"));
var _compiled = require("@atlaskit/primitives/compiled");
var _visuallyHidden = _interopRequireDefault(require("@atlaskit/visually-hidden"));
var _fieldIdContext = require("./field-id-context");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
// 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: (0, _runtime.ax)(["_1e0c1txw _4t3i7vkz _4cvr1h6o"])
}, /*#__PURE__*/React.createElement(_statusError.default, {
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 = (0, _react.useState)(''),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
announcementText = _useState2[0],
setAnnouncementText = _useState2[1];
var debounceTimeoutRef = (0, _react.useRef)(null);
// Resolve the field ID from context (form use) or inputId prop (standalone use)
var contextFieldId = (0, _react.useContext)(_fieldIdContext.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
(0, _react.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(_compiled.Flex, {
testId: testId
}, /*#__PURE__*/React.createElement(_compiled.Flex, {
gap: "space.075",
xcss: messageContainerStyles.root
}, displayAsError && /*#__PURE__*/React.createElement(ErrorIconWithWrapper, null), /*#__PURE__*/React.createElement(_compiled.Text, {
color: displayAsError ? 'color.text.danger' : 'color.text.subtlest',
size: "small",
id: resolvedFieldId ? "".concat(resolvedFieldId, "-character-counter") : undefined
}, displayText)), /*#__PURE__*/React.createElement(_visuallyHidden.default, null, /*#__PURE__*/React.createElement("div", {
"aria-live": "polite"
}, announcementText)));
};
var _default = exports.default = CharacterCounter;