@contentful/field-editor-slug 3.0.4 → 3.0.5-canary.2

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.
@@ -56,7 +56,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
56
56
  function isSupportedFieldTypes(val) {
57
57
  return val === 'Symbol';
58
58
  }
59
- function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id }) {
59
+ function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id, maxLength }) {
60
60
  const safeSetValue = _react.useCallback(async (...args)=>{
61
61
  try {
62
62
  await setValue(...args);
@@ -77,7 +77,8 @@ function FieldConnectorCallback({ Component, value, disabled, setValue, errors,
77
77
  isDisabled: disabled,
78
78
  titleValue: titleValue,
79
79
  setValue: safeSetValue,
80
- id: id
80
+ id: id,
81
+ maxLength: maxLength
81
82
  }));
82
83
  }
83
84
  function SlugEditor(props) {
@@ -89,6 +90,7 @@ function SlugEditor(props) {
89
90
  const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
90
91
  const entrySys = entry.getSys();
91
92
  const isUniqueValidationEnabled = (field.validations || []).some((validation)=>'unique' in validation && validation.unique === true);
93
+ const maxLength = (field.validations || []).find((validation)=>'size' in validation)?.size?.max;
92
94
  const isLocaleOptional = locales.optional[field.locale];
93
95
  const localeFallbackCode = locales.fallbacks[field.locale];
94
96
  const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
@@ -139,7 +141,8 @@ function SlugEditor(props) {
139
141
  performUniqueCheck: performUniqueCheck,
140
142
  isUniqueValidationEnabled: isUniqueValidationEnabled,
141
143
  key: `slug-editor-${externalReset}`,
142
- id: id
144
+ id: id,
145
+ maxLength: maxLength
143
146
  });
144
147
  }));
145
148
  }
@@ -527,22 +527,31 @@ describe('SlugEditor', ()=>{
527
527
  });
528
528
  });
529
529
  });
