@contentful/field-editor-slug 1.2.0 → 1.3.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.
- package/dist/cjs/SlugEditor.js +139 -0
- package/dist/cjs/SlugEditor.test.js +508 -0
- package/dist/cjs/SlugEditorField.js +186 -0
- package/dist/cjs/TrackingFieldConnector.js +137 -0
- package/dist/cjs/index.js +24 -0
- package/dist/cjs/services/makeSlug.js +42 -0
- package/dist/cjs/services/makeSlug.test.js +14 -0
- package/dist/cjs/services/slugify.js +64 -0
- package/dist/cjs/services/slugify.test.js +30 -0
- package/dist/cjs/styles.js +68 -0
- package/dist/esm/SlugEditor.js +90 -0
- package/dist/esm/SlugEditor.test.js +460 -0
- package/dist/esm/SlugEditorField.js +129 -0
- package/dist/esm/TrackingFieldConnector.js +88 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/services/makeSlug.js +24 -0
- package/dist/esm/services/makeSlug.test.js +10 -0
- package/dist/esm/services/slugify.js +49 -0
- package/dist/esm/services/slugify.test.js +26 -0
- package/dist/esm/styles.js +33 -0
- package/dist/{SlugEditor.d.ts → types/SlugEditor.d.ts} +24 -24
- package/dist/types/SlugEditor.test.d.ts +1 -0
- package/dist/{SlugEditorField.d.ts → types/SlugEditorField.d.ts} +18 -18
- package/dist/{TrackingFieldConnector.d.ts → types/TrackingFieldConnector.d.ts} +29 -29
- package/dist/{index.d.ts → types/index.d.ts} +3 -3
- package/dist/{services → types/services}/makeSlug.d.ts +8 -8
- package/dist/types/services/makeSlug.test.d.ts +1 -0
- package/dist/{services → types/services}/slugify.d.ts +12 -12
- package/dist/types/services/slugify.test.d.ts +1 -0
- package/dist/{styles.d.ts → types/styles.d.ts} +6 -6
- package/package.json +25 -11
- package/CHANGELOG.md +0 -206
- package/dist/field-editor-slug.cjs.development.js +0 -463
- package/dist/field-editor-slug.cjs.development.js.map +0 -1
- package/dist/field-editor-slug.cjs.production.min.js +0 -2
- package/dist/field-editor-slug.cjs.production.min.js.map +0 -1
- package/dist/field-editor-slug.esm.js +0 -454
- package/dist/field-editor-slug.esm.js.map +0 -1
- package/dist/index.js +0 -8
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
SlugEditorFieldStatic: function() {
|
|
13
|
+
return SlugEditorFieldStatic;
|
|
14
|
+
},
|
|
15
|
+
SlugEditorField: function() {
|
|
16
|
+
return SlugEditorField;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _react = _interop_require_wildcard(require("react"));
|
|
20
|
+
const _f36components = require("@contentful/f36-components");
|
|
21
|
+
const _f36icons = require("@contentful/f36-icons");
|
|
22
|
+
const _usedebounce = require("use-debounce");
|
|
23
|
+
const _makeSlug = require("./services/makeSlug");
|
|
24
|
+
const _styles = _interop_require_wildcard(require("./styles"));
|
|
25
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
26
|
+
if (typeof WeakMap !== "function") return null;
|
|
27
|
+
var cacheBabelInterop = new WeakMap();
|
|
28
|
+
var cacheNodeInterop = new WeakMap();
|
|
29
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
30
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
31
|
+
})(nodeInterop);
|
|
32
|
+
}
|
|
33
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
34
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
|
37
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
38
|
+
return {
|
|
39
|
+
default: obj
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
43
|
+
if (cache && cache.has(obj)) {
|
|
44
|
+
return cache.get(obj);
|
|
45
|
+
}
|
|
46
|
+
var newObj = {};
|
|
47
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
48
|
+
for(var key in obj){
|
|
49
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
50
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
51
|
+
if (desc && (desc.get || desc.set)) {
|
|
52
|
+
Object.defineProperty(newObj, key, desc);
|
|
53
|
+
} else {
|
|
54
|
+
newObj[key] = obj[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
newObj.default = obj;
|
|
59
|
+
if (cache) {
|
|
60
|
+
cache.set(obj, newObj);
|
|
61
|
+
}
|
|
62
|
+
return newObj;
|
|
63
|
+
}
|
|
64
|
+
function useSlugUpdater(props, check) {
|
|
65
|
+
const { value , setValue , createdAt , locale , titleValue , isOptionalLocaleWithFallback } = props;
|
|
66
|
+
_react.useEffect(()=>{
|
|
67
|
+
if (check === false) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const newSlug = (0, _makeSlug.makeSlug)(titleValue, {
|
|
71
|
+
isOptionalLocaleWithFallback,
|
|
72
|
+
locale,
|
|
73
|
+
createdAt
|
|
74
|
+
});
|
|
75
|
+
if (newSlug !== value) {
|
|
76
|
+
setValue(newSlug);
|
|
77
|
+
}
|
|
78
|
+
}, [
|
|
79
|
+
value,
|
|
80
|
+
titleValue,
|
|
81
|
+
isOptionalLocaleWithFallback,
|
|
82
|
+
check,
|
|
83
|
+
createdAt,
|
|
84
|
+
locale,
|
|
85
|
+
setValue
|
|
86
|
+
]);
|
|
87
|
+
}
|
|
88
|
+
function useUniqueChecker(props) {
|
|
89
|
+
const { performUniqueCheck } = props;
|
|
90
|
+
const [status, setStatus] = _react.useState(props.value ? 'checking' : 'unique');
|
|
91
|
+
const [debouncedValue] = (0, _usedebounce.useDebounce)(props.value, 1000);
|
|
92
|
+
_react.useEffect(()=>{
|
|
93
|
+
if (!debouncedValue) {
|
|
94
|
+
setStatus('unique');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
setStatus('checking');
|
|
98
|
+
performUniqueCheck(debouncedValue).then((unique)=>{
|
|
99
|
+
setStatus(unique ? 'unique' : 'duplicate');
|
|
100
|
+
}).catch(()=>{
|
|
101
|
+
setStatus('checking');
|
|
102
|
+
});
|
|
103
|
+
}, [
|
|
104
|
+
debouncedValue,
|
|
105
|
+
performUniqueCheck
|
|
106
|
+
]);
|
|
107
|
+
return status;
|
|
108
|
+
}
|
|
109
|
+
function SlugEditorFieldStatic(props) {
|
|
110
|
+
const { hasError , isDisabled , value , setValue , onChange , onBlur } = props;
|
|
111
|
+
const status = useUniqueChecker(props);
|
|
112
|
+
return _react.createElement("div", {
|
|
113
|
+
className: _styles.inputContainer
|
|
114
|
+
}, _react.createElement(_f36icons.LinkIcon, {
|
|
115
|
+
className: _styles.icon
|
|
116
|
+
}), _react.createElement(_f36components.TextInput, {
|
|
117
|
+
className: _styles.input,
|
|
118
|
+
isInvalid: hasError || status === 'duplicate',
|
|
119
|
+
isDisabled: isDisabled,
|
|
120
|
+
value: value || '',
|
|
121
|
+
onChange: (e)=>{
|
|
122
|
+
setValue(e.target.value);
|
|
123
|
+
if (onChange) {
|
|
124
|
+
onChange();
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
onBlur: ()=>{
|
|
128
|
+
if (onBlur) {
|
|
129
|
+
onBlur();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}), status === 'checking' && _react.createElement("div", {
|
|
133
|
+
className: _styles.spinnerContainer
|
|
134
|
+
}, _react.createElement(_f36components.Spinner, {
|
|
135
|
+
testId: "slug-editor-spinner"
|
|
136
|
+
})), status === 'duplicate' && _react.createElement(_f36components.ValidationMessage, {
|
|
137
|
+
testId: "slug-editor-duplicate-error",
|
|
138
|
+
className: _styles.uniqueValidationError
|
|
139
|
+
}, "This slug has already been published in another entry"));
|
|
140
|
+
}
|
|
141
|
+
function SlugEditorField(props) {
|
|
142
|
+
const { titleValue , isOptionalLocaleWithFallback , locale , createdAt , value } = props;
|
|
143
|
+
const areEqual = _react.useCallback(()=>{
|
|
144
|
+
const potentialSlug = (0, _makeSlug.makeSlug)(titleValue, {
|
|
145
|
+
isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
|
|
146
|
+
locale: locale,
|
|
147
|
+
createdAt: createdAt
|
|
148
|
+
});
|
|
149
|
+
return value === potentialSlug;
|
|
150
|
+
}, [
|
|
151
|
+
titleValue,
|
|
152
|
+
isOptionalLocaleWithFallback,
|
|
153
|
+
locale,
|
|
154
|
+
createdAt,
|
|
155
|
+
value
|
|
156
|
+
]);
|
|
157
|
+
const [check, setCheck] = _react.useState(()=>{
|
|
158
|
+
if (props.value) {
|
|
159
|
+
if (!props.titleValue) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
return areEqual();
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
});
|
|
166
|
+
_react.useEffect(()=>{
|
|
167
|
+
if (areEqual()) {
|
|
168
|
+
setCheck(true);
|
|
169
|
+
}
|
|
170
|
+
}, [
|
|
171
|
+
props.titleValue,
|
|
172
|
+
areEqual
|
|
173
|
+
]);
|
|
174
|
+
useSlugUpdater(props, check);
|
|
175
|
+
return _react.createElement(SlugEditorFieldStatic, {
|
|
176
|
+
...props,
|
|
177
|
+
onChange: ()=>{
|
|
178
|
+
setCheck(false);
|
|
179
|
+
},
|
|
180
|
+
onBlur: ()=>{
|
|
181
|
+
if (areEqual()) {
|
|
182
|
+
setCheck(true);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "TrackingFieldConnector", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return TrackingFieldConnector;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _react = _interop_require_wildcard(require("react"));
|
|
12
|
+
function _define_property(obj, key, value) {
|
|
13
|
+
if (key in obj) {
|
|
14
|
+
Object.defineProperty(obj, key, {
|
|
15
|
+
value: value,
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
obj[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return obj;
|
|
24
|
+
}
|
|
25
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
26
|
+
if (typeof WeakMap !== "function") return null;
|
|
27
|
+
var cacheBabelInterop = new WeakMap();
|
|
28
|
+
var cacheNodeInterop = new WeakMap();
|
|
29
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
30
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
31
|
+
})(nodeInterop);
|
|
32
|
+
}
|
|
33
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
34
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
|
37
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
38
|
+
return {
|
|
39
|
+
default: obj
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
43
|
+
if (cache && cache.has(obj)) {
|
|
44
|
+
return cache.get(obj);
|
|
45
|
+
}
|
|
46
|
+
var newObj = {};
|
|
47
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
48
|
+
for(var key in obj){
|
|
49
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
50
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
51
|
+
if (desc && (desc.get || desc.set)) {
|
|
52
|
+
Object.defineProperty(newObj, key, desc);
|
|
53
|
+
} else {
|
|
54
|
+
newObj[key] = obj[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
newObj.default = obj;
|
|
59
|
+
if (cache) {
|
|
60
|
+
cache.set(obj, newObj);
|
|
61
|
+
}
|
|
62
|
+
return newObj;
|
|
63
|
+
}
|
|
64
|
+
function getTitleField(sdk, trackingFieldId) {
|
|
65
|
+
const { entry , contentType } = sdk;
|
|
66
|
+
if (trackingFieldId && entry.fields[trackingFieldId]) {
|
|
67
|
+
return entry.fields[trackingFieldId];
|
|
68
|
+
}
|
|
69
|
+
return entry.fields[contentType.displayField];
|
|
70
|
+
}
|
|
71
|
+
var _React_Component;
|
|
72
|
+
class TrackingFieldConnector extends (_React_Component = _react.Component) {
|
|
73
|
+
componentDidMount() {
|
|
74
|
+
this.unsubscribeSysChanges = this.props.sdk.entry.onSysChanged((sys)=>{
|
|
75
|
+
this.setState({
|
|
76
|
+
isPublished: Boolean(sys.publishedVersion)
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
const titleField = getTitleField(this.props.sdk, this.props.trackingFieldId);
|
|
80
|
+
if (!titleField) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (!this.state.isSame) {
|
|
84
|
+
this.unsubscribeLocalizedValue = titleField.onValueChanged(this.props.field.locale, (value)=>{
|
|
85
|
+
this.setState({
|
|
86
|
+
titleValue: value
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (this.props.field.locale !== this.props.defaultLocale) {
|
|
91
|
+
if (!this.props.isOptionalLocaleWithFallback) {
|
|
92
|
+
this.unsubscribeValue = titleField.onValueChanged(this.props.defaultLocale, (value)=>{
|
|
93
|
+
if (!titleField.getValue(this.props.field.locale)) {
|
|
94
|
+
this.setState({
|
|
95
|
+
titleValue: value
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
componentWillUnmount() {
|
|
103
|
+
if (typeof this.unsubscribeValue === 'function') {
|
|
104
|
+
this.unsubscribeValue();
|
|
105
|
+
}
|
|
106
|
+
if (typeof this.unsubscribeLocalizedValue === 'function') {
|
|
107
|
+
this.unsubscribeLocalizedValue();
|
|
108
|
+
}
|
|
109
|
+
if (typeof this.unsubscribeSysChanges === 'function') {
|
|
110
|
+
this.unsubscribeSysChanges();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
render() {
|
|
114
|
+
return this.props.children({
|
|
115
|
+
...this.state
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
constructor(props){
|
|
119
|
+
super(props);
|
|
120
|
+
_define_property(this, "unsubscribeValue", null);
|
|
121
|
+
_define_property(this, "unsubscribeLocalizedValue", null);
|
|
122
|
+
_define_property(this, "unsubscribeSysChanges", null);
|
|
123
|
+
const titleField = getTitleField(props.sdk, props.trackingFieldId);
|
|
124
|
+
const entrySys = props.sdk.entry.getSys();
|
|
125
|
+
const isSame = titleField ? props.field.id === titleField.id : false;
|
|
126
|
+
this.state = {
|
|
127
|
+
titleValue: titleField ? titleField.getValue() : '',
|
|
128
|
+
isPublished: Boolean(entrySys.publishedVersion),
|
|
129
|
+
isSame
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
_define_property(TrackingFieldConnector, "defaultProps", {
|
|
134
|
+
children: ()=>{
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
SlugEditor: function() {
|
|
13
|
+
return _SlugEditor.SlugEditor;
|
|
14
|
+
},
|
|
15
|
+
slugify: function() {
|
|
16
|
+
return _slugify.slugify;
|
|
17
|
+
},
|
|
18
|
+
makeSlug: function() {
|
|
19
|
+
return _makeSlug.makeSlug;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const _SlugEditor = require("./SlugEditor");
|
|
23
|
+
const _slugify = require("./services/slugify");
|
|
24
|
+
const _makeSlug = require("./services/makeSlug");
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
formatUtcDate: function() {
|
|
13
|
+
return formatUtcDate;
|
|
14
|
+
},
|
|
15
|
+
makeSlug: function() {
|
|
16
|
+
return makeSlug;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _slugify = require("./slugify");
|
|
20
|
+
function formatTwoDigit(num) {
|
|
21
|
+
const asString = String(num);
|
|
22
|
+
return asString.length === 1 ? `0${asString}` : asString;
|
|
23
|
+
}
|
|
24
|
+
function formatUtcDate(date) {
|
|
25
|
+
const year = date.getFullYear();
|
|
26
|
+
const month = formatTwoDigit(date.getUTCMonth() + 1);
|
|
27
|
+
const day = formatTwoDigit(date.getUTCDate());
|
|
28
|
+
const hour = formatTwoDigit(date.getUTCHours());
|
|
29
|
+
const minutes = formatTwoDigit(date.getUTCMinutes());
|
|
30
|
+
const seconds = formatTwoDigit(date.getUTCSeconds());
|
|
31
|
+
return `${year} ${month} ${day} at ${hour} ${minutes} ${seconds}`;
|
|
32
|
+
}
|
|
33
|
+
function untitledSlug({ isOptionalLocaleWithFallback , createdAt }) {
|
|
34
|
+
if (isOptionalLocaleWithFallback) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
const createdAtFormatted = formatUtcDate(new Date(createdAt));
|
|
38
|
+
return (0, _slugify.slugify)('Untitled entry ' + createdAtFormatted, 'en-US');
|
|
39
|
+
}
|
|
40
|
+
function makeSlug(title, options) {
|
|
41
|
+
return title ? (0, _slugify.slugify)(title, options.locale) : untitledSlug(options);
|
|
42
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _makeSlug = require("./makeSlug");
|
|
6
|
+
describe('makeSlug', ()=>{
|
|
7
|
+
it('should return untitled slug if title is empty', ()=>{
|
|
8
|
+
expect((0, _makeSlug.makeSlug)('', {
|
|
9
|
+
locale: 'en',
|
|
10
|
+
isOptionalLocaleWithFallback: false,
|
|
11
|
+
createdAt: '2020-01-14T14:45:39.709Z'
|
|
12
|
+
})).toBe('untitled-entry-2020-01-14-at-14-45-39');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "slugify", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return slugify;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _speakingurl = _interop_require_default(require("speakingurl"));
|
|
12
|
+
function _interop_require_default(obj) {
|
|
13
|
+
return obj && obj.__esModule ? obj : {
|
|
14
|
+
default: obj
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const CF_GENERATED_SLUG_MAX_LENGTH = 75;
|
|
18
|
+
const languages = [
|
|
19
|
+
'ar',
|
|
20
|
+
'az',
|
|
21
|
+
'cs',
|
|
22
|
+
'de',
|
|
23
|
+
'dv',
|
|
24
|
+
'en',
|
|
25
|
+
'es',
|
|
26
|
+
'fa',
|
|
27
|
+
'fi',
|
|
28
|
+
'fr',
|
|
29
|
+
'ge',
|
|
30
|
+
'gr',
|
|
31
|
+
'hu',
|
|
32
|
+
'it',
|
|
33
|
+
'lt',
|
|
34
|
+
'lv',
|
|
35
|
+
'my',
|
|
36
|
+
'mk',
|
|
37
|
+
'nl',
|
|
38
|
+
'pl',
|
|
39
|
+
'pt',
|
|
40
|
+
'ro',
|
|
41
|
+
'ru',
|
|
42
|
+
'sk',
|
|
43
|
+
'sr',
|
|
44
|
+
'tr',
|
|
45
|
+
'uk',
|
|
46
|
+
'vn'
|
|
47
|
+
];
|
|
48
|
+
function supportedLanguage(locale) {
|
|
49
|
+
const prefix = locale.slice(0, 2).toLowerCase();
|
|
50
|
+
return languages[languages.indexOf(prefix)];
|
|
51
|
+
}
|
|
52
|
+
function slugify(text, locale = 'en') {
|
|
53
|
+
return (0, _speakingurl.default)(text, {
|
|
54
|
+
separator: '-',
|
|
55
|
+
lang: supportedLanguage(locale) || 'en',
|
|
56
|
+
truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,
|
|
57
|
+
custom: {
|
|
58
|
+
"'": '',
|
|
59
|
+
'`': '',
|
|
60
|
+
'’': '',
|
|
61
|
+
'‘': ''
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
const _slugify = require("./slugify");
|
|
6
|
+
describe('slugify', ()=>{
|
|
7
|
+
const cases = [
|
|
8
|
+
[
|
|
9
|
+
'We ♥ $ & €',
|
|
10
|
+
'we-love-usd-and-eur'
|
|
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
|
+
"it's a SLUG",
|
|
22
|
+
'its-a-slug'
|
|
23
|
+
]
|
|
24
|
+
];
|
|
25
|
+
cases.forEach((input)=>{
|
|
26
|
+
it(`converts "${input[0]}" to "${input[1]}"`, ()=>{
|
|
27
|
+
expect((0, _slugify.slugify)(input[0])).toBe(input[1]);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
validationRow: function() {
|
|
13
|
+
return validationRow;
|
|
14
|
+
},
|
|
15
|
+
inputContainer: function() {
|
|
16
|
+
return inputContainer;
|
|
17
|
+
},
|
|
18
|
+
input: function() {
|
|
19
|
+
return input;
|
|
20
|
+
},
|
|
21
|
+
icon: function() {
|
|
22
|
+
return icon;
|
|
23
|
+
},
|
|
24
|
+
spinnerContainer: function() {
|
|
25
|
+
return spinnerContainer;
|
|
26
|
+
},
|
|
27
|
+
uniqueValidationError: function() {
|
|
28
|
+
return uniqueValidationError;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const _f36tokens = _interop_require_default(require("@contentful/f36-tokens"));
|
|
32
|
+
const _emotion = require("emotion");
|
|
33
|
+
function _interop_require_default(obj) {
|
|
34
|
+
return obj && obj.__esModule ? obj : {
|
|
35
|
+
default: obj
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const validationRow = (0, _emotion.css)({
|
|
39
|
+
display: 'flex',
|
|
40
|
+
flexDirection: 'row-reverse',
|
|
41
|
+
fontSize: _f36tokens.default.fontSizeM,
|
|
42
|
+
marginTop: _f36tokens.default.spacingXs,
|
|
43
|
+
color: _f36tokens.default.gray700
|
|
44
|
+
});
|
|
45
|
+
const inputContainer = (0, _emotion.css)({
|
|
46
|
+
position: 'relative'
|
|
47
|
+
});
|
|
48
|
+
const input = (0, _emotion.css)({
|
|
49
|
+
paddingLeft: '40px'
|
|
50
|
+
});
|
|
51
|
+
const icon = (0, _emotion.css)({
|
|
52
|
+
position: 'absolute',
|
|
53
|
+
left: '10px',
|
|
54
|
+
top: '8px',
|
|
55
|
+
zIndex: 2,
|
|
56
|
+
width: '25px',
|
|
57
|
+
height: '25px',
|
|
58
|
+
fill: _f36tokens.default.gray500
|
|
59
|
+
});
|
|
60
|
+
const spinnerContainer = (0, _emotion.css)({
|
|
61
|
+
position: 'absolute',
|
|
62
|
+
zIndex: 2,
|
|
63
|
+
right: '8px',
|
|
64
|
+
top: '8px'
|
|
65
|
+
});
|
|
66
|
+
const uniqueValidationError = (0, _emotion.css)({
|
|
67
|
+
marginTop: _f36tokens.default.spacingS
|
|
68
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { FieldConnector } from '@contentful/field-editor-shared';
|
|
3
|
+
import { SlugEditorField, SlugEditorFieldStatic } from './SlugEditorField';
|
|
4
|
+
import { TrackingFieldConnector } from './TrackingFieldConnector';
|
|
5
|
+
function isSupportedFieldTypes(val) {
|
|
6
|
+
return val === 'Symbol';
|
|
7
|
+
}
|
|
8
|
+
function FieldConnectorCallback({ Component , value , disabled , setValue , errors , titleValue , isOptionalLocaleWithFallback , locale , createdAt , performUniqueCheck }) {
|
|
9
|
+
const safeSetValue = React.useCallback(async (...args)=>{
|
|
10
|
+
try {
|
|
11
|
+
await setValue(...args);
|
|
12
|
+
} catch (e) {}
|
|
13
|
+
}, [
|
|
14
|
+
setValue
|
|
15
|
+
]);
|
|
16
|
+
return React.createElement("div", {
|
|
17
|
+
"data-test-id": "slug-editor"
|
|
18
|
+
}, React.createElement(Component, {
|
|
19
|
+
locale: locale,
|
|
20
|
+
createdAt: createdAt,
|
|
21
|
+
performUniqueCheck: performUniqueCheck,
|
|
22
|
+
hasError: errors.length > 0,
|
|
23
|
+
value: value,
|
|
24
|
+
isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
|
|
25
|
+
isDisabled: disabled,
|
|
26
|
+
titleValue: titleValue,
|
|
27
|
+
setValue: safeSetValue
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
export function SlugEditor(props) {
|
|
31
|
+
const { field , parameters } = props;
|
|
32
|
+
const { locales , entry , space } = props.baseSdk;
|
|
33
|
+
if (!isSupportedFieldTypes(field.type)) {
|
|
34
|
+
throw new Error(`"${field.type}" field type is not supported by SlugEditor`);
|
|
35
|
+
}
|
|
36
|
+
const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
|
|
37
|
+
const entrySys = entry.getSys();
|
|
38
|
+
const isLocaleOptional = locales.optional[field.locale];
|
|
39
|
+
const localeFallbackCode = locales.fallbacks[field.locale];
|
|
40
|
+
const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
|
|
41
|
+
const isOptionalLocaleWithFallback = Boolean(isOptionalFieldLocale && localeFallbackCode && locales.available.includes(localeFallbackCode));
|
|
42
|
+
const performUniqueCheck = React.useCallback((value)=>{
|
|
43
|
+
const searchQuery = {
|
|
44
|
+
content_type: entrySys?.contentType?.sys?.id,
|
|
45
|
+
[`fields.${field.id}.${field.locale}`]: value,
|
|
46
|
+
'sys.id[ne]': entrySys.id,
|
|
47
|
+
'sys.publishedAt[exists]': true,
|
|
48
|
+
limit: 0
|
|
49
|
+
};
|
|
50
|
+
return space.getEntries(searchQuery).then((res)=>{
|
|
51
|
+
return res.total === 0;
|
|
52
|
+
});
|
|
53
|
+
}, [
|
|
54
|
+
entrySys?.contentType?.sys?.id,
|
|
55
|
+
field.id,
|
|
56
|
+
field.locale,
|
|
57
|
+
entrySys.id,
|
|
58
|
+
space
|
|
59
|
+
]);
|
|
60
|
+
return React.createElement(TrackingFieldConnector, {
|
|
61
|
+
sdk: props.baseSdk,
|
|
62
|
+
field: field,
|
|
63
|
+
defaultLocale: locales.default,
|
|
64
|
+
isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
|
|
65
|
+
trackingFieldId: trackingFieldId
|
|
66
|
+
}, ({ titleValue , isPublished , isSame })=>React.createElement(FieldConnector, {
|
|
67
|
+
field: field,
|
|
68
|
+
isInitiallyDisabled: props.isInitiallyDisabled,
|
|
69
|
+
throttle: 0
|
|
70
|
+
}, ({ value , errors , disabled , setValue , externalReset })=>{
|
|
71
|
+
const shouldTrackTitle = isPublished === false && isSame === false;
|
|
72
|
+
const Component = shouldTrackTitle ? SlugEditorField : SlugEditorFieldStatic;
|
|
73
|
+
return React.createElement(FieldConnectorCallback, {
|
|
74
|
+
Component: Component,
|
|
75
|
+
titleValue: titleValue,
|
|
76
|
+
value: value,
|
|
77
|
+
errors: errors,
|
|
78
|
+
disabled: disabled,
|
|
79
|
+
setValue: setValue,
|
|
80
|
+
isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
|
|
81
|
+
createdAt: entrySys.createdAt,
|
|
82
|
+
locale: field.locale,
|
|
83
|
+
performUniqueCheck: performUniqueCheck,
|
|
84
|
+
key: `slug-editor-${externalReset}`
|
|
85
|
+
});
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
SlugEditor.defaultProps = {
|
|
89
|
+
isInitiallyDisabled: true
|
|
90
|
+
};
|