@webbycrown/advanced-fields 1.0.7 → 1.0.9
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/README.md +199 -51
- package/dist/_chunks/index-B6ENZ58R.js +212 -0
- package/dist/_chunks/index-BIX3GMgH.mjs +330 -0
- package/dist/_chunks/index-BYdUTGX8.mjs +212 -0
- package/dist/_chunks/index-CaEWvvZV.js +330 -0
- package/dist/_chunks/index-ClnVdkjS.js +1225 -0
- package/dist/_chunks/index-D2fdW_nl.mjs +1226 -0
- package/dist/_chunks/index-DW9l5xXR.js +191 -0
- package/dist/_chunks/index-Djus_suc.mjs +191 -0
- package/dist/admin/index.js +2 -878
- package/dist/admin/index.mjs +2 -878
- package/dist/server/index.js +54 -26
- package/dist/server/index.mjs +54 -26
- package/package.json +3 -2
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
3
|
+
import { Box, Field, MultiSelect, MultiSelectOption } from "@strapi/design-system";
|
|
4
|
+
import { useState, useEffect } from "react";
|
|
5
|
+
const AdvancedEnumeration = ({
|
|
6
|
+
attribute = {},
|
|
7
|
+
description = { id: "", defaultMessage: "" },
|
|
8
|
+
disabled,
|
|
9
|
+
error,
|
|
10
|
+
intlLabel = { id: "", defaultMessage: "" },
|
|
11
|
+
labelAction,
|
|
12
|
+
name,
|
|
13
|
+
onChange,
|
|
14
|
+
required,
|
|
15
|
+
value
|
|
16
|
+
}) => {
|
|
17
|
+
const { formatMessage } = useIntl();
|
|
18
|
+
const {
|
|
19
|
+
enumOptions = "",
|
|
20
|
+
minChoices = 0,
|
|
21
|
+
maxChoices = 0,
|
|
22
|
+
defaultSelected = "",
|
|
23
|
+
customErrorMessage = "",
|
|
24
|
+
fieldNote = ""
|
|
25
|
+
} = attribute.options || attribute;
|
|
26
|
+
const fieldNoteFromAttribute = attribute.options?.fieldNote || "";
|
|
27
|
+
const options = enumOptions.split("\n").filter((opt) => opt.trim()).map((opt) => {
|
|
28
|
+
const parts = opt.split("|");
|
|
29
|
+
const optionValue = parts[0]?.trim() || "";
|
|
30
|
+
const label = parts[1]?.trim() || optionValue;
|
|
31
|
+
return { value: optionValue, label };
|
|
32
|
+
}).filter((opt) => opt.value);
|
|
33
|
+
const getInitialValues = () => {
|
|
34
|
+
if (value && Array.isArray(value) && value.length > 0) {
|
|
35
|
+
return value.map(String);
|
|
36
|
+
} else if (value && typeof value === "string" && value.trim()) {
|
|
37
|
+
return value.split(",").map((v) => v.trim()).filter((v) => v);
|
|
38
|
+
} else if (defaultSelected && typeof defaultSelected === "string" && defaultSelected.trim()) {
|
|
39
|
+
return defaultSelected.split("\n").map((v) => v.trim()).filter((v) => v);
|
|
40
|
+
}
|
|
41
|
+
return [];
|
|
42
|
+
};
|
|
43
|
+
const [fieldValue, setFieldValue] = useState(getInitialValues);
|
|
44
|
+
const [validationError, setValidationError] = useState(null);
|
|
45
|
+
const [hasInteracted, setHasInteracted] = useState(false);
|
|
46
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
47
|
+
const validateSelection = (val) => {
|
|
48
|
+
const values = Array.isArray(val) ? val : [];
|
|
49
|
+
if (required && values.length === 0) {
|
|
50
|
+
return customErrorMessage || "This field is required";
|
|
51
|
+
}
|
|
52
|
+
if (values.length === 0) return null;
|
|
53
|
+
if (minChoices > 0 && values.length < Number(minChoices)) {
|
|
54
|
+
return customErrorMessage || `Please select at least ${minChoices} option${Number(minChoices) > 1 ? "s" : ""}`;
|
|
55
|
+
}
|
|
56
|
+
if (maxChoices > 0 && values.length > Number(maxChoices)) {
|
|
57
|
+
return customErrorMessage || `Please select at most ${maxChoices} option${Number(maxChoices) > 1 ? "s" : ""}`;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
};
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const initialValues = getInitialValues();
|
|
63
|
+
setFieldValue(initialValues);
|
|
64
|
+
const validationResult = validateSelection(initialValues);
|
|
65
|
+
setValidationError(validationResult);
|
|
66
|
+
if (onChange && initialValues.length > 0 && (!value || Array.isArray(value) && value.length === 0) && !isInitialized) {
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
onChange({
|
|
69
|
+
target: {
|
|
70
|
+
value: initialValues,
|
|
71
|
+
name,
|
|
72
|
+
id: name
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
setIsInitialized(true);
|
|
76
|
+
}, 0);
|
|
77
|
+
} else if (!isInitialized) {
|
|
78
|
+
setIsInitialized(true);
|
|
79
|
+
}
|
|
80
|
+
}, [value, defaultSelected, onChange, error]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (value && Array.isArray(value) && value.length > 0) {
|
|
83
|
+
setFieldValue(value.map(String));
|
|
84
|
+
const validationResult = validateSelection(value);
|
|
85
|
+
setValidationError(validationResult);
|
|
86
|
+
}
|
|
87
|
+
}, [value]);
|
|
88
|
+
const handleChange = (newValues) => {
|
|
89
|
+
setFieldValue(newValues);
|
|
90
|
+
setHasInteracted(true);
|
|
91
|
+
const errMsg = validateSelection(newValues);
|
|
92
|
+
setValidationError(errMsg);
|
|
93
|
+
if (onChange) {
|
|
94
|
+
onChange({
|
|
95
|
+
target: {
|
|
96
|
+
value: newValues,
|
|
97
|
+
name,
|
|
98
|
+
id: name
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const displayError = error || hasInteracted && validationError;
|
|
104
|
+
const buildConstraintHint = () => {
|
|
105
|
+
const min = Number(minChoices);
|
|
106
|
+
const max = Number(maxChoices);
|
|
107
|
+
if (min > 0 && max > 0) {
|
|
108
|
+
return `Select between ${min} and ${max} options`;
|
|
109
|
+
} else if (min > 0) {
|
|
110
|
+
return `Select at least ${min} option${min > 1 ? "s" : ""}`;
|
|
111
|
+
} else if (max > 0) {
|
|
112
|
+
return `Select at most ${max} option${max > 1 ? "s" : ""}`;
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
};
|
|
116
|
+
const constraintHint = buildConstraintHint();
|
|
117
|
+
const renderContent = () => {
|
|
118
|
+
if (!options || options.length === 0) {
|
|
119
|
+
return /* @__PURE__ */ jsx(
|
|
120
|
+
"div",
|
|
121
|
+
{
|
|
122
|
+
style: {
|
|
123
|
+
padding: "10px 12px",
|
|
124
|
+
color: "#8e8ea9",
|
|
125
|
+
fontStyle: "italic",
|
|
126
|
+
fontSize: "14px",
|
|
127
|
+
backgroundColor: "#f6f6f9",
|
|
128
|
+
borderRadius: "4px",
|
|
129
|
+
border: "1px dashed #dcdce4"
|
|
130
|
+
},
|
|
131
|
+
children: formatMessage({
|
|
132
|
+
id: "advanced-fields.enumeration.no-options",
|
|
133
|
+
defaultMessage: "No options defined. Please configure this field in the content type settings (one per line: value|label)."
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
139
|
+
/* @__PURE__ */ jsx(
|
|
140
|
+
MultiSelect,
|
|
141
|
+
{
|
|
142
|
+
id: name,
|
|
143
|
+
name,
|
|
144
|
+
placeholder: formatMessage({
|
|
145
|
+
id: "advanced-fields.enumeration.placeholder",
|
|
146
|
+
defaultMessage: "Select one or more options..."
|
|
147
|
+
}),
|
|
148
|
+
onChange: handleChange,
|
|
149
|
+
value: fieldValue,
|
|
150
|
+
disabled,
|
|
151
|
+
hasError: !!displayError,
|
|
152
|
+
withTags: true,
|
|
153
|
+
children: options.map((option) => /* @__PURE__ */ jsx(MultiSelectOption, { value: option.value, children: option.label }, option.value))
|
|
154
|
+
}
|
|
155
|
+
),
|
|
156
|
+
fieldValue.length > 0 && /* @__PURE__ */ jsxs(
|
|
157
|
+
"div",
|
|
158
|
+
{
|
|
159
|
+
style: {
|
|
160
|
+
marginTop: "4px",
|
|
161
|
+
fontSize: "12px",
|
|
162
|
+
color: "#666687",
|
|
163
|
+
textAlign: "right"
|
|
164
|
+
},
|
|
165
|
+
children: [
|
|
166
|
+
fieldValue.length,
|
|
167
|
+
" of ",
|
|
168
|
+
options.length,
|
|
169
|
+
" selected",
|
|
170
|
+
Number(maxChoices) > 0 && ` (max ${maxChoices})`
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
] });
|
|
175
|
+
};
|
|
176
|
+
return /* @__PURE__ */ jsx(Box, { col: 6, children: /* @__PURE__ */ jsxs(Field.Root, { name, error: displayError, children: [
|
|
177
|
+
/* @__PURE__ */ jsxs(Field.Label, { children: [
|
|
178
|
+
intlLabel.id ? formatMessage(intlLabel) : intlLabel.defaultMessage || name,
|
|
179
|
+
required && /* @__PURE__ */ jsx("span", { style: { color: "#d02b20", marginLeft: "4px" }, children: "*" })
|
|
180
|
+
] }),
|
|
181
|
+
renderContent(),
|
|
182
|
+
displayError && /* @__PURE__ */ jsx(Field.Error, { children: displayError }),
|
|
183
|
+
constraintHint && !displayError && /* @__PURE__ */ jsx(
|
|
184
|
+
"div",
|
|
185
|
+
{
|
|
186
|
+
style: {
|
|
187
|
+
fontSize: "12px",
|
|
188
|
+
color: "#666687",
|
|
189
|
+
marginTop: "4px"
|
|
190
|
+
},
|
|
191
|
+
children: constraintHint
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
description && (description.id || description.defaultMessage) && /* @__PURE__ */ jsx(Field.Hint, { children: description.id ? formatMessage(description) : description.defaultMessage }),
|
|
195
|
+
(fieldNote || fieldNoteFromAttribute) && /* @__PURE__ */ jsx(
|
|
196
|
+
"span",
|
|
197
|
+
{
|
|
198
|
+
style: {
|
|
199
|
+
fontStyle: "italic",
|
|
200
|
+
color: "#666",
|
|
201
|
+
fontSize: "12px",
|
|
202
|
+
display: "block",
|
|
203
|
+
marginTop: "4px"
|
|
204
|
+
},
|
|
205
|
+
children: fieldNote || fieldNoteFromAttribute
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
] }) });
|
|
209
|
+
};
|
|
210
|
+
export {
|
|
211
|
+
AdvancedEnumeration as default
|
|
212
|
+
};
|