@carbon/vue 3.0.5-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/README.md +16 -0
- package/dist/carbon-vue-3.common.js +22859 -11008
- package/dist/carbon-vue-3.common.js.map +1 -1
- package/dist/carbon-vue-3.css +1 -0
- package/dist/carbon-vue-3.umd.js +22859 -11008
- package/dist/carbon-vue-3.umd.js.map +1 -1
- package/dist/carbon-vue-3.umd.min.js +30 -2
- package/dist/carbon-vue-3.umd.min.js.map +1 -1
- package/package.json +5 -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-notes.md +86 -0
- package/src/components/CvDatePicker/CvDatePicker.stories.js +241 -0
- package/src/components/CvDatePicker/CvDatePicker.vue +402 -0
- package/src/components/CvDatePicker/CvDatePickerSkeleton.vue +106 -0
- package/src/components/CvDatePicker/index.js +4 -0
- package/src/components/CvDatePicker/plugins/appendToPlugin.js +64 -0
- package/src/components/CvDatePicker/plugins/fixEventsPlugin.js +79 -0
- package/src/components/CvDatePicker/plugins/monthSelectPlugin.js +86 -0
- package/src/components/CvDatePicker/plugins/rangePlugin.js +47 -0
- 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/CvForm.stories.mdx +193 -0
- package/src/components/CvForm/CvForm.vue +9 -0
- package/src/components/CvForm/CvFormGroup.vue +27 -0
- package/src/components/CvForm/CvFormItem.vue +9 -0
- package/src/components/CvForm/index.js +5 -0
- 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 +236 -0
- package/src/components/CvModal/CvModal.vue +401 -0
- package/src/components/CvModal/index.js +3 -0
- 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,265 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import {
|
|
3
|
+
sbCompPrefix,
|
|
4
|
+
storyParametersObject,
|
|
5
|
+
} from '../../global/storybook-utils';
|
|
6
|
+
import { StorybookGroupConst } from './StorybookGroupConst';
|
|
7
|
+
import CvNumberInput from './CvNumberInput.vue';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: `${sbCompPrefix}/${StorybookGroupConst}/CvNumberInput`,
|
|
11
|
+
component: CvNumberInput,
|
|
12
|
+
argTypes: {
|
|
13
|
+
// attrs
|
|
14
|
+
ariaLabelForDownButton: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
table: {
|
|
17
|
+
type: { summary: 'string' },
|
|
18
|
+
category: 'attributes',
|
|
19
|
+
},
|
|
20
|
+
description: 'Aria label for down (decrease) button',
|
|
21
|
+
},
|
|
22
|
+
ariaLabelForUpButton: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
table: {
|
|
25
|
+
type: { summary: 'string' },
|
|
26
|
+
category: 'attributes',
|
|
27
|
+
},
|
|
28
|
+
description: 'Aria label for up (increase) button',
|
|
29
|
+
},
|
|
30
|
+
disabled: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
table: {
|
|
33
|
+
type: { summary: 'boolean' },
|
|
34
|
+
category: 'attributes',
|
|
35
|
+
},
|
|
36
|
+
description: 'Specify whether the `<input>` should be disabled',
|
|
37
|
+
},
|
|
38
|
+
max: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
table: {
|
|
41
|
+
type: { summary: 'string | number' },
|
|
42
|
+
category: 'attributes',
|
|
43
|
+
},
|
|
44
|
+
description: '`max` attribute for input HTML element',
|
|
45
|
+
},
|
|
46
|
+
min: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
table: {
|
|
49
|
+
type: { summary: 'string | number' },
|
|
50
|
+
category: 'attributes',
|
|
51
|
+
},
|
|
52
|
+
description: '`min` attribute for input HTML element',
|
|
53
|
+
},
|
|
54
|
+
step: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
table: {
|
|
57
|
+
type: { summary: 'string | number' },
|
|
58
|
+
category: 'attributes',
|
|
59
|
+
},
|
|
60
|
+
description: '`step` attribute for input HTML element',
|
|
61
|
+
},
|
|
62
|
+
// props
|
|
63
|
+
formItem: {
|
|
64
|
+
type: 'boolean',
|
|
65
|
+
table: {
|
|
66
|
+
type: { summary: 'boolean' },
|
|
67
|
+
category: 'props',
|
|
68
|
+
defaultValue: true,
|
|
69
|
+
},
|
|
70
|
+
description:
|
|
71
|
+
"Adds .bx--form-item class to component's wrapping HTML element",
|
|
72
|
+
},
|
|
73
|
+
helperText: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
table: {
|
|
76
|
+
type: { summary: 'string' },
|
|
77
|
+
category: 'props',
|
|
78
|
+
},
|
|
79
|
+
description:
|
|
80
|
+
'Provide text that is used alongside the control label for additional help',
|
|
81
|
+
},
|
|
82
|
+
invalidMessage: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
table: {
|
|
85
|
+
type: { summary: 'string' },
|
|
86
|
+
category: 'props',
|
|
87
|
+
},
|
|
88
|
+
description:
|
|
89
|
+
'Provide the text that is displayed when the control is in an invalid state',
|
|
90
|
+
},
|
|
91
|
+
label: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
table: {
|
|
94
|
+
type: { summary: 'string' },
|
|
95
|
+
category: 'props',
|
|
96
|
+
},
|
|
97
|
+
description: "Input's label",
|
|
98
|
+
},
|
|
99
|
+
light: {
|
|
100
|
+
type: 'boolean',
|
|
101
|
+
table: {
|
|
102
|
+
type: { summary: 'boolean' },
|
|
103
|
+
category: 'props',
|
|
104
|
+
defaultValue: false,
|
|
105
|
+
},
|
|
106
|
+
description:
|
|
107
|
+
"Toggles light version. For use on `$ui-01` backgrounds only. Don't use this to make tile background color same as container background color.",
|
|
108
|
+
},
|
|
109
|
+
warnText: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
table: {
|
|
112
|
+
type: { summary: 'string' },
|
|
113
|
+
category: 'props',
|
|
114
|
+
},
|
|
115
|
+
description:
|
|
116
|
+
'Provide the text that is displayed when the control is in warning state',
|
|
117
|
+
},
|
|
118
|
+
// slots
|
|
119
|
+
'label ': {
|
|
120
|
+
type: 'string',
|
|
121
|
+
table: {
|
|
122
|
+
type: { summary: 'string | html | Component' },
|
|
123
|
+
category: 'slots',
|
|
124
|
+
},
|
|
125
|
+
description: 'Input label slot',
|
|
126
|
+
},
|
|
127
|
+
'helper-text': {
|
|
128
|
+
type: 'string',
|
|
129
|
+
table: {
|
|
130
|
+
type: { summary: 'string | html | Component' },
|
|
131
|
+
category: 'slots',
|
|
132
|
+
},
|
|
133
|
+
description:
|
|
134
|
+
"Helper text slot. It isn't shown if invalid message or warn text, either props or slots, are available",
|
|
135
|
+
},
|
|
136
|
+
'invalid-message': {
|
|
137
|
+
type: 'string',
|
|
138
|
+
table: {
|
|
139
|
+
type: { summary: 'string | html | Component' },
|
|
140
|
+
category: 'slots',
|
|
141
|
+
},
|
|
142
|
+
description: 'Invalid message slot.',
|
|
143
|
+
},
|
|
144
|
+
'warn-text': {
|
|
145
|
+
type: 'string',
|
|
146
|
+
table: {
|
|
147
|
+
type: { summary: 'string | html | Component' },
|
|
148
|
+
category: 'slots',
|
|
149
|
+
},
|
|
150
|
+
description:
|
|
151
|
+
"Warn text slot. It isn't shown if invalid message, either prop or slot, is available",
|
|
152
|
+
},
|
|
153
|
+
// events
|
|
154
|
+
'update:modelValue': {
|
|
155
|
+
type: 'event',
|
|
156
|
+
table: {
|
|
157
|
+
type: { summary: 'event' },
|
|
158
|
+
category: 'events',
|
|
159
|
+
},
|
|
160
|
+
control: { type: null },
|
|
161
|
+
description:
|
|
162
|
+
"Triggered on textarea update. `update:modelValue` is the vue3 default 'event' for two-way data binding with v-model",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const template = `
|
|
168
|
+
<cv-number-input v-bind="args">
|
|
169
|
+
<template v-if="args['helper-text']" v-slot:helper-text />
|
|
170
|
+
<template v-if="args['warn-text']" v-slot:warn-text />
|
|
171
|
+
<template v-if="args['invalid-message']" v-slot:invalid-message />
|
|
172
|
+
<template v-if="args['label']" v-slot:label />
|
|
173
|
+
</cv-number-input>
|
|
174
|
+
`;
|
|
175
|
+
const Template = (args, { argTypes }) => {
|
|
176
|
+
return {
|
|
177
|
+
props: Object.keys(argTypes),
|
|
178
|
+
components: { CvNumberInput },
|
|
179
|
+
template,
|
|
180
|
+
setup: () => ({
|
|
181
|
+
args,
|
|
182
|
+
}),
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const Default = Template.bind({});
|
|
187
|
+
Default.args = { label: 'Number input label' };
|
|
188
|
+
Default.parameters = storyParametersObject(
|
|
189
|
+
Default.parameters,
|
|
190
|
+
template,
|
|
191
|
+
Default.args
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const vModelHTML = `
|
|
195
|
+
<cv-number-input v-bind="args" v-model="modelValue" />
|
|
196
|
+
<div style="margin-top:1rem; background-color: #888888; padding:1rem">
|
|
197
|
+
<div style="font-size: 150%">
|
|
198
|
+
Sample interaction
|
|
199
|
+
</div>
|
|
200
|
+
<input v-model="modelValue" type="number" />
|
|
201
|
+
<div>
|
|
202
|
+
Entered value:
|
|
203
|
+
<span style="font-weight: bold;">{{modelValue}}</span>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
`;
|
|
207
|
+
|
|
208
|
+
const VModelTemplate = args => {
|
|
209
|
+
return {
|
|
210
|
+
components: { CvNumberInput },
|
|
211
|
+
setup: () => ({ args, modelValue: ref(3) }),
|
|
212
|
+
template: vModelHTML,
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
export const vModel = VModelTemplate.bind({});
|
|
216
|
+
vModel.parameters = storyParametersObject(
|
|
217
|
+
vModel.parameters,
|
|
218
|
+
vModelHTML,
|
|
219
|
+
vModel.args
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const withTypeofMessageHTML = `
|
|
223
|
+
<cv-number-input v-bind="args" v-model="modelValue" />
|
|
224
|
+
<p style="margin-top: 1rem;">Entered value: {{ modelValue }} | typeof: {{ typeof modelValue }}</p>
|
|
225
|
+
`;
|
|
226
|
+
const NumberTemplate = args => {
|
|
227
|
+
return {
|
|
228
|
+
components: { CvNumberInput },
|
|
229
|
+
setup: () => ({ args, modelValue: ref(3) }),
|
|
230
|
+
template: withTypeofMessageHTML,
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
export const NumberValue = NumberTemplate.bind({});
|
|
234
|
+
NumberValue.parameters = storyParametersObject(
|
|
235
|
+
NumberValue.parameters,
|
|
236
|
+
withTypeofMessageHTML,
|
|
237
|
+
NumberValue.args
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
const StringTemplate = args => {
|
|
241
|
+
return {
|
|
242
|
+
components: { CvNumberInput },
|
|
243
|
+
setup: () => ({ args, modelValue: ref('3') }),
|
|
244
|
+
template: withTypeofMessageHTML,
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
export const StringValue = StringTemplate.bind({});
|
|
248
|
+
StringValue.parameters = storyParametersObject(
|
|
249
|
+
StringValue.parameters,
|
|
250
|
+
withTypeofMessageHTML,
|
|
251
|
+
StringValue.args
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
export const Slots = Template.bind({});
|
|
255
|
+
Slots.args = {
|
|
256
|
+
'invalid-message': 'Some invalid message from slot',
|
|
257
|
+
'warn-text': 'Some warn message from slot',
|
|
258
|
+
'helper-text': 'Some help message from slot',
|
|
259
|
+
label: 'Number input label from slot',
|
|
260
|
+
};
|
|
261
|
+
Slots.parameters = storyParametersObject(
|
|
262
|
+
Slots.parameters,
|
|
263
|
+
template,
|
|
264
|
+
Slots.args
|
|
265
|
+
);
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<cv-wrapper
|
|
3
|
+
:tag-type="formItem ? 'div' : ''"
|
|
4
|
+
class="cv-number-input"
|
|
5
|
+
:class="`${carbonPrefix}--form-item`"
|
|
6
|
+
>
|
|
7
|
+
<div
|
|
8
|
+
:class="[
|
|
9
|
+
`${carbonPrefix}--number`,
|
|
10
|
+
{
|
|
11
|
+
[`${carbonPrefix}--number--light`]: isLight,
|
|
12
|
+
[`${carbonPrefix}--number--helpertext`]: isHelper,
|
|
13
|
+
[`cv-number-input`]: !formItem,
|
|
14
|
+
},
|
|
15
|
+
]"
|
|
16
|
+
:data-invalid="dataInvalidAttributeValue"
|
|
17
|
+
>
|
|
18
|
+
<label
|
|
19
|
+
v-show="label || slots['label']"
|
|
20
|
+
:for="cvId"
|
|
21
|
+
:class="`${carbonPrefix}--label`"
|
|
22
|
+
>
|
|
23
|
+
<slot name="label">
|
|
24
|
+
{{ label }}
|
|
25
|
+
</slot>
|
|
26
|
+
</label>
|
|
27
|
+
|
|
28
|
+
<div
|
|
29
|
+
:class="[
|
|
30
|
+
`${carbonPrefix}--number__input-wrapper`,
|
|
31
|
+
{ [`${carbonPrefix}--number__input-wrapper--warning`]: isWarn },
|
|
32
|
+
]"
|
|
33
|
+
>
|
|
34
|
+
<input
|
|
35
|
+
ref="input"
|
|
36
|
+
v-model="internalValue"
|
|
37
|
+
:id="cvId"
|
|
38
|
+
:data-invalid="dataInvalidAttributeValue"
|
|
39
|
+
type="number"
|
|
40
|
+
v-bind="$attrs"
|
|
41
|
+
:disabled="disabled"
|
|
42
|
+
:step="step"
|
|
43
|
+
:min="min"
|
|
44
|
+
:max="max"
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
<WarningFilled16 v-if="isInvalid" :class="iconClasses" />
|
|
48
|
+
|
|
49
|
+
<WarningAltFilled16 v-if="isWarn && !isInvalid" :class="iconClasses" />
|
|
50
|
+
|
|
51
|
+
<div :class="`${carbonPrefix}--number__controls`">
|
|
52
|
+
<button
|
|
53
|
+
:class="`${carbonPrefix}--number__control-btn down-icon`"
|
|
54
|
+
type="button"
|
|
55
|
+
:aria-label="ariaLabelForDownButton"
|
|
56
|
+
:disabled="disabled"
|
|
57
|
+
aria-live="polite"
|
|
58
|
+
aria-atomic="true"
|
|
59
|
+
@click="doDown"
|
|
60
|
+
>
|
|
61
|
+
<Subtract16 class="down-icon" />
|
|
62
|
+
</button>
|
|
63
|
+
|
|
64
|
+
<div :class="`${carbonPrefix}--number__rule-divider`" />
|
|
65
|
+
|
|
66
|
+
<button
|
|
67
|
+
:class="`${carbonPrefix}--number__control-btn up-icon`"
|
|
68
|
+
type="button"
|
|
69
|
+
:aria-label="ariaLabelForUpButton"
|
|
70
|
+
:disabled="disabled"
|
|
71
|
+
aria-live="polite"
|
|
72
|
+
aria-atomic="true"
|
|
73
|
+
@click="doUp"
|
|
74
|
+
>
|
|
75
|
+
<Add16 class="up-icon" />
|
|
76
|
+
</button>
|
|
77
|
+
|
|
78
|
+
<div :class="`${carbonPrefix}--number__rule-divider`" />
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div v-if="isInvalid" :class="`${carbonPrefix}--form-requirement`">
|
|
83
|
+
<slot name="invalid-message">{{ invalidMessage }}</slot>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div v-else-if="isWarn" :class="`${carbonPrefix}--form-requirement`">
|
|
87
|
+
<slot name="warn-text">{{ warnText }}</slot>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<div v-if="isHelper" :class="`${carbonPrefix}--form__helper-text`">
|
|
91
|
+
<slot name="helper-text">{{ helperText }}</slot>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</cv-wrapper>
|
|
95
|
+
</template>
|
|
96
|
+
|
|
97
|
+
<script setup>
|
|
98
|
+
import { computed, ref, useSlots } from 'vue';
|
|
99
|
+
import Add16 from '@carbon/icons-vue/es/add/16';
|
|
100
|
+
import Subtract16 from '@carbon/icons-vue/es/subtract/16';
|
|
101
|
+
import WarningFilled16 from '@carbon/icons-vue/es/warning--filled/16';
|
|
102
|
+
import WarningAltFilled16 from '@carbon/icons-vue/es/warning--alt--filled/16';
|
|
103
|
+
import { useCvId, props as propsCvId } from '../../use/cvId';
|
|
104
|
+
import { props as propsTheme } from '../../use/cvTheme';
|
|
105
|
+
import { useCvInputHelpers } from '../../use/cvInput';
|
|
106
|
+
import { carbonPrefix } from '../../global/settings';
|
|
107
|
+
import CvWrapper from '../CvWrapper/CvWrapper';
|
|
108
|
+
|
|
109
|
+
const props = defineProps({
|
|
110
|
+
disabled: Boolean,
|
|
111
|
+
modelValue: {
|
|
112
|
+
type: [String, Number],
|
|
113
|
+
default: '',
|
|
114
|
+
},
|
|
115
|
+
formItem: {
|
|
116
|
+
type: Boolean,
|
|
117
|
+
default: true,
|
|
118
|
+
},
|
|
119
|
+
helperText: {
|
|
120
|
+
type: String,
|
|
121
|
+
default: undefined,
|
|
122
|
+
},
|
|
123
|
+
invalidMessage: {
|
|
124
|
+
type: String,
|
|
125
|
+
default: undefined,
|
|
126
|
+
},
|
|
127
|
+
label: {
|
|
128
|
+
type: String,
|
|
129
|
+
default: '',
|
|
130
|
+
},
|
|
131
|
+
ariaLabelForUpButton: {
|
|
132
|
+
type: String,
|
|
133
|
+
default: 'Increase number input',
|
|
134
|
+
},
|
|
135
|
+
ariaLabelForDownButton: {
|
|
136
|
+
type: String,
|
|
137
|
+
default: 'Decrease number input',
|
|
138
|
+
},
|
|
139
|
+
min: {
|
|
140
|
+
type: [String, Number],
|
|
141
|
+
default: undefined,
|
|
142
|
+
},
|
|
143
|
+
max: {
|
|
144
|
+
type: [String, Number],
|
|
145
|
+
default: undefined,
|
|
146
|
+
},
|
|
147
|
+
step: {
|
|
148
|
+
type: [String, Number],
|
|
149
|
+
default: undefined,
|
|
150
|
+
},
|
|
151
|
+
warnText: {
|
|
152
|
+
type: String,
|
|
153
|
+
default: undefined,
|
|
154
|
+
},
|
|
155
|
+
...propsCvId,
|
|
156
|
+
...propsTheme,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const emit = defineEmits(['update:modelValue']);
|
|
160
|
+
const cvId = useCvId(props);
|
|
161
|
+
const { isInvalid, isWarn, isHelper, isLight } = useCvInputHelpers(props);
|
|
162
|
+
const dataInvalidAttributeValue = computed(() =>
|
|
163
|
+
isInvalid.value ? true : undefined
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const iconClasses = computed(() => {
|
|
167
|
+
const classes = [];
|
|
168
|
+
if (isInvalid.value || isWarn.value) {
|
|
169
|
+
classes.push(`${carbonPrefix}--number__invalid`);
|
|
170
|
+
}
|
|
171
|
+
if (isWarn.value && !isInvalid.value) {
|
|
172
|
+
classes.push(`${carbonPrefix}--number__invalid--warning`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return classes.join(' ');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const input = ref(null);
|
|
179
|
+
const modelValueType = typeof props.modelValue;
|
|
180
|
+
const valuesToNaN = ['', null, undefined];
|
|
181
|
+
|
|
182
|
+
const formatInputValueType = value => {
|
|
183
|
+
if (modelValueType === 'string') return value.toString();
|
|
184
|
+
// According to Vue2 component if there is no value NaN is emitted
|
|
185
|
+
return valuesToNaN.includes(value) ? NaN : Number(value);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const internalValue = computed({
|
|
189
|
+
get() {
|
|
190
|
+
return props.modelValue;
|
|
191
|
+
},
|
|
192
|
+
set(value) {
|
|
193
|
+
const valueFormatted = formatInputValueType(value);
|
|
194
|
+
onInput(valueFormatted);
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const onInput = value => {
|
|
199
|
+
emit('update:modelValue', value);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const programmaticEventsToTrigger = ['input', 'change'];
|
|
203
|
+
const onProgrammaticValueChanged = inputRef => {
|
|
204
|
+
programmaticEventsToTrigger.forEach(eventName => {
|
|
205
|
+
const event = new Event(eventName);
|
|
206
|
+
inputRef.value.dispatchEvent(event);
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const doUp = () => {
|
|
211
|
+
input.value.stepUp();
|
|
212
|
+
onProgrammaticValueChanged(input);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const doDown = () => {
|
|
216
|
+
input.value.stepDown();
|
|
217
|
+
onProgrammaticValueChanged(input);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const slots = useSlots();
|
|
221
|
+
</script>
|
|
222
|
+
|
|
223
|
+
<script>
|
|
224
|
+
export default {
|
|
225
|
+
inheritAttrs: false,
|
|
226
|
+
};
|
|
227
|
+
</script>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sbCompPrefix,
|
|
3
|
+
storyParametersObject,
|
|
4
|
+
} from '../../global/storybook-utils';
|
|
5
|
+
import { StorybookGroupConst } from './StorybookGroupConst';
|
|
6
|
+
import CvNumberInputSkeleton from './CvNumberInputSkeleton.vue';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: `${sbCompPrefix}/${StorybookGroupConst}/CvNumberInputSkeleton`,
|
|
10
|
+
component: CvNumberInputSkeleton,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const template = `<cv-number-input-skeleton></cv-number-input-skeleton>`;
|
|
14
|
+
const Template = (args, { argTypes }) => {
|
|
15
|
+
return {
|
|
16
|
+
props: Object.keys(argTypes),
|
|
17
|
+
components: { CvNumberInputSkeleton },
|
|
18
|
+
template,
|
|
19
|
+
setup() {
|
|
20
|
+
return { args };
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Default = Template.bind({});
|
|
26
|
+
Default.parameters = storyParametersObject(
|
|
27
|
+
Default.parameters,
|
|
28
|
+
template,
|
|
29
|
+
Default.args
|
|
30
|
+
);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="cv-number-input" :class="`${carbonPrefix}--form-item`">
|
|
3
|
+
<label :class="`${carbonPrefix}--label ${carbonPrefix}--skeleton`" />
|
|
4
|
+
<div :class="`${carbonPrefix}--number ${carbonPrefix}--skeleton`" />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup>
|
|
9
|
+
import { carbonPrefix } from '../../global/settings';
|
|
10
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const StorybookGroupConst = 'CvNumberInput';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`CvNumberInput should match snapshot when all props are default 1`] = `<cv-wrapper-stub tagtype="div" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
4
|
+
|
|
5
|
+
exports[`CvNumberInput should match snapshot when all props are provided 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
6
|
+
|
|
7
|
+
exports[`CvNumberInput should match snapshot when helper-text slot is provided 1`] = `<cv-wrapper-stub tagtype="div" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
8
|
+
|
|
9
|
+
exports[`CvNumberInput should match snapshot when invalid-message slot is provided 1`] = `<cv-wrapper-stub tagtype="div" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
10
|
+
|
|
11
|
+
exports[`CvNumberInput should match snapshot when it is not a formItem 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
12
|
+
|
|
13
|
+
exports[`CvNumberInput should match snapshot when light theme 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
14
|
+
|
|
15
|
+
exports[`CvNumberInput should match snapshot when value is Number 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
16
|
+
|
|
17
|
+
exports[`CvNumberInput should match snapshot when value is String 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
18
|
+
|
|
19
|
+
exports[`CvNumberInput should match snapshot with min, max and step as Strings 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
20
|
+
|
|
21
|
+
exports[`CvNumberInput should match snapshot with optional min, max and step as numbers 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="`cv-tab ${carbonPrefix}--tab-content`"
|
|
4
|
+
:id="uid"
|
|
5
|
+
role="tabpanel"
|
|
6
|
+
:aria-labelledby="`${uid}-link`"
|
|
7
|
+
:aria-hidden="!dataSelected ? 'true' : 'false'"
|
|
8
|
+
:hidden="!dataSelected"
|
|
9
|
+
>
|
|
10
|
+
<slot>
|
|
11
|
+
<!-- Content for tab goes here. -->
|
|
12
|
+
</slot>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
import { carbonPrefix } from '../../global/settings';
|
|
18
|
+
import { useCvId, props as propsCvId } from '../../use/cvId';
|
|
19
|
+
import { inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
20
|
+
|
|
21
|
+
const props = defineProps({
|
|
22
|
+
selected: { type: Boolean, default: false },
|
|
23
|
+
disabled: { type: Boolean, default: false },
|
|
24
|
+
label: { type: String, required: true },
|
|
25
|
+
...propsCvId,
|
|
26
|
+
});
|
|
27
|
+
const uid = useCvId(props, true);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Is this tab selected?
|
|
31
|
+
* @type {Ref<UnwrapRef<string>>}
|
|
32
|
+
*/
|
|
33
|
+
const tabSelected = inject('tab-selected');
|
|
34
|
+
const dataSelected = ref(props.selected);
|
|
35
|
+
onMounted(() => {
|
|
36
|
+
if (props.selected) tabSelected.value = uid.value;
|
|
37
|
+
});
|
|
38
|
+
watch(
|
|
39
|
+
() => props.selected,
|
|
40
|
+
() => {
|
|
41
|
+
if (props.selected) tabSelected.value = uid.value;
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
watch(tabSelected, () => {
|
|
45
|
+
dataSelected.value = tabSelected.value === uid.value;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Is this tab disabled?
|
|
50
|
+
* @type {Ref<UnwrapRef<Set>>}
|
|
51
|
+
*/
|
|
52
|
+
const tabDisabledIds = inject('tab-disabled-ids');
|
|
53
|
+
function updateTabDisabled() {
|
|
54
|
+
if (props.disabled) tabDisabledIds.value?.add(uid.value);
|
|
55
|
+
else tabDisabledIds.value?.delete(uid.value);
|
|
56
|
+
}
|
|
57
|
+
onMounted(updateTabDisabled);
|
|
58
|
+
watch(() => props.disabled, updateTabDisabled);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Keep this tab's data up to date
|
|
62
|
+
* @type {Ref<UnwrapRef<Array<TabData>>>}
|
|
63
|
+
*/
|
|
64
|
+
const tabData = inject('tab-data');
|
|
65
|
+
function updateTabData() {
|
|
66
|
+
const index = tabData.value?.findIndex(tab => tab.uid === uid.value);
|
|
67
|
+
if (index > -1)
|
|
68
|
+
tabData.value.splice(index, 1, { uid: uid.value, label: props.label });
|
|
69
|
+
else tabData.value.push({ uid: uid.value, label: props.label });
|
|
70
|
+
}
|
|
71
|
+
onMounted(updateTabData);
|
|
72
|
+
watch(() => props.label, updateTabData);
|
|
73
|
+
onBeforeUnmount(() => {
|
|
74
|
+
const index = tabData.value?.findIndex(tab => tab.uid === uid.value);
|
|
75
|
+
if (index > -1) tabData.value.splice(index, 1);
|
|
76
|
+
});
|
|
77
|
+
</script>
|