@empathyco/x-components
Version:
Empathy X Components
186 lines (183 loc) • 6.12 kB
JavaScript
import { defineComponent, ref, computed, watch, onBeforeUnmount } from 'vue';
import { animateTranslate } from '../../../components/animations/animate-translate/animate-translate.factory.js';
import { use$x } from '../../../composables/use-_x.js';
import { useState } from '../../../composables/use-state.js';
import { AnimationProp } from '../../../types/animation-prop.js';
import { searchBoxXModule } from '../x-module.js';
/**.
* This component renders an animated placeholder for the search input in the shape of a list of
* iterating messages that can be configured to happen always or only when hovering the input
*
* @public
*/
var _sfc_main = defineComponent({
name: 'SearchInputPlaceholder',
xModule: searchBoxXModule.name,
props: {
/**
* List of messages to animate.
*
* @public
*/
messages: {
type: Array,
required: true,
},
/**
* Animation component used for the messages.
*
* @public
*/
animation: {
type: AnimationProp,
default: () => animateTranslate('bottom-to-top'),
},
/**
* Time in milliseconds during which each message is visible.
*
* @public
*/
animationIntervalMs: {
type: Number,
default: 1500,
},
/**
* Whether the messages animation is active only when hovering the search input or always.
*
* @public
*/
animateOnlyOnHover: Boolean,
},
setup(props) {
const $x = use$x();
/**.
* The search box written query
*
* @internal
*/
const { query } = useState('searchBox');
/**.
* The search box hover status
*
* @internal
*/
const isSearchBoxHovered = ref(false);
/**.
* The search box focus status
*
* @internal
*/
const isSearchBoxFocused = ref(false);
/**
* The index used to point to the current animation message in the list.
*
* @internal
*/
const animationMessageIndex = ref(0);
/**
* The interval used for the animation.
*
* @internal
*/
const animationInterval = ref(undefined);
/**
* The visibility state of the component.
*
* @returns The visibility state based on the search input state (query & focus).
*
* @internal
*/
const isVisible = computed(() => !query.value && !isSearchBoxFocused.value);
/**
* The animation state of the component.
*
* @returns Whether the animation is active or not.
*
* @internal
*/
const isBeingAnimated = computed(() => isVisible.value && (!props.animateOnlyOnHover || isSearchBoxHovered.value));
/**
* The current placeholder message.
*
* @returns The message to display as placeholder at any moment.
*
* @internal
*/
const message = computed(() => isBeingAnimated.value ? props.messages[animationMessageIndex.value] : props.messages[0]);
/**
* Clears the interval used for the animation.
*
* @internal
*/
const stopAnimationInterval = () => {
if (animationInterval.value) {
clearInterval(animationInterval.value);
animationInterval.value = undefined;
}
};
/**
* Increments animation message index; if the new index exceeds the messages list length, it is
* reset to 0.
*
* @internal
*/
const incrementAnimationMessageIndex = () => {
animationMessageIndex.value = (animationMessageIndex.value + 1) % props.messages.length;
};
$x.on('UserHoveredInSearchBox', false).subscribe(() => (isSearchBoxHovered.value = true));
$x.on('UserHoveredOutSearchBox', false).subscribe(() => (isSearchBoxHovered.value = false));
$x.on('UserFocusedSearchBox', false).subscribe(() => (isSearchBoxFocused.value = true));
$x.on('UserBlurredSearchBox', false).subscribe(() => (isSearchBoxFocused.value = false));
/**
* Starts or stops the animation depending on the current animation state.
*
* @internal
*/
const resetAnimation = () => {
stopAnimationInterval();
if (isBeingAnimated.value) {
animationInterval.value = window.setInterval(() => {
incrementAnimationMessageIndex();
}, props.animationIntervalMs);
}
};
watch(() => 'animationIntervalMs', resetAnimation);
/**
* Resets the animation message index to zero.
*
* @internal
*/
const resetAnimationMessageIndex = () => {
animationMessageIndex.value = 0;
};
watch(() => props.messages, () => {
resetAnimationMessageIndex();
resetAnimation();
}, { deep: true });
/**
* Sets the animation message index with the right value for the next future iteration when the
* current one stops,assuring the user will see always a new message on each animation state
* change.
*
* @internal
*/
watch(isBeingAnimated, () => {
if (!isBeingAnimated.value) {
if (props.animateOnlyOnHover) {
resetAnimationMessageIndex();
}
incrementAnimationMessageIndex();
}
resetAnimation();
}, { immediate: true });
onBeforeUnmount(() => {
stopAnimationInterval();
});
return {
isVisible,
message,
};
},
});
export { _sfc_main as default };
//# sourceMappingURL=search-input-placeholder.vue2.js.map