@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.
Files changed (71) hide show
  1. package/dist/module.d.mts +270 -2
  2. package/dist/module.d.ts +270 -2
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +21 -2
  5. package/dist/runtime/components/data/Table.vue +8 -6
  6. package/dist/runtime/components/data/Table.vue.d.ts +2 -1
  7. package/dist/runtime/components/elements/Accordion.vue +15 -13
  8. package/dist/runtime/components/elements/Accordion.vue.d.ts +5 -2
  9. package/dist/runtime/components/elements/Button.vue.d.ts +2 -2
  10. package/dist/runtime/components/elements/Dropdown.vue +31 -25
  11. package/dist/runtime/components/elements/Dropdown.vue.d.ts +2 -0
  12. package/dist/runtime/components/elements/Meter.vue +166 -0
  13. package/dist/runtime/components/elements/Meter.vue.d.ts +123 -0
  14. package/dist/runtime/components/elements/MeterGroup.d.ts +78 -0
  15. package/dist/runtime/components/elements/MeterGroup.mjs +172 -0
  16. package/dist/runtime/components/elements/Progress.vue +284 -0
  17. package/dist/runtime/components/elements/Progress.vue.d.ts +2 -0
  18. package/dist/runtime/components/forms/Checkbox.vue.d.ts +2 -2
  19. package/dist/runtime/components/forms/Form.vue +32 -7
  20. package/dist/runtime/components/forms/Form.vue.d.ts +2 -1
  21. package/dist/runtime/components/forms/Input.vue +5 -1
  22. package/dist/runtime/components/forms/Input.vue.d.ts +12 -3
  23. package/dist/runtime/components/forms/Radio.vue +10 -9
  24. package/dist/runtime/components/forms/Radio.vue.d.ts +3 -3
  25. package/dist/runtime/components/forms/RadioGroup.vue +136 -0
  26. package/dist/runtime/components/forms/RadioGroup.vue.d.ts +118 -0
  27. package/dist/runtime/components/forms/Range.vue.d.ts +3 -3
  28. package/dist/runtime/components/forms/Select.vue.d.ts +2 -2
  29. package/dist/runtime/components/forms/SelectMenu.vue +62 -57
  30. package/dist/runtime/components/forms/SelectMenu.vue.d.ts +6 -5
  31. package/dist/runtime/components/forms/Textarea.vue +5 -1
  32. package/dist/runtime/components/forms/Textarea.vue.d.ts +11 -2
  33. package/dist/runtime/components/forms/Toggle.vue.d.ts +2 -2
  34. package/dist/runtime/components/layout/Divider.vue +107 -0
  35. package/dist/runtime/components/layout/Divider.vue.d.ts +82 -0
  36. package/dist/runtime/components/navigation/CommandPalette.vue +10 -3
  37. package/dist/runtime/components/navigation/CommandPalette.vue.d.ts +1 -1
  38. package/dist/runtime/components/navigation/Pagination.vue +65 -9
  39. package/dist/runtime/components/navigation/Pagination.vue.d.ts +41 -3
  40. package/dist/runtime/components/navigation/Tabs.vue +1 -1
  41. package/dist/runtime/components/overlays/ContextMenu.vue +7 -2
  42. package/dist/runtime/components/overlays/ContextMenu.vue.d.ts +2 -1
  43. package/dist/runtime/components/overlays/Modal.vue +1 -1
  44. package/dist/runtime/components/overlays/Modal.vue.d.ts +1 -1
  45. package/dist/runtime/components/overlays/Notification.vue +7 -1
  46. package/dist/runtime/components/overlays/Notifications.vue +1 -1
  47. package/dist/runtime/components/overlays/Popover.vue +22 -7
  48. package/dist/runtime/components/overlays/Popover.vue.d.ts +14 -0
  49. package/dist/runtime/components/overlays/Slideover.vue.d.ts +1 -1
  50. package/dist/runtime/components/overlays/Tooltip.vue +16 -10
  51. package/dist/runtime/components/overlays/Tooltip.vue.d.ts +1 -0
  52. package/dist/runtime/composables/useFormGroup.d.ts +3 -3
  53. package/dist/runtime/composables/useFormGroup.mjs +17 -6
  54. package/dist/runtime/composables/usePopper.d.ts +3 -3
  55. package/dist/runtime/composables/usePopper.mjs +7 -1
  56. package/dist/runtime/composables/useUI.d.ts +2 -2
  57. package/dist/runtime/composables/useUI.mjs +2 -2
  58. package/dist/runtime/types/command-palette.d.ts +1 -0
  59. package/dist/runtime/types/form.d.ts +13 -6
  60. package/dist/runtime/types/index.d.ts +2 -0
  61. package/dist/runtime/types/meter.d.ts +5 -0
  62. package/dist/runtime/types/popper.d.ts +1 -0
  63. package/dist/runtime/types/progress.d.ts +4 -0
  64. package/dist/runtime/types/utils.d.ts +1 -1
  65. package/dist/runtime/ui.config.d.ts +263 -0
  66. package/dist/runtime/ui.config.mjs +263 -19
  67. package/dist/types.d.mts +1 -1
  68. package/dist/types.d.ts +1 -1
  69. package/package.json +19 -19
  70. package/dist/runtime/utils/StateEmitter.d.ts +0 -17
  71. 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
- <HMenuItems :class="[ui.base, ui.divide, ui.ring, ui.rounded, ui.shadow, ui.background, ui.height]" static>
21
- <div v-for="(subItems, index) of items" :key="index" :class="ui.padding">
22
- <HMenuItem v-for="(item, subIndex) of subItems" :key="subIndex" v-slot="{ active, disabled: itemDisabled }" :disabled="item.disabled">
23
- <ULink
24
- v-bind="omit(item, ['label', 'slot', 'icon', 'iconClass', 'avatar', 'shortcuts', 'disabled', 'click'])"
25
- :class="[ui.item.base, ui.item.padding, ui.item.size, ui.item.rounded, active ? ui.item.active : ui.item.inactive, itemDisabled && ui.item.disabled]"
26
- @click="item.click"
27
- >
28
- <slot :name="item.slot || 'item'" :item="item">
29
- <UIcon v-if="item.icon" :name="item.icon" :class="[ui.item.icon.base, active ? ui.item.icon.active : ui.item.icon.inactive, item.iconClass]" />
30
- <UAvatar v-else-if="item.avatar" v-bind="{ size: ui.item.avatar.size, ...item.avatar }" :class="ui.item.avatar.base" />
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
- <span class="truncate">{{ item.label }}</span>
35
+ <span class="truncate">{{ item.label }}</span>
33
36
 
34
- <span v-if="item.shortcuts?.length" :class="ui.item.shortcuts">
35
- <UKbd v-for="shortcut of item.shortcuts" :key="shortcut">{{ shortcut }}</UKbd>
36
- </span>
37
- </slot>
38
- </ULink>
39
- </HMenuItem>
40
- </div>
41
- </HMenuItems>
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
+ });