@carbon/vue 3.0.7-alpha.0 → 3.0.8-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 (73) hide show
  1. package/README.md +7 -0
  2. package/dist/carbon-vue-3.common.js +3438 -177
  3. package/dist/carbon-vue-3.common.js.map +1 -1
  4. package/dist/carbon-vue-3.umd.js +3438 -177
  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/CvProgress/CvProgress.stories.mdx +202 -0
  23. package/src/components/CvProgress/CvProgress.vue +78 -0
  24. package/src/components/CvProgress/CvProgressStep.vue +124 -0
  25. package/src/components/CvProgress/index.js +4 -0
  26. package/src/components/CvRadioButton/CvRadioButton.stories.js +166 -0
  27. package/src/components/CvRadioButton/CvRadioButton.vue +57 -0
  28. package/src/components/CvRadioButton/CvRadioGroup.vue +27 -0
  29. package/src/components/CvRadioButton/__tests__/__snapshots__/CvRadioButton.spec.js.snap +27 -0
  30. package/src/components/CvRadioButton/index.js +6 -0
  31. package/src/components/CvSearch/CvSearch.stories.mdx +168 -0
  32. package/src/components/CvSearch/CvSearch.vue +250 -0
  33. package/src/components/CvSearch/index.js +3 -0
  34. package/src/components/CvSelect/CvSelect.vue +27 -6
  35. package/src/components/CvSlider/CvSlider.stories.js +166 -0
  36. package/src/components/CvSlider/CvSlider.vue +324 -0
  37. package/src/components/CvSlider/CvSliderSkeleton.stories.js +26 -0
  38. package/src/components/CvSlider/CvSliderSkeleton.vue +18 -0
  39. package/src/components/CvSlider/__tests__/__snapshots__/CvSlider.spec.js.snap +13 -0
  40. package/src/components/CvSlider/__tests__/__snapshots__/CvSliderSkeleton.spec.js.snap +13 -0
  41. package/src/components/CvSlider/index.js +5 -0
  42. package/src/components/CvSlider/sbSliderPrefix.js +2 -0
  43. package/src/components/CvTextArea/CvTextArea.stories.js +2 -2
  44. package/src/components/CvTextArea/CvTextAreaSkeleton.stories.js +29 -0
  45. package/src/components/CvTextArea/CvTextAreaSkeleton.vue +10 -0
  46. package/src/components/CvTextArea/StorybookGroupConst.js +1 -0
  47. package/src/components/CvTextArea/__tests__/__snapshots__/CvTextAreaSkeleton.spec.js.snap +7 -0
  48. package/src/components/CvTextArea/index.js +2 -1
  49. package/src/components/CvTimePicker/CvTimePicker.stories.mdx +325 -0
  50. package/src/components/CvTimePicker/CvTimePicker.vue +217 -0
  51. package/src/components/CvTimePicker/index.js +21 -0
  52. package/src/components/CvToggle/CvToggle-Skeleton.vue +27 -12
  53. package/src/components/CvToggle/CvToggle.stories.js +20 -3
  54. package/src/components/CvToggle/CvToggle.vue +22 -5
  55. package/src/components/CvToggle/__tests__/__snapshots__/CvToggle.spec.js.snap +3 -3
  56. package/src/components/CvTooltip/CvDefinitionTooltip.stories.js +80 -0
  57. package/src/components/CvTooltip/CvDefinitionTooltip.vue +61 -0
  58. package/src/components/CvTooltip/CvInteractiveTooltip.stories.js +90 -0
  59. package/src/components/CvTooltip/CvInteractiveTooltip.vue +267 -0
  60. package/src/components/CvTooltip/CvTooltip.stories.js +128 -0
  61. package/src/components/CvTooltip/CvTooltip.vue +44 -0
  62. package/src/components/CvTooltip/__tests__/__snapshots__/CvTooltip.spec.js.snap +525 -0
  63. package/src/components/CvTooltip/consts.js +15 -0
  64. package/src/components/CvTooltip/index.js +6 -0
  65. package/src/components/CvTooltip/sbTooltipPrefix.js +2 -0
  66. package/src/components/CvUIShell/CvSideNav.vue +10 -1
  67. package/src/components/CvUIShell/CvUIShell.stories.mdx +116 -50
  68. package/src/index.d.ts +6 -0
  69. package/src/index.js +11 -0
  70. package/src/use/cvCheck.js +3 -0
  71. package/src/use/index.js +2 -0
  72. package/src/use/useMethods.js +18 -0
  73. package/src/use/useRadio.js +25 -0
