minsky-webform-formkit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pnp.cjs +11555 -0
- package/.pnp.loader.mjs +2126 -0
- package/LICENSE +21 -0
- package/README.md +324 -0
- package/dist/index.css +1 -0
- package/dist/index.js +1 -0
- package/package.json +55 -0
- package/src/components/FormKit/FormKitPhoneEnhanced/FormKitPhoneEnhanced.js +100 -0
- package/src/components/FormKit/FormKitPhoneEnhanced/FormKitPhoneEnhanced.vue +30 -0
- package/src/components/FormKit/FormKitPhoneEnhanced/countryCodes.js +1214 -0
- package/src/components/FormKit/FormKitRecaptcha/FormKitRecaptcha.vue +46 -0
- package/src/components/Icon.vue +38 -0
- package/src/components/InfoTooltip.vue +16 -0
- package/src/components/MinksyWebformFormKit/MinskyWebformFormKit.vue +357 -0
- package/src/components/MinksyWebformFormKit/_MinskyWebformFormKit.js +282 -0
- package/src/composables/useExample.js +0 -0
- package/src/formkit.config.js +72 -0
- package/src/index.mjs +20 -0
- package/src/plugins/customLabelPlugin.js +42 -0
- package/src/plugins/htmlHelpPlugin.js +23 -0
- package/src/rules/iban.js +9 -0
- package/src/rules/insz.js +21 -0
- package/src/rules/phone.js +29 -0
- package/src/rules/time.js +79 -0
- package/src/rules/vat.js +42 -0
- package/src/styles/_functions.scss +96 -0
- package/src/styles/_mixins.scss +29 -0
- package/src/styles/_variables.scss +7 -0
- package/src/styles/main.scss +11 -0
- package/src/styles/webform-formkit-multistep.scss +98 -0
- package/src/styles/webform-formkit.scss +215 -0
- package/src/styles/webform.scss +400 -0
- package/src/utils/functions.js +78 -0
- package/src/utils/lodash.js +208 -0
- package/src/utils/messages.js +37 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="formkit-recaptcha">
|
|
3
|
+
<div class="g-recaptcha" ref="recaptchaRef" data-theme="light" data-type="image"></div>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
import { ref, onMounted } from 'vue';
|
|
9
|
+
|
|
10
|
+
/* ------------------------------------------------------------------
|
|
11
|
+
* Props / Emits
|
|
12
|
+
* ------------------------------------------------------------------ */
|
|
13
|
+
const props = defineProps({
|
|
14
|
+
context: Object,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/* ------------------------------------------------------------------
|
|
18
|
+
* Template refs
|
|
19
|
+
* ------------------------------------------------------------------ */
|
|
20
|
+
const recaptchaRef = ref(null);
|
|
21
|
+
|
|
22
|
+
/* ========================================================================= */
|
|
23
|
+
/* Methods */
|
|
24
|
+
/* ========================================================================= */
|
|
25
|
+
function onSubmit(e) {
|
|
26
|
+
props.context.node.input({
|
|
27
|
+
captcha_sid: props.context.attrs.sid,
|
|
28
|
+
captcha_token: props.context.attrs.token,
|
|
29
|
+
captcha_response: '',
|
|
30
|
+
'g-recaptcha-response': e,
|
|
31
|
+
captcha_cacheable: '1',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* ------------------------------------------------------------------
|
|
36
|
+
* Lifecycle
|
|
37
|
+
* ------------------------------------------------------------------ */
|
|
38
|
+
onMounted(() => {
|
|
39
|
+
grecaptcha.ready(() => {
|
|
40
|
+
grecaptcha.render(recaptchaRef.value, {
|
|
41
|
+
sitekey: props.context.attrs.siteKey,
|
|
42
|
+
callback: onSubmit,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
</script>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="icon" :class="[name !== '' ? 'icon--' + name : '', modifiers.length ? 'icon--' + modifiers.join(' icon--') : '']">
|
|
3
|
+
<svg v-if="loading" role="img" id="L9" version="1.1" class="icon-svg icon-svg--loader" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" 1 enable-background="new 0 0 0 0" xml:space="preserve">
|
|
4
|
+
<title>Loading</title>
|
|
5
|
+
<path fill="currentColor" d="M73,50c0-12.7-10.3-23-23-23S27,37.3,27,50 M30.9,50c0-10.5,8.5-19.1,19.1-19.1S69.1,39.5,69.1,50">
|
|
6
|
+
<animateTransform attributeName="transform" attributeType="XML" type="rotate" dur="1s" from="0 50 50" to="360 50 50" repeatCount="indefinite" />
|
|
7
|
+
</path>
|
|
8
|
+
</svg>
|
|
9
|
+
|
|
10
|
+
<svg v-else role="img" class="icon__svg" :aria-hidden="!ariaTitle">
|
|
11
|
+
<title v-if="ariaTitle">{{ ariaTitle }}</title>
|
|
12
|
+
<use v-if="!!name" :xlink:href="'#sprite-' + name" />
|
|
13
|
+
</svg>
|
|
14
|
+
</span>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup>
|
|
18
|
+
const props = defineProps({
|
|
19
|
+
name: {
|
|
20
|
+
type: String,
|
|
21
|
+
default: '',
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
loading: {
|
|
25
|
+
type: Boolean,
|
|
26
|
+
default: false,
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
modifiers: {
|
|
30
|
+
type: Array,
|
|
31
|
+
default: () => [],
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
ariaTitle: {
|
|
35
|
+
type: String,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="info-tooltip">
|
|
3
|
+
<Tooltip :triggers="['click', 'hover']">
|
|
4
|
+
<Icon name="info" />
|
|
5
|
+
<template #popper>
|
|
6
|
+
<div v-html="props.content" />
|
|
7
|
+
</template>
|
|
8
|
+
</Tooltip>
|
|
9
|
+
</span>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
import { Tooltip } from 'floating-vue';
|
|
14
|
+
|
|
15
|
+
const props = defineProps(['content']);
|
|
16
|
+
</script>
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div ref="formRef" class="webform-formkit" :class="[{ 'webform-formkit--loading': submissionLoading || loading }, `webform-formkit--${props.id}`, props.classModifier ? `webform-formkit--${props.classModifier}` : null]">
|
|
3
|
+
<div v-if="loading && !success && !showErrorMessage" class="webform-formkit__placeholder">
|
|
4
|
+
<slot name="placeholder" />
|
|
5
|
+
</div>
|
|
6
|
+
<div v-if="!loading && !success && !showErrorMessage">
|
|
7
|
+
<FormKitSchema :schema="schema" :data="formData" :library="props.cmpLibrary" />
|
|
8
|
+
<slot name="afterSchema" />
|
|
9
|
+
</div>
|
|
10
|
+
<div v-if="loading || submissionLoading" class="webform-formkit__loader">
|
|
11
|
+
<Icon :loading="true" />
|
|
12
|
+
<p v-if="loadingMessage" class="webform-formkit__message">
|
|
13
|
+
{{ loadingMessage }}
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
16
|
+
<div v-if="success" class="webform-formkit__success">
|
|
17
|
+
<h5 v-if="successTitle" class="webform-formkit__succes-title">
|
|
18
|
+
{{ successTitle }}
|
|
19
|
+
</h5>
|
|
20
|
+
<div v-if="successMessage" class="webform-formkit__message" v-html="successMessage"></div>
|
|
21
|
+
</div>
|
|
22
|
+
<ul v-if="showErrorMessage" class="webform-formkit__errors">
|
|
23
|
+
<li v-for="error in errorMessages" v-html="error.message"></li>
|
|
24
|
+
</ul>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup>
|
|
29
|
+
import { ref, reactive, computed, watch, onMounted, nextTick } from 'vue';
|
|
30
|
+
import { _keys, _pick, _merge, _defaultsDeep } from '../../utils/lodash';
|
|
31
|
+
import gsap from 'gsap';
|
|
32
|
+
import ScrollToPlugin from 'gsap/ScrollToPlugin';
|
|
33
|
+
import { flattenObject, hasValue } from '../../utils/functions';
|
|
34
|
+
import defaultMessages from '../../utils/messages';
|
|
35
|
+
|
|
36
|
+
gsap.registerPlugin(ScrollToPlugin);
|
|
37
|
+
const { lang } = document.documentElement;
|
|
38
|
+
/* ------------------------------------------------------------------
|
|
39
|
+
* Props / Emits
|
|
40
|
+
* ------------------------------------------------------------------ */
|
|
41
|
+
const props = defineProps({
|
|
42
|
+
id: {
|
|
43
|
+
type: String,
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
api: {
|
|
47
|
+
type: String,
|
|
48
|
+
default: window.location.origin,
|
|
49
|
+
},
|
|
50
|
+
classModifier: String,
|
|
51
|
+
defaults: Object,
|
|
52
|
+
schemeProcessor: Function,
|
|
53
|
+
formDataAddons: Object,
|
|
54
|
+
submitProcessor: Function,
|
|
55
|
+
forceRedirect: {
|
|
56
|
+
type: Object,
|
|
57
|
+
default: () => ({ bool: false }),
|
|
58
|
+
},
|
|
59
|
+
cmpLibrary: {
|
|
60
|
+
type: Object,
|
|
61
|
+
default: () => ({}),
|
|
62
|
+
},
|
|
63
|
+
messages: {
|
|
64
|
+
type: Object,
|
|
65
|
+
default: () => {},
|
|
66
|
+
},
|
|
67
|
+
setUserData: Function,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const emit = defineEmits(['success']);
|
|
71
|
+
|
|
72
|
+
/* ------------------------------------------------------------------
|
|
73
|
+
* Template refs
|
|
74
|
+
* ------------------------------------------------------------------ */
|
|
75
|
+
const formRef = ref(null);
|
|
76
|
+
|
|
77
|
+
/* ------------------------------------------------------------------
|
|
78
|
+
* State
|
|
79
|
+
* ------------------------------------------------------------------ */
|
|
80
|
+
const schema = ref(null);
|
|
81
|
+
const schemaDefaults = ref({});
|
|
82
|
+
const msgs = ref({});
|
|
83
|
+
const loading = ref(true);
|
|
84
|
+
const success = ref(false);
|
|
85
|
+
const submissionLoading = ref(false);
|
|
86
|
+
const loadingMessage = ref(null);
|
|
87
|
+
const successMessage = ref(null);
|
|
88
|
+
const successTitle = ref(null);
|
|
89
|
+
const errorMessages = ref(null);
|
|
90
|
+
const showErrorMessage = ref(false);
|
|
91
|
+
|
|
92
|
+
const formData = reactive({
|
|
93
|
+
values: {},
|
|
94
|
+
// helpers: window.WebformHeadless.helpers,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
/* ------------------------------------------------------------------
|
|
98
|
+
* Lifecycle
|
|
99
|
+
* ------------------------------------------------------------------ */
|
|
100
|
+
onMounted(() => {
|
|
101
|
+
// we merge messages provided by the user with default messages so there will alway be feedback when the form is submitted or missing
|
|
102
|
+
msgs.value = Object.assign(defaultMessages, props.messages);
|
|
103
|
+
|
|
104
|
+
formData.submit = async (data) => {
|
|
105
|
+
// remove vue values so they don't f*ck up the submit in drupal
|
|
106
|
+
delete data.form_id;
|
|
107
|
+
delete data.vApp;
|
|
108
|
+
delete data.webformId;
|
|
109
|
+
|
|
110
|
+
// check if data has multi step values + extract them
|
|
111
|
+
_keys(data).forEach((key) => {
|
|
112
|
+
if (key.includes('captcha')) {
|
|
113
|
+
Object.assign(data, data[key]);
|
|
114
|
+
delete data[key];
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// we flatten all the data to a one level object so drupal can handle the data
|
|
119
|
+
data = flattenObject(data);
|
|
120
|
+
submitForm(data);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
formData.submitInvalid = () => {
|
|
124
|
+
gsap.to(window, {
|
|
125
|
+
duration: 0.5,
|
|
126
|
+
scrollTo: { y: formRef.value, offsetY: 300 },
|
|
127
|
+
ease: 'power2',
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
fetchForm();
|
|
132
|
+
|
|
133
|
+
if (props.formDataAddons) {
|
|
134
|
+
Object.assign(formData, props.formDataAddons);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
/* ------------------------------------------------------------------
|
|
139
|
+
* Computed
|
|
140
|
+
* ------------------------------------------------------------------ */
|
|
141
|
+
const formKeys = computed(() => _keys(formData.values));
|
|
142
|
+
|
|
143
|
+
/* ------------------------------------------------------------------
|
|
144
|
+
* Methods
|
|
145
|
+
* ------------------------------------------------------------------ */
|
|
146
|
+
async function fetchForm() {
|
|
147
|
+
const params = new URLSearchParams(window.location.search);
|
|
148
|
+
params.append('schema', 'form_kit');
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const response = await fetch(`${props.api}/webform/${props.id}/json/schema?${params.toString()}`);
|
|
152
|
+
|
|
153
|
+
// Always read body first
|
|
154
|
+
const data = await response.json();
|
|
155
|
+
|
|
156
|
+
if (!response.ok) {
|
|
157
|
+
// Try to extract a meaningful backend error
|
|
158
|
+
throw new Error(data.errors ? data.errors.map((err) => err.message).join(', ') : 'Unknown error');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (data.schema) {
|
|
162
|
+
schema.value = addSlots(data.schema); // TODO
|
|
163
|
+
if (props.schemeProcessor) schema.value = props.schemeProcessor(data.schema);
|
|
164
|
+
schemaDefaults.value = data.values;
|
|
165
|
+
} else {
|
|
166
|
+
showErrorMessage.value = true;
|
|
167
|
+
errorMessages.value = [{ message: msgs.value[lang].messages.missing }];
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
showErrorMessage.value = true;
|
|
171
|
+
|
|
172
|
+
// show extended error only for user roles that can adjust webforms
|
|
173
|
+
// user roles needs to be populated with a drupal hook (check README.md)
|
|
174
|
+
if (window.drupalSettings) {
|
|
175
|
+
const userRoles = window.drupalSettings.user.roles || [];
|
|
176
|
+
if (userRoles.some((role) => ['administrator', 'editor'].includes(role))) {
|
|
177
|
+
errorMessages.value = [
|
|
178
|
+
{ message: error },
|
|
179
|
+
{
|
|
180
|
+
message: msgs.value.global.error,
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
} else {
|
|
184
|
+
errorMessages.value = [{ message: msgs.value[lang].messages.error }];
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
errorMessages.value = [{ message: msgs.value[lang].messages.error }];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.error(`Error fetching schema of form with ID ${props.id}:`, error);
|
|
191
|
+
} finally {
|
|
192
|
+
loading.value = false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function setDefaults() {
|
|
197
|
+
// set default values from schema
|
|
198
|
+
// use defaultsDeep to fill in the default value only 1 time AMNESTY-815
|
|
199
|
+
_defaultsDeep(formData.values, _pick(schemaDefaults.value, formKeys.value));
|
|
200
|
+
|
|
201
|
+
// set default values if any, like hidden fields and stuff (only those whose are available on form)
|
|
202
|
+
if (props.defaults) {
|
|
203
|
+
_merge(formData.values, _pick(props.defaults, formKeys.value));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function submitForm(data) {
|
|
208
|
+
if (props.submitProcessor) {
|
|
209
|
+
data = props.submitProcessor(data);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
submissionLoading.value = true;
|
|
213
|
+
|
|
214
|
+
// disable submit button
|
|
215
|
+
const submitButton = document.querySelector('.formkit-input[type=submit]');
|
|
216
|
+
if (submitButton) {
|
|
217
|
+
submitButton.disabled = true;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const params = new URLSearchParams(window.location.search);
|
|
221
|
+
params.append('schema', 'form_kit');
|
|
222
|
+
|
|
223
|
+
const fd = new FormData();
|
|
224
|
+
// convert data to formdata
|
|
225
|
+
for (const key in data) {
|
|
226
|
+
if (hasValue(data[key])) {
|
|
227
|
+
if (Array.isArray(data[key])) {
|
|
228
|
+
if (data[key].length) {
|
|
229
|
+
data[key].forEach((val) => {
|
|
230
|
+
if (this.$formkit.get(`${this.id}--${key}`).context.type === 'imageUpload') {
|
|
231
|
+
if (typeof val === 'object') {
|
|
232
|
+
formData.append(`${key}[]`, _values(val)[0]);
|
|
233
|
+
} else {
|
|
234
|
+
formData.append(`${key}[]`, val);
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
fd.append(`${key}[]`, val);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
} else {
|
|
241
|
+
// if array is empty, sent empty string with FormData. Fix for AMNESTY-663
|
|
242
|
+
fd.append(key, '');
|
|
243
|
+
}
|
|
244
|
+
} else if (typeof data[key] === 'string') {
|
|
245
|
+
if (data[key].indexOf('json_value') === 2) {
|
|
246
|
+
const values = JSON.parse(data[key]).json_value;
|
|
247
|
+
_keys(values).forEach((subkey) => {
|
|
248
|
+
fd.append(`${key}[${subkey}]`, values[subkey]);
|
|
249
|
+
});
|
|
250
|
+
} else {
|
|
251
|
+
fd.append(key, data[key]);
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
fd.append(key, data[key]);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
fetch(`${props.api}/webform/${props.id}/json/submission?${params.toString()}`, {
|
|
260
|
+
method: 'POST',
|
|
261
|
+
body: fd,
|
|
262
|
+
query: window.location.search,
|
|
263
|
+
})
|
|
264
|
+
.then((r) => {
|
|
265
|
+
if (r.status === 200) {
|
|
266
|
+
r.json().then((response) => {
|
|
267
|
+
handleSuccess(response);
|
|
268
|
+
|
|
269
|
+
// store user data in localstorage
|
|
270
|
+
if (props.setUserData) {
|
|
271
|
+
props.setUserData(data);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
} else {
|
|
275
|
+
r.json().then((response) => {
|
|
276
|
+
showErrorMessage.value = true;
|
|
277
|
+
submissionLoading.value = false;
|
|
278
|
+
errorMessages.value = response.errors;
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
.catch(() => {
|
|
283
|
+
showErrorMessage.value = true;
|
|
284
|
+
submissionLoading.value = false;
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function handleSuccess(response) {
|
|
289
|
+
if (!props.forceRedirect.bool) {
|
|
290
|
+
switch (response.confirmation.type) {
|
|
291
|
+
case 'inline':
|
|
292
|
+
successTitle.value = response.confirmation.title;
|
|
293
|
+
successMessage.value = response.confirmation.message;
|
|
294
|
+
success.value = true;
|
|
295
|
+
|
|
296
|
+
gsap.to(window, {
|
|
297
|
+
duration: 0.5,
|
|
298
|
+
scrollTo: { y: formRef.value, offsetY: 200 },
|
|
299
|
+
ease: 'power2',
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
submissionLoading.value = false;
|
|
303
|
+
break;
|
|
304
|
+
|
|
305
|
+
case 'url':
|
|
306
|
+
window.location = response.confirmation.url;
|
|
307
|
+
break;
|
|
308
|
+
|
|
309
|
+
default:
|
|
310
|
+
successTitle.value = msgs.value[lang].success.title;
|
|
311
|
+
successMessage.value = msgs.value[lang].success.message;
|
|
312
|
+
success.value = true;
|
|
313
|
+
submissionLoading.value = false;
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
window.location = props.forceRedirect.url;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
emit('success');
|
|
320
|
+
}
|
|
321
|
+
/* ------------------------------------------------------------------
|
|
322
|
+
* Watchers
|
|
323
|
+
* ------------------------------------------------------------------ */
|
|
324
|
+
watch(formKeys, async () => {
|
|
325
|
+
setDefaults();
|
|
326
|
+
|
|
327
|
+
await nextTick();
|
|
328
|
+
|
|
329
|
+
const $form = formRef.value?.querySelector('form');
|
|
330
|
+
if ($form) {
|
|
331
|
+
$form.setAttribute('novalidate', true); // remove native js form validation because of time input error AMNESTY-785
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
/* ------------------------------------------------------------------
|
|
336
|
+
* Helpers (unchanged)
|
|
337
|
+
* ------------------------------------------------------------------ */
|
|
338
|
+
function addSlots(schema) {
|
|
339
|
+
// if (schema[0].children) {
|
|
340
|
+
// // check if actions element is present to add slot
|
|
341
|
+
// const actions = schema[0].children.filter((cmp) => cmp.name === 'actions');
|
|
342
|
+
// if (actions[0]) {
|
|
343
|
+
// const index = schema[0].children.indexOf(actions[0]);
|
|
344
|
+
// schema[0].children.splice(index, 0, {
|
|
345
|
+
// $el: 'div',
|
|
346
|
+
// name: 'before-actions-slot',
|
|
347
|
+
// attrs: {
|
|
348
|
+
// class: 'formkit-before-actions',
|
|
349
|
+
// },
|
|
350
|
+
// children: '$slots.beforeActions',
|
|
351
|
+
// });
|
|
352
|
+
// }
|
|
353
|
+
// }
|
|
354
|
+
|
|
355
|
+
return schema;
|
|
356
|
+
}
|
|
357
|
+
</script>
|