@contentful/field-editor-slug 3.0.0 → 3.0.1-canary.0

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.
@@ -53,10 +53,20 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
53
  }
54
54
  return newObj;
55
55
  }
56
+ const DEFAULT_SYMBOL_FIELD_MAX_LENGTH = 256;
57
+ function getSlugFieldMaxLength(validations = []) {
58
+ const maxFromValidations = validations.reduce((currentMax, validation)=>{
59
+ if (!('size' in validation) || typeof validation.size?.max !== 'number') {
60
+ return currentMax;
61
+ }
62
+ return currentMax === null ? validation.size.max : Math.min(currentMax, validation.size.max);
63
+ }, null);
64
+ return maxFromValidations === null ? DEFAULT_SYMBOL_FIELD_MAX_LENGTH : Math.min(DEFAULT_SYMBOL_FIELD_MAX_LENGTH, maxFromValidations);
65
+ }
56
66
  function isSupportedFieldTypes(val) {
57
67
  return val === 'Symbol';
58
68
  }
59
- function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id }) {
69
+ function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, maxLength, performUniqueCheck, isUniqueValidationEnabled, id }) {
60
70
  const safeSetValue = _react.useCallback(async (...args)=>{
61
71
  try {
62
72
  await setValue(...args);
@@ -69,6 +79,7 @@ function FieldConnectorCallback({ Component, value, disabled, setValue, errors,
69
79
  }, /*#__PURE__*/ _react.createElement(Component, {
70
80
  locale: locale,
71
81
  createdAt: createdAt,
82
+ maxLength: maxLength,
72
83
  performUniqueCheck: performUniqueCheck,
73
84
  isUniqueValidationEnabled: isUniqueValidationEnabled,
74
85
  hasError: errors.length > 0,
@@ -89,6 +100,7 @@ function SlugEditor(props) {
89
100
  const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
90
101
  const entrySys = entry.getSys();
91
102
  const isUniqueValidationEnabled = (field.validations || []).some((validation)=>'unique' in validation && validation.unique === true);
103
+ const maxLength = getSlugFieldMaxLength(field.validations);
92
104
  const isLocaleOptional = locales.optional[field.locale];
93
105
  const localeFallbackCode = locales.fallbacks[field.locale];
94
106
  const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
@@ -136,6 +148,7 @@ function SlugEditor(props) {
136
148
  isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
137
149
  createdAt: entrySys.createdAt,
138
150
  locale: field.locale,
151
+ maxLength: maxLength,
139
152
  performUniqueCheck: performUniqueCheck,
140
153
  isUniqueValidationEnabled: isUniqueValidationEnabled,
141
154
  key: `slug-editor-${externalReset}`,
@@ -316,6 +316,7 @@ describe('SlugEditor', ()=>{
316
316
  locale: "en-US",
317
317
  titleValue: "Slug value",
318
318
  createdAt: "2020-01-24T15:33:47.906Z",
319
+ maxLength: 256,
319
320
  setValue: setValue,
320
321
  performUniqueCheck: performUniqueCheck
321
322
  }));
@@ -527,22 +528,46 @@ describe('SlugEditor', ()=>{
527
528
  });
528
529
  });
529
530
  });
530
- it('slug suggestion is limited to 75 symbols', async ()=>{
531
+ it('slug suggestion is limited to 256 characters by default', async ()=>{
532
+ const longTitle = 'a'.repeat(300);
531
533
  const { field, sdk } = createMocks({
532
534
  field: '',
533
- titleField: ''
535
+ titleField: longTitle
534
536
  });
535
- (0, _react1.render)(/*#__PURE__*/ _react.createElement(_SlugEditor.SlugEditor, {
537
+ const { getByTestId } = (0, _react1.render)(/*#__PURE__*/ _react.createElement(_SlugEditor.SlugEditor, {
536
538
  field: field,
537
539
  baseSdk: sdk,
538
540
  isInitiallyDisabled: false
539
541
  }));
540
- await (0, _react1.waitFor)(async ()=>{
541
- await sdk.entry.fields['title-id'].setValue('a'.repeat(80));
542
- });
543
542
  await (0, _react1.waitFor)(()=>{
544
- const expectedSlug = 'a'.repeat(75);
543
+ const expectedSlug = 'a'.repeat(256);
545
544
  expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
545
+ expect(getByTestId('cf-ui-text-input')).toHaveAttribute('maxlength', '256');
546
+ });
547
+ });
548
+ it('slug suggestion respects size max validation', async ()=>{
549
+ const { field, sdk } = createMocks({
550
+ field: '',
551
+ titleField: 'one two three four'
552
+ });
553
+ field.validations = [
554
+ {
555
+ unique: true
556
+ },
557
+ {
558
+ size: {
559
+ max: 13
560
+ }
561
+ }
562
+ ];
563
+ const { getByTestId } = (0, _react1.render)(/*#__PURE__*/ _react.createElement(_SlugEditor.SlugEditor, {
564
+ field: field,
565
+ baseSdk: sdk,
566
+ isInitiallyDisabled: false
567
+ }));
568
+ await (0, _react1.waitFor)(()=>{
569
+ expect(field.setValue).toHaveBeenLastCalledWith('one-two-three');
570
+ expect(getByTestId('cf-ui-text-input')).toHaveAttribute('maxlength', '13');
546
571
  });
547
572
  });
548
573
  it('slug suggestion does not contain cut-off words', async ()=>{
@@ -556,7 +581,7 @@ describe('SlugEditor', ()=>{
556
581
  isInitiallyDisabled: false
557
582
  }));
558
583
  await (0, _react1.waitFor)(async ()=>{
559
- await sdk.entry.fields['title-id'].setValue(`one two three ${'a'.repeat(80)}`);
584
+ await sdk.entry.fields['title-id'].setValue(`one two three ${'a'.repeat(300)}`);
560
585
  });
561
586
  await (0, _react1.waitFor)(()=>{
562
587
  const expectedSlug = 'one-two-three';
@@ -66,7 +66,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
66
66
  return newObj;
67
67
  }
68
68
  function useSlugUpdater(props, check) {
69
- const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;
69
+ const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback, maxLength } = props;
70
70
  _react.useEffect(()=>{
71
71
  if (check === false) {
72
72
  return;
@@ -74,7 +74,8 @@ function useSlugUpdater(props, check) {
74
74
  const newSlug = (0, _makeSlug.makeSlug)(titleValue, {
75
75
  isOptionalLocaleWithFallback,
76
76
  locale,
77
- createdAt
77
+ createdAt,
78
+ maxLength
78
79
  });
79
80
  if (newSlug !== value) {
80
81
  setValue(newSlug);
@@ -86,6 +87,7 @@ function useSlugUpdater(props, check) {
86
87
  check,
87
88
  createdAt,
88
89
  locale,
90
+ maxLength,
89
91
  setValue
90
92
  ]);
91
93
  }
@@ -111,7 +113,7 @@ function useUniqueChecker(props) {
111
113
  return status;
112
114
  }
113
115
  function SlugEditorFieldStatic(props) {
114
- const { hasError, isDisabled, value, setValue, onChange, onBlur, isUniqueValidationEnabled, id } = props;
116
+ const { hasError, isDisabled, value, setValue, onChange, onBlur, isUniqueValidationEnabled, id, maxLength } = props;
115
117
  const status = useUniqueChecker(props);
116
118
  const hasDuplicate = status === 'duplicate';
117
119
  const shouldShowDuplicateAsError = hasDuplicate && isUniqueValidationEnabled && !hasError;
@@ -126,6 +128,7 @@ function SlugEditorFieldStatic(props) {
126
128
  isDisabled: isDisabled,
127
129
  value: value || '',
128
130
  id: id,
131
+ maxLength: maxLength,
129
132
  onChange: (e)=>{
130
133
  setValue(e.target.value);
131
134
  if (onChange) {
@@ -157,12 +160,13 @@ function SlugEditorFieldStatic(props) {
157
160
  })));
158
161
  }
159
162
  function SlugEditorField(props) {
160
- const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;
163
+ const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxLength } = props;
161
164
  const areEqual = _react.useCallback(()=>{
162
165
  const potentialSlug = (0, _makeSlug.makeSlug)(titleValue, {
163
- isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
164
- locale: locale,
165
- createdAt: createdAt
166
+ isOptionalLocaleWithFallback,
167
+ locale,
168
+ createdAt,
169
+ maxLength
166
170
  });
167
171
  return value === potentialSlug;
168
172
  }, [
@@ -170,6 +174,7 @@ function SlugEditorField(props) {
170
174
  isOptionalLocaleWithFallback,
171
175
  locale,
172
176
  createdAt,
177
+ maxLength,
173
178
  value
174
179
  ]);
175
180
  const [check, setCheck] = _react.useState(()=>{
@@ -30,13 +30,13 @@ function formatUtcDate(date) {
30
30
  const seconds = formatTwoDigit(date.getUTCSeconds());
31
31
  return `${year} ${month} ${day} at ${hour} ${minutes} ${seconds}`;
32
32
  }
33
- function untitledSlug({ isOptionalLocaleWithFallback, createdAt }) {
33
+ function untitledSlug({ isOptionalLocaleWithFallback, createdAt, maxLength }) {
34
34
  if (isOptionalLocaleWithFallback) {
35
35
  return '';
36
36
  }
37
37
  const createdAtFormatted = formatUtcDate(new Date(createdAt));
38
- return (0, _slugify.slugify)('Untitled entry ' + createdAtFormatted, 'en-US');
38
+ return (0, _slugify.slugify)('Untitled entry ' + createdAtFormatted, 'en-US', maxLength);
39
39
  }
40
40
  function makeSlug(title, options) {
41
- return title ? (0, _slugify.slugify)(title, options.locale) : untitledSlug(options);
41
+ return title ? (0, _slugify.slugify)(title, options.locale, options.maxLength) : untitledSlug(options);
42
42
  }
@@ -11,4 +11,12 @@ describe('makeSlug', ()=>{
11
11
  createdAt: '2020-01-14T14:45:39.709Z'
12
12
  })).toBe('untitled-entry-2020-01-14-at-14-45-39');
13
13
  });
14
+ it('should respect maxLength when title is present', ()=>{
15
+ expect((0, _makeSlug.makeSlug)('a'.repeat(300), {
16
+ locale: 'en',
17
+ isOptionalLocaleWithFallback: false,
18
+ createdAt: '2020-01-14T14:45:39.709Z',
19
+ maxLength: 256
20
+ })).toBe('a'.repeat(256));
21
+ });
14
22
  });
@@ -14,7 +14,7 @@ function _interop_require_default(obj) {
14
14
  default: obj
15
15
  };
16
16
  }
17
- const CF_GENERATED_SLUG_MAX_LENGTH = 75;
17
+ const DEFAULT_SLUG_MAX_LENGTH = 75;
18
18
  const languages = [
19
19
  'ar',
20
20
  'az',
@@ -49,11 +49,11 @@ function supportedLanguage(locale) {
49
49
  const prefix = locale.slice(0, 2).toLowerCase();
50
50
  return languages[languages.indexOf(prefix)];
51
51
  }
52
- function slugify(text, locale = 'en') {
52
+ function slugify(text, locale = 'en', maxLength = DEFAULT_SLUG_MAX_LENGTH) {
53
53
  return (0, _speakingurl.default)(text, {
54
54
  separator: '-',
55
55
  lang: supportedLanguage(locale) || 'en',
56
- truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,
56
+ truncate: maxLength + 1,
57
57
  custom: {
58
58
  "'": '',
59
59
  '`': '',
@@ -27,4 +27,13 @@ describe('slugify', ()=>{
27
27
  expect((0, _slugify.slugify)(input[0])).toBe(input[1]);
28
28
  });
29
29
  });
30
+ it('defaults to a 75 character limit', ()=>{
31
+ expect((0, _slugify.slugify)('a'.repeat(80))).toBe('a'.repeat(75));
32
+ });
33
+ it('accepts a custom max length', ()=>{
34
+ expect((0, _slugify.slugify)('a'.repeat(80), 'en', 80)).toBe('a'.repeat(80));
35
+ });
36
+ it('does not cut off words when a custom max length is provided', ()=>{
37
+ expect((0, _slugify.slugify)('one two three four', 'en', 13)).toBe('one-two-three');
38
+ });
30
39
  });
@@ -2,10 +2,20 @@ import * as React from 'react';
2
2
  import { FieldConnector } from '@contentful/field-editor-shared';
3
3
  import { SlugEditorField, SlugEditorFieldStatic } from './SlugEditorField';
4
4
  import { TrackingFieldConnector } from './TrackingFieldConnector';
5
+ const DEFAULT_SYMBOL_FIELD_MAX_LENGTH = 256;
6
+ function getSlugFieldMaxLength(validations = []) {
7
+ const maxFromValidations = validations.reduce((currentMax, validation)=>{
8
+ if (!('size' in validation) || typeof validation.size?.max !== 'number') {
9
+ return currentMax;
10
+ }
11
+ return currentMax === null ? validation.size.max : Math.min(currentMax, validation.size.max);
12
+ }, null);
13
+ return maxFromValidations === null ? DEFAULT_SYMBOL_FIELD_MAX_LENGTH : Math.min(DEFAULT_SYMBOL_FIELD_MAX_LENGTH, maxFromValidations);
14
+ }
5
15
  function isSupportedFieldTypes(val) {
6
16
  return val === 'Symbol';
7
17
  }
8
- function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id }) {
18
+ function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, maxLength, performUniqueCheck, isUniqueValidationEnabled, id }) {
9
19
  const safeSetValue = React.useCallback(async (...args)=>{
10
20
  try {
11
21
  await setValue(...args);
@@ -18,6 +28,7 @@ function FieldConnectorCallback({ Component, value, disabled, setValue, errors,
18
28
  }, /*#__PURE__*/ React.createElement(Component, {
19
29
  locale: locale,
20
30
  createdAt: createdAt,
31
+ maxLength: maxLength,
21
32
  performUniqueCheck: performUniqueCheck,
22
33
  isUniqueValidationEnabled: isUniqueValidationEnabled,
23
34
  hasError: errors.length > 0,
@@ -38,6 +49,7 @@ export function SlugEditor(props) {
38
49
  const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
39
50
  const entrySys = entry.getSys();
40
51
  const isUniqueValidationEnabled = (field.validations || []).some((validation)=>'unique' in validation && validation.unique === true);
52
+ const maxLength = getSlugFieldMaxLength(field.validations);
41
53
  const isLocaleOptional = locales.optional[field.locale];
42
54
  const localeFallbackCode = locales.fallbacks[field.locale];
43
55
  const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
@@ -85,6 +97,7 @@ export function SlugEditor(props) {
85
97
  isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
86
98
  createdAt: entrySys.createdAt,
87
99
  locale: field.locale,
100
+ maxLength: maxLength,
88
101
  performUniqueCheck: performUniqueCheck,
89
102
  isUniqueValidationEnabled: isUniqueValidationEnabled,
90
103
  key: `slug-editor-${externalReset}`,
@@ -271,6 +271,7 @@ describe('SlugEditor', ()=>{
271
271
  locale: "en-US",
272
272
  titleValue: "Slug value",
273
273
  createdAt: "2020-01-24T15:33:47.906Z",
274
+ maxLength: 256,
274
275
  setValue: setValue,
275
276
  performUniqueCheck: performUniqueCheck
276
277
  }));
@@ -482,22 +483,46 @@ describe('SlugEditor', ()=>{
482
483
  });
483
484
  });
484
485
  });
485
- it('slug suggestion is limited to 75 symbols', async ()=>{
486
+ it('slug suggestion is limited to 256 characters by default', async ()=>{
487
+ const longTitle = 'a'.repeat(300);
486
488
  const { field, sdk } = createMocks({
487
489
  field: '',
488
- titleField: ''
490
+ titleField: longTitle
489
491
  });
490
- render(/*#__PURE__*/ React.createElement(SlugEditor, {
492
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(SlugEditor, {
491
493
  field: field,
492
494
  baseSdk: sdk,
493
495
  isInitiallyDisabled: false
494
496
  }));
495
- await waitFor(async ()=>{
496
- await sdk.entry.fields['title-id'].setValue('a'.repeat(80));
497
- });
498
497
  await waitFor(()=>{
499
- const expectedSlug = 'a'.repeat(75);
498
+ const expectedSlug = 'a'.repeat(256);
500
499
  expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
500
+ expect(getByTestId('cf-ui-text-input')).toHaveAttribute('maxlength', '256');
501
+ });
502
+ });
503
+ it('slug suggestion respects size max validation', async ()=>{
504
+ const { field, sdk } = createMocks({
505
+ field: '',
506
+ titleField: 'one two three four'
507
+ });
508
+ field.validations = [
509
+ {
510
+ unique: true
511
+ },
512
+ {
513
+ size: {
514
+ max: 13
515
+ }
516
+ }
517
+ ];
518
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(SlugEditor, {
519
+ field: field,
520
+ baseSdk: sdk,
521
+ isInitiallyDisabled: false
522
+ }));
523
+ await waitFor(()=>{
524
+ expect(field.setValue).toHaveBeenLastCalledWith('one-two-three');
525
+ expect(getByTestId('cf-ui-text-input')).toHaveAttribute('maxlength', '13');
501
526
  });
502
527
  });
503
528
  it('slug suggestion does not contain cut-off words', async ()=>{
@@ -511,7 +536,7 @@ describe('SlugEditor', ()=>{
511
536
  isInitiallyDisabled: false
512
537
  }));
513
538
  await waitFor(async ()=>{
514
- await sdk.entry.fields['title-id'].setValue(`one two three ${'a'.repeat(80)}`);
539
+ await sdk.entry.fields['title-id'].setValue(`one two three ${'a'.repeat(300)}`);
515
540
  });
516
541
  await waitFor(()=>{
517
542
  const expectedSlug = 'one-two-three';
@@ -7,7 +7,7 @@ import { useDebounce } from 'use-debounce';
7
7
  import { makeSlug } from './services/makeSlug';
8
8
  import * as styles from './styles';
9
9
  function useSlugUpdater(props, check) {
10
- const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;
10
+ const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback, maxLength } = props;
11
11
  React.useEffect(()=>{
12
12
  if (check === false) {
13
13
  return;
@@ -15,7 +15,8 @@ function useSlugUpdater(props, check) {
15
15
  const newSlug = makeSlug(titleValue, {
16
16
  isOptionalLocaleWithFallback,
17
17
  locale,
18
- createdAt
18
+ createdAt,
19
+ maxLength
19
20
  });
20
21
  if (newSlug !== value) {
21
22
  setValue(newSlug);
@@ -27,6 +28,7 @@ function useSlugUpdater(props, check) {
27
28
  check,
28
29
  createdAt,
29
30
  locale,
31
+ maxLength,
30
32
  setValue
31
33
  ]);
32
34
  }
@@ -52,7 +54,7 @@ function useUniqueChecker(props) {
52
54
  return status;
53
55
  }
54
56
  export function SlugEditorFieldStatic(props) {
55
- const { hasError, isDisabled, value, setValue, onChange, onBlur, isUniqueValidationEnabled, id } = props;
57
+ const { hasError, isDisabled, value, setValue, onChange, onBlur, isUniqueValidationEnabled, id, maxLength } = props;
56
58
  const status = useUniqueChecker(props);
57
59
  const hasDuplicate = status === 'duplicate';
58
60
  const shouldShowDuplicateAsError = hasDuplicate && isUniqueValidationEnabled && !hasError;
@@ -67,6 +69,7 @@ export function SlugEditorFieldStatic(props) {
67
69
  isDisabled: isDisabled,
68
70
  value: value || '',
69
71
  id: id,
72
+ maxLength: maxLength,
70
73
  onChange: (e)=>{
71
74
  setValue(e.target.value);
72
75
  if (onChange) {
@@ -98,12 +101,13 @@ export function SlugEditorFieldStatic(props) {
98
101
  })));
99
102
  }
100
103
  export function SlugEditorField(props) {
101
- const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;
104
+ const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxLength } = props;
102
105
  const areEqual = React.useCallback(()=>{
103
106
  const potentialSlug = makeSlug(titleValue, {
104
- isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
105
- locale: locale,
106
- createdAt: createdAt
107
+ isOptionalLocaleWithFallback,
108
+ locale,
109
+ createdAt,
110
+ maxLength
107
111
  });
108
112
  return value === potentialSlug;
109
113
  }, [
@@ -111,6 +115,7 @@ export function SlugEditorField(props) {
111
115
  isOptionalLocaleWithFallback,
112
116
  locale,
113
117
  createdAt,
118
+ maxLength,
114
119
  value
115
120
  ]);
116
121
  const [check, setCheck] = React.useState(()=>{
@@ -12,13 +12,13 @@ export function formatUtcDate(date) {
12
12
  const seconds = formatTwoDigit(date.getUTCSeconds());
13
13
  return `${year} ${month} ${day} at ${hour} ${minutes} ${seconds}`;
14
14
  }
15
- function untitledSlug({ isOptionalLocaleWithFallback, createdAt }) {
15
+ function untitledSlug({ isOptionalLocaleWithFallback, createdAt, maxLength }) {
16
16
  if (isOptionalLocaleWithFallback) {
17
17
  return '';
18
18
  }
19
19
  const createdAtFormatted = formatUtcDate(new Date(createdAt));
20
- return slugify('Untitled entry ' + createdAtFormatted, 'en-US');
20
+ return slugify('Untitled entry ' + createdAtFormatted, 'en-US', maxLength);
21
21
  }
22
22
  export function makeSlug(title, options) {
23
- return title ? slugify(title, options.locale) : untitledSlug(options);
23
+ return title ? slugify(title, options.locale, options.maxLength) : untitledSlug(options);
24
24
  }
@@ -7,4 +7,12 @@ describe('makeSlug', ()=>{
7
7
  createdAt: '2020-01-14T14:45:39.709Z'
8
8
  })).toBe('untitled-entry-2020-01-14-at-14-45-39');
9
9
  });
10
+ it('should respect maxLength when title is present', ()=>{
11
+ expect(makeSlug('a'.repeat(300), {
12
+ locale: 'en',
13
+ isOptionalLocaleWithFallback: false,
14
+ createdAt: '2020-01-14T14:45:39.709Z',
15
+ maxLength: 256
16
+ })).toBe('a'.repeat(256));
17
+ });
10
18
  });
@@ -1,5 +1,5 @@
1
1
  import getSlug from 'speakingurl';
2
- const CF_GENERATED_SLUG_MAX_LENGTH = 75;
2
+ const DEFAULT_SLUG_MAX_LENGTH = 75;
3
3
  const languages = [
4
4
  'ar',
5
5
  'az',
@@ -34,11 +34,11 @@ function supportedLanguage(locale) {
34
34
  const prefix = locale.slice(0, 2).toLowerCase();
35
35
  return languages[languages.indexOf(prefix)];
36
36
  }
37
- export function slugify(text, locale = 'en') {
37
+ export function slugify(text, locale = 'en', maxLength = DEFAULT_SLUG_MAX_LENGTH) {
38
38
  return getSlug(text, {
39
39
  separator: '-',
40
40
  lang: supportedLanguage(locale) || 'en',
41
- truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,
41
+ truncate: maxLength + 1,
42
42
  custom: {
43
43
  "'": '',
44
44
  '`': '',
@@ -23,4 +23,13 @@ describe('slugify', ()=>{
23
23
  expect(slugify(input[0])).toBe(input[1]);
24
24
  });
25
25
  });
26
+ it('defaults to a 75 character limit', ()=>{
27
+ expect(slugify('a'.repeat(80))).toBe('a'.repeat(75));
28
+ });
29
+ it('accepts a custom max length', ()=>{
30
+ expect(slugify('a'.repeat(80), 'en', 80)).toBe('a'.repeat(80));
31
+ });
32
+ it('does not cut off words when a custom max length is provided', ()=>{
33
+ expect(slugify('one two three four', 'en', 13)).toBe('one-two-three');
34
+ });
26
35
  });
@@ -8,6 +8,7 @@ interface SlugEditorFieldProps {
8
8
  locale: string;
9
9
  titleValue: string | null | undefined;
10
10
  createdAt: string;
11
+ maxLength: number;
11
12
  setValue: (value: string | null | undefined) => void;
12
13
  performUniqueCheck: (value: string) => Promise<boolean>;
13
14
  id?: string;
@@ -2,6 +2,7 @@ type MakeSlugOptions = {
2
2
  locale: string;
3
3
  isOptionalLocaleWithFallback: boolean;
4
4
  createdAt: string;
5
+ maxLength?: number;
5
6
  };
6
7
  export declare function formatUtcDate(date: Date): string;
7
8
  export declare function makeSlug(title: string | null | undefined, options: MakeSlugOptions): string;
@@ -3,10 +3,13 @@
3
3
  * If the locale belongs to a language supported by SpeakingURL, it
4
4
  * is used as the symbol language. Otherwise, the symbol language
5
5
  * is english.
6
- * Slug suggestions are limited to 75 characters.
6
+ *
7
+ * By default slug suggestions are limited to 75 characters.
8
+ * Consumers can override that limit via maxLength.
7
9
  *
8
10
  * @param {string} text To be turned into a slug.
9
11
  * @param {string?} locale
12
+ * @param {number?} maxLength
10
13
  * @returns {string} Slug for provided text.
11
14
  */
12
- export declare function slugify(text: string, locale?: string): string;
15
+ export declare function slugify(text: string, locale?: string, maxLength?: number): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/field-editor-slug",
3
- "version": "3.0.0",
3
+ "version": "3.0.1-canary.0+bb95f1db",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -59,5 +59,5 @@
59
59
  "publishConfig": {
60
60
  "registry": "https://npm.pkg.github.com/"
61
61
  },
62
- "gitHead": "edde3372ed00ed0fd6a798233284618983383869"
62
+ "gitHead": "bb95f1dbd95f3bcfcd9bfb9cbd058e5810796f44"
63
63
  }