@dpa-id-components/dpa-shared-components 20.0.6 → 20.0.7

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.
Files changed (81) hide show
  1. package/dist/src/components/DpaMediaItem/DpaMediaItem.spec.ts +123 -0
  2. package/dist/src/components/DpaMediaItem/DpaMediaItem.stories.ts +140 -0
  3. package/dist/src/components/UiAutocomplete/UiAutocomplete.spec.ts +39 -0
  4. package/dist/src/components/UiAutocomplete/UiAutocomplete.stories.ts +46 -0
  5. package/dist/src/components/UiBadge/UiBadge.spec.ts +32 -0
  6. package/dist/src/components/UiBadge/UiBadge.stories.ts +80 -0
  7. package/dist/src/components/UiButton/UiButton.spec.ts +136 -0
  8. package/dist/src/components/UiButton/UiButton.stories.ts +57 -0
  9. package/dist/src/components/UiButtonGroup/UiButtonGroup.spec.ts +16 -0
  10. package/dist/src/components/UiButtonGroup/UiButtonGroup.stories.ts +50 -0
  11. package/dist/src/components/UiCard/UiCard.spec.ts +16 -0
  12. package/dist/src/components/UiCard/UiCard.stories.ts +30 -0
  13. package/dist/src/components/UiCheckBoxGroup/UiCheckBoxGroup.spec.ts +67 -0
  14. package/dist/src/components/UiCheckBoxGroup/UiCheckBoxGroup.stories.ts +59 -0
  15. package/dist/src/components/UiCheckbox/UiCheckbox.spec.ts +173 -0
  16. package/dist/src/components/UiCheckbox/UiCheckbox.stories.ts +99 -0
  17. package/dist/src/components/UiChip/UiChip.spec.ts +75 -0
  18. package/dist/src/components/UiChip/UiChip.stories.ts +39 -0
  19. package/dist/src/components/UiCollapseNavigation/UiCollapseNavigation.spec.ts +21 -0
  20. package/dist/src/components/UiCollapseNavigation/UiCollapseNavigation.stories.ts +66 -0
  21. package/dist/src/components/UiColorPicker/UiColorPicker.spec.ts +52 -0
  22. package/dist/src/components/UiColorPicker/UiColorPicker.stories.ts +44 -0
  23. package/dist/src/components/UiDatePicker/UiDatePicker.spec.ts +335 -0
  24. package/dist/src/components/UiDatePicker/UiDatePicker.stories.ts +273 -0
  25. package/dist/src/components/UiDialog/UiDialog.spec.ts +160 -0
  26. package/dist/src/components/UiDialog/UiDialog.stories.ts +79 -0
  27. package/dist/src/components/UiFilterBadge/UiFilterBadge.spec.ts +17 -0
  28. package/dist/src/components/UiFilterBadge/UiFilterBadge.stories.ts +44 -0
  29. package/dist/src/components/UiFilterBadgeButton/UiFilterBadgeButton.spec.ts +41 -0
  30. package/dist/src/components/UiFilterBadgeButton/UiFilterBadgeButton.stories.ts +55 -0
  31. package/dist/src/components/UiFilterButton/UiFilterButton.spec.ts +79 -0
  32. package/dist/src/components/UiFilterButton/UiFilterButton.stories.ts +88 -0
  33. package/dist/src/components/UiIcon/IconOverview.stories.vue +23 -0
  34. package/dist/src/components/UiIcon/UiIcon.spec.ts +56 -0
  35. package/dist/src/components/UiIcon/UiIcon.stories.ts +48 -0
  36. package/dist/src/components/UiIconButton/UiIconButton.spec.ts +78 -0
  37. package/dist/src/components/UiIconButton/UiIconButton.stories.ts +63 -0
  38. package/dist/src/components/UiInfoContent/UiInfoContent.spec.ts +43 -0
  39. package/dist/src/components/UiInfoContent/UiInfoContent.stories.ts +56 -0
  40. package/dist/src/components/UiInput/UiInput.spec.ts +239 -0
  41. package/dist/src/components/UiInput/UiInput.stories.ts +127 -0
  42. package/dist/src/components/UiList/UiList.spec.ts +22 -0
  43. package/dist/src/components/UiList/UiList.stories.ts +64 -0
  44. package/dist/src/components/UiListItem/UiListItem.spec.ts +99 -0
  45. package/dist/src/components/UiListItem/UiListItem.stories.ts +83 -0
  46. package/dist/src/components/UiMenu/UiMenu.spec.ts +319 -0
  47. package/dist/src/components/UiMenu/UiMenu.stories.ts +634 -0
  48. package/dist/src/components/UiOverlay/UiOverlay.spec.ts +16 -0
  49. package/dist/src/components/UiOverlay/UiOverlay.stories.ts +22 -0
  50. package/dist/src/components/UiOverlayMenu/UiOverlayMenu.spec.ts +32 -0
  51. package/dist/src/components/UiOverlayMenu/UiOverlayMenu.stories.ts +39 -0
  52. package/dist/src/components/UiRadioInputGroup/UiRadioInputGroup.spec.ts +66 -0
  53. package/dist/src/components/UiRadioInputGroup/UiRadioInputGroup.stories.ts +70 -0
  54. package/dist/src/components/UiSearchBar/UiSearchBar.spec.ts +82 -0
  55. package/dist/src/components/UiSearchBar/UiSearchBar.stories.ts +191 -0
  56. package/dist/src/components/UiSearchInput/UiSearchInput.spec.ts +45 -0
  57. package/dist/src/components/UiSearchInput/UiSearchInput.stories.ts +61 -0
  58. package/dist/src/components/UiSection/UiSection.spec.ts +49 -0
  59. package/dist/src/components/UiSection/UiSection.stories.ts +61 -0
  60. package/dist/src/components/UiSectionDivider/UiSectionDivider.spec.ts +19 -0
  61. package/dist/src/components/UiSectionDivider/UiSectionDivider.stories.ts +48 -0
  62. package/dist/src/components/UiSelect/UIiSelect.spec.ts +102 -0
  63. package/dist/src/components/UiSelect/UiSelect.stories.ts +94 -0
  64. package/dist/src/components/UiSimpleInput/UiSimpleInput.spec.ts +58 -0
  65. package/dist/src/components/UiSimpleInput/UiSimpleInput.stories.ts +53 -0
  66. package/dist/src/components/UiSkeletonBox/UiSkeletonBox.spec.ts +15 -0
  67. package/dist/src/components/UiSkeletonBox/UiSkeletonBox.stories.ts +33 -0
  68. package/dist/src/components/UiSnackbar/UiSnackbar.spec.ts +63 -0
  69. package/dist/src/components/UiSnackbar/UiSnackbar.stories.ts +65 -0
  70. package/dist/src/components/UiSpinner/UiSpinner.spec.ts +30 -0
  71. package/dist/src/components/UiSpinner/UiSpinner.stories.ts +48 -0
  72. package/dist/src/components/UiTextButton/UiTextButton.spec.ts +99 -0
  73. package/dist/src/components/UiTextButton/UiTextButton.stories.ts +60 -0
  74. package/dist/src/components/UiToggleButton/UiToggleButton.spec.ts +89 -0
  75. package/dist/src/components/UiToggleButton/UiToggleButton.stories.ts +102 -0
  76. package/dist/src/components/UiTooltip/UiTooltip.spec.ts +139 -0
  77. package/dist/src/components/UiTooltip/UiTooltip.stories.ts +107 -0
  78. package/dist/src/compositions/useBreakpoints/UseBreakpoints.stories.ts +23 -0
  79. package/dist/src/compositions/useBreakpoints/UseBreakpoints.stories.vue +12 -0
  80. package/dist/src/utils/index.spec.ts +12 -0
  81. package/package.json +5 -4
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from "@storybook/vue3-vite";
2
+
3
+ import UiSection from "../UiSection/UiSection.vue";
4
+ import UiSectionDivider from "./UiSectionDivider.vue";
5
+
6
+ const meta = {
7
+ title: "Ui/UiSectionDivider",
8
+ component: UiSectionDivider,
9
+ subcomponents: { UiSection },
10
+ argTypes: {
11
+ size: {
12
+ control: "select",
13
+ options: ["large", "small"],
14
+ },
15
+ },
16
+ args: {
17
+ size: "large",
18
+ },
19
+ tags: ["deprecated"],
20
+ } satisfies Meta<typeof UiSectionDivider>;
21
+
22
+ export default meta;
23
+ type Story = StoryObj<typeof meta>;
24
+
25
+ export const Default: Story = {
26
+ render: (args) => ({
27
+ setup() {
28
+ return { args };
29
+ },
30
+ components: { UiSectionDivider },
31
+ template: "<UiSectionDivider v-bind='args'>Slot</UiSectionDivider>",
32
+ }),
33
+ };
34
+
35
+ export const WithSection: Story = {
36
+ render: (args) => ({
37
+ setup() {
38
+ return { args };
39
+ },
40
+ components: { UiSectionDivider, UiSection },
41
+ template:
42
+ "<UiSection>Section 1</UiSection>" +
43
+ "<UiSectionDivider v-bind='args'></UiSectionDivider>" +
44
+ "<UiSection>Section 2</UiSection>" +
45
+ "<UiSectionDivider v-bind='args'>Slot4</UiSectionDivider>" +
46
+ "<UiSection>Section 3</UiSection>",
47
+ }),
48
+ };
@@ -0,0 +1,102 @@
1
+ import { type ComponentMountingOptions, mount } from "@vue/test-utils";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import UiSelect from "./UiSelect.vue";
5
+
6
+ function createWrapper(
7
+ options: ComponentMountingOptions<typeof UiSelect> = {},
8
+ ) {
9
+ return mount(UiSelect, options);
10
+ }
11
+
12
+ describe("UiSelect", () => {
13
+ it("renders attributes on correct element", () => {
14
+ const wrapper = createWrapper({
15
+ props: {
16
+ id: "id",
17
+ class: "class",
18
+ name: "name",
19
+ modelValue: "value",
20
+ placeholder: "placeholder",
21
+ required: "required",
22
+ disabled: true,
23
+ "aria-invalid": "true",
24
+ "aria-errormessage": "message",
25
+ },
26
+ });
27
+
28
+ const root = wrapper.find(":first-child");
29
+ expect(root.element.classList.contains("class")).toBe(true);
30
+
31
+ const select = wrapper.find("select");
32
+ expect(select.element.classList.contains("class")).toBe(false);
33
+ expect(select.element.getAttribute("id")).toBe("id");
34
+ expect(select.element.getAttribute("name")).toBe("name");
35
+ expect(select.element.hasAttribute("required")).toBe(true);
36
+ expect(select.element.hasAttribute("disabled")).toBe(true);
37
+ expect(select.element.getAttribute("aria-invalid")).toBe("true");
38
+ expect(select.element.getAttribute("aria-errormessage")).toBe("message");
39
+ });
40
+
41
+ it("implements working v-model interface", async () => {
42
+ const wrapper = createWrapper({
43
+ slots: {
44
+ default: { template: "Options" },
45
+ options: {
46
+ template: `
47
+ <option value="primary">Primary</option>
48
+ <option value="secondary">Secondary</option>
49
+ <option value="tertiary">Tertiary</option>
50
+ `,
51
+ },
52
+ },
53
+ props: {
54
+ modelValue: "primary",
55
+ },
56
+ });
57
+ const select = wrapper.find("select");
58
+ expect(select.element.value).toBe("primary");
59
+
60
+ let lastEvent = (wrapper.emitted<string>("update:modelValue") ?? []).at(-1);
61
+ expect(lastEvent).toEqual(undefined);
62
+
63
+ await select.setValue("secondary");
64
+ expect(select.element.value).toBe("secondary");
65
+ lastEvent = (wrapper.emitted<string>("update:modelValue") ?? []).at(-1);
66
+ expect(lastEvent).toEqual(["secondary"]);
67
+
68
+ await select.setValue("tertiary");
69
+ expect(select.element.value).toBe("tertiary");
70
+ lastEvent = (wrapper.emitted<string>("update:modelValue") ?? []).at(-1);
71
+ expect(lastEvent).toEqual(["tertiary"]);
72
+ });
73
+
74
+ it("works without v-model", async () => {
75
+ const wrapper = createWrapper({
76
+ slots: {
77
+ default: { template: "Options" },
78
+ options: {
79
+ template: `
80
+ <option value="">None</option>
81
+ <option value="primary">Primary</option>
82
+ <option value="secondary">Secondary</option>
83
+ `,
84
+ },
85
+ },
86
+ });
87
+ const select = wrapper.find("select");
88
+ expect(select.element.value).toBe("");
89
+ let lastEvent = (wrapper.emitted<string>("update:modelValue") ?? []).at(-1);
90
+ expect(lastEvent).toEqual(undefined);
91
+
92
+ await select.setValue("primary");
93
+ expect(select.element.value).toBe("primary");
94
+ lastEvent = (wrapper.emitted<string>("update:modelValue") ?? []).at(-1);
95
+ expect(lastEvent).toEqual(["primary"]);
96
+
97
+ await select.setValue("secondary");
98
+ expect(select.element.value).toBe("secondary");
99
+ lastEvent = (wrapper.emitted<string>("update:modelValue") ?? []).at(-1);
100
+ expect(lastEvent).toEqual(["secondary"]);
101
+ });
102
+ });
@@ -0,0 +1,94 @@
1
+ import type { Meta, StoryObj } from "@storybook/vue3-vite";
2
+
3
+ import UiSelect from "./UiSelect.vue";
4
+
5
+ const options: string[] = [
6
+ "backlog",
7
+ "to-do",
8
+ "progress",
9
+ "code-review",
10
+ "deployment",
11
+ "approval",
12
+ "done",
13
+ ];
14
+
15
+ const meta = {
16
+ title: "Ui/UiSelect",
17
+ component: UiSelect,
18
+ args: {
19
+ // Attributes
20
+ // @ts-ignore Storybook doesn't know that **any** component can receive arbitrary attributes and enforces this on the type level.
21
+ name: "status",
22
+ disabled: false,
23
+
24
+ // Props
25
+ modelValue: "progress",
26
+
27
+ // Slots
28
+ default: "Status",
29
+ options,
30
+ },
31
+ argTypes: {
32
+ // Attributes
33
+ // @ts-ignore Storybook doesn't know that **any** component can receive arbitrary attributes and enforces this on the type level.
34
+ name: { control: "text" },
35
+ disabled: { control: "boolean" },
36
+
37
+ // Props
38
+ modelValue: { control: "select", options },
39
+ },
40
+ } satisfies Meta<typeof UiSelect>;
41
+
42
+ export default meta;
43
+ type Story = StoryObj<typeof UiSelect>;
44
+
45
+ export const Default: Story = {
46
+ render: (args) => ({
47
+ setup() {
48
+ return { args };
49
+ },
50
+ components: { UiSelect },
51
+ template: `
52
+ <UiSelect
53
+ v-model="args.modelValue"
54
+ v-bind="args"
55
+ >
56
+ {{ args.default }}
57
+
58
+ <template #options>
59
+ <option
60
+ v-for="(option, index) in args.options"
61
+ :key="index"
62
+ :value="option"
63
+ >
64
+ {{ option }}
65
+ </option>
66
+ </template>
67
+
68
+ <template v-if="args.errors" #errors>
69
+ {{ args.errors }}
70
+ </template>
71
+ </UiSelect>
72
+ `,
73
+ }),
74
+ };
75
+
76
+ export const WithoutInitialValue: Story = {
77
+ render: Default.render,
78
+ args: {
79
+ ...meta.args,
80
+
81
+ // Props
82
+ modelValue: undefined,
83
+
84
+ // Slots
85
+ options: options.concat(""),
86
+ },
87
+ };
88
+
89
+ export const Errors: Story = {
90
+ args: {
91
+ errors: "This field is required.",
92
+ },
93
+ ...Default,
94
+ };
@@ -0,0 +1,58 @@
1
+ import { type ComponentMountingOptions, mount } from "@vue/test-utils";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import UiIconSearchInput from "./UiSimpleInput.vue";
5
+
6
+ function createWrapper(
7
+ options: ComponentMountingOptions<typeof UiIconSearchInput> = {},
8
+ ) {
9
+ return mount(UiIconSearchInput, {
10
+ ...options,
11
+ });
12
+ }
13
+
14
+ describe("UiSimpleInput", () => {
15
+ it("renders attributes on correct element", () => {
16
+ const wrapper = createWrapper({
17
+ props: {
18
+ id: "id",
19
+ class: "testClass",
20
+ "data-testid": "testId",
21
+ },
22
+ });
23
+
24
+ const root = wrapper.find(":first-child");
25
+ expect(root.element.classList.contains("testClass")).toBe(true);
26
+ expect(root.element.getAttribute("data-testid")).not.toBe("testId");
27
+
28
+ const input = wrapper.find("input");
29
+ expect(input.element.classList.contains("testClass")).toBe(false);
30
+ expect(input.element.getAttribute("data-testid")).toBe("testId");
31
+ expect(input.element.getAttribute("id")).toBe("id");
32
+ });
33
+
34
+ it("has initial value", async () => {
35
+ const wrapper = createWrapper({
36
+ props: {
37
+ value: "a",
38
+ },
39
+ });
40
+
41
+ const input = wrapper.find("input");
42
+ expect(input.element.value).toBe("a");
43
+
44
+ await wrapper.setProps({ value: "b" });
45
+ expect(input.element.value).toBe("b");
46
+ });
47
+
48
+ it("emits search input event", async () => {
49
+ const wrapper = createWrapper({
50
+ props: {
51
+ placeholder: "Suchen",
52
+ },
53
+ });
54
+
55
+ await wrapper.find("input").setValue("Hello World");
56
+ expect(wrapper.emitted("input")).toEqual([["Hello World"]]);
57
+ });
58
+ });
@@ -0,0 +1,53 @@
1
+ import type { Meta, StoryObj } from "@storybook/vue3-vite";
2
+ import { action } from "storybook/actions";
3
+
4
+ import UiSimpleInput from "./UiSimpleInput.vue";
5
+
6
+ const meta = {
7
+ title: "Ui/UiSimpleInput",
8
+ component: UiSimpleInput,
9
+ argTypes: {
10
+ value: {
11
+ control: "text",
12
+ },
13
+ placeholder: {
14
+ control: "text",
15
+ },
16
+ size: {
17
+ control: "select",
18
+ options: ["xs", "small", "medium", "large", "xl"],
19
+ },
20
+ hasIcon: {
21
+ control: "boolean",
22
+ },
23
+ autofocus: {
24
+ control: "boolean",
25
+ },
26
+ },
27
+ args: {
28
+ value: "",
29
+ placeholder: "Suchen",
30
+ size: "small",
31
+ hasIcon: true,
32
+ autofocus: true,
33
+ },
34
+ render: (args) => ({
35
+ setup() {
36
+ return { args };
37
+ },
38
+ components: { UiSimpleInput },
39
+ template: `
40
+ <div class="p-4 bg-white">
41
+ <UiSimpleInput v-bind="args" @input="input" />
42
+ </div>
43
+ `,
44
+ methods: {
45
+ input: action("input"),
46
+ },
47
+ }),
48
+ } satisfies Meta<typeof UiSimpleInput>;
49
+
50
+ export default meta;
51
+ type Story = StoryObj<typeof meta>;
52
+
53
+ export const Default: Story = {};
@@ -0,0 +1,15 @@
1
+ import { mount } from "@vue/test-utils";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import UiSkeletonBox from "./UiSkeletonBox.vue";
5
+
6
+ describe("UiSkeletonBox", () => {
7
+ const wrapper = mount(UiSkeletonBox);
8
+
9
+ it("renders default", () => {
10
+ expect(wrapper.classes("inline-block")).toBe(true);
11
+ expect(wrapper.classes("animate-pulse")).toBe(true);
12
+ expect(wrapper.classes("rounded-sm")).toBe(true);
13
+ expect(wrapper.classes("bg-gray-200")).toBe(true);
14
+ });
15
+ });
@@ -0,0 +1,33 @@
1
+ import type { Meta, StoryObj } from "@storybook/vue3-vite";
2
+
3
+ import UiSkeletonBox from "./UiSkeletonBox.vue";
4
+
5
+ const meta = {
6
+ title: "Ui/UiSkeletonBox",
7
+ component: UiSkeletonBox,
8
+ argTypes: {
9
+ maxWidth: { type: "number" },
10
+ minWidth: { type: "number" },
11
+ dynamicSize: { type: "boolean" },
12
+ },
13
+ args: {
14
+ maxWidth: 100,
15
+ minWidth: 80,
16
+ dynamicSize: true,
17
+ },
18
+ parameters: {
19
+ backgrounds: { default: "white" },
20
+ },
21
+ render: (args) => ({
22
+ setup() {
23
+ return { args };
24
+ },
25
+ components: { UiSkeletonBox },
26
+ template: "<UiSkeletonBox v-bind='args'></UiSkeletonBox>",
27
+ }),
28
+ } satisfies Meta<typeof UiSkeletonBox>;
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof meta>;
32
+
33
+ export const Default: Story = {};
@@ -0,0 +1,63 @@
1
+ import { mount } from "@vue/test-utils";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import UiIcon from "../UiIcon/UiIcon.vue";
5
+ import UiSnackbar from "./UiSnackbar.vue";
6
+
7
+ describe("UiSnackbar", () => {
8
+ it("displays a text message via the default slot", () => {
9
+ const wrapper = mount(UiSnackbar, {
10
+ slots: {
11
+ default: "Hello, from snackbar",
12
+ },
13
+ props: {
14
+ isShown: true,
15
+ },
16
+ });
17
+
18
+ expect(wrapper.text()).toBe("Hello, from snackbar");
19
+ });
20
+
21
+ it("Is not visible when props don't say so", () => {
22
+ const wrapper = mount(UiSnackbar, {
23
+ slots: {
24
+ default: "Hello, from snackbar",
25
+ },
26
+ props: {
27
+ isShown: false,
28
+ },
29
+ });
30
+
31
+ expect(wrapper.find("div").exists()).toBe(false);
32
+ });
33
+
34
+ it("displays an SVG icon via the icon slot", () => {
35
+ const wrapper = mount(UiSnackbar, {
36
+ slots: {
37
+ default: "Hello, from snackbar",
38
+ iconName: "close",
39
+ },
40
+ props: {
41
+ isShown: true,
42
+ },
43
+ });
44
+
45
+ expect(wrapper.findComponent(UiIcon)).toBeTruthy();
46
+ });
47
+
48
+ it("has an action button via the action slot", () => {
49
+ const wrapper = mount(UiSnackbar, {
50
+ slots: {
51
+ default: "Hello, from snackbar",
52
+ action: "click me",
53
+ },
54
+ props: {
55
+ isShown: true,
56
+ },
57
+ });
58
+ const actionButton = wrapper.find("button");
59
+ actionButton.trigger("click");
60
+
61
+ expect(wrapper.emitted()["action-click"]).toBeTruthy();
62
+ });
63
+ });
@@ -0,0 +1,65 @@
1
+ import type { Meta, StoryObj } from "@storybook/vue3-vite";
2
+ import { action } from "storybook/actions";
3
+ import { ref } from "vue";
4
+
5
+ import { icons } from "../UiIcon/icons.js";
6
+ import UiSnackbar from "./UiSnackbar.vue";
7
+
8
+ const meta = {
9
+ title: "Ui/UiSnackbar",
10
+ component: UiSnackbar,
11
+ argTypes: {
12
+ position: {
13
+ control: "select",
14
+ options: ["left", "right"],
15
+ },
16
+ isShown: {
17
+ control: "boolean",
18
+ },
19
+ iconName: {
20
+ control: "select",
21
+ options: [null, ...Object.keys(icons)],
22
+ },
23
+ iconSize: {
24
+ control: "select",
25
+ options: ["small", "medium", "large"],
26
+ },
27
+ type: {
28
+ control: "select",
29
+ options: ["info", "error"],
30
+ },
31
+ },
32
+ args: {
33
+ position: "left",
34
+ isShown: true,
35
+ iconName: null,
36
+ iconSize: "medium",
37
+ type: "info",
38
+ },
39
+ render: (args) => ({
40
+ setup() {
41
+ const isVisible = ref(args.isShown);
42
+
43
+ const toggle = () => {
44
+ isVisible.value = !isVisible.value;
45
+ };
46
+ return { args, isVisible, toggle };
47
+ },
48
+ components: { UiSnackbar },
49
+ template: `
50
+ <div>
51
+ <button @click="toggle">toggle snackbar</button>
52
+ <UiSnackbar v-bind="args" :is-shown="isVisible" @action-click="action" @input="input">
53
+ This is a message
54
+ <template #action>Action</template>
55
+ </UiSnackbar>
56
+ </div>
57
+ `,
58
+ methods: { input: action("input"), action: action("action") },
59
+ }),
60
+ } satisfies Meta<typeof UiSnackbar>;
61
+
62
+ export default meta;
63
+ type Story = StoryObj<typeof meta>;
64
+
65
+ export const Default: Story = {};
@@ -0,0 +1,30 @@
1
+ import { mount } from "@vue/test-utils";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import UiIcon from "../UiIcon/UiIcon.vue";
5
+ import UiSpinner from "./UiSpinner.vue";
6
+
7
+ describe("UiSpinner", () => {
8
+ const wrapper = mount(UiSpinner, {});
9
+
10
+ it("renders default", () => {
11
+ expect(wrapper.exists()).toBe(true);
12
+ expect(wrapper.findComponent(UiIcon).exists()).toBe(true);
13
+ expect(wrapper.classes("text-blue-default")).toBe(true);
14
+ });
15
+
16
+ it("renders bubbles variant", async () => {
17
+ await wrapper.setProps({ variant: "bubbles" });
18
+ expect(wrapper.find("div").exists()).toBe(true);
19
+ });
20
+
21
+ it("renders green color class", async () => {
22
+ await wrapper.setProps({ color: "green" });
23
+ expect(wrapper.classes("text-green-primary")).toBe(true);
24
+ });
25
+
26
+ it("renders white color class", async () => {
27
+ await wrapper.setProps({ color: "white" });
28
+ expect(wrapper.classes("text-white")).toBe(true);
29
+ });
30
+ });
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from "@storybook/vue3-vite";
2
+
3
+ import UiSpinner from "./UiSpinner.vue";
4
+
5
+ const meta = {
6
+ title: "UI/UiSpinner",
7
+ component: UiSpinner,
8
+ argTypes: {
9
+ variant: {
10
+ control: { type: "select" },
11
+ options: ["spinner", "bubbles"],
12
+ },
13
+ color: {
14
+ control: { type: "select" },
15
+ options: ["blue", "white", "green"],
16
+ },
17
+ },
18
+ args: {
19
+ variant: "spinner",
20
+ color: "blue",
21
+ },
22
+ render: (args) => ({
23
+ components: { UiSpinner },
24
+ setup() {
25
+ return { args };
26
+ },
27
+ template: '<UiSpinner v-bind="args" ></UiSpinner>',
28
+ }),
29
+ } satisfies Meta<typeof UiSpinner>;
30
+
31
+ export default meta;
32
+ type Story = StoryObj<typeof meta>;
33
+
34
+ export const Default: Story = {};
35
+
36
+ export const WithGreenSpinner: Story = {
37
+ args: {
38
+ variant: "spinner",
39
+ color: "green",
40
+ },
41
+ };
42
+
43
+ export const WithBlueBubbles: Story = {
44
+ args: {
45
+ variant: "bubbles",
46
+ color: "blue",
47
+ },
48
+ };