UNPKG

@atlaskit/form

Version:

A form allows people to input information.

182 lines (168 loc) • 8.74 kB
/* character-counter.tsx generated by @compiled/babel-plugin v3.0.2 */ "use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.CharacterCounterMotionContext = exports.CharacterCounter = 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 _useMotion2 = require("@atlaskit/motion/entering/use-motion"); var _exitingPersistence = _interopRequireDefault(require("@atlaskit/motion/exiting-persistence")); var _fg = require("@atlaskit/platform-feature-flags/fg"); var _compiled = require("@atlaskit/primitives/compiled"); var _visuallyHidden = _interopRequireDefault(require("@atlaskit/visually-hidden/visually-hidden")); var _fieldIdContext = require("./field-id-context"); var _messageTrack = _interopRequireDefault(require("./message-track")); 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 _syaz1tmw _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' : ''); }; var CharacterCounterMotionContext = exports.CharacterCounterMotionContext = /*#__PURE__*/(0, _react.createContext)(false); var CounterVisual = function CounterVisual(_ref) { var shouldDisplayAsError = _ref.shouldDisplayAsError, displayText = _ref.displayText, _ref$isExiting = _ref.isExiting, isExiting = _ref$isExiting === void 0 ? false : _ref$isExiting, resolvedFieldId = _ref.resolvedFieldId; return /*#__PURE__*/React.createElement(_compiled.Flex, { gap: "space.075", xcss: messageContainerStyles.root }, shouldDisplayAsError && /*#__PURE__*/React.createElement(ErrorIconWithWrapper, null), /*#__PURE__*/React.createElement(_compiled.Text, { color: shouldDisplayAsError ? 'color.text.danger' : 'color.text.subtlest', size: "small", id: resolvedFieldId && !isExiting ? "".concat(resolvedFieldId, "-character-counter") : undefined }, displayText)); }; var AnimatedCounterVisual = function AnimatedCounterVisual(_ref2) { var shouldDisplayAsError = _ref2.shouldDisplayAsError, displayText = _ref2.displayText, transition = _ref2.transition, resolvedFieldId = _ref2.resolvedFieldId, testId = _ref2.testId; var _useMotion = (0, _useMotion2.useMotion)({ initialState: transition === 'instant' ? 'visible' : undefined }), ref = _useMotion.ref, state = _useMotion.state; return /*#__PURE__*/React.createElement(_messageTrack.default, { motionRef: ref, state: state, transition: transition, testId: testId }, /*#__PURE__*/React.createElement(CounterVisual, { shouldDisplayAsError: shouldDisplayAsError, displayText: displayText, isExiting: state === 'exiting', resolvedFieldId: resolvedFieldId })); }; /** * __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 = exports.CharacterCounter = function CharacterCounter(_ref3) { var maxCharacters = _ref3.maxCharacters, minCharacters = _ref3.minCharacters, currentValue = _ref3.currentValue, overMaximumMessage = _ref3.overMaximumMessage, underMaximumMessage = _ref3.underMaximumMessage, underMinimumMessage = _ref3.underMinimumMessage, _ref3$shouldShowAsErr = _ref3.shouldShowAsError, shouldShowAsError = _ref3$shouldShowAsErr === void 0 ? true : _ref3$shouldShowAsErr, inputId = _ref3.inputId, testId = _ref3.testId; var _useState = (0, _react.useState)(''), _useState2 = (0, _slicedToArray2.default)(_useState, 2), announcementText = _useState2[0], setAnnouncementText = _useState2[1]; var debounceTimeoutRef = (0, _react.useRef)(null); var isMotionEnabled = (0, _react.useContext)(CharacterCounterMotionContext) && (0, _fg.fg)('platform-dst-motion-uplift-input'); // 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 && !isMotionEnabled) { return null; } return /*#__PURE__*/React.createElement(_compiled.Flex, { testId: testId }, isMotionEnabled ? /*#__PURE__*/React.createElement(_exitingPersistence.default, { appear: true }, displayText && /*#__PURE__*/React.createElement(AnimatedCounterVisual, { key: displayAsError ? 'error' : 'default', shouldDisplayAsError: displayAsError, displayText: displayText, transition: maxCharacters !== undefined ? 'instant' : 'row', resolvedFieldId: resolvedFieldId, testId: testId && "".concat(testId, "-motion") })) : /*#__PURE__*/React.createElement(CounterVisual, { shouldDisplayAsError: displayAsError, displayText: displayText, resolvedFieldId: resolvedFieldId }), /*#__PURE__*/React.createElement(_visuallyHidden.default, null, /*#__PURE__*/React.createElement("div", { "aria-live": "polite", "data-testid": isMotionEnabled && testId ? "".concat(testId, "-announcer") : undefined }, announcementText))); };