apostrophe 3.63.3 → 4.1.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 (184) hide show
  1. package/.eslintrc +13 -4
  2. package/CHANGELOG.md +37 -5
  3. package/defaults.js +2 -1
  4. package/modules/@apostrophecms/admin-bar/ui/apos/apps/AposAdminBar.js +7 -17
  5. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBar.vue +14 -16
  6. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +1 -1
  7. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarMenu.vue +22 -15
  8. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarUser.vue +2 -2
  9. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +13 -8
  10. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextModeAndSettings.vue +18 -10
  11. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +4 -4
  12. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextUndoRedo.vue +14 -8
  13. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposSavingIndicator.vue +2 -1
  14. package/modules/@apostrophecms/area/ui/apos/apps/AposAreas.js +36 -54
  15. package/modules/@apostrophecms/area/ui/apos/components/AposAreaContextualMenu.vue +20 -25
  16. package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +5 -12
  17. package/modules/@apostrophecms/area/ui/apos/components/AposAreaExpandedMenu.vue +11 -3
  18. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenu.vue +6 -6
  19. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenuItem.vue +3 -2
  20. package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +31 -44
  21. package/modules/@apostrophecms/area/ui/apos/components/AposWidgetControls.vue +16 -16
  22. package/modules/@apostrophecms/asset/index.js +25 -12
  23. package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.config.js +3 -3
  24. package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.vue.js +7 -1
  25. package/modules/@apostrophecms/attachment/index.js +2 -1
  26. package/modules/@apostrophecms/attachment/public/img/missing-icon.svg +14 -0
  27. package/modules/@apostrophecms/busy/ui/apos/apps/AposBusy.js +8 -7
  28. package/modules/@apostrophecms/busy/ui/apos/components/TheAposBusy.vue +1 -1
  29. package/modules/@apostrophecms/command-menu/ui/apos/apps/AposCommandMenu.js +11 -29
  30. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuKey.vue +1 -1
  31. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuShortcut.vue +6 -6
  32. package/modules/@apostrophecms/command-menu/ui/apos/components/TheAposCommandMenu.vue +10 -7
  33. package/modules/@apostrophecms/doc-type/index.js +34 -13
  34. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +3 -3
  35. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +20 -15
  36. package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +1 -1
  37. package/modules/@apostrophecms/i18n/i18n/en.json +13 -0
  38. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +209 -33
  39. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalizeErrors.vue +3 -3
  40. package/modules/@apostrophecms/image/ui/apos/components/AposImageCropper.vue +5 -5
  41. package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +6 -6
  42. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +23 -16
  43. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerDisplay.vue +11 -11
  44. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +28 -21
  45. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerSelections.vue +4 -3
  46. package/modules/@apostrophecms/image/ui/apos/components/AposMediaUploader.vue +5 -4
  47. package/modules/@apostrophecms/login/index.js +18 -1
  48. package/modules/@apostrophecms/login/ui/apos/apps/AposLogin.js +6 -7
  49. package/modules/@apostrophecms/login/ui/apos/components/AposForgotPasswordForm.vue +3 -3
  50. package/modules/@apostrophecms/login/ui/apos/components/AposLoginForm.vue +10 -10
  51. package/modules/@apostrophecms/login/ui/apos/components/AposResetPasswordForm.vue +3 -3
  52. package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +2 -2
  53. package/modules/@apostrophecms/login/ui/apos/logic/AposLoginForm.js +1 -16
  54. package/modules/@apostrophecms/modal/ui/apos/apps/AposModals.js +60 -87
  55. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +15 -11
  56. package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +17 -11
  57. package/modules/@apostrophecms/modal/ui/apos/components/AposModalBreadcrumbs.vue +7 -4
  58. package/modules/@apostrophecms/modal/ui/apos/components/AposModalConfirm.vue +9 -9
  59. package/modules/@apostrophecms/modal/ui/apos/components/AposModalLip.vue +2 -2
  60. package/modules/@apostrophecms/modal/ui/apos/components/AposModalShareDraft.vue +8 -8
  61. package/modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue +4 -3
  62. package/modules/@apostrophecms/modal/ui/apos/components/AposModalToolbar.vue +7 -7
  63. package/modules/@apostrophecms/modal/ui/apos/components/TheAposModals.vue +22 -4
  64. package/modules/@apostrophecms/modal/ui/apos/composables/AposFocus.js +95 -0
  65. package/modules/@apostrophecms/modal/ui/apos/mixins/AposDocsManagerMixin.js +2 -3
  66. package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +6 -0
  67. package/modules/@apostrophecms/notification/index.js +4 -4
  68. package/modules/@apostrophecms/notification/ui/apos/apps/AposNotification.js +6 -9
  69. package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +12 -8
  70. package/modules/@apostrophecms/notification/ui/apos/components/TheAposNotifications.vue +4 -2
  71. package/modules/@apostrophecms/oembed-field/ui/apos/components/AposInputOembed.vue +12 -10
  72. package/modules/@apostrophecms/page/index.js +1 -0
  73. package/modules/@apostrophecms/page/ui/apos/components/AposPagesManager.vue +15 -11
  74. package/modules/@apostrophecms/page/ui/apos/logic/AposPagesManager.js +1 -1
  75. package/modules/@apostrophecms/permission/ui/apos/components/AposInputRole.vue +3 -3
  76. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +25 -17
  77. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerDisplay.vue +24 -20
  78. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerSelectBox.vue +9 -5
  79. package/modules/@apostrophecms/piece-type/ui/apos/components/AposRelationshipEditor.vue +15 -11
  80. package/modules/@apostrophecms/rich-text-widget/index.js +1 -0
  81. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposImageControlDialog.vue +7 -6
  82. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +31 -30
  83. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapAnchor.vue +12 -10
  84. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapButton.vue +1 -1
  85. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapImage.vue +1 -1
  86. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapLink.vue +9 -8
  87. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapStyles.vue +3 -3
  88. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapTable.vue +3 -3
  89. package/modules/@apostrophecms/schema/index.js +69 -8
  90. package/modules/@apostrophecms/schema/lib/addFieldTypes.js +1 -1
  91. package/modules/@apostrophecms/schema/ui/apos/components/AposArrayEditor.vue +10 -8
  92. package/modules/@apostrophecms/schema/ui/apos/components/AposInputArea.vue +5 -3
  93. package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +81 -277
  94. package/modules/@apostrophecms/schema/ui/apos/components/AposInputAttachment.vue +4 -2
  95. package/modules/@apostrophecms/schema/ui/apos/components/AposInputBoolean.vue +24 -14
  96. package/modules/@apostrophecms/schema/ui/apos/components/AposInputCheckboxes.vue +7 -6
  97. package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +10 -7
  98. package/modules/@apostrophecms/schema/ui/apos/components/AposInputObject.vue +3 -3
  99. package/modules/@apostrophecms/schema/ui/apos/components/AposInputPassword.vue +6 -4
  100. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRadio.vue +5 -4
  101. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRange.vue +9 -6
  102. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +15 -12
  103. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSelect.vue +1 -1
  104. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +16 -12
  105. package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +19 -11
  106. package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +15 -12
  107. package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +75 -22
  108. package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +1 -1
  109. package/modules/@apostrophecms/schema/ui/apos/components/AposSubform.vue +2 -2
  110. package/modules/@apostrophecms/schema/ui/apos/logic/AposArrayEditor.js +0 -4
  111. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArea.js +3 -3
  112. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArray.js +15 -4
  113. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputAttachment.js +3 -3
  114. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputCheckboxes.js +7 -7
  115. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputColor.js +5 -8
  116. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputDateAndTime.js +1 -1
  117. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputObject.js +1 -1
  118. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRadio.js +1 -1
  119. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRelationship.js +12 -9
  120. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSelect.js +3 -3
  121. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputString.js +7 -9
  122. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputWrapper.js +4 -4
  123. package/modules/@apostrophecms/schema/ui/apos/logic/AposSchema.js +42 -13
  124. package/modules/@apostrophecms/schema/ui/apos/logic/AposSubform.js +1 -1
  125. package/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js +9 -9
  126. package/modules/@apostrophecms/schema/ui/apos/scss/AposInputArray.scss +205 -0
  127. package/modules/@apostrophecms/settings/ui/apos/components/AposSettingsManager.vue +5 -5
  128. package/modules/@apostrophecms/settings/ui/apos/logic/AposSettingsManager.js +4 -4
  129. package/modules/@apostrophecms/submitted-draft/ui/apos/components/AposSubmittedDraftIcon.vue +5 -4
  130. package/modules/@apostrophecms/task/index.js +2 -0
  131. package/modules/@apostrophecms/translation/index.js +233 -0
  132. package/modules/@apostrophecms/translation/ui/apos/components/AposTranslationIndicator.vue +84 -0
  133. package/modules/@apostrophecms/ui/ui/apos/components/AposAvatar.vue +2 -1
  134. package/modules/@apostrophecms/ui/ui/apos/components/AposButton.vue +4 -4
  135. package/modules/@apostrophecms/ui/ui/apos/components/AposButtonGroup.vue +6 -6
  136. package/modules/@apostrophecms/ui/ui/apos/components/AposButtonSplit.vue +120 -113
  137. package/modules/@apostrophecms/ui/ui/apos/components/AposCellButton.vue +2 -1
  138. package/modules/@apostrophecms/ui/ui/apos/components/AposCellLabels.vue +49 -5
  139. package/modules/@apostrophecms/ui/ui/apos/components/AposCheckbox.vue +19 -19
  140. package/modules/@apostrophecms/ui/ui/apos/components/AposCloudUploadIcon.vue +10 -5
  141. package/modules/@apostrophecms/ui/ui/apos/components/AposCombo.vue +15 -15
  142. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +214 -191
  143. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuDialog.vue +77 -65
  144. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuItem.vue +1 -1
  145. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuTip.vue +28 -50
  146. package/modules/@apostrophecms/ui/ui/apos/components/AposEmptyState.vue +3 -3
  147. package/modules/@apostrophecms/ui/ui/apos/components/AposFile.vue +5 -5
  148. package/modules/@apostrophecms/ui/ui/apos/components/AposFilterMenu.vue +4 -4
  149. package/modules/@apostrophecms/ui/ui/apos/components/AposIndicator.vue +1 -1
  150. package/modules/@apostrophecms/ui/ui/apos/components/AposLabel.vue +1 -1
  151. package/modules/@apostrophecms/ui/ui/apos/components/AposMinMaxCount.vue +5 -5
  152. package/modules/@apostrophecms/ui/ui/apos/components/AposPager.vue +14 -8
  153. package/modules/@apostrophecms/ui/ui/apos/components/AposPagerDots.vue +2 -1
  154. package/modules/@apostrophecms/ui/ui/apos/components/AposSlat.vue +13 -12
  155. package/modules/@apostrophecms/ui/ui/apos/components/AposSlatList.vue +53 -59
  156. package/modules/@apostrophecms/ui/ui/apos/components/AposSpinner.vue +2 -2
  157. package/modules/@apostrophecms/ui/ui/apos/components/AposSubformPreview.vue +2 -2
  158. package/modules/@apostrophecms/ui/ui/apos/components/AposTag.vue +3 -2
  159. package/modules/@apostrophecms/ui/ui/apos/components/AposTagApply.vue +40 -35
  160. package/modules/@apostrophecms/ui/ui/apos/components/AposTagListItem.vue +2 -1
  161. package/modules/@apostrophecms/ui/ui/apos/components/AposToggle.vue +2 -2
  162. package/modules/@apostrophecms/ui/ui/apos/components/AposTree.vue +9 -11
  163. package/modules/@apostrophecms/ui/ui/apos/components/AposTreeHeader.vue +5 -3
  164. package/modules/@apostrophecms/ui/ui/apos/components/AposTreeRows.vue +129 -129
  165. package/modules/@apostrophecms/ui/ui/apos/composables/AposTheme.js +11 -0
  166. package/modules/@apostrophecms/ui/ui/apos/lib/click-outside-element.js +4 -4
  167. package/modules/@apostrophecms/ui/ui/apos/lib/i18next.js +56 -50
  168. package/modules/@apostrophecms/ui/ui/apos/lib/tooltip.js +191 -0
  169. package/modules/@apostrophecms/ui/ui/apos/lib/vue.js +19 -10
  170. package/modules/@apostrophecms/ui/ui/apos/mixins/AposAdvisoryLockMixin.js +1 -1
  171. package/modules/@apostrophecms/ui/ui/apos/scss/global/_tables.scss +1 -1
  172. package/modules/@apostrophecms/ui/ui/apos/scss/global/_theme.scss +1 -0
  173. package/modules/@apostrophecms/ui/ui/apos/scss/global/_tooltips.scss +6 -22
  174. package/modules/@apostrophecms/ui/ui/apos/scss/shared/_table-rows.scss +1 -1
  175. package/modules/@apostrophecms/widget-type/index.js +8 -2
  176. package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +26 -22
  177. package/modules/@apostrophecms/widget-type/ui/apos/mixins/AposWidgetMixin.js +4 -4
  178. package/package.json +31 -44
  179. package/test/attachments.js +5 -0
  180. package/test/schemas.js +138 -0
  181. package/test/translation.js +538 -0
  182. package/test-lib/util.js +21 -0
  183. package/modules/@apostrophecms/ui/ui/apos/lib/localized-v-tooltip.js +0 -63
  184. package/modules/@apostrophecms/ui/ui/apos/lib/tooltip-options.js +0 -13
