@omnitend/dashboard-for-laravel 0.4.14 → 0.6.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/dist/components/base/DButton.vue.d.ts +2 -3
- package/dist/components/base/DTable.vue.d.ts +11 -3
- package/dist/components/extended/DXBasicForm.vue.d.ts +4 -33
- package/dist/components/extended/DXField.vue.d.ts +88 -0
- package/dist/components/extended/DXForm.vue.d.ts +34 -8
- package/dist/components/extended/DXRepeater.vue.d.ts +30 -0
- package/dist/components/extended/DXTable.vue.d.ts +10 -17
- package/dist/dashboard-for-laravel.js +31131 -16052
- package/dist/dashboard-for-laravel.js.map +1 -1
- package/dist/dashboard-for-laravel.umd.cjs +10 -7
- package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/style.css +1 -1
- package/dist/types/index.d.ts +114 -9
- package/dist/utils/objectPath.d.ts +18 -0
- package/docs/public/api-reference.json +354 -130
- package/docs/public/docs-map.md +5 -4
- package/docs/public/llms.txt +8 -7
- package/package.json +3 -3
- package/resources/js/components/base/DButton.vue +2 -3
- package/resources/js/components/base/{DCarousel.vue → DFormRadioGroup.vue} +5 -5
- package/resources/js/components/base/DTable.vue +39 -3
- package/resources/js/components/base/DToaster.vue +5 -3
- package/resources/js/components/extended/DXBasicForm.vue +35 -184
- package/resources/js/components/extended/DXField.vue +402 -0
- package/resources/js/components/extended/DXForm.vue +282 -17
- package/resources/js/components/extended/DXRepeater.vue +216 -0
- package/resources/js/components/extended/DXTable.vue +96 -210
- package/resources/js/composables/defineForm.ts +7 -0
- package/resources/js/index.ts +18 -3
- package/resources/js/types/index.ts +146 -9
- package/resources/js/utils/objectPath.ts +59 -0
- package/dist/components/base/DCarouselSlide.vue.d.ts +0 -12
- package/resources/js/components/base/DCarouselSlide.vue +0 -14
- /package/dist/components/base/{DCarousel.vue.d.ts → DFormRadioGroup.vue.d.ts} +0 -0
package/docs/public/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Vue 3 dashboard components for Laravel with Bootstrap Vue Next
|
|
4
4
|
>
|
|
5
|
-
> A dual-package library (NPM + Composer) providing
|
|
5
|
+
> A dual-package library (NPM + Composer) providing 62 Vue 3 components for building Laravel dashboards with Bootstrap Vue Next.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
- [Theming](/guide/theming): Customize appearance with CSS variables
|
|
20
20
|
- [TypeScript](/guide/typescript): TypeScript types and best practices
|
|
21
21
|
|
|
22
|
-
## Base Components (
|
|
22
|
+
## Base Components (54 components)
|
|
23
23
|
|
|
24
24
|
Lightweight type-safe wrappers around Bootstrap Vue Next components providing API stability and consistent theming.
|
|
25
25
|
|
|
@@ -33,8 +33,6 @@ Lightweight type-safe wrappers around Bootstrap Vue Next components providing AP
|
|
|
33
33
|
- [DButtonGroup](/components/base/dbuttongroup): Bootstrap Vue Next ButtonGroup wrapper
|
|
34
34
|
- [DButtonToolbar](/components/base/dbuttontoolbar): Bootstrap Vue Next ButtonToolbar wrapper
|
|
35
35
|
- [DCard](/components/base/dcard): Bootstrap Vue Next Card wrapper
|
|
36
|
-
- [DCarousel](/components/base/dcarousel): Bootstrap Vue Next Carousel wrapper
|
|
37
|
-
- [DCarouselSlide](/components/base/dcarouselslide): Bootstrap Vue Next CarouselSlide wrapper
|
|
38
36
|
- [DCol](/components/base/dcol): Bootstrap Vue Next Col wrapper
|
|
39
37
|
- [DCollapse](/components/base/dcollapse): Bootstrap Vue Next Collapse wrapper
|
|
40
38
|
- [DContainer](/components/base/dcontainer): Bootstrap Vue Next Container wrapper
|
|
@@ -47,6 +45,7 @@ Lightweight type-safe wrappers around Bootstrap Vue Next components providing AP
|
|
|
47
45
|
- [DFormInput](/components/base/dforminput): Bootstrap Vue Next FormInput wrapper
|
|
48
46
|
- [DFormInvalidFeedback](/components/base/dforminvalidfeedback): Bootstrap Vue Next FormInvalidFeedback wrapper
|
|
49
47
|
- [DFormRadio](/components/base/dformradio): Bootstrap Vue Next FormRadio wrapper
|
|
48
|
+
- [DFormRadioGroup](/components/base/dformradiogroup): Bootstrap Vue Next FormRadioGroup wrapper
|
|
50
49
|
- [DFormSelect](/components/base/dformselect): Bootstrap Vue Next FormSelect wrapper
|
|
51
50
|
- [DFormSpinbutton](/components/base/dformspinbutton): Bootstrap Vue Next FormSpinbutton wrapper
|
|
52
51
|
- [DFormTags](/components/base/dformtags): Bootstrap Vue Next FormTags wrapper
|
|
@@ -79,15 +78,17 @@ Lightweight type-safe wrappers around Bootstrap Vue Next components providing AP
|
|
|
79
78
|
- [DToaster](/components/base/dtoaster): Bootstrap Vue Next Toaster wrapper
|
|
80
79
|
- [DTooltip](/components/base/dtooltip): Bootstrap Vue Next Tooltip wrapper
|
|
81
80
|
|
|
82
|
-
## Extended Components (
|
|
81
|
+
## Extended Components (8 components)
|
|
83
82
|
|
|
84
83
|
Custom dashboard components with advanced functionality beyond Bootstrap Vue Next.
|
|
85
84
|
|
|
86
|
-
- [DXBasicForm](/components/extended/dxbasicform):
|
|
85
|
+
- [DXBasicForm](/components/extended/dxbasicform): Extended dashboard component
|
|
87
86
|
- [DXDashboard](/components/extended/dxdashboard): Complete dashboard layout with sidebar and navbar
|
|
88
87
|
- [DXDashboardNavbar](/components/extended/dxdashboardnavbar): Top navbar with user dropdown
|
|
89
88
|
- [DXDashboardSidebar](/components/extended/dxdashboardsidebar): Collapsible sidebar with navigation
|
|
90
|
-
- [
|
|
89
|
+
- [DXField](/components/extended/dxfield): Single-field renderer for any field type with value/span/info/hint slots
|
|
90
|
+
- [DXForm](/components/extended/dxform): Form renderer driven by field definitions, with optional tabs, conditional fields, per-field slots, async options, nested repeaters, and auto error-tab switching
|
|
91
|
+
- [DXRepeater](/components/extended/dxrepeater): Repeatable nested sub-form (field array) primitive
|
|
91
92
|
- [DXTable](/components/extended/dxtable): Data table with pagination, filtering, and sorting
|
|
92
93
|
|
|
93
94
|
## Composables
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnitend/dashboard-for-laravel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Vue 3 dashboard components for Laravel with Bootstrap Vue Next",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/dashboard-for-laravel.umd.cjs",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@inertiajs/vue3": "^2.0.0",
|
|
49
49
|
"axios": "^1.6.0",
|
|
50
|
-
"vue": "^3.
|
|
50
|
+
"vue": "^3.5.13"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"axios": {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@modelcontextprotocol/sdk": "^1.22.0",
|
|
62
|
-
"bootstrap-vue-next": "^0.
|
|
62
|
+
"bootstrap-vue-next": "^0.45.6",
|
|
63
63
|
"highlight.js": "^11.11.1",
|
|
64
64
|
"pluralize": "^8.0.0",
|
|
65
65
|
"rehype-autolink-headings": "^7.1.0",
|
|
@@ -33,15 +33,14 @@ interface Props {
|
|
|
33
33
|
variant?: ButtonVariant | LinkVariant | null;
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* The size of the button
|
|
37
|
-
*
|
|
36
|
+
* The size of the button. Omit for the default (medium) size —
|
|
37
|
+
* bootstrap-vue-next 0.45 removed the no-op `'md'` value from `Size`.
|
|
38
38
|
*/
|
|
39
39
|
size?: Size;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
withDefaults(defineProps<Props>(), {
|
|
43
43
|
variant: 'primary',
|
|
44
|
-
size: 'md',
|
|
45
44
|
});
|
|
46
45
|
</script>
|
|
47
46
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @component
|
|
3
|
-
* Type-safe wrapper around Bootstrap Vue Next
|
|
4
|
-
*
|
|
3
|
+
* Type-safe wrapper around Bootstrap Vue Next BFormRadioGroup component.
|
|
4
|
+
* Renders a group of radio inputs from an `options` array or slot content.
|
|
5
5
|
*/
|
|
6
6
|
<script setup lang="ts">
|
|
7
|
-
import {
|
|
7
|
+
import { BFormRadioGroup } from "bootstrap-vue-next";
|
|
8
8
|
|
|
9
9
|
defineOptions({
|
|
10
10
|
inheritAttrs: false,
|
|
@@ -12,10 +12,10 @@ defineOptions({
|
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
14
|
<template>
|
|
15
|
-
<
|
|
15
|
+
<BFormRadioGroup v-bind="$attrs">
|
|
16
16
|
<!-- Dynamically pass through all named slots with their props -->
|
|
17
17
|
<template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
|
|
18
18
|
<slot :name="name" v-bind="slotProps" />
|
|
19
19
|
</template>
|
|
20
|
-
</
|
|
20
|
+
</BFormRadioGroup>
|
|
21
21
|
</template>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<BTable
|
|
3
3
|
ref="bTableRef"
|
|
4
4
|
v-bind="$attrs"
|
|
5
|
+
:fields="shieldedFields"
|
|
5
6
|
@update:sort-by="handleSortByUpdate"
|
|
6
7
|
@update:current-page="handleCurrentPageUpdate"
|
|
7
8
|
@update:busy="handleBusyUpdate"
|
|
@@ -15,19 +16,49 @@
|
|
|
15
16
|
</template>
|
|
16
17
|
|
|
17
18
|
<script setup lang="ts">
|
|
18
|
-
import { ref } from 'vue';
|
|
19
|
+
import { ref, computed } from 'vue';
|
|
19
20
|
import { BTable } from "bootstrap-vue-next";
|
|
20
21
|
|
|
21
22
|
defineOptions({
|
|
22
23
|
inheritAttrs: false,
|
|
23
24
|
});
|
|
24
25
|
|
|
26
|
+
const props = defineProps<{
|
|
27
|
+
/**
|
|
28
|
+
* Column definitions. Declared as a prop (rather than passed through
|
|
29
|
+
* `$attrs`) so we can shield the field `formatter` signature across
|
|
30
|
+
* bootstrap-vue-next versions.
|
|
31
|
+
*/
|
|
32
|
+
fields?: any[];
|
|
33
|
+
}>();
|
|
34
|
+
|
|
25
35
|
// Define emits to forward BTable events
|
|
26
36
|
const emit = defineEmits(['update:sortBy', 'update:currentPage', 'update:busy', 'sorted', 'rowClicked']);
|
|
27
37
|
|
|
28
38
|
// Reference to BTable for exposing methods
|
|
29
39
|
const bTableRef = ref<any>(null);
|
|
30
40
|
|
|
41
|
+
/**
|
|
42
|
+
* bootstrap-vue-next 0.43 changed the field `formatter` to receive a single
|
|
43
|
+
* object `{ value, key, item }`. This library has always documented the
|
|
44
|
+
* positional `(value, key, item)` signature, so wrap each formatter to keep
|
|
45
|
+
* existing consumer formatters working across the upgrade.
|
|
46
|
+
*/
|
|
47
|
+
const shieldedFields = computed(() => {
|
|
48
|
+
if (!props.fields) return undefined;
|
|
49
|
+
return props.fields.map((field) => {
|
|
50
|
+
if (field && typeof field.formatter === 'function') {
|
|
51
|
+
const original = field.formatter;
|
|
52
|
+
return {
|
|
53
|
+
...field,
|
|
54
|
+
formatter: (obj: { value: unknown; key: string; item: any }) =>
|
|
55
|
+
original(obj?.value, obj?.key, obj?.item),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return field;
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
31
62
|
// Event handlers to forward BTable events
|
|
32
63
|
const handleSortByUpdate = (val: any) => {
|
|
33
64
|
emit('update:sortBy', val);
|
|
@@ -45,8 +76,13 @@ const handleSorted = (val: any) => {
|
|
|
45
76
|
emit('sorted', val);
|
|
46
77
|
};
|
|
47
78
|
|
|
48
|
-
|
|
49
|
-
|
|
79
|
+
/**
|
|
80
|
+
* bootstrap-vue-next 0.43 changed row events to a single object payload
|
|
81
|
+
* `{ item, index, event }`. Re-emit in the historic `(item, index, event)`
|
|
82
|
+
* shape so consumers (incl. DXTable) keep their handler signatures.
|
|
83
|
+
*/
|
|
84
|
+
const handleRowClicked = (obj: any) => {
|
|
85
|
+
emit('rowClicked', obj?.item, obj?.index, obj?.event);
|
|
50
86
|
};
|
|
51
87
|
|
|
52
88
|
// Expose refresh method from BTable
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
2
|
+
// bootstrap-vue-next 0.44 removed BToastOrchestrator; the toast/modal/popover
|
|
3
|
+
// renderer is now the unified BOrchestrator (also included inside BApp).
|
|
4
|
+
import { BOrchestrator } from "bootstrap-vue-next";
|
|
3
5
|
|
|
4
6
|
defineOptions({
|
|
5
7
|
inheritAttrs: false,
|
|
@@ -7,10 +9,10 @@ defineOptions({
|
|
|
7
9
|
</script>
|
|
8
10
|
|
|
9
11
|
<template>
|
|
10
|
-
<
|
|
12
|
+
<BOrchestrator v-bind="$attrs">
|
|
11
13
|
<!-- Dynamically pass through all named slots with their props -->
|
|
12
14
|
<template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
|
|
13
15
|
<slot :name="name" v-bind="slotProps" />
|
|
14
16
|
</template>
|
|
15
|
-
</
|
|
17
|
+
</BOrchestrator>
|
|
16
18
|
</template>
|
|
@@ -1,189 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<!-- Render each field -->
|
|
14
|
-
<template v-for="field in visibleFields" :key="field.key">
|
|
15
|
-
<!-- Custom slot for this field -->
|
|
16
|
-
<slot :name="`field-${field.key}`" :field="field" :form="form">
|
|
17
|
-
<!-- Default field rendering -->
|
|
18
|
-
<DFormGroup
|
|
19
|
-
:label="field.label"
|
|
20
|
-
:label-for="field.key"
|
|
21
|
-
:class="field.class || 'mb-3'"
|
|
22
|
-
>
|
|
23
|
-
<!-- Text-based inputs -->
|
|
24
|
-
<DFormInput
|
|
25
|
-
v-if="isTextInput(field.type)"
|
|
26
|
-
:id="field.key"
|
|
27
|
-
v-model="form.data[field.key]"
|
|
28
|
-
:type="field.type"
|
|
29
|
-
:required="field.required"
|
|
30
|
-
:placeholder="field.placeholder"
|
|
31
|
-
:state="form.getState(field.key)"
|
|
32
|
-
v-bind="field.inputProps"
|
|
33
|
-
@input="form.clearError(field.key)"
|
|
34
|
-
/>
|
|
35
|
-
|
|
36
|
-
<!-- Textarea -->
|
|
37
|
-
<DFormTextarea
|
|
38
|
-
v-else-if="field.type === 'textarea'"
|
|
39
|
-
:id="field.key"
|
|
40
|
-
v-model="form.data[field.key]"
|
|
41
|
-
:required="field.required"
|
|
42
|
-
:placeholder="field.placeholder"
|
|
43
|
-
:rows="field.rows || 3"
|
|
44
|
-
:state="form.getState(field.key)"
|
|
45
|
-
v-bind="field.inputProps"
|
|
46
|
-
@input="form.clearError(field.key)"
|
|
47
|
-
/>
|
|
48
|
-
|
|
49
|
-
<!-- Select -->
|
|
50
|
-
<DFormSelect
|
|
51
|
-
v-else-if="field.type === 'select'"
|
|
52
|
-
:id="field.key"
|
|
53
|
-
v-model="form.data[field.key]"
|
|
54
|
-
:required="field.required"
|
|
55
|
-
:options="field.options"
|
|
56
|
-
:state="form.getState(field.key)"
|
|
57
|
-
v-bind="field.inputProps"
|
|
58
|
-
@change="form.clearError(field.key)"
|
|
59
|
-
/>
|
|
60
|
-
|
|
61
|
-
<!-- Checkbox -->
|
|
62
|
-
<DFormCheckbox
|
|
63
|
-
v-else-if="field.type === 'checkbox'"
|
|
64
|
-
:id="field.key"
|
|
65
|
-
v-model="form.data[field.key]"
|
|
66
|
-
v-bind="field.inputProps"
|
|
67
|
-
>
|
|
68
|
-
{{ field.label }}
|
|
69
|
-
</DFormCheckbox>
|
|
70
|
-
|
|
71
|
-
<!-- Radio group -->
|
|
72
|
-
<BFormRadioGroup
|
|
73
|
-
v-else-if="field.type === 'radio'"
|
|
74
|
-
:id="field.key"
|
|
75
|
-
v-model="form.data[field.key]"
|
|
76
|
-
:options="field.options"
|
|
77
|
-
:required="field.required"
|
|
78
|
-
:state="form.getState(field.key)"
|
|
79
|
-
v-bind="field.inputProps"
|
|
80
|
-
@change="form.clearError(field.key)"
|
|
81
|
-
/>
|
|
82
|
-
|
|
83
|
-
<!-- Validation error -->
|
|
84
|
-
<DFormInvalidFeedback v-if="form.hasError(field.key)">
|
|
85
|
-
{{ form.getError(field.key) }}
|
|
86
|
-
</DFormInvalidFeedback>
|
|
87
|
-
|
|
88
|
-
<!-- Help text -->
|
|
89
|
-
<DFormText v-if="field.help">
|
|
90
|
-
{{ field.help }}
|
|
91
|
-
</DFormText>
|
|
92
|
-
</DFormGroup>
|
|
93
|
-
</slot>
|
|
94
|
-
</template>
|
|
95
|
-
|
|
96
|
-
<!-- Submit button -->
|
|
97
|
-
<DButton
|
|
98
|
-
v-if="showSubmit"
|
|
99
|
-
type="submit"
|
|
100
|
-
variant="primary"
|
|
101
|
-
:disabled="form.processing"
|
|
102
|
-
class="w-100"
|
|
103
|
-
>
|
|
104
|
-
<span v-if="form.processing">{{ submitLoadingText }}</span>
|
|
105
|
-
<span v-else>{{ submitText }}</span>
|
|
106
|
-
</DButton>
|
|
107
|
-
|
|
108
|
-
<!-- Footer slot -->
|
|
109
|
-
<slot name="footer"></slot>
|
|
110
|
-
</BForm>
|
|
111
|
-
</template>
|
|
1
|
+
<!--
|
|
2
|
+
DXBasicForm — deprecated alias of DXForm.
|
|
3
|
+
|
|
4
|
+
A flat form is just DXForm without a `tabs` prop. This wrapper forwards
|
|
5
|
+
everything to DXForm and logs a one-time deprecation warning so existing
|
|
6
|
+
callers keep working while they migrate. Remove in a future major.
|
|
7
|
+
-->
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
// Module scope: warn at most once per session, not once per instance.
|
|
10
|
+
let hasWarned = false;
|
|
11
|
+
</script>
|
|
112
12
|
|
|
113
13
|
<script setup lang="ts">
|
|
114
|
-
import {
|
|
115
|
-
import
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
import type { FieldDefinition, FieldType } from "../../types";
|
|
127
|
-
|
|
128
|
-
interface Props {
|
|
129
|
-
/** Form instance from useForm composable */
|
|
130
|
-
form: UseFormReturn<any>;
|
|
131
|
-
|
|
132
|
-
/** Field definitions */
|
|
133
|
-
fields: FieldDefinition[];
|
|
134
|
-
|
|
135
|
-
/** Submit button text */
|
|
136
|
-
submitText?: string;
|
|
137
|
-
|
|
138
|
-
/** Submit button loading text */
|
|
139
|
-
submitLoadingText?: string;
|
|
140
|
-
|
|
141
|
-
/** Show submit button */
|
|
142
|
-
showSubmit?: boolean;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
146
|
-
submitText: "Submit",
|
|
147
|
-
submitLoadingText: "Submitting...",
|
|
148
|
-
showSubmit: true,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Fields whose `show()` predicate evaluates to true (or omits the
|
|
153
|
-
* predicate entirely). Computed so the form re-renders when reactive
|
|
154
|
-
* sources used inside `show` change.
|
|
155
|
-
*/
|
|
156
|
-
const visibleFields = computed(() => {
|
|
157
|
-
return props.fields.filter((field) =>
|
|
158
|
-
field.show ? field.show() : true,
|
|
14
|
+
import { onMounted } from "vue";
|
|
15
|
+
import DXForm from "./DXForm.vue";
|
|
16
|
+
|
|
17
|
+
defineOptions({ inheritAttrs: false });
|
|
18
|
+
|
|
19
|
+
onMounted(() => {
|
|
20
|
+
if (hasWarned) return;
|
|
21
|
+
hasWarned = true;
|
|
22
|
+
console.warn(
|
|
23
|
+
"[dashboard-for-laravel] DXBasicForm is deprecated and will be " +
|
|
24
|
+
"removed in a future major version. Use DXForm instead " +
|
|
25
|
+
"(a flat form is DXForm without a `tabs` prop).",
|
|
159
26
|
);
|
|
160
27
|
});
|
|
161
|
-
|
|
162
|
-
const emit = defineEmits<{
|
|
163
|
-
submit: [];
|
|
164
|
-
}>();
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Check if field type is a text-based input
|
|
168
|
-
*/
|
|
169
|
-
const isTextInput = (type: FieldType): boolean => {
|
|
170
|
-
return [
|
|
171
|
-
"text",
|
|
172
|
-
"email",
|
|
173
|
-
"password",
|
|
174
|
-
"number",
|
|
175
|
-
"url",
|
|
176
|
-
"tel",
|
|
177
|
-
"date",
|
|
178
|
-
"datetime-local",
|
|
179
|
-
"time",
|
|
180
|
-
].includes(type);
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Handle form submission
|
|
185
|
-
*/
|
|
186
|
-
const handleSubmit = () => {
|
|
187
|
-
emit("submit");
|
|
188
|
-
};
|
|
189
28
|
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<!-- `form`/`fields`/etc. arrive via $attrs (inheritAttrs: false) and are
|
|
32
|
+
forwarded to DXForm. Cast because the type-checker can't see the
|
|
33
|
+
required `form` prop inside the untyped attrs spread. -->
|
|
34
|
+
<DXForm v-bind="($attrs as any)">
|
|
35
|
+
<!-- Forward all slots (#value(<key>), #footer, etc.) to DXForm. -->
|
|
36
|
+
<template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
|
|
37
|
+
<slot :name="name" v-bind="slotProps" />
|
|
38
|
+
</template>
|
|
39
|
+
</DXForm>
|
|
40
|
+
</template>
|