Skip to content

Commit

Permalink
refactor(context-menu-fixed-style-hook): refactor contextMenuFixedSty…
Browse files Browse the repository at this point in the history
…leHook (#115)
  • Loading branch information
piggggggggy authored Oct 27, 2022
1 parent a47c83a commit 0719047
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 68 deletions.
19 changes: 8 additions & 11 deletions src/hooks/context-menu-fixed-style/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import type { ComputedRef } from 'vue';
import type { ComputedRef, Ref } from 'vue';
import {
computed, getCurrentInstance, onMounted, onUnmounted, reactive, toRefs, watch,
computed, nextTick, onMounted, onUnmounted, reactive, toRefs, watch,
} from 'vue';
import type { Vue } from 'vue/types/vue';

import type { ResizeObserverEntry } from '@juggle/resize-observer';
import { ResizeObserver } from '@juggle/resize-observer';
import { throttle } from 'lodash';

import { makeOptionalProxy } from '@/util/composition-helpers';

export interface ContextMenuFixedStyleProps {
useFixedMenuStyle?: boolean;
visibleMenu?: boolean;
}

interface StateArgs {
useFixedMenuStyle?: ComputedRef<boolean|undefined> | boolean;
visibleMenu?: ComputedRef<boolean|undefined> | boolean;
visibleMenu: Ref<boolean>;
}

const isScrollable = (ele: Element) => {
Expand All @@ -35,20 +33,19 @@ const getScrollableParent = (ele?: Element|null): Element => {
};

export const useContextMenuFixedStyle = ({ useFixedMenuStyle, visibleMenu }: StateArgs) => {
const vm = getCurrentInstance()?.proxy as Vue;
const state = reactive({
useFixedMenuStyle,
visibleMenu,
});

const contextMenuFixedStyleState = reactive({
proxyVisibleMenu: makeOptionalProxy('visibleMenu', vm, false),
targetRef: null as Vue|Element|null,
targetElement: computed<Element|null>(() => (contextMenuFixedStyleState.targetRef as Vue)?.$el ?? contextMenuFixedStyleState.targetRef),
contextMenuStyle: {},
});

const hideMenu = throttle(() => {
if (contextMenuFixedStyleState.proxyVisibleMenu) contextMenuFixedStyleState.proxyVisibleMenu = false;
if (state.visibleMenu) state.visibleMenu = false;
}, 300);

const setStyleOfContextMenu = () => {
Expand Down Expand Up @@ -82,12 +79,12 @@ export const useContextMenuFixedStyle = ({ useFixedMenuStyle, visibleMenu }: Sta
contextMenuFixedStyleState.contextMenuStyle = contextMenuStyle;
};

watch(() => contextMenuFixedStyleState.proxyVisibleMenu, async () => {
if (!contextMenuFixedStyleState.proxyVisibleMenu || !contextMenuFixedStyleState.targetRef) {
watch(() => state.visibleMenu, async () => {
if (!state.visibleMenu || !contextMenuFixedStyleState.targetRef) {
contextMenuFixedStyleState.contextMenuStyle = {};
}

await vm.$nextTick(); // Needed codes for timing issues between painting DOM and proxyVisibleMenu
await nextTick(); // Needed codes for timing issues between painting DOM and visibleMenu

setStyleOfContextMenu();
}, { immediate: true });
Expand Down
42 changes: 34 additions & 8 deletions src/inputs/dropdown/query-search-dropdown/PQuerySearchDropdown.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div v-click-outside="hideMenu" class="p-query-search-dropdown">
<p-search :class="{'no-menu': querySearchState.menu ? querySearchState.menu.length === 0 : false}"
<p-search ref="targetRef"
:class="{'no-menu': querySearchState.menu ? querySearchState.menu.length === 0 : false}"
:value="querySearchState.searchText"
:placeholder="placeholder ? placeholder : 'Select Key: value'"
disable-icon
Expand Down Expand Up @@ -41,18 +42,19 @@
/>
</span>
<span class="dropdown-button" :class="{'text-blue-600': querySearchState.isFocused}" @click="handleClickDropdownButton">
<p-i class="icon" :name="querySearchState.visibleMenu ? 'ic_arrow_top' : 'ic_arrow_bottom'"
<p-i class="icon" :name="visibleMenuRef ? 'ic_arrow_top' : 'ic_arrow_bottom'"
color="inherit"
/>
</span>
</div>
</template>
</p-search>
<div v-show="querySearchState.visibleMenu" class="menu-container">
<div v-show="visibleMenuRef" class="menu-container">
<p-context-menu ref="menuRef"
:loading="querySearchState.lazyLoading"
:menu="querySearchState.menu"
:highlight-term="querySearchState.searchText"
:style="{...contextMenuStyle, maxWidth: contextMenuStyle.minWidth, width: contextMenuStyle.minWidth}"
no-select-indication
@keyup:up:end="focus"
@keyup:down:end="focus"
Expand All @@ -64,16 +66,19 @@
</template>

<script lang="ts">
import type { PropType, DirectiveFunction, SetupContext } from 'vue';
import type {
PropType, DirectiveFunction, SetupContext, Ref,
} from 'vue';
import {
computed, ref,
defineComponent, reactive, toRefs,
} from 'vue';
import { vOnClickOutside } from '@vueuse/components';
import { focus as vFocus } from 'vue-focus';
import PI from '@/foundation/icons/PI.vue';
import { useProxyValue } from '@/hooks';
import { useContextMenuFixedStyle, useProxyValue } from '@/hooks';
import { useQuerySearch } from '@/hooks/query-search';
import { PTag } from '@/index';
import PContextMenu from '@/inputs/context-menu/PContextMenu.vue';
Expand Down Expand Up @@ -111,6 +116,14 @@ export default defineComponent<QuerySearchDropdownProps>({
type: Boolean,
default: false,
},
visibleMenu: {
type: Boolean,
default: false,
},
useFixedMenuStyle: {
type: Boolean,
default: false,
},
keyItemSets: {
// FIXME:: below any type
type: Array as PropType<any>,
Expand All @@ -130,6 +143,21 @@ export default defineComponent<QuerySearchDropdownProps>({
},
},
setup(props, { emit }: SetupContext) {
const state = reactive({
proxySelected: useProxyValue('selected', props, emit),
});
const visibleMenuRef: Ref<boolean> = ref<boolean>(props.visibleMenu || false);
const {
targetRef, targetElement, contextMenuStyle,
} = useContextMenuFixedStyle({
useFixedMenuStyle: computed(() => props.useFixedMenuStyle),
visibleMenu: visibleMenuRef,
});
const contextMenuFixedStyleState = reactive({
visibleMenuRef, targetRef, targetElement, contextMenuStyle,
});
const {
state: querySearchState,
focus, blur, hideMenu, showMenu,
Expand All @@ -141,9 +169,6 @@ export default defineComponent<QuerySearchDropdownProps>({
preTreatSelectedMenuItem,
} = useQuerySearch(props, { strict: true });
const state = reactive({
proxySelected: useProxyValue('selected', props, emit),
});
/* util */
const selectItem = (queryItem: QueryItem) => {
Expand Down Expand Up @@ -178,6 +203,7 @@ export default defineComponent<QuerySearchDropdownProps>({
return {
querySearchState,
...toRefs(state),
...toRefs(contextMenuFixedStyleState),
focus,
blur,
showMenu,
Expand Down
3 changes: 2 additions & 1 deletion src/inputs/dropdown/query-search-dropdown/type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ContextMenuFixedStyleProps } from '@/hooks';
import type { KeyItemSet, QueryItem, ValueHandlerMap } from '@/inputs/search/query-search/type';

export interface QuerySearchDropdownProps {
export interface QuerySearchDropdownProps extends ContextMenuFixedStyleProps {
value: string;
placeholder: string;
focused: boolean;
Expand Down
33 changes: 17 additions & 16 deletions src/inputs/dropdown/search-dropdown/PSearchDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
>
<div v-if="searchDropdownType === SEARCH_DROPDOWN_TYPE.radioButton &&
proxySelected.length &&
!proxyVisibleMenu &&
!visibleMenuRef &&
!proxyIsFocused"
class="selected-radio-label"
>
Expand All @@ -36,8 +36,8 @@
@click="onDeleteAllTags"
/>
</template>
<template v-if="searchDropdownType !== SEARCH_DROPDOWN_TYPE.default || !proxySelected.length || proxyVisibleMenu" #right>
<p-i :name="proxyVisibleMenu ? 'ic_arrow_top' : 'ic_arrow_bottom'"
<template v-if="searchDropdownType !== SEARCH_DROPDOWN_TYPE.default || !proxySelected.length || visibleMenuRef" #right>
<p-i :name="visibleMenuRef ? 'ic_arrow_top' : 'ic_arrow_bottom'"
color="inherit" class="dropdown-button" :class="disabled"
@click.stop="handleClickDropdownButton"
/>
Expand All @@ -46,7 +46,7 @@
<slot :name="`search-${slot}`" v-bind="{...scope}" />
</template>
</p-search>
<p-context-menu v-show="proxyVisibleMenu"
<p-context-menu v-show="visibleMenuRef"
ref="menuRef"
:menu="bindingMenu"
:loading="loading"
Expand Down Expand Up @@ -81,10 +81,10 @@

<script lang="ts">
import {
computed, defineComponent, onMounted, onUnmounted, reactive, toRefs, watch, nextTick,
computed, defineComponent, onMounted, onUnmounted, reactive, toRefs, watch, nextTick, ref,
} from 'vue';
import type Vue from 'vue';
import type { DirectiveFunction, SetupContext } from 'vue';
import type { DirectiveFunction, SetupContext, Ref } from 'vue';
import { vOnClickOutside } from '@vueuse/components';
import { reduce } from 'lodash';
Expand Down Expand Up @@ -195,14 +195,15 @@ export default defineComponent<SearchDropdownProps>({
},
},
setup(props, { emit, slots, listeners }: SetupContext) {
const visibleMenuRef: Ref<boolean> = ref<boolean>(props.visibleMenu || false);
const {
proxyVisibleMenu, targetRef, targetElement, contextMenuStyle,
targetRef, targetElement, contextMenuStyle,
} = useContextMenuFixedStyle({
useFixedMenuStyle: computed(() => props.useFixedMenuStyle),
visibleMenu: computed(() => props.visibleMenu),
visibleMenu: visibleMenuRef,
});
const contextMenuFixedStyleState = reactive({
proxyVisibleMenu, targetRef, targetElement, contextMenuStyle,
visibleMenuRef, targetRef, targetElement, contextMenuStyle,
});
const state = reactive({
Expand Down Expand Up @@ -275,7 +276,7 @@ export default defineComponent<SearchDropdownProps>({
};
const hideMenu = (mode?: string) => {
if (!contextMenuFixedStyleState.proxyVisibleMenu) return;
if (!contextMenuFixedStyleState.visibleMenuRef) return;
// placeholder
const isRadioItemSelected = state.searchDropdownType === SEARCH_DROPDOWN_TYPE.radioButton && (mode === 'click' || state.proxySelected.length);
if (isRadioItemSelected) {
Expand All @@ -297,12 +298,12 @@ export default defineComponent<SearchDropdownProps>({
state.proxyValue = '';
}
contextMenuFixedStyleState.proxyVisibleMenu = false;
contextMenuFixedStyleState.visibleMenuRef = false;
emit('hide-menu');
};
const showMenu = () => {
if (contextMenuFixedStyleState.proxyVisibleMenu) return;
if (contextMenuFixedStyleState.visibleMenuRef) return;
if (
state.proxySelected.length && (
Expand All @@ -319,7 +320,7 @@ export default defineComponent<SearchDropdownProps>({
filterMenu(state.proxyValue);
}
contextMenuFixedStyleState.proxyVisibleMenu = true;
contextMenuFixedStyleState.visibleMenuRef = true;
emit('show-menu');
};
Expand Down Expand Up @@ -370,7 +371,7 @@ export default defineComponent<SearchDropdownProps>({
};
const onInput = (val: string, e) => {
if (!contextMenuFixedStyleState.proxyVisibleMenu) showMenu();
if (!contextMenuFixedStyleState.visibleMenuRef) showMenu();
state.proxyValue = val;
emit('input', val, e);
Expand Down Expand Up @@ -424,7 +425,7 @@ export default defineComponent<SearchDropdownProps>({
const handleClickDropdownButton = () => {
if (props.disabled) return;
if (contextMenuFixedStyleState.proxyVisibleMenu) hideMenu();
if (contextMenuFixedStyleState.visibleMenuRef) hideMenu();
else showMenu();
};
Expand Down Expand Up @@ -455,7 +456,7 @@ export default defineComponent<SearchDropdownProps>({
};
const onWindowKeydown = (e: KeyboardEvent) => {
if (contextMenuFixedStyleState.proxyVisibleMenu && ['ArrowDown', 'ArrowUp'].includes(e.key)) {
if (contextMenuFixedStyleState.visibleMenuRef && ['ArrowDown', 'ArrowUp'].includes(e.key)) {
e.preventDefault();
}
};
Expand Down
31 changes: 16 additions & 15 deletions src/inputs/dropdown/select-dropdown/PSelectDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
invalid,
disabled,
'read-only': readOnly,
active: proxyVisibleMenu && !readOnly,
active: visibleMenuRef && !readOnly,
}"
>
<p-icon-button v-if="styleType === SELECT_DROPDOWN_STYLE_TYPE.ICON_BUTTON"
ref="targetRef"
:name="buttonIcon || (proxyVisibleMenu ? 'ic_arrow_top' : 'ic_arrow_bottom')"
:activated="proxyVisibleMenu"
:name="buttonIcon || (visibleMenuRef ? 'ic_arrow_top' : 'ic_arrow_bottom')"
:activated="visibleMenuRef"
:disabled="disabled"
color="inherit"
class="icon-button"
Expand All @@ -34,14 +34,14 @@
</slot>
</span>
<p-i v-if="!(styleType === SELECT_DROPDOWN_STYLE_TYPE.TRANSPARENT && readOnly)"
:name="proxyVisibleMenu ? 'ic_arrow_top' : 'ic_arrow_bottom'"
:activated="proxyVisibleMenu"
:name="visibleMenuRef ? 'ic_arrow_top' : 'ic_arrow_bottom'"
:activated="visibleMenuRef"
:disabled="disabled"
color="inherit"
class="dropdown-icon"
/>
</button>
<p-context-menu v-show="proxyVisibleMenu"
<p-context-menu v-show="visibleMenuRef"
ref="contextMenuRef"
:class="{ [menuPosition]: !useFixedMenuStyle }"
:menu="items"
Expand All @@ -68,9 +68,9 @@ import {
defineComponent,
reactive,
toRefs,
nextTick,
nextTick, ref,
} from 'vue';
import type { DirectiveFunction, SetupContext } from 'vue';
import type { DirectiveFunction, SetupContext, Ref } from 'vue';
import { vOnClickOutside } from '@vueuse/components';
import { groupBy, reduce } from 'lodash';
Expand Down Expand Up @@ -163,14 +163,15 @@ export default defineComponent<SelectDropdownProps>({
},
},
setup(props, { emit, slots }: SetupContext) {
const visibleMenuRef: Ref<boolean> = ref<boolean>(props.visibleMenu || false);
const {
proxyVisibleMenu, targetRef, targetElement, contextMenuStyle,
targetRef, targetElement, contextMenuStyle,
} = useContextMenuFixedStyle({
useFixedMenuStyle: computed(() => props.useFixedMenuStyle),
visibleMenu: computed(() => props.visibleMenu),
visibleMenu: visibleMenuRef,
});
const contextMenuFixedStyleState = reactive({
proxyVisibleMenu, targetRef, targetElement, contextMenuStyle,
visibleMenuRef, targetRef, targetElement, contextMenuStyle,
});
const state = reactive({
Expand Down Expand Up @@ -208,18 +209,18 @@ export default defineComponent<SelectDropdownProps>({
emit('select', item.name, event);
state.proxySelected = item.name;
}
contextMenuFixedStyleState.proxyVisibleMenu = false;
contextMenuFixedStyleState.visibleMenuRef = false;
};
const handleClick = (e: MouseEvent) => {
if (props.readOnly || props.disabled) return;
contextMenuFixedStyleState.proxyVisibleMenu = !contextMenuFixedStyleState.proxyVisibleMenu;
contextMenuFixedStyleState.visibleMenuRef = !contextMenuFixedStyleState.visibleMenuRef;
e.stopPropagation();
};
const handleClickOutside = (): void => {
contextMenuFixedStyleState.proxyVisibleMenu = false;
contextMenuFixedStyleState.visibleMenuRef = false;
};
const handlePressDownKey = () => {
if (!contextMenuFixedStyleState.proxyVisibleMenu) contextMenuFixedStyleState.proxyVisibleMenu = true;
if (!contextMenuFixedStyleState.visibleMenuRef) contextMenuFixedStyleState.visibleMenuRef = true;
nextTick(() => {
if (state.contextMenuRef) {
if (slots['menu-menu']) emit('focus-menu');
Expand Down
Loading

0 comments on commit 0719047

Please sign in to comment.