@@ -4,11 +4,14 @@
4
4
  // each app
5
5
 
6
6
  import i18next from 'i18next';
7
+ let i18n;
7
8
 
8
9
  export default {
9
10
 
10
- install(Vue, options) {
11
- const i18n = options.i18n;
11
+ install(app, options) {
12
+ if (!i18n) {
13
+ i18n = options.i18n;
14
+ }
12
15
 
13
16
  const fallbackLng = [ i18n.defaultLocale ];
14
17
  // In case the default locale also has inadequate admin UI phrases
@@ -67,56 +70,59 @@ export default {
67
70
  // property for instance. You may also specify
68
71
  // `localize: false` to pass a string through without
69
72
  // invoking i18next.
70
- Vue.prototype.$t = (key, options = {}) => {
71
- if ((key !== null) && ((typeof key) === 'object')) {
72
- options = key;
73
- key = options.key;
74
- }
75
- if (options.localize === false) {
76
- return key;
77
- }
78
- // Check carefully for empty string and equivalent scenarios
79
- // before doing any work
80
- if (key == null) {
81
- return '';
82
- }
83
- key += '';
84
- if (!key.length) {
85
- return '';
86
- }
87
- const result = i18next.t(key, {
88
- lng: i18n.adminLocale,
89
- ...options
90
- });
91
- if (i18n.show) {
92
- if (result === key) {
93
- if (key.match(/^\S+:/)) {
94
- // The l10n key does not have a value assigned (or the key is
95
- // actually the same as the phrase). The key seems to have a
96
- // namespace, so might be from the Apostrophe UI.
97
- return `❌ ${result}`;
98
- } else {
99
- // The l10n key does not have a value assigned (or the key is
100
- // actually the same as the phrase). It is in the default namespace.
101
- return `🕳 ${result}`;
102
- }
103
- } else {
104
- // The phrase is fully localized.
105
- return `🌍 ${result}`;
106
- }
107
- } else {
108
- return result;
109
- }
110
- };
73
+ app.config.globalProperties.$t = $t;
74
+ }
75
+ };
111
76
 
112
- function canonicalize(locale) {
113
- const [ language, territory ] = locale.split('-');
114
- if (territory) {
115
- return `${language}-${territory.toUpperCase()}`;
77
+ export function $t(key, options = {}) {
78
+ if (!i18n) {
79
+ return '';
80
+ }
81
+ if ((key !== null) && ((typeof key) === 'object')) {
82
+ options = key;
83
+ key = options.key;
84
+ }
85
+ if (options.localize === false) {
86
+ return key;
87
+ }
88
+ // Check carefully for empty string and equivalent scenarios
89
+ // before doing any work
90
+ if (key == null) {
91
+ return '';
92
+ }
93
+ key += '';
94
+ if (!key.length) {
95
+ return '';
96
+ }
97
+ const result = i18next.t(key, {
98
+ lng: i18n.adminLocale,
99
+ ...options
100
+ });
101
+ if (i18n.show) {
102
+ if (result === key) {
103
+ if (key.match(/^\S+:/)) {
104
+ // The l10n key does not have a value assigned (or the key is
105
+ // actually the same as the phrase). The key seems to have a
106
+ // namespace, so might be from the Apostrophe UI.
107
+ return `❌ ${result}`;
108
+ } else {
109
+ // The l10n key does not have a value assigned (or the key is
110
+ // actually the same as the phrase). It is in the default namespace.
111
+ return `🕳 ${result}`;
116
112
  }
117
- return locale;
113
+ } else {
114
+ // The phrase is fully localized.
115
+ return `🌍 ${result}`;
118
116
  }
119
-
117
+ } else {
118
+ return result;
120
119
  }
121
-
122
120
  };
121
+
122
+ function canonicalize(locale) {
123
+ const [ language, territory ] = locale.split('-');
124
+ if (territory) {
125
+ return `${language}-${territory.toUpperCase()}`;
126
+ }
127
+ return locale;
128
+ }
@@ -0,0 +1,191 @@
1
+ // Vue plugin. Create a new directive with i18n support by applying the decorator
2
+ import { $t } from './i18next';
3
+ import {
4
+ computePosition, arrow, offset, shift
5
+ } from '@floating-ui/dom';
6
+ import cuid from 'cuid';
7
+ import { isEqual } from 'lodash';
8
+
9
+ const getTooltipHtml = (id, tooltip) =>
10
+ `<div id="${id}" class="apos-tooltip" role="tooltip">
11
+ <div class="apos-tooltip__wrapper">
12
+ <div class="apos-tooltip__arrow"></div>
13
+ <div class="apos-tooltip__inner">
14
+ ${tooltip}
15
+ </div>
16
+ </div>
17
+ </div>`;
18
+
19
+ export default {
20
+ install(app) {
21
+ app.directive('apos-tooltip', {
22
+ mounted(el, binding, vnodes) {
23
+ addEventListeners(el, binding);
24
+ },
25
+ updated(el, binding) {
26
+ const contentValue = Object.hasOwn(binding.value || {}, 'content')
27
+ ? binding.value.content
28
+ : binding.value;
29
+ const oldValue = Object.hasOwn(binding.oldValue || {}, 'content')
30
+ ? binding.oldValue.content
31
+ : binding.oldValue;
32
+
33
+ if (isEqual(contentValue, oldValue)) {
34
+ return;
35
+ }
36
+
37
+ if (el.aposShowTooltipListener) {
38
+ removeEventListeners(el);
39
+ }
40
+
41
+ addEventListeners(el, binding);
42
+ },
43
+ beforeUnmount(el, binding) {
44
+ removeEventListeners(el);
45
+ }
46
+ });
47
+
48
+ function addEventListeners(el, binding) {
49
+ let tooltipTimeout;
50
+ let delayTimeout;
51
+ if (!binding.value && !binding.value?.content) {
52
+ return;
53
+ }
54
+
55
+ const delay = binding.value?.delay;
56
+ const localized = localize(binding.value, app);
57
+ if (!localized) {
58
+ return;
59
+ }
60
+ const tooltipId = `tooltip__${cuid()}`;
61
+
62
+ // Attach event listeners to elements to retrieve them in beforeUnmount
63
+ el.aposShowTooltipListener = setupShowTooltip({
64
+ el,
65
+ value: binding.value,
66
+ tooltipTimeout,
67
+ delayTimeout,
68
+ tooltipId,
69
+ localized
70
+ });
71
+ el.aposHideTooltipListener = setupHideTooltip({
72
+ tooltipId,
73
+ tooltipTimeout,
74
+ delayTimeout,
75
+ delay
76
+ });
77
+
78
+ el.addEventListener('mouseenter', el.aposShowTooltipListener);
79
+ el.addEventListener('mouseleave', el.aposHideTooltipListener);
80
+ el.addEventListener('click', el.aposHideTooltipListener);
81
+
82
+ }
83
+
84
+ function removeEventListeners(el) {
85
+ if (el.aposHideTooltipListener) {
86
+ el.aposHideTooltipListener(true);
87
+ }
88
+ el.removeEventListener('mouseenter', el.aposShowTooltipListener);
89
+ el.removeEventListener('mouseleave', el.aposHideTooltipListener);
90
+ el.removeEventListener('click', el.aposHideTooltipListener);
91
+ }
92
+
93
+ function setupShowTooltip({
94
+ el, value, tooltipTimeout, delayTimeout, tooltipId, localized
95
+ }) {
96
+ return async () => {
97
+ if (tooltipTimeout) {
98
+ clearTimeout(tooltipTimeout);
99
+ }
100
+ if (delayTimeout) {
101
+ clearTimeout(delayTimeout);
102
+ }
103
+
104
+ const existingEl = document.querySelector(`#${tooltipId}`);
105
+ if (!existingEl) {
106
+ document.body.insertAdjacentHTML('beforeend', getTooltipHtml(tooltipId, localized));
107
+ } else {
108
+ existingEl.setAttribute('aria-hidden', false);
109
+ }
110
+
111
+ const tooltipEl = existingEl || document.querySelector(`#${tooltipId}`);
112
+ if (!tooltipEl) {
113
+ return;
114
+ }
115
+
116
+ const arrowEl = tooltipEl.querySelector('.apos-tooltip__arrow');
117
+
118
+ const {
119
+ x, y, middlewareData, placement
120
+ } = await computePosition(el, tooltipEl, {
121
+ placement: value.placement || 'bottom-end',
122
+ middleware: [
123
+ offset(11),
124
+ shift({ padding: 5 }),
125
+ arrow({
126
+ element: arrowEl,
127
+ padding: 10
128
+ })
129
+ ]
130
+ });
131
+
132
+ const [ sidePosition ] = placement.split('-');
133
+
134
+ const { x: arrowX, y: arrowY } = middlewareData.arrow;
135
+ if (!existingEl) {
136
+ tooltipEl.setAttribute('x-placement', sidePosition);
137
+ tooltipEl.setAttribute('aria-hidden', false);
138
+ }
139
+ Object.assign(tooltipEl.style, {
140
+ left: `${x}px`,
141
+ top: `${y}px`
142
+ });
143
+
144
+ Object.assign(arrowEl.style, {
145
+ ...arrowX && { left: `${arrowX}px` },
146
+ ...arrowY && { top: `${arrowY}px` }
147
+ });
148
+ };
149
+ }
150
+
151
+ function setupHideTooltip({
152
+ tooltipId, tooltipTimeout, delayTimeout, delay
153
+ }) {
154
+ return (immediate = false) => {
155
+ const tooltipEl = document.querySelector(`#${tooltipId}`);
156
+ if (!tooltipEl) {
157
+ return;
158
+ }
159
+
160
+ if (immediate) {
161
+ tooltipEl.remove();
162
+ return;
163
+ }
164
+
165
+ if (delay) {
166
+ delayTimeout = setTimeout(() => {
167
+ tooltipEl.setAttribute('aria-hidden', true);
168
+ }, delay);
169
+ } else {
170
+ tooltipEl.setAttribute('aria-hidden', true);
171
+ }
172
+
173
+ tooltipTimeout = setTimeout(() => {
174
+ tooltipEl.remove();
175
+ }, 5000);
176
+ };
177
+ }
178
+
179
+ function localize(value) {
180
+ if (!value) {
181
+ return;
182
+ }
183
+
184
+ if (value.content) {
185
+ return (value.localize === false) ? value.content : $t(value.content);
186
+ }
187
+
188
+ return $t(value);
189
+ }
190
+ }
191
+ };
@@ -1,14 +1,23 @@
1
- import Vue from 'vue';
1
+ import { createApp } from 'vue';
2
2
  import ClickOutsideElement from './click-outside-element';
3
- import LocalizedVTooltip from './localized-v-tooltip';
4
- import tooltipOptions from './tooltip-options';
3
+ import Tooltip from './tooltip';
5
4
  import VueAposI18Next from './i18next';
6
5
 
7
- Vue.use(LocalizedVTooltip, tooltipOptions);
8
- Vue.use(ClickOutsideElement);
9
- Vue.use(VueAposI18Next, {
10
- // Module aliases are not available yet when this code executes
11
- i18n: apos.modules['@apostrophecms/i18n']
12
- });
6
+ export default (appConfig, props = {}) => {
7
+ const app = createApp(appConfig, props);
13
8
 
14
- export default Vue;
9
+ app.use(VueAposI18Next, {
10
+ // Module aliases are not available yet when this code executes
11
+ i18n: apos.modules['@apostrophecms/i18n']
12
+ });
13
+ app.use(Tooltip);
14
+ app.use(ClickOutsideElement);
15
+
16
+ const sources = [ window.apos.vueComponents, window.apos.iconComponents ];
17
+ for (const source of sources) {
18
+ for (const [ name, component ] of Object.entries(source)) {
19
+ app.component(name, component);
20
+ }
21
+ }
22
+ return app;
23
+ };
@@ -12,7 +12,7 @@ export default {
12
12
  lockApiUrl: null
13
13
  };
14
14
  },
15
- async destroyed () {
15
+ async unmounted () {
16
16
  await this.unlock();
17
17
  },
18
18
  methods: {
@@ -43,7 +43,7 @@ span.apos-table__header-label:hover {
43
43
  cursor: auto;
44
44
  }
45
45
 
46
- .apos-table ::v-deep .apos-choice-label {
46
+ .apos-table :deep(.apos-choice-label) {
47
47
  margin-top: 0;
48
48
  }
49
49
 
@@ -8,6 +8,7 @@
8
8
  --a-warning-dark: #a75c07;
9
9
  --a-warning-fade: #ffce0030;
10
10
  --a-progress-bg: #2c354d;
11
+ --a-highlight: #fff6e8;
11
12
 
12
13
  --a-danger-button-hover: #c00717;
13
14
  --a-danger-button-active: #a10000;
@@ -2,7 +2,9 @@
2
2
  // https://github.com/Akryum/v-tooltip/blob/83615e394c96ca491a4df04b892ae87e833beb97/demo-src/src/App.vue#L179-L303
3
3
  .apos-tooltip {
4
4
  z-index: $z-index-notifications;
5
+ position: absolute;
5
6
  display: block;
7
+ width: max-content;
6
8
  max-width: 285px;
7
9
  /* stylelint-disable-next-line time-min-milliseconds */
8
10
  transition-delay: 0.1s;
@@ -32,6 +34,7 @@
32
34
 
33
35
  .apos-tooltip__inner {
34
36
  @include type-small;
37
+
35
38
  z-index: $z-index-default;
36
39
  position: relative;
37
40
  padding: 8px 10px;
@@ -46,7 +49,6 @@
46
49
  position: absolute;
47
50
  width: 8px;
48
51
  height: 8px;
49
- margin: 5px;
50
52
  border-radius: 1px;
51
53
  // Solid border style needed to work with v-apos-tooltip placement.
52
54
  border-style: solid;
@@ -56,50 +58,31 @@
56
58
  }
57
59
 
58
60
  &[x-placement^='top'] {
59
- margin-bottom: 5px;
60
-
61
61
  .apos-tooltip__arrow {
62
62
  bottom: -4px;
63
- left: calc(50% - 5px);
64
- margin-top: 0;
65
- margin-bottom: 0;
66
63
  }
67
64
  }
68
65
 
69
66
  &[x-placement^='bottom'] {
70
- margin-top: 5px;
71
-
72
67
  .apos-tooltip__arrow {
73
68
  top: -3px;
74
- left: calc(50% - 5px);
75
- margin-top: 0;
76
- margin-bottom: 0;
77
69
  }
78
70
  }
79
71
 
80
72
  &[x-placement^='right'] {
81
- margin-left: 5px;
82
-
83
73
  .apos-tooltip__arrow {
84
- top: calc(50% - 5px);
85
74
  left: -3px;
86
- margin-left: 0;
87
- margin-right: 0;
88
75
  }
89
76
  }
90
77
 
91
78
  &[x-placement^='left'] {
92
- margin-right: 5px;
93
-
94
79
  .apos-tooltip__arrow {
95
- top: calc(50% - 5px);
96
80
  right: -3px;
97
- margin-left: 0;
98
- margin-right: 0;
99
81
  }
100
82
  }
101
83
 
102
84
  &[aria-hidden='true'] {
85
+ display: none;
103
86
  visibility: hidden;
104
87
  opacity: 0;
105
88
  transition: opacity 0.15s, visibilty 0.15s;
@@ -109,6 +92,7 @@
109
92
  }
110
93
 
111
94
  &[aria-hidden='false'] {
95
+ display: initial;
112
96
  visibility: visible;
113
97
  opacity: 1;
114
98
  transition: opacity 0.15s;
@@ -123,4 +107,4 @@
123
107
  /* stylelint-disable-next-line time-min-milliseconds */
124
108
  transition-delay: 0.1s;
125
109
  transform: scale(0.8);
126
- }
110
+ }
@@ -26,7 +26,7 @@ span.apos-tree__cell:first-of-type {
26
26
  margin-left: 5px;
27
27
  }
28
28
 
29
- .apos-tree__cell[disabled] {
29
+ .apos-tree__cell[disabled='true'] {
30
30
  color: $input-color-disabled;
31
31
  &:hover {
32
32
  cursor: not-allowed;
@@ -100,7 +100,11 @@ module.exports = {
100
100
  neverLoadSelf: true,
101
101
  initialModal: true,
102
102
  placeholder: false,
103
- placeholderClass: 'apos-placeholder'
103
+ placeholderClass: 'apos-placeholder',
104
+ // two-thirds, half or full:
105
+ width: '',
106
+ // left or right:
107
+ origin: 'right'
104
108
  },
105
109
  init(self) {
106
110
  const badFieldName = Object.keys(self.fields).indexOf('type') !== -1;
@@ -400,7 +404,9 @@ module.exports = {
400
404
  contextual: self.options.contextual,
401
405
  placeholderClass: self.options.placeholderClass,
402
406
  className: self.options.className,
403
- components: self.options.components
407
+ components: self.options.components,
408
+ width: self.options.width,
409
+ origin: self.options.origin
404
410
  });
405
411
  return result;
406
412
  }
@@ -1,13 +1,17 @@
1
1
  <template>
2
2
  <AposModal
3
3
  class="apos-widget-editor"
4
- :modal="modal" :modal-title="editLabel"
5
- @inactive="modal.active = false" @show-modal="modal.showModal = true"
6
- @esc="confirmAndCancel" @no-modal="$emit('safe-close')"
4
+ :modal="modal"
5
+ :modal-title="editLabel"
6
+ @inactive="modal.active = false"
7
+ @show-modal="modal.showModal = true"
8
+ @esc="confirmAndCancel"
9
+ @no-modal="$emit('safe-close')"
7
10
  >
8
11
  <template #breadcrumbs>
9
12
  <AposModalBreadcrumbs
10
- v-if="breadcrumbs && breadcrumbs.length" :items="breadcrumbs"
13
+ v-if="breadcrumbs && breadcrumbs.length"
14
+ :items="breadcrumbs"
11
15
  />
12
16
  </template>
13
17
  <template #main>
@@ -15,15 +19,15 @@
15
19
  <template #bodyMain>
16
20
  <div class="apos-widget-editor__body">
17
21
  <AposSchema
22
+ ref="schema"
18
23
  :trigger-validation="triggerValidation"
19
24
  :schema="schema"
20
- :value="docFields"
25
+ :model-value="docFields"
21
26
  :meta="meta"
22
- @input="updateDocFields"
23
- @validate="triggerValidate"
24
27
  :following-values="followingValues()"
25
28
  :conditional-fields="conditionalFields"
26
- ref="schema"
29
+ @update:model-value="updateDocFields"
30
+ @validate="triggerValidate"
27
31
  />
28
32
  </div>
29
33
  </template>
@@ -31,13 +35,15 @@
31
35
  </template>
32
36
  <template #footer>
33
37
  <AposButton
34
- type="default" label="apostrophe:cancel"
38
+ type="default"
39
+ label="apostrophe:cancel"
35
40
  @click="confirmAndCancel"
36
41
  />
37
42
  <AposButton
38
- type="primary" @click="save"
43
+ type="primary"
39
44
  :label="saveLabel"
40
45
  :disabled="docFields.hasErrors"
46
+ @click="save"
41
47
  />
42
48
  </template>
43
49
  </AposModal>
@@ -68,7 +74,7 @@ export default {
68
74
  required: true,
69
75
  type: Object
70
76
  },
71
- value: {
77
+ modelValue: {
72
78
  required: false,
73
79
  type: Object,
74
80
  default() {
@@ -92,8 +98,10 @@ export default {
92
98
  },
93
99
  emits: [ 'safe-close', 'modal-result' ],
94
100
  data() {
101
+ const moduleOptions = window.apos.modules[apos.area.widgetManagers[this.type]];
102
+
95
103
  return {
96
- id: this.value && this.value._id,
104
+ id: this.modelValue && this.modelValue._id,
97
105
  original: null,
98
106
  docFields: {
99
107
  data: {},
@@ -103,6 +111,8 @@ export default {
103
111
  title: this.editLabel,
104
112
  active: false,
105
113
  type: 'slide',
114
+ width: moduleOptions.width,
115
+ origin: moduleOptions.origin,
106
116
  showModal: false
107
117
  },
108
118
  triggerValidation: false
@@ -151,17 +161,17 @@ export default {
151
161
  ...apos.area.widgetOptions
152
162
  ];
153
163
  },
154
- destroyed() {
164
+ unmounted() {
155
165
  apos.area.widgetOptions = apos.area.widgetOptions.slice(1);
156
166
  },
157
167
  created() {
158
168
  const defaults = this.getDefault();
159
169
 
160
- if (this.value) {
161
- this.original = klona(this.value);
170
+ if (this.modelValue) {
171
+ this.original = klona(this.modelValue);
162
172
  this.docFields.data = {
163
173
  ...defaults,
164
- ...this.value
174
+ ...this.modelValue
165
175
  };
166
176
  return;
167
177
  }
@@ -218,9 +228,3 @@ export default {
218
228
  }
219
229
  };
220
230
  </script>
221
-
222
- <style lang="scss" scoped>
223
- .apos-widget-editor ::v-deep .apos-modal__inner {
224
- max-width: 458px;
225
- }
226
- </style>
@@ -6,7 +6,7 @@ export default {
6
6
  docId: String,
7
7
  type: String,
8
8
  areaFieldId: String,
9
- value: Object,
9
+ modelValue: Object,
10
10
  meta: {
11
11
  type: Object,
12
12
  default() {
@@ -26,7 +26,7 @@ export default {
26
26
  }
27
27
  },
28
28
  watch: {
29
- value: {
29
+ modelValue: {
30
30
  handler() {
31
31
  this.renderContent();
32
32
  }
@@ -50,7 +50,7 @@ export default {
50
50
  apos.bus.$emit('widget-rendering');
51
51
  const parameters = {
52
52
  _docId: this.docId,
53
- widget: this.value,
53
+ widget: this.modelValue,
54
54
  areaFieldId: this.areaFieldId,
55
55
  type: this.type
56
56
  };
@@ -83,7 +83,7 @@ export default {
83
83
  }
84
84
 
85
85
  return {
86
- [placeholderClass]: this.value.aposPlaceholder === true
86
+ [placeholderClass]: this.modelValue.aposPlaceholder === true
87
87
  };
88
88
  }
89
89
  }