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.
Files changed (114) hide show
  1. package/README.md +79 -0
  2. package/index.d.ts +351 -0
  3. package/index.js +46 -0
  4. package/package.json +84 -0
  5. package/src/components/Browser/Browser.vue +496 -0
  6. package/src/components/Browser/TreeNav.vue +408 -0
  7. package/src/components/Browser/ViurBrowser.d.vue.ts +64 -0
  8. package/src/components/Browser/ViurBrowser.vue +271 -0
  9. package/src/components/Browser/dragSession.ts +134 -0
  10. package/src/components/Browser/index.ts +14 -0
  11. package/src/components/Browser/types.ts +30 -0
  12. package/src/components/DataTable/ColumnFilterPanel.vue +225 -0
  13. package/src/components/DataTable/DataTable.vue +3155 -0
  14. package/src/components/DataTable/ViurDataTable.d.vue.ts +72 -0
  15. package/src/components/DataTable/ViurDataTable.vue +331 -0
  16. package/src/components/DataTable/columns.ts +400 -0
  17. package/src/components/DataTable/index.ts +60 -0
  18. package/src/components/DataTable/rows.ts +446 -0
  19. package/src/components/DataTable/types.ts +267 -0
  20. package/src/components/DataTable/useColumnLayout.ts +294 -0
  21. package/src/components/DataTable/useGridNavigation.ts +193 -0
  22. package/src/components/DataTable/useVirtualRows.ts +126 -0
  23. package/src/components/DataTable/viurColumns.ts +330 -0
  24. package/src/forms/ViForm.d.vue.ts +106 -0
  25. package/src/forms/ViForm.vue +592 -0
  26. package/src/forms/ViFormCategory.vue +57 -0
  27. package/src/forms/bones/Bone.vue +1023 -0
  28. package/src/forms/bones/BoneActions.vue +127 -0
  29. package/src/forms/bones/BoneLabel.vue +122 -0
  30. package/src/forms/bones/BoneMultipleList.vue +91 -0
  31. package/src/forms/bones/BoneMultipleWrapper.vue +105 -0
  32. package/src/forms/bones/BoneNestedWrapper.vue +155 -0
  33. package/src/forms/bones/BoneSingleEntry.vue +51 -0
  34. package/src/forms/bones/FilterBone.vue +694 -0
  35. package/src/forms/bones/actionbar/defaultBar.vue +98 -0
  36. package/src/forms/bones/actionbar/fileBar.vue +165 -0
  37. package/src/forms/bones/actionbar/relationalBar.vue +125 -0
  38. package/src/forms/bones/actions/ActionDialog.vue +70 -0
  39. package/src/forms/bones/actions/Debug.vue +106 -0
  40. package/src/forms/bones/actions/Delete.vue +13 -0
  41. package/src/forms/bones/actions/DescribeImage.vue +201 -0
  42. package/src/forms/bones/actions/Download.vue +27 -0
  43. package/src/forms/bones/actions/Placeholder.vue +14 -0
  44. package/src/forms/bones/actions/Translation.vue +238 -0
  45. package/src/forms/bones/actions/index.js +280 -0
  46. package/src/forms/bones/bone.d.ts +45 -0
  47. package/src/forms/bones/country_information.json +779 -0
  48. package/src/forms/bones/index.js +225 -0
  49. package/src/forms/bones/uploadAdapter.js +46 -0
  50. package/src/forms/bones/utils.js +284 -0
  51. package/src/forms/bones/view/base_item.vue +35 -0
  52. package/src/forms/bones/view/boneLogic.js +202 -0
  53. package/src/forms/bones/view/index.js +5 -0
  54. package/src/forms/bones/widgets/booleanBone.vue +83 -0
  55. package/src/forms/bones/widgets/booleanBoneChoose.vue +57 -0
  56. package/src/forms/bones/widgets/booleanBoneSelect.vue +58 -0
  57. package/src/forms/bones/widgets/codeBone.vue +214 -0
  58. package/src/forms/bones/widgets/colorBone.vue +75 -0
  59. package/src/forms/bones/widgets/dateBone.vue +114 -0
  60. package/src/forms/bones/widgets/emailBone.vue +100 -0
  61. package/src/forms/bones/widgets/fileBone.vue +273 -0
  62. package/src/forms/bones/widgets/jsonBone.vue +63 -0
  63. package/src/forms/bones/widgets/keyBone.vue +71 -0
  64. package/src/forms/bones/widgets/numericBone.vue +125 -0
  65. package/src/forms/bones/widgets/passwordBone.vue +215 -0
  66. package/src/forms/bones/widgets/phoneBone.vue +173 -0
  67. package/src/forms/bones/widgets/rawBone.vue +94 -0
  68. package/src/forms/bones/widgets/recordBone.vue +64 -0
  69. package/src/forms/bones/widgets/relationalBone.vue +164 -0
  70. package/src/forms/bones/widgets/relationalBoneSelect.vue +120 -0
  71. package/src/forms/bones/widgets/selectBone.vue +122 -0
  72. package/src/forms/bones/widgets/selectBoneChoose.vue +104 -0
  73. package/src/forms/bones/widgets/spatialBone.vue +111 -0
  74. package/src/forms/bones/widgets/stringBone.vue +139 -0
  75. package/src/forms/bones/widgets/textBone.vue +641 -0
  76. package/src/forms/install.d.ts +4 -0
  77. package/src/forms/install.js +43 -0
  78. package/src/forms/layouts/LayloutList2Columns.vue +57 -0
  79. package/src/forms/layouts/LayoutCategory.vue +38 -0
  80. package/src/forms/layouts/LayoutList.vue +31 -0
  81. package/src/forms/utils.js +601 -0
  82. package/src/public/assets/icons/fontawesome-manifest.json +8 -0
  83. package/src/public/assets/icons/regular/file.svg +1 -0
  84. package/src/public/assets/icons/solid/arrows-left-right.svg +1 -0
  85. package/src/public/assets/icons/solid/bug.svg +1 -0
  86. package/src/public/assets/icons/solid/check.svg +1 -0
  87. package/src/public/assets/icons/solid/circle-info.svg +1 -0
  88. package/src/public/assets/icons/solid/compress.svg +1 -0
  89. package/src/public/assets/icons/solid/download.svg +1 -0
  90. package/src/public/assets/icons/solid/expand.svg +1 -0
  91. package/src/public/assets/icons/solid/grip-vertical.svg +1 -0
  92. package/src/public/assets/icons/solid/plus.svg +1 -0
  93. package/src/public/assets/icons/solid/question.svg +1 -0
  94. package/src/public/assets/icons/solid/triangle-exclamation.svg +1 -0
  95. package/src/public/assets/icons/solid/upload.svg +1 -0
  96. package/src/public/assets/icons/solid/xmark.svg +1 -0
  97. package/src/request/cache.js +183 -0
  98. package/src/request/configStore.js +516 -0
  99. package/src/request/envelope.js +211 -0
  100. package/src/request/index.js +35 -0
  101. package/src/request/messageStore.js +201 -0
  102. package/src/request/request.js +752 -0
  103. package/src/request/skel.js +90 -0
  104. package/src/theme/colorStore.js +168 -0
  105. package/src/translations/de.js +178 -0
  106. package/src/translations/en.js +177 -0
  107. package/src/user/LoginScreen.d.vue.ts +54 -0
  108. package/src/user/LoginScreen.vue +627 -0
  109. package/src/user/google.js +75 -0
  110. package/src/user/index.js +3 -0
  111. package/src/user/store.d.ts +59 -0
  112. package/src/user/store.js +183 -0
  113. package/src/webawesomeCompat.css +72 -0
  114. package/src/webawesomeConfig.js +61 -0
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <div class="actionbar">
3
+ <wa-button
4
+ v-if="boneState.multiple && !readonly"
5
+ variant="danger"
6
+ :title="$t('bone.delAll')"
7
+ appearance="outlined"
8
+ class="delete-btn"
9
+ @click="handleRemove(lang)"
10
+ >
11
+ {{ $t("bone.delAll") }}
12
+ </wa-button>
13
+
14
+ <wa-button
15
+ v-if="boneState.multiple && !readonly"
16
+ variant="success"
17
+ :title="$t('bone.add')"
18
+ appearance="outlined"
19
+ class="add-btn"
20
+ @click="handleAdd(lang)"
21
+ >
22
+ <wa-icon
23
+ slot="start"
24
+ name="plus"
25
+ ></wa-icon>
26
+ {{ $t("bone.add") }}
27
+ <template v-if="state.counter > 1">({{ state.counter }})</template>
28
+ </wa-button>
29
+ </div>
30
+ </template>
31
+
32
+ <script setup>
33
+ import { reactive, defineComponent, onMounted, inject } from "vue"
34
+
35
+ const props = defineProps({
36
+ name: String,
37
+ value: Object,
38
+ index: Number,
39
+ lang: String,
40
+ readonly: Boolean,
41
+ params: Object,
42
+ })
43
+
44
+ const emit = defineEmits(["change"])
45
+
46
+ const boneState = inject("boneState")
47
+ const state = reactive({
48
+ counter: 0,
49
+ debounce: null,
50
+ })
51
+ const addMultipleEntry = inject("addMultipleEntry")
52
+ const removeMultipleEntries = inject("removeMultipleEntries")
53
+
54
+ function handleAdd() {
55
+ state.counter += 1
56
+ let delay = 200
57
+ if (state.counter > 1) {
58
+ delay = 500
59
+ }
60
+ if (state.debounce) {
61
+ clearTimeout(state.debounce)
62
+ }
63
+ state.debounce = setTimeout(() => {
64
+ for (let i = state.counter; i--; ) {
65
+ addMultipleEntry(props.lang)
66
+ }
67
+ state.counter = 0
68
+ }, delay)
69
+ }
70
+
71
+ function handleRemove() {
72
+ let delay = 200
73
+ if (state.debounce) {
74
+ clearTimeout(state.debounce)
75
+ }
76
+ state.debounce = setTimeout(() => {
77
+ removeMultipleEntries(props.lang)
78
+ }, delay)
79
+ }
80
+
81
+ onMounted(() => {
82
+ if (!props.value || props.value.length === 0) {
83
+ emit("change", props.name, [], props.lang) //init
84
+ }
85
+ })
86
+ </script>
87
+
88
+ <style scoped>
89
+ .actionbar {
90
+ display: flex;
91
+ flex-direction: row;
92
+ flex-wrap: nowrap;
93
+ }
94
+
95
+ .add-btn {
96
+ margin-left: auto;
97
+ }
98
+ </style>
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <div
3
+ class="actionbar"
4
+ @dragover.prevent="state.droparea = true"
5
+ @dragleave="state.droparea = false"
6
+ @drop.prevent="handleDrop"
7
+ >
8
+ <wa-button
9
+ v-if="boneState.multiple && !readonly"
10
+ variant="danger"
11
+ :title="$t('bone.del')"
12
+ appearance="outlined"
13
+ class="delete-btn"
14
+ @click="openSelector()"
15
+ >
16
+ <wa-icon
17
+ slot="start"
18
+ name="xmark"
19
+ ></wa-icon>
20
+ </wa-button>
21
+
22
+ <div
23
+ v-if="state.droparea"
24
+ class="droparea"
25
+ >
26
+ {{ t("bone.dragFile") }}
27
+ </div>
28
+
29
+ <input
30
+ ref="uploadinput"
31
+ hidden
32
+ type="file"
33
+ :multiple="boneState.multiple"
34
+ @change="handleUpload"
35
+ />
36
+ <wa-button
37
+ v-if="boneState.multiple && !readonly"
38
+ appearance="outlined"
39
+ :title="$t('bone.list')"
40
+ class="add-btn"
41
+ @click="addMultipleEntry(lang)"
42
+ >
43
+ <wa-icon
44
+ slot="start"
45
+ name="plus"
46
+ ></wa-icon>
47
+ </wa-button>
48
+
49
+ <wa-button
50
+ v-if="boneState.multiple && !readonly"
51
+ variant="success"
52
+ appearance="outlined"
53
+ :title="$t('bone.upload')"
54
+ class="upload-btn"
55
+ @click="uploadinput.click()"
56
+ >
57
+ <wa-icon name="upload"></wa-icon>
58
+ {{ $t("bone.upload") }}
59
+ <wa-spinner
60
+ v-if="state.loading"
61
+ slot="end"
62
+ ></wa-spinner>
63
+ </wa-button>
64
+ </div>
65
+ </template>
66
+
67
+ <script setup>
68
+ import { useI18n } from "vue-i18n"
69
+ import { reactive, onMounted, inject, ref, computed } from "vue"
70
+ import { uploadFile } from "../../../request/index.js"
71
+
72
+ const { t } = useI18n()
73
+
74
+ const props = defineProps({
75
+ name: String,
76
+ value: Object,
77
+ index: Number,
78
+ lang: String,
79
+ readonly: Boolean,
80
+ params: Object,
81
+ })
82
+
83
+ const emit = defineEmits(["change"])
84
+
85
+ const boneState = inject("boneState")
86
+ const addMultipleEntry = inject("addMultipleEntry")
87
+ const removeMultipleEntries = null
88
+ const uploadinput = ref()
89
+ const state = reactive({
90
+ skels: {},
91
+ uploadinput: null,
92
+ loading: false,
93
+ droparea: false,
94
+ hasUsing: computed(() => boneState?.bonestructure["using"]),
95
+ })
96
+
97
+ async function handleUpload(event) {
98
+ state.loading = true
99
+ for (let file of event.target.files) {
100
+ let fileresult = await uploadFile(file, { publicUpload: !!boneState?.bonestructure["public"] })
101
+ uploadinput.value.value = null
102
+ let relDefault = null
103
+ if (state.hasUsing) {
104
+ relDefault = undefined
105
+ }
106
+ addMultipleEntry(props.lang, { dest: fileresult, rel: relDefault })
107
+ }
108
+ state.loading = false
109
+ }
110
+
111
+ async function handleDrop(event) {
112
+ state.loading = true
113
+ state.droparea = false
114
+ for (let file of event.dataTransfer.files) {
115
+ let fileresult = await uploadFile(file, { publicUpload: !!boneState?.bonestructure["public"] })
116
+ uploadinput.value.value = null
117
+ let relDefault = null
118
+ if (state.hasUsing) {
119
+ relDefault = undefined
120
+ }
121
+ addMultipleEntry(props.lang, { dest: fileresult, rel: relDefault })
122
+ }
123
+ state.loading = false
124
+ }
125
+
126
+ onMounted(() => {
127
+ if (!props.value || props.value.length === 0) {
128
+ emit("change", props.name, [], props.lang) //init
129
+ }
130
+ })
131
+ </script>
132
+
133
+ <style scoped>
134
+ .actionbar {
135
+ display: flex;
136
+ position: relative;
137
+ flex-wrap: nowrap;
138
+ }
139
+ wa-combobox {
140
+ width: 100%;
141
+ }
142
+
143
+ .droparea {
144
+ width: 100%;
145
+ height: 100%;
146
+ position: absolute;
147
+ z-index: 10;
148
+ pointer-events: none;
149
+ opacity: 0.9;
150
+ border: 1px solid var(--wa-color-info-50);
151
+ background-color: var(--wa-color-info-80);
152
+ color: var(--wa-color-info-10);
153
+ display: flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ }
157
+
158
+ .add-btn {
159
+ margin-left: var(--wa-space-xs);
160
+ }
161
+
162
+ .upload-btn {
163
+ margin-left: auto;
164
+ }
165
+ </style>
@@ -0,0 +1,125 @@
1
+ <template>
2
+ <div class="actionbar">
3
+ <wa-button
4
+ v-if="boneState.multiple && !readonly"
5
+ variant="danger"
6
+ :title="$t('bone.del')"
7
+ appearance="outlined"
8
+ class="delete-btn"
9
+ @click="openSelector()"
10
+ >
11
+ <wa-icon
12
+ slot="start"
13
+ name="xmark"
14
+ ></wa-icon>
15
+ </wa-button>
16
+
17
+ <wa-combobox
18
+ :source="getList"
19
+ @change="
20
+ addMultipleEntry(lang, {
21
+ dest: state.skels?.[$event.target.value],
22
+ rel: state.hasUsing ? undefined : null,
23
+ })
24
+ "
25
+ ></wa-combobox>
26
+
27
+ <wa-button
28
+ v-if="boneState.multiple && !readonly"
29
+ variant="success"
30
+ :title="$t('bone.add')"
31
+ appearance="outlined"
32
+ class="add-btn"
33
+ @click="addMultiple"
34
+ >
35
+ <wa-icon
36
+ slot="start"
37
+ name="plus"
38
+ ></wa-icon>
39
+ {{ $t("bone.addEmpty") }}
40
+ </wa-button>
41
+ </div>
42
+ </template>
43
+
44
+ <script setup>
45
+ import { reactive, onMounted, inject, computed } from "vue"
46
+ import { useListFetch } from "../../../request/index.js"
47
+
48
+ const props = defineProps({
49
+ name: String,
50
+ value: Object,
51
+ index: Number,
52
+ lang: String,
53
+ readonly: Boolean,
54
+ params: Object,
55
+ })
56
+
57
+ const emit = defineEmits(["change"])
58
+
59
+ const boneState = inject("boneState")
60
+ const addMultipleEntry = inject("addMultipleEntry")
61
+ const formatString = inject("formatString")
62
+ const removeMultipleEntries = null
63
+ const state = reactive({
64
+ skels: {},
65
+ hasUsing: computed(() => boneState?.bonestructure["using"]),
66
+ })
67
+
68
+ async function getList(search) {
69
+ let params = { limit: 99 }
70
+ if (boneState.bonestructure["type"].startsWith("relational.tree.leaf")) {
71
+ params.skelType = "leaf"
72
+ } else if (boneState.bonestructure["type"].startsWith("relational.tree.node")) {
73
+ params.skelType = "node"
74
+ }
75
+ const listFetch = useListFetch(boneState.bonestructure["module"], {
76
+ immediate: false,
77
+ params,
78
+ renderer: import.meta.env.VITE_DEFAULT_RENDERER || "vi",
79
+ })
80
+
81
+ await listFetch.execute()
82
+
83
+ //?viurTags$lk=${search.toLowerCase()}
84
+ const data = { skellist: listFetch.data.value }
85
+ state.skels = data["skellist"].reduce((acc, curr) => ((acc[curr["key"]] = curr), acc), {})
86
+
87
+ return data["skellist"]?.map((d) => {
88
+ return { text: formatString(boneState.bonestructure["format"], { dest: d }), value: d.key, data: d }
89
+ })
90
+ }
91
+
92
+ onMounted(() => {
93
+ if (!props.value || props.value.length === 0) {
94
+ emit("change", props.name, [], props.lang) //init
95
+ }
96
+ })
97
+
98
+ function addMultiple() {
99
+ let relDefault = null
100
+ if (state.hasUsing) {
101
+ relDefault = undefined
102
+ }
103
+ addMultipleEntry(props.lang, { dest: {}, rel: relDefault })
104
+ }
105
+ </script>
106
+
107
+ <style scoped>
108
+ .actionbar {
109
+ display: flex;
110
+ flex-direction: row;
111
+ flex-wrap: nowrap;
112
+ }
113
+
114
+ wa-combobox {
115
+ width: 100%;
116
+ }
117
+
118
+ .delete-btn {
119
+ margin-right: var(--wa-space-xs);
120
+ }
121
+
122
+ .add-btn {
123
+ margin-left: var(--wa-space-xs);
124
+ }
125
+ </style>
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <teleport
3
+ v-if="open"
4
+ to="body"
5
+ >
6
+ <wa-dialog
7
+ open
8
+ :label="action.name + (name ? ' - ' + name : '')"
9
+ class="bone-action-dialog"
10
+ @wa-after-hide="emit('close', null, null, action)"
11
+ >
12
+ <component
13
+ :is="component"
14
+ v-if="component"
15
+ :name="name"
16
+ :module="module"
17
+ :tab-id="tabId"
18
+ :action="action"
19
+ :params="params"
20
+ @close="(val, lang) => emit('close', val ?? null, lang ?? null, action)"
21
+ @next="(val, lang) => emit('next', val ?? null, lang ?? null, action)"
22
+ ></component>
23
+ </wa-dialog>
24
+ </teleport>
25
+ </template>
26
+
27
+ <script setup>
28
+ import { computed } from "vue"
29
+ import { getActionComponent } from "./index"
30
+
31
+ const props = defineProps({
32
+ open: Boolean,
33
+ name: String,
34
+ module: String,
35
+ tabId: String,
36
+ params: Object,
37
+ action: Object,
38
+ })
39
+
40
+ const emit = defineEmits(["close", "next"])
41
+ const component = computed(() => getActionComponent(props.action?.arg))
42
+ </script>
43
+
44
+ <style scoped>
45
+ .bone-action-dialog {
46
+ --width: 85%;
47
+
48
+ &::part(body) {
49
+ display: contents;
50
+ }
51
+
52
+ &::part(base) {
53
+ position: absolute;
54
+ height: 100%;
55
+ }
56
+
57
+ &::part(panel) {
58
+ margin-bottom: 40px;
59
+ max-width: 1400px;
60
+ }
61
+
62
+ &::part(footer) {
63
+ padding: var(--wa-space-s);
64
+ }
65
+
66
+ &::part(overlay) {
67
+ position: absolute;
68
+ }
69
+ }
70
+ </style>
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <div class="debug-wrapper">
3
+ <wa-details
4
+ summary="Bone Structure"
5
+ open
6
+ >
7
+ <pre>{{ stringify(params.bone) }}</pre>
8
+ </wa-details>
9
+ <wa-details
10
+ summary="Bone Value"
11
+ open
12
+ >
13
+ <pre>{{ stringify(params.value) }}</pre>
14
+ </wa-details>
15
+ <wa-details summary="Bone State">
16
+ <pre>{{ stringify(params.boneState) }}</pre>
17
+ </wa-details>
18
+ <wa-details summary="Context">
19
+ <pre>{{ stringify({ name: params.name, lang: params.lang, index: params.index }) }}</pre>
20
+ </wa-details>
21
+ </div>
22
+
23
+ <div
24
+ slot="footer"
25
+ class="debug-footer"
26
+ >
27
+ <wa-button
28
+ size="small"
29
+ variant="brand"
30
+ appearance="outlined"
31
+ @click="CloseAction"
32
+ >
33
+ {{ t("actions.close") }}
34
+ </wa-button>
35
+ </div>
36
+ </template>
37
+
38
+ <script setup>
39
+ import { useI18n } from "vue-i18n"
40
+
41
+ const { t } = useI18n()
42
+ const props = defineProps({
43
+ name: String,
44
+ module: String,
45
+ tabId: String,
46
+ action: Object,
47
+ params: Object,
48
+ })
49
+
50
+ const emit = defineEmits(["close", "next"])
51
+
52
+ /**
53
+ * Stringifiziert ein Objekt für die Debug-Anzeige.
54
+ * Überspringt interne Felder (`_*`) und behandelt Zyklen.
55
+ */
56
+ function stringify(obj) {
57
+ const seen = new WeakSet()
58
+ try {
59
+ return JSON.stringify(
60
+ obj,
61
+ (key, val) => {
62
+ if (typeof key === "string" && key.startsWith("_")) return undefined
63
+ if (typeof val === "function") return `[Function ${val.name || "anonymous"}]`
64
+ if (val && typeof val === "object") {
65
+ if (seen.has(val)) return "[Circular]"
66
+ seen.add(val)
67
+ }
68
+ return val
69
+ },
70
+ 2
71
+ )
72
+ } catch (e) {
73
+ return String(obj)
74
+ }
75
+ }
76
+
77
+ function CloseAction() {
78
+ emit("close")
79
+ }
80
+ </script>
81
+
82
+ <style scoped>
83
+ .debug-wrapper {
84
+ padding: var(--wa-space-l);
85
+ display: flex;
86
+ flex-direction: column;
87
+ gap: var(--wa-space-xs);
88
+ }
89
+
90
+ pre {
91
+ margin: 0;
92
+ padding: var(--wa-space-s);
93
+ background-color: var(--wa-color-neutral-95);
94
+ border-radius: var(--wa-border-radius-m);
95
+ font-size: 0.8em;
96
+ font-family: var(--wa-font-family-code, monospace);
97
+ overflow: auto;
98
+ max-height: 50vh;
99
+ }
100
+
101
+ .debug-footer {
102
+ display: flex;
103
+ justify-content: flex-end;
104
+ gap: var(--wa-space-s);
105
+ }
106
+ </style>
@@ -0,0 +1,13 @@
1
+ <script>
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.
5
+ *
6
+ * @param {{ value: object, name: string, lang: string, index: number, bone: object, boneState: object, update: Function }} ctx
7
+ */
8
+ export function handler(ctx) {
9
+ ctx.update("")
10
+ }
11
+
12
+ export default {}
13
+ </script>