@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.
Files changed (91) hide show
  1. package/README.md +7 -0
  2. package/dist/carbon-vue-3.common.js +3850 -217
  3. package/dist/carbon-vue-3.common.js.map +1 -1
  4. package/dist/carbon-vue-3.umd.js +3850 -217
  5. package/dist/carbon-vue-3.umd.js.map +1 -1
  6. package/dist/carbon-vue-3.umd.min.js +4 -4
  7. package/dist/carbon-vue-3.umd.min.js.map +1 -1
  8. package/package.json +7 -4
  9. package/src/components/CvCheckbox/CvCheckbox.stories.js +18 -7
  10. package/src/components/CvCheckbox/CvCheckbox.vue +19 -3
  11. package/src/components/CvCheckbox/CvCheckboxSkeleton.vue +16 -0
  12. package/src/components/CvCheckbox/__tests__/__snapshots__/CvCheckboxSkeleton.spec.js.snap +3 -0
  13. package/src/components/CvCheckbox/index.js +2 -1
  14. package/src/components/CvDropdown/CvDropdown.vue +0 -2
  15. package/src/components/CvFileUploader/CvFileUploader.stories.mdx +333 -0
  16. package/src/components/CvFileUploader/CvFileUploader.vue +286 -0
  17. package/src/components/CvFileUploader/CvFileUploaderItem.vue +92 -0
  18. package/src/components/CvFileUploader/CvFileUploaderSkeleton.vue +16 -0
  19. package/src/components/CvFileUploader/const.js +10 -0
  20. package/src/components/CvFileUploader/index.js +5 -0
  21. package/src/components/CvMultiSelect/CvMultiSelect.stories.mdx +1 -1
  22. package/src/components/CvNotification/CvToastNotification.stories.js +71 -1
  23. package/src/components/CvNotification/CvToastNotification.vue +6 -4
  24. package/src/components/CvOverflowMenu/CvOverflowMenu.stories.mdx +68 -12
  25. package/src/components/CvOverflowMenu/CvOverflowMenu.vue +39 -45
  26. package/src/components/CvOverflowMenu/CvOverflowMenuItem.vue +6 -11
  27. package/src/components/CvOverflowMenu/index.js +2 -1
  28. package/src/components/CvProgress/CvProgress.stories.mdx +202 -0
  29. package/src/components/CvProgress/CvProgress.vue +78 -0
  30. package/src/components/CvProgress/CvProgressStep.vue +124 -0
  31. package/src/components/CvProgress/index.js +4 -0
  32. package/src/components/CvRadioButton/CvRadioButton.stories.js +166 -0
  33. package/src/components/CvRadioButton/CvRadioButton.vue +57 -0
  34. package/src/components/CvRadioButton/CvRadioGroup.vue +27 -0
  35. package/src/components/CvRadioButton/__tests__/__snapshots__/CvRadioButton.spec.js.snap +27 -0
  36. package/src/components/CvRadioButton/index.js +6 -0
  37. package/src/components/CvSearch/CvSearch.stories.mdx +168 -0
  38. package/src/components/CvSearch/CvSearch.vue +250 -0
  39. package/src/components/CvSearch/index.js +3 -0
  40. package/src/components/CvSelect/CvSelect.vue +27 -6
  41. package/src/components/CvSlider/CvSlider.stories.js +166 -0
  42. package/src/components/CvSlider/CvSlider.vue +324 -0
  43. package/src/components/CvSlider/CvSliderSkeleton.stories.js +26 -0
  44. package/src/components/CvSlider/CvSliderSkeleton.vue +18 -0
  45. package/src/components/CvSlider/__tests__/__snapshots__/CvSlider.spec.js.snap +13 -0
  46. package/src/components/CvSlider/__tests__/__snapshots__/CvSliderSkeleton.spec.js.snap +13 -0
  47. package/src/components/CvSlider/index.js +5 -0
  48. package/src/components/CvSlider/sbSliderPrefix.js +2 -0
  49. package/src/components/CvStructuredList/CvStructuredList.stories.js +141 -0
  50. package/src/components/CvStructuredList/CvStructuredList.vue +44 -0
  51. package/src/components/CvStructuredList/CvStructuredListData.vue +19 -0
  52. package/src/components/CvStructuredList/CvStructuredListHeading.vue +11 -0
  53. package/src/components/CvStructuredList/CvStructuredListItem.vue +47 -0
  54. package/src/components/CvStructuredList/CvStructuredListItemSelectable.vue +56 -0
  55. package/src/components/CvStructuredList/CvStructuredListItemStandard.vue +11 -0
  56. package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredList.spec.js.snap +73 -0
  57. package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredListData.spec.js.snap +5 -0
  58. package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredListHeading.spec.js.snap +9 -0
  59. package/src/components/CvStructuredList/__tests__/__snapshots__/CvStructuredListItem.spec.js.snap +7 -0
  60. package/src/components/CvStructuredList/index.js +12 -0
  61. package/src/components/CvTextArea/CvTextArea.stories.js +2 -2
  62. package/src/components/CvTextArea/CvTextAreaSkeleton.stories.js +29 -0
  63. package/src/components/CvTextArea/CvTextAreaSkeleton.vue +10 -0
  64. package/src/components/CvTextArea/StorybookGroupConst.js +1 -0
  65. package/src/components/CvTextArea/__tests__/__snapshots__/CvTextAreaSkeleton.spec.js.snap +7 -0
  66. package/src/components/CvTextArea/index.js +2 -1
  67. package/src/components/CvTimePicker/CvTimePicker.stories.mdx +325 -0
  68. package/src/components/CvTimePicker/CvTimePicker.vue +217 -0
  69. package/src/components/CvTimePicker/index.js +21 -0
  70. package/src/components/CvToggle/CvToggle-Skeleton.vue +27 -12
  71. package/src/components/CvToggle/CvToggle.stories.js +20 -3
  72. package/src/components/CvToggle/CvToggle.vue +22 -5
  73. package/src/components/CvToggle/__tests__/__snapshots__/CvToggle.spec.js.snap +3 -3
  74. package/src/components/CvTooltip/CvDefinitionTooltip.stories.js +80 -0
  75. package/src/components/CvTooltip/CvDefinitionTooltip.vue +61 -0
  76. package/src/components/CvTooltip/CvInteractiveTooltip.stories.js +90 -0
  77. package/src/components/CvTooltip/CvInteractiveTooltip.vue +267 -0
  78. package/src/components/CvTooltip/CvTooltip.stories.js +128 -0
  79. package/src/components/CvTooltip/CvTooltip.vue +44 -0
  80. package/src/components/CvTooltip/__tests__/__snapshots__/CvTooltip.spec.js.snap +525 -0
  81. package/src/components/CvTooltip/consts.js +15 -0
  82. package/src/components/CvTooltip/index.js +6 -0
  83. package/src/components/CvTooltip/sbTooltipPrefix.js +2 -0
  84. package/src/components/CvUIShell/CvSideNav.vue +10 -1
  85. package/src/components/CvUIShell/CvUIShell.stories.mdx +116 -50
  86. package/src/index.d.ts +6 -0
  87. package/src/index.js +11 -0
  88. package/src/use/cvCheck.js +3 -0
  89. package/src/use/index.js +2 -0
  90. package/src/use/useMethods.js +18 -0
  91. package/src/use/useRadio.js +24 -0
