@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.
Files changed (39) hide show
  1. package/dist/cjs/SlugEditor.js +139 -0
  2. package/dist/cjs/SlugEditor.test.js +508 -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 +460 -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
@@ -1,463 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
- var React = require('react');
8
- var React__default = _interopDefault(React);
9
- var fieldEditorShared = require('@contentful/field-editor-shared');
10
- var f36Components = require('@contentful/f36-components');
11
- var f36Icons = require('@contentful/f36-icons');
12
- var useDebounce = require('use-debounce');
13
- var getSlug = _interopDefault(require('speakingurl'));
14
- var tokens = _interopDefault(require('@contentful/f36-tokens'));
15
- var emotion = require('emotion');
16
-
17
- const CF_GENERATED_SLUG_MAX_LENGTH = 75;
18
- const languages = ['ar', 'az', 'cs', 'de', 'dv', 'en', 'es', 'fa', 'fi', 'fr', 'ge', 'gr', 'hu', 'it', 'lt', 'lv', 'my', 'mk', 'nl', 'pl', 'pt', 'ro', 'ru', 'sk', 'sr', 'tr', 'uk', 'vn'];
19
- /**
20
- * Extracts the first two lowercased characters from the locale,
21
- * and returns the supported language prefix.
22
- */
23
-
24
- function supportedLanguage(locale) {
25
- const prefix = locale.slice(0, 2).toLowerCase();
26
- return languages[languages.indexOf(prefix)];
27
- }
28
- /**
29
- * Returns the slug for a given string and locale.
30
- * If the locale belongs to a language supported by SpeakingURL, it
31
- * is used as the symbol language. Otherwise, the symbol language
32
- * is english.
33
- * Slug suggestions are limited to 75 characters.
34
- *
35
- * @param {string} text To be turned into a slug.
36
- * @param {string?} locale
37
- * @returns {string} Slug for provided text.
38
- */
39
-
40
-
41
- function slugify(text, locale = 'en') {
42
- return getSlug(text, {
43
- separator: '-',
44
- lang: supportedLanguage(locale) || 'en',
45
- truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,
46
- custom: {
47
- "'": '',
48
- '`': '',
49
- '’': '',
50
- '‘': ''
51
- }
52
- });
53
- }
54
-
55
- function formatTwoDigit(num) {
56
- const asString = String(num);
57
- return asString.length === 1 ? `0${asString}` : asString;
58
- }
59
-
60
- function formatUtcDate(date) {
61
- const year = date.getFullYear();
62
- const month = formatTwoDigit(date.getUTCMonth() + 1);
63
- const day = formatTwoDigit(date.getUTCDate());
64
- const hour = formatTwoDigit(date.getUTCHours());
65
- const minutes = formatTwoDigit(date.getUTCMinutes());
66
- const seconds = formatTwoDigit(date.getUTCSeconds());
67
- return `${year} ${month} ${day} at ${hour} ${minutes} ${seconds}`;
68
- }
69
-
70
- function untitledSlug({
71
- isOptionalLocaleWithFallback,
72
- createdAt
73
- }) {
74
- if (isOptionalLocaleWithFallback) {
75
- return ''; // Will result in `undefined` slug.
76
- }
77
-
78
- const createdAtFormatted = formatUtcDate(new Date(createdAt));
79
- return slugify('Untitled entry ' + createdAtFormatted, 'en-US');
80
- }
81
-
82
- function makeSlug(title, options) {
83
- return title ? slugify(title, options.locale) : untitledSlug(options);
84
- }
85
-
86
- const inputContainer = /*#__PURE__*/emotion.css({
87
- position: 'relative'
88
- });
89
- const input = /*#__PURE__*/emotion.css({
90
- paddingLeft: '40px'
91
- });
92
- const icon = /*#__PURE__*/emotion.css({
93
- position: 'absolute',
94
- left: '10px',
95
- top: '8px',
96
- zIndex: 2,
97
- width: '25px',
98
- height: '25px',
99
- fill: tokens.gray500
100
- });
101
- const spinnerContainer = /*#__PURE__*/emotion.css({
102
- position: 'absolute',
103
- zIndex: 2,
104
- right: '8px',
105
- top: '8px'
106
- });
107
- const uniqueValidationError = /*#__PURE__*/emotion.css({
108
- marginTop: tokens.spacingS
109
- });
110
-
111
- function useSlugUpdater(props, check) {
112
- const {
113
- value,
114
- setValue,
115
- createdAt,
116
- locale,
117
- titleValue,
118
- isOptionalLocaleWithFallback
119
- } = props;
120
- React__default.useEffect(() => {
121
- if (check === false) {
122
- return;
123
- }
124
-
125
- const newSlug = makeSlug(titleValue, {
126
- isOptionalLocaleWithFallback,
127
- locale,
128
- createdAt
129
- });
130
-
131
- if (newSlug !== value) {
132
- setValue(newSlug);
133
- }
134
- }, [value, titleValue, isOptionalLocaleWithFallback, check, createdAt, locale, setValue]);
135
- }
136
-
137
- function useUniqueChecker(props) {
138
- const {
139
- performUniqueCheck
140
- } = props;
141
- const [status, setStatus] = React__default.useState(props.value ? 'checking' : 'unique');
142
- const [debouncedValue] = useDebounce.useDebounce(props.value, 1000);
143
- /**
144
- * Check the uniqueness of the slug in the current space.
145
- * The slug is unique if there is no published entry other than the
146
- * current one, with the same slug.
147
- */
148
-
149
- React__default.useEffect(() => {
150
- if (!debouncedValue) {
151
- setStatus('unique');
152
- return;
153
- }
154
-
155
- setStatus('checking');
156
- performUniqueCheck(debouncedValue).then(unique => {
157
- setStatus(unique ? 'unique' : 'duplicate');
158
- }).catch(() => {
159
- setStatus('checking');
160
- });
161
- }, [debouncedValue, performUniqueCheck]);
162
- return status;
163
- }
164
-
165
- function SlugEditorFieldStatic(props) {
166
- const {
167
- hasError,
168
- isDisabled,
169
- value,
170
- setValue,
171
- onChange,
172
- onBlur
173
- } = props;
174
- const status = useUniqueChecker(props);
175
- return React__default.createElement("div", {
176
- className: inputContainer
177
- }, React__default.createElement(f36Icons.LinkIcon, {
178
- className: icon
179
- }), React__default.createElement(f36Components.TextInput, {
180
- className: input,
181
- isInvalid: hasError || status === 'duplicate',
182
- isDisabled: isDisabled,
183
- value: value || '',
184
- onChange: e => {
185
- setValue(e.target.value);
186
-
187
- if (onChange) {
188
- onChange();
189
- }
190
- },
191
- onBlur: () => {
192
- if (onBlur) {
193
- onBlur();
194
- }
195
- }
196
- }), status === 'checking' && React__default.createElement("div", {
197
- className: spinnerContainer
198
- }, React__default.createElement(f36Components.Spinner, {
199
- testId: "slug-editor-spinner"
200
- })), status === 'duplicate' && React__default.createElement(f36Components.ValidationMessage, {
201
- testId: "slug-editor-duplicate-error",
202
- className: uniqueValidationError
203
- }, "This slug has already been published in another entry"));
204
- }
205
- function SlugEditorField(props) {
206
- const {
207
- titleValue,
208
- isOptionalLocaleWithFallback,
209
- locale,
210
- createdAt,
211
- value
212
- } = props;
213
- const areEqual = React__default.useCallback(() => {
214
- const potentialSlug = makeSlug(titleValue, {
215
- isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
216
- locale: locale,
217
- createdAt: createdAt
218
- });
219
- return value === potentialSlug;
220
- }, [titleValue, isOptionalLocaleWithFallback, locale, createdAt, value]);
221
- const [check, setCheck] = React__default.useState(() => {
222
- if (props.value) {
223
- if (!props.titleValue) {
224
- return false;
225
- }
226
-
227
- return areEqual();
228
- }
229
-
230
- return true;
231
- });
232
- React__default.useEffect(() => {
233
- if (areEqual()) {
234
- setCheck(true);
235
- }
236
- }, [props.titleValue, areEqual]);
237
- useSlugUpdater(props, check);
238
- return React__default.createElement(SlugEditorFieldStatic, { ...props,
239
- onChange: () => {
240
- setCheck(false);
241
- },
242
- onBlur: () => {
243
- if (areEqual()) {
244
- setCheck(true);
245
- }
246
- }
247
- });
248
- }
249
-
250
- function getTitleField(sdk, trackingFieldId) {
251
- const {
252
- entry,
253
- contentType
254
- } = sdk;
255
-
256
- if (trackingFieldId && entry.fields[trackingFieldId]) {
257
- return entry.fields[trackingFieldId];
258
- }
259
-
260
- return entry.fields[contentType.displayField];
261
- }
262
-
263
- class TrackingFieldConnector extends React__default.Component {
264
- constructor(props) {
265
- super(props);
266
- this.unsubscribeValue = null;
267
- this.unsubscribeLocalizedValue = null;
268
- this.unsubscribeSysChanges = null;
269
- const titleField = getTitleField(props.sdk, props.trackingFieldId);
270
- const entrySys = props.sdk.entry.getSys();
271
- const isSame = titleField ? props.field.id === titleField.id : false;
272
- this.state = {
273
- titleValue: titleField ? titleField.getValue() : '',
274
- isPublished: Boolean(entrySys.publishedVersion),
275
- isSame
276
- };
277
- }
278
-
279
- componentDidMount() {
280
- this.unsubscribeSysChanges = this.props.sdk.entry.onSysChanged(sys => {
281
- this.setState({
282
- isPublished: Boolean(sys.publishedVersion)
283
- });
284
- });
285
- const titleField = getTitleField(this.props.sdk, this.props.trackingFieldId); // the content type's display field might not exist
286
-
287
- if (!titleField) {
288
- return;
289
- }
290
-
291
- if (!this.state.isSame) {
292
- this.unsubscribeLocalizedValue = titleField.onValueChanged(this.props.field.locale, value => {
293
- this.setState({
294
- titleValue: value
295
- });
296
- });
297
- }
298
-
299
- if (this.props.field.locale !== this.props.defaultLocale) {
300
- if (!this.props.isOptionalLocaleWithFallback) {
301
- this.unsubscribeValue = titleField.onValueChanged(this.props.defaultLocale, value => {
302
- if (!titleField.getValue(this.props.field.locale)) {
303
- this.setState({
304
- titleValue: value
305
- });
306
- }
307
- });
308
- }
309
- }
310
- }
311
-
312
- componentWillUnmount() {
313
- if (typeof this.unsubscribeValue === 'function') {
314
- this.unsubscribeValue();
315
- }
316
-
317
- if (typeof this.unsubscribeLocalizedValue === 'function') {
318
- this.unsubscribeLocalizedValue();
319
- }
320
-
321
- if (typeof this.unsubscribeSysChanges === 'function') {
322
- this.unsubscribeSysChanges();
323
- }
324
- }
325
-
326
- render() {
327
- return this.props.children({ ...this.state
328
- });
329
- }
330
-
331
- }
332
- TrackingFieldConnector.defaultProps = {
333
- children: () => {
334
- return null;
335
- }
336
- };
337
-
338
- function isSupportedFieldTypes(val) {
339
- return val === 'Symbol';
340
- }
341
-
342
- function FieldConnectorCallback({
343
- Component,
344
- value,
345
- disabled,
346
- setValue,
347
- errors,
348
- titleValue,
349
- isOptionalLocaleWithFallback,
350
- locale,
351
- createdAt,
352
- performUniqueCheck
353
- }) {
354
- // it is needed to silent permission errors
355
- // this happens when setValue is called on a field which is disabled for permission reasons
356
- const safeSetValue = React.useCallback(async (...args) => {
357
- try {
358
- await setValue(...args);
359
- } catch (e) {// do nothing
360
- }
361
- }, [setValue]);
362
- return React.createElement("div", {
363
- "data-test-id": "slug-editor"
364
- }, React.createElement(Component, {
365
- locale: locale,
366
- createdAt: createdAt,
367
- performUniqueCheck: performUniqueCheck,
368
- hasError: errors.length > 0,
369
- value: value,
370
- isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
371
- isDisabled: disabled,
372
- titleValue: titleValue,
373
- setValue: safeSetValue
374
- }));
375
- }
376
-
377
- function SlugEditor(props) {
378
- var _parameters$instance, _entrySys$contentType3, _entrySys$contentType4;
379
-
380
- const {
381
- field,
382
- parameters
383
- } = props;
384
- const {
385
- locales,
386
- entry,
387
- space
388
- } = props.baseSdk;
389
-
390
- if (!isSupportedFieldTypes(field.type)) {
391
- throw new Error(`"${field.type}" field type is not supported by SlugEditor`);
392
- }
393
-
394
- const trackingFieldId = (parameters == null ? void 0 : (_parameters$instance = parameters.instance) == null ? void 0 : _parameters$instance.trackingFieldId) ?? undefined;
395
- const entrySys = entry.getSys();
396
- const isLocaleOptional = locales.optional[field.locale];
397
- const localeFallbackCode = locales.fallbacks[field.locale]; // If the field or the locale are not required (there's a locale setting that
398
- // allows publishing even if the field is required) and if the locale has a
399
- // fallback than there's no need for a slug unless the user manually enters
400
- // one or the title field is also localized with a custom value.
401
-
402
- const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
403
- const isOptionalLocaleWithFallback = Boolean(isOptionalFieldLocale && localeFallbackCode && locales.available.includes(localeFallbackCode));
404
- const performUniqueCheck = React.useCallback(value => {
405
- var _entrySys$contentType, _entrySys$contentType2;
406
-
407
- const searchQuery = {
408
- content_type: entrySys == null ? void 0 : (_entrySys$contentType = entrySys.contentType) == null ? void 0 : (_entrySys$contentType2 = _entrySys$contentType.sys) == null ? void 0 : _entrySys$contentType2.id,
409
- [`fields.${field.id}.${field.locale}`]: value,
410
- 'sys.id[ne]': entrySys.id,
411
- 'sys.publishedAt[exists]': true,
412
- limit: 0
413
- };
414
- return space.getEntries(searchQuery).then(res => {
415
- return res.total === 0;
416
- });
417
- }, [entrySys == null ? void 0 : (_entrySys$contentType3 = entrySys.contentType) == null ? void 0 : (_entrySys$contentType4 = _entrySys$contentType3.sys) == null ? void 0 : _entrySys$contentType4.id, field.id, field.locale, entrySys.id, space]);
418
- return React.createElement(TrackingFieldConnector, {
419
- sdk: props.baseSdk,
420
- field: field,
421
- defaultLocale: locales.default,
422
- isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
423
- trackingFieldId: trackingFieldId
424
- }, ({
425
- titleValue,
426
- isPublished,
427
- isSame
428
- }) => React.createElement(fieldEditorShared.FieldConnector, {
429
- field: field,
430
- isInitiallyDisabled: props.isInitiallyDisabled,
431
- throttle: 0
432
- }, ({
433
- value,
434
- errors,
435
- disabled,
436
- setValue,
437
- externalReset
438
- }) => {
439
- const shouldTrackTitle = isPublished === false && isSame === false;
440
- const Component = shouldTrackTitle ? SlugEditorField : SlugEditorFieldStatic;
441
- return React.createElement(FieldConnectorCallback, {
442
- Component: Component,
443
- titleValue: titleValue,
444
- value: value,
445
- errors: errors,
446
- disabled: disabled,
447
- setValue: setValue,
448
- isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
449
- createdAt: entrySys.createdAt,
450
- locale: field.locale,
451
- performUniqueCheck: performUniqueCheck,
452
- key: `slug-editor-${externalReset}`
453
- });
454
- }));
455
- }
456
- SlugEditor.defaultProps = {
457
- isInitiallyDisabled: true
458
- };
459
-
460
- exports.SlugEditor = SlugEditor;
461
- exports.makeSlug = makeSlug;
462
- exports.slugify = slugify;
463
- //# sourceMappingURL=field-editor-slug.cjs.development.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"field-editor-slug.cjs.development.js","sources":["../src/services/slugify.ts","../src/services/makeSlug.ts","../src/styles.ts","../src/SlugEditorField.tsx","../src/TrackingFieldConnector.tsx","../src/SlugEditor.tsx"],"sourcesContent":["import getSlug from 'speakingurl';\n\nconst CF_GENERATED_SLUG_MAX_LENGTH = 75;\n\nconst languages = [\n 'ar',\n 'az',\n 'cs',\n 'de',\n 'dv',\n 'en',\n 'es',\n 'fa',\n 'fi',\n 'fr',\n 'ge',\n 'gr',\n 'hu',\n 'it',\n 'lt',\n 'lv',\n 'my',\n 'mk',\n 'nl',\n 'pl',\n 'pt',\n 'ro',\n 'ru',\n 'sk',\n 'sr',\n 'tr',\n 'uk',\n 'vn',\n];\n\n/**\n * Extracts the first two lowercased characters from the locale,\n * and returns the supported language prefix.\n */\nfunction supportedLanguage(locale: string) {\n const prefix = locale.slice(0, 2).toLowerCase();\n return languages[languages.indexOf(prefix)];\n}\n\n/**\n * Returns the slug for a given string and locale.\n * If the locale belongs to a language supported by SpeakingURL, it\n * is used as the symbol language. Otherwise, the symbol language\n * is english.\n * Slug suggestions are limited to 75 characters.\n *\n * @param {string} text To be turned into a slug.\n * @param {string?} locale\n * @returns {string} Slug for provided text.\n */\nexport function slugify(text: string, locale = 'en') {\n return getSlug(text, {\n separator: '-',\n lang: supportedLanguage(locale) || 'en',\n truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,\n custom: {\n \"'\": '',\n '`': '',\n '’': '',\n '‘': '',\n },\n });\n}\n","import { slugify } from './slugify';\n\ntype MakeSlugOptions = {\n locale: string;\n isOptionalLocaleWithFallback: boolean;\n createdAt: string;\n};\n\nfunction formatTwoDigit(num: number) {\n const asString = String(num);\n return asString.length === 1 ? `0${asString}` : asString;\n}\n\nexport function formatUtcDate(date: Date) {\n const year = date.getFullYear();\n const month = formatTwoDigit(date.getUTCMonth() + 1);\n const day = formatTwoDigit(date.getUTCDate());\n const hour = formatTwoDigit(date.getUTCHours());\n const minutes = formatTwoDigit(date.getUTCMinutes());\n const seconds = formatTwoDigit(date.getUTCSeconds());\n\n return `${year} ${month} ${day} at ${hour} ${minutes} ${seconds}`;\n}\n\nfunction untitledSlug({ isOptionalLocaleWithFallback, createdAt }: MakeSlugOptions) {\n if (isOptionalLocaleWithFallback) {\n return ''; // Will result in `undefined` slug.\n }\n\n const createdAtFormatted = formatUtcDate(new Date(createdAt));\n return slugify('Untitled entry ' + createdAtFormatted, 'en-US');\n}\n\nexport function makeSlug(title: string | null | undefined, options: MakeSlugOptions) {\n return title ? slugify(title, options.locale) : untitledSlug(options);\n}\n","import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const validationRow = css({\n display: 'flex',\n flexDirection: 'row-reverse',\n fontSize: tokens.fontSizeM,\n marginTop: tokens.spacingXs,\n color: tokens.gray700,\n});\n\nexport const inputContainer = css({\n position: 'relative',\n});\n\nexport const input = css({\n paddingLeft: '40px',\n});\n\nexport const icon = css({\n position: 'absolute',\n left: '10px',\n top: '8px',\n zIndex: 2,\n width: '25px',\n height: '25px',\n fill: tokens.gray500,\n});\n\nexport const spinnerContainer = css({\n position: 'absolute',\n zIndex: 2,\n right: '8px',\n top: '8px',\n});\n\nexport const uniqueValidationError = css({\n marginTop: tokens.spacingS,\n});\n","import React from 'react';\n\nimport { Spinner, ValidationMessage, TextInput } from '@contentful/f36-components';\nimport { LinkIcon } from '@contentful/f36-icons';\nimport { useDebounce } from 'use-debounce';\n\nimport { makeSlug } from './services/makeSlug';\nimport * as styles from './styles';\n\n\n\ninterface SlugEditorFieldProps {\n hasError: boolean;\n isOptionalLocaleWithFallback: boolean;\n isDisabled: boolean;\n value: string | null | undefined;\n locale: string;\n titleValue: string | null | undefined;\n createdAt: string;\n setValue: (value: string | null | undefined) => void;\n performUniqueCheck: (value: string) => Promise<boolean>;\n}\n\ntype CheckerState = 'checking' | 'unique' | 'duplicate';\n\nfunction useSlugUpdater(props: SlugEditorFieldProps, check: boolean) {\n const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;\n\n React.useEffect(() => {\n if (check === false) {\n return;\n }\n const newSlug = makeSlug(titleValue, {\n isOptionalLocaleWithFallback,\n locale,\n createdAt,\n });\n if (newSlug !== value) {\n setValue(newSlug);\n }\n }, [value, titleValue, isOptionalLocaleWithFallback, check, createdAt, locale, setValue]);\n}\n\nfunction useUniqueChecker(props: SlugEditorFieldProps) {\n const { performUniqueCheck } = props;\n const [status, setStatus] = React.useState<CheckerState>(props.value ? 'checking' : 'unique');\n const [debouncedValue] = useDebounce(props.value, 1000);\n\n /**\n * Check the uniqueness of the slug in the current space.\n * The slug is unique if there is no published entry other than the\n * current one, with the same slug.\n */\n React.useEffect(() => {\n if (!debouncedValue) {\n setStatus('unique');\n return;\n }\n setStatus('checking');\n performUniqueCheck(debouncedValue)\n .then((unique) => {\n setStatus(unique ? 'unique' : 'duplicate');\n })\n .catch(() => {\n setStatus('checking');\n });\n }, [debouncedValue, performUniqueCheck]);\n\n return status;\n}\n\nexport function SlugEditorFieldStatic(\n props: SlugEditorFieldProps & { onChange?: Function; onBlur?: Function }\n) {\n const { hasError, isDisabled, value, setValue, onChange, onBlur } = props;\n\n const status = useUniqueChecker(props);\n\n return (\n <div className={styles.inputContainer}>\n <LinkIcon className={styles.icon} />\n <TextInput\n className={styles.input}\n isInvalid={hasError || status === 'duplicate'}\n isDisabled={isDisabled}\n value={value || ''}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setValue(e.target.value);\n if (onChange) {\n onChange();\n }\n }}\n onBlur={() => {\n if (onBlur) {\n onBlur();\n }\n }}\n />\n {status === 'checking' && (\n <div className={styles.spinnerContainer}>\n <Spinner testId=\"slug-editor-spinner\" />\n </div>\n )}\n {status === 'duplicate' && (\n <ValidationMessage\n testId=\"slug-editor-duplicate-error\"\n className={styles.uniqueValidationError}>\n This slug has already been published in another entry\n </ValidationMessage>\n )}\n </div>\n );\n}\n\nexport function SlugEditorField(props: SlugEditorFieldProps) {\n const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;\n\n const areEqual = React.useCallback(() => {\n const potentialSlug = makeSlug(titleValue, {\n isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,\n locale: locale,\n createdAt: createdAt,\n });\n return value === potentialSlug;\n }, [titleValue, isOptionalLocaleWithFallback, locale, createdAt, value]);\n\n const [check, setCheck] = React.useState<boolean>(() => {\n if (props.value) {\n if (!props.titleValue) {\n return false;\n }\n return areEqual();\n }\n return true;\n });\n\n React.useEffect(() => {\n if (areEqual()) {\n setCheck(true);\n }\n }, [props.titleValue, areEqual]);\n\n useSlugUpdater(props, check);\n\n return (\n <SlugEditorFieldStatic\n {...props}\n onChange={() => {\n setCheck(false);\n }}\n onBlur={() => {\n if (areEqual()) {\n setCheck(true);\n }\n }}\n />\n );\n}\n","import React from 'react';\n\nimport { FieldExtensionSDK, FieldAPI } from '@contentful/app-sdk';\n\ntype Nullable = null | undefined;\n\ninterface TrackingFieldConnectorState<ValueType> {\n titleValue: ValueType | Nullable;\n isPublished: boolean;\n isSame: boolean;\n}\n\ninterface TrackingFieldConnectorProps<ValueType> {\n sdk: FieldExtensionSDK;\n field: FieldAPI;\n defaultLocale: string;\n trackingFieldId?: string;\n isOptionalLocaleWithFallback: boolean;\n children: (state: TrackingFieldConnectorState<ValueType>) => React.ReactNode;\n}\n\nfunction getTitleField(sdk: FieldExtensionSDK, trackingFieldId?: string) {\n const { entry, contentType } = sdk;\n if (trackingFieldId && entry.fields[trackingFieldId]) {\n return entry.fields[trackingFieldId];\n }\n return entry.fields[contentType.displayField];\n}\n\nexport class TrackingFieldConnector<ValueType> extends React.Component<\n TrackingFieldConnectorProps<ValueType>,\n TrackingFieldConnectorState<ValueType>\n> {\n static defaultProps = {\n children: () => {\n return null;\n },\n };\n\n constructor(props: TrackingFieldConnectorProps<ValueType>) {\n super(props);\n const titleField = getTitleField(props.sdk, props.trackingFieldId);\n const entrySys = props.sdk.entry.getSys();\n const isSame = titleField ? props.field.id === titleField.id : false;\n this.state = {\n titleValue: titleField ? titleField.getValue() : '',\n isPublished: Boolean(entrySys.publishedVersion),\n isSame,\n };\n }\n\n unsubscribeValue: Function | null = null;\n unsubscribeLocalizedValue: Function | null = null;\n unsubscribeSysChanges: Function | null = null;\n\n componentDidMount() {\n this.unsubscribeSysChanges = this.props.sdk.entry.onSysChanged((sys) => {\n this.setState({\n isPublished: Boolean(sys.publishedVersion),\n });\n });\n\n const titleField = getTitleField(this.props.sdk, this.props.trackingFieldId);\n\n // the content type's display field might not exist\n if (!titleField) {\n return;\n }\n\n if (!this.state.isSame) {\n this.unsubscribeLocalizedValue = titleField.onValueChanged(\n this.props.field.locale,\n (value: ValueType | Nullable) => {\n this.setState({ titleValue: value });\n }\n );\n }\n\n if (this.props.field.locale !== this.props.defaultLocale) {\n if (!this.props.isOptionalLocaleWithFallback) {\n this.unsubscribeValue = titleField.onValueChanged(\n this.props.defaultLocale,\n (value: ValueType | Nullable) => {\n if (!titleField.getValue(this.props.field.locale)) {\n this.setState({ titleValue: value });\n }\n }\n );\n }\n }\n }\n\n componentWillUnmount() {\n if (typeof this.unsubscribeValue === 'function') {\n this.unsubscribeValue();\n }\n if (typeof this.unsubscribeLocalizedValue === 'function') {\n this.unsubscribeLocalizedValue();\n }\n if (typeof this.unsubscribeSysChanges === 'function') {\n this.unsubscribeSysChanges();\n }\n }\n\n render() {\n return this.props.children({\n ...this.state,\n });\n }\n}\n","import * as React from 'react';\n\nimport { FieldExtensionSDK, FieldAPI, ValidationError } from '@contentful/app-sdk';\nimport { FieldConnector } from '@contentful/field-editor-shared';\n\nimport { SlugEditorField, SlugEditorFieldStatic } from './SlugEditorField';\nimport { TrackingFieldConnector } from './TrackingFieldConnector';\n\nexport interface SlugEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n baseSdk: FieldExtensionSDK;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n\n parameters?: {\n instance: {\n trackingFieldId?: string;\n };\n };\n}\n\nfunction isSupportedFieldTypes(val: string): val is 'Symbol' {\n return val === 'Symbol';\n}\n\nfunction FieldConnectorCallback({\n Component,\n value,\n disabled,\n setValue,\n errors,\n titleValue,\n isOptionalLocaleWithFallback,\n locale,\n createdAt,\n performUniqueCheck,\n}: {\n Component: typeof SlugEditorFieldStatic | typeof SlugEditorField;\n value: string | null | undefined;\n disabled: boolean;\n titleValue: string | null | undefined;\n setValue: (value: string | null | undefined) => Promise<unknown>;\n errors: ValidationError[];\n isOptionalLocaleWithFallback: boolean;\n locale: FieldAPI['locale'];\n createdAt: string;\n performUniqueCheck: (value: string) => Promise<boolean>;\n}) {\n // it is needed to silent permission errors\n // this happens when setValue is called on a field which is disabled for permission reasons\n const safeSetValue = React.useCallback(\n async (...args: Parameters<typeof setValue>) => {\n try {\n await setValue(...args);\n } catch (e) {\n // do nothing\n }\n },\n [setValue]\n );\n\n return (\n <div data-test-id=\"slug-editor\">\n <Component\n locale={locale}\n createdAt={createdAt}\n performUniqueCheck={performUniqueCheck}\n hasError={errors.length > 0}\n value={value}\n isOptionalLocaleWithFallback={isOptionalLocaleWithFallback}\n isDisabled={disabled}\n titleValue={titleValue}\n setValue={safeSetValue}\n />\n </div>\n );\n}\n\nexport function SlugEditor(props: SlugEditorProps) {\n const { field, parameters } = props;\n const { locales, entry, space } = props.baseSdk;\n\n if (!isSupportedFieldTypes(field.type)) {\n throw new Error(`\"${field.type}\" field type is not supported by SlugEditor`);\n }\n\n const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;\n const entrySys = entry.getSys();\n\n const isLocaleOptional = locales.optional[field.locale];\n const localeFallbackCode = locales.fallbacks[field.locale];\n\n // If the field or the locale are not required (there's a locale setting that\n // allows publishing even if the field is required) and if the locale has a\n // fallback than there's no need for a slug unless the user manually enters\n // one or the title field is also localized with a custom value.\n const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);\n const isOptionalLocaleWithFallback = Boolean(\n isOptionalFieldLocale && localeFallbackCode && locales.available.includes(localeFallbackCode)\n );\n\n const performUniqueCheck = React.useCallback(\n (value: string) => {\n const searchQuery = {\n content_type: entrySys?.contentType?.sys?.id,\n [`fields.${field.id}.${field.locale}`]: value,\n 'sys.id[ne]': entrySys.id,\n 'sys.publishedAt[exists]': true,\n limit: 0,\n };\n return space.getEntries(searchQuery).then((res) => {\n return res.total === 0;\n });\n },\n [entrySys?.contentType?.sys?.id, field.id, field.locale, entrySys.id, space]\n );\n\n return (\n <TrackingFieldConnector<string>\n sdk={props.baseSdk}\n field={field}\n defaultLocale={locales.default}\n isOptionalLocaleWithFallback={isOptionalLocaleWithFallback}\n trackingFieldId={trackingFieldId}>\n {({ titleValue, isPublished, isSame }) => (\n <FieldConnector<string>\n field={field}\n isInitiallyDisabled={props.isInitiallyDisabled}\n throttle={0}>\n {({ value, errors, disabled, setValue, externalReset }) => {\n const shouldTrackTitle = isPublished === false && isSame === false;\n\n const Component = shouldTrackTitle ? SlugEditorField : SlugEditorFieldStatic;\n\n return (\n <FieldConnectorCallback\n Component={Component}\n titleValue={titleValue}\n value={value}\n errors={errors}\n disabled={disabled}\n setValue={setValue}\n isOptionalLocaleWithFallback={isOptionalLocaleWithFallback}\n createdAt={entrySys.createdAt}\n locale={field.locale}\n performUniqueCheck={performUniqueCheck}\n key={`slug-editor-${externalReset}`}\n />\n );\n }}\n </FieldConnector>\n )}\n </TrackingFieldConnector>\n );\n}\n\nSlugEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n"],"names":["CF_GENERATED_SLUG_MAX_LENGTH","languages","supportedLanguage","locale","prefix","slice","toLowerCase","indexOf","slugify","text","getSlug","separator","lang","truncate","custom","formatTwoDigit","num","asString","String","length","formatUtcDate","date","year","getFullYear","month","getUTCMonth","day","getUTCDate","hour","getUTCHours","minutes","getUTCMinutes","seconds","getUTCSeconds","untitledSlug","isOptionalLocaleWithFallback","createdAt","createdAtFormatted","Date","makeSlug","title","options","inputContainer","css","position","input","paddingLeft","icon","left","top","zIndex","width","height","fill","tokens","gray500","spinnerContainer","right","uniqueValidationError","marginTop","spacingS","useSlugUpdater","props","check","value","setValue","titleValue","React","useEffect","newSlug","useUniqueChecker","performUniqueCheck","status","setStatus","useState","debouncedValue","useDebounce","then","unique","catch","SlugEditorFieldStatic","hasError","isDisabled","onChange","onBlur","className","styles","LinkIcon","TextInput","isInvalid","e","target","Spinner","testId","ValidationMessage","SlugEditorField","areEqual","useCallback","potentialSlug","setCheck","getTitleField","sdk","trackingFieldId","entry","contentType","fields","displayField","TrackingFieldConnector","Component","constructor","unsubscribeValue","unsubscribeLocalizedValue","unsubscribeSysChanges","titleField","entrySys","getSys","isSame","field","id","state","getValue","isPublished","Boolean","publishedVersion","componentDidMount","onSysChanged","sys","setState","onValueChanged","defaultLocale","componentWillUnmount","render","children","defaultProps","isSupportedFieldTypes","val","FieldConnectorCallback","disabled","errors","safeSetValue","args","SlugEditor","parameters","locales","space","baseSdk","type","Error","instance","undefined","isLocaleOptional","optional","localeFallbackCode","fallbacks","isOptionalFieldLocale","required","available","includes","searchQuery","content_type","limit","getEntries","res","total","default","FieldConnector","isInitiallyDisabled","throttle","externalReset","shouldTrackTitle","key"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var t=require("react"),l=e(t),i=require("@contentful/field-editor-shared"),s=require("@contentful/f36-components"),a=require("@contentful/f36-icons"),n=require("use-debounce"),o=e(require("speakingurl")),r=e(require("@contentful/f36-tokens")),u=require("emotion");const c=["ar","az","cs","de","dv","en","es","fa","fi","fr","ge","gr","hu","it","lt","lv","my","mk","nl","pl","pt","ro","ru","sk","sr","tr","uk","vn"];function d(e){const t=e.slice(0,2).toLowerCase();return c[c.indexOf(t)]}function p(e,t="en"){return o(e,{separator:"-",lang:d(t)||"en",truncate:76,custom:{"'":"","`":"","’":"","‘":""}})}function h(e){const t=String(e);return 1===t.length?"0"+t:t}function f(e,t){return e?p(e,t.locale):function({isOptionalLocaleWithFallback:e,createdAt:t}){return e?"":p(`Untitled entry ${(l=new Date(t)).getFullYear()} ${h(l.getUTCMonth()+1)} ${h(l.getUTCDate())} at ${h(l.getUTCHours())} ${h(l.getUTCMinutes())} ${h(l.getUTCSeconds())}`,"en-US");var l}(t)}const b=u.css({position:"relative"}),g=u.css({paddingLeft:"40px"}),y=u.css({position:"absolute",left:"10px",top:"8px",zIndex:2,width:"25px",height:"25px",fill:r.gray500}),k=u.css({position:"absolute",zIndex:2,right:"8px",top:"8px"}),m=u.css({marginTop:r.spacingS});function V(e){const{hasError:t,isDisabled:i,value:o,setValue:r,onChange:u,onBlur:c}=e,d=function(e){const{performUniqueCheck:t}=e,[i,s]=l.useState(e.value?"checking":"unique"),[a]=n.useDebounce(e.value,1e3);return l.useEffect(()=>{a?(s("checking"),t(a).then(e=>{s(e?"unique":"duplicate")}).catch(()=>{s("checking")})):s("unique")},[a,t]),i}(e);return l.createElement("div",{className:b},l.createElement(a.LinkIcon,{className:y}),l.createElement(s.TextInput,{className:g,isInvalid:t||"duplicate"===d,isDisabled:i,value:o||"",onChange:e=>{r(e.target.value),u&&u()},onBlur:()=>{c&&c()}}),"checking"===d&&l.createElement("div",{className:k},l.createElement(s.Spinner,{testId:"slug-editor-spinner"})),"duplicate"===d&&l.createElement(s.ValidationMessage,{testId:"slug-editor-duplicate-error",className:m},"This slug has already been published in another entry"))}function v(e){const{titleValue:t,isOptionalLocaleWithFallback:i,locale:s,createdAt:a,value:n}=e,o=l.useCallback(()=>{const e=f(t,{isOptionalLocaleWithFallback:i,locale:s,createdAt:a});return n===e},[t,i,s,a,n]),[r,u]=l.useState(()=>!e.value||!!e.titleValue&&o());return l.useEffect(()=>{o()&&u(!0)},[e.titleValue,o]),function(e,t){const{value:i,setValue:s,createdAt:a,locale:n,titleValue:o,isOptionalLocaleWithFallback:r}=e;l.useEffect(()=>{if(!1===t)return;const e=f(o,{isOptionalLocaleWithFallback:r,locale:n,createdAt:a});e!==i&&s(e)},[i,o,r,t,a,n,s])}(e,r),l.createElement(V,{...e,onChange:()=>{u(!1)},onBlur:()=>{o()&&u(!0)}})}function C(e,t){const{entry:l,contentType:i}=e;return t&&l.fields[t]?l.fields[t]:l.fields[i.displayField]}class S extends l.Component{constructor(e){super(e),this.unsubscribeValue=null,this.unsubscribeLocalizedValue=null,this.unsubscribeSysChanges=null;const t=C(e.sdk,e.trackingFieldId),l=e.sdk.entry.getSys(),i=!!t&&e.field.id===t.id;this.state={titleValue:t?t.getValue():"",isPublished:Boolean(l.publishedVersion),isSame:i}}componentDidMount(){this.unsubscribeSysChanges=this.props.sdk.entry.onSysChanged(e=>{this.setState({isPublished:Boolean(e.publishedVersion)})});const e=C(this.props.sdk,this.props.trackingFieldId);e&&(this.state.isSame||(this.unsubscribeLocalizedValue=e.onValueChanged(this.props.field.locale,e=>{this.setState({titleValue:e})})),this.props.field.locale!==this.props.defaultLocale&&(this.props.isOptionalLocaleWithFallback||(this.unsubscribeValue=e.onValueChanged(this.props.defaultLocale,t=>{e.getValue(this.props.field.locale)||this.setState({titleValue:t})}))))}componentWillUnmount(){"function"==typeof this.unsubscribeValue&&this.unsubscribeValue(),"function"==typeof this.unsubscribeLocalizedValue&&this.unsubscribeLocalizedValue(),"function"==typeof this.unsubscribeSysChanges&&this.unsubscribeSysChanges()}render(){return this.props.children({...this.state})}}function E({Component:e,value:l,disabled:i,setValue:s,errors:a,titleValue:n,isOptionalLocaleWithFallback:o,locale:r,createdAt:u,performUniqueCheck:c}){const d=t.useCallback(async(...e)=>{try{await s(...e)}catch(e){}},[s]);return t.createElement("div",{"data-test-id":"slug-editor"},t.createElement(e,{locale:r,createdAt:u,performUniqueCheck:c,hasError:a.length>0,value:l,isOptionalLocaleWithFallback:o,isDisabled:i,titleValue:n,setValue:d}))}function L(e){var l,s,a;const{field:n,parameters:o}=e,{locales:r,entry:u,space:c}=e.baseSdk;if("Symbol"!==n.type)throw new Error(`"${n.type}" field type is not supported by SlugEditor`);const d=(null==o||null==(l=o.instance)?void 0:l.trackingFieldId)??void 0,p=u.getSys(),h=r.fallbacks[n.locale],f=Boolean(!n.required||r.optional[n.locale]),b=Boolean(f&&h&&r.available.includes(h)),g=t.useCallback(e=>{var t,l;const i={content_type:null==p||null==(t=p.contentType)||null==(l=t.sys)?void 0:l.id,[`fields.${n.id}.${n.locale}`]:e,"sys.id[ne]":p.id,"sys.publishedAt[exists]":!0,limit:0};return c.getEntries(i).then(e=>0===e.total)},[null==p||null==(s=p.contentType)||null==(a=s.sys)?void 0:a.id,n.id,n.locale,p.id,c]);return t.createElement(S,{sdk:e.baseSdk,field:n,defaultLocale:r.default,isOptionalLocaleWithFallback:b,trackingFieldId:d},({titleValue:l,isPublished:s,isSame:a})=>t.createElement(i.FieldConnector,{field:n,isInitiallyDisabled:e.isInitiallyDisabled,throttle:0},({value:e,errors:i,disabled:o,setValue:r,externalReset:u})=>t.createElement(E,{Component:!1===s&&!1===a?v:V,titleValue:l,value:e,errors:i,disabled:o,setValue:r,isOptionalLocaleWithFallback:b,createdAt:p.createdAt,locale:n.locale,performUniqueCheck:g,key:"slug-editor-"+u})))}S.defaultProps={children:()=>null},L.defaultProps={isInitiallyDisabled:!0},exports.SlugEditor=L,exports.makeSlug=f,exports.slugify=p;
2
- //# sourceMappingURL=field-editor-slug.cjs.production.min.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"field-editor-slug.cjs.production.min.js","sources":["../src/services/slugify.ts","../src/services/makeSlug.ts","../src/styles.ts","../src/SlugEditorField.tsx","../src/TrackingFieldConnector.tsx","../src/SlugEditor.tsx"],"sourcesContent":["import getSlug from 'speakingurl';\n\nconst CF_GENERATED_SLUG_MAX_LENGTH = 75;\n\nconst languages = [\n 'ar',\n 'az',\n 'cs',\n 'de',\n 'dv',\n 'en',\n 'es',\n 'fa',\n 'fi',\n 'fr',\n 'ge',\n 'gr',\n 'hu',\n 'it',\n 'lt',\n 'lv',\n 'my',\n 'mk',\n 'nl',\n 'pl',\n 'pt',\n 'ro',\n 'ru',\n 'sk',\n 'sr',\n 'tr',\n 'uk',\n 'vn',\n];\n\n/**\n * Extracts the first two lowercased characters from the locale,\n * and returns the supported language prefix.\n */\nfunction supportedLanguage(locale: string) {\n const prefix = locale.slice(0, 2).toLowerCase();\n return languages[languages.indexOf(prefix)];\n}\n\n/**\n * Returns the slug for a given string and locale.\n * If the locale belongs to a language supported by SpeakingURL, it\n * is used as the symbol language. Otherwise, the symbol language\n * is english.\n * Slug suggestions are limited to 75 characters.\n *\n * @param {string} text To be turned into a slug.\n * @param {string?} locale\n * @returns {string} Slug for provided text.\n */\nexport function slugify(text: string, locale = 'en') {\n return getSlug(text, {\n separator: '-',\n lang: supportedLanguage(locale) || 'en',\n truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,\n custom: {\n \"'\": '',\n '`': '',\n '’': '',\n '‘': '',\n },\n });\n}\n","import { slugify } from './slugify';\n\ntype MakeSlugOptions = {\n locale: string;\n isOptionalLocaleWithFallback: boolean;\n createdAt: string;\n};\n\nfunction formatTwoDigit(num: number) {\n const asString = String(num);\n return asString.length === 1 ? `0${asString}` : asString;\n}\n\nexport function formatUtcDate(date: Date) {\n const year = date.getFullYear();\n const month = formatTwoDigit(date.getUTCMonth() + 1);\n const day = formatTwoDigit(date.getUTCDate());\n const hour = formatTwoDigit(date.getUTCHours());\n const minutes = formatTwoDigit(date.getUTCMinutes());\n const seconds = formatTwoDigit(date.getUTCSeconds());\n\n return `${year} ${month} ${day} at ${hour} ${minutes} ${seconds}`;\n}\n\nfunction untitledSlug({ isOptionalLocaleWithFallback, createdAt }: MakeSlugOptions) {\n if (isOptionalLocaleWithFallback) {\n return ''; // Will result in `undefined` slug.\n }\n\n const createdAtFormatted = formatUtcDate(new Date(createdAt));\n return slugify('Untitled entry ' + createdAtFormatted, 'en-US');\n}\n\nexport function makeSlug(title: string | null | undefined, options: MakeSlugOptions) {\n return title ? slugify(title, options.locale) : untitledSlug(options);\n}\n","import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const validationRow = css({\n display: 'flex',\n flexDirection: 'row-reverse',\n fontSize: tokens.fontSizeM,\n marginTop: tokens.spacingXs,\n color: tokens.gray700,\n});\n\nexport const inputContainer = css({\n position: 'relative',\n});\n\nexport const input = css({\n paddingLeft: '40px',\n});\n\nexport const icon = css({\n position: 'absolute',\n left: '10px',\n top: '8px',\n zIndex: 2,\n width: '25px',\n height: '25px',\n fill: tokens.gray500,\n});\n\nexport const spinnerContainer = css({\n position: 'absolute',\n zIndex: 2,\n right: '8px',\n top: '8px',\n});\n\nexport const uniqueValidationError = css({\n marginTop: tokens.spacingS,\n});\n","import React from 'react';\n\nimport { Spinner, ValidationMessage, TextInput } from '@contentful/f36-components';\nimport { LinkIcon } from '@contentful/f36-icons';\nimport { useDebounce } from 'use-debounce';\n\nimport { makeSlug } from './services/makeSlug';\nimport * as styles from './styles';\n\n\n\ninterface SlugEditorFieldProps {\n hasError: boolean;\n isOptionalLocaleWithFallback: boolean;\n isDisabled: boolean;\n value: string | null | undefined;\n locale: string;\n titleValue: string | null | undefined;\n createdAt: string;\n setValue: (value: string | null | undefined) => void;\n performUniqueCheck: (value: string) => Promise<boolean>;\n}\n\ntype CheckerState = 'checking' | 'unique' | 'duplicate';\n\nfunction useSlugUpdater(props: SlugEditorFieldProps, check: boolean) {\n const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;\n\n React.useEffect(() => {\n if (check === false) {\n return;\n }\n const newSlug = makeSlug(titleValue, {\n isOptionalLocaleWithFallback,\n locale,\n createdAt,\n });\n if (newSlug !== value) {\n setValue(newSlug);\n }\n }, [value, titleValue, isOptionalLocaleWithFallback, check, createdAt, locale, setValue]);\n}\n\nfunction useUniqueChecker(props: SlugEditorFieldProps) {\n const { performUniqueCheck } = props;\n const [status, setStatus] = React.useState<CheckerState>(props.value ? 'checking' : 'unique');\n const [debouncedValue] = useDebounce(props.value, 1000);\n\n /**\n * Check the uniqueness of the slug in the current space.\n * The slug is unique if there is no published entry other than the\n * current one, with the same slug.\n */\n React.useEffect(() => {\n if (!debouncedValue) {\n setStatus('unique');\n return;\n }\n setStatus('checking');\n performUniqueCheck(debouncedValue)\n .then((unique) => {\n setStatus(unique ? 'unique' : 'duplicate');\n })\n .catch(() => {\n setStatus('checking');\n });\n }, [debouncedValue, performUniqueCheck]);\n\n return status;\n}\n\nexport function SlugEditorFieldStatic(\n props: SlugEditorFieldProps & { onChange?: Function; onBlur?: Function }\n) {\n const { hasError, isDisabled, value, setValue, onChange, onBlur } = props;\n\n const status = useUniqueChecker(props);\n\n return (\n <div className={styles.inputContainer}>\n <LinkIcon className={styles.icon} />\n <TextInput\n className={styles.input}\n isInvalid={hasError || status === 'duplicate'}\n isDisabled={isDisabled}\n value={value || ''}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setValue(e.target.value);\n if (onChange) {\n onChange();\n }\n }}\n onBlur={() => {\n if (onBlur) {\n onBlur();\n }\n }}\n />\n {status === 'checking' && (\n <div className={styles.spinnerContainer}>\n <Spinner testId=\"slug-editor-spinner\" />\n </div>\n )}\n {status === 'duplicate' && (\n <ValidationMessage\n testId=\"slug-editor-duplicate-error\"\n className={styles.uniqueValidationError}>\n This slug has already been published in another entry\n </ValidationMessage>\n )}\n </div>\n );\n}\n\nexport function SlugEditorField(props: SlugEditorFieldProps) {\n const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;\n\n const areEqual = React.useCallback(() => {\n const potentialSlug = makeSlug(titleValue, {\n isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,\n locale: locale,\n createdAt: createdAt,\n });\n return value === potentialSlug;\n }, [titleValue, isOptionalLocaleWithFallback, locale, createdAt, value]);\n\n const [check, setCheck] = React.useState<boolean>(() => {\n if (props.value) {\n if (!props.titleValue) {\n return false;\n }\n return areEqual();\n }\n return true;\n });\n\n React.useEffect(() => {\n if (areEqual()) {\n setCheck(true);\n }\n }, [props.titleValue, areEqual]);\n\n useSlugUpdater(props, check);\n\n return (\n <SlugEditorFieldStatic\n {...props}\n onChange={() => {\n setCheck(false);\n }}\n onBlur={() => {\n if (areEqual()) {\n setCheck(true);\n }\n }}\n />\n );\n}\n","import React from 'react';\n\nimport { FieldExtensionSDK, FieldAPI } from '@contentful/app-sdk';\n\ntype Nullable = null | undefined;\n\ninterface TrackingFieldConnectorState<ValueType> {\n titleValue: ValueType | Nullable;\n isPublished: boolean;\n isSame: boolean;\n}\n\ninterface TrackingFieldConnectorProps<ValueType> {\n sdk: FieldExtensionSDK;\n field: FieldAPI;\n defaultLocale: string;\n trackingFieldId?: string;\n isOptionalLocaleWithFallback: boolean;\n children: (state: TrackingFieldConnectorState<ValueType>) => React.ReactNode;\n}\n\nfunction getTitleField(sdk: FieldExtensionSDK, trackingFieldId?: string) {\n const { entry, contentType } = sdk;\n if (trackingFieldId && entry.fields[trackingFieldId]) {\n return entry.fields[trackingFieldId];\n }\n return entry.fields[contentType.displayField];\n}\n\nexport class TrackingFieldConnector<ValueType> extends React.Component<\n TrackingFieldConnectorProps<ValueType>,\n TrackingFieldConnectorState<ValueType>\n> {\n static defaultProps = {\n children: () => {\n return null;\n },\n };\n\n constructor(props: TrackingFieldConnectorProps<ValueType>) {\n super(props);\n const titleField = getTitleField(props.sdk, props.trackingFieldId);\n const entrySys = props.sdk.entry.getSys();\n const isSame = titleField ? props.field.id === titleField.id : false;\n this.state = {\n titleValue: titleField ? titleField.getValue() : '',\n isPublished: Boolean(entrySys.publishedVersion),\n isSame,\n };\n }\n\n unsubscribeValue: Function | null = null;\n unsubscribeLocalizedValue: Function | null = null;\n unsubscribeSysChanges: Function | null = null;\n\n componentDidMount() {\n this.unsubscribeSysChanges = this.props.sdk.entry.onSysChanged((sys) => {\n this.setState({\n isPublished: Boolean(sys.publishedVersion),\n });\n });\n\n const titleField = getTitleField(this.props.sdk, this.props.trackingFieldId);\n\n // the content type's display field might not exist\n if (!titleField) {\n return;\n }\n\n if (!this.state.isSame) {\n this.unsubscribeLocalizedValue = titleField.onValueChanged(\n this.props.field.locale,\n (value: ValueType | Nullable) => {\n this.setState({ titleValue: value });\n }\n );\n }\n\n if (this.props.field.locale !== this.props.defaultLocale) {\n if (!this.props.isOptionalLocaleWithFallback) {\n this.unsubscribeValue = titleField.onValueChanged(\n this.props.defaultLocale,\n (value: ValueType | Nullable) => {\n if (!titleField.getValue(this.props.field.locale)) {\n this.setState({ titleValue: value });\n }\n }\n );\n }\n }\n }\n\n componentWillUnmount() {\n if (typeof this.unsubscribeValue === 'function') {\n this.unsubscribeValue();\n }\n if (typeof this.unsubscribeLocalizedValue === 'function') {\n this.unsubscribeLocalizedValue();\n }\n if (typeof this.unsubscribeSysChanges === 'function') {\n this.unsubscribeSysChanges();\n }\n }\n\n render() {\n return this.props.children({\n ...this.state,\n });\n }\n}\n","import * as React from 'react';\n\nimport { FieldExtensionSDK, FieldAPI, ValidationError } from '@contentful/app-sdk';\nimport { FieldConnector } from '@contentful/field-editor-shared';\n\nimport { SlugEditorField, SlugEditorFieldStatic } from './SlugEditorField';\nimport { TrackingFieldConnector } from './TrackingFieldConnector';\n\nexport interface SlugEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n baseSdk: FieldExtensionSDK;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n\n parameters?: {\n instance: {\n trackingFieldId?: string;\n };\n };\n}\n\nfunction isSupportedFieldTypes(val: string): val is 'Symbol' {\n return val === 'Symbol';\n}\n\nfunction FieldConnectorCallback({\n Component,\n value,\n disabled,\n setValue,\n errors,\n titleValue,\n isOptionalLocaleWithFallback,\n locale,\n createdAt,\n performUniqueCheck,\n}: {\n Component: typeof SlugEditorFieldStatic | typeof SlugEditorField;\n value: string | null | undefined;\n disabled: boolean;\n titleValue: string | null | undefined;\n setValue: (value: string | null | undefined) => Promise<unknown>;\n errors: ValidationError[];\n isOptionalLocaleWithFallback: boolean;\n locale: FieldAPI['locale'];\n createdAt: string;\n performUniqueCheck: (value: string) => Promise<boolean>;\n}) {\n // it is needed to silent permission errors\n // this happens when setValue is called on a field which is disabled for permission reasons\n const safeSetValue = React.useCallback(\n async (...args: Parameters<typeof setValue>) => {\n try {\n await setValue(...args);\n } catch (e) {\n // do nothing\n }\n },\n [setValue]\n );\n\n return (\n <div data-test-id=\"slug-editor\">\n <Component\n locale={locale}\n createdAt={createdAt}\n performUniqueCheck={performUniqueCheck}\n hasError={errors.length > 0}\n value={value}\n isOptionalLocaleWithFallback={isOptionalLocaleWithFallback}\n isDisabled={disabled}\n titleValue={titleValue}\n setValue={safeSetValue}\n />\n </div>\n );\n}\n\nexport function SlugEditor(props: SlugEditorProps) {\n const { field, parameters } = props;\n const { locales, entry, space } = props.baseSdk;\n\n if (!isSupportedFieldTypes(field.type)) {\n throw new Error(`\"${field.type}\" field type is not supported by SlugEditor`);\n }\n\n const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;\n const entrySys = entry.getSys();\n\n const isLocaleOptional = locales.optional[field.locale];\n const localeFallbackCode = locales.fallbacks[field.locale];\n\n // If the field or the locale are not required (there's a locale setting that\n // allows publishing even if the field is required) and if the locale has a\n // fallback than there's no need for a slug unless the user manually enters\n // one or the title field is also localized with a custom value.\n const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);\n const isOptionalLocaleWithFallback = Boolean(\n isOptionalFieldLocale && localeFallbackCode && locales.available.includes(localeFallbackCode)\n );\n\n const performUniqueCheck = React.useCallback(\n (value: string) => {\n const searchQuery = {\n content_type: entrySys?.contentType?.sys?.id,\n [`fields.${field.id}.${field.locale}`]: value,\n 'sys.id[ne]': entrySys.id,\n 'sys.publishedAt[exists]': true,\n limit: 0,\n };\n return space.getEntries(searchQuery).then((res) => {\n return res.total === 0;\n });\n },\n [entrySys?.contentType?.sys?.id, field.id, field.locale, entrySys.id, space]\n );\n\n return (\n <TrackingFieldConnector<string>\n sdk={props.baseSdk}\n field={field}\n defaultLocale={locales.default}\n isOptionalLocaleWithFallback={isOptionalLocaleWithFallback}\n trackingFieldId={trackingFieldId}>\n {({ titleValue, isPublished, isSame }) => (\n <FieldConnector<string>\n field={field}\n isInitiallyDisabled={props.isInitiallyDisabled}\n throttle={0}>\n {({ value, errors, disabled, setValue, externalReset }) => {\n const shouldTrackTitle = isPublished === false && isSame === false;\n\n const Component = shouldTrackTitle ? SlugEditorField : SlugEditorFieldStatic;\n\n return (\n <FieldConnectorCallback\n Component={Component}\n titleValue={titleValue}\n value={value}\n errors={errors}\n disabled={disabled}\n setValue={setValue}\n isOptionalLocaleWithFallback={isOptionalLocaleWithFallback}\n createdAt={entrySys.createdAt}\n locale={field.locale}\n performUniqueCheck={performUniqueCheck}\n key={`slug-editor-${externalReset}`}\n />\n );\n }}\n </FieldConnector>\n )}\n </TrackingFieldConnector>\n );\n}\n\nSlugEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n"],"names":["languages","supportedLanguage","locale","prefix","slice","toLowerCase","indexOf","slugify","text","getSlug","separator","lang","truncate","CF_GENERATED_SLUG_MAX_LENGTH","custom","formatTwoDigit","num","asString","String","length","makeSlug","title","options","isOptionalLocaleWithFallback","createdAt","date","Date","getFullYear","getUTCMonth","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","untitledSlug","inputContainer","css","position","input","paddingLeft","icon","left","top","zIndex","width","height","fill","tokens","gray500","spinnerContainer","right","uniqueValidationError","marginTop","spacingS","SlugEditorFieldStatic","props","hasError","isDisabled","value","setValue","onChange","onBlur","status","performUniqueCheck","setStatus","React","useState","debouncedValue","useDebounce","useEffect","then","unique","catch","useUniqueChecker","className","styles","LinkIcon","TextInput","isInvalid","e","target","Spinner","testId","ValidationMessage","SlugEditorField","titleValue","areEqual","useCallback","potentialSlug","check","setCheck","newSlug","useSlugUpdater","getTitleField","sdk","trackingFieldId","entry","contentType","fields","displayField","TrackingFieldConnector","Component","constructor","unsubscribeValue","unsubscribeLocalizedValue","unsubscribeSysChanges","titleField","entrySys","getSys","isSame","field","id","state","getValue","isPublished","Boolean","publishedVersion","componentDidMount","this","onSysChanged","sys","setState","onValueChanged","defaultLocale","componentWillUnmount","render","children","FieldConnectorCallback","disabled","errors","safeSetValue","async","args","SlugEditor","parameters","locales","space","baseSdk","type","Error","instance","undefined","localeFallbackCode","fallbacks","isOptionalFieldLocale","required","optional","available","includes","searchQuery","content_type","_entrySys$contentType","_entrySys$contentType2","limit","getEntries","res","total","_entrySys$contentType3","_entrySys$contentType4","default","FieldConnector","isInitiallyDisabled","throttle","externalReset","key","defaultProps"],"mappings":"kZAEA,MAEMA,EAAY,CAChB,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,MAOF,SAASC,EAAkBC,SACnBC,EAASD,EAAOE,MAAM,EAAG,GAAGC,qBAC3BL,EAAUA,EAAUM,QAAQH,aAcrBI,EAAQC,EAAcN,EAAS,aACtCO,EAAQD,EAAM,CACnBE,UAAW,IACXC,KAAMV,EAAkBC,IAAW,KACnCU,SAAUC,GACVC,OAAQ,KACD,OACA,OACA,OACA,MCxDX,SAASC,EAAeC,SAChBC,EAAWC,OAAOF,UACG,IAApBC,EAASE,WAAmBF,EAAaA,WAuBlCG,EAASC,EAAkCC,UAClDD,EAAQd,EAAQc,EAAOC,EAAQpB,QAVxC,UAAsBqB,6BAAEA,EAAFC,UAAgCA,WAChDD,EACK,GAIFhB,qBAjBqBkB,EAgBa,IAAIC,KAAKF,IAfhCG,iBACJZ,EAAeU,EAAKG,cAAgB,MACtCb,EAAeU,EAAKI,oBACnBd,EAAeU,EAAKK,kBACjBf,EAAeU,EAAKM,oBACpBhB,EAAeU,EAAKO,mBAWmB,aAjB3BP,EAqBoBQ,CAAaX,GCvBxD,MAAMY,EAAiBC,MAAI,CAChCC,SAAU,aAGCC,EAAQF,MAAI,CACvBG,YAAa,SAGFC,EAAOJ,MAAI,CACtBC,SAAU,WACVI,KAAM,OACNC,IAAK,MACLC,OAAQ,EACRC,MAAO,OACPC,OAAQ,OACRC,KAAMC,EAAOC,UAGFC,EAAmBb,MAAI,CAClCC,SAAU,WACVM,OAAQ,EACRO,MAAO,MACPR,IAAK,QAGMS,EAAwBf,MAAI,CACvCgB,UAAWL,EAAOM,oBCkCJC,EACdC,SAEMC,SAAEA,EAAFC,WAAYA,EAAZC,MAAwBA,EAAxBC,SAA+BA,EAA/BC,SAAyCA,EAAzCC,OAAmDA,GAAWN,EAE9DO,EAjCR,SAA0BP,SAClBQ,mBAAEA,GAAuBR,GACxBO,EAAQE,GAAaC,EAAMC,SAAuBX,EAAMG,MAAQ,WAAa,WAC7ES,GAAkBC,cAAYb,EAAMG,MAAO,YAOlDO,EAAMI,UAAU,KACTF,GAILH,EAAU,YACVD,EAAmBI,GAChBG,KAAMC,IACLP,EAAUO,EAAS,SAAW,eAE/BC,MAAM,KACLR,EAAU,eATZA,EAAU,WAWX,CAACG,EAAgBJ,IAEbD,EAQQW,CAAiBlB,UAG9BU,uBAAKS,UAAWC,GACdV,gBAACW,YAASF,UAAWC,IACrBV,gBAACY,aACCH,UAAWC,EACXG,UAAWtB,GAAuB,cAAXM,EACvBL,WAAYA,EACZC,MAAOA,GAAS,GAChBE,SAAWmB,IACTpB,EAASoB,EAAEC,OAAOtB,OACdE,GACFA,KAGJC,OAAQ,KACFA,GACFA,OAIM,aAAXC,GACCG,uBAAKS,UAAWC,GACdV,gBAACgB,WAAQC,OAAO,yBAGR,cAAXpB,GACCG,gBAACkB,qBACCD,OAAO,8BACPR,UAAWC,sEAQLS,EAAgB7B,SACxB8B,WAAEA,EAAF7D,6BAAcA,EAAdrB,OAA4CA,EAA5CsB,UAAoDA,EAApDiC,MAA+DA,GAAUH,EAEzE+B,EAAWrB,EAAMsB,YAAY,WAC3BC,EAAgBnE,EAASgE,EAAY,CACzC7D,6BAA8BA,EAC9BrB,OAAQA,EACRsB,UAAWA,WAENiC,IAAU8B,GAChB,CAACH,EAAY7D,EAA8BrB,EAAQsB,EAAWiC,KAE1D+B,EAAOC,GAAYzB,EAAMC,SAAkB,KAC5CX,EAAMG,SACHH,EAAM8B,YAGJC,YAKXrB,EAAMI,UAAU,KACViB,KACFI,GAAS,IAEV,CAACnC,EAAM8B,WAAYC,IAnHxB,SAAwB/B,EAA6BkC,SAC7C/B,MAAEA,EAAFC,SAASA,EAATlC,UAAmBA,EAAnBtB,OAA8BA,EAA9BkF,WAAsCA,EAAtC7D,6BAAkDA,GAAiC+B,EAEzFU,EAAMI,UAAU,SACA,IAAVoB,eAGEE,EAAUtE,EAASgE,EAAY,CACnC7D,6BAAAA,EACArB,OAAAA,EACAsB,UAAAA,IAEEkE,IAAYjC,GACdC,EAASgC,IAEV,CAACjC,EAAO2B,EAAY7D,EAA8BiE,EAAOhE,EAAWtB,EAAQwD,IAsG/EiC,CAAerC,EAAOkC,GAGpBxB,gBAACX,MACKC,EACJK,SAAU,KACR8B,GAAS,IAEX7B,OAAQ,KACFyB,KACFI,GAAS,MCnInB,SAASG,EAAcC,EAAwBC,SACvCC,MAAEA,EAAFC,YAASA,GAAgBH,SAC3BC,GAAmBC,EAAME,OAAOH,GAC3BC,EAAME,OAAOH,GAEfC,EAAME,OAAOD,EAAYE,oBAGrBC,UAA0CnC,EAAMoC,UAU3DC,YAAY/C,SACJA,QAWRgD,iBAAoC,UACpCC,0BAA6C,UAC7CC,sBAAyC,WAZjCC,EAAab,EAActC,EAAMuC,IAAKvC,EAAMwC,iBAC5CY,EAAWpD,EAAMuC,IAAIE,MAAMY,SAC3BC,IAASH,GAAanD,EAAMuD,MAAMC,KAAOL,EAAWK,QACrDC,MAAQ,CACX3B,WAAYqB,EAAaA,EAAWO,WAAa,GACjDC,YAAaC,QAAQR,EAASS,kBAC9BP,OAAAA,GAQJQ,yBACOZ,sBAAwBa,KAAK/D,MAAMuC,IAAIE,MAAMuB,aAAcC,SACzDC,SAAS,CACZP,YAAaC,QAAQK,EAAIJ,4BAIvBV,EAAab,EAAcyB,KAAK/D,MAAMuC,IAAKwB,KAAK/D,MAAMwC,iBAGvDW,IAIAY,KAAKN,MAAMH,cACTL,0BAA4BE,EAAWgB,eAC1CJ,KAAK/D,MAAMuD,MAAM3G,OAChBuD,SACM+D,SAAS,CAAEpC,WAAY3B,OAK9B4D,KAAK/D,MAAMuD,MAAM3G,SAAWmH,KAAK/D,MAAMoE,gBACpCL,KAAK/D,MAAM/B,oCACT+E,iBAAmBG,EAAWgB,eACjCJ,KAAK/D,MAAMoE,cACVjE,IACMgD,EAAWO,SAASK,KAAK/D,MAAMuD,MAAM3G,cACnCsH,SAAS,CAAEpC,WAAY3B,SAQxCkE,uBACuC,mBAA1BN,KAAKf,uBACTA,mBAEuC,mBAAnCe,KAAKd,gCACTA,4BAEmC,mBAA/Bc,KAAKb,4BACTA,wBAIToB,gBACSP,KAAK/D,MAAMuE,SAAS,IACtBR,KAAKN,SC1Ed,SAASe,GAAuB1B,UAC9BA,EAD8B3C,MAE9BA,EAF8BsE,SAG9BA,EAH8BrE,SAI9BA,EAJ8BsE,OAK9BA,EAL8B5C,WAM9BA,EAN8B7D,6BAO9BA,EAP8BrB,OAQ9BA,EAR8BsB,UAS9BA,EAT8BsC,mBAU9BA,UAeMmE,EAAejE,cACnBkE,SAAUC,eAEAzE,KAAYyE,GAClB,MAAOrD,MAIX,CAACpB,WAIDM,sCAAkB,eAChBA,gBAACoC,GACClG,OAAQA,EACRsB,UAAWA,EACXsC,mBAAoBA,EACpBP,SAAUyE,EAAO7G,OAAS,EAC1BsC,MAAOA,EACPlC,6BAA8BA,EAC9BiC,WAAYuE,EACZ3C,WAAYA,EACZ1B,SAAUuE,cAMFG,EAAW9E,mBACnBuD,MAAEA,EAAFwB,WAASA,GAAe/E,GACxBgF,QAAEA,EAAFvC,MAAWA,EAAXwC,MAAkBA,GAAUjF,EAAMkF,WA1DzB,WA4DY3B,EAAM4B,WACzB,IAAIC,UAAU7B,EAAM4B,yDAGtB3C,SAAkBuC,YAAAA,EAAYM,mBAAU7C,uBAAmB8C,EAC3DlC,EAAWX,EAAMY,SAGjBkC,EAAqBP,EAAQQ,UAAUjC,EAAM3G,QAM7C6I,EAAwB7B,SAASL,EAAMmC,UAPpBV,EAAQW,SAASpC,EAAM3G,SAQ1CqB,EAA+B2F,QACnC6B,GAAyBF,GAAsBP,EAAQY,UAAUC,SAASN,IAGtE/E,EAAqBE,cACxBP,kBACO2F,EAAc,CAClBC,mBAAc3C,YAAAA,EAAUV,uBAAVsD,EAAuB/B,YAAvBgC,EAA4BzC,cAC/BD,EAAMC,MAAMD,EAAM3G,UAAWuD,eAC1BiD,EAASI,8BACI,EAC3B0C,MAAO,UAEFjB,EAAMkB,WAAWL,GAAa/E,KAAMqF,GACpB,IAAdA,EAAIC,QAGf,OAACjD,YAAAA,EAAUV,uBAAV4D,EAAuBrC,YAAvBsC,EAA4B/C,GAAID,EAAMC,GAAID,EAAM3G,OAAQwG,EAASI,GAAIyB,WAItEvE,gBAACmC,GACCN,IAAKvC,EAAMkF,QACX3B,MAAOA,EACPa,cAAeY,EAAQwB,QACvBvI,6BAA8BA,EAC9BuE,gBAAiBA,GAChB,EAAGV,WAAAA,EAAY6B,YAAAA,EAAaL,OAAAA,KAC3B5C,gBAAC+F,kBACClD,MAAOA,EACPmD,oBAAqB1G,EAAM0G,oBAC3BC,SAAU,GACT,EAAGxG,MAAAA,EAAOuE,OAAAA,EAAQD,SAAAA,EAAUrE,SAAAA,EAAUwG,cAAAA,KAMnClG,gBAAC8D,GACC1B,WANqC,IAAhBa,IAAoC,IAAXL,EAEbzB,EAAkB9B,EAKnD+B,WAAYA,EACZ3B,MAAOA,EACPuE,OAAQA,EACRD,SAAUA,EACVrE,SAAUA,EACVnC,6BAA8BA,EAC9BC,UAAWkF,EAASlF,UACpBtB,OAAQ2G,EAAM3G,OACd4D,mBAAoBA,EACpBqG,mBAAoBD,MD5HvB/D,EAIJiE,aAAe,CACpBvC,SAAU,IACD,MCgIbO,EAAWgC,aAAe,CACxBJ,qBAAqB"}