@carbon/vue 3.0.6-alpha.0 → 3.0.7-alpha.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.
- package/dist/carbon-vue-3.common.js +11880 -8135
- package/dist/carbon-vue-3.common.js.map +1 -1
- package/dist/carbon-vue-3.umd.js +11880 -8135
- package/dist/carbon-vue-3.umd.js.map +1 -1
- package/dist/carbon-vue-3.umd.min.js +4 -4
- package/dist/carbon-vue-3.umd.min.js.map +1 -1
- package/package.json +4 -4
- package/src/components/CvAccordion/CvAccordion.stories.js +1 -0
- package/src/components/CvButton/CvButton.stories.js +3 -3
- package/src/components/CvButton/CvButtonSkeleton.stories.js +79 -0
- package/src/components/CvButton/CvButtonSkeleton.vue +19 -0
- package/src/components/CvButton/index.js +8 -1
- package/src/components/CvDatePicker/CvDatePicker.vue +1 -1
- package/src/components/CvDropdown/CvDropdown.stories.mdx +407 -0
- package/src/components/CvDropdown/CvDropdown.vue +418 -0
- package/src/components/CvDropdown/CvDropdownItem.vue +86 -0
- package/src/components/CvDropdown/CvDropdownSkeleton.vue +17 -0
- package/src/components/CvDropdown/index.js +5 -0
- package/src/components/CvForm/CvFormGroup.vue +1 -1
- package/src/components/CvInlineLoading/CvInlineLoading.stories.mdx +87 -0
- package/src/components/CvInlineLoading/CvInlineLoading.vue +144 -0
- package/src/components/CvInlineLoading/consts.js +9 -0
- package/src/components/CvInlineLoading/index.js +4 -0
- package/src/components/CvModal/CvModal.stories.mdx +4 -2
- package/src/components/CvModal/CvModal.vue +3 -5
- package/src/components/CvMultiSelect/CvMultiSelect.stories.mdx +333 -0
- package/src/components/CvMultiSelect/CvMultiSelect.vue +705 -0
- package/src/components/CvMultiSelect/consts.js +16 -0
- package/src/components/CvMultiSelect/index.js +3 -0
- package/src/components/CvNumberInput/CvNumberInput.stories.js +265 -0
- package/src/components/CvNumberInput/CvNumberInput.vue +227 -0
- package/src/components/CvNumberInput/CvNumberInputSkeleton.stories.js +30 -0
- package/src/components/CvNumberInput/CvNumberInputSkeleton.vue +10 -0
- package/src/components/CvNumberInput/StorybookGroupConst.js +1 -0
- package/src/components/CvNumberInput/__tests__/__snapshots__/CvNumberInput.spec.js.snap +21 -0
- package/src/components/CvNumberInput/index.js +5 -0
- package/src/components/CvTabs/CvTab.vue +77 -0
- package/src/components/CvTabs/CvTabs.stories.mdx +175 -0
- package/src/components/CvTabs/CvTabs.vue +406 -0
- package/src/components/CvTabs/CvTabsSkeleton.vue +24 -0
- package/src/components/CvTabs/_SbContainer.vue +22 -0
- package/src/components/CvTabs/index.js +5 -0
- package/src/components/CvToggle/CvToggle-Skeleton.vue +29 -0
- package/src/components/CvToggle/CvToggle.stories.js +232 -0
- package/src/components/CvToggle/CvToggle.vue +70 -0
- package/src/components/CvToggle/__tests__/__snapshots__/CvToggle.spec.js.snap +7 -0
- package/src/components/CvToggle/index.js +4 -0
- package/src/global/storybook-utils/story-source-code.js +1 -0
- package/src/use/cvInput.js +34 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Carbon Style Dropdown
|
|
3
|
+
|
|
4
|
+
Attributes:
|
|
5
|
+
placeholder: Placeholder text displayed before any selection is made.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
<cv-dropdown placeholder="Choose an option">
|
|
9
|
+
<cv-dropdown-item value="10">Option 1</cv-dropdown-item>
|
|
10
|
+
<cv-dropdown-item value="20">Option 2</cv-dropdown-item>
|
|
11
|
+
<cv-dropdown-item value="30">Option 3</cv-dropdown-item>
|
|
12
|
+
<cv-dropdown-item value="40">Option 4</cv-dropdown-item>
|
|
13
|
+
<cv-dropdown-item value="50">Option 5</cv-dropdown-item>
|
|
14
|
+
</cv-dropdown>
|
|
15
|
+
|
|
16
|
+
-->
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div :id="uid" ref="el" :class="{ [`${carbonPrefix}--form-item`]: formItem }">
|
|
20
|
+
<div
|
|
21
|
+
:class="[
|
|
22
|
+
`${carbonPrefix}--dropdown__wrapper`,
|
|
23
|
+
`${carbonPrefix}--list-box__wrapper`,
|
|
24
|
+
{
|
|
25
|
+
[`${carbonPrefix}--dropdown__wrapper--inline`]: inline,
|
|
26
|
+
[`${carbonPrefix}--list-box__wrapper--inline`]: inline,
|
|
27
|
+
'cv-dropdown': !formItem,
|
|
28
|
+
},
|
|
29
|
+
]"
|
|
30
|
+
:style="wrapperStyleOverride"
|
|
31
|
+
>
|
|
32
|
+
<label
|
|
33
|
+
v-if="label"
|
|
34
|
+
:id="`${uid}-label`"
|
|
35
|
+
:class="[
|
|
36
|
+
`${carbonPrefix}--label`,
|
|
37
|
+
{ [`${carbonPrefix}--label--disabled`]: disabled },
|
|
38
|
+
]"
|
|
39
|
+
>{{ label }}</label
|
|
40
|
+
>
|
|
41
|
+
|
|
42
|
+
<div
|
|
43
|
+
ref="listBox"
|
|
44
|
+
:aria-label="ariaLabel"
|
|
45
|
+
:class="[
|
|
46
|
+
`${carbonPrefix}--dropdown`,
|
|
47
|
+
`${carbonPrefix}--dropdown--${size}`,
|
|
48
|
+
{
|
|
49
|
+
[`${carbonPrefix}--dropdown--show-selected`]: !hideSelected,
|
|
50
|
+
[`${carbonPrefix}--dropdown--warning`]: isWarning,
|
|
51
|
+
[`${carbonPrefix}--list-box--warning`]: isWarning,
|
|
52
|
+
[`${carbonPrefix}--dropdown--invalid`]: data.isInvalid,
|
|
53
|
+
[`${carbonPrefix}--list-box`]: true,
|
|
54
|
+
[`${carbonPrefix}--dropdown--light`]: isLight,
|
|
55
|
+
[`${carbonPrefix}--list-box--up`]: up,
|
|
56
|
+
[`${carbonPrefix}--dropdown--open`]: open,
|
|
57
|
+
[`${carbonPrefix}--list-box--expanded`]: open,
|
|
58
|
+
[`${carbonPrefix}--dropdown--disabled`]: disabled,
|
|
59
|
+
[`${carbonPrefix}--dropdown--inline`]: inline,
|
|
60
|
+
},
|
|
61
|
+
]"
|
|
62
|
+
:data-invalid="data.isInvalid"
|
|
63
|
+
:data-value="dataValue"
|
|
64
|
+
data-dropdown
|
|
65
|
+
v-bind="$attrs"
|
|
66
|
+
@click="onClick"
|
|
67
|
+
@keydown.down.prevent="onDown"
|
|
68
|
+
@keydown.up.prevent="onUp"
|
|
69
|
+
@keydown.enter.prevent="onClick"
|
|
70
|
+
@keydown.esc.prevent="onEsc"
|
|
71
|
+
@keydown.tab="onTab"
|
|
72
|
+
>
|
|
73
|
+
<button
|
|
74
|
+
ref="button"
|
|
75
|
+
:aria-controls="`${uid}-menu`"
|
|
76
|
+
:aria-disabled="disabled"
|
|
77
|
+
:aria-expanded="open ? 'true' : 'false'"
|
|
78
|
+
:aria-labelledby="ariaLabeledBy"
|
|
79
|
+
:class="`${carbonPrefix}--list-box__field`"
|
|
80
|
+
:disabled="disabled"
|
|
81
|
+
aria-haspopup="true"
|
|
82
|
+
type="button"
|
|
83
|
+
>
|
|
84
|
+
<warning-alt-filled
|
|
85
|
+
v-if="isWarning"
|
|
86
|
+
:class="`${carbonPrefix}--list-box__invalid-icon ${carbonPrefix}--list-box__invalid-icon--warning`"
|
|
87
|
+
/>
|
|
88
|
+
<warning-filled
|
|
89
|
+
v-else-if="data.isInvalid"
|
|
90
|
+
:class="`${carbonPrefix}--list-box__invalid-icon`"
|
|
91
|
+
/>
|
|
92
|
+
<span
|
|
93
|
+
:id="`${uid}-value`"
|
|
94
|
+
:class="`${carbonPrefix}--list-box__label`"
|
|
95
|
+
data-test="internalCaption"
|
|
96
|
+
>
|
|
97
|
+
<slot name="internal-caption">{{ internalCaption }}</slot>
|
|
98
|
+
</span>
|
|
99
|
+
<div
|
|
100
|
+
:class="[
|
|
101
|
+
`${carbonPrefix}--list-box__menu-icon`,
|
|
102
|
+
{ [`${carbonPrefix}--list-box__menu-icon--open`]: open },
|
|
103
|
+
]"
|
|
104
|
+
>
|
|
105
|
+
<chevron-down :aria-label="open ? 'Close menu' : 'Open menu'" />
|
|
106
|
+
</div>
|
|
107
|
+
</button>
|
|
108
|
+
<ul
|
|
109
|
+
:id="`${uid}-menu`"
|
|
110
|
+
ref="dropList"
|
|
111
|
+
:aria-hidden="!open ? 'true' : 'false'"
|
|
112
|
+
:aria-labelledby="`${uid}-label`"
|
|
113
|
+
:class="`${carbonPrefix}--list-box__menu`"
|
|
114
|
+
role="menu"
|
|
115
|
+
tabindex="-1"
|
|
116
|
+
>
|
|
117
|
+
<slot>
|
|
118
|
+
<cv-dropdown-item
|
|
119
|
+
v-for="item in items"
|
|
120
|
+
v-bind:key="item"
|
|
121
|
+
:value="item"
|
|
122
|
+
>{{ item }}</cv-dropdown-item
|
|
123
|
+
>
|
|
124
|
+
</slot>
|
|
125
|
+
</ul>
|
|
126
|
+
</div>
|
|
127
|
+
<div v-if="data.isInvalid" :class="`${carbonPrefix}--form-requirement`">
|
|
128
|
+
<slot name="invalid-message">{{ invalidMessage }}</slot>
|
|
129
|
+
</div>
|
|
130
|
+
<div v-else-if="isWarning" :class="`${carbonPrefix}--form-requirement`">
|
|
131
|
+
<slot name="warning-message">{{ warningMessage }}</slot>
|
|
132
|
+
</div>
|
|
133
|
+
<div
|
|
134
|
+
v-else-if="data.isHelper"
|
|
135
|
+
:aria-disabled="disabled"
|
|
136
|
+
:class="[
|
|
137
|
+
`${carbonPrefix}--form__helper-text`,
|
|
138
|
+
{ [`${carbonPrefix}--form__helper-text--disabled`]: disabled },
|
|
139
|
+
]"
|
|
140
|
+
>
|
|
141
|
+
<slot name="helper-text">{{ helperText }}</slot>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</template>
|
|
146
|
+
|
|
147
|
+
<script setup>
|
|
148
|
+
import { carbonPrefix } from '../../global/settings';
|
|
149
|
+
import { props as propsCvId, useCvId } from '../../use/cvId';
|
|
150
|
+
import { props as propsCvTheme, useIsLight } from '../../use/cvTheme';
|
|
151
|
+
import CvDropdownItem from './CvDropdownItem.vue';
|
|
152
|
+
import ChevronDown from '@carbon/icons-vue/es/chevron--down/16';
|
|
153
|
+
import WarningFilled from '@carbon/icons-vue/es/warning--filled/16';
|
|
154
|
+
import WarningAltFilled from '@carbon/icons-vue/es/warning--alt--filled/16';
|
|
155
|
+
import {
|
|
156
|
+
computed,
|
|
157
|
+
nextTick,
|
|
158
|
+
onMounted,
|
|
159
|
+
onUpdated,
|
|
160
|
+
provide,
|
|
161
|
+
reactive,
|
|
162
|
+
ref,
|
|
163
|
+
useSlots,
|
|
164
|
+
watch,
|
|
165
|
+
} from 'vue';
|
|
166
|
+
import { onClickOutside } from '@vueuse/core';
|
|
167
|
+
|
|
168
|
+
const props = defineProps({
|
|
169
|
+
/**
|
|
170
|
+
* 'aria-label' of the ListBox component.
|
|
171
|
+
*/
|
|
172
|
+
ariaLabel: { type: String, default: 'Dropdown' },
|
|
173
|
+
/**
|
|
174
|
+
* Disable the control
|
|
175
|
+
*/
|
|
176
|
+
disabled: { type: Boolean, default: false },
|
|
177
|
+
/**
|
|
178
|
+
* Add carbon form classes to the dropdown list
|
|
179
|
+
*/
|
|
180
|
+
formItem: { type: Boolean, default: true },
|
|
181
|
+
/**
|
|
182
|
+
* Provide helper text that is used alongside the control label for additional help
|
|
183
|
+
*/
|
|
184
|
+
helperText: { type: String, default: undefined },
|
|
185
|
+
/**
|
|
186
|
+
* Not documented in react. Removes `dropdown--show-selected` class from component.
|
|
187
|
+
*/
|
|
188
|
+
hideSelected: { type: Boolean, default: false },
|
|
189
|
+
/**
|
|
190
|
+
* Specify whether you want the inline version of this control
|
|
191
|
+
*/
|
|
192
|
+
inline: { type: Boolean, default: false },
|
|
193
|
+
/**
|
|
194
|
+
* Message which is displayed if the value is invalid.
|
|
195
|
+
*/
|
|
196
|
+
invalidMessage: { type: String, default: undefined },
|
|
197
|
+
/**
|
|
198
|
+
* an array of strings to display as choices.
|
|
199
|
+
*/
|
|
200
|
+
items: {
|
|
201
|
+
type: Array,
|
|
202
|
+
validator(arr) {
|
|
203
|
+
if (!Array.isArray(arr)) {
|
|
204
|
+
console.warn('CvDropdown - items must be in array');
|
|
205
|
+
}
|
|
206
|
+
return arr;
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
/**
|
|
210
|
+
* Generic label that will be used as the textual representation of what this field is for
|
|
211
|
+
*/
|
|
212
|
+
label: String,
|
|
213
|
+
/**
|
|
214
|
+
* Value shown when nothing has been selected
|
|
215
|
+
*/
|
|
216
|
+
placeholder: {
|
|
217
|
+
type: String,
|
|
218
|
+
default: 'Choose an option',
|
|
219
|
+
},
|
|
220
|
+
/**
|
|
221
|
+
* Specify the size of the ListBox. Currently, supports either `sm`, `md` or `lg` as an option.
|
|
222
|
+
* @values sm,md,lg
|
|
223
|
+
*/
|
|
224
|
+
size: {
|
|
225
|
+
type: String,
|
|
226
|
+
default: 'md',
|
|
227
|
+
validator: val => ['sm', 'md', 'lg'].includes(val),
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* Specify the direction of the dropdown. Can be either true (top) or (false) bottom.
|
|
231
|
+
*/
|
|
232
|
+
up: { type: Boolean, default: false },
|
|
233
|
+
/**
|
|
234
|
+
* Render with a value already selected. Available as `v-model:value`.
|
|
235
|
+
*/
|
|
236
|
+
value: String,
|
|
237
|
+
/**
|
|
238
|
+
* Provide the text that is displayed and put the control in warning state
|
|
239
|
+
*/
|
|
240
|
+
warningMessage: { type: String, default: undefined },
|
|
241
|
+
/**
|
|
242
|
+
* @deprecated - use v-model:value
|
|
243
|
+
*/
|
|
244
|
+
modelValue: {
|
|
245
|
+
type: String,
|
|
246
|
+
validator: val => {
|
|
247
|
+
console.warn(
|
|
248
|
+
`v-model for cv-dropdown is deprecated. Specify "v-model:value" instead [${val}]`
|
|
249
|
+
);
|
|
250
|
+
return true;
|
|
251
|
+
},
|
|
252
|
+
default: undefined,
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
...propsCvId,
|
|
256
|
+
...propsCvTheme,
|
|
257
|
+
});
|
|
258
|
+
const uid = useCvId(props, true);
|
|
259
|
+
const isLight = useIsLight(props);
|
|
260
|
+
const dataValue = ref(props.value);
|
|
261
|
+
provide('dropdown-selected', dataValue);
|
|
262
|
+
const focusItem = ref(undefined);
|
|
263
|
+
provide('dropdown-focus', focusItem);
|
|
264
|
+
const dataCaption = ref(undefined);
|
|
265
|
+
provide('dropdown-caption', dataCaption);
|
|
266
|
+
/**
|
|
267
|
+
* List of children values
|
|
268
|
+
* @type {Ref<UnwrapRef<[{value:string}]>>}
|
|
269
|
+
*/
|
|
270
|
+
const itemsList = ref([]);
|
|
271
|
+
provide('dropdown-items', itemsList);
|
|
272
|
+
const open = ref(false);
|
|
273
|
+
const data = reactive({
|
|
274
|
+
isHelper: false,
|
|
275
|
+
isInvalid: undefined,
|
|
276
|
+
isWarning: false,
|
|
277
|
+
});
|
|
278
|
+
const slots = useSlots();
|
|
279
|
+
function checkSlots() {
|
|
280
|
+
// NOTE: slots is not reactive so needs to be managed on updated
|
|
281
|
+
data.isInvalid =
|
|
282
|
+
!!(slots['invalid-message'] || props.invalidMessage?.length) || undefined;
|
|
283
|
+
data.isWarning = !!(slots['warning-message'] || props.warningMessage?.length);
|
|
284
|
+
data.isHelper = !!(slots['helper-text'] || props.helperText?.length);
|
|
285
|
+
}
|
|
286
|
+
const isWarning = computed(() => {
|
|
287
|
+
if (data.isInvalid) return false;
|
|
288
|
+
else return !!data.isWarning;
|
|
289
|
+
});
|
|
290
|
+
onMounted(checkSlots);
|
|
291
|
+
onUpdated(checkSlots);
|
|
292
|
+
const emit = defineEmits(['update:value', 'update:modelValue', 'change']);
|
|
293
|
+
watch(
|
|
294
|
+
() => props.value,
|
|
295
|
+
() => {
|
|
296
|
+
dataValue.value = props.value;
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
watch(dataValue, () => {
|
|
300
|
+
emit('change', dataValue.value);
|
|
301
|
+
emit('update:value', dataValue.value);
|
|
302
|
+
emit('update:modelValue', dataValue.value);
|
|
303
|
+
});
|
|
304
|
+
watch(open, () => {
|
|
305
|
+
focusItem.value = '';
|
|
306
|
+
});
|
|
307
|
+
const ariaLabeledBy = computed(() => {
|
|
308
|
+
if (props.label) {
|
|
309
|
+
return `${uid}-label ${uid}-value`;
|
|
310
|
+
} else {
|
|
311
|
+
return `${uid}-value`;
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
const internalCaption = computed(() => {
|
|
315
|
+
if (dataCaption.value) {
|
|
316
|
+
return dataCaption.value;
|
|
317
|
+
} else {
|
|
318
|
+
return props.placeholder;
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const wrapperStyleOverride = computed(() => {
|
|
323
|
+
// ensures correct width when used inside tabs component
|
|
324
|
+
return { width: '100%' };
|
|
325
|
+
});
|
|
326
|
+
const el = ref(null);
|
|
327
|
+
function onClickOut() {
|
|
328
|
+
// eslint-disable-next-line no-console
|
|
329
|
+
console.log('onClickOut');
|
|
330
|
+
open.value = false;
|
|
331
|
+
}
|
|
332
|
+
onClickOutside(el, onClickOut);
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Set the focus on one of the items in the dropdown list
|
|
336
|
+
* @param {boolean} up - Direction to move focus
|
|
337
|
+
*/
|
|
338
|
+
function doMove(up) {
|
|
339
|
+
// re-query could have changed
|
|
340
|
+
const currentFocusEl = el.value?.querySelector('.cv-dropdown-item :focus');
|
|
341
|
+
const numChildren = itemsList.value.length || 0;
|
|
342
|
+
|
|
343
|
+
const currentFocusValue =
|
|
344
|
+
currentFocusEl?.parentNode?.getAttribute('data-value');
|
|
345
|
+
|
|
346
|
+
const currentFocusIndex = itemsList.value?.findIndex(
|
|
347
|
+
child => child.value === currentFocusValue
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
const direction = up ? -1 : 1;
|
|
351
|
+
let nextFocusIndex = currentFocusIndex + direction;
|
|
352
|
+
if (nextFocusIndex >= numChildren) nextFocusIndex = 0;
|
|
353
|
+
else if (nextFocusIndex < 0) nextFocusIndex = numChildren - 1;
|
|
354
|
+
focusItem.value = itemsList.value[nextFocusIndex]?.value;
|
|
355
|
+
}
|
|
356
|
+
const dropList = ref(null);
|
|
357
|
+
function doFocus() {
|
|
358
|
+
nextTick(() => {
|
|
359
|
+
if (open.value) {
|
|
360
|
+
dropList.value?.focus();
|
|
361
|
+
} else {
|
|
362
|
+
focus();
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
function onDown() {
|
|
367
|
+
if (!open.value) {
|
|
368
|
+
open.value = true;
|
|
369
|
+
} else {
|
|
370
|
+
doMove(false);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function onUp() {
|
|
374
|
+
if (open.value) {
|
|
375
|
+
doMove(true);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function onEsc() {
|
|
379
|
+
open.value = false;
|
|
380
|
+
doFocus();
|
|
381
|
+
}
|
|
382
|
+
const button = ref(null);
|
|
383
|
+
const listBox = ref(null);
|
|
384
|
+
function onTab(ev) {
|
|
385
|
+
if (open.value) {
|
|
386
|
+
if (button.value === ev.target) {
|
|
387
|
+
// button has focus ensure we are closed
|
|
388
|
+
open.value = false;
|
|
389
|
+
} else if (ev.target === null || listBox.value?.contains(ev.target)) {
|
|
390
|
+
// list has focus, close and return focus to dropdown
|
|
391
|
+
open.value = false;
|
|
392
|
+
doFocus();
|
|
393
|
+
ev.preventDefault();
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function onClick(ev) {
|
|
398
|
+
if (props.disabled) {
|
|
399
|
+
ev.preventDefault();
|
|
400
|
+
} else {
|
|
401
|
+
open.value = !open.value;
|
|
402
|
+
doFocus(); // open or close (Some browsers do not focus on button when clicked)
|
|
403
|
+
|
|
404
|
+
let target = ev.target;
|
|
405
|
+
while (
|
|
406
|
+
!target.classList.contains(`${carbonPrefix}--dropdown-link`) &&
|
|
407
|
+
dropList.value?.contains(target)
|
|
408
|
+
) {
|
|
409
|
+
target = target.parentNode; // try next one up
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (target.classList.contains(`${carbonPrefix}--dropdown-link`)) {
|
|
413
|
+
const targetItemEl = target.parentNode;
|
|
414
|
+
dataValue.value = targetItemEl.getAttribute('data-value');
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
</script>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Carbon dropdown item
|
|
3
|
+
|
|
4
|
+
Attributes:
|
|
5
|
+
value: The value for the item. Optional.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
See dropdown.vue
|
|
9
|
+
|
|
10
|
+
-->
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<li
|
|
14
|
+
data-option
|
|
15
|
+
:data-value="value"
|
|
16
|
+
:class="[
|
|
17
|
+
`cv-dropdown-item ${carbonPrefix}--dropdown-item`,
|
|
18
|
+
{ [`${carbonPrefix}--dropdown--selected`]: dataSelected },
|
|
19
|
+
]"
|
|
20
|
+
role="menuitem"
|
|
21
|
+
>
|
|
22
|
+
<a
|
|
23
|
+
:aria-checked="dataSelected"
|
|
24
|
+
:class="`${carbonPrefix}--dropdown-link`"
|
|
25
|
+
href="javascript:void(0)"
|
|
26
|
+
ref="link"
|
|
27
|
+
role="menuitemradio"
|
|
28
|
+
tabindex="-1"
|
|
29
|
+
>
|
|
30
|
+
<slot></slot>
|
|
31
|
+
</a>
|
|
32
|
+
</li>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
import { carbonPrefix } from '../../global/settings';
|
|
37
|
+
import { inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
38
|
+
const props = defineProps({
|
|
39
|
+
value: {
|
|
40
|
+
type: String,
|
|
41
|
+
required: true,
|
|
42
|
+
},
|
|
43
|
+
selected: { type: Boolean, default: false },
|
|
44
|
+
});
|
|
45
|
+
const dataSelected = ref(props.selected);
|
|
46
|
+
/**
|
|
47
|
+
* @type {Ref<string>}
|
|
48
|
+
*/
|
|
49
|
+
const parentSelected = inject('dropdown-selected');
|
|
50
|
+
/**
|
|
51
|
+
* @type {Ref<string>}
|
|
52
|
+
*/
|
|
53
|
+
const parentFocus = inject('dropdown-focus');
|
|
54
|
+
const parentCaption = inject('dropdown-caption');
|
|
55
|
+
watch(
|
|
56
|
+
() => props.selected,
|
|
57
|
+
() => {
|
|
58
|
+
dataSelected.value = props.selected;
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
watch(parentSelected, () => {
|
|
62
|
+
dataSelected.value = props.value === parentSelected.value;
|
|
63
|
+
});
|
|
64
|
+
const link = ref(null);
|
|
65
|
+
watch(parentFocus, () => {
|
|
66
|
+
if (props.value === parentFocus.value) link.value?.focus();
|
|
67
|
+
});
|
|
68
|
+
watch(dataSelected, val => {
|
|
69
|
+
if (val) {
|
|
70
|
+
parentSelected.value = props.value;
|
|
71
|
+
parentCaption.value = link.value?.text || props.value;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const parentList = inject('dropdown-items');
|
|
75
|
+
onMounted(() => {
|
|
76
|
+
dataSelected.value = props.value === parentSelected.value;
|
|
77
|
+
parentList.value?.push({
|
|
78
|
+
value: props.value,
|
|
79
|
+
selected: props.selected,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
onBeforeUnmount(() => {
|
|
83
|
+
const index = parentList.value?.findIndex(item => item.value === props.value);
|
|
84
|
+
if (index > -1) parentList.value?.splice(index, 1);
|
|
85
|
+
});
|
|
86
|
+
</script>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
disabled
|
|
4
|
+
:class="[
|
|
5
|
+
`${carbonPrefix}--list-box ${carbonPrefix}--dropdown ${carbonPrefix}--skeleton`,
|
|
6
|
+
{ [`${carbonPrefix}--list-box--inline`]: inline },
|
|
7
|
+
]"
|
|
8
|
+
></div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
import { carbonPrefix } from '../../global/settings';
|
|
13
|
+
|
|
14
|
+
defineProps({
|
|
15
|
+
inline: { type: Boolean, default: false },
|
|
16
|
+
});
|
|
17
|
+
</script>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Canvas, Meta, Story } from '@storybook/addon-docs';
|
|
2
|
+
import CvInlineLoading from './CvInlineLoading.vue';
|
|
3
|
+
import { sbCompPrefix } from '../../global/storybook-utils';
|
|
4
|
+
|
|
5
|
+
<Meta title={`${sbCompPrefix}/CvInlineLoading`} component={CvInlineLoading} />
|
|
6
|
+
|
|
7
|
+
export const Template = args => ({
|
|
8
|
+
// Components used in your story `template` are defined in the `components` object
|
|
9
|
+
components: {
|
|
10
|
+
CvInlineLoading,
|
|
11
|
+
},
|
|
12
|
+
// The story's `args` need to be mapped into the template through the `setup()` method
|
|
13
|
+
setup() {
|
|
14
|
+
return {
|
|
15
|
+
description: args.description,
|
|
16
|
+
errorText: args.errorText,
|
|
17
|
+
endingText: args.endingText,
|
|
18
|
+
loadingText: args.loadingText,
|
|
19
|
+
loadedText: args.loadedText,
|
|
20
|
+
state: args.state,
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
template: args.template,
|
|
24
|
+
});
|
|
25
|
+
const defaultTemplate = `
|
|
26
|
+
<cv-inline-loading
|
|
27
|
+
:description="description"
|
|
28
|
+
:ending-text="endingText"
|
|
29
|
+
:error-text="errorText"
|
|
30
|
+
:loading-text="loadingText"
|
|
31
|
+
:loaded-text="loadedText"
|
|
32
|
+
:state="state" />
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
# CvInlineLoading
|
|
36
|
+
|
|
37
|
+
Migration notes:
|
|
38
|
+
|
|
39
|
+
- The `active` property is still available but does not actually work. Please use the `state` property instead.
|
|
40
|
+
- The state has two new values to make it easier to transition form `loading` to either `loaded` or `error`.
|
|
41
|
+
Setting `state` to "ending:loaded" or "ending:error" will first set the `ending` state and then, when
|
|
42
|
+
the ending animation completes, the `loaded` or `error` state.
|
|
43
|
+
- The states can be imported like `import { STATES } from "@/components/CvInlineLoading";` and used
|
|
44
|
+
as:
|
|
45
|
+
- `STATES.LOADING`
|
|
46
|
+
- `STATES.ENDING`
|
|
47
|
+
- `STATES.LOADED`
|
|
48
|
+
- `STATES.ERROR`
|
|
49
|
+
- `STATES.ENDING_LOADED`
|
|
50
|
+
- `STATES.ENDING_ERROR`
|
|
51
|
+
|
|
52
|
+
<Canvas>
|
|
53
|
+
<Story
|
|
54
|
+
name="Default"
|
|
55
|
+
parameters={{
|
|
56
|
+
controls: {
|
|
57
|
+
exclude: ['template'],
|
|
58
|
+
},
|
|
59
|
+
docs: { source: { code: defaultTemplate } },
|
|
60
|
+
}}
|
|
61
|
+
args={{
|
|
62
|
+
template: defaultTemplate,
|
|
63
|
+
endingText: 'Jumping to warp 9',
|
|
64
|
+
description: 'Warp engine status',
|
|
65
|
+
errorText: 'Warp drive is damaged',
|
|
66
|
+
loadingText: 'Warp drive coming online...',
|
|
67
|
+
loadedText: 'Warp drive engaged',
|
|
68
|
+
state: 'loading',
|
|
69
|
+
}}
|
|
70
|
+
argTypes={{
|
|
71
|
+
state: {
|
|
72
|
+
control: 'select',
|
|
73
|
+
default: 'loading',
|
|
74
|
+
options: [
|
|
75
|
+
'loading',
|
|
76
|
+
'ending',
|
|
77
|
+
'loaded',
|
|
78
|
+
'error',
|
|
79
|
+
'ending:loaded',
|
|
80
|
+
'ending:error',
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
{Template.bind({})}
|
|
86
|
+
</Story>
|
|
87
|
+
</Canvas>
|