@code-coaching/vuetiful 0.17.1 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-coaching/vuetiful",
3
- "version": "0.17.1",
3
+ "version": "0.18.1",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "onchange 'src/**/*.vue' 'src/**/*.ts' 'src/**/*.css' -- npm run build",
@@ -101,7 +101,9 @@ const showText = computed(() => {
101
101
  v-model="parentModelValue"
102
102
  >
103
103
  <v-listbox-label v-if="labelText" :class="labelClasses">{{ labelText }}</v-listbox-label>
104
- <v-listbox-button data-test="v-listbox-button">{{ showText }}</v-listbox-button>
104
+ <v-listbox-button data-test="v-listbox-button" :class="`${background} ${text}`">
105
+ {{ showText }}
106
+ </v-listbox-button>
105
107
  <!-- TODO: Add configurable transition -->
106
108
  <transition
107
109
  enter-active-class="transition duration-150 ease-in-out"
@@ -0,0 +1,122 @@
1
+ import { mount } from "@vue/test-utils";
2
+ import { describe, expect, test } from "vitest";
3
+ import { VTab, VTabs } from "..";
4
+
5
+ describe("VTab", () => {
6
+ test("defaults", async () => {
7
+ const wrapper = mount({
8
+ template: /*html*/ `
9
+ <v-tabs>
10
+ <template v-slot="tabs">
11
+ <v-tab data-test="vuetiful">Vuetiful</v-tab>
12
+ </template>
13
+ </v-tabs>
14
+ `,
15
+ components: {
16
+ "v-tabs": VTabs,
17
+ "v-tab": VTab,
18
+ },
19
+ });
20
+
21
+ const vuetiful = wrapper.find("[data-test='vuetiful']");
22
+ const slotContainer = vuetiful.find("[data-test='slot-container']");
23
+ expect(vuetiful.classes()).toEqual(["flex", "flex-col"]);
24
+ expect(slotContainer.classes()).toEqual([
25
+ "text-base",
26
+ "rounded-token",
27
+ "w-full",
28
+ "px-4",
29
+ "py-2",
30
+ ]);
31
+ });
32
+
33
+ test("vertical", async () => {
34
+ const wrapper = mount({
35
+ template: /*html*/ `
36
+ <v-tabs vertical>
37
+ <template v-slot="tabs">
38
+ <v-tab data-test="vuetiful">Vuetiful</v-tab>
39
+ </template>
40
+ </v-tabs>
41
+ `,
42
+ components: {
43
+ "v-tabs": VTabs,
44
+ "v-tab": VTab,
45
+ },
46
+ });
47
+
48
+ const vuetiful = wrapper.find("[data-test='vuetiful']");
49
+ expect(vuetiful.classes()).toEqual(["flex", "flex-row", "justify-between"]);
50
+ });
51
+
52
+ test("class-tab", async () => {
53
+ const wrapper = mount({
54
+ template: /*html*/ `
55
+ <v-tabs class-tab="my-custom-class">
56
+ <template v-slot="tabs">
57
+ <v-tab data-test="vuetiful">Vuetiful</v-tab>
58
+ </template>
59
+ </v-tabs>
60
+ `,
61
+ components: {
62
+ "v-tabs": VTabs,
63
+ "v-tab": VTab,
64
+ },
65
+ });
66
+
67
+ const vuetiful = wrapper.find("[data-test='vuetiful']");
68
+ const slotContainer = vuetiful.find("[data-test='slot-container']");
69
+ expect(slotContainer.classes()).toEqual(["text-base", "rounded-token", "my-custom-class"]);
70
+ });
71
+
72
+ test("hover/active", async () => {
73
+ const wrapper = mount({
74
+ template: /*html*/ `
75
+ <v-tabs active="my-custom-active-class">
76
+ <template v-slot="tabs">
77
+ <v-tab data-test="vuetiful">Vuetiful</v-tab>
78
+ <v-tab data-test="is">Is</v-tab>
79
+ <v-tab data-test="beautiful">Beautiful</v-tab>
80
+ </template>
81
+ </v-tabs>
82
+ `,
83
+ components: {
84
+ "v-tabs": VTabs,
85
+ "v-tab": VTab,
86
+ },
87
+ });
88
+
89
+ const vuetifulSlotContainer = wrapper
90
+ .find("[data-test='vuetiful']")
91
+ .find("[data-test='slot-container']");
92
+ const isSlotContainer = wrapper.find("[data-test='is']").find("[data-test='slot-container']");
93
+ const beautifulSlotContainer = wrapper
94
+ .find("[data-test='beautiful']")
95
+ .find("[data-test='slot-container']");
96
+
97
+ expect(vuetifulSlotContainer.classes()).toEqual([
98
+ "text-base",
99
+ "rounded-token",
100
+ "my-custom-active-class",
101
+ "w-full",
102
+ "px-4",
103
+ "py-2",
104
+ ]);
105
+ expect(isSlotContainer.classes()).toEqual([
106
+ "text-base",
107
+ "rounded-token",
108
+ "hover:variant-ghost",
109
+ "w-full",
110
+ "px-4",
111
+ "py-2",
112
+ ]);
113
+ expect(beautifulSlotContainer.classes()).toEqual([
114
+ "text-base",
115
+ "rounded-token",
116
+ "hover:variant-ghost",
117
+ "w-full",
118
+ "px-4",
119
+ "py-2",
120
+ ]);
121
+ });
122
+ });
@@ -0,0 +1,39 @@
1
+ <script setup lang="ts">
2
+ import { Tab } from "@headlessui/vue";
3
+ import { computed, inject } from "vue";
4
+
5
+ defineProps({
6
+ disabled: {
7
+ type: Boolean,
8
+ default: false,
9
+ },
10
+ });
11
+
12
+ const activeClass = inject("active") as string;
13
+ const hoverClass = inject("hover") as string;
14
+ const vertical = inject("vertical") as boolean;
15
+ const classTab = inject("classTab") as string;
16
+ const hideSeparator = inject("hideSeparator") as boolean;
17
+
18
+ const tabClass = computed(() => {
19
+ return classTab ? classTab : "w-full px-4 py-2";
20
+ });
21
+ </script>
22
+
23
+ <template>
24
+ <Tab
25
+ :disabled="disabled"
26
+ v-slot="{ selected }"
27
+ :class="`flex ${vertical ? 'flex-row justify-between' : 'flex-col'}`"
28
+ >
29
+ <div data-test="slot-container" :class="`text-base rounded-token ${selected ? activeClass : hoverClass} ${tabClass}`">
30
+ <slot />
31
+ </div>
32
+ <div
33
+ v-show="selected && !hideSeparator"
34
+ :class="`z-10 border-surface-900-50-token ${
35
+ vertical ? 'mr-[-2px] h-full border-r-2' : 'mb-[-2px] border-b-2'
36
+ }`"
37
+ ></div>
38
+ </Tab>
39
+ </template>
@@ -0,0 +1,23 @@
1
+ import { TabGroup } from "@headlessui/vue";
2
+ import { mount } from "@vue/test-utils";
3
+ import { describe, expect, test } from "vitest";
4
+ import { VTabPanel } from "..";
5
+
6
+ describe("VTabs", () => {
7
+ test("default props", () => {
8
+ const wrapper = mount({
9
+ template: /*html*/ `
10
+ <TabGroup>
11
+ <v-tab-panel data-test='tab-panel'>John Duck</v-tab-panel>
12
+ </TabGroup>
13
+ `,
14
+ components: {
15
+ TabGroup: TabGroup,
16
+ "v-tab-panel": VTabPanel,
17
+ },
18
+ });
19
+
20
+ const tabPanel = wrapper.find("[data-test='tab-panel']");
21
+ expect(tabPanel.text()).toEqual("John Duck");
22
+ });
23
+ });
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import { TabPanel } from '@headlessui/vue';
3
+ </script>
4
+
5
+ <template>
6
+ <TabPanel>
7
+ <slot />
8
+ </TabPanel>
9
+ </template>
@@ -0,0 +1,90 @@
1
+ import { mount } from "@vue/test-utils";
2
+ import { describe, expect, test } from "vitest";
3
+ import { VTab, VTabPanel, VTabs } from "..";
4
+
5
+ describe("VTabs", () => {
6
+ test("hide separator", () => {
7
+ const wrapper = mount({
8
+ template: /*html*/ `
9
+ <v-tabs hide-separator></v-tabs>
10
+ `,
11
+ components: {
12
+ "v-tabs": VTabs,
13
+ },
14
+ });
15
+
16
+ const separator = wrapper.find("[data-test='vuetiful-separator']");
17
+ expect(separator.exists()).toBeFalsy();
18
+ });
19
+
20
+ test("default props", () => {
21
+ const wrapper = mount({
22
+ template: /*html*/ `
23
+ <v-tabs>
24
+ <template v-slot="tabs">
25
+ <v-tab>John Duck</v-tab>
26
+ </template>
27
+ <v-tab-panel>John Duck Panel</v-tab-panel>
28
+ </v-tabs>
29
+ `,
30
+ components: {
31
+ "v-tabs": VTabs,
32
+ "v-tab": VTab,
33
+ "v-tab-panel": VTabPanel,
34
+ },
35
+ });
36
+
37
+ const tabList = wrapper.find("[data-test='vuetiful-tab-list']");
38
+ expect(tabList.classes()).toEqual([
39
+ "vuetiful-tab-list",
40
+ "flex",
41
+ "!rounded-bl-none",
42
+ "!rounded-br-none",
43
+ "rounded-container-token",
44
+ ]);
45
+ expect(tabList.classes()).not.toContain("flex-col");
46
+
47
+ const tabPanels = wrapper.find("[data-test='vuetiful-tab-panels']");
48
+ expect(tabPanels.classes()).toEqual([
49
+ "vuetiful-tab-panels",
50
+ "!rounded-tl-none",
51
+ "!rounded-tr-none",
52
+ "rounded-container-token",
53
+ ]);
54
+ });
55
+
56
+ test("vertical", () => {
57
+ const wrapper = mount({
58
+ template: /*html*/ `
59
+ <v-tabs vertical>
60
+ <template v-slot="tabs">
61
+ <v-tab>Tab 1</v-tab>
62
+ </template>
63
+ <v-tab-panel>Panel 1</v-tab-panel>
64
+ </v-tabs>
65
+ `,
66
+ components: {
67
+ "v-tabs": VTabs,
68
+ "v-tab": VTab,
69
+ "v-tab-panel": VTabPanel,
70
+ },
71
+ });
72
+ const tabList = wrapper.find("[data-test='vuetiful-tab-list']");
73
+ expect(tabList.classes()).toEqual([
74
+ "vuetiful-tab-list",
75
+ "flex",
76
+ "flex-col",
77
+ "!rounded-br-none",
78
+ "!rounded-tr-none",
79
+ "rounded-container-token",
80
+ ]);
81
+
82
+ const tabPanels = wrapper.find("[data-test='vuetiful-tab-panels']");
83
+ expect(tabPanels.classes()).toEqual([
84
+ "vuetiful-tab-panels",
85
+ "!rounded-bl-none",
86
+ "!rounded-tl-none",
87
+ "rounded-container-token",
88
+ ]);
89
+ });
90
+ });
@@ -0,0 +1,84 @@
1
+ <script setup lang="ts">
2
+ import { TabGroup, TabList, TabPanels } from "@headlessui/vue";
3
+ import { provide } from "vue";
4
+
5
+ const props = defineProps({
6
+ hideSeparator: {
7
+ type: Boolean,
8
+ default: false,
9
+ },
10
+
11
+ vertical: {
12
+ type: Boolean,
13
+ default: false,
14
+ },
15
+
16
+ active: {
17
+ type: String,
18
+ default: "",
19
+ },
20
+ hover: {
21
+ type: String,
22
+ default: "hover:variant-ghost",
23
+ },
24
+
25
+ classPanels: {
26
+ type: String,
27
+ default: "",
28
+ },
29
+ classTabs: {
30
+ type: String,
31
+ default: "",
32
+ },
33
+ classTab: {
34
+ type: String,
35
+ default: "",
36
+ },
37
+ classSeparator: {
38
+ type: String,
39
+ default: "border border-surface-400-500-token",
40
+ },
41
+
42
+ defaultIndex: {
43
+ type: Number,
44
+ default: 0,
45
+ },
46
+ });
47
+
48
+ provide("active", props.active);
49
+ provide("hover", props.hover);
50
+ provide("vertical", props.vertical);
51
+ provide("classTab", props.classTab);
52
+ provide("hideSeparator", props.hideSeparator);
53
+ </script>
54
+
55
+ <template>
56
+ <TabGroup
57
+ as="div"
58
+ :vertical="vertical"
59
+ :defaultIndex="defaultIndex"
60
+ :class="`${vertical ? 'flex' : ''}`"
61
+ >
62
+ <TabList
63
+ data-test="vuetiful-tab-list"
64
+ :class="`vuetiful-tab-list flex ${vertical ? 'flex-col' : ''} ${
65
+ vertical ? '!rounded-br-none !rounded-tr-none' : '!rounded-bl-none !rounded-br-none'
66
+ } rounded-container-token ${classTabs}`"
67
+ >
68
+ <slot name="tabs" />
69
+ </TabList>
70
+ <div
71
+ data-test="vuetiful-tab-separator"
72
+ v-if="!hideSeparator"
73
+ :class="`${classSeparator}`"
74
+ ></div>
75
+ <TabPanels
76
+ data-test="vuetiful-tab-panels"
77
+ :class="`vuetiful-tab-panels ${
78
+ vertical ? '!rounded-bl-none !rounded-tl-none' : '!rounded-tl-none !rounded-tr-none'
79
+ } rounded-container-token ${classPanels}`"
80
+ >
81
+ <slot />
82
+ </TabPanels>
83
+ </TabGroup>
84
+ </template>
@@ -1,23 +1,31 @@
1
1
  import VDrawer from "./VDrawer.vue";
2
+ import VPreview from "./VPreview.vue";
2
3
  import VRail from "./VRail.vue";
3
4
  import VRailTile from "./VRailTile.vue";
4
5
  import VShell from "./VShell.vue";
5
- import VPreview from "./VPreview.vue";
6
+
6
7
  import VListbox from "./VListbox/VListbox.vue";
8
+ import VListboxButton from "./VListbox/VListboxButton.vue";
7
9
  import VListboxItem from "./VListbox/VListboxItem.vue";
8
10
  import VListboxItems from "./VListbox/VListboxItems.vue";
9
11
  import VListboxLabel from "./VListbox/VListboxLabel.vue";
10
- import VListboxButton from "./VListbox/VListboxButton.vue";
12
+
13
+ import VTab from "./VTabs/VTab.vue";
14
+ import VTabPanel from "./VTabs/VTabPanel.vue";
15
+ import VTabs from "./VTabs/VTabs.vue";
11
16
 
12
17
  export {
13
- VRail,
14
- VRailTile,
15
- VShell,
16
18
  VDrawer,
17
- VPreview,
18
19
  VListbox,
20
+ VListboxButton,
19
21
  VListboxItem,
20
22
  VListboxItems,
21
23
  VListboxLabel,
22
- VListboxButton,
24
+ VPreview,
25
+ VRail,
26
+ VRailTile,
27
+ VShell,
28
+ VTab,
29
+ VTabPanel,
30
+ VTabs,
23
31
  };