dashboard-shell-shell 1.0.111 → 1.0.113

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 (180) hide show
  1. package/.DS_Store +0 -0
  2. package/assets/icons/demo.css +539 -0
  3. package/assets/icons/demo_index.html +1131 -0
  4. package/assets/icons/iconfont.css +200 -0
  5. package/assets/icons/iconfont.js +1 -0
  6. package/assets/icons/iconfont.json +296 -0
  7. package/assets/icons/iconfont.ttf +0 -0
  8. package/assets/icons/iconfont.woff +0 -0
  9. package/assets/icons/iconfont.woff2 +0 -0
  10. package/assets/images/API.svg +3 -0
  11. package/assets/images/login/password.svg +20 -0
  12. package/assets/images/login/user.svg +6 -0
  13. package/assets/images/login-bg.png +0 -0
  14. package/assets/images/login-left.png +0 -0
  15. package/assets/images/login-logo.svg +19 -0
  16. package/assets/images/logo.png +0 -0
  17. package/assets/images/pl/harvester.png +0 -0
  18. package/assets/images/promp-yellow.svg +5 -0
  19. package/assets/images/user.png +0 -0
  20. package/assets/styles/all.scss +63 -0
  21. package/assets/styles/app.scss +2 -0
  22. package/assets/styles/base/_basic.scss +8 -2
  23. package/assets/styles/base/_helpers.scss +4 -0
  24. package/assets/styles/base/_typography.scss +2 -1
  25. package/assets/styles/base/_variables.scss +10 -2
  26. package/assets/styles/global/_button.scss +37 -25
  27. package/assets/styles/global/_columns.scss +3 -1
  28. package/assets/styles/global/_form.scss +45 -13
  29. package/assets/styles/global/_labeled-input.scss +50 -25
  30. package/assets/styles/global/_layout.scss +9 -3
  31. package/assets/styles/global/_select.scss +20 -13
  32. package/assets/styles/global/_table.scss +1 -1
  33. package/assets/styles/global/_tooltip.scss +47 -6
  34. package/assets/styles/themes/_dark.scss +1 -0
  35. package/assets/styles/themes/_light.scss +59 -46
  36. package/assets/styles/themes/_suse.scss +1 -0
  37. package/assets/styles/vendor/vue-select.scss +18 -7
  38. package/assets/translations/en-us.yaml +93 -12
  39. package/assets/translations/zh-hans.yaml +278 -141
  40. package/components/ActionDropdown.vue +1 -1
  41. package/components/ActionDropdownShell.vue +71 -0
  42. package/components/ActionMenu.vue +2 -2
  43. package/components/ActionMenuShell.vue +1 -0
  44. package/components/AppModal.vue +78 -6
  45. package/components/AssignTo.vue +25 -11
  46. package/components/AsyncButton.vue +24 -7
  47. package/components/BannerGraphic.vue +1 -0
  48. package/components/ButtonDropdown.vue +26 -4
  49. package/components/ButtonGroup.vue +4 -0
  50. package/components/ButtonMultiAction.vue +1 -0
  51. package/components/CommunityLinks.vue +3 -3
  52. package/components/ConsumptionGauge.vue +24 -5
  53. package/components/CopyToClipboardText.vue +2 -1
  54. package/components/CruResource.vue +12 -7
  55. package/components/CruResourceFooter.vue +2 -2
  56. package/components/DashboardOptions.vue +21 -15
  57. package/components/DetailText.vue +5 -0
  58. package/components/DisableAuthProviderModal.vue +1 -0
  59. package/components/DotState.vue +84 -0
  60. package/components/ExplorerMembers.vue +1 -1
  61. package/components/ExplorerProjectsNamespaces.vue +56 -14
  62. package/components/FixedBanner.vue +19 -12
  63. package/components/GlobalRoleBindings.vue +5 -1
  64. package/components/GrafanaDashboard.vue +4 -4
  65. package/components/GrowlManager.vue +4 -1
  66. package/components/HardwareResourceGauge.vue +39 -3
  67. package/components/InfoBox.vue +3 -3
  68. package/components/InputOrDisplay.vue +28 -2
  69. package/components/LabelValue.vue +16 -1
  70. package/components/LandingPagePreference.vue +5 -3
  71. package/components/LocaleSelector.vue +39 -93
  72. package/components/ModalManager.vue +55 -0
  73. package/components/ModalWithCard.vue +2 -0
  74. package/components/MoveModal.vue +1 -0
  75. package/components/PromptChangePassword.vue +1 -1
  76. package/components/PromptModal.vue +15 -2
  77. package/components/PromptRemove.vue +28 -8
  78. package/components/PromptRestore.vue +1 -0
  79. package/components/ResourceCancelModal.vue +1 -0
  80. package/components/ResourceDetail/Masthead.vue +188 -43
  81. package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
  82. package/components/ResourceDetail/index.vue +49 -14
  83. package/components/ResourceList/Masthead.vue +80 -18
  84. package/components/ResourceTable.vue +60 -19
  85. package/components/SideNav.vue +32 -12
  86. package/components/SlideInPanelManager.vue +126 -0
  87. package/components/SortableTable/THead.vue +34 -5
  88. package/components/SortableTable/actions.js +1 -1
  89. package/components/SortableTable/index.vue +649 -142
  90. package/components/SortableTable/paging.js +36 -28
  91. package/components/SortableTable/selection.js +0 -11
  92. package/components/StatusBadge.vue +77 -0
  93. package/components/Tabbed/Tab.vue +3 -3
  94. package/components/Tabbed/index.vue +44 -26
  95. package/components/Wizard.vue +2 -2
  96. package/components/__tests__/AsyncButton.test.ts +2 -2
  97. package/components/__tests__/FixedBanner.test.ts +3 -3
  98. package/components/__tests__/ModalManager.spec.ts +176 -0
  99. package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
  100. package/components/auth/Principal.vue +10 -3
  101. package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
  102. package/components/form/ArrayList.vue +123 -85
  103. package/components/form/ArrayListGrouped.vue +10 -2
  104. package/components/form/Command.vue +6 -15
  105. package/components/form/EnvVars.vue +16 -8
  106. package/components/form/Footer.vue +8 -5
  107. package/components/form/HealthCheck.vue +3 -3
  108. package/components/form/HookOption.vue +11 -16
  109. package/components/form/KeyValue.vue +16 -7
  110. package/components/form/LabeledSelect.vue +59 -76
  111. package/components/form/LifecycleHooks.vue +3 -3
  112. package/components/form/MatchExpressions.vue +35 -12
  113. package/components/form/NameNsDescription.vue +147 -115
  114. package/components/form/Networking.vue +20 -12
  115. package/components/form/NodeAffinity.vue +31 -23
  116. package/components/form/NodeScheduling.vue +13 -3
  117. package/components/form/Password.vue +11 -5
  118. package/components/form/PodAffinity.vue +43 -44
  119. package/components/form/Probe.vue +68 -66
  120. package/components/form/ResourceQuota/Project.vue +5 -1
  121. package/components/form/ResourceSelector.vue +7 -9
  122. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +6 -3
  123. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +12 -1
  124. package/components/form/SSHKnownHosts/index.vue +16 -2
  125. package/components/form/Security.vue +54 -56
  126. package/components/form/Select.vue +41 -7
  127. package/components/form/ShellInput.vue +5 -1
  128. package/components/form/Tolerations.vue +5 -1
  129. package/components/form/UnitInput.vue +2 -2
  130. package/components/form/ValueFromResource.vue +134 -121
  131. package/components/form/WorkloadPorts.vue +18 -18
  132. package/components/form/__tests__/ArrayList.test.ts +5 -2
  133. package/components/form/__tests__/MatchExpressions.test.ts +12 -12
  134. package/components/form/__tests__/NameNsDescription.test.ts +115 -14
  135. package/components/form/__tests__/Probe.test.ts +12 -8
  136. package/components/form/__tests__/SSHKnownHosts.test.ts +11 -0
  137. package/components/form/__tests__/Select.test.ts +37 -0
  138. package/components/form/__tests__/UnitInput.test.ts +4 -5
  139. package/components/formatter/BadgeStateFormatter.vue +8 -5
  140. package/components/formatter/InternalExternalIP.vue +2 -0
  141. package/components/formatter/SecretData.vue +20 -7
  142. package/components/nav/Favorite.vue +5 -1
  143. package/components/nav/Group.vue +60 -27
  144. package/components/nav/Header.vue +39 -13
  145. package/components/nav/Jump.vue +7 -0
  146. package/components/nav/NamespaceFilter.vue +14 -8
  147. package/components/nav/Pinned.vue +1 -1
  148. package/components/nav/TopLevelMenu.vue +5 -17
  149. package/components/nav/Type.vue +32 -35
  150. package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
  151. package/components/templates/blank.vue +4 -1
  152. package/components/templates/default.vue +8 -0
  153. package/components/templates/home.vue +10 -1
  154. package/components/templates/plain.vue +10 -1
  155. package/package.json +1 -1
  156. package/rancher-components/Banner/Banner.vue +6 -4
  157. package/rancher-components/Card/Card.vue +6 -4
  158. package/rancher-components/Form/Checkbox/Checkbox.vue +20 -1
  159. package/rancher-components/Form/LabeledInput/LabeledInput.vue +46 -5
  160. package/rancher-components/Form/Radio/RadioButton.vue +32 -8
  161. package/rancher-components/Form/Radio/RadioGroup.vue +31 -24
  162. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
  163. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +8 -3
  164. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +15 -3
  165. package/rancher-components/RcButton/RcButton.vue +1 -0
  166. package/rancher-components/RcButton/types.ts +1 -0
  167. package/rancher-components/RcDropdown/RcDropdown.vue +54 -15
  168. package/rancher-components/RcDropdown/RcDropdownItem.vue +5 -4
  169. package/rancher-components/RcDropdown/RcDropdownMenu.vue +11 -7
  170. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +12 -2
  171. package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
  172. package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
  173. package/rancher-components/StringList/StringList.vue +1 -1
  174. package/store/type-map.js +29 -2
  175. package/utils/error.js +30 -8
  176. package/utils/errorTranslate.json +916 -0
  177. package/vue.config.js +1 -1
  178. package/components/formatter/ExtensionCache.vue +0 -74
  179. package/components/formatter/Port.vue +0 -24
  180. package/components/formatter/SecretType.vue +0 -41
