vueless 0.0.684 → 0.0.686
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 +1 -1
- package/ui.data-table/UTable.vue +33 -1
- package/ui.data-table/config.ts +5 -0
- package/ui.dropdown-badge/UDropdownBadge.vue +1 -0
- package/ui.dropdown-button/UDropdownButton.vue +1 -0
- package/ui.dropdown-button/config.ts +1 -1
- package/ui.dropdown-link/UDropdownLink.vue +1 -0
- package/ui.dropdown-list/UDropdownList.vue +9 -2
- package/ui.dropdown-list/config.ts +6 -4
- package/ui.dropdown-list/storybook/docs.mdx +19 -1
- package/ui.dropdown-list/storybook/stories.ts +84 -14
- package/ui.dropdown-list/types.ts +26 -0
package/package.json
CHANGED
package/ui.data-table/UTable.vue
CHANGED
|
@@ -406,6 +406,20 @@ function onToggleExpand(row: Row, expanded: boolean) {
|
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
function isRowSelectedWithin(rowIndex: number) {
|
|
410
|
+
const prevRow = sortedRows.value[rowIndex - 1];
|
|
411
|
+
const isPrevRowSelected = prevRow && selectedRows.value.find((rowId) => rowId === prevRow.id);
|
|
412
|
+
const isRowsSelected = selectedRows.value.find(
|
|
413
|
+
(rowId) => rowId === sortedRows.value[rowIndex].id,
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
if (prevRow) {
|
|
417
|
+
return isPrevRowSelected && isRowsSelected;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return isRowsSelected;
|
|
421
|
+
}
|
|
422
|
+
|
|
409
423
|
defineExpose({
|
|
410
424
|
/**
|
|
411
425
|
* Allows to clear selected rows.
|
|
@@ -438,6 +452,7 @@ const {
|
|
|
438
452
|
bodyRowBeforeCellAttrs,
|
|
439
453
|
footerAttrs,
|
|
440
454
|
bodyRowDateDividerAttrs,
|
|
455
|
+
bodyRowCheckedDateDividerAttrs,
|
|
441
456
|
headerCellBaseAttrs,
|
|
442
457
|
headerCellCheckboxAttrs,
|
|
443
458
|
headerActionsCheckboxAttrs,
|
|
@@ -446,6 +461,7 @@ const {
|
|
|
446
461
|
headerCounterAttrs,
|
|
447
462
|
bodyEmptyStateAttrs,
|
|
448
463
|
bodyDateDividerAttrs,
|
|
464
|
+
bodySelectedDateDividerAttrs,
|
|
449
465
|
bodyCellDateDividerAttrs,
|
|
450
466
|
headerActionsCounterAttrs,
|
|
451
467
|
stickyHeaderCounterAttrs,
|
|
@@ -666,7 +682,10 @@ const {
|
|
|
666
682
|
</td>
|
|
667
683
|
</tr>
|
|
668
684
|
|
|
669
|
-
<tr
|
|
685
|
+
<tr
|
|
686
|
+
v-if="isShownDateDivider(rowIndex) && !isRowSelectedWithin(rowIndex) && row.rowDate"
|
|
687
|
+
v-bind="bodyRowDateDividerAttrs"
|
|
688
|
+
>
|
|
670
689
|
<td v-bind="bodyCellDateDividerAttrs" :colspan="colsCount">
|
|
671
690
|
<UDivider
|
|
672
691
|
size="xs"
|
|
@@ -676,6 +695,19 @@ const {
|
|
|
676
695
|
</td>
|
|
677
696
|
</tr>
|
|
678
697
|
|
|
698
|
+
<tr
|
|
699
|
+
v-if="isShownDateDivider(rowIndex) && isRowSelectedWithin(rowIndex) && row.rowDate"
|
|
700
|
+
v-bind="bodyRowCheckedDateDividerAttrs"
|
|
701
|
+
>
|
|
702
|
+
<td v-bind="bodyCellDateDividerAttrs" :colspan="colsCount">
|
|
703
|
+
<UDivider
|
|
704
|
+
size="xs"
|
|
705
|
+
:label="getDateDividerLabel(row.rowDate)"
|
|
706
|
+
v-bind="bodySelectedDateDividerAttrs"
|
|
707
|
+
/>
|
|
708
|
+
</td>
|
|
709
|
+
</tr>
|
|
710
|
+
|
|
679
711
|
<UTableRow
|
|
680
712
|
v-model:selected-rows="selectedRows"
|
|
681
713
|
:selectable="selectable"
|
package/ui.data-table/config.ts
CHANGED
|
@@ -50,6 +50,7 @@ export default /*tw*/ {
|
|
|
50
50
|
bodyRowBeforeCell: "{>bodyCellBase} py-1",
|
|
51
51
|
bodyRowAfter: "!p-0",
|
|
52
52
|
bodyRowDateDivider: "",
|
|
53
|
+
bodyRowCheckedDateDivider: "{>bodyRowChecked} {>bodyRowChecked}",
|
|
53
54
|
bodyCellBase: {
|
|
54
55
|
base: "p-4 truncate align-top",
|
|
55
56
|
variants: {
|
|
@@ -78,6 +79,10 @@ export default /*tw*/ {
|
|
|
78
79
|
base: "{UDivider}",
|
|
79
80
|
label: "py-0",
|
|
80
81
|
},
|
|
82
|
+
bodySelectedDateDivider: {
|
|
83
|
+
base: "{>bodyDateDivider}",
|
|
84
|
+
label: "bg-gray-200 transition",
|
|
85
|
+
},
|
|
81
86
|
bodyEmptyState: "{UEmpty} my-8",
|
|
82
87
|
footer: {
|
|
83
88
|
base: "group/footer border-t border-solid border-gray-200",
|
|
@@ -8,6 +8,7 @@ import { isMac } from "../utils/platform.ts";
|
|
|
8
8
|
|
|
9
9
|
import UIcon from "../ui.image-icon/UIcon.vue";
|
|
10
10
|
import UButton from "../ui.button/UButton.vue";
|
|
11
|
+
import UDivider from "../ui.container-divider/UDivider.vue";
|
|
11
12
|
|
|
12
13
|
import usePointer from "./usePointer.ts";
|
|
13
14
|
import { useLocale } from "../composables/useLocale.ts";
|
|
@@ -136,7 +137,7 @@ function onClickAddOption() {
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
function isMetaKey(key: string) {
|
|
139
|
-
return ["isSubGroup", "groupLabel", "level", "isHidden", "onClick"].includes(key);
|
|
140
|
+
return ["isSubGroup", "groupLabel", "level", "isHidden", "onClick", "divider"].includes(key);
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
function select(option: Option, keyCode?: string) {
|
|
@@ -261,6 +262,7 @@ const {
|
|
|
261
262
|
subGroupAttrs,
|
|
262
263
|
groupAttrs,
|
|
263
264
|
optionContentAttrs,
|
|
265
|
+
optionDividerAttrs,
|
|
264
266
|
} = useUI<Config>(defaultConfig);
|
|
265
267
|
</script>
|
|
266
268
|
|
|
@@ -285,9 +287,14 @@ const {
|
|
|
285
287
|
:role="!(option && option.groupLabel) ? 'option' : undefined"
|
|
286
288
|
:data-group-label="Boolean(option.groupLabel)"
|
|
287
289
|
>
|
|
290
|
+
<UDivider v-if="option.divider" padding="none" v-bind="optionDividerAttrs" />
|
|
288
291
|
<!-- option title -->
|
|
289
292
|
<span
|
|
290
|
-
v-if="
|
|
293
|
+
v-if="
|
|
294
|
+
!(option && (option.groupLabel || option.isSubGroup)) &&
|
|
295
|
+
!option.isHidden &&
|
|
296
|
+
!option.divider
|
|
297
|
+
"
|
|
291
298
|
v-bind="isSelectedOption(option) ? optionActiveAttrs : optionAttrs"
|
|
292
299
|
:data-test="`${dataTest}-option`"
|
|
293
300
|
:class="optionHighlight(index, option)"
|
|
@@ -11,7 +11,7 @@ export default /*tw*/ {
|
|
|
11
11
|
base: `
|
|
12
12
|
rounded-dynamic-sm px-2 py-2.5 flex items-center align-middle whitespace-nowrap cursor-pointer
|
|
13
13
|
font-normal !leading-none text-gray-900
|
|
14
|
-
hover:bg-
|
|
14
|
+
hover:bg-{color}-50 active:bg-{color}-100
|
|
15
15
|
overflow-hidden text-ellipsis
|
|
16
16
|
`,
|
|
17
17
|
variants: {
|
|
@@ -21,12 +21,12 @@ export default /*tw*/ {
|
|
|
21
21
|
lg: "text-base",
|
|
22
22
|
},
|
|
23
23
|
disabled: {
|
|
24
|
-
true: "pointer-events-none",
|
|
24
|
+
true: "pointer-events-none text-gray-400",
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
},
|
|
28
|
-
optionActive: "{>option} font-semibold bg-
|
|
29
|
-
optionHighlighted: "bg-
|
|
28
|
+
optionActive: "{>option} font-semibold bg-{color}-100 hover:bg-{color}-100 text-brand-600",
|
|
29
|
+
optionHighlighted: "bg-{color}-50",
|
|
30
30
|
optionContent: "overflow-visible text-ellipsis",
|
|
31
31
|
groupBase: {
|
|
32
32
|
base: "px-2 pb-2.5 font-medium !leading-none text-gray-400 overflow-hidden text-ellipsis",
|
|
@@ -50,11 +50,13 @@ export default /*tw*/ {
|
|
|
50
50
|
addOptionLabelHotkey: "text-gray-500",
|
|
51
51
|
addOptionButton: "{UButton} !leading-none sticky left-[calc(100%-2.15rem)] bottom-2 p-1",
|
|
52
52
|
addOptionIcon: "{UIcon} bg-transparent",
|
|
53
|
+
optionDivider: "{UDivider}",
|
|
53
54
|
i18n: {
|
|
54
55
|
noDataToShow: "No data to show.",
|
|
55
56
|
add: "Add",
|
|
56
57
|
},
|
|
57
58
|
defaults: {
|
|
59
|
+
color: "brand",
|
|
58
60
|
size: "md",
|
|
59
61
|
labelKey: "label",
|
|
60
62
|
valueKey: "id",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
|
|
1
|
+
import { Markdown, Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
|
|
2
2
|
import { getSource } from "../../utils/storybook.ts";
|
|
3
3
|
|
|
4
4
|
import * as stories from "./stories.ts";
|
|
@@ -12,5 +12,23 @@ import defaultConfig from "../config.ts?raw"
|
|
|
12
12
|
<Controls of={stories.Default} />
|
|
13
13
|
<Stories of={stories} />
|
|
14
14
|
|
|
15
|
+
## Row meta keys
|
|
16
|
+
Keys you may/have to provide to component in an option object.
|
|
17
|
+
|
|
18
|
+
<Markdown>
|
|
19
|
+
{`
|
|
20
|
+
| Key name | Description | Type |
|
|
21
|
+
| ------------------| ---------------------------------- | ---------------|
|
|
22
|
+
| id | A unique identifier for option | String, Number |
|
|
23
|
+
| label | Option label | String |
|
|
24
|
+
| isHidden | Indicates if option is hidden | Boolean |
|
|
25
|
+
| isSubGroup | Indicates if option is subGroup | Boolean |
|
|
26
|
+
| groupLabel | Option group label | String |
|
|
27
|
+
| level | Indicates option nesting level | Number |
|
|
28
|
+
| divider | Adds divider instead of option | Boolean |
|
|
29
|
+
| onClick | Option event handler | Function |
|
|
30
|
+
`}
|
|
31
|
+
</Markdown>
|
|
32
|
+
|
|
15
33
|
## Default config
|
|
16
34
|
<Source code={getSource(defaultConfig)} language="jsx" dark />
|
|
@@ -16,7 +16,7 @@ interface DefaultUDropdownListArgs extends Props {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
interface EnumUDropdownListArgs extends DefaultUDropdownListArgs {
|
|
19
|
-
enum: keyof Pick<Props, "size">;
|
|
19
|
+
enum: keyof Pick<Props, "size" | "color">;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export default {
|
|
@@ -25,9 +25,11 @@ export default {
|
|
|
25
25
|
component: UDropdownList,
|
|
26
26
|
args: {
|
|
27
27
|
options: [
|
|
28
|
-
{ label: "
|
|
29
|
-
{ label: "
|
|
30
|
-
{ label: "
|
|
28
|
+
{ label: "New York", id: "1" },
|
|
29
|
+
{ label: "Los Angeles", id: "2" },
|
|
30
|
+
{ label: "Chicago", id: "3" },
|
|
31
|
+
{ label: "Houston", id: "4" },
|
|
32
|
+
{ label: "San Francisco", id: "5" },
|
|
31
33
|
],
|
|
32
34
|
},
|
|
33
35
|
argTypes: {
|
|
@@ -37,7 +39,7 @@ export default {
|
|
|
37
39
|
docs: {
|
|
38
40
|
...getDocsDescription(UDropdownList.__name),
|
|
39
41
|
story: {
|
|
40
|
-
height: "
|
|
42
|
+
height: "250px",
|
|
41
43
|
},
|
|
42
44
|
},
|
|
43
45
|
},
|
|
@@ -48,10 +50,16 @@ const DefaultTemplate: StoryFn<DefaultUDropdownListArgs> = (args: DefaultUDropdo
|
|
|
48
50
|
setup() {
|
|
49
51
|
const slots = getSlotNames(UDropdownList.__name);
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
const showAlert = (message: string) => alert(message);
|
|
54
|
+
|
|
55
|
+
return { args, slots, showAlert };
|
|
52
56
|
},
|
|
53
57
|
template: `
|
|
54
|
-
<UDropdownList
|
|
58
|
+
<UDropdownList
|
|
59
|
+
v-bind="args"
|
|
60
|
+
class="mx-4 w-[24rem]"
|
|
61
|
+
@add="showAlert('You triggered the add action!')"
|
|
62
|
+
>
|
|
55
63
|
${args.slotTemplate || getSlotsFragment("")}
|
|
56
64
|
</UDropdownList>
|
|
57
65
|
`,
|
|
@@ -69,27 +77,51 @@ const EnumVariantTemplate: StoryFn<EnumUDropdownListArgs> = (
|
|
|
69
77
|
};
|
|
70
78
|
},
|
|
71
79
|
template: `
|
|
72
|
-
|
|
73
|
-
<URow>
|
|
80
|
+
<URow class="w-fit">
|
|
74
81
|
<UDropdownList
|
|
75
82
|
v-for="(option, index) in options"
|
|
76
83
|
:key="index"
|
|
77
84
|
v-bind="args"
|
|
78
85
|
:[args.enum]="option"
|
|
86
|
+
class="static w-36"
|
|
79
87
|
/>
|
|
80
88
|
</URow>
|
|
81
|
-
</div>
|
|
82
89
|
`,
|
|
83
90
|
});
|
|
84
91
|
|
|
85
92
|
export const Default = DefaultTemplate.bind({});
|
|
86
93
|
Default.args = {};
|
|
87
94
|
|
|
95
|
+
export const AddOption = DefaultTemplate.bind({});
|
|
96
|
+
AddOption.args = { addOption: true };
|
|
97
|
+
AddOption.parameters = {
|
|
98
|
+
docs: {
|
|
99
|
+
description: {
|
|
100
|
+
story:
|
|
101
|
+
// eslint-disable-next-line vue/max-len
|
|
102
|
+
"The `addOption` prop displays an 'Add option' button, while the `add` event allows handling custom functionality when the button is clicked.",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
88
107
|
export const Sizes = EnumVariantTemplate.bind({});
|
|
89
108
|
Sizes.args = { enum: "size" };
|
|
90
109
|
|
|
110
|
+
export const Colors = EnumVariantTemplate.bind({});
|
|
111
|
+
Colors.args = { enum: "color", modelValue: "2" };
|
|
112
|
+
|
|
91
113
|
export const VisibleOptions = DefaultTemplate.bind({});
|
|
92
114
|
VisibleOptions.args = { visibleOptions: 3 };
|
|
115
|
+
VisibleOptions.parameters = {
|
|
116
|
+
docs: {
|
|
117
|
+
description: {
|
|
118
|
+
story: "`visibleOptions` prop regulates number of options to show without a scroll.",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const Disabled = DefaultTemplate.bind({});
|
|
124
|
+
Disabled.args = { disabled: true };
|
|
93
125
|
|
|
94
126
|
export const WithoutOptions = DefaultTemplate.bind({});
|
|
95
127
|
WithoutOptions.args = { options: [] };
|
|
@@ -111,16 +143,54 @@ GroupedOptions.args = {
|
|
|
111
143
|
{ name: "Phoenix" },
|
|
112
144
|
],
|
|
113
145
|
};
|
|
146
|
+
GroupedOptions.parameters = {
|
|
147
|
+
docs: {
|
|
148
|
+
story: {
|
|
149
|
+
height: "500px",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const Divider = DefaultTemplate.bind({});
|
|
155
|
+
Divider.args = {
|
|
156
|
+
options: [
|
|
157
|
+
{ label: "North America", id: "1" },
|
|
158
|
+
{ label: "South America", id: "2" },
|
|
159
|
+
{ divider: true },
|
|
160
|
+
{ label: "Europe", id: "3" },
|
|
161
|
+
{ divider: true },
|
|
162
|
+
{ label: "Asia", id: "4" },
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
Divider.parameters = {
|
|
166
|
+
docs: {
|
|
167
|
+
description: {
|
|
168
|
+
story:
|
|
169
|
+
// eslint-disable-next-line vue/max-len
|
|
170
|
+
"In addition to grouping options, you can insert a divider between specific items by adding an object with a single `divider: true` property.",
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
};
|
|
114
174
|
|
|
115
175
|
export const OptionSettings = DefaultTemplate.bind({});
|
|
116
176
|
OptionSettings.args = {
|
|
117
177
|
options: [
|
|
118
|
-
{ label: "
|
|
119
|
-
{ label: "
|
|
178
|
+
{ label: "New York", id: "1" },
|
|
179
|
+
{ label: "Los Angeles", id: "2", isHidden: true },
|
|
120
180
|
{
|
|
121
|
-
label: "
|
|
181
|
+
label: "Chicago",
|
|
122
182
|
id: "3",
|
|
123
|
-
onClick: (option: Option) =>
|
|
183
|
+
onClick: (option: Option) =>
|
|
184
|
+
alert("onClick function for the third option: " + JSON.stringify(option)),
|
|
124
185
|
},
|
|
125
186
|
],
|
|
126
187
|
};
|
|
188
|
+
OptionSettings.parameters = {
|
|
189
|
+
docs: {
|
|
190
|
+
description: {
|
|
191
|
+
story:
|
|
192
|
+
// eslint-disable-next-line vue/max-len
|
|
193
|
+
"The second option of the array is hidden (`isHidden` object property is set to `true`). <br/> The third option has `onClick` event handler: <br/> `onClick: (option: Option) => alert('onClick function for option 3: ' + JSON.stringify(option))`",
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
};
|
|
@@ -47,6 +47,32 @@ export interface Props {
|
|
|
47
47
|
*/
|
|
48
48
|
size?: "sm" | "md" | "lg";
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Option highlight color.
|
|
52
|
+
*/
|
|
53
|
+
color?:
|
|
54
|
+
| "grayscale"
|
|
55
|
+
| "red"
|
|
56
|
+
| "orange"
|
|
57
|
+
| "amber"
|
|
58
|
+
| "yellow"
|
|
59
|
+
| "lime"
|
|
60
|
+
| "green"
|
|
61
|
+
| "emerald"
|
|
62
|
+
| "teal"
|
|
63
|
+
| "cyan"
|
|
64
|
+
| "sky"
|
|
65
|
+
| "blue"
|
|
66
|
+
| "indigo"
|
|
67
|
+
| "violet"
|
|
68
|
+
| "purple"
|
|
69
|
+
| "fuchsia"
|
|
70
|
+
| "pink"
|
|
71
|
+
| "rose"
|
|
72
|
+
| "gray"
|
|
73
|
+
| "white"
|
|
74
|
+
| "brand";
|
|
75
|
+
|
|
50
76
|
/**
|
|
51
77
|
* Number of options to show without a scroll.
|
|
52
78
|
*/
|