@@ -0,0 +1,166 @@
1
+ import { action } from '@storybook/addon-actions';
2
+ import { CvRadioButton, CvRadioGroup } from '.';
3
+ import {
4
+ sbCompPrefix,
5
+ storyParametersObject,
6
+ } from '../../global/storybook-utils';
7
+ import { ref } from 'vue';
8
+
9
+ export default {
10
+ title: `${sbCompPrefix}/CvRadioButton`,
11
+ component: CvRadioButton,
12
+ argTypes: {
13
+ checked: {
14
+ type: 'boolean',
15
+ control: false,
16
+ table: {
17
+ type: { summary: 'boolean' },
18
+ category: 'props',
19
+ },
20
+ },
21
+ label: {
22
+ description: 'radio-button label',
23
+ control: false,
24
+ },
25
+ hideLabel: {
26
+ description:
27
+ 'makes the label visually hidden but still labels the radio input',
28
+ },
29
+ labelLeft: {
30
+ type: 'boolean',
31
+ table: {
32
+ type: { summary: 'boolean' },
33
+ category: 'props',
34
+ },
35
+ description: 'position label on left',
36
+ },
37
+ vertical: {
38
+ type: 'boolean',
39
+ table: {
40
+ type: { summary: 'boolean' },
41
+ category: 'props',
42
+ },
43
+ description:
44
+ 'Property of CvRadioGroup component - stacks inside radio components vertically',
45
+ },
46
+ },
47
+ };
48
+
49
+ const DefaultRadioItems = [
50
+ {
51
+ label: 'radio-1',
52
+ id: 'value-1',
53
+ checked: true,
54
+ },
55
+ {
56
+ label: 'radio-2',
57
+ id: 'value-2',
58
+ disabled: true,
59
+ },
60
+ {
61
+ label: 'radio-3',
62
+ id: 'value-3',
63
+ },
64
+ ];
65
+
66
+ const DefaultStoryParameters = {
67
+ controls: {
68
+ exclude: ['change', 'update:modelValue', 'modelValue'],
69
+ },
70
+ };
71
+
72
+ const defaultTemplate = `
73
+ <cv-radio-group v-bind="args" @change="onChange">
74
+ <cv-radio-button
75
+ v-for="({id, label, checked, disabled}, index) in DefaultRadioItems"
76
+ :key="index"
77
+ name="group-1"
78
+ :label="label"
79
+ :value="id"
80
+ :checked="checked"
81
+ :disabled="disabled"
82
+ :hide-label="hideLabel"
83
+ :label-left='labelLeft'
84
+ />
85
+ </cv-radio-group>
86
+ `;
87
+
88
+ const Template = (args, { argTypes }) => {
89
+ return {
90
+ props: Object.keys(argTypes),
91
+ components: { CvRadioButton, CvRadioGroup },
92
+ template: defaultTemplate,
93
+ setup() {
94
+ return {
95
+ args,
96
+ hideLabel: args.hideLabel,
97
+ labelLeft: args.labelLeft,
98
+ onChange: action('change'),
99
+ DefaultRadioItems,
100
+ };
101
+ },
102
+ };
103
+ };
104
+
105
+ export const Default = Template.bind({});
106
+ Default.args = {
107
+ vertical: false,
108
+ };
109
+ Default.parameters = storyParametersObject(
110
+ DefaultStoryParameters,
111
+ defaultTemplate,
112
+ Default.args
113
+ );
114
+
115
+ const vModelTemplate = `
116
+ <cv-radio-group v-bind="args" @change="onChange">
117
+ <cv-radio-button
118
+ v-for="({id, label, checked, disabled}, index) in DefaultRadioItems"
119
+ v-model="modelValue"
120
+ :key="index"
121
+ name="group-1"
122
+ :label="label"
123
+ :value="id"
124
+ :disabled="disabled"
125
+ :hide-label="hideLabel"
126
+ :label-left='labelLeft'
127
+ />
128
+ </cv-radio-group>
129
+
130
+ <div style="margin-top:1rem; background-color: #888888; padding:1rem">
131
+ V-model:
132
+ <template
133
+ v-for="({id, label}, index) in DefaultRadioItems"
134
+ :key="index"
135
+ >
136
+ <input name="modelValue" :id="id" type="radio" @change="(ev) => {modelValue = ev.target.id}" :checked="id === modelValue" />
137
+ <label :for="id" style="margin-right: 16px;">{{label}}:</label>
138
+ </template>
139
+
140
+ <div style="margin-top: 16px;">Checked: <span style="font-weight: bold;">{{modelValue}}</span></div>
141
+ </div>
142
+ `;
143
+
144
+ const VModelTemplate = args => {
145
+ return {
146
+ components: { CvRadioButton, CvRadioGroup },
147
+ template: vModelTemplate,
148
+ setup() {
149
+ return {
150
+ args,
151
+ hideLabel: args.hideLabel,
152
+ labelLeft: args.labelLeft,
153
+ modelValue: ref(DefaultRadioItems[0].id),
154
+ onChange: action('change'),
155
+ DefaultRadioItems,
156
+ };
157
+ },
158
+ };
159
+ };
160
+
161
+ export const VModel = VModelTemplate.bind({});
162
+ VModel.parameters = storyParametersObject(
163
+ DefaultStoryParameters,
164
+ vModelTemplate,
165
+ VModel.args
166
+ );
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ `cv-radio-button ${carbonPrefix}--radio-button-wrapper`,
5
+ { [`${carbonPrefix}--radio-button-wrapper--label-left`]: labelLeft },
6
+ ]"
7
+ >
8
+ <input
9
+ v-bind="$attrs"
10
+ :id="cvId"
11
+ :checked="isChecked"
12
+ :class="`${carbonPrefix}--radio-button`"
13
+ ref="input"
14
+ type="radio"
15
+ :value="value"
16
+ @change="onChange"
17
+ />
18
+ <!-- symbol causes problem in codepen? -->
19
+ <label :for="cvId" :class="`${carbonPrefix}--radio-button__label`">
20
+ <span :class="`${carbonPrefix}--radio-button__appearance`"></span>
21
+ <span
22
+ v-if="label"
23
+ :class="{ [`${carbonPrefix}--visually-hidden`]: hideLabel }"
24
+ >
25
+ {{ label }}
26
+ </span>
27
+ </label>
28
+ </div>
29
+ </template>
30
+
31
+ <script setup>
32
+ import { carbonPrefix } from '../../global/settings';
33
+ import { useCvId, propsCvId, useMethods, useRadio } from '../../use';
34
+
35
+ const props = defineProps({
36
+ modelValue: String,
37
+ checked: Boolean,
38
+ label: String,
39
+ value: { type: String, required: true },
40
+ hideLabel: Boolean,
41
+ labelLeft: Boolean,
42
+ ...propsCvId,
43
+ });
44
+
45
+ const cvId = useCvId(props);
46
+
47
+ const emit = defineEmits(['update:modelValue', 'change']);
48
+
49
+ useMethods({ input: ['blur', 'focus'] });
50
+ const { isChecked, onChange } = useRadio(props, emit);
51
+ </script>
52
+
53
+ <script>
54
+ export default {
55
+ inheritAttrs: false,
56
+ };
57
+ </script>
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <div :class="`cv-radio-group ${carbonPrefix}--form-item`">
3
+ <div
4
+ :class="[
5
+ `${carbonPrefix}--radio-button-group`,
6
+ { [`${carbonPrefix}--radio-button-group--vertical`]: vertical },
7
+ ]"
8
+ >
9
+ <slot></slot>
10
+ </div>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup>
15
+ import { provide } from 'vue';
16
+ import { carbonPrefix } from '../../global/settings';
17
+
18
+ defineProps({
19
+ vertical: Boolean,
20
+ });
21
+
22
+ const emit = defineEmits(['change']);
23
+
24
+ provide('onRadioItemChange', clickedItemCvId => {
25
+ emit('change', clickedItemCvId);
26
+ });
27
+ </script>
@@ -0,0 +1,27 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`CvRadioButton matches render when checked 1`] = `<div class="cv-radio-button bx--radio-button-wrapper"><input id="1" class="bx--radio-button" type="radio" value=""><!-- symbol causes problem in codepen? --><label for="1" class="bx--radio-button__label"><span class="bx--radio-button__appearance"></span><span class="">test label</span></label></div>`;
4
+
5
+ exports[`CvRadioButton matches render when modelValue is equal to value 1`] = `<div class="cv-radio-button bx--radio-button-wrapper"><input id="1" class="bx--radio-button" type="radio" value="test value"><!-- symbol causes problem in codepen? --><label for="1" class="bx--radio-button__label"><span class="bx--radio-button__appearance"></span><span class="">test label</span></label></div>`;
6
+
7
+ exports[`CvRadioButton matches render when modelValue is not equal to value 1`] = `<div class="cv-radio-button bx--radio-button-wrapper"><input id="1" class="bx--radio-button" type="radio" value="test value"><!-- symbol causes problem in codepen? --><label for="1" class="bx--radio-button__label"><span class="bx--radio-button__appearance"></span><span class="">test label</span></label></div>`;
8
+
9
+ exports[`CvRadioButton matches render with left label 1`] = `<div class="cv-radio-button bx--radio-button-wrapper bx--radio-button-wrapper--label-left"><input id="1" class="bx--radio-button" type="radio" value=""><!-- symbol causes problem in codepen? --><label for="1" class="bx--radio-button__label"><span class="bx--radio-button__appearance"></span><span class="">left label</span></label></div>`;
10
+
11
+ exports[`CvRadioButton matches render with right label 1`] = `<div class="cv-radio-button bx--radio-button-wrapper"><input id="1" class="bx--radio-button" type="radio" value=""><!-- symbol causes problem in codepen? --><label for="1" class="bx--radio-button__label"><span class="bx--radio-button__appearance"></span><span class="">right label</span></label></div>`;
12
+
13
+ exports[`CvRadioGroup matches render when horizontal 1`] = `
14
+ <div class="cv-radio-group bx--form-item">
15
+ <div class="bx--radio-button-group">
16
+ <div class="cv-radio-button-stub">RadioButtonStub</div>
17
+ </div>
18
+ </div>
19
+ `;
20
+
21
+ exports[`CvRadioGroup matches render when vertical 1`] = `
22
+ <div class="cv-radio-group bx--form-item">
23
+ <div class="bx--radio-button-group bx--radio-button-group--vertical">
24
+ <div class="cv-radio-button-stub">RadioButtonStub</div>
25
+ </div>
26
+ </div>
27
+ `;
@@ -0,0 +1,6 @@
1
+ import CvRadioButton from './CvRadioButton.vue';
2
+ import CvRadioGroup from './CvRadioGroup.vue';
3
+
4
+ export { CvRadioButton, CvRadioGroup };
5
+
6
+ export default CvRadioButton;
@@ -0,0 +1,168 @@
1
+ import { Canvas, Meta, Story } from '@storybook/addon-docs';
2
+ import CvSearch from './CvSearch.vue';
3
+ import { sbCompPrefix } from '../../global/storybook-utils';
4
+ import { SEARCH_SIZES } from './index';
5
+ import { action } from '@storybook/addon-actions';
6
+ import { ref } from 'vue';
7
+ const myValue = ref('searching galaxies');
8
+
9
+ <Meta title={`${sbCompPrefix}/CvSearch`} component={CvSearch} />
10
+
11
+ export const Template = args => ({
12
+ // Components used in your story `template` are defined in the `components` object
13
+ components: {
14
+ CvSearch,
15
+ },
16
+ // The story's `args` need to be mapped into the template through the `setup()` method
17
+ setup() {
18
+ return {
19
+ light: args.light,
20
+ label: args.label,
21
+ placeholder: args.placeholder,
22
+ disabled: args.disabled,
23
+ size: args.size,
24
+ ariaLabel: args.ariaLabel,
25
+ clearAriaLabel: args.clearAriaLabel,
26
+ formItem: args.formItem,
27
+ expandable: args.expandable,
28
+ value: args.value,
29
+ myValue: myValue,
30
+ onInput: action('input'),
31
+ };
32
+ },
33
+ template: args.template,
34
+ });
35
+ const defaultTemplate = `
36
+ <cv-search
37
+ :light="light"
38
+ :label="label"
39
+ :placeholder="placeholder"
40
+ :disabled="disabled"
41
+ :size="size"
42
+ :expandable="expandable"
43
+ :value="value"
44
+ :form-item="formItem"
45
+ :aria-label="ariaLabel"
46
+ :clear-aria-label="clearAriaLabel"
47
+ @input="onInput"
48
+ >
49
+ </cv-search>
50
+ `;
51
+ const vModelTemplate = `
52
+ <div>
53
+ <cv-search
54
+ v-model:value="myValue"
55
+ :light="light"
56
+ :label="label"
57
+ :placeholder="placeholder"
58
+ :disabled="disabled"
59
+ :size="size"
60
+ :expandable="expandable"
61
+ :form-item="formItem"
62
+ :aria-label="ariaLabel"
63
+ :clear-aria-label="clearAriaLabel"
64
+ >
65
+ </cv-search>
66
+ <div style="margin-top:1rem; background-color: #888888; padding:1rem">
67
+ <div style="padding:1rem">v-model value: {{ myValue }}</div>
68
+ <input type="search" v-model="myValue"/>
69
+ </div>
70
+ </div>
71
+ `;
72
+
73
+ # CvSearch
74
+
75
+ Migration notes:
76
+
77
+ - The `v-model` is different in Vue 3 than Vue 2. If you specify it you will see an error deprecation message in the log.
78
+ Please use `v-model:value=something` instead.
79
+ - The "toolbar" mode is removed in this version. Please use the `expandable` mode instead.
80
+
81
+ <Canvas>
82
+ <Story
83
+ name="Default"
84
+ parameters={{
85
+ controls: {
86
+ exclude: [
87
+ 'input',
88
+ 'modelValue',
89
+ 'template',
90
+ 'update:modelValue',
91
+ 'update:value',
92
+ 'large',
93
+ 'small',
94
+ 'toolbarAriaLabel',
95
+ 'kind',
96
+ ],
97
+ },
98
+ docs: { source: { code: defaultTemplate } },
99
+ }}
100
+ args={{
101
+ template: defaultTemplate,
102
+ light: false,
103
+ disabled: false,
104
+ placeholder: 'JWST: search for light from the first stars',
105
+ }}
106
+ argTypes={{
107
+ light: {
108
+ description: '`true` to use the light version.',
109
+ table: { category: 'props', defaultValue: { summary: false } },
110
+ },
111
+ size: {
112
+ control: 'select',
113
+ default: 'xl',
114
+ options: SEARCH_SIZES,
115
+ table: { defaultValue: { summary: 'xl' } },
116
+ },
117
+ }}
118
+ >
119
+ {Template.bind({})}
120
+ </Story>
121
+ </Canvas>
122
+
123
+ # v-model
124
+
125
+ - The `v-model` is different in Vue 3 than Vue 2.If you specify it you will see an error deprecation message in the log.
126
+ Please use `v-model:value=something` instead.
127
+
128
+ <Canvas>
129
+ <Story
130
+ name="v-model"
131
+ parameters={{
132
+ controls: {
133
+ exclude: [
134
+ 'input',
135
+ 'modelValue',
136
+ 'template',
137
+ 'update:modelValue',
138
+ 'update:value',
139
+ 'large',
140
+ 'small',
141
+ 'toolbarAriaLabel',
142
+ 'kind',
143
+ ],
144
+ },
145
+ docs: { source: { code: vModelTemplate } },
146
+ }}
147
+ args={{
148
+ template: vModelTemplate,
149
+ light: false,
150
+ disabled: false,
151
+ placeholder: 'JWST: search for light from the first stars',
152
+ }}
153
+ argTypes={{
154
+ light: {
155
+ description: '`true` to use the light version.',
156
+ table: { category: 'props', defaultValue: { summary: false } },
157
+ },
158
+ size: {
159
+ control: 'select',
160
+ default: 'xl',
161
+ options: SEARCH_SIZES,
162
+ table: { defaultValue: { summary: 'xl' } },
163
+ },
164
+ }}
165
+ >
166
+ {Template.bind({})}
167
+ </Story>
168
+ </Canvas>
@@ -0,0 +1,250 @@
1
+ <template>
2
+ <component
3
+ :is="formItem ? 'div' : CvEmpty"
4
+ :class="`cv-search ${carbonPrefix}--form-item`"
5
+ >
6
+ <div
7
+ :aria-label="internalAriaLabel"
8
+ :aria-labelledby="internalAriaLabelBy"
9
+ :class="[
10
+ `${carbonPrefix}--search`,
11
+ `${carbonPrefix}--search--${size}`,
12
+ {
13
+ [`${carbonPrefix}--search--expandable`]: expandable,
14
+ [`${carbonPrefix}--search--expanded`]: isExpanded,
15
+ [`${carbonPrefix}--search--disabled`]: disabled,
16
+ [`${carbonPrefix}--search--light`]: isLight,
17
+ 'cv-search': !formItem,
18
+ },
19
+ ]"
20
+ role="search"
21
+ ref="elSearch"
22
+ >
23
+ <div
24
+ :class="`${carbonPrefix}--search-magnifier`"
25
+ @click="toggleActive(true)"
26
+ @blur="checkFocus"
27
+ >
28
+ <search-icon :class="`${carbonPrefix}--search-magnifier-icon`" />
29
+ </div>
30
+
31
+ <label v-show="label" :for="uid" :class="`${carbonPrefix}--label`">{{
32
+ label
33
+ }}</label>
34
+
35
+ <input
36
+ role="searchbox"
37
+ :id="uid"
38
+ :class="`${carbonPrefix}--search-input`"
39
+ v-bind="$attrs"
40
+ v-model="internalSearchText"
41
+ @input="onInput"
42
+ type="text"
43
+ ref="elInput"
44
+ :placeholder="placeholder"
45
+ :aria-labelledby="uid"
46
+ @blur="checkFocus"
47
+ @click="toggleActive"
48
+ @keydown.esc="onClearClick"
49
+ :disabled="disabled ? 'true' : undefined"
50
+ />
51
+
52
+ <button
53
+ type="button"
54
+ :class="[
55
+ `${carbonPrefix}--search-close`,
56
+ { [`${carbonPrefix}--search-close--hidden`]: !clearVisible },
57
+ ]"
58
+ :title="clearAriaLabel"
59
+ :aria-label="clearAriaLabel"
60
+ @click="onClearClick"
61
+ >
62
+ <close-icon />
63
+ </button>
64
+ </div>
65
+ </component>
66
+ </template>
67
+
68
+ <script setup>
69
+ import { carbonPrefix } from '../../global/settings';
70
+ import { useIsLight, props as propsTheme } from '../../use/cvTheme';
71
+ import { useCvId, props as propsCvId } from '../../use/cvId';
72
+ import SearchIcon from '@carbon/icons-vue/es/search/16';
73
+ import CloseIcon from '@carbon/icons-vue/es/close/16';
74
+ import { computed, ref, watch } from 'vue';
75
+ import { SEARCH_SIZES } from '.';
76
+ import CvEmpty from '../CvEmpty/_CvEmpty.vue';
77
+
78
+ defineOptions({
79
+ inheritAttrs: false,
80
+ });
81
+
82
+ const props = defineProps({
83
+ ariaLabel: { type: String, default: 'search input' },
84
+ /**
85
+ * Specify a label to be read by screen readers on the "close" button
86
+ */
87
+ clearAriaLabel: { type: String, default: 'Clear search input' },
88
+ /**
89
+ * Specify whether the `<input>` should be disabled
90
+ */
91
+ disabled: { type: Boolean, default: false },
92
+ /**
93
+ * Do no show full control until it has focus. Similar to deprecated toolbar search.
94
+ */
95
+ expandable: { type: Boolean, default: false },
96
+ /**
97
+ * Wrap search in `<div>` if part of a form
98
+ */
99
+ formItem: { type: Boolean, default: true },
100
+ /**
101
+ * @deprecated use expandable
102
+ */
103
+ kind: {
104
+ type: String,
105
+ default: undefined,
106
+ validator: () => {
107
+ console.warn('Deprecated: probably you want expandable=true');
108
+ return true;
109
+ },
110
+ },
111
+ /**
112
+ * Provide the label text for the Search icon
113
+ */
114
+ label: String,
115
+ /**
116
+ * Specify the search size ('sm', 'md', 'lg', 'xl')
117
+ */
118
+ size: {
119
+ type: String,
120
+ default: 'xl',
121
+ validator: val => SEARCH_SIZES.includes(val),
122
+ },
123
+ /**
124
+ * @deprecated use size
125
+ */
126
+ small: {
127
+ type: Boolean,
128
+ default: undefined,
129
+ validator: val => {
130
+ if (val !== undefined) {
131
+ console.error('Error: Use size property: sm, lg or xl (default)');
132
+ return false;
133
+ }
134
+ return true;
135
+ },
136
+ },
137
+ /**
138
+ * @deprecated use size
139
+ */
140
+ large: {
141
+ type: Boolean,
142
+ default: undefined,
143
+ validator: val => {
144
+ if (val !== undefined) {
145
+ console.error('Error: Use size property: sm, lg or xl (default)');
146
+ return false;
147
+ }
148
+ return true;
149
+ },
150
+ },
151
+ /**
152
+ * Optionally provide the default value of the `<input>`
153
+ */
154
+ value: String,
155
+ /**
156
+ * @deprecated use value
157
+ */
158
+ modelValue: {
159
+ type: String,
160
+ default: undefined,
161
+ validator: () => {
162
+ console.warn('Deprecated: use v-model:value instead');
163
+ return true;
164
+ },
165
+ },
166
+ /**
167
+ * Provide an optional placeholder text for the Search. Note: if the label and placeholder differ, VoiceOver on Mac will read both
168
+ */
169
+ placeholder: { type: String, default: 'Search' },
170
+ /**
171
+ * @deprecated
172
+ */
173
+ toolbarAriaLabel: {
174
+ type: String,
175
+ validator: () => {
176
+ console.warn('Deprecated: probably you want expandable=true');
177
+ return true;
178
+ },
179
+ },
180
+ ...propsTheme,
181
+ ...propsCvId,
182
+ });
183
+ const uid = useCvId(props, true);
184
+ const isLight = useIsLight(props);
185
+
186
+ const clearVisible = ref(props.value ? props.value.length : false);
187
+ const internalSearchText = ref(props.value || props.modelValue);
188
+ const searchActive = ref(false);
189
+ watch(
190
+ () => props.value,
191
+ () => {
192
+ clearVisible.value = props.value ? props.value.length : false;
193
+ internalSearchText.value = props.value;
194
+ }
195
+ );
196
+
197
+ const internalAriaLabel = computed(() => {
198
+ if (!props.label) return props.ariaLabel;
199
+ else return undefined;
200
+ });
201
+ const internalAriaLabelBy = computed(() => {
202
+ if (props.label) return uid.value;
203
+ else return undefined;
204
+ });
205
+
206
+ const emit = defineEmits(['input', 'update:value', 'update:modelValue']);
207
+ watch(internalSearchText, () => {
208
+ emit('input', internalSearchText.value);
209
+ emit('update:value', internalSearchText.value);
210
+ if (props.modelValue) {
211
+ console.warn('Deprecated: use v-model:value instead');
212
+ emit('update:modelValue', internalSearchText.value);
213
+ }
214
+ });
215
+ function onClearClick() {
216
+ internalSearchText.value = '';
217
+ clearVisible.value = false;
218
+ if (props.expandable) {
219
+ elInput.value?.focus();
220
+ }
221
+ checkFocus();
222
+ }
223
+ function onInput() {
224
+ clearVisible.value = internalSearchText.value.length > 0;
225
+ }
226
+ const elInput = ref(null);
227
+ const isExpanded = computed(() => {
228
+ return props.expandable && searchActive.value;
229
+ });
230
+ function toggleActive(force) {
231
+ if (props.disabled) return;
232
+
233
+ if (typeof force === 'boolean') searchActive.value = force;
234
+ else if (internalSearchText.value?.length > 0) searchActive.value = true;
235
+ else searchActive.value = !searchActive.value;
236
+
237
+ if (searchActive.value) {
238
+ elInput.value?.focus();
239
+ }
240
+ }
241
+ const elSearch = ref(null);
242
+ function checkFocus() {
243
+ if (props.disabled) return;
244
+
245
+ if (props.expandable) {
246
+ if (elInput.value !== document.activeElement)
247
+ searchActive.value = internalSearchText.value?.length > 0;
248
+ }
249
+ }
250
+ </script>