aboutsummaryrefslogtreecommitdiff
path: root/admin/src
diff options
context:
space:
mode:
Diffstat (limited to 'admin/src')
-rw-r--r--admin/src/components/CheckboxListDefaultInput.tsx109
-rw-r--r--admin/src/components/CheckboxListInput.tsx2
-rw-r--r--admin/src/index.ts93
3 files changed, 185 insertions, 19 deletions
diff --git a/admin/src/components/CheckboxListDefaultInput.tsx b/admin/src/components/CheckboxListDefaultInput.tsx
new file mode 100644
index 0000000..465d0d3
--- /dev/null
+++ b/admin/src/components/CheckboxListDefaultInput.tsx
@@ -0,0 +1,109 @@
+import type { ReactNode } from 'react';
+
+import { Box, Checkbox, Field, Flex, Typography } from '@strapi/design-system';
+import { useIntl } from 'react-intl';
+
+type CheckboxListDefaultInputProps = {
+ 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>;
+ };
+ labelAction?: ReactNode;
+ required?: boolean;
+ disabled?: boolean;
+ error?: string;
+ modifiedData?: {
+ enum?: string[];
+ };
+};
+
+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 CheckboxListDefaultInput = ({
+ name,
+ value,
+ onChange,
+ intlLabel,
+ description,
+ labelAction,
+ required = false,
+ disabled = false,
+ error,
+ modifiedData,
+}: CheckboxListDefaultInputProps) => {
+ const { formatMessage } = useIntl();
+ const enumValues = Array.isArray(modifiedData?.enum) ? modifiedData.enum : [];
+ const selectedValues = normalizeValue(value);
+
+ 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);
+
+ onChange({
+ target: {
+ name,
+ value: nextValues,
+ },
+ });
+ };
+
+ 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>
+ ) : (
+ <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 { CheckboxListDefaultInput };
diff --git a/admin/src/components/CheckboxListInput.tsx b/admin/src/components/CheckboxListInput.tsx
index 6da9766..51a0d22 100644
--- a/admin/src/components/CheckboxListInput.tsx
+++ b/admin/src/components/CheckboxListInput.tsx
@@ -82,7 +82,7 @@ const CheckboxListInput = ({
<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}>
+ <Flex direction="column" gap={2} paddingTop={1} alignItems="flex-start">
{enumValues.map((option) => (
<Checkbox
key={option}
diff --git a/admin/src/index.ts b/admin/src/index.ts
index f3e7a28..a1c0473 100644
--- a/admin/src/index.ts
+++ b/admin/src/index.ts
@@ -1,25 +1,10 @@
-import { Check } from '@strapi/icons';
+import { EnumerationField } from '@strapi/icons/symbols';
import { Initializer } from './components/Initializer';
-import { PluginIcon } from './components/PluginIcon';
+import { CheckboxListDefaultInput } from './components/CheckboxListDefaultInput';
import { PLUGIN_ID } from './pluginId';
-import { getTranslation } from './utils/getTranslation';
export default {
register(app: any) {
- app.addMenuLink({
- to: `plugins/${PLUGIN_ID}`,
- icon: PluginIcon,
- intlLabel: {
- id: `${PLUGIN_ID}.plugin.name`,
- defaultMessage: PLUGIN_ID,
- },
- Component: async () => {
- const { App } = await import('./pages/App');
-
- return App;
- },
- });
-
app.registerPlugin({
id: PLUGIN_ID,
initializer: Initializer,
@@ -27,11 +12,20 @@ export default {
name: PLUGIN_ID,
});
+ const ctbPlugin = app.getPlugin?.('content-type-builder');
+
+ if (ctbPlugin?.apis?.forms?.components?.add) {
+ ctbPlugin.apis.forms.components.add({
+ id: 'checkbox-list-default',
+ component: CheckboxListDefaultInput,
+ });
+ }
+
app.customFields.register({
name: 'checkbox-list',
pluginId: PLUGIN_ID,
type: 'json',
- icon: Check,
+ icon: EnumerationField,
intlLabel: {
id: `${PLUGIN_ID}.customField.label`,
defaultMessage: 'Checkbox list',
@@ -71,6 +65,69 @@ export default {
],
},
],
+ advanced: [
+ {
+ sectionTitle: null,
+ items: [
+ {
+ name: 'default',
+ type: 'checkbox-list-default',
+ size: 6,
+ intlLabel: {
+ id: 'form.attribute.settings.default',
+ defaultMessage: 'Default value',
+ },
+ validations: {},
+ },
+ {
+ name: 'options.enumName',
+ type: 'text',
+ size: 6,
+ intlLabel: {
+ id: 'form.attribute.item.enumeration.graphql',
+ defaultMessage: 'Name override for GraphQL',
+ },
+ description: {
+ id: 'form.attribute.item.enumeration.graphql.description',
+ defaultMessage: 'Allows you to override the default generated name for GraphQL',
+ },
+ validations: {},
+ },
+ ],
+ },
+ {
+ sectionTitle: {
+ id: 'global.settings',
+ defaultMessage: 'Settings',
+ },
+ items: [
+ {
+ name: 'required',
+ type: 'checkbox',
+ intlLabel: {
+ id: 'form.attribute.item.requiredField',
+ defaultMessage: 'Required field',
+ },
+ description: {
+ id: 'form.attribute.item.requiredField.description',
+ defaultMessage: "You won't be able to create an entry if this field is empty",
+ },
+ },
+ {
+ name: 'private',
+ type: 'checkbox',
+ intlLabel: {
+ id: 'form.attribute.item.privateField',
+ defaultMessage: 'Private field',
+ },
+ description: {
+ id: 'form.attribute.item.privateField.description',
+ defaultMessage: 'This field will not show up in the API response',
+ },
+ },
+ ],
+ },
+ ],
},
});
},