@byline/admin 6.1.0 → 6.2.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 (119) hide show
  1. package/dist/forms/form-layout-styles.test.node.d.ts +8 -0
  2. package/dist/forms/form-layout.d.ts +39 -0
  3. package/dist/forms/form-layout.js +100 -0
  4. package/dist/forms/form-page-chrome.d.ts +110 -0
  5. package/dist/forms/form-page-chrome.js +253 -0
  6. package/dist/forms/form-renderer.d.ts +2 -18
  7. package/dist/forms/form-renderer.js +104 -418
  8. package/dist/forms/form-renderer.module.js +2 -0
  9. package/dist/forms/form-renderer_module.css +13 -0
  10. package/dist/forms/use-form-submission.d.ts +74 -0
  11. package/dist/forms/use-form-submission.js +166 -0
  12. package/dist/forms/use-form-tabs.d.ts +29 -0
  13. package/dist/forms/use-form-tabs.js +45 -0
  14. package/dist/presentation/tab-strip-drag.d.ts +75 -0
  15. package/dist/presentation/tab-strip-drag.js +25 -0
  16. package/dist/presentation/tab-strip-drag.test.node.d.ts +8 -0
  17. package/dist/presentation/tab-strip-geometry.d.ts +75 -0
  18. package/dist/presentation/tab-strip-geometry.js +36 -0
  19. package/dist/presentation/tab-strip-geometry.test.node.d.ts +8 -0
  20. package/dist/presentation/tabs.d.ts +30 -7
  21. package/dist/presentation/tabs.js +260 -29
  22. package/dist/presentation/tabs.module.js +11 -1
  23. package/dist/presentation/tabs_module.css +166 -5
  24. package/package.json +7 -7
  25. package/src/forms/form-layout-styles.test.node.ts +32 -0
  26. package/src/forms/form-layout.test.tsx +276 -0
  27. package/src/forms/form-layout.tsx +198 -0
  28. package/src/forms/form-page-chrome.tsx +460 -0
  29. package/src/forms/form-renderer-submit.test.tsx +40 -0
  30. package/src/forms/form-renderer-tab-persistence.test.tsx +145 -0
  31. package/src/forms/form-renderer.module.css +18 -0
  32. package/src/forms/form-renderer.tsx +115 -593
  33. package/src/forms/use-form-submission.test.tsx +564 -0
  34. package/src/forms/use-form-submission.ts +293 -0
  35. package/src/forms/use-form-tabs.ts +89 -0
  36. package/src/presentation/tab-strip-drag.test.node.ts +143 -0
  37. package/src/presentation/tab-strip-drag.ts +114 -0
  38. package/src/presentation/tab-strip-geometry.test.node.ts +254 -0
  39. package/src/presentation/tab-strip-geometry.ts +158 -0
  40. package/src/presentation/tabs.module.css +209 -11
  41. package/src/presentation/tabs.test.tsx +481 -0
  42. package/src/presentation/tabs.tsx +369 -34
  43. package/dist/exports-parity.test.node.js +0 -37
  44. package/dist/fields/array/array-field.jsx +0 -209
  45. package/dist/fields/blocks/blocks-field.jsx +0 -248
  46. package/dist/fields/checkbox/checkbox-field.jsx +0 -24
  47. package/dist/fields/code/code-editor.jsx +0 -211
  48. package/dist/fields/code/code-field.jsx +0 -109
  49. package/dist/fields/column-formatter.jsx +0 -25
  50. package/dist/fields/date-time-formatter.jsx +0 -18
  51. package/dist/fields/datetime/datetime-field.jsx +0 -22
  52. package/dist/fields/draggable-context-menu.jsx +0 -50
  53. package/dist/fields/field-admin.test.node.js +0 -40
  54. package/dist/fields/field-renderer.jsx +0 -136
  55. package/dist/fields/field-services-context.jsx +0 -17
  56. package/dist/fields/file/file-field.jsx +0 -176
  57. package/dist/fields/file/file-upload-field.jsx +0 -89
  58. package/dist/fields/group/group-field.jsx +0 -46
  59. package/dist/fields/image/image-field.jsx +0 -183
  60. package/dist/fields/image/image-upload-field.jsx +0 -157
  61. package/dist/fields/local-date-time.jsx +0 -69
  62. package/dist/fields/locale-badge.jsx +0 -19
  63. package/dist/fields/numerical/numerical-field.jsx +0 -93
  64. package/dist/fields/relation/relation-column-formatter.jsx +0 -74
  65. package/dist/fields/relation/relation-display.jsx +0 -118
  66. package/dist/fields/relation/relation-field.jsx +0 -108
  67. package/dist/fields/relation/relation-many-field.jsx +0 -142
  68. package/dist/fields/relation/relation-picker.jsx +0 -240
  69. package/dist/fields/relation/relation-summary.jsx +0 -45
  70. package/dist/fields/select/select-field.jsx +0 -27
  71. package/dist/fields/sortable-item.jsx +0 -54
  72. package/dist/fields/text/text-field.jsx +0 -79
  73. package/dist/fields/text-area/text-area-field.jsx +0 -79
  74. package/dist/forms/available-locales-reconcile.test.node.js +0 -43
  75. package/dist/forms/available-locales-widget.jsx +0 -63
  76. package/dist/forms/document-actions.jsx +0 -486
  77. package/dist/forms/form-context.jsx +0 -598
  78. package/dist/forms/form-modals.jsx +0 -128
  79. package/dist/forms/form-renderer.jsx +0 -532
  80. package/dist/forms/form-status-display.jsx +0 -69
  81. package/dist/forms/navigation-guard.jsx +0 -68
  82. package/dist/forms/nested-path.test.node.js +0 -115
  83. package/dist/forms/path-widget.jsx +0 -125
  84. package/dist/forms/pending-uploads.test.node.js +0 -19
  85. package/dist/forms/repeating-items.test.node.js +0 -29
  86. package/dist/forms/scheduled-publication-control.jsx +0 -389
  87. package/dist/forms/scheduled-publication-state.test.node.js +0 -121
  88. package/dist/forms/scheduled-publication-time.test.node.js +0 -70
  89. package/dist/forms/status-transitions.test.node.js +0 -76
  90. package/dist/forms/tree-placement-widget.jsx +0 -160
  91. package/dist/forms/upload-executor.test.node.js +0 -368
  92. package/dist/forms/use-form-layout.test.node.js +0 -69
  93. package/dist/modules/admin-account/components/change-password.jsx +0 -169
  94. package/dist/modules/admin-account/components/container.jsx +0 -164
  95. package/dist/modules/admin-account/components/preferences.jsx +0 -148
  96. package/dist/modules/admin-account/components/theme-switch.jsx +0 -52
  97. package/dist/modules/admin-account/components/update.jsx +0 -186
  98. package/dist/modules/admin-permissions/components/inspector.jsx +0 -200
  99. package/dist/modules/admin-preferences/schemas.test.node.js +0 -48
  100. package/dist/modules/admin-roles/components/create.jsx +0 -155
  101. package/dist/modules/admin-roles/components/permissions.jsx +0 -239
  102. package/dist/modules/admin-roles/components/update.jsx +0 -148
  103. package/dist/modules/admin-users/components/create.jsx +0 -206
  104. package/dist/modules/admin-users/components/roles.jsx +0 -126
  105. package/dist/modules/admin-users/components/set-password.jsx +0 -133
  106. package/dist/modules/admin-users/components/update.jsx +0 -215
  107. package/dist/modules/analytics/components/dashboard.jsx +0 -208
  108. package/dist/modules/analytics/components/dashboard.test.node.js +0 -162
  109. package/dist/modules/analytics/components/timeseries.jsx +0 -193
  110. package/dist/modules/auth/components/sign-in-form.jsx +0 -89
  111. package/dist/modules/auth/safe-redirect.test.node.js +0 -40
  112. package/dist/modules/auth/sign-in-form-props.test.node.js +0 -7
  113. package/dist/presentation/group.jsx +0 -26
  114. package/dist/presentation/row.jsx +0 -23
  115. package/dist/presentation/tabs.jsx +0 -39
  116. package/dist/services/admin-services-context.jsx +0 -17
  117. package/dist/widgets/diff-viewer/diff-modal.jsx +0 -110
  118. package/dist/widgets/source-locale-badge/source-locale-badge.jsx +0 -28
  119. package/dist/widgets/status-badge/status-badge.jsx +0 -46
