apostrophe 4.6.1 → 4.7.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 (124) hide show
  1. package/.github/workflows/main.yml +1 -1
  2. package/CHANGELOG.md +39 -1
  3. package/lib/big-upload-client.js +100 -0
  4. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBar.vue +5 -3
  5. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +6 -3
  6. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarUser.vue +4 -1
  7. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +24 -16
  8. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +1 -0
  9. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposSavingIndicator.vue +7 -5
  10. package/modules/@apostrophecms/area/index.js +5 -2
  11. package/modules/@apostrophecms/area/ui/apos/components/AposAreaContextualMenu.vue +20 -12
  12. package/modules/@apostrophecms/area/ui/apos/components/AposAreaExpandedMenu.vue +11 -7
  13. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenu.vue +20 -12
  14. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenuItem.vue +3 -1
  15. package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +15 -11
  16. package/modules/@apostrophecms/attachment/index.js +4 -2
  17. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuKey.vue +28 -24
  18. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuShortcut.vue +17 -11
  19. package/modules/@apostrophecms/doc/index.js +22 -19
  20. package/modules/@apostrophecms/doc-type/index.js +6 -2
  21. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +9 -5
  22. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocLocalePicker.vue +10 -5
  23. package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +12 -0
  24. package/modules/@apostrophecms/http/index.js +19 -3
  25. package/modules/@apostrophecms/http/lib/big-upload-middleware.js +251 -0
  26. package/modules/@apostrophecms/i18n/i18n/de.json +1 -1
  27. package/modules/@apostrophecms/i18n/i18n/en.json +9 -1
  28. package/modules/@apostrophecms/i18n/i18n/es.json +1 -1
  29. package/modules/@apostrophecms/i18n/i18n/fr.json +1 -1
  30. package/modules/@apostrophecms/i18n/i18n/it.json +1 -1
  31. package/modules/@apostrophecms/i18n/i18n/pt-BR.json +1 -1
  32. package/modules/@apostrophecms/i18n/i18n/sk.json +1 -1
  33. package/modules/@apostrophecms/i18n/index.js +3 -0
  34. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +30 -16
  35. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalizeErrors.vue +7 -5
  36. package/modules/@apostrophecms/image/ui/apos/components/AposImageCropper.vue +5 -1
  37. package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +10 -6
  38. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +40 -18
  39. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerDisplay.vue +35 -25
  40. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +11 -5
  41. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerSelections.vue +15 -9
  42. package/modules/@apostrophecms/image/ui/apos/components/AposMediaUploader.vue +39 -31
  43. package/modules/@apostrophecms/job/index.js +1 -1
  44. package/modules/@apostrophecms/login/ui/apos/components/AposLoginForm.vue +9 -7
  45. package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +17 -13
  46. package/modules/@apostrophecms/login/ui/apos/components/TheAposLoginHeader.vue +30 -20
  47. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +5 -0
  48. package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +4 -1
  49. package/modules/@apostrophecms/modal/ui/apos/components/AposModalBreadcrumbs.vue +8 -4
  50. package/modules/@apostrophecms/modal/ui/apos/components/AposModalConfirm.vue +14 -8
  51. package/modules/@apostrophecms/modal/ui/apos/components/AposModalShareDraft.vue +32 -22
  52. package/modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue +16 -14
  53. package/modules/@apostrophecms/modal/ui/apos/components/AposWidgetModalTabs.vue +16 -14
  54. package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +93 -91
  55. package/modules/@apostrophecms/page/index.js +482 -13
  56. package/modules/@apostrophecms/page/ui/apos/components/AposPagesManager.vue +43 -23
  57. package/modules/@apostrophecms/page/ui/apos/logic/AposPagesManager.js +248 -156
  58. package/modules/@apostrophecms/permission/ui/apos/components/AposPermissionGrid.vue +9 -5
  59. package/modules/@apostrophecms/piece-type/index.js +7 -7
  60. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +92 -36
  61. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +30 -24
  62. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapDivider.vue +4 -2
  63. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapLink.vue +2 -1
  64. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapMarks.vue +5 -3
  65. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapStyles.vue +5 -3
  66. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapTable.vue +5 -2
  67. package/modules/@apostrophecms/schema/index.js +26 -5
  68. package/modules/@apostrophecms/schema/lib/addFieldTypes.js +42 -9
  69. package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +4 -2
  70. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRange.vue +8 -4
  71. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +6 -4
  72. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +5 -3
  73. package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +19 -13
  74. package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +6 -2
  75. package/modules/@apostrophecms/schema/ui/apos/components/AposSubform.vue +6 -4
  76. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSlug.js +28 -25
  77. package/modules/@apostrophecms/schema/ui/apos/scss/AposInputArray.scss +13 -7
  78. package/modules/@apostrophecms/settings/ui/apos/components/AposSettingsManager.vue +11 -6
  79. package/modules/@apostrophecms/translation/ui/apos/components/AposTranslationIndicator.vue +5 -3
  80. package/modules/@apostrophecms/ui/ui/apos/components/AposAvatar.vue +14 -12
  81. package/modules/@apostrophecms/ui/ui/apos/components/AposButton.vue +14 -11
  82. package/modules/@apostrophecms/ui/ui/apos/components/AposButtonSplit.vue +7 -3
  83. package/modules/@apostrophecms/ui/ui/apos/components/AposCellContextMenu.vue +4 -2
  84. package/modules/@apostrophecms/ui/ui/apos/components/AposCombo.vue +23 -17
  85. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +25 -10
  86. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuDialog.vue +7 -5
  87. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuItem.vue +10 -8
  88. package/modules/@apostrophecms/ui/ui/apos/components/AposEmptyState.vue +9 -5
  89. package/modules/@apostrophecms/ui/ui/apos/components/AposFile.vue +9 -6
  90. package/modules/@apostrophecms/ui/ui/apos/components/AposIndicator.vue +5 -0
  91. package/modules/@apostrophecms/ui/ui/apos/components/AposLoadingBlock.vue +3 -1
  92. package/modules/@apostrophecms/ui/ui/apos/components/AposLocale.vue +3 -1
  93. package/modules/@apostrophecms/ui/ui/apos/components/AposLocalePicker.vue +11 -9
  94. package/modules/@apostrophecms/ui/ui/apos/components/AposMinMaxCount.vue +5 -3
  95. package/modules/@apostrophecms/ui/ui/apos/components/AposPager.vue +4 -2
  96. package/modules/@apostrophecms/ui/ui/apos/components/AposPagerDots.vue +8 -6
  97. package/modules/@apostrophecms/ui/ui/apos/components/AposSlat.vue +25 -17
  98. package/modules/@apostrophecms/ui/ui/apos/components/AposSlatList.vue +5 -9
  99. package/modules/@apostrophecms/ui/ui/apos/components/AposSubformPreview.vue +10 -6
  100. package/modules/@apostrophecms/ui/ui/apos/components/AposTag.vue +9 -7
  101. package/modules/@apostrophecms/ui/ui/apos/components/AposTagApply.vue +8 -4
  102. package/modules/@apostrophecms/ui/ui/apos/components/AposTagList.vue +4 -2
  103. package/modules/@apostrophecms/ui/ui/apos/components/AposTagListItem.vue +7 -5
  104. package/modules/@apostrophecms/ui/ui/apos/components/AposToggle.vue +16 -0
  105. package/modules/@apostrophecms/ui/ui/apos/components/AposTree.vue +3 -1
  106. package/modules/@apostrophecms/ui/ui/apos/components/AposTreeRows.vue +11 -9
  107. package/modules/@apostrophecms/ui/ui/apos/mixins/AposArchiveMixin.js +2 -2
  108. package/modules/@apostrophecms/ui/ui/apos/mixins/AposPublishMixin.js +6 -6
  109. package/modules/@apostrophecms/ui/ui/apos/scss/global/_inputs.scss +30 -22
  110. package/modules/@apostrophecms/ui/ui/apos/scss/global/_theme.scss +22 -18
  111. package/modules/@apostrophecms/ui/ui/apos/scss/global/_tooltips.scss +18 -15
  112. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_input_mixins.scss +8 -6
  113. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_mixins.scss +3 -1
  114. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_theme_mixins.scss +34 -19
  115. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_type_mixins.scss +3 -1
  116. package/modules/@apostrophecms/ui/ui/apos/utils/index.js +140 -51
  117. package/modules/@apostrophecms/widget-type/index.js +3 -2
  118. package/modules/@apostrophecms/widget-type/ui/apos/mixins/AposWidgetMixin.js +5 -1
  119. package/package.json +5 -6
  120. package/test/big-upload.js +111 -0
  121. package/test/change-doc-ids.js +60 -1
  122. package/test/pages.js +488 -0
  123. package/test/schemas.js +327 -0
  124. package/test/utils.js +266 -5
