UNPKG

@react-md/form

Version:

This package is for creating all the different form input types.

204 lines 10.5 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Listbox = void 0; var jsx_runtime_1 = require("react/jsx-runtime"); var react_1 = require("react"); var classnames_1 = __importDefault(require("classnames")); var list_1 = require("@react-md/list"); var portal_1 = require("@react-md/portal"); var transition_1 = require("@react-md/transition"); var utils_1 = require("@react-md/utils"); var Option_1 = require("./Option"); var utils_2 = require("./utils"); var block = (0, utils_1.bem)("rmd-listbox"); var warned; /** * This component is used to render the list part of a `<select>` element with * built-in accessibility and the ability to add custom styles. This should * probably not be used much outside of `react-md` itself and the `Select` * component, but I'm planning on adding support for an inline listbox at some * point. */ exports.Listbox = (0, react_1.forwardRef)(function Listbox(_a, nodeRef) { var propClassName = _a.className, _b = _a.visible, visible = _b === void 0 ? true : _b, _c = _a.temporary, temporary = _c === void 0 ? false : _c, _d = _a.labelKey, labelKey = _d === void 0 ? "label" : _d, _e = _a.valueKey, valueKey = _e === void 0 ? "value" : _e, _f = _a.getOptionId, getOptionId = _f === void 0 ? utils_2.getOptionId : _f, _g = _a.getOptionLabel, getOptionLabel = _g === void 0 ? utils_2.getOptionLabel : _g, _h = _a.getOptionValue, getOptionValue = _h === void 0 ? utils_1.DEFAULT_GET_ITEM_VALUE : _h, _j = _a.isOptionDisabled, isOptionDisabled = _j === void 0 ? utils_2.defaultIsOptionDisabled : _j, _k = _a.disableMovementChange, disableMovementChange = _k === void 0 ? false : _k, onFocus = _a.onFocus, propOnKeyDown = _a.onKeyDown, name = _a.name, options = _a.options, value = _a.value, onChange = _a.onChange, propTabIndex = _a.tabIndex, portal = _a.portal, portalInto = _a.portalInto, portalIntoId = _a.portalIntoId, onRequestClose = _a.onRequestClose, timeout = _a.timeout, readOnly = _a.readOnly, classNames = _a.classNames, onEnter = _a.onEnter, onEntering = _a.onEntering, onEntered = _a.onEntered, onExit = _a.onExit, onExiting = _a.onExiting, onExited = _a.onExited, props = __rest(_a, ["className", "visible", "temporary", "labelKey", "valueKey", "getOptionId", "getOptionLabel", "getOptionValue", "isOptionDisabled", "disableMovementChange", "onFocus", "onKeyDown", "name", "options", "value", "onChange", "tabIndex", "portal", "portalInto", "portalIntoId", "onRequestClose", "timeout", "readOnly", "classNames", "onEnter", "onEntering", "onEntered", "onExit", "onExiting", "onExited"]); var id = props.id; var tabIndex = propTabIndex; if (temporary) { tabIndex = -1; } else if (typeof propTabIndex === "undefined") { tabIndex = 0; } /** * Gets the current index of the option that has the same value as the * provided prop value. */ var getIndex = (0, react_1.useCallback)(function () { return options.findIndex(function (option) { return value === getOptionValue(option, valueKey); }); }, [getOptionValue, options, value, valueKey]); /** * Conditionally calls the onChange callback with the new value and option if * the value has changed. This will be called when: * - the user presses the enter or space key while "focusing" an option * - the user keyboard navigates to a new option while the * `disableMovementChange` prop is `false` * - the user clicks the option with a mouse or touch */ var handleChange = (0, react_1.useCallback)(function (index) { if (readOnly) { return; } var option = options[index]; if (!option || isOptionDisabled(option)) { return; } var optionValue = getOptionValue(option, valueKey); if (value !== optionValue) { onChange(optionValue, options[index], { id: id, name: name, value: value, valueKey: valueKey, options: options, }); } }, [ getOptionValue, id, isOptionDisabled, name, onChange, options, readOnly, value, valueKey, ]); var handleKeyboardClick = (0, react_1.useCallback)(function (focusedIndex) { handleChange(focusedIndex); if (temporary && onRequestClose) { onRequestClose(); } }, [handleChange, onRequestClose, temporary]); var _l = (0, utils_1.useActiveDescendantMovement)(__assign(__assign({}, utils_1.MovementPresets.VERTICAL_LISTBOX), { defaultFocusedIndex: getIndex, items: options, baseId: id, valueKey: labelKey, getId: getOptionId, getItemValue: function (option, key) { if (!(0, utils_2.isListboxOptionProps)(option)) { return "".concat(option); } var search = option[key]; if (typeof search === "number" || typeof search === "string") { return "".concat(search); } if (process.env.NODE_ENV !== "production") { if (!warned) { warned = new Set(); } if (!warned.has(id)) { /* eslint-disable no-console */ console.warn("A listbox with an id of \"".concat(id, "\" has an option that does not have a searchable label string. ") + "Users will be unable to use the typeahead feature in the Listbox component until this is fixed. " + "To fix this warning, you can use the `labelKey` prop on the `Listbox`/`Select` component to point " + "to a string on the following option:", option); warned.add(id); } } return ""; }, onChange: function (data) { if (disableMovementChange) { return; } handleChange(data.index); }, onEnter: handleKeyboardClick, onSpace: handleKeyboardClick, onKeyDown: function (event) { if (propOnKeyDown) { propOnKeyDown(event); } switch (event.key) { case "Tab": case "Escape": if (event.key === "Escape") { event.stopPropagation(); } if (temporary && onRequestClose) { onRequestClose(); } break; // no default } } })), activeId = _l.activeId, itemRefs = _l.itemRefs, onKeyDown = _l.onKeyDown, focusedIndex = _l.focusedIndex, setFocusedIndex = _l.setFocusedIndex; var prevVisible = (0, react_1.useRef)(visible); (0, react_1.useEffect)(function () { if (prevVisible.current === visible) { return; } prevVisible.current = visible; // whenever it gains visibility, try to set the focused index to the // current active value if (visible) { setFocusedIndex(getIndex()); } }, [getIndex, setFocusedIndex, visible]); var handleFocus = (0, react_1.useCallback)(function (event) { if (onFocus) { onFocus(event); } var item = itemRefs[focusedIndex] && itemRefs[focusedIndex].current; if (item) { (0, utils_1.scrollIntoView)(event.currentTarget, item); } }, [focusedIndex, itemRefs, onFocus]); var _m = (0, transition_1.useScaleTransition)({ nodeRef: nodeRef, timeout: timeout, className: (0, classnames_1.default)(block({ temporary: temporary }), propClassName), classNames: classNames, transitionIn: visible, onEnter: onEnter, onEntering: onEntering, onEntered: onEntered, onExit: onExit, onExiting: onExiting, onExited: onExited, }), elementProps = _m.elementProps, rendered = _m.rendered; return ((0, jsx_runtime_1.jsx)(portal_1.ConditionalPortal, __assign({ portal: portal, portalInto: portalInto, portalIntoId: portalIntoId }, { children: rendered && ((0, jsx_runtime_1.jsx)(list_1.List, __assign({}, props, elementProps, { "aria-activedescendant": activeId, role: "listbox", tabIndex: tabIndex, onFocus: handleFocus, onKeyDown: onKeyDown }, { children: options.map(function (option, i) { var optionId = getOptionId(id, i); var optionValue = getOptionValue(option, valueKey); var optionLabel = getOptionLabel(option, labelKey); var optionProps; if ((0, utils_2.isListboxOptionProps)(option)) { optionProps = (0, utils_1.omit)(option, [labelKey, valueKey]); } var disabled = isOptionDisabled(option); var onClick; if (!readOnly && !disabled) { onClick = function () { handleChange(i); setFocusedIndex(i); }; } return ((0, jsx_runtime_1.jsx)(Option_1.Option, __assign({ id: optionId, disabled: disabled }, optionProps, { ref: itemRefs[i], focused: optionId === activeId, selected: value === optionValue, onClick: onClick }, { children: optionLabel }), optionValue)); }) }))) }))); }); //# sourceMappingURL=Listbox.js.map