530
- it('slug suggestion is limited to 75 symbols', async ()=>{
530
+ it('slug suggestion is limited to size validation max', async ()=>{
531
531
  const { field, sdk } = createMocks({
532
532
  field: '',
533
533
  titleField: ''
534
534
  });
535
+ field.validations = [
536
+ {
537
+ unique: true
538
+ },
539
+ {
540
+ size: {
541
+ max: 20
542
+ }
543
+ }
544
+ ];
535
545
  (0, _react1.render)(/*#__PURE__*/ _react.createElement(_SlugEditor.SlugEditor, {
536
546
  field: field,
537
547
  baseSdk: sdk,
538
548
  isInitiallyDisabled: false
539
549
  }));
540
550
  await (0, _react1.waitFor)(async ()=>{
541
- await sdk.entry.fields['title-id'].setValue('a'.repeat(80));
551
+ await sdk.entry.fields['title-id'].setValue('the quick brown fox jumps over the lazy dog');
542
552
  });
543
553
  await (0, _react1.waitFor)(()=>{
544
- const expectedSlug = 'a'.repeat(75);
545
- expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
554
+ expect(field.setValue).toHaveBeenLastCalledWith('the-quick-brown-fox');
546
555
  });
547
556
  });
548
557
  it('slug suggestion does not contain cut-off words', async ()=>{
@@ -550,6 +559,16 @@ describe('SlugEditor', ()=>{
550
559
  field: '',
551
560
  titleField: ''
552
561
  });
562
+ field.validations = [
563
+ {
564
+ unique: true
565
+ },
566
+ {
567
+ size: {
568
+ max: 20
569
+ }
570
+ }
571
+ ];
553
572
  (0, _react1.render)(/*#__PURE__*/ _react.createElement(_SlugEditor.SlugEditor, {
554
573
  field: field,
555
574
  baseSdk: sdk,
@@ -65,27 +65,19 @@ function _interop_require_wildcard(obj, nodeInterop) {
65
65
  }
66
66
  return newObj;
67
67
  }
68
- function useSlugUpdater(props, check) {
69
- const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;
68
+ function useSlugUpdater({ value, setValue }, check, generateSlug) {
70
69
  _react.useEffect(()=>{
71
70
  if (check === false) {
72
71
  return;
73
72
  }
74
- const newSlug = (0, _makeSlug.makeSlug)(titleValue, {
75
- isOptionalLocaleWithFallback,
76
- locale,
77
- createdAt
78
- });
73
+ const newSlug = generateSlug();
79
74
  if (newSlug !== value) {
80
75
  setValue(newSlug);
81
76
  }
82
77
  }, [
83
78
  value,
84
- titleValue,
85
- isOptionalLocaleWithFallback,
79
+ generateSlug,
86
80
  check,
87
- createdAt,
88
- locale,
89
81
  setValue
90
82
  ]);
91
83
  }
@@ -157,19 +149,26 @@ function SlugEditorFieldStatic(props) {
157
149
  })));
158
150
  }
159
151
  function SlugEditorField(props) {
160
- const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;
161
- const areEqual = _react.useCallback(()=>{
162
- const potentialSlug = (0, _makeSlug.makeSlug)(titleValue, {
152
+ const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxLength } = props;
153
+ const generateSlug = _react.useCallback(()=>{
154
+ return (0, _makeSlug.makeSlug)(titleValue, {
163
155
  isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
164
156
  locale: locale,
165
- createdAt: createdAt
157
+ createdAt: createdAt,
158
+ maxLength: maxLength
166
159
  });
167
- return value === potentialSlug;
168
160
  }, [
169
161
  titleValue,
170
162
  isOptionalLocaleWithFallback,
171
163
  locale,
172
164
  createdAt,
165
+ maxLength
166
+ ]);
167
+ const areEqual = _react.useCallback(()=>{
168
+ const potentialSlug = generateSlug();
169
+ return value === potentialSlug;
170
+ }, [
171
+ generateSlug,
173
172
  value
174
173
  ]);
175
174
  const [check, setCheck] = _react.useState(()=>{
@@ -189,7 +188,7 @@ function SlugEditorField(props) {
189
188
  props.titleValue,
190
189
  areEqual
191
190
  ]);
192
- useSlugUpdater(props, check);
191
+ useSlugUpdater(props, check, generateSlug);
193
192
  return /*#__PURE__*/ _react.createElement(SlugEditorFieldStatic, {
194
193
  ...props,
195
194
  onChange: ()=>{
@@ -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 provided', ()=>{
15
+ expect((0, _makeSlug.makeSlug)('hello world foo bar', {
16
+ locale: 'en',
17
+ isOptionalLocaleWithFallback: false,
18
+ createdAt: '2020-01-14T14:45:39.709Z',
19
+ maxLength: 11
20
+ })).toBe('hello-world');
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 MAX_FIELD_LENGTH = 256;
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) {
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 ?? MAX_FIELD_LENGTH,
57
57
  custom: {
58
58
  "'": '',
59
59
  '`': '',
@@ -27,4 +27,7 @@ describe('slugify', ()=>{
27
27
  expect((0, _slugify.slugify)(input[0])).toBe(input[1]);
28
28
  });
29
29
  });
30
+ it('truncates to maxLength', ()=>{
31
+ expect((0, _slugify.slugify)('hello world', 'en', 5)).toBe('hello');
32
+ });
30
33
  });
@@ -5,7 +5,7 @@ import { TrackingFieldConnector } from './TrackingFieldConnector';
5
5
  function isSupportedFieldTypes(val) {
6
6
  return val === 'Symbol';
7
7
  }
8
- function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id }) {
8
+ function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id, maxLength }) {
9
9
  const safeSetValue = React.useCallback(async (...args)=>{
10
10
  try {
11
11
  await setValue(...args);
@@ -26,7 +26,8 @@ function FieldConnectorCallback({ Component, value, disabled, setValue, errors,
26
26
  isDisabled: disabled,
27
27
  titleValue: titleValue,
28
28
  setValue: safeSetValue,
29
- id: id
29
+ id: id,
30
+ maxLength: maxLength
30
31
  }));
31
32
  }
32
33
  export function SlugEditor(props) {
@@ -38,6 +39,7 @@ export function SlugEditor(props) {
38
39
  const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
39
40
  const entrySys = entry.getSys();
40
41
  const isUniqueValidationEnabled = (field.validations || []).some((validation)=>'unique' in validation && validation.unique === true);
42
+ const maxLength = (field.validations || []).find((validation)=>'size' in validation)?.size?.max;
41
43
  const isLocaleOptional = locales.optional[field.locale];
42
44
  const localeFallbackCode = locales.fallbacks[field.locale];
43
45
  const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
@@ -88,7 +90,8 @@ export function SlugEditor(props) {
88
90
  performUniqueCheck: performUniqueCheck,
89
91
  isUniqueValidationEnabled: isUniqueValidationEnabled,
90
92
  key: `slug-editor-${externalReset}`,
91
- id: id
93
+ id: id,
94
+ maxLength: maxLength
92
95
  });
93
96
  }));
94
97
  }
@@ -482,22 +482,31 @@ describe('SlugEditor', ()=>{
482
482
  });
483
483
  });
484
484
  });
