@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.
- package/README.md +7 -0
- package/dist/carbon-vue-3.common.js +3438 -177
- package/dist/carbon-vue-3.common.js.map +1 -1
- package/dist/carbon-vue-3.umd.js +3438 -177
- package/dist/carbon-vue-3.umd.js.map +1 -1
- package/dist/carbon-vue-3.umd.min.js +4 -4
- package/dist/carbon-vue-3.umd.min.js.map +1 -1
- package/package.json +7 -4
- package/src/components/CvCheckbox/CvCheckbox.stories.js +18 -7
- package/src/components/CvCheckbox/CvCheckbox.vue +19 -3
- package/src/components/CvCheckbox/CvCheckboxSkeleton.vue +16 -0
- package/src/components/CvCheckbox/__tests__/__snapshots__/CvCheckboxSkeleton.spec.js.snap +3 -0
- package/src/components/CvCheckbox/index.js +2 -1
- package/src/components/CvDropdown/CvDropdown.vue +0 -2
- package/src/components/CvFileUploader/CvFileUploader.stories.mdx +333 -0
- package/src/components/CvFileUploader/CvFileUploader.vue +286 -0
- package/src/components/CvFileUploader/CvFileUploaderItem.vue +92 -0
- package/src/components/CvFileUploader/CvFileUploaderSkeleton.vue +16 -0
- package/src/components/CvFileUploader/const.js +10 -0
- package/src/components/CvFileUploader/index.js +5 -0
- package/src/components/CvMultiSelect/CvMultiSelect.stories.mdx +1 -1
- package/src/components/CvProgress/CvProgress.stories.mdx +202 -0
- package/src/components/CvProgress/CvProgress.vue +78 -0
- package/src/components/CvProgress/CvProgressStep.vue +124 -0
- package/src/components/CvProgress/index.js +4 -0
- package/src/components/CvRadioButton/CvRadioButton.stories.js +166 -0
- package/src/components/CvRadioButton/CvRadioButton.vue +57 -0
- package/src/components/CvRadioButton/CvRadioGroup.vue +27 -0
- package/src/components/CvRadioButton/__tests__/__snapshots__/CvRadioButton.spec.js.snap +27 -0
- package/src/components/CvRadioButton/index.js +6 -0
- package/src/components/CvSearch/CvSearch.stories.mdx +168 -0
- package/src/components/CvSearch/CvSearch.vue +250 -0
- package/src/components/CvSearch/index.js +3 -0
- package/src/components/CvSelect/CvSelect.vue +27 -6
- package/src/components/CvSlider/CvSlider.stories.js +166 -0
- package/src/components/CvSlider/CvSlider.vue +324 -0
- package/src/components/CvSlider/CvSliderSkeleton.stories.js +26 -0
- package/src/components/CvSlider/CvSliderSkeleton.vue +18 -0
- package/src/components/CvSlider/__tests__/__snapshots__/CvSlider.spec.js.snap +13 -0
- package/src/components/CvSlider/__tests__/__snapshots__/CvSliderSkeleton.spec.js.snap +13 -0
- package/src/components/CvSlider/index.js +5 -0
- package/src/components/CvSlider/sbSliderPrefix.js +2 -0
- package/src/components/CvTextArea/CvTextArea.stories.js +2 -2
- package/src/components/CvTextArea/CvTextAreaSkeleton.stories.js +29 -0
- package/src/components/CvTextArea/CvTextAreaSkeleton.vue +10 -0
- package/src/components/CvTextArea/StorybookGroupConst.js +1 -0
- package/src/components/CvTextArea/__tests__/__snapshots__/CvTextAreaSkeleton.spec.js.snap +7 -0
- package/src/components/CvTextArea/index.js +2 -1
- package/src/components/CvTimePicker/CvTimePicker.stories.mdx +325 -0
- package/src/components/CvTimePicker/CvTimePicker.vue +217 -0
- package/src/components/CvTimePicker/index.js +21 -0
- package/src/components/CvToggle/CvToggle-Skeleton.vue +27 -12
- package/src/components/CvToggle/CvToggle.stories.js +20 -3
- package/src/components/CvToggle/CvToggle.vue +22 -5
- package/src/components/CvToggle/__tests__/__snapshots__/CvToggle.spec.js.snap +3 -3
- package/src/components/CvTooltip/CvDefinitionTooltip.stories.js +80 -0
- package/src/components/CvTooltip/CvDefinitionTooltip.vue +61 -0
- package/src/components/CvTooltip/CvInteractiveTooltip.stories.js +90 -0
- package/src/components/CvTooltip/CvInteractiveTooltip.vue +267 -0
- package/src/components/CvTooltip/CvTooltip.stories.js +128 -0
- package/src/components/CvTooltip/CvTooltip.vue +44 -0
- package/src/components/CvTooltip/__tests__/__snapshots__/CvTooltip.spec.js.snap +525 -0
- package/src/components/CvTooltip/consts.js +15 -0
- package/src/components/CvTooltip/index.js +6 -0
- package/src/components/CvTooltip/sbTooltipPrefix.js +2 -0
- package/src/components/CvUIShell/CvSideNav.vue +10 -1
- package/src/components/CvUIShell/CvUIShell.stories.mdx +116 -50
- package/src/index.d.ts +6 -0
- package/src/index.js +11 -0
- package/src/use/cvCheck.js +3 -0
- package/src/use/index.js +2 -0
- package/src/use/useMethods.js +18 -0
- package/src/use/useRadio.js +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
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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"
|
|
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"
|
|
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"
|
|
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
|
+
);
|