@@ -1,18 +1,20 @@
1
1
  <template>
2
2
  <div :class="{ [`${carbonPrefix}--form-item`]: formItem }">
3
3
  <input
4
+ :id="cvId"
5
+ ref="input"
4
6
  role="toggle"
5
7
  v-bind="$attrs"
6
8
  :class="[
7
9
  `${carbonPrefix}--toggle-input`,
8
- { 'bx--toggle-input--small': small },
10
+ {
11
+ [`${carbonPrefix}--toggle-input--small`]: small,
12
+ },
9
13
  ]"
10
14
  type="checkbox"
11
- :id="cvId"
12
15
  :checked="isChecked"
13
- @change="onChange"
14
16
  :value="value"
15
- ref="input"
17
+ @change="onChange"
16
18
  />
17
19
  <label
18
20
  :class="`${carbonPrefix}--toggle-input__label`"
@@ -55,9 +57,24 @@ const visibleLabel = computed(() => {
55
57
  });
56
58
 
57
59
  const props = defineProps({
60
+ /**
61
+ * Specify the size of the Toggle. Default is medium. Set to `true` for small.
62
+ */
58
63
  small: Boolean,
59
- label: String,
64
+ /**
65
+ * Label and aria-label for the toggle
66
+ */
67
+ label: {
68
+ type: String,
69
+ default: 'Toggle element',
70
+ },
71
+ /**
72
+ * Set the carbon form-item class
73
+ */
60
74
  formItem: { type: Boolean, default: true },
75
+ /**
76
+ * Visibly hide the toggle label
77
+ */
61
78
  hideLabel: Boolean,
62
79
  ...propsCvId,
63
80
  ...propsCvCheck,
@@ -1,7 +1,7 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`CvToggle CvToggle - should render formItem: default 1`] = `<div class="bx--form-item"><input role="toggle" class="bx--toggle-input" type="checkbox" id="test-1" value="check-1"><label class="bx--toggle-input__label" for="test-1"> <span class="bx--toggle__switch"><svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5"><path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z"></path></svg><span class="bx--toggle__text--off" aria-hidden="true">Off</span><span class="bx--toggle__text--on" aria-hidden="true">On</span></span></label></div>`;
3
+ exports[`CvToggle CvToggle - should render formItem: default 1`] = `<div class="bx--form-item"><input id="test-1" role="toggle" class="bx--toggle-input" type="checkbox" value="check-1"><label class="bx--toggle-input__label" for="test-1">Toggle element <span class="bx--toggle__switch"><svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5"><path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z"></path></svg><span class="bx--toggle__text--off" aria-hidden="true">Off</span><span class="bx--toggle__text--on" aria-hidden="true">On</span></span></label></div>`;
4
4
 
5
- exports[`CvToggle CvToggle - should render when formItem: false && small && hideLabel 1`] = `<div class="" disabled="true"><input role="toggle" disabled="" class="bx--toggle-input bx--toggle-input--small" type="checkbox" id="test-1" value="check-1"><label class="bx--toggle-input__label" for="test-1"> <span class="bx--toggle__switch"><svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5"><path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z"></path></svg><span class="bx--toggle__text--off" aria-hidden="true">Off</span><span class="bx--toggle__text--on" aria-hidden="true">On</span></span></label></div>`;
5
+ exports[`CvToggle CvToggle - should render when formItem: false && small && hideLabel 1`] = `<div class="" disabled="true"><input id="test-1" role="toggle" disabled="" class="bx--toggle-input bx--toggle-input--small" type="checkbox" value="check-1"><label class="bx--toggle-input__label" for="test-1" aria-label="Toggle element"> <span class="bx--toggle__switch"><svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5"><path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z"></path></svg><span class="bx--toggle__text--off" aria-hidden="true">Off</span><span class="bx--toggle__text--on" aria-hidden="true">On</span></span></label></div>`;
6
6
 
7
- exports[`CvToggle CvToggle - should render when formItem: true && disabled 1`] = `<div class="bx--form-item" disabled="true"><input role="toggle" disabled="" class="bx--toggle-input" type="checkbox" id="test-1" value="check-1"><label class="bx--toggle-input__label" for="test-1"> <span class="bx--toggle__switch"><svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5"><path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z"></path></svg><span class="bx--toggle__text--off" aria-hidden="true">Off</span><span class="bx--toggle__text--on" aria-hidden="true">On</span></span></label></div>`;
7
+ exports[`CvToggle CvToggle - should render when formItem: true && disabled 1`] = `<div class="bx--form-item" disabled="true"><input id="test-1" role="toggle" disabled="" class="bx--toggle-input" type="checkbox" value="check-1"><label class="bx--toggle-input__label" for="test-1">Toggle element <span class="bx--toggle__switch"><svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5"><path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z"></path></svg><span class="bx--toggle__text--off" aria-hidden="true">Off</span><span class="bx--toggle__text--on" aria-hidden="true">On</span></span></label></div>`;
@@ -0,0 +1,80 @@
1
+ import CvDefinitionTooltip from './CvDefinitionTooltip.vue';
2
+ import {
3
+ sbCompPrefix,
4
+ storyParametersObject,
5
+ } from '../../global/storybook-utils';
6
+ import { alignments, directions } from './consts';
7
+ import { sbTooltipPrefix } from './sbTooltipPrefix';
8
+
9
+ export default {
10
+ title: `${sbCompPrefix}/${sbTooltipPrefix}/CvDefinitionTooltip`,
11
+ component: CvDefinitionTooltip,
12
+ argTypes: {
13
+ alignment: {
14
+ control: {
15
+ type: 'select',
16
+ },
17
+ options: alignments,
18
+ defaultValue: CvDefinitionTooltip.props.alignment.default,
19
+ },
20
+ direction: {
21
+ control: {
22
+ type: 'select',
23
+ },
24
+ options: directions,
25
+ defaultValue: CvDefinitionTooltip.props.direction.default,
26
+ },
27
+ definition: {
28
+ control: { type: 'text' },
29
+ table: { category: 'props' },
30
+ description: 'Definition of the term',
31
+ },
32
+ term: {
33
+ control: { type: 'text' },
34
+ table: { category: 'props' },
35
+ description: 'Term to be defined',
36
+ },
37
+ 'definition ': {
38
+ table: {
39
+ type: { summary: 'string | html | Component' },
40
+ category: 'slots',
41
+ },
42
+ description: 'Definition of the term slot.',
43
+ },
44
+ 'term ': {
45
+ table: {
46
+ type: { summary: 'string | html | Component' },
47
+ category: 'slots',
48
+ },
49
+ description: 'Term slot',
50
+ },
51
+ },
52
+ };
53
+
54
+ const Term = 'A term needing definition';
55
+ const Definition = 'Brief description of the dotted, underlined term';
56
+
57
+ const template = `<cv-definition-tooltip v-bind="args" />`;
58
+
59
+ const Template = args => {
60
+ return {
61
+ components: { CvDefinitionTooltip },
62
+ template,
63
+ setup() {
64
+ return {
65
+ args,
66
+ };
67
+ },
68
+ };
69
+ };
70
+
71
+ export const Default = Template.bind({});
72
+ Default.args = {
73
+ term: Term,
74
+ definition: Definition,
75
+ };
76
+ Default.parameters = storyParametersObject(
77
+ Default.parameters,
78
+ template,
79
+ Default.args
80
+ );
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <div
3
+ :class="`cv-definition-tooltip ${carbonPrefix}--tooltip--definition ${carbonPrefix}--tooltip--a11y`"
4
+ :id="cvId"
5
+ >
6
+ <button
7
+ :aria-describedby="`${cvId}-label`"
8
+ :class="[
9
+ `${carbonPrefix}--tooltip__trigger`,
10
+ `${carbonPrefix}--tooltip--a11y`,
11
+ `${carbonPrefix}--tooltip__trigger--definition`,
12
+ `${carbonPrefix}--tooltip--${direction}`,
13
+ `${carbonPrefix}--tooltip--align-${alignment}`,
14
+ ]"
15
+ type="button"
16
+ >
17
+ <slot name="term">
18
+ {{ term }}
19
+ </slot>
20
+ </button>
21
+ <div
22
+ :class="`${carbonPrefix}--assistive-text`"
23
+ :id="`${cvId}-label`"
24
+ role="tooltip"
25
+ >
26
+ <slot name="definition">
27
+ {{ definition }}
28
+ </slot>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script setup>
34
+ import { carbonPrefix } from '../../global/settings';
35
+ import { useCvId, props as propsCvId } from '../../use/cvId';
36
+ import { TipAlignments, alignments, TipDirections, directions } from './consts';
37
+
38
+ const props = defineProps({
39
+ alignment: {
40
+ type: String,
41
+ default: TipAlignments.center,
42
+ validator: val => alignments.includes(val),
43
+ },
44
+ direction: {
45
+ type: String,
46
+ default: TipDirections.top,
47
+ validator: val => directions.includes(val),
48
+ },
49
+ definition: {
50
+ type: String,
51
+ default: '',
52
+ },
53
+ term: {
54
+ type: String,
55
+ default: '',
56
+ },
57
+ ...propsCvId,
58
+ });
59
+
60
+ const cvId = useCvId(props);
61
+ </script>
@@ -0,0 +1,90 @@
1
+ import CvInteractiveTooltip from './CvInteractiveTooltip.vue';
2
+ import {
3
+ sbCompPrefix,
4
+ storyParametersObject,
5
+ } from '../../global/storybook-utils';
6
+ import { alignments, directions } from './consts';
7
+ import { sbTooltipPrefix } from './sbTooltipPrefix';
8
+ import Filter16 from '@carbon/icons-vue/es/filter/16';
9
+
10
+ export default {
11
+ title: `${sbCompPrefix}/${sbTooltipPrefix}/CvInteractiveTooltip`,
12
+ component: CvInteractiveTooltip,
13
+ argTypes: {
14
+ alignment: {
15
+ control: {
16
+ type: 'select',
17
+ },
18
+ options: alignments,
19
+ defaultValue: CvInteractiveTooltip.props.alignment.default,
20
+ },
21
+ direction: {
22
+ control: {
23
+ type: 'select',
24
+ },
25
+ options: directions,
26
+ defaultValue: CvInteractiveTooltip.props.direction.default,
27
+ },
28
+ visible: {
29
+ control: {
30
+ type: 'boolean',
31
+ },
32
+ defaultValue: CvInteractiveTooltip.props.visible.default,
33
+ description: 'Initial tooltip visibility state',
34
+ },
35
+ label: {
36
+ table: {
37
+ type: { summary: 'string | html | Component' },
38
+ category: 'slots',
39
+ },
40
+ description: 'Label slot.',
41
+ },
42
+ content: {
43
+ table: {
44
+ type: { summary: 'string | html | Component' },
45
+ category: 'slots',
46
+ },
47
+ description: 'Content slot.',
48
+ },
49
+ trigger: {
50
+ table: {
51
+ type: { summary: 'string | html | Component' },
52
+ category: 'slots',
53
+ },
54
+ description: 'Trigger slot',
55
+ },
56
+ },
57
+ };
58
+ const template = `
59
+ <cv-interactive-tooltip v-bind="args">
60
+ <template #label>
61
+ Tooltip label
62
+ </template>
63
+ <template #trigger>
64
+ <Filter16 class="bx--overflow-menu__icon bx--toolbar-filter-icon" />
65
+ </template>
66
+ <template #content>
67
+ <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, seed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
68
+ <button class="bx--button">Clicky one</button>
69
+ </template>
70
+ </cv-interactive-tooltip>
71
+ `;
72
+
73
+ const Template = args => {
74
+ return {
75
+ components: { CvInteractiveTooltip, Filter16 },
76
+ template,
77
+ setup() {
78
+ return {
79
+ args,
80
+ };
81
+ },
82
+ };
83
+ };
84
+
85
+ export const Default = Template.bind({});
86
+ Default.parameters = storyParametersObject(
87
+ Default.parameters,
88
+ template,
89
+ Default.args
90
+ );
@@ -0,0 +1,267 @@
1
+ <template>
2
+ <div class="cv-interactive-tooltip" ref="root">
3
+ <div :id="`${cvId}-label`" :class="`${carbonPrefix}--tooltip__label`">
4
+ <slot name="label"></slot>
5
+
6
+ <button
7
+ :aria-expanded="dataVisible ? 'true' : 'false'"
8
+ :aria-labelledby="`${cvId}-label`"
9
+ :class="`${carbonPrefix}--tooltip__trigger`"
10
+ :aria-controls="`${cvId}`"
11
+ aria-haspopup="true"
12
+ ref="trigger"
13
+ type="button"
14
+ @click="toggle(dataVisible)"
15
+ @keydown.tab="onTriggerTab"
16
+ @focusout="checkFocusOut"
17
+ >
18
+ <slot name="trigger">
19
+ <Information16 />
20
+ </slot>
21
+ </button>
22
+ </div>
23
+
24
+ <div
25
+ :id="cvId"
26
+ :aria-hidden="!dataVisible"
27
+ :data-floating-menu-direction="direction"
28
+ :class="[
29
+ `${carbonPrefix}--tooltip`,
30
+ {
31
+ [`${carbonPrefix}--tooltip--shown`]: dataVisible,
32
+ [`${carbonPrefix}--tooltip--${direction}`]: direction,
33
+ [`${carbonPrefix}--tooltip--align-${alignment}`]: alignment,
34
+ },
35
+ ]"
36
+ ref="popup"
37
+ role="dialog"
38
+ :aria-describedby="`${cvId}-body`"
39
+ :aria-labelledby="`${cvId}-label`"
40
+ @focusout="checkFocusOut"
41
+ :style="{ left: left + 'px', top: top + 'px' }"
42
+ tabindex="-1"
43
+ @mousedown.prevent="preventFocusOut"
44
+ >
45
+ <div
46
+ class="cv-interactive-tooltip__before-content"
47
+ ref="beforeContent"
48
+ tabindex="0"
49
+ style="position: absolute; left: -9999px; width: 1px; height: 1px"
50
+ @focus="focusBeforeContent"
51
+ />
52
+ <span :class="`${carbonPrefix}--tooltip__caret`"></span>
53
+ <div :class="`${carbonPrefix}--tooltip__content`">
54
+ <slot name="content"></slot>
55
+ </div>
56
+ <div
57
+ class="cv-interactive-tooltip__after-content"
58
+ ref="afterContent"
59
+ tabindex="0"
60
+ style="position: absolute; left: -9999px; width: 1px; height: 1px"
61
+ @focus="focusAfterContent"
62
+ />
63
+ </div>
64
+ </div>
65
+ </template>
66
+
67
+ <script setup>
68
+ import Information16 from '@carbon/icons-vue/es/information/16';
69
+ import {
70
+ ref,
71
+ computed,
72
+ watch,
73
+ onMounted,
74
+ onBeforeUnmount,
75
+ nextTick,
76
+ toRefs,
77
+ } from 'vue';
78
+ import { carbonPrefix } from '../../global/settings';
79
+ import { useCvId, props as propsCvId } from '../../use/cvId';
80
+ import { TipAlignments, alignments, TipDirections, directions } from './consts';
81
+
82
+ const props = defineProps({
83
+ alignment: {
84
+ type: String,
85
+ default: TipAlignments.center,
86
+ validator: val => alignments.includes(val),
87
+ },
88
+ direction: {
89
+ type: String,
90
+ default: TipDirections.top,
91
+ validator: val => directions.includes(val),
92
+ },
93
+ visible: {
94
+ type: Boolean,
95
+ default: false,
96
+ },
97
+ ...propsCvId,
98
+ });
99
+
100
+ const { direction, visible } = toRefs(props);
101
+ const cvId = useCvId(props);
102
+ const dataVisible = ref(false);
103
+ const left = ref(-9999); // position offscreen
104
+ const top = ref(0);
105
+ const root = ref(null);
106
+ let popupEl = ref(null);
107
+ const popup = ref(null);
108
+ const trigger = ref(null);
109
+ const beforeContent = ref(null);
110
+ const afterContent = ref(null);
111
+
112
+ const contentAfter = computed(() => {
113
+ return [TipDirections.right, TipDirections.bottom].includes(direction.value);
114
+ });
115
+
116
+ onMounted(() => {
117
+ // move popup out to body to ensure it appears above other elements
118
+ popupEl = document.body.appendChild(popup.value);
119
+ toggle(!visible.value);
120
+ });
121
+
122
+ watch(visible, newValue => {
123
+ toggle(!newValue);
124
+ });
125
+
126
+ watch(direction, () => {
127
+ if (!visible.value) return;
128
+ position();
129
+ });
130
+
131
+ function positionListen(on) {
132
+ if (on) {
133
+ window.addEventListener('scroll', position);
134
+ window.addEventListener('resize', position);
135
+ return;
136
+ }
137
+ window.removeEventListener('scroll', position);
138
+ window.removeEventListener('resize', position);
139
+ }
140
+
141
+ function position() {
142
+ const menuPosition = trigger.value.getBoundingClientRect();
143
+ const pixelsScrolledX = window.scrollX || window.pageXOffset;
144
+ const pixelsScrolledY = window.scrollY || window.pageYOffset;
145
+ const positioningMethod = [TipDirections.top, TipDirections.bottom].includes(
146
+ direction.value
147
+ )
148
+ ? positionForTopBottomDirections
149
+ : positionForLeftRightDirections;
150
+
151
+ positioningMethod({
152
+ menuPosition,
153
+ pixelsScrolledX,
154
+ pixelsScrolledY,
155
+ });
156
+ }
157
+
158
+ function positionForTopBottomDirections({
159
+ menuPosition,
160
+ pixelsScrolledX,
161
+ pixelsScrolledY,
162
+ }) {
163
+ top.value =
164
+ direction.value === TipDirections.bottom
165
+ ? menuPosition.bottom + 10 + pixelsScrolledY
166
+ : menuPosition.top - 15 - popup.value.offsetHeight + pixelsScrolledY;
167
+
168
+ left.value =
169
+ menuPosition.left +
170
+ 0.5 +
171
+ (trigger.value.offsetWidth - popup.value.offsetWidth) / 2 +
172
+ pixelsScrolledX;
173
+ }
174
+
175
+ function positionForLeftRightDirections({
176
+ menuPosition,
177
+ pixelsScrolledX,
178
+ pixelsScrolledY,
179
+ }) {
180
+ top.value =
181
+ menuPosition.top +
182
+ (trigger.value.offsetHeight - 0.5 - popup.value.offsetHeight) / 2 +
183
+ pixelsScrolledY;
184
+
185
+ left.value =
186
+ direction.value === TipDirections.left
187
+ ? menuPosition.left - 10 - popup.value.offsetWidth + pixelsScrolledX
188
+ : menuPosition.right + 15 + pixelsScrolledX;
189
+ }
190
+
191
+ async function show() {
192
+ dataVisible.value = true;
193
+ positionListen(true);
194
+
195
+ await nextTick(() => {
196
+ position();
197
+ trigger.value.focus();
198
+ });
199
+ }
200
+
201
+ function hide() {
202
+ dataVisible.value = false;
203
+ positionListen(true);
204
+ }
205
+
206
+ function toggle(isVisible) {
207
+ if (isVisible) {
208
+ hide();
209
+ return;
210
+ }
211
+ show();
212
+ }
213
+
214
+ function onTriggerTab(ev) {
215
+ if (!ev.shiftKey) {
216
+ if (contentAfter.value) {
217
+ // move focus before content before tab press
218
+ beforeContent.value.focus();
219
+ }
220
+ return;
221
+ }
222
+
223
+ if (contentAfter.value) return;
224
+ // move focus after content before tab press
225
+ afterContent.value.focus();
226
+ }
227
+
228
+ function checkFocusOut(ev) {
229
+ dataVisible.value =
230
+ ev.relatedTarget === trigger.value ||
231
+ popup.value.contains(ev.relatedTarget);
232
+ }
233
+
234
+ function focusBeforeContent(ev) {
235
+ if (contentAfter.value) {
236
+ if (popup.value.contains(ev.relatedTarget)) {
237
+ trigger.value.focus();
238
+ }
239
+ return;
240
+ }
241
+
242
+ trigger.value.focus();
243
+ dataVisible.value = contentAfter.value;
244
+ }
245
+
246
+ function focusAfterContent(ev) {
247
+ if (!contentAfter.value) {
248
+ if (popup.value.contains(ev.relatedTarget)) {
249
+ trigger.value.focus();
250
+ }
251
+ } else {
252
+ trigger.value.focus();
253
+ dataVisible.value = !contentAfter.value;
254
+ }
255
+ }
256
+
257
+ function preventFocusOut() {
258
+ // This is here to prevent focus being lost if the user clicks on the contents of the interactive tooltip
259
+ }
260
+
261
+ onBeforeUnmount(() => {
262
+ positionListen(false);
263
+ if (!popupEl.value) return;
264
+ // move back to where it came from
265
+ root.value.appendChild(popupEl.value);
266
+ });
267
+ </script>
@@ -0,0 +1,128 @@
1
+ import CvTooltip from './CvTooltip.vue';
2
+ import {
3
+ sbCompPrefix,
4
+ storyParametersObject,
5
+ } from '../../global/storybook-utils';
6
+ import { alignments, directions } from './consts';
7
+ import { sbTooltipPrefix } from './sbTooltipPrefix';
8
+
9
+ export default {
10
+ title: `${sbCompPrefix}/${sbTooltipPrefix}/CvTooltip`,
11
+ component: CvTooltip,
12
+ argTypes: {
13
+ alignment: {
14
+ control: {
15
+ type: 'select',
16
+ },
17
+ options: alignments,
18
+ defaultValue: CvTooltip.props.alignment.default,
19
+ },
20
+ direction: {
21
+ control: {
22
+ type: 'select',
23
+ },
24
+ options: directions,
25
+ defaultValue: CvTooltip.props.direction.default,
26
+ },
27
+ default: {
28
+ table: {
29
+ type: { summary: 'string | html | Component' },
30
+ category: 'slots',
31
+ },
32
+ description: 'Tooltip trigger slot.',
33
+ },
34
+ content: {
35
+ table: {
36
+ type: { summary: 'string | html | Component' },
37
+ category: 'slots',
38
+ },
39
+ description: 'Tooltip text slot',
40
+ },
41
+ },
42
+ };
43
+
44
+ const TipText = 'This is a tooltip';
45
+
46
+ const template = `<cv-tooltip v-bind="args" />`;
47
+
48
+ const Template = args => {
49
+ return {
50
+ components: { CvTooltip },
51
+ template,
52
+ setup() {
53
+ return {
54
+ args,
55
+ };
56
+ },
57
+ };
58
+ };
59
+
60
+ export const Default = Template.bind({});
61
+ Default.args = {
62
+ tip: TipText,
63
+ };
64
+ Default.parameters = storyParametersObject(
65
+ Default.parameters,
66
+ template,
67
+ Default.args
68
+ );
69
+
70
+ const triggerSlotTemplate = `
71
+ <cv-tooltip v-bind="args">
72
+ <svg width="16" height="12" viewBox="0 0 16 12">
73
+ <path d="M8.05 2a2.5 2.5 0 0 1 4.9 0H16v1h-3.05a2.5 2.5 0 0 1-4.9 0H0V2h8.05zm2.45 2a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM3.05 9a2.5 2.5 0 0 1 4.9 0H16v1H7.95a2.5 2.5 0 0 1-4.9 0H0V9h3.05zm2.45 2a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z" />
74
+ </svg>
75
+ </cv-tooltip>
76
+ `;
77
+
78
+ const TriggerSlotTemplate = args => {
79
+ return {
80
+ components: { CvTooltip },
81
+ template: triggerSlotTemplate,
82
+ setup() {
83
+ return {
84
+ args,
85
+ };
86
+ },
87
+ };
88
+ };
89
+
90
+ export const TriggerSlot = TriggerSlotTemplate.bind({});
91
+ TriggerSlot.args = {
92
+ tip: TipText,
93
+ };
94
+ TriggerSlot.parameters = storyParametersObject(
95
+ TriggerSlot.parameters,
96
+ triggerSlotTemplate,
97
+ TriggerSlot.args
98
+ );
99
+
100
+ const contentSlotTemplate = `
101
+ <cv-tooltip v-bind="args">
102
+ <template #content>
103
+ <div>
104
+ <p style="color:green;font-weight:bold;margin-bottom:5px;">Title</p>
105
+ <p>Lorem ipsum dolor</p>
106
+ </div>
107
+ </template>
108
+ </cv-tooltip>
109
+ `;
110
+
111
+ const ContentSlotTemplate = args => {
112
+ return {
113
+ components: { CvTooltip },
114
+ template: contentSlotTemplate,
115
+ setup() {
116
+ return {
117
+ args,
118
+ };
119
+ },
120
+ };
121
+ };
122
+
123
+ export const ContentSlot = ContentSlotTemplate.bind({});
124
+ ContentSlot.parameters = storyParametersObject(
125
+ ContentSlot.parameters,
126
+ contentSlotTemplate,
127
+ ContentSlot.args
128
+ );