@@ -1,486 +0,0 @@
1
- 'use client';
2
- /**
3
- * This Source Code is subject to the terms of the Mozilla Public
4
- * License, v. 2.0. If a copy of the MPL was not distributed with this
5
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
- *
7
- * Copyright (c) Infonomic Company Limited
8
- */
9
- import { useState } from 'react';
10
- import { useTranslation } from '@byline/i18n/react';
11
- import { Button, Checkbox, CloseIcon, DeleteIcon, Dropdown as DropdownComponent, EllipsisIcon, IconButton, Modal, Select, } from '@byline/ui/react';
12
- import cx from 'clsx';
13
- import styles from './document-actions.module.css';
14
- const DUPLICATE_TITLE_SUFFIX = ' (copy)';
15
- export function DocumentActions({ disabled = false, publishedVersion, onUnpublish, onDelete, onDuplicate, sourceTitle, onCopyToLocale, sourceLocale, contentLocales, hasUnsavedChanges, onUnsavedChanges, onDeleteLocale, defaultLocale, availableLocales, scheduledPublicationState, onSchedulePublication, onConfirmScheduledPublication, onCancelScheduledPublication, }) {
16
- const { t } = useTranslation('byline-admin');
17
- const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
18
- const [showDuplicateConfirm, setShowDuplicateConfirm] = useState(false);
19
- const [duplicateBusy, setDuplicateBusy] = useState(false);
20
- // Copy-to-Locale modal state. The menu item is hidden entirely unless
21
- // the host has supplied a handler AND there is at least one *other*
22
- // locale to copy into.
23
- const availableTargetLocales = (contentLocales ?? []).filter((loc) => loc.code !== sourceLocale);
24
- const copyToLocaleAvailable = onCopyToLocale != null && availableTargetLocales.length > 0;
25
- const [showCopyToLocaleConfirm, setShowCopyToLocaleConfirm] = useState(false);
26
- const [copyToLocaleBusy, setCopyToLocaleBusy] = useState(false);
27
- const [copyTargetLocale, setCopyTargetLocale] = useState(availableTargetLocales[0]?.code ?? '');
28
- const [copyOverwrite, setCopyOverwrite] = useState(false);
29
- // Delete-Locale modal state. The menu item is hidden unless the host
30
- // supplied a handler AND the document has at least one non-default locale
31
- // with content. The default locale is the document's anchor and is never
32
- // listed (it cannot be removed).
33
- const deletableLocales = (availableLocales ?? [])
34
- .filter((code) => code !== defaultLocale && code !== 'all')
35
- .map((code) => ({
36
- code,
37
- label: contentLocales?.find((loc) => loc.code === code)?.label ?? code,
38
- }));
39
- const deleteLocaleAvailable = onDeleteLocale != null && deletableLocales.length > 0;
40
- const [showDeleteLocaleConfirm, setShowDeleteLocaleConfirm] = useState(false);
41
- const [deleteLocaleBusy, setDeleteLocaleBusy] = useState(false);
42
- const [deleteTargetLocale, setDeleteTargetLocale] = useState('');
43
- // Scheduled-publication menu items. The derived state already accounts for
44
- // eligibility and for the abilities the actor holds, so the only thing left
45
- // here is to map the permitted operations onto entries. The group renders
46
- // above the locale and duplicate items because scheduling acts on the
47
- // document's lifecycle rather than on its copies.
48
- const scheduling = scheduledPublicationState;
49
- const schedulingActions = [];
50
- if (scheduling != null) {
51
- if (scheduling.actions.schedule && onSchedulePublication != null) {
52
- schedulingActions.push({
53
- key: 'schedule',
54
- // Short form: the menu supplies the "this document" context that the
55
- // modal's title and submit button have to spell out for themselves.
56
- label: t('scheduledPublication.actions.scheduleMenuItem'),
57
- onSelect: onSchedulePublication,
58
- });
59
- }
60
- if (scheduling.actions.confirm && onConfirmScheduledPublication != null) {
61
- schedulingActions.push({
62
- key: 'confirm',
63
- label: t('scheduledPublication.actions.confirm'),
64
- onSelect: () => void onConfirmScheduledPublication(),
65
- });
66
- }
67
- if (scheduling.actions.reschedule && onSchedulePublication != null) {
68
- schedulingActions.push({
69
- key: 'reschedule',
70
- label: t('scheduledPublication.actions.reschedule'),
71
- onSelect: onSchedulePublication,
72
- });
73
- }
74
- if (scheduling.actions.cancel && onCancelScheduledPublication != null) {
75
- schedulingActions.push({
76
- key: 'cancel',
77
- label: t('scheduledPublication.actions.cancel'),
78
- onSelect: () => void onCancelScheduledPublication(),
79
- });
80
- }
81
- }
82
- // Whether the ellipsis menu has anything to show. Every entry below is
83
- // conditional, so with no available action the trigger would open an empty
84
- // menu.
85
- const hasAnyAction = schedulingActions.length > 0 ||
86
- copyToLocaleAvailable ||
87
- deleteLocaleAvailable ||
88
- onDuplicate != null ||
89
- onDelete != null;
90
- const handleOnDelete = () => {
91
- if (disabled)
92
- return;
93
- setShowDeleteConfirm(false);
94
- if (onDelete) {
95
- void onDelete().catch(() => { });
96
- }
97
- };
98
- const handleOnDuplicate = async () => {
99
- if (disabled)
100
- return;
101
- if (!onDuplicate)
102
- return;
103
- setDuplicateBusy(true);
104
- try {
105
- await onDuplicate();
106
- setShowDuplicateConfirm(false);
107
- }
108
- catch {
109
- // The host reports the failure and retains the editor observation.
110
- }
111
- finally {
112
- setDuplicateBusy(false);
113
- }
114
- };
115
- const handleOpenDuplicate = () => {
116
- if (disabled)
117
- return;
118
- // Duplicate copies the saved version — block when the form is dirty so
119
- // unsaved edits are not silently dropped from the copy.
120
- if (hasUnsavedChanges) {
121
- onUnsavedChanges?.();
122
- return;
123
- }
124
- setShowDuplicateConfirm(true);
125
- };
126
- const handleOpenCopyToLocale = () => {
127
- if (disabled)
128
- return;
129
- // Copy-to-Locale reads the saved version — block when the form is dirty.
130
- if (hasUnsavedChanges) {
131
- onUnsavedChanges?.();
132
- return;
133
- }
134
- // Reset on open: pick the first available target and clear the
135
- // overwrite checkbox so a previous-session "overwrite=true" choice
136
- // is not silently sticky.
137
- setCopyTargetLocale(availableTargetLocales[0]?.code ?? '');
138
- setCopyOverwrite(false);
139
- setShowCopyToLocaleConfirm(true);
140
- };
141
- const handleOnCopyToLocale = async () => {
142
- if (disabled)
143
- return;
144
- if (!onCopyToLocale || !copyTargetLocale)
145
- return;
146
- setCopyToLocaleBusy(true);
147
- try {
148
- await onCopyToLocale({ targetLocale: copyTargetLocale, overwrite: copyOverwrite });
149
- setShowCopyToLocaleConfirm(false);
150
- }
151
- catch {
152
- // The host reports the failure and retains the editor observation.
153
- }
154
- finally {
155
- setCopyToLocaleBusy(false);
156
- }
157
- };
158
- const handleOpenDeleteLocale = () => {
159
- if (disabled)
160
- return;
161
- // Delete-Locale removes the saved version's locale content — block when
162
- // the form is dirty so the editor saves (or discards) first.
163
- if (hasUnsavedChanges) {
164
- onUnsavedChanges?.();
165
- return;
166
- }
167
- // Default to the currently-viewed locale when it is deletable, otherwise
168
- // the first available target.
169
- const preferred = deletableLocales.find((loc) => loc.code === sourceLocale)?.code;
170
- setDeleteTargetLocale(preferred ?? deletableLocales[0]?.code ?? '');
171
- setShowDeleteLocaleConfirm(true);
172
- };
173
- const handleOnDeleteLocale = async () => {
174
- if (disabled)
175
- return;
176
- if (!onDeleteLocale || !deleteTargetLocale)
177
- return;
178
- setDeleteLocaleBusy(true);
179
- try {
180
- await onDeleteLocale({ targetLocale: deleteTargetLocale });
181
- setShowDeleteLocaleConfirm(false);
182
- }
183
- catch {
184
- // The host reports the failure and retains the editor observation.
185
- }
186
- finally {
187
- setDeleteLocaleBusy(false);
188
- }
189
- };
190
- // Preview text shown inside the modal. Falls back to the literal suffix
191
- // when no source title is supplied (collections without `useAsTitle`).
192
- const duplicatePreviewBefore = sourceTitle ?? '';
193
- const duplicatePreviewAfter = (sourceTitle ?? '') + DUPLICATE_TITLE_SUFFIX;
194
- const sourceLocaleLabel = contentLocales?.find((loc) => loc.code === sourceLocale)?.label ?? sourceLocale ?? '';
195
- return (<>
196
- {hasAnyAction && (<DropdownComponent.Root>
197
- <DropdownComponent.Trigger disabled={disabled} render={<IconButton variant="text" intent="noeffect" size="sm"/>}>
198
- <EllipsisIcon className={cx('byline-form-actions-icon', styles.icon)} width="15px" height="15px"/>
199
- </DropdownComponent.Trigger>
200
-
201
- <DropdownComponent.Portal>
202
- <DropdownComponent.Content className={cx('byline-form-actions-menu', styles.menu)} align="end" data-side="top" sideOffset={10}>
203
- {/*{publishedVersion && (
204
- <>
205
- <DropdownComponent.Item disabled={disabled} onClick={onUnpublish}>
206
- <div className={cx('byline-form-actions-item', styles.item)}>
207
- <span className={cx('byline-form-actions-item-icon', styles['item-icon'])} />
208
- <span className={cx('byline-form-actions-item-text', styles['item-text'])}>
209
- Unpublish
210
- </span>
211
- </div>
212
- </DropdownComponent.Item>
213
- <DropdownComponent.Separator />
214
- </>
215
- )}*/}
216
- {schedulingActions.length > 0 && (<>
217
- {schedulingActions.map((action) => (<DropdownComponent.Item disabled={disabled} key={action.key} onClick={action.onSelect}>
218
- <div className={cx('byline-form-actions-item', styles.item)}>
219
- <span className={cx('byline-form-actions-item-text', styles['item-text'])}>
220
- <button type="button" disabled={disabled}>
221
- {action.label}
222
- </button>
223
- </span>
224
- </div>
225
- </DropdownComponent.Item>))}
226
- <DropdownComponent.Separator />
227
- </>)}
228
- {copyToLocaleAvailable && (<DropdownComponent.Item disabled={disabled} onClick={handleOpenCopyToLocale}>
229
- <div className={cx('byline-form-actions-item', styles.item)}>
230
- <span className={cx('byline-form-actions-item-text', styles['item-text'])}>
231
- <button type="button" disabled={disabled}>
232
- {t('documentActions.copyToLocaleMenuItem')}
233
- </button>
234
- </span>
235
- </div>
236
- </DropdownComponent.Item>)}
237
- {deleteLocaleAvailable && (<DropdownComponent.Item disabled={disabled} onClick={handleOpenDeleteLocale}>
238
- <div className={cx('byline-form-actions-item', styles.item)}>
239
- <span className={cx('byline-form-actions-item-text', styles['item-text'])}>
240
- <button type="button" disabled={disabled}>
241
- {t('documentActions.deleteLocale.menuItem')}
242
- </button>
243
- </span>
244
- </div>
245
- </DropdownComponent.Item>)}
246
- {onDuplicate && (<DropdownComponent.Item disabled={disabled} onClick={handleOpenDuplicate}>
247
- <div className={cx('byline-form-actions-item', styles.item)}>
248
- <span className={cx('byline-form-actions-item-text', styles['item-text'])}>
249
- <button type="button" disabled={disabled}>
250
- {t('common.actions.duplicate')}
251
- </button>
252
- </span>
253
- </div>
254
- </DropdownComponent.Item>)}
255
- {onDelete && (<>
256
- <DropdownComponent.Separator />
257
- <DropdownComponent.Item disabled={disabled} onClick={() => {
258
- setShowDeleteConfirm(true);
259
- }}>
260
- <div className={cx('byline-form-actions-item', styles.item)}>
261
- <span className={cx('byline-form-actions-item-icon', styles['item-icon'])}>
262
- <DeleteIcon width="16px" height="16px"/>
263
- </span>
264
- <span className={cx('byline-form-actions-item-text', styles['item-text'])}>
265
- <button type="button" className={cx('byline-form-actions-delete', styles.delete)}>
266
- {t('common.actions.delete')}
267
- </button>
268
- </span>
269
- </div>
270
- </DropdownComponent.Item>
271
- </>)}
272
- </DropdownComponent.Content>
273
- </DropdownComponent.Portal>
274
- </DropdownComponent.Root>)}
275
-
276
- <Modal isOpen={showDeleteConfirm} closeOnOverlayClick={true} onDismiss={() => {
277
- setShowDeleteConfirm(false);
278
- }}>
279
- <Modal.Container style={{ maxWidth: '500px' }}>
280
- <Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
281
- <h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
282
- {t('documentActions.delete.title')}
283
- </h3>
284
- <IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
285
- setShowDeleteConfirm(false);
286
- }}>
287
- <CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
288
- </IconButton>
289
- </Modal.Header>
290
- <Modal.Content>
291
- <p>{t('documentActions.delete.warning')}</p>
292
- </Modal.Content>
293
- <Modal.Actions>
294
- <button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
295
- no action
296
- </button>
297
- <Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
298
- setShowDeleteConfirm(false);
299
- }}>
300
- {t('common.actions.cancel')}
301
- </Button>
302
- <Button size="sm" style={{ minWidth: '80px' }} intent="danger" disabled={disabled} onClick={handleOnDelete}>
303
- {t('common.actions.delete')}
304
- </Button>
305
- </Modal.Actions>
306
- </Modal.Container>
307
- </Modal>
308
-
309
- <Modal isOpen={showDuplicateConfirm} closeOnOverlayClick={!duplicateBusy} onDismiss={() => {
310
- if (!duplicateBusy)
311
- setShowDuplicateConfirm(false);
312
- }}>
313
- <Modal.Container style={{ maxWidth: '560px' }}>
314
- <Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
315
- <h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
316
- {t('documentActions.duplicate.title')}
317
- </h3>
318
- <IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
319
- if (!duplicateBusy)
320
- setShowDuplicateConfirm(false);
321
- }}>
322
- <CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
323
- </IconButton>
324
- </Modal.Header>
325
- <Modal.Content className="prose">
326
- <p className="m-0">{t('documentActions.duplicate.intro')}</p>
327
- <ul className={cx('byline-form-actions-list', styles.list)}>
328
- <li>
329
- {t('documentActions.duplicate.bulletTitle')}{' '}
330
- <code>{DUPLICATE_TITLE_SUFFIX.trim()}</code>.
331
- </li>
332
- <li>{t('documentActions.duplicate.bulletPath')}</li>
333
- </ul>
334
- {sourceTitle != null && sourceTitle.length > 0 && (<div className={cx('byline-form-actions-preview', styles.preview)}>
335
- <div className={cx('byline-form-actions-preview-label', styles['preview-label'])}>
336
- {t('documentActions.duplicate.previewLabel')}
337
- </div>
338
- <div className={cx('byline-form-actions-preview-row', styles['preview-row'])}>
339
- <span className={cx('byline-form-actions-preview-before', styles['preview-before'])}>
340
- {duplicatePreviewBefore}
341
- </span>
342
- <span className={cx('byline-form-actions-preview-arrow', styles['preview-arrow'])}>
343
- →
344
- </span>
345
- <span className={cx('byline-form-actions-preview-after', styles['preview-after'])}>
346
- {duplicatePreviewAfter}
347
- </span>
348
- </div>
349
- </div>)}
350
- </Modal.Content>
351
- <Modal.Actions>
352
- <button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
353
- no action
354
- </button>
355
- <Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
356
- if (!duplicateBusy)
357
- setShowDuplicateConfirm(false);
358
- }} disabled={disabled || duplicateBusy}>
359
- {t('common.actions.cancel')}
360
- </Button>
361
- <Button size="sm" style={{ minWidth: '80px' }} intent="primary" onClick={handleOnDuplicate} disabled={disabled || duplicateBusy}>
362
- {duplicateBusy
363
- ? t('documentActions.duplicate.busyButton')
364
- : t('common.actions.duplicate')}
365
- </Button>
366
- </Modal.Actions>
367
- </Modal.Container>
368
- </Modal>
369
-
370
- <Modal isOpen={showCopyToLocaleConfirm} closeOnOverlayClick={!copyToLocaleBusy} onDismiss={() => {
371
- if (!copyToLocaleBusy)
372
- setShowCopyToLocaleConfirm(false);
373
- }}>
374
- <Modal.Container style={{ maxWidth: '560px' }}>
375
- <Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
376
- <h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
377
- {t('documentActions.copyToLocale.title')}
378
- </h3>
379
- <IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
380
- if (!copyToLocaleBusy)
381
- setShowCopyToLocaleConfirm(false);
382
- }}>
383
- <CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
384
- </IconButton>
385
- </Modal.Header>
386
- <Modal.Content>
387
- <p>{t('documentActions.copyToLocale.intro')}</p>
388
- <div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-12)' }}>
389
- <span className={cx('byline-form-actions-copy-label', styles['copy-label'])} style={{ fontWeight: 500 }}>
390
- {t('documentActions.copyToLocale.fromLabel')}&nbsp;
391
- </span>
392
- <span className={cx('byline-form-actions-copy-source', styles['copy-source'])}>
393
- {sourceLocaleLabel}
394
- </span>
395
- </div>
396
- <div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-12)' }}>
397
- <span className={cx('byline-form-actions-copy-label', styles['copy-label'])} style={{ fontWeight: 500, marginRight: 'var(--spacing-8)' }}>
398
- {t('documentActions.copyToLocale.toLabel')}
399
- </span>
400
- <Select size="sm" ariaLabel={t('documentActions.copyToLocale.targetAriaLabel')} value={copyTargetLocale} items={availableTargetLocales.map((loc) => ({
401
- value: loc.code,
402
- label: loc.label,
403
- }))} onValueChange={(value) => {
404
- if (value != null)
405
- setCopyTargetLocale(value);
406
- }} disabled={disabled || copyToLocaleBusy}/>
407
- </div>
408
- <div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-16)' }}>
409
- <Checkbox id="copy-to-locale-overwrite" name="overwrite" label={t('documentActions.copyToLocale.overwriteLabel')} checked={copyOverwrite} disabled={disabled || copyToLocaleBusy} helpText={t('documentActions.copyToLocale.overwriteHelp')} onCheckedChange={(value) => {
410
- setCopyOverwrite(value === true);
411
- }}/>
412
- </div>
413
- </Modal.Content>
414
- <Modal.Actions>
415
- <button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
416
- no action
417
- </button>
418
- <Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
419
- if (!copyToLocaleBusy)
420
- setShowCopyToLocaleConfirm(false);
421
- }} disabled={disabled || copyToLocaleBusy}>
422
- {t('common.actions.cancel')}
423
- </Button>
424
- <Button size="sm" style={{ minWidth: '80px' }} intent="primary" onClick={handleOnCopyToLocale} disabled={disabled || copyToLocaleBusy || !copyTargetLocale}>
425
- {copyToLocaleBusy
426
- ? t('documentActions.copyToLocale.busyButton')
427
- : t('documentActions.copyToLocale.confirmButton')}
428
- </Button>
429
- </Modal.Actions>
430
- </Modal.Container>
431
- </Modal>
432
-
433
- <Modal isOpen={showDeleteLocaleConfirm} closeOnOverlayClick={!deleteLocaleBusy} onDismiss={() => {
434
- if (!deleteLocaleBusy)
435
- setShowDeleteLocaleConfirm(false);
436
- }}>
437
- <Modal.Container style={{ maxWidth: '560px' }}>
438
- <Modal.Header className={cx('byline-form-actions-modal-head', styles['modal-head'])}>
439
- <h3 className={cx('byline-form-actions-modal-title', styles['modal-title'])}>
440
- {t('documentActions.deleteLocale.title')}
441
- </h3>
442
- <IconButton arial-label={t('common.actions.close')} size="xs" onClick={() => {
443
- if (!deleteLocaleBusy)
444
- setShowDeleteLocaleConfirm(false);
445
- }}>
446
- <CloseIcon width="16px" height="16px" svgClassName="white-icon"/>
447
- </IconButton>
448
- </Modal.Header>
449
- <Modal.Content>
450
- <p>{t('documentActions.deleteLocale.intro')}</p>
451
- <div className={cx('byline-form-actions-copy-row', styles['copy-row'])} style={{ marginTop: 'var(--spacing-12)' }}>
452
- <span className={cx('byline-form-actions-copy-label', styles['copy-label'])} style={{ fontWeight: 500, marginRight: 'var(--spacing-8)' }}>
453
- {t('documentActions.deleteLocale.localeLabel')}
454
- </span>
455
- <Select size="sm" ariaLabel={t('documentActions.deleteLocale.targetAriaLabel')} value={deleteTargetLocale} items={deletableLocales.map((loc) => ({
456
- value: loc.code,
457
- label: loc.label,
458
- }))} onValueChange={(value) => {
459
- if (value != null)
460
- setDeleteTargetLocale(value);
461
- }} disabled={disabled || deleteLocaleBusy}/>
462
- </div>
463
- <p style={{ marginTop: 'var(--spacing-12)' }}>
464
- {t('documentActions.deleteLocale.warning')}
465
- </p>
466
- </Modal.Content>
467
- <Modal.Actions>
468
- <button data-autofocus type="button" tabIndex={0} className={cx('byline-form-actions-sr-only', styles['sr-only'])}>
469
- no action
470
- </button>
471
- <Button size="sm" style={{ minWidth: '80px' }} intent="noeffect" onClick={() => {
472
- if (!deleteLocaleBusy)
473
- setShowDeleteLocaleConfirm(false);
474
- }} disabled={disabled || deleteLocaleBusy}>
475
- {t('common.actions.cancel')}
476
- </Button>
477
- <Button size="sm" style={{ minWidth: '80px' }} intent="danger" onClick={handleOnDeleteLocale} disabled={disabled || deleteLocaleBusy || !deleteTargetLocale}>
478
- {deleteLocaleBusy
479
- ? t('documentActions.deleteLocale.busyButton')
480
- : t('documentActions.deleteLocale.confirmButton')}
481
- </Button>
482
- </Modal.Actions>
483
- </Modal.Container>
484
- </Modal>
485
- </>);
486
- }