contact-input-component
Version:

308 lines (294 loc) • 15.1 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
function _objectWithoutPropertiesLoose(r, e) {
if (null == r) return {};
var t = {};
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
if (-1 !== e.indexOf(n)) continue;
t[n] = r[n];
}
return t;
}
function XIcon() {
return React.createElement("svg", {
width: "14",
height: "14",
viewBox: "0 0 24 24",
fill: "none",
xmlns: "http://www.w3.org/2000/svg",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
}, React.createElement("path", {
d: "M18 6L6 18"
}), React.createElement("path", {
d: "M6 6l12 12"
}));
}
function CheckIcon() {
return React.createElement("svg", {
width: "18",
height: "18",
viewBox: "0 0 24 24",
fill: "none",
xmlns: "http://www.w3.org/2000/svg",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round"
}, React.createElement("path", {
d: "M20 6L9 17L4 12"
}));
}
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = "body, html {\n\tmargin: 0;\n\tpadding: 0;\n}\n\ninput, button {\n\tall: unset;\n}\n\ninput {\n\twidth: auto;\n\tmin-width: 20px;\n}\n\nbutton {\n\tcursor: pointer;\n}\n\n.index_contact-input-wrapper__I0mwg {\n position: relative;\n width: 100%;\n}\n\n.index_contact-input-container__JWTEt {\n display: flex;\n align-items: center;\n min-height: 40px;\n width: 100%;\n border-radius: 4px;\n border: 1px solid #dbdde1;\n padding: 6px 12px;\n font-size: 14px;\n transition: all 0.2s ease;\n background-color: white;\n box-sizing: border-box;\n}\n\n.index_contact-input-container__JWTEt:focus-within {\n border-color: #1a73e8;\n box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.3);\n}\n\n.index_contact-input-focused__94W3D {\n background-color: #f1f3f4;\n}\n\n.index_contact-input-label__ehkIk {\n color: #5f6368;\n margin-right: 8px;\n font-weight: 500;\n flex-shrink: 0;\n}\n\n.index_contact-input-tags__iAIum {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.index_contact-tag__K3ZEa {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background-color: #e8eaed;\n border-radius: 16px;\n padding: 2px 4px;\n font-size: 14px;\n transition: background-color 0.2s ease;\n}\n\n.index_contact-tag__K3ZEa:hover {\n background-color: #dadce0;\n}\n\n.index_contact-avatar__uxua5 {\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n font-size: 12px;\n color: white;\n font-weight: 500;\n background-color: #4285f4;\n overflow: hidden;\n}\n\n.index_contact-tag-name__jZt-C {\n font-weight: 500;\n margin-top: -2px;\n}\n\n.index_contact-tag-remove__rcPdA {\n color: #5f6368;\n border-radius: 50%;\n padding: 2px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.index_contact-tag-remove__rcPdA:hover {\n color: #202124;\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.index_contact-input__c71ii {\n flex: 1;\n background-color: transparent;\n border: none;\n outline: none;\n min-width: 120px;\n height: 28px;\n}\n\n.index_contact-suggestions__dJuYK {\n position: absolute;\n z-index: 50;\n width: 100%;\n margin-top: 4px;\n background-color: white;\n border-radius: 4px;\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n animation: index_scaleIn__YOBnR 0.2s ease;\n}\n\n@keyframes index_scaleIn__YOBnR {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.index_contact-suggestions-list__XdJLM {\n padding: 4px 0;\n max-height: 280px;\n overflow-y: auto;\n}\n\n.index_contact-suggestion-item__5dlRN {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 16px;\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n\n.index_contact-suggestion-item__5dlRN:hover,\n.index_highlighted__juYTV {\n background-color: #f1f3f4;\n}\n\n.index_suggestion-details__qdLRu {\n display: flex;\n flex-direction: column;\n}\n\n.index_suggestion-name__2n4Gs {\n font-weight: 500;\n}\n\n.index_suggestion-contact__yj-0u {\n font-size: 13px;\n color: #5f6368;\n}\n\n.index_suggestion-check__vfUMT {\n margin-left: auto;\n color: #1a73e8;\n} ";
var styles = {"contact-input-wrapper":"index_contact-input-wrapper__I0mwg","contact-input-container":"index_contact-input-container__JWTEt","contact-input-focused":"index_contact-input-focused__94W3D","contact-input-label":"index_contact-input-label__ehkIk","contact-input-tags":"index_contact-input-tags__iAIum","contact-tag":"index_contact-tag__K3ZEa","contact-avatar":"index_contact-avatar__uxua5","contact-tag-name":"index_contact-tag-name__jZt-C","contact-tag-remove":"index_contact-tag-remove__rcPdA","contact-input":"index_contact-input__c71ii","contact-suggestions":"index_contact-suggestions__dJuYK","scaleIn":"index_scaleIn__YOBnR","contact-suggestions-list":"index_contact-suggestions-list__XdJLM","contact-suggestion-item":"index_contact-suggestion-item__5dlRN","highlighted":"index_highlighted__juYTV","suggestion-details":"index_suggestion-details__qdLRu","suggestion-name":"index_suggestion-name__2n4Gs","suggestion-contact":"index_suggestion-contact__yj-0u","suggestion-check":"index_suggestion-check__vfUMT"};
styleInject(css_248z);
var _excluded = ["label", "contacts", "selectedContacts", "onChange", "onInputChange", "allowNewContacts"];
var getFilteredContacts = function getFilteredContacts(inputValue, contacts) {
return contacts.filter(function (_ref) {
var name = _ref.name,
description = _ref.description;
var value = inputValue.toLowerCase();
return name.toLowerCase().includes(value) || (description == null ? void 0 : description.toLowerCase().includes(value));
});
};
var contactInput = function contactInput(_ref2) {
var _ref2$label = _ref2.label,
label = _ref2$label === void 0 ? 'To' : _ref2$label,
_ref2$contacts = _ref2.contacts,
contacts = _ref2$contacts === void 0 ? [] : _ref2$contacts,
_ref2$selectedContact = _ref2.selectedContacts,
selectedContacts = _ref2$selectedContact === void 0 ? [] : _ref2$selectedContact,
onChange = _ref2.onChange,
onInputChange = _ref2.onInputChange,
_ref2$allowNewContact = _ref2.allowNewContacts,
allowNewContacts = _ref2$allowNewContact === void 0 ? true : _ref2$allowNewContact,
props = _objectWithoutPropertiesLoose(_ref2, _excluded);
var _useState = React.useState(''),
inputValue = _useState[0],
setInputValue = _useState[1];
var _useState2 = React.useState(false),
isFocused = _useState2[0],
setIsFocused = _useState2[1];
var _useState3 = React.useState(false),
isOpen = _useState3[0],
setIsOpen = _useState3[1];
var _useState4 = React.useState(selectedContacts),
selected = _useState4[0],
setSelected = _useState4[1];
var _useState5 = React.useState([]),
filteredContacts = _useState5[0],
setFilteredContacts = _useState5[1];
var _useState6 = React.useState(-1),
highlightedIndex = _useState6[0],
setHighlightedIndex = _useState6[1];
var inputRef = React.useRef(null);
var containerRef = React.useRef(null);
React.useEffect(function () {
setSelected(selectedContacts);
}, [selectedContacts]);
React.useEffect(function () {
if (inputValue.trim()) {
setFilteredContacts(getFilteredContacts(inputValue, contacts));
} else {
setFilteredContacts([]);
}
}, [inputValue, contacts]);
React.useEffect(function () {
var handleClickOutside = function handleClickOutside(event) {
if (containerRef.current && !containerRef.current.contains(event.target)) {
setIsOpen(false);
setIsFocused(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return function () {
document.removeEventListener('mousedown', handleClickOutside);
};
}, []);
var handleInputChange = function handleInputChange(e) {
var value = e.target.value;
setInputValue(value);
if (value.trim()) {
setIsOpen(true);
setFilteredContacts(getFilteredContacts(value, contacts));
setHighlightedIndex(-1);
} else {
setIsOpen(false);
setFilteredContacts([]);
}
if (onInputChange) {
onInputChange(value);
}
};
var handleSelectContact = function handleSelectContact(contact) {
var _inputRef$current;
if (!selected.some(function (c) {
return c.id === contact.id;
})) {
var newSelected = [].concat(selected, [contact]);
setSelected(newSelected);
if (onChange) {
onChange(newSelected);
}
}
setInputValue('');
setIsOpen(false);
setFilteredContacts([]);
(_inputRef$current = inputRef.current) == null || _inputRef$current.focus();
};
var handleRemoveContact = function handleRemoveContact(contactId) {
var newSelected = selected.filter(function (c) {
return c.id !== contactId;
});
setSelected(newSelected);
if (onChange) {
onChange(newSelected);
}
};
var handleAddCustomContact = function handleAddCustomContact() {
if (!inputValue.trim()) return;
var newContact = {
id: "" + Date.now(),
name: inputValue.trim()
};
var newSelected = [].concat(selected, [newContact]);
setSelected(newSelected);
if (onChange) {
onChange(newSelected);
}
setInputValue('');
setIsOpen(false);
setFilteredContacts([]);
};
var handleKeyDown = function handleKeyDown(e) {
if (e.key === 'ArrowDown' && (filteredContacts == null ? void 0 : filteredContacts.length) > 0) {
e.preventDefault();
setHighlightedIndex(function (prevIndex) {
return prevIndex < (filteredContacts == null ? void 0 : filteredContacts.length) - 1 ? prevIndex + 1 : 0;
});
} else if (e.key === 'ArrowUp' && (filteredContacts == null ? void 0 : filteredContacts.length) > 0) {
e.preventDefault();
setHighlightedIndex(function (prevIndex) {
return prevIndex > 0 ? prevIndex - 1 : (filteredContacts == null ? void 0 : filteredContacts.length) - 1;
});
} else if (e.key === 'Enter') {
e.preventDefault();
if (highlightedIndex >= 0 && (filteredContacts == null ? void 0 : filteredContacts.length) > 0) {
handleSelectContact(filteredContacts[highlightedIndex]);
} else if (allowNewContacts && inputValue.trim()) {
handleAddCustomContact();
}
} else if (e.key === 'Escape') {
setIsOpen(false);
} else if (e.key === 'Backspace' && inputValue === '' && selected.length > 0) {
handleRemoveContact(selected[selected.length - 1].id);
}
};
return React__default.createElement("div", {
ref: containerRef,
className: styles["contact-input-wrapper"]
}, React__default.createElement("div", {
className: styles["contact-input-container"] + " " + (isFocused ? styles["contact-input-focused"] : ''),
onClick: function onClick() {
var _inputRef$current2;
return (_inputRef$current2 = inputRef.current) == null ? void 0 : _inputRef$current2.focus();
}
}, label && React__default.createElement("span", {
className: styles["contact-input-label"]
}, label), React__default.createElement("div", {
className: styles["contact-input-tags"]
}, selected.map(function (contact) {
return React__default.createElement("div", {
key: contact.id,
className: styles["contact-tag"]
}, contact.image ? React__default.createElement("img", {
src: contact.image,
alt: contact.name,
className: styles["contact-avatar"]
}) : null, React__default.createElement("span", {
className: styles["contact-tag-name"]
}, contact.name), React__default.createElement("button", {
type: "button",
onClick: function onClick(e) {
e.stopPropagation();
handleRemoveContact(contact.id);
},
className: styles["contact-tag-remove"]
}, React__default.createElement(XIcon, null)));
}), React__default.createElement("input", Object.assign({
ref: inputRef,
type: "text",
className: styles["contact-input"],
value: inputValue,
onChange: handleInputChange,
onFocus: function onFocus() {
setIsFocused(true);
if (inputValue.trim()) {
setIsOpen(true);
}
},
onKeyDown: handleKeyDown
}, props)))), isOpen && React__default.createElement("div", {
className: styles["contact-suggestions"]
}, React__default.createElement("div", {
className: styles["contact-suggestions-list"]
}, filteredContacts.length > 0 ? filteredContacts.map(function (contact, index) {
return React__default.createElement("div", {
key: contact.id,
onClick: function onClick() {
return handleSelectContact(contact);
},
className: styles["contact-suggestion-item"] + " " + (highlightedIndex === index ? styles.highlighted : '')
}, contact.image ? React__default.createElement("img", {
src: contact.image,
alt: contact.name,
className: styles["contact-avatar"]
}) : null, React__default.createElement("div", {
className: styles["suggestion-details"]
}, React__default.createElement("span", {
className: styles["suggestion-name"]
}, contact.name), contact.description && React__default.createElement("span", {
className: styles["suggestion-contact"]
}, contact.description)), highlightedIndex === index && React__default.createElement("span", {
className: styles["suggestion-check"]
}, React__default.createElement(CheckIcon, null)));
}) : allowNewContacts && inputValue.trim() ? React__default.createElement("div", {
className: styles["contact-suggestion-item"] + " " + styles.highlighted,
onClick: handleAddCustomContact
}, React__default.createElement("div", {
className: styles["suggestion-details"]
}, React__default.createElement("span", {
className: styles["suggestion-name"]
}, "\"", inputValue, "\"")), React__default.createElement("span", {
className: styles["suggestion-check"]
}, React__default.createElement(CheckIcon, null))) : null)));
};
exports.default = contactInput;
//# sourceMappingURL=contact-input-component.cjs.development.js.map