@react-md/form
Version:
This package is for creating all the different form input types.
204 lines • 10.5 kB
JavaScript
;
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