pdyform 1.1.0 → 2.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/README.md +28 -1
- package/example/README.md +36 -0
- package/example/react-demo/dist/assets/index-BBU9cJqy.css +1 -0
- package/example/react-demo/dist/assets/index-DeJS8UcQ.js +105 -0
- package/example/react-demo/dist/index.html +13 -0
- package/example/react-demo/index.html +12 -0
- package/example/react-demo/node_modules/.bin/browserslist +17 -0
- package/example/react-demo/node_modules/.bin/tsc +17 -0
- package/example/react-demo/node_modules/.bin/tsserver +17 -0
- package/example/react-demo/node_modules/.bin/vite +17 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-checkbox.js +300 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-checkbox.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-label.js +194 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-label.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-radio-group.js +530 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-radio-group.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-select.js +4808 -0
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-select.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/_metadata.json +115 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-3D5PZ6F6.js +49 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-3D5PZ6F6.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-5Q2RBQLA.js +127 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-5Q2RBQLA.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-G3PMV62Z.js +36 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-G3PMV62Z.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-GX7YZ5KV.js +370 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-GX7YZ5KV.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-PUFJGYAC.js +928 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-PUFJGYAC.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-SIU35MPB.js +21 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-SIU35MPB.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-TOMGVNQP.js +1906 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-TOMGVNQP.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-YYN6DZAU.js +21628 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-YYN6DZAU.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-ZE5VSJFE.js +144 -0
- package/example/react-demo/node_modules/.vite/deps/chunk-ZE5VSJFE.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/class-variance-authority.js +51 -0
- package/example/react-demo/node_modules/.vite/deps/class-variance-authority.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/clsx.js +10 -0
- package/example/react-demo/node_modules/.vite/deps/clsx.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/lucide-react.js +29725 -0
- package/example/react-demo/node_modules/.vite/deps/lucide-react.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/package.json +3 -0
- package/example/react-demo/node_modules/.vite/deps/react-dom.js +7 -0
- package/example/react-demo/node_modules/.vite/deps/react-dom.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/react-dom_client.js +39 -0
- package/example/react-demo/node_modules/.vite/deps/react-dom_client.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/react.js +6 -0
- package/example/react-demo/node_modules/.vite/deps/react.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/react_jsx-dev-runtime.js +913 -0
- package/example/react-demo/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/react_jsx-runtime.js +7 -0
- package/example/react-demo/node_modules/.vite/deps/react_jsx-runtime.js.map +7 -0
- package/example/react-demo/node_modules/.vite/deps/tailwind-merge.js +2534 -0
- package/example/react-demo/node_modules/.vite/deps/tailwind-merge.js.map +7 -0
- package/example/react-demo/package.json +23 -0
- package/example/react-demo/postcss.config.mjs +6 -0
- package/example/react-demo/src/App.tsx +64 -0
- package/example/react-demo/src/main.tsx +10 -0
- package/example/react-demo/src/styles.css +102 -0
- package/example/react-demo/tailwind.config.mjs +50 -0
- package/example/react-demo/tsconfig.json +16 -0
- package/example/react-demo/vite.config.ts +14 -0
- package/example/shared/defaultSchema.ts +68 -0
- package/example/vue-demo/dist/assets/index-BhWj3D5x.css +1 -0
- package/example/vue-demo/dist/assets/index-Bw3THsrD.js +44 -0
- package/example/vue-demo/dist/index.html +13 -0
- package/example/vue-demo/index.html +12 -0
- package/example/vue-demo/node_modules/.bin/tsc +17 -0
- package/example/vue-demo/node_modules/.bin/tsserver +17 -0
- package/example/vue-demo/node_modules/.bin/vite +17 -0
- package/example/vue-demo/node_modules/.vite/deps/_metadata.json +46 -0
- package/example/vue-demo/node_modules/.vite/deps/chunk-PZ5AY32C.js +10 -0
- package/example/vue-demo/node_modules/.vite/deps/chunk-PZ5AY32C.js.map +7 -0
- package/example/vue-demo/node_modules/.vite/deps/chunk-TCXBSQ4M.js +12877 -0
- package/example/vue-demo/node_modules/.vite/deps/chunk-TCXBSQ4M.js.map +7 -0
- package/example/vue-demo/node_modules/.vite/deps/clsx.js +22 -0
- package/example/vue-demo/node_modules/.vite/deps/clsx.js.map +7 -0
- package/example/vue-demo/node_modules/.vite/deps/lucide-vue-next.js +29720 -0
- package/example/vue-demo/node_modules/.vite/deps/lucide-vue-next.js.map +7 -0
- package/example/vue-demo/node_modules/.vite/deps/package.json +3 -0
- package/example/vue-demo/node_modules/.vite/deps/radix-vue.js +24321 -0
- package/example/vue-demo/node_modules/.vite/deps/radix-vue.js.map +7 -0
- package/example/vue-demo/node_modules/.vite/deps/tailwind-merge.js +2534 -0
- package/example/vue-demo/node_modules/.vite/deps/tailwind-merge.js.map +7 -0
- package/example/vue-demo/node_modules/.vite/deps/vue.js +348 -0
- package/example/vue-demo/node_modules/.vite/deps/vue.js.map +7 -0
- package/example/vue-demo/package.json +20 -0
- package/example/vue-demo/postcss.config.mjs +6 -0
- package/example/vue-demo/src/App.vue +61 -0
- package/example/vue-demo/src/env.d.ts +1 -0
- package/example/vue-demo/src/main.ts +5 -0
- package/example/vue-demo/src/style.css +102 -0
- package/example/vue-demo/tailwind.config.mjs +50 -0
- package/example/vue-demo/tsconfig.json +15 -0
- package/example/vue-demo/vite.config.ts +14 -0
- package/package.json +10 -2
- package/packages/core/dist/{chunk-KQR3LFND.js → chunk-GQASS6PM.js} +20 -0
- package/packages/core/dist/index.cjs +20 -0
- package/packages/core/dist/index.js +1 -1
- package/packages/core/dist/utils.cjs +20 -0
- package/packages/core/dist/utils.js +1 -1
- package/packages/core/node_modules/.bin/jiti +17 -0
- package/packages/core/node_modules/.bin/tsup +2 -2
- package/packages/core/node_modules/.bin/tsup-node +2 -2
- package/packages/core/node_modules/.vite/vitest/results.json +1 -1
- package/packages/core/src/utils.ts +21 -0
- package/packages/core/test/utils.test.ts +99 -0
- package/packages/react/dist/index.cjs +383 -110
- package/packages/react/dist/index.d.cts +80 -4
- package/packages/react/dist/index.d.ts +80 -4
- package/packages/react/dist/index.js +355 -110
- package/packages/react/node_modules/.bin/jiti +17 -0
- package/packages/react/node_modules/.bin/tsup +2 -2
- package/packages/react/node_modules/.bin/tsup-node +2 -2
- package/packages/react/node_modules/.bin/vite +4 -4
- package/packages/react/node_modules/.vite/vitest/results.json +1 -1
- package/packages/react/package.json +7 -2
- package/packages/react/postcss.config.mjs +6 -0
- package/packages/react/src/FormFieldRenderer.tsx +32 -112
- package/packages/react/src/components/Checkbox.tsx +28 -0
- package/packages/react/src/components/CheckboxRenderer.tsx +37 -0
- package/packages/react/src/components/Input.tsx +24 -0
- package/packages/react/src/components/InputRenderer.tsx +29 -0
- package/packages/react/src/components/Label.tsx +24 -0
- package/packages/react/src/components/RadioGroup.tsx +42 -0
- package/packages/react/src/components/RadioRenderer.tsx +29 -0
- package/packages/react/src/components/Select.tsx +93 -0
- package/packages/react/src/components/SelectRenderer.tsx +27 -0
- package/packages/react/src/components/Textarea.tsx +23 -0
- package/packages/react/src/components/TextareaRenderer.tsx +17 -0
- package/packages/react/src/components/index.ts +55 -0
- package/packages/react/src/components/types.ts +17 -0
- package/packages/react/src/index.tsx +1 -0
- package/packages/react/src/utils.ts +7 -0
- package/packages/react/tailwind.config.mjs +10 -0
- package/packages/react/test/FormFieldRenderer.test.tsx +127 -0
- package/packages/vue/dist/index.d.ts +33 -0
- package/packages/vue/dist/index.js +28 -1
- package/packages/vue/dist/index.mjs +6798 -142
- package/packages/vue/node_modules/.bin/tsc +2 -2
- package/packages/vue/node_modules/.bin/tsserver +2 -2
- package/packages/vue/node_modules/.bin/vite +2 -2
- package/packages/vue/node_modules/.bin/vitest +2 -2
- package/packages/vue/node_modules/.bin/vue-tsc +2 -2
- package/packages/vue/node_modules/.vite/vitest/results.json +1 -1
- package/packages/vue/package.json +4 -2
- package/packages/vue/postcss.config.mjs +6 -0
- package/packages/vue/src/FormFieldRenderer.vue +46 -90
- package/packages/vue/src/components/Checkbox.vue +28 -0
- package/packages/vue/src/components/CheckboxRenderer.vue +35 -0
- package/packages/vue/src/components/Input.vue +21 -0
- package/packages/vue/src/components/InputRenderer.vue +28 -0
- package/packages/vue/src/components/Label.vue +21 -0
- package/packages/vue/src/components/RadioGroup.vue +30 -0
- package/packages/vue/src/components/RadioGroupItem.vue +26 -0
- package/packages/vue/src/components/RadioRenderer.vue +24 -0
- package/packages/vue/src/components/Select.vue +40 -0
- package/packages/vue/src/components/SelectContent.vue +38 -0
- package/packages/vue/src/components/SelectItem.vue +43 -0
- package/packages/vue/src/components/SelectRenderer.vue +30 -0
- package/packages/vue/src/components/SelectTrigger.vue +27 -0
- package/packages/vue/src/components/Textarea.vue +19 -0
- package/packages/vue/src/components/TextareaRenderer.vue +18 -0
- package/packages/vue/src/components/index.ts +24 -0
- package/packages/vue/src/fieldComponentMap.ts +34 -0
- package/packages/vue/src/index.ts +2 -0
- package/packages/vue/src/utils.ts +6 -0
- package/packages/vue/tailwind.config.mjs +10 -0
- package/packages/vue/test/FormFieldRenderer.test.ts +133 -0
- package/pnpm-workspace.yaml +1 -1
- package/packages/core/src/index.test.ts +0 -37
- /package/packages/react/{src → test}/DynamicForm.test.tsx +0 -0
- /package/packages/vue/{src → test}/DynamicForm.test.ts +0 -0
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
17
17
|
fi
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
17
17
|
fi
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules/vite/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules/vite/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vite@5.4.21_@types+node@20.19.35/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../vite/bin/vite.js" "$@"
|
|
17
17
|
fi
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.35_jsdom@22.1.0/node_modules/vitest/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.35_jsdom@22.1.0/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../vitest/vitest.mjs" "$@"
|
|
17
17
|
fi
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules/vue-tsc/bin/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules/vue-tsc/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/vue-tsc@2.2.12_typescript@5.9.3/node_modules:/Users/pidan/Work/Learn/dynamic-form/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../vue-tsc/bin/vue-tsc.js" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../vue-tsc/bin/vue-tsc.js" "$@"
|
|
17
17
|
fi
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.6.1","results":[[":
|
|
1
|
+
{"version":"1.6.1","results":[[":test/DynamicForm.test.ts",{"duration":22,"failed":false}],[":test/FormFieldRenderer.test.ts",{"duration":82,"failed":false}]]}
|
|
@@ -27,10 +27,12 @@
|
|
|
27
27
|
"lint": "eslint src/**/*.{ts,vue} --no-error-on-unmatched-pattern"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"
|
|
30
|
+
"class-variance-authority": "^0.7.1",
|
|
31
|
+
"clsx": "^2.1.1",
|
|
31
32
|
"lucide-vue-next": "^0.300.0",
|
|
32
33
|
"pdyform": "workspace:*",
|
|
33
|
-
"
|
|
34
|
+
"radix-vue": "^1.9.17",
|
|
35
|
+
"tailwind-merge": "^2.6.1"
|
|
34
36
|
},
|
|
35
37
|
"peerDependencies": {
|
|
36
38
|
"vue": "^3.5.0"
|
|
@@ -1,114 +1,70 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { FormField } from 'pdyform/core';
|
|
3
|
+
import type { Component } from 'vue';
|
|
3
4
|
import { computed } from 'vue';
|
|
5
|
+
import { defaultComponentMap, type FieldComponentMap } from './fieldComponentMap';
|
|
6
|
+
import Label from './components/Label.vue';
|
|
7
|
+
import InputRenderer from './components/InputRenderer.vue';
|
|
4
8
|
|
|
5
9
|
const props = defineProps<{
|
|
6
10
|
field: FormField;
|
|
7
11
|
modelValue: any;
|
|
8
12
|
error?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Custom component map.
|
|
15
|
+
* Entries here are merged with the default map, so you can override
|
|
16
|
+
* specific types or add entirely new ones.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { defaultComponentMap } from 'pdyform-vue';
|
|
21
|
+
* const myMap = {
|
|
22
|
+
* ...defaultComponentMap,
|
|
23
|
+
* text: MyCustomInput, // overrides built-in text input
|
|
24
|
+
* rating: StarRatingField, // adds a new field type
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
componentMap?: FieldComponentMap;
|
|
9
29
|
}>();
|
|
10
30
|
|
|
11
31
|
const emit = defineEmits(['update:modelValue']);
|
|
12
32
|
|
|
13
33
|
const fieldId = computed(() => `field-${props.field.name}`);
|
|
14
34
|
|
|
15
|
-
|
|
35
|
+
// Merge external map over defaults — external wins
|
|
36
|
+
const resolvedMap = computed<FieldComponentMap>(() =>
|
|
37
|
+
props.componentMap
|
|
38
|
+
? { ...defaultComponentMap, ...props.componentMap }
|
|
39
|
+
: defaultComponentMap
|
|
40
|
+
);
|
|
16
41
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const handleCheckboxChange = (val: any, checked: boolean) => {
|
|
22
|
-
const current = Array.isArray(props.modelValue) ? [...props.modelValue] : [];
|
|
23
|
-
if (checked) {
|
|
24
|
-
current.push(val);
|
|
25
|
-
} else {
|
|
26
|
-
const idx = current.indexOf(val);
|
|
27
|
-
if (idx > -1) current.splice(idx, 1);
|
|
28
|
-
}
|
|
29
|
-
handleUpdate(current);
|
|
30
|
-
};
|
|
42
|
+
// Resolve a component or fall back to InputRenderer
|
|
43
|
+
const ResolvedFieldComponent = computed<Component>(
|
|
44
|
+
() => resolvedMap.value[props.field.type] ?? InputRenderer
|
|
45
|
+
);
|
|
31
46
|
</script>
|
|
32
47
|
|
|
33
48
|
<template>
|
|
34
49
|
<div :class="['space-y-2', field.className]">
|
|
35
|
-
<
|
|
50
|
+
<Label v-if="field.label" :for="fieldId">
|
|
36
51
|
{{ field.label }}
|
|
37
|
-
</
|
|
38
|
-
|
|
39
|
-
<template v-if="field.type === 'textarea'">
|
|
40
|
-
<textarea
|
|
41
|
-
:id="fieldId"
|
|
42
|
-
:class="[baseInputClasses, 'min-h-[80px]']"
|
|
43
|
-
:placeholder="field.placeholder"
|
|
44
|
-
:disabled="field.disabled"
|
|
45
|
-
:name="field.name"
|
|
46
|
-
:value="modelValue"
|
|
47
|
-
@input="(e: any) => handleUpdate(e.target.value)"
|
|
48
|
-
/>
|
|
49
|
-
</template>
|
|
50
|
-
|
|
51
|
-
<template v-else-if="field.type === 'select'">
|
|
52
|
-
<select
|
|
53
|
-
:id="fieldId"
|
|
54
|
-
:class="baseInputClasses"
|
|
55
|
-
:disabled="field.disabled"
|
|
56
|
-
:name="field.name"
|
|
57
|
-
:value="modelValue"
|
|
58
|
-
@change="(e: any) => handleUpdate(e.target.value)"
|
|
59
|
-
>
|
|
60
|
-
<option value="" disabled>{{ field.placeholder || 'Select an option' }}</option>
|
|
61
|
-
<option v-for="opt in field.options" :key="opt.value" :value="opt.value">
|
|
62
|
-
{{ opt.label }}
|
|
63
|
-
</option>
|
|
64
|
-
</select>
|
|
65
|
-
</template>
|
|
66
|
-
|
|
67
|
-
<template v-else-if="field.type === 'checkbox'">
|
|
68
|
-
<div class="flex flex-wrap gap-4">
|
|
69
|
-
<label v-for="opt in field.options" :key="opt.value" class="flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
|
70
|
-
<input
|
|
71
|
-
type="checkbox"
|
|
72
|
-
class="h-4 w-4 rounded border-primary text-primary focus:ring-primary"
|
|
73
|
-
:disabled="field.disabled"
|
|
74
|
-
:checked="Array.isArray(modelValue) && modelValue.includes(opt.value)"
|
|
75
|
-
@change="(e: any) => handleCheckboxChange(opt.value, e.target.checked)"
|
|
76
|
-
/>
|
|
77
|
-
<span>{{ opt.label }}</span>
|
|
78
|
-
</label>
|
|
79
|
-
</div>
|
|
80
|
-
</template>
|
|
81
|
-
|
|
82
|
-
<template v-else-if="field.type === 'radio'">
|
|
83
|
-
<div class="flex flex-wrap gap-4">
|
|
84
|
-
<label v-for="opt in field.options" :key="opt.value" class="flex items-center space-x-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
|
85
|
-
<input
|
|
86
|
-
type="radio"
|
|
87
|
-
class="h-4 w-4 border-primary text-primary focus:ring-primary"
|
|
88
|
-
:disabled="field.disabled"
|
|
89
|
-
:name="field.name"
|
|
90
|
-
:checked="modelValue === opt.value"
|
|
91
|
-
@change="handleUpdate(opt.value)"
|
|
92
|
-
/>
|
|
93
|
-
<span>{{ opt.label }}</span>
|
|
94
|
-
</label>
|
|
95
|
-
</div>
|
|
96
|
-
</template>
|
|
52
|
+
</Label>
|
|
97
53
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
:value="modelValue"
|
|
107
|
-
@input="(e: any) => handleUpdate(e.target.value)"
|
|
108
|
-
/>
|
|
109
|
-
</template>
|
|
54
|
+
<!-- All field rendering is delegated to the resolved component -->
|
|
55
|
+
<component
|
|
56
|
+
:is="ResolvedFieldComponent"
|
|
57
|
+
:field="field"
|
|
58
|
+
:fieldId="fieldId"
|
|
59
|
+
:modelValue="modelValue"
|
|
60
|
+
@update:modelValue="emit('update:modelValue', $event)"
|
|
61
|
+
/>
|
|
110
62
|
|
|
111
|
-
<p v-if="field.description" class="text-
|
|
112
|
-
|
|
63
|
+
<p v-if="field.description" class="text-[0.8rem] text-muted-foreground">
|
|
64
|
+
{{ field.description }}
|
|
65
|
+
</p>
|
|
66
|
+
<p v-if="error" class="text-[0.8rem] font-medium text-destructive">
|
|
67
|
+
{{ error }}
|
|
68
|
+
</p>
|
|
113
69
|
</div>
|
|
114
70
|
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { CheckboxIndicator, CheckboxRoot, type CheckboxRootEmits, type CheckboxRootProps, useForwardPropsEmits } from 'radix-vue'
|
|
4
|
+
import { Check } from 'lucide-vue-next'
|
|
5
|
+
import { cn } from '../utils'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<CheckboxRootProps & { class?: any }>()
|
|
8
|
+
const emits = defineEmits<CheckboxRootEmits & { blur: [] }>()
|
|
9
|
+
|
|
10
|
+
const delegatedProps = computed(() => {
|
|
11
|
+
const { class: _, ...delegated } = props
|
|
12
|
+
return delegated
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<CheckboxRoot
|
|
20
|
+
v-bind="forwarded"
|
|
21
|
+
:class="cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground', props.class)"
|
|
22
|
+
@blur="emits('blur')"
|
|
23
|
+
>
|
|
24
|
+
<CheckboxIndicator class="flex h-full w-full items-center justify-center text-current">
|
|
25
|
+
<Check class="h-4 w-4" />
|
|
26
|
+
</CheckboxIndicator>
|
|
27
|
+
</CheckboxRoot>
|
|
28
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FieldRendererProps } from '../fieldComponentMap';
|
|
3
|
+
import Checkbox from '../components/Checkbox.vue';
|
|
4
|
+
import Label from '../components/Label.vue';
|
|
5
|
+
|
|
6
|
+
const props = defineProps<FieldRendererProps>();
|
|
7
|
+
const emit = defineEmits<{ 'update:modelValue': [value: any] }>();
|
|
8
|
+
|
|
9
|
+
const handleChange = (optValue: any, checked: boolean) => {
|
|
10
|
+
const current = Array.isArray(props.modelValue) ? [...props.modelValue] : [];
|
|
11
|
+
if (checked) {
|
|
12
|
+
current.push(optValue);
|
|
13
|
+
} else {
|
|
14
|
+
const idx = current.indexOf(optValue);
|
|
15
|
+
if (idx > -1) current.splice(idx, 1);
|
|
16
|
+
}
|
|
17
|
+
emit('update:modelValue', current);
|
|
18
|
+
};
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div class="flex flex-wrap gap-4">
|
|
23
|
+
<div v-for="opt in field.options" :key="opt.value" class="flex items-center space-x-2">
|
|
24
|
+
<Checkbox
|
|
25
|
+
:id="`checkbox-${field.name}-${opt.value}`"
|
|
26
|
+
:disabled="field.disabled"
|
|
27
|
+
:checked="Array.isArray(modelValue) && modelValue.includes(opt.value)"
|
|
28
|
+
@update:checked="(checked) => handleChange(opt.value, !!checked)"
|
|
29
|
+
/>
|
|
30
|
+
<Label :for="`checkbox-${field.name}-${opt.value}`" class="font-normal">
|
|
31
|
+
{{ opt.label }}
|
|
32
|
+
</Label>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { cn } from '../utils'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
class?: any
|
|
6
|
+
type?: string
|
|
7
|
+
modelValue?: any
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
const emit = defineEmits(['update:modelValue', 'blur'])
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<input
|
|
15
|
+
:type="type"
|
|
16
|
+
:class="cn('flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', props.class)"
|
|
17
|
+
:value="modelValue"
|
|
18
|
+
@input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
|
|
19
|
+
@blur="emit('blur', $event)"
|
|
20
|
+
/>
|
|
21
|
+
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FieldRendererProps } from '../fieldComponentMap';
|
|
3
|
+
import Input from '../components/Input.vue';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<FieldRendererProps>();
|
|
6
|
+
const emit = defineEmits<{ 'update:modelValue': [value: any] }>();
|
|
7
|
+
|
|
8
|
+
const handleInput = (nextValue: any) => {
|
|
9
|
+
if (props.field.type !== 'number') {
|
|
10
|
+
emit('update:modelValue', nextValue);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
emit('update:modelValue', nextValue === '' ? '' : Number(nextValue));
|
|
15
|
+
};
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<Input
|
|
20
|
+
:id="fieldId"
|
|
21
|
+
:type="field.type"
|
|
22
|
+
:placeholder="field.placeholder"
|
|
23
|
+
:disabled="field.disabled"
|
|
24
|
+
:name="field.name"
|
|
25
|
+
:modelValue="modelValue ?? ''"
|
|
26
|
+
@update:modelValue="handleInput"
|
|
27
|
+
/>
|
|
28
|
+
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { Label, type LabelProps } from 'radix-vue'
|
|
4
|
+
import { cn } from '../utils'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<LabelProps & { class?: any }>()
|
|
7
|
+
|
|
8
|
+
const delegatedProps = computed(() => {
|
|
9
|
+
const { class: _, ...delegated } = props
|
|
10
|
+
return delegated
|
|
11
|
+
})
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<Label
|
|
16
|
+
v-bind="delegatedProps"
|
|
17
|
+
:class="cn('text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', props.class)"
|
|
18
|
+
>
|
|
19
|
+
<slot />
|
|
20
|
+
</Label>
|
|
21
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { RadioGroupItem, type RadioGroupItemProps, RadioGroupRoot, type RadioGroupRootEmits, type RadioGroupRootProps, useForwardPropsEmits } from 'radix-vue'
|
|
4
|
+
import { Circle } from 'lucide-vue-next'
|
|
5
|
+
import { cn } from '../utils'
|
|
6
|
+
|
|
7
|
+
// Root
|
|
8
|
+
const props = defineProps<RadioGroupRootProps & { class?: any }>()
|
|
9
|
+
const emits = defineEmits<RadioGroupRootEmits>()
|
|
10
|
+
|
|
11
|
+
const delegatedProps = computed(() => {
|
|
12
|
+
const { class: _, ...delegated } = props
|
|
13
|
+
return delegated
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
export { default as RadioGroupItem } from './RadioGroupItem.vue'
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<RadioGroupRoot
|
|
25
|
+
v-bind="forwarded"
|
|
26
|
+
:class="cn('grid gap-2', props.class)"
|
|
27
|
+
>
|
|
28
|
+
<slot />
|
|
29
|
+
</RadioGroupRoot>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { RadioGroupIndicator, RadioGroupItem, type RadioGroupItemProps, useForwardProps } from 'radix-vue'
|
|
4
|
+
import { Circle } from 'lucide-vue-next'
|
|
5
|
+
import { cn } from '../utils'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<RadioGroupItemProps & { class?: any }>()
|
|
8
|
+
|
|
9
|
+
const delegatedProps = computed(() => {
|
|
10
|
+
const { class: _, ...delegated } = props
|
|
11
|
+
return delegated
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<RadioGroupItem
|
|
19
|
+
v-bind="forwardedProps"
|
|
20
|
+
:class="cn('aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', props.class)"
|
|
21
|
+
>
|
|
22
|
+
<RadioGroupIndicator class="flex items-center justify-center">
|
|
23
|
+
<Circle class="h-2.5 w-2.5 fill-current text-current" />
|
|
24
|
+
</RadioGroupIndicator>
|
|
25
|
+
</RadioGroupItem>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FieldRendererProps } from '../fieldComponentMap';
|
|
3
|
+
import RadioGroup from '../components/RadioGroup.vue';
|
|
4
|
+
import RadioGroupItem from '../components/RadioGroupItem.vue';
|
|
5
|
+
import Label from '../components/Label.vue';
|
|
6
|
+
|
|
7
|
+
const props = defineProps<FieldRendererProps>();
|
|
8
|
+
const emit = defineEmits<{ 'update:modelValue': [value: any] }>();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<RadioGroup
|
|
13
|
+
class="flex flex-wrap gap-4"
|
|
14
|
+
:disabled="field.disabled"
|
|
15
|
+
:name="field.name"
|
|
16
|
+
:modelValue="modelValue != null ? String(modelValue) : ''"
|
|
17
|
+
@update:modelValue="emit('update:modelValue', $event)"
|
|
18
|
+
>
|
|
19
|
+
<div v-for="opt in field.options" :key="opt.value" class="flex items-center space-x-2">
|
|
20
|
+
<RadioGroupItem :id="`radio-${field.name}-${opt.value}`" :value="String(opt.value)" />
|
|
21
|
+
<Label :for="`radio-${field.name}-${opt.value}`" class="font-normal">{{ opt.label }}</Label>
|
|
22
|
+
</div>
|
|
23
|
+
</RadioGroup>
|
|
24
|
+
</template>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import {
|
|
4
|
+
SelectContent,
|
|
5
|
+
SelectGroup,
|
|
6
|
+
SelectItem,
|
|
7
|
+
SelectItemIndicator,
|
|
8
|
+
SelectItemText,
|
|
9
|
+
SelectPortal,
|
|
10
|
+
SelectRoot,
|
|
11
|
+
type SelectRootEmits,
|
|
12
|
+
type SelectRootProps,
|
|
13
|
+
SelectScrollDownButton,
|
|
14
|
+
SelectScrollUpButton,
|
|
15
|
+
SelectTrigger,
|
|
16
|
+
SelectValue,
|
|
17
|
+
SelectViewport,
|
|
18
|
+
useForwardPropsEmits,
|
|
19
|
+
} from 'radix-vue'
|
|
20
|
+
import { Check, ChevronDown, ChevronUp } from 'lucide-vue-next'
|
|
21
|
+
import { cn } from '../utils'
|
|
22
|
+
|
|
23
|
+
const props = defineProps<SelectRootProps>()
|
|
24
|
+
const emits = defineEmits<SelectRootEmits>()
|
|
25
|
+
|
|
26
|
+
const forwarded = useForwardPropsEmits(props, emits)
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<script lang="ts">
|
|
30
|
+
export { default as SelectTrigger } from './SelectTrigger.vue'
|
|
31
|
+
export { default as SelectContent } from './SelectContent.vue'
|
|
32
|
+
export { default as SelectItem } from './SelectItem.vue'
|
|
33
|
+
export { SelectValue, SelectGroup } from 'radix-vue'
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<SelectRoot v-bind="forwarded">
|
|
38
|
+
<slot />
|
|
39
|
+
</SelectRoot>
|
|
40
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import {
|
|
4
|
+
SelectContent,
|
|
5
|
+
type SelectContentProps,
|
|
6
|
+
SelectPortal,
|
|
7
|
+
SelectViewport,
|
|
8
|
+
useForwardProps,
|
|
9
|
+
} from 'radix-vue'
|
|
10
|
+
import { cn } from '../utils'
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(
|
|
13
|
+
defineProps<SelectContentProps & { class?: any }>(),
|
|
14
|
+
{
|
|
15
|
+
position: 'popper',
|
|
16
|
+
},
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
const delegatedProps = computed(() => {
|
|
20
|
+
const { class: _, ...delegated } = props
|
|
21
|
+
return delegated
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<SelectPortal>
|
|
29
|
+
<SelectContent
|
|
30
|
+
v-bind="forwardedProps"
|
|
31
|
+
:class="cn('relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', position === 'popper' && 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', props.class)"
|
|
32
|
+
>
|
|
33
|
+
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]')">
|
|
34
|
+
<slot />
|
|
35
|
+
</SelectViewport>
|
|
36
|
+
</SelectContent>
|
|
37
|
+
</SelectPortal>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import {
|
|
4
|
+
SelectItem,
|
|
5
|
+
SelectItemIndicator,
|
|
6
|
+
type SelectItemProps,
|
|
7
|
+
SelectItemText,
|
|
8
|
+
useForwardProps,
|
|
9
|
+
} from 'radix-vue'
|
|
10
|
+
import { Check } from 'lucide-vue-next'
|
|
11
|
+
import { cn } from '../utils'
|
|
12
|
+
|
|
13
|
+
const props = defineProps<SelectItemProps & { class?: any }>()
|
|
14
|
+
|
|
15
|
+
const delegatedProps = computed(() => {
|
|
16
|
+
const { class: _, ...delegated } = props
|
|
17
|
+
return delegated
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<SelectItem
|
|
25
|
+
v-bind="forwardedProps"
|
|
26
|
+
:class="
|
|
27
|
+
cn(
|
|
28
|
+
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
29
|
+
props.class,
|
|
30
|
+
)
|
|
31
|
+
"
|
|
32
|
+
>
|
|
33
|
+
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
34
|
+
<SelectItemIndicator>
|
|
35
|
+
<Check class="h-4 w-4" />
|
|
36
|
+
</SelectItemIndicator>
|
|
37
|
+
</span>
|
|
38
|
+
|
|
39
|
+
<SelectItemText>
|
|
40
|
+
<slot />
|
|
41
|
+
</SelectItemText>
|
|
42
|
+
</SelectItem>
|
|
43
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FieldRendererProps } from '../fieldComponentMap';
|
|
3
|
+
import Select from '../components/Select.vue';
|
|
4
|
+
import SelectTrigger from '../components/SelectTrigger.vue';
|
|
5
|
+
import SelectContent from '../components/SelectContent.vue';
|
|
6
|
+
import SelectItem from '../components/SelectItem.vue';
|
|
7
|
+
import { SelectValue } from 'radix-vue';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const props = defineProps<FieldRendererProps>();
|
|
11
|
+
const emit = defineEmits<{ 'update:modelValue': [value: any] }>();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<Select
|
|
16
|
+
:disabled="field.disabled"
|
|
17
|
+
:name="field.name"
|
|
18
|
+
:modelValue="modelValue != null ? String(modelValue) : ''"
|
|
19
|
+
@update:modelValue="emit('update:modelValue', $event)"
|
|
20
|
+
>
|
|
21
|
+
<SelectTrigger :id="fieldId">
|
|
22
|
+
<SelectValue :placeholder="field.placeholder || 'Select an option'" />
|
|
23
|
+
</SelectTrigger>
|
|
24
|
+
<SelectContent>
|
|
25
|
+
<SelectItem v-for="opt in field.options" :key="opt.value" :value="String(opt.value)">
|
|
26
|
+
{{ opt.label }}
|
|
27
|
+
</SelectItem>
|
|
28
|
+
</SelectContent>
|
|
29
|
+
</Select>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue'
|
|
3
|
+
import { ChevronDown } from 'lucide-vue-next'
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
import { cn } from '../utils'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<SelectTriggerProps & { class?: any }>()
|
|
8
|
+
|
|
9
|
+
const delegatedProps = computed(() => {
|
|
10
|
+
const { class: _, ...delegated } = props
|
|
11
|
+
return delegated
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<SelectTrigger
|
|
19
|
+
v-bind="forwardedProps"
|
|
20
|
+
:class="cn('flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', props.class)"
|
|
21
|
+
>
|
|
22
|
+
<slot />
|
|
23
|
+
<SelectIcon as-child>
|
|
24
|
+
<ChevronDown class="h-4 w-4 opacity-50" />
|
|
25
|
+
</SelectIcon>
|
|
26
|
+
</SelectTrigger>
|
|
27
|
+
</template>
|