diff options
| author | Valentin Popov <valentin@popov.link> | 2026-02-05 16:45:40 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-02-05 16:45:40 +0300 |
| commit | 59be13de07143e546284c75d00ea98c9159aa573 (patch) | |
| tree | 10d1033894649df3eb6d4fb2c5b66ff42fa42caf /admin/src/components | |
| parent | b9bd07c53d8c624f14f9b7da71ff1e4de099a029 (diff) | |
| download | strapi-plugin-checkbox-list-59be13de07143e546284c75d00ea98c9159aa573.tar.xz strapi-plugin-checkbox-list-59be13de07143e546284c75d00ea98c9159aa573.zip | |
Enhance checkbox-list custom field functionality
- Added CheckboxListEnumInput component for handling enumeration inputs.
- Updated CheckboxListDefaultInput to support new options structure.
- Integrated validation for checkbox list options using Yup.
- Modified package.json and package-lock.json to include new dependencies.
- Improved admin interface with enhanced input handling and validation feedback.
Diffstat (limited to 'admin/src/components')
| -rw-r--r-- | admin/src/components/CheckboxListDefaultInput.tsx | 59 | ||||
| -rw-r--r-- | admin/src/components/CheckboxListEnumInput.tsx | 126 | ||||
| -rw-r--r-- | admin/src/components/CheckboxListInput.tsx | 8 |
3 files changed, 166 insertions, 27 deletions
diff --git a/admin/src/components/CheckboxListDefaultInput.tsx b/admin/src/components/CheckboxListDefaultInput.tsx index 465d0d3..ffd0551 100644 --- a/admin/src/components/CheckboxListDefaultInput.tsx +++ b/admin/src/components/CheckboxListDefaultInput.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react'; -import { Box, Checkbox, Field, Flex, Typography } from '@strapi/design-system'; +import { Box, Field, MultiSelect, MultiSelectOption, Typography } from '@strapi/design-system'; import { useIntl } from 'react-intl'; type CheckboxListDefaultInputProps = { @@ -23,6 +23,9 @@ type CheckboxListDefaultInputProps = { error?: string; modifiedData?: { enum?: string[]; + options?: { + enum?: string[]; + }; }; }; @@ -51,23 +54,26 @@ const CheckboxListDefaultInput = ({ modifiedData, }: CheckboxListDefaultInputProps) => { const { formatMessage } = useIntl(); - const enumValues = Array.isArray(modifiedData?.enum) ? modifiedData.enum : []; + const enumValues = Array.isArray(modifiedData?.options?.enum) + ? modifiedData.options.enum + : Array.isArray(modifiedData?.enum) + ? modifiedData.enum + : []; const selectedValues = normalizeValue(value); + const uniqueValues = Array.from( + new Set(enumValues.filter((option) => typeof option === 'string' && option.trim().length > 0)) + ); const label = intlLabel ? formatMessage(intlLabel, intlLabel.values ?? {}) : name; const hint = description ? formatMessage(description, description.values ?? {}) : undefined; - const handleToggle = (option: string, isChecked: boolean) => { - const nextValues = isChecked - ? Array.from(new Set([...selectedValues, option])) - : selectedValues.filter((item) => item !== option); - + const handleChange = (nextValues: string[] | undefined) => { onChange({ target: { name, - value: nextValues, + value: Array.isArray(nextValues) ? nextValues : [], }, }); }; @@ -75,21 +81,28 @@ const CheckboxListDefaultInput = ({ return ( <Field.Root name={name} hint={hint} error={error} required={required}> <Field.Label action={labelAction}>{label}</Field.Label> - {enumValues.length > 0 ? ( - <Flex direction="column" gap={2} paddingTop={1} alignItems="flex-start"> - {enumValues.map((option) => ( - <Checkbox - key={option} - checked={selectedValues.includes(option)} - disabled={disabled} - onCheckedChange={(checked: boolean | 'indeterminate') => - handleToggle(option, Boolean(checked)) - } - > - {option} - </Checkbox> - ))} - </Flex> + {uniqueValues.length > 0 ? ( + <Box paddingTop={1}> + <MultiSelect + aria-label={label} + disabled={disabled} + id={name} + name={name} + onChange={handleChange} + placeholder={formatMessage({ + id: 'checkbox-list.default.placeholder', + defaultMessage: 'Select default values', + })} + value={selectedValues} + withTags + > + {uniqueValues.map((option) => ( + <MultiSelectOption key={option} value={option}> + {option} + </MultiSelectOption> + ))} + </MultiSelect> + </Box> ) : ( <Box paddingTop={1}> <Typography variant="pi" textColor="neutral500"> diff --git a/admin/src/components/CheckboxListEnumInput.tsx b/admin/src/components/CheckboxListEnumInput.tsx new file mode 100644 index 0000000..0a1ac73 --- /dev/null +++ b/admin/src/components/CheckboxListEnumInput.tsx @@ -0,0 +1,126 @@ +import type { ChangeEvent, ReactNode } from 'react'; + +import { Field, Textarea } from '@strapi/design-system'; +import { useIntl } from 'react-intl'; + +type CheckboxListEnumInputProps = { + name: string; + value?: unknown; + onChange: (eventOrPath: { target: { name: string; value: string[] } }, value?: unknown) => void; + intlLabel: { + id: string; + defaultMessage: string; + values?: Record<string, string | number | boolean | null | undefined>; + }; + description?: { + id: string; + defaultMessage: string; + values?: Record<string, string | number | boolean | null | undefined>; + } | null; + labelAction?: ReactNode; + placeholder?: { + id: string; + defaultMessage: string; + values?: Record<string, string | number | boolean | null | undefined>; + } | null; + disabled?: boolean; + error?: string; + modifiedData?: { + enum?: string[]; + options?: { + enum?: string[]; + }; + }; +}; + +const normalizeEnum = (value: unknown): string[] => { + if (Array.isArray(value)) { + return value.filter((item): item is string => typeof item === 'string'); + } + + return []; +}; + +const CheckboxListEnumInput = ({ + description = null, + disabled = false, + error = '', + intlLabel, + labelAction, + name, + onChange, + placeholder = null, + value, + modifiedData, +}: CheckboxListEnumInputProps) => { + const { formatMessage } = useIntl(); + + const fallbackEnum = normalizeEnum(modifiedData?.enum); + const resolvedEnum = normalizeEnum(value).length > 0 ? normalizeEnum(value) : fallbackEnum; + + const errorMessage = error + ? formatMessage({ + id: error, + defaultMessage: error, + }) + : ''; + + const hint = description + ? formatMessage( + { + id: description.id, + defaultMessage: description.defaultMessage, + }, + description.values + ) + : ''; + + const label = formatMessage(intlLabel, intlLabel.values ?? {}); + const formattedPlaceholder = placeholder + ? formatMessage( + { + id: placeholder.id, + defaultMessage: placeholder.defaultMessage, + }, + placeholder.values + ) + : ''; + + const inputValue = resolvedEnum.join('\n'); + + const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => { + const arrayValue = event.target.value.split('\n'); + + onChange({ + target: { + name, + value: arrayValue, + }, + }); + + if (name !== 'enum') { + onChange({ + target: { + name: 'enum', + value: arrayValue, + }, + }); + } + }; + + return ( + <Field.Root error={errorMessage} hint={hint} name={name}> + <Field.Label action={labelAction}>{label}</Field.Label> + <Textarea + disabled={disabled} + onChange={handleChange} + placeholder={formattedPlaceholder} + value={inputValue} + /> + <Field.Error /> + <Field.Hint /> + </Field.Root> + ); +}; + +export { CheckboxListEnumInput }; diff --git a/admin/src/components/CheckboxListInput.tsx b/admin/src/components/CheckboxListInput.tsx index 51a0d22..07d2776 100644 --- a/admin/src/components/CheckboxListInput.tsx +++ b/admin/src/components/CheckboxListInput.tsx @@ -26,14 +26,14 @@ const getEnumValues = (attribute: CheckboxListInputProps['attribute']): string[] return []; } - if (Array.isArray(attribute.enum)) { - return attribute.enum; - } - if (Array.isArray(attribute.options?.enum)) { return attribute.options.enum; } + if (Array.isArray(attribute.enum)) { + return attribute.enum; + } + return []; }; |
