@primer/components
Version:
Primer react components
236 lines (192 loc) • 8.48 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _props = require("@styled-system/props");
var _styledComponents = _interopRequireDefault(require("styled-components"));
var _focusZone = require("./behaviors/focusZone");
var _useCombinedRefs = require("./hooks/useCombinedRefs");
var _useFocusZone = require("./hooks/useFocusZone");
var _Token = _interopRequireDefault(require("./Token/Token"));
var _TextInput = _interopRequireDefault(require("./TextInput"));
var _hooks = require("./hooks");
var _UnstyledTextInput = _interopRequireDefault(require("./_UnstyledTextInput"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const InputWrapper = _styledComponents.default.div.withConfig({
displayName: "TextInputWithTokens__InputWrapper",
componentId: "sc-8z94t5-0"
})(["order:1;flex-grow:1;"]);
// using forwardRef is important so that other components (ex. Autocomplete) can use the ref
const TextInputWithTokensComponent = /*#__PURE__*/_react.default.forwardRef(({
icon: IconComponent,
contrast,
className,
block,
disabled,
theme,
sx: sxProp,
tokens,
onTokenRemove,
tokenComponent: TokenComponent,
preventTokenWrapping,
tokenSizeVariant,
hideTokenRemoveButtons,
selectedTokenIdx,
setSelectedTokenIdx,
...rest
}, externalRef) => {
const ref = (0, _hooks.useProvidedRefOrCreate)(externalRef);
const {
onFocus,
onKeyDown,
...inputPropsRest
} = (0, _props.omit)(rest);
const handleTokenFocus = tokenIdx => () => {
setSelectedTokenIdx(tokenIdx);
};
const handleTokenBlur = () => {
setSelectedTokenIdx(undefined);
};
const handleTokenKeyUp = e => {
if (e.key === 'Escape') {
var _ref$current;
ref === null || ref === void 0 ? void 0 : (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.focus();
}
};
const handleInputFocus = e => {
onFocus && onFocus(e);
setSelectedTokenIdx(undefined);
};
const handleInputKeyDown = e => {
var _ref$current2;
if (onKeyDown) {
onKeyDown(e);
}
if (ref !== null && ref !== void 0 && (_ref$current2 = ref.current) !== null && _ref$current2 !== void 0 && _ref$current2.value) {
return;
}
const lastToken = tokens[tokens.length - 1];
if (e.key === 'Backspace' && lastToken) {
onTokenRemove(lastToken.id);
if (ref !== null && ref !== void 0 && ref.current) {
// TODO: eliminate the first hack by making changes to the Autocomplete component
//
// HACKS:
// 1. Directly setting `ref.current.value` instead of updating state because the autocomplete
// highlight behavior doesn't work correctly if we update the value with a setState action in onChange
// 2. Adding an extra space so that when I backspace, it doesn't delete the last letter
ref.current.value = `${lastToken.text} `;
} // HACK: for some reason we need to wait a tick for `.select()` to work
setTimeout(() => {
var _ref$current3;
ref === null || ref === void 0 ? void 0 : (_ref$current3 = ref.current) === null || _ref$current3 === void 0 ? void 0 : _ref$current3.select();
}, 1);
}
};
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(InputWrapper, {
key: "inputWrapper"
}, /*#__PURE__*/_react.default.createElement(_UnstyledTextInput.default, _extends({
ref: ref,
disabled: disabled,
onFocus: handleInputFocus,
onKeyDown: handleInputKeyDown,
type: "text",
sx: {
height: '100%'
}
}, inputPropsRest))), tokens !== null && tokens !== void 0 && tokens.length && TokenComponent ? tokens.map(({
id,
...tokenRest
}, i) => /*#__PURE__*/_react.default.createElement(TokenComponent, _extends({
key: id,
onFocus: handleTokenFocus(i),
onBlur: handleTokenBlur,
onKeyUp: handleTokenKeyUp,
isSelected: selectedTokenIdx === i,
handleRemove: () => {
onTokenRemove(id);
},
hideRemoveButton: hideTokenRemoveButtons,
variant: tokenSizeVariant,
tabIndex: 0
}, tokenRest))) : null);
});
const TextInputWithTokens = /*#__PURE__*/_react.default.forwardRef(({
tokens,
onTokenRemove,
sx: sxProp,
...props
}, ref) => {
const localInputRef = (0, _react.useRef)(null);
const combinedInputRef = (0, _useCombinedRefs.useCombinedRefs)(localInputRef, ref);
const [selectedTokenIdx, setSelectedTokenIdx] = (0, _react.useState)();
const {
containerRef
} = (0, _useFocusZone.useFocusZone)({
focusOutBehavior: 'wrap',
bindKeys: _focusZone.FocusKeys.ArrowHorizontal | _focusZone.FocusKeys.HomeAndEnd,
focusableElementFilter: element => {
return !element.getAttributeNames().includes('aria-hidden');
},
getNextFocusable: direction => {
var _containerRef$current;
if (!selectedTokenIdx && selectedTokenIdx !== 0) {
return undefined;
}
let nextIndex = selectedTokenIdx + 1; // "+ 1" accounts for the first element: the text input
if (direction === 'next') {
nextIndex += 1;
}
if (direction === 'previous') {
nextIndex -= 1;
}
if (nextIndex > tokens.length || nextIndex < 1) {
return combinedInputRef.current || undefined;
}
return containerRef === null || containerRef === void 0 ? void 0 : (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.children[nextIndex];
}
}, [selectedTokenIdx]);
const handleTokenRemove = tokenId => {
onTokenRemove(tokenId);
if (selectedTokenIdx) {
var _containerRef$current2;
const nextElementToFocus = containerRef === null || containerRef === void 0 ? void 0 : (_containerRef$current2 = containerRef.current) === null || _containerRef$current2 === void 0 ? void 0 : _containerRef$current2.children[selectedTokenIdx];
nextElementToFocus.focus();
}
};
return /*#__PURE__*/_react.default.createElement(_TextInput.default, _extends({
ref: combinedInputRef,
wrapperRef: containerRef,
as: TextInputWithTokensComponent,
selectedTokenIdx: selectedTokenIdx,
setSelectedTokenIdx: setSelectedTokenIdx,
tokens: tokens,
onTokenRemove: handleTokenRemove,
sx: {
'alignItems': 'center',
'flexWrap': props.preventTokenWrapping ? 'nowrap' : 'wrap',
'gap': '0.25rem',
'> *': {
'flexShrink': 0
},
...(props.block ? {
display: 'flex',
width: '100%'
} : {}),
...sxProp
}
}, props));
});
TextInputWithTokens.defaultProps = {
tokenComponent: _Token.default,
tokenSizeVariant: "xl",
hideTokenRemoveButtons: false
};
TextInputWithTokens.displayName = 'TextInputWithTokens';
var _default = TextInputWithTokens;
exports.default = _default;