From 6306b367150666a6d28c01553bd019030a56860f Mon Sep 17 00:00:00 2001 From: Mantra Date: Thu, 14 Dec 2023 17:01:16 +0000 Subject: [PATCH 1/3] add single select --- demo/App.vue | 92 ++++++++++++++++++++++++++- demo/main.ts | 1 + src/components/SingleSelect.vue | 73 +++++++++++++++++++++ src/index.ts | 3 + src/style.css | 5 ++ src/utils.ts | 11 ++++ tests/components/singleSelect.spec.ts | 73 +++++++++++++++++++++ tests/utils.spec.ts | 8 ++- 8 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 src/components/SingleSelect.vue create mode 100644 tests/components/singleSelect.spec.ts diff --git a/demo/App.vue b/demo/App.vue index e039d47..1b18630 100644 --- a/demo/App.vue +++ b/demo/App.vue @@ -1,8 +1,94 @@ \ No newline at end of file diff --git a/demo/main.ts b/demo/main.ts index 65a01a4..4c78d54 100644 --- a/demo/main.ts +++ b/demo/main.ts @@ -1,5 +1,6 @@ import { createApp } from 'vue' import '../src/style.css' import App from './App.vue' +import '@coreui/coreui/dist/css/coreui.min.css' createApp(App).mount('#app') diff --git a/src/components/SingleSelect.vue b/src/components/SingleSelect.vue new file mode 100644 index 0000000..56c220b --- /dev/null +++ b/src/components/SingleSelect.vue @@ -0,0 +1,73 @@ + + + + + \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e69de29..9b00c73 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,3 @@ +import SingleSelect from "./components/SingleSelect.vue"; + +export { SingleSelect }; \ No newline at end of file diff --git a/src/style.css b/src/style.css index e69de29..cbd3635 100644 --- a/src/style.css +++ b/src/style.css @@ -0,0 +1,5 @@ +.dropdown-menu { + --cui-dropdown-link-active-bg: #ebedef !important; + --cui-dropdown-link-active-color: rbga(44, 56, 74, 0.95) !important; + } + \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 89e8e80..05be759 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -71,3 +71,14 @@ export const collapseOptions = (array: FlatOption[], optionPath: string[]) => { index++; }; }; + +export const getNode = (optionId: string, flatOptions: FlatOption[], options: Option[]) => { + const flatOptionPath = flatOptions.find(op => op.id === optionId)!.path; + let nodes = options; + flatOptionPath.forEach((id, index) => { + if (index < flatOptionPath.length - 1) { + nodes = nodes.find(node => node.id === id)!.children!; + } + }); + return nodes.find(node => node.id === optionId)!; +}; diff --git a/tests/components/singleSelect.spec.ts b/tests/components/singleSelect.spec.ts new file mode 100644 index 0000000..0bcb52d --- /dev/null +++ b/tests/components/singleSelect.spec.ts @@ -0,0 +1,73 @@ +import { mount } from "@vue/test-utils"; +import SingleSelect from "../../src/components/SingleSelect.vue"; +import BaseSelect from "../../src/components/BaseSelect.vue"; + +describe("Dropdown item tests", () => { + const options = [ + { + id: "id1", + label: "parent1", + children: [ + { + id: "id1_1", + label: "child1" + } + ] + }, + { + id: "id2", + label: "parent2" + } + ]; + + const getWrapper = (id: string | undefined = undefined, placeholder = undefined) => { + return mount(SingleSelect, { + props: { + options, + placeholder, + modelValue: id + } + }); + }; + + it("renders as expected", async () => { + const wrapper = getWrapper(); + + const baseSelect = wrapper.findComponent(BaseSelect); + expect(baseSelect.props("options")).toStrictEqual(options); + expect(baseSelect.props("showDropdownMenu")).toBe(false); + + const label = baseSelect.find(".label"); + expect(label.text()).toBe("Select..."); + }); + + it("sets label as expected", () => { + const wrapper = getWrapper("id1_1"); + const label = wrapper.find(".label"); + expect(label.text()).toBe("child1"); + }); + + it("toggle click toggles showDropdownMenu", () => { + const wrapper = getWrapper(); + const baseSelect = wrapper.findComponent(BaseSelect); + baseSelect.vm.$emit("toggle-click"); + // is false by default + expect(wrapper.vm.showDropdownMenu).toBe(true); + }); + + it("show dropdown menu is set to false when menu hides", () => { + const wrapper = getWrapper(); + const baseSelect = wrapper.findComponent(BaseSelect); + wrapper.vm.showDropdownMenu = true; + baseSelect.vm.$emit("hide"); + expect(wrapper.vm.showDropdownMenu).toBe(false); + }); + + it("select item event correctly triggers handleSelectItem", () => { + const wrapper = getWrapper(); + const baseSelect = wrapper.findComponent(BaseSelect); + baseSelect.vm.$emit("select-item", "id1_1"); + expect(wrapper.emitted("update:modelValue")![0][0]).toStrictEqual({id: "id1_1", label: "child1"}); + expect(wrapper.vm.showDropdownMenu).toBe(false); + }); +}); \ No newline at end of file diff --git a/tests/utils.spec.ts b/tests/utils.spec.ts index d84fed4..00a22af 100644 --- a/tests/utils.spec.ts +++ b/tests/utils.spec.ts @@ -1,5 +1,5 @@ import { FlatOption } from "../src/types"; -import { collapseOptions, expandOptions, flattenOptions } from "../src/utils"; +import { collapseOptions, expandOptions, flattenOptions, getNode } from "../src/utils"; describe("Utils tests", () => { const dummyOptions = [ @@ -124,4 +124,10 @@ describe("Utils tests", () => { } }); }); + + it("get node works as expected", () => { + const array: FlatOption[] = JSON.parse(JSON.stringify(flatOptionsExpanded)); + const node = getNode("id1_1", array, dummyOptions); + expect(node).toStrictEqual(dummyOptions[0].children![0]); + }); }); \ No newline at end of file From b8f78658581fa02b4685d0b75c77893b368376ad Mon Sep 17 00:00:00 2001 From: Mantra Date: Thu, 14 Dec 2023 17:11:21 +0000 Subject: [PATCH 2/3] tweak single select emit --- src/components/SingleSelect.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/SingleSelect.vue b/src/components/SingleSelect.vue index 56c220b..15569f5 100644 --- a/src/components/SingleSelect.vue +++ b/src/components/SingleSelect.vue @@ -46,8 +46,8 @@ }); const handleSelectItem = (optionId: string) => { - const node = getNode(optionId, flatOptions.value, props.options); - emit("update:modelValue", node); + const { id, label } = getNode(optionId, flatOptions.value, props.options); + emit("update:modelValue", { id, label }); showDropdownMenu.value = false; }; From a46b2c62b43d6e4bd7e264c869234f2cf119ded3 Mon Sep 17 00:00:00 2001 From: Mantra Date: Thu, 14 Dec 2023 17:17:13 +0000 Subject: [PATCH 3/3] emmas comment --- src/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils.ts b/src/utils.ts index 05be759..a725728 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -43,6 +43,7 @@ export const expandOptions = (array: FlatOption[], optionPath: string[]) => { while (index < array.length && array[index].path.length > optionPath.length) { const currentOption = array[index]; + // Show options whose immediate parents are marked as open const show = openOptionsPaths.some(openOpPath => { return openOpPath.length === array[index].path.length - 1 && arraysAreEqual(openOpPath, array[index].path.slice(0, -1));