viur-ui 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +67 -41
  2. package/index.d.ts +18 -9
  3. package/index.js +6 -3
  4. package/package.json +3 -5
  5. package/src/components/Browser/Browser.vue +58 -58
  6. package/src/components/Browser/TreeNav.vue +32 -32
  7. package/src/components/Browser/ViurBrowser.d.vue.ts +21 -21
  8. package/src/components/Browser/ViurBrowser.vue +47 -44
  9. package/src/components/Browser/dragSession.ts +27 -27
  10. package/src/components/Browser/index.ts +3 -3
  11. package/src/components/Browser/types.ts +9 -9
  12. package/src/components/DataTable/ColumnFilterPanel.vue +7 -7
  13. package/src/components/DataTable/DataTable.vue +346 -346
  14. package/src/components/DataTable/ViurDataTable.d.vue.ts +26 -26
  15. package/src/components/DataTable/ViurDataTable.vue +51 -50
  16. package/src/components/DataTable/columns.ts +30 -30
  17. package/src/components/DataTable/index.ts +12 -12
  18. package/src/components/DataTable/rows.ts +71 -72
  19. package/src/components/DataTable/types.ts +55 -55
  20. package/src/components/DataTable/useColumnLayout.ts +28 -28
  21. package/src/components/DataTable/useGridNavigation.ts +15 -15
  22. package/src/components/DataTable/useVirtualRows.ts +10 -10
  23. package/src/components/DataTable/viurColumns.ts +69 -69
  24. package/src/forms/ViForm.d.vue.ts +32 -32
  25. package/src/forms/ViForm.vue +17 -16
  26. package/src/forms/ViFormCategory.vue +3 -1
  27. package/src/forms/bones/Bone.vue +125 -108
  28. package/src/forms/bones/BoneActions.vue +21 -21
  29. package/src/forms/bones/BoneLabel.vue +1 -1
  30. package/src/forms/bones/BoneMultipleWrapper.vue +3 -3
  31. package/src/forms/bones/BoneNestedWrapper.vue +3 -3
  32. package/src/forms/bones/BoneSingleEntry.vue +2 -2
  33. package/src/forms/bones/FilterBone.vue +3 -3
  34. package/src/forms/bones/actions/ActionDialog.vue +2 -2
  35. package/src/forms/bones/actions/Debug.vue +6 -6
  36. package/src/forms/bones/actions/Delete.vue +2 -2
  37. package/src/forms/bones/actions/DescribeImage.vue +4 -3
  38. package/src/forms/bones/actions/Download.vue +4 -4
  39. package/src/forms/bones/actions/Placeholder.vue +2 -2
  40. package/src/forms/bones/actions/index.js +72 -74
  41. package/src/forms/bones/bone.d.ts +19 -19
  42. package/src/forms/bones/uploadAdapter.js +3 -3
  43. package/src/forms/bones/utils.js +40 -41
  44. package/src/forms/bones/view/base_item.vue +1 -1
  45. package/src/forms/bones/view/boneLogic.js +1 -1
  46. package/src/forms/bones/widgets/booleanBone.vue +19 -19
  47. package/src/forms/bones/widgets/booleanBoneChoose.vue +2 -2
  48. package/src/forms/bones/widgets/booleanBoneSelect.vue +3 -3
  49. package/src/forms/bones/widgets/codeBone.vue +22 -22
  50. package/src/forms/bones/widgets/colorBone.vue +18 -18
  51. package/src/forms/bones/widgets/dateBone.vue +22 -22
  52. package/src/forms/bones/widgets/emailBone.vue +20 -20
  53. package/src/forms/bones/widgets/fileBone.vue +32 -31
  54. package/src/forms/bones/widgets/keyBone.vue +21 -21
  55. package/src/forms/bones/widgets/numericBone.vue +21 -21
  56. package/src/forms/bones/widgets/passwordBone.vue +34 -31
  57. package/src/forms/bones/widgets/phoneBone.vue +20 -20
  58. package/src/forms/bones/widgets/rawBone.vue +19 -19
  59. package/src/forms/bones/widgets/recordBone.vue +16 -16
  60. package/src/forms/bones/widgets/relationalBone.vue +26 -26
  61. package/src/forms/bones/widgets/selectBone.vue +23 -23
  62. package/src/forms/bones/widgets/selectBoneChoose.vue +2 -2
  63. package/src/forms/bones/widgets/spatialBone.vue +21 -21
  64. package/src/forms/bones/widgets/stringBone.vue +27 -27
  65. package/src/forms/bones/widgets/textBone.vue +28 -26
  66. package/src/forms/install.d.ts +1 -1
  67. package/src/forms/install.js +7 -0
  68. package/src/forms/layouts/LayloutList2Columns.vue +1 -1
  69. package/src/forms/layouts/LayoutCategory.vue +1 -1
  70. package/src/forms/layouts/LayoutList.vue +1 -1
  71. package/src/forms/utils.js +22 -22
  72. package/src/request/configStore.js +4 -4
  73. package/src/request/envelope.js +6 -6
  74. package/src/request/request.js +22 -22
  75. package/src/translations/de.js +31 -0
  76. package/src/translations/en.js +31 -0
  77. package/src/user/LoginScreen.d.vue.ts +24 -24
  78. package/src/user/LoginScreen.vue +6 -7
  79. package/src/user/store.d.ts +16 -16
  80. package/src/vite/safeHtml.js +73 -0
  81. package/src/vite/sanitizeVHtml.d.ts +4 -0
  82. package/src/vite/sanitizeVHtml.js +15 -0
  83. package/src/webawesomeCompat.css +0 -40