@@ -4,6 +4,7 @@ import TextAreaAutoGrow from '@components/Form/TextArea/TextAreaAutoGrow.vue';
4
4
  import LabeledTooltip from '@components/LabeledTooltip/LabeledTooltip.vue';
5
5
  import { escapeHtml, generateRandomAlphaString } from '@shell/utils/string';
6
6
  import cronstrue from 'cronstrue';
7
+ import 'cronstrue/locales/zh_CN';
7
8
  import { isValidCron } from 'cron-validator';
8
9
  import { debounce } from 'lodash';
9
10
  import { useLabeledFormElement, labeledFormElementProps } from '@shell/composables/useLabeledFormElement';
@@ -148,7 +149,8 @@ export default defineComponent({
148
149
  return {
149
150
  updated: false,
150
151
  validationErrors: '',
151
- inputId: `input-${ generateRandomAlphaString(12) }`
152
+ inputId: `input-${ generateRandomAlphaString(12) }`,
153
+ describedById: `described-by-${ generateRandomAlphaString(12) }`
152
154
  };
153
155
  },
154
156
 
@@ -212,7 +214,8 @@ export default defineComponent({
212
214
  }
213
215
 
214
216
  try {
215
- const hint = cronstrue.toString(this.value as string || '', { verbose: true });
217
+ // const hint = cronstrue.toString(this.value as string || '', { verbose: true });
218
+ const hint = cronstrue.toString(this.value as string || '', { locale: 'zh_CN' });
216
219
 
217
220
  return hint;
218
221
  } catch (e) {
@@ -333,6 +336,24 @@ export default defineComponent({
333
336
  </script>
334
337
 
335
338
  <template>
339
+ <div class="label-input-all">
340
+ <slot name="label">
341
+ <label
342
+ v-if="hasLabel"
343
+ :for="inputId"
344
+ >
345
+ <t
346
+ v-if="labelKey"
347
+ :k="labelKey"
348
+ />
349
+ <template v-else-if="label">{{ label }}</template>
350
+
351
+ <span
352
+ v-if="requiredField"
353
+ class="required"
354
+ >*</span>
355
+ </label>
356
+ </slot>
336
357
  <div
337
358
  :class="{
338
359
  'labeled-input': true,
@@ -347,7 +368,7 @@ export default defineComponent({
347
368
  [className]: true
348
369
  }"
349
370
  >
350
- <slot name="label">
371
+ <!-- <slot name="label">
351
372
  <label
352
373
  v-if="hasLabel"
353
374
  :for="inputId"
@@ -363,7 +384,7 @@ export default defineComponent({
363
384
  class="required"
364
385
  >*</span>
365
386
  </label>
366
- </slot>
387
+ </slot> -->
367
388
 
368
389
  <slot name="prefix" />
369
390
 
@@ -380,6 +401,7 @@ export default defineComponent({
380
401
  :placeholder="_placeholder"
381
402
  autocapitalize="off"
382
403
  :class="{ conceal: type === 'multiline-password' }"
404
+ :aria-describedby="cronHint || subLabel ? describedById : undefined"
383
405
  @update:value="onInput"
384
406
  @focus="onFocus"
385
407
  @blur="onBlur"
@@ -400,6 +422,7 @@ export default defineComponent({
400
422
  autocomplete="off"
401
423
  autocapitalize="off"
402
424
  :data-lpignore="ignorePasswordManagers"
425
+ :aria-describedby="cronHint || subLabel ? describedById : undefined"
403
426
  @input="onInput"
404
427
  @focus="onFocus"
405
428
  @blur="onBlur"
@@ -428,17 +451,20 @@ export default defineComponent({
428
451
  >
429
452
  <div
430
453
  v-if="cronHint"
454
+ :id="describedById"
431
455
  role="alert"
432
456
  :aria-label="cronHint"
433
457
  >
434
458
  {{ cronHint }}
435
459
  </div>
436
460
  <div
437
- v-if="subLabel"
461
+ v-else-if="subLabel"
462
+ :id="describedById"
438
463
  v-clean-html="subLabel"
439
464
  />
440
465
  </div>
441
466
  </div>
467
+ </div>
442
468
  </template>
443
469
  <style scoped lang="scss">
444
470
  .labeled-input.view {
@@ -461,6 +487,21 @@ export default defineComponent({
461
487
  -moz-appearance: textfield;
462
488
  }
463
489
  }
490
+ .label-input-all{
491
+ display: flex;
492
+ label{
493
+ width: 160px;
494
+ line-height: 32px;
495
+ .required{
496
+ color: red;
497
+ }
498
+ }
499
+ }
500
+
501
+ .v-popper--has-tooltip INPUT, .v-popper--has-tooltip INPUT:hover, .v-popper--has-tooltip INPUT:focus{
502
+ padding: 0px 0px 0px 11px;
503
+ }
504
+
464
505
  </style>
465
506
  <style>
466
507
  .validation-message {
@@ -251,15 +251,21 @@ $fontColor: var(--input-label);
251
251
  cursor: not-allowed
252
252
  }
253
253
 
254
- .radio-custom {
255
- height: 14px;
256
- width: 14px;
257
- min-height: 14px;
258
- min-width: 14px;
254
+ .radio-custom {
255
+ height: 12px;
256
+ width: 12px;
257
+ min-height: 13px;
258
+ min-width: 13px;
259
259
  background-color: var(--input-bg);
260
260
  border-radius: 50%;
261
+ transition: all 0.3s ease-out;
261
262
  border: 1.5px solid var(--border);
262
- margin-top: 5px;
263
+ margin-top: 4px;
264
+
265
+ &:focus {
266
+ outline: none;
267
+ border-radius: 50%;
268
+ }
263
269
  }
264
270
 
265
271
  input {
@@ -268,13 +274,31 @@ $fontColor: var(--input-label);
268
274
 
269
275
  .radio-custom {
270
276
  &[aria-checked="true"] {
271
- background-color: var(--primary);
277
+ background-color: #fff;
272
278
  -webkit-transform: rotate(0deg) scale(1);
273
279
  -ms-transform: rotate(0deg) scale(1);
274
280
  transform: rotate(0deg) scale(1);
275
281
  opacity:1;
276
282
  border: 1.5px solid var(--primary);
283
+ display: flex;
284
+ align-items: center;
285
+ justify-content: center;
286
+
277
287
 
288
+ &::after {
289
+ background-color: var(--primary);
290
+ width: 7px;
291
+ height: 7px;
292
+ display: inline;
293
+ content: "";
294
+ /* position: absolute; */
295
+ /* top: 17%;
296
+ left: 19%;
297
+ margin-left: 0.4px; */
298
+ /* top: 1.5px;
299
+ left: 1.5px; */
300
+ border-radius: 50%;
301
+ }
278
302
  // Ensure that checked radio buttons are muted but still visibly selected when muted
279
303
  &.text-muted {
280
304
  opacity: .25;
@@ -297,7 +321,7 @@ $fontColor: var(--input-label);
297
321
  display: inline-flex;
298
322
  flex-direction: column;
299
323
 
300
- margin: 3px 10px 0px 5px;
324
+ margin: 3px 16px 0px 5px;
301
325
  }
302
326
  }
303
327
 
@@ -199,33 +199,35 @@ export default defineComponent({
199
199
  </script>
200
200
 
201
201
  <template>
202
- <div>
202
+ <fieldset>
203
203
  <!-- Label -->
204
204
  <div
205
205
  v-if="label || labelKey || tooltip || tooltipKey || $slots.label"
206
206
  class="radio-group label"
207
207
  >
208
- <slot name="label">
209
- <h3>
210
- <t
211
- v-if="labelKey"
212
- :k="labelKey"
213
- />
214
- <template v-else-if="label">
215
- {{ label }}
216
- </template>
217
- <i
218
- v-if="tooltipKey"
219
- v-clean-tooltip="t(tooltipKey)"
220
- class="icon icon-info icon-lg"
221
- />
222
- <i
223
- v-else-if="tooltip"
224
- v-clean-tooltip="tooltip"
225
- class="icon icon-info icon-lg"
226
- />
227
- </h3>
228
- </slot>
208
+ <legend>
209
+ <slot name="label">
210
+ <span class="radio-group-title">
211
+ <t
212
+ v-if="labelKey"
213
+ :k="labelKey"
214
+ />
215
+ <template v-else-if="label">
216
+ {{ label }}
217
+ </template>
218
+ <i
219
+ v-if="tooltipKey"
220
+ v-clean-tooltip="t(tooltipKey)"
221
+ class="icon icon-info icon-lg"
222
+ />
223
+ <i
224
+ v-else-if="tooltip"
225
+ v-clean-tooltip="tooltip"
226
+ class="icon icon-info icon-lg"
227
+ />
228
+ </span>
229
+ </slot>
230
+ </legend>
229
231
  </div>
230
232
 
231
233
  <!-- Group -->
@@ -266,7 +268,7 @@ export default defineComponent({
266
268
  </slot>
267
269
  </div>
268
270
  </div>
269
- </div>
271
+ </fieldset>
270
272
  </template>
271
273
 
272
274
  <style lang='scss'>
@@ -292,7 +294,12 @@ export default defineComponent({
292
294
  }
293
295
 
294
296
  .label{
295
- font-size: 14px !important;
297
+ font-size: 12px !important;
296
298
  }
297
299
  }
300
+ .radio-group-title{
301
+ font-size: 14px;
302
+ margin-bottom: 15px;
303
+ display: inline-block;
304
+ }
298
305
  </style>
@@ -91,4 +91,21 @@ describe('toggleSwitch.vue', () => {
91
91
  expect(wrapper.emitted('update:value')).toHaveLength(1);
92
92
  expect(wrapper.emitted('update:value')[0][0]).toBe(offValue);
93
93
  });
94
+
95
+ it('adds focus class when input is focused', async() => {
96
+ const wrapper = shallowMount(ToggleSwitch);
97
+
98
+ await wrapper.find('input').trigger('focus');
99
+
100
+ expect(wrapper.find('.slider').classes()).toContain('focus');
101
+ });
102
+
103
+ it('removes focus class when input is blurred', async() => {
104
+ const wrapper = shallowMount(ToggleSwitch);
105
+
106
+ await wrapper.find('input').trigger('focus');
107
+ await wrapper.find('input').trigger('blur');
108
+
109
+ expect(wrapper.find('.slider').classes()).not.toContain('focus');
110
+ });
94
111
  });
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { defineComponent, onMounted, onBeforeUnmount, useTemplateRef } from 'vue';
2
+ import { defineComponent, onMounted, onBeforeUnmount, ref } from 'vue';
3
3
 
4
4
  type StateType = boolean | 'true' | 'false' | undefined;
5
5
 
@@ -34,7 +34,7 @@ export default defineComponent({
34
34
  emits: ['update:value'],
35
35
 
36
36
  setup() {
37
- const switchChrome = useTemplateRef<HTMLElement>('switchChrome');
37
+ const switchChrome = ref<HTMLElement | null>(null);
38
38
  const focus = () => {
39
39
  switchChrome.value?.classList.add('focus');
40
40
  };
@@ -43,7 +43,7 @@ export default defineComponent({
43
43
  switchChrome.value?.classList.remove('focus');
44
44
  };
45
45
 
46
- const switchInput = useTemplateRef<HTMLInputElement>('switchInput');
46
+ const switchInput = ref<HTMLInputElement | null>(null);
47
47
 
48
48
  onMounted(() => {
49
49
  switchInput.value?.addEventListener('focus', focus);
@@ -54,6 +54,11 @@ export default defineComponent({
54
54
  switchInput.value?.removeEventListener('focus', focus);
55
55
  switchInput.value?.removeEventListener('blur', blur);
56
56
  });
57
+
58
+ return {
59
+ switchChrome,
60
+ switchInput,
61
+ };
57
62
  },
58
63
 
59
64
  data() {
@@ -26,7 +26,15 @@ export default defineComponent({
26
26
  hover: {
27
27
  type: Boolean,
28
28
  default: true
29
- }
29
+ },
30
+ /**
31
+ * Inherited global identifier prefix for tests
32
+ * Define a term based on the parent component to avoid conflicts on multiple components
33
+ */
34
+ componentTestid: {
35
+ type: String,
36
+ default: 'labeledTooltip-info-icon'
37
+ },
30
38
  },
31
39
  computed: {
32
40
  iconClass(): string {
@@ -64,6 +72,7 @@ export default defineComponent({
64
72
  :class="{'hover':!value, [iconClass]: true}"
65
73
  class="icon status-icon"
66
74
  tabindex="0"
75
+ :data-testid="componentTestid"
67
76
  />
68
77
  </template>
69
78
  <template v-else>
@@ -99,9 +108,12 @@ export default defineComponent({
99
108
 
100
109
  .status-icon {
101
110
  position: absolute;
102
- right: 30px;
111
+ right: 5px;
112
+ top: 10px;
113
+ z-index: 3;
114
+ /* right: 30px;
103
115
  top: $input-padding-lg;
104
- z-index: z-index(hoverOverContent);
116
+ z-index: z-index(hoverOverContent); */
105
117
  }
106
118
 
107
119
  @mixin tooltipColors($color) {
@@ -15,6 +15,7 @@ const buttonRoles: { role: keyof ButtonRoleProps, className: string }[] = [
15
15
  { role: 'secondary', className: 'role-secondary' },
16
16
  { role: 'tertiary', className: 'role-tertiary' },
17
17
  { role: 'link', className: 'role-link' },
18
+ { role: 'multiAction', className: 'role-multi-action' },
18
19
  { role: 'ghost', className: 'role-ghost' },
19
20
  ];
20
21
 
@@ -9,6 +9,7 @@ export type ButtonRoleProps = {
9
9
  secondary?: boolean;
10
10
  tertiary?: boolean;
11
11
  link?: boolean;
12
+ multiAction?: boolean;
12
13
  ghost?: boolean;
13
14
  }
14
15
 
@@ -20,13 +20,22 @@
20
20
  * </template>
21
21
  * </rc-dropdown>
22
22
  */
23
- import { useTemplateRef } from 'vue';
23
+ import { ref } from 'vue';
24
24
  import { useClickOutside } from '@shell/composables/useClickOutside';
25
25
  import { useDropdownContext } from '@components/RcDropdown/useDropdownContext';
26
26
 
27
- defineProps<{
28
- ariaLabel?: string
29
- }>();
27
+ import type { Placement } from 'floating-vue';
28
+
29
+ withDefaults(
30
+ defineProps<{
31
+ // eslint-disable-next-line vue/require-default-prop
32
+ ariaLabel?: string;
33
+ // eslint-disable-next-line vue/require-default-prop
34
+ distance?: number;
35
+ placement?: Placement;
36
+ }>(),
37
+ { placement: 'bottom-end' }
38
+ );
30
39
 
31
40
  const emit = defineEmits(['update:open']);
32
41
 
@@ -42,14 +51,14 @@ const {
42
51
 
43
52
  provideDropdownContext();
44
53
 
45
- const popperContainer = useTemplateRef<HTMLElement>('popperContainer');
46
- const dropdownTarget = useTemplateRef<HTMLElement>('dropdownTarget');
54
+ // const popperContainer = ref(null);
55
+ const dropdownTarget = ref(null);
47
56
 
48
57
  useClickOutside(dropdownTarget, () => showMenu(false));
49
58
 
50
59
  const applyShow = () => {
51
60
  registerDropdownCollection(dropdownTarget.value);
52
- setFocus();
61
+ setFocus('down');
53
62
  };
54
63
 
55
64
  </script>
@@ -60,15 +69,30 @@ const applyShow = () => {
60
69
  :triggers="[]"
61
70
  :shown="isMenuOpen"
62
71
  :auto-hide="false"
63
- :container="popperContainer"
64
- :placement="'bottom-end'"
72
+ append-to-body
73
+ :placement="placement"
74
+ :distance="distance"
65
75
  @apply-show="applyShow"
76
+ popper-class="custom-dropdown"
66
77
  >
67
78
  <slot name="default">
68
79
  <!--Empty slot content Trigger-->
69
80
  </slot>
70
81
 
71
82
  <template #popper>
83
+ <!-- <div
84
+ ref="dropdownTarget"
85
+ class="dropdownTarget"
86
+ tabindex="-1"
87
+ role="menu"
88
+ aria-orientation="vertical"
89
+ dropdown-menu-collection
90
+ :aria-label="ariaLabel || 'Dropdown Menu'"
91
+ @keydown="handleKeydown"
92
+ @keydown.down.prevent="setFocus('down')"
93
+ @keydown.up.prevent="setFocus('up')"
94
+
95
+ > -->
72
96
  <div
73
97
  ref="dropdownTarget"
74
98
  class="dropdownTarget"
@@ -78,7 +102,10 @@ const applyShow = () => {
78
102
  dropdown-menu-collection
79
103
  :aria-label="ariaLabel || 'Dropdown Menu'"
80
104
  @keydown="handleKeydown"
81
- @keydown.down="setFocus()"
105
+ @keydown.down.prevent="setFocus('down')"
106
+ @keydown.up.prevent="setFocus('up')"
107
+ @keydown.tab="showMenu(false)"
108
+ @keydown.escape="returnFocus"
82
109
  >
83
110
  <slot name="dropdownCollection">
84
111
  <!--Empty slot content-->
@@ -86,14 +113,13 @@ const applyShow = () => {
86
113
  </div>
87
114
  </template>
88
115
  </v-dropdown>
89
- <div
116
+ <!-- <div
90
117
  ref="popperContainer"
91
118
  class="popperContainer"
92
119
  @keydown.tab="showMenu(false)"
93
120
  @keydown.escape="returnFocus"
94
121
  >
95
- <!--Empty container for mounting popper content-->
96
- </div>
122
+ </div> -->
97
123
  </template>
98
124
 
99
125
  <style lang="scss" scoped>
@@ -102,7 +128,8 @@ const applyShow = () => {
102
128
  &:deep(.v-popper__popper) {
103
129
 
104
130
  .v-popper__wrapper {
105
- box-shadow: 0px 6px 18px 0px rgba(0, 0, 0, 0.25), 0px 4px 10px 0px rgba(0, 0, 0, 0.15);
131
+ box-shadow: 0 5px 20px var(--shadow);
132
+ /* box-shadow: 0px 6px 18px 0px rgba(0, 0, 0, 0.25), 0px 4px 10px 0px rgba(0, 0, 0, 0.15); */
106
133
  border-radius: var(--border-radius-lg);
107
134
 
108
135
  .v-popper__arrow-container {
@@ -110,7 +137,9 @@ const applyShow = () => {
110
137
  }
111
138
 
112
139
  .v-popper__inner {
113
- padding: 10px 0 10px 0;
140
+ /* padding: 10px 0 10px 0; */
141
+ padding: 0px;
142
+ /* min-width: 145px; */
114
143
  }
115
144
  }
116
145
  }
@@ -121,4 +150,14 @@ const applyShow = () => {
121
150
  outline: none;
122
151
  }
123
152
  }
153
+
154
+ .custom-dropdown{
155
+ .v-popper__wrapper{
156
+ .v-popper__inner {
157
+ padding: 0px;
158
+ }
159
+ }
160
+ }
161
+
124
162
  </style>
163
+
@@ -83,7 +83,7 @@ const handleActivate = (e: KeyboardEvent) => {
83
83
  :aria-disabled="disabled || false"
84
84
  @click.stop="handleClick"
85
85
  @keydown.enter.space="handleActivate"
86
- @keydown.up.down.stop="handleKeydown"
86
+ @keydown.up.down.prevent.stop="handleKeydown"
87
87
  >
88
88
  <slot name="before">
89
89
  <!--Empty slot content-->
@@ -99,9 +99,10 @@ const handleActivate = (e: KeyboardEvent) => {
99
99
  display: flex;
100
100
  gap: 8px;
101
101
  align-items: center;
102
- padding: 9px 8px;
103
- margin: 0 9px;
104
- border-radius: 4px;
102
+ padding: 8px 10px;
103
+ min-width: 145px;
104
+ /* margin: 0 9px; */
105
+ /* border-radius: 4px; */
105
106
 
106
107
  &:hover {
107
108
  cursor: pointer;
@@ -8,8 +8,11 @@ import {
8
8
  import { RcDropdownMenuComponentProps, DropdownOption } from './types';
9
9
  import IconOrSvg from '@shell/components/IconOrSvg';
10
10
 
11
- // eslint-disable-next-line vue/no-setup-props-destructure
12
- const { buttonRole = 'primary', buttonSize = '' } = defineProps<RcDropdownMenuComponentProps>();
11
+ withDefaults(defineProps<RcDropdownMenuComponentProps>(), {
12
+ buttonRole: 'primary',
13
+ buttonSize: undefined,
14
+ isDetail: false,
15
+ });
13
16
 
14
17
  const emit = defineEmits(['update:open', 'select']);
15
18
 
@@ -29,7 +32,8 @@ const hasOptions = (options: DropdownOption[]) => {
29
32
  :data-testid="dataTestid"
30
33
  :aria-label="buttonAriaLabel"
31
34
  >
32
- <i class="icon icon-actions" />
35
+ <i style="font-style: normal;" v-if="buttonRole === 'link'">操作</i>
36
+ <i class="icon icon-actions" v-else/>
33
37
  </rc-dropdown-trigger>
34
38
  <template #dropdownCollection>
35
39
  <template
@@ -40,7 +44,7 @@ const hasOptions = (options: DropdownOption[]) => {
40
44
  v-if="!a.divider"
41
45
  @click="(e: MouseEvent) => emit('select', e, a)"
42
46
  >
43
- <template #before>
47
+ <!-- <template #before>
44
48
  <IconOrSvg
45
49
  v-if="a.icon || a.svg"
46
50
  :icon="a.icon"
@@ -48,12 +52,12 @@ const hasOptions = (options: DropdownOption[]) => {
48
52
  class="icon"
49
53
  color="header"
50
54
  />
51
- </template>
55
+ </template> -->
52
56
  {{ a.label }}
53
57
  </rc-dropdown-item>
54
- <rc-dropdown-separator
58
+ <!-- <rc-dropdown-separator
55
59
  v-else
56
- />
60
+ /> -->
57
61
  </template>
58
62
  <rc-dropdown-item
59
63
  v-if="!hasOptions(options)"
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * A button that opens a menu. Used in conjunction with `RcDropdown.vue`.
4
4
  */
5
- import { inject, onMounted, useTemplateRef } from 'vue';
5
+ import { inject, onMounted, ref } from 'vue';
6
6
  import { RcButton, RcButtonType } from '@components/RcButton';
7
7
  import { DropdownContext, defaultContext } from './types';
8
8
 
@@ -13,7 +13,7 @@ const {
13
13
  handleKeydown,
14
14
  } = inject<DropdownContext>('dropdownContext') || defaultContext;
15
15
 
16
- const dropdownTrigger = useTemplateRef<RcButtonType>('dropdownTrigger');
16
+ const dropdownTrigger = ref<RcButtonType | null>(null);
17
17
 
18
18
  onMounted(() => {
19
19
  registerTrigger(dropdownTrigger.value);
@@ -35,8 +35,18 @@ defineExpose({ focus });
35
35
  @keydown.enter.space="handleKeydown"
36
36
  @click="showMenu(true)"
37
37
  >
38
+ <template #before>
39
+ <slot name="before">
40
+ <!-- Empty Content -->
41
+ </slot>
42
+ </template>
38
43
  <slot name="default">
39
44
  <!--Empty slot content-->
40
45
  </slot>
46
+ <template #after>
47
+ <slot name="after">
48
+ <!-- Empty Content -->
49
+ </slot>
50
+ </template>
41
51
  </RcButton>
42
52
  </template>
@@ -10,6 +10,7 @@ export const useDropdownCollection = () => {
10
10
  const dropdownItems = ref<Element[]>([]);
11
11
  const dropdownContainer = ref<HTMLElement | null>(null);
12
12
  const firstDropdownItem = ref<HTMLElement | null>(null);
13
+ const lastDropdownItem = ref<HTMLElement | null>(null);
13
14
 
14
15
  /**
15
16
  * Registers the dropdown container and initializes dropdown items.
@@ -22,6 +23,12 @@ export const useDropdownCollection = () => {
22
23
  if (dropdownItems.value[0] instanceof HTMLElement) {
23
24
  firstDropdownItem.value = dropdownItems.value[0];
24
25
  }
26
+
27
+ const lastItem = dropdownItems.value[dropdownItems.value.length - 1];
28
+
29
+ if (lastItem instanceof HTMLElement) {
30
+ lastDropdownItem.value = lastItem;
31
+ }
25
32
  }
26
33
  };
27
34
 
@@ -40,6 +47,7 @@ export const useDropdownCollection = () => {
40
47
  return {
41
48
  dropdownItems,
42
49
  firstDropdownItem,
50
+ lastDropdownItem,
43
51
  dropdownContainer,
44
52
  registerDropdownCollection,
45
53
  };