@webbycrown/advanced-fields 1.0.0 → 1.0.2

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 CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  Professional custom fields for Strapi CMS that provide advanced functionality with comprehensive validation, dynamic options, and user-friendly interfaces.
8
8
 
9
+ 📦 **NPM Package**: [@webbycrown/advanced-fields](https://www.npmjs.com/package/@webbycrown/advanced-fields)
10
+
9
11
  ## ✨ Features
10
12
 
11
13
  ### 🔤 Advanced Input
@@ -14,6 +16,7 @@ Professional custom fields for Strapi CMS that provide advanced functionality wi
14
16
  - **Custom Error Messages**: User-friendly validation feedback
15
17
  - **Default Values**: Pre-filled content for new entries
16
18
  - **Placeholder Support**: Helpful hints for content creators
19
+ - **Field Notes**: Display helpful notes below the field
17
20
  - **Private Fields**: Hide sensitive data from API responses
18
21
 
19
22
  ### ☑️ Advanced Checkbox
@@ -22,6 +25,7 @@ Professional custom fields for Strapi CMS that provide advanced functionality wi
22
25
  - **Min/Max Validation**: Control minimum and maximum selections
23
26
  - **Layout Options**: Vertical, horizontal, or grid layouts
24
27
  - **Default Selections**: Pre-select options for new entries
28
+ - **Field Notes**: Display helpful notes below the field
25
29
 
26
30
  ### 🔘 Advanced Radio
27
31
  - **Single & Multiple Selection**: Choose between single or multiple radio selections
@@ -29,6 +33,7 @@ Professional custom fields for Strapi CMS that provide advanced functionality wi
29
33
  - **Selection Limits**: Control minimum and maximum choices
30
34
  - **Layout Flexibility**: Multiple visual layouts
31
35
  - **Custom Validation**: Tailored error messages
36
+ - **Field Notes**: Display helpful notes below the field
32
37
 
33
38
  ## 🛠️ Installation
34
39
 
@@ -57,7 +62,7 @@ yarn add @webbycrown/advanced-fields
57
62
  ### Advanced Input Configuration
58
63
 
59
64
  ```javascript
60
- // Example: Text validation with custom error message
65
+ // Example: Text validation with custom error message and field note
61
66
  {
62
67
  "required": true,
63
68
  "maxLength": 255,
@@ -66,7 +71,8 @@ yarn add @webbycrown/advanced-fields
66
71
  "options": {
67
72
  "customErrorMessage": "Please enter valid text",
68
73
  "placeholder": "Enter your text here",
69
- "defaultValue": "Default text"
74
+ "defaultValue": "Default text",
75
+ "fieldNote": "This field accepts alphanumeric characters and spaces only"
70
76
  }
71
77
  }
72
78
  ```
@@ -74,7 +80,7 @@ yarn add @webbycrown/advanced-fields
74
80
  ### Advanced Checkbox Configuration
75
81
 
76
82
  ```javascript
77
- // Example: Multiple checkbox with validation
83
+ // Example: Multiple checkbox with validation and field note
78
84
  {
79
85
  "required": true,
80
86
  "options": {
@@ -83,7 +89,8 @@ yarn add @webbycrown/advanced-fields
83
89
  "minChoices": 1,
84
90
  "maxChoices": 2,
85
91
  "layout": "vertical",
86
- "defaultSelected": "1\n2"
92
+ "defaultSelected": "1\n2",
93
+ "fieldNote": "Please select at least 1 and at most 2 options"
87
94
  }
88
95
  }
89
96
  ```
@@ -91,14 +98,15 @@ yarn add @webbycrown/advanced-fields
91
98
  ### Advanced Radio Configuration
92
99
 
93
100
  ```javascript
94
- // Example: Single radio with dynamic options
101
+ // Example: Single radio with dynamic options and field note
95
102
  {
96
103
  "required": true,
97
104
  "options": {
98
105
  "selectionType": "single",
99
106
  "radioOptions": "small|Small\nmedium|Medium\nlarge|Large",
100
107
  "layout": "horizontal",
101
- "defaultSelected": "medium"
108
+ "defaultSelected": "medium",
109
+ "fieldNote": "Choose the size that best fits your needs"
102
110
  }
103
111
  }
104
112
  ```
@@ -117,6 +125,7 @@ yarn add @webbycrown/advanced-fields
117
125
  | `options.defaultValue` | string | Pre-filled value | `""` |
118
126
  | `options.placeholder` | string | Placeholder text | `""` |
119
127
  | `options.customErrorMessage` | string | Custom error message | `""` |
128
+ | `options.fieldNote` | string | Helpful note displayed below field | `""` |
120
129
  | `private` | boolean | Hide from API | `false` |
121
130
 
122
131
  ### Advanced Checkbox Options
@@ -131,6 +140,7 @@ yarn add @webbycrown/advanced-fields
131
140
  | `options.maxChoices` | number | Maximum selections | `0` |
132
141
  | `options.layout` | string | `vertical`, `horizontal`, or `grid` | `vertical` |
133
142
  | `options.customErrorMessage` | string | Custom error message | `""` |
143
+ | `options.fieldNote` | string | Helpful note displayed below field | `""` |
134
144
  | `private` | boolean | Hide from API | `false` |
135
145
 
136
146
  ### Advanced Radio Options
@@ -145,6 +155,7 @@ yarn add @webbycrown/advanced-fields
145
155
  | `options.maxChoices` | number | Maximum selections | `0` |
146
156
  | `options.layout` | string | `vertical`, `horizontal`, or `grid` | `vertical` |
147
157
  | `options.customErrorMessage` | string | Custom error message | `""` |
158
+ | `options.fieldNote` | string | Helpful note displayed below field | `""` |
148
159
  | `private` | boolean | Hide from API | `false` |
149
160
 
150
161
  ## 🔧 API Usage
@@ -259,8 +270,10 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
259
270
  - 🔘 Advanced Radio (single/multiple)
260
271
  - 🎨 Multiple layout options
261
272
  - ✅ Comprehensive validation system
273
+ - 📝 Field notes support for all field types
262
274
  - 📱 Responsive design
263
275
  - 🌐 Internationalization support
276
+ - 🚀 Published to NPM: [@webbycrown/advanced-fields](https://www.npmjs.com/package/@webbycrown/advanced-fields)
264
277
 
265
278
  ---
266
279
 
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es6",
4
+ "jsx": "react",
5
+ "module": "esnext",
6
+ "allowSyntheticDefaultImports": true,
7
+ "esModuleInterop": true
8
+ },
9
+ "include": ["./src/**/*.js", "./src/**/*.jsx"]
10
+ }
@@ -0,0 +1,377 @@
1
+ "use client";
2
+
3
+ import { useIntl } from "react-intl";
4
+ import { Field, Box, Flex, Typography } from "@strapi/design-system";
5
+ import { useState, useEffect } from "react";
6
+
7
+ const AdvancedCheckbox = ({
8
+ attribute = {},
9
+ description = { id: "", defaultMessage: "" },
10
+ disabled,
11
+ error,
12
+ intlLabel = { id: "", defaultMessage: "" },
13
+ labelAction,
14
+ name,
15
+ onChange,
16
+ required,
17
+ value,
18
+ }) => {
19
+ const { formatMessage } = useIntl();
20
+
21
+ const {
22
+ checkboxType = "multiple",
23
+ layout = "vertical",
24
+ minChoices = 0,
25
+ maxChoices = 0,
26
+ defaultSelected = "",
27
+ checkboxOptions = "",
28
+ customErrorMessage = "",
29
+ fieldNote = "",
30
+ } = attribute.options || attribute;
31
+
32
+ // Also check attribute.options for fieldNote
33
+ const fieldNoteFromAttribute = attribute.options?.fieldNote || '';
34
+
35
+
36
+ // Initialize with default values if available
37
+ const getInitialValues = () => {
38
+ if (checkboxType === "single") {
39
+ // For single checkbox mode, return array with one value (like radio button)
40
+ if (value && Array.isArray(value) && value.length > 0) {
41
+ return value;
42
+ } else if (value && typeof value === "string" && value.trim()) {
43
+ return [value.trim()];
44
+ } else if (defaultSelected && typeof defaultSelected === "string" && defaultSelected.trim()) {
45
+ return [defaultSelected.trim()];
46
+ } else if (defaultSelected && Array.isArray(defaultSelected) && defaultSelected.length > 0) {
47
+ return defaultSelected;
48
+ }
49
+ return [];
50
+ } else {
51
+ // For multiple checkboxes, return array of selected values
52
+ if (value && Array.isArray(value)) {
53
+ return value;
54
+ } else if (value && typeof value === "string") {
55
+ return value.split(",").map(v => v.trim()).filter(v => v);
56
+ } else if (defaultSelected) {
57
+ return defaultSelected.split(",").map(v => v.trim()).filter(v => v);
58
+ }
59
+ return [];
60
+ }
61
+ };
62
+
63
+ const [fieldValue, setFieldValue] = useState(getInitialValues);
64
+ const [validationError, setValidationError] = useState(null);
65
+ const [hasInteracted, setHasInteracted] = useState(false);
66
+ const [isInitialized, setIsInitialized] = useState(false);
67
+
68
+ // Parse checkbox options
69
+ const options = checkboxOptions
70
+ .split("\n")
71
+ .filter((opt) => opt.trim())
72
+ .map((opt) => {
73
+ const [value, label] = opt.split("|");
74
+ return { value: value?.trim() || "", label: label?.trim() || value?.trim() || "" };
75
+ });
76
+
77
+ // Initialize selected values - only run once on mount
78
+ useEffect(() => {
79
+ const initialValues = getInitialValues();
80
+
81
+
82
+ setFieldValue(initialValues);
83
+
84
+ // Validate the initial values
85
+ const validationResult = validateSelection(initialValues);
86
+ setValidationError(validationResult);
87
+
88
+ // Only trigger onChange if we have initial values and it's different from current value
89
+ // AND only if the value prop is not already set (to avoid overriding during publish)
90
+ // AND only if this is the first initialization
91
+ if (onChange && initialValues.length > 0 && (!value || (Array.isArray(value) && value.length === 0)) && !isInitialized) {
92
+ // Use setTimeout to ensure this happens after the component is fully mounted
93
+ setTimeout(() => {
94
+ onChange({
95
+ target: {
96
+ value: initialValues,
97
+ name: name,
98
+ id: name
99
+ }
100
+ });
101
+ setIsInitialized(true);
102
+ }, 0);
103
+ } else if (!isInitialized) {
104
+ setIsInitialized(true);
105
+ }
106
+ }, []); // Remove dependencies to only run once on mount
107
+
108
+ // Handle external value changes (like when loading existing data)
109
+ useEffect(() => {
110
+ // Only update if the value prop has changed and it's not empty
111
+ // This handles cases like loading existing content
112
+ if (value && Array.isArray(value) && value.length > 0) {
113
+ setFieldValue(value);
114
+ const validationResult = validateSelection(value);
115
+ setValidationError(validationResult);
116
+ }
117
+ }, [value]);
118
+
119
+ // Validation function - this should match server-side validation
120
+ const validateSelection = (val) => {
121
+ const values = Array.isArray(val) ? val : [];
122
+
123
+ // Check required validation first
124
+ if (required && values.length === 0) {
125
+ return customErrorMessage || 'This field is required';
126
+ }
127
+
128
+ // If field is empty and not required, no validation error
129
+ if (values.length === 0) {
130
+ return null;
131
+ }
132
+
133
+ // Check min/max choices validation (only for multiple mode)
134
+ if (checkboxType === "multiple") {
135
+ if (minChoices > 0 && values.length < minChoices) {
136
+ return customErrorMessage || `Please select at least ${minChoices} option${minChoices > 1 ? 's' : ''}`;
137
+ }
138
+ if (maxChoices > 0 && values.length > maxChoices) {
139
+ return customErrorMessage || `Please select at most ${maxChoices} option${maxChoices > 1 ? 's' : ''}`;
140
+ }
141
+ }
142
+
143
+ return null;
144
+ };
145
+
146
+ const handleCheckboxChange = (optionValue, isChecked) => {
147
+ let newValue;
148
+
149
+ if (checkboxType === "single") {
150
+ // For single checkbox mode, work like radio button - only one option can be selected
151
+ if (isChecked) {
152
+ // If checking an option, set it as the only selected value
153
+ newValue = [optionValue];
154
+ } else {
155
+ // If unchecking, clear the selection
156
+ newValue = [];
157
+ }
158
+ } else {
159
+ // For multiple checkboxes, handle array of values
160
+ if (isChecked) {
161
+ newValue = [...fieldValue, optionValue];
162
+ } else {
163
+ newValue = fieldValue.filter(val => val !== optionValue);
164
+ }
165
+ }
166
+
167
+ setFieldValue(newValue);
168
+ setHasInteracted(true);
169
+
170
+ // Validate selection only after user interaction
171
+ const error = validateSelection(newValue);
172
+ setValidationError(error);
173
+
174
+
175
+ // Always trigger onChange for user interactions
176
+ if (onChange) {
177
+ onChange({
178
+ target: {
179
+ value: newValue,
180
+ name: name,
181
+ id: name
182
+ }
183
+ });
184
+ }
185
+ };
186
+
187
+ // Show validation error - prioritize Strapi's error, then our validation only after user interaction
188
+ const displayError = error || (hasInteracted && validationError);
189
+ const renderCheckboxes = () => {
190
+
191
+ const checkboxStyle = {
192
+ display: "flex",
193
+ alignItems: "center",
194
+ gap: "8px",
195
+ marginBottom: "8px",
196
+ };
197
+
198
+ const checkboxInputStyle = {
199
+ width: "16px",
200
+ height: "16px",
201
+ accentColor: "#4945ff",
202
+ margin: "0",
203
+ padding: "0",
204
+ opacity: "1",
205
+ visibility: "visible",
206
+ display: "block",
207
+ position: "relative",
208
+ zIndex: "1",
209
+ };
210
+
211
+ const checkboxLabelStyle = {
212
+ fontSize: "14px",
213
+ fontFamily: "inherit",
214
+ cursor: "pointer",
215
+ userSelect: "none",
216
+ };
217
+
218
+ // Single checkbox mode - show multiple options but only one selectable (like radio buttons)
219
+ if (checkboxType === "single") {
220
+ // If no options are defined for single mode, show a message
221
+ if (!options || options.length === 0) {
222
+ return (
223
+ <div style={{ padding: "8px", color: "#666", fontStyle: "italic" }}>
224
+ {formatMessage({
225
+ id: 'advanced-fields.checkbox.options.checkboxOptions.description',
226
+ defaultMessage: 'Define available options for multiple checkboxes (one per line: value|label)'
227
+ })}
228
+ </div>
229
+ );
230
+ }
231
+
232
+ if (layout === "horizontal") {
233
+ return (
234
+ <Flex wrap="wrap" gap={2}>
235
+ {options.map((option) => (
236
+ <div key={option.value} style={checkboxStyle}>
237
+ <input
238
+ type="checkbox"
239
+ id={`${name}-${option.value}`}
240
+ checked={fieldValue.includes(option.value)}
241
+ onChange={(e) => handleCheckboxChange(option.value, e.target.checked)}
242
+ disabled={disabled}
243
+ style={checkboxInputStyle}
244
+ />
245
+ <label
246
+ htmlFor={`${name}-${option.value}`}
247
+ style={checkboxLabelStyle}
248
+ >
249
+ {option.label}
250
+ </label>
251
+ </div>
252
+ ))}
253
+ </Flex>
254
+ );
255
+ }
256
+
257
+ return (
258
+ <div>
259
+ {options.map((option) => (
260
+ <div key={option.value} style={checkboxStyle}>
261
+ <input
262
+ type="checkbox"
263
+ id={`${name}-${option.value}`}
264
+ checked={fieldValue.includes(option.value)}
265
+ onChange={(e) => handleCheckboxChange(option.value, e.target.checked)}
266
+ disabled={disabled}
267
+ style={checkboxInputStyle}
268
+ />
269
+ <label
270
+ htmlFor={`${name}-${option.value}`}
271
+ style={checkboxLabelStyle}
272
+ >
273
+ {option.label}
274
+ </label>
275
+ </div>
276
+ ))}
277
+ </div>
278
+ );
279
+ }
280
+
281
+ // Multiple checkbox mode
282
+ // If no options are defined, show a message
283
+ if (!options || options.length === 0) {
284
+ return (
285
+ <div style={{ padding: "8px", color: "#666", fontStyle: "italic" }}>
286
+ {formatMessage({
287
+ id: 'advanced-fields.checkbox.options.checkboxOptions.description',
288
+ defaultMessage: 'Define available options for multiple checkboxes (one per line: value|label)'
289
+ })}
290
+ </div>
291
+ );
292
+ }
293
+
294
+ if (layout === "horizontal") {
295
+ return (
296
+ <Flex wrap="wrap" gap={2}>
297
+ {options.map((option) => (
298
+ <div key={option.value} style={checkboxStyle}>
299
+ <input
300
+ type="checkbox"
301
+ id={`${name}-${option.value}`}
302
+ checked={fieldValue.includes(option.value)}
303
+ onChange={(e) => handleCheckboxChange(option.value, e.target.checked)}
304
+ disabled={disabled}
305
+ style={checkboxInputStyle}
306
+ />
307
+ <label
308
+ htmlFor={`${name}-${option.value}`}
309
+ style={checkboxLabelStyle}
310
+ >
311
+ {option.label}
312
+ </label>
313
+ </div>
314
+ ))}
315
+ </Flex>
316
+ );
317
+ }
318
+
319
+ return (
320
+ <div>
321
+ {options.map((option) => (
322
+ <div key={option.value} style={checkboxStyle}>
323
+ <input
324
+ type="checkbox"
325
+ id={`${name}-${option.value}`}
326
+ checked={fieldValue.includes(option.value)}
327
+ onChange={(e) => handleCheckboxChange(option.value, e.target.checked)}
328
+ disabled={disabled}
329
+ style={checkboxInputStyle}
330
+ />
331
+ <label
332
+ htmlFor={`${name}-${option.value}`}
333
+ style={checkboxLabelStyle}
334
+ >
335
+ {option.label}
336
+ </label>
337
+ </div>
338
+ ))}
339
+ </div>
340
+ );
341
+ };
342
+
343
+ return (
344
+ <Box col={6}>
345
+ <Field.Root name={name} error={displayError}>
346
+ <Field.Label>
347
+ {intlLabel.id ? formatMessage(intlLabel) : intlLabel.defaultMessage || name}
348
+ {required && <span style={{ color: "#d02b20", marginLeft: "4px" }}>*</span>}
349
+ </Field.Label>
350
+ {renderCheckboxes()}
351
+ {displayError && (
352
+ <Field.Error>
353
+ {displayError}
354
+ </Field.Error>
355
+ )}
356
+ {description && (description.id || description.defaultMessage) && (
357
+ <Field.Hint>
358
+ {description.id ? formatMessage(description) : description.defaultMessage}
359
+ </Field.Hint>
360
+ )}
361
+ {(fieldNote || fieldNoteFromAttribute) && (
362
+ <span style={{
363
+ fontStyle: 'italic',
364
+ color: '#666',
365
+ fontSize: '12px',
366
+ display: 'block',
367
+ marginTop: '4px'
368
+ }}>
369
+ {fieldNote || fieldNoteFromAttribute}
370
+ </span>
371
+ )}
372
+ </Field.Root>
373
+ </Box>
374
+ );
375
+ };
376
+
377
+ export default AdvancedCheckbox;
@@ -0,0 +1,179 @@
1
+ "use client";
2
+
3
+ import { useIntl } from "react-intl";
4
+ import { Field, Box } from "@strapi/design-system";
5
+ import { Cross } from "@strapi/icons";
6
+ import { useState, useEffect } from "react";
7
+
8
+ const AdvancedInput = ({
9
+ attribute = {},
10
+ description = { id: "", defaultMessage: "" },
11
+ disabled,
12
+ error,
13
+ intlLabel = { id: "", defaultMessage: "" },
14
+ labelAction,
15
+ name,
16
+ onChange,
17
+ required,
18
+ value,
19
+ }) => {
20
+ const { formatMessage } = useIntl();
21
+ const [inputValue, setInputValue] = useState(value || "");
22
+ const [validationError, setValidationError] = useState(null);
23
+ const [hasInteracted, setHasInteracted] = useState(false);
24
+
25
+ const {
26
+ minLength = 0,
27
+ maxLength = 0,
28
+ min = 0,
29
+ max = 0,
30
+ step = 1,
31
+ rows = 4,
32
+ options = {},
33
+ } = attribute;
34
+
35
+ // Extract options with defaults
36
+ const {
37
+ placeholder = '',
38
+ defaultValue = '',
39
+ customErrorMessage = '',
40
+ regex = '',
41
+ fieldNote = '',
42
+ } = options;
43
+
44
+ // Also check attribute.options for fieldNote
45
+ const fieldNoteFromAttribute = attribute.options?.fieldNote || '';
46
+
47
+
48
+ // Initialize input value
49
+ useEffect(() => {
50
+ const initialValue = value === undefined ? defaultValue : value;
51
+ setInputValue(initialValue);
52
+
53
+ // Don't validate on initial load unless there's an error from Strapi
54
+ if (error) {
55
+ setValidationError(error);
56
+ }
57
+
58
+ if (onChange) {
59
+ onChange({ target: { value: initialValue } });
60
+ }
61
+ }, [value, defaultValue, onChange, error]);
62
+
63
+ // Validation function - this should match server-side validation
64
+ const validateInput = (val) => {
65
+ // Check required validation first
66
+ if (required && (!val || val.toString().trim().length === 0)) {
67
+ return customErrorMessage || "This field is required";
68
+ }
69
+
70
+ // If no value, no additional validation needed
71
+ if (!val || val.toString().trim().length === 0) {
72
+ return null;
73
+ }
74
+
75
+ const stringValue = val.toString().trim();
76
+
77
+ // Check min/max length validation
78
+ if (minLength > 0 && stringValue.length < minLength) {
79
+ return customErrorMessage || `Minimum length is ${minLength} characters`;
80
+ }
81
+ if (maxLength > 0 && stringValue.length > maxLength) {
82
+ return customErrorMessage || `Maximum length is ${maxLength} characters`;
83
+ }
84
+
85
+ // Check regex validation if provided
86
+ if (regex && stringValue) {
87
+ try {
88
+ const regexPattern = new RegExp(regex);
89
+ if (!regexPattern.test(stringValue)) {
90
+ return customErrorMessage || "Invalid format";
91
+ }
92
+ } catch (e) {
93
+ // Invalid regex pattern, skip validation
94
+ }
95
+ }
96
+
97
+ return null;
98
+ };
99
+
100
+ const handleChange = (e) => {
101
+ const newValue = e.target.value;
102
+ setInputValue(newValue);
103
+ setHasInteracted(true);
104
+
105
+ // Validate input only after user interaction
106
+ const error = validateInput(newValue);
107
+ setValidationError(error);
108
+
109
+ if (onChange) {
110
+ onChange(e);
111
+ }
112
+ };
113
+
114
+ // Show validation error - prioritize Strapi's error, then our validation only after user interaction
115
+ const displayError = error || (hasInteracted && validationError);
116
+
117
+ const renderInput = () => {
118
+ const commonProps = {
119
+ name,
120
+ value: inputValue,
121
+ onChange: handleChange,
122
+ disabled,
123
+ placeholder: placeholder || (intlLabel.id ? formatMessage(intlLabel) : intlLabel.defaultMessage || ""),
124
+ };
125
+
126
+ const inputStyle = {
127
+ width: "100%",
128
+ padding: "8px 12px",
129
+ border: `1px solid ${displayError ? "#d02b20" : "#dcdce4"}`,
130
+ borderRadius: "4px",
131
+ fontSize: "14px",
132
+ fontFamily: "inherit",
133
+ backgroundColor: disabled ? "#f6f6f9" : "#ffffff",
134
+ };
135
+
136
+ return (
137
+ <input
138
+ {...commonProps}
139
+ type="text"
140
+ style={inputStyle}
141
+ />
142
+ );
143
+ };
144
+
145
+ return (
146
+ <Box col={6}>
147
+ <Field.Root name={name} error={displayError}>
148
+ <Field.Label>
149
+ {intlLabel.id ? formatMessage(intlLabel) : intlLabel.defaultMessage || name}
150
+ {required && <span style={{ color: "#d02b20", marginLeft: "4px" }}>*</span>}
151
+ </Field.Label>
152
+ {renderInput()}
153
+ {displayError && (
154
+ <Field.Error>
155
+ {displayError}
156
+ </Field.Error>
157
+ )}
158
+ {description && (description.id || description.defaultMessage) && (
159
+ <Field.Hint>
160
+ {description.id ? formatMessage(description) : description.defaultMessage}
161
+ </Field.Hint>
162
+ )}
163
+ {(fieldNote || fieldNoteFromAttribute) && (
164
+ <span style={{
165
+ fontStyle: 'italic',
166
+ color: '#666',
167
+ fontSize: '12px',
168
+ display: 'block',
169
+ marginTop: '4px'
170
+ }}>
171
+ {fieldNote || fieldNoteFromAttribute}
172
+ </span>
173
+ )}
174
+ </Field.Root>
175
+ </Box>
176
+ );
177
+ };
178
+
179
+ export default AdvancedInput;