@@ -37,7 +37,7 @@
37
37
 
38
38
  <script setup>
39
39
  import { reactive, inject, computed, unref } from "vue"
40
- import { buildBoneDomId } from "./utils"
40
+ import { buildBoneDomId } from "./utils.js"
41
41
  const props = defineProps({
42
42
  name: String,
43
43
  value: Object,
@@ -12,9 +12,9 @@
12
12
  <slot></slot>
13
13
  </div>
14
14
  <div class="wa-cluster wa-gap-xs">
15
- <!-- IMMER gerendert: Das Zeilen-X ist die Pflicht-Action "removeEntry"
16
- (actions/index.js) — BoneActions filtert ohne `boneactions` selbst
17
- auf die Pflicht-Actions herunter. -->
15
+ <!-- ALWAYS rendered: the row X is the required action "removeEntry"
16
+ (actions/index.js) — without `boneactions`, BoneActions itself filters
17
+ down to the required actions. -->
18
18
  <bone-actions
19
19
  :value="state.value"
20
20
  :name="name"
@@ -47,7 +47,7 @@ import {
47
47
  provide,
48
48
  unref,
49
49
  } from "vue"
50
- import { getBoneWidget } from "./index"
50
+ import { getBoneWidget } from "./index.js"
51
51
  import ViForm from "../ViForm.vue"
52
52
  import { useTimeoutFn } from "@vueuse/core"
53
53
 
@@ -64,8 +64,8 @@ const props = defineProps({
64
64
  const skelRef = ref(null)
65
65
  const boneState = inject("boneState")
66
66
  const mainformState = inject("mainformState")
67
- // Action-Konfiguration des umgebenden Formulars (ViForm `actions`) — das
68
- // Unterformular stellt sonst seine eigene (leere) bereit.
67
+ // Action configuration of the surrounding form (ViForm `actions`) — the
68
+ // subform would otherwise provide its own (empty) one.
69
69
  const parentActionsConfig = inject("boneActionsConfig", null)
70
70
  const parentBonePath = inject("bonePath", [])
71
71
  const bonePath = computed(() => {
@@ -13,8 +13,8 @@
13
13
  @keypress.enter="updateValue"
14
14
  ></component>
15
15
  </div>
16
- <!-- Pflicht-Actions (Löschen, Download …) auch ohne `boneactions`; am
17
- Wert DIESES Eintrags, bei Mehrsprachigkeit also seiner Sprache -->
16
+ <!-- Required actions (delete, download …) even without `boneactions`; on the
17
+ value of THIS entry, i.e. of its language when multilingual -->
18
18
  <div
19
19
  v-if="(boneactions && boneState?.hasActions) || boneState?.hasRequiredActions"
20
20
  class="wa-cluster wa-gap-xs"
@@ -100,7 +100,7 @@
100
100
  <wa-alert
101
101
  v-for="message in state.errorMessages"
102
102
  open
103
- summary="Errors"
103
+ :summary="$t('bone.errors_summary')"
104
104
  variant="danger"
105
105
  class="bone-error"
106
106
  >
@@ -141,9 +141,9 @@ import {
141
141
  } from "vue"
142
142
  import wrapperMultiple from "./BoneMultipleWrapper.vue"
143
143
  import BoneLabel from "./BoneLabel.vue"
144
- import { BoneHasMultipleHandling, getBoneActionbar } from "./index"
144
+ import { BoneHasMultipleHandling, getBoneActionbar } from "./index.js"
145
145
  import rawBone from "./rawBone.vue"
146
- import Utils, { buildBoneDomId } from "./utils"
146
+ import Utils, { buildBoneDomId } from "./utils.js"
147
147
  import { VueDraggable } from "vue-draggable-plus"
148
148
  import BoneActions from "./BoneActions.vue"
149
149
 
@@ -5,7 +5,7 @@
5
5
  >
6
6
  <wa-dialog
7
7
  open
8
- :label="action.name + (name ? ' - ' + name : '')"
8
+ :label="(action.name && $te(action.name) ? $t(action.name) : action.name) + (name ? ' - ' + name : '')"
9
9
  class="bone-action-dialog"
10
10
  @wa-after-hide="emit('close', null, null, action)"
11
11
  >
@@ -26,7 +26,7 @@
26
26
 
27
27
  <script setup>
28
28
  import { computed } from "vue"
29
- import { getActionComponent } from "./index"
29
+ import { getActionComponent } from "./index.js"
30
30
 
31
31
  const props = defineProps({
32
32
  open: Boolean,
@@ -1,21 +1,21 @@
1
1
  <template>
2
2
  <div class="debug-wrapper">
3
3
  <wa-details
4
- summary="Bone Structure"
4
+ :summary="t('actions.debug.structure')"
5
5
  open
6
6
  >
7
7
  <pre>{{ stringify(params.bone) }}</pre>
8
8
  </wa-details>
9
9
  <wa-details
10
- summary="Bone Value"
10
+ :summary="t('actions.debug.value')"
11
11
  open
12
12
  >
13
13
  <pre>{{ stringify(params.value) }}</pre>
14
14
  </wa-details>
15
- <wa-details summary="Bone State">
15
+ <wa-details :summary="t('actions.debug.state')">
16
16
  <pre>{{ stringify(params.boneState) }}</pre>
17
17
  </wa-details>
18
- <wa-details summary="Context">
18
+ <wa-details :summary="t('actions.debug.context')">
19
19
  <pre>{{ stringify({ name: params.name, lang: params.lang, index: params.index }) }}</pre>
20
20
  </wa-details>
21
21
  </div>
@@ -50,8 +50,8 @@ const props = defineProps({
50
50
  const emit = defineEmits(["close", "next"])
51
51
 
52
52
  /**
53
- * Stringifiziert ein Objekt für die Debug-Anzeige.
54
- * Überspringt interne Felder (`_*`) und behandelt Zyklen.
53
+ * Stringifies an object for the debug display.
54
+ * Skips internal fields (`_*`) and handles cycles.
55
55
  */
56
56
  function stringify(obj) {
57
57
  const seen = new WeakSet()
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  /**
3
- * Direct-fire Action: setzt den Bone-Wert auf einen leeren String zurück.
4
- * Wird von `BoneActions` bei `type: "callback"` direkt aufgerufen — kein Dialog.
3
+ * Direct-fire action: resets the bone value to an empty string.
4
+ * Called directly by `BoneActions` for `type: "callback"` — no dialog.
5
5
  *
6
6
  * @param {{ value: object, name: string, lang: string, index: number, bone: object, boneState: object, update: Function }} ctx
7
7
  */
@@ -2,10 +2,12 @@
2
2
  <div class="image-description-wrapper">
3
3
  <div class="image-description-grid">
4
4
  <div>
5
- <vi-image
5
+ <img
6
6
  :src="state.url"
7
+ alt=""
8
+ draggable="false"
7
9
  style="height: 50px"
8
- ></vi-image>
10
+ />
9
11
  </div>
10
12
 
11
13
  <div class="image-description-flex">
@@ -83,7 +85,6 @@
83
85
  import { useI18n } from "vue-i18n"
84
86
  import { reactive, onMounted, inject, computed } from "vue"
85
87
  import { createControllerFetch } from "../../../request/index.js"
86
- import viImage from "@viur/vue-utils/generic/Image.vue"
87
88
 
88
89
  const { t } = useI18n()
89
90
 
@@ -2,8 +2,8 @@
2
2
  import { downloadUrlFor } from "../../../request/index.js"
3
3
 
4
4
  /**
5
- * Direct-fire Action: lädt die im Bone-Value referenzierte Datei herunter.
6
- * Wird von `BoneActions` bei `type: "callback"` direkt aufgerufen — kein Dialog.
5
+ * Direct-fire action: downloads the file referenced in the bone value.
6
+ * Called directly by `BoneActions` for `type: "callback"` — no dialog.
7
7
  *
8
8
  * @param {{ value: object, name: string, lang: string, index: number, bone: object, boneState: object }} ctx
9
9
  */
@@ -11,8 +11,8 @@ export function handler(ctx) {
11
11
  const url = downloadUrlFor(ctx.value)
12
12
  if (!url) return
13
13
 
14
- // Anchor-Click statt window.open: funktioniert auch mit Data-URLs
15
- // (Browser blockt Top-Level-Navigation zu data:-URLs aus Phishing-Gründen).
14
+ // Anchor click instead of window.open: also works with data URLs
15
+ // (browsers block top-level navigation to data: URLs for phishing reasons).
16
16
  const a = document.createElement("a")
17
17
  a.href = url
18
18
  a.download = ctx.value?.dest?.name ?? ""
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  /**
3
- * Platzhalter-Action zum Testen der Anzeige mehrerer Buttons.
4
- * TODO: wieder entfernen sobald nicht mehr benötigt.
3
+ * Placeholder action for testing the display of multiple buttons.
4
+ * TODO: remove again once no longer needed.
5
5
  *
6
6
  * @param {{ value: object, name: string, lang: string, index: number, bone: object, boneState: object }} ctx
7
7
  */
@@ -2,105 +2,103 @@ import { defineAsyncComponent, unref } from "vue"
2
2
  import Translation from "./Translation.vue"
3
3
  import Debug from "./Debug.vue"
4
4
 
5
- // Lazy: DescribeImage zieht `@viur/vue-utils` (Legacy-Paket) nach. Eager
6
- // importiert bricht damit der ganze Formular-Baum in Anwendungen, die dieses
7
- // Paket nicht haben — obwohl sie die Action gar nicht benutzen. So wird es erst
8
- // beim tatsächlichen Öffnen des Dialogs geladen (wie die schweren Bones).
5
+ // Lazy: DescribeImage is only loaded when the dialog is actually opened
6
+ // (like the heavy bones).
9
7
  const DescribeImage = defineAsyncComponent(() => import("./DescribeImage.vue"))
10
8
  import { handler as downloadHandler } from "./Download.vue"
11
9
  import { handler as placeholderHandler } from "./Placeholder.vue"
12
10
  import { handler as deleteHandler } from "./Delete.vue"
13
11
 
14
12
  /**
15
- * Default-Definitionen: identisches Inline-Format wie früher in BoneActions.
16
- * Strings in `bone.params.actions` werden hier nachgeschlagen.
17
- * Custom-Objekte aus `bone.params.actions` werden in gleicher Form durchgereicht.
13
+ * Default definitions: same inline format as formerly in BoneActions.
14
+ * Strings in `bone.params.actions` are looked up here.
15
+ * Custom objects from `bone.params.actions` are passed through in the same form.
18
16
  */
19
17
  const defaultActions = {
20
18
  translate: {
21
19
  type: "assistant",
22
20
  arg: "translate",
23
- name: "Übersetzen",
21
+ name: "actions.translate.name",
24
22
  icon: "translate",
25
23
  library: "default",
26
- title: "Übersetzen",
24
+ title: "actions.translate.name",
27
25
  },
28
26
  describe_image: {
29
27
  type: "assistant",
30
28
  arg: "describe_image",
31
- name: "Bildbeschreibung erstellen",
29
+ name: "actions.describeImage.name",
32
30
  icon: "file-richtext",
33
31
  library: "default",
34
- title: "Bild beschreiben",
32
+ title: "actions.describeImage.title",
35
33
  },
36
34
  download: {
37
35
  type: "callback",
38
36
  arg: "download",
39
- name: "Download",
37
+ name: "bone.download",
40
38
  icon: "download",
41
39
  library: "default",
42
40
  title: "bone.download",
43
- // Gerüst wie das Zeilen-X: auch ohne `boneactions` da (früher ein Knopf im
44
- // Datei-Widget) — und nur lesend, also auch bei readonly-Bones.
41
+ // Scaffolding like the row X: present even without `boneactions` (formerly a button in the
42
+ // file widget) — and read-only, so also on readonly bones.
45
43
  required: true,
46
44
  allowReadonly: true,
47
45
  },
48
46
  debug: {
49
47
  type: "assistant",
50
48
  arg: "debug",
51
- name: "Debug",
49
+ name: "actions.debug.name",
52
50
  icon: "bug",
53
51
  library: "default",
54
- title: "Bone Debug-Informationen anzeigen",
52
+ title: "actions.debug.title",
55
53
  },
56
54
  placeholder: {
57
55
  type: "callback",
58
56
  arg: "placeholder",
59
- name: "Placeholder",
57
+ name: "actions.placeholder.name",
60
58
  icon: "wrench",
61
59
  library: "default",
62
- title: "Platzhalter (TODO: entfernen)",
60
+ title: "actions.placeholder.title",
63
61
  },
64
62
  delete: {
65
63
  type: "callback",
66
64
  arg: "delete",
67
- name: "Löschen",
65
+ name: "actions.delete.name",
68
66
  icon: "xmark",
69
67
  library: "default",
70
68
  title: "bone.del",
71
69
  position: "end",
72
70
  variant: "danger",
73
- // Gerüst: ohne sie wird man eine gesetzte Relation/Datei nicht wieder los
74
- // (früher ein Knopf im Widget) — daher auch ohne `boneactions` da.
71
+ // Scaffolding: without it you can't get rid of a set relation/file
72
+ // (formerly a button in the widget) — hence present even without `boneactions`.
75
73
  required: true,
76
- // Nur bei relationalen Single-Bones sichtbar (nicht multiple).
74
+ // Only visible on relational single bones (not multiple).
77
75
  when: (ctx) => prefixMatches("relational", ctx?.bone?.type) && !ctx?.bone?.multiple,
78
76
  },
79
77
  removeEntry: {
80
78
  type: "callback",
81
79
  arg: "removeEntry",
82
- name: "Entfernen",
80
+ name: "bone.del",
83
81
  icon: "xmark",
84
82
  library: "default",
85
83
  title: "bone.del",
86
84
  position: "end",
87
85
  variant: "danger",
88
- // PFLICHT-Action (Gerüst): entfernt DIESE Zeile eines multiple-Bones —
89
- // ohne sie würde man einen Eintrag nie wieder los. Nur in Zeilen-Kontexten
90
- // (BoneActions mit index) sichtbar.
86
+ // REQUIRED action (scaffolding): removes THIS row of a multiple bone —
87
+ // without it you could never get rid of an entry. Only visible in row contexts
88
+ // (BoneActions with index).
91
89
  required: true,
92
90
  when: (ctx) => ctx?.multipleRow === true,
93
91
  },
94
92
  }
95
93
 
96
- /** Dialog-Inhalt für `type: "assistant"` Actions, gemappt per `arg`. */
94
+ /** Dialog content for `type: "assistant"` actions, mapped by `arg`. */
97
95
  const componentRegistry = {
98
96
  translate: Translation,
99
97
  describe_image: DescribeImage,
100
98
  debug: Debug,
101
99
  }
102
100
 
103
- /** Direkt aufgerufene Handler für `type: "callback"` Actions, gemappt per `arg`. */
101
+ /** Directly invoked handlers for `type: "callback"` actions, mapped by `arg`. */
104
102
  const handlerRegistry = {
105
103
  download: downloadHandler,
106
104
  placeholder: placeholderHandler,
@@ -108,32 +106,32 @@ const handlerRegistry = {
108
106
  removeEntry: (ctx) => ctx.removeEntry?.(),
109
107
  }
110
108
 
111
- /** Kein Wert zum Bearbeiten: leer, oder ein Objekt/Array ohne Inhalt (nur
112
- * null/undefined/leere Listen — wie `isObjectEmpty` im Bone). */
109
+ /** No value to act on: empty, or an object/array without content (only
110
+ * null/undefined/empty lists — like `isObjectEmpty` in the bone). */
113
111
  function isEmptyValue(value) {
114
112
  if (!value) return true
115
113
  if (typeof value !== "object") return false
116
114
  return Object.values(value).every((entry) => entry == null || (Array.isArray(entry) && entry.length === 0))
117
115
  }
118
116
 
119
- /** Disabled-Check per `arg`. Erhält den Action-Kontext (name, value, index, lang, bone, boneState). */
117
+ /** Disabled check by `arg`. Receives the action context (name, value, index, lang, bone, boneState). */
120
118
  const disabledRegistry = {
121
119
  translate: (ctx) => !ctx.bone?.languages,
122
120
  describe_image: (ctx) => !ctx.value?.dest?.key,
123
121
  download: (ctx) => !ctx.value?.dest?.downloadUrl,
124
- // am EIGENEN Wert — bei Mehrsprachigkeit der einer Sprache, nicht des Bones
122
+ // on its OWN value — when multilingual that of one language, not of the bone
125
123
  delete: (ctx) => isEmptyValue(ctx.value),
126
124
  }
127
125
 
128
126
  /**
129
- * Default-Actions pro Bone-Type-Prefix. Beim Auflösen werden ALLE matchenden
130
- * Prefixes zusammengeführt (kürzester zuerst, dedupliziert).
127
+ * Default actions per bone type prefix. When resolving, ALL matching
128
+ * prefixes are merged (shortest first, deduplicated).
131
129
  *
132
- * Matching-Regel: Prefix matcht, wenn `boneType === prefix` (exakt) ODER
133
- * `boneType.startsWith(prefix + ".")` (Subtype). Der leere Prefix `""` matcht alles.
130
+ * Matching rule: a prefix matches if `boneType === prefix` (exact) OR
131
+ * `boneType.startsWith(prefix + ".")` (subtype). The empty prefix `""` matches everything.
134
132
  *
135
- * Definitionen mit `required: true` (delete, download) erscheinen auch ohne
136
- * `boneactions`; ein Host kann sie hier trotzdem abwählen (wie per `"-name"`).
133
+ * Definitions with `required: true` (delete, download) appear even without
134
+ * `boneactions`; a host can still deselect them here (as with `"-name"`).
137
135
  */
138
136
  const defaultActionsByType = {
139
137
  "": ["debug", "placeholder"],
@@ -142,11 +140,11 @@ const defaultActionsByType = {
142
140
  }
143
141
 
144
142
  /**
145
- * PFLICHT-Actions pro Bone-Type-Prefix (Gerüst-Funktionen). Anders als die
146
- * Defaults überleben sie sowohl eine `bone.params.actions`-Liste des Servers
147
- * als auch `setDefaultActionsForType` des Hosts — nur ihr eigenes
148
- * `when`-Prädikat (funktionale Verfügbarkeit) blendet sie aus. Sie werden
149
- * außerdem auch OHNE `boneactions` gerendert (BoneActions filtert darauf).
143
+ * REQUIRED actions per bone type prefix (scaffolding functions). Unlike the
144
+ * defaults, they survive both a `bone.params.actions` list from the server
145
+ * and the host's `setDefaultActionsForType` — only their own
146
+ * `when` predicate (functional availability) hides them. They are
147
+ * also rendered WITHOUT `boneactions` (BoneActions filters for them).
150
148
  */
151
149
  const requiredActionsByType = {
152
150
  "": ["removeEntry"],
@@ -159,7 +157,7 @@ function prefixMatches(prefix, boneType) {
159
157
  }
160
158
 
161
159
  /**
162
- * Erweitert die Registry. Jedes Feld ist optional.
160
+ * Extends the registry. Every field is optional.
163
161
  * @param {string} name
164
162
  * @param {{ default?: object, component?: object, handler?: Function, disabled?: Function }} opts
165
163
  */
@@ -170,21 +168,21 @@ export function addAction(name, opts) {
170
168
  if (opts.disabled) disabledRegistry[name] = opts.disabled
171
169
  }
172
170
 
173
- /** Setzt die Standard-Actions für einen Bone-Type-Prefix. */
171
+ /** Sets the default actions for a bone type prefix. */
174
172
  export function setDefaultActionsForType(typePrefix, actionNames) {
175
173
  defaultActionsByType[typePrefix] = actionNames
176
174
  }
177
175
 
178
- /** Setzt die PFLICHT-Actions für einen Bone-Type-Prefix (Host-Kuratierung). */
176
+ /** Sets the REQUIRED actions for a bone type prefix (host curation). */
179
177
  export function setRequiredActionsForType(typePrefix, actionNames) {
180
178
  requiredActionsByType[typePrefix] = actionNames
181
179
  }
182
180
 
183
181
  /**
184
- * Formular-weite Action-Konfiguration (ViForm `actions`-Prop, via
185
- * provide("boneActionsConfig") — ggf. eine Ref) für EINEN Bone auflösen:
186
- * Array gilt für alle Bones, Objekt pro Bone-Name mit `"*"` für alle.
187
- * Die Einträge haben dieselbe Form wie `bone.params.actions` (inkl. `"-name"`).
182
+ * Resolve the form-wide action configuration (ViForm `actions` prop, via
183
+ * provide("boneActionsConfig") — possibly a ref) for ONE bone:
184
+ * an array applies to all bones, an object per bone name with `"*"` for all.
185
+ * The entries have the same form as `bone.params.actions` (incl. `"-name"`).
188
186
  */
189
187
  export function formConfiguredActions(config, boneName) {
190
188
  const value = unref(config)
@@ -202,16 +200,16 @@ export function getActionHandler(arg) {
202
200
  }
203
201
 
204
202
  export function isActionDisabled(action, ctx) {
205
- // Im Readonly-Modus sind grundsätzlich alle Actions deaktiviert — bis auf
206
- // rein lesende (`allowReadonly`, z.B. Download).
203
+ // In readonly mode all actions are disabled in principle — except for
204
+ // purely read-only ones (`allowReadonly`, e.g. download).
207
205
  if (ctx?.boneState?.readonly && !action?.allowReadonly) return true
208
206
  const fn = disabledRegistry[action?.arg]
209
207
  return fn ? !!fn(ctx) : false
210
208
  }
211
209
 
212
210
  /**
213
- * Sammelt alle Action-Namen einer Prefix-Map für einen Bone-Type über
214
- * matchende Prefixes (kürzester zuerst, dedupliziert).
211
+ * Collects all action names of a prefix map for a bone type across
212
+ * matching prefixes (shortest first, deduplicated).
215
213
  *
216
214
  * @param {Record<string, string[]>} map
217
215
  * @param {string} boneType
@@ -230,40 +228,40 @@ function collectFromMap(map, boneType) {
230
228
  return names
231
229
  }
232
230
 
233
- /** Liefert den `arg`-Identifier eines Eintrags (String oder Inline-Definition). */
231
+ /** Returns the `arg` identifier of an entry (string or inline definition). */
234
232
  function entryArg(entry) {
235
233
  return typeof entry === "string" ? entry : entry?.arg
236
234
  }
237
235
 
238
236
  /**
239
- * Löst die Action-Liste für einen Bone auf.
240
- * - Type-Defaults aus `defaultActionsByType` werden **immer** angewendet
241
- * (matchende Prefixes vereint, kürzester zuerst).
242
- * - PFLICHT-Actions aus `requiredActionsByType` kommen zusätzlich IMMER dazu.
243
- * - `configured` (typisch `bone.params.actions`) wird vorangestellt und die
244
- * Defaults werden dedupliziert dazugemerged. So bleibt z.B. die `delete`-
245
- * Action für relationale Bones immer verfügbar, auch wenn das Backend eine
246
- * `params.actions`-Liste schickt.
247
- * - EXPLIZITE ABWAHL: ein String-Eintrag `"-name"` in `configured` entfernt
248
- * die Action `name` — auch eine Default- oder Pflicht-Action (die bewusste
249
- * Abwahl am Bone schlägt die Pflicht; nur sie).
250
- * - Strings werden via Default-Lookup aufgelöst, Inline-Objekte durchgereicht.
251
- * - Actions mit `when(ctx)` werden ausgefiltert, wenn das Prädikat falsy liefert.
237
+ * Resolves the action list for a bone.
238
+ * - Type defaults from `defaultActionsByType` are **always** applied
239
+ * (matching prefixes combined, shortest first).
240
+ * - REQUIRED actions from `requiredActionsByType` are ALWAYS added on top.
241
+ * - `configured` (typically `bone.params.actions`) is prepended and the
242
+ * defaults are merged in deduplicated. This way e.g. the `delete`
243
+ * action always stays available for relational bones, even if the backend sends a
244
+ * `params.actions` list.
245
+ * - EXPLICIT DESELECTION: a string entry `"-name"` in `configured` removes
246
+ * the action `name` — even a default or required action (the deliberate
247
+ * deselection on the bone overrides the requirement; only it does).
248
+ * - Strings are resolved via default lookup, inline objects are passed through.
249
+ * - Actions with `when(ctx)` are filtered out if the predicate returns falsy.
252
250
  *
253
- * Jede zurückgegebene Action ist eine flache Kopie, damit `_opened`-Mutationen
254
- * den Source nicht verändern. Sortiert: Actions mit `position: "end"` ans Ende.
251
+ * Every returned action is a shallow copy so that `_opened` mutations
252
+ * don't change the source. Sorted: actions with `position: "end"` go last.
255
253
  *
256
- * @param {object} bone - vollständige Bone-Definition (mit type, multiple, params)
254
+ * @param {object} bone - complete bone definition (with type, multiple, params)
257
255
  * @param {Array<string|object>|undefined} configured
258
- * @param {object} [boneState] - reactive Bone-State (für when/disabled-Predicates)
259
- * @param {object} [extras] - zusätzlicher Kontext für `when` (z.B. injizierte Hosts wie `relationSelector`)
256
+ * @param {object} [boneState] - reactive bone state (for when/disabled predicates)
257
+ * @param {object} [extras] - additional context for `when` (e.g. injected hosts like `relationSelector`)
260
258
  * @returns {object[]}
261
259
  */
262
260
  export function resolveActions(bone, configured, boneState, extras = {}) {
263
261
  const defaults = collectFromMap(defaultActionsByType, bone?.type)
264
262
  const required = collectFromMap(requiredActionsByType, bone?.type)
265
263
  const entries = Array.isArray(configured) ? [...configured] : []
266
- // Explizite Abwahl: "-name"-Einträge sammeln und aus der Liste nehmen.
264
+ // Explicit deselection: collect "-name" entries and remove them from the list.
267
265
  const disabled = new Set(entries.filter((e) => typeof e === "string" && e.startsWith("-")).map((e) => e.slice(1)))
268
266
  const names = entries.filter((e) => !(typeof e === "string" && e.startsWith("-")))
269
267
  for (const d of [...defaults, ...required]) {
@@ -1,43 +1,43 @@
1
1
  import type { DefineComponent } from "vue"
2
2
 
3
3
  export interface BoneProps {
4
- /** Das Bone-Widget-Component-Objekt (z.B. StringBone). Typischerweise von ViForm gesetzt. */
4
+ /** The bone widget component object (e.g. StringBone). Typically set by ViForm. */
5
5
  is?: object
6
- /** Bone-Identifier; muss einem Key in structure und skel entsprechen. */
6
+ /** Bone identifier; must match a key in structure and skel. */
7
7
  name: string
8
- /** Explizite Sprach-Liste; überschreibt bonestructure.languages. */
8
+ /** Explicit language list; overrides bonestructure.languages. */
9
9
  languages?: unknown[]
10
- /** Expliziter Multiple-Flag; überschreibt bonestructure.multiple. */
10
+ /** Explicit multiple flag; overrides bonestructure.multiple. */
11
11
  multiple?: boolean
12
- /** Expliziter Readonly-Flag; überschreibt bonestructure.readonly. */
12
+ /** Explicit readonly flag; overrides bonestructure.readonly. */
13
13
  readonly?: boolean
14
- /** Expliziter Required-Flag; überschreibt bonestructure.required. */
14
+ /** Explicit required flag; overrides bonestructure.required. */
15
15
  required?: boolean
16
- /** Zusätzliche Parameter; überschreibt bonestructure.params. */
16
+ /** Additional parameters; overrides bonestructure.params. */
17
17
  params?: Record<string, unknown>
18
- /** Expliziter Wert; überschreibt skel[name] wenn gesetzt. */
18
+ /** Explicit value; overrides skel[name] if set. */
19
19
  value?: object | string | number | boolean | unknown[]
20
- /** Vollständige Skeleton-Struktur (alle Bone-Definitionen des Formulars). */
20
+ /** Complete skeleton structure (all bone definitions of the form). */
21
21
  structure: Record<string, unknown>
22
- /** Skeleton-Datenobjekt mit den aktuellen Werten. */
22
+ /** Skeleton data object with the current values. */
23
23
  skel: unknown
24
- /** Fehler-Array aus der Server-Antwort. Einträge mit passendem fieldPath werden angezeigt. */
24
+ /** Error array from the server response. Entries with a matching fieldPath are displayed. */
25
25
  errors?: unknown[]
26
- /** Label-Modus. */
26
+ /** Label mode. */
27
27
  label?: "normal" | "top" | "hide" | "placeholder"
28
- /** Aktiviert BoneActions-Schaltflächen neben dem Input. */
28
+ /** Enables BoneActions buttons next to the input. */
29
29
  boneactions?: boolean
30
- /** Zeigt Tooltip-Inhalt als wa-alert statt als Tooltip. */
30
+ /** Shows tooltip content as wa-alert instead of a tooltip. */
31
31
  showLabelInfo?: boolean
32
- /** Gibt autofocus an das Bone-Widget weiter. */
32
+ /** Passes autofocus on to the bone widget. */
33
33
  autofocus?: boolean
34
- /** Standardmäßig aktive Sprache im Multilang-Tab. */
34
+ /** Language active by default in the multilang tab. */
35
35
  defaultLanguage?: string
36
- /** Erzwingt den Tooltip auf dem Input-Bereich unabhängig vom Label-Modus. */
36
+ /** Forces the tooltip on the input area regardless of the label mode. */
37
37
  showBoneTooltip?: boolean
38
- /** Fehler-Darstellungsstil. */
38
+ /** Error display style. */
39
39
  errorStyle?: "default" | "decent"
40
- /** Aktiviert Debug-Modus: Bone-Name als Tooltip am Label. */
40
+ /** Enables debug mode: bone name as tooltip on the label. */
41
41
  debug?: boolean
42
42
  }
43
43
 
@@ -18,9 +18,9 @@ class ViURUploadAdapter {
18
18
  this.loader.uploaded = 75
19
19
  this.loader.uploaded = 100
20
20
  resolve({
21
- // Die URL landet im HTML des Text-Bones: als /file/download/…
22
- // (nur absolut gemacht) — die erkennt viur-core wieder
23
- // (Blob-Referenz, srcset) und sie liegt nicht hinter /vi.
21
+ // The URL ends up in the text bone's HTML: as /file/download/…
22
+ // (only made absolute) — viur-core recognizes those again
23
+ // (blob reference, srcset) and it doesn't sit behind /vi.
24
24
  default: downloadUrlFor(uploadedData["downloadUrl"]),
25
25
  })
26
26
  })