@xwiki/cristal-dsvuetify 0.12.0 → 0.14.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/CHANGELOG.md +29 -0
- package/dist/{index-DCILSBLH.js → index-C4ioHAez.js} +4114 -4063
- package/dist/index-C4ioHAez.js.map +1 -0
- package/dist/index.es.js +6 -4
- package/dist/index.umd.js +10 -8
- package/dist/index.umd.js.map +1 -1
- package/dist/vue/form/x-checkbox.vue.d.ts +11 -0
- package/dist/vue/form/x-file-input.vue.d.ts +6 -6
- package/dist/vue/form/x-form.vue.d.ts +2 -1
- package/dist/vue/form/x-text-field.vue.d.ts +9 -1
- package/dist/vue/x-alert.vue.d.ts +2 -1
- package/dist/vue/x-avatar.vue.d.ts +2 -19
- package/dist/vue/x-btn.vue.d.ts +2 -1
- package/dist/vue/x-dialog.vue.d.ts +8 -8
- package/dist/vue/x-load.vue.d.ts +1 -1
- package/dist/vue/x-menu-item.vue.d.ts +6 -6
- package/dist/vue/x-menu-label.vue.d.ts +2 -1
- package/dist/vue/x-menu.vue.d.ts +2 -1
- package/dist/vue/x-navigation-tree.vue.d.ts +3 -5
- package/dist/vue/x-tab-group.vue.d.ts +4 -3
- package/dist/vue/x-tab-panel.vue.d.ts +2 -1
- package/dist/vue/x-tab.vue.d.ts +2 -1
- package/dist/x-alert-CTAhsN6L.js +46 -0
- package/dist/x-alert-CTAhsN6L.js.map +1 -0
- package/dist/x-avatar-Ds9aYRI9.js +28 -0
- package/dist/x-avatar-Ds9aYRI9.js.map +1 -0
- package/dist/x-breadcrumb-C2iUd4Sf.js.map +1 -1
- package/dist/{x-btn-DNlhiqjD.js → x-btn-BsiSIiiO.js} +9 -7
- package/dist/{x-btn-DNlhiqjD.js.map → x-btn-BsiSIiiO.js.map} +1 -1
- package/dist/x-card-CRM9KUby.js.map +1 -1
- package/dist/x-checkbox-CJ3_IJ-Y.js +28 -0
- package/dist/x-checkbox-CJ3_IJ-Y.js.map +1 -0
- package/dist/x-dialog-C4gz0mOu.js +48 -0
- package/dist/x-dialog-C4gz0mOu.js.map +1 -0
- package/dist/{x-file-input-BtGTZtfq.js → x-file-input-CMM5DWJc.js} +11 -9
- package/dist/{x-file-input-BtGTZtfq.js.map → x-file-input-CMM5DWJc.js.map} +1 -1
- package/dist/{x-form-pSj3365X.js → x-form-BLg386BG.js} +2 -2
- package/dist/{x-form-pSj3365X.js.map → x-form-BLg386BG.js.map} +1 -1
- package/dist/x-img-BYgs_O1F.js.map +1 -1
- package/dist/x-navigation-tree-BW05Yivz.js +502 -0
- package/dist/x-navigation-tree-BW05Yivz.js.map +1 -0
- package/dist/{x-tab-group-ngNByee3.js → x-tab-group-Bp7V46k9.js} +5 -5
- package/dist/{x-tab-group-ngNByee3.js.map → x-tab-group-Bp7V46k9.js.map} +1 -1
- package/dist/x-text-field-BxSiyeFc.js +38 -0
- package/dist/x-text-field-BxSiyeFc.js.map +1 -0
- package/langs/translation-de.json +4 -0
- package/langs/translation-fr.json +4 -1
- package/package.json +18 -11
- package/src/components/vuetifyDesignSystemLoader.ts +7 -0
- package/src/vue/css/style.css +17 -4
- package/src/vue/form/x-checkbox.vue +35 -0
- package/src/vue/form/x-file-input.vue +2 -2
- package/src/vue/form/x-text-field.vue +8 -1
- package/src/vue/x-alert.vue +10 -0
- package/src/vue/x-avatar.vue +9 -9
- package/src/vue/x-dialog.vue +10 -3
- package/src/vue/x-navigation-tree.vue +109 -68
- package/src/vue/x-tab-group.vue +2 -2
- package/src/vue/x-tab-panel.vue +0 -2
- package/tsconfig.json +14 -8
- package/dist/index-DCILSBLH.js.map +0 -1
- package/dist/x-alert-C3nY6ghP.js +0 -42
- package/dist/x-alert-C3nY6ghP.js.map +0 -1
- package/dist/x-avatar-But_Z7ic.js +0 -20
- package/dist/x-avatar-But_Z7ic.js.map +0 -1
- package/dist/x-dialog-Ce8KWptm.js +0 -38
- package/dist/x-dialog-Ce8KWptm.js.map +0 -1
- package/dist/x-navigation-tree-W6QDS4uh.js +0 -499
- package/dist/x-navigation-tree-W6QDS4uh.js.map +0 -1
- package/dist/x-text-field-CAVD3OjY.js +0 -29
- package/dist/x-text-field-CAVD3OjY.js.map +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { defineComponent as n, mergeModels as m, useModel as d, computed as i, openBlock as p, createBlock as f, unref as c } from "vue";
|
|
2
|
+
import { t as V } from "./translations-BNEIsfPR.js";
|
|
3
|
+
import { useI18n as b } from "vue-i18n";
|
|
4
|
+
import { a as v } from "./index-C4ioHAez.js";
|
|
5
|
+
const g = /* @__PURE__ */ n({
|
|
6
|
+
__name: "x-text-field",
|
|
7
|
+
props: /* @__PURE__ */ m({
|
|
8
|
+
name: {},
|
|
9
|
+
label: {},
|
|
10
|
+
required: { type: Boolean },
|
|
11
|
+
autofocus: { type: Boolean },
|
|
12
|
+
modelValue: {}
|
|
13
|
+
}, {
|
|
14
|
+
modelValue: {},
|
|
15
|
+
modelModifiers: {}
|
|
16
|
+
}),
|
|
17
|
+
emits: ["update:modelValue"],
|
|
18
|
+
setup(l) {
|
|
19
|
+
const { t: u } = b({
|
|
20
|
+
messages: V
|
|
21
|
+
}), a = l, t = d(l, "modelValue"), r = i(() => {
|
|
22
|
+
const e = [];
|
|
23
|
+
return a.required && e.push((o) => o ? !0 : u("vuetify.text.input.mandatory")), e;
|
|
24
|
+
});
|
|
25
|
+
return (e, o) => (p(), f(c(v), {
|
|
26
|
+
modelValue: t.value,
|
|
27
|
+
"onUpdate:modelValue": o[0] || (o[0] = (s) => t.value = s),
|
|
28
|
+
label: e.label,
|
|
29
|
+
name: e.name,
|
|
30
|
+
autofocus: e.autofocus,
|
|
31
|
+
rules: r.value
|
|
32
|
+
}, null, 8, ["modelValue", "label", "name", "autofocus", "rules"]));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
export {
|
|
36
|
+
g as default
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=x-text-field-BxSiyeFc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x-text-field-BxSiyeFc.js","sources":["../src/vue/form/x-text-field.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport messages from \"../../translations\";\nimport { computed } from \"vue\";\nimport { useI18n } from \"vue-i18n\";\nimport { VTextField } from \"vuetify/components/VTextField\";\nimport type { TextFieldProps } from \"@xwiki/cristal-dsapi\";\n\nconst { t } = useI18n({\n messages,\n});\nconst props = defineProps<TextFieldProps>();\nconst input = defineModel<string>();\n\nconst rules = computed(() => {\n const rulesList = [];\n if (props.required) {\n rulesList.push((value: unknown) => {\n if (value) {\n return true;\n } else {\n return t(\"vuetify.text.input.mandatory\");\n }\n });\n }\n return rulesList;\n});\n</script>\n\n<template>\n <v-text-field\n v-model=\"input\"\n :label=\"label\"\n :name=\"name\"\n :autofocus=\"autofocus\"\n :rules=\"rules\"\n ></v-text-field>\n</template>\n\n<style scoped></style>\n"],"names":["t","useI18n","messages","props","__props","input","_useModel","rules","computed","rulesList","value"],"mappings":";;;;;;;;;;;;;;;;;;AAOM,UAAA,EAAE,GAAAA,EAAE,IAAIC,EAAQ;AAAA,MACpBC,UAAAA;AAAAA,IAAA,CACD,GACKC,IAAQC,GACRC,IAAQC,EAAmBF,GAAA,YAAC,GAE5BG,IAAQC,EAAS,MAAM;AAC3B,YAAMC,IAAY,CAAC;AACnB,aAAIN,EAAM,YACEM,EAAA,KAAK,CAACC,MACVA,IACK,KAEAV,EAAE,8BAA8B,CAE1C,GAEIS;AAAA,IAAA,CACR;;;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xwiki/cristal-dsvuetify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"license": "LGPL 2.1",
|
|
5
5
|
"author": "XWiki Org Community <contact@xwiki.org>",
|
|
6
6
|
"homepage": "https://cristal.xwiki.org/",
|
|
@@ -22,19 +22,26 @@
|
|
|
22
22
|
},
|
|
23
23
|
"main": "./dist/index.es.js",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"inversify": "6.
|
|
26
|
-
"vue": "3.5.
|
|
27
|
-
"vue-i18n": "
|
|
28
|
-
"vuetify": "3.7.
|
|
29
|
-
"@xwiki/cristal-api": "0.
|
|
30
|
-
"@xwiki/cristal-
|
|
31
|
-
"@xwiki/cristal-
|
|
32
|
-
"@xwiki/cristal-
|
|
25
|
+
"inversify": "6.2.1",
|
|
26
|
+
"vue": "3.5.13",
|
|
27
|
+
"vue-i18n": "11.0.1",
|
|
28
|
+
"vuetify": "3.7.6",
|
|
29
|
+
"@xwiki/cristal-api": "0.14.0",
|
|
30
|
+
"@xwiki/cristal-model-api": "0.14.0",
|
|
31
|
+
"@xwiki/cristal-document-api": "0.14.0",
|
|
32
|
+
"@xwiki/cristal-navigation-tree-api": "0.14.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"reflect-metadata": "0.2.2"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
35
38
|
"@vue/test-utils": "2.4.6",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
39
|
+
"reflect-metadata": "0.2.2",
|
|
40
|
+
"typescript": "5.7.3",
|
|
41
|
+
"vite": "6.0.11",
|
|
42
|
+
"vue-tsc": "2.2.0",
|
|
43
|
+
"@xwiki/cristal-dev-config": "0.14.0",
|
|
44
|
+
"@xwiki/cristal-dsapi": "0.14.0"
|
|
38
45
|
},
|
|
39
46
|
"scripts": {
|
|
40
47
|
"build": "pnpm compile",
|
|
@@ -33,6 +33,8 @@ import type { App } from "vue";
|
|
|
33
33
|
|
|
34
34
|
@injectable()
|
|
35
35
|
export class VuetifyDesignSystemLoader implements DesignSystemLoader {
|
|
36
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
37
|
+
// eslint-disable-next-line max-statements
|
|
36
38
|
loadDesignSystem(app: App): void {
|
|
37
39
|
/*
|
|
38
40
|
// Manuel importing to reduce build size
|
|
@@ -139,5 +141,10 @@ export class VuetifyDesignSystemLoader implements DesignSystemLoader {
|
|
|
139
141
|
"XNavigationTree",
|
|
140
142
|
() => import("../vue/x-navigation-tree.vue"),
|
|
141
143
|
);
|
|
144
|
+
registerAsyncComponent(
|
|
145
|
+
app,
|
|
146
|
+
"XCheckbox",
|
|
147
|
+
() => import("../vue/form/x-checkbox.vue"),
|
|
148
|
+
);
|
|
142
149
|
}
|
|
143
150
|
}
|
package/src/vue/css/style.css
CHANGED
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
height: 64px;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
main ul {
|
|
29
|
+
padding-inline-start: var(--cr-spacing-x-large);
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
:root {
|
|
29
33
|
--cr-sizes-max-page-width: 960px; /*This value controls the width of the main content. It should be 100% for spanning text along the whole width or an arbitraty value*/
|
|
30
34
|
--cr-sizes-main-sidebar-width: 15%; /*The default width of the main sidebar*/
|
|
@@ -32,12 +36,15 @@
|
|
|
32
36
|
--cr-sizes-collapsed-main-sidebar-width: 32px; /*The width of the bar that gets shown containing the menu button to reopen the standard main main sidebar*/
|
|
33
37
|
--cr-base-font-size: 16px;
|
|
34
38
|
--cr-base-text-color: var(--cr-color-gray-950);
|
|
35
|
-
|
|
39
|
+
--cr-base-link-color: var(--cr-color-sky-700);
|
|
40
|
+
--cr-base-visited-link-color: var(--cr-color-blue-700);
|
|
36
41
|
|
|
37
42
|
/*
|
|
38
43
|
* Typography
|
|
39
44
|
*/
|
|
40
45
|
|
|
46
|
+
|
|
47
|
+
|
|
41
48
|
/* Fonts */
|
|
42
49
|
--cr-font-mono: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
|
|
43
50
|
--cr-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
|
|
@@ -82,9 +89,9 @@
|
|
|
82
89
|
--cr-focus-ring: var(--cr-focus-ring-style) var(--cr-focus-ring-width) var(--cr-focus-ring-color);
|
|
83
90
|
--cr-focus-ring-offset: 1px;
|
|
84
91
|
|
|
85
|
-
/*
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
/*
|
|
93
|
+
* Color Primitives
|
|
94
|
+
*/
|
|
88
95
|
|
|
89
96
|
/* Gray */
|
|
90
97
|
--cr-color-gray-50: hsl(0 0% 97.5%);
|
|
@@ -535,6 +542,12 @@
|
|
|
535
542
|
--cr-panel-border-color: var(--cr-color-neutral-200);
|
|
536
543
|
--cr-panel-border-width: 1px;
|
|
537
544
|
|
|
545
|
+
/*
|
|
546
|
+
* Header
|
|
547
|
+
*/
|
|
548
|
+
|
|
549
|
+
--cr-panel-background-color: var(--cr-color-neutral-0);
|
|
550
|
+
|
|
538
551
|
/*
|
|
539
552
|
* Tooltips
|
|
540
553
|
*/
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
See the LICENSE file distributed with this work for additional
|
|
3
|
+
information regarding copyright ownership.
|
|
4
|
+
|
|
5
|
+
This is free software; you can redistribute it and/or modify it
|
|
6
|
+
under the terms of the GNU Lesser General Public License as
|
|
7
|
+
published by the Free Software Foundation; either version 2.1 of
|
|
8
|
+
the License, or (at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This software is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
Lesser General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Lesser General Public
|
|
16
|
+
License along with this software; if not, write to the Free
|
|
17
|
+
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
18
|
+
02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
|
+
-->
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import { VCheckbox } from "vuetify/components/VCheckbox";
|
|
22
|
+
import type { CheckboxProps } from "@xwiki/cristal-dsapi";
|
|
23
|
+
|
|
24
|
+
defineProps<CheckboxProps>();
|
|
25
|
+
|
|
26
|
+
const checked = defineModel<boolean>();
|
|
27
|
+
</script>
|
|
28
|
+
<template>
|
|
29
|
+
<v-checkbox
|
|
30
|
+
v-model="checked"
|
|
31
|
+
:label="label"
|
|
32
|
+
:messages="help"
|
|
33
|
+
density="compact"
|
|
34
|
+
></v-checkbox>
|
|
35
|
+
</template>
|
|
@@ -3,13 +3,13 @@ import messages from "../../translations";
|
|
|
3
3
|
import { computed, defineModel } from "vue";
|
|
4
4
|
import { useI18n } from "vue-i18n";
|
|
5
5
|
import { VFileInput } from "vuetify/components/VFileInput";
|
|
6
|
-
import type {
|
|
6
|
+
import type { FileInputModel, TextFieldProps } from "@xwiki/cristal-dsapi";
|
|
7
7
|
|
|
8
8
|
const { t } = useI18n({
|
|
9
9
|
messages,
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
const model = defineModel<
|
|
12
|
+
const model = defineModel<FileInputModel>();
|
|
13
13
|
const props = defineProps<TextFieldProps>();
|
|
14
14
|
|
|
15
15
|
const rules = computed(() => {
|
|
@@ -9,6 +9,7 @@ const { t } = useI18n({
|
|
|
9
9
|
messages,
|
|
10
10
|
});
|
|
11
11
|
const props = defineProps<TextFieldProps>();
|
|
12
|
+
const input = defineModel<string>();
|
|
12
13
|
|
|
13
14
|
const rules = computed(() => {
|
|
14
15
|
const rulesList = [];
|
|
@@ -26,7 +27,13 @@ const rules = computed(() => {
|
|
|
26
27
|
</script>
|
|
27
28
|
|
|
28
29
|
<template>
|
|
29
|
-
<v-text-field
|
|
30
|
+
<v-text-field
|
|
31
|
+
v-model="input"
|
|
32
|
+
:label="label"
|
|
33
|
+
:name="name"
|
|
34
|
+
:autofocus="autofocus"
|
|
35
|
+
:rules="rules"
|
|
36
|
+
></v-text-field>
|
|
30
37
|
</template>
|
|
31
38
|
|
|
32
39
|
<style scoped></style>
|
package/src/vue/x-alert.vue
CHANGED
|
@@ -32,6 +32,16 @@ defineProps<AlertProps>();
|
|
|
32
32
|
@click="action.callback"
|
|
33
33
|
>{{ action.name }}</x-btn
|
|
34
34
|
>
|
|
35
|
+
<br v-if="details" />
|
|
36
|
+
<small v-if="details">{{ details }}</small>
|
|
35
37
|
<slot />
|
|
36
38
|
</v-alert>
|
|
37
39
|
</template>
|
|
40
|
+
|
|
41
|
+
<style scoped>
|
|
42
|
+
:deep(.v-alert__content a.router-link-active),
|
|
43
|
+
:deep(.v-alert__content a.router-link-active:visited) {
|
|
44
|
+
color: inherit;
|
|
45
|
+
text-decoration-color: inherit;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
package/src/vue/x-avatar.vue
CHANGED
|
@@ -17,14 +17,14 @@ License along with this software; if not, write to the Free
|
|
|
17
17
|
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
18
18
|
02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
19
19
|
-->
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import type { AvatarProps } from "@xwiki/cristal-dsapi";
|
|
22
|
+
|
|
23
|
+
defineProps<AvatarProps>();
|
|
24
|
+
</script>
|
|
20
25
|
<template>
|
|
21
|
-
<v-avatar :
|
|
26
|
+
<v-avatar :size="size">
|
|
27
|
+
<v-img v-if="image" :alt="name" :src="image"></v-img>
|
|
28
|
+
<span v-else>{{ name }}</span>
|
|
29
|
+
</v-avatar>
|
|
22
30
|
</template>
|
|
23
|
-
<script lang="ts">
|
|
24
|
-
export default {
|
|
25
|
-
props: {
|
|
26
|
-
image: { type: String, required: true },
|
|
27
|
-
size: { type: String, required: true },
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
</script>
|
package/src/vue/x-dialog.vue
CHANGED
|
@@ -22,12 +22,10 @@ defineProps<{
|
|
|
22
22
|
title: string;
|
|
23
23
|
width: string | number | undefined;
|
|
24
24
|
}>();
|
|
25
|
-
|
|
26
|
-
// const innerIsActive = ref(props.isActive);
|
|
27
25
|
</script>
|
|
28
26
|
|
|
29
27
|
<template>
|
|
30
|
-
<v-dialog :width="width">
|
|
28
|
+
<v-dialog :width="width" scrollable>
|
|
31
29
|
<template #activator="{ props }">
|
|
32
30
|
<span v-bind="props">
|
|
33
31
|
<slot name="activator" />
|
|
@@ -38,7 +36,16 @@ defineProps<{
|
|
|
38
36
|
<v-card-text>
|
|
39
37
|
<slot name="default" />
|
|
40
38
|
</v-card-text>
|
|
39
|
+
<v-card-actions v-if="$slots.footer">
|
|
40
|
+
<slot name="footer" />
|
|
41
|
+
</v-card-actions>
|
|
41
42
|
</v-card>
|
|
42
43
|
</template>
|
|
43
44
|
</v-dialog>
|
|
44
45
|
</template>
|
|
46
|
+
|
|
47
|
+
<style scoped>
|
|
48
|
+
:deep(.v-card-actions) {
|
|
49
|
+
padding: var(--cr-spacing-large);
|
|
50
|
+
}
|
|
51
|
+
</style>
|
|
@@ -33,6 +33,7 @@ import { inject, onBeforeMount, ref, watch } from "vue";
|
|
|
33
33
|
import { VTreeview } from "vuetify/labs/VTreeview";
|
|
34
34
|
import type { CristalApp, PageData } from "@xwiki/cristal-api";
|
|
35
35
|
import type { DocumentService } from "@xwiki/cristal-document-api";
|
|
36
|
+
import type { SpaceReference } from "@xwiki/cristal-model-api";
|
|
36
37
|
import type {
|
|
37
38
|
NavigationTreeNode,
|
|
38
39
|
NavigationTreeSource,
|
|
@@ -45,7 +46,7 @@ type TreeItem = {
|
|
|
45
46
|
title: string;
|
|
46
47
|
href: string;
|
|
47
48
|
children?: Array<TreeItem>;
|
|
48
|
-
_location:
|
|
49
|
+
_location: SpaceReference;
|
|
49
50
|
};
|
|
50
51
|
|
|
51
52
|
type OnClickAction = (node: NavigationTreeNode) => void;
|
|
@@ -60,10 +61,10 @@ const treeSource: NavigationTreeSource = cristal
|
|
|
60
61
|
.get();
|
|
61
62
|
|
|
62
63
|
const rootNodes: Ref<Array<TreeItem>> = ref([]);
|
|
63
|
-
const tree: Ref<VTreeview | undefined> = ref(undefined);
|
|
64
64
|
|
|
65
65
|
const activatedNodes: Ref<Array<string>> = ref(new Array<string>());
|
|
66
66
|
const expandedNodes: Ref<Array<string>> = ref(new Array<string>());
|
|
67
|
+
var isExpanding: boolean = false;
|
|
67
68
|
|
|
68
69
|
const props = defineProps<{
|
|
69
70
|
clickAction?: OnClickAction;
|
|
@@ -80,59 +81,56 @@ onBeforeMount(async () => {
|
|
|
80
81
|
_location: node.location,
|
|
81
82
|
});
|
|
82
83
|
}
|
|
83
|
-
|
|
84
|
-
await expandTree();
|
|
85
|
-
}
|
|
84
|
+
await expandTree();
|
|
86
85
|
|
|
87
86
|
documentService.registerDocumentChangeListener("delete", onDocumentDelete);
|
|
88
87
|
documentService.registerDocumentChangeListener("update", onDocumentUpdate);
|
|
89
88
|
});
|
|
90
89
|
|
|
91
|
-
watch(
|
|
92
|
-
() => props.currentPage,
|
|
93
|
-
async () => {
|
|
94
|
-
if (props.currentPage) {
|
|
95
|
-
await expandTree();
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
);
|
|
90
|
+
watch(() => props.currentPage, expandTree);
|
|
99
91
|
|
|
92
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
93
|
+
// eslint-disable-next-line max-statements
|
|
100
94
|
async function expandTree() {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
95
|
+
if (props.currentPage && !isExpanding) {
|
|
96
|
+
isExpanding = true;
|
|
97
|
+
const newExpandedNodes = treeSource.getParentNodesId(props.currentPage);
|
|
98
|
+
let i;
|
|
99
|
+
let currentNodes = rootNodes.value;
|
|
100
|
+
for (i = 0; i < newExpandedNodes.length - 1; i++) {
|
|
101
|
+
if (currentNodes) {
|
|
102
|
+
for (const node of currentNodes) {
|
|
103
|
+
if (node.id == newExpandedNodes[i]) {
|
|
104
|
+
if (node.children?.length == 0) {
|
|
105
|
+
await lazyLoadChildren(node);
|
|
106
|
+
}
|
|
107
|
+
if (!expandedNodes.value.includes(node.id)) {
|
|
108
|
+
expandedNodes.value.push(node.id);
|
|
109
|
+
}
|
|
110
|
+
currentNodes = node.children!;
|
|
113
111
|
}
|
|
114
|
-
currentNodes = node.children!;
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
115
|
+
if (currentNodes) {
|
|
116
|
+
for (const node of currentNodes) {
|
|
117
|
+
if (node.id == newExpandedNodes[i]) {
|
|
118
|
+
activatedNodes.value = [node.id];
|
|
119
|
+
// If we have a custom click action, we want to use it on dynamic
|
|
120
|
+
// selection.
|
|
121
|
+
if (props.clickAction) {
|
|
122
|
+
props.clickAction({
|
|
123
|
+
id: node.id,
|
|
124
|
+
label: node.title,
|
|
125
|
+
location: node._location,
|
|
126
|
+
url: node.href,
|
|
127
|
+
has_children: node.children !== undefined,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
133
130
|
}
|
|
134
131
|
}
|
|
135
132
|
}
|
|
133
|
+
isExpanding = false;
|
|
136
134
|
}
|
|
137
135
|
}
|
|
138
136
|
|
|
@@ -163,31 +161,45 @@ function clearSelection() {
|
|
|
163
161
|
}
|
|
164
162
|
}
|
|
165
163
|
|
|
164
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
165
|
+
// eslint-disable-next-line max-statements
|
|
166
166
|
async function onDocumentDelete(page: PageData) {
|
|
167
167
|
const parents = treeSource.getParentNodesId(page);
|
|
168
|
-
let
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
let currentItem: TreeItem | undefined = undefined;
|
|
169
|
+
let currentItemChildren: TreeItem[] | undefined = rootNodes.value;
|
|
170
|
+
let notFound = false;
|
|
171
|
+
|
|
172
|
+
currentItemsLoop: while (currentItemChildren && !notFound) {
|
|
173
|
+
for (const i of currentItemChildren.keys()) {
|
|
174
|
+
if (currentItemChildren[i].id == parents[0]) {
|
|
172
175
|
if (parents.length == 1) {
|
|
173
|
-
|
|
176
|
+
currentItemChildren.splice(i, 1);
|
|
177
|
+
if (currentItem && currentItemChildren.length == 0) {
|
|
178
|
+
currentItem!.children = undefined;
|
|
179
|
+
}
|
|
174
180
|
return;
|
|
175
181
|
} else {
|
|
176
|
-
|
|
182
|
+
currentItem = currentItemChildren[i];
|
|
183
|
+
currentItemChildren = currentItem.children;
|
|
177
184
|
parents.shift();
|
|
178
|
-
|
|
185
|
+
continue currentItemsLoop;
|
|
179
186
|
}
|
|
180
187
|
}
|
|
181
188
|
}
|
|
189
|
+
notFound = true;
|
|
182
190
|
}
|
|
183
191
|
}
|
|
184
192
|
|
|
193
|
+
// TODO: reduce the number of statements in the following method and reactivate the disabled eslint rule.
|
|
194
|
+
// eslint-disable-next-line max-statements
|
|
185
195
|
async function onDocumentUpdate(page: PageData) {
|
|
186
196
|
const parents = treeSource.getParentNodesId(page);
|
|
187
197
|
let currentParent: string | undefined = undefined;
|
|
188
198
|
let currentItems: TreeItem[] | undefined = rootNodes.value;
|
|
199
|
+
let notFound = false;
|
|
200
|
+
let isRoot = true;
|
|
189
201
|
|
|
190
|
-
while (currentItems) {
|
|
202
|
+
currentItemsLoop: while (currentItems && !notFound) {
|
|
191
203
|
for (const i of currentItems.keys()) {
|
|
192
204
|
if (currentItems[i].id == parents[0]) {
|
|
193
205
|
if (parents.length == 1) {
|
|
@@ -203,30 +215,49 @@ async function onDocumentUpdate(page: PageData) {
|
|
|
203
215
|
}
|
|
204
216
|
} else {
|
|
205
217
|
currentParent = currentItems[i].id;
|
|
218
|
+
if (!currentItems[i].children) {
|
|
219
|
+
// This node had no children, we reset this so new ones can be
|
|
220
|
+
// loaded lazily.
|
|
221
|
+
currentItems[i].children = [];
|
|
222
|
+
}
|
|
206
223
|
currentItems = currentItems[i].children;
|
|
207
224
|
parents.shift();
|
|
208
|
-
|
|
225
|
+
isRoot = false;
|
|
226
|
+
continue currentItemsLoop;
|
|
209
227
|
}
|
|
210
228
|
}
|
|
211
229
|
}
|
|
230
|
+
notFound = true;
|
|
231
|
+
}
|
|
212
232
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
233
|
+
// New page
|
|
234
|
+
if (currentItems.length == 0 && !isRoot) {
|
|
235
|
+
// We don't do anything because this node will be loaded lazily anyway.
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const newItems = await treeSource.getChildNodes(
|
|
239
|
+
currentParent ? currentParent : "",
|
|
240
|
+
);
|
|
241
|
+
const currentPageParents = treeSource.getParentNodesId(props.currentPage);
|
|
242
|
+
newItemsLoop: for (const newItem of newItems) {
|
|
243
|
+
for (const i of currentItems!.keys()) {
|
|
244
|
+
if (newItem.id == currentItems![i].id) {
|
|
245
|
+
continue newItemsLoop;
|
|
222
246
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
247
|
+
}
|
|
248
|
+
currentItems!.push({
|
|
249
|
+
id: newItem.id,
|
|
250
|
+
title: newItem.label,
|
|
251
|
+
href: newItem.url,
|
|
252
|
+
children: newItem.has_children ? [] : undefined,
|
|
253
|
+
_location: newItem.location,
|
|
254
|
+
});
|
|
255
|
+
if (
|
|
256
|
+
currentPageParents.length > 0 &&
|
|
257
|
+
currentPageParents[currentPageParents.length - 1] === newItem.id
|
|
258
|
+
) {
|
|
259
|
+
// If we add a node, and it's the current page, it should be activated.
|
|
260
|
+
activatedNodes.value = [newItem.id];
|
|
230
261
|
}
|
|
231
262
|
}
|
|
232
263
|
}
|
|
@@ -234,7 +265,6 @@ async function onDocumentUpdate(page: PageData) {
|
|
|
234
265
|
|
|
235
266
|
<template>
|
|
236
267
|
<v-treeview
|
|
237
|
-
ref="tree"
|
|
238
268
|
v-model:opened="expandedNodes"
|
|
239
269
|
density="compact"
|
|
240
270
|
:activated="activatedNodes"
|
|
@@ -243,7 +273,6 @@ async function onDocumentUpdate(page: PageData) {
|
|
|
243
273
|
activatable
|
|
244
274
|
active-strategy="independent"
|
|
245
275
|
item-value="id"
|
|
246
|
-
open-strategy="multiple"
|
|
247
276
|
@update:activated="clearSelection"
|
|
248
277
|
>
|
|
249
278
|
<template #title="{ item }: { item: any }">
|
|
@@ -283,4 +312,16 @@ async function onDocumentUpdate(page: PageData) {
|
|
|
283
312
|
:deep(.v-list-item--link) {
|
|
284
313
|
cursor: default;
|
|
285
314
|
}
|
|
315
|
+
/*TODO: This section needs to be removed when the oficial fix is released on Vuetify
|
|
316
|
+
https://github.com/vuetifyjs/vuetify/issues/20421#event-16001533054
|
|
317
|
+
START FIX
|
|
318
|
+
*/
|
|
319
|
+
:deep(.v-treeview-item:not(.v-list-group__header)) {
|
|
320
|
+
padding-inline-start: calc(39px + 6px) !important;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
:deep(.v-treeview-item .v-list-item__spacer) {
|
|
324
|
+
width: 4px !important;
|
|
325
|
+
}
|
|
326
|
+
/*END FIX*/
|
|
286
327
|
</style>
|
package/src/vue/x-tab-group.vue
CHANGED
|
@@ -21,11 +21,11 @@ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
21
21
|
import { ref } from "vue";
|
|
22
22
|
const tab = ref(null);
|
|
23
23
|
|
|
24
|
-
const emits = defineEmits(["change"]);
|
|
24
|
+
const emits = defineEmits(["tab-change"]);
|
|
25
25
|
|
|
26
26
|
function change(tabId: unknown) {
|
|
27
27
|
if (typeof tabId == "string") {
|
|
28
|
-
emits("change", tabId);
|
|
28
|
+
emits("tab-change", tabId);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
</script>
|
package/src/vue/x-tab-panel.vue
CHANGED
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"rootDir": "src",
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"isolatedDeclarations": false
|
|
6
|
+
},
|
|
7
|
+
"extends": "./../../tsconfig.json",
|
|
8
|
+
"include": [
|
|
9
|
+
"./src/index.ts",
|
|
10
|
+
"./src/**/*"
|
|
11
|
+
],
|
|
12
|
+
"exclude": [
|
|
13
|
+
"**/*.spec.ts",
|
|
14
|
+
"**/*.test.ts"
|
|
15
|
+
]
|
|
10
16
|
}
|