aboutsummaryrefslogtreecommitdiff
path: root/admin/src/components/CheckboxListInput.tsx
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-02-05 14:53:17 +0300
committerValentin Popov <valentin@popov.link>2026-02-05 14:53:17 +0300
commit7fe5502dc173cfee7c3b3178fb233264ad7c6dc3 (patch)
treee8d82ba993ae0a044c3ce322114851aa9683b51c /admin/src/components/CheckboxListInput.tsx
parentefa89313fa4152252b477aafd88f7cf4a66747d8 (diff)
downloadstrapi-plugin-checkbox-list-7fe5502dc173cfee7c3b3178fb233264ad7c6dc3.tar.xz
strapi-plugin-checkbox-list-7fe5502dc173cfee7c3b3178fb233264ad7c6dc3.zip
Add checkbox-list custom field plugin to Strapi
- Introduced a new custom field type 'checkbox-list' with associated input component. - Updated package.json to reflect the new plugin name. - Added necessary server-side files for plugin registration, including bootstrap, destroy, and service methods. - Updated package-lock.json to include new dependencies and versions. - Enhanced admin interface with custom field registration and input handling.
Diffstat (limited to 'admin/src/components/CheckboxListInput.tsx')
-rw-r--r--admin/src/components/CheckboxListInput.tsx115
1 files changed, 115 insertions, 0 deletions
diff --git a/admin/src/components/CheckboxListInput.tsx b/admin/src/components/CheckboxListInput.tsx
new file mode 100644
index 0000000..6da9766
--- /dev/null
+++ b/admin/src/components/CheckboxListInput.tsx
@@ -0,0 +1,115 @@
+import type { ReactNode } from 'react';
+
+import { Box, Checkbox, Field, Flex, Typography } from '@strapi/design-system';
+import { useIntl } from 'react-intl';
+
+type CheckboxListInputProps = {
+ name: string;
+ value?: unknown;
+ onChange: (eventOrPath: { target: { name: string; value: string[] } }, value?: unknown) => void;
+ attribute?: {
+ enum?: string[];
+ options?: {
+ enum?: string[];
+ };
+ } | null;
+ label?: ReactNode;
+ hint?: ReactNode;
+ required?: boolean;
+ disabled?: boolean;
+ error?: string;
+ labelAction?: ReactNode;
+};
+
+const getEnumValues = (attribute: CheckboxListInputProps['attribute']): string[] => {
+ if (!attribute) {
+ return [];
+ }
+
+ if (Array.isArray(attribute.enum)) {
+ return attribute.enum;
+ }
+
+ if (Array.isArray(attribute.options?.enum)) {
+ return attribute.options.enum;
+ }
+
+ return [];
+};
+
+const normalizeValue = (value: unknown): string[] => {
+ if (Array.isArray(value)) {
+ return value.filter((item): item is string => typeof item === 'string');
+ }
+
+ if (typeof value === 'string' && value.length > 0) {
+ return [value];
+ }
+
+ return [];
+};
+
+const CheckboxListInput = ({
+ name,
+ value,
+ onChange,
+ attribute,
+ label,
+ hint,
+ required = false,
+ disabled = false,
+ error,
+ labelAction,
+}: CheckboxListInputProps) => {
+ const { formatMessage } = useIntl();
+ const enumValues = getEnumValues(attribute);
+ const selectedValues = normalizeValue(value);
+
+ const handleToggle = (option: string, isChecked: boolean) => {
+ const nextValues = isChecked
+ ? Array.from(new Set([...selectedValues, option]))
+ : selectedValues.filter((item) => item !== option);
+
+ onChange({
+ target: {
+ name,
+ value: nextValues,
+ },
+ });
+ };
+
+ return (
+ <Field.Root name={name} hint={hint} error={error} required={required}>
+ <Field.Label action={labelAction}>{label ?? name}</Field.Label>
+ {enumValues.length > 0 ? (
+ <Flex direction="column" gap={2} paddingTop={1}>
+ {enumValues.map((option) => (
+ <Checkbox
+ key={option}
+ checked={selectedValues.includes(option)}
+ disabled={disabled}
+ onCheckedChange={(checked: boolean | 'indeterminate') =>
+ handleToggle(option, Boolean(checked))
+ }
+ >
+ {option}
+ </Checkbox>
+ ))}
+ </Flex>
+ ) : (
+ <Box paddingTop={1}>
+ <Typography variant="pi" textColor="neutral500">
+ {formatMessage({
+ id: 'checkbox-list.field.empty',
+ defaultMessage: 'No values configured yet.',
+ })}
+ </Typography>
+ </Box>
+ )}
+ <Field.Error />
+ <Field.Hint />
+ </Field.Root>
+ );
+};
+
+export default CheckboxListInput;