diff --git a/packages/slug/src/SlugEditor.test.tsx b/packages/slug/src/SlugEditor.test.tsx
index a7d8d0882..9faccd51a 100644
--- a/packages/slug/src/SlugEditor.test.tsx
+++ b/packages/slug/src/SlugEditor.test.tsx
@@ -3,6 +3,7 @@ import identity from 'lodash/identity';
import { render, configure, cleanup, wait, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { SlugEditor } from './SlugEditor';
+import { CF_GENERATED_SLUG_MAX_LENGTH } from './services/slugify';
import { createFakeFieldAPI, createFakeLocalesAPI } from '@contentful/field-editor-test-utils';
configure({
@@ -453,21 +454,34 @@ describe('SlugEditor', () => {
});
});
- it('slug suggestion is limited to 75 symbols', async () => {
- const { field, sdk } = createMocks({
- field: '',
- titleField: '',
- });
+ [undefined, 50, 100].forEach((maxSlugLength) => {
+ it(`slug suggestion is limited to ${
+ maxSlugLength || `${CF_GENERATED_SLUG_MAX_LENGTH} (default)`
+ } symbols`, async () => {
+ const { field, sdk } = createMocks({
+ field: '',
+ titleField: '',
+ });
- render();
+ render(
+
+ );
- await wait();
+ await wait();
- await sdk.entry.fields['title-id'].setValue('a'.repeat(80));
- await wait();
+ await sdk.entry.fields['title-id'].setValue(
+ 'a'.repeat((maxSlugLength ?? CF_GENERATED_SLUG_MAX_LENGTH) + 10)
+ );
+ await wait();
- const expectedSlug = 'a'.repeat(75);
- expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
+ const expectedSlug = 'a'.repeat(maxSlugLength ?? CF_GENERATED_SLUG_MAX_LENGTH);
+ expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
+ });
});
it('slug suggestion does not contain cut-off words', async () => {
diff --git a/packages/slug/src/SlugEditor.tsx b/packages/slug/src/SlugEditor.tsx
index 3de639130..3bce17184 100644
--- a/packages/slug/src/SlugEditor.tsx
+++ b/packages/slug/src/SlugEditor.tsx
@@ -20,6 +20,7 @@ export interface SlugEditorProps {
parameters?: {
instance: {
trackingFieldId?: string;
+ maxSlugLength?: number;
};
};
}
@@ -39,6 +40,7 @@ function FieldConnectorCallback({
locale,
createdAt,
performUniqueCheck,
+ maxSlugLength,
}: {
Component: typeof SlugEditorFieldStatic | typeof SlugEditorField;
value: string | null | undefined;
@@ -50,6 +52,7 @@ function FieldConnectorCallback({
locale: FieldAPI['locale'];
createdAt: string;
performUniqueCheck: (value: string) => Promise;
+ maxSlugLength?: number;
}) {
// it is needed to silent permission errors
// this happens when setValue is called on a field which is disabled for permission reasons
@@ -76,6 +79,7 @@ function FieldConnectorCallback({
isDisabled={disabled}
titleValue={titleValue}
setValue={safeSetValue}
+ maxSlugLength={maxSlugLength}
/>
);
@@ -90,6 +94,7 @@ export function SlugEditor(props: SlugEditorProps) {
}
const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
+ const maxSlugLength = parameters?.instance?.maxSlugLength ?? undefined;
const entrySys = entry.getSys();
const isLocaleOptional = locales.optional[field.locale];
@@ -149,6 +154,7 @@ export function SlugEditor(props: SlugEditorProps) {
createdAt={entrySys.createdAt}
locale={field.locale}
performUniqueCheck={performUniqueCheck}
+ maxSlugLength={maxSlugLength}
key={`slug-editor-${externalReset}`}
/>
);
diff --git a/packages/slug/src/SlugEditorField.tsx b/packages/slug/src/SlugEditorField.tsx
index c14b93ab2..85f7187e5 100644
--- a/packages/slug/src/SlugEditorField.tsx
+++ b/packages/slug/src/SlugEditorField.tsx
@@ -17,12 +17,13 @@ interface SlugEditorFieldProps {
createdAt: string;
setValue: (value: string | null | undefined) => void;
performUniqueCheck: (value: string) => Promise;
+ maxSlugLength?: number;
}
type CheckerState = 'checking' | 'unique' | 'duplicate';
function useSlugUpdater(props: SlugEditorFieldProps, check: boolean) {
- const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;
+ const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback, maxSlugLength } = props;
React.useEffect(() => {
if (check === false) {
@@ -32,11 +33,12 @@ function useSlugUpdater(props: SlugEditorFieldProps, check: boolean) {
isOptionalLocaleWithFallback,
locale,
createdAt,
+ maxSlugLength
});
if (newSlug !== value) {
setValue(newSlug);
}
- }, [value, titleValue, isOptionalLocaleWithFallback, check, createdAt, locale, setValue]);
+ }, [value, titleValue, isOptionalLocaleWithFallback, check, createdAt, locale, setValue, maxSlugLength]);
}
function useUniqueChecker(props: SlugEditorFieldProps) {
@@ -111,16 +113,17 @@ export function SlugEditorFieldStatic(
}
export function SlugEditorField(props: SlugEditorFieldProps) {
- const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;
+ const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxSlugLength } = props;
const areEqual = React.useCallback(() => {
const potentialSlug = makeSlug(titleValue, {
isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
locale: locale,
createdAt: createdAt,
+ maxSlugLength
});
return value === potentialSlug;
- }, [titleValue, isOptionalLocaleWithFallback, locale, createdAt, value]);
+ }, [titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxSlugLength]);
const [check, setCheck] = React.useState(() => {
if (props.value) {
diff --git a/packages/slug/src/services/makeSlug.ts b/packages/slug/src/services/makeSlug.ts
index ec85b06e6..5602c6f1b 100644
--- a/packages/slug/src/services/makeSlug.ts
+++ b/packages/slug/src/services/makeSlug.ts
@@ -4,6 +4,7 @@ type MakeSlugOptions = {
locale: string;
isOptionalLocaleWithFallback: boolean;
createdAt: string;
+ maxSlugLength?: number;
};
function formatTwoDigit(num: number) {
@@ -32,5 +33,5 @@ function untitledSlug({ isOptionalLocaleWithFallback, createdAt }: MakeSlugOptio
}
export function makeSlug(title: string | null | undefined, options: MakeSlugOptions) {
- return title ? slugify(title, options.locale) : untitledSlug(options);
+ return title ? slugify(title, options.locale, options.maxSlugLength) : untitledSlug(options);
}
diff --git a/packages/slug/src/services/slugify.ts b/packages/slug/src/services/slugify.ts
index 1163dc435..eba580c7e 100644
--- a/packages/slug/src/services/slugify.ts
+++ b/packages/slug/src/services/slugify.ts
@@ -1,6 +1,6 @@
import getSlug from 'speakingurl';
-const CF_GENERATED_SLUG_MAX_LENGTH = 75;
+export const CF_GENERATED_SLUG_MAX_LENGTH = 75;
const languages = [
'ar',
@@ -51,13 +51,14 @@ function supportedLanguage(locale: string) {
*
* @param {string} text To be turned into a slug.
* @param {string?} locale
+ * @param {number?} maxLength
* @returns {string} Slug for provided text.
*/
-export function slugify(text: string, locale = 'en') {
+export function slugify(text: string, locale = 'en', maxLength = CF_GENERATED_SLUG_MAX_LENGTH) {
return getSlug(text, {
separator: '-',
lang: supportedLanguage(locale) || 'en',
- truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,
+ truncate: maxLength + 1,
custom: {
"'": '',
'`': '',