485
- it('slug suggestion is limited to 75 symbols', async ()=>{
485
+ it('slug suggestion is limited to size validation max', async ()=>{
486
486
  const { field, sdk } = createMocks({
487
487
  field: '',
488
488
  titleField: ''
489
489
  });
490
+ field.validations = [
491
+ {
492
+ unique: true
493
+ },
494
+ {
495
+ size: {
496
+ max: 20
497
+ }
498
+ }
499
+ ];
490
500
  render(/*#__PURE__*/ React.createElement(SlugEditor, {
491
501
  field: field,
492
502
  baseSdk: sdk,
493
503
  isInitiallyDisabled: false
494
504
  }));
495
505
  await waitFor(async ()=>{
496
- await sdk.entry.fields['title-id'].setValue('a'.repeat(80));
506
+ await sdk.entry.fields['title-id'].setValue('the quick brown fox jumps over the lazy dog');
497
507
  });
498
508
  await waitFor(()=>{
499
- const expectedSlug = 'a'.repeat(75);
500
- expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
509
+ expect(field.setValue).toHaveBeenLastCalledWith('the-quick-brown-fox');
501
510
  });
502
511
  });
503
512
  it('slug suggestion does not contain cut-off words', async ()=>{
@@ -505,6 +514,16 @@ describe('SlugEditor', ()=>{
505
514
  field: '',
506
515
  titleField: ''
507
516
  });
517
+ field.validations = [
518
+ {
519
+ unique: true
520
+ },
521
+ {
522
+ size: {
523
+ max: 20
524
+ }
525
+ }
526
+ ];
508
527
  render(/*#__PURE__*/ React.createElement(SlugEditor, {
509
528
  field: field,
510
529
  baseSdk: sdk,
@@ -6,27 +6,19 @@ import { i18n as $_i18n } from "@lingui/core";
6
6
  import { useDebounce } from 'use-debounce';
7
7
  import { makeSlug } from './services/makeSlug';
8
8
  import * as styles from './styles';
9
- function useSlugUpdater(props, check) {
10
- const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;
9
+ function useSlugUpdater({ value, setValue }, check, generateSlug) {
11
10
  React.useEffect(()=>{
12
11
  if (check === false) {
13
12
  return;
14
13
  }
15
- const newSlug = makeSlug(titleValue, {
16
- isOptionalLocaleWithFallback,
17
- locale,
18
- createdAt
19
- });
14
+ const newSlug = generateSlug();
20
15
  if (newSlug !== value) {
21
16
  setValue(newSlug);
22
17
  }
23
18
  }, [
24
19
  value,
25
- titleValue,
26
- isOptionalLocaleWithFallback,
20
+ generateSlug,
27
21
  check,
28
- createdAt,
29
- locale,
30
22
  setValue
31
23
  ]);
32
24
  }
@@ -98,19 +90,26 @@ export function SlugEditorFieldStatic(props) {
98
90
  })));
99
91
  }
100
92
  export function SlugEditorField(props) {
101
- const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;
102
- const areEqual = React.useCallback(()=>{
103
- const potentialSlug = makeSlug(titleValue, {
93
+ const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxLength } = props;
94
+ const generateSlug = React.useCallback(()=>{
95
+ return makeSlug(titleValue, {
104
96
  isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
105
97
  locale: locale,
106
- createdAt: createdAt
98
+ createdAt: createdAt,
99
+ maxLength: maxLength
107
100
  });
108
- return value === potentialSlug;
109
101
  }, [
110
102
  titleValue,
111
103
  isOptionalLocaleWithFallback,
112
104
  locale,
113
105
  createdAt,
106
+ maxLength
107
+ ]);
108
+ const areEqual = React.useCallback(()=>{
109
+ const potentialSlug = generateSlug();
110
+ return value === potentialSlug;
111
+ }, [
112
+ generateSlug,
114
113
  value
115
114
  ]);
116
115
  const [check, setCheck] = React.useState(()=>{
@@ -130,7 +129,7 @@ export function SlugEditorField(props) {
130
129
  props.titleValue,
131
130
  areEqual
132
131
  ]);
133
- useSlugUpdater(props, check);
132
+ useSlugUpdater(props, check, generateSlug);
134
133
  return /*#__PURE__*/ React.createElement(SlugEditorFieldStatic, {
135
134
  ...props,
136
135
  onChange: ()=>{
@@ -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 provided', ()=>{
11
+ expect(makeSlug('hello world foo bar', {
12
+ locale: 'en',
13
+ isOptionalLocaleWithFallback: false,
14
+ createdAt: '2020-01-14T14:45:39.709Z',
15
+ maxLength: 11
16
+ })).toBe('hello-world');
17
+ });
10
18
  });
@@ -1,5 +1,5 @@
1
1
  import getSlug from 'speakingurl';
2
- const CF_GENERATED_SLUG_MAX_LENGTH = 75;
2
+ const MAX_FIELD_LENGTH = 256;
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) {
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 ?? MAX_FIELD_LENGTH,
42
42
  custom: {
43
43
  "'": '',
44
44
  '`': '',
@@ -23,4 +23,7 @@ describe('slugify', ()=>{
23
23
  expect(slugify(input[0])).toBe(input[1]);
24
24
  });
25
25
  });
26
+ it('truncates to maxLength', ()=>{
27
+ expect(slugify('hello world', 'en', 5)).toBe('hello');
28
+ });
26
29
  });
@@ -11,6 +11,7 @@ interface SlugEditorFieldProps {
11
11
  setValue: (value: string | null | undefined) => void;
12
12
  performUniqueCheck: (value: string) => Promise<boolean>;
13
13
  id?: string;
14
+ maxLength?: number;
14
15
  }
15
16
  export declare function SlugEditorFieldStatic(props: SlugEditorFieldProps & {
16
17
  onChange?: Function;
@@ -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;
@@ -4,9 +4,5 @@
4
4
  * is used as the symbol language. Otherwise, the symbol language
5
5
  * is english.
6
6
  * Slug suggestions are limited to 75 characters.
7
- *
8
- * @param {string} text To be turned into a slug.
9
- * @param {string?} locale
10
- * @returns {string} Slug for provided text.
11
7
  */
12
- export declare function slugify(text: string, locale?: string): string;
8
+ 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.4",
3
+ "version": "3.0.5-canary.2+1e7df5e6",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -40,7 +40,7 @@
40
40
  "@contentful/f36-icons": "^6.7.1",
41
41
  "@contentful/f36-note": "^6.7.0",
42
42
  "@contentful/f36-tokens": "^6.1.2",
43
- "@contentful/field-editor-shared": "^3.1.1",
43
+ "@contentful/field-editor-shared": "^3.1.2-canary.2+1e7df5e6",
44
44
  "@emotion/css": "^11.13.5",
45
45
  "@types/speakingurl": "^13.0.2",
46
46
  "speakingurl": "^14.0.1",
@@ -59,5 +59,5 @@
59
59
  "publishConfig": {
60
60
  "registry": "https://npm.pkg.github.com/"
61
61
  },
62
- "gitHead": "b4833085fd4ade2941f02110e34511a35634197a"
62
+ "gitHead": "1e7df5e61478c4c0c53e53b3dcb39f5947cbd4b8"
63
63
  }