strapi-plugin-tagsinput
Version:
Tagsinput plugin for your strapi project
337 lines (324 loc) • 10 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const jsxRuntime = require("react/jsx-runtime");
const react = require("react");
const PropTypes = require("prop-types");
const axios = require("axios");
const designSystem = require("@strapi/design-system");
const reactIntl = require("react-intl");
const TagsInput = require("react-tagsinput");
const Autosuggest = require("react-autosuggest");
const styledComponents = require("styled-components");
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
const PropTypes__default = /* @__PURE__ */ _interopDefault(PropTypes);
const axios__default = /* @__PURE__ */ _interopDefault(axios);
const TagsInput__default = /* @__PURE__ */ _interopDefault(TagsInput);
const Autosuggest__default = /* @__PURE__ */ _interopDefault(Autosuggest);
const light = styledComponents.css`
:root {
--primary: #7b79ff;
--secondary: rgb(255, 255, 255);
--text: #32324d;
--input-background: #ffffff;
--input-border: #dcdce4;
--tag-background: #f0f0ff;
--tag-text: #4945ff;
--suggestion-background: #ffffff;
--suggestion-hover: #f6f6f9;
}
`;
const dark = styledComponents.css`
:root {
--primary: #7b79ff;
--secondary: rgb(33, 33, 52);
--text: #ffffff;
--input-background: #181826;
--input-border: #4a4a6a;
--tag-background: #7b79ff;
--tag-text: #ffffff;
--suggestion-background: #181826;
--suggestion-hover: #212134;
}
`;
const styles = styledComponents.css`
.react-tagsinput {
width: 100%;
border: 1px solid var(--input-border);
border-radius: 4px;
overflow: hidden;
padding-left: 5px;
padding-top: 5px;
}
.react-tagsinput--focused {
outline: 3px solid var(--primary);
}
.react-tagsinput-tag {
background-color: var(--tag-background);
border-radius: 2px;
border: 1px solid var(--tag-background);
color: var(--tag-text);
display: inline-block;
font-family: sans-serif;
font-size: 13px;
font-weight: 400;
margin-bottom: 5px;
margin-right: 5px;
padding: 5px;
}
.react-tagsinput-remove {
cursor: pointer;
font-weight: bold;
}
.react-tagsinput-tag a::before {
content: " ×";
}
.react-tagsinput-input {
background: transparent;
border: 0;
color: var(--text);
font-family: sans-serif;
font-size: 13px;
font-weight: 400;
margin-bottom: 6px;
margin-top: 1px;
outline: none;
padding: 5px;
width: 100%;
}
.react-tagsinput > span {
display: flex;
flex-flow: wrap;
}
.react-autosuggest__container {
display: flex;
flex-direction: column;
flex: auto;
}
.react-autosuggest__suggestions-container {
position: absolute;
z-index: 200;
width: 280px;
margin: 0;
padding: 0;
list-style-type: none;
background-color: var(--suggestion-background);
}
.react-autosuggest__suggestions-container--open {
border: 1px solid var(--input-border);
}
.react-autosuggest__suggestion {
cursor: pointer;
padding: 10px 20px;
}
.react-autosuggest__suggestion > span {
font-size: 13px;
font-weight: 400;
}
.react-autosuggest__suggestion--highlighted,
.react-autosuggest__suggestion--focused {
background-color: var(--suggestion-hover);
}
`;
const getStyling = (theme) => {
let themeStyle = light;
switch (theme) {
case "dark":
themeStyle = dark;
break;
default:
themeStyle = light;
}
return styledComponents.createGlobalStyle`
${themeStyle}
${styles}
`;
};
const ThemeStyle = getStyling(localStorage.getItem("STRAPI_THEME"));
const Tags = ({
attribute,
description,
error,
label,
labelAction,
name,
onChange,
required,
value
}) => {
const { formatMessage } = reactIntl.useIntl();
const apiUrl = attribute?.options?.apiUrl || "";
const attrName = apiUrl.slice(apiUrl.lastIndexOf("=") + 1) || "name";
const inputEle = react.useRef(null);
const [tags, setTags] = react.useState(() => {
try {
const values = typeof value === "string" ? JSON.parse(value) : value;
return Array.isArray(values) ? values.map((v) => v[attrName] || v.name || v) : [];
} catch (e) {
return [];
}
});
const [suggestions, setSuggestions] = react.useState([]);
react.useEffect(() => {
const suggestionsContainer = document.querySelector(
".react-autosuggest__suggestions-container"
);
if (suggestionsContainer && inputEle.current) {
suggestionsContainer.style.top = `${inputEle.current.offsetHeight + 5}px`;
}
const handleClickOutside = (event) => {
const tagsInput = document.querySelector(".react-tagsinput");
if (tagsInput) {
tagsInput.classList.toggle(
"react-tagsinput--focused",
inputEle.current?.contains(event.target)
);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
const handleTagsChange = async (newTags) => {
const lastTag = newTags[newTags.length - 1];
const suggestionsArray = suggestions.data || [];
const existingTag = suggestionsArray.find(
(s) => s[attrName]?.toLowerCase() === lastTag.toLowerCase()
);
if (!existingTag) {
if (apiUrl) {
try {
const response = await axios__default.default.post(apiUrl, {
data: {
[attrName]: lastTag
}
});
setSuggestions((prevSuggestions) => {
const newSuggestionsData = [...prevSuggestions.data || [], response.data.data];
return { ...prevSuggestions, data: newSuggestionsData };
});
newTags[newTags.length - 1] = response.data.data[attrName];
} catch (error2) {
console.error("Error creating new tag:", error2);
}
} else {
setSuggestions((prevSuggestions) => {
const newSuggestion = { id: Date.now(), [attrName]: lastTag };
const newSuggestionsData = [...prevSuggestions.data || [], newSuggestion];
return { ...prevSuggestions, data: newSuggestionsData };
});
}
}
setTags(newTags);
const value2 = JSON.stringify(newTags.map((tag) => ({ [attrName]: tag })));
onChange({
target: {
name,
value: value2,
type: attribute.type
}
});
};
const getSuggestions = async () => {
if (!apiUrl)
return;
try {
const res = await axios__default.default.get(apiUrl);
setSuggestions(res.data);
} catch (err) {
setSuggestions({ data: [] });
}
};
const autocompleteRenderInput = (props) => {
const handleOnChange = (e, { newValue, method }) => {
if (method === "enter") {
e.preventDefault();
} else {
props.onChange(e);
}
};
const inputValue = props.value && props.value.trim() || "";
const inputLength = inputValue.length;
let s = suggestions.data || [];
if (s.length <= 0) {
getSuggestions();
}
if (inputLength > 0) {
s = s.filter((state) => {
const suggestionName = state[attrName] || "";
return suggestionName.toLowerCase().slice(0, inputLength) === inputValue;
}).map((state) => ({
id: state.id,
[attrName]: state[attrName] || ""
}));
}
return /* @__PURE__ */ jsxRuntime.jsx(
Autosuggest__default.default,
{
ref: props.ref,
suggestions: s,
shouldRenderSuggestions: (value2) => value2 && value2.trim().length > 0,
getSuggestionValue: (s2) => s2[attrName],
renderSuggestion: (s2) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: s2[attrName] }),
inputProps: { ...props, onChange: handleOnChange },
onSuggestionSelected: (_, { suggestion }) => props.addTag(suggestion[attrName]),
onSuggestionsFetchRequested: () => {
}
}
);
};
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
designSystem.Field.Root,
{
name,
id: name,
error,
hint: description && formatMessage({ id: description }),
required,
children: /* @__PURE__ */ jsxRuntime.jsxs(
designSystem.Flex,
{
direction: "column",
alignItems: "stretch",
gap: 1,
style: { position: "relative" },
ref: inputEle,
children: [
label && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { action: labelAction, children: formatMessage({ id: label, defaultMessage: "Tags" }) }),
/* @__PURE__ */ jsxRuntime.jsx(ThemeStyle, {}),
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", children: /* @__PURE__ */ jsxRuntime.jsx(
TagsInput__default.default,
{
value: tags,
onChange: handleTagsChange,
onlyUnique: true,
renderInput: autocompleteRenderInput
}
) }),
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {}),
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
]
}
)
}
) });
};
Tags.defaultProps = {
description: null,
disabled: false,
error: null,
labelAction: null,
required: false,
value: ""
};
Tags.propTypes = {
label: PropTypes__default.default.object.isRequired,
onChange: PropTypes__default.default.func.isRequired,
attribute: PropTypes__default.default.object.isRequired,
name: PropTypes__default.default.string.isRequired,
description: PropTypes__default.default.object,
error: PropTypes__default.default.string,
labelAction: PropTypes__default.default.object,
required: PropTypes__default.default.bool,
value: PropTypes__default.default.string
};
exports.default = Tags;
//# sourceMappingURL=Input-Dhgse2n1.js.map