dashboard-shell-shell 1.0.111 → 1.0.112

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.
package/.DS_Store ADDED
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "license": "Apache-2.0",
6
6
  "author": "SUSE",
7
7
  "private": false,
8
- "version": "1.0.00000000111",
8
+ "version": "1.0.00000000112",
9
9
  "engines": {
10
10
  "node": ">=20.0.0"
11
11
  },
@@ -125,7 +125,8 @@ $icon-size: 24px;
125
125
 
126
126
  .banner {
127
127
  display: flex;
128
- margin: 15px 0;
128
+ /* margin: 15px 0; */
129
+ margin: 0px 0px 20px 0px;
129
130
  position: relative;
130
131
  width: 100%;
131
132
  color: var(--body-text);
@@ -165,9 +166,9 @@ $icon-size: 24px;
165
166
  }
166
167
 
167
168
  &__content {
168
- padding: 10px;
169
+ padding: 9px 10px;
169
170
  transition: all 0.2s ease;
170
- line-height: 20px;
171
+ line-height: 12px;
171
172
  width: 100%;
172
173
  border-left: solid $left-border-size transparent;
173
174
  display: flex;
@@ -189,7 +190,8 @@ $icon-size: 24px;
189
190
  }
190
191
 
191
192
  .info & {
192
- background: var(--info-banner-bg);
193
+ /* background: var(--info-banner-bg); */
194
+ background: #f2f2f2;
193
195
  border-color: var(--info);
194
196
  }
195
197
 
