@contentful/field-editor-slug 1.2.0 → 1.3.1

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.
Files changed (39) hide show
  1. package/dist/cjs/SlugEditor.js +139 -0
  2. package/dist/cjs/SlugEditor.test.js +538 -0
  3. package/dist/cjs/SlugEditorField.js +186 -0
  4. package/dist/cjs/TrackingFieldConnector.js +137 -0
  5. package/dist/cjs/index.js +24 -0
  6. package/dist/cjs/services/makeSlug.js +42 -0
  7. package/dist/cjs/services/makeSlug.test.js +14 -0
  8. package/dist/cjs/services/slugify.js +64 -0
  9. package/dist/cjs/services/slugify.test.js +30 -0
  10. package/dist/cjs/styles.js +68 -0
  11. package/dist/esm/SlugEditor.js +90 -0
  12. package/dist/esm/SlugEditor.test.js +490 -0
  13. package/dist/esm/SlugEditorField.js +129 -0
  14. package/dist/esm/TrackingFieldConnector.js +88 -0
  15. package/dist/esm/index.js +3 -0
  16. package/dist/esm/services/makeSlug.js +24 -0
  17. package/dist/esm/services/makeSlug.test.js +10 -0
  18. package/dist/esm/services/slugify.js +49 -0
  19. package/dist/esm/services/slugify.test.js +26 -0
  20. package/dist/esm/styles.js +33 -0
  21. package/dist/{SlugEditor.d.ts → types/SlugEditor.d.ts} +24 -24
  22. package/dist/types/SlugEditor.test.d.ts +1 -0
  23. package/dist/{SlugEditorField.d.ts → types/SlugEditorField.d.ts} +18 -18
  24. package/dist/{TrackingFieldConnector.d.ts → types/TrackingFieldConnector.d.ts} +29 -29
  25. package/dist/{index.d.ts → types/index.d.ts} +3 -3
  26. package/dist/{services → types/services}/makeSlug.d.ts +8 -8
  27. package/dist/types/services/makeSlug.test.d.ts +1 -0
  28. package/dist/{services → types/services}/slugify.d.ts +12 -12
  29. package/dist/types/services/slugify.test.d.ts +1 -0
  30. package/dist/{styles.d.ts → types/styles.d.ts} +6 -6
  31. package/package.json +25 -11
  32. package/CHANGELOG.md +0 -206
  33. package/dist/field-editor-slug.cjs.development.js +0 -463
  34. package/dist/field-editor-slug.cjs.development.js.map +0 -1
  35. package/dist/field-editor-slug.cjs.production.min.js +0 -2
  36. package/dist/field-editor-slug.cjs.production.min.js.map +0 -1
  37. package/dist/field-editor-slug.esm.js +0 -454
  38. package/dist/field-editor-slug.esm.js.map +0 -1
  39. package/dist/index.js +0 -8
