@vc-shell/framework 1.1.30 → 1.1.34
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/CHANGELOG.md +34 -0
- package/core/composables/useErrorHandler/index.ts +28 -36
- package/core/composables/useLanguages/index.ts +1 -0
- package/core/services/settings-menu-service.ts +6 -6
- package/core/utilities/error.ts +89 -0
- package/dist/core/composables/useErrorHandler/index.d.ts +10 -1
- package/dist/core/composables/useErrorHandler/index.d.ts.map +1 -1
- package/dist/core/composables/useLanguages/index.d.ts.map +1 -1
- package/dist/core/services/settings-menu-service.d.ts +3 -3
- package/dist/core/services/settings-menu-service.d.ts.map +1 -1
- package/dist/core/utilities/error.d.ts +13 -0
- package/dist/core/utilities/error.d.ts.map +1 -0
- package/dist/framework.js +138 -134
- package/dist/{index-Bpzd_lmX.js → index-0JXtGXkU.js} +1 -1
- package/dist/{index-DJxEdMUZ.js → index-B4vlCcFR.js} +1 -1
- package/dist/{index-Bn87vMP8.js → index-Bo-tMcwW.js} +1 -1
- package/dist/{index-CM7z23lM.js → index-Bxzy9NzM.js} +1 -1
- package/dist/{index-BhEc39Bx.js → index-C0HMg87C.js} +1 -1
- package/dist/{index-DFp2PcZu.js → index-C34EKuYz.js} +1 -1
- package/dist/{index-B8e874V3.js → index-CIYNhqa0.js} +1 -1
- package/dist/{index-CK1ZmJzV.js → index-D2ktcdHl.js} +30374 -30127
- package/dist/{index-CR9ZPpuz.js → index-DKAEB9Q6.js} +1 -1
- package/dist/{index-BeTy-tH8.js → index-DWkmlYj4.js} +1 -1
- package/dist/{index-Cl-FWJ0z.js → index-Dxs7WOw2.js} +1 -1
- package/dist/{index-sElVLLwP.js → index-NFZ0riWN.js} +1 -1
- package/dist/{index-BerVe4OV.js → index-W3dvhLJ3.js} +1 -1
- package/dist/{index-C-pBZXky.js → index-Yu2Xrty9.js} +1 -1
- package/dist/{index-AgS-u96H.js → index-jKOJ5dxS.js} +1 -1
- package/dist/{index-HFn5nMnu.js → index-lJ-eV6nh.js} +1 -1
- package/dist/{index-NX-Ek0LQ.js → index-uOSH3WBg.js} +1 -1
- package/dist/index.css +1 -1
- package/dist/locales/de.json +1 -1
- package/dist/locales/en.json +1 -1
- package/dist/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/components/vc-blade-view/vc-blade-view.d.ts +3 -2
- package/dist/shared/components/blade-navigation/components/vc-blade-view/vc-blade-view.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts +2 -0
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.d.ts +2 -0
- package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.d.ts.map +1 -1
- package/dist/shared/components/blade-navigation/types/index.d.ts +3 -2
- package/dist/shared/components/blade-navigation/types/index.d.ts.map +1 -1
- package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts +18 -363
- package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts.map +1 -1
- package/dist/shared/components/error-interceptor/interceptor.d.ts +7 -4
- package/dist/shared/components/error-interceptor/interceptor.d.ts.map +1 -1
- package/dist/shared/components/index.d.ts +1 -0
- package/dist/shared/components/index.d.ts.map +1 -1
- package/dist/shared/components/multilanguage-selector/index.d.ts +2 -0
- package/dist/shared/components/multilanguage-selector/index.d.ts.map +1 -0
- package/dist/shared/components/multilanguage-selector/multilanguage-selector.vue.d.ts +43 -0
- package/dist/shared/components/multilanguage-selector/multilanguage-selector.vue.d.ts.map +1 -0
- package/dist/shared/composables/index.d.ts +1 -0
- package/dist/shared/composables/index.d.ts.map +1 -1
- package/dist/shared/composables/useModificationTracker/index.d.ts +34 -0
- package/dist/shared/composables/useModificationTracker/index.d.ts.map +1 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/atoms/index.d.ts +1 -0
- package/dist/ui/components/atoms/index.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-banner/index.d.ts +2 -0
- package/dist/ui/components/atoms/vc-banner/index.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-banner/vc-banner.vue.d.ts +25 -0
- package/dist/ui/components/atoms/vc-banner/vc-banner.vue.d.ts.map +1 -0
- package/dist/ui/components/atoms/vc-card/vc-card.vue.d.ts.map +1 -1
- package/dist/ui/components/molecules/vc-checkbox/vc-checkbox.vue.d.ts +1 -0
- package/dist/ui/components/molecules/vc-checkbox/vc-checkbox.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts +1 -0
- package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-blade/vc-blade.backupsb.d.ts +5 -1
- package/dist/ui/components/organisms/vc-blade/vc-blade.backupsb.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts +3 -1
- package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-body/vc-table-body.vue.d.ts +0 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-body/vc-table-body.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-row/vc-table-row.vue.d.ts +0 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-row/vc-table-row.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/vc-table-desktop-view.vue.d.ts +0 -1
- package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/vc-table-desktop-view.vue.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/composables/useTableActions.d.ts +4 -4
- package/dist/ui/components/organisms/vc-table/composables/useTableActions.d.ts.map +1 -1
- package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts.map +1 -1
- package/package.json +5 -6
- package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +18 -18
- package/shared/components/blade-navigation/components/vc-blade-view/vc-blade-view.ts +5 -3
- package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +12 -1
- package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeState.ts +34 -0
- package/shared/components/blade-navigation/types/index.ts +2 -1
- package/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.ts +17 -3
- package/shared/components/error-interceptor/interceptor.ts +48 -44
- package/shared/components/index.ts +1 -0
- package/shared/components/multilanguage-selector/index.ts +1 -0
- package/shared/components/multilanguage-selector/multilanguage-selector.vue +144 -0
- package/shared/composables/index.ts +2 -1
- package/shared/composables/useModificationTracker/index.ts +93 -0
- package/shared/index.ts +1 -0
- package/ui/components/atoms/index.ts +1 -0
- package/ui/components/atoms/vc-banner/index.ts +1 -0
- package/ui/components/atoms/vc-banner/vc-banner.vue +138 -0
- package/ui/components/atoms/vc-card/vc-card.vue +6 -0
- package/ui/components/molecules/vc-checkbox/vc-checkbox.vue +9 -3
- package/ui/components/organisms/vc-app/vc-app.vue +6 -1
- package/ui/components/organisms/vc-blade/vc-blade.vue +40 -50
- package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-body/vc-table-body.vue +0 -2
- package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-row/vc-table-row.vue +1 -2
- package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/vc-table-desktop-view.vue +0 -2
- package/ui/components/organisms/vc-table/composables/useTableActions.ts +13 -8
- package/ui/components/organisms/vc-table/vc-table.vue +6 -6
|
@@ -1,44 +1,48 @@
|
|
|
1
|
-
import { useErrorHandler } from "./../../../core/composables";
|
|
2
|
-
import { defineComponent, VNode } from "vue";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
import { useErrorHandler } from "./../../../core/composables";
|
|
2
|
+
import { defineComponent, VNode } from "vue";
|
|
3
|
+
|
|
4
|
+
// This is an internal type used within useErrorHandler now.
|
|
5
|
+
// We are re-exporting a similar structure for clarity in components that use it.
|
|
6
|
+
export type DisplayableError = Error & { details?: string };
|
|
7
|
+
|
|
8
|
+
export interface Props {
|
|
9
|
+
capture?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Emits {
|
|
13
|
+
(event: "error", value: DisplayableError): void;
|
|
14
|
+
(event: "reset"): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type Slots = {
|
|
18
|
+
slots: {
|
|
19
|
+
default: (args: { error: DisplayableError | null; reset: () => void }) => VNode[];
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default defineComponent({
|
|
24
|
+
name: "ErrorInterceptor",
|
|
25
|
+
props: {
|
|
26
|
+
capture: {
|
|
27
|
+
default: false,
|
|
28
|
+
type: Boolean,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
emits: {
|
|
32
|
+
error(value: Error) {
|
|
33
|
+
return value instanceof Error;
|
|
34
|
+
},
|
|
35
|
+
reset(): boolean {
|
|
36
|
+
return true;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
setup(props, { slots }) {
|
|
40
|
+
const { error, reset } = useErrorHandler(props.capture);
|
|
41
|
+
|
|
42
|
+
return () =>
|
|
43
|
+
slots.default?.({
|
|
44
|
+
error: error.value,
|
|
45
|
+
reset,
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as VcLanguageSelector } from "./multilanguage-selector.vue";
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="vc-language-selector">
|
|
3
|
+
<GenericDropdown
|
|
4
|
+
:opened="isOpened"
|
|
5
|
+
:items="options"
|
|
6
|
+
:floating="true"
|
|
7
|
+
placement="bottom-end"
|
|
8
|
+
:offset="{ mainAxis: 10, crossAxis: -15 }"
|
|
9
|
+
:disabled="disabled"
|
|
10
|
+
:empty-text="t('common.no_options', 'No options')"
|
|
11
|
+
:is-item-active="(item: any) => item.value === modelValue"
|
|
12
|
+
@item-click="onItemClick"
|
|
13
|
+
@update:opened="isOpened = $event"
|
|
14
|
+
>
|
|
15
|
+
<template #trigger>
|
|
16
|
+
<div
|
|
17
|
+
class="tw-flex tw-cursor-pointer tw-items-center tw-justify-center tw-bg-[--primary-100] tw-w-8 tw-h-8 tw-rounded-full hover:tw-bg-[--primary-200]"
|
|
18
|
+
@click="onTriggerClick"
|
|
19
|
+
>
|
|
20
|
+
<VcImage
|
|
21
|
+
:src="currentLanguageOption?.flag"
|
|
22
|
+
class="tw-w-6 tw-h-6"
|
|
23
|
+
empty-icon=""
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
<template #item="{ item }">
|
|
28
|
+
<div class="tw-flex tw-items-center tw-gap-2 tw-p-2">
|
|
29
|
+
<VcImage
|
|
30
|
+
:src="item.flag"
|
|
31
|
+
class="tw-w-6 tw-h-6"
|
|
32
|
+
empty-icon=""
|
|
33
|
+
/>
|
|
34
|
+
<span class="tw-text-sm">{{ item.label }}</span>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
<template #empty>
|
|
38
|
+
<div class="tw-p-2 tw-text-sm">
|
|
39
|
+
{{ t("common.no_options", "No options") }}
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
42
|
+
</GenericDropdown>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<script lang="ts" setup>
|
|
47
|
+
import { computed, h, ref, type PropType } from "vue";
|
|
48
|
+
import { VcImage } from "../../../ui/components";
|
|
49
|
+
import { GenericDropdown } from "../../../shared/components";
|
|
50
|
+
import { useI18n } from "vue-i18n";
|
|
51
|
+
|
|
52
|
+
type LanguageOption = {
|
|
53
|
+
value: string;
|
|
54
|
+
label: string;
|
|
55
|
+
flag?: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const props = defineProps({
|
|
59
|
+
options: {
|
|
60
|
+
type: Array as PropType<LanguageOption[]>,
|
|
61
|
+
default: () => [],
|
|
62
|
+
},
|
|
63
|
+
modelValue: {
|
|
64
|
+
type: String,
|
|
65
|
+
default: "",
|
|
66
|
+
},
|
|
67
|
+
disabled: {
|
|
68
|
+
type: Boolean,
|
|
69
|
+
default: false,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
74
|
+
|
|
75
|
+
const { t } = useI18n({ useScope: "global" });
|
|
76
|
+
const isOpened = ref(false);
|
|
77
|
+
|
|
78
|
+
const currentLanguageOption = computed(() => {
|
|
79
|
+
return props.options.find((option) => option.value === props.modelValue);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const onTriggerClick = () => {
|
|
83
|
+
if (props.disabled) return;
|
|
84
|
+
isOpened.value = !isOpened.value;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const onItemClick = (item: LanguageOption) => {
|
|
88
|
+
isOpened.value = false;
|
|
89
|
+
emit("update:modelValue", item.value);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// // We use a computed property to build the dropdown via render function `h`.
|
|
93
|
+
// // This is because the old implementation in `dynamic-blade-form` used this pattern,
|
|
94
|
+
// // and it's a powerful way to construct complex components with custom slots programmatically.
|
|
95
|
+
// const dropdownComponent = computed(() => {
|
|
96
|
+
// return h(
|
|
97
|
+
// GenericDropdown,
|
|
98
|
+
// {
|
|
99
|
+
// opened: isOpened.value,
|
|
100
|
+
// items: props.options,
|
|
101
|
+
// floating: true,
|
|
102
|
+
// placement: "bottom-end",
|
|
103
|
+
// offset: { mainAxis: 10, crossAxis: -15 },
|
|
104
|
+
// variant: "secondary",
|
|
105
|
+
// disabled: props.disabled,
|
|
106
|
+
// emptyText: t("common.no_options", "No options"),
|
|
107
|
+
// isItemActive: (item: any) => item.value === props.modelValue,
|
|
108
|
+
// onItemClick: (item: any) => {
|
|
109
|
+
// isOpened.value = false;
|
|
110
|
+
// emit("update:modelValue", item.value);
|
|
111
|
+
// },
|
|
112
|
+
// "onUpdate:opened": (state: boolean) => {
|
|
113
|
+
// isOpened.value = state;
|
|
114
|
+
// },
|
|
115
|
+
// },
|
|
116
|
+
// {
|
|
117
|
+
// // Custom trigger slot: a circular button with the current language's flag
|
|
118
|
+
// trigger: () =>
|
|
119
|
+
// h(
|
|
120
|
+
// "div",
|
|
121
|
+
// {
|
|
122
|
+
// onClick: () => {
|
|
123
|
+
// if (props.disabled) return;
|
|
124
|
+
// isOpened.value = !isOpened.value;
|
|
125
|
+
// },
|
|
126
|
+
// class: [
|
|
127
|
+
// "tw-flex tw-cursor-pointer tw-items-center tw-justify-center tw-bg-[--primary-100]",
|
|
128
|
+
// "tw-w-8 tw-h-8 tw-rounded-full hover:tw-bg-[--primary-200]",
|
|
129
|
+
// { "tw-cursor-not-allowed tw-opacity-50": props.disabled },
|
|
130
|
+
// ],
|
|
131
|
+
// },
|
|
132
|
+
// [h(VcImage, { src: currentLanguageOption.value?.flag, class: "tw-w-6 tw-h-6", emptyIcon: "" })],
|
|
133
|
+
// ),
|
|
134
|
+
// // Custom item slot: a row with the flag and language name
|
|
135
|
+
// item: ({ item }: { item: any }) =>
|
|
136
|
+
// h("div", { class: "tw-flex tw-items-center tw-gap-2 tw-p-2" }, [
|
|
137
|
+
// h(VcImage, { src: item.flag, class: "tw-w-6 tw-h-6", emptyIcon: "" }),
|
|
138
|
+
// h("span", { class: "tw-text-sm" }, item.label),
|
|
139
|
+
// ]),
|
|
140
|
+
// empty: () => h("div", { class: "tw-p-2 tw-text-sm" }, t("common.no_options", "No options")),
|
|
141
|
+
// },
|
|
142
|
+
// );
|
|
143
|
+
// });
|
|
144
|
+
</script>
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from "./useMenuExpanded";
|
|
1
|
+
export * from "./useMenuExpanded";
|
|
2
|
+
export * from "./useModificationTracker";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ref, watch, Ref, computed, DeepReadonly, unref, isRef } from "vue";
|
|
2
|
+
import { cloneDeep, isEqual } from "lodash-es";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Return values from useModificationTracker.
|
|
6
|
+
* @template T Type of the tracked value.
|
|
7
|
+
*/
|
|
8
|
+
export interface UseModificationTrackerReturn<T> {
|
|
9
|
+
/**
|
|
10
|
+
* Reactive reference to the current tracked value.
|
|
11
|
+
* It can be changed directly or through v-model.
|
|
12
|
+
*/
|
|
13
|
+
currentValue: Ref<T>;
|
|
14
|
+
/**
|
|
15
|
+
* Shows if currentValue has been modified compared to its "pristine" state.
|
|
16
|
+
* Read-only.
|
|
17
|
+
*/
|
|
18
|
+
isModified: DeepReadonly<Ref<boolean>>;
|
|
19
|
+
/**
|
|
20
|
+
* Resets the modification state.
|
|
21
|
+
* The new "pristine" state will be set based on the current value of currentValue,
|
|
22
|
+
* or based on `newBaselineValue` if provided.
|
|
23
|
+
* `isModified` will become false.
|
|
24
|
+
* @param newBaselineValue Optional new value (or Ref) that will become "pristine".
|
|
25
|
+
*/
|
|
26
|
+
resetModificationState: (newBaselineValue?: T | Ref<T>) => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Composable for tracking value changes (including deeply nested objects).
|
|
31
|
+
*
|
|
32
|
+
* @template T Type of the tracked value.
|
|
33
|
+
* @param initialValueProp Initial value or Ref to it.
|
|
34
|
+
* @returns {UseModificationTrackerReturn<T>} Object with `currentValue`, `isModified` and `resetModificationState`.
|
|
35
|
+
*/
|
|
36
|
+
export function useModificationTracker<T>(initialValueProp: T | Ref<T>): UseModificationTrackerReturn<T> {
|
|
37
|
+
const getClonedUnreffedValue = (val: T | Ref<T>): T => cloneDeep(unref(val));
|
|
38
|
+
|
|
39
|
+
const pristineValue = ref(getClonedUnreffedValue(initialValueProp)) as Ref<T>;
|
|
40
|
+
const currentValue = ref(getClonedUnreffedValue(initialValueProp)) as Ref<T>;
|
|
41
|
+
const isModified = ref(false);
|
|
42
|
+
|
|
43
|
+
if (isRef(initialValueProp)) {
|
|
44
|
+
watch(
|
|
45
|
+
initialValueProp,
|
|
46
|
+
(newExternalInitialValue) => {
|
|
47
|
+
// When the external initialValueProp (Ref) changes,
|
|
48
|
+
// we need to decide if we should update currentValue.
|
|
49
|
+
const wasModified = !isEqual(currentValue.value, pristineValue.value);
|
|
50
|
+
|
|
51
|
+
// Always update the "pristine" value (pristineValue), to reflect the new external source.
|
|
52
|
+
pristineValue.value = cloneDeep(newExternalInitialValue);
|
|
53
|
+
|
|
54
|
+
// If the user has not made any changes until this point,
|
|
55
|
+
// we also update currentValue.
|
|
56
|
+
// This prevents false triggering of isModified when loading data asynchronously.
|
|
57
|
+
if (!wasModified) {
|
|
58
|
+
currentValue.value = cloneDeep(newExternalInitialValue);
|
|
59
|
+
}
|
|
60
|
+
// If the user has already made changes (wasModified = true), we do not update currentValue,
|
|
61
|
+
// to not overwrite their changes. isModified will remain true, because
|
|
62
|
+
// currentValue will now be different from the new pristineValue.
|
|
63
|
+
},
|
|
64
|
+
{ deep: true }, // Deep tracking, if initialValueProp is a Ref to an object/array
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
watch(
|
|
69
|
+
[currentValue, pristineValue], // Track changes in currentValue or pristineValue
|
|
70
|
+
([newCurrentVal, newPristineVal]) => {
|
|
71
|
+
isModified.value = !isEqual(newCurrentVal, newPristineVal);
|
|
72
|
+
},
|
|
73
|
+
{ deep: true },
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const resetModificationState = (newBaselineValueInput?: T | Ref<T>) => {
|
|
77
|
+
if (newBaselineValueInput !== undefined) {
|
|
78
|
+
const newClonedBase = getClonedUnreffedValue(newBaselineValueInput);
|
|
79
|
+
pristineValue.value = newClonedBase;
|
|
80
|
+
currentValue.value = cloneDeep(newClonedBase); // Reset currentValue to the new baseline
|
|
81
|
+
} else {
|
|
82
|
+
pristineValue.value = cloneDeep(currentValue.value);
|
|
83
|
+
}
|
|
84
|
+
// isModified will be updated by the watcher above, but for immediate synchronization you can do this:
|
|
85
|
+
// isModified.value = false; // This will happen automatically due to the watch on [currentValue, pristineValue]
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
currentValue,
|
|
90
|
+
isModified: computed(() => isModified.value),
|
|
91
|
+
resetModificationState,
|
|
92
|
+
};
|
|
93
|
+
}
|
package/shared/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as VcBanner } from "./vc-banner.vue";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="vc-banner"
|
|
4
|
+
:class="[`vc-banner_${variant}`]"
|
|
5
|
+
>
|
|
6
|
+
<div class="vc-banner__container">
|
|
7
|
+
<VcIcon
|
|
8
|
+
v-if="icon"
|
|
9
|
+
:icon="icon"
|
|
10
|
+
:size="iconSize"
|
|
11
|
+
:variant="iconVariant"
|
|
12
|
+
class="vc-banner__icon"
|
|
13
|
+
/>
|
|
14
|
+
<div class="vc-banner__wrapper">
|
|
15
|
+
<div class="vc-banner__title">
|
|
16
|
+
<slot name="title"></slot>
|
|
17
|
+
</div>
|
|
18
|
+
<div
|
|
19
|
+
ref="contentRef"
|
|
20
|
+
class="vc-banner__content"
|
|
21
|
+
:class="[
|
|
22
|
+
{
|
|
23
|
+
'tw-max-h-[100px] tw-line-clamp-4': !isExpanded,
|
|
24
|
+
'tw-max-h-full': isExpanded,
|
|
25
|
+
},
|
|
26
|
+
]"
|
|
27
|
+
>
|
|
28
|
+
<slot name="default"></slot>
|
|
29
|
+
</div>
|
|
30
|
+
<div v-if="hasOverflow">
|
|
31
|
+
<slot
|
|
32
|
+
name="trigger"
|
|
33
|
+
:is-expanded="isExpanded"
|
|
34
|
+
:toggle="toggle"
|
|
35
|
+
>
|
|
36
|
+
<VcButton
|
|
37
|
+
class="tw-self-end"
|
|
38
|
+
text
|
|
39
|
+
@click="toggle"
|
|
40
|
+
>
|
|
41
|
+
{{ isExpanded ? $t("COMPONENTS.ATOMS.VC_BANNER.SHOW_LESS") : $t("COMPONENTS.ATOMS.VC_BANNER.SHOW_MORE") }}
|
|
42
|
+
</VcButton>
|
|
43
|
+
</slot>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
<!-- eslint-disable @typescript-eslint/no-explicit-any -->
|
|
50
|
+
<script lang="ts" setup>
|
|
51
|
+
import { onMounted, ref } from "vue";
|
|
52
|
+
import { VcIcon } from "..";
|
|
53
|
+
|
|
54
|
+
// TODO: Add to docs
|
|
55
|
+
|
|
56
|
+
type StatusVariant = "info" | "warning" | "danger" | "success" | "light-danger" | "info-dark" | "primary";
|
|
57
|
+
|
|
58
|
+
export interface Props {
|
|
59
|
+
variant?: StatusVariant;
|
|
60
|
+
icon?: string;
|
|
61
|
+
iconSize?: InstanceType<typeof VcIcon>["$props"]["size"];
|
|
62
|
+
iconVariant?: InstanceType<typeof VcIcon>["$props"]["variant"];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
defineSlots<{
|
|
66
|
+
title: (props: any) => any;
|
|
67
|
+
default: (props: any) => any;
|
|
68
|
+
trigger: (props: any) => any;
|
|
69
|
+
}>();
|
|
70
|
+
|
|
71
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
72
|
+
variant: "info",
|
|
73
|
+
iconSize: "xxl",
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const contentRef = ref<HTMLDivElement>();
|
|
77
|
+
const isExpanded = ref(false);
|
|
78
|
+
const hasOverflow = ref(false);
|
|
79
|
+
|
|
80
|
+
const toggle = () => {
|
|
81
|
+
isExpanded.value = !isExpanded.value;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const checkOverflow = () => {
|
|
85
|
+
if (contentRef.value) {
|
|
86
|
+
hasOverflow.value = contentRef.value.scrollHeight > 100;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
onMounted(() => {
|
|
91
|
+
checkOverflow();
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<style lang="scss">
|
|
96
|
+
:root {
|
|
97
|
+
--banner-text-color: var(--neutrals-700);
|
|
98
|
+
}
|
|
99
|
+
$variants: info, warning, danger, success, light-danger, info-dark, primary;
|
|
100
|
+
|
|
101
|
+
.vc-banner {
|
|
102
|
+
@apply tw-whitespace-normal tw-justify-start tw-max-w-full tw-border-none;
|
|
103
|
+
|
|
104
|
+
border-radius: var(--status-border-radius-extended);
|
|
105
|
+
padding: var(--status-padding-extended);
|
|
106
|
+
|
|
107
|
+
@each $variant in $variants {
|
|
108
|
+
&.vc-banner_#{$variant} {
|
|
109
|
+
background-color: var(--status-#{$variant}-bg-color);
|
|
110
|
+
color: var(--status-#{$variant}-color);
|
|
111
|
+
|
|
112
|
+
.vc-banner__content {
|
|
113
|
+
color: var(--status-#{$variant}-color);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&__wrapper {
|
|
119
|
+
@apply tw-flex tw-flex-col tw-text-start;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&__container {
|
|
123
|
+
@apply tw-flex tw-flex-row tw-items-center;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&__title {
|
|
127
|
+
@apply tw-font-bold;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&__content {
|
|
131
|
+
@apply tw-overflow-hidden tw-truncate tw-text-[color:var(--banner-text-color)] tw-font-medium tw-text-xs;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&__icon {
|
|
135
|
+
@apply tw-mr-3;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
<div
|
|
37
37
|
v-show="!isCollapsedInternal"
|
|
38
38
|
:class="[{ 'tw-flex': fill }, 'vc-card__body']"
|
|
39
|
+
v-bind="$attrs"
|
|
39
40
|
>
|
|
40
41
|
<slot></slot>
|
|
41
42
|
</div>
|
|
@@ -70,6 +71,11 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
70
71
|
|
|
71
72
|
const emit = defineEmits<Emits>();
|
|
72
73
|
|
|
74
|
+
defineOptions({
|
|
75
|
+
name: "VcCard",
|
|
76
|
+
inheritAttrs: false,
|
|
77
|
+
});
|
|
78
|
+
|
|
73
79
|
defineSlots<{
|
|
74
80
|
default: (props?: any) => any;
|
|
75
81
|
actions: (props?: any) => any;
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
<label class="vc-checkbox__container">
|
|
26
26
|
<input
|
|
27
27
|
ref="checkboxRef"
|
|
28
|
-
v-model="
|
|
28
|
+
v-model="model"
|
|
29
|
+
:value="value"
|
|
29
30
|
type="checkbox"
|
|
30
31
|
class="vc-checkbox__input"
|
|
31
32
|
:disabled="disabled"
|
|
@@ -90,6 +91,7 @@ import { VcLabel } from "../../atoms/vc-label";
|
|
|
90
91
|
|
|
91
92
|
export interface Props {
|
|
92
93
|
modelValue: MaybeRef<boolean>;
|
|
94
|
+
value?: any;
|
|
93
95
|
disabled?: boolean;
|
|
94
96
|
required?: boolean;
|
|
95
97
|
name?: string;
|
|
@@ -124,7 +126,7 @@ defineSlots<{
|
|
|
124
126
|
|
|
125
127
|
const checkboxRef = ref<HTMLInputElement | null>(null);
|
|
126
128
|
|
|
127
|
-
const
|
|
129
|
+
const model = computed({
|
|
128
130
|
get() {
|
|
129
131
|
return unref(props.modelValue);
|
|
130
132
|
},
|
|
@@ -134,7 +136,11 @@ const value = computed({
|
|
|
134
136
|
});
|
|
135
137
|
|
|
136
138
|
const checked = computed(() => {
|
|
137
|
-
|
|
139
|
+
const modelVal = unref(props.modelValue);
|
|
140
|
+
if (Array.isArray(modelVal)) {
|
|
141
|
+
return modelVal.includes(props.value);
|
|
142
|
+
}
|
|
143
|
+
return modelVal === props.trueValue;
|
|
138
144
|
});
|
|
139
145
|
|
|
140
146
|
// Managing indeterminate state
|
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
@backlink:click="closeBlade(blades.length - 1)"
|
|
24
24
|
@logo:click="openRoot"
|
|
25
25
|
>
|
|
26
|
-
<template
|
|
26
|
+
<template
|
|
27
|
+
v-if="!disableAppSwitcher"
|
|
28
|
+
#app-switcher
|
|
29
|
+
>
|
|
27
30
|
<slot name="app-switcher">
|
|
28
31
|
<VcAppSwitcher
|
|
29
32
|
:apps-list="appsList"
|
|
@@ -95,6 +98,7 @@ import { provideMenuService } from "../../../../core/composables/useMenuService"
|
|
|
95
98
|
import { BellIcon } from "../../atoms/vc-icon/icons";
|
|
96
99
|
import { provideAppBarMobileButtonsService } from "../../../../core/composables/useAppBarMobileButtons";
|
|
97
100
|
import { useUserManagement } from "../../../../core/composables/useUserManagement";
|
|
101
|
+
import { BladeRegistryKey } from "../../../../core/composables/useBladeRegistry";
|
|
98
102
|
|
|
99
103
|
export interface Props {
|
|
100
104
|
isReady: boolean;
|
|
@@ -104,6 +108,7 @@ export interface Props {
|
|
|
104
108
|
avatar?: string;
|
|
105
109
|
name?: string;
|
|
106
110
|
disableMenu?: boolean;
|
|
111
|
+
disableAppSwitcher?: boolean;
|
|
107
112
|
role?: string;
|
|
108
113
|
}
|
|
109
114
|
|