vueless 1.3.6-beta.1 → 1.3.6-beta.3
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/components.d.ts +1 -0
- package/components.ts +1 -0
- package/constants.d.ts +1 -0
- package/constants.js +1 -0
- package/package.json +2 -2
- package/ui.container-grid/UGrid.vue +39 -0
- package/ui.container-grid/config.ts +123 -0
- package/ui.container-grid/constants.ts +5 -0
- package/ui.container-grid/storybook/docs.mdx +17 -0
- package/ui.container-grid/storybook/stories.ts +246 -0
- package/ui.container-grid/types.ts +91 -0
- package/ui.form-calendar/tests/UCalendar.test.ts +113 -0
- package/ui.form-date-picker-range/tests/UDatePickerRange.test.ts +114 -0
package/components.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export { default as UBadge } from "./ui.text-badge/UBadge.vue";
|
|
|
41
41
|
export { default as UDivider } from "./ui.container-divider/UDivider.vue";
|
|
42
42
|
export { default as UCol } from "./ui.container-col/UCol.vue";
|
|
43
43
|
export { default as URow } from "./ui.container-row/URow.vue";
|
|
44
|
+
export { default as UGrid } from "./ui.container-grid/UGrid.vue";
|
|
44
45
|
export { default as UGroup } from "./ui.container-group/UGroup.vue";
|
|
45
46
|
export { default as UGroups } from "./ui.container-groups/UGroups.vue";
|
|
46
47
|
export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
|
package/components.ts
CHANGED
|
@@ -41,6 +41,7 @@ export { default as UBadge } from "./ui.text-badge/UBadge.vue";
|
|
|
41
41
|
export { default as UDivider } from "./ui.container-divider/UDivider.vue";
|
|
42
42
|
export { default as UCol } from "./ui.container-col/UCol.vue";
|
|
43
43
|
export { default as URow } from "./ui.container-row/URow.vue";
|
|
44
|
+
export { default as UGrid } from "./ui.container-grid/UGrid.vue";
|
|
44
45
|
export { default as UGroup } from "./ui.container-group/UGroup.vue";
|
|
45
46
|
export { default as UGroups } from "./ui.container-groups/UGroups.vue";
|
|
46
47
|
export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
|
package/constants.d.ts
CHANGED
package/constants.js
CHANGED
|
@@ -290,6 +290,7 @@ export const COMPONENTS = {
|
|
|
290
290
|
UDivider: "ui.container-divider",
|
|
291
291
|
UCol: "ui.container-col",
|
|
292
292
|
URow: "ui.container-row",
|
|
293
|
+
UGrid: "ui.container-grid",
|
|
293
294
|
UGroup: "ui.container-group",
|
|
294
295
|
UGroups: "ui.container-groups",
|
|
295
296
|
UAccordion: "ui.container-accordion",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "1.3.6-beta.
|
|
3
|
+
"version": "1.3.6-beta.3",
|
|
4
4
|
"description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
|
|
5
5
|
"author": "Johnny Grid <hello@vueless.com> (https://vueless.com)",
|
|
6
6
|
"homepage": "https://vueless.com",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"@vue/eslint-config-typescript": "^14.6.0",
|
|
58
58
|
"@vue/test-utils": "^2.4.6",
|
|
59
59
|
"@vue/tsconfig": "^0.7.0",
|
|
60
|
-
"@vueless/storybook": "^1.3.
|
|
60
|
+
"@vueless/storybook": "^1.3.8",
|
|
61
61
|
"eslint": "^9.32.0",
|
|
62
62
|
"eslint-plugin-storybook": "^10.0.2",
|
|
63
63
|
"eslint-plugin-vue": "^10.3.0",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useTemplateRef } from "vue";
|
|
3
|
+
import { useUI } from "../composables/useUI";
|
|
4
|
+
import { getDefaults } from "../utils/ui";
|
|
5
|
+
|
|
6
|
+
import { COMPONENT_NAME } from "./constants";
|
|
7
|
+
import defaultConfig from "./config";
|
|
8
|
+
|
|
9
|
+
import type { Props, Config } from "./types";
|
|
10
|
+
|
|
11
|
+
defineOptions({ inheritAttrs: false });
|
|
12
|
+
|
|
13
|
+
withDefaults(defineProps<Props>(), {
|
|
14
|
+
...getDefaults<Props, Config>(defaultConfig, COMPONENT_NAME),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const wrapperRef = useTemplateRef<HTMLElement>("wrapper");
|
|
18
|
+
|
|
19
|
+
defineExpose({
|
|
20
|
+
/**
|
|
21
|
+
* A reference to the component's wrapper element for direct DOM manipulation.
|
|
22
|
+
* @property {HTMLElement}
|
|
23
|
+
*/
|
|
24
|
+
wrapperRef,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get element / nested component attributes for each config token ✨
|
|
29
|
+
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
30
|
+
*/
|
|
31
|
+
const { getDataTest, wrapperAttrs } = useUI<Config>(defaultConfig);
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<component :is="tag" ref="wrapper" v-bind="wrapperAttrs" :data-test="getDataTest()">
|
|
36
|
+
<!-- @slot Use it to add grid items. -->
|
|
37
|
+
<slot />
|
|
38
|
+
</component>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export default /*tw*/ {
|
|
2
|
+
wrapper: {
|
|
3
|
+
base: "grid",
|
|
4
|
+
variants: {
|
|
5
|
+
cols: {
|
|
6
|
+
"1": "grid-cols-1",
|
|
7
|
+
"2": "grid-cols-2",
|
|
8
|
+
"3": "grid-cols-3",
|
|
9
|
+
"4": "grid-cols-4",
|
|
10
|
+
"5": "grid-cols-5",
|
|
11
|
+
"6": "grid-cols-6",
|
|
12
|
+
"7": "grid-cols-7",
|
|
13
|
+
"8": "grid-cols-8",
|
|
14
|
+
"9": "grid-cols-9",
|
|
15
|
+
"10": "grid-cols-10",
|
|
16
|
+
"11": "grid-cols-11",
|
|
17
|
+
"12": "grid-cols-12",
|
|
18
|
+
},
|
|
19
|
+
rows: {
|
|
20
|
+
"1": "grid-rows-1",
|
|
21
|
+
"2": "grid-rows-2",
|
|
22
|
+
"3": "grid-rows-3",
|
|
23
|
+
"4": "grid-rows-4",
|
|
24
|
+
"5": "grid-rows-5",
|
|
25
|
+
"6": "grid-rows-6",
|
|
26
|
+
"7": "grid-rows-7",
|
|
27
|
+
"8": "grid-rows-8",
|
|
28
|
+
"9": "grid-rows-9",
|
|
29
|
+
"10": "grid-rows-10",
|
|
30
|
+
"11": "grid-rows-11",
|
|
31
|
+
"12": "grid-rows-12",
|
|
32
|
+
},
|
|
33
|
+
gap: {
|
|
34
|
+
none: "gap-0",
|
|
35
|
+
"2xs": "gap-1",
|
|
36
|
+
xs: "gap-2",
|
|
37
|
+
sm: "gap-3",
|
|
38
|
+
md: "gap-4",
|
|
39
|
+
lg: "gap-5",
|
|
40
|
+
xl: "gap-6",
|
|
41
|
+
"2xl": "gap-8",
|
|
42
|
+
},
|
|
43
|
+
rowGap: {
|
|
44
|
+
none: "gap-y-0",
|
|
45
|
+
"2xs": "gap-y-1",
|
|
46
|
+
xs: "gap-y-2",
|
|
47
|
+
sm: "gap-y-3",
|
|
48
|
+
md: "gap-y-4",
|
|
49
|
+
lg: "gap-y-5",
|
|
50
|
+
xl: "gap-y-6",
|
|
51
|
+
"2xl": "gap-y-8",
|
|
52
|
+
},
|
|
53
|
+
colGap: {
|
|
54
|
+
none: "gap-x-0",
|
|
55
|
+
"2xs": "gap-x-1",
|
|
56
|
+
xs: "gap-x-2",
|
|
57
|
+
sm: "gap-x-3",
|
|
58
|
+
md: "gap-x-4",
|
|
59
|
+
lg: "gap-x-5",
|
|
60
|
+
xl: "gap-x-6",
|
|
61
|
+
"2xl": "gap-x-8",
|
|
62
|
+
},
|
|
63
|
+
align: {
|
|
64
|
+
start: "items-start",
|
|
65
|
+
end: "items-end",
|
|
66
|
+
center: "items-center",
|
|
67
|
+
stretch: "items-stretch",
|
|
68
|
+
baseline: "items-baseline",
|
|
69
|
+
normal: "items-normal",
|
|
70
|
+
},
|
|
71
|
+
content: {
|
|
72
|
+
start: "content-start",
|
|
73
|
+
end: "content-end",
|
|
74
|
+
center: "content-center",
|
|
75
|
+
around: "content-around",
|
|
76
|
+
evenly: "content-evenly",
|
|
77
|
+
between: "content-between",
|
|
78
|
+
normal: "content-normal",
|
|
79
|
+
stretch: "content-stretch",
|
|
80
|
+
baseline: "content-baseline",
|
|
81
|
+
},
|
|
82
|
+
justify: {
|
|
83
|
+
start: "justify-items-start",
|
|
84
|
+
end: "justify-items-end",
|
|
85
|
+
"end-safe": "justify-items-end-safe",
|
|
86
|
+
center: "justify-items-center",
|
|
87
|
+
"center-safe": "justify-items-center-safe",
|
|
88
|
+
stretch: "justify-items-stretch",
|
|
89
|
+
normal: "justify-items-normal",
|
|
90
|
+
},
|
|
91
|
+
placeContent: {
|
|
92
|
+
start: "place-content-start",
|
|
93
|
+
end: "place-content-end",
|
|
94
|
+
"end-safe": "place-content-end-safe",
|
|
95
|
+
center: "place-content-center",
|
|
96
|
+
"center-safe": "place-content-center-safe",
|
|
97
|
+
around: "place-content-around",
|
|
98
|
+
evenly: "place-content-evenly",
|
|
99
|
+
between: "place-content-between",
|
|
100
|
+
stretch: "place-content-stretch",
|
|
101
|
+
baseline: "place-content-baseline",
|
|
102
|
+
},
|
|
103
|
+
placeItems: {
|
|
104
|
+
start: "place-items-start",
|
|
105
|
+
end: "place-items-end",
|
|
106
|
+
"end-safe": "place-items-end-safe",
|
|
107
|
+
center: "place-items-center",
|
|
108
|
+
"center-safe": "place-items-center-safe",
|
|
109
|
+
stretch: "place-items-stretch",
|
|
110
|
+
baseline: "place-items-baseline",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
defaults: {
|
|
115
|
+
gap: "md",
|
|
116
|
+
align: "normal",
|
|
117
|
+
content: "normal",
|
|
118
|
+
justify: "normal",
|
|
119
|
+
placeContent: "start",
|
|
120
|
+
placeItems: "start",
|
|
121
|
+
tag: "div",
|
|
122
|
+
},
|
|
123
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/addon-docs/blocks";
|
|
2
|
+
import { getSource } from "../../utils/storybook";
|
|
3
|
+
|
|
4
|
+
import * as stories from "./stories";
|
|
5
|
+
import defaultConfig from "../config?raw"
|
|
6
|
+
|
|
7
|
+
<Meta of={stories} />
|
|
8
|
+
<Title of={stories} />
|
|
9
|
+
<Subtitle of={stories} />
|
|
10
|
+
<Description of={stories} />
|
|
11
|
+
<Primary of={stories} />
|
|
12
|
+
<Controls of={stories.Default} />
|
|
13
|
+
<Stories of={stories} />
|
|
14
|
+
|
|
15
|
+
## Default config
|
|
16
|
+
<Source code={getSource(defaultConfig)} language="jsx" dark />
|
|
17
|
+
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getArgs,
|
|
3
|
+
getArgTypes,
|
|
4
|
+
getSlotNames,
|
|
5
|
+
getSlotsFragment,
|
|
6
|
+
getDocsDescription,
|
|
7
|
+
} from "../../utils/storybook";
|
|
8
|
+
|
|
9
|
+
import UGrid from "../UGrid.vue";
|
|
10
|
+
import UText from "../../ui.text-block/UText.vue";
|
|
11
|
+
import UPlaceholder from "../../ui.container-placeholder/UPlaceholder.vue";
|
|
12
|
+
import UCol from "../../ui.container-col/UCol.vue";
|
|
13
|
+
|
|
14
|
+
import type { Meta, StoryFn } from "@storybook/vue3-vite";
|
|
15
|
+
import type { Props } from "../types";
|
|
16
|
+
|
|
17
|
+
interface UGridArgs extends Props {
|
|
18
|
+
slotTemplate?: string;
|
|
19
|
+
enum:
|
|
20
|
+
| "gap"
|
|
21
|
+
| "rowGap"
|
|
22
|
+
| "colGap"
|
|
23
|
+
| "align"
|
|
24
|
+
| "content"
|
|
25
|
+
| "justify"
|
|
26
|
+
| "placeContent"
|
|
27
|
+
| "placeItems";
|
|
28
|
+
class?: string;
|
|
29
|
+
itemClass?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default {
|
|
33
|
+
id: "5025",
|
|
34
|
+
title: "Containers / Grid",
|
|
35
|
+
component: UGrid,
|
|
36
|
+
argTypes: {
|
|
37
|
+
...getArgTypes(UGrid.__name),
|
|
38
|
+
},
|
|
39
|
+
parameters: {
|
|
40
|
+
docs: {
|
|
41
|
+
...getDocsDescription(UGrid.__name),
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
} as Meta;
|
|
45
|
+
|
|
46
|
+
const defaultTemplate = `
|
|
47
|
+
<UPlaceholder label="1" class="min-h-10 col-span-1 row-span-3" />
|
|
48
|
+
<UPlaceholder label="2" class="min-h-10 col-span-3 row-span-1" />
|
|
49
|
+
<UPlaceholder label="3" class="min-h-10 col-span-3 row-span-2" />
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const DefaultTemplate: StoryFn<UGridArgs> = (args: UGridArgs) => ({
|
|
53
|
+
components: { UGrid, UPlaceholder },
|
|
54
|
+
setup: () => ({ args, slots: getSlotNames(UGrid.__name) }),
|
|
55
|
+
template: `
|
|
56
|
+
<UGrid v-bind="args">
|
|
57
|
+
${args.slotTemplate || getSlotsFragment(defaultTemplate)}
|
|
58
|
+
</UGrid>
|
|
59
|
+
`,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const EnumTemplate: StoryFn<UGridArgs> = (args: UGridArgs, { argTypes }) => ({
|
|
63
|
+
components: { UGrid, UText, UPlaceholder, UCol },
|
|
64
|
+
setup: () => ({ args, argTypes, getArgs }),
|
|
65
|
+
template: `
|
|
66
|
+
<UCol block gap="lg">
|
|
67
|
+
<UGrid
|
|
68
|
+
v-for="option in argTypes?.[args.enum]?.options"
|
|
69
|
+
v-bind="getArgs(args, option)"
|
|
70
|
+
:key="option"
|
|
71
|
+
cols="3"
|
|
72
|
+
class="border border-primary border-dashed rounded p-4 w-full"
|
|
73
|
+
:class="args.class"
|
|
74
|
+
>
|
|
75
|
+
<UPlaceholder :label="option" class="h-auto" :class="args.itemClass" />
|
|
76
|
+
<UPlaceholder :label="option" class="h-auto" :class="args.itemClass" />
|
|
77
|
+
<UPlaceholder :label="option" class="h-auto" :class="args.itemClass" />
|
|
78
|
+
<UPlaceholder :label="option" class="h-auto" :class="args.itemClass" />
|
|
79
|
+
<UPlaceholder :label="option" class="h-auto" :class="args.itemClass" />
|
|
80
|
+
<UPlaceholder :label="option" class="h-auto" :class="args.itemClass" />
|
|
81
|
+
</UGrid>
|
|
82
|
+
</UCol>
|
|
83
|
+
`,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export const Default = DefaultTemplate.bind({});
|
|
87
|
+
Default.args = { cols: "4", rows: "3", gap: "md" };
|
|
88
|
+
|
|
89
|
+
export const Gap = EnumTemplate.bind({});
|
|
90
|
+
Gap.args = { enum: "gap" };
|
|
91
|
+
Gap.parameters = {
|
|
92
|
+
docs: {
|
|
93
|
+
description: {
|
|
94
|
+
story: "Gap between items.",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const RowGap = EnumTemplate.bind({});
|
|
100
|
+
RowGap.args = { enum: "rowGap" };
|
|
101
|
+
Gap.parameters = {
|
|
102
|
+
docs: {
|
|
103
|
+
description: {
|
|
104
|
+
story: "Vertical gap override.",
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const ColGap = EnumTemplate.bind({});
|
|
110
|
+
ColGap.args = { enum: "colGap" };
|
|
111
|
+
Gap.parameters = {
|
|
112
|
+
docs: {
|
|
113
|
+
description: {
|
|
114
|
+
story: "Horizontal gap override.",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const Justify = EnumTemplate.bind({});
|
|
120
|
+
Justify.args = { enum: "justify", itemClass: "w-auto min-w-20" };
|
|
121
|
+
Justify.parameters = {
|
|
122
|
+
docs: {
|
|
123
|
+
description: {
|
|
124
|
+
story: "Horizontal alignment (justify-items).",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export const Align = EnumTemplate.bind({});
|
|
130
|
+
Align.args = {
|
|
131
|
+
enum: "align",
|
|
132
|
+
class: "h-40 !content-normal",
|
|
133
|
+
};
|
|
134
|
+
Align.parameters = {
|
|
135
|
+
docs: {
|
|
136
|
+
description: {
|
|
137
|
+
story: "Vertical alignment (align-items).",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const Content: StoryFn<UGridArgs> = (args: UGridArgs, { argTypes }) => ({
|
|
143
|
+
components: { UGrid, UText, UPlaceholder, UCol },
|
|
144
|
+
setup: () => ({ args, argTypes, getArgs }),
|
|
145
|
+
template: `
|
|
146
|
+
<UCol gap="lg" block>
|
|
147
|
+
<UGrid
|
|
148
|
+
v-for="option in argTypes?.[args.enum]?.options"
|
|
149
|
+
v-bind="getArgs(args, option)"
|
|
150
|
+
:key="option"
|
|
151
|
+
cols="3"
|
|
152
|
+
class="h-52 w-full border border-primary border-dashed rounded-medium p-4"
|
|
153
|
+
>
|
|
154
|
+
<UPlaceholder :label="option" />
|
|
155
|
+
<UPlaceholder :label="option" />
|
|
156
|
+
<UPlaceholder :label="option" />
|
|
157
|
+
<UPlaceholder :label="option" />
|
|
158
|
+
<UPlaceholder :label="option" />
|
|
159
|
+
</UGrid>
|
|
160
|
+
</UCol>
|
|
161
|
+
`,
|
|
162
|
+
});
|
|
163
|
+
Content.args = { enum: "content", gap: "md" };
|
|
164
|
+
Content.parameters = {
|
|
165
|
+
docs: {
|
|
166
|
+
description: {
|
|
167
|
+
story: "Items vertical align for multi-row grid containers (align-content).",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export const PlaceContent: StoryFn<UGridArgs> = (args: UGridArgs, { argTypes }) => ({
|
|
173
|
+
components: { UGrid, UText, UPlaceholder, UCol },
|
|
174
|
+
setup: () => {
|
|
175
|
+
function getItemClass(option: string) {
|
|
176
|
+
return option === "stretch" ? "w-auto" : "size-14";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function getGridClass(option: string) {
|
|
180
|
+
return option === "stretch" ? "grid-cols-2" : "grid-cols-[repeat(2,56px)]";
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return { args, argTypes, getArgs, getItemClass, getGridClass };
|
|
184
|
+
},
|
|
185
|
+
template: `
|
|
186
|
+
<UCol block gap="lg">
|
|
187
|
+
<UGrid
|
|
188
|
+
v-for="option in argTypes?.[args.enum]?.options"
|
|
189
|
+
v-bind="getArgs(args, option)"
|
|
190
|
+
:key="option"
|
|
191
|
+
class="border border-primary border-dashed rounded p-4 w-full h-56"
|
|
192
|
+
:class="getGridClass(option)"
|
|
193
|
+
>
|
|
194
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
195
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
196
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
197
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
198
|
+
</UGrid>
|
|
199
|
+
</UCol>
|
|
200
|
+
`,
|
|
201
|
+
});
|
|
202
|
+
PlaceContent.args = { enum: "placeContent" };
|
|
203
|
+
PlaceContent.parameters = {
|
|
204
|
+
docs: {
|
|
205
|
+
description: {
|
|
206
|
+
story: "Control how content is justified and aligned within the grid (place-content).",
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export const PlaceItems: StoryFn<UGridArgs> = (args: UGridArgs, { argTypes }) => ({
|
|
212
|
+
components: { UGrid, UText, UPlaceholder, UCol },
|
|
213
|
+
setup: () => {
|
|
214
|
+
function getItemClass(option: string) {
|
|
215
|
+
return option === "stretch" ? "w-auto" : "size-14";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return { args, argTypes, getArgs, getItemClass };
|
|
219
|
+
},
|
|
220
|
+
template: `
|
|
221
|
+
<UCol block gap="lg">
|
|
222
|
+
<UGrid
|
|
223
|
+
v-for="option in argTypes?.[args.enum]?.options"
|
|
224
|
+
v-bind="getArgs(args, option)"
|
|
225
|
+
:key="option"
|
|
226
|
+
cols="3"
|
|
227
|
+
class="border border-primary border-dashed rounded p-4 w-full h-56"
|
|
228
|
+
>
|
|
229
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
230
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
231
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
232
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
233
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
234
|
+
<UPlaceholder :label="option" :class="getItemClass(option)" />
|
|
235
|
+
</UGrid>
|
|
236
|
+
</UCol>
|
|
237
|
+
`,
|
|
238
|
+
});
|
|
239
|
+
PlaceItems.args = { enum: "placeItems" };
|
|
240
|
+
PlaceItems.parameters = {
|
|
241
|
+
docs: {
|
|
242
|
+
description: {
|
|
243
|
+
story: "Control how items are justified and aligned within the grid (place-items).",
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import defaultConfig from "./config";
|
|
2
|
+
|
|
3
|
+
import type { ComponentConfig } from "../types";
|
|
4
|
+
|
|
5
|
+
export type Config = typeof defaultConfig;
|
|
6
|
+
|
|
7
|
+
export interface Props {
|
|
8
|
+
/**
|
|
9
|
+
* Number of columns.
|
|
10
|
+
*/
|
|
11
|
+
cols?: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Number of rows.
|
|
15
|
+
*/
|
|
16
|
+
rows?: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gap between items.
|
|
20
|
+
*/
|
|
21
|
+
gap?: "none" | "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Vertical gap override.
|
|
25
|
+
*/
|
|
26
|
+
rowGap?: "none" | "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Horizontal gap override.
|
|
30
|
+
*/
|
|
31
|
+
colGap?: "none" | "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Vertical alignment (align-items).
|
|
35
|
+
*/
|
|
36
|
+
align?: "start" | "end" | "center" | "stretch" | "baseline" | "normal";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Items vertical align for multi-row grid containers (align-content).
|
|
40
|
+
*/
|
|
41
|
+
content?:
|
|
42
|
+
| "start"
|
|
43
|
+
| "end"
|
|
44
|
+
| "center"
|
|
45
|
+
| "around"
|
|
46
|
+
| "evenly"
|
|
47
|
+
| "between"
|
|
48
|
+
| "normal"
|
|
49
|
+
| "stretch"
|
|
50
|
+
| "baseline";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Control how grid items are aligned along their inline axis (justify-items).
|
|
54
|
+
*/
|
|
55
|
+
justify?: "start" | "end" | "end-safe" | "center" | "center-safe" | "stretch" | "normal";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Control how content is justified and aligned within the grid (place-content).
|
|
59
|
+
*/
|
|
60
|
+
placeContent?:
|
|
61
|
+
| "start"
|
|
62
|
+
| "end"
|
|
63
|
+
| "end-safe"
|
|
64
|
+
| "center"
|
|
65
|
+
| "center-safe"
|
|
66
|
+
| "around"
|
|
67
|
+
| "evenly"
|
|
68
|
+
| "between"
|
|
69
|
+
| "stretch"
|
|
70
|
+
| "baseline";
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Control how items are justified and aligned within the grid (place-items).
|
|
74
|
+
*/
|
|
75
|
+
placeItems?: "start" | "end" | "end-safe" | "center" | "center-safe" | "stretch" | "baseline";
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Allows changing HTML tag.
|
|
79
|
+
*/
|
|
80
|
+
tag?: string;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Component config object.
|
|
84
|
+
*/
|
|
85
|
+
config?: ComponentConfig<Config>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Data-test attribute for automated testing.
|
|
89
|
+
*/
|
|
90
|
+
dataTest?: string | null;
|
|
91
|
+
}
|
|
@@ -131,6 +131,31 @@ describe("UCalendar.vue", () => {
|
|
|
131
131
|
expect(rangeUpdate.to).not.toBeNull();
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
it("Range – allows selecting the same day for from and to", async () => {
|
|
135
|
+
const component = mount(UCalendar, {
|
|
136
|
+
props: {
|
|
137
|
+
range: true,
|
|
138
|
+
modelValue: { from: null, to: null },
|
|
139
|
+
dateFormat: "Y-m-d",
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const dayView = component.findComponent(DayView);
|
|
144
|
+
const days = dayView.findAll('[vl-key="day"]');
|
|
145
|
+
|
|
146
|
+
await days[5].trigger("click");
|
|
147
|
+
await days[5].trigger("click");
|
|
148
|
+
|
|
149
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
150
|
+
expect(component.emitted("update:modelValue")).toHaveLength(2);
|
|
151
|
+
|
|
152
|
+
const rangeUpdate = component.emitted("update:modelValue")![1][0] as RangeDate;
|
|
153
|
+
|
|
154
|
+
expect(rangeUpdate.from).not.toBeNull();
|
|
155
|
+
expect(rangeUpdate.to).not.toBeNull();
|
|
156
|
+
expect(rangeUpdate.from).toBe(rangeUpdate.to);
|
|
157
|
+
});
|
|
158
|
+
|
|
134
159
|
it("Timepicker – shows timepicker when enabled", () => {
|
|
135
160
|
const component = mount(UCalendar, {
|
|
136
161
|
props: {
|
|
@@ -518,6 +543,94 @@ describe("UCalendar.vue", () => {
|
|
|
518
543
|
|
|
519
544
|
expect(component.emitted("userDateChange")).toBeTruthy();
|
|
520
545
|
});
|
|
546
|
+
|
|
547
|
+
it("ChangeRange – emits when first date is selected in range mode", async () => {
|
|
548
|
+
const component = mount(UCalendar, {
|
|
549
|
+
props: {
|
|
550
|
+
range: true,
|
|
551
|
+
modelValue: { from: null, to: null },
|
|
552
|
+
dateFormat: "Y-m-d",
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
const dayView = component.findComponent(DayView);
|
|
557
|
+
const days = dayView.findAll('[vl-key="day"]');
|
|
558
|
+
|
|
559
|
+
await days[0].trigger("click");
|
|
560
|
+
|
|
561
|
+
expect(component.emitted("change-range")).toBeTruthy();
|
|
562
|
+
expect(component.emitted("change-range")![0][0]).toHaveProperty("from");
|
|
563
|
+
expect(component.emitted("change-range")![0][0]).toHaveProperty("to");
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it("ChangeRange – emits when both dates are selected in range mode", async () => {
|
|
567
|
+
const component = mount(UCalendar, {
|
|
568
|
+
props: {
|
|
569
|
+
range: true,
|
|
570
|
+
modelValue: { from: null, to: null },
|
|
571
|
+
dateFormat: "Y-m-d",
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
const dayView = component.findComponent(DayView);
|
|
576
|
+
const days = dayView.findAll('[vl-key="day"]');
|
|
577
|
+
|
|
578
|
+
await days[0].trigger("click");
|
|
579
|
+
await days[3].trigger("click");
|
|
580
|
+
|
|
581
|
+
const changeRangeEvents = component.emitted("change-range");
|
|
582
|
+
|
|
583
|
+
expect(changeRangeEvents).toBeTruthy();
|
|
584
|
+
expect(changeRangeEvents!.length).toBeGreaterThan(0);
|
|
585
|
+
|
|
586
|
+
const lastEvent = changeRangeEvents![changeRangeEvents!.length - 1][0] as RangeDate;
|
|
587
|
+
|
|
588
|
+
expect(lastEvent.from).not.toBeNull();
|
|
589
|
+
expect(lastEvent.to).not.toBeNull();
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
it("ChangeRange – emits when same date is selected twice in range mode", async () => {
|
|
593
|
+
const component = mount(UCalendar, {
|
|
594
|
+
props: {
|
|
595
|
+
range: true,
|
|
596
|
+
modelValue: { from: null, to: null },
|
|
597
|
+
dateFormat: "Y-m-d",
|
|
598
|
+
},
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
const dayView = component.findComponent(DayView);
|
|
602
|
+
const days = dayView.findAll('[vl-key="day"]');
|
|
603
|
+
|
|
604
|
+
await days[5].trigger("click");
|
|
605
|
+
await days[5].trigger("click");
|
|
606
|
+
|
|
607
|
+
const changeRangeEvents = component.emitted("change-range");
|
|
608
|
+
|
|
609
|
+
expect(changeRangeEvents).toBeTruthy();
|
|
610
|
+
|
|
611
|
+
const lastEvent = changeRangeEvents![changeRangeEvents!.length - 1][0] as RangeDate;
|
|
612
|
+
|
|
613
|
+
expect(lastEvent.from).not.toBeNull();
|
|
614
|
+
expect(lastEvent.to).not.toBeNull();
|
|
615
|
+
expect(lastEvent.from).toBe(lastEvent.to);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it("ChangeRange – does not emit when range mode is disabled", async () => {
|
|
619
|
+
const component = mount(UCalendar, {
|
|
620
|
+
props: {
|
|
621
|
+
range: false,
|
|
622
|
+
modelValue: null,
|
|
623
|
+
dateFormat: "Y-m-d",
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
const dayView = component.findComponent(DayView);
|
|
628
|
+
const day = dayView.find('[vl-key="day"]');
|
|
629
|
+
|
|
630
|
+
await day.trigger("click");
|
|
631
|
+
|
|
632
|
+
expect(component.emitted("change-range")).toBeFalsy();
|
|
633
|
+
});
|
|
521
634
|
});
|
|
522
635
|
|
|
523
636
|
describe("Exposed Properties", () => {
|
|
@@ -440,6 +440,37 @@ describe("UDatePickerRange.vue", () => {
|
|
|
440
440
|
|
|
441
441
|
expect(component.find("[vl-key='datepickerCalendar']").exists()).toBe(true);
|
|
442
442
|
});
|
|
443
|
+
|
|
444
|
+
it("Menu – allows selecting the same day for from and to in range mode", async () => {
|
|
445
|
+
const component = mount(UDatePickerRange, {
|
|
446
|
+
props: {
|
|
447
|
+
variant: "input",
|
|
448
|
+
modelValue: { from: null, to: null },
|
|
449
|
+
dateFormat: "Y-m-d",
|
|
450
|
+
"onUpdate:modelValue": (value: RangeDate) => {
|
|
451
|
+
component.setProps({ modelValue: value });
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const input = component.findComponent(UInput).get("input");
|
|
457
|
+
|
|
458
|
+
await input.trigger("focus");
|
|
459
|
+
|
|
460
|
+
const days = component.findAll("[vl-key='day']");
|
|
461
|
+
|
|
462
|
+
await days[10].trigger("click");
|
|
463
|
+
await days[10].trigger("click");
|
|
464
|
+
|
|
465
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
466
|
+
|
|
467
|
+
const emittedValues = component.emitted("update:modelValue")!;
|
|
468
|
+
const lastEmittedValue = emittedValues[emittedValues.length - 1][0] as RangeDate;
|
|
469
|
+
|
|
470
|
+
expect(lastEmittedValue.from).not.toBeNull();
|
|
471
|
+
expect(lastEmittedValue.to).not.toBeNull();
|
|
472
|
+
expect(lastEmittedValue.from).toBe(lastEmittedValue.to);
|
|
473
|
+
});
|
|
443
474
|
});
|
|
444
475
|
|
|
445
476
|
describe("Range Navigation", () => {
|
|
@@ -554,6 +585,89 @@ describe("UDatePickerRange.vue", () => {
|
|
|
554
585
|
});
|
|
555
586
|
});
|
|
556
587
|
|
|
588
|
+
describe("Events", () => {
|
|
589
|
+
it("ChangeRange – handles change-range event from calendar when dates are selected", async () => {
|
|
590
|
+
const component = mount(UDatePickerRange, {
|
|
591
|
+
props: {
|
|
592
|
+
variant: "input",
|
|
593
|
+
modelValue: { from: null, to: null },
|
|
594
|
+
dateFormat: "Y-m-d",
|
|
595
|
+
"onUpdate:modelValue": (value: RangeDate) => {
|
|
596
|
+
component.setProps({ modelValue: value });
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
const input = component.findComponent(UInput).find("input");
|
|
602
|
+
|
|
603
|
+
await input.trigger("focus");
|
|
604
|
+
|
|
605
|
+
const days = component.findAll("[vl-key='day']");
|
|
606
|
+
|
|
607
|
+
expect(days.length).toBeGreaterThan(0);
|
|
608
|
+
|
|
609
|
+
await days[0].trigger("click");
|
|
610
|
+
await days[3].trigger("click");
|
|
611
|
+
|
|
612
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it("ChangeRange – handles change-range event from calendar when both dates are selected", async () => {
|
|
616
|
+
const component = mount(UDatePickerRange, {
|
|
617
|
+
props: {
|
|
618
|
+
variant: "input",
|
|
619
|
+
modelValue: { from: null, to: null },
|
|
620
|
+
dateFormat: "Y-m-d",
|
|
621
|
+
"onUpdate:modelValue": (value: RangeDate) => {
|
|
622
|
+
component.setProps({ modelValue: value });
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
const input = component.findComponent(UInput).find("input");
|
|
628
|
+
|
|
629
|
+
await input.trigger("focus");
|
|
630
|
+
|
|
631
|
+
const days = component.findAll("[vl-key='day']");
|
|
632
|
+
|
|
633
|
+
await days[0].trigger("click");
|
|
634
|
+
await days[3].trigger("click");
|
|
635
|
+
|
|
636
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it("ChangeRange – handles change-range event from calendar when same date is selected twice", async () => {
|
|
640
|
+
const component = mount(UDatePickerRange, {
|
|
641
|
+
props: {
|
|
642
|
+
variant: "input",
|
|
643
|
+
modelValue: { from: null, to: null },
|
|
644
|
+
dateFormat: "Y-m-d",
|
|
645
|
+
"onUpdate:modelValue": (value: RangeDate) => {
|
|
646
|
+
component.setProps({ modelValue: value });
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
const input = component.findComponent(UInput).find("input");
|
|
652
|
+
|
|
653
|
+
await input.trigger("focus");
|
|
654
|
+
|
|
655
|
+
const days = component.findAll("[vl-key='day']");
|
|
656
|
+
|
|
657
|
+
await days[10].trigger("click");
|
|
658
|
+
await days[10].trigger("click");
|
|
659
|
+
|
|
660
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
661
|
+
|
|
662
|
+
const emittedValues = component.emitted("update:modelValue")!;
|
|
663
|
+
const lastEmittedValue = emittedValues[emittedValues.length - 1][0] as RangeDate;
|
|
664
|
+
|
|
665
|
+
expect(lastEmittedValue.from).not.toBeNull();
|
|
666
|
+
expect(lastEmittedValue.to).not.toBeNull();
|
|
667
|
+
expect(lastEmittedValue.from).toBe(lastEmittedValue.to);
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
|
|
557
671
|
describe("Exposed Properties", () => {
|
|
558
672
|
it("Exposes wrapper element ref", () => {
|
|
559
673
|
const component = mount(UDatePickerRange, {
|