v-nuxt-ui 0.2.34 → 0.3.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 (95) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/AsyncSelect.vue +13 -2
  3. package/dist/runtime/components/ScrollArea.vue +2 -2
  4. package/dist/runtime/components/Select.vue +13 -2
  5. package/dist/runtime/components/Watermark.d.vue.ts +2 -2
  6. package/dist/runtime/components/Watermark.vue.d.ts +2 -2
  7. package/dist/runtime/components/button/Confirm.d.vue.ts +22 -0
  8. package/dist/runtime/components/button/Confirm.vue +47 -0
  9. package/dist/runtime/components/button/Confirm.vue.d.ts +22 -0
  10. package/dist/runtime/components/button/Theme.vue +7 -13
  11. package/dist/runtime/components/date-picker/Input.d.vue.ts +1 -0
  12. package/dist/runtime/components/date-picker/Input.vue +12 -3
  13. package/dist/runtime/components/date-picker/Input.vue.d.ts +1 -0
  14. package/dist/runtime/components/form/save-modal-template/WithApi.vue +1 -2
  15. package/dist/runtime/components/form/save-modal-template/index.vue +23 -23
  16. package/dist/runtime/components/layout/button/ThemePicker.vue +2 -2
  17. package/dist/runtime/components/layout/default.vue +10 -4
  18. package/dist/runtime/components/simple-table/index.d.vue.ts +1 -1
  19. package/dist/runtime/components/simple-table/index.vue +72 -1
  20. package/dist/runtime/components/simple-table/index.vue.d.ts +1 -1
  21. package/dist/runtime/components/sys/department/SaveModal.vue +0 -1
  22. package/dist/runtime/components/sys/flow/EditNodeModal.vue +5 -4
  23. package/dist/runtime/components/sys/flow/SaveModal.vue +0 -1
  24. package/dist/runtime/components/sys/menu/SaveModal.vue +0 -1
  25. package/dist/runtime/components/sys/role/SaveModal.vue +0 -1
  26. package/dist/runtime/components/sys/table/SaveModal.vue +0 -1
  27. package/dist/runtime/components/sys/table/TableColumnModal.vue +5 -4
  28. package/dist/runtime/components/sys/user/SaveModal.vue +0 -1
  29. package/dist/runtime/components/sys/user/Table.vue +19 -29
  30. package/dist/runtime/components/table/Page.vue +23 -2
  31. package/dist/runtime/components/table/Pagination.vue +1 -1
  32. package/dist/runtime/components/table/header/index.vue +231 -84
  33. package/dist/runtime/components/table/header/settings/columns/DndList.d.vue.ts +1 -0
  34. package/dist/runtime/components/table/header/settings/columns/DndList.vue +3 -1
  35. package/dist/runtime/components/table/header/settings/columns/DndList.vue.d.ts +1 -0
  36. package/dist/runtime/components/table/header/settings/columns/Item.d.vue.ts +1 -0
  37. package/dist/runtime/components/table/header/settings/columns/Item.vue +7 -3
  38. package/dist/runtime/components/table/header/settings/columns/Item.vue.d.ts +1 -0
  39. package/dist/runtime/components/table/header/settings/columns/index.d.vue.ts +3 -3
  40. package/dist/runtime/components/table/header/settings/columns/index.vue +7 -5
  41. package/dist/runtime/components/table/header/settings/columns/index.vue.d.ts +3 -3
  42. package/dist/runtime/components/table/header/settings/index.d.vue.ts +3 -2
  43. package/dist/runtime/components/table/header/settings/index.vue +5 -4
  44. package/dist/runtime/components/table/header/settings/index.vue.d.ts +3 -2
  45. package/dist/runtime/components/table/query/order/Newer.d.vue.ts +1 -0
  46. package/dist/runtime/components/table/query/order/Newer.vue +9 -2
  47. package/dist/runtime/components/table/query/order/Newer.vue.d.ts +1 -0
  48. package/dist/runtime/components/table/query/order/index.vue +46 -54
  49. package/dist/runtime/components/table/query/order/{Item.d.vue.ts → item.d.vue.ts} +2 -0
  50. package/dist/runtime/components/table/query/order/{Item.vue → item.vue} +25 -17
  51. package/dist/runtime/components/table/query/order/{Item.vue.d.ts → item.vue.d.ts} +2 -0
  52. package/dist/runtime/components/table/query/where/Newer.vue +2 -2
  53. package/dist/runtime/components/table/query/where/index.vue +90 -77
  54. package/dist/runtime/components/table/query/where/simple/item/ColumnPicker.vue +8 -7
  55. package/dist/runtime/components/table/query/where/simple/item/OprPicker.d.vue.ts +1 -0
  56. package/dist/runtime/components/table/query/where/simple/item/OprPicker.vue +6 -1
  57. package/dist/runtime/components/table/query/where/simple/item/OprPicker.vue.d.ts +1 -0
  58. package/dist/runtime/components/table/query/where/simple/item/index.d.vue.ts +3 -1
  59. package/dist/runtime/components/table/query/where/simple/item/index.vue +84 -39
  60. package/dist/runtime/components/table/query/where/simple/item/index.vue.d.ts +3 -1
  61. package/dist/runtime/components/table/query/where/simple/item/opr/AsyncSelect.vue +0 -1
  62. package/dist/runtime/components/table/query/where/simple/item/opr/DatePicker.d.vue.ts +1 -0
  63. package/dist/runtime/components/table/query/where/simple/item/opr/DatePicker.vue +42 -40
  64. package/dist/runtime/components/table/query/where/simple/item/opr/DatePicker.vue.d.ts +1 -0
  65. package/dist/runtime/components/table/query/where/simple/item/opr/Input.vue +3 -0
  66. package/dist/runtime/components/table/query/where/simple/item/opr/Select.vue +0 -1
  67. package/dist/runtime/components/table/query/where/simple/item/opr/index.vue +3 -0
  68. package/dist/runtime/composables/api/useApi.js +1 -0
  69. package/dist/runtime/composables/form/useForm.d.ts +2 -2
  70. package/dist/runtime/composables/form/useForm.js +10 -9
  71. package/dist/runtime/composables/table/useTable.js +9 -1
  72. package/dist/runtime/composables/table/useTableColumns.d.ts +1 -1
  73. package/dist/runtime/composables/table/useTableColumns.js +2 -2
  74. package/dist/runtime/composables/table/useTableQuery.d.ts +1 -0
  75. package/dist/runtime/composables/table/useTableQuery.js +8 -3
  76. package/dist/runtime/composables/table/useTableView.js +209 -11
  77. package/dist/runtime/composables/useTheme.js +10 -3
  78. package/dist/runtime/constants/columns.js +6 -6
  79. package/dist/runtime/types/components/form/index.d.ts +1 -1
  80. package/dist/runtime/types/components/table/column.d.ts +3 -1
  81. package/dist/runtime/types/components/table/header.d.ts +3 -1
  82. package/dist/runtime/types/components/table/query/order.d.ts +2 -0
  83. package/dist/runtime/types/components/table/query/where.d.ts +0 -1
  84. package/dist/runtime/types/query.d.ts +1 -0
  85. package/dist/runtime/types/storage.d.ts +1 -0
  86. package/package.json +1 -1
  87. package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.d.vue.ts +0 -19
  88. package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.vue +0 -111
  89. package/dist/runtime/components/form/save-model-template/ConfirmUpdateModal.vue.d.ts +0 -19
  90. package/dist/runtime/components/form/save-model-template/WithApi.d.vue.ts +0 -19
  91. package/dist/runtime/components/form/save-model-template/WithApi.vue +0 -37
  92. package/dist/runtime/components/form/save-model-template/WithApi.vue.d.ts +0 -19
  93. package/dist/runtime/components/form/save-model-template/index.d.vue.ts +0 -21
  94. package/dist/runtime/components/form/save-model-template/index.vue +0 -123
  95. package/dist/runtime/components/form/save-model-template/index.vue.d.ts +0 -21
package/dist/module.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "dependencies": [
8
8
  "@nuxt/ui"
9
9
  ],
10
- "version": "0.2.34",
10
+ "version": "0.3.0",
11
11
  "builder": {
12
12
  "@nuxt/module-builder": "1.0.2",
13
13
  "unbuild": "3.6.1"
@@ -147,6 +147,12 @@ function findLabel(tagItem) {
147
147
  const match = items.value.find((i) => i != null && String(i.value) === String(tagItem));
148
148
  return match?.label ?? String(tagItem ?? "");
149
149
  }
150
+ const showPlaceholder = computed(() => {
151
+ if (props.multiple) {
152
+ return !modelValue.value.values || Array.isArray(modelValue.value.values) && modelValue.value.values.length === 0 ? props.placeholder : "";
153
+ }
154
+ return !modelValue.value.values ? props.placeholder : "";
155
+ });
150
156
  </script>
151
157
 
152
158
  <template>
@@ -158,7 +164,7 @@ function findLabel(tagItem) {
158
164
  :items="items"
159
165
  :multiple="multiple"
160
166
  :size="size"
161
- :placeholder="placeholder"
167
+ :placeholder="showPlaceholder && placeholder"
162
168
  :create-item="canCreate && createModalComponent && {
163
169
  position: 'top',
164
170
  when: 'always'
@@ -166,13 +172,18 @@ function findLabel(tagItem) {
166
172
  color="neutral"
167
173
  delete-icon="i-lucide-trash"
168
174
  value-key="value"
169
- clear
175
+ :clear="{
176
+ ui: {
177
+ leadingIcon: 'size-3 text-dimmed'
178
+ }
179
+ }"
170
180
  clear-icon="i-lucide-circle-x"
171
181
  :icon="icon"
172
182
  :loading="fetching"
173
183
  :disabled="disabled"
174
184
  open-on-focus
175
185
  trailing
186
+ trailing-icon=""
176
187
  ignore-filter
177
188
  :ui="ui"
178
189
  :content="{
@@ -165,7 +165,7 @@ onActivated(() => {
165
165
  </ScrollAreaViewport>
166
166
 
167
167
  <ScrollAreaScrollbar
168
- class="flex select-none touch-none p-0.5 z-99 data-[state=visible]:animate-[fade-in_300ms_ease-in] data-[state=hidden]:animate-[fade-out_300ms_ease-out] data-[orientation=vertical]:w-2 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:h-2"
168
+ class="flex select-none touch-none p-0.5 z-99 transition-[width,height] duration-150 ease-out data-[state=visible]:animate-[fade-in_300ms_ease-in] data-[state=hidden]:animate-[fade-out_300ms_ease-out] data-[orientation=vertical]:w-2 data-[orientation=vertical]:hover:w-3 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:h-2 data-[orientation=horizontal]:hover:h-3"
169
169
  orientation="vertical"
170
170
  >
171
171
  <ScrollAreaThumb
@@ -174,7 +174,7 @@ onActivated(() => {
174
174
  </ScrollAreaScrollbar>
175
175
 
176
176
  <ScrollAreaScrollbar
177
- class="flex select-none touch-none p-0.5 z-99 data-[state=visible]:animate-[fade-in_300ms_ease-in] data-[state=hidden]:animate-[fade-out_300ms_ease-out] data-[orientation=vertical]:w-2 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:h-2"
177
+ class="flex select-none touch-none p-0.5 z-99 transition-[width,height] duration-150 ease-out data-[state=visible]:animate-[fade-in_300ms_ease-in] data-[state=hidden]:animate-[fade-out_300ms_ease-out] data-[orientation=vertical]:w-2 data-[orientation=vertical]:hover:w-3 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:h-2 data-[orientation=horizontal]:hover:h-3"
178
178
  orientation="horizontal"
179
179
  >
180
180
  <UTooltip
@@ -41,6 +41,12 @@ defineExpose({
41
41
  inputMenuRef.value?.inputRef.focus();
42
42
  }
43
43
  });
44
+ const showPlaceholder = computed(() => {
45
+ if (props.multiple) {
46
+ return !modelValue.value || Array.isArray(modelValue.value) && modelValue.value.length === 0 ? props.placeholder : "";
47
+ }
48
+ return !modelValue.value ? props.placeholder : "";
49
+ });
44
50
  </script>
45
51
 
46
52
  <template>
@@ -50,18 +56,23 @@ defineExpose({
50
56
  v-model:search-term="searchTerm"
51
57
  v-model="modelValue"
52
58
  :items="filteredItems"
53
- :placeholder="placeholder"
59
+ :placeholder="showPlaceholder && placeholder"
54
60
  :multiple="multiple"
55
61
  :size="size"
56
62
  color="neutral"
57
63
  delete-icon="i-lucide-trash"
58
64
  value-key="value"
59
- clear
65
+ :clear="{
66
+ ui: {
67
+ leadingIcon: 'size-3 text-dimmed'
68
+ }
69
+ }"
60
70
  clear-icon="i-lucide-circle-x"
61
71
  :icon="icon"
62
72
  :disabled="disabled"
63
73
  open-on-focus
64
74
  trailing
75
+ trailing-icon=""
65
76
  ignore-filter
66
77
  :ui="ui"
67
78
  :content="{
@@ -26,10 +26,10 @@ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, i
26
26
  rotate: number;
27
27
  fontColor: string;
28
28
  fontSize: number;
29
+ debug: boolean;
30
+ gap: number;
29
31
  fontWeight: string | number;
30
32
  lineHeight: number;
31
- gap: number;
32
- debug: boolean;
33
33
  textAlign: "left" | "center" | "right";
34
34
  xOffset: number;
35
35
  yOffset: number;
@@ -26,10 +26,10 @@ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, i
26
26
  rotate: number;
27
27
  fontColor: string;
28
28
  fontSize: number;
29
+ debug: boolean;
30
+ gap: number;
29
31
  fontWeight: string | number;
30
32
  lineHeight: number;
31
- gap: number;
32
- debug: boolean;
33
33
  textAlign: "left" | "center" | "right";
34
34
  xOffset: number;
35
35
  yOffset: number;
@@ -0,0 +1,22 @@
1
+ import type { ButtonProps } from '@nuxt/ui';
2
+ type __VLS_Props = {
3
+ button?: ButtonProps;
4
+ confirmButton?: ButtonProps;
5
+ resetOnMouseleave?: boolean;
6
+ ui?: Record<string, any>;
7
+ };
8
+ type __VLS_ModelProps = {
9
+ 'confirming'?: boolean;
10
+ };
11
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
12
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
+ confirm: () => any;
14
+ "update:confirming": (value: boolean) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
16
+ onConfirm?: (() => any) | undefined;
17
+ "onUpdate:confirming"?: ((value: boolean) => any) | undefined;
18
+ }>, {
19
+ resetOnMouseleave: boolean;
20
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
@@ -0,0 +1,47 @@
1
+ <script setup>
2
+ import defu from "defu";
3
+ import { computed } from "vue";
4
+ const props = defineProps({
5
+ button: { type: Object, required: false },
6
+ confirmButton: { type: Object, required: false },
7
+ resetOnMouseleave: { type: Boolean, required: false, default: true },
8
+ ui: { type: Object, required: false }
9
+ });
10
+ const emit = defineEmits(["confirm"]);
11
+ const buttonProps = computed(() => defu(props.button, {
12
+ icon: "i-lucide-x",
13
+ color: "neutral",
14
+ variant: "link",
15
+ size: "sm"
16
+ }));
17
+ const confirmButtonProps = computed(() => defu(props.confirmButton, {
18
+ icon: "i-lucide-x",
19
+ color: "error",
20
+ variant: "ghost",
21
+ size: "sm",
22
+ label: "\u786E\u8BA4"
23
+ }));
24
+ const confirming = defineModel("confirming", { type: Boolean, ...{ default: false } });
25
+ const activeButton = computed(() => confirming.value ? confirmButtonProps.value : buttonProps.value);
26
+ const onClick = () => {
27
+ if (activeButton.value?.disabled) return;
28
+ if (!confirming.value) {
29
+ confirming.value = true;
30
+ return;
31
+ }
32
+ confirming.value = false;
33
+ emit("confirm");
34
+ };
35
+ </script>
36
+
37
+ <template>
38
+ <UButton
39
+ v-bind="activeButton"
40
+ :ui="ui"
41
+ class="transition-all duration-200 ease-out"
42
+ @click="onClick"
43
+ @mouseleave="() => {
44
+ if (resetOnMouseleave) confirming = false;
45
+ }"
46
+ />
47
+ </template>
@@ -0,0 +1,22 @@
1
+ import type { ButtonProps } from '@nuxt/ui';
2
+ type __VLS_Props = {
3
+ button?: ButtonProps;
4
+ confirmButton?: ButtonProps;
5
+ resetOnMouseleave?: boolean;
6
+ ui?: Record<string, any>;
7
+ };
8
+ type __VLS_ModelProps = {
9
+ 'confirming'?: boolean;
10
+ };
11
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
12
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
+ confirm: () => any;
14
+ "update:confirming": (value: boolean) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
16
+ onConfirm?: (() => any) | undefined;
17
+ "onUpdate:confirming"?: ((value: boolean) => any) | undefined;
18
+ }>, {
19
+ resetOnMouseleave: boolean;
20
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
@@ -1,8 +1,6 @@
1
1
  <script setup>
2
- import { computed } from "vue";
3
2
  import { getEmojiFlag } from "#v/utils";
4
- import { useColorMode } from "@vueuse/core";
5
- const props = defineProps({
3
+ defineProps({
6
4
  label: { type: String, required: true },
7
5
  icon: { type: String, required: false },
8
6
  chip: { type: String, required: false },
@@ -10,14 +8,6 @@ const props = defineProps({
10
8
  selected: { type: Boolean, required: false }
11
9
  });
12
10
  const slots = defineSlots();
13
- const colorMode = useColorMode();
14
- const emojiFlag = computed(() => props.locale ? getEmojiFlag(props.locale) : "");
15
- const chipColor = computed(() => {
16
- if (!props.chip) return void 0;
17
- if (props.chip === "black") return "black";
18
- const shade = colorMode.value === "dark" ? "400" : "500";
19
- return `var(--color-${props.chip}-${shade})`;
20
- });
21
11
  </script>
22
12
 
23
13
  <template>
@@ -34,11 +24,15 @@ const chipColor = computed(() => {
34
24
  <slot v-if="chip" name="leading">
35
25
  <span
36
26
  class="inline-block size-2 rounded-full"
37
- :style="{ backgroundColor: chipColor }"
27
+ :class="chip === 'black' ? 'bg-black dark:bg-white' : 'bg-(--chip-color-light) dark:bg-(--chip-color-dark)'"
28
+ :style="chip && chip !== 'black' ? {
29
+ '--chip-color-light': `var(--color-${chip}-500)`,
30
+ '--chip-color-dark': `var(--color-${chip}-400)`
31
+ } : void 0"
38
32
  />
39
33
  </slot>
40
34
  <slot v-else-if="locale" name="leading">
41
- {{ emojiFlag }}
35
+ {{ getEmojiFlag(locale) }}
42
36
  </slot>
43
37
  <slot v-else name="leading" />
44
38
  </template>
@@ -4,6 +4,7 @@ type __VLS_Props = {
4
4
  size?: InputProps['size'];
5
5
  icon?: InputProps['icon'];
6
6
  inputClass?: string;
7
+ roundedNone?: boolean;
7
8
  };
8
9
  type __VLS_ModelProps = {
9
10
  'value': undefined | string;
@@ -6,7 +6,8 @@ defineProps({
6
6
  placeholder: { type: String, required: false },
7
7
  size: { type: null, required: false },
8
8
  icon: { type: null, required: false, default: "i-lucide-calendar" },
9
- inputClass: { type: String, required: false }
9
+ inputClass: { type: String, required: false },
10
+ roundedNone: { type: Boolean, required: false }
10
11
  });
11
12
  const value = defineModel("value", { type: null, ...{ required: true } });
12
13
  const emit = defineEmits(["focus", "blur"]);
@@ -40,7 +41,9 @@ const onInput = () => {
40
41
  isInternalUpdate = false;
41
42
  }
42
43
  };
43
- const handleClear = () => {
44
+ const handleClear = (e) => {
45
+ e.preventDefault();
46
+ e.stopPropagation();
44
47
  inputBuffer.value = "";
45
48
  isInternalUpdate = true;
46
49
  value.value = void 0;
@@ -63,6 +66,9 @@ defineExpose({
63
66
  :placeholder="placeholder"
64
67
  :color="isInvalid ? 'error' : 'neutral'"
65
68
  :highlight="isInvalid"
69
+ :ui="{
70
+ base: roundedNone && 'rounded-none'
71
+ }"
66
72
  @input="onInput"
67
73
  @focus="(e) => emit('focus', e)"
68
74
  @blur="(e) => emit('blur', e)"
@@ -71,8 +77,11 @@ defineExpose({
71
77
  <UButton
72
78
  color="neutral"
73
79
  variant="link"
74
- size="sm"
80
+ size="xs"
75
81
  icon="i-lucide-circle-x"
82
+ :ui="{
83
+ leadingIcon: 'size-3 text-dimmed'
84
+ }"
76
85
  aria-label="Clear input"
77
86
  @mousedown.prevent
78
87
  @click="handleClear"
@@ -4,6 +4,7 @@ type __VLS_Props = {
4
4
  size?: InputProps['size'];
5
5
  icon?: InputProps['icon'];
6
6
  inputClass?: string;
7
+ roundedNone?: boolean;
7
8
  };
8
9
  type __VLS_ModelProps = {
9
10
  'value': undefined | string;
@@ -18,7 +18,6 @@ const { oldValues, newValues } = useFormValues(toRef(props.modelValue), props.de
18
18
  const { onSubmit } = useFormSubmission(
19
19
  toRef(oldValues),
20
20
  toRef(newValues),
21
- props.onClose,
22
21
  props.onSave,
23
22
  props.apiGroup
24
23
  );
@@ -31,7 +30,7 @@ const { onSubmit } = useFormSubmission(
31
30
  :title="title"
32
31
  :description="description"
33
32
  :on-close="onClose"
34
- :on-submit="onSubmit"
35
33
  :fields="fields"
34
+ @submit="onSubmit"
36
35
  />
37
36
  </template>
@@ -46,14 +46,6 @@ function computeDiff() {
46
46
  return items;
47
47
  }
48
48
  const { submitting, startSubmitting, endSubmitting } = useSubmitting();
49
- async function doSubmit() {
50
- try {
51
- startSubmitting();
52
- await props.onSubmit();
53
- } finally {
54
- endSubmitting();
55
- }
56
- }
57
49
  async function onSubmitWithValidation(e) {
58
50
  e.preventDefault();
59
51
  e.stopPropagation();
@@ -62,24 +54,32 @@ async function onSubmitWithValidation(e) {
62
54
  } catch {
63
55
  return;
64
56
  }
65
- if (isUpdate.value) {
66
- const items = computeDiff();
67
- if (items.length === 0) {
68
- await doSubmit();
69
- return;
57
+ startSubmitting();
58
+ let keepSubmitting = false;
59
+ try {
60
+ if (isUpdate.value) {
61
+ const items = computeDiff();
62
+ if (items.length > 0) {
63
+ const confirmed = await confirmModal.open({
64
+ fields: props.fields,
65
+ diffItems: items,
66
+ oldModelValue: props.oldModelValue,
67
+ newModelValue: props.modelValue
68
+ }).result;
69
+ if (!confirmed) {
70
+ return;
71
+ }
72
+ }
70
73
  }
71
- const confirmed = await confirmModal.open({
72
- fields: props.fields,
73
- diffItems: items,
74
- oldModelValue: props.oldModelValue,
75
- newModelValue: props.modelValue
76
- }).result;
77
- if (confirmed) {
78
- await doSubmit();
74
+ keepSubmitting = await props.onSubmit() === true;
75
+ if (keepSubmitting) {
76
+ props.onClose(true);
77
+ }
78
+ } finally {
79
+ if (!keepSubmitting) {
80
+ endSubmitting();
79
81
  }
80
- return;
81
82
  }
82
- await doSubmit();
83
83
  }
84
84
  </script>
85
85
 
@@ -6,7 +6,7 @@ const neutralColorOptions = theme.neutralColors.map((c) => ({ color: c, chip: c
6
6
  </script>
7
7
 
8
8
  <template>
9
- <UPopover :ui="{ content: 'px-6 py-4 flex flex-col gap-4' }">
9
+ <UPopover :open-delay="0" :ui="{ content: 'px-6 py-4 flex flex-col gap-4' }">
10
10
  <template #default="{ open }">
11
11
  <UButton
12
12
  icon="i-lucide-swatch-book"
@@ -91,7 +91,7 @@ const neutralColorOptions = theme.neutralColors.map((c) => ({ color: c, chip: c
91
91
  v-for="m in theme.modes.value"
92
92
  :key="m.label"
93
93
  v-bind="m"
94
- :selected="theme.mode.value === m.label"
94
+ :selected="theme.mode.value === m.value"
95
95
  @click="theme.mode.value = m.value"
96
96
  />
97
97
  </div>
@@ -8,12 +8,18 @@ import LayoutModuleMenu from "#v/components/layout/button/ModuleMenu.vue";
8
8
  import LayoutThemePicker from "#v/components/layout/button/ThemePicker.vue";
9
9
  import LayoutUserMenu from "#v/components/layout/button/UserMenu.vue";
10
10
  import Watermark from "#v/components/Watermark.vue";
11
- import { watch } from "vue";
11
+ import { watch, computed } from "vue";
12
12
  const app = useApp();
13
13
  const theme = useTheme();
14
14
  const loginUser = useAuth().loginUser;
15
15
  const route = useRoute();
16
16
  const { sidebarMenus, expandSidebarMenu, breadcrumbs, getBreadcrumbs } = useSidebarMenus();
17
+ const sidebarOpen = computed({
18
+ get: () => !app.sidebarCollapsed.value,
19
+ set: (val) => {
20
+ app.sidebarCollapsed.value = !val;
21
+ }
22
+ });
17
23
  watch(() => route.path, (newPath) => {
18
24
  expandSidebarMenu(newPath);
19
25
  }, { immediate: true });
@@ -38,7 +44,7 @@ watch(
38
44
  >
39
45
  <!-- sidebar -->
40
46
  <USidebar
41
- v-model:open="app.sidebarCollapsed.value"
47
+ v-model:open="sidebarOpen"
42
48
  :variant="theme.sidebarVariant.value"
43
49
  :collapsible="theme.sidebarCollapsible.value"
44
50
  :side="theme.sidebarSide.value"
@@ -47,7 +53,7 @@ watch(
47
53
  footer: 'h-(--ui-footer-height)',
48
54
  container: 'ease-in-out duration-360',
49
55
  gap: 'ease-in-out duration-360',
50
- inner: 'bg-default'
56
+ inner: ['sidebar', 'floating'].includes(theme.sidebarVariant.value) && 'bg-default'
51
57
  }"
52
58
  >
53
59
  <template #header="{ state }">
@@ -78,7 +84,7 @@ watch(
78
84
 
79
85
  <!-- main content -->
80
86
  <div
81
- class="flex-1 flex flex-col w-full overflow-hidden lg:peer-data-[variant=floating]:my-4 peer-data-[variant=inset]:m-4 lg:peer-data-[variant=inset]:not-peer-data-[collapsible=offcanvas]:ms-0 peer-data-[variant=inset]:rounded-xl peer-data-[variant=inset]:shadow-sm peer-data-[variant=inset]:ring peer-data-[variant=inset]:ring-default bg-default"
87
+ class="flex-1 flex flex-col w-full overflow-hidden lg:peer-data-[variant=floating]:my-4 lg:peer-data-[variant=floating]:rounded-l-lg lg:peer-data-[variant=floating]:border lg:peer-data-[variant=floating]:border-r-0 lg:peer-data-[variant=floating]:border-default peer-data-[variant=inset]:m-4 lg:peer-data-[variant=inset]:not-peer-data-[collapsible=offcanvas]:ms-0 peer-data-[variant=inset]:rounded-xl peer-data-[variant=inset]:shadow-sm peer-data-[variant=inset]:ring peer-data-[variant=inset]:ring-default bg-default"
82
88
  >
83
89
  <Watermark
84
90
  :text="stringsJoin([
@@ -1,6 +1,6 @@
1
1
  import type { VTableProps } from '#v/types';
2
2
  declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
- props: import("vue").PublicProps & __VLS_PrettifyLocal<Pick<VTableProps<T>, "bizColumns" | "singleRow" | "singleColumn" | "hideLastRowBorder"> & {
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<Pick<VTableProps<T>, "bizColumns" | "disableRowActions" | "extraRowActions" | "singleRow" | "singleColumn" | "hideLastRowBorder"> & {
4
4
  data: T[];
5
5
  }> & (typeof globalThis extends {
6
6
  __VLS_PROPS_FALLBACK: infer P;
@@ -2,11 +2,14 @@
2
2
  import { computed, ref, useTemplateRef, h, onMounted, onUnmounted, watch, nextTick } from "vue";
3
3
  import UButton from "@nuxt/ui/components/Button.vue";
4
4
  import UBadge from "@nuxt/ui/components/Badge.vue";
5
+ import UDropdownMenu from "@nuxt/ui/components/DropdownMenu.vue";
5
6
  const props = defineProps({
6
7
  singleRow: { type: Boolean, required: false, default: true },
7
8
  singleColumn: { type: Boolean, required: false, default: false },
8
9
  hideLastRowBorder: { type: Boolean, required: false },
9
10
  bizColumns: { type: Array, required: true },
11
+ extraRowActions: { type: Array, required: false },
12
+ disableRowActions: { type: Boolean, required: false },
10
13
  data: { type: Array, required: true }
11
14
  });
12
15
  const thClass = computed(() => {
@@ -120,8 +123,72 @@ const columnsWithHeader = computed(() => props.bizColumns.map((col) => ({
120
123
  });
121
124
  }
122
125
  })) || []);
126
+ function buildActionItem(action) {
127
+ const item = {
128
+ label: action.label,
129
+ icon: action.icon,
130
+ type: action.type,
131
+ color: action.color
132
+ };
133
+ if (action.children && action.children.length > 0) {
134
+ item.children = action.children.map(buildActionItem);
135
+ return item;
136
+ }
137
+ item.onClick = () => {
138
+ };
139
+ return item;
140
+ }
141
+ function getActionColumn() {
142
+ return {
143
+ id: "actions",
144
+ accessorKey: "actions",
145
+ header: "\u64CD\u4F5C",
146
+ meta: {
147
+ class: {
148
+ th: "w-15 min-w-15 px-4"
149
+ }
150
+ },
151
+ cell: ({ row }) => {
152
+ const items = (props.extraRowActions || []).map((action) => {
153
+ const item = buildActionItem(action);
154
+ if (!action.children?.length) {
155
+ item.onClick = async () => {
156
+ if (action.fn) {
157
+ action.fn(row.original);
158
+ }
159
+ if (action.asyncFn) {
160
+ await action.asyncFn(row.original);
161
+ }
162
+ if (action.fnWithModal) {
163
+ await action.fnWithModal(row.original);
164
+ }
165
+ };
166
+ }
167
+ return item;
168
+ });
169
+ return h(
170
+ "div",
171
+ { class: "text-center" },
172
+ h(
173
+ UDropdownMenu,
174
+ { content: { align: "end" }, items },
175
+ {
176
+ "default": () => h(UButton, { icon: "i-lucide-ellipsis", color: "neutral", variant: "ghost", size: "sm", class: "ml-auto" }),
177
+ "item": () => null,
178
+ "item-leading": () => null,
179
+ "item-label": () => null,
180
+ "item-description": () => null,
181
+ "item-trailing": () => null,
182
+ "content-top": () => null,
183
+ "content-bottom": () => null
184
+ }
185
+ )
186
+ );
187
+ }
188
+ };
189
+ }
123
190
  const columnsWithFilterOptions = computed(() => {
124
- return columnsWithHeader.value.map((col) => {
191
+ const cols = columnsWithHeader.value.map((col) => {
125
192
  if (!col.filterOption) {
126
193
  return col;
127
194
  }
@@ -139,6 +206,10 @@ const columnsWithFilterOptions = computed(() => {
139
206
  return col;
140
207
  }
141
208
  });
209
+ if (!props.disableRowActions && props.extraRowActions?.length) {
210
+ cols.push(getActionColumn());
211
+ }
212
+ return cols;
142
213
  });
143
214
  </script>
144
215
 
@@ -1,6 +1,6 @@
1
1
  import type { VTableProps } from '#v/types';
2
2
  declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
- props: import("vue").PublicProps & __VLS_PrettifyLocal<Pick<VTableProps<T>, "bizColumns" | "singleRow" | "singleColumn" | "hideLastRowBorder"> & {
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<Pick<VTableProps<T>, "bizColumns" | "disableRowActions" | "extraRowActions" | "singleRow" | "singleColumn" | "hideLastRowBorder"> & {
4
4
  data: T[];
5
5
  }> & (typeof globalThis extends {
6
6
  __VLS_PROPS_FALLBACK: infer P;
@@ -20,7 +20,6 @@ watch(
20
20
  const { onSubmit } = useFormSubmission(
21
21
  toRef(oldValues),
22
22
  toRef(newValues),
23
- (close) => emit("close", close),
24
23
  (model) => emit("save", model),
25
24
  useDepartmentApi
26
25
  );
@@ -11,6 +11,10 @@ const { oldValues, newValues } = useFormValues(toRef(props.model), {
11
11
  id: 0,
12
12
  name: ""
13
13
  });
14
+ async function onSubmit() {
15
+ emit("save", newValues.value);
16
+ return true;
17
+ }
14
18
  </script>
15
19
 
16
20
  <template>
@@ -23,9 +27,6 @@ const { oldValues, newValues } = useFormValues(toRef(props.model), {
23
27
  :model-value="newValues"
24
28
  :old-model-value="oldValues"
25
29
  @update-model-value="(newVal) => newValues = { ...props.model, ...newVal }"
26
- @submit="async () => {
27
- emit('save', newValues);
28
- emit('close', true);
29
- }"
30
+ @submit="onSubmit"
30
31
  />
31
32
  </template>
@@ -11,7 +11,6 @@ const { oldValues, newValues } = useFormValues(toRef(props.model), { id: 0 });
11
11
  const { onSubmit } = useFormSubmission(
12
12
  toRef(oldValues),
13
13
  toRef(newValues),
14
- (close) => emit("close", close),
15
14
  (model) => emit("save", model),
16
15
  useFlowApi
17
16
  );
@@ -12,7 +12,6 @@ const { oldValues, newValues } = useFormValues(toRef(props.model), { id: 0, disa
12
12
  const { onSubmit } = useFormSubmission(
13
13
  toRef(oldValues),
14
14
  toRef(newValues),
15
- (close) => emit("close", close),
16
15
  (model) => emit("save", model),
17
16
  useMenuApi,
18
17
  ["staticRouteKeys"]
@@ -13,7 +13,6 @@ const { oldValues, newValues } = useFormValues(toRef(props.model), { id: 0, disa
13
13
  const { onSubmit } = useFormSubmission(
14
14
  toRef(oldValues),
15
15
  toRef(newValues),
16
- (close) => emit("close", close),
17
16
  (model) => emit("save", model),
18
17
  useRoleApi,
19
18
  ["menus"],