@@ -0,0 +1,88 @@
1
+ function _define_property(obj, key, value) {
2
+ if (key in obj) {
3
+ Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ } else {
10
+ obj[key] = value;
11
+ }
12
+ return obj;
13
+ }
14
+ import * as React from 'react';
15
+ function getTitleField(sdk, trackingFieldId) {
16
+ const { entry , contentType } = sdk;
17
+ if (trackingFieldId && entry.fields[trackingFieldId]) {
18
+ return entry.fields[trackingFieldId];
19
+ }
20
+ return entry.fields[contentType.displayField];
21
+ }
22
+ var _React_Component;
23
+ export class TrackingFieldConnector extends (_React_Component = React.Component) {
24
+ componentDidMount() {
25
+ this.unsubscribeSysChanges = this.props.sdk.entry.onSysChanged((sys)=>{
26
+ this.setState({
27
+ isPublished: Boolean(sys.publishedVersion)
28
+ });
29
+ });
30
+ const titleField = getTitleField(this.props.sdk, this.props.trackingFieldId);
31
+ if (!titleField) {
32
+ return;
33
+ }
34
+ if (!this.state.isSame) {
35
+ this.unsubscribeLocalizedValue = titleField.onValueChanged(this.props.field.locale, (value)=>{
36
+ this.setState({
37
+ titleValue: value
38
+ });
39
+ });
40
+ }
41
+ if (this.props.field.locale !== this.props.defaultLocale) {
42
+ if (!this.props.isOptionalLocaleWithFallback) {
43
+ this.unsubscribeValue = titleField.onValueChanged(this.props.defaultLocale, (value)=>{
44
+ if (!titleField.getValue(this.props.field.locale)) {
45
+ this.setState({
46
+ titleValue: value
47
+ });
48
+ }
49
+ });
50
+ }
51
+ }
52
+ }
53
+ componentWillUnmount() {
54
+ if (typeof this.unsubscribeValue === 'function') {
55
+ this.unsubscribeValue();
56
+ }
57
+ if (typeof this.unsubscribeLocalizedValue === 'function') {
58
+ this.unsubscribeLocalizedValue();
59
+ }
60
+ if (typeof this.unsubscribeSysChanges === 'function') {
61
+ this.unsubscribeSysChanges();
62
+ }
63
+ }
64
+ render() {
65
+ return this.props.children({
66
+ ...this.state
67
+ });
68
+ }
69
+ constructor(props){
70
+ super(props);
71
+ _define_property(this, "unsubscribeValue", null);
72
+ _define_property(this, "unsubscribeLocalizedValue", null);
73
+ _define_property(this, "unsubscribeSysChanges", null);
74
+ const titleField = getTitleField(props.sdk, props.trackingFieldId);
75
+ const entrySys = props.sdk.entry.getSys();
76
+ const isSame = titleField ? props.field.id === titleField.id : false;
77
+ this.state = {
78
+ titleValue: titleField ? titleField.getValue() : '',
79
+ isPublished: Boolean(entrySys.publishedVersion),
80
+ isSame
81
+ };
82
+ }
83
+ }
84
+ _define_property(TrackingFieldConnector, "defaultProps", {
85
+ children: ()=>{
86
+ return null;
87
+ }
88
+ });
@@ -0,0 +1,3 @@
1
+ export { SlugEditor } from './SlugEditor';
2
+ export { slugify } from './services/slugify';
3
+ export { makeSlug } from './services/makeSlug';
@@ -0,0 +1,24 @@
1
+ import { slugify } from './slugify';
2
+ function formatTwoDigit(num) {
3
+ const asString = String(num);
4
+ return asString.length === 1 ? `0${asString}` : asString;
5
+ }
6
+ export function formatUtcDate(date) {
7
+ const year = date.getFullYear();
8
+ const month = formatTwoDigit(date.getUTCMonth() + 1);
9
+ const day = formatTwoDigit(date.getUTCDate());
10
+ const hour = formatTwoDigit(date.getUTCHours());
11
+ const minutes = formatTwoDigit(date.getUTCMinutes());
12
+ const seconds = formatTwoDigit(date.getUTCSeconds());
13
+ return `${year} ${month} ${day} at ${hour} ${minutes} ${seconds}`;
14
+ }
15
+ function untitledSlug({ isOptionalLocaleWithFallback , createdAt }) {
16
+ if (isOptionalLocaleWithFallback) {
17
+ return '';
18
+ }
19
+ const createdAtFormatted = formatUtcDate(new Date(createdAt));
20
+ return slugify('Untitled entry ' + createdAtFormatted, 'en-US');
21
+ }
22
+ export function makeSlug(title, options) {
23
+ return title ? slugify(title, options.locale) : untitledSlug(options);
24
+ }
@@ -0,0 +1,10 @@
1
+ import { makeSlug } from './makeSlug';
2
+ describe('makeSlug', ()=>{
3
+ it('should return untitled slug if title is empty', ()=>{
4
+ expect(makeSlug('', {
5
+ locale: 'en',
6
+ isOptionalLocaleWithFallback: false,
7
+ createdAt: '2020-01-14T14:45:39.709Z'
8
+ })).toBe('untitled-entry-2020-01-14-at-14-45-39');
9
+ });
10
+ });
@@ -0,0 +1,49 @@
1
+ import getSlug from 'speakingurl';
2
+ const CF_GENERATED_SLUG_MAX_LENGTH = 75;
3
+ const languages = [
4
+ 'ar',
5
+ 'az',
6
+ 'cs',
7
+ 'de',
8
+ 'dv',
9
+ 'en',
10
+ 'es',
11
+ 'fa',
12
+ 'fi',
13
+ 'fr',
14
+ 'ge',
15
+ 'gr',
16
+ 'hu',
17
+ 'it',
18
+ 'lt',
19
+ 'lv',
20
+ 'my',
21
+ 'mk',
22
+ 'nl',
23
+ 'pl',
24
+ 'pt',
25
+ 'ro',
26
+ 'ru',
27
+ 'sk',
28
+ 'sr',
29
+ 'tr',
30
+ 'uk',
31
+ 'vn'
32
+ ];
33
+ function supportedLanguage(locale) {
34
+ const prefix = locale.slice(0, 2).toLowerCase();
35
+ return languages[languages.indexOf(prefix)];
36
+ }
37
+ export function slugify(text, locale = 'en') {
38
+ return getSlug(text, {
39
+ separator: '-',
40
+ lang: supportedLanguage(locale) || 'en',
41
+ truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,
42
+ custom: {
43
+ "'": '',
44
+ '`': '',
45
+ '’': '',
46
+ '‘': ''
47
+ }
48
+ });
49
+ }
@@ -0,0 +1,26 @@
1
+ import { slugify } from './slugify';
2
+ describe('slugify', ()=>{
3
+ const cases = [
4
+ [
5
+ 'We ♥ $ & €',
6
+ 'we-love-usd-and-eur'
7
+ ],
8
+ [
9
+ 'it`s a Slug',
10
+ 'its-a-slug'
11
+ ],
12
+ [
13
+ 'it’S a slug',
14
+ 'its-a-slug'
15
+ ],
16
+ [
17
+ "it's a SLUG",
18
+ 'its-a-slug'
19
+ ]
20
+ ];
21
+ cases.forEach((input)=>{
22
+ it(`converts "${input[0]}" to "${input[1]}"`, ()=>{
23
+ expect(slugify(input[0])).toBe(input[1]);
24
+ });
25
+ });
26
+ });
@@ -0,0 +1,33 @@
1
+ import tokens from '@contentful/f36-tokens';
2
+ import { css } from 'emotion';
3
+ export const validationRow = css({
4
+ display: 'flex',
5
+ flexDirection: 'row-reverse',
6
+ fontSize: tokens.fontSizeM,
7
+ marginTop: tokens.spacingXs,
8
+ color: tokens.gray700
9
+ });
10
+ export const inputContainer = css({
11
+ position: 'relative'
12
+ });
13
+ export const input = css({
14
+ paddingLeft: '40px'
15
+ });
16
+ export const icon = css({
17
+ position: 'absolute',
18
+ left: '10px',
19
+ top: '8px',
20
+ zIndex: 2,
21
+ width: '25px',
22
+ height: '25px',
23
+ fill: tokens.gray500
24
+ });
25
+ export const spinnerContainer = css({
26
+ position: 'absolute',
27
+ zIndex: 2,
28
+ right: '8px',
29
+ top: '8px'
30
+ });
31
+ export const uniqueValidationError = css({
32
+ marginTop: tokens.spacingS
33
+ });
@@ -1,24 +1,24 @@
1
- /// <reference types="react" />
2
- import { FieldExtensionSDK, FieldAPI } from '@contentful/app-sdk';
3
- export interface SlugEditorProps {
4
- /**
5
- * is the field disabled initially
6
- */
7
- isInitiallyDisabled: boolean;
8
- baseSdk: FieldExtensionSDK;
9
- /**
10
- * sdk.field
11
- */
12
- field: FieldAPI;
13
- parameters?: {
14
- instance: {
15
- trackingFieldId?: string;
16
- };
17
- };
18
- }
19
- export declare function SlugEditor(props: SlugEditorProps): JSX.Element;
20
- export declare namespace SlugEditor {
21
- var defaultProps: {
22
- isInitiallyDisabled: boolean;
23
- };
24
- }
1
+ import * as React from 'react';
2
+ import { FieldExtensionSDK, FieldAPI } from '@contentful/app-sdk';
3
+ export interface SlugEditorProps {
4
+ /**
5
+ * is the field disabled initially
6
+ */
7
+ isInitiallyDisabled: boolean;
8
+ baseSdk: FieldExtensionSDK;
9
+ /**
10
+ * sdk.field
11
+ */
12
+ field: FieldAPI;
13
+ parameters?: {
14
+ instance: {
15
+ trackingFieldId?: string;
16
+ };
17
+ };
18
+ }
19
+ export declare function SlugEditor(props: SlugEditorProps): React.JSX.Element;
20
+ export declare namespace SlugEditor {
21
+ var defaultProps: {
22
+ isInitiallyDisabled: boolean;
23
+ };
24
+ }
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom/extend-expect';
@@ -1,18 +1,18 @@
1
- /// <reference types="react" />
2
- interface SlugEditorFieldProps {
3
- hasError: boolean;
4
- isOptionalLocaleWithFallback: boolean;
5
- isDisabled: boolean;
6
- value: string | null | undefined;
7
- locale: string;
8
- titleValue: string | null | undefined;
9
- createdAt: string;
10
- setValue: (value: string | null | undefined) => void;
11
- performUniqueCheck: (value: string) => Promise<boolean>;
12
- }
13
- export declare function SlugEditorFieldStatic(props: SlugEditorFieldProps & {
14
- onChange?: Function;
15
- onBlur?: Function;
16
- }): JSX.Element;
17
- export declare function SlugEditorField(props: SlugEditorFieldProps): JSX.Element;
18
- export {};
1
+ import * as React from 'react';
2
+ interface SlugEditorFieldProps {
3
+ hasError: boolean;
4
+ isOptionalLocaleWithFallback: boolean;
5
+ isDisabled: boolean;
6
+ value: string | null | undefined;
7
+ locale: string;
8
+ titleValue: string | null | undefined;
9
+ createdAt: string;
10
+ setValue: (value: string | null | undefined) => void;
11
+ performUniqueCheck: (value: string) => Promise<boolean>;
12
+ }
13
+ export declare function SlugEditorFieldStatic(props: SlugEditorFieldProps & {
14
+ onChange?: Function;
15
+ onBlur?: Function;
16
+ }): React.JSX.Element;
17
+ export declare function SlugEditorField(props: SlugEditorFieldProps): React.JSX.Element;
18
+ export {};
@@ -1,29 +1,29 @@
1
- import React from 'react';
2
- import { FieldExtensionSDK, FieldAPI } from '@contentful/app-sdk';
3
- declare type Nullable = null | undefined;
4
- interface TrackingFieldConnectorState<ValueType> {
5
- titleValue: ValueType | Nullable;
6
- isPublished: boolean;
7
- isSame: boolean;
8
- }
9
- interface TrackingFieldConnectorProps<ValueType> {
10
- sdk: FieldExtensionSDK;
11
- field: FieldAPI;
12
- defaultLocale: string;
13
- trackingFieldId?: string;
14
- isOptionalLocaleWithFallback: boolean;
15
- children: (state: TrackingFieldConnectorState<ValueType>) => React.ReactNode;
16
- }
17
- export declare class TrackingFieldConnector<ValueType> extends React.Component<TrackingFieldConnectorProps<ValueType>, TrackingFieldConnectorState<ValueType>> {
18
- static defaultProps: {
19
- children: () => null;
20
- };
21
- constructor(props: TrackingFieldConnectorProps<ValueType>);
22
- unsubscribeValue: Function | null;
23
- unsubscribeLocalizedValue: Function | null;
24
- unsubscribeSysChanges: Function | null;
25
- componentDidMount(): void;
26
- componentWillUnmount(): void;
27
- render(): React.ReactNode;
28
- }
29
- export {};
1
+ import * as React from 'react';
2
+ import { FieldAPI, FieldExtensionSDK } from '@contentful/app-sdk';
3
+ type Nullable = null | undefined;
4
+ interface TrackingFieldConnectorState<ValueType> {
5
+ titleValue: ValueType | Nullable;
6
+ isPublished: boolean;
7
+ isSame: boolean;
8
+ }
9
+ interface TrackingFieldConnectorProps<ValueType> {
10
+ sdk: FieldExtensionSDK;
11
+ field: FieldAPI;
12
+ defaultLocale: string;
13
+ trackingFieldId?: string;
14
+ isOptionalLocaleWithFallback: boolean;
15
+ children: (state: TrackingFieldConnectorState<ValueType>) => React.ReactNode;
16
+ }
17
+ export declare class TrackingFieldConnector<ValueType> extends React.Component<TrackingFieldConnectorProps<ValueType>, TrackingFieldConnectorState<ValueType>> {
18
+ static defaultProps: {
19
+ children: () => null;
20
+ };
21
+ constructor(props: TrackingFieldConnectorProps<ValueType>);
22
+ unsubscribeValue: Function | null;
23
+ unsubscribeLocalizedValue: Function | null;
24
+ unsubscribeSysChanges: Function | null;
25
+ componentDidMount(): void;
26
+ componentWillUnmount(): void;
27
+ render(): React.ReactNode;
28
+ }
29
+ export {};
@@ -1,3 +1,3 @@
1
- export { SlugEditor } from './SlugEditor';
2
- export { slugify } from './services/slugify';
3
- export { makeSlug } from './services/makeSlug';
1
+ export { SlugEditor } from './SlugEditor';
2
+ export { slugify } from './services/slugify';
3
+ export { makeSlug } from './services/makeSlug';
@@ -1,8 +1,8 @@
1
- declare type MakeSlugOptions = {
2
- locale: string;
3
- isOptionalLocaleWithFallback: boolean;
4
- createdAt: string;
5
- };
6
- export declare function formatUtcDate(date: Date): string;
7
- export declare function makeSlug(title: string | null | undefined, options: MakeSlugOptions): string;
8
- export {};
1
+ type MakeSlugOptions = {
2
+ locale: string;
3
+ isOptionalLocaleWithFallback: boolean;
4
+ createdAt: string;
5
+ };
6
+ export declare function formatUtcDate(date: Date): string;
7
+ export declare function makeSlug(title: string | null | undefined, options: MakeSlugOptions): string;
8
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,12 +1,12 @@
1
- /**
2
- * Returns the slug for a given string and locale.
3
- * If the locale belongs to a language supported by SpeakingURL, it
4
- * is used as the symbol language. Otherwise, the symbol language
5
- * is english.
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
- */
12
- export declare function slugify(text: string, locale?: string): string;
1
+ /**
2
+ * Returns the slug for a given string and locale.
3
+ * If the locale belongs to a language supported by SpeakingURL, it
4
+ * is used as the symbol language. Otherwise, the symbol language
5
+ * is english.
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
+ */
12
+ export declare function slugify(text: string, locale?: string): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
- export declare const validationRow: string;
2
- export declare const inputContainer: string;
3
- export declare const input: string;
4
- export declare const icon: string;
5
- export declare const spinnerContainer: string;
6
- export declare const uniqueValidationError: string;
1
+ export declare const validationRow: string;
2
+ export declare const inputContainer: string;
3
+ export declare const input: string;
4
+ export declare const icon: string;
5
+ export declare const spinnerContainer: string;
6
+ export declare const uniqueValidationError: string;
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "@contentful/field-editor-slug",
3
- "version": "1.2.0",
4
- "main": "dist/index.js",
5
- "module": "dist/field-editor-slug.esm.js",
6
- "typings": "dist/index.d.ts",
3
+ "version": "1.3.1",
4
+ "main": "dist/cjs/index.js",
5
+ "module": "dist/esm/index.js",
6
+ "types": "dist/types/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/types/index.d.ts",
10
+ "require": "./dist/cjs/index.js",
11
+ "default": "./dist/cjs/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
7
15
  "files": [
8
16
  "dist"
9
17
  ],
