viur-ui 0.0.1
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/README.md +79 -0
- package/index.d.ts +351 -0
- package/index.js +46 -0
- package/package.json +84 -0
- package/src/components/Browser/Browser.vue +496 -0
- package/src/components/Browser/TreeNav.vue +408 -0
- package/src/components/Browser/ViurBrowser.d.vue.ts +64 -0
- package/src/components/Browser/ViurBrowser.vue +271 -0
- package/src/components/Browser/dragSession.ts +134 -0
- package/src/components/Browser/index.ts +14 -0
- package/src/components/Browser/types.ts +30 -0
- package/src/components/DataTable/ColumnFilterPanel.vue +225 -0
- package/src/components/DataTable/DataTable.vue +3155 -0
- package/src/components/DataTable/ViurDataTable.d.vue.ts +72 -0
- package/src/components/DataTable/ViurDataTable.vue +331 -0
- package/src/components/DataTable/columns.ts +400 -0
- package/src/components/DataTable/index.ts +60 -0
- package/src/components/DataTable/rows.ts +446 -0
- package/src/components/DataTable/types.ts +267 -0
- package/src/components/DataTable/useColumnLayout.ts +294 -0
- package/src/components/DataTable/useGridNavigation.ts +193 -0
- package/src/components/DataTable/useVirtualRows.ts +126 -0
- package/src/components/DataTable/viurColumns.ts +330 -0
- package/src/forms/ViForm.d.vue.ts +106 -0
- package/src/forms/ViForm.vue +592 -0
- package/src/forms/ViFormCategory.vue +57 -0
- package/src/forms/bones/Bone.vue +1023 -0
- package/src/forms/bones/BoneActions.vue +127 -0
- package/src/forms/bones/BoneLabel.vue +122 -0
- package/src/forms/bones/BoneMultipleList.vue +91 -0
- package/src/forms/bones/BoneMultipleWrapper.vue +105 -0
- package/src/forms/bones/BoneNestedWrapper.vue +155 -0
- package/src/forms/bones/BoneSingleEntry.vue +51 -0
- package/src/forms/bones/FilterBone.vue +694 -0
- package/src/forms/bones/actionbar/defaultBar.vue +98 -0
- package/src/forms/bones/actionbar/fileBar.vue +165 -0
- package/src/forms/bones/actionbar/relationalBar.vue +125 -0
- package/src/forms/bones/actions/ActionDialog.vue +70 -0
- package/src/forms/bones/actions/Debug.vue +106 -0
- package/src/forms/bones/actions/Delete.vue +13 -0
- package/src/forms/bones/actions/DescribeImage.vue +201 -0
- package/src/forms/bones/actions/Download.vue +27 -0
- package/src/forms/bones/actions/Placeholder.vue +14 -0
- package/src/forms/bones/actions/Translation.vue +238 -0
- package/src/forms/bones/actions/index.js +280 -0
- package/src/forms/bones/bone.d.ts +45 -0
- package/src/forms/bones/country_information.json +779 -0
- package/src/forms/bones/index.js +225 -0
- package/src/forms/bones/uploadAdapter.js +46 -0
- package/src/forms/bones/utils.js +284 -0
- package/src/forms/bones/view/base_item.vue +35 -0
- package/src/forms/bones/view/boneLogic.js +202 -0
- package/src/forms/bones/view/index.js +5 -0
- package/src/forms/bones/widgets/booleanBone.vue +83 -0
- package/src/forms/bones/widgets/booleanBoneChoose.vue +57 -0
- package/src/forms/bones/widgets/booleanBoneSelect.vue +58 -0
- package/src/forms/bones/widgets/codeBone.vue +214 -0
- package/src/forms/bones/widgets/colorBone.vue +75 -0
- package/src/forms/bones/widgets/dateBone.vue +114 -0
- package/src/forms/bones/widgets/emailBone.vue +100 -0
- package/src/forms/bones/widgets/fileBone.vue +273 -0
- package/src/forms/bones/widgets/jsonBone.vue +63 -0
- package/src/forms/bones/widgets/keyBone.vue +71 -0
- package/src/forms/bones/widgets/numericBone.vue +125 -0
- package/src/forms/bones/widgets/passwordBone.vue +215 -0
- package/src/forms/bones/widgets/phoneBone.vue +173 -0
- package/src/forms/bones/widgets/rawBone.vue +94 -0
- package/src/forms/bones/widgets/recordBone.vue +64 -0
- package/src/forms/bones/widgets/relationalBone.vue +164 -0
- package/src/forms/bones/widgets/relationalBoneSelect.vue +120 -0
- package/src/forms/bones/widgets/selectBone.vue +122 -0
- package/src/forms/bones/widgets/selectBoneChoose.vue +104 -0
- package/src/forms/bones/widgets/spatialBone.vue +111 -0
- package/src/forms/bones/widgets/stringBone.vue +139 -0
- package/src/forms/bones/widgets/textBone.vue +641 -0
- package/src/forms/install.d.ts +4 -0
- package/src/forms/install.js +43 -0
- package/src/forms/layouts/LayloutList2Columns.vue +57 -0
- package/src/forms/layouts/LayoutCategory.vue +38 -0
- package/src/forms/layouts/LayoutList.vue +31 -0
- package/src/forms/utils.js +601 -0
- package/src/public/assets/icons/fontawesome-manifest.json +8 -0
- package/src/public/assets/icons/regular/file.svg +1 -0
- package/src/public/assets/icons/solid/arrows-left-right.svg +1 -0
- package/src/public/assets/icons/solid/bug.svg +1 -0
- package/src/public/assets/icons/solid/check.svg +1 -0
- package/src/public/assets/icons/solid/circle-info.svg +1 -0
- package/src/public/assets/icons/solid/compress.svg +1 -0
- package/src/public/assets/icons/solid/download.svg +1 -0
- package/src/public/assets/icons/solid/expand.svg +1 -0
- package/src/public/assets/icons/solid/grip-vertical.svg +1 -0
- package/src/public/assets/icons/solid/plus.svg +1 -0
- package/src/public/assets/icons/solid/question.svg +1 -0
- package/src/public/assets/icons/solid/triangle-exclamation.svg +1 -0
- package/src/public/assets/icons/solid/upload.svg +1 -0
- package/src/public/assets/icons/solid/xmark.svg +1 -0
- package/src/request/cache.js +183 -0
- package/src/request/configStore.js +516 -0
- package/src/request/envelope.js +211 -0
- package/src/request/index.js +35 -0
- package/src/request/messageStore.js +201 -0
- package/src/request/request.js +752 -0
- package/src/request/skel.js +90 -0
- package/src/theme/colorStore.js +168 -0
- package/src/translations/de.js +178 -0
- package/src/translations/en.js +177 -0
- package/src/user/LoginScreen.d.vue.ts +54 -0
- package/src/user/LoginScreen.vue +627 -0
- package/src/user/google.js +75 -0
- package/src/user/index.js +3 -0
- package/src/user/store.d.ts +59 -0
- package/src/user/store.js +183 -0
- package/src/webawesomeCompat.css +72 -0
- package/src/webawesomeConfig.js +61 -0
|
@@ -0,0 +1,1023 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="bone"
|
|
4
|
+
:class="{
|
|
5
|
+
'has-subbones': state.bonestructure['using'],
|
|
6
|
+
'is-label-top': label === 'top',
|
|
7
|
+
'is-label-hide': ['hide', 'placeholder'].includes(label),
|
|
8
|
+
[`bone-type-${state.bonestructure['type'].split('.')[0]}`]: true,
|
|
9
|
+
[`bone-name-${name}`]: true,
|
|
10
|
+
'is-required': state.required,
|
|
11
|
+
}"
|
|
12
|
+
>
|
|
13
|
+
<bone-label
|
|
14
|
+
v-if="!['hide', 'placeholder'].includes(label)"
|
|
15
|
+
:name="name"
|
|
16
|
+
:debug="state.debug"
|
|
17
|
+
>
|
|
18
|
+
<span :class="{ 'bone-label-required': state.required }">{{ state.bonestructure["descr"] }}</span>
|
|
19
|
+
<span
|
|
20
|
+
v-if="state.required"
|
|
21
|
+
class="bone-label-required"
|
|
22
|
+
>
|
|
23
|
+
*
|
|
24
|
+
</span>
|
|
25
|
+
<wa-tooltip
|
|
26
|
+
v-if="state.hasTooltip && !showLabelInfo"
|
|
27
|
+
:for="state.labelTooltipTargetId"
|
|
28
|
+
:content="$t(state.bonestructure.params['tooltip'])"
|
|
29
|
+
placement="top-center"
|
|
30
|
+
></wa-tooltip>
|
|
31
|
+
<div
|
|
32
|
+
v-if="state.hasTooltip && !showLabelInfo"
|
|
33
|
+
:id="state.labelTooltipTargetId"
|
|
34
|
+
class="bone-label-tooltip"
|
|
35
|
+
>
|
|
36
|
+
<wa-icon name="question"></wa-icon>
|
|
37
|
+
</div>
|
|
38
|
+
</bone-label>
|
|
39
|
+
|
|
40
|
+
<wa-alert
|
|
41
|
+
v-if="showLabelInfo && state.hasTooltip"
|
|
42
|
+
variant="brand"
|
|
43
|
+
open
|
|
44
|
+
class="bone-label-info"
|
|
45
|
+
>
|
|
46
|
+
<wa-icon
|
|
47
|
+
slot="icon"
|
|
48
|
+
name="circle-info"
|
|
49
|
+
></wa-icon>
|
|
50
|
+
{{ state.bonestructure.params["tooltip"] }}
|
|
51
|
+
</wa-alert>
|
|
52
|
+
<wa-tooltip
|
|
53
|
+
class="bone-tooltip"
|
|
54
|
+
:for="state.boneTooltipTargetId"
|
|
55
|
+
:disabled="!state.showtooltip"
|
|
56
|
+
:content="state.bonestructure?.['descr']"
|
|
57
|
+
style="--show-delay: 1000"
|
|
58
|
+
></wa-tooltip>
|
|
59
|
+
|
|
60
|
+
<div
|
|
61
|
+
:id="state.boneTooltipTargetId"
|
|
62
|
+
class="bone-inner wa-stack wa-gap-xs"
|
|
63
|
+
:class="{ 'is-required': state.required }"
|
|
64
|
+
>
|
|
65
|
+
<!-- Multilanguage: Tab per Sprache -->
|
|
66
|
+
<div
|
|
67
|
+
v-if="state.multilanguage"
|
|
68
|
+
class="bone-row wa-flank:end wa-gap-xs wa-align-items-start"
|
|
69
|
+
>
|
|
70
|
+
<wa-tab-group
|
|
71
|
+
class="bone-lang-tabs"
|
|
72
|
+
placement="bottom"
|
|
73
|
+
>
|
|
74
|
+
<template
|
|
75
|
+
v-for="lang in state.languages"
|
|
76
|
+
:key="name + '_' + lang + '_tab'"
|
|
77
|
+
>
|
|
78
|
+
<wa-tab
|
|
79
|
+
slot="nav"
|
|
80
|
+
:panel="'lang_' + lang"
|
|
81
|
+
:active="state.currentLanguage === lang"
|
|
82
|
+
:data-lang="lang"
|
|
83
|
+
@click="updateLanguage"
|
|
84
|
+
>
|
|
85
|
+
{{ $t(lang) }}
|
|
86
|
+
</wa-tab>
|
|
87
|
+
<wa-tab-panel
|
|
88
|
+
:name="'lang_' + lang"
|
|
89
|
+
:active="state.currentLanguage === lang"
|
|
90
|
+
>
|
|
91
|
+
<bone-multiple-list
|
|
92
|
+
:is="is"
|
|
93
|
+
v-if="state.multiple && !BoneHasMultipleHandling(state.bonestructure['type'])"
|
|
94
|
+
:name="name"
|
|
95
|
+
:lang="lang"
|
|
96
|
+
:entries="state.bonevalue?.[lang]"
|
|
97
|
+
:bonestructure="state.bonestructure"
|
|
98
|
+
:readonly="state.readonly"
|
|
99
|
+
:actionbar="state.actionbar"
|
|
100
|
+
/>
|
|
101
|
+
<!-- Wert-Actions (Löschen, Download …) je Sprache am Eintrag -->
|
|
102
|
+
<bone-single-entry
|
|
103
|
+
:is="is"
|
|
104
|
+
v-else
|
|
105
|
+
:name="name"
|
|
106
|
+
:lang="lang"
|
|
107
|
+
:bonevalue="state.bonevalue?.[lang]"
|
|
108
|
+
:bonestructure="state.bonestructure"
|
|
109
|
+
:boneactions="false"
|
|
110
|
+
/>
|
|
111
|
+
</wa-tab-panel>
|
|
112
|
+
</template>
|
|
113
|
+
</wa-tab-group>
|
|
114
|
+
<!-- Bone-Actions über alle Sprachen (Übersetzen …) -->
|
|
115
|
+
<div
|
|
116
|
+
v-if="state.boneactions && !state.multiple && state.hasOptionalActions"
|
|
117
|
+
class="wa-cluster wa-gap-xs"
|
|
118
|
+
>
|
|
119
|
+
<bone-actions
|
|
120
|
+
:value="state.bonevalue"
|
|
121
|
+
:name="name"
|
|
122
|
+
:index="null"
|
|
123
|
+
:bone="state.bonestructure"
|
|
124
|
+
scope="bone"
|
|
125
|
+
@change="updateValue"
|
|
126
|
+
></bone-actions>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<!-- Einsprachig -->
|
|
131
|
+
<template v-else>
|
|
132
|
+
<bone-multiple-list
|
|
133
|
+
:is="is"
|
|
134
|
+
v-if="state.multiple && !BoneHasMultipleHandling(state.bonestructure['type'])"
|
|
135
|
+
:name="name"
|
|
136
|
+
:entries="state.bonevalue"
|
|
137
|
+
:bonestructure="state.bonestructure"
|
|
138
|
+
:readonly="state.readonly"
|
|
139
|
+
:actionbar="state.actionbar"
|
|
140
|
+
/>
|
|
141
|
+
<bone-single-entry
|
|
142
|
+
:is="is"
|
|
143
|
+
v-else
|
|
144
|
+
:name="name"
|
|
145
|
+
:bonevalue="state.bonevalue"
|
|
146
|
+
:bonestructure="state.bonestructure"
|
|
147
|
+
:boneactions="state.boneactions"
|
|
148
|
+
:autofocus="autofocus"
|
|
149
|
+
/>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<!-- Fehlermeldungen -->
|
|
153
|
+
<template v-if="errorStyle === 'default'">
|
|
154
|
+
<wa-callout
|
|
155
|
+
v-for="message in state.errorMessages"
|
|
156
|
+
:key="message"
|
|
157
|
+
open
|
|
158
|
+
:summary="$t('bone.errors_summary')"
|
|
159
|
+
variant="danger"
|
|
160
|
+
class="bone-error"
|
|
161
|
+
>
|
|
162
|
+
<wa-icon
|
|
163
|
+
slot="icon"
|
|
164
|
+
name="triangle-exclamation"
|
|
165
|
+
></wa-icon>
|
|
166
|
+
<div class="bone-error">
|
|
167
|
+
{{ errorMessage(message) }}
|
|
168
|
+
</div>
|
|
169
|
+
</wa-callout>
|
|
170
|
+
</template>
|
|
171
|
+
<template v-else>
|
|
172
|
+
<div
|
|
173
|
+
v-for="message in state.errorMessages"
|
|
174
|
+
:key="message"
|
|
175
|
+
style="font-size: 0.8em; color: red"
|
|
176
|
+
>
|
|
177
|
+
{{ errorMessage(message) }}
|
|
178
|
+
</div>
|
|
179
|
+
</template>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</template>
|
|
183
|
+
|
|
184
|
+
<script setup>
|
|
185
|
+
/** @displayName Bone */
|
|
186
|
+
import { reactive, computed, onBeforeMount, provide, watch, watchEffect, inject, unref } from "vue"
|
|
187
|
+
import BoneLabel from "./BoneLabel.vue"
|
|
188
|
+
import { BoneHasMultipleHandling, getBoneActionbar } from "./index"
|
|
189
|
+
import rawBone from "./widgets/rawBone.vue"
|
|
190
|
+
import Utils, { buildBoneDomId } from "./utils"
|
|
191
|
+
import BoneActions from "./BoneActions.vue"
|
|
192
|
+
import { formConfiguredActions, resolveActions } from "./actions"
|
|
193
|
+
import BoneMultipleList from "./BoneMultipleList.vue"
|
|
194
|
+
import BoneSingleEntry from "./BoneSingleEntry.vue"
|
|
195
|
+
import { useI18n } from "vue-i18n"
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @emits change - Historisches Relikt, wird nicht direkt genutzt
|
|
199
|
+
* @emits change-internal {Object} - Internes Event für ViForm: { name, value, lang, index, valid }
|
|
200
|
+
* @emits handleClick - Historisches Relikt, wird nicht direkt genutzt
|
|
201
|
+
*/
|
|
202
|
+
const emit = defineEmits(["change", "change-internal", "handleClick"])
|
|
203
|
+
|
|
204
|
+
const props = defineProps({
|
|
205
|
+
is: {
|
|
206
|
+
type: Object,
|
|
207
|
+
default: rawBone, // Das zu rendernde Bone-Widget (z.B. StringBone), typischerweise von ViForm gesetzt
|
|
208
|
+
},
|
|
209
|
+
name: {
|
|
210
|
+
type: String,
|
|
211
|
+
required: true, // Bone-Identifier; muss einem Key in structure und skel entsprechen
|
|
212
|
+
},
|
|
213
|
+
languages: {
|
|
214
|
+
type: Array,
|
|
215
|
+
default: undefined, // Explizite Sprach-Liste; überschreibt bonestructure.languages
|
|
216
|
+
},
|
|
217
|
+
multiple: {
|
|
218
|
+
type: Boolean,
|
|
219
|
+
default: false, // Expliziter Multiple-Flag; überschreibt bonestructure.multiple
|
|
220
|
+
},
|
|
221
|
+
readonly: {
|
|
222
|
+
type: Boolean,
|
|
223
|
+
default: false, // Expliziter Readonly-Flag; überschreibt bonestructure.readonly
|
|
224
|
+
},
|
|
225
|
+
required: {
|
|
226
|
+
type: Boolean,
|
|
227
|
+
default: false, // Expliziter Required-Flag; überschreibt bonestructure.required
|
|
228
|
+
},
|
|
229
|
+
params: {
|
|
230
|
+
type: Object,
|
|
231
|
+
default: undefined, // Zusätzliche Parameter; überschreibt bonestructure.params
|
|
232
|
+
},
|
|
233
|
+
value: {
|
|
234
|
+
type: [Object, String, Number, Boolean, Array],
|
|
235
|
+
default: undefined, // Expliziter Wert; überschreibt skel[name] wenn gesetzt
|
|
236
|
+
},
|
|
237
|
+
structure: {
|
|
238
|
+
type: Object,
|
|
239
|
+
required: true, // Vollständige Skeleton-Struktur (alle Bone-Definitionen des Formulars)
|
|
240
|
+
},
|
|
241
|
+
skel: {
|
|
242
|
+
type: null,
|
|
243
|
+
required: true, // Skeleton-Datenobjekt mit den aktuellen Werten
|
|
244
|
+
},
|
|
245
|
+
errors: {
|
|
246
|
+
type: Array,
|
|
247
|
+
default: () => [], // Fehler-Array aus der Server-Antwort; Einträge mit passendem fieldPath werden angezeigt
|
|
248
|
+
},
|
|
249
|
+
label: {
|
|
250
|
+
type: String,
|
|
251
|
+
default: "normal", // Label-Modus: "normal" | "top" | "hide" | "placeholder"
|
|
252
|
+
validator(value, props) {
|
|
253
|
+
return ["normal", "top", "hide", "placeholder"].includes(value)
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
boneactions: {
|
|
257
|
+
type: Boolean,
|
|
258
|
+
default: true, // Aktiviert BoneActions (Defaults pro Bone-Type + bone.params.actions). Explizit false um Actions zu unterdrücken.
|
|
259
|
+
},
|
|
260
|
+
showLabelInfo: {
|
|
261
|
+
type: Boolean,
|
|
262
|
+
default: false, // Zeigt Tooltip-Inhalt als wa-alert statt als Tooltip
|
|
263
|
+
},
|
|
264
|
+
autofocus: {
|
|
265
|
+
type: Boolean,
|
|
266
|
+
default: false, // Gibt autofocus an das Bone-Widget weiter
|
|
267
|
+
},
|
|
268
|
+
defaultLanguage: {
|
|
269
|
+
type: String,
|
|
270
|
+
default: "de", // Standardmäßig aktive Sprache im Multilang-Tab
|
|
271
|
+
},
|
|
272
|
+
showBoneTooltip: {
|
|
273
|
+
type: Boolean,
|
|
274
|
+
default: false, // Erzwingt den Tooltip auf dem Input-Bereich
|
|
275
|
+
},
|
|
276
|
+
errorStyle: {
|
|
277
|
+
type: String,
|
|
278
|
+
default: "default", // Fehler-Darstellungsstil: "default" (wa-alert) | "decent" (kleiner roter Text)
|
|
279
|
+
validator(value, props) {
|
|
280
|
+
return ["default", "decent"].includes(value)
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
debug: {
|
|
284
|
+
type: Boolean,
|
|
285
|
+
default: false, // Aktiviert Debug-Modus: Bone-Name als Tooltip am Label
|
|
286
|
+
},
|
|
287
|
+
})
|
|
288
|
+
const { t } = useI18n()
|
|
289
|
+
|
|
290
|
+
const parentBonePath = inject("bonePath", [])
|
|
291
|
+
// Für die Sichtbarkeit der Relations-Auswahl (Action-`when` prüft darauf).
|
|
292
|
+
const relationSelector = inject("viurRelationSelector", null)
|
|
293
|
+
// Formular-weite Action-Konfiguration (ViForm `actions`-Prop).
|
|
294
|
+
const boneActionsConfig = inject("boneActionsConfig", null)
|
|
295
|
+
/** Vollständiger Bone-Pfad als Array für verschachtelte Bone-DOM-IDs. @returns {ComputedRef<string[]>} */
|
|
296
|
+
const bonePath = computed(() => [...(unref(parentBonePath) ?? []), props.name])
|
|
297
|
+
provide("bonePath", bonePath)
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Prüft ob ein Objekt ausschließlich null-Werte oder leere Arrays enthält.
|
|
301
|
+
* @param {Object} obj - Das zu prüfende Objekt
|
|
302
|
+
* @returns {boolean}
|
|
303
|
+
*/
|
|
304
|
+
function isObjectEmpty(obj) {
|
|
305
|
+
for (const [, value] of Object.entries(obj)) {
|
|
306
|
+
if (value !== null) {
|
|
307
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
308
|
+
return false
|
|
309
|
+
} else if (!Array.isArray(value)) {
|
|
310
|
+
return false
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return true
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const state = reactive({
|
|
318
|
+
boneactions: computed(() => props.boneactions), // Ob BoneActions-Schaltflächen angezeigt werden
|
|
319
|
+
|
|
320
|
+
// Die Bone-Definition aus der Struktur (z.B. type, params, languages)
|
|
321
|
+
bonestructure: computed(() => {
|
|
322
|
+
return props.structure?.[props.name]
|
|
323
|
+
}),
|
|
324
|
+
bonevalue: null, // Aktueller Bone-Wert; wird aus skel initialisiert und bei Änderungen aktualisiert
|
|
325
|
+
multilanguage: computed(() => state.languages?.length && state.languages.length > 0), // Ob der Bone mehrsprachig ist (mindestens eine Sprache konfiguriert)
|
|
326
|
+
// Aktive Sprach-Liste: aus props.languages oder bonestructure.languages
|
|
327
|
+
languages: computed(() => {
|
|
328
|
+
if (props.languages) {
|
|
329
|
+
return props.languages
|
|
330
|
+
}
|
|
331
|
+
return state.bonestructure && Object.keys(state.bonestructure).includes("languages")
|
|
332
|
+
? state.bonestructure["languages"]
|
|
333
|
+
: []
|
|
334
|
+
}),
|
|
335
|
+
// Readonly-Status: props.readonly hat Vorrang vor bonestructure.readonly
|
|
336
|
+
readonly: computed(() => {
|
|
337
|
+
if (props.readonly) {
|
|
338
|
+
return props.readonly
|
|
339
|
+
}
|
|
340
|
+
return state.bonestructure && Object.keys(state.bonestructure).includes("readonly")
|
|
341
|
+
? state.bonestructure["readonly"]
|
|
342
|
+
: false
|
|
343
|
+
}),
|
|
344
|
+
// Required-Status: props.required hat Vorrang vor bonestructure.required
|
|
345
|
+
required: computed(() => {
|
|
346
|
+
if (props.required) {
|
|
347
|
+
return props.required
|
|
348
|
+
}
|
|
349
|
+
return state.bonestructure && Object.keys(state.bonestructure).includes("required")
|
|
350
|
+
? state.bonestructure["required"]
|
|
351
|
+
: false
|
|
352
|
+
}),
|
|
353
|
+
// Ob ein Tooltip-Text in bonestructure.params vorhanden ist
|
|
354
|
+
hasTooltip: computed(() => {
|
|
355
|
+
// `params` kommt von viur-core immer als Objekt; fehlt es (eigener Renderer,
|
|
356
|
+
// handgebaute Struktur), darf das Formular davon nicht sterben.
|
|
357
|
+
return state.bonestructure && Object.keys(state.bonestructure["params"] ?? {}).includes("tooltip") ? true : false
|
|
358
|
+
}),
|
|
359
|
+
// Multiple-Status: props.multiple hat Vorrang vor bonestructure.multiple
|
|
360
|
+
multiple: computed(() => {
|
|
361
|
+
if (props.multiple) {
|
|
362
|
+
return props.multiple
|
|
363
|
+
}
|
|
364
|
+
return state.bonestructure && Object.keys(state.bonestructure).includes("multiple")
|
|
365
|
+
? state.bonestructure["multiple"]
|
|
366
|
+
: false
|
|
367
|
+
}),
|
|
368
|
+
// Bone-Parameter: props.params hat Vorrang vor bonestructure.params
|
|
369
|
+
params: computed(() => {
|
|
370
|
+
if (props.params) {
|
|
371
|
+
return props.params
|
|
372
|
+
}
|
|
373
|
+
return state.bonestructure && Object.keys(state.bonestructure).includes("params")
|
|
374
|
+
? state.bonestructure["params"]
|
|
375
|
+
: {}
|
|
376
|
+
}),
|
|
377
|
+
// Die Actionbar-Komponente passend zum Bone-Typ (z.B. für File, Relational)
|
|
378
|
+
actionbar: computed(() => {
|
|
379
|
+
return getBoneActionbar(state.bonestructure?.["type"])
|
|
380
|
+
}),
|
|
381
|
+
// Ob der Bone-Wert leer ist (null, leeres Array, leeres Objekt). Im Readonly-Modus immer false
|
|
382
|
+
isEmpty: computed(() => {
|
|
383
|
+
// Ignore the computation when the state is readonly
|
|
384
|
+
if (state.readonly) return false
|
|
385
|
+
|
|
386
|
+
// Check for null or undefined values
|
|
387
|
+
if (!state.bonevalue) return true
|
|
388
|
+
|
|
389
|
+
// Check if the value is an array with elements
|
|
390
|
+
if (Array.isArray(state.bonevalue) && state.bonevalue.length === 0) return true
|
|
391
|
+
|
|
392
|
+
// Check if the value is an object and not an array, then use helper function to check if it's empty
|
|
393
|
+
if (state.bonevalue === Object(state.bonevalue) && !Array.isArray(state.bonevalue))
|
|
394
|
+
return isObjectEmpty(state.bonevalue)
|
|
395
|
+
|
|
396
|
+
return false
|
|
397
|
+
}),
|
|
398
|
+
// Fehlermeldungen aus props.errors, gefiltert auf diesen Bone (fieldPath + severity)
|
|
399
|
+
errorMessages: computed(() => {
|
|
400
|
+
let errors = []
|
|
401
|
+
for (let error of props.errors) {
|
|
402
|
+
if (
|
|
403
|
+
error["fieldPath"][0] === props.name &&
|
|
404
|
+
(error["fieldPath"].length === 1 ||
|
|
405
|
+
((state.multilanguage || state.multiple) && error["fieldPath"].length === 2) ||
|
|
406
|
+
(state.multilanguage && state.multiple && error["fieldPath"].length === 3)) &&
|
|
407
|
+
(error["severity"] > 2 || (state.required && (error["severity"] === 2 || error["severity"] === 0)))
|
|
408
|
+
) {
|
|
409
|
+
//severity level???
|
|
410
|
+
errors.push(error["errorMessage"])
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return errors
|
|
414
|
+
}),
|
|
415
|
+
label: computed(() => props.label), // Aktueller Label-Modus (gespiegelt von props.label)
|
|
416
|
+
// Ob der Bone-Tooltip angezeigt wird (bei hidden/placeholder-Label oder showBoneTooltip=true)
|
|
417
|
+
showtooltip: computed(() => {
|
|
418
|
+
if (props.showBoneTooltip) {
|
|
419
|
+
return true
|
|
420
|
+
}
|
|
421
|
+
if (["hide", "placeholder"].includes(props.label)) {
|
|
422
|
+
return true
|
|
423
|
+
}
|
|
424
|
+
return false
|
|
425
|
+
}),
|
|
426
|
+
defaultLanguage: computed(() => props.defaultLanguage), // Standardsprache (gespiegelt von props.defaultLanguage)
|
|
427
|
+
currentLanguage: null, // Aktuell aktiver Sprach-Tab
|
|
428
|
+
debug: computed(() => props.debug), // Debug-Modus (gespiegelt von props.debug)
|
|
429
|
+
labelTooltipTargetId: computed(() => buildBoneDomId(unref(bonePath) ?? [], "label-tooltip")), // Eindeutige DOM-ID für den Label-Tooltip-Anker
|
|
430
|
+
boneTooltipTargetId: computed(() => buildBoneDomId(unref(bonePath) ?? [], "field-tooltip")), // Eindeutige DOM-ID für den Bone-Tooltip-Anker
|
|
431
|
+
// Ob für diesen Bone überhaupt Actions auflösbar sind (für UI-Wrapper-Sichtbarkeit).
|
|
432
|
+
// MIT demselben Extra-Kontext und derselben Konfigurations-Merge-Reihenfolge
|
|
433
|
+
// wie BoneActions selbst — sonst fällt z.B. die Relations-Auswahl
|
|
434
|
+
// (when: relationSelector) hier raus und der Wrapper versteckt eine real
|
|
435
|
+
// vorhandene Action, oder eine per ViForm abgewählte bleibt "sichtbar".
|
|
436
|
+
resolvedActions: computed(() =>
|
|
437
|
+
resolveActions(
|
|
438
|
+
state.bonestructure,
|
|
439
|
+
[...formConfiguredActions(boneActionsConfig, props.name), ...(state.bonestructure?.params?.actions ?? [])],
|
|
440
|
+
state,
|
|
441
|
+
{ relationSelector }
|
|
442
|
+
)
|
|
443
|
+
),
|
|
444
|
+
hasActions: computed(() => state.resolvedActions.length > 0),
|
|
445
|
+
// Pflicht-Actions (Löschen, Download …) erscheinen auch ohne `boneactions`
|
|
446
|
+
hasRequiredActions: computed(() => state.resolvedActions.some((action) => action.required)),
|
|
447
|
+
hasOptionalActions: computed(() => state.resolvedActions.some((action) => !action.required)),
|
|
448
|
+
})
|
|
449
|
+
provide("boneState", state)
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Weist jedem Objekt im Array ein stabiles _key-Attribut (UUID) zu, falls noch keines vorhanden ist.
|
|
453
|
+
* Wird via watchEffect aufgerufen um stabile :key-Bindings für vue-draggable sicherzustellen.
|
|
454
|
+
* @param {Array<Object>} arr - Multiple-Array dessen Einträge Objekte sind
|
|
455
|
+
*/
|
|
456
|
+
function ensureKeys(arr) {
|
|
457
|
+
for (const it of arr) {
|
|
458
|
+
if (!it._key && typeof it === "object") {
|
|
459
|
+
it._key = crypto.randomUUID()
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
watchEffect(() => {
|
|
464
|
+
if (Array.isArray(state.bonevalue)) {
|
|
465
|
+
ensureKeys(state.bonevalue)
|
|
466
|
+
}
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Aktualisiert state.bonevalue anhand von lang/index-Kontext und feuert change-internal.
|
|
471
|
+
* Bei valid=false wird der Wert nicht gespeichert, das Event aber trotzdem gefeuert.
|
|
472
|
+
* Bei state.readonly wird kein Event gefeuert.
|
|
473
|
+
* @param {string} name - Bone-Name
|
|
474
|
+
* @param {unknown} val - Neuer Wert
|
|
475
|
+
* @param {string|null} lang - Sprach-Key (bei Multilang-Bones)
|
|
476
|
+
* @param {number|null} index - Index (bei Multiple-Bones)
|
|
477
|
+
* @param {boolean} valid - Ob der Wert valide ist
|
|
478
|
+
* @returns {false|void}
|
|
479
|
+
*/
|
|
480
|
+
function updateValue(name, val, lang = null, index = null, valid = true) {
|
|
481
|
+
if (val === undefined) return false
|
|
482
|
+
if (valid) {
|
|
483
|
+
if (lang) {
|
|
484
|
+
if (!state.bonevalue) {
|
|
485
|
+
state.bonevalue = {}
|
|
486
|
+
}
|
|
487
|
+
if (Object.keys(state.bonevalue).includes(lang) && index !== null) {
|
|
488
|
+
state.bonevalue[lang][index] = val
|
|
489
|
+
} else {
|
|
490
|
+
state.bonevalue[lang] = val
|
|
491
|
+
}
|
|
492
|
+
} else if (index !== null) {
|
|
493
|
+
state.bonevalue[index] = val
|
|
494
|
+
} else {
|
|
495
|
+
state.bonevalue = val
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (state.readonly) return false
|
|
500
|
+
|
|
501
|
+
let changeInternalObj = {
|
|
502
|
+
name: name,
|
|
503
|
+
value: val,
|
|
504
|
+
lang: lang,
|
|
505
|
+
index: index,
|
|
506
|
+
valid: valid,
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
emit("change-internal", changeInternalObj)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Fügt einen neuen Eintrag zum Multiple-Array hinzu.
|
|
514
|
+
* Wird via provide("addMultipleEntry") an Actionbars weitergegeben.
|
|
515
|
+
* @param {string|null} lang - Sprach-Key (bei Multilang-Bones)
|
|
516
|
+
* @param {unknown} data - Initialer Wert des neuen Eintrags
|
|
517
|
+
*/
|
|
518
|
+
function addMultipleEntry(lang = null, data = "") {
|
|
519
|
+
if (lang) {
|
|
520
|
+
if (Object.keys(state.bonevalue).includes(lang)) {
|
|
521
|
+
state.bonevalue[lang].push(data)
|
|
522
|
+
} else {
|
|
523
|
+
state.bonevalue[lang] = [data]
|
|
524
|
+
}
|
|
525
|
+
} else {
|
|
526
|
+
if (state.bonevalue) {
|
|
527
|
+
state.bonevalue.push(data)
|
|
528
|
+
} else {
|
|
529
|
+
state.bonevalue = [data]
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Feuert updateValue nach einer Multiple-Array-Mutation (splice).
|
|
536
|
+
* @param {string|null} lang - Sprach-Key oder null
|
|
537
|
+
*/
|
|
538
|
+
function emitMultipleUpdate(lang) {
|
|
539
|
+
if (lang) {
|
|
540
|
+
updateValue(props.name, state.bonevalue[lang], lang)
|
|
541
|
+
} else {
|
|
542
|
+
updateValue(props.name, state.bonevalue)
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Entfernt einen einzelnen Eintrag aus dem Multiple-Array per Index.
|
|
548
|
+
* @param {number} index - Index des zu entfernenden Eintrags
|
|
549
|
+
* @param {string|null} lang - Sprach-Key (bei Multilang-Bones)
|
|
550
|
+
*/
|
|
551
|
+
function removeMultipleEntry(index, lang = null) {
|
|
552
|
+
if (lang) {
|
|
553
|
+
state.bonevalue?.[lang].splice(index, 1)
|
|
554
|
+
} else {
|
|
555
|
+
state.bonevalue.splice(index, 1)
|
|
556
|
+
}
|
|
557
|
+
emitMultipleUpdate(lang)
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Entfernt alle Einträge aus dem Multiple-Array.
|
|
562
|
+
* Wird via provide("removeMultipleEntries") an Actionbars weitergegeben.
|
|
563
|
+
* @param {string|null} lang - Sprach-Key (bei Multilang-Bones)
|
|
564
|
+
*/
|
|
565
|
+
function removeMultipleEntries(lang = null) {
|
|
566
|
+
if (lang) {
|
|
567
|
+
state.bonevalue?.[lang].splice(0)
|
|
568
|
+
} else {
|
|
569
|
+
state.bonevalue.splice(0)
|
|
570
|
+
}
|
|
571
|
+
emitMultipleUpdate(lang)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Wechselt die aktive Sprache anhand des data-lang-Attributs des geklickten Tab-Elements.
|
|
576
|
+
* @param {Event} e - Click-Event vom wa-tab
|
|
577
|
+
*/
|
|
578
|
+
function updateLanguage(e) {
|
|
579
|
+
state.currentLanguage = e.target.dataset.lang
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Delegiert an Utils.formatString — wird via provide("formatString") für Relational-Bones bereitgestellt.
|
|
584
|
+
* @param {string} formatstr - Format-Template
|
|
585
|
+
* @param {unknown} boneValue - Bone-Wert der in das Template eingesetzt wird
|
|
586
|
+
* @returns {string}
|
|
587
|
+
*/
|
|
588
|
+
function formatString(formatstr, boneValue) {
|
|
589
|
+
return Utils.formatString(formatstr, boneValue)
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Übersetzt einen Fehler-Key via vue-i18n (errors.{key}). Fällt auf den rohen String zurück.
|
|
594
|
+
* @param {string} error - Fehler-Key oder roher Fehlertext
|
|
595
|
+
* @returns {string}
|
|
596
|
+
*/
|
|
597
|
+
function errorMessage(error) {
|
|
598
|
+
const key = `errors.${error}`
|
|
599
|
+
let temp = t(key)
|
|
600
|
+
if (temp === key) {
|
|
601
|
+
temp = t(error)
|
|
602
|
+
}
|
|
603
|
+
return temp
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
watch(
|
|
607
|
+
() => props.skel?.[props.name],
|
|
608
|
+
() => {
|
|
609
|
+
state.bonevalue = props.skel?.[props.name]
|
|
610
|
+
}
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
// Sprach-Tab wählen: die gewünschte Sprache — führt der Bone sie nicht,
|
|
614
|
+
// die erste seiner Sprachen (sonst wäre KEIN Tab aktiv).
|
|
615
|
+
function pickLanguage(wanted) {
|
|
616
|
+
if (!state.languages?.length || state.languages.includes(wanted)) return wanted
|
|
617
|
+
return state.languages[0]
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
watch(
|
|
621
|
+
() => state.defaultLanguage,
|
|
622
|
+
(newVal) => {
|
|
623
|
+
state.currentLanguage = pickLanguage(newVal)
|
|
624
|
+
}
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
onBeforeMount(() => {
|
|
628
|
+
if (props.value) {
|
|
629
|
+
state.bonevalue = props.value
|
|
630
|
+
} else {
|
|
631
|
+
state.bonevalue = props.skel?.[props.name]
|
|
632
|
+
}
|
|
633
|
+
state.currentLanguage = pickLanguage(state.defaultLanguage)
|
|
634
|
+
})
|
|
635
|
+
|
|
636
|
+
provide("updateValue", updateValue)
|
|
637
|
+
provide("addMultipleEntry", addMultipleEntry)
|
|
638
|
+
// Für die Pflicht-Action "removeEntry" (Zeilen-X der Multiple-Listen).
|
|
639
|
+
provide("removeMultipleEntry", removeMultipleEntry)
|
|
640
|
+
provide("removeMultipleEntries", removeMultipleEntries)
|
|
641
|
+
provide("formatString", formatString)
|
|
642
|
+
</script>
|
|
643
|
+
|
|
644
|
+
<style scoped>
|
|
645
|
+
@layer foundation.form {
|
|
646
|
+
/* Bone-Wrapper: Label links, Inhalt rechts (auf Mobile gestapelt) */
|
|
647
|
+
.bone {
|
|
648
|
+
display: grid;
|
|
649
|
+
grid-template-columns: 235px 1fr;
|
|
650
|
+
grid-gap: var(--wa-space-s);
|
|
651
|
+
margin-bottom: 20px;
|
|
652
|
+
|
|
653
|
+
/* Label über dem Inhalt oder gar keins: eine Spalte auf jeder Breite */
|
|
654
|
+
&.is-label-top,
|
|
655
|
+
&.is-label-hide {
|
|
656
|
+
grid-template-columns: 1fr;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
@media (max-width: 900px) {
|
|
660
|
+
grid-template-columns: 1fr;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
.bone-label-required {
|
|
664
|
+
color: var(--wa-color-brand-50);
|
|
665
|
+
font-weight: 700;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/* Fehler-Callout unter dem Bone-Inhalt */
|
|
669
|
+
wa-callout.bone-error {
|
|
670
|
+
padding: var(--wa-space-xs);
|
|
671
|
+
border: 1px solid var(--wa-color-border-loud);
|
|
672
|
+
border-radius: var(--wa-border-radius-m);
|
|
673
|
+
color: var(--wa-color-on-quiet);
|
|
674
|
+
|
|
675
|
+
& wa-icon {
|
|
676
|
+
margin-inline-end: var(--wa-space-2xs);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/* Sprachumschaltung: Tabs unter dem Eingabefeld (Multilang-Bones) */
|
|
681
|
+
.bone-lang-tabs {
|
|
682
|
+
width: 100%;
|
|
683
|
+
--track-width: 0;
|
|
684
|
+
|
|
685
|
+
&::part(body) {
|
|
686
|
+
overflow-x: hidden;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
& wa-tab-panel::part(base) {
|
|
690
|
+
padding: 0;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
& wa-tab {
|
|
694
|
+
&::part(base) {
|
|
695
|
+
padding: var(--wa-space-xs);
|
|
696
|
+
background-color: var(--wa-color-neutral-80);
|
|
697
|
+
border-radius: 0;
|
|
698
|
+
border-left: 1px solid var(--wa-color-border-loud);
|
|
699
|
+
border-bottom: 1px solid var(--wa-color-border-loud);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
&:hover::part(base) {
|
|
703
|
+
background-color: var(--wa-color-neutral-90);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
&[aria-selected="true"] {
|
|
707
|
+
&::part(base) {
|
|
708
|
+
border-bottom: 2px solid var(--wa-color-brand-50);
|
|
709
|
+
background-color: var(--wa-color-fill-quiet);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/* abgerundete Außenecken; Nachbar-Tabs überlappen sich um 1px */
|
|
714
|
+
&:first-child::part(base) {
|
|
715
|
+
margin-left: 1rem;
|
|
716
|
+
border-bottom-left-radius: 5px;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
&:nth-last-child(2)::part(base) {
|
|
720
|
+
border-bottom-right-radius: 5px;
|
|
721
|
+
border-right: 1px solid var(--wa-color-border-loud);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
&:not(:first-child)::part(base) {
|
|
725
|
+
margin-left: -1px;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
</style>
|
|
731
|
+
<style>
|
|
732
|
+
* {
|
|
733
|
+
box-sizing: border-box;
|
|
734
|
+
}
|
|
735
|
+
</style>
|
|
736
|
+
<!--
|
|
737
|
+
<style scoped>
|
|
738
|
+
@layer foundation.form {
|
|
739
|
+
.bone-wrapper {
|
|
740
|
+
display: grid;
|
|
741
|
+
grid-template-columns: 235px 1fr;
|
|
742
|
+
grid-gap: var(--wa-space-s);
|
|
743
|
+
margin-bottom: 20px;
|
|
744
|
+
|
|
745
|
+
&.bone-wrapper-record,
|
|
746
|
+
&.label-top,
|
|
747
|
+
&.has-subbones {
|
|
748
|
+
display: flex;
|
|
749
|
+
flex-direction: column;
|
|
750
|
+
grid-gap: 0;
|
|
751
|
+
|
|
752
|
+
& > :deep(.bone-name) {
|
|
753
|
+
border-bottom-left-radius: 0;
|
|
754
|
+
border-top-right-radius: var(--wa-border-radius-m);
|
|
755
|
+
min-width: 235px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
& > .bone-inner-wrap {
|
|
759
|
+
padding-top: var(--wa-space-s);
|
|
760
|
+
border-top: 2px solid var(--wa-color-neutral-80);
|
|
761
|
+
margin-bottom: 5px;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
& .multiple-bone {
|
|
765
|
+
border-bottom: 1px solid var(--wa-color-neutral-80);
|
|
766
|
+
padding-bottom: var(--wa-space-s);
|
|
767
|
+
margin-bottom: var(--wa-space-s);
|
|
768
|
+
|
|
769
|
+
&:deep(wa-details) {
|
|
770
|
+
&:last-child {
|
|
771
|
+
&::part(base) {
|
|
772
|
+
border-bottom: none;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
&.label-hide {
|
|
780
|
+
display: flex;
|
|
781
|
+
flex-direction: column;
|
|
782
|
+
grid-gap: 0;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
@media (max-width: 900px) {
|
|
786
|
+
grid-template-columns: 1fr;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
wa-tab-panel::part(base) {
|
|
791
|
+
padding: 0;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.lang-tab {
|
|
795
|
+
width: 100%;
|
|
796
|
+
--track-width: 0;
|
|
797
|
+
--indicator-color: var(--vi-background-color);
|
|
798
|
+
--track-color: var(--vi-border-color);
|
|
799
|
+
|
|
800
|
+
&::part(body) {
|
|
801
|
+
padding-bottom: var(--wa-space-xs);
|
|
802
|
+
overflow-x: hidden;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
&::part(tabs) {
|
|
806
|
+
border-top: 1px solid var(--vi-border-color);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
& wa-tab {
|
|
810
|
+
margin-top: -1px;
|
|
811
|
+
|
|
812
|
+
&[aria-selected="true"] {
|
|
813
|
+
z-index: 1;
|
|
814
|
+
|
|
815
|
+
&::part(base) {
|
|
816
|
+
background-color: var(--vi-background-color);
|
|
817
|
+
border: 1px solid var(--vi-border-color);
|
|
818
|
+
border-top: 1px solid var(--vi-background-color) !important;
|
|
819
|
+
border-bottom: 2px solid var(--wa-color-brand-50) !important;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
&::part(base) {
|
|
824
|
+
background-color: var(--wa-color-neutral-90);
|
|
825
|
+
border: 1px solid var(--wa-color-neutral-70);
|
|
826
|
+
border-top: 1px solid var(--vi-border-color);
|
|
827
|
+
border-radius: 0;
|
|
828
|
+
padding: var(--wa-space-xs);
|
|
829
|
+
transition: all ease 0.3s;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
&:hover {
|
|
833
|
+
&::part(base) {
|
|
834
|
+
background-color: var(--vi-background-color);
|
|
835
|
+
border: 1px solid var(--vi-border-color);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
&:first-child {
|
|
840
|
+
&::part(base) {
|
|
841
|
+
border-bottom-left-radius: 5px;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
&:nth-last-child(2) {
|
|
846
|
+
&::part(base) {
|
|
847
|
+
border-bottom-right-radius: 5px;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
&:not(:first-child) {
|
|
852
|
+
&::part(base) {
|
|
853
|
+
margin-left: -1px;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
.multiple-placeholder {
|
|
860
|
+
&:not(.readonly) {
|
|
861
|
+
margin-bottom: var(--wa-space-xs);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
& wa-input {
|
|
865
|
+
&::part(base) {
|
|
866
|
+
border-top-left-radius: 0;
|
|
867
|
+
border-bottom-left-radius: 0;
|
|
868
|
+
opacity: 0.7;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
@media (max-width: 900px) {
|
|
873
|
+
& wa-input {
|
|
874
|
+
&::part(base) {
|
|
875
|
+
border-top-right-radius: 0;
|
|
876
|
+
border-bottom-left-radius: var(--wa-border-radius-m);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.multiple-bone {
|
|
883
|
+
margin-bottom: var(--wa-space-xs);
|
|
884
|
+
|
|
885
|
+
&:first-child {
|
|
886
|
+
padding-top: var(--wa-space-xs);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
& .bone-wrapper {
|
|
890
|
+
margin-bottom: var(--wa-space-xs);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
&:first-child {
|
|
894
|
+
& :deep(.value-line) {
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.bone-inner-wrap {
|
|
900
|
+
min-width: 1px;
|
|
901
|
+
|
|
902
|
+
& wa-alert {
|
|
903
|
+
margin-top: var(--wa-space-xs);
|
|
904
|
+
background-color: transparent;
|
|
905
|
+
|
|
906
|
+
&::part(message) {
|
|
907
|
+
padding: var(--wa-space-xs) var(--wa-space-s);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
&::part(icon) {
|
|
911
|
+
padding-left: var(--wa-space-s);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.label-info {
|
|
917
|
+
&::part(base) {
|
|
918
|
+
align-items: center;
|
|
919
|
+
margin-left: 0.5em;
|
|
920
|
+
background-color: var(--wa-color-info-95);
|
|
921
|
+
border: none;
|
|
922
|
+
overflow: visible;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
&::part(message) {
|
|
926
|
+
padding: var(--wa-space-s);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
&::part(icon) {
|
|
930
|
+
display: flex;
|
|
931
|
+
align-items: center;
|
|
932
|
+
justify-content: center;
|
|
933
|
+
border-radius: 50%;
|
|
934
|
+
background-color: var(--wa-color-surface-default);
|
|
935
|
+
width: 1em;
|
|
936
|
+
height: 1em;
|
|
937
|
+
margin-left: -0.5em;
|
|
938
|
+
padding-left: 0;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
.tooltip {
|
|
943
|
+
display: flex;
|
|
944
|
+
align-items: center;
|
|
945
|
+
justify-content: center;
|
|
946
|
+
margin-left: auto;
|
|
947
|
+
padding-left: 0.4em;
|
|
948
|
+
|
|
949
|
+
& wa-icon {
|
|
950
|
+
background-color: var(--wa-color-info-50);
|
|
951
|
+
color: #fff;
|
|
952
|
+
padding: 0.4em;
|
|
953
|
+
border-radius: 50%;
|
|
954
|
+
font-size: 0.55em;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
wa-tooltip {
|
|
959
|
+
&::part(body) {
|
|
960
|
+
background-color: var(--wa-color-info-50);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
&::part(base__arrow) {
|
|
964
|
+
background-color: var(--wa-color-info-50);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.required {
|
|
969
|
+
color: var(--wa-color-brand-50);
|
|
970
|
+
font-weight: 700;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
:deep(wa-combobox) {
|
|
974
|
+
&::part(input__base) {
|
|
975
|
+
border: 1px solid var(--vi-border-color);
|
|
976
|
+
box-shadow: none !important;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
&::part(input__prefix) {
|
|
980
|
+
display: none !important;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
&::part(input__suffix) {
|
|
984
|
+
display: none !important;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
wa-tooltip.bone-tooltip {
|
|
989
|
+
&::part(body) {
|
|
990
|
+
background-color: var(--wa-color-brand-50);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
&::part(base__arrow) {
|
|
994
|
+
background-color: var(--wa-color-brand-50);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.error-msg::part(base) {
|
|
1000
|
+
background-color: #ffecec;
|
|
1001
|
+
color: var(--wa-color-danger-30);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
.wrapper-bone-row {
|
|
1005
|
+
display: flex;
|
|
1006
|
+
flex-direction: row;
|
|
1007
|
+
gap: var(--wa-space-xs);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
.wrapper-bone-block {
|
|
1011
|
+
display: block;
|
|
1012
|
+
width: 100%;
|
|
1013
|
+
}
|
|
1014
|
+
</style>
|
|
1015
|
+
|
|
1016
|
+
<style>
|
|
1017
|
+
wa-input[data-user-invalid]::part(base),
|
|
1018
|
+
wa-select[data-user-invalid]::part(combobox),
|
|
1019
|
+
wa-checkbox[data-user-invalid]::part(control) {
|
|
1020
|
+
border-color: var(--wa-color-danger-50);
|
|
1021
|
+
}
|
|
1022
|
+
</style>
|
|
1023
|
+
-->
|