@frigear-nu/forms 0.0.6 → 0.0.7
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 +16 -1
- package/dist/module.d.mts +148 -8
- package/dist/module.json +1 -1
- package/dist/module.mjs +64 -35
- package/dist/runtime/app/components/FormBuilder.d.vue.ts +26 -0
- package/dist/runtime/app/components/FormBuilder.vue +220 -0
- package/dist/runtime/app/components/FormBuilder.vue.d.ts +26 -0
- package/dist/runtime/app/components/FormBuilderAccess.d.vue.ts +16 -0
- package/dist/runtime/app/components/FormBuilderAccess.vue +404 -0
- package/dist/runtime/app/components/FormBuilderAccess.vue.d.ts +16 -0
- package/dist/runtime/app/components/FormBuilderCaptchaSettings.d.vue.ts +15 -0
- package/dist/runtime/app/components/FormBuilderCaptchaSettings.vue +126 -0
- package/dist/runtime/app/components/FormBuilderCaptchaSettings.vue.d.ts +15 -0
- package/dist/runtime/app/components/FormBuilderCondition.d.vue.ts +16 -0
- package/dist/runtime/app/components/FormBuilderCondition.vue +62 -0
- package/dist/runtime/app/components/FormBuilderCondition.vue.d.ts +16 -0
- package/dist/runtime/app/components/FormBuilderFieldRow.d.vue.ts +27 -0
- package/dist/runtime/app/components/FormBuilderFieldRow.vue +87 -0
- package/dist/runtime/app/components/FormBuilderFieldRow.vue.d.ts +27 -0
- package/dist/runtime/app/components/FormBuilderFieldSettings.d.vue.ts +25 -0
- package/dist/runtime/app/components/FormBuilderFieldSettings.vue +170 -0
- package/dist/runtime/app/components/FormBuilderFieldSettings.vue.d.ts +25 -0
- package/dist/runtime/app/components/FormBuilderInsertRow.d.vue.ts +20 -0
- package/dist/runtime/app/components/FormBuilderInsertRow.vue +51 -0
- package/dist/runtime/app/components/FormBuilderInsertRow.vue.d.ts +20 -0
- package/dist/runtime/app/components/FormBuilderOptions.d.vue.ts +11 -0
- package/dist/runtime/app/components/FormBuilderOptions.vue +81 -0
- package/dist/runtime/app/components/FormBuilderOptions.vue.d.ts +11 -0
- package/dist/runtime/app/components/FormBuilderPhoneSettings.d.vue.ts +11 -0
- package/dist/runtime/app/components/FormBuilderPhoneSettings.vue +63 -0
- package/dist/runtime/app/components/FormBuilderPhoneSettings.vue.d.ts +11 -0
- package/dist/runtime/app/components/FormBuilderSettings.d.vue.ts +11 -0
- package/dist/runtime/app/components/FormBuilderSettings.vue +233 -0
- package/dist/runtime/app/components/FormBuilderSettings.vue.d.ts +11 -0
- package/dist/runtime/app/components/FormBuilderStepHeader.d.vue.ts +27 -0
- package/dist/runtime/app/components/FormBuilderStepHeader.vue +71 -0
- package/dist/runtime/app/components/FormBuilderStepHeader.vue.d.ts +27 -0
- package/dist/runtime/app/components/FormBuilderStepSettings.d.vue.ts +13 -0
- package/dist/runtime/app/components/FormBuilderStepSettings.vue +33 -0
- package/dist/runtime/app/components/FormBuilderStepSettings.vue.d.ts +13 -0
- package/dist/runtime/app/components/FormBuilderText.d.vue.ts +19 -0
- package/dist/runtime/app/components/FormBuilderText.vue +127 -0
- package/dist/runtime/app/components/FormBuilderText.vue.d.ts +19 -0
- package/dist/runtime/app/components/FormCaptcha.d.vue.ts +19 -0
- package/dist/runtime/app/components/FormCaptcha.vue +95 -0
- package/dist/runtime/app/components/FormCaptcha.vue.d.ts +19 -0
- package/dist/runtime/app/components/FormEmbed.d.vue.ts +17 -0
- package/dist/runtime/app/components/FormEmbed.vue +113 -0
- package/dist/runtime/app/components/FormEmbed.vue.d.ts +17 -0
- package/dist/runtime/app/components/FormField.d.vue.ts +4 -0
- package/dist/runtime/app/components/FormField.vue +35 -3
- package/dist/runtime/app/components/FormField.vue.d.ts +4 -0
- package/dist/runtime/app/components/FormPhoneInput.d.vue.ts +20 -0
- package/dist/runtime/app/components/FormPhoneInput.vue +56 -0
- package/dist/runtime/app/components/FormPhoneInput.vue.d.ts +20 -0
- package/dist/runtime/app/components/FormPreview.d.vue.ts +12 -0
- package/dist/runtime/app/components/FormPreview.vue +244 -0
- package/dist/runtime/app/components/FormPreview.vue.d.ts +12 -0
- package/dist/runtime/app/components/FormRenderer.d.vue.ts +6 -0
- package/dist/runtime/app/components/FormRenderer.vue +16 -7
- package/dist/runtime/app/components/FormRenderer.vue.d.ts +6 -0
- package/dist/runtime/app/components/FormSubmissionView.vue +2 -2
- package/dist/runtime/app/composables/index.d.ts +4 -1
- package/dist/runtime/app/composables/index.js +4 -1
- package/dist/runtime/app/composables/useCaptcha.d.ts +22 -0
- package/dist/runtime/app/composables/useCaptcha.js +39 -0
- package/dist/runtime/app/composables/useCaptchaSecrets.d.ts +7 -0
- package/dist/runtime/app/composables/useCaptchaSecrets.js +69 -0
- package/dist/runtime/app/composables/useFormBuilderEditor.d.ts +49 -0
- package/dist/runtime/app/composables/useFormBuilderEditor.js +210 -0
- package/dist/runtime/app/composables/useFormBuilderLabels.d.ts +8 -0
- package/dist/runtime/app/composables/useFormBuilderLabels.js +41 -0
- package/dist/runtime/app/composables/useForms.d.ts +18 -3
- package/dist/runtime/app/composables/useForms.js +38 -5
- package/dist/runtime/app/pages/admin-form.vue +112 -69
- package/dist/runtime/app/pages/admin-submission.vue +7 -16
- package/dist/runtime/app/pages/admin-submissions.vue +41 -46
- package/dist/runtime/app/pages/admin.vue +128 -44
- package/dist/runtime/app/pages/form.vue +71 -5
- package/dist/runtime/i18n/lang/da.json +231 -3
- package/dist/runtime/i18n/lang/en.json +231 -3
- package/dist/runtime/menus.js +10 -0
- package/dist/runtime/server/db/schema.sqlite.d.ts +283 -0
- package/dist/runtime/server/db/schema.sqlite.js +33 -1
- package/dist/runtime/server/mcp/schemas.d.ts +9 -0
- package/dist/runtime/server/mcp/schemas.js +8 -0
- package/dist/runtime/server/mcp/tools/admin/create-form.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/create-form.js +21 -0
- package/dist/runtime/server/mcp/tools/admin/get-form-definition.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/get-form-definition.js +14 -0
- package/dist/runtime/server/mcp/tools/admin/get-submission.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/get-submission.js +26 -0
- package/dist/runtime/server/mcp/tools/admin/list-all-forms.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/list-all-forms.js +21 -0
- package/dist/runtime/server/mcp/tools/admin/list-submissions.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/list-submissions.js +22 -0
- package/dist/runtime/server/mcp/tools/admin/update-form.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/update-form.js +24 -0
- package/dist/runtime/server/mcp/tools/get-form.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/get-form.js +12 -0
- package/dist/runtime/server/mcp/tools/list-forms.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/list-forms.js +11 -0
- package/dist/runtime/server/mcp/tools/submit-form.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/submit-form.js +17 -0
- package/dist/runtime/server/plugins/email-delivery.js +16 -11
- package/dist/runtime/server/plugins/encryption.d.ts +2 -0
- package/dist/runtime/server/plugins/encryption.js +4 -0
- package/dist/runtime/server/plugins/staff-scopes.d.ts +2 -0
- package/dist/runtime/server/plugins/staff-scopes.js +1 -0
- package/dist/runtime/server/routes/admin/form-clone.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-clone.post.js +17 -0
- package/dist/runtime/server/routes/admin/form-password.delete.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-password.delete.js +8 -0
- package/dist/runtime/server/routes/admin/form-password.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-password.get.js +8 -0
- package/dist/runtime/server/routes/admin/form-password.put.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-password.put.js +14 -0
- package/dist/runtime/server/routes/admin/form-secret.delete.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-secret.delete.js +8 -0
- package/dist/runtime/server/routes/admin/form-secrets.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-secrets.get.js +5 -0
- package/dist/runtime/server/routes/admin/form-secrets.put.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-secrets.put.js +12 -0
- package/dist/runtime/server/routes/admin/form-token.delete.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-token.delete.js +12 -0
- package/dist/runtime/server/routes/admin/form-tokens.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-tokens.get.js +8 -0
- package/dist/runtime/server/routes/admin/form-tokens.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/form-tokens.post.js +12 -0
- package/dist/runtime/server/routes/admin/form.get.js +5 -1
- package/dist/runtime/server/routes/admin/form.patch.js +3 -12
- package/dist/runtime/server/routes/admin/forms.post.js +1 -6
- package/dist/runtime/server/routes/public/access.get.d.ts +2 -0
- package/dist/runtime/server/routes/public/access.get.js +3 -0
- package/dist/runtime/server/routes/public/form.get.js +3 -1
- package/dist/runtime/server/routes/public/submit.post.js +2 -2
- package/dist/runtime/server/utils/access.d.ts +27 -0
- package/dist/runtime/server/utils/access.js +63 -0
- package/dist/runtime/server/utils/admin-schemas.d.ts +219 -15
- package/dist/runtime/server/utils/auth.d.ts +7 -7
- package/dist/runtime/server/utils/auth.js +4 -4
- package/dist/runtime/server/utils/captcha.d.ts +10 -0
- package/dist/runtime/server/utils/captcha.js +25 -0
- package/dist/runtime/server/utils/crypto.d.ts +18 -0
- package/dist/runtime/server/utils/crypto.js +48 -0
- package/dist/runtime/server/utils/forms.d.ts +6 -1
- package/dist/runtime/server/utils/forms.js +28 -0
- package/dist/runtime/server/utils/mcp-access.d.ts +9 -0
- package/dist/runtime/server/utils/mcp-access.js +8 -0
- package/dist/runtime/server/utils/rate-limit.d.ts +3 -0
- package/dist/runtime/server/utils/rate-limit.js +19 -0
- package/dist/runtime/server/utils/render.d.ts +2 -11
- package/dist/runtime/server/utils/render.js +1 -26
- package/dist/runtime/server/utils/secrets.d.ts +28 -0
- package/dist/runtime/server/utils/secrets.js +60 -0
- package/dist/runtime/server/utils/submit.d.ts +12 -1
- package/dist/runtime/server/utils/submit.js +18 -4
- package/dist/runtime/utils/builder.d.ts +73 -0
- package/dist/runtime/utils/builder.js +220 -0
- package/dist/runtime/utils/captcha.d.ts +9 -0
- package/dist/runtime/utils/captcha.js +7 -0
- package/dist/runtime/utils/conditions.d.ts +3 -1
- package/dist/runtime/utils/conditions.js +4 -0
- package/dist/runtime/utils/definition.d.ts +116 -6
- package/dist/runtime/utils/definition.js +53 -4
- package/dist/runtime/utils/embed.d.ts +8 -0
- package/dist/runtime/utils/embed.js +7 -0
- package/dist/runtime/utils/index.d.ts +16 -3
- package/dist/runtime/utils/index.js +66 -3
- package/dist/runtime/utils/markdown.d.ts +1 -5
- package/dist/runtime/utils/markdown.js +1 -5
- package/dist/runtime/utils/phone.d.ts +29 -0
- package/dist/runtime/utils/phone.js +294 -0
- package/dist/runtime/utils/preview.d.ts +12 -0
- package/dist/runtime/utils/preview.js +17 -0
- package/dist/runtime/utils/schedule.d.ts +1 -0
- package/dist/runtime/utils/schedule.js +1 -0
- package/dist/runtime/utils/schema.d.ts +2 -0
- package/dist/runtime/utils/schema.js +12 -4
- package/dist/runtime/utils/template.d.ts +57 -0
- package/dist/runtime/utils/template.js +147 -0
- package/dist/runtime/utils/text.d.ts +0 -3
- package/dist/runtime/utils/text.js +0 -5
- package/dist/types.d.mts +5 -1
- package/package.json +13 -5
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FormStep } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
step: FormStep;
|
|
4
|
+
/** Keys of the fields the step condition may look at. */
|
|
5
|
+
conditionFields: string[];
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
patch: (patch: Partial<FormStep>) => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
onPatch?: ((patch: Partial<FormStep>) => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
defineProps({
|
|
3
|
+
step: { type: Object, required: true },
|
|
4
|
+
conditionFields: { type: Array, required: true }
|
|
5
|
+
});
|
|
6
|
+
const emit = defineEmits(["patch"]);
|
|
7
|
+
const t = useModuleT("forms");
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<aside class="space-y-4 border-b border-default bg-elevated/40 p-3">
|
|
12
|
+
<h3 class="font-semibold">
|
|
13
|
+
{{ t("builder.step", "Step") }}
|
|
14
|
+
</h3>
|
|
15
|
+
<UFormField :label="t('builder.stepTitle', 'Title')">
|
|
16
|
+
<FormBuilderText
|
|
17
|
+
:model-value="step.title"
|
|
18
|
+
@update:model-value="emit('patch', { title: $event })"
|
|
19
|
+
/>
|
|
20
|
+
</UFormField>
|
|
21
|
+
<UFormField :label="t('builder.description', 'Help text')">
|
|
22
|
+
<FormBuilderText
|
|
23
|
+
:model-value="step.description"
|
|
24
|
+
@update:model-value="emit('patch', { description: $event })"
|
|
25
|
+
/>
|
|
26
|
+
</UFormField>
|
|
27
|
+
<FormBuilderCondition
|
|
28
|
+
:model-value="step.showIf"
|
|
29
|
+
:fields="conditionFields"
|
|
30
|
+
@update:model-value="emit('patch', { showIf: $event })"
|
|
31
|
+
/>
|
|
32
|
+
</aside>
|
|
33
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FormStep } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
step: FormStep;
|
|
4
|
+
/** Keys of the fields the step condition may look at. */
|
|
5
|
+
conditionFields: string[];
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
patch: (patch: Partial<FormStep>) => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
onPatch?: ((patch: Partial<FormStep>) => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Translated } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
placeholder?: string;
|
|
4
|
+
multiline?: boolean;
|
|
5
|
+
/** Write / Preview toggle for multiline text (markdown). */
|
|
6
|
+
preview?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_ModelProps = {
|
|
9
|
+
/** Either one string for every language, or a map of locale → text. */
|
|
10
|
+
modelValue?: Translated | undefined;
|
|
11
|
+
};
|
|
12
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
"update:modelValue": (value: Translated | undefined) => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
16
|
+
"onUpdate:modelValue"?: ((value: Translated | undefined) => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { collapseTranslated, expandTranslated, readTranslated } from "../../utils";
|
|
3
|
+
import { useFormsLocale, useFormsLocales } from "../composables/useForms";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
placeholder: { type: String, required: false },
|
|
6
|
+
multiline: { type: Boolean, required: false },
|
|
7
|
+
preview: { type: Boolean, required: false, default: true }
|
|
8
|
+
});
|
|
9
|
+
const model = defineModel({ type: null });
|
|
10
|
+
const t = useModuleT("forms");
|
|
11
|
+
const current = useFormsLocale();
|
|
12
|
+
const available = useFormsLocales();
|
|
13
|
+
const translated = computed(() => !!model.value && typeof model.value === "object");
|
|
14
|
+
const added = ref([]);
|
|
15
|
+
const newLocale = ref("");
|
|
16
|
+
const locales = computed(() => [.../* @__PURE__ */ new Set([...available.value, ...Object.keys(translated.value ? model.value : {}), ...added.value])]);
|
|
17
|
+
function addLocale() {
|
|
18
|
+
const code = newLocale.value.trim();
|
|
19
|
+
if (/^[a-z]{2,3}(?:[-_][a-z0-9]{2,8})*$/i.test(code) && !locales.value.includes(code)) added.value.push(code);
|
|
20
|
+
newLocale.value = "";
|
|
21
|
+
}
|
|
22
|
+
function toggle() {
|
|
23
|
+
model.value = translated.value ? collapseTranslated(model.value, current.value) : expandTranslated(model.value, current.value) ?? {};
|
|
24
|
+
}
|
|
25
|
+
function setPlain(text) {
|
|
26
|
+
model.value = text || void 0;
|
|
27
|
+
}
|
|
28
|
+
function setLocale(locale, text) {
|
|
29
|
+
model.value = Object.fromEntries(Object.entries({ ...model.value, [locale]: text }).filter(([, entry]) => entry));
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<div class="space-y-1">
|
|
35
|
+
<div
|
|
36
|
+
v-if="!translated"
|
|
37
|
+
class="flex items-start gap-1"
|
|
38
|
+
>
|
|
39
|
+
<MarkdownTextarea
|
|
40
|
+
v-if="multiline"
|
|
41
|
+
:model-value="readTranslated(model, current)"
|
|
42
|
+
:placeholder="placeholder"
|
|
43
|
+
:rows="4"
|
|
44
|
+
:preview="props.preview"
|
|
45
|
+
class="min-w-0 flex-1"
|
|
46
|
+
@update:model-value="setPlain(String($event))"
|
|
47
|
+
/>
|
|
48
|
+
<UInput
|
|
49
|
+
v-else
|
|
50
|
+
:model-value="readTranslated(model, current)"
|
|
51
|
+
:placeholder="placeholder"
|
|
52
|
+
class="min-w-0 flex-1"
|
|
53
|
+
@update:model-value="setPlain(String($event))"
|
|
54
|
+
/>
|
|
55
|
+
<UButton
|
|
56
|
+
color="neutral"
|
|
57
|
+
variant="outline"
|
|
58
|
+
icon="i-lucide-languages"
|
|
59
|
+
:aria-label="t('builder.translate', 'Translate')"
|
|
60
|
+
:title="t('builder.translate', 'Translate')"
|
|
61
|
+
@click="toggle"
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div
|
|
66
|
+
v-else
|
|
67
|
+
class="space-y-1 rounded-md border border-default p-1.5"
|
|
68
|
+
>
|
|
69
|
+
<div
|
|
70
|
+
v-for="locale in locales"
|
|
71
|
+
:key="locale"
|
|
72
|
+
class="flex items-start gap-1.5"
|
|
73
|
+
>
|
|
74
|
+
<UBadge
|
|
75
|
+
:color="locale === current ? 'primary' : 'neutral'"
|
|
76
|
+
variant="subtle"
|
|
77
|
+
size="sm"
|
|
78
|
+
class="mt-1.5 w-8 justify-center uppercase"
|
|
79
|
+
:label="locale"
|
|
80
|
+
/>
|
|
81
|
+
<MarkdownTextarea
|
|
82
|
+
v-if="multiline"
|
|
83
|
+
:model-value="readTranslated(model, locale)"
|
|
84
|
+
:placeholder="placeholder"
|
|
85
|
+
:rows="3"
|
|
86
|
+
:preview="props.preview"
|
|
87
|
+
class="min-w-0 flex-1"
|
|
88
|
+
@update:model-value="setLocale(locale, String($event))"
|
|
89
|
+
/>
|
|
90
|
+
<UInput
|
|
91
|
+
v-else
|
|
92
|
+
:model-value="readTranslated(model, locale)"
|
|
93
|
+
:placeholder="placeholder"
|
|
94
|
+
class="min-w-0 flex-1"
|
|
95
|
+
@update:model-value="setLocale(locale, String($event))"
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
<form
|
|
99
|
+
class="flex gap-1"
|
|
100
|
+
@submit.prevent="addLocale"
|
|
101
|
+
>
|
|
102
|
+
<UInput
|
|
103
|
+
v-model="newLocale"
|
|
104
|
+
size="xs"
|
|
105
|
+
:placeholder="t('builder.addLanguage', 'Add language, e.g. da')"
|
|
106
|
+
class="min-w-0 flex-1"
|
|
107
|
+
/>
|
|
108
|
+
<UButton
|
|
109
|
+
type="submit"
|
|
110
|
+
color="neutral"
|
|
111
|
+
variant="outline"
|
|
112
|
+
size="xs"
|
|
113
|
+
icon="i-lucide-plus"
|
|
114
|
+
:aria-label="t('builder.addLanguage', 'Add language, e.g. da')"
|
|
115
|
+
/>
|
|
116
|
+
</form>
|
|
117
|
+
<UButton
|
|
118
|
+
color="neutral"
|
|
119
|
+
variant="link"
|
|
120
|
+
size="xs"
|
|
121
|
+
icon="i-lucide-x"
|
|
122
|
+
:label="t('builder.singleLanguage', 'Same text in every language')"
|
|
123
|
+
@click="toggle"
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Translated } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
placeholder?: string;
|
|
4
|
+
multiline?: boolean;
|
|
5
|
+
/** Write / Preview toggle for multiline text (markdown). */
|
|
6
|
+
preview?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_ModelProps = {
|
|
9
|
+
/** Either one string for every language, or a map of locale → text. */
|
|
10
|
+
modelValue?: Translated | undefined;
|
|
11
|
+
};
|
|
12
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
"update:modelValue": (value: Translated | undefined) => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
16
|
+
"onUpdate:modelValue"?: ((value: Translated | undefined) => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FormField } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
field: FormField;
|
|
4
|
+
/** Admin preview: shows a stub and supplies a dummy token instead of loading the provider. */
|
|
5
|
+
preview?: boolean;
|
|
6
|
+
/** Bump to reset the widget (and clear the token), e.g. after a failed submit. */
|
|
7
|
+
resetKey?: number;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_ModelProps = {
|
|
10
|
+
modelValue?: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
16
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { resolveCaptcha } from "../../utils";
|
|
3
|
+
import { captchaDefaultProvider, captchaSiteKey, loadCaptchaScript } from "../composables/useCaptcha";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
field: { type: Object, required: true },
|
|
6
|
+
preview: { type: Boolean, required: false },
|
|
7
|
+
resetKey: { type: Number, required: false }
|
|
8
|
+
});
|
|
9
|
+
const model = defineModel({ type: null });
|
|
10
|
+
const t = useModuleT("forms");
|
|
11
|
+
const config = computed(() => resolveCaptcha(props.field, captchaDefaultProvider()));
|
|
12
|
+
const siteKey = computed(() => captchaSiteKey(props.field));
|
|
13
|
+
const providerName = computed(() => t(`captcha.providers.${config.value.provider}`, config.value.provider));
|
|
14
|
+
const container = useTemplateRef("container");
|
|
15
|
+
const failed = ref(false);
|
|
16
|
+
let api;
|
|
17
|
+
let widgetId;
|
|
18
|
+
async function renderWidget() {
|
|
19
|
+
if (props.preview || !container.value || !siteKey.value) return;
|
|
20
|
+
failed.value = false;
|
|
21
|
+
try {
|
|
22
|
+
api = await loadCaptchaScript(config.value.provider);
|
|
23
|
+
} catch {
|
|
24
|
+
failed.value = true;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!container.value) return;
|
|
28
|
+
const theme = config.value.theme && (config.value.theme !== "auto" || config.value.provider === "turnstile") ? config.value.theme : void 0;
|
|
29
|
+
widgetId = api.render(container.value, {
|
|
30
|
+
"sitekey": siteKey.value,
|
|
31
|
+
theme,
|
|
32
|
+
"size": config.value.size,
|
|
33
|
+
"callback": (token) => {
|
|
34
|
+
model.value = token;
|
|
35
|
+
},
|
|
36
|
+
"expired-callback": () => {
|
|
37
|
+
model.value = void 0;
|
|
38
|
+
},
|
|
39
|
+
"error-callback": () => {
|
|
40
|
+
model.value = void 0;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function resetWidget() {
|
|
45
|
+
model.value = props.preview ? "preview" : void 0;
|
|
46
|
+
if (!props.preview && api && widgetId !== void 0) api.reset(widgetId);
|
|
47
|
+
}
|
|
48
|
+
model.value = props.preview ? "preview" : void 0;
|
|
49
|
+
onMounted(renderWidget);
|
|
50
|
+
onBeforeUnmount(() => {
|
|
51
|
+
if (api && widgetId !== void 0) api.remove?.(widgetId);
|
|
52
|
+
});
|
|
53
|
+
watch(() => props.resetKey, resetWidget);
|
|
54
|
+
watch([() => config.value.provider, siteKey], () => {
|
|
55
|
+
if (api && widgetId !== void 0) api.remove?.(widgetId);
|
|
56
|
+
widgetId = void 0;
|
|
57
|
+
if (container.value) container.value.innerHTML = "";
|
|
58
|
+
model.value = void 0;
|
|
59
|
+
renderWidget();
|
|
60
|
+
});
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<template>
|
|
64
|
+
<div
|
|
65
|
+
v-if="preview"
|
|
66
|
+
data-testid="captcha-stub"
|
|
67
|
+
class="flex items-center gap-3 rounded-md border border-dashed border-default bg-elevated/50 px-3 py-4 text-sm text-muted"
|
|
68
|
+
>
|
|
69
|
+
<UIcon
|
|
70
|
+
name="i-lucide-shield-check"
|
|
71
|
+
class="size-5 shrink-0"
|
|
72
|
+
/>
|
|
73
|
+
<span>{{ t("captcha.preview", "Captcha: {provider} \u2014 shown to visitors", { provider: providerName }) }}</span>
|
|
74
|
+
</div>
|
|
75
|
+
<UAlert
|
|
76
|
+
v-else-if="!siteKey"
|
|
77
|
+
color="error"
|
|
78
|
+
variant="subtle"
|
|
79
|
+
icon="i-lucide-shield-alert"
|
|
80
|
+
:title="t('captcha.missingKey', 'The {provider} captcha has no site key configured.', { provider: providerName })"
|
|
81
|
+
/>
|
|
82
|
+
<UAlert
|
|
83
|
+
v-else-if="failed"
|
|
84
|
+
color="error"
|
|
85
|
+
variant="subtle"
|
|
86
|
+
icon="i-lucide-shield-alert"
|
|
87
|
+
:title="t('captcha.loadFailed', 'The captcha could not be loaded. Reload the page to try again.')"
|
|
88
|
+
/>
|
|
89
|
+
<div
|
|
90
|
+
v-else
|
|
91
|
+
ref="container"
|
|
92
|
+
data-testid="captcha-widget"
|
|
93
|
+
class="min-h-[65px]"
|
|
94
|
+
/>
|
|
95
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FormField } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
field: FormField;
|
|
4
|
+
/** Admin preview: shows a stub and supplies a dummy token instead of loading the provider. */
|
|
5
|
+
preview?: boolean;
|
|
6
|
+
/** Bump to reset the widget (and clear the token), e.g. after a failed submit. */
|
|
7
|
+
resetKey?: number;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_ModelProps = {
|
|
10
|
+
modelValue?: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
16
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embeds a published form in a page or in Markdown (MDC): `::form-embed{slug="contact"}`.
|
|
3
|
+
* Honors the form's access settings: sign-in prompt, password gate, nothing for API-only/token forms.
|
|
4
|
+
*/
|
|
5
|
+
type __VLS_Props = {
|
|
6
|
+
/** Slug of a published form. */
|
|
7
|
+
slug: string;
|
|
8
|
+
/** Show the form's name as a heading above it. */
|
|
9
|
+
title?: boolean;
|
|
10
|
+
/** Overrides the locale of translated form content (defaults to the app's locale). */
|
|
11
|
+
locale?: string;
|
|
12
|
+
/** Extra classes for the wrapper. */
|
|
13
|
+
class?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { embedMode } from "../../utils";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
slug: { type: String, required: true },
|
|
5
|
+
title: { type: Boolean, required: false, default: false },
|
|
6
|
+
locale: { type: String, required: false, default: void 0 },
|
|
7
|
+
class: { type: String, required: false, default: void 0 }
|
|
8
|
+
});
|
|
9
|
+
const route = useRoute();
|
|
10
|
+
const t = useModuleT("forms");
|
|
11
|
+
const { data: access, status } = useFormAccess(() => props.slug);
|
|
12
|
+
const mode = computed(() => embedMode(access.value));
|
|
13
|
+
const loading = computed(() => !access.value && (status.value === "pending" || status.value === "idle"));
|
|
14
|
+
if (import.meta.dev) {
|
|
15
|
+
watch(mode, (value) => {
|
|
16
|
+
if (value === "hidden") console.warn(`[forms] <FormEmbed slug="${props.slug}"> renders nothing: API-only and token forms have no public UI.`);
|
|
17
|
+
}, { immediate: true });
|
|
18
|
+
}
|
|
19
|
+
const loginPath = computed(() => useAuthPages().login);
|
|
20
|
+
const password = ref("");
|
|
21
|
+
const unlocked = ref("");
|
|
22
|
+
const checking = ref(false);
|
|
23
|
+
const wrong = ref(false);
|
|
24
|
+
async function unlock() {
|
|
25
|
+
checking.value = true;
|
|
26
|
+
wrong.value = false;
|
|
27
|
+
try {
|
|
28
|
+
await $fetch(`/api/forms/${props.slug}`, { headers: { [FORM_PASSWORD_HEADER]: password.value } });
|
|
29
|
+
unlocked.value = password.value;
|
|
30
|
+
} catch {
|
|
31
|
+
wrong.value = true;
|
|
32
|
+
} finally {
|
|
33
|
+
checking.value = false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<div
|
|
40
|
+
v-if="mode !== 'hidden'"
|
|
41
|
+
:class="['not-prose', props.class]"
|
|
42
|
+
data-form-embed
|
|
43
|
+
>
|
|
44
|
+
<div
|
|
45
|
+
v-if="loading"
|
|
46
|
+
class="space-y-4"
|
|
47
|
+
aria-busy="true"
|
|
48
|
+
>
|
|
49
|
+
<USkeleton class="h-10 w-full" />
|
|
50
|
+
<USkeleton class="h-10 w-full" />
|
|
51
|
+
<USkeleton class="h-24 w-full" />
|
|
52
|
+
<USkeleton class="h-10 w-32" />
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<UAlert
|
|
56
|
+
v-else-if="mode === 'not-found'"
|
|
57
|
+
color="error"
|
|
58
|
+
variant="subtle"
|
|
59
|
+
:title="t('error.notFound', 'This form could not be found.')"
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
<template v-else>
|
|
63
|
+
<h2
|
|
64
|
+
v-if="props.title && access"
|
|
65
|
+
class="mb-4 text-2xl font-bold"
|
|
66
|
+
>
|
|
67
|
+
{{ access.name }}
|
|
68
|
+
</h2>
|
|
69
|
+
|
|
70
|
+
<UAlert
|
|
71
|
+
v-if="mode === 'sign-in'"
|
|
72
|
+
color="neutral"
|
|
73
|
+
variant="subtle"
|
|
74
|
+
icon="i-lucide-lock"
|
|
75
|
+
:title="t('embed.signInTitle', 'Sign in to use this form')"
|
|
76
|
+
:actions="[{ label: t('embed.signIn', 'Sign in'), to: { path: loginPath, query: { redirect: route.fullPath } } }]"
|
|
77
|
+
/>
|
|
78
|
+
|
|
79
|
+
<UCard v-else-if="mode === 'password' && !unlocked">
|
|
80
|
+
<form
|
|
81
|
+
class="space-y-4"
|
|
82
|
+
@submit.prevent="unlock"
|
|
83
|
+
>
|
|
84
|
+
<UFormField
|
|
85
|
+
:label="t('access.passwordLabel', 'Password')"
|
|
86
|
+
:description="t('access.passwordHint', 'This form is protected. Enter the password you were given.')"
|
|
87
|
+
:error="wrong ? t('access.passwordWrong', 'Wrong password.') : void 0"
|
|
88
|
+
>
|
|
89
|
+
<UInput
|
|
90
|
+
v-model="password"
|
|
91
|
+
type="password"
|
|
92
|
+
autocomplete="off"
|
|
93
|
+
class="w-full"
|
|
94
|
+
/>
|
|
95
|
+
</UFormField>
|
|
96
|
+
<UButton
|
|
97
|
+
type="submit"
|
|
98
|
+
:loading="checking"
|
|
99
|
+
:disabled="!password"
|
|
100
|
+
:label="t('access.unlock', 'Continue')"
|
|
101
|
+
/>
|
|
102
|
+
</form>
|
|
103
|
+
</UCard>
|
|
104
|
+
|
|
105
|
+
<FormRenderer
|
|
106
|
+
v-else
|
|
107
|
+
:slug="props.slug"
|
|
108
|
+
:password="unlocked || void 0"
|
|
109
|
+
:locale="props.locale"
|
|
110
|
+
/>
|
|
111
|
+
</template>
|
|
112
|
+
</div>
|
|
113
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embeds a published form in a page or in Markdown (MDC): `::form-embed{slug="contact"}`.
|
|
3
|
+
* Honors the form's access settings: sign-in prompt, password gate, nothing for API-only/token forms.
|
|
4
|
+
*/
|
|
5
|
+
type __VLS_Props = {
|
|
6
|
+
/** Slug of a published form. */
|
|
7
|
+
slug: string;
|
|
8
|
+
/** Show the form's name as a heading above it. */
|
|
9
|
+
title?: boolean;
|
|
10
|
+
/** Overrides the locale of translated form content (defaults to the app's locale). */
|
|
11
|
+
locale?: string;
|
|
12
|
+
/** Extra classes for the wrapper. */
|
|
13
|
+
class?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
@@ -2,6 +2,10 @@ import type { FormField } from '../../../types.js';
|
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
field: FormField;
|
|
4
4
|
locale: string;
|
|
5
|
+
/** Admin preview: captcha fields render a stub instead of the provider widget. */
|
|
6
|
+
preview?: boolean;
|
|
7
|
+
/** Bumped by the form after a failed submit so captcha widgets reset. */
|
|
8
|
+
captchaResetKey?: number;
|
|
5
9
|
};
|
|
6
10
|
type __VLS_ModelProps = {
|
|
7
11
|
modelValue?: unknown;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { renderMarkdown, translate } from "../../utils";
|
|
2
|
+
import { isCountryPhone, renderMarkdown, translate } from "../../utils";
|
|
3
3
|
const props = defineProps({
|
|
4
4
|
field: { type: Object, required: true },
|
|
5
|
-
locale: { type: String, required: true }
|
|
5
|
+
locale: { type: String, required: true },
|
|
6
|
+
preview: { type: Boolean, required: false },
|
|
7
|
+
captchaResetKey: { type: Number, required: false }
|
|
6
8
|
});
|
|
7
9
|
const model = defineModel({ type: null });
|
|
10
|
+
const t = useModuleT("forms");
|
|
11
|
+
const defaultAutocomplete = { email: "email", tel: "tel" };
|
|
8
12
|
const text = (value) => translate(value, props.locale) || void 0;
|
|
9
13
|
const items = computed(() => (props.field.options ?? []).map((option) => ({
|
|
10
14
|
value: option.value,
|
|
@@ -23,6 +27,25 @@ const isCheckbox = computed(() => props.field.type === "checkbox");
|
|
|
23
27
|
/>
|
|
24
28
|
<!-- eslint-enable vue/no-v-html -->
|
|
25
29
|
|
|
30
|
+
<UFormField
|
|
31
|
+
v-else-if="field.type === 'captcha'"
|
|
32
|
+
:name="field.key"
|
|
33
|
+
:label="text(field.label)"
|
|
34
|
+
:description="text(field.description)"
|
|
35
|
+
>
|
|
36
|
+
<ClientOnly>
|
|
37
|
+
<FormCaptcha
|
|
38
|
+
v-model="model"
|
|
39
|
+
:field="field"
|
|
40
|
+
:preview="preview"
|
|
41
|
+
:reset-key="captchaResetKey"
|
|
42
|
+
/>
|
|
43
|
+
<template #fallback>
|
|
44
|
+
<div class="h-[65px] rounded-md bg-elevated/50" />
|
|
45
|
+
</template>
|
|
46
|
+
</ClientOnly>
|
|
47
|
+
</UFormField>
|
|
48
|
+
|
|
26
49
|
<UFormField
|
|
27
50
|
v-else
|
|
28
51
|
:name="field.key"
|
|
@@ -68,11 +91,20 @@ const isCheckbox = computed(() => props.field.type === "checkbox");
|
|
|
68
91
|
:accept="field.validation?.accept?.join(',')"
|
|
69
92
|
class="w-full"
|
|
70
93
|
/>
|
|
94
|
+
<FormPhoneInput
|
|
95
|
+
v-else-if="isCountryPhone(field)"
|
|
96
|
+
v-model="model"
|
|
97
|
+
:config="field.phone"
|
|
98
|
+
:locale="locale"
|
|
99
|
+
:placeholder="text(field.placeholder)"
|
|
100
|
+
:country-label="t('field.phoneCountry', 'Country')"
|
|
101
|
+
/>
|
|
71
102
|
<UInput
|
|
72
103
|
v-else
|
|
73
104
|
v-model="model"
|
|
74
105
|
:type="field.type === 'date' ? 'date' : field.type === 'tel' ? 'tel' : field.type === 'email' ? 'email' : 'text'"
|
|
75
|
-
:
|
|
106
|
+
:inputmode="field.type === 'tel' ? 'tel' : void 0"
|
|
107
|
+
:autocomplete="field.autocomplete ?? defaultAutocomplete[field.type]"
|
|
76
108
|
:placeholder="text(field.placeholder)"
|
|
77
109
|
class="w-full"
|
|
78
110
|
/>
|
|
@@ -2,6 +2,10 @@ import type { FormField } from '../../../types.js';
|
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
field: FormField;
|
|
4
4
|
locale: string;
|
|
5
|
+
/** Admin preview: captcha fields render a stub instead of the provider widget. */
|
|
6
|
+
preview?: boolean;
|
|
7
|
+
/** Bumped by the form after a failed submit so captcha widgets reset. */
|
|
8
|
+
captchaResetKey?: number;
|
|
5
9
|
};
|
|
6
10
|
type __VLS_ModelProps = {
|
|
7
11
|
modelValue?: unknown;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PhoneConfig } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
config?: PhoneConfig;
|
|
4
|
+
locale: string;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
/** Name of the country selector for assistive technology. */
|
|
7
|
+
countryLabel: string;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_ModelProps = {
|
|
10
|
+
/** The single merged value, e.g. `+4512345678`. */
|
|
11
|
+
modelValue?: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
14
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
16
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
17
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
18
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|