@nuxt/ui 2.9.0 → 2.10.0
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/dist/module.d.mts +270 -2
- package/dist/module.d.ts +270 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +21 -2
- package/dist/runtime/components/data/Table.vue +8 -6
- package/dist/runtime/components/data/Table.vue.d.ts +2 -1
- package/dist/runtime/components/elements/Accordion.vue +15 -13
- package/dist/runtime/components/elements/Accordion.vue.d.ts +5 -2
- package/dist/runtime/components/elements/Button.vue.d.ts +2 -2
- package/dist/runtime/components/elements/Dropdown.vue +31 -25
- package/dist/runtime/components/elements/Dropdown.vue.d.ts +2 -0
- package/dist/runtime/components/elements/Meter.vue +166 -0
- package/dist/runtime/components/elements/Meter.vue.d.ts +123 -0
- package/dist/runtime/components/elements/MeterGroup.d.ts +78 -0
- package/dist/runtime/components/elements/MeterGroup.mjs +172 -0
- package/dist/runtime/components/elements/Progress.vue +284 -0
- package/dist/runtime/components/elements/Progress.vue.d.ts +2 -0
- package/dist/runtime/components/forms/Checkbox.vue.d.ts +2 -2
- package/dist/runtime/components/forms/Form.vue +32 -7
- package/dist/runtime/components/forms/Form.vue.d.ts +2 -1
- package/dist/runtime/components/forms/Input.vue +5 -1
- package/dist/runtime/components/forms/Input.vue.d.ts +12 -3
- package/dist/runtime/components/forms/Radio.vue +10 -9
- package/dist/runtime/components/forms/Radio.vue.d.ts +3 -3
- package/dist/runtime/components/forms/RadioGroup.vue +136 -0
- package/dist/runtime/components/forms/RadioGroup.vue.d.ts +118 -0
- package/dist/runtime/components/forms/Range.vue.d.ts +3 -3
- package/dist/runtime/components/forms/Select.vue.d.ts +2 -2
- package/dist/runtime/components/forms/SelectMenu.vue +62 -57
- package/dist/runtime/components/forms/SelectMenu.vue.d.ts +6 -5
- package/dist/runtime/components/forms/Textarea.vue +5 -1
- package/dist/runtime/components/forms/Textarea.vue.d.ts +11 -2
- package/dist/runtime/components/forms/Toggle.vue.d.ts +2 -2
- package/dist/runtime/components/layout/Divider.vue +107 -0
- package/dist/runtime/components/layout/Divider.vue.d.ts +82 -0
- package/dist/runtime/components/navigation/CommandPalette.vue +10 -3
- package/dist/runtime/components/navigation/CommandPalette.vue.d.ts +1 -1
- package/dist/runtime/components/navigation/Pagination.vue +65 -9
- package/dist/runtime/components/navigation/Pagination.vue.d.ts +41 -3
- package/dist/runtime/components/navigation/Tabs.vue +1 -1
- package/dist/runtime/components/overlays/ContextMenu.vue +7 -2
- package/dist/runtime/components/overlays/ContextMenu.vue.d.ts +2 -1
- package/dist/runtime/components/overlays/Modal.vue +1 -1
- package/dist/runtime/components/overlays/Modal.vue.d.ts +1 -1
- package/dist/runtime/components/overlays/Notification.vue +7 -1
- package/dist/runtime/components/overlays/Notifications.vue +1 -1
- package/dist/runtime/components/overlays/Popover.vue +22 -7
- package/dist/runtime/components/overlays/Popover.vue.d.ts +14 -0
- package/dist/runtime/components/overlays/Slideover.vue.d.ts +1 -1
- package/dist/runtime/components/overlays/Tooltip.vue +16 -10
- package/dist/runtime/components/overlays/Tooltip.vue.d.ts +1 -0
- package/dist/runtime/composables/useFormGroup.d.ts +3 -3
- package/dist/runtime/composables/useFormGroup.mjs +17 -6
- package/dist/runtime/composables/usePopper.d.ts +3 -3
- package/dist/runtime/composables/usePopper.mjs +7 -1
- package/dist/runtime/composables/useUI.d.ts +2 -2
- package/dist/runtime/composables/useUI.mjs +2 -2
- package/dist/runtime/types/command-palette.d.ts +1 -0
- package/dist/runtime/types/form.d.ts +13 -6
- package/dist/runtime/types/index.d.ts +2 -0
- package/dist/runtime/types/meter.d.ts +5 -0
- package/dist/runtime/types/popper.d.ts +1 -0
- package/dist/runtime/types/progress.d.ts +4 -0
- package/dist/runtime/types/utils.d.ts +1 -1
- package/dist/runtime/ui.config.d.ts +263 -0
- package/dist/runtime/ui.config.mjs +263 -19
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +19 -19
- package/dist/runtime/utils/StateEmitter.d.ts +0 -17
- package/dist/runtime/utils/StateEmitter.mjs +0 -21
|
@@ -17,41 +17,44 @@
|
|
|
17
17
|
|
|
18
18
|
<div v-if="open && items.length" ref="container" :class="[ui.container, ui.width]" :style="containerStyle" @mouseover="onMouseOver">
|
|
19
19
|
<Transition appear v-bind="ui.transition">
|
|
20
|
-
<
|
|
21
|
-
<div v-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
<div>
|
|
21
|
+
<div v-if="popper.arrow" data-popper-arrow :class="['invisible before:visible before:block before:rotate-45 before:z-[-1]', Object.values(ui.arrow)]" />
|
|
22
|
+
<HMenuItems :class="[ui.base, ui.divide, ui.ring, ui.rounded, ui.shadow, ui.background, ui.height]" static>
|
|
23
|
+
<div v-for="(subItems, index) of items" :key="index" :class="ui.padding">
|
|
24
|
+
<HMenuItem v-for="(item, subIndex) of subItems" :key="subIndex" v-slot="{ active, disabled: itemDisabled }" :disabled="item.disabled">
|
|
25
|
+
<component
|
|
26
|
+
:is="!!item.to ? NuxtLink : 'button'"
|
|
27
|
+
v-bind="omit(item, ['label', 'slot', 'icon', 'iconClass', 'avatar', 'shortcuts', 'disabled', 'click'])"
|
|
28
|
+
:class="[ui.item.base, ui.item.padding, ui.item.size, ui.item.rounded, active ? ui.item.active : ui.item.inactive, itemDisabled && ui.item.disabled]"
|
|
29
|
+
@click="item.click"
|
|
30
|
+
>
|
|
31
|
+
<slot :name="item.slot || 'item'" :item="item">
|
|
32
|
+
<UIcon v-if="item.icon" :name="item.icon" :class="[ui.item.icon.base, active ? ui.item.icon.active : ui.item.icon.inactive, item.iconClass]" />
|
|
33
|
+
<UAvatar v-else-if="item.avatar" v-bind="{ size: ui.item.avatar.size, ...item.avatar }" :class="ui.item.avatar.base" />
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
<span class="truncate">{{ item.label }}</span>
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
<span v-if="item.shortcuts?.length" :class="ui.item.shortcuts">
|
|
38
|
+
<UKbd v-for="shortcut of item.shortcuts" :key="shortcut">{{ shortcut }}</UKbd>
|
|
39
|
+
</span>
|
|
40
|
+
</slot>
|
|
41
|
+
</component>
|
|
42
|
+
</HMenuItem>
|
|
43
|
+
</div>
|
|
44
|
+
</HMenuItems>
|
|
45
|
+
</div>
|
|
42
46
|
</Transition>
|
|
43
47
|
</div>
|
|
44
48
|
</HMenu>
|
|
45
49
|
</template>
|
|
46
50
|
|
|
47
51
|
<script>
|
|
48
|
-
import { defineComponent, ref, computed, toRef, onMounted } from "vue";
|
|
52
|
+
import { defineComponent, ref, computed, toRef, onMounted, resolveComponent } from "vue";
|
|
49
53
|
import { Menu as HMenu, MenuButton as HMenuButton, MenuItems as HMenuItems, MenuItem as HMenuItem } from "@headlessui/vue";
|
|
50
54
|
import { defu } from "defu";
|
|
51
55
|
import UIcon from "../elements/Icon.vue";
|
|
52
56
|
import UAvatar from "../elements/Avatar.vue";
|
|
53
57
|
import UKbd from "../elements/Kbd.vue";
|
|
54
|
-
import ULink from "../elements/Link.vue";
|
|
55
58
|
import { useUI } from "../../composables/useUI";
|
|
56
59
|
import { usePopper } from "../../composables/usePopper";
|
|
57
60
|
import { mergeConfig, omit } from "../../utils";
|
|
@@ -66,8 +69,7 @@ export default defineComponent({
|
|
|
66
69
|
HMenuItem,
|
|
67
70
|
UIcon,
|
|
68
71
|
UAvatar,
|
|
69
|
-
UKbd
|
|
70
|
-
ULink
|
|
72
|
+
UKbd
|
|
71
73
|
},
|
|
72
74
|
inheritAttrs: false,
|
|
73
75
|
props: {
|
|
@@ -158,16 +160,20 @@ export default defineComponent({
|
|
|
158
160
|
closeTimeout = null;
|
|
159
161
|
}, props.closeDelay);
|
|
160
162
|
}
|
|
163
|
+
const NuxtLink = resolveComponent("NuxtLink");
|
|
161
164
|
return {
|
|
162
165
|
// eslint-disable-next-line vue/no-dupe-keys
|
|
163
166
|
ui,
|
|
164
167
|
attrs,
|
|
168
|
+
// eslint-disable-next-line vue/no-dupe-keys
|
|
169
|
+
popper,
|
|
165
170
|
trigger,
|
|
166
171
|
container,
|
|
167
172
|
containerStyle,
|
|
168
173
|
onMouseOver,
|
|
169
174
|
onMouseLeave,
|
|
170
|
-
omit
|
|
175
|
+
omit,
|
|
176
|
+
NuxtLink
|
|
171
177
|
};
|
|
172
178
|
}
|
|
173
179
|
});
|
|
@@ -40,6 +40,7 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
40
40
|
attrs: import("vue").ComputedRef<Pick<{
|
|
41
41
|
[x: string]: unknown;
|
|
42
42
|
}, string>>;
|
|
43
|
+
popper: import("vue").ComputedRef<PopperOptions>;
|
|
43
44
|
trigger: import("vue").Ref<import("@vueuse/core").MaybeElement>;
|
|
44
45
|
container: import("vue").Ref<import("@vueuse/core").MaybeElement>;
|
|
45
46
|
containerStyle: import("vue").ComputedRef<{
|
|
@@ -52,6 +53,7 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
52
53
|
onMouseOver: () => void;
|
|
53
54
|
onMouseLeave: () => void;
|
|
54
55
|
omit: typeof omit;
|
|
56
|
+
NuxtLink: string | import("vue").ConcreteComponent<{}, any, any, import("vue").ComputedOptions, import("vue").MethodOptions>;
|
|
55
57
|
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
56
58
|
items: {
|
|
57
59
|
type: PropType<DropdownItem[][]>;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="ui.wrapper" v-bind="attrs">
|
|
3
|
+
<template v-if="indicator || $slots.indicator">
|
|
4
|
+
<slot name="indicator" v-bind="{ percent, value }">
|
|
5
|
+
<div :class="indicatorContainerClass" :style="{ width: `${percent}%` }">
|
|
6
|
+
<div :class="indicatorClass">
|
|
7
|
+
{{ Math.round(percent) }}%
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</slot>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<meter
|
|
14
|
+
:value="value"
|
|
15
|
+
:min="normalizedMin"
|
|
16
|
+
:max="normalizedMax"
|
|
17
|
+
:class="[meterClass, meterAppearanceClass, meterBarClass]"
|
|
18
|
+
/>
|
|
19
|
+
|
|
20
|
+
<template v-if="label || $slots.label">
|
|
21
|
+
<slot name="label" v-bind="{ percent, value }">
|
|
22
|
+
<div :class="labelClass">
|
|
23
|
+
<UIcon v-if="icon" :name="icon" /> {{ label }}
|
|
24
|
+
</div>
|
|
25
|
+
</slot>
|
|
26
|
+
</template>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script>
|
|
31
|
+
import { computed, defineComponent, toRef } from "vue";
|
|
32
|
+
import { twJoin } from "tailwind-merge";
|
|
33
|
+
import { useUI } from "../../composables/useUI";
|
|
34
|
+
import { mergeConfig } from "../../utils";
|
|
35
|
+
import appConfig from "#build/app.config";
|
|
36
|
+
import { meter } from "#ui/ui.config";
|
|
37
|
+
const config = mergeConfig(appConfig.ui.strategy, appConfig.ui.meter, meter);
|
|
38
|
+
export default defineComponent({
|
|
39
|
+
inheritAttrs: false,
|
|
40
|
+
slots: Object,
|
|
41
|
+
props: {
|
|
42
|
+
value: {
|
|
43
|
+
type: Number,
|
|
44
|
+
default: 0
|
|
45
|
+
},
|
|
46
|
+
min: {
|
|
47
|
+
type: Number,
|
|
48
|
+
default: 0
|
|
49
|
+
},
|
|
50
|
+
max: {
|
|
51
|
+
type: Number,
|
|
52
|
+
default: 100
|
|
53
|
+
},
|
|
54
|
+
indicator: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false
|
|
57
|
+
},
|
|
58
|
+
label: {
|
|
59
|
+
type: String,
|
|
60
|
+
default: null
|
|
61
|
+
},
|
|
62
|
+
size: {
|
|
63
|
+
type: String,
|
|
64
|
+
default: () => config.default.size,
|
|
65
|
+
validator(value) {
|
|
66
|
+
return Object.keys(config.meter.size).includes(value);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
color: {
|
|
70
|
+
type: String,
|
|
71
|
+
default: () => config.default.color,
|
|
72
|
+
validator(value) {
|
|
73
|
+
return [...appConfig.ui.colors, ...Object.keys(config.color)].includes(value);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
icon: {
|
|
77
|
+
type: String,
|
|
78
|
+
default: null
|
|
79
|
+
},
|
|
80
|
+
class: {
|
|
81
|
+
type: [String, Object, Array],
|
|
82
|
+
default: void 0
|
|
83
|
+
},
|
|
84
|
+
ui: {
|
|
85
|
+
type: Object,
|
|
86
|
+
default: void 0
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
setup(props) {
|
|
90
|
+
const { ui, attrs } = useUI("meter", toRef(props, "ui"), config, toRef(props, "class"));
|
|
91
|
+
function clampPercent(value, min, max) {
|
|
92
|
+
if (min == max) {
|
|
93
|
+
return value < min ? 0 : 100;
|
|
94
|
+
}
|
|
95
|
+
if (min > max) {
|
|
96
|
+
max = [min, min = max][0];
|
|
97
|
+
}
|
|
98
|
+
const percent2 = (value - min) / (max - min) * 100;
|
|
99
|
+
return Math.max(0, Math.min(100, percent2));
|
|
100
|
+
}
|
|
101
|
+
const indicatorContainerClass = computed(() => {
|
|
102
|
+
return twJoin(
|
|
103
|
+
ui.value.indicator.container
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
const indicatorClass = computed(() => {
|
|
107
|
+
return twJoin(
|
|
108
|
+
ui.value.indicator.text,
|
|
109
|
+
ui.value.indicator.size[props.size]
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
const meterClass = computed(() => {
|
|
113
|
+
return twJoin(
|
|
114
|
+
ui.value.meter.base,
|
|
115
|
+
ui.value.meter.background,
|
|
116
|
+
ui.value.meter.ring,
|
|
117
|
+
ui.value.meter.rounded,
|
|
118
|
+
ui.value.meter.shadow,
|
|
119
|
+
ui.value.color[props.color] ?? ui.value.meter.color.replaceAll("{color}", props.color),
|
|
120
|
+
ui.value.meter.size[props.size]
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
const meterAppearanceClass = computed(() => {
|
|
124
|
+
return twJoin(
|
|
125
|
+
ui.value.meter.appearance.inner,
|
|
126
|
+
ui.value.meter.appearance.meter,
|
|
127
|
+
ui.value.meter.appearance.bar,
|
|
128
|
+
ui.value.meter.appearance.value
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
const meterBarClass = computed(() => {
|
|
132
|
+
return twJoin(
|
|
133
|
+
ui.value.meter.bar.transition,
|
|
134
|
+
ui.value.meter.bar.ring,
|
|
135
|
+
ui.value.meter.bar.rounded,
|
|
136
|
+
ui.value.meter.bar.size[props.size]
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
const labelClass = computed(() => {
|
|
140
|
+
return twJoin(
|
|
141
|
+
ui.value.label.base,
|
|
142
|
+
ui.value.label.text,
|
|
143
|
+
ui.value.color[props.color] ?? ui.value.label.color.replaceAll("{color}", props.color),
|
|
144
|
+
ui.value.label.size[props.size]
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
const normalizedMin = computed(() => props.min > props.max ? props.max : props.min);
|
|
148
|
+
const normalizedMax = computed(() => props.max < props.min ? props.min : props.max);
|
|
149
|
+
const percent = computed(() => clampPercent(Number(props.value), normalizedMin.value, normalizedMax.value));
|
|
150
|
+
return {
|
|
151
|
+
// eslint-disable-next-line vue/no-dupe-keys
|
|
152
|
+
ui,
|
|
153
|
+
attrs,
|
|
154
|
+
indicatorContainerClass,
|
|
155
|
+
indicatorClass,
|
|
156
|
+
meterClass,
|
|
157
|
+
meterAppearanceClass,
|
|
158
|
+
meterBarClass,
|
|
159
|
+
labelClass,
|
|
160
|
+
normalizedMin,
|
|
161
|
+
normalizedMax,
|
|
162
|
+
percent
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
</script>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { SlotsType, PropType } from 'vue';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<{
|
|
3
|
+
value: {
|
|
4
|
+
type: NumberConstructor;
|
|
5
|
+
default: number;
|
|
6
|
+
};
|
|
7
|
+
min: {
|
|
8
|
+
type: NumberConstructor;
|
|
9
|
+
default: number;
|
|
10
|
+
};
|
|
11
|
+
max: {
|
|
12
|
+
type: NumberConstructor;
|
|
13
|
+
default: number;
|
|
14
|
+
};
|
|
15
|
+
indicator: {
|
|
16
|
+
type: BooleanConstructor;
|
|
17
|
+
default: boolean;
|
|
18
|
+
};
|
|
19
|
+
label: {
|
|
20
|
+
type: StringConstructor;
|
|
21
|
+
default: null;
|
|
22
|
+
};
|
|
23
|
+
size: {
|
|
24
|
+
type: PropType<"sm" | "md" | "xs" | "2xs" | "lg" | "xl" | "2xl">;
|
|
25
|
+
default: () => any;
|
|
26
|
+
validator(value: string): boolean;
|
|
27
|
+
};
|
|
28
|
+
color: {
|
|
29
|
+
type: PropType<any>;
|
|
30
|
+
default: () => any;
|
|
31
|
+
validator(value: string): boolean;
|
|
32
|
+
};
|
|
33
|
+
icon: {
|
|
34
|
+
type: StringConstructor;
|
|
35
|
+
default: null;
|
|
36
|
+
};
|
|
37
|
+
class: {
|
|
38
|
+
type: PropType<any>;
|
|
39
|
+
default: undefined;
|
|
40
|
+
};
|
|
41
|
+
ui: {
|
|
42
|
+
type: PropType<Partial<any>>;
|
|
43
|
+
default: undefined;
|
|
44
|
+
};
|
|
45
|
+
}, {
|
|
46
|
+
ui: import("vue").ComputedRef<any>;
|
|
47
|
+
attrs: import("vue").ComputedRef<Pick<{
|
|
48
|
+
[x: string]: unknown;
|
|
49
|
+
}, string>>;
|
|
50
|
+
indicatorContainerClass: import("vue").ComputedRef<string>;
|
|
51
|
+
indicatorClass: import("vue").ComputedRef<string>;
|
|
52
|
+
meterClass: import("vue").ComputedRef<string>;
|
|
53
|
+
meterAppearanceClass: import("vue").ComputedRef<string>;
|
|
54
|
+
meterBarClass: import("vue").ComputedRef<string>;
|
|
55
|
+
labelClass: import("vue").ComputedRef<string>;
|
|
56
|
+
normalizedMin: import("vue").ComputedRef<number>;
|
|
57
|
+
normalizedMax: import("vue").ComputedRef<number>;
|
|
58
|
+
percent: import("vue").ComputedRef<number>;
|
|
59
|
+
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
60
|
+
value: {
|
|
61
|
+
type: NumberConstructor;
|
|
62
|
+
default: number;
|
|
63
|
+
};
|
|
64
|
+
min: {
|
|
65
|
+
type: NumberConstructor;
|
|
66
|
+
default: number;
|
|
67
|
+
};
|
|
68
|
+
max: {
|
|
69
|
+
type: NumberConstructor;
|
|
70
|
+
default: number;
|
|
71
|
+
};
|
|
72
|
+
indicator: {
|
|
73
|
+
type: BooleanConstructor;
|
|
74
|
+
default: boolean;
|
|
75
|
+
};
|
|
76
|
+
label: {
|
|
77
|
+
type: StringConstructor;
|
|
78
|
+
default: null;
|
|
79
|
+
};
|
|
80
|
+
size: {
|
|
81
|
+
type: PropType<"sm" | "md" | "xs" | "2xs" | "lg" | "xl" | "2xl">;
|
|
82
|
+
default: () => any;
|
|
83
|
+
validator(value: string): boolean;
|
|
84
|
+
};
|
|
85
|
+
color: {
|
|
86
|
+
type: PropType<any>;
|
|
87
|
+
default: () => any;
|
|
88
|
+
validator(value: string): boolean;
|
|
89
|
+
};
|
|
90
|
+
icon: {
|
|
91
|
+
type: StringConstructor;
|
|
92
|
+
default: null;
|
|
93
|
+
};
|
|
94
|
+
class: {
|
|
95
|
+
type: PropType<any>;
|
|
96
|
+
default: undefined;
|
|
97
|
+
};
|
|
98
|
+
ui: {
|
|
99
|
+
type: PropType<Partial<any>>;
|
|
100
|
+
default: undefined;
|
|
101
|
+
};
|
|
102
|
+
}>>, {
|
|
103
|
+
icon: string;
|
|
104
|
+
color: any;
|
|
105
|
+
ui: Partial<any>;
|
|
106
|
+
class: any;
|
|
107
|
+
value: number;
|
|
108
|
+
label: string;
|
|
109
|
+
size: "sm" | "md" | "xs" | "2xs" | "lg" | "xl" | "2xl";
|
|
110
|
+
max: number;
|
|
111
|
+
min: number;
|
|
112
|
+
indicator: boolean;
|
|
113
|
+
}, SlotsType<{
|
|
114
|
+
indicator?: {
|
|
115
|
+
percent: number;
|
|
116
|
+
value: number;
|
|
117
|
+
} | undefined;
|
|
118
|
+
label?: {
|
|
119
|
+
percent: number;
|
|
120
|
+
value: number;
|
|
121
|
+
} | undefined;
|
|
122
|
+
}>>;
|
|
123
|
+
export default _default;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { VNode, SlotsType, PropType } from 'vue';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<{
|
|
3
|
+
min: {
|
|
4
|
+
type: NumberConstructor;
|
|
5
|
+
default: number;
|
|
6
|
+
};
|
|
7
|
+
max: {
|
|
8
|
+
type: NumberConstructor;
|
|
9
|
+
default: number;
|
|
10
|
+
};
|
|
11
|
+
size: {
|
|
12
|
+
type: PropType<"sm" | "md" | "xs" | "2xs" | "lg" | "xl" | "2xl">;
|
|
13
|
+
default: () => any;
|
|
14
|
+
validator(value: string): boolean;
|
|
15
|
+
};
|
|
16
|
+
indicator: {
|
|
17
|
+
type: BooleanConstructor;
|
|
18
|
+
default: boolean;
|
|
19
|
+
};
|
|
20
|
+
icon: {
|
|
21
|
+
type: StringConstructor;
|
|
22
|
+
default: string;
|
|
23
|
+
};
|
|
24
|
+
class: {
|
|
25
|
+
type: PropType<any>;
|
|
26
|
+
default: undefined;
|
|
27
|
+
};
|
|
28
|
+
ui: {
|
|
29
|
+
type: PropType<Partial<any>>;
|
|
30
|
+
default: undefined;
|
|
31
|
+
};
|
|
32
|
+
}, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
33
|
+
[key: string]: any;
|
|
34
|
+
}>, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
35
|
+
min: {
|
|
36
|
+
type: NumberConstructor;
|
|
37
|
+
default: number;
|
|
38
|
+
};
|
|
39
|
+
max: {
|
|
40
|
+
type: NumberConstructor;
|
|
41
|
+
default: number;
|
|
42
|
+
};
|
|
43
|
+
size: {
|
|
44
|
+
type: PropType<"sm" | "md" | "xs" | "2xs" | "lg" | "xl" | "2xl">;
|
|
45
|
+
default: () => any;
|
|
46
|
+
validator(value: string): boolean;
|
|
47
|
+
};
|
|
48
|
+
indicator: {
|
|
49
|
+
type: BooleanConstructor;
|
|
50
|
+
default: boolean;
|
|
51
|
+
};
|
|
52
|
+
icon: {
|
|
53
|
+
type: StringConstructor;
|
|
54
|
+
default: string;
|
|
55
|
+
};
|
|
56
|
+
class: {
|
|
57
|
+
type: PropType<any>;
|
|
58
|
+
default: undefined;
|
|
59
|
+
};
|
|
60
|
+
ui: {
|
|
61
|
+
type: PropType<Partial<any>>;
|
|
62
|
+
default: undefined;
|
|
63
|
+
};
|
|
64
|
+
}>>, {
|
|
65
|
+
icon: string;
|
|
66
|
+
ui: Partial<any>;
|
|
67
|
+
class: any;
|
|
68
|
+
size: "sm" | "md" | "xs" | "2xs" | "lg" | "xl" | "2xl";
|
|
69
|
+
max: number;
|
|
70
|
+
min: number;
|
|
71
|
+
indicator: boolean;
|
|
72
|
+
}, SlotsType<{
|
|
73
|
+
default?: any[] | undefined;
|
|
74
|
+
indicator?: {
|
|
75
|
+
percent: number;
|
|
76
|
+
} | undefined;
|
|
77
|
+
}>>;
|
|
78
|
+
export default _default;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { h, cloneVNode, computed, toRef, defineComponent } from "vue";
|
|
2
|
+
import { twJoin } from "tailwind-merge";
|
|
3
|
+
import UIcon from "./Icon.vue";
|
|
4
|
+
import { useUI } from "../../composables/useUI.mjs";
|
|
5
|
+
import { mergeConfig, getSlotsChildren } from "../../utils/index.mjs";
|
|
6
|
+
import appConfig from "#build/app.config";
|
|
7
|
+
import { meter, meterGroup } from "#ui/ui.config";
|
|
8
|
+
const meterConfig = mergeConfig(appConfig.ui.strategy, appConfig.ui.meter, meter);
|
|
9
|
+
const meterGroupConfig = mergeConfig(appConfig.ui.strategy, appConfig.ui.meterGroup, meterGroup);
|
|
10
|
+
export default defineComponent({
|
|
11
|
+
components: {
|
|
12
|
+
UIcon
|
|
13
|
+
},
|
|
14
|
+
inheritAttrs: false,
|
|
15
|
+
slots: Object,
|
|
16
|
+
props: {
|
|
17
|
+
min: {
|
|
18
|
+
type: Number,
|
|
19
|
+
default: 0
|
|
20
|
+
},
|
|
21
|
+
max: {
|
|
22
|
+
type: Number,
|
|
23
|
+
default: 100
|
|
24
|
+
},
|
|
25
|
+
size: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: () => meterConfig.default.size,
|
|
28
|
+
validator(value) {
|
|
29
|
+
return Object.keys(meterConfig.meter.bar.size).includes(value);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
indicator: {
|
|
33
|
+
type: Boolean,
|
|
34
|
+
default: false
|
|
35
|
+
},
|
|
36
|
+
icon: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: "i-heroicons-minus"
|
|
39
|
+
},
|
|
40
|
+
class: {
|
|
41
|
+
type: [String, Object, Array],
|
|
42
|
+
default: void 0
|
|
43
|
+
},
|
|
44
|
+
ui: {
|
|
45
|
+
type: Object,
|
|
46
|
+
default: void 0
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
setup(props, { slots }) {
|
|
50
|
+
const { ui, attrs } = useUI("meterGroup", toRef(props, "ui"), meterGroupConfig);
|
|
51
|
+
const { ui: uiMeter } = useUI("meter", void 0, meterConfig);
|
|
52
|
+
if (!slots.default) {
|
|
53
|
+
throw new Error("Meter Group has no Meter children.");
|
|
54
|
+
}
|
|
55
|
+
const normalizedMin = computed(() => props.min > props.max ? props.max : props.min);
|
|
56
|
+
const normalizedMax = computed(() => props.max < props.min ? props.min : props.max);
|
|
57
|
+
const children = computed(() => getSlotsChildren(slots));
|
|
58
|
+
const rounded = computed(() => {
|
|
59
|
+
const roundedMap = {
|
|
60
|
+
"rounded-none": { left: "rounded-s-none", right: "rounded-e-none" },
|
|
61
|
+
"rounded-sm": { left: "rounded-s-sm", right: "rounded-e-sm" },
|
|
62
|
+
rounded: { left: "rounded-s", right: "rounded-e" },
|
|
63
|
+
"rounded-md": { left: "rounded-s-md", right: "rounded-e-md" },
|
|
64
|
+
"rounded-lg": { left: "rounded-s-lg", right: "rounded-e-lg" },
|
|
65
|
+
"rounded-xl": { left: "rounded-s-xl", right: "rounded-e-xl" },
|
|
66
|
+
"rounded-2xl": { left: "rounded-s-2xl", right: "rounded-e-2xl" },
|
|
67
|
+
"rounded-3xl": { left: "rounded-s-3xl", right: "rounded-e-3xl" },
|
|
68
|
+
"rounded-full": { left: "rounded-s-full", right: "rounded-e-full" }
|
|
69
|
+
};
|
|
70
|
+
return roundedMap[ui.value.rounded];
|
|
71
|
+
});
|
|
72
|
+
function clampPercent(value, min, max) {
|
|
73
|
+
if (min == max) {
|
|
74
|
+
return value < min ? 0 : 100;
|
|
75
|
+
}
|
|
76
|
+
if (min > max) {
|
|
77
|
+
max = [min, min = max][0];
|
|
78
|
+
}
|
|
79
|
+
const percent2 = (value - min) / (max - min) * 100;
|
|
80
|
+
return Math.max(0, Math.min(100, percent2));
|
|
81
|
+
}
|
|
82
|
+
const labels = computed(() => {
|
|
83
|
+
return children.value.map((node) => node.props.label);
|
|
84
|
+
});
|
|
85
|
+
const percents = computed(() => {
|
|
86
|
+
return children.value.map((node) => clampPercent(node.props.value, props.min, props.max));
|
|
87
|
+
});
|
|
88
|
+
const percent = computed(() => {
|
|
89
|
+
return Math.max(0, Math.max(percents.value.reduce((prev, percent2) => prev + percent2, 0)));
|
|
90
|
+
});
|
|
91
|
+
const clones = computed(() => children.value.map((node, index) => {
|
|
92
|
+
const vProps = {};
|
|
93
|
+
vProps.style = { width: `${percents.value[index]}%` };
|
|
94
|
+
vProps.size = props.size;
|
|
95
|
+
vProps.min = normalizedMin.value;
|
|
96
|
+
vProps.max = normalizedMax.value;
|
|
97
|
+
vProps.ui = node.props?.ui || {};
|
|
98
|
+
vProps.ui.wrapper = node.props?.ui?.wrapper || "";
|
|
99
|
+
vProps.ui.wrapper += [
|
|
100
|
+
node.props?.ui?.wrapper,
|
|
101
|
+
props.ui?.meter?.background || ui.value.background,
|
|
102
|
+
ui.value.transition
|
|
103
|
+
].filter(Boolean).join(" ");
|
|
104
|
+
vProps.ui.meter = node.props?.ui?.meter || {};
|
|
105
|
+
vProps.ui.meter.background = `bg-${node.props.color}-500 dark:bg-${node.props.color}-400`;
|
|
106
|
+
vProps.ui.meter.rounded = "rounded-none";
|
|
107
|
+
vProps.ui.meter.bar = node.props?.ui?.meter?.bar || {};
|
|
108
|
+
if (index === 0) {
|
|
109
|
+
vProps.ui.meter.rounded = `${rounded.value.left} rounded-e-none`;
|
|
110
|
+
}
|
|
111
|
+
if (index === children.value.length - 1) {
|
|
112
|
+
vProps.ui.meter.rounded = `${rounded.value.right} rounded-s-none`;
|
|
113
|
+
}
|
|
114
|
+
labels.value[index] = node.props.label;
|
|
115
|
+
const clone = cloneVNode(node, vProps);
|
|
116
|
+
delete clone.children?.label;
|
|
117
|
+
delete clone.props.indicator;
|
|
118
|
+
delete clone.props.label;
|
|
119
|
+
return clone;
|
|
120
|
+
}));
|
|
121
|
+
const baseClass = computed(() => {
|
|
122
|
+
return twJoin(
|
|
123
|
+
ui.value.base,
|
|
124
|
+
ui.value.background,
|
|
125
|
+
ui.value.rounded,
|
|
126
|
+
ui.value.shadow,
|
|
127
|
+
uiMeter.value.meter.size[props.size]
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
const indicatorContainerClass = computed(() => {
|
|
131
|
+
return twJoin(
|
|
132
|
+
uiMeter.value.indicator.container
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
const indicatorClass = computed(() => {
|
|
136
|
+
return twJoin(
|
|
137
|
+
uiMeter.value.indicator.text,
|
|
138
|
+
uiMeter.value.indicator.size[props.size]
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
const vNodeChildren = computed(() => {
|
|
142
|
+
const vNodeSlots = [
|
|
143
|
+
void 0,
|
|
144
|
+
h("div", { class: baseClass.value }, clones.value),
|
|
145
|
+
void 0
|
|
146
|
+
];
|
|
147
|
+
if (props.indicator) {
|
|
148
|
+
vNodeSlots[0] = h("div", { class: indicatorContainerClass.value }, [
|
|
149
|
+
h("div", { class: indicatorClass.value, style: { width: `${percent.value}%` } }, Math.round(percent.value) + "%")
|
|
150
|
+
]);
|
|
151
|
+
} else if (slots.indicator) {
|
|
152
|
+
vNodeSlots[0] = slots.indicator({ percent: percent.value });
|
|
153
|
+
}
|
|
154
|
+
vNodeSlots[2] = h("ol", { class: "list-disc list-inside" }, labels.value.map((label, key) => {
|
|
155
|
+
const labelClass = computed(() => {
|
|
156
|
+
return twJoin(
|
|
157
|
+
uiMeter.value.label.base,
|
|
158
|
+
uiMeter.value.label.text,
|
|
159
|
+
uiMeter.value.color[clones.value[key]?.props.color] ?? uiMeter.value.label.color.replaceAll("{color}", clones.value[key]?.props.color ?? uiMeter.value.default.color),
|
|
160
|
+
uiMeter.value.label.size[props.size]
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
return h("li", { class: labelClass.value }, [
|
|
164
|
+
h(UIcon, { name: clones.value[key]?.props.icon ?? props.icon }),
|
|
165
|
+
`${label} (${Math.round(percents.value[key])}%)`
|
|
166
|
+
]);
|
|
167
|
+
}));
|
|
168
|
+
return vNodeSlots;
|
|
169
|
+
});
|
|
170
|
+
return () => h("div", { class: ui.value.wrapper, ...attrs.value }, vNodeChildren.value);
|
|
171
|
+
}
|
|
172
|
+
});
|