@@ -89,7 +89,7 @@ export default defineComponent({
89
89
  {{ title }}
90
90
  </slot>
91
91
  </div>
92
- <hr>
92
+ <!-- <hr role="none"> -->
93
93
  <div
94
94
  class="card-body"
95
95
  data-testid="card-body-slot"
@@ -124,9 +124,9 @@ export default defineComponent({
124
124
  border-radius: var(--border-radius);
125
125
  display: flex;
126
126
  flex-basis: 40%;
127
- margin: 10px;
127
+ /* margin: 10px; */
128
128
  min-height: 100px;
129
- padding: 10px;
129
+ padding: 24px;
130
130
  box-shadow: 0 0 20px var(--shadow);
131
131
  &:not(.top) {
132
132
  align-items: top;
@@ -143,14 +143,16 @@ export default defineComponent({
143
143
  justify-content: center;
144
144
  }
145
145
  & .card-actions {
146
- align-self: end;
146
+ /* align-self: end; */
147
147
  display: flex;
148
+ justify-content: flex-end;
148
149
  padding-top: 20px;
149
150
  }
150
151
  & .card-title {
151
152
  align-items: center;
152
153
  display: flex;
153
154
  width: 100%;
155
+ margin-bottom: 15px;
154
156
  h5 {
155
157
  margin: 0;
156
158
  }
@@ -124,10 +124,23 @@ export default defineComponent({
124
124
  type: String,
125
125
  default: undefined
126
126
  },
127
+
128
+ /**
129
+ * Inherited global identifier prefix for tests
130
+ * Define a term based on the parent component to avoid conflicts on multiple components
131
+ */
132
+ componentTestid: {
133
+ type: String,
134
+ default: 'checkbox'
135
+ },
127
136
  },
128
137
 
129
138
  emits: ['update:value'],
130
139
 
140
+ data() {
141
+ return { describedById: `described-by-${ generateRandomAlphaString(12) }` };
142
+ },
143
+
131
144
  computed: {
132
145
  /**
133
146
  * Determines if the checkbox is disabled.
@@ -270,6 +283,7 @@ export default defineComponent({
270
283
  :aria-label="replacementLabel"
271
284
  :aria-checked="!!value"
272
285
  :aria-labelledby="labelKey || label ? idForLabel : undefined"
286
+ :aria-describedby="descriptionKey || description ? describedById : undefined"
273
287
  role="checkbox"
274
288
  />
275
289
  <span
@@ -293,6 +307,7 @@ export default defineComponent({
293
307
  v-clean-tooltip="{content: t(tooltipKey), triggers: ['hover', 'touch', 'focus']}"
294
308
  v-stripped-aria-label="t(tooltipKey)"
295
309
  class="checkbox-info icon icon-info icon-lg"
310
+ :data-testid="componentTestid + '-info-icon'"
296
311
  :tabindex="isDisabled ? -1 : 0"
297
312
  />
298
313
  <i
@@ -300,6 +315,7 @@ export default defineComponent({
300
315
  v-clean-tooltip="{content: tooltip, triggers: ['hover', 'touch', 'focus']}"
301
316
  v-stripped-aria-label="tooltip"
302
317
  class="checkbox-info icon icon-info icon-lg"
318
+ :data-testid="componentTestid + '-info-icon'"
303
319
  :tabindex="isDisabled ? -1 : 0"
304
320
  />
305
321
  </slot>
@@ -311,10 +327,13 @@ export default defineComponent({
311
327
  >
312
328
  <t
313
329
  v-if="descriptionKey"
330
+ :id="describedById"
314
331
  :k="descriptionKey"
315
332
  />
316
333
  <template v-else-if="description">
317
- {{ description }}
334
+ <p :id="describedById">
335
+ {{ description }}
336
+ </p>
318
337
  </template>
319
338
  </div>
320
339
  <div class="checkbox-outer-container-extra">
@@ -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
  };
@@ -17,6 +17,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
17
17
  const {
18
18
  dropdownItems,
19
19
  firstDropdownItem,
20
+ lastDropdownItem,
20
21
  dropdownContainer,
21
22
  registerDropdownCollection,
22
23
  } = useDropdownCollection();
@@ -70,7 +71,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
70
71
  /**
71
72
  * Sets focus to the first dropdown item if a keydown event has occurred.
72
73
  */
73
- const setFocus = () => {
74
+ const setFocus = (direction: 'down' | 'up') => {
74
75
  nextTick(() => {
75
76
  if (!didKeydown.value) {
76
77
  dropdownContainer.value?.focus();
@@ -78,7 +79,12 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
78
79
  return;
79
80
  }
80
81
 
81
- firstDropdownItem.value?.focus();
82
+ if (direction === 'down') {
83
+ firstDropdownItem.value?.focus();
84
+ } else if (direction === 'up') {
85
+ lastDropdownItem.value?.focus();
86
+ }
87
+
82
88
  didKeydown.value = false;
83
89
  });
84
90
  };
@@ -95,7 +101,7 @@ export const useDropdownContext = (emit: typeof rcDropdownEmits) => {
95
101
  dropdownItems,
96
102
  close: () => returnFocus(),
97
103
  focusFirstElement: () => {
98
- setFocus();
104
+ setFocus('down');
99
105
  },
100
106
  handleKeydown,
101
107
  });
@@ -633,7 +633,7 @@ export default defineComponent({
633
633
  }
634
634
 
635
635
  :deep() {
636
- .labeled-input INPUT.no-label,
636
+ /* .labeled-input INPUT.no-label, */
637
637
  .labeled-input INPUT:hover.no-label,
638
638
  .labeled-input INPUT:focus.no-label {
639
639
  padding: 1px 0px 0px 0px;
package/vue.config.js CHANGED
@@ -37,7 +37,7 @@ const perfTest = (process.env.PERF_TEST === 'true'); // Enable performance testi
37
37
  * Paths to the shell folder when it is included as a node dependency
38
38
  */
39
39
  const getShellPaths = (dir) => {
40
- let SHELL_ABS = path.join(dir, 'node_modules/@rancher/shell');
40
+ let SHELL_ABS = path.join(dir, 'node_modules/dashboard-shell-shell');
41
41
  let COMPONENTS_DIR = path.join(SHELL_ABS, 'rancher-components');
42
42
 
43
43
  if (fs.existsSync(SHELL_ABS)) {