├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── build.config.ts
├── components.d.ts
├── dev
├── App.scss
├── App.vue
├── assets
│ ├── favicon.ico
│ ├── fonts
│ │ ├── Inter-italic.var.woff2
│ │ └── Inter-roman.var.woff2
│ └── logo.png
├── auto-import.d.ts
├── components.d.ts
├── components
│ ├── app
│ │ ├── AppFooter.vue
│ │ └── AppTopbar.vue
│ └── demo
│ │ ├── PrimeData.vue
│ │ ├── PrimeInput.vue
│ │ ├── PrimeOutput.vue
│ │ └── PrimeSchemaEditor.vue
├── composables
│ └── messages.ts
├── dev
│ └── components.d.ts
├── env.d.ts
├── index.html
├── locales
│ ├── de.json
│ └── en.json
├── main.ts
├── modules
│ ├── formkit.ts
│ ├── i18n.ts
│ └── primevue.ts
├── pages
│ ├── data
│ │ ├── Edit.vue
│ │ ├── Slots.vue
│ │ ├── View.vue
│ │ └── WithoutSchema.vue
│ ├── index.vue
│ ├── inputs
│ │ ├── AutoComplete.vue
│ │ ├── CascadeSelect.vue
│ │ ├── Checkbox.vue
│ │ ├── ColorPicker.vue
│ │ ├── DatePicker.vue
│ │ ├── Editor.vue
│ │ ├── InputMask.vue
│ │ ├── InputNumber.vue
│ │ ├── InputOtp.vue
│ │ ├── InputText.vue
│ │ ├── Knob.vue
│ │ ├── Listbox.vue
│ │ ├── MultiSelect.vue
│ │ ├── Password.vue
│ │ ├── RadioButton.vue
│ │ ├── Rating.vue
│ │ ├── Select.vue
│ │ ├── SelectButton.vue
│ │ ├── Slider.vue
│ │ ├── Textarea.vue
│ │ ├── ToggleButton.vue
│ │ ├── ToggleSwitch.vue
│ │ └── TreeSelect.vue
│ ├── outputs
│ │ ├── OutputBoolean.vue
│ │ ├── OutputDate.vue
│ │ ├── OutputDuration.vue
│ │ ├── OutputLink.vue
│ │ ├── OutputList.vue
│ │ ├── OutputNumber.vue
│ │ ├── OutputReference.vue
│ │ └── OutputText.vue
│ ├── samples
│ │ ├── FormEditor.vue
│ │ ├── InputEditor.vue
│ │ ├── MultiStep.vue
│ │ └── Repeater.vue
│ └── styling
│ │ ├── Base.vue
│ │ ├── Class.vue
│ │ ├── Grid.vue
│ │ ├── Horizontal.vue
│ │ └── PassThrough.vue
├── tsconfig.json
├── types.ts
├── uno.config.ts
├── utils
│ └── presets.ts
└── vite.config.ts
├── docs
├── .vitepress
│ ├── config.mts
│ └── theme
│ │ ├── components
│ │ ├── DisplayComponents.vue
│ │ ├── DisplayFormComponents.vue
│ │ ├── DisplayOutputComponents.vue
│ │ └── Todo.vue
│ │ └── index.ts
├── advanced
│ ├── composables.md
│ ├── index.md
│ ├── nuxt.md
│ ├── plugins.md
│ └── schema.md
├── guide
│ ├── examples.md
│ ├── form.md
│ ├── getting-started.md
│ ├── history.md
│ ├── index.md
│ ├── inputs.md
│ ├── options.md
│ ├── outputs.md
│ ├── prefix.md
│ ├── styling.md
│ └── usage.md
├── index.md
└── uno.config.ts
├── env.d.ts
├── eslint.config.js
├── formkit-primevue.png
├── netlify.toml
├── package.json
├── pnpm-lock.yaml
├── primevue-formkit.iml
├── src
├── components
│ ├── FormKitDataEdit.vue
│ ├── FormKitDataView.vue
│ ├── FormKitDebug.vue
│ ├── PrimeAutoComplete.vue
│ ├── PrimeCascadeSelect.vue
│ ├── PrimeCheckbox.vue
│ ├── PrimeColorPicker.vue
│ ├── PrimeDatePicker.vue
│ ├── PrimeEditor.vue
│ ├── PrimeInputMask.vue
│ ├── PrimeInputNumber.vue
│ ├── PrimeInputOtp.vue
│ ├── PrimeInputText.vue
│ ├── PrimeKnob.vue
│ ├── PrimeListbox.vue
│ ├── PrimeMultiSelect.vue
│ ├── PrimeOutputBoolean.vue
│ ├── PrimeOutputDate.vue
│ ├── PrimeOutputDuration.vue
│ ├── PrimeOutputLink.vue
│ ├── PrimeOutputList.vue
│ ├── PrimeOutputNumber.vue
│ ├── PrimeOutputReference.vue
│ ├── PrimeOutputText.vue
│ ├── PrimePassword.vue
│ ├── PrimeRadioButton.vue
│ ├── PrimeRating.vue
│ ├── PrimeSelect.vue
│ ├── PrimeSelectButton.vue
│ ├── PrimeSlider.vue
│ ├── PrimeTextarea.vue
│ ├── PrimeToggleButton.vue
│ ├── PrimeToggleSwitch.vue
│ ├── PrimeTreeSelect.vue
│ └── index.ts
├── composables
│ ├── index.ts
│ ├── useFormKitInput.ts
│ ├── useFormKitRepeater.ts
│ ├── useFormKitSchema.ts
│ ├── useFormKitSection.ts
│ ├── useInputEditor.ts
│ ├── useInputEditorSchema.ts
│ ├── useOutputDuration.ts
│ └── usePrimeInputs.ts
├── definitions
│ ├── index.ts
│ ├── input.ts
│ └── output.ts
├── index.ts
├── plugins
│ └── index.ts
└── sass
│ └── formkit-primevue.scss
├── test
├── useFormKitInput.test.ts
├── useFormKitSchema.test.ts
├── useFormKitSection.test.ts
└── useOutputDuration.test.ts
├── tsconfig.json
└── vite.config.ts
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy
2 |
3 | on:
4 | push:
5 |
6 | jobs:
7 | deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 | - uses: pnpm/action-setup@v4
12 | - uses: actions/setup-node@v4
13 | with:
14 | node-version: lts/*
15 | cache: pnpm
16 |
17 | - name: Install dependencies
18 | run: pnpm install
19 |
20 | - run: pnpm build
21 |
22 | - run: pnpm docs:build
23 |
24 | - name: Deploy
25 | uses: peaceiris/actions-gh-pages@v4
26 | with:
27 | github_token: ${{ secrets.GITHUB_TOKEN }}
28 | publish_dir: docs/.vitepress/dist
29 | # cname: example.com # if wanna deploy to custom domain
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 | coverage
15 |
16 | # Editor directories and files
17 | .vscode/*
18 | !.vscode/extensions.json
19 | .idea
20 | .DS_Store
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 | *.iml
27 | *.tsbuildinfo
28 |
29 | .gitconfig
30 |
31 | # vitepress
32 | docs/.vitepress/cache
33 | docs/.vitepress/dist
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 sfxcode
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/build.config.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs-extra'
2 | import sass from 'sass'
3 | import { defineBuildConfig } from 'unbuild'
4 |
5 | export default defineBuildConfig({
6 | entries: [
7 | { builder: 'mkdist', input: './src', pattern: ['**/*.vue'], loaders: ['vue'] },
8 | { builder: 'mkdist', input: './src', pattern: ['**/*.ts'], format: 'cjs', loaders: ['js'] },
9 | { builder: 'mkdist', input: './src', pattern: ['**/*.ts'], format: 'esm', loaders: ['js'] },
10 | ],
11 | hooks: {
12 | 'mkdist:done': () => {
13 | const compiledSass = sass.compile('./src/sass/formkit-primevue.scss', { style: 'compressed', loadPaths: ['./node_modules/'] })
14 |
15 | fs.writeFileSync(
16 | 'dist/style.css',
17 | compiledSass.css,
18 | { encoding: 'utf-8' },
19 | )
20 |
21 | fs.mkdirSync('dist/sass')
22 | fs.copyFileSync(
23 | 'src/sass/formkit-primevue.scss',
24 | 'dist/sass/formkit-primevue.scss',
25 |
26 | )
27 | },
28 | },
29 | declaration: true,
30 | clean: true,
31 | })
32 |
--------------------------------------------------------------------------------
/components.d.ts:
--------------------------------------------------------------------------------
1 | export * from './dist/components'
2 |
--------------------------------------------------------------------------------
/dev/App.scss:
--------------------------------------------------------------------------------
1 | @use "../src/sass/formkit-primevue";
2 |
3 | :root {
4 | font-family: "Inter var", sans-serif;
5 | font-feature-settings: "cv02", "cv03", "cv04", "cv11";
6 | font-variation-settings: normal;
7 | --font-family: "Inter var", sans-serif;
8 | --font-feature-settings: "cv02", "cv03", "cv04", "cv11";
9 | }
10 |
11 | :root {
12 | --multistep-color-border: var(--p-primary-color);
13 | --multistep-color-tab: var(--p-primary-active-color);
14 | --multistep-color-tab-active: var(--p-primary-color);
15 | --multistep-color-success: #2b7a60;
16 | --multistep-color-danger: #ef9a9a;
17 | --multistep-color-tab-active-text: var(--p-button-primary-color);
18 | --multistep-color-tab-text: var(--p-button-primary-color);
19 | --multistep-radius: 0.4em;
20 | --multistep-shadow: 0.25em 0.25em 1em 0 rgb(0 0 0 / 10%);
21 | }
22 |
23 | html {
24 | height: 100%;
25 | font-size: 16px;
26 | }
27 |
28 | a {
29 | text-decoration: none;
30 | color: var(--p-primary-color);
31 | }
32 |
33 | .formkit-step-actions {
34 | button {
35 | display: inline-flex;
36 | cursor: pointer;
37 | user-select: none;
38 | align-items: center;
39 | justify-content: center;
40 | overflow: hidden;
41 | position: relative;
42 | color: var(--p-button-primary-color);
43 | background: var(--p-button-primary-background);
44 | border: 1px solid var(--p-button-primary-border-color);
45 | padding: var(--p-button-padding-y) var(--p-button-padding-x);
46 | font-size: 1rem;
47 | font-family: inherit;
48 | font-feature-settings: inherit;
49 | transition: background var(--p-button-transition-duration), color var(--p-button-transition-duration), border-color var(--p-button-transition-duration), outline-color var(--p-button-transition-duration), box-shadow var(--p-button-transition-duration);
50 | border-radius: var(--p-button-border-radius);
51 | outline-color: transparent;
52 | gap: var(--p-button-gap);
53 | }
54 | }
55 |
56 |
57 |
--------------------------------------------------------------------------------
/dev/App.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
--------------------------------------------------------------------------------
/dev/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sfxcode/formkit-primevue/9e49e70fd4c5e0a9ba1ca3250d58cb52cec008cd/dev/assets/favicon.ico
--------------------------------------------------------------------------------
/dev/assets/fonts/Inter-italic.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sfxcode/formkit-primevue/9e49e70fd4c5e0a9ba1ca3250d58cb52cec008cd/dev/assets/fonts/Inter-italic.var.woff2
--------------------------------------------------------------------------------
/dev/assets/fonts/Inter-roman.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sfxcode/formkit-primevue/9e49e70fd4c5e0a9ba1ca3250d58cb52cec008cd/dev/assets/fonts/Inter-roman.var.woff2
--------------------------------------------------------------------------------
/dev/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sfxcode/formkit-primevue/9e49e70fd4c5e0a9ba1ca3250d58cb52cec008cd/dev/assets/logo.png
--------------------------------------------------------------------------------
/dev/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // @ts-nocheck
3 | // Generated by unplugin-vue-components
4 | // Read more: https://github.com/vuejs/core/pull/3399
5 | // biome-ignore lint: disable
6 | export {}
7 |
8 | /* prettier-ignore */
9 | declare module 'vue' {
10 | export interface GlobalComponents {
11 | AppFooter: typeof import('./components/app/AppFooter.vue')['default']
12 | AppTopbar: typeof import('./components/app/AppTopbar.vue')['default']
13 | PrimeData: typeof import('./components/demo/PrimeData.vue')['default']
14 | PrimeInput: typeof import('./components/demo/PrimeInput.vue')['default']
15 | PrimeOutput: typeof import('./components/demo/PrimeOutput.vue')['default']
16 | PrimeSchemaEditor: typeof import('./components/demo/PrimeSchemaEditor.vue')['default']
17 | RouterLink: typeof import('vue-router')['RouterLink']
18 | RouterView: typeof import('vue-router')['RouterView']
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/dev/components/app/AppFooter.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
9 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/dev/components/demo/PrimeData.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 | {{ header }}
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/dev/components/demo/PrimeSchemaEditor.vue:
--------------------------------------------------------------------------------
1 |
51 |
52 |
53 |
54 |
55 | {{ header }}
56 |
57 |
58 |
59 |
60 |
Create Formkit Input
61 |
70 |
71 |
72 |
{{ formSchema }}
73 |
74 |
75 |
Generated Formkit Input Preview
76 |
77 | Some changes require to trigger the update of generated input
78 |
79 |
80 |
81 |
89 |
90 |
91 |
92 |
Generated Formkit Schema
93 |
{{ schemaResult }}
94 |
95 |
96 |
Generated Formkit Data
97 |
{{ data }}
98 |
99 |
100 |
101 |
102 |
103 |
104 |
107 |
--------------------------------------------------------------------------------
/dev/composables/messages.ts:
--------------------------------------------------------------------------------
1 | import type { ToastMessageOptions } from 'primevue/toast'
2 | import { useToast } from 'primevue/usetoast'
3 |
4 | export enum MessageSeverity {
5 | SUCCESS = 'success',
6 | INFO = 'info',
7 | WARN = 'warn',
8 | ERROR = 'error',
9 | }
10 |
11 | export function useMessages() {
12 | const toast = useToast()
13 |
14 | function showMessage(severity: ToastMessageOptions['severity'], summary: string, detail: string, life: number = 3000) {
15 | toast.add({ severity, summary, detail, life })
16 | }
17 |
18 | function showSuccessMessage(summary: string, detail: string = summary, life: number = 3000) {
19 | showMessage(MessageSeverity.SUCCESS, summary, detail, life)
20 | }
21 |
22 | function showInfoMessage(summary: string, detail: string = summary, life: number = 3000) {
23 | showMessage(MessageSeverity.INFO, summary, detail, life)
24 | }
25 |
26 | function showWarnMessage(summary: string, detail: string = summary, life: number = 3000) {
27 | showMessage(MessageSeverity.WARN, summary, detail, life)
28 | }
29 |
30 | function showErrorMessage(summary: string, detail: string = summary, life: number = 3000) {
31 | showMessage(MessageSeverity.ERROR, summary, detail, life)
32 | }
33 |
34 | return { showSuccessMessage, showInfoMessage, showWarnMessage, showErrorMessage }
35 | }
36 |
--------------------------------------------------------------------------------
/dev/dev/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // Generated by unplugin-vue-components
5 | // Read more: https://github.com/vuejs/core/pull/3399
6 | export {}
7 |
8 | declare module 'vue' {
9 | export interface GlobalComponents {
10 | RouterLink: typeof import('vue-router')['RouterLink']
11 | RouterView: typeof import('vue-router')['RouterView']
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/dev/env.d.ts:
--------------------------------------------------------------------------------
1 | interface ImportMetaEnv {
2 | VITE_APP_VERSION: string
3 | VITE_APP_BUILD_EPOCH: number
4 | }
5 |
--------------------------------------------------------------------------------
/dev/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/dev/locales/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "welcome": "Willkommen",
3 | "sample": "Hallo Welt",
4 | "save": "Speichern",
5 | "search": "Suchen",
6 | "formkit": {
7 | "prime": {
8 | "true": "Ja",
9 | "false": "Nein"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/dev/locales/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "welcome": "Welcome",
3 | "sample": "Hello World",
4 | "save": "Save",
5 | "search": "Search",
6 | "formkit": {
7 | "prime": {
8 | "true": "Yes",
9 | "false": "No"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/dev/main.ts:
--------------------------------------------------------------------------------
1 | // register vue composition api globally
2 | import type { UserModule } from '@/types'
3 | import generatedRoutes from 'virtual:generated-pages'
4 | import { ViteSSG } from 'vite-ssg'
5 | import App from './App.vue'
6 | import 'uno.css'
7 |
8 | const routes = generatedRoutes
9 |
10 | export const createApp = ViteSSG(
11 | App,
12 | { routes },
13 | (ctx) => {
14 | // install all modules under `modules/`
15 | Object.values(import.meta.glob<{ install: UserModule }>('./modules/*.ts', { eager: true }))
16 | .forEach(i => i.install?.(ctx))
17 | },
18 |
19 | )
20 |
--------------------------------------------------------------------------------
/dev/modules/formkit.ts:
--------------------------------------------------------------------------------
1 | import type { UserModule } from '@/types'
2 | import { createAutoAnimatePlugin, createMultiStepPlugin } from '@formkit/addons'
3 | import { de, en } from '@formkit/i18n'
4 |
5 | import { defaultConfig, plugin } from '@formkit/vue'
6 | import { primeInputs, primeOutputs } from 'my-library/definitions'
7 | import { addPrimeAsteriskPlugin } from 'my-library/plugins'
8 | import '@formkit/addons/css/multistep'
9 |
10 | export const install: UserModule = ({ app }) => {
11 | app.use(plugin, defaultConfig({
12 | locales: { de, en },
13 | // Define the active locale
14 | locale: 'en',
15 | inputs: { ...primeInputs, ...primeOutputs },
16 | plugins: [
17 | createAutoAnimatePlugin(
18 | {
19 | /* optional AutoAnimate config */
20 | // default:
21 | duration: 250,
22 | easing: 'ease-in-out',
23 | },
24 | {
25 | /* optional animation targets object */
26 | // default:
27 | global: ['outer', 'inner'],
28 | form: ['form'],
29 | repeater: ['items'],
30 | },
31 | ),
32 | addPrimeAsteriskPlugin,
33 | createMultiStepPlugin(),
34 | ],
35 | }))
36 | }
37 |
--------------------------------------------------------------------------------
/dev/modules/i18n.ts:
--------------------------------------------------------------------------------
1 | import type { UserModule } from '@/types'
2 | import { createI18n } from 'vue-i18n'
3 | import en from '@/locales/en.json'
4 |
5 | export const install: UserModule = ({ app }) => {
6 | const i18n = createI18n({
7 | locale: 'en',
8 | legacy: false, // you must set `false`, to use Composition API
9 | messages: {
10 | en,
11 | },
12 | numberFormats: {
13 | en: {
14 | decimal: {
15 | style: 'decimal',
16 | minimumFractionDigits: 2,
17 | maximumFractionDigits: 2,
18 | },
19 | short: {
20 | style: 'decimal',
21 | minimumFractionDigits: 0,
22 | maximumFractionDigits: 0,
23 | },
24 | percent: {
25 | style: 'percent',
26 | minimumFractionDigits: 2,
27 | useGrouping: false,
28 | },
29 | currency: {
30 | style: 'currency',
31 | minimumFractionDigits: 2,
32 | maximumFractionDigits: 2,
33 | currency: 'USD',
34 | },
35 | },
36 | de: {
37 | decimal: {
38 | style: 'decimal',
39 | minimumFractionDigits: 2,
40 | maximumFractionDigits: 2,
41 | },
42 | short: {
43 | style: 'decimal',
44 | minimumFractionDigits: 0,
45 | maximumFractionDigits: 0,
46 | },
47 | percent: {
48 | style: 'percent',
49 | minimumFractionDigits: 2,
50 | useGrouping: false,
51 | },
52 | currency: {
53 | style: 'currency',
54 | minimumFractionDigits: 2,
55 | maximumFractionDigits: 2,
56 | currency: 'EUR',
57 | },
58 | },
59 | },
60 | datetimeFormats: {
61 | en: {
62 | short: {
63 | year: 'numeric',
64 | month: '2-digit',
65 | day: '2-digit',
66 | },
67 | rangeYear: {
68 | year: 'numeric',
69 | },
70 | rangeMonth: {
71 | month: '2-digit',
72 | },
73 | rangeDay: {
74 | day: '2-digit',
75 | },
76 | long: {
77 | day: '2-digit',
78 | month: '2-digit',
79 | year: 'numeric',
80 | hour: '2-digit',
81 | minute: '2-digit',
82 | },
83 | },
84 | de: {
85 | short: {
86 | day: '2-digit',
87 | month: '2-digit',
88 | year: 'numeric',
89 | },
90 | long: {
91 | day: '2-digit',
92 | month: '2-digit',
93 | year: 'numeric',
94 | hour: '2-digit',
95 | minute: '2-digit',
96 | },
97 | rangeYear: {
98 | year: 'numeric',
99 | },
100 | rangeMonth: {
101 | month: '2-digit',
102 | },
103 | rangeDay: {
104 | day: '2-digit',
105 | },
106 | },
107 | },
108 | })
109 |
110 | app.use(i18n)
111 | }
112 |
--------------------------------------------------------------------------------
/dev/modules/primevue.ts:
--------------------------------------------------------------------------------
1 | import type { UserModule } from '@/types'
2 | import Aura from '@primeuix/themes/aura'
3 | import { usePrimeInputs } from 'my-library'
4 | import PrimeVue from 'primevue/config'
5 | import ConfirmationService from 'primevue/confirmationservice'
6 | import Editor from 'primevue/editor'
7 | import MegaMenu from 'primevue/megamenu'
8 |
9 | import Ripple from 'primevue/ripple'
10 | import Tab from 'primevue/tab'
11 | import TabList from 'primevue/tablist'
12 | import TabPanel from 'primevue/tabpanel'
13 | import TabPanels from 'primevue/tabpanels'
14 |
15 | import Tabs from 'primevue/tabs'
16 |
17 | import Toast from 'primevue/toast'
18 |
19 | // services
20 |
21 | import ToastService from 'primevue/toastservice'
22 | import Toolbar from 'primevue/toolbar'
23 | import Tooltip from 'primevue/tooltip'
24 | import 'primeicons/primeicons.css'
25 |
26 | export const install: UserModule = ({ app }) => {
27 | // directives
28 | app.directive('ripple', Ripple)
29 | app.directive('tooltip', Tooltip)
30 |
31 | // input components
32 | const { registerInputs } = usePrimeInputs()
33 | registerInputs(app)
34 |
35 | // other components
36 | app.component('MegaMenu', MegaMenu)
37 | app.component('Tab', Tab)
38 | app.component('Tabs', Tabs)
39 | app.component('TabList', TabList)
40 | app.component('TabPanels', TabPanels)
41 | app.component('TabPanel', TabPanel)
42 | app.component('Toast', Toast)
43 | app.component('Toolbar', Toolbar)
44 | app.component('Editor', Editor)
45 |
46 | app.use(PrimeVue, {
47 | theme: {
48 | preset: Aura,
49 | options: {
50 | darkModeSelector: '.p-dark',
51 | },
52 | },
53 | ripple: false,
54 | })
55 |
56 | // services
57 | app.use(ConfirmationService)
58 | app.use(ToastService)
59 | }
60 |
--------------------------------------------------------------------------------
/dev/pages/data/Slots.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
32 |
33 |
34 |
Option: {{ slotProps.option.label }}
35 |
36 |
37 |
38 |
39 | Select Option:
40 |
41 |
42 |
43 |
44 | More Options to come soon ...
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
55 |
--------------------------------------------------------------------------------
/dev/pages/data/View.vue:
--------------------------------------------------------------------------------
1 |
52 |
53 |
54 |
55 |
56 |
57 | Horizontal
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/dev/pages/data/WithoutSchema.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
29 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
54 |
--------------------------------------------------------------------------------
/dev/pages/index.vue:
--------------------------------------------------------------------------------
1 |
78 |
79 |
80 |
85 |
86 |
--------------------------------------------------------------------------------
/dev/pages/inputs/AutoComplete.vue:
--------------------------------------------------------------------------------
1 |
46 |
47 |
48 |
54 |
55 |
56 |
59 |
--------------------------------------------------------------------------------
/dev/pages/inputs/CascadeSelect.vue:
--------------------------------------------------------------------------------
1 |
97 |
98 |
99 |
105 |
106 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Checkbox.vue:
--------------------------------------------------------------------------------
1 |
46 |
47 |
48 |
54 |
55 |
56 |
59 |
--------------------------------------------------------------------------------
/dev/pages/inputs/ColorPicker.vue:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 |
40 |
41 |
42 |
45 |
--------------------------------------------------------------------------------
/dev/pages/inputs/DatePicker.vue:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
57 |
58 |
59 |
62 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Editor.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
32 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/dev/pages/inputs/InputMask.vue:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 |
43 |
44 |
45 |
48 |
--------------------------------------------------------------------------------
/dev/pages/inputs/InputNumber.vue:
--------------------------------------------------------------------------------
1 |
60 |
61 |
62 |
68 |
69 |
70 |
73 |
--------------------------------------------------------------------------------
/dev/pages/inputs/InputOtp.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
32 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/dev/pages/inputs/InputText.vue:
--------------------------------------------------------------------------------
1 |
45 |
46 |
47 |
53 |
54 |
55 |
58 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Knob.vue:
--------------------------------------------------------------------------------
1 |
29 |
30 |
31 |
37 |
38 |
39 |
42 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Listbox.vue:
--------------------------------------------------------------------------------
1 |
56 |
57 |
58 |
64 |
65 |
--------------------------------------------------------------------------------
/dev/pages/inputs/MultiSelect.vue:
--------------------------------------------------------------------------------
1 |
53 |
54 |
55 |
61 |
62 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Password.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
33 |
34 |
35 |
38 |
--------------------------------------------------------------------------------
/dev/pages/inputs/RadioButton.vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
49 |
50 |
51 |
54 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Rating.vue:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 |
40 |
41 |
42 |
45 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Select.vue:
--------------------------------------------------------------------------------
1 |
79 |
80 |
81 |
87 |
88 |
89 |
92 |
--------------------------------------------------------------------------------
/dev/pages/inputs/SelectButton.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
51 |
52 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Slider.vue:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 |
40 |
41 |
42 |
45 |
--------------------------------------------------------------------------------
/dev/pages/inputs/Textarea.vue:
--------------------------------------------------------------------------------
1 |
39 |
40 |
41 |
47 |
48 |
49 |
52 |
--------------------------------------------------------------------------------
/dev/pages/inputs/ToggleButton.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
41 |
42 |
--------------------------------------------------------------------------------
/dev/pages/inputs/ToggleSwitch.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
51 |
52 |
53 |
56 |
--------------------------------------------------------------------------------
/dev/pages/inputs/TreeSelect.vue:
--------------------------------------------------------------------------------
1 |
59 |
60 |
61 |
67 |
68 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputBoolean.vue:
--------------------------------------------------------------------------------
1 |
55 |
56 |
57 |
63 |
64 |
65 |
68 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputDate.vue:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 |
40 |
41 |
42 |
45 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputDuration.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
35 |
36 |
37 |
40 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputLink.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
31 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputList.vue:
--------------------------------------------------------------------------------
1 |
67 |
68 |
69 |
75 |
76 |
77 |
82 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputNumber.vue:
--------------------------------------------------------------------------------
1 |
34 |
35 |
36 |
42 |
43 |
44 |
47 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputReference.vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
48 |
49 |
50 |
53 |
--------------------------------------------------------------------------------
/dev/pages/outputs/OutputText.vue:
--------------------------------------------------------------------------------
1 |
50 |
51 |
52 |
58 |
59 |
60 |
63 |
--------------------------------------------------------------------------------
/dev/pages/samples/InputEditor.vue:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
25 |
26 |
27 |
30 |
--------------------------------------------------------------------------------
/dev/pages/samples/MultiStep.vue:
--------------------------------------------------------------------------------
1 |
86 |
87 |
88 |
89 |
93 |
97 | Mode: {{ mode }}
98 |
99 |
100 |
101 |
102 |
105 |
--------------------------------------------------------------------------------
/dev/pages/samples/Repeater.vue:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
56 |
57 |
58 |
61 |
--------------------------------------------------------------------------------
/dev/pages/styling/Base.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
31 |
32 | Use Custom classes for better styling. To be specific you can use use the parent div class: p-formkit.
33 |
34 | Direct styling by the style attribute.
35 |
36 | In this demo elements with the p-formkit class use the parent width.
37 |
38 |
39 |
40 |
41 |
42 |
43 |
50 |
--------------------------------------------------------------------------------
/dev/pages/styling/Class.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
33 |
34 |
35 |
45 |
--------------------------------------------------------------------------------
/dev/pages/styling/Grid.vue:
--------------------------------------------------------------------------------
1 |
58 |
59 |
60 |
61 | Grid in Data Edit
62 |
63 | 12 Column Grid used
64 |
65 |
66 |
67 |
68 | Grid in Data View
69 |
70 |
71 |
72 |
73 |
74 |
75 |
78 |
--------------------------------------------------------------------------------
/dev/pages/styling/Horizontal.vue:
--------------------------------------------------------------------------------
1 |
72 |
73 |
74 |
79 |
80 |
--------------------------------------------------------------------------------
/dev/pages/styling/PassThrough.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
35 |
36 |
37 |
40 |
--------------------------------------------------------------------------------
/dev/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "paths": {
5 | "my-library": ["../src"]
6 | },
7 | "types": ["vite/client"]
8 | },
9 | "include": ["./**/*"]
10 | }
11 |
--------------------------------------------------------------------------------
/dev/types.ts:
--------------------------------------------------------------------------------
1 | import type { ViteSSGContext } from 'vite-ssg'
2 |
3 | export type UserModule = (ctx: ViteSSGContext) => void
4 |
--------------------------------------------------------------------------------
/dev/uno.config.ts:
--------------------------------------------------------------------------------
1 | import {
2 | defineConfig,
3 | presetIcons,
4 | presetWind4,
5 | transformerDirectives,
6 | transformerVariantGroup,
7 | } from 'unocss'
8 |
9 | function convert(color: string) {
10 | return `color-mix(in srgb, ${color} 100%, transparent)`
11 | }
12 |
13 | export default defineConfig({
14 | presets: [
15 | presetWind4({
16 | preflights: {
17 | reset: false,
18 | },
19 | }),
20 | presetIcons({
21 | scale: 1.2,
22 | unit: 'em',
23 | }),
24 | ],
25 | theme: {
26 | colors: {
27 | 'primary': convert('var(--p-primary-color)'),
28 | 'primary-emphasis': convert('var(--p-primary-hover-color)'),
29 | 'primary-emphasis-alt': convert('var(--p-primary-active-color)'),
30 | 'primary-contrast': convert('var(--p-primary-contrast-color)'),
31 | 'primary-50': convert('var(--p-primary-50)'),
32 | 'primary-100': convert('var(--p-primary-100)'),
33 | 'primary-200': convert('var(--p-primary-200)'),
34 | 'primary-300': convert('var(--p-primary-300)'),
35 | 'primary-400': convert('var(--p-primary-400)'),
36 | 'primary-500': convert('var(--p-primary-500)'),
37 | 'primary-600': convert('var(--p-primary-600)'),
38 | 'primary-700': convert('var(--p-primary-700)'),
39 | 'primary-800': convert('var(--p-primary-800)'),
40 | 'primary-900': convert('var(--p-primary-900)'),
41 | 'primary-950': convert('var(--p-primary-950)'),
42 | 'surface-0': convert('var(--p-surface-0)'),
43 | 'surface-50': convert('var(--p-surface-50)'),
44 | 'surface-100': convert('var(--p-surface-100)'),
45 | 'surface-200': convert('var(--p-surface-200)'),
46 | 'surface-300': convert('var(--p-surface-300)'),
47 | 'surface-400': convert('var(--p-surface-400)'),
48 | 'surface-500': convert('var(--p-surface-500)'),
49 | 'surface-600': convert('var(--p-surface-600)'),
50 | 'surface-700': convert('var(--p-surface-700)'),
51 | 'surface-800': convert('var(--p-surface-800)'),
52 | 'surface-900': convert('var(--p-surface-900)'),
53 | 'surface-950': convert('var(--p-surface-950)'),
54 | },
55 | breakpoints: {
56 | sm: '640px',
57 | md: '768px',
58 | lg: '1024px',
59 | xl: '1280px',
60 | xxl: '1536px',
61 | },
62 |
63 | },
64 | transformers: [
65 | transformerVariantGroup(),
66 | transformerDirectives(),
67 | ],
68 | content: {
69 | pipeline: {
70 | include: ['./**/*.vue', './**/*.md'],
71 | },
72 | },
73 | })
74 |
--------------------------------------------------------------------------------
/dev/utils/presets.ts:
--------------------------------------------------------------------------------
1 | export const blueprint = {
2 | $formkit: 'primeInputText',
3 | name: 'field',
4 | options: [{ label: 'Option 1', value: 'option1' }, { label: 'Option 2', value: 'option2' }],
5 | }
6 |
7 | export const formkitPreset = [{
8 | $formkit: 'primeInputText',
9 | name: 'email',
10 | label: 'Email',
11 | help: 'This will be used for your account.',
12 | validation: 'required|email',
13 | }, {
14 | $formkit: 'primeTextarea',
15 | name: 'myText',
16 | label: 'Text',
17 | validation: '',
18 | rows: '3',
19 | }, {
20 | $formkit: 'primeEditor',
21 | name: 'myEditor',
22 | label: 'Editor',
23 | style: 'height: 160px; margin-bottom:80px;',
24 | }, {
25 | $formkit: 'primePassword',
26 | name: 'password',
27 | label: 'Password',
28 | help: 'Enter your new password.',
29 | validation: 'required|length:5,16',
30 | feedback: true,
31 | }, {
32 | $formkit: 'primePassword',
33 | name: 'password_confirm',
34 | label: 'Confirm password',
35 | help: 'Enter your new password again.',
36 | validation: 'required|confirm',
37 | validationLabel: 'password confirmation',
38 | }, {
39 | $formkit: 'primeCheckbox',
40 | name: 'eu_citizen',
41 | id: 'eu',
42 | label: 'Are you a european citizen?',
43 | }, {
44 | $formkit: 'primeSelect',
45 | if: '$get(eu).value', // 👀 Oooo, conditionals!
46 | name: 'cookie_notice',
47 | label: 'Cookie notice frequency',
48 | optionLabel: 'label',
49 | optionValue: 'value',
50 | help: 'How often should we display a cookie notice?',
51 | }]
52 |
--------------------------------------------------------------------------------
/dev/vite.config.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'node:path'
2 | import Vue from '@vitejs/plugin-vue'
3 | import Unocss from 'unocss/vite'
4 | import AutoImport from 'unplugin-auto-import/vite'
5 | import Components from 'unplugin-vue-components/vite'
6 | import { defineConfig } from 'vite'
7 | import Pages from 'vite-plugin-pages'
8 | import pkg from '../package.json'
9 |
10 | // eslint-disable-next-line node/prefer-global/process
11 | process.env.VITE_APP_BUILD_EPOCH = new Date().getTime().toString()
12 | // eslint-disable-next-line node/prefer-global/process
13 | process.env.VITE_APP_VERSION = pkg.version
14 |
15 | /**
16 | * @type {import('vite').UserConfig}
17 | */
18 | export default defineConfig({
19 | server: {
20 | hmr: {
21 | port: false,
22 | path: '/ws',
23 | },
24 | },
25 | // https://github.com/antfu/vite-ssg
26 | ssgOptions: {
27 | script: 'async',
28 | formatting: 'minify',
29 | },
30 | test: {
31 | globals: true,
32 | include: ['test/**/*.test.ts'],
33 | environment: 'happy-dom',
34 | },
35 |
36 | optimizeDeps: {
37 | include: [
38 | 'vue',
39 | 'vue-router',
40 | '@vueuse/core',
41 | ],
42 | exclude: [
43 | 'vue-demi',
44 | ],
45 | },
46 | plugins: [
47 | Unocss(),
48 | Vue({
49 | include: [/\.vue$/, /\.md$/],
50 | }),
51 |
52 | Components({
53 | dirs: ['components'],
54 | dts: 'components.d.ts',
55 | }),
56 |
57 | AutoImport({
58 | imports: [
59 | 'vue',
60 | 'vue-router',
61 | 'vue-i18n',
62 | '@vueuse/head',
63 | ],
64 | exclude: [
65 | '**/dist/**',
66 | ],
67 | dts: 'auto-import.d.ts',
68 | }),
69 | Pages({
70 | dirs: [
71 | { dir: 'pages', baseRoute: '' },
72 | ],
73 | extensions: ['vue', 'md'],
74 | extendRoute(route) {
75 | if (route.name === 'about')
76 | route.props = route => ({ query: route.query.q })
77 |
78 | if (route.name === 'components') {
79 | return {
80 | ...route,
81 | }
82 | }
83 | },
84 | }),
85 |
86 | ],
87 | resolve: {
88 | alias: {
89 | '@': path.resolve(__dirname, '.'),
90 | '~': path.resolve(__dirname, 'node_modules/'),
91 | 'my-library': path.resolve(__dirname, '../src'),
92 | 'my-library-components': path.resolve(__dirname, '../src/components'),
93 |
94 | },
95 | },
96 |
97 | })
98 |
--------------------------------------------------------------------------------
/docs/.vitepress/config.mts:
--------------------------------------------------------------------------------
1 | import Unocss from 'unocss/vite'
2 | import { defineConfig } from 'vitepress'
3 | import { version } from '../../package.json'
4 |
5 | export default defineConfig({
6 | title: 'FormKit-PrimeVue',
7 | description: 'Formkit PrimeVue Integration',
8 | base: '/formkit-primevue/',
9 | themeConfig: {
10 | footer: {
11 | message: 'FormKit PrimeVue Module',
12 | copyright: 'Copyright © 2024 SFXCode',
13 | },
14 | socialLinks: [
15 | { icon: 'github', link: 'https://github.com/sfxcode/formkit-primevue' },
16 | ],
17 | editLink: {
18 | pattern: 'https://github.com/sfxcode/formkit-primevue/edit/main/docs/:path',
19 | text: 'Edit this page on GitHub',
20 | },
21 | nav: nav(),
22 | search: {
23 | provider: 'local',
24 | },
25 | sidebar: {
26 | '/guide/': sidebarGuide(),
27 | '/advanced/': sidebarGuide(),
28 | '/config/': sidebarConfig(),
29 | },
30 | },
31 | markdown: {
32 | headers: {
33 | level: [0, 0],
34 | },
35 | },
36 | vite: {
37 | plugins: [
38 | Unocss({
39 | configFile: '../../unocss.config.ts',
40 | }),
41 | ],
42 | },
43 | })
44 |
45 | function nav() {
46 | return [
47 | { text: 'Guide', link: '/guide/', activeMatch: '/guide/' },
48 | { text: 'Advanced', link: '/advanced/', activeMatch: '/advanced/' },
49 | {
50 | text: 'Playground',
51 | link: 'https://formkit-primevue.netlify.app',
52 | },
53 | {
54 | text: 'External Docs',
55 | items: [
56 | {
57 | text: 'PrimeVue',
58 | link: 'https://www.primefaces.org/primevue',
59 | },
60 | {
61 | text: 'Formkit',
62 | link: 'https://formkit.com',
63 | },
64 | ],
65 | },
66 | {
67 | text: version,
68 | items: [
69 | {
70 | text: 'Changelog',
71 | link: 'https://github.com/sfxcode/formkit-primevue/blob/main/CHANGELOG.md',
72 | },
73 | ],
74 | },
75 | ]
76 | }
77 |
78 | function sidebarGuide() {
79 | return [
80 | {
81 | text: 'Introduction',
82 | collapsible: true,
83 | items: [
84 | { text: 'What is this?', link: '/guide/' },
85 | { text: 'Getting started', link: '/guide/getting-started' },
86 | ],
87 | },
88 | {
89 | text: 'Guide',
90 | collapsible: true,
91 | items: [
92 | { text: 'Usage', link: '/guide/usage' },
93 | { text: 'Input Components', link: '/guide/inputs' },
94 | { text: 'Output Components', link: '/guide/outputs' },
95 | { text: 'Form Components', link: '/guide/form' },
96 | { text: 'Input Options', link: '/guide/options' },
97 | { text: 'Styling', link: '/guide/styling' },
98 | { text: 'Prefix / Suffix', link: '/guide/prefix' },
99 | { text: 'Examples', link: '/guide/examples' },
100 | ],
101 | },
102 | {
103 | text: 'Advanced',
104 | collapsible: true,
105 | items: [
106 | { text: 'Composables', link: '/advanced/composables' },
107 | { text: 'Nuxt', link: '/advanced/nuxt' },
108 | { text: 'Schema', link: '/advanced/schema' },
109 | { text: 'Plugins', link: '/advanced/plugins' },
110 | ],
111 | },
112 | ]
113 | }
114 |
115 | function sidebarConfig() {
116 | return [
117 | {
118 | text: 'Config',
119 | items: [
120 | { text: 'Introduction', link: '/config/' },
121 | ],
122 | },
123 | ]
124 | }
125 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/DisplayComponents.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
31 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/DisplayFormComponents.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
17 |
18 |
19 |
22 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/DisplayOutputComponents.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
17 |
18 |
19 |
22 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/Todo.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | TODO
10 |
11 |
12 |
13 | More Info to come ...
14 |
15 |
16 |
17 |
18 |
21 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.ts:
--------------------------------------------------------------------------------
1 | import type { Theme } from 'vitepress'
2 | import type { App } from 'vue'
3 | import DefaultTheme from 'vitepress/theme'
4 | import DisplayComponents from './components/DisplayComponents.vue'
5 | import DisplayFormComponents from './components/DisplayFormComponents.vue'
6 | import DisplayOutputComponents from './components/DisplayOutputComponents.vue'
7 | import Todo from './components/Todo.vue'
8 | import 'uno.css'
9 |
10 | export default {
11 | ...DefaultTheme,
12 | enhanceApp({ app }: { app: App }) {
13 | app.component('Todo', Todo)
14 | app.component('DisplayComponents', DisplayComponents)
15 | app.component('DisplayOutputComponents', DisplayOutputComponents)
16 | app.component('DisplayFormComponents', DisplayFormComponents)
17 | },
18 | } satisfies Theme
19 |
--------------------------------------------------------------------------------
/docs/advanced/composables.md:
--------------------------------------------------------------------------------
1 | # Composables
2 |
3 | Composables are used make your development with this library a little easier.
4 |
5 | ## useFormkitSchema
6 |
7 | This composable provides helper functions to simplify building a schema.
8 |
9 | Sometimes it provides a little more concise syntax or provide the needed helper functions.
10 |
11 | ### addComponent
12 |
13 | ```ts
14 | const { addComponent } = useFormKitSchema()
15 |
16 | function addButtonComponent(onClick: string = '', label: string = '', icon: string = '', severity: string = '', render: string = 'true', styleClass: string = 'p-button-sm ml-2'): object {
17 | return addComponent('Button', { onClick, label, icon, class: styleClass, severity }, render)
18 | }
19 | ```
20 |
21 | ### addElement
22 |
23 | Following json in the schema
24 |
25 | ```json
26 | [
27 | {
28 | "$el": "h2",
29 | "children": ["Register ", "$email"]
30 | },
31 | {
32 | "$el": "h3",
33 | "children": "Header Text H3"
34 | }
35 | ]
36 | ```
37 |
38 | can be replaced by:
39 |
40 | ```ts
41 | const { addElement } = useFormKitSchema()
42 |
43 | const formData = ref([
44 | addElement('h2', ['Register ', '$email']),
45 | addElement('h3', 'Header Text H3')
46 | // more form elements ...
47 | ])
48 | ```
49 |
50 | ## useFormkitRepeater
51 |
52 | To simplify the build of a repeater you can use:
53 |
54 | - addInsertButton
55 | - addGroupButtons
56 | - addListGroupFunctions
57 |
58 | ```vue
59 |
64 | ```
65 |
66 | A working example can be found in the [repeater demo](https://github.com/sfxcode/formkit-primevue/blob/main/dev/pages/samples/Repeater.vue).
67 |
--------------------------------------------------------------------------------
/docs/advanced/index.md:
--------------------------------------------------------------------------------
1 | # Advanced
2 |
3 | ## Composables
4 |
5 | Composables are used make your development with this library a little easier.
6 | Schema- and Repeater-related composables are provided to simplify the usage of the library.
7 |
8 | ## Nuxt
9 |
10 | Nuxt Module is available.
11 |
--------------------------------------------------------------------------------
/docs/advanced/nuxt.md:
--------------------------------------------------------------------------------
1 | # Nuxt
2 |
3 | ## Nuxt Module
4 |
5 | [FormKit-PrimeVue-Nuxt](https://github.com/sfxcode/formkit-primevue-nuxt) module available.
6 |
7 | ### Nuxt Module Dependencies
8 |
9 | - primevue-nuxt Module
10 | - formkit-nuxt Module
11 |
12 | Both are auto installed by default, this can be disabled in the module options.
13 |
14 | ### Quick Setup
15 |
16 | Install the module to your Nuxt application with one command:
17 |
18 | ```bash
19 | npx nuxi module add @sfxcode/formkit-primevue-nuxt
20 | ```
21 |
22 | That's it! You can now use FormKit PrimeVue Nuxt Module in your Nuxt app ✨
23 |
24 | ### Module Options
25 |
26 | - **includePrimeIcons** (default: `true`): Add PrimeIcons CSS to the project.
27 | - **includeStyles** (default: `true`): Add custom FormKit CSS to the project.
28 | - **installI18N** (default: `true`): Install nuxt i18n module automatically.
29 | - **installFormKit** (default: `true`): Install nuxt formkit module automatically.
30 |
--------------------------------------------------------------------------------
/docs/advanced/plugins.md:
--------------------------------------------------------------------------------
1 | # Plugins
2 |
3 | Plugins are a powerful way to extend the functionality of FormKit. They allow you to add new features, modify existing ones, or integrate with third-party services.
4 |
5 | ## AsteriskPlugin
6 |
7 | The AsteriskPlugin is a simple plugin that adds an asterisk to the end of the label of any input that has validation rules.
8 | This is useful for indicating to users that the field is required.
9 |
10 | ### Usage
11 |
12 | To use the AsteriskPlugin, you need to import it and add it to your FormKit configuration file.
13 |
14 | ```ts
15 | plugins: [
16 | addPrimeAsteriskPlugin,
17 | ]
18 | ```
19 |
--------------------------------------------------------------------------------
/docs/advanced/schema.md:
--------------------------------------------------------------------------------
1 | # Schema
2 |
3 | FormKit Schema usage was the main reason for this library. The schema is used to create the form and the validation.
4 |
5 | [Formkit Schema Documentation](https://formkit.com/essentials/schema)
6 |
7 | However, if you do not want to use the schema, you can also use the FormKit components directly.
8 |
9 | ## FormKit Components
10 |
11 | <<< ../../dev/pages/data/WithoutSchema.vue{vue}
12 |
--------------------------------------------------------------------------------
/docs/guide/examples.md:
--------------------------------------------------------------------------------
1 | # Usage Examples
2 |
3 | ::: info
4 | If you are using this package in your project, please let me know or create a PR for this site
5 | :::
6 |
7 | ## Vue 3
8 |
9 | [FormKit PrimeVue Demo Application](https://formkit-primevue.netlify.app/)
10 |
11 | [Vite PrimeVue Starter](https://github.com/sfxcode/vite-primevue-starter)
12 |
13 | ## Nuxt 3 (4)
14 |
15 | [Nuxt 3 PrimeVue Starter](https://github.com/sfxcode/nuxt3-primevue-starter)
16 |
--------------------------------------------------------------------------------
/docs/guide/form.md:
--------------------------------------------------------------------------------
1 | # Form Components
2 |
3 | For the simple usage with schema and data values FormKitDataEdit and FormKitDataView (and FormkitDebug) components are available.
4 |
5 |
6 |
7 | ## Usage
8 |
9 | To use the components there must be an import or global registration.
10 |
11 | ```vue
12 |
15 | ```
16 |
17 | ### Debug
18 |
19 | Use properties **:debug-schema="true"** and / or **:debug-data="true"** for debugging of schema / data.
20 |
21 | ## FormKitDataEdit
22 |
23 | ### Main Properties
24 |
25 | | Property | Type | Description
26 | |:--------------| :-------- |:--------------------------------------------------------|
27 | | v-model | Object | The data object to be edited with 2-Way-Binding |
28 | | data | Object | The data object to be edited |
29 | | :schema | Object | The schema object to be used |
30 | | :debug-schema | Boolean | Display the schema |
31 | | :debug-data | Boolean | Display the data |
32 | | :show-reset | Boolean | Display some Button for resetting data to initial state |
33 | ### Style Properties
34 |
35 | | Property | Type | Description
36 | |:---------------|:--------|:--------------------------------------------|
37 | | formClass | String | Add additional classes to the form |
38 | | actionsClass | String | Add additional classes to the action div |
39 | | submitClass | String | Add additional classes to the submit button |
40 | | submitSeverity | String | PrimeVue Button severity |
41 | | submitLabel | String | Default: Save |
42 | | submitIcon | String | PrimeVue Button icon |
43 | | resetClass | String | Add additional classes to the reset button |
44 | | resetSeverity | String | PrimeVue Button severity |
45 | | resetLabel | String | Default: Reset |
46 | | resetIcon | String | PrimeVue Button icon |
47 |
48 | ### Example
49 |
50 | ```vue
51 |
61 |
62 |
63 |
64 |
69 |
70 |
71 | ```
72 |
73 | ## FormKitDataView
74 |
75 | Same as FormKitDataEdit but without Action Buttons.
76 |
--------------------------------------------------------------------------------
/docs/guide/history.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | Only some topics are mentioned ....
4 |
5 | ## 0.x to 1.0.0 (2023-03-08)
6 |
7 | - First version of this framework with PrimeVue 3
8 |
9 | ## 1.1.x
10 |
11 | - Added some styles to visualize errors on prime inputs
12 |
13 | ## 1.2.x
14 |
15 | - Added Radio Button
16 |
17 | ## 1.3.x
18 |
19 | - **FormKit 1.0**
20 |
21 | ## 1.4.x
22 |
23 | - more styling by sass
24 | - default style of all inputs to width of 100% (when it makes sense)
25 |
26 | ## 1.5.x
27 |
28 | - autoAnimate Plugin in ShowCase
29 | - add missing props to some components
30 | - **FormKit 1.5**
31 |
32 | ## 1.6.x
33 |
34 | - Better Option Handling
35 | - Provide simple option usage
36 |
37 | ## 1.7.x
38 |
39 | - TreeSelect
40 | - v-bind for passthrough of missing options
41 |
42 | ## 1.8.x
43 |
44 | - use InputField/InputIcon
45 | - types added
46 |
47 | ## 1.9.x
48 |
49 | - useFormKitSchema composable
50 | - vitest - create some tests
51 |
52 | ## 1.11.x
53 |
54 | - Input Editor
55 | - **FormKit 1.6.5**
56 |
57 | ## 2.0.x
58 |
59 | - Update to **PrimeVue 4**
60 |
61 | ## 2.1.x
62 |
63 | - Stabilize the usage with PrimeVue 4
64 |
65 | ## 2.3.x
66 |
67 | - FormEditor
68 | - Form Outputs
69 | - Better Styling with the provided sass file
70 | - Simple Grid by adding col-[1-12] to outerClass
71 | - Better Prefix / Suffix Handling
72 |
73 | ## 2.4.x
74 |
75 | - change to iconPrefix/iconSuffix
76 |
--------------------------------------------------------------------------------
/docs/guide/index.md:
--------------------------------------------------------------------------------
1 | # Formkit PrimeVue
2 |
3 | **formkit-primevue** combines the [PrimeVue](https://www.primefaces.org/primevue) component framework (V4) with the validation power of [Formkit](https://formkit.com/) in your Vue/Nuxt application.
4 |
5 | The main motivation for this project is to use Formkit Validation by Schema with form elements provided by PrimeVue.
6 |
7 | ## Formkit Schema
8 |
9 | [Formkit Schema Documentation](https://formkit.com/essentials/schema)
10 |
11 | ::: info
12 | FormKit's schema is a JSON-serializable data format for storing DOM structures and component implementations, including FormKit forms. Although created specifically for implementing and generating forms, the format is capable of generating any HTML markup or using any third-party components.
13 | :::
14 |
15 | PrimeVue inputs are prefixed with prime and try to use as many properties as possible from their definition.
16 |
17 | ```ts
18 | const schema = reactive(
19 | [
20 | {
21 | $el: 'h2',
22 | children: ['Register ', '$email'],
23 | },
24 | {
25 | $el: 'h3',
26 | children: 'Header Text H3',
27 | },
28 | {
29 | $formkit: 'primeInputText',
30 | name: 'email',
31 | label: 'Email',
32 | help: 'This will be used for your account.',
33 | validation: 'required|email',
34 | },
35 | {
36 | $formkit: 'primeTextarea',
37 | name: 'myText',
38 | label: 'Text',
39 | validation: '',
40 | rows: '3',
41 | }
42 | ]
43 | )
44 | ```
45 |
--------------------------------------------------------------------------------
/docs/guide/inputs.md:
--------------------------------------------------------------------------------
1 | # Input Components
2 |
3 | formkit-primevue tries to integrate as much PrimeVue inputs as possible.
4 |
5 | ::: warning
6 | Used inputs by FormKit must be imported global (default).
7 |
8 | They are referenced in the startup phase, if FormKit is enabled.
9 | :::
10 |
11 | ## Naming in FormKit
12 | Inputs are used in schema with **prime** as prefix and the **input name** as suffix.
13 |
14 | E.g. InputMask -> primeInputMask
15 |
16 | ## Supported Inputs
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/guide/options.md:
--------------------------------------------------------------------------------
1 | # Options
2 |
3 | In some inputs options are needed. There are several ways to deal with the options.
4 |
5 | ## Option based Inputs
6 |
7 |
8 |
9 | ## Ways of Usage
10 |
11 | ### Simple Array
12 |
13 | ```vue
14 | const stringArray = ['refresh', 'hourly', 'daily']
15 |
16 | const schema
17 | = [
18 | {
19 | $formkit: 'primeDropdown',
20 | name: 'selectString',
21 | label: 'Simple String Array Dropdown',
22 | options: stringArray,
23 | },
24 | ]
25 | ```
26 |
27 | ### Object Array / Select Object by key
28 |
29 | Here you have to select a property name for **optionLabel** as key.
30 |
31 | ```vue
32 | const cities = [
33 | { name: 'New York', code: 'NY' },
34 | { name: 'Rome', code: 'RM' },
35 | { name: 'London', code: 'LDN' },
36 | { name: 'Istanbul', code: 'IST' },
37 | { name: 'Paris', code: 'PRS' },
38 | ]
39 |
40 | const schema = [
41 | {
42 | $formkit: 'primeDropdown',
43 | name: 'selectObjectByLabel',
44 | label: 'Select Object Dropdown',
45 | optionLabel: 'name',
46 | options: cities,
47 | },
48 | ]
49 | ```
50 |
51 | ### Object Array / Select Object by key and value by key
52 |
53 | Here you have to select a property name for **optionLabel** as key and a property name for **optionValue** as key.
54 |
55 | ```vue
56 | const options = [
57 | { label: 'Every page load', value: 'refresh' },
58 | { label: 'Every hour', value: 'hourly' },
59 | { label: 'Every day', value: 'daily' },
60 | ]
61 |
62 | const schema = [
63 | {
64 | $formkit: 'primeDropdown',
65 | name: 'selectValue',
66 | label: 'Cookie notice Dropdown',
67 | value: 'hourly',
68 | optionLabel: 'label',
69 | optionValue: 'value',
70 | options,
71 | help: 'Cookie notice frequency ?',
72 | },
73 | ]
74 | ```
75 |
--------------------------------------------------------------------------------
/docs/guide/outputs.md:
--------------------------------------------------------------------------------
1 | # Output Components
2 |
3 | formkit-primevue can also be used to output data.
4 |
5 | Different types of data can behandled.
6 |
7 | ::: warning
8 | Some outputs depends on vue-i18n e.g. **OutputNumber** or **OutputDate**.
9 |
10 | numberFormats / datetimeFormats from vue-i18n are used to display the values accordingly to the selected format.
11 | :::
12 |
13 | ## Examples
14 |
15 | ### OutputNumber
16 |
17 | ```ts
18 | const formkitItem = {
19 | $formkit: 'primeOutputNumber',
20 | name: 'mumber',
21 | format: 'decimal', // vue-i18n format
22 | }
23 | ```
24 |
25 | ## Naming in FormKit
26 | Outputs are used in schema with **prime** as prefix and the **output name** as suffix.
27 |
28 | E.g. OutputText -> primeOutputText
29 |
30 | ## Supported Inputs
31 |
32 |
33 |
--------------------------------------------------------------------------------
/docs/guide/prefix.md:
--------------------------------------------------------------------------------
1 | # Usage Examples
2 |
3 | All **Output classes** support the **optional** usage of a prefix (text/icon) and a suffix (text/icon).
4 |
5 | **InputText** and **InputMask** uses iconPrefix/iconSuffix, **CheckBox** and **ToggleButton** uses prefix/suffix.
6 |
7 | ::: warning
8 | FormKit use the props prefixIcon/suffixIcon internal for theme and provides a lookup for available icons when some pattern for props is used.
9 | To prevent the behavior for this framework the property names are switched to **iconPrefix** and **iconSuffix**.
10 | :::
11 | ## Sample Definition
12 |
13 | ```ts
14 | export const primeOutputTextDefinition: FormKitTypeDefinition = createInput(PrimeOutputText, {
15 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix'],
16 | })
17 | ```
18 |
19 | Icons are rendered in an i-Tag and requires a class and text in a span-Tag.
20 |
21 | ## Example
22 |
23 | ```ts
24 | const schema
25 | = [
26 | {
27 | $formkit: 'primeOutputBoolean',
28 | name: 'falseValue',
29 | label: 'False',
30 | prefix: 'prefix',
31 | iconPrefix: 'pi pi-check',
32 | suffix: 'suffix',
33 | iconSuffix: 'pi pi-times',
34 | }
35 | ]
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/guide/styling.md:
--------------------------------------------------------------------------------
1 | # Styling
2 |
3 | PrimeVue has a lot of styling possiblities and the structure of a formkit form gives you all possibilities needed for advanced styling.
4 |
5 | ## Basic Styling
6 |
7 | Basic styling is provided with the **formkit-primevue.scss** file.
8 |
9 | Features:
10 |
11 | - Width of all text and dropdown elements is set to 100%
12 | - Error Color by variable (--formkit-error-color)
13 | - Some margins, font sizes ...
14 |
15 | You can use it or take it as base for your own styling.
16 |
17 | ## PrimeVue Tailwind / Unstyled mode
18 |
19 | Make sure to add a class selector for **p-invalid**.
20 |
21 | ## Grid
22 |
23 | **formkit-primevue.scss** defines a simple grid system based on flex with a 12 columns layout.
24 |
25 | For example to place 2 elements side by side give both of them the **outerClass** value **col-6**.
26 |
27 | ```ts
28 | const formkitItems = [
29 | {
30 | $formkit: 'primePassword',
31 | name: 'password',
32 | label: 'Password',
33 | help: 'Enter your new password.',
34 | validation: 'required|length:5,16',
35 | feedback: true,
36 | outerClass: 'col-6',
37 | },
38 | {
39 | $formkit: 'primePassword',
40 | name: 'password_confirm',
41 | label: 'Confirm password',
42 | help: 'Enter your new password again.',
43 | validation: 'required|confirm',
44 | validationLabel: 'password confirmation',
45 | outerClass: 'col-6',
46 | },
47 | ]
48 | ```
49 |
50 | ## Extended Styling
51 |
52 | - All components are wrapped in a div with a **p-formkit** class
53 | - Use *outerClass*, *wrapperClass*, *innerClass* to add additional styleclasses to formkit generated classes
54 | - Most Prime Components have access to class / styles attributes
55 | - Some Components have addtional properties for the rendered inputs (eg: optionClass, labelClass in primeRadioButton)
56 | - PT and PTOptions are available ([https://primevue.org/passthrough/](https://primevue.org/passthrough/))
57 | - [Styling](https://formkit-primevue.netlify.app/demo/styling), [Grid](https://formkit-primevue.netlify.app/demo/grid) and [PT](https://formkit-primevue.netlify.app/demo/passThrough) demo available
58 |
--------------------------------------------------------------------------------
/docs/guide/usage.md:
--------------------------------------------------------------------------------
1 | # Usage
2 |
3 | To build a form a schema is required and some kind of data.
4 |
5 | More information can be found in the [Formkit Schema](https://formkit.com/essentials/schema) documentation.
6 |
7 | ## Example
8 |
9 | ```ts
10 | const schema = reactive(
11 | [
12 | {
13 | $el: 'h2',
14 | children: 'Registration Form',
15 | },
16 | {
17 | $el: 'h3',
18 | children: ['Register ', '$email'],
19 | },
20 | {
21 | $formkit: 'primeInputText',
22 | name: 'email',
23 | label: 'Email',
24 | help: 'This will be used for your account.',
25 | validation: 'required|email',
26 | },
27 | {
28 | $formkit: 'primeTextarea',
29 | name: 'comment',
30 | label: 'Text',
31 | validation: '',
32 | rows: '3',
33 | }
34 | ]
35 | )
36 |
37 | const data = ref({ email: 'tom@sfxcode.com' })
38 |
39 | async function submitHandler() {
40 | await new Promise(resolve => setTimeout(resolve, 1000))
41 | }
42 | ```
43 |
44 | ```vue
45 |
46 |
55 |
56 |
57 |
58 | ```
59 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | hero:
5 | name: FormKit PrimeVue
6 | text: Schema based Validation
7 | tagline: Use PrimeVue and FormKit Validation
8 | actions:
9 | - theme: brand
10 | text: Get Started
11 | link: /guide/getting-started
12 | - theme: alt
13 | text: Guide
14 | link: /guide/
15 |
16 | features:
17 | - title: "Formkit-PrimeVue"
18 | details: PrimeVue support for the FormKit validation Framework. PrimeVue inputs are prepared for seamless FormKit integration.
19 | - title: "PrimeVue"
20 | details: Next Generation Vue UI Component Library. Rich set of open source native components for Vue.
21 | - title: "FormKit"
22 | details: A Vue form building framework that simplifies form structure, generation, validation, theming, submission, error handling, and more.
23 | ---
24 |
--------------------------------------------------------------------------------
/docs/uno.config.ts:
--------------------------------------------------------------------------------
1 | import {
2 | defineConfig,
3 | presetIcons,
4 | presetUno,
5 | transformerDirectives,
6 | transformerVariantGroup,
7 | } from 'unocss'
8 |
9 | export default defineConfig({
10 | presets: [
11 | presetUno(),
12 | presetIcons({
13 | scale: 1.2,
14 | unit: 'em',
15 | }),
16 | ],
17 | transformers: [
18 | transformerVariantGroup(),
19 | transformerDirectives(),
20 | ],
21 | content: {
22 | pipeline: {
23 | include: ['./**/*.vue', './**/*.md'],
24 | },
25 | },
26 | })
27 |
--------------------------------------------------------------------------------
/env.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import type { DefineComponent } from 'vue'
3 |
4 | const component: DefineComponent, Record, any>
5 | export default component
6 | }
7 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | // eslint.config.js
2 | import antfu from '@antfu/eslint-config'
3 |
4 | export default antfu(
5 | {
6 | ignores: ['README.md'],
7 | },
8 | {
9 | rules: {
10 | 'vue/no-mutating-props': ['error', {
11 | shallowOnly: true,
12 | }],
13 | 'unicorn/consistent-function-scoping': 'off',
14 | },
15 |
16 | },
17 | )
18 |
--------------------------------------------------------------------------------
/formkit-primevue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sfxcode/formkit-primevue/9e49e70fd4c5e0a9ba1ca3250d58cb52cec008cd/formkit-primevue.png
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | command = "pnpm run dev:build"
3 |
4 | [build.environment]
5 | NPM_FLAGS = "--prefix=/dev/null"
6 | NODE_VERSION = "20"
7 |
8 | [[redirects]]
9 | from = "/*"
10 | to = "/index.html"
11 | status = 200
12 |
--------------------------------------------------------------------------------
/primevue-formkit.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/components/FormKitDataEdit.vue:
--------------------------------------------------------------------------------
1 |
94 |
95 |
96 |
97 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
129 |
--------------------------------------------------------------------------------
/src/components/FormKitDataView.vue:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
39 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
56 |
--------------------------------------------------------------------------------
/src/components/FormKitDebug.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
21 |
22 |
23 |
26 |
--------------------------------------------------------------------------------
/src/components/PrimeAutoComplete.vue:
--------------------------------------------------------------------------------
1 |
58 |
59 |
60 |
94 |
95 |
--------------------------------------------------------------------------------
/src/components/PrimeCascadeSelect.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
33 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/components/PrimeCheckbox.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 |
37 | {{ context?.prefix }}
38 |
39 |
63 |
64 |
65 |
66 |
67 |
68 | {{ context?.suffix }}
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/components/PrimeColorPicker.vue:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/components/PrimeEditor.vue:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/components/PrimeInputMask.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 |
37 |
38 |
61 |
62 |
63 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/components/PrimeInputOtp.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
31 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/components/PrimeInputText.vue:
--------------------------------------------------------------------------------
1 |
29 |
30 |
31 |
32 |
33 |
34 |
55 |
56 |
57 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/src/components/PrimeKnob.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
46 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/src/components/PrimeListbox.vue:
--------------------------------------------------------------------------------
1 |
34 |
35 |
36 |
37 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputBoolean.vue:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
30 |
31 | {{ context?.prefix }}
32 |
33 |
34 | {{ translated }}
35 |
36 |
37 | {{ context?.suffix }}
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputDate.vue:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 |
38 |
39 |
40 | {{ context?.prefix }}
41 |
42 |
43 | {{ converted }}
44 |
45 |
46 | {{ context?.suffix }}
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputDuration.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 | {{ context?.prefix }}
22 |
23 |
24 | {{ formattedDuration(context?._value) }}
25 |
26 |
27 | {{ context?.suffix }}
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputLink.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
50 |
51 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputList.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
63 |
64 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputNumber.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
46 |
47 |
48 | {{ context?.prefix }}
49 |
50 |
51 | {{ converted }}
52 |
53 |
54 | {{ context?.suffix }}
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputReference.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
62 |
63 |
--------------------------------------------------------------------------------
/src/components/PrimeOutputText.vue:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 |
36 | {{ context?.prefix }}
37 |
38 |
39 |
40 |
41 | {{ context?.suffix }}
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/components/PrimePassword.vue:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 |
73 |
74 |
--------------------------------------------------------------------------------
/src/components/PrimeRadioButton.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
53 |
54 |
--------------------------------------------------------------------------------
/src/components/PrimeRating.vue:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/components/PrimeSelectButton.vue:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/components/PrimeSlider.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/components/PrimeTextarea.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/components/PrimeToggleButton.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
33 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/components/PrimeToggleSwitch.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
31 | {{ context?.prefix }}
32 |
33 |
53 |
54 | {{ context?.suffix }}
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/components/PrimeTreeSelect.vue:
--------------------------------------------------------------------------------
1 |
34 |
35 |
36 |
37 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/components/index.ts:
--------------------------------------------------------------------------------
1 | import FormKitDataEdit from './FormKitDataEdit.vue'
2 | import FormKitDataView from './FormKitDataView.vue'
3 | import FormKitDataDebug from './FormKitDebug.vue'
4 | import PrimeAutoComplete from './PrimeAutoComplete.vue'
5 | import PrimeCascadeSelect from './PrimeCascadeSelect.vue'
6 | import PrimeCheckbox from './PrimeCheckbox.vue'
7 | import PrimeColorPicker from './PrimeColorPicker.vue'
8 | import PrimeDatePicker from './PrimeDatePicker.vue'
9 | import PrimeEditor from './PrimeEditor.vue'
10 | import PrimeInputMask from './PrimeInputMask.vue'
11 | import PrimeInputNumber from './PrimeInputNumber.vue'
12 | import PrimeInputText from './PrimeInputText.vue'
13 | import PrimeKnob from './PrimeKnob.vue'
14 | import PrimeListbox from './PrimeListbox.vue'
15 | import PrimeMultiSelect from './PrimeMultiSelect.vue'
16 | import PrimePassword from './PrimePassword.vue'
17 | import PrimeRadioButton from './PrimeRadioButton.vue'
18 | import PrimeRating from './PrimeRating.vue'
19 | import PrimeSelect from './PrimeSelect.vue'
20 | import PrimeSelectButton from './PrimeSelectButton.vue'
21 | import PrimeSlider from './PrimeSlider.vue'
22 | import PrimeTextarea from './PrimeTextarea.vue'
23 | import PrimeToggleButton from './PrimeToggleButton.vue'
24 | import PrimeInputSwitch from './PrimeToggleSwitch.vue'
25 | import PrimeTreeSelect from './PrimeTreeSelect.vue'
26 |
27 | export {
28 | FormKitDataDebug,
29 | FormKitDataEdit,
30 | FormKitDataView,
31 | PrimeAutoComplete,
32 | PrimeCascadeSelect,
33 | PrimeCheckbox,
34 | PrimeColorPicker,
35 | PrimeDatePicker,
36 | PrimeEditor,
37 | PrimeInputMask,
38 | PrimeInputNumber,
39 | PrimeInputSwitch,
40 | PrimeInputText,
41 | PrimeKnob,
42 | PrimeListbox,
43 | PrimeMultiSelect,
44 | PrimePassword,
45 | PrimeRadioButton,
46 | PrimeRating,
47 | PrimeSelect,
48 | PrimeSelectButton,
49 | PrimeSlider,
50 | PrimeTextarea,
51 | PrimeToggleButton,
52 | PrimeTreeSelect,
53 | }
54 |
--------------------------------------------------------------------------------
/src/composables/index.ts:
--------------------------------------------------------------------------------
1 | import { useFormKitInput } from './useFormKitInput'
2 | import { useFormKitRepeater } from './useFormKitRepeater'
3 | import { useFormKitSchema } from './useFormKitSchema'
4 | import { useFormKitSection } from './useFormKitSection'
5 | import { useInputEditor } from './useInputEditor'
6 | import { useInputEditorSchema } from './useInputEditorSchema'
7 | import { useOutputDuration } from './useOutputDuration'
8 | import { usePrimeInputs } from './usePrimeInputs'
9 |
10 | export {
11 | useFormKitInput,
12 | useFormKitRepeater,
13 | useFormKitSchema,
14 | useFormKitSection,
15 | useInputEditor,
16 | useInputEditorSchema,
17 | useOutputDuration,
18 | usePrimeInputs,
19 | }
20 |
--------------------------------------------------------------------------------
/src/composables/useFormKitInput.ts:
--------------------------------------------------------------------------------
1 | import { usePrimeVue } from 'primevue/config'
2 | import { computed } from 'vue'
3 |
4 | export function useFormKitInput(context: any) {
5 | const isInvalid = computed(() => {
6 | return context?.state?.validationVisible && !context?.state?.valid
7 | })
8 |
9 | const styleClass = computed(() => {
10 | return (context?.state?.validationVisible && !context?.state?.valid)
11 | ? `${context?.attrs?.class || ''} p-invalid`
12 | : context?.attrs?.class || ''
13 | })
14 |
15 | function isGlobalUnstyledMode(): boolean {
16 | let result = false
17 | try {
18 | const primevue = usePrimeVue()
19 | result = primevue?.config?.unstyled || false
20 | }
21 | // eslint-disable-next-line unused-imports/no-unused-vars
22 | catch (e) {
23 | }
24 | return result
25 | }
26 |
27 | const unstyled = computed(() => {
28 | return context?.unstyled ?? isGlobalUnstyledMode()
29 | })
30 |
31 | const formKitCreateInputSlots = new Set(['label', 'help', 'messages', 'message', 'input'])
32 |
33 | // FormKit slots added by createInput() and should be passed to FormKit not to the wrapped component.
34 | const validSlotNames = computed(() =>
35 | Object.keys(context?.slots || {}).filter(slotName => !formKitCreateInputSlots.has(slotName)),
36 | )
37 |
38 | function handleBlur(event: Event) {
39 | context?.handlers?.blur?.(event)
40 | }
41 |
42 | function handleChange(_: any) {
43 | context?.node?.input?.(context?._value)
44 | }
45 |
46 | function handleInput(_: any) {
47 | context?.node?.input?.(context?._value)
48 | }
49 |
50 | function handleSelect(e: any) {
51 | context?.node?.input?.(e)
52 | }
53 |
54 | return { isInvalid, validSlotNames, styleClass, unstyled, handleBlur, handleChange, handleInput, handleSelect }
55 | }
56 |
--------------------------------------------------------------------------------
/src/composables/useFormKitRepeater.ts:
--------------------------------------------------------------------------------
1 | import { useFormKitSchema } from './useFormKitSchema'
2 |
3 | export function useFormKitRepeater() {
4 | const { addElement, addComponent, addElementsInOuterDiv } = useFormKitSchema()
5 |
6 | function addInsertButton(label: string = 'Add', innerClass: string = '', outerClass: string = '', buttonClass: string = 'p-button-sm', iconClass: string = 'pi pi-plus') {
7 | return addElementsInOuterDiv([
8 | addComponent('Button', { onClick: '$addNode($node)', label, class: buttonClass, icon: iconClass }, '$node.value.length == 0'),
9 | ], innerClass, outerClass)
10 | }
11 |
12 | function addListGroupFunctions(data: any, addNodeDefaultObject: object = {}) {
13 | const swapElements = (array: any[], index1: number, index2: number) => {
14 | array[index1] = array.splice(index2, 1, array[index1])[0]
15 | return array
16 | }
17 |
18 | data.addNode = (parentNode: any) => (): void => {
19 | const newArray: any[] = [...parentNode.value, addNodeDefaultObject]
20 | parentNode.input(newArray, false)
21 | }
22 | data.removeNode = (parentNode: any, index: number) => (): void => {
23 | parentNode.input(parentNode._value.filter((_: any, i: number): boolean => i !== index), false)
24 | }
25 | data.moveNodeUp = (parentNode: any, index: number) => (): void => {
26 | const array: any[] = [...parentNode.value]
27 | if (index > 0)
28 | parentNode.input(swapElements(array, index - 1, index), false)
29 | }
30 | data.moveNodeDown = (parentNode: any, index: number) => (): void => {
31 | const array: any[] = [...parentNode.value]
32 | if (index < array.length - 1)
33 | parentNode.input(swapElements(array, index, index + 1), false)
34 | }
35 | data.copyNode = (parentNode: any, index: number) => (): void => {
36 | const obj: any = parentNode.value[index]
37 | const newArray: any[] = [...parentNode.value, { ...obj }]
38 | parentNode.input(newArray, false)
39 | }
40 | }
41 |
42 | function addGroupButtons(innerClass: string = '', outerClass: string = 'col-4', label: string = 'Actions', help: string = '', render: string = 'true') {
43 | const addButtonComponent = (onClick: string = '', label: string = '', icon: string = '', severity: string = '', render: string = 'true', styleClass: string = 'p-button-sm'): object => {
44 | return addComponent('Button', { onClick, label, icon, class: styleClass, severity }, render)
45 | }
46 |
47 | return addElementsInOuterDiv([
48 | addButtonComponent('$removeNode($node, $index)', '', 'pi pi-times', 'danger'),
49 | addButtonComponent('$copyNode($node, $index)', '', 'pi pi-plus'),
50 | addButtonComponent('$moveNodeUp($node, $index)', '', 'pi pi-arrow-up', 'secondary', '$index != 0'),
51 | addElement('span', [], { class: 'p-space' }, '$index == 0'),
52 | addButtonComponent('$moveNodeDown($node, $index)', '', 'pi pi-arrow-down', 'secondary', '$index < $node.value.length -1'),
53 | addElement('span', [], { class: 'p-space' }, '$index == $node.value.length -1'),
54 | ], `p-action-buttons ${innerClass}`, outerClass, label, help, render)
55 | }
56 |
57 | return { addInsertButton, addGroupButtons, addListGroupFunctions }
58 | }
59 |
--------------------------------------------------------------------------------
/src/composables/useFormKitSchema.ts:
--------------------------------------------------------------------------------
1 | export function useFormKitSchema() {
2 | const addComponent = (component: string = 'Button', props: object = {}, render: string | boolean = true, formKitAttrs: object = {}): object => {
3 | return {
4 | $cmp: component,
5 | if: render.toString(),
6 | props,
7 | ...formKitAttrs,
8 | }
9 | }
10 |
11 | const addElement = (element: string = 'div', children: any[] | string = [], attrs: object = {}, render: string | boolean = true, formKitAttrs: object = {}) => {
12 | return {
13 | $el: element,
14 | if: render.toString(),
15 | attrs,
16 | children,
17 | ...formKitAttrs,
18 | }
19 | }
20 |
21 | const addGroup = (name: string, children: object[] = [], render: string | boolean = true, formKitAttrs: object = {}) => {
22 | return {
23 | $formkit: 'group',
24 | if: render.toString(),
25 | name,
26 | children,
27 | ...formKitAttrs,
28 | }
29 | }
30 |
31 | const addList = (name: string, children: object[] = [], dynamic: boolean = true, render: string | boolean = true, formKitAttrs: object = {}) => {
32 | return {
33 | $formkit: 'list',
34 | if: render.toString(),
35 | name,
36 | dynamic,
37 | children,
38 | ...formKitAttrs,
39 | }
40 | }
41 |
42 | const addListGroup = (children: object[] = [], render: string | boolean = true, formKitAttrs: object = {}) => {
43 | return {
44 | $formkit: 'group',
45 | if: render.toString(),
46 | for: ['item', 'index', '$items'], // 👈 $items is in the slot’s scope
47 | key: '$item',
48 | index: '$index',
49 | children,
50 | ...formKitAttrs,
51 | }
52 | }
53 |
54 | const addElementsInOuterDiv = (children: object[] = [], innerClass: string = '', outerClass: string = '', label: string = '', help: string = '', render: string | boolean = true) => {
55 | const inner = addElement('div', children, { class: `formkit-inner ${innerClass}`, style: 'position: relative;' })
56 | const labelDiv = addElement('label', [label], { class: 'formkit-label' })
57 | const wrapperDiv = addElement('div', [labelDiv, inner], { class: 'formkit-wrapper' })
58 | const helpDiv = addElement('div', [help], { class: 'formkit-help' })
59 | return addElement('div', [wrapperDiv, helpDiv], { class: `formkit-outer ${outerClass}`, style: 'position: relative;' }, render)
60 | }
61 |
62 | return { addComponent, addElement, addGroup, addList, addListGroup, addElementsInOuterDiv }
63 | }
64 |
--------------------------------------------------------------------------------
/src/composables/useFormKitSection.ts:
--------------------------------------------------------------------------------
1 | import { v4 as uuidv4 } from 'uuid'
2 | import { computed } from 'vue'
3 |
4 | export function useFormKitSection(context: any) {
5 | const hasPrefix = computed(() => {
6 | return Boolean(context?.prefix?.length > 0)
7 | })
8 |
9 | const hasPrefixIcon = computed(() => {
10 | return Boolean(context?.iconPrefix?.length > 0)
11 | })
12 |
13 | const hasSuffixIcon = computed(() => {
14 | return Boolean(context?.iconSuffix?.length > 0)
15 | })
16 |
17 | const hasSuffix = computed(() => {
18 | return Boolean(context?.suffix?.length > 0)
19 | })
20 |
21 | function generateId() {
22 | return uuidv4()
23 | }
24 |
25 | return { generateId, hasPrefix, hasPrefixIcon, hasSuffix, hasSuffixIcon }
26 | }
27 |
--------------------------------------------------------------------------------
/src/composables/useOutputDuration.ts:
--------------------------------------------------------------------------------
1 | export function useOutputDuration() {
2 | function durationToMinutes(duration: string): number {
3 | let hours = 0
4 | let minutes = 0
5 |
6 | const lowerDuration = duration.toLowerCase()
7 |
8 | if (lowerDuration.includes(':')) {
9 | [hours, minutes] = lowerDuration.split(':').map(part => +part.trim())
10 | }
11 | else {
12 | if (lowerDuration.includes('h')) {
13 | hours = +lowerDuration.split('h')[0].trim()
14 | const remainder = lowerDuration.split('h')[1] || ''
15 |
16 | if (remainder.includes('m'))
17 | minutes = +remainder.split('m')[0].trim()
18 | else if (/^\d+$/.test(remainder))
19 | minutes = +remainder
20 | }
21 | else if (lowerDuration.includes('m')) {
22 | minutes = +lowerDuration.split('m')[0].trim()
23 | }
24 | else if (/^\d+$/.test(lowerDuration)) {
25 | minutes = +lowerDuration
26 | }
27 | }
28 |
29 | return hours * 60 + minutes
30 | }
31 |
32 | function formattedDuration(duration: string): string {
33 | const minutes = durationToMinutes(duration)
34 | const hours = Math.trunc(minutes / 60)
35 | const remainingMinutes = minutes % 60
36 |
37 | if (minutes === 0)
38 | return '0'
39 | return `${hours > 0 ? `${hours}h` : ''}${hours > 0 && remainingMinutes > 0 ? ' ' : ''}${remainingMinutes > 0 ? `${remainingMinutes}m` : ''}`
40 | }
41 |
42 | return { durationToMinutes, formattedDuration }
43 | }
44 |
--------------------------------------------------------------------------------
/src/composables/usePrimeInputs.ts:
--------------------------------------------------------------------------------
1 | import AutoComplete from 'primevue/autocomplete'
2 | import Button from 'primevue/button'
3 | import CascadeSelect from 'primevue/cascadeselect'
4 | import Checkbox from 'primevue/checkbox'
5 | import Chip from 'primevue/chip'
6 | import ColorPicker from 'primevue/colorpicker'
7 | import DatePicker from 'primevue/datepicker'
8 | import InputMask from 'primevue/inputmask'
9 | import InputNumber from 'primevue/inputnumber'
10 | import InputOtp from 'primevue/inputotp'
11 | import InputText from 'primevue/inputtext'
12 | import Knob from 'primevue/knob'
13 | import Listbox from 'primevue/listbox'
14 | import MultiSelect from 'primevue/multiselect'
15 | import Password from 'primevue/password'
16 | import RadioButton from 'primevue/radiobutton'
17 | import Rating from 'primevue/rating'
18 | import Select from 'primevue/select'
19 | import SelectButton from 'primevue/selectbutton'
20 | import Slider from 'primevue/slider'
21 | import Textarea from 'primevue/textarea'
22 | import ToggleButton from 'primevue/togglebutton'
23 | import ToggleSwitch from 'primevue/toggleswitch'
24 | import TreeSelect from 'primevue/treeselect'
25 |
26 | export function usePrimeInputs() {
27 | function registerInputs(app: any) {
28 | app.component('AutoComplete', AutoComplete)
29 | app.component('Button', Button)
30 | app.component('CascadeSelect', CascadeSelect)
31 | app.component('Checkbox', Checkbox)
32 | app.component('Chip', Chip)
33 | app.component('ColorPicker', ColorPicker)
34 | app.component('DatePicker', DatePicker)
35 | app.component('InputMask', InputMask)
36 | app.component('InputNumber', InputNumber)
37 | app.component('InputOtp', InputOtp)
38 | app.component('InputText', InputText)
39 | app.component('Knob', Knob)
40 | app.component('Listbox', Listbox)
41 | app.component('MultiSelect', MultiSelect)
42 | app.component('Password', Password)
43 | app.component('RadioButton', RadioButton)
44 | app.component('Rating', Rating)
45 | app.component('Select', Select)
46 | app.component('SelectButton', SelectButton)
47 | app.component('Slider', Slider)
48 | app.component('Textarea', Textarea)
49 | app.component('ToggleButton', ToggleButton)
50 | app.component('ToggleSwitch', ToggleSwitch)
51 | app.component('TreeSelect', TreeSelect)
52 | }
53 | return { registerInputs }
54 | }
55 |
--------------------------------------------------------------------------------
/src/definitions/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | primeAutoCompleteDefinition,
3 | primeCascadeSelectDefinition,
4 | primeCheckboxDefinition,
5 | primeColorPickerDefinition,
6 | primeDatePickerDefinition,
7 | primeEditorDefinition,
8 | primeInputMaskDefinition,
9 | primeInputNumberDefinition,
10 | primeInputOtpDefinition,
11 | primeInputTextDefinition,
12 | primeKnobDefinition,
13 | primeListboxDefinition,
14 | primeMultiSelectDefinition,
15 | primePasswordDefinition,
16 | primeRadioButtonDefinition,
17 | primeRatingDefinition,
18 | primeSelectButtonDefinition,
19 | primeSelectDefinition,
20 | primeSliderDefinition,
21 | primeTextareaDefinition,
22 | primeToggleButtonDefinition,
23 | primeToggleSwitchDefinition,
24 | primeTreeSelectDefinition,
25 | } from './input'
26 |
27 | import {
28 | primeOutputBooleanDefinition,
29 | primeOutputDateDefinition,
30 | primeOutputDurationDefinition,
31 | primeOutputLinkDefinition,
32 | primeOutputListDefinition,
33 | primeOutputNumberDefinition,
34 | primeOutputReferenceDefinition,
35 | primeOutputTextDefinition,
36 | } from './output'
37 |
38 | export const primeInputs = {
39 | primeAutoComplete: primeAutoCompleteDefinition,
40 | primeInputText: primeInputTextDefinition,
41 | primeInputNumber: primeInputNumberDefinition,
42 | primeInputMask: primeInputMaskDefinition,
43 | primePassword: primePasswordDefinition,
44 | primeCheckbox: primeCheckboxDefinition,
45 | primeToggleSwitch: primeToggleSwitchDefinition,
46 | primeTextarea: primeTextareaDefinition,
47 | primeSelect: primeSelectDefinition,
48 | primeMultiSelect: primeMultiSelectDefinition,
49 | primeDatePicker: primeDatePickerDefinition,
50 | primeSlider: primeSliderDefinition,
51 | primeKnob: primeKnobDefinition,
52 | primeRating: primeRatingDefinition,
53 | primeRadioButton: primeRadioButtonDefinition,
54 | primeColorPicker: primeColorPickerDefinition,
55 | primeToggleButton: primeToggleButtonDefinition,
56 | primeListbox: primeListboxDefinition,
57 | primeSelectButton: primeSelectButtonDefinition,
58 | primeCascadeSelect: primeCascadeSelectDefinition,
59 | primeTreeSelect: primeTreeSelectDefinition,
60 | primeInputOtp: primeInputOtpDefinition,
61 | primeEditor: primeEditorDefinition,
62 | }
63 |
64 | export const primeOutputs = {
65 | primeOutputText: primeOutputTextDefinition,
66 | primeOutputLink: primeOutputLinkDefinition,
67 | primeOutputReference: primeOutputReferenceDefinition,
68 | primeOutputNumber: primeOutputNumberDefinition,
69 | primeOutputDate: primeOutputDateDefinition,
70 | primeOutputBoolean: primeOutputBooleanDefinition,
71 | primeOutputDuration: primeOutputDurationDefinition,
72 | primeOutputList: primeOutputListDefinition,
73 | primeEditor: primeEditorDefinition,
74 | }
75 |
--------------------------------------------------------------------------------
/src/definitions/output.ts:
--------------------------------------------------------------------------------
1 | import type { FormKitTypeDefinition } from '@formkit/core'
2 | import { createInput } from '@formkit/vue'
3 | import PrimeOutputBoolean from '../components/PrimeOutputBoolean.vue'
4 | import PrimeOutputDate from '../components/PrimeOutputDate.vue'
5 | import PrimeOutputDuration from '../components/PrimeOutputDuration.vue'
6 | import PrimeOutputLink from '../components/PrimeOutputLink.vue'
7 | import PrimeOutputList from '../components/PrimeOutputList.vue'
8 | import PrimeOutputNumber from '../components/PrimeOutputNumber.vue'
9 | import PrimeOutputReference from '../components/PrimeOutputReference.vue'
10 | import PrimeOutputText from '../components/PrimeOutputText.vue'
11 |
12 | export const primeOutputTextDefinition: FormKitTypeDefinition = createInput(PrimeOutputText, {
13 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix', 'isTranslationKey', 'html'],
14 | })
15 |
16 | export const primeOutputDateDefinition: FormKitTypeDefinition = createInput(PrimeOutputDate, {
17 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix'],
18 | })
19 |
20 | export const primeOutputNumberDefinition: FormKitTypeDefinition = createInput(PrimeOutputNumber, {
21 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix'],
22 | })
23 |
24 | export const primeOutputLinkDefinition: FormKitTypeDefinition = createInput(PrimeOutputLink, {
25 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix', 'title'],
26 | })
27 |
28 | export const primeOutputReferenceDefinition: FormKitTypeDefinition = createInput(PrimeOutputReference, {
29 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix', 'reference', 'internal', 'linkComponentName', 'title'],
30 | })
31 |
32 | export const primeOutputBooleanDefinition: FormKitTypeDefinition = createInput(PrimeOutputBoolean, {
33 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix', 'trueValue', 'falseValue'],
34 | })
35 |
36 | export const primeOutputDurationDefinition: FormKitTypeDefinition = createInput(PrimeOutputDuration, {
37 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix'],
38 | })
39 |
40 | export const primeOutputListDefinition: FormKitTypeDefinition = createInput(PrimeOutputList, {
41 | props: ['prefix', 'suffix', 'iconPrefix', 'iconSuffix', 'divider', 'itemClass', 'dividerClass', 'listStyle'],
42 | })
43 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { FormKitInputs } from '@formkit/inputs'
2 | import type { CascadeSelectProps } from 'primevue/cascadeselect'
3 | import type { ListboxProps } from 'primevue/listbox'
4 | import type { MultiSelectProps } from 'primevue/multiselect'
5 | import type { SelectProps } from 'primevue/select'
6 | import type { SelectButtonProps } from 'primevue/selectbutton'
7 | import type { TreeSelectProps } from 'primevue/treeselect'
8 | import { FormKitDataDebug, FormKitDataEdit, FormKitDataView } from './components'
9 | import { useFormKitRepeater, useFormKitSchema, useInputEditor, useInputEditorSchema, usePrimeInputs } from './composables'
10 | import { primeInputs, primeOutputs } from './definitions'
11 |
12 | export {
13 | FormKitDataDebug,
14 | FormKitDataEdit,
15 | FormKitDataView,
16 | primeInputs,
17 | primeOutputs,
18 | useFormKitRepeater,
19 | useFormKitSchema,
20 | useInputEditor,
21 | useInputEditorSchema,
22 | usePrimeInputs,
23 | }
24 |
25 | declare module '@formkit/inputs' {
26 | interface FormKitInputProps> {
27 | primeAutoComplete: {
28 | type: 'primeAutoComplete'
29 | }
30 | primeInputText: {
31 | type: 'primeInputText'
32 | }
33 | primeInputNumber: {
34 | type: 'primeInputNumber'
35 | }
36 | primeInputMask: {
37 | type: 'primeInputMask'
38 | }
39 | primePassword: {
40 | type: 'primePassword'
41 | }
42 | primeCheckbox: {
43 | type: 'primeCheckbox'
44 | }
45 | primeToggleSwitch: {
46 | type: 'primeToggleSwitch'
47 | }
48 | primeTextarea: {
49 | type: 'primeTextarea'
50 | }
51 | primeEditor: {
52 | type: 'primeEditor'
53 | }
54 | primeSelect: {
55 | type: 'primeSelect'
56 | options?: SelectProps['options']
57 | }
58 | primeMultiSelect: {
59 | type: 'primeMultiSelect'
60 | options?: MultiSelectProps['options']
61 | }
62 | primeDatePicker: {
63 | type: 'primeDatePicker'
64 | }
65 | primeSlider: {
66 | type: 'primeSlider'
67 | }
68 | primeKnob: {
69 | type: 'primeKnob'
70 | }
71 | primeRating: {
72 | type: 'primeRating'
73 | }
74 | primeRadioButton: {
75 | type: 'primeRadioButton'
76 | }
77 | primeColorPicker: {
78 | type: 'primeColorPicker'
79 | }
80 | primeToggleButton: {
81 | type: 'primeToggleButton'
82 | }
83 | primeListbox: {
84 | type: 'primeListbox'
85 | options?: ListboxProps['options']
86 | }
87 | primeSelectButton: {
88 | type: 'primeSelectButton'
89 | options?: SelectButtonProps['options']
90 | }
91 | primeCascadeSelect: {
92 | type: 'primeCascadeSelect'
93 | options?: CascadeSelectProps['options']
94 | }
95 | primeTreeSelect: {
96 | type: 'primeTreeSelect'
97 | options?: TreeSelectProps['options']
98 | }
99 | primeInputOtp: {
100 | type: 'primeInputOtp'
101 | }
102 | primeOutputText: {
103 | type: 'primeOutputText'
104 | }
105 | primeOutputLink: {
106 | type: 'primeOutputLink'
107 | }
108 | primeOutputReference: {
109 | type: 'primeOutputReference'
110 | }
111 | primeOutputNumber: {
112 | type: 'primeOutputNumber'
113 | }
114 | primeOutputDate: {
115 | type: 'primeOutputDate'
116 | }
117 | primeOutputBoolean: {
118 | type: 'primeOutputBoolean'
119 | }
120 | primeOutputDuration: {
121 | type: 'primeOutputDuration'
122 | }
123 | primeOutputList: {
124 | type: 'primeOutputList'
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/plugins/index.ts:
--------------------------------------------------------------------------------
1 | import type { FormKitExtendableSchemaRoot, FormKitNode } from '@formkit/core'
2 |
3 | export function addPrimeAsteriskPlugin(node: FormKitNode): void {
4 | if (!node.props.type.startsWith('prime'))
5 | return
6 |
7 | node.on('created', () => {
8 | if (node.props.definition?.schema) {
9 | const schemaFn = node.props.definition?.schema as FormKitExtendableSchemaRoot
10 | node.props.definition!.schema = (sectionsSchema = {}) => {
11 | sectionsSchema.label = {
12 | children: ['$label', {
13 | $el: 'span',
14 | if: '$state.required',
15 | attrs: {
16 | class: 'p-formkit-asterisk',
17 | },
18 | children: ['*'],
19 | }],
20 | }
21 |
22 | return schemaFn(sectionsSchema)
23 | }
24 | }
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/test/useOutputDuration.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, it } from 'vitest'
2 | import { useOutputDuration } from '../src/composables'
3 |
4 | it('durationToMinutes', () => {
5 | const { durationToMinutes } = useOutputDuration()
6 | expect(durationToMinutes('2h')).toBe(120)
7 | expect(durationToMinutes('40m')).toBe(40)
8 | expect(durationToMinutes('2h20m')).toBe(140)
9 | expect(durationToMinutes('2:40')).toBe(160)
10 | })
11 |
12 | it('formattedDuration', () => {
13 | const { formattedDuration } = useOutputDuration()
14 | expect(formattedDuration('120m')).toBe('2h')
15 | expect(formattedDuration('40m')).toBe('40m')
16 | expect(formattedDuration('140m')).toBe('2h 20m')
17 | })
18 |
19 | it('handles empty duration string', () => {
20 | const { durationToMinutes } = useOutputDuration()
21 | expect(durationToMinutes('')).toBe(0)
22 | })
23 |
24 | it('handles hours-only duration', () => {
25 | const { durationToMinutes } = useOutputDuration()
26 | expect(durationToMinutes('3h')).toBe(180)
27 | })
28 |
29 | it('handles minutes-only duration', () => {
30 | const { durationToMinutes } = useOutputDuration()
31 | expect(durationToMinutes('45m')).toBe(45)
32 | })
33 |
34 | it('handles colon-separated hours and minutes', () => {
35 | const { durationToMinutes } = useOutputDuration()
36 | expect(durationToMinutes('1:30')).toBe(90)
37 | })
38 |
39 | it('handles text format hours and minutes', () => {
40 | const { durationToMinutes } = useOutputDuration()
41 | expect(durationToMinutes('2h15m')).toBe(135)
42 | })
43 |
44 | it('returns original string for invalid input', () => {
45 | const { formattedDuration } = useOutputDuration()
46 | expect(formattedDuration('invalid')).toBe('0')
47 | })
48 |
49 | it('formats minutes-only duration', () => {
50 | const { formattedDuration } = useOutputDuration()
51 | expect(formattedDuration('45m')).toBe('45m')
52 | })
53 |
54 | it('formats hours-only duration', () => {
55 | const { formattedDuration } = useOutputDuration()
56 | expect(formattedDuration('120m')).toBe('2h')
57 | })
58 |
59 | it('formats hours and minutes duration', () => {
60 | const { formattedDuration } = useOutputDuration()
61 | expect(formattedDuration('135M')).toBe('2h 15m')
62 | })
63 |
64 | it('handles non-numeric duration values', () => {
65 | const { durationToMinutes } = useOutputDuration()
66 | expect(durationToMinutes('h')).toBe(0)
67 | expect(durationToMinutes('m')).toBe(0)
68 | })
69 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@vue/tsconfig/tsconfig.dom.json",
3 | "compilerOptions": {
4 | "types": ["vitest/globals"]
5 | },
6 | "include": [
7 | "src",
8 | "test"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import vue from '@vitejs/plugin-vue'
2 | import { defineConfig } from 'vite'
3 |
4 | export default defineConfig({
5 | plugins: [vue()],
6 | test: {
7 | // enable jest-like global test APIs
8 | globals: true,
9 |
10 | // simulate DOM with happy-dom
11 | // (requires installing happy-dom as a peer dependency)
12 | environment: 'happy-dom',
13 |
14 | coverage: {
15 | exclude: ['dev/**', 'docs/**'],
16 | },
17 | },
18 | })
19 |
--------------------------------------------------------------------------------