@carbon/vue 3.0.7-alpha.0 → 3.0.9-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/README.md +7 -0
- package/dist/carbon-vue-3.common.js +3850 -217
- package/dist/carbon-vue-3.common.js.map +1 -1
- package/dist/carbon-vue-3.umd.js +3850 -217
- 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 +7 -4
- package/src/components/CvCheckbox/CvCheckbox.stories.js +18 -7
- package/src/components/CvCheckbox/CvCheckbox.vue +19 -3
- package/src/components/CvCheckbox/CvCheckboxSkeleton.vue +16 -0
- package/src/components/CvCheckbox/__tests__/__snapshots__/CvCheckboxSkeleton.spec.js.snap +3 -0
- package/src/components/CvCheckbox/index.js +2 -1
- package/src/components/CvDropdown/CvDropdown.vue +0 -2
- package/src/components/CvFileUploader/CvFileUploader.stories.mdx +333 -0
- package/src/components/CvFileUploader/CvFileUploader.vue +286 -0
- package/src/components/CvFileUploader/CvFileUploaderItem.vue +92 -0
- package/src/components/CvFileUploader/CvFileUploaderSkeleton.vue +16 -0
- package/src/components/CvFileUploader/const.js +10 -0
- package/src/components/CvFileUploader/index.js +5 -0
- package/src/components/CvMultiSelect/CvMultiSelect.stories.mdx +1 -1
- package/src/components/CvNotification/CvToastNotification.stories.js +71 -1
- package/src/components/CvNotification/CvToastNotification.vue +6 -4
- package/src/components/CvOverflowMenu/CvOverflowMenu.stories.mdx +68 -12
- package/src/components/CvOverflowMenu/CvOverflowMenu.vue +39 -45
- package/src/components/CvOverflowMenu/CvOverflowMenuItem.vue +6 -11
- package/src/components/CvOverflowMenu/index.js +2 -1
- package/src/components/CvProgress/CvProgress.stories.mdx +202 -0
- package/src/components/CvProgress/CvProgress.vue +78 -0
- package/src/components/CvProgress/CvProgressStep.vue +124 -0
- package/src/components/CvProgress/index.js +4 -0
- package/src/components/CvRadioButton/CvRadioButton.stories.js +166 -0
- package/src/components/CvRadioButton/CvRadioButton.vue +57 -0
- package/src/components/CvRadioButton/CvRadioGroup.vue +27 -0
- package/src/components/CvRadioButton/__tests__/__snapshots__/CvRadioButton.spec.js.snap +27 -0
- package/src/components/CvRadioButton/index.js +6 -0
- package/src/components/CvSearch/CvSearch.stories.mdx +168 -0
- package/src/components/CvSearch/CvSearch.vue +250 -0
- package/src/components/CvSearch/index.js +3 -0
- package/src/components/CvSelect/CvSelect.vue +27 -6
- package/src/components/CvSlider/CvSlider.stories.js +166 -0
- package/src/components/CvSlider/CvSlider.vue +324 -0
- package/src/components/CvSlider/CvSliderSkeleton.stories.js +26 -0
- package/src/components/CvSlider/CvSliderSkeleton.vue +18 -0
- package/src/components/CvSlider/__tests__/__snapshots__/CvSlider.spec.js.snap +13 -0
- package/src/components/CvSlider/__tests__/__snapshots__/CvSliderSkeleton.spec.js.snap +13 -0
- package/src/components/CvSlider/index.js +5 -0
- package/src/components/CvSlider/sbSliderPrefix.js +2 -0
- package/src/components/CvStructuredList/CvStructuredList.stories.js +141 -0
- package/src/components/CvStructuredList/CvStructuredList.vue +44 -0
- package/src/components/CvStructuredList/CvStructuredListData.vue +19 -0
- package/src/components/CvStructuredList/CvStructuredListHeading.vue +11 -0
- package/src/components/CvStructuredList/CvStructuredListItem.vue +47 -0
- package/src/components/CvStructuredList/CvStructuredListItemSelectable.vue +56 -0
- package/src/components/CvStructuredList/CvStructuredListItemStandard.vue +11 -0
- package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredList.spec.js.snap +73 -0
- package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredListData.spec.js.snap +5 -0
- package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredListHeading.spec.js.snap +9 -0
- package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredListItem.spec.js.snap +7 -0
- package/src/components/CvStructuredList/index.js +12 -0
- package/src/components/CvTextArea/CvTextArea.stories.js +2 -2
- package/src/components/CvTextArea/CvTextAreaSkeleton.stories.js +29 -0
- package/src/components/CvTextArea/CvTextAreaSkeleton.vue +10 -0
- package/src/components/CvTextArea/StorybookGroupConst.js +1 -0
- package/src/components/CvTextArea/__tests__/__snapshots__/CvTextAreaSkeleton.spec.js.snap +7 -0
- package/src/components/CvTextArea/index.js +2 -1
- package/src/components/CvTimePicker/CvTimePicker.stories.mdx +325 -0
- package/src/components/CvTimePicker/CvTimePicker.vue +217 -0
- package/src/components/CvTimePicker/index.js +21 -0
- package/src/components/CvToggle/CvToggle-Skeleton.vue +27 -12
- package/src/components/CvToggle/CvToggle.stories.js +20 -3
- package/src/components/CvToggle/CvToggle.vue +22 -5
- package/src/components/CvToggle/__tests__/__snapshots__/CvToggle.spec.js.snap +3 -3
- package/src/components/CvTooltip/CvDefinitionTooltip.stories.js +80 -0
- package/src/components/CvTooltip/CvDefinitionTooltip.vue +61 -0
- package/src/components/CvTooltip/CvInteractiveTooltip.stories.js +90 -0
- package/src/components/CvTooltip/CvInteractiveTooltip.vue +267 -0
- package/src/components/CvTooltip/CvTooltip.stories.js +128 -0
- package/src/components/CvTooltip/CvTooltip.vue +44 -0
- package/src/components/CvTooltip/__tests__/__snapshots__/CvTooltip.spec.js.snap +525 -0
- package/src/components/CvTooltip/consts.js +15 -0
- package/src/components/CvTooltip/index.js +6 -0
- package/src/components/CvTooltip/sbTooltipPrefix.js +2 -0
- package/src/components/CvUIShell/CvSideNav.vue +10 -1
- package/src/components/CvUIShell/CvUIShell.stories.mdx +116 -50
- package/src/index.d.ts +6 -0
- package/src/index.js +11 -0
- package/src/use/cvCheck.js +3 -0
- package/src/use/index.js +2 -0
- package/src/use/useMethods.js +18 -0
- package/src/use/useRadio.js +24 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<cv-wrapper
|
|
3
|
+
ref="el"
|
|
3
4
|
:tag-type="formItem ? 'div' : ''"
|
|
4
5
|
:class="`cv-select ${carbonPrefix}--form-item`"
|
|
5
|
-
ref="el"
|
|
6
6
|
>
|
|
7
7
|
<div
|
|
8
8
|
:data-test="value"
|
|
9
9
|
:class="[
|
|
10
10
|
`${carbonPrefix}--select`,
|
|
11
|
+
`${carbonClasses}`,
|
|
11
12
|
{
|
|
12
13
|
'cv-select': !formItem,
|
|
13
14
|
[`${carbonPrefix}--select--inline`]: inline,
|
|
@@ -48,9 +49,8 @@
|
|
|
48
49
|
size || 'md',
|
|
49
50
|
},
|
|
50
51
|
]"
|
|
51
|
-
@change="onChange"
|
|
52
|
-
ref="select"
|
|
53
52
|
:value="internalValue"
|
|
53
|
+
@change="onChange"
|
|
54
54
|
>
|
|
55
55
|
<slot></slot>
|
|
56
56
|
</select>
|
|
@@ -77,7 +77,6 @@
|
|
|
77
77
|
>
|
|
78
78
|
<slot name="helper-text">{{ helperText }}</slot>
|
|
79
79
|
</div>
|
|
80
|
-
|
|
81
80
|
<!-- cv-wrapper div ${carbonPrefix}--select-input--inline__wrapper -->
|
|
82
81
|
</cv-wrapper>
|
|
83
82
|
</div>
|
|
@@ -87,7 +86,15 @@
|
|
|
87
86
|
|
|
88
87
|
<script setup>
|
|
89
88
|
import { carbonPrefix } from '../../global/settings';
|
|
90
|
-
import {
|
|
89
|
+
import {
|
|
90
|
+
computed,
|
|
91
|
+
onMounted,
|
|
92
|
+
onUpdated,
|
|
93
|
+
ref,
|
|
94
|
+
useAttrs,
|
|
95
|
+
useSlots,
|
|
96
|
+
watch,
|
|
97
|
+
} from 'vue';
|
|
91
98
|
import {
|
|
92
99
|
WarningFilled16 as WarningFilled,
|
|
93
100
|
ChevronDown16 as ChevronDown,
|
|
@@ -112,6 +119,7 @@ const props = defineProps({
|
|
|
112
119
|
// multiple does not work with styling from carbon-components 9.20
|
|
113
120
|
multiple: {
|
|
114
121
|
type: String,
|
|
122
|
+
default: undefined,
|
|
115
123
|
validator: () => {
|
|
116
124
|
console.warn('property multiple not supported in CvSelect');
|
|
117
125
|
return false;
|
|
@@ -123,7 +131,7 @@ const props = defineProps({
|
|
|
123
131
|
default: 'md',
|
|
124
132
|
validator: val => ['sm', 'md', 'lg'].includes(val),
|
|
125
133
|
},
|
|
126
|
-
modelValue: { type: String },
|
|
134
|
+
modelValue: { type: String, default: undefined },
|
|
127
135
|
...propsTheme,
|
|
128
136
|
...propsCvId,
|
|
129
137
|
});
|
|
@@ -221,4 +229,17 @@ function updateWarning() {
|
|
|
221
229
|
}
|
|
222
230
|
onMounted(updateWarning);
|
|
223
231
|
onUpdated(updateWarning);
|
|
232
|
+
|
|
233
|
+
// There is an oddity here with Vue2 vs Vue3. The Vue2 component uses CvWrapper to determine if this component
|
|
234
|
+
// is wrapped in a div or not. Either way the class attributes are applied in Vue2. In Vue3 the attributes are
|
|
235
|
+
// not applied. The CvTimePicker consumes this component and needs to apply styles in both the wrapped and
|
|
236
|
+
// unwrapped case. Here we apply any carbon styles to the outer div.
|
|
237
|
+
const attrs = useAttrs();
|
|
238
|
+
const carbonClasses = computed(() => {
|
|
239
|
+
if (props.formItem || !attrs.class) return '';
|
|
240
|
+
return attrs.class
|
|
241
|
+
?.split(' ')
|
|
242
|
+
.filter(c => c.startsWith(`${carbonPrefix}--`))
|
|
243
|
+
.join(' ');
|
|
244
|
+
});
|
|
224
245
|
</script>
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import { action } from '@storybook/addon-actions';
|
|
3
|
+
import {
|
|
4
|
+
sbCompPrefix,
|
|
5
|
+
storyParametersObject,
|
|
6
|
+
} from '../../global/storybook-utils';
|
|
7
|
+
import { sbSliderPrefix } from './sbSliderPrefix';
|
|
8
|
+
import { CvSlider } from '.';
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
title: `${sbCompPrefix}/${sbSliderPrefix}/CvSlider`,
|
|
12
|
+
component: CvSlider,
|
|
13
|
+
argTypes: {
|
|
14
|
+
disabled: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
table: {
|
|
17
|
+
type: { summary: 'boolean' },
|
|
18
|
+
category: 'attributes',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
value: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
table: {
|
|
24
|
+
type: { summary: 'string' },
|
|
25
|
+
category: 'props',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
label: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
table: {
|
|
31
|
+
type: { summary: 'string' },
|
|
32
|
+
category: 'props',
|
|
33
|
+
},
|
|
34
|
+
description: 'Slider top label',
|
|
35
|
+
},
|
|
36
|
+
light: {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
table: {
|
|
39
|
+
type: { summary: 'boolean' },
|
|
40
|
+
category: 'props',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
min: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
table: {
|
|
46
|
+
type: { summary: 'string' },
|
|
47
|
+
category: 'props',
|
|
48
|
+
},
|
|
49
|
+
description: 'Slider input min value',
|
|
50
|
+
},
|
|
51
|
+
max: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
table: {
|
|
54
|
+
type: { summary: 'string' },
|
|
55
|
+
category: 'props',
|
|
56
|
+
},
|
|
57
|
+
description: 'Slider input max value',
|
|
58
|
+
},
|
|
59
|
+
minLabel: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
table: {
|
|
62
|
+
type: { summary: 'string' },
|
|
63
|
+
category: 'props',
|
|
64
|
+
},
|
|
65
|
+
description: 'Label for min side of slider, otherwise min value used',
|
|
66
|
+
},
|
|
67
|
+
maxLabel: {
|
|
68
|
+
type: 'string',
|
|
69
|
+
table: {
|
|
70
|
+
type: { summary: 'string' },
|
|
71
|
+
category: 'props',
|
|
72
|
+
},
|
|
73
|
+
description: 'Label for max side of slider, otherwise max value used',
|
|
74
|
+
},
|
|
75
|
+
step: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
table: {
|
|
78
|
+
type: { summary: 'string' },
|
|
79
|
+
category: 'props',
|
|
80
|
+
},
|
|
81
|
+
description: 'Slider input step value',
|
|
82
|
+
},
|
|
83
|
+
stepMultiplier: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
table: {
|
|
86
|
+
type: { summary: 'string' },
|
|
87
|
+
category: 'props',
|
|
88
|
+
},
|
|
89
|
+
description: 'multiplier > 1',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
// events
|
|
94
|
+
change: {
|
|
95
|
+
type: 'event',
|
|
96
|
+
table: {
|
|
97
|
+
type: { summary: 'event' },
|
|
98
|
+
category: 'events',
|
|
99
|
+
},
|
|
100
|
+
control: { type: null },
|
|
101
|
+
},
|
|
102
|
+
'update:modelValue': {
|
|
103
|
+
type: 'event',
|
|
104
|
+
table: {
|
|
105
|
+
type: { summary: 'event' },
|
|
106
|
+
category: 'events',
|
|
107
|
+
},
|
|
108
|
+
control: { type: null },
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const template = `<cv-slider v-bind="args" @change="onChange"/>`;
|
|
113
|
+
const Template = args => {
|
|
114
|
+
return {
|
|
115
|
+
components: { CvSlider },
|
|
116
|
+
setup: () => ({
|
|
117
|
+
args,
|
|
118
|
+
onChange: action('change'),
|
|
119
|
+
}),
|
|
120
|
+
template,
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const Default = Template.bind({});
|
|
125
|
+
Default.args = {};
|
|
126
|
+
Default.parameters = storyParametersObject(
|
|
127
|
+
Default.parameters,
|
|
128
|
+
template,
|
|
129
|
+
Default.args
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const vModelTemplate = `
|
|
133
|
+
<cv-slider v-bind="args" v-model="modelValue" />
|
|
134
|
+
|
|
135
|
+
<div style="margin-top:1rem; background-color: #888888; padding:1rem">
|
|
136
|
+
<div style="font-size: 150%">
|
|
137
|
+
Sample interaction
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<input v-model="modelValue" type="string" />
|
|
141
|
+
<div>
|
|
142
|
+
Entered value:
|
|
143
|
+
<span style="font-weight: bold;">{{modelValue}}</span>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
const VModelTemplate = args => {
|
|
149
|
+
return {
|
|
150
|
+
components: { CvSlider },
|
|
151
|
+
setup: () => ({
|
|
152
|
+
args,
|
|
153
|
+
onChange: action('change'),
|
|
154
|
+
modelValue: ref('15'),
|
|
155
|
+
}),
|
|
156
|
+
template: vModelTemplate,
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const vModel = VModelTemplate.bind({});
|
|
161
|
+
vModel.args = {};
|
|
162
|
+
vModel.parameters = storyParametersObject(
|
|
163
|
+
vModel.parameters,
|
|
164
|
+
vModelTemplate,
|
|
165
|
+
vModel.args
|
|
166
|
+
);
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="`cv-slider ${carbonPrefix}--form-item`">
|
|
3
|
+
<label
|
|
4
|
+
v-show="label"
|
|
5
|
+
:for="cvId"
|
|
6
|
+
:class="[
|
|
7
|
+
`${carbonPrefix}--label`,
|
|
8
|
+
{ [`${carbonPrefix}--label--disabled`]: disabled },
|
|
9
|
+
]"
|
|
10
|
+
:id="labelId"
|
|
11
|
+
>
|
|
12
|
+
{{ label }}
|
|
13
|
+
</label>
|
|
14
|
+
|
|
15
|
+
<div :class="`${carbonPrefix}--slider-container`">
|
|
16
|
+
<span :class="`${carbonPrefix}--slider__range-label`">
|
|
17
|
+
{{ internalMinLabel }}
|
|
18
|
+
</span>
|
|
19
|
+
|
|
20
|
+
<div
|
|
21
|
+
:class="[
|
|
22
|
+
`${carbonPrefix}--slider`,
|
|
23
|
+
{ [`${carbonPrefix}--slider--disabled`]: disabled },
|
|
24
|
+
]"
|
|
25
|
+
data-slider
|
|
26
|
+
data-slider-input-box="#slider-input-box"
|
|
27
|
+
>
|
|
28
|
+
<div
|
|
29
|
+
:class="`${carbonPrefix}--slider__track`"
|
|
30
|
+
@click="onTrackClick"
|
|
31
|
+
ref="track"
|
|
32
|
+
></div>
|
|
33
|
+
|
|
34
|
+
<div
|
|
35
|
+
:class="`${carbonPrefix}--slider__filled-track`"
|
|
36
|
+
:style="`width: ${percentage};`"
|
|
37
|
+
></div>
|
|
38
|
+
|
|
39
|
+
<div
|
|
40
|
+
:class="[
|
|
41
|
+
`${carbonPrefix}--slider__thumb`,
|
|
42
|
+
{
|
|
43
|
+
[`${carbonPrefix}--slider__thumb--clicked`]: animateClick,
|
|
44
|
+
},
|
|
45
|
+
]"
|
|
46
|
+
tabindex="0"
|
|
47
|
+
:aria-labelledby="labelId"
|
|
48
|
+
:style="`left: ${percentage};`"
|
|
49
|
+
ref="thumb"
|
|
50
|
+
@keydown.up.right.prevent="onUp"
|
|
51
|
+
@keydown.down.left.prevent="onDown"
|
|
52
|
+
@mousedown="onStartDrag"
|
|
53
|
+
></div>
|
|
54
|
+
|
|
55
|
+
<input
|
|
56
|
+
:id="cvId"
|
|
57
|
+
:class="`${carbonPrefix}--slider__input`"
|
|
58
|
+
type="range"
|
|
59
|
+
:step="step"
|
|
60
|
+
:min="min"
|
|
61
|
+
:max="max"
|
|
62
|
+
ref="range"
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<span :class="`${carbonPrefix}--slider__range-label`">
|
|
67
|
+
{{ internalMaxLabel }}
|
|
68
|
+
</span>
|
|
69
|
+
|
|
70
|
+
<input
|
|
71
|
+
type="string"
|
|
72
|
+
:class="[
|
|
73
|
+
`${carbonPrefix}--text-input ${carbonPrefix}--slider-text-input`,
|
|
74
|
+
{ [`${carbonPrefix}--text-input--light`]: isLight },
|
|
75
|
+
]"
|
|
76
|
+
:placeholder="min"
|
|
77
|
+
v-model="internalValue"
|
|
78
|
+
@change="onChange"
|
|
79
|
+
ref="inputBox"
|
|
80
|
+
@keydown.up.prevent="onUp"
|
|
81
|
+
@keydown.down.prevent="onDown"
|
|
82
|
+
:disabled="disabled"
|
|
83
|
+
/>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
87
|
+
|
|
88
|
+
<script setup>
|
|
89
|
+
import { computed, ref, onMounted, nextTick, watch } from 'vue';
|
|
90
|
+
import { carbonPrefix } from '../../global/settings';
|
|
91
|
+
import { props as propsCvId, useCvId } from '../../use/cvId';
|
|
92
|
+
import { useIsLight, props as propsTheme } from '../../use/cvTheme';
|
|
93
|
+
|
|
94
|
+
const props = defineProps({
|
|
95
|
+
modelValue: {
|
|
96
|
+
type: String,
|
|
97
|
+
default: undefined,
|
|
98
|
+
},
|
|
99
|
+
value: {
|
|
100
|
+
type: String,
|
|
101
|
+
default: undefined,
|
|
102
|
+
},
|
|
103
|
+
disabled: Boolean,
|
|
104
|
+
label: {
|
|
105
|
+
type: String,
|
|
106
|
+
default: undefined,
|
|
107
|
+
},
|
|
108
|
+
// NOTE: It is not safe to rely on Numbers for non-integer steps
|
|
109
|
+
min: {
|
|
110
|
+
type: String,
|
|
111
|
+
default: '0',
|
|
112
|
+
},
|
|
113
|
+
max: {
|
|
114
|
+
type: String,
|
|
115
|
+
default: '100',
|
|
116
|
+
},
|
|
117
|
+
minLabel: {
|
|
118
|
+
type: String,
|
|
119
|
+
default: undefined,
|
|
120
|
+
},
|
|
121
|
+
maxLabel: {
|
|
122
|
+
type: String,
|
|
123
|
+
default: undefined,
|
|
124
|
+
},
|
|
125
|
+
step: {
|
|
126
|
+
type: String,
|
|
127
|
+
default: '1',
|
|
128
|
+
},
|
|
129
|
+
stepMultiplier: {
|
|
130
|
+
type: String,
|
|
131
|
+
default: '4',
|
|
132
|
+
validator(val) {
|
|
133
|
+
if (val.length) {
|
|
134
|
+
let intMultiplier = parseInt(val);
|
|
135
|
+
if (isNaN(intMultiplier) || intMultiplier < 1) {
|
|
136
|
+
console.warn('cv-slider: multiplier must be >= 1');
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
...propsTheme,
|
|
144
|
+
...propsCvId,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const range = ref(null);
|
|
148
|
+
const thumb = ref(null);
|
|
149
|
+
const track = ref(null);
|
|
150
|
+
const DefaultRangeMin = 0;
|
|
151
|
+
const DefaultRangeMax = 100;
|
|
152
|
+
const DefaultValue = 0;
|
|
153
|
+
const StepNaNReplacement = 0;
|
|
154
|
+
const StepDefaultValue = 1;
|
|
155
|
+
const DefaultMultiplier = 4;
|
|
156
|
+
|
|
157
|
+
const emit = defineEmits(['update:modelValue', 'change', 'update:value']);
|
|
158
|
+
|
|
159
|
+
const cvId = useCvId(props, true);
|
|
160
|
+
const isLight = useIsLight(props);
|
|
161
|
+
const internalValue = ref('');
|
|
162
|
+
const animateClick = ref(false);
|
|
163
|
+
const isDragging = ref(false);
|
|
164
|
+
const dragStartX = ref(0);
|
|
165
|
+
const dragStartValue = ref(0);
|
|
166
|
+
const percentage = ref('0%');
|
|
167
|
+
|
|
168
|
+
const labelId = computed(() => `${cvId.value}-label`);
|
|
169
|
+
|
|
170
|
+
const internalMinLabel = computed(() => props.minLabel ?? getMin());
|
|
171
|
+
|
|
172
|
+
const internalMaxLabel = computed(() => props.maxLabel ?? getMax());
|
|
173
|
+
|
|
174
|
+
const rangePropsObserver = computed(() => ({
|
|
175
|
+
min: props.min,
|
|
176
|
+
max: props.max,
|
|
177
|
+
step: props.step,
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
const internalMultiplier = computed(() => {
|
|
181
|
+
let intMultiplier = parseInt(props.stepMultiplier);
|
|
182
|
+
// default to 4 fro multiplier
|
|
183
|
+
return isNaN(intMultiplier) ? DefaultMultiplier : Math.max(intMultiplier, 1);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const getRangeAttributeValue = (
|
|
187
|
+
attributeName,
|
|
188
|
+
defaultForNaN,
|
|
189
|
+
defaultReturnValue
|
|
190
|
+
) => {
|
|
191
|
+
if (range?.value) {
|
|
192
|
+
const val = parseFloat(range.value[attributeName]);
|
|
193
|
+
return isNaN(val) ? defaultForNaN : val;
|
|
194
|
+
}
|
|
195
|
+
return defaultReturnValue ?? defaultForNaN;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const getMin = () => {
|
|
199
|
+
return getRangeAttributeValue('min', DefaultRangeMin);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const getMax = () => {
|
|
203
|
+
return getRangeAttributeValue('max', DefaultRangeMax);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const getValue = () => {
|
|
207
|
+
const middleValue = (getMax() + getMin()) / 2;
|
|
208
|
+
return getRangeAttributeValue('value', DefaultValue, middleValue);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const getStep = () => {
|
|
212
|
+
return getRangeAttributeValue('step', StepNaNReplacement, StepDefaultValue);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const setValue = newValue => {
|
|
216
|
+
if (props.disabled) return;
|
|
217
|
+
|
|
218
|
+
range.value.value = newValue;
|
|
219
|
+
internalValue.value = range.value.value;
|
|
220
|
+
|
|
221
|
+
percentage.value = `${
|
|
222
|
+
((internalValue.value - getMin()) * 100) / (getMax() - getMin())
|
|
223
|
+
}%`;
|
|
224
|
+
|
|
225
|
+
const { value: rangeValue } = range.value;
|
|
226
|
+
emit('update:modelValue', rangeValue);
|
|
227
|
+
emit('update:value', rangeValue);
|
|
228
|
+
emit('change', rangeValue);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const onChange = () => {
|
|
232
|
+
let newValue = internalValue.value.length
|
|
233
|
+
? parseFloat(internalValue.value)
|
|
234
|
+
: getMin();
|
|
235
|
+
setValue(newValue);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const onStartDrag = ev => {
|
|
239
|
+
document.body.addEventListener('mousemove', onDrag);
|
|
240
|
+
document.body.addEventListener('mouseup', onStopDrag);
|
|
241
|
+
|
|
242
|
+
dragStartX.value = ev.clientX;
|
|
243
|
+
dragStartValue.value = getValue();
|
|
244
|
+
isDragging.value = true;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const onDrag = ev => {
|
|
248
|
+
if (isDragging.value) {
|
|
249
|
+
// percentage change
|
|
250
|
+
let newValue = (ev.clientX - dragStartX.value) / track.value.offsetWidth;
|
|
251
|
+
// uncapped new value
|
|
252
|
+
newValue = dragStartValue.value + (getMax() - getMin()) * newValue;
|
|
253
|
+
setValue(newValue);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const onStopDrag = () => {
|
|
258
|
+
isDragging.value = false;
|
|
259
|
+
document.body.removeEventListener('mousemove', onDrag);
|
|
260
|
+
document.body.removeEventListener('mouseup', onStopDrag);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const onTrackClick = ev => {
|
|
264
|
+
const afterAnimate = ev => {
|
|
265
|
+
if (ev.propertyName === 'left') {
|
|
266
|
+
animateClick.value = false;
|
|
267
|
+
thumb.value.removeEventListener('transitionend', afterAnimate);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
let newValue = ev.offsetX / track.value.offsetWidth;
|
|
272
|
+
const min = getMin();
|
|
273
|
+
newValue = (getMax() - min) * newValue + min;
|
|
274
|
+
thumb.value.addEventListener('transitionend', afterAnimate);
|
|
275
|
+
animateClick.value = true;
|
|
276
|
+
setValue(newValue);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const onUpDown = (ev, isUp = true) => {
|
|
280
|
+
let curValue =
|
|
281
|
+
ev.target.type === 'number' ? parseFloat(ev.target.value) : getValue();
|
|
282
|
+
const step = getStep();
|
|
283
|
+
const progressValue = ev.shiftKey ? internalMultiplier.value * step : step;
|
|
284
|
+
const direction = isUp ? 1 : -1;
|
|
285
|
+
let newValue = curValue + progressValue * direction;
|
|
286
|
+
setValue(newValue);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const onUp = ev => {
|
|
290
|
+
onUpDown(ev);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const onDown = ev => {
|
|
294
|
+
onUpDown(ev, false);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
onMounted(() => {
|
|
298
|
+
range.value.value = props.value ?? props.modelValue;
|
|
299
|
+
internalValue.value = range.value.value;
|
|
300
|
+
percentage.value = `${
|
|
301
|
+
((internalValue.value - getMin()) * 100) / (getMax() - getMin())
|
|
302
|
+
}%`;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
watch(
|
|
306
|
+
() => props.modelValue,
|
|
307
|
+
modelValue => {
|
|
308
|
+
setValue(modelValue);
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
watch(
|
|
313
|
+
() => props.value,
|
|
314
|
+
value => {
|
|
315
|
+
setValue(value);
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
watch(rangePropsObserver, () => {
|
|
320
|
+
nextTick(() => {
|
|
321
|
+
setValue(internalValue.value);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
</script>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sbCompPrefix,
|
|
3
|
+
storyParametersObject,
|
|
4
|
+
} from '../../global/storybook-utils';
|
|
5
|
+
import { sbSliderPrefix } from './sbSliderPrefix';
|
|
6
|
+
import { CvSliderSkeleton } from '.';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: `${sbCompPrefix}/${sbSliderPrefix}/CvSliderSkeleton`,
|
|
10
|
+
component: CvSliderSkeleton,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const template = `<cv-slider-skeleton />`;
|
|
14
|
+
const Template = () => {
|
|
15
|
+
return {
|
|
16
|
+
components: { CvSliderSkeleton },
|
|
17
|
+
template,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Default = Template.bind({});
|
|
22
|
+
Default.parameters = storyParametersObject(
|
|
23
|
+
Default.parameters,
|
|
24
|
+
template,
|
|
25
|
+
Default.args
|
|
26
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="`cv-slider ${carbonPrefix}--form-item`">
|
|
3
|
+
<label :class="`${carbonPrefix}--label ${carbonPrefix}--skeleton`"></label>
|
|
4
|
+
<div :class="`${carbonPrefix}--slider-container ${carbonPrefix}--skeleton`">
|
|
5
|
+
<span :class="`${carbonPrefix}--slider__range-label`"></span>
|
|
6
|
+
<div :class="`${carbonPrefix}--slider`">
|
|
7
|
+
<div :class="`${carbonPrefix}--slider__track`"></div>
|
|
8
|
+
<div :class="`${carbonPrefix}--slider__filled-track`"></div>
|
|
9
|
+
<div :class="`${carbonPrefix}--slider__thumb`"></div>
|
|
10
|
+
</div>
|
|
11
|
+
<span :class="`${carbonPrefix}--slider__range-label`"></span>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
import { carbonPrefix } from '../../global/settings';
|
|
18
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`CvSlider should match snapshot 1`] = `
|
|
4
|
+
<div class="cv-slider bx--form-item"><label for="abc" class="bx--label" id="abc-label" style="display: none;"></label>
|
|
5
|
+
<div class="bx--slider-container"><span class="bx--slider__range-label">0</span>
|
|
6
|
+
<div class="bx--slider" data-slider="" data-slider-input-box="#slider-input-box">
|
|
7
|
+
<div class="bx--slider__track"></div>
|
|
8
|
+
<div class="bx--slider__filled-track" style="width: 0%;"></div>
|
|
9
|
+
<div class="bx--slider__thumb" tabindex="0" aria-labelledby="abc-label" style="left: 0%;"></div><input id="abc" class="bx--slider__input" type="range" step="1" min="0" max="100">
|
|
10
|
+
</div><span class="bx--slider__range-label">100</span><input type="string" class="bx--text-input bx--slider-text-input" placeholder="0">
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`CvSliderSkeleton should match snapshot 1`] = `
|
|
4
|
+
<div class="cv-slider bx--form-item"><label class="bx--label bx--skeleton"></label>
|
|
5
|
+
<div class="bx--slider-container bx--skeleton"><span class="bx--slider__range-label"></span>
|
|
6
|
+
<div class="bx--slider">
|
|
7
|
+
<div class="bx--slider__track"></div>
|
|
8
|
+
<div class="bx--slider__filled-track"></div>
|
|
9
|
+
<div class="bx--slider__thumb"></div>
|
|
10
|
+
</div><span class="bx--slider__range-label"></span>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
`;
|