Skip to content

Commit

Permalink
refactor: enhance useParentProvider composable type support (#851)
Browse files Browse the repository at this point in the history
  • Loading branch information
mlmoravek authored Mar 10, 2024
1 parent 6e9416a commit 041eeab
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 35 deletions.
5 changes: 3 additions & 2 deletions packages/oruga/src/components/carousel/Carousel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
useProviderParent,
} from "@/composables";
import type { CarouselComponent } from "./types";
import type { ComponentClass, ClassBind } from "@/types";
/**
Expand Down Expand Up @@ -234,11 +235,11 @@ function restartTimer(): void {
startTimer();
}
const provideData = computed(() => ({
const provideData = computed<CarouselComponent>(() => ({
restartTimer,
itemWidth: itemWidth.value,
activeIndex: scrollIndex.value,
onClick: (event: MouseEvent): void => emits("click", event),
onClick: (event: Event): void => emits("click", event),
setActive: (index: number): void => switchTo(index),
}));
Expand Down
5 changes: 3 additions & 2 deletions packages/oruga/src/components/carousel/CarouselItem.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script setup lang="ts">
import { computed, type PropType, type Ref } from "vue";
import { computed, type PropType } from "vue";
import { getOption } from "@/utils/config";
import { defineClasses, useProviderChild } from "@/composables";
import type { CarouselComponent } from "./types";
import type { ComponentClass } from "@/types";
/**
Expand Down Expand Up @@ -45,7 +46,7 @@ const props = defineProps({
});
// Inject functionalities and data from the parent carousel component
const { parent, item } = useProviderChild<Ref<any>>();
const { parent, item } = useProviderChild<CarouselComponent>();
const isActive = computed(() => parent.value.activeIndex === item.value.index);
Expand Down
7 changes: 7 additions & 0 deletions packages/oruga/src/components/carousel/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type CarouselComponent = {
restartTimer: () => void;
itemWidth: number;
activeIndex: number;
onClick: (event: Event) => void;
setActive: (index: number) => void;
};
4 changes: 2 additions & 2 deletions packages/oruga/src/components/dropdown/DropdownItem.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts" generic="T">
import { computed, type ComputedRef, type PropType } from "vue";
import { computed, type PropType } from "vue";
import { getOption } from "@/utils/config";
import { uuid, isEqual } from "@/utils/helpers";
Expand Down Expand Up @@ -80,7 +80,7 @@ const emits = defineEmits<{
const itemValue = computed(() => (props.value || uuid()) as T);
// Inject functionalities and data from the parent component
const { parent } = useProviderChild<ComputedRef<DropdownComponent<T>>>();
const { parent } = useProviderChild<DropdownComponent<T>>();
const isClickable = computed(
() => !parent.value.props.disabled && !props.disabled && props.clickable,
Expand Down
7 changes: 4 additions & 3 deletions packages/oruga/src/components/menu/Menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
type ProviderItem,
} from "@/composables";
import type { MenuComponent, MenuItemComponent } from "./types";
import type { ComponentClass } from "@/types";
/**
Expand Down Expand Up @@ -81,20 +82,20 @@ const props = defineProps({
const rootRef = ref();
// Provided data is a computed ref to enjure reactivity.
const provideData = computed(() => ({
const provideData = computed<MenuComponent>(() => ({
activable: props.activable,
accordion: props.accordion,
resetMenu,
}));
/** Provide functionalities and data to child item components */
const { childItems } = useProviderParent<{ reset: () => void }>(rootRef, {
const { childItems } = useProviderParent<MenuItemComponent>(rootRef, {
data: provideData,
});
function resetMenu(excludedItems: ProviderItem[] = []): void {
childItems.value.forEach((item) => {
if (!excludedItems.includes(toRaw(item))) item.data.reset();
if (!excludedItems.includes(toRaw(item))) item.data.value.reset();
});
}
Expand Down
19 changes: 11 additions & 8 deletions packages/oruga/src/components/menu/MenuItem.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed, toRaw, type PropType, type Ref } from "vue";
import { ref, computed, toRaw, type PropType } from "vue";
import { getOption } from "@/utils/config";
import {
Expand All @@ -10,6 +10,11 @@ import {
type ProviderItem,
} from "@/composables";
import type {
MenuComponent,
MenuItemComponent,
MenuItemProvider,
} from "./types";
import type { ComponentClass, DynamicComponent } from "@/types";
/**
Expand Down Expand Up @@ -116,19 +121,17 @@ const emits = defineEmits<{
(e: "update:expanded", value: boolean): void;
}>();
const providedData = computed(() => ({
const providedData = computed<MenuItemComponent>(() => ({
reset,
}));
// Inject functionalities and data from the parent menu component
const { parent, item } = useProviderChild<Ref<any>>({
const { parent, item } = useProviderChild<MenuComponent>({
data: providedData,
});
// Inject functionalities and data from the parent menu-item component
const providedItem = useProviderChild<
Ref<{ triggerReset: typeof triggerReset } | undefined>
>({
const providedItem = useProviderChild<MenuItemProvider>({
key: "menu-item",
needParent: false,
});
Expand Down Expand Up @@ -173,12 +176,12 @@ function reset(): void {
const rootRef = ref();
// Provided data is a computed ref to enjure reactivity.
const provideData = computed(() => ({
const provideData = computed<MenuItemProvider>(() => ({
triggerReset,
}));
/** Provide functionalities and data to child item components */
useProviderParent(rootRef, { data: provideData, key: "menu-item" });
useProviderParent(rootRef, { key: "menu-item", data: provideData });
// --- Computed Component Classes ---
Expand Down
15 changes: 15 additions & 0 deletions packages/oruga/src/components/menu/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { ProviderItem } from "@/composables";

export type MenuComponent = {
activable: boolean;
accordion: boolean;
resetMenu: (excludedItems?: ProviderItem[]) => void;
};

export type MenuItemComponent = {
reset: () => void;
};

export type MenuItemProvider = {
triggerReset: (child?: ProviderItem) => void;
};
4 changes: 2 additions & 2 deletions packages/oruga/src/components/slider/SliderTick.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, type ComputedRef, type PropType } from "vue";
import { computed, type PropType } from "vue";
import { defineClasses, useProviderChild } from "@/composables";
import type { SliderComponent } from "./types";
Expand Down Expand Up @@ -38,7 +38,7 @@ const props = defineProps({
});
// Inject functionalities and data from the parent carousel component
const { parent } = useProviderChild<ComputedRef<SliderComponent>>();
const { parent } = useProviderChild<SliderComponent>();
const position = computed(() => {
const pos =
Expand Down
6 changes: 3 additions & 3 deletions packages/oruga/src/components/steps/StepItem.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref, useSlots, type ComputedRef, type PropType } from "vue";
import { computed, toRaw, ref, useSlots, type PropType } from "vue";
import { getOption } from "@/utils/config";
import { isEqual, uuid } from "@/utils/helpers";
Expand Down Expand Up @@ -99,15 +99,15 @@ const emits = defineEmits<{
const slots = useSlots();
const providedData = computed<StepItemComponent>(() => ({
...props,
...toRaw(props),
$slots: slots,
isTransitioning: isTransitioning.value,
activate,
deactivate,
}));
// Inject functionalities and data from the parent carousel component
const { parent, item } = useProviderChild<ComputedRef<StepsComponent>>({
const { parent, item } = useProviderChild<StepsComponent>({
data: providedData,
});
Expand Down
3 changes: 1 addition & 2 deletions packages/oruga/src/components/table/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
useSlots,
toValue,
type PropType,
type ComputedRef,
} from "vue";
import OCheckbox from "../checkbox/Checkbox.vue";
Expand Down Expand Up @@ -709,7 +708,7 @@ const rootRef = ref<HTMLElement>();
const slotRef = ref<HTMLElement>();
/** Provide functionalities and data to child item components */
const provider = useProviderParent<ComputedRef<TableColumnComponent>>(slotRef);
const provider = useProviderParent<TableColumnComponent>(slotRef);
const tableColumns = computed<TableColumn[]>(() =>
provider.sortedItems.value.map((column) => ({
Expand Down
6 changes: 3 additions & 3 deletions packages/oruga/src/components/tabs/TabItem.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref, useSlots, type ComputedRef, type PropType } from "vue";
import { computed, toRaw, ref, useSlots, type PropType } from "vue";
import { getOption } from "@/utils/config";
import { isEqual, uuid } from "@/utils/helpers";
Expand Down Expand Up @@ -98,7 +98,7 @@ const emits = defineEmits<{
const slots = useSlots();
const providedData = computed<TabItemComponent>(() => ({
...props,
...toRaw(props),
$slots: slots,
headerIconClasses: headerIconClasses.value,
headerTextClasses: headerTextClasses.value,
Expand All @@ -108,7 +108,7 @@ const providedData = computed<TabItemComponent>(() => ({
}));
// Inject functionalities and data from the parent component
const { parent, item } = useProviderChild<ComputedRef<TabsComponent>>({
const { parent, item } = useProviderChild<TabsComponent>({
data: providedData,
});
Expand Down
22 changes: 14 additions & 8 deletions packages/oruga/src/composables/useParentProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ import {
onUnmounted,
provide,
ref,
type ComputedRef,
type Ref,
} from "vue";

export type ProviderItem<T = unknown> = {
index: number;
data: T;
data: ComputedRef<T>;
identifier: string;
};

type PovidedData<P, I = unknown> = {
registerItem: (data: I) => ProviderItem<I>;
registerItem: (data: ComputedRef<I>) => ProviderItem<I>;
unregisterItem: (item: ProviderItem<I>) => void;
data?: P;
data?: ComputedRef<P>;
};

type ProviderParentOptions<T = unknown> = {
Expand All @@ -30,7 +31,7 @@ type ProviderParentOptions<T = unknown> = {
/**
* Additional data provided for the child to the item
*/
data?: T;
data?: ComputedRef<T>;
};

/**
Expand All @@ -42,7 +43,10 @@ type ProviderParentOptions<T = unknown> = {
export function useProviderParent<ItemData = unknown, ParentData = unknown>(
rootRef?: Ref<HTMLElement>,
options?: ProviderParentOptions<ParentData>,
) {
): {
childItems: Ref<ProviderItem<ItemData>[]>;
sortedItems: Ref<ProviderItem<ItemData>[]>;
} {
// getting a hold of the internal instance in setup()
const vm = getCurrentInstance();
if (!vm)
Expand All @@ -65,7 +69,9 @@ export function useProviderParent<ItemData = unknown, ParentData = unknown>(
childItems.value.slice().sort((a, b) => a.index - b.index),
);

function registerItem(data?: ItemData): ProviderItem<ItemData> {
function registerItem(
data?: ComputedRef<ItemData>,
): ProviderItem<ItemData> {
const index = childItems.value.length;
const identifier = nextSequence();
const item = { index, data, identifier };
Expand Down Expand Up @@ -124,7 +130,7 @@ type ProviderChildOptions<T = unknown> = {
/**
* Additional data appended to the item
*/
data?: T;
data?: ComputedRef<T>;
/**
* Register child on parent
* @default true
Expand All @@ -138,7 +144,7 @@ type ProviderChildOptions<T = unknown> = {
*/
export function useProviderChild<ParentData, ItemData = unknown>(
options: ProviderChildOptions<ItemData> = { needParent: true },
): { parent: ParentData; item: Ref<ProviderItem<ItemData>> } {
): { parent: ComputedRef<ParentData>; item: Ref<ProviderItem<ItemData>> } {
// getting a hold of the internal instance in setup()
const vm = getCurrentInstance();
if (!vm)
Expand Down

0 comments on commit 041eeab

Please sign in to comment.