@@ -14,17 +22,23 @@
14
22
  "url": "https://github.com/contentful/field-editors"
15
23
  },
16
24
  "scripts": {
17
- "watch": "tsdx watch",
18
- "build": "tsdx build",
19
- "test": "tsdx test --env=jsdom --watch",
20
- "test:ci": "tsdx test --env=jsdom --ci",
25
+ "watch": "yarn concurrently \"yarn:watch:*\"",
26
+ "watch:cjs": "yarn build:cjs -w",
27
+ "watch:esm": "yarn build:esm -w",
28
+ "watch:types": "yarn build:types --watch",
29
+ "build": "yarn build:types && yarn build:cjs && yarn build:esm",
30
+ "build:types": "tsc --outDir dist/types --emitDeclarationOnly",
31
+ "build:cjs": "swc src --config-file ../../.swcrc -d dist/cjs -C module.type=commonjs",
32
+ "build:esm": "swc src --config-file ../../.swcrc -d dist/esm",
33
+ "test": "jest --watch",
34
+ "test:ci": "jest --ci",
21
35
  "tsc": "tsc -p ./ --noEmit"
22
36
  },
23
37
  "dependencies": {
24
38
  "@contentful/f36-components": "^4.0.27",
25
39
  "@contentful/f36-icons": "^4.1.0",
26
40
  "@contentful/f36-tokens": "^4.0.0",
27
- "@contentful/field-editor-shared": "^1.2.0",
41
+ "@contentful/field-editor-shared": "^1.3.0",
28
42
  "@types/speakingurl": "^13.0.2",
29
43
  "emotion": "^10.0.17",
30
44
  "lodash": "^4.17.15",
@@ -34,11 +48,11 @@
34
48
  },
35
49
  "devDependencies": {
36
50
  "@contentful/app-sdk": "^4.2.0",
37
- "@contentful/field-editor-test-utils": "^1.3.0"
51
+ "@contentful/field-editor-test-utils": "^1.4.0"
38
52
  },
39
53
  "peerDependencies": {
40
54
  "@contentful/app-sdk": "^4.2.0",
41
55
  "react": ">=16.8.0"
42
56
  },
43
- "gitHead": "de7e74e3485dd69c240cfe9c545e6e50e41fb295"
57
+ "gitHead": "83b651f1638ad6bab53565479e76b8d29b86af3a"
44
58
  }