@@ -143,14 +143,16 @@ export default {
143
143
  .apos-field__label {
144
144
  @include type-label;
145
145
 
146
- display: flex;
147
- flex-wrap: nowrap;
148
- align-items: center;
149
- justify-content: space-between;
150
- margin: 0 0 $spacing-base;
151
- padding: 0;
152
- color: var(--a-text-primary);
153
- gap: $spacing-double;
146
+ & {
147
+ display: flex;
148
+ flex-wrap: nowrap;
149
+ align-items: center;
150
+ justify-content: space-between;
151
+ margin: 0 0 $spacing-base;
152
+ padding: 0;
153
+ color: var(--a-text-primary);
154
+ gap: $spacing-double;
155
+ }
154
156
 
155
157
  &.apos-field__label--meta-left {
156
158
  justify-content: flex-start;
@@ -180,9 +182,11 @@ export default {
180
182
  .apos-field__help {
181
183
  @include type-base;
182
184
 
183
- margin: 0 0 $spacing-base;
184
- line-height: var(--a-line-tall);
185
- color: var(--a-base-3);
185
+ & {
186
+ margin: 0 0 $spacing-base;
187
+ line-height: var(--a-line-tall);
188
+ color: var(--a-base-3);
189
+ }
186
190
  }
187
191
 
188
192
  .apos-field__help-tooltip__icon {
@@ -198,8 +202,10 @@ export default {
198
202
  .apos-field__error {
199
203
  @include type-help;
200
204
 
201
- margin: $spacing-base 0;
202
- color: var(--a-danger);
205
+ & {
206
+ margin: $spacing-base 0;
207
+ color: var(--a-danger);
208
+ }
203
209
  }
204
210
 
205
211
  .apos-field__required {
@@ -149,13 +149,17 @@ export default {
149
149
  &__title {
150
150
  @include type-base;
151
151
 
152
- color: var(--a-text-primary);
152
+ & {
153
+ color: var(--a-text-primary);
154
+ }
153
155
  }
154
156
 
155
157
  &__field {
156
158
  @include type-base;
157
159
 
158
- color: var(--a-base-2);
160
+ & {
161
+ color: var(--a-base-2);
162
+ }
159
163
  }
160
164
 
161
165
  &.apos-search__item--disabled {
@@ -111,10 +111,12 @@ export default {
111
111
  &__schema-label {
112
112
  @include type-base;
113
113
 
114
- display: block;
115
- padding-bottom: $spacing-double;
116
- color: var(--a-base-3);
117
- line-height: 1;
114
+ & {
115
+ display: block;
116
+ padding-bottom: $spacing-double;
117
+ color: var(--a-base-3);
118
+ line-height: 1;
119
+ }
118
120
  }
119
121
 
120
122
  &__controls {
@@ -1,10 +1,10 @@
1
1
  // NOTE: This is a temporary component, copying AposInputString. Base modules
2
2
  // already have `type: 'slug'` fields, so this is needed to avoid distracting
3
3
  // errors.
4
- import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin';
5
- import sluggo from 'sluggo';
6
- import debounce from 'debounce-async';
7
4
  import { klona } from 'klona';
5
+ import sluggo from 'sluggo';
6
+ import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin';
7
+ import { debounceAsync } from 'Modules/@apostrophecms/ui/utils';
8
8
 
9
9
  export default {
10
10
  name: 'AposInputSlug',
@@ -102,12 +102,17 @@ export default {
102
102
  }
103
103
  },
104
104
  async mounted() {
105
- this.debouncedCheckConflict = debounce(() => this.checkConflict(), 250);
105
+ this.debouncedCheckConflict = debounceAsync(this.requestCheckConflict, 250, {
106
+ onSuccess: this.setConflict
107
+ });
106
108
  if (this.next.length) {
107
- await this.debouncedCheckConflict();
109
+ await this.debouncedCheckConflict.skipDelay();
108
110
  }
109
111
  this.originalParentSlug = this.getParentSlug(this.next);
110
112
  },
113
+ onBeforeUnmount() {
114
+ this.debouncedCheckConflict.cancel();
115
+ },
111
116
  methods: {
112
117
  getParentSlug(slug = '') {
113
118
  return slug.slice(-1) === '/'
@@ -117,15 +122,7 @@ export default {
117
122
  async watchNext() {
118
123
  this.next = this.slugify(this.next);
119
124
  this.validateAndEmit();
120
- try {
121
- await this.debouncedCheckConflict();
122
- } catch (e) {
123
- if (e === 'canceled') {
124
- // That's fine
125
- } else {
126
- throw e;
127
- }
128
- }
125
+ await this.debouncedCheckConflict();
129
126
  },
130
127
  validate(value) {
131
128
  if (this.conflict) {
@@ -231,7 +228,7 @@ export default {
231
228
 
232
229
  return updated;
233
230
  },
234
- async checkConflict() {
231
+ async requestCheckConflict() {
235
232
  let slug;
236
233
  try {
237
234
  slug = this.next;
@@ -243,31 +240,37 @@ export default {
243
240
  },
244
241
  draft: true
245
242
  });
243
+
246
244
  // Still relevant?
247
245
  if (slug === this.next) {
248
- this.conflict = false;
249
- this.validateAndEmit();
250
- } else {
251
- // Can ignore it, another request
252
- // probably already in-flight
246
+ return false;
253
247
  }
248
+ // Should not happen, another request
249
+ // already in-flight shouldn't be possible now.
250
+ return null;
254
251
  }
255
252
  } catch (e) {
256
253
  // 409: Conflict (slug in use)
257
254
  if (e.status === 409) {
258
255
  // Still relevant?
259
256
  if (slug === this.next) {
260
- this.conflict = true;
261
- this.validateAndEmit();
262
- } else {
263
- // Can ignore it, another request
264
- // probably already in-flight
257
+ return true;
265
258
  }
259
+ // Should not happen, another request
260
+ // already in-flight shouldn't be possible now.
261
+ return null;
266
262
  } else {
267
263
  throw e;
268
264
  }
269
265
  }
270
266
  },
267
+ async setConflict(result) {
268
+ if (result === null) {
269
+ return;
270
+ }
271
+ this.conflict = result;
272
+ this.validateAndEmit();
273
+ },
271
274
  passFocus() {
272
275
  this.$refs.input.focus();
273
276
  },
@@ -46,18 +46,22 @@
46
46
  .apos-input-array-inline-empty-label {
47
47
  @include type-label;
48
48
 
49
- color: var(--a-base-3);
49
+ & {
50
+ color: var(--a-base-3);
51
+ }
50
52
  }
51
53
 
52
54
  .apos-input-array-inline-table {
53
55
  @include type-label;
54
56
 
55
- position: relative;
56
- left: -35px;
57
- min-width: calc(100% + 35px);
58
- width: max-content;
59
- margin: 0 0 $spacing-base;
60
- border-collapse: collapse;
57
+ & {
58
+ position: relative;
59
+ left: -35px;
60
+ min-width: calc(100% + 35px);
61
+ width: max-content;
62
+ margin: 0 0 $spacing-base;
63
+ border-collapse: collapse;
64
+ }
61
65
 
62
66
  th {
63
67
  height: 40px;
@@ -211,7 +215,9 @@
211
215
 
212
216
  .apos-input-array-inline-label {
213
217
  @include type-label;
218
+ }
214
219
 
220
+ .apos-input-array-inline-label {
215
221
  margin: 0;
216
222
  padding-top: $spacing-base;
217
223
  padding-bottom: $spacing-base;
@@ -122,7 +122,9 @@ export default {
122
122
  &__heading {
123
123
  @include type-title;
124
124
 
125
- margin: 0 0 $spacing-double;
125
+ & {
126
+ margin: 0 0 $spacing-double;
127
+ }
126
128
  }
127
129
 
128
130
  &__content {
@@ -143,7 +145,9 @@ export default {
143
145
  .apos-settings__group-item {
144
146
  @include type-base;
145
147
 
146
- margin-bottom: $spacing-half;
148
+ & {
149
+ margin-bottom: $spacing-half;
150
+ }
147
151
 
148
152
  &.apos-is-active {
149
153
  color: var(--a-primary);
@@ -152,10 +156,11 @@ export default {
152
156
  > button {
153
157
  @include apos-button-reset();
154
158
 
155
- width: 100%;
156
- padding: $spacing-base 0;
157
- // TODO do a11y
158
- outline: none;
159
+ & {
160
+ width: 100%;
161
+ padding: $spacing-base 0;
162
+ outline: none;
163
+ }
159
164
  }
160
165
  }
161
166
  </style>
@@ -66,9 +66,11 @@ $background: #F7FEF4;
66
66
  .apos-translation-indicator__text {
67
67
  @include type-label;
68
68
 
69
- margin: 0 0 0 4px;
70
- color: $color;
71
- font-size: var(--a-type-tiny);
69
+ & {
70
+ margin: 0 0 0 4px;
71
+ color: $color;
72
+ font-size: var(--a-type-tiny);
73
+ }
72
74
  }
73
75
 
74
76
  #svg-path {
@@ -60,17 +60,19 @@ export default {
60
60
  .apos-avatar {
61
61
  @include type-small;
62
62
 
63
- display: flex;
64
- align-items: center;
65
- justify-content: center;
66
- width: 30px;
67
- height: 30px;
68
- border: 1px solid var(--a-base-9);
69
- /* stylelint-disable */
70
- border-radius: 100%;
71
- line-height: 30px;
72
- /* stylelint-enable */
73
- color: var(--a-white);
74
- text-transform: uppercase;
63
+ & {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ width: 30px;
68
+ height: 30px;
69
+ border: 1px solid var(--a-base-9);
70
+ /* stylelint-disable */
71
+ border-radius: 100%;
72
+ line-height: 30px;
73
+ /* stylelint-enable */
74
+ color: var(--a-white);
75
+ text-transform: uppercase;
76
+ }
75
77
  }
76
78
  </style>
@@ -37,6 +37,7 @@
37
37
  :icon-size="iconSize"
38
38
  class="apos-button__icon"
39
39
  :icon-color="iconFill"
40
+ @icon="$emit('icon', $event)"
40
41
  />
41
42
  <slot name="label">
42
43
  <span class="apos-button__label" :class="{ 'apos-sr-only' : (iconOnly || type === 'color') }">
@@ -138,7 +139,7 @@ export default {
138
139
  default: null
139
140
  }
140
141
  },
141
- emits: [ 'click' ],
142
+ emits: [ 'click', 'icon' ],
142
143
  data() {
143
144
  return {
144
145
  id: createId()
@@ -231,16 +232,18 @@ export default {
231
232
  .apos-button {
232
233
  @include type-base;
233
234
 
234
- position: relative;
235
- display: inline-block;
236
- overflow: hidden;
237
- padding: 10px 20px;
238
- border: 1px solid var(--a-base-5);
239
- color: var(--a-text-primary);
240
- border-radius: var(--a-border-radius);
241
- background-color: var(--a-base-9);
242
- transition: all 200ms ease;
243
- text-decoration: none;
235
+ & {
236
+ position: relative;
237
+ display: inline-block;
238
+ overflow: hidden;
239
+ padding: 10px 20px;
240
+ border: 1px solid var(--a-base-5);
241
+ color: var(--a-text-primary);
242
+ border-radius: var(--a-border-radius);
243
+ background-color: var(--a-base-9);
244
+ transition: all 200ms ease;
245
+ text-decoration: none;
246
+ }
244
247
 
245
248
  &:hover {
246
249
  cursor: pointer;
@@ -182,8 +182,10 @@ function menuClose() {
182
182
  @include apos-button-reset();
183
183
  @include apos-transition();
184
184
 
185
- padding: $spacing-base + $spacing-half $spacing-double $spacing-base + $spacing-half $spacing-quadruple;
186
- border-bottom: 1px solid var(--a-base-9);
185
+ & {
186
+ padding: $spacing-base + $spacing-half $spacing-double $spacing-base + $spacing-half $spacing-quadruple;
187
+ border-bottom: 1px solid var(--a-base-9);
188
+ }
187
189
 
188
190
  &:hover,
189
191
  &:focus,
@@ -211,7 +213,9 @@ function menuClose() {
211
213
  .apos-button-split__menu__dialog-label {
212
214
  @include type-large;
213
215
 
214
- margin-bottom: $spacing-half;
216
+ & {
217
+ margin-bottom: $spacing-half;
218
+ }
215
219
  }
216
220
 
217
221
  .apos-button-split__menu__dialog-description {
@@ -65,8 +65,10 @@ export default {
65
65
  .apos-table__cell-field--context-menu__content {
66
66
  @include apos-transition();
67
67
 
68
- display: inline-block;
69
- opacity: 0.3;
68
+ & {
69
+ display: inline-block;
70
+ opacity: 0.3;
71
+ }
70
72
 
71
73
  &.apos-is-visible {
72
74
  opacity: 1;
@@ -461,14 +461,16 @@ export default {
461
461
  .apos-combo__selected {
462
462
  @include type-base;
463
463
 
464
- display: flex;
465
- align-items: center;
466
- gap: 4px;
467
- background-color: var(--a-white);
468
- margin: 2px;
469
- padding: 5px 8px;
470
- border: 1px solid var(--a-base-8);
471
- border-radius: var(--a-border-radius);
464
+ & {
465
+ display: flex;
466
+ align-items: center;
467
+ gap: 4px;
468
+ background-color: var(--a-white);
469
+ margin: 2px;
470
+ padding: 5px 8px;
471
+ border: 1px solid var(--a-base-8);
472
+ border-radius: var(--a-border-radius);
473
+ }
472
474
 
473
475
  &:hover {
474
476
  background-color: var(--a-base-8);
@@ -513,8 +515,10 @@ export default {
513
515
  .apos-combo__list-item {
514
516
  @include type-base;
515
517
 
516
- padding: 10px 10px 10px 20px;
517
- cursor: pointer;
518
+ & {
519
+ padding: 10px 10px 10px 20px;
520
+ cursor: pointer;
521
+ }
518
522
 
519
523
  &.focused {
520
524
  background-color: var(--a-base-9);
@@ -524,13 +528,15 @@ export default {
524
528
  .apos-combo__typehead {
525
529
  @include type-base;
526
530
 
527
- box-sizing: border-box;
528
- flex-grow: 1;
529
- margin: 0;
530
- padding: 10px 10px 10px 20px;
531
- border: none;
532
- outline: none;
533
- background-color: transparent;
531
+ & {
532
+ box-sizing: border-box;
533
+ flex-grow: 1;
534
+ margin: 0;
535
+ padding: 10px 10px 10px 20px;
536
+ border: none;
537
+ outline: none;
538
+ background-color: transparent;
539
+ }
534
540
  }
535
541
 
536
542
  .apos-combo__spinner {
@@ -18,6 +18,7 @@
18
18
  'aria-haspopup': 'menu',
19
19
  'aria-expanded': isOpen ? true : false
20
20
  }"
21
+ @icon="setIconToCenterTo"
21
22
  @click.stop="buttonClicked($event)"
22
23
  />
23
24
  <div
@@ -112,6 +113,10 @@ const props = defineProps({
112
113
  default() {
113
114
  return createId();
114
115
  }
116
+ },
117
+ centerOnIcon: {
118
+ type: Boolean,
119
+ default: false
115
120
  }
116
121
  });
117
122
 
@@ -120,10 +125,11 @@ const emit = defineEmits([ 'open', 'close', 'item-clicked' ]);
120
125
  const isOpen = ref(false);
121
126
  const placement = ref(props.menuPlacement);
122
127
  const event = ref(null);
123
- const dropdown = ref();
124
- const dropdownContent = ref();
128
+ const dropdown = ref(null);
129
+ const dropdownContent = ref(null);
125
130
  const dropdownContentStyle = ref({});
126
- const arrowEl = ref();
131
+ const arrowEl = ref(null);
132
+ const iconToCenterTo = ref(null);
127
133
  const menuOffset = getMenuOffset();
128
134
 
129
135
  defineExpose({
@@ -161,10 +167,10 @@ const buttonState = computed(() => {
161
167
  watch(isOpen, (newVal) => {
162
168
  emit(newVal ? 'open' : 'close', event.value);
163
169
  if (newVal) {
170
+ setDropdownPosition();
164
171
  window.addEventListener('resize', setDropdownPosition);
165
172
  window.addEventListener('scroll', setDropdownPosition);
166
173
  window.addEventListener('keydown', handleKeyboard);
167
- setDropdownPosition();
168
174
  dropdownContent.value.querySelector('[tabindex]')?.focus();
169
175
  } else {
170
176
  window.removeEventListener('resize', setDropdownPosition);
@@ -199,6 +205,12 @@ function hideWhenOtherOpen({ menuId }) {
199
205
  }
200
206
  }
201
207
 
208
+ function setIconToCenterTo(el) {
209
+ if (el && props.centerOnIcon) {
210
+ iconToCenterTo.value = el;
211
+ }
212
+ }
213
+
202
214
  function hide() {
203
215
  isOpen.value = false;
204
216
  }
@@ -225,9 +237,10 @@ async function setDropdownPosition() {
225
237
  if (!dropdown.value || !dropdownContent.value) {
226
238
  return;
227
239
  }
240
+ const centerArrowEl = iconToCenterTo.value || dropdown.value;
228
241
  const {
229
242
  x, y, middlewareData, placement: dropdownPlacement
230
- } = await computePosition(dropdown.value, dropdownContent.value, {
243
+ } = await computePosition(centerArrowEl, dropdownContent.value, {
231
244
  placement: props.menuPlacement,
232
245
  middleware: [
233
246
  offset(menuOffset),
@@ -303,11 +316,13 @@ function handleKeyboard(event) {
303
316
  .apos-context-menu__pane {
304
317
  @include type-base;
305
318
 
306
- padding: 20px;
307
- border: 1px solid var(--a-base-8);
308
- border-radius: var(--a-border-radius);
309
- box-shadow: var(--a-box-shadow);
310
- background-color: var(--a-background-primary);
319
+ & {
320
+ padding: 20px;
321
+ border: 1px solid var(--a-base-8);
322
+ border-radius: var(--a-border-radius);
323
+ box-shadow: var(--a-box-shadow);
324
+ background-color: var(--a-background-primary);
325
+ }
311
326
 
312
327
  &:focus {
313
328
  outline: none;
@@ -126,11 +126,13 @@ function emitSetArrow(arrowEl) {
126
126
  .apos-context-menu__pane {
127
127
  @include type-base;
128
128
 
129
- padding: 20px;
130
- border: 1px solid var(--a-base-8);
131
- border-radius: var(--a-border-radius);
132
- box-shadow: var(--a-box-shadow);
133
- background-color: var(--a-background-primary);
129
+ & {
130
+ padding: 20px;
131
+ border: 1px solid var(--a-base-8);
132
+ border-radius: var(--a-border-radius);
133
+ box-shadow: var(--a-box-shadow);
134
+ background-color: var(--a-background-primary);
135
+ }
134
136
  }
135
137
 
136
138
  .apos-context-menu__items {
@@ -76,14 +76,16 @@ export default {
76
76
  .apos-context-menu__button {
77
77
  @include type-base;
78
78
 
79
- display: inline-block;
80
- flex-grow: 1;
81
- width: 100%;
82
- padding: 10px 20px;
83
- border: none;
84
- color: var(--a-base-1);
85
- text-align: left;
86
- background-color: var(--a-background-primary);
79
+ & {
80
+ display: inline-block;
81
+ flex-grow: 1;
82
+ width: 100%;
83
+ padding: 10px 20px;
84
+ border: none;
85
+ color: var(--a-base-1);
86
+ text-align: left;
87
+ background-color: var(--a-background-primary);
88
+ }
87
89
 
88
90
  &:hover {
89
91
  cursor: pointer;
@@ -34,16 +34,20 @@ export default {
34
34
  .apos-title {
35
35
  @include type-title;
36
36
 
37
- margin: 0 0 10px;
37
+ & {
38
+ margin: 0 0 10px;
39
+ }
38
40
  }
39
41
 
40
42
  .apos-hint {
41
43
  @include type-base;
42
44
 
43
- font-style: italic;
44
- line-height: var(--a-line-tallest);
45
- color: var(--a-base-1);
46
- text-align: center;
45
+ & {
46
+ font-style: italic;
47
+ line-height: var(--a-line-tallest);
48
+ color: var(--a-base-1);
49
+ text-align: center;
50
+ }
47
51
  }
48
52
 
49
53
  .apos-emoji {
@@ -160,16 +160,19 @@ export default {
160
160
  };
161
161
  </script>
162
162
  <style scoped lang='scss'>
163
+
163
164
  .apos-file-dropzone {
164
165
  @include apos-button-reset();
165
166
  @include type-base;
166
167
 
167
- display: block;
168
- margin: 10px 0;
169
- padding: 20px;
170
- border: 2px dashed var(--a-base-8);
171
- border-radius: var(--a-border-radius);
172
- transition: all 200ms ease;
168
+ & {
169
+ display: block;
170
+ margin: 10px 0;
171
+ padding: 20px;
172
+ border: 2px dashed var(--a-base-8);
173
+ border-radius: var(--a-border-radius);
174
+ transition: all 200ms ease;
175
+ }
173
176
 
174
177
  &:hover {
175
178
  border-color: var(--a-primary);
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <span
3
+ ref="icon"
3
4
  v-apos-tooltip="tooltip"
4
5
  class="apos-indicator"
5
6
  :aria-hidden="decorative"
@@ -43,6 +44,10 @@ export default {
43
44
  type: Boolean,
44
45
  default: true
45
46
  }
47
+ },
48
+ emits: [ 'icon' ],
49
+ mounted() {
50
+ this.$emit('icon', this.$refs.icon);
46
51
  }
47
52
  };
48
53
  </script>