@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.
Files changed (64) hide show
  1. package/README.md +16 -0
  2. package/dist/carbon-vue-3.common.js +22859 -11008
  3. package/dist/carbon-vue-3.common.js.map +1 -1
  4. package/dist/carbon-vue-3.css +1 -0
  5. package/dist/carbon-vue-3.umd.js +22859 -11008
  6. package/dist/carbon-vue-3.umd.js.map +1 -1
  7. package/dist/carbon-vue-3.umd.min.js +30 -2
  8. package/dist/carbon-vue-3.umd.min.js.map +1 -1
  9. package/package.json +5 -4
  10. package/src/components/CvAccordion/CvAccordion.stories.js +1 -0
  11. package/src/components/CvButton/CvButton.stories.js +3 -3
  12. package/src/components/CvButton/CvButtonSkeleton.stories.js +79 -0
  13. package/src/components/CvButton/CvButtonSkeleton.vue +19 -0
  14. package/src/components/CvButton/index.js +8 -1
  15. package/src/components/CvDatePicker/CvDatePicker-notes.md +86 -0
  16. package/src/components/CvDatePicker/CvDatePicker.stories.js +241 -0
  17. package/src/components/CvDatePicker/CvDatePicker.vue +402 -0
  18. package/src/components/CvDatePicker/CvDatePickerSkeleton.vue +106 -0
  19. package/src/components/CvDatePicker/index.js +4 -0
  20. package/src/components/CvDatePicker/plugins/appendToPlugin.js +64 -0
  21. package/src/components/CvDatePicker/plugins/fixEventsPlugin.js +79 -0
  22. package/src/components/CvDatePicker/plugins/monthSelectPlugin.js +86 -0
  23. package/src/components/CvDatePicker/plugins/rangePlugin.js +47 -0
  24. package/src/components/CvDropdown/CvDropdown.stories.mdx +407 -0
  25. package/src/components/CvDropdown/CvDropdown.vue +418 -0
  26. package/src/components/CvDropdown/CvDropdownItem.vue +86 -0
  27. package/src/components/CvDropdown/CvDropdownSkeleton.vue +17 -0
  28. package/src/components/CvDropdown/index.js +5 -0
  29. package/src/components/CvForm/CvForm.stories.mdx +193 -0
  30. package/src/components/CvForm/CvForm.vue +9 -0
  31. package/src/components/CvForm/CvFormGroup.vue +27 -0
  32. package/src/components/CvForm/CvFormItem.vue +9 -0
  33. package/src/components/CvForm/index.js +5 -0
  34. package/src/components/CvInlineLoading/CvInlineLoading.stories.mdx +87 -0
  35. package/src/components/CvInlineLoading/CvInlineLoading.vue +144 -0
  36. package/src/components/CvInlineLoading/consts.js +9 -0
  37. package/src/components/CvInlineLoading/index.js +4 -0
  38. package/src/components/CvModal/CvModal.stories.mdx +236 -0
  39. package/src/components/CvModal/CvModal.vue +401 -0
  40. package/src/components/CvModal/index.js +3 -0
  41. package/src/components/CvMultiSelect/CvMultiSelect.stories.mdx +333 -0
  42. package/src/components/CvMultiSelect/CvMultiSelect.vue +705 -0
  43. package/src/components/CvMultiSelect/consts.js +16 -0
  44. package/src/components/CvMultiSelect/index.js +3 -0
  45. package/src/components/CvNumberInput/CvNumberInput.stories.js +265 -0
  46. package/src/components/CvNumberInput/CvNumberInput.vue +227 -0
  47. package/src/components/CvNumberInput/CvNumberInputSkeleton.stories.js +30 -0
  48. package/src/components/CvNumberInput/CvNumberInputSkeleton.vue +10 -0
  49. package/src/components/CvNumberInput/StorybookGroupConst.js +1 -0
  50. package/src/components/CvNumberInput/__tests__/__snapshots__/CvNumberInput.spec.js.snap +21 -0
  51. package/src/components/CvNumberInput/index.js +5 -0
  52. package/src/components/CvTabs/CvTab.vue +77 -0
  53. package/src/components/CvTabs/CvTabs.stories.mdx +175 -0
  54. package/src/components/CvTabs/CvTabs.vue +406 -0
  55. package/src/components/CvTabs/CvTabsSkeleton.vue +24 -0
  56. package/src/components/CvTabs/_SbContainer.vue +22 -0
  57. package/src/components/CvTabs/index.js +5 -0
  58. package/src/components/CvToggle/CvToggle-Skeleton.vue +29 -0
  59. package/src/components/CvToggle/CvToggle.stories.js +232 -0
  60. package/src/components/CvToggle/CvToggle.vue +70 -0
  61. package/src/components/CvToggle/__tests__/__snapshots__/CvToggle.spec.js.snap +7 -0
  62. package/src/components/CvToggle/index.js +4 -0
  63. package/src/global/storybook-utils/story-source-code.js +1 -0
  64. package/src/use/cvInput.js +34 -0
@@ -0,0 +1,3 @@
1
+ import CvMultiSelect from './CvMultiSelect.vue';
2
+
3
+ export { CvMultiSelect };
@@ -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,5 @@
1
+ import CvNumberInput from './CvNumberInput.vue';
2
+ import CvNumberInputSkeleton from './CvNumberInputSkeleton.vue';
3
+
4
+ export { CvNumberInput, CvNumberInputSkeleton };
5
+ export default CvNumberInput;
@@ -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>