Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-12-01 18:13:55 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-01 18:13:55 +0300
commit66629d156e2420269ed53eff3dca0912cfe848e2 (patch)
tree64491b1d9bbb19ea8a8e336b92484ca70d94d84d /app/assets/javascripts/vue_shared/components/tooltip_on_truncate
parentc9439a09c51acff525f2e5c5cba8caecc270da8b (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/tooltip_on_truncate')
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js88
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue85
2 files changed, 173 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js
new file mode 100644
index 00000000000..f27901a30a9
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js
@@ -0,0 +1,88 @@
+/* eslint-disable @gitlab/require-i18n-strings */
+import TooltipOnTruncate from './tooltip_on_truncate.vue';
+
+const defaultWidth = '250px';
+
+export default {
+ component: TooltipOnTruncate,
+ title: 'vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue',
+};
+
+const createStory = ({ ...options }) => {
+ return (_, { argTypes }) => {
+ const comp = {
+ components: { TooltipOnTruncate },
+ props: Object.keys(argTypes),
+ template: `
+ <div class="gl-bg-blue-50" :style="{ width }">
+ <tooltip-on-truncate :title="title" :placement="placement" class="gl-display-block gl-text-truncate">
+ {{title}}
+ </tooltip-on-truncate>
+ </div>
+ `,
+ ...options,
+ };
+
+ return comp;
+ };
+};
+
+export const Default = createStory();
+Default.args = {
+ width: defaultWidth,
+ title: 'Hover on this text to see the content in a tooltip.',
+};
+
+export const NoOverflow = createStory();
+NoOverflow.args = {
+ width: defaultWidth,
+ title: "Short text doesn't need a tooltip.",
+};
+
+export const Placement = createStory();
+Placement.args = {
+ width: defaultWidth,
+ title: 'Use `placement="right"` to display this tooltip at the right.',
+ placement: 'right',
+};
+
+const TIMEOUT_S = 3;
+
+export const LiveUpdates = createStory({
+ props: ['width', 'placement'],
+ data() {
+ return {
+ title: `(loading in ${TIMEOUT_S}s)`,
+ };
+ },
+ mounted() {
+ setTimeout(() => {
+ this.title = 'Content updated! The content is now overflowing so we use a tooltip!';
+ }, TIMEOUT_S * 1000);
+ },
+});
+LiveUpdates.args = {
+ width: defaultWidth,
+};
+LiveUpdates.argTypes = {
+ title: {
+ control: false,
+ },
+};
+
+export const TruncateTarget = createStory({
+ template: `
+ <div class="gl-bg-black" :style="{ width }">
+ <tooltip-on-truncate class="gl-display-flex" :truncate-target="truncateTarget" :title="title">
+ <div class="gl-m-5 gl-bg-blue-50 gl-text-truncate">
+ {{ title }}
+ </div>
+ </tooltip-on-truncate>
+ </div>
+ `,
+});
+TruncateTarget.args = {
+ width: defaultWidth,
+ truncateTarget: 'child',
+ title: 'Wrap in container and use `truncate-target="child"` prop.',
+};
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue
new file mode 100644
index 00000000000..09414e679bb
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue
@@ -0,0 +1,85 @@
+<script>
+import { GlTooltipDirective, GlResizeObserverDirective } from '@gitlab/ui';
+import { isFunction, debounce } from 'lodash';
+import { hasHorizontalOverflow } from '~/lib/utils/dom_utils';
+
+const UPDATE_TOOLTIP_DEBOUNCED_WAIT_MS = 300;
+
+export default {
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ GlResizeObserver: GlResizeObserverDirective,
+ },
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ placement: {
+ type: String,
+ required: false,
+ default: 'top',
+ },
+ truncateTarget: {
+ type: [String, Function],
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ tooltipDisabled: true,
+ };
+ },
+ computed: {
+ classes() {
+ if (this.tooltipDisabled) {
+ return '';
+ }
+ return 'js-show-tooltip';
+ },
+ tooltip() {
+ return {
+ title: this.title,
+ placement: this.placement,
+ disabled: this.tooltipDisabled,
+ };
+ },
+ },
+ watch: {
+ title() {
+ // Wait on $nextTick in case the slot width changes
+ this.$nextTick(this.updateTooltip);
+ },
+ },
+ created() {
+ this.updateTooltipDebounced = debounce(this.updateTooltip, UPDATE_TOOLTIP_DEBOUNCED_WAIT_MS);
+ },
+ mounted() {
+ this.updateTooltip();
+ },
+ methods: {
+ selectTarget() {
+ if (isFunction(this.truncateTarget)) {
+ return this.truncateTarget(this.$el);
+ } else if (this.truncateTarget === 'child') {
+ return this.$el.childNodes[0];
+ }
+ return this.$el;
+ },
+ updateTooltip() {
+ this.tooltipDisabled = !hasHorizontalOverflow(this.selectTarget());
+ },
+ onResize() {
+ this.updateTooltipDebounced();
+ },
+ },
+};
+</script>
+
+<template>
+ <span v-gl-tooltip="tooltip" v-gl-resize-observer="onResize" :class="classes" class="gl-min-w-0">
+ <slot></slot>
+ </span>
+</template>