@gregcm999/strapi-plugin-tagsinput 2.0.3-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/_chunks/Input-DSV3HDg_.mjs +329 -0
- package/dist/_chunks/Input-jl4WBtpd.js +334 -0
- package/dist/admin/index.js +53 -0
- package/dist/admin/index.mjs +54 -0
- package/dist/server/index.js +17 -0
- package/dist/server/index.mjs +18 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Sumita Canopas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<p align="center"><a href="https://canopas.com/contact"><img src="./assets/banner.png"></a></p>
|
|
2
|
+
|
|
3
|
+
<h1><strong>Tagsinput plugin for strapi with suggestions</strong></h1>
|
|
4
|
+
|
|
5
|
+
<h3>🚀<strong>Strapi 5 supported from <a href="https://github.com/canopas/strapi-plugin-tagsinput/releases/tag/2.0.2">2.0.2</a> </strong>🚀</h3>
|
|
6
|
+
|
|
7
|
+
This plugin is used to add tagsinput in your strapi admin panel.
|
|
8
|
+
Read more about it at [tagsinput guidence](https://blog.canopas.com/the-simple-guidance-how-to-add-tagsinput-customfield-plugin-in-strapi-b5d2b5af7c3b).
|
|
9
|
+
|
|
10
|
+
<img src="./assets/demo.png">
|
|
11
|
+
|
|
12
|
+
## How to Install
|
|
13
|
+
|
|
14
|
+
Using npm,
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
npm i strapi-plugin-tagsinput
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Using yarn,
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
yarn add strapi-plugin-tagsinput
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## How to use
|
|
27
|
+
|
|
28
|
+
After installation, you can add tagsinput as a custom field.
|
|
29
|
+
|
|
30
|
+
#### Suggestions for tag
|
|
31
|
+
|
|
32
|
+
While adding tagsInput, you will see the `API URL` field.
|
|
33
|
+
|
|
34
|
+
If you want to use REST API for suggestions, then add your API url in this field.
|
|
35
|
+
|
|
36
|
+
**Notes:**
|
|
37
|
+
|
|
38
|
+
- If the API domain is different, then a full API URL is required. i.e. `http://localhost:1337/api/tags?fields[0]=name` (Make sure API CORS are enabled for your strapi domain in this case).
|
|
39
|
+
- Otherwise, add only the path of API i.e `/api/tags?fields[0]=name`
|
|
40
|
+
- You need to add custom logic for adding created tags in `Tags` collection.
|
|
41
|
+
|
|
42
|
+
## Showcase
|
|
43
|
+
|
|
44
|
+
How to use tagsinput?
|
|
45
|
+
|
|
46
|
+
<img src="./assets/showcase.gif">
|
|
47
|
+
|
|
48
|
+
## Issues
|
|
49
|
+
|
|
50
|
+
If you face any issues, feel free to submit them with detailed information.
|
|
51
|
+
|
|
52
|
+
## Contribution
|
|
53
|
+
|
|
54
|
+
The Canopas team enthusiastically welcomes contributions and project participation! There are a bunch of things you can do if you want to contribute! The [Contributor Guide](CONTRIBUTING.md) has all the information you need for everything from reporting bugs to contributing entire new features. Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear.
|
|
55
|
+
|
|
56
|
+
## Show your support ⭐️
|
|
57
|
+
|
|
58
|
+
Add a star if this project helped you.
|
|
59
|
+
|
|
60
|
+
## Credits
|
|
61
|
+
|
|
62
|
+
This repository is owned and maintained by the [Canopas team](https://canopas.com/). If you are interested in building web apps, plugins or designing products, please let us know. We'd love to hear from you!
|
|
63
|
+
|
|
64
|
+
<a href="https://canopas.com/contact"><img src="./assets/cta.png" width=300></a>
|
|
65
|
+
|
|
66
|
+
## Licence
|
|
67
|
+
|
|
68
|
+
This repository is licenced under [MIT](https://github.com/canopas/strapi-plugin-tagsinput/blob/master/LICENSE).
|
|
69
|
+
|
|
70
|
+
## Custom Fix Purpose
|
|
71
|
+
|
|
72
|
+
- **Plugin Tags Input**
|
|
73
|
+
- Fork from `strapi-plugin-tagsinput` to `gregcm999/strapi-plugin-tagsinput`
|
|
74
|
+
- **Improve theme handling**: Added system preference support for dark/light mode ([PR #45](https://github.com/canopas/strapi-plugin-tagsinput/pull/45))
|
|
75
|
+
- **Fix deletion error**: Resolved error when removing the last tag from the input field ([PR #44](https://github.com/canopas/strapi-plugin-tagsinput/pull/44))
|
|
76
|
+
- **Better field labels**: Updated custom tag fields to use their specific labels instead of a generic "Tags" label ([PR #42](https://github.com/canopas/strapi-plugin-tagsinput/pull/42))
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useEffect } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import axios from "axios";
|
|
5
|
+
import { Field, Flex } from "@strapi/design-system";
|
|
6
|
+
import { useIntl } from "react-intl";
|
|
7
|
+
import TagsInput from "react-tagsinput";
|
|
8
|
+
import Autosuggest from "react-autosuggest";
|
|
9
|
+
import { createGlobalStyle, css } from "styled-components";
|
|
10
|
+
const light = css`
|
|
11
|
+
:root {
|
|
12
|
+
--primary: #7b79ff;
|
|
13
|
+
--secondary: rgb(255, 255, 255);
|
|
14
|
+
--text: #32324d;
|
|
15
|
+
--input-background: #ffffff;
|
|
16
|
+
--input-border: #dcdce4;
|
|
17
|
+
--tag-background: #f0f0ff;
|
|
18
|
+
--tag-text: #4945ff;
|
|
19
|
+
--suggestion-background: #ffffff;
|
|
20
|
+
--suggestion-hover: #f6f6f9;
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
const dark = css`
|
|
24
|
+
:root {
|
|
25
|
+
--primary: #7b79ff;
|
|
26
|
+
--secondary: rgb(33, 33, 52);
|
|
27
|
+
--text: #ffffff;
|
|
28
|
+
--input-background: #181826;
|
|
29
|
+
--input-border: #4a4a6a;
|
|
30
|
+
--tag-background: #7b79ff;
|
|
31
|
+
--tag-text: #ffffff;
|
|
32
|
+
--suggestion-background: #181826;
|
|
33
|
+
--suggestion-hover: #212134;
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
const styles = css`
|
|
37
|
+
.react-tagsinput {
|
|
38
|
+
width: 100%;
|
|
39
|
+
border: 1px solid var(--input-border);
|
|
40
|
+
border-radius: 4px;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
padding-left: 5px;
|
|
43
|
+
padding-top: 5px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.react-tagsinput--focused {
|
|
47
|
+
outline: 3px solid var(--primary);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.react-tagsinput-tag {
|
|
51
|
+
background-color: var(--tag-background);
|
|
52
|
+
border-radius: 2px;
|
|
53
|
+
border: 1px solid var(--tag-background);
|
|
54
|
+
color: var(--tag-text);
|
|
55
|
+
display: inline-block;
|
|
56
|
+
font-family: sans-serif;
|
|
57
|
+
font-size: 13px;
|
|
58
|
+
font-weight: 400;
|
|
59
|
+
margin-bottom: 5px;
|
|
60
|
+
margin-right: 5px;
|
|
61
|
+
padding: 5px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.react-tagsinput-remove {
|
|
65
|
+
cursor: pointer;
|
|
66
|
+
font-weight: bold;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.react-tagsinput-tag a::before {
|
|
70
|
+
content: " ×";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.react-tagsinput-input {
|
|
74
|
+
background: transparent;
|
|
75
|
+
border: 0;
|
|
76
|
+
color: var(--text);
|
|
77
|
+
font-family: sans-serif;
|
|
78
|
+
font-size: 13px;
|
|
79
|
+
font-weight: 400;
|
|
80
|
+
margin-bottom: 6px;
|
|
81
|
+
margin-top: 1px;
|
|
82
|
+
outline: none;
|
|
83
|
+
padding: 5px;
|
|
84
|
+
width: 100%;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.react-tagsinput > span {
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-flow: wrap;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.react-autosuggest__container {
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
flex: auto;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.react-autosuggest__suggestions-container {
|
|
99
|
+
position: absolute;
|
|
100
|
+
z-index: 200;
|
|
101
|
+
width: 280px;
|
|
102
|
+
margin: 0;
|
|
103
|
+
padding: 0;
|
|
104
|
+
list-style-type: none;
|
|
105
|
+
background-color: var(--suggestion-background);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.react-autosuggest__suggestions-container--open {
|
|
109
|
+
border: 1px solid var(--input-border);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.react-autosuggest__suggestion {
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
padding: 10px 20px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.react-autosuggest__suggestion > span {
|
|
118
|
+
font-size: 13px;
|
|
119
|
+
font-weight: 400;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.react-autosuggest__suggestion--highlighted,
|
|
123
|
+
.react-autosuggest__suggestion--focused {
|
|
124
|
+
background-color: var(--suggestion-hover);
|
|
125
|
+
}
|
|
126
|
+
`;
|
|
127
|
+
const getStyling = (theme) => {
|
|
128
|
+
let themeStyle = light;
|
|
129
|
+
switch (theme) {
|
|
130
|
+
case "dark":
|
|
131
|
+
themeStyle = dark;
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
themeStyle = light;
|
|
135
|
+
}
|
|
136
|
+
return createGlobalStyle`
|
|
137
|
+
${themeStyle}
|
|
138
|
+
${styles}
|
|
139
|
+
`;
|
|
140
|
+
};
|
|
141
|
+
const ThemeStyle = getStyling(getCurrentTheme());
|
|
142
|
+
const Tags = ({
|
|
143
|
+
attribute,
|
|
144
|
+
description,
|
|
145
|
+
error,
|
|
146
|
+
label,
|
|
147
|
+
labelAction,
|
|
148
|
+
name,
|
|
149
|
+
onChange,
|
|
150
|
+
required,
|
|
151
|
+
value
|
|
152
|
+
}) => {
|
|
153
|
+
const { formatMessage } = useIntl();
|
|
154
|
+
const apiUrl = attribute?.options?.apiUrl || "";
|
|
155
|
+
const attrName = apiUrl.slice(apiUrl.lastIndexOf("=") + 1) || "name";
|
|
156
|
+
const inputEle = useRef(null);
|
|
157
|
+
const [tags, setTags] = useState(() => {
|
|
158
|
+
try {
|
|
159
|
+
const values = typeof value === "string" ? JSON.parse(value) : value;
|
|
160
|
+
return Array.isArray(values) ? values.map((v) => v[attrName] || v.name || v) : [];
|
|
161
|
+
} catch (e) {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
const [suggestions, setSuggestions] = useState([]);
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
const suggestionsContainer = document.querySelector(
|
|
168
|
+
".react-autosuggest__suggestions-container"
|
|
169
|
+
);
|
|
170
|
+
if (suggestionsContainer && inputEle.current) {
|
|
171
|
+
suggestionsContainer.style.top = `${inputEle.current.offsetHeight + 5}px`;
|
|
172
|
+
}
|
|
173
|
+
const handleClickOutside = (event) => {
|
|
174
|
+
const tagsInput = document.querySelector(".react-tagsinput");
|
|
175
|
+
if (tagsInput) {
|
|
176
|
+
tagsInput.classList.toggle(
|
|
177
|
+
"react-tagsinput--focused",
|
|
178
|
+
inputEle.current?.contains(event.target)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
183
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
184
|
+
}, []);
|
|
185
|
+
const handleTagsChange = async (newTags) => {
|
|
186
|
+
const lastTag = newTags[newTags.length - 1];
|
|
187
|
+
const suggestionsArray = suggestions.data || [];
|
|
188
|
+
const existingTag = suggestionsArray.find(
|
|
189
|
+
(s) => s[attrName]?.toLowerCase() === lastTag?.toLowerCase()
|
|
190
|
+
);
|
|
191
|
+
if (lastTag && !existingTag) {
|
|
192
|
+
if (apiUrl) {
|
|
193
|
+
try {
|
|
194
|
+
const response = await axios.post(apiUrl, {
|
|
195
|
+
data: {
|
|
196
|
+
[attrName]: lastTag
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
setSuggestions((prevSuggestions) => {
|
|
200
|
+
const newSuggestionsData = [...prevSuggestions.data || [], response.data.data];
|
|
201
|
+
return { ...prevSuggestions, data: newSuggestionsData };
|
|
202
|
+
});
|
|
203
|
+
newTags[newTags.length - 1] = response.data.data[attrName];
|
|
204
|
+
} catch (error2) {
|
|
205
|
+
console.error("Error creating new tag:", error2);
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
setSuggestions((prevSuggestions) => {
|
|
209
|
+
const newSuggestion = { id: Date.now(), [attrName]: lastTag };
|
|
210
|
+
const newSuggestionsData = [...prevSuggestions.data || [], newSuggestion];
|
|
211
|
+
return { ...prevSuggestions, data: newSuggestionsData };
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
setTags(newTags);
|
|
216
|
+
const value2 = JSON.stringify(newTags.map((tag) => ({ [attrName]: tag })));
|
|
217
|
+
onChange({
|
|
218
|
+
target: {
|
|
219
|
+
name,
|
|
220
|
+
value: value2,
|
|
221
|
+
type: attribute.type
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
const getSuggestions = async () => {
|
|
226
|
+
if (!apiUrl) return;
|
|
227
|
+
try {
|
|
228
|
+
const res = await axios.get(apiUrl);
|
|
229
|
+
setSuggestions(res.data);
|
|
230
|
+
} catch (err) {
|
|
231
|
+
setSuggestions({ data: [] });
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const autocompleteRenderInput = (props) => {
|
|
235
|
+
const handleOnChange = (e, { newValue, method }) => {
|
|
236
|
+
if (method === "enter") {
|
|
237
|
+
e.preventDefault();
|
|
238
|
+
} else {
|
|
239
|
+
props.onChange(e);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const inputValue = props.value && props.value.trim() || "";
|
|
243
|
+
const inputLength = inputValue.length;
|
|
244
|
+
let s = suggestions.data || [];
|
|
245
|
+
if (s.length <= 0) {
|
|
246
|
+
getSuggestions();
|
|
247
|
+
}
|
|
248
|
+
if (inputLength > 0) {
|
|
249
|
+
s = s.filter((state) => {
|
|
250
|
+
const suggestionName = state[attrName] || "";
|
|
251
|
+
return suggestionName.toLowerCase().slice(0, inputLength) === inputValue;
|
|
252
|
+
}).map((state) => ({
|
|
253
|
+
id: state.id,
|
|
254
|
+
[attrName]: state[attrName] || ""
|
|
255
|
+
}));
|
|
256
|
+
}
|
|
257
|
+
return /* @__PURE__ */ jsx(
|
|
258
|
+
Autosuggest,
|
|
259
|
+
{
|
|
260
|
+
ref: props.ref,
|
|
261
|
+
suggestions: s,
|
|
262
|
+
shouldRenderSuggestions: (value2) => value2 && value2.trim().length > 0,
|
|
263
|
+
getSuggestionValue: (s2) => s2[attrName],
|
|
264
|
+
renderSuggestion: (s2) => /* @__PURE__ */ jsx("span", { children: s2[attrName] }),
|
|
265
|
+
inputProps: { ...props, onChange: handleOnChange },
|
|
266
|
+
onSuggestionSelected: (_, { suggestion }) => props.addTag(suggestion[attrName]),
|
|
267
|
+
onSuggestionsFetchRequested: () => {
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
};
|
|
272
|
+
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
273
|
+
Field.Root,
|
|
274
|
+
{
|
|
275
|
+
name,
|
|
276
|
+
id: name,
|
|
277
|
+
error,
|
|
278
|
+
hint: description && formatMessage({ id: description }),
|
|
279
|
+
required,
|
|
280
|
+
children: /* @__PURE__ */ jsxs(
|
|
281
|
+
Flex,
|
|
282
|
+
{
|
|
283
|
+
direction: "column",
|
|
284
|
+
alignItems: "stretch",
|
|
285
|
+
gap: 1,
|
|
286
|
+
style: { position: "relative" },
|
|
287
|
+
ref: inputEle,
|
|
288
|
+
children: [
|
|
289
|
+
label && /* @__PURE__ */ jsx(Field.Label, { action: labelAction, children: formatMessage({ id: label, defaultMessage: label }) }),
|
|
290
|
+
/* @__PURE__ */ jsx(ThemeStyle, {}),
|
|
291
|
+
/* @__PURE__ */ jsx(Flex, { direction: "column", children: /* @__PURE__ */ jsx(
|
|
292
|
+
TagsInput,
|
|
293
|
+
{
|
|
294
|
+
value: tags,
|
|
295
|
+
onChange: handleTagsChange,
|
|
296
|
+
onlyUnique: true,
|
|
297
|
+
renderInput: autocompleteRenderInput
|
|
298
|
+
}
|
|
299
|
+
) }),
|
|
300
|
+
/* @__PURE__ */ jsx(Field.Hint, {}),
|
|
301
|
+
/* @__PURE__ */ jsx(Field.Error, {})
|
|
302
|
+
]
|
|
303
|
+
}
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
) });
|
|
307
|
+
};
|
|
308
|
+
Tags.defaultProps = {
|
|
309
|
+
description: null,
|
|
310
|
+
disabled: false,
|
|
311
|
+
error: null,
|
|
312
|
+
labelAction: null,
|
|
313
|
+
required: false,
|
|
314
|
+
value: ""
|
|
315
|
+
};
|
|
316
|
+
Tags.propTypes = {
|
|
317
|
+
label: PropTypes.object.isRequired,
|
|
318
|
+
onChange: PropTypes.func.isRequired,
|
|
319
|
+
attribute: PropTypes.object.isRequired,
|
|
320
|
+
name: PropTypes.string.isRequired,
|
|
321
|
+
description: PropTypes.object,
|
|
322
|
+
error: PropTypes.string,
|
|
323
|
+
labelAction: PropTypes.object,
|
|
324
|
+
required: PropTypes.bool,
|
|
325
|
+
value: PropTypes.string
|
|
326
|
+
};
|
|
327
|
+
export {
|
|
328
|
+
Tags as default
|
|
329
|
+
};
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const PropTypes = require("prop-types");
|
|
6
|
+
const axios = require("axios");
|
|
7
|
+
const designSystem = require("@strapi/design-system");
|
|
8
|
+
const reactIntl = require("react-intl");
|
|
9
|
+
const TagsInput = require("react-tagsinput");
|
|
10
|
+
const Autosuggest = require("react-autosuggest");
|
|
11
|
+
const styledComponents = require("styled-components");
|
|
12
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
13
|
+
const PropTypes__default = /* @__PURE__ */ _interopDefault(PropTypes);
|
|
14
|
+
const axios__default = /* @__PURE__ */ _interopDefault(axios);
|
|
15
|
+
const TagsInput__default = /* @__PURE__ */ _interopDefault(TagsInput);
|
|
16
|
+
const Autosuggest__default = /* @__PURE__ */ _interopDefault(Autosuggest);
|
|
17
|
+
const light = styledComponents.css`
|
|
18
|
+
:root {
|
|
19
|
+
--primary: #7b79ff;
|
|
20
|
+
--secondary: rgb(255, 255, 255);
|
|
21
|
+
--text: #32324d;
|
|
22
|
+
--input-background: #ffffff;
|
|
23
|
+
--input-border: #dcdce4;
|
|
24
|
+
--tag-background: #f0f0ff;
|
|
25
|
+
--tag-text: #4945ff;
|
|
26
|
+
--suggestion-background: #ffffff;
|
|
27
|
+
--suggestion-hover: #f6f6f9;
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
const dark = styledComponents.css`
|
|
31
|
+
:root {
|
|
32
|
+
--primary: #7b79ff;
|
|
33
|
+
--secondary: rgb(33, 33, 52);
|
|
34
|
+
--text: #ffffff;
|
|
35
|
+
--input-background: #181826;
|
|
36
|
+
--input-border: #4a4a6a;
|
|
37
|
+
--tag-background: #7b79ff;
|
|
38
|
+
--tag-text: #ffffff;
|
|
39
|
+
--suggestion-background: #181826;
|
|
40
|
+
--suggestion-hover: #212134;
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
const styles = styledComponents.css`
|
|
44
|
+
.react-tagsinput {
|
|
45
|
+
width: 100%;
|
|
46
|
+
border: 1px solid var(--input-border);
|
|
47
|
+
border-radius: 4px;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
padding-left: 5px;
|
|
50
|
+
padding-top: 5px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.react-tagsinput--focused {
|
|
54
|
+
outline: 3px solid var(--primary);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.react-tagsinput-tag {
|
|
58
|
+
background-color: var(--tag-background);
|
|
59
|
+
border-radius: 2px;
|
|
60
|
+
border: 1px solid var(--tag-background);
|
|
61
|
+
color: var(--tag-text);
|
|
62
|
+
display: inline-block;
|
|
63
|
+
font-family: sans-serif;
|
|
64
|
+
font-size: 13px;
|
|
65
|
+
font-weight: 400;
|
|
66
|
+
margin-bottom: 5px;
|
|
67
|
+
margin-right: 5px;
|
|
68
|
+
padding: 5px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.react-tagsinput-remove {
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
font-weight: bold;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.react-tagsinput-tag a::before {
|
|
77
|
+
content: " ×";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.react-tagsinput-input {
|
|
81
|
+
background: transparent;
|
|
82
|
+
border: 0;
|
|
83
|
+
color: var(--text);
|
|
84
|
+
font-family: sans-serif;
|
|
85
|
+
font-size: 13px;
|
|
86
|
+
font-weight: 400;
|
|
87
|
+
margin-bottom: 6px;
|
|
88
|
+
margin-top: 1px;
|
|
89
|
+
outline: none;
|
|
90
|
+
padding: 5px;
|
|
91
|
+
width: 100%;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.react-tagsinput > span {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-flow: wrap;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.react-autosuggest__container {
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-direction: column;
|
|
102
|
+
flex: auto;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.react-autosuggest__suggestions-container {
|
|
106
|
+
position: absolute;
|
|
107
|
+
z-index: 200;
|
|
108
|
+
width: 280px;
|
|
109
|
+
margin: 0;
|
|
110
|
+
padding: 0;
|
|
111
|
+
list-style-type: none;
|
|
112
|
+
background-color: var(--suggestion-background);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.react-autosuggest__suggestions-container--open {
|
|
116
|
+
border: 1px solid var(--input-border);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.react-autosuggest__suggestion {
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
padding: 10px 20px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.react-autosuggest__suggestion > span {
|
|
125
|
+
font-size: 13px;
|
|
126
|
+
font-weight: 400;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.react-autosuggest__suggestion--highlighted,
|
|
130
|
+
.react-autosuggest__suggestion--focused {
|
|
131
|
+
background-color: var(--suggestion-hover);
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
const getStyling = (theme) => {
|
|
135
|
+
let themeStyle = light;
|
|
136
|
+
switch (theme) {
|
|
137
|
+
case "dark":
|
|
138
|
+
themeStyle = dark;
|
|
139
|
+
break;
|
|
140
|
+
default:
|
|
141
|
+
themeStyle = light;
|
|
142
|
+
}
|
|
143
|
+
return styledComponents.createGlobalStyle`
|
|
144
|
+
${themeStyle}
|
|
145
|
+
${styles}
|
|
146
|
+
`;
|
|
147
|
+
};
|
|
148
|
+
const ThemeStyle = getStyling(getCurrentTheme());
|
|
149
|
+
const Tags = ({
|
|
150
|
+
attribute,
|
|
151
|
+
description,
|
|
152
|
+
error,
|
|
153
|
+
label,
|
|
154
|
+
labelAction,
|
|
155
|
+
name,
|
|
156
|
+
onChange,
|
|
157
|
+
required,
|
|
158
|
+
value
|
|
159
|
+
}) => {
|
|
160
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
161
|
+
const apiUrl = attribute?.options?.apiUrl || "";
|
|
162
|
+
const attrName = apiUrl.slice(apiUrl.lastIndexOf("=") + 1) || "name";
|
|
163
|
+
const inputEle = react.useRef(null);
|
|
164
|
+
const [tags, setTags] = react.useState(() => {
|
|
165
|
+
try {
|
|
166
|
+
const values = typeof value === "string" ? JSON.parse(value) : value;
|
|
167
|
+
return Array.isArray(values) ? values.map((v) => v[attrName] || v.name || v) : [];
|
|
168
|
+
} catch (e) {
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const [suggestions, setSuggestions] = react.useState([]);
|
|
173
|
+
react.useEffect(() => {
|
|
174
|
+
const suggestionsContainer = document.querySelector(
|
|
175
|
+
".react-autosuggest__suggestions-container"
|
|
176
|
+
);
|
|
177
|
+
if (suggestionsContainer && inputEle.current) {
|
|
178
|
+
suggestionsContainer.style.top = `${inputEle.current.offsetHeight + 5}px`;
|
|
179
|
+
}
|
|
180
|
+
const handleClickOutside = (event) => {
|
|
181
|
+
const tagsInput = document.querySelector(".react-tagsinput");
|
|
182
|
+
if (tagsInput) {
|
|
183
|
+
tagsInput.classList.toggle(
|
|
184
|
+
"react-tagsinput--focused",
|
|
185
|
+
inputEle.current?.contains(event.target)
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
190
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
191
|
+
}, []);
|
|
192
|
+
const handleTagsChange = async (newTags) => {
|
|
193
|
+
const lastTag = newTags[newTags.length - 1];
|
|
194
|
+
const suggestionsArray = suggestions.data || [];
|
|
195
|
+
const existingTag = suggestionsArray.find(
|
|
196
|
+
(s) => s[attrName]?.toLowerCase() === lastTag?.toLowerCase()
|
|
197
|
+
);
|
|
198
|
+
if (lastTag && !existingTag) {
|
|
199
|
+
if (apiUrl) {
|
|
200
|
+
try {
|
|
201
|
+
const response = await axios__default.default.post(apiUrl, {
|
|
202
|
+
data: {
|
|
203
|
+
[attrName]: lastTag
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
setSuggestions((prevSuggestions) => {
|
|
207
|
+
const newSuggestionsData = [...prevSuggestions.data || [], response.data.data];
|
|
208
|
+
return { ...prevSuggestions, data: newSuggestionsData };
|
|
209
|
+
});
|
|
210
|
+
newTags[newTags.length - 1] = response.data.data[attrName];
|
|
211
|
+
} catch (error2) {
|
|
212
|
+
console.error("Error creating new tag:", error2);
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
setSuggestions((prevSuggestions) => {
|
|
216
|
+
const newSuggestion = { id: Date.now(), [attrName]: lastTag };
|
|
217
|
+
const newSuggestionsData = [...prevSuggestions.data || [], newSuggestion];
|
|
218
|
+
return { ...prevSuggestions, data: newSuggestionsData };
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
setTags(newTags);
|
|
223
|
+
const value2 = JSON.stringify(newTags.map((tag) => ({ [attrName]: tag })));
|
|
224
|
+
onChange({
|
|
225
|
+
target: {
|
|
226
|
+
name,
|
|
227
|
+
value: value2,
|
|
228
|
+
type: attribute.type
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
const getSuggestions = async () => {
|
|
233
|
+
if (!apiUrl) return;
|
|
234
|
+
try {
|
|
235
|
+
const res = await axios__default.default.get(apiUrl);
|
|
236
|
+
setSuggestions(res.data);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
setSuggestions({ data: [] });
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const autocompleteRenderInput = (props) => {
|
|
242
|
+
const handleOnChange = (e, { newValue, method }) => {
|
|
243
|
+
if (method === "enter") {
|
|
244
|
+
e.preventDefault();
|
|
245
|
+
} else {
|
|
246
|
+
props.onChange(e);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
const inputValue = props.value && props.value.trim() || "";
|
|
250
|
+
const inputLength = inputValue.length;
|
|
251
|
+
let s = suggestions.data || [];
|
|
252
|
+
if (s.length <= 0) {
|
|
253
|
+
getSuggestions();
|
|
254
|
+
}
|
|
255
|
+
if (inputLength > 0) {
|
|
256
|
+
s = s.filter((state) => {
|
|
257
|
+
const suggestionName = state[attrName] || "";
|
|
258
|
+
return suggestionName.toLowerCase().slice(0, inputLength) === inputValue;
|
|
259
|
+
}).map((state) => ({
|
|
260
|
+
id: state.id,
|
|
261
|
+
[attrName]: state[attrName] || ""
|
|
262
|
+
}));
|
|
263
|
+
}
|
|
264
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
265
|
+
Autosuggest__default.default,
|
|
266
|
+
{
|
|
267
|
+
ref: props.ref,
|
|
268
|
+
suggestions: s,
|
|
269
|
+
shouldRenderSuggestions: (value2) => value2 && value2.trim().length > 0,
|
|
270
|
+
getSuggestionValue: (s2) => s2[attrName],
|
|
271
|
+
renderSuggestion: (s2) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: s2[attrName] }),
|
|
272
|
+
inputProps: { ...props, onChange: handleOnChange },
|
|
273
|
+
onSuggestionSelected: (_, { suggestion }) => props.addTag(suggestion[attrName]),
|
|
274
|
+
onSuggestionsFetchRequested: () => {
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
};
|
|
279
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
280
|
+
designSystem.Field.Root,
|
|
281
|
+
{
|
|
282
|
+
name,
|
|
283
|
+
id: name,
|
|
284
|
+
error,
|
|
285
|
+
hint: description && formatMessage({ id: description }),
|
|
286
|
+
required,
|
|
287
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
288
|
+
designSystem.Flex,
|
|
289
|
+
{
|
|
290
|
+
direction: "column",
|
|
291
|
+
alignItems: "stretch",
|
|
292
|
+
gap: 1,
|
|
293
|
+
style: { position: "relative" },
|
|
294
|
+
ref: inputEle,
|
|
295
|
+
children: [
|
|
296
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { action: labelAction, children: formatMessage({ id: label, defaultMessage: label }) }),
|
|
297
|
+
/* @__PURE__ */ jsxRuntime.jsx(ThemeStyle, {}),
|
|
298
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
299
|
+
TagsInput__default.default,
|
|
300
|
+
{
|
|
301
|
+
value: tags,
|
|
302
|
+
onChange: handleTagsChange,
|
|
303
|
+
onlyUnique: true,
|
|
304
|
+
renderInput: autocompleteRenderInput
|
|
305
|
+
}
|
|
306
|
+
) }),
|
|
307
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {}),
|
|
308
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
) });
|
|
314
|
+
};
|
|
315
|
+
Tags.defaultProps = {
|
|
316
|
+
description: null,
|
|
317
|
+
disabled: false,
|
|
318
|
+
error: null,
|
|
319
|
+
labelAction: null,
|
|
320
|
+
required: false,
|
|
321
|
+
value: ""
|
|
322
|
+
};
|
|
323
|
+
Tags.propTypes = {
|
|
324
|
+
label: PropTypes__default.default.object.isRequired,
|
|
325
|
+
onChange: PropTypes__default.default.func.isRequired,
|
|
326
|
+
attribute: PropTypes__default.default.object.isRequired,
|
|
327
|
+
name: PropTypes__default.default.string.isRequired,
|
|
328
|
+
description: PropTypes__default.default.object,
|
|
329
|
+
error: PropTypes__default.default.string,
|
|
330
|
+
labelAction: PropTypes__default.default.object,
|
|
331
|
+
required: PropTypes__default.default.bool,
|
|
332
|
+
value: PropTypes__default.default.string
|
|
333
|
+
};
|
|
334
|
+
exports.default = Tags;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const name = "@gregcm999/strapi-plugin-tagsinput";
|
|
3
|
+
const pluginPkg = {
|
|
4
|
+
name
|
|
5
|
+
};
|
|
6
|
+
const pluginId = pluginPkg.name.replace(/^(@[^/]+\/)?strapi-plugin-/i, "");
|
|
7
|
+
const getTranslation = (id) => `${pluginId}.${id}`;
|
|
8
|
+
const index = {
|
|
9
|
+
register(app) {
|
|
10
|
+
app.customFields.register({
|
|
11
|
+
name: "tags",
|
|
12
|
+
pluginId,
|
|
13
|
+
type: "text",
|
|
14
|
+
intlLabel: {
|
|
15
|
+
id: getTranslation("form.label"),
|
|
16
|
+
defaultMessage: "TagsInput"
|
|
17
|
+
},
|
|
18
|
+
intlDescription: {
|
|
19
|
+
id: getTranslation("form.description"),
|
|
20
|
+
defaultMessage: "TagsInput to add custom tags"
|
|
21
|
+
},
|
|
22
|
+
components: {
|
|
23
|
+
Input: async () => Promise.resolve().then(() => require(
|
|
24
|
+
/* webpackChunkName: "input-component" */
|
|
25
|
+
"../_chunks/Input-jl4WBtpd.js"
|
|
26
|
+
))
|
|
27
|
+
},
|
|
28
|
+
options: {
|
|
29
|
+
base: [
|
|
30
|
+
{
|
|
31
|
+
sectionTitle: {
|
|
32
|
+
id: "form.section.apiUrl",
|
|
33
|
+
defaultMessage: "API Url"
|
|
34
|
+
},
|
|
35
|
+
items: [
|
|
36
|
+
{
|
|
37
|
+
intlLabel: {
|
|
38
|
+
id: "form.apiUrl",
|
|
39
|
+
defaultMessage: "Rest API URL for suggestions"
|
|
40
|
+
},
|
|
41
|
+
name: "options.apiUrl",
|
|
42
|
+
type: "text",
|
|
43
|
+
value: "",
|
|
44
|
+
options: []
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
module.exports = index;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const name = "@gregcm999/strapi-plugin-tagsinput";
|
|
2
|
+
const pluginPkg = {
|
|
3
|
+
name
|
|
4
|
+
};
|
|
5
|
+
const pluginId = pluginPkg.name.replace(/^(@[^/]+\/)?strapi-plugin-/i, "");
|
|
6
|
+
const getTranslation = (id) => `${pluginId}.${id}`;
|
|
7
|
+
const index = {
|
|
8
|
+
register(app) {
|
|
9
|
+
app.customFields.register({
|
|
10
|
+
name: "tags",
|
|
11
|
+
pluginId,
|
|
12
|
+
type: "text",
|
|
13
|
+
intlLabel: {
|
|
14
|
+
id: getTranslation("form.label"),
|
|
15
|
+
defaultMessage: "TagsInput"
|
|
16
|
+
},
|
|
17
|
+
intlDescription: {
|
|
18
|
+
id: getTranslation("form.description"),
|
|
19
|
+
defaultMessage: "TagsInput to add custom tags"
|
|
20
|
+
},
|
|
21
|
+
components: {
|
|
22
|
+
Input: async () => import(
|
|
23
|
+
/* webpackChunkName: "input-component" */
|
|
24
|
+
"../_chunks/Input-DSV3HDg_.mjs"
|
|
25
|
+
)
|
|
26
|
+
},
|
|
27
|
+
options: {
|
|
28
|
+
base: [
|
|
29
|
+
{
|
|
30
|
+
sectionTitle: {
|
|
31
|
+
id: "form.section.apiUrl",
|
|
32
|
+
defaultMessage: "API Url"
|
|
33
|
+
},
|
|
34
|
+
items: [
|
|
35
|
+
{
|
|
36
|
+
intlLabel: {
|
|
37
|
+
id: "form.apiUrl",
|
|
38
|
+
defaultMessage: "Rest API URL for suggestions"
|
|
39
|
+
},
|
|
40
|
+
name: "options.apiUrl",
|
|
41
|
+
type: "text",
|
|
42
|
+
value: "",
|
|
43
|
+
options: []
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
export {
|
|
53
|
+
index as default
|
|
54
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
function getDefaultExportFromCjs(x) {
|
|
3
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
4
|
+
}
|
|
5
|
+
var register$1 = ({ strapi }) => {
|
|
6
|
+
strapi.customFields.register({
|
|
7
|
+
name: "tags",
|
|
8
|
+
plugin: "tagsinput",
|
|
9
|
+
type: "json"
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
const register = register$1;
|
|
13
|
+
var src = {
|
|
14
|
+
register
|
|
15
|
+
};
|
|
16
|
+
const index = /* @__PURE__ */ getDefaultExportFromCjs(src);
|
|
17
|
+
module.exports = index;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function getDefaultExportFromCjs(x) {
|
|
2
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
3
|
+
}
|
|
4
|
+
var register$1 = ({ strapi }) => {
|
|
5
|
+
strapi.customFields.register({
|
|
6
|
+
name: "tags",
|
|
7
|
+
plugin: "tagsinput",
|
|
8
|
+
type: "json"
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
const register = register$1;
|
|
12
|
+
var src = {
|
|
13
|
+
register
|
|
14
|
+
};
|
|
15
|
+
const index = /* @__PURE__ */ getDefaultExportFromCjs(src);
|
|
16
|
+
export {
|
|
17
|
+
index as default
|
|
18
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gregcm999/strapi-plugin-tagsinput",
|
|
3
|
+
"version": "2.0.3-beta.3",
|
|
4
|
+
"description": "Tagsinput plugin for your strapi project",
|
|
5
|
+
"strapi": {
|
|
6
|
+
"name": "tagsinput",
|
|
7
|
+
"description": "Tagsinput plugin for your strapi project",
|
|
8
|
+
"kind": "plugin",
|
|
9
|
+
"displayName": "Tagsinput"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/canopas/strapi-plugin-tagsinput.git"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "strapi-plugin build",
|
|
17
|
+
"verify": "strapi-plugin verify",
|
|
18
|
+
"watch": "strapi-plugin watch",
|
|
19
|
+
"watch:link": "strapi-plugin watch:link"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
"./package.json": "./package.json",
|
|
23
|
+
"./strapi-admin": {
|
|
24
|
+
"source": "./admin/src/index.js",
|
|
25
|
+
"import": "./dist/admin/index.mjs",
|
|
26
|
+
"require": "./dist/admin/index.js",
|
|
27
|
+
"default": "./dist/admin/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./strapi-server": {
|
|
30
|
+
"source": "./server/src/index.js",
|
|
31
|
+
"import": "./dist/server/index.mjs",
|
|
32
|
+
"require": "./dist/server/index.js",
|
|
33
|
+
"default": "./dist/server/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@strapi/design-system": "^2.0.0-rc.11",
|
|
41
|
+
"@strapi/icons": "^2.0.0-rc.11",
|
|
42
|
+
"axios": "^1.7.7",
|
|
43
|
+
"prop-types": "^15.8.1",
|
|
44
|
+
"react-autosuggest": "^10.1.0",
|
|
45
|
+
"react-intl": "^6.7.0",
|
|
46
|
+
"react-tagsinput": "^3.20.3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@strapi/sdk-plugin": "^5.2.6",
|
|
50
|
+
"@strapi/strapi": "^5.0.2",
|
|
51
|
+
"react": "^18.3.1",
|
|
52
|
+
"react-dom": "^18.3.1",
|
|
53
|
+
"react-router-dom": "^6.26.2",
|
|
54
|
+
"styled-components": "^6.1.13"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@strapi/sdk-plugin": "^5.2.6",
|
|
58
|
+
"@strapi/strapi": "^5.0.2",
|
|
59
|
+
"react": "^18.3.1",
|
|
60
|
+
"react-dom": "^18.3.1",
|
|
61
|
+
"react-router-dom": "^6.26.2",
|
|
62
|
+
"styled-components": "^6.1.13"
|
|
63
|
+
},
|
|
64
|
+
"author": "Canopas",
|
|
65
|
+
"maintainers": [
|
|
66
|
+
"Canopas"
|
|
67
|
+
],
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=20.0.0 <=24.x.x",
|
|
70
|
+
"npm": ">=6.0.0"
|
|
71
|
+
},
|
|
72
|
+
"license": "MIT",
|
|
73
|
+
"main": "strapi-server.js",
|
|
74
|
+
"keywords": [
|
|
75
|
+
"strapi",
|
|
76
|
+
"plugin",
|
|
77
|
+
"tagsinput"
|
|
78
|
+
],
|
|
79
|
+
"bugs": {
|
|
80
|
+
"url": "https://github.com/canopas/strapi-plugin-tagsinput/issues"
|
|
81
|
+
},
|
|
82
|
+
"homepage": "https://github.com/canopas/strapi-plugin-tagsinput#readme",
|
|
83
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
84
|
+
}
|