diff --git a/package.json b/package.json
index b5a74e17ec..5357fc9be7 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"lint:style": "yarn workspace vuestic-ui lint:style",
"serve:docs": "yarn workspace docs serve",
"build:docs": "yarn workspace docs build",
- "build:docs:ci": "yarn workspace docs build:ci",
+ "build:docs:ci": "yarn workspace @vuestic/formkit build && yarn workspace docs build:ci",
"push": "yarn workspace vuestic-ui push",
"push-production": "yarn workspace vuestic-ui push-production",
"build:nuxt": "yarn workspace @vuestic/nuxt build",
@@ -34,7 +34,10 @@
"sandbox:nuxt": "yarn workspace sandbox dev:nuxt",
"sandbox:vue-cli": "yarn workspace sandbox dev:vue-cli",
"sandbox:web-components": "yarn workspace sandbox dev:web-components",
- "release": "yarn workspace deploy release"
+ "release": "yarn workspace deploy release",
+ "serve:formkit": "yarn workspace @vuestic/formkit serve:storybook",
+ "build:formkit": "yarn workspace @vuestic/formkit build:storybook",
+ "start:formkit": "yarn workspace @vuestic/formkit start:storybook"
},
"workspaces": {
"packages": [
@@ -56,6 +59,7 @@
"@vue/server-renderer": "3.5.12",
"@vue/compiler-dom": "3.5.12",
"sass": "1.52.0",
+ "typescript": "5.3.2",
"vue-tsc": "2.0.7"
}
}
diff --git a/packages/docs/formkit.config.ts b/packages/docs/formkit.config.ts
new file mode 100644
index 0000000000..22ad165205
--- /dev/null
+++ b/packages/docs/formkit.config.ts
@@ -0,0 +1,6 @@
+import { defaultConfig } from '@formkit/vue'
+import * as inputs from '@vuestic/formkit'
+
+export default defaultConfig({
+ inputs,
+})
diff --git a/packages/docs/nuxt.config.ts b/packages/docs/nuxt.config.ts
index 40a9f28aa0..7286bb4fa9 100644
--- a/packages/docs/nuxt.config.ts
+++ b/packages/docs/nuxt.config.ts
@@ -74,12 +74,14 @@ export default defineNuxtConfig({
nitro: {
// compressPublicAssets: true,
},
+
gtm: {
id: process.env.GTM_ID, // Your GTM single container ID, array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'] or array of objects [{id: 'GTM-xxxxxx', queryParams: { gtm_auth: 'abc123', gtm_preview: 'env-4', gtm_cookies_win: 'x'}}, {id: 'GTM-yyyyyy', queryParams: {gtm_auth: 'abc234', gtm_preview: 'env-5', gtm_cookies_win: 'x'}}], // Your GTM single container ID or array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy']
enabled: process.env.GTM_ENABLED === 'true', // defaults to true. Plugin can be disabled by setting this to false for Ex: enabled: !!GDPR_Cookie (optional)
},
modules: [
+ '@formkit/nuxt',
'./modules/repl',
'./modules/banner',
'./modules/vuestic',
@@ -139,7 +141,6 @@ export default defineNuxtConfig({
},
},
-
css: [
'@/assets/css/tailwind.css',
],
@@ -183,6 +184,13 @@ export default defineNuxtConfig({
}
},
+ formkit: {
+ defaultConfig: false,
+ autoImport: true,
+ },
+
+ compatibilityDate: '2024-11-29',
+
devtools: {
enabled: false,
}
diff --git a/packages/docs/package.json b/packages/docs/package.json
index 7bb6444d14..283a801f66 100644
--- a/packages/docs/package.json
+++ b/packages/docs/package.json
@@ -41,6 +41,7 @@
},
"dependencies": {
"@docsearch/js": "^3.2.1",
+ "@formkit/nuxt": "^1.6.9",
"@funken-studio/sitemap-nuxt-3": "^4.0.4",
"@nuxtjs/google-fonts": "^3.0.1",
"@types/acorn": "^6.0.0",
diff --git a/packages/docs/page-config/extensions/formkit/examples/AdvancedForm.vue b/packages/docs/page-config/extensions/formkit/examples/AdvancedForm.vue
new file mode 100644
index 0000000000..ecb612b305
--- /dev/null
+++ b/packages/docs/page-config/extensions/formkit/examples/AdvancedForm.vue
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Payment method
+
+
+
+
+
+
+ Submit
+
+
+
+
+
+ Validate
+
+
+ Reset validation
+
+
+ Reset
+
+
+
+
+
diff --git a/packages/docs/page-config/extensions/formkit/examples/BasicForm.vue b/packages/docs/page-config/extensions/formkit/examples/BasicForm.vue
new file mode 100644
index 0000000000..ad9b560110
--- /dev/null
+++ b/packages/docs/page-config/extensions/formkit/examples/BasicForm.vue
@@ -0,0 +1,66 @@
+
+
+ Carbon Sequestration Grant
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formValue }}
+
+
+
+
+
+
diff --git a/packages/docs/page-config/extensions/formkit/examples/MultiStepForm.vue b/packages/docs/page-config/extensions/formkit/examples/MultiStepForm.vue
new file mode 100644
index 0000000000..585c2256b2
--- /dev/null
+++ b/packages/docs/page-config/extensions/formkit/examples/MultiStepForm.vue
@@ -0,0 +1,245 @@
+
+
+ Carbon Sequestration Grant
+
+
+
+
+
+
+
+ check
+
+ {{ camel2title(stepName) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'Previous step' }}
+
+
+
+ {{ 'Next step' }}
+
+
+
+
+ {{ loading ? 'Submitting...' : 'Submit Application' }}
+
+
+
+
+
+ {{ formValue }}
+
+
+
+
+
+
diff --git a/packages/docs/page-config/extensions/formkit/examples/useSteps.js b/packages/docs/page-config/extensions/formkit/examples/useSteps.js
new file mode 100644
index 0000000000..2be132b500
--- /dev/null
+++ b/packages/docs/page-config/extensions/formkit/examples/useSteps.js
@@ -0,0 +1,69 @@
+import { reactive, toRef, ref, watch } from 'vue'
+import { getNode, createMessage } from '@formkit/core'
+
+export default function useSteps () {
+ const activeStep = ref('')
+ const steps = reactive({})
+ const visitedSteps = ref([]) // track visited steps
+
+ // NEW: watch our activeStep and store visited steps
+ // to know when to show errors
+ watch(activeStep, (newStep, oldStep) => {
+ if (oldStep && !visitedSteps.value.includes(oldStep)) {
+ visitedSteps.value.push(oldStep)
+ }
+ // NEW: trigger showing validation on fields
+ // within all visited steps
+ visitedSteps.value.forEach((step) => {
+ const node = getNode(step)
+ node.walk((n) => {
+ n.store.set(
+ createMessage({
+ key: 'submitted',
+ value: true,
+ visible: false,
+ })
+ )
+ })
+ })
+ })
+
+ const setStep = (delta) => {
+ const stepNames = Object.keys(steps)
+ const currentIndex = stepNames.indexOf(activeStep.value)
+ activeStep.value = stepNames[currentIndex + delta]
+ }
+
+ const stepPlugin = (node) => {
+ if (node.props.type === "group") {
+ // builds an object of the top-level groups
+ steps[node.name] = steps[node.name] || {}
+
+ node.on('created', () => {
+ // use 'on created' to ensure context object is available
+ steps[node.name].valid = toRef(node.context.state, 'valid')
+ })
+
+ // listen for changes in error count and store it
+ node.on('count:errors', ({ payload: count }) => {
+ steps[node.name].errorCount = count
+ })
+
+ // listen for changes in count of blocking validations messages
+ node.on('count:blocking', ({ payload: count }) => {
+ steps[node.name].blockingCount = count
+ })
+
+ // set the active tab to the 1st tab
+ if (activeStep.value === '') {
+ activeStep.value = node.name
+ }
+
+ // Stop plugin inheritance to descendant nodes
+ return false
+ }
+ }
+
+ // NEW: include visitedSteps in our return
+ return { activeStep, visitedSteps, steps, stepPlugin, setStep }
+}
diff --git a/packages/docs/page-config/extensions/formkit/examples/utils.js b/packages/docs/page-config/extensions/formkit/examples/utils.js
new file mode 100644
index 0000000000..b4754cfa3b
--- /dev/null
+++ b/packages/docs/page-config/extensions/formkit/examples/utils.js
@@ -0,0 +1,32 @@
+export { axios, camel2title }
+
+// This is just a mock of an actual axios instance.
+const axios = {
+ post: (formData) => {
+ return new Promise((resolve, reject) => {
+ let response = { status: 200 }
+ if (formData.organizationInfo.org_name.toLowerCase().trim() !== 'formkit') {
+ response = {
+ status: 400,
+ formErrors: ['There was an error in this form, please correct and re-submit to validate.'],
+ fieldErrors: {
+ 'organizationInfo.org_name': 'Organization Name must be "FormKit", we tricked you!'
+ }
+ }
+ }
+ setTimeout(() => {
+ if (response.status === 200) {
+ resolve(response)
+ } else {
+ reject(response)
+ }
+ }, 1500)
+ })
+
+ }
+}
+
+const camel2title = (str) => str
+ .replace(/([A-Z])/g, (match) => ` ${match}`)
+ .replace(/^./, (match) => match.toUpperCase())
+ .trim()
diff --git a/packages/docs/page-config/extensions/formkit/index.ts b/packages/docs/page-config/extensions/formkit/index.ts
new file mode 100644
index 0000000000..57d34c65e0
--- /dev/null
+++ b/packages/docs/page-config/extensions/formkit/index.ts
@@ -0,0 +1,51 @@
+const installCommandObject = {
+ npm: "npm install @vuestic/formkit",
+ yarn: "yarn add @vuestic/formkit",
+};
+
+
+const setupCode = `
+// main.*
+import { createApp } from 'vue'
+import App from './App.vue'
+
+import { plugin, defaultConfig } from '@formkit/vue'
+import * as inputs from '@vuestic/formkit'
+
+createApp(App)
+ .use(plugin, defaultConfig({ inputs }))
+ .mount('#app')
+`;
+
+const dependencies = {
+ "@vuestic/formkit": "latest",
+ "vuestic-ui": "latest",
+ "vue": "latest"
+};
+
+export default definePageConfig({
+ blocks: [
+ block.title("FormKit integration"),
+ block.paragraph("If you need a powerful tool for building forms, we recommend using the [FormKit](https://formkit.com/getting-started/what-is-formkit)[[target=_blank]] form framework. Vuestic UI provides a ready-made style theme for this framework."),
+ block.headline("FormKit installation"),
+ block.paragraph("To start using FormKit, install the dependencies in your project."),
+ block.code(installCommandObject, "bash"),
+ block.paragraph("Then add the plugin to your main.* file"),
+ block.code(setupCode, "js"),
+ block.subtitle("Examples"),
+ block.paragraph("Here are some implementation examples of what is possible with Vuestic and FormKit:"),
+ block.example("BasicForm", {
+ codesandboxConfig: { dependencies },
+ title: "Basic Form",
+ }),
+ block.example("AdvancedForm", {
+ codesandboxConfig: { dependencies },
+ title: "Advanced Form",
+ description: "[Here](https://ui.vuestic.dev/ui-elements/form#default-usage) you can find this example done using only Vuestic components."
+ }),
+ block.example("MultiStepForm", {
+ codesandboxConfig: { dependencies },
+ title: "Multi Step Form",
+ }),
+ ],
+});
diff --git a/packages/docs/page-config/navigationRoutes.ts b/packages/docs/page-config/navigationRoutes.ts
index aa80c26980..4a3460b981 100644
--- a/packages/docs/page-config/navigationRoutes.ts
+++ b/packages/docs/page-config/navigationRoutes.ts
@@ -651,6 +651,10 @@ export const navigationRoutes: NavigationRoute[] = [
meta: {
badge: navigationBadge.new('1.9.9'),
}
+ },
+ {
+ name: 'formkit',
+ displayName: 'FormKit integration',
}
],
},
diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json
index 7118c591fd..134b30335d 100644
--- a/packages/docs/tsconfig.json
+++ b/packages/docs/tsconfig.json
@@ -5,6 +5,7 @@
"compilerOptions": {
"types": [
"vite/client",
+ "@vuestic/formkit"
]
},
"exclude": [
diff --git a/packages/formkit/.npmignore b/packages/formkit/.npmignore
new file mode 100644
index 0000000000..036780d6fc
--- /dev/null
+++ b/packages/formkit/.npmignore
@@ -0,0 +1,3 @@
+/src/
+/playground/
+tsconfig.json
\ No newline at end of file
diff --git a/packages/formkit/.storybook/main.ts b/packages/formkit/.storybook/main.ts
new file mode 100644
index 0000000000..99cfcaac2a
--- /dev/null
+++ b/packages/formkit/.storybook/main.ts
@@ -0,0 +1,8 @@
+import { type StorybookConfig } from '@storybook/vue3-vite'
+
+const config: StorybookConfig = {
+ stories: ['../stories/**/**.stories.ts'],
+ framework: '@storybook/vue3-vite',
+}
+
+export default config
diff --git a/packages/formkit/.storybook/preview.ts b/packages/formkit/.storybook/preview.ts
new file mode 100644
index 0000000000..0ac02434b7
--- /dev/null
+++ b/packages/formkit/.storybook/preview.ts
@@ -0,0 +1,20 @@
+import { type Preview, setup } from '@storybook/vue3'
+import { createVuestic } from 'vuestic-ui'
+import { plugin as formkitPlugin, defaultConfig as formkitConfig } from '@formkit/vue'
+import * as inputs from '../src'
+import 'vuestic-ui/css'
+import 'vuestic-ui/styles/essential.css'
+import 'vuestic-ui/styles/typography.css'
+import './vuestic.css'
+import './tailwind.css'
+
+setup((app) => {
+ app.use(createVuestic())
+ app.use(formkitPlugin, formkitConfig({
+ inputs
+ }))
+})
+
+const preview: Preview = {}
+
+export default preview
diff --git a/packages/formkit/.storybook/tailwind.css b/packages/formkit/.storybook/tailwind.css
new file mode 100644
index 0000000000..d39710d7ec
--- /dev/null
+++ b/packages/formkit/.storybook/tailwind.css
@@ -0,0 +1 @@
+@import url('https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css');
diff --git a/packages/formkit/.storybook/vuestic.css b/packages/formkit/.storybook/vuestic.css
new file mode 100644
index 0000000000..c089eead15
--- /dev/null
+++ b/packages/formkit/.storybook/vuestic.css
@@ -0,0 +1,2 @@
+@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,400;1,700&display=swap");
+@import url("https://fonts.googleapis.com/icon?family=Material+Icons");
diff --git a/packages/formkit/README.md b/packages/formkit/README.md
new file mode 100644
index 0000000000..dc508e6840
--- /dev/null
+++ b/packages/formkit/README.md
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+# @vuestic/formkit
+
+The official Vuestic UI integration with FormKit. Read the [documentation](https://ui.vuestic.dev/extensions/formkit) for usage instructions.
diff --git a/packages/formkit/package.json b/packages/formkit/package.json
new file mode 100644
index 0000000000..4a1132d216
--- /dev/null
+++ b/packages/formkit/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@vuestic/formkit",
+ "version": "0.0.1",
+ "keywords": [
+ "vuesticui",
+ "vuestic",
+ "formkit",
+ "vue"
+ ],
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "description": "Custom FormKit inputs done with Vuestic UI.",
+ "homepage": "https://vuestic.dev",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/epicmaxco/vuestic-ui.git"
+ },
+ "license": "MIT",
+ "type": "module",
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "build": "tsup src/index.ts --format esm --dts",
+ "prepublishOnly": "npm run build",
+ "serve:storybook": "storybook dev -p 6007",
+ "build:storybook": "storybook build",
+ "start:storybook": "serve storybook-static"
+ },
+ "dependencies": {
+ "@formkit/core": "^1.6.9",
+ "@formkit/inputs": "^1.6.9",
+ "@formkit/utils": "^1.6.9",
+ "@formkit/vue": "^1.6.9"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.4",
+ "vuestic-ui": "^1.10.3"
+ },
+ "devDependencies": {
+ "@storybook/vue3-vite": "^7.1.0",
+ "storybook": "^7.1.0",
+ "tsup": "^6.5.0"
+ }
+}
diff --git a/packages/formkit/shims-vue.d.ts b/packages/formkit/shims-vue.d.ts
new file mode 100644
index 0000000000..4d6b5162a4
--- /dev/null
+++ b/packages/formkit/shims-vue.d.ts
@@ -0,0 +1,5 @@
+declare module '*.vue' {
+ import { DefineComponent } from '@vue/runtime-core'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/packages/formkit/src/createInputWrapper.ts b/packages/formkit/src/createInputWrapper.ts
new file mode 100644
index 0000000000..46f55e565f
--- /dev/null
+++ b/packages/formkit/src/createInputWrapper.ts
@@ -0,0 +1,40 @@
+import { type FormKitFrameworkContext } from '@formkit/core'
+import { type Component, defineComponent, h, type PropType } from 'vue'
+import { VaIcon } from 'vuestic-ui'
+
+export const createInputWrapper = (component: C) => {
+ return defineComponent({
+ name: `${component.name ?? 'Va'}FormKitWrapper`,
+
+ props: {
+ context: {
+ type: Object as PropType,
+ required: true,
+ },
+ prefixIcon: String as PropType,
+ suffixIcon: String as PropType,
+ },
+
+ setup(props, { slots, attrs }) {
+ return () => {
+ return h(component, {
+ ...attrs,
+ modelValue: props.context._value,
+ 'onUpdate:modelValue': props.context.node.input,
+ onBlur: props.context.handlers.blur,
+ error: props.context.error,
+ messages: props.context.help,
+ errorMessages: props.context.errorMessages,
+ disabled: props.context.disabled,
+ label: props.context.label,
+ loading: props.context.loading,
+ dirty: props.context.state.validationVisible,
+ }, {
+ ...(props.prefixIcon && { prependInner: () => h(VaIcon, { class: 'material-icons' }, props.prefixIcon) }),
+ ...(props.suffixIcon && { appendInner: () => h(VaIcon, { class: 'material-icons' }, props.suffixIcon) }),
+ ...slots
+ })
+ }
+ }
+ })
+}
diff --git a/packages/formkit/src/features/vuesticInputs.ts b/packages/formkit/src/features/vuesticInputs.ts
new file mode 100644
index 0000000000..7457478365
--- /dev/null
+++ b/packages/formkit/src/features/vuesticInputs.ts
@@ -0,0 +1,23 @@
+import type { FormKitNode } from '@formkit/core'
+import { computed } from 'vue';
+
+export function vuesticInputs(node: FormKitNode): void {
+ node.addProps(['loading'])
+
+ node.on('created', () => {
+ const errorMessages = computed(() =>
+ node.context!.fns.arrayMessages(node.context!.messages)
+ )
+ const error = computed(() =>
+ node.context!.defaultMessagePlacement && Boolean(node.context!.fns.length(node.context!.messages))
+ )
+
+ node.context!.fns.arrayMessages = (obj: Record) =>
+ Object.values(obj)
+ .filter(m => m.visible)
+ .map(m => m.value)
+
+ node.context!.errorMessages = errorMessages
+ node.context!.error = error
+ })
+}
diff --git a/packages/formkit/src/index.ts b/packages/formkit/src/index.ts
new file mode 100644
index 0000000000..57eddbc4e8
--- /dev/null
+++ b/packages/formkit/src/index.ts
@@ -0,0 +1,23 @@
+export { group, hidden, list, meta } from '@formkit/inputs'
+export { button } from './inputs/button'
+export { checkbox } from './inputs/checkbox'
+export { colorpicker } from './inputs/colorpicker'
+export { counter } from './inputs/counter'
+export { datepicker } from './inputs/datepicker'
+export { email } from './inputs/email'
+export { file } from './inputs/file'
+export { form } from './inputs/form'
+export { number } from './inputs/number'
+export { password } from './inputs/password'
+export { radio } from './inputs/radio'
+export { rating } from './inputs/rating'
+export { select } from './inputs/select.ts'
+export { slider } from './inputs/slider'
+export { submit } from './inputs/submit'
+export { tel } from './inputs/tel'
+export { text } from './inputs/text'
+export { textarea } from './inputs/textarea'
+export { timepicker } from './inputs/timepicker'
+export { toggle } from './inputs/toggle'
+export { togglebuttons } from './inputs/togglebuttons'
+export { url } from './inputs/url'
diff --git a/packages/formkit/src/inputs/button.ts b/packages/formkit/src/inputs/button.ts
new file mode 100644
index 0000000000..8a9ce2d250
--- /dev/null
+++ b/packages/formkit/src/inputs/button.ts
@@ -0,0 +1,83 @@
+import { FormKitTypeDefinition } from '@formkit/core'
+import {
+ outer,
+ wrapper,
+ prefix,
+ suffix,
+ createSection,
+ buttonLabel,
+ localize,
+ ignores,
+} from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaButton, VaMessageList, VaIcon } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { icon, messages, help } from '../sections'
+
+export const buttonInput = createSection('input', () => ({
+ $cmp: 'VaButton',
+ bind: '$attrs',
+ props: {
+ type: '$type',
+ disabled: '$disabled',
+ name: '$node.name',
+ id: '$id',
+ loading: '$loading'
+ },
+}))
+
+/**
+ * Input definition for a button.
+ * @public
+ */
+export const button: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: outer(
+ messages(),
+ wrapper(
+ buttonInput(
+ icon('prefix'),
+ prefix(),
+ buttonLabel('$label || $ui.submit.value'),
+ suffix(),
+ icon('suffix')
+ )
+ ),
+ help()
+ ),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'button',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * Forces node.props.type to be this explicit value.
+ */
+ forceTypeProp: 'button',
+
+ library: {
+ VaButton,
+ VaMessageList,
+ VaIcon
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [localize('submit'), ignores, vuesticInputs],
+
+ /**
+ * A key to use for memoizing the schema. This is used to prevent the schema
+ * from needing to be stringified when performing a memo lookup.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/checkbox.ts b/packages/formkit/src/inputs/checkbox.ts
new file mode 100644
index 0000000000..5af837d479
--- /dev/null
+++ b/packages/formkit/src/inputs/checkbox.ts
@@ -0,0 +1,60 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaCheckbox } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaCheckbox)
+
+const boxInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a checkbox.
+ * @public
+ */
+export const checkbox: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: boxInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Forces node.props.type to be this explicit value.
+ */
+ forceTypeProp: 'checkbox',
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/colorpicker.ts b/packages/formkit/src/inputs/colorpicker.ts
new file mode 100644
index 0000000000..fae01f0495
--- /dev/null
+++ b/packages/formkit/src/inputs/colorpicker.ts
@@ -0,0 +1,60 @@
+import type { FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaColorInput } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaColorInput);
+
+const colorInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a colorpicker.
+ * @public
+ */
+export const colorpicker: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: colorInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Forces node.props.type to be this explicit value.
+ */
+ forceTypeProp: 'text',
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/counter.ts b/packages/formkit/src/inputs/counter.ts
new file mode 100644
index 0000000000..33b2863ffd
--- /dev/null
+++ b/packages/formkit/src/inputs/counter.ts
@@ -0,0 +1,60 @@
+import type { FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaCounter } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaCounter);
+
+const counterInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a counter.
+ * @public
+ */
+export const counter: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: counterInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Forces node.props.type to be this explicit value.
+ */
+ forceTypeProp: 'text',
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/datepicker.ts b/packages/formkit/src/inputs/datepicker.ts
new file mode 100644
index 0000000000..18ee9ea675
--- /dev/null
+++ b/packages/formkit/src/inputs/datepicker.ts
@@ -0,0 +1,60 @@
+import type { FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaDateInput } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+
+const dateInput = createSection('input', () => ({
+ $cmp: 'VaDateInput',
+ bind: '$attrs',
+ props: {
+ modelValue: '$node.context._value',
+ 'onUpdate:modelValue': '$node.context.node.input',
+ onBlur: '$node.context.handlers.blur',
+ error: '$node.context.error',
+ messages: '$node.context.help',
+ errorMessages: '$node.context.errorMessages',
+ disabled: '$node.context.disabled',
+ label: '$node.context.label',
+ loading: '$node.context.loading',
+ dirty: '$node.context.state.validationVisible',
+ },
+}))
+
+/**
+ * Input definition for a datepicker.
+ * @public
+ */
+export const datepicker: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: dateInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ VaDateInput,
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/email.ts b/packages/formkit/src/inputs/email.ts
new file mode 100644
index 0000000000..2ddd962b3e
--- /dev/null
+++ b/packages/formkit/src/inputs/email.ts
@@ -0,0 +1,13 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { token } from '@formkit/utils'
+import { text } from './text'
+
+/**
+ * Input definition for a email.
+ * @public
+ */
+export const email: FormKitTypeDefinition = {
+ ...text,
+ forceTypeProp: 'email',
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/file.ts b/packages/formkit/src/inputs/file.ts
new file mode 100644
index 0000000000..e2f2d4ee7b
--- /dev/null
+++ b/packages/formkit/src/inputs/file.ts
@@ -0,0 +1,61 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection, outer } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaFileUpload } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { help, messages } from '../sections';
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaFileUpload)
+
+const fileInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ },
+}))
+
+/**
+ * Input definition for a file.
+ * @public
+ */
+export const file: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: outer(
+ messages(),
+ fileInput(),
+ help(),
+ ),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/form.ts b/packages/formkit/src/inputs/form.ts
new file mode 100644
index 0000000000..db85dd3496
--- /dev/null
+++ b/packages/formkit/src/inputs/form.ts
@@ -0,0 +1,75 @@
+import { FormKitTypeDefinition } from '@formkit/core'
+import { token } from '@formkit/utils'
+import { VaForm, VaMessageList } from 'vuestic-ui'
+import {
+ actions,
+ createSection,
+ forms,
+ disablesChildren,
+} from '@formkit/inputs'
+import { messages } from '../sections'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { submit } from './submit'
+
+export const formInput = createSection('form', () => ({
+ $cmp: 'VaForm',
+ bind: '$attrs',
+ props: {
+ id: '$id',
+ name: '$node.name',
+ onSubmit: '$handlers.submit',
+ 'data-loading': '$state.loading || undefined',
+ },
+}))
+
+export const submitInput = createSection('submit', () => ({
+ $cmp: 'FormKit',
+ bind: '$submitAttrs',
+ props: {
+ type: submit,
+ },
+ children: "$submitLabel || Submit"
+}))
+
+/**
+ * Input definition for a form.
+ * @public
+ */
+export const form: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: formInput(
+ '$slots.default',
+ messages(),
+ actions(submitInput())
+ ),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'group',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [
+ 'actions',
+ 'submit',
+ 'submitLabel',
+ 'submitAttrs',
+ 'submitBehavior',
+ 'incompleteMessage',
+ ],
+
+ library: {
+ VaForm,
+ VaMessageList,
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs, forms, disablesChildren],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/number.ts b/packages/formkit/src/inputs/number.ts
new file mode 100644
index 0000000000..794938841d
--- /dev/null
+++ b/packages/formkit/src/inputs/number.ts
@@ -0,0 +1,13 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { token } from '@formkit/utils'
+import { text } from './text'
+
+/**
+ * Input definition for a number.
+ * @public
+ */
+export const number: FormKitTypeDefinition = {
+ ...text,
+ forceTypeProp: 'number',
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/password.ts b/packages/formkit/src/inputs/password.ts
new file mode 100644
index 0000000000..a3b1d4f511
--- /dev/null
+++ b/packages/formkit/src/inputs/password.ts
@@ -0,0 +1,13 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { token } from '@formkit/utils'
+import { text } from './text'
+
+/**
+ * Input definition for a password.
+ * @public
+ */
+export const password: FormKitTypeDefinition = {
+ ...text,
+ forceTypeProp: 'password',
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/radio.ts b/packages/formkit/src/inputs/radio.ts
new file mode 100644
index 0000000000..6a92cec4ac
--- /dev/null
+++ b/packages/formkit/src/inputs/radio.ts
@@ -0,0 +1,71 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaRadio, VaFormField } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+
+
+const radioInput = createSection('input', () => ({
+ $cmp: 'VaFormField',
+ props: {
+ error: '$node.context.error',
+ messages: '$node.context.help',
+ errorMessages: '$node.context.errorMessages',
+ loading: '$node.context.loading',
+ dirty: '$node.context.state.validationVisible',
+ label: '$node.context.label',
+ },
+ children: [
+ {
+ for: ['option', '$attrs.options'],
+ $cmp: 'VaRadio',
+ bind: '$attrs',
+ props: {
+ option: '$option',
+ modelValue: '$node.context._value',
+ 'onUpdate:modelValue': '$node.context.node.input',
+ onBlur: '$node.context.handlers.blur',
+ disabled: '$node.context.disabled',
+ }
+ }
+ ]
+}))
+
+/**
+ * Input definition for a radio.
+ * @public
+ */
+export const radio: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: radioInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ VaFormField,
+ VaRadio
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/rating.ts b/packages/formkit/src/inputs/rating.ts
new file mode 100644
index 0000000000..413941b984
--- /dev/null
+++ b/packages/formkit/src/inputs/rating.ts
@@ -0,0 +1,56 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaRating } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaRating)
+
+const ratingInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a rating.
+ * @public
+ */
+export const rating: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: ratingInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/select.ts b/packages/formkit/src/inputs/select.ts
new file mode 100644
index 0000000000..85e30a6200
--- /dev/null
+++ b/packages/formkit/src/inputs/select.ts
@@ -0,0 +1,56 @@
+import type { FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaSelect } from 'vuestic-ui'
+import { createInputWrapper } from '../createInputWrapper'
+import { vuesticInputs } from '../features/vuesticInputs'
+
+const FormKitInputWrapper = createInputWrapper(VaSelect);
+
+const dropdownInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+ /**
+ * Input definition for a dropdown.
+* @public
+*/
+export const select: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: dropdownInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper,
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/slider.ts b/packages/formkit/src/inputs/slider.ts
new file mode 100644
index 0000000000..606549a2d6
--- /dev/null
+++ b/packages/formkit/src/inputs/slider.ts
@@ -0,0 +1,68 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaSlider, VaFormField } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+
+const sliderInput = createSection('input', () => ({
+ $cmp: 'VaFormField',
+ props: {
+ error: '$node.context.error',
+ messages: '$node.context.help',
+ errorMessages: '$node.context.errorMessages',
+ loading: '$node.context.loading',
+ dirty: '$node.context.state.validationVisible',
+ },
+ children: [
+ {
+ $cmp: 'VaSlider',
+ bind: '$attrs',
+ props: {
+ modelValue: '$node.context._value',
+ 'onUpdate:modelValue': '$node.context.node.input',
+ onBlur: '$node.context.handlers.blur',
+ disabled: '$node.context.disabled',
+ label: '$node.context.label',
+ }
+ }
+ ]
+}))
+
+/**
+ * Input definition for a slider.
+ * @public
+ */
+export const slider: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: sliderInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ VaFormField,
+ VaSlider,
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/submit.ts b/packages/formkit/src/inputs/submit.ts
new file mode 100644
index 0000000000..560cdfadfb
--- /dev/null
+++ b/packages/formkit/src/inputs/submit.ts
@@ -0,0 +1,12 @@
+import { token } from '@formkit/utils'
+import { button } from './button'
+
+/**
+ * Input definition for a submit button.
+ * @public
+ */
+export const submit = {
+ ...button,
+ forceTypeProp: 'submit',
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/tel.ts b/packages/formkit/src/inputs/tel.ts
new file mode 100644
index 0000000000..5790844ca2
--- /dev/null
+++ b/packages/formkit/src/inputs/tel.ts
@@ -0,0 +1,13 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { token } from '@formkit/utils'
+import { text } from './text'
+
+/**
+ * Input definition for a telephone.
+ * @public
+ */
+export const tel: FormKitTypeDefinition = {
+ ...text,
+ forceTypeProp: 'tel',
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/text.ts b/packages/formkit/src/inputs/text.ts
new file mode 100644
index 0000000000..b8e1e8dd8c
--- /dev/null
+++ b/packages/formkit/src/inputs/text.ts
@@ -0,0 +1,60 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaInput } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaInput)
+
+const textInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a text.
+ * @public
+ */
+export const text: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: textInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Forces node.props.type to be this explicit value.
+ */
+ forceTypeProp: 'text',
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/textarea.ts b/packages/formkit/src/inputs/textarea.ts
new file mode 100644
index 0000000000..860ee71d46
--- /dev/null
+++ b/packages/formkit/src/inputs/textarea.ts
@@ -0,0 +1,60 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaTextarea } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaTextarea)
+
+const textareaInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a textarea.
+ * @public
+ */
+export const textarea: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: textareaInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Forces node.props.type to be this explicit value.
+ */
+ forceTypeProp: 'text',
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/timepicker.ts b/packages/formkit/src/inputs/timepicker.ts
new file mode 100644
index 0000000000..4e015ff29a
--- /dev/null
+++ b/packages/formkit/src/inputs/timepicker.ts
@@ -0,0 +1,60 @@
+import type { FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaTimeInput } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+
+const timeInput = createSection('input', () => ({
+ $cmp: 'VaTimeInput',
+ bind: '$attrs',
+ props: {
+ modelValue: '$node.context._value',
+ 'onUpdate:modelValue': '$node.context.node.input',
+ onBlur: '$node.context.handlers.blur',
+ error: '$node.context.error',
+ messages: '$node.context.help',
+ errorMessages: '$node.context.errorMessages',
+ disabled: '$node.context.disabled',
+ label: '$node.context.label',
+ loading: '$node.context.loading',
+ dirty: '$node.context.state.validationVisible',
+ }
+}))
+
+/**
+ * Input definition for a timepicker.
+ * @public
+ */
+export const timepicker: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: timeInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ VaTimeInput,
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/toggle.ts b/packages/formkit/src/inputs/toggle.ts
new file mode 100644
index 0000000000..04b5d82b8d
--- /dev/null
+++ b/packages/formkit/src/inputs/toggle.ts
@@ -0,0 +1,56 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaSwitch } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaSwitch)
+
+const toggleInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a toggle.
+ * @public
+ */
+export const toggle: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: toggleInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/togglebuttons.ts b/packages/formkit/src/inputs/togglebuttons.ts
new file mode 100644
index 0000000000..35c98c1aab
--- /dev/null
+++ b/packages/formkit/src/inputs/togglebuttons.ts
@@ -0,0 +1,60 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { createSection } from '@formkit/inputs'
+import { token } from '@formkit/utils'
+import { VaButtonToggle } from 'vuestic-ui'
+import { vuesticInputs } from '../features/vuesticInputs'
+import { createInputWrapper } from '../createInputWrapper'
+
+const FormKitInputWrapper = createInputWrapper(VaButtonToggle)
+
+const toggleButtonsInput = createSection('input', () => ({
+ $cmp: 'FormKitInputWrapper',
+ bind: '$attrs',
+ props: {
+ context: '$node.context',
+ prefixIcon: '$prefixIcon',
+ suffixIcon: '$suffixIcon'
+ }
+}))
+
+/**
+ * Input definition for a togglebuttons.
+ * @public
+ */
+export const togglebuttons: FormKitTypeDefinition = {
+ /**
+ * The actual schema of the input, or a function that returns the schema.
+ */
+ schema: toggleButtonsInput(),
+ /**
+ * The type of node, can be a list, group, or input.
+ */
+ type: 'input',
+ /**
+ * The family of inputs this one belongs too. For example "text" and "email"
+ * are both part of the "text" family. This is primary used for styling.
+ */
+ family: 'text',
+ /**
+ * An array of extra props to accept for this input.
+ */
+ props: [],
+ /**
+ * A library of components to provide to the internal input schema
+ */
+ library: {
+ FormKitInputWrapper
+ },
+ /**
+ * Forces node.props.type to be this explicit value.
+ */
+ forceTypeProp: 'text',
+ /**
+ * Additional features that should be added to your input
+ */
+ features: [vuesticInputs],
+ /**
+ * The key used to memoize the schema.
+ */
+ schemaMemoKey: token(),
+}
diff --git a/packages/formkit/src/inputs/url.ts b/packages/formkit/src/inputs/url.ts
new file mode 100644
index 0000000000..9b9ed23fdb
--- /dev/null
+++ b/packages/formkit/src/inputs/url.ts
@@ -0,0 +1,14 @@
+import { type FormKitTypeDefinition } from '@formkit/core'
+import { token } from '@formkit/utils'
+import { text } from './text'
+
+/**
+ * Input definition for a url.
+ * @public
+ */
+export const url: FormKitTypeDefinition = {
+ ...text,
+ forceTypeProp: 'url',
+ schemaMemoKey: token(),
+}
+
diff --git a/packages/formkit/src/sections/index.ts b/packages/formkit/src/sections/index.ts
new file mode 100644
index 0000000000..9aa73e1ccd
--- /dev/null
+++ b/packages/formkit/src/sections/index.ts
@@ -0,0 +1,44 @@
+import { createSection, type FormKitSchemaExtendableSection } from '@formkit/inputs'
+
+export const icon = (
+ sectionKey: string,
+ el?: string
+): FormKitSchemaExtendableSection => {
+ return createSection(`${sectionKey}Icon`, () => {
+ return {
+ if: `$${sectionKey}Icon`,
+ $cmp: 'VaIcon',
+ props: {
+ tag: el,
+ for: {
+ if: `${el === 'label'}`,
+ then: '$id',
+ },
+ class: 'material-icons',
+ onClick: `$handlers.iconClick(${sectionKey})`,
+ role: `$fns.iconRole(${sectionKey})`,
+ tabindex: `$fns.iconRole(${sectionKey}) === "button" && "0" || undefined`,
+ },
+ children: '$prefixIcon'
+ }
+ })()
+}
+
+export const help = createSection('help', () => ({
+ $cmp: 'VaMessageList',
+ if: '$help',
+ props: {
+ id: '$: "help-" + $id',
+ modelValue: '$help'
+ }
+}))
+
+export const messages = createSection('messages', () => ({
+ $cmp: 'VaMessageList',
+ if: '$defaultMessagePlacement && $fns.length($messages)',
+ props: {
+ id: '$: "errors-" + $id',
+ modelValue: '$fns.arrayMessages($messages)',
+ color: 'danger'
+ }
+}))
diff --git a/packages/formkit/stories/Button.stories.ts b/packages/formkit/stories/Button.stories.ts
new file mode 100644
index 0000000000..7bf2e567c2
--- /dev/null
+++ b/packages/formkit/stories/Button.stories.ts
@@ -0,0 +1,60 @@
+import { StoryFn } from '@storybook/vue3'
+
+export default {
+ title: 'Formkit Integration/Button',
+}
+
+export const Default: StoryFn = () => ({
+ setup () {
+ const randomColor = (e: { target: { setAttribute: (...args: string[]) => void } }) => {
+ const hex = Math
+ .floor(Math.random() * 16777215)
+ .toString(16)
+ e.target.setAttribute(
+ 'style',
+ 'background-color: #' + hex + '88;',
+ )
+ }
+
+ return {
+ randomColor,
+ }
+ },
+ template: `
+
+
Basic example
+
+
+ Default slot
+
+ I have slot content
+
+
+ Event listeners
+
+ Click me!
+
+
+ Loading
+
+ Click me!
+
+
+ `,
+})
diff --git a/packages/formkit/stories/Checkbox.stories.ts b/packages/formkit/stories/Checkbox.stories.ts
new file mode 100644
index 0000000000..aa83298ccf
--- /dev/null
+++ b/packages/formkit/stories/Checkbox.stories.ts
@@ -0,0 +1,26 @@
+import { StoryFn } from '@storybook/vue3'
+import { ref } from 'vue'
+
+export default {
+ title: 'Formkit Integration/Checkbox',
+}
+
+export const SingleCheckbox: StoryFn = () => ({
+ setup () {
+ const value = ref(true)
+ return {
+ value,
+ }
+ },
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/Colorpicker.stories.ts b/packages/formkit/stories/Colorpicker.stories.ts
new file mode 100644
index 0000000000..0d9927d4e3
--- /dev/null
+++ b/packages/formkit/stories/Colorpicker.stories.ts
@@ -0,0 +1,17 @@
+import { StoryFn } from '@storybook/vue3'
+
+export default {
+ title: 'Formkit Integration/Colorpicker',
+}
+
+export const Default: StoryFn = () => ({
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/Datepicker.stories.ts b/packages/formkit/stories/Datepicker.stories.ts
new file mode 100644
index 0000000000..ae031531f5
--- /dev/null
+++ b/packages/formkit/stories/Datepicker.stories.ts
@@ -0,0 +1,18 @@
+import { StoryFn } from '@storybook/vue3'
+
+export default {
+ title: 'Formkit Integration/Datepicker',
+}
+
+export const Default: StoryFn = () => ({
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/File.stories.ts b/packages/formkit/stories/File.stories.ts
new file mode 100644
index 0000000000..365eee74f0
--- /dev/null
+++ b/packages/formkit/stories/File.stories.ts
@@ -0,0 +1,18 @@
+import { StoryFn } from '@storybook/vue3'
+
+export default {
+ title: 'Formkit Integration/File',
+}
+
+export const Default: StoryFn = () => ({
+ template: `
+
+
+
+ `,
+})
diff --git a/packages/formkit/stories/Input.stories.ts b/packages/formkit/stories/Input.stories.ts
new file mode 100644
index 0000000000..b1fdd26909
--- /dev/null
+++ b/packages/formkit/stories/Input.stories.ts
@@ -0,0 +1,86 @@
+import { StoryFn } from '@storybook/vue3'
+
+export default {
+ title: 'Formkit Integration/Input',
+}
+
+export const Default: StoryFn = () => ({
+ template: `
+
+
Text input
+
+
+ Email
+
+
+ Number
+
+
+ Password
+
+ Create a new password
+
+
+
+
+ Telephone
+
+
+ Url
+
+
+ `,
+})
diff --git a/packages/formkit/stories/Radio.stories.ts b/packages/formkit/stories/Radio.stories.ts
new file mode 100644
index 0000000000..d896fba3d6
--- /dev/null
+++ b/packages/formkit/stories/Radio.stories.ts
@@ -0,0 +1,27 @@
+import { StoryFn } from '@storybook/vue3'
+import { ref } from 'vue'
+
+export default {
+ title: 'Formkit Integration/Radio',
+}
+
+export const Default: StoryFn = () => ({
+ setup () {
+ const form = ref({})
+ return {
+ form,
+ }
+ },
+ template: `
+
+
+
+ `,
+})
diff --git a/packages/formkit/stories/Rating.stories.ts b/packages/formkit/stories/Rating.stories.ts
new file mode 100644
index 0000000000..24211b27f7
--- /dev/null
+++ b/packages/formkit/stories/Rating.stories.ts
@@ -0,0 +1,22 @@
+import { StoryFn } from '@storybook/vue3'
+import { ref } from 'vue'
+
+export default {
+ title: 'Formkit Integration/Rating',
+}
+
+export const Default: StoryFn = () => ({
+ setup () {
+ const value = ref(0)
+ return {
+ value,
+ }
+ },
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/Select.stories.ts b/packages/formkit/stories/Select.stories.ts
new file mode 100644
index 0000000000..b6c539e1d0
--- /dev/null
+++ b/packages/formkit/stories/Select.stories.ts
@@ -0,0 +1,49 @@
+import { StoryFn } from '@storybook/vue3'
+import countries from './countries'
+
+export default {
+ title: 'Formkit Integration/Select',
+}
+
+export const Default: StoryFn = () => ({
+
+ setup () {
+ const frameworks = [
+ { text: 'React', value: 'react' },
+ { text: 'Vue', value: 'vue' },
+ { text: 'Angular', value: 'angular' },
+ { text: 'Svelte', value: 'svelte' },
+ ]
+ return {
+ frameworks,
+ }
+ },
+ template: `
+
+ `,
+})
+
+export const Autocomplete: StoryFn = () => ({
+
+ setup () {
+ return {
+ countries,
+ }
+ },
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/Slider.stories.ts b/packages/formkit/stories/Slider.stories.ts
new file mode 100644
index 0000000000..edf4b445cc
--- /dev/null
+++ b/packages/formkit/stories/Slider.stories.ts
@@ -0,0 +1,26 @@
+import { StoryFn } from '@storybook/vue3'
+import { ref } from 'vue'
+
+export default {
+ title: 'Formkit Integration/Slider',
+}
+
+export const Default: StoryFn = () => ({
+ setup () {
+ const value = ref(true)
+ return {
+ value,
+ }
+ },
+ template: `
+
+ {{ value }}
+ `,
+})
diff --git a/packages/formkit/stories/Submit.stories.ts b/packages/formkit/stories/Submit.stories.ts
new file mode 100644
index 0000000000..cedb3543fb
--- /dev/null
+++ b/packages/formkit/stories/Submit.stories.ts
@@ -0,0 +1,15 @@
+import { StoryFn } from '@storybook/vue3'
+
+export default {
+ title: 'Formkit Integration/Submit',
+}
+
+export const Default: StoryFn = () => ({
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/Textarea.stories.ts b/packages/formkit/stories/Textarea.stories.ts
new file mode 100644
index 0000000000..405111bfd1
--- /dev/null
+++ b/packages/formkit/stories/Textarea.stories.ts
@@ -0,0 +1,43 @@
+import { StoryFn } from '@storybook/vue3'
+import { ref } from 'vue'
+
+export default {
+ title: 'Formkit Integration/Textarea',
+}
+
+export const Default: StoryFn = () => ({
+ setup () {
+ const getLength = (value: { instructions: string[] }) => {
+ return `${value.instructions ? value.instructions.length : 0} / 120`
+ }
+
+ const value = ref({})
+
+ return {
+ getLength,
+ value,
+ }
+ },
+ template: `
+
+
+
+
+
+ `,
+})
diff --git a/packages/formkit/stories/Timepicker.stories.ts b/packages/formkit/stories/Timepicker.stories.ts
new file mode 100644
index 0000000000..749cf4dcf4
--- /dev/null
+++ b/packages/formkit/stories/Timepicker.stories.ts
@@ -0,0 +1,25 @@
+import { StoryFn } from '@storybook/vue3'
+import { ref } from 'vue'
+
+export default {
+ title: 'Formkit Integration/Timepicker',
+}
+
+export const Default: StoryFn = () => ({
+ setup() {
+ const date = ref(new Date('2010-01-01'))
+ return {
+ date
+ }
+ },
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/Toggle.stories.ts b/packages/formkit/stories/Toggle.stories.ts
new file mode 100644
index 0000000000..38678e0530
--- /dev/null
+++ b/packages/formkit/stories/Toggle.stories.ts
@@ -0,0 +1,24 @@
+import { StoryFn } from '@storybook/vue3'
+import { ref } from 'vue'
+
+export default {
+ title: 'Formkit Integration/Toggle',
+}
+
+export const Default: StoryFn = () => ({
+ setup () {
+ const value = ref(false)
+
+ return {
+ value,
+ }
+ },
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/ToggleButtons.stories.ts b/packages/formkit/stories/ToggleButtons.stories.ts
new file mode 100644
index 0000000000..5c01f101bb
--- /dev/null
+++ b/packages/formkit/stories/ToggleButtons.stories.ts
@@ -0,0 +1,16 @@
+import { StoryFn } from '@storybook/vue3'
+
+export default {
+ title: 'Formkit Integration/ToggleButtons',
+}
+
+export const Default: StoryFn = () => ({
+ template: `
+
+ `,
+})
diff --git a/packages/formkit/stories/countries.ts b/packages/formkit/stories/countries.ts
new file mode 100644
index 0000000000..712e24a416
--- /dev/null
+++ b/packages/formkit/stories/countries.ts
@@ -0,0 +1,246 @@
+export default [
+ { text: 'Afghanistan', value: 'AF' },
+ { text: 'Ă…land Islands', value: 'AX' },
+ { text: 'Albania', value: 'AL' },
+ { text: 'Algeria', value: 'DZ' },
+ { text: 'American Samoa', value: 'AS' },
+ { text: 'AndorrA', value: 'AD' },
+ { text: 'Angola', value: 'AO' },
+ { text: 'Anguilla', value: 'AI' },
+ { text: 'Antarctica', value: 'AQ' },
+ { text: 'Antigua and Barbuda', value: 'AG' },
+ { text: 'Argentina', value: 'AR' },
+ { text: 'Armenia', value: 'AM' },
+ { text: 'Aruba', value: 'AW' },
+ { text: 'Australia', value: 'AU' },
+ { text: 'Austria', value: 'AT' },
+ { text: 'Azerbaijan', value: 'AZ' },
+ { text: 'Bahamas', value: 'BS' },
+ { text: 'Bahrain', value: 'BH' },
+ { text: 'Bangladesh', value: 'BD' },
+ { text: 'Barbados', value: 'BB' },
+ { text: 'Belarus', value: 'BY' },
+ { text: 'Belgium', value: 'BE' },
+ { text: 'Belize', value: 'BZ' },
+ { text: 'Benin', value: 'BJ' },
+ { text: 'Bermuda', value: 'BM' },
+ { text: 'Bhutan', value: 'BT' },
+ { text: 'Bolivia', value: 'BO' },
+ { text: 'Bosnia and Herzegovina', value: 'BA' },
+ { text: 'Botswana', value: 'BW' },
+ { text: 'Bouvet Island', value: 'BV' },
+ { text: 'Brazil', value: 'BR' },
+ { text: 'British Indian Ocean Territory', value: 'IO' },
+ { text: 'Brunei Darussalam', value: 'BN' },
+ { text: 'Bulgaria', value: 'BG' },
+ { text: 'Burkina Faso', value: 'BF' },
+ { text: 'Burundi', value: 'BI' },
+ { text: 'Cambodia', value: 'KH' },
+ { text: 'Cameroon', value: 'CM' },
+ { text: 'Canada', value: 'CA' },
+ { text: 'Cape Verde', value: 'CV' },
+ { text: 'Cayman Islands', value: 'KY' },
+ { text: 'Central African Republic', value: 'CF' },
+ { text: 'Chad', value: 'TD' },
+ { text: 'Chile', value: 'CL' },
+ { text: 'China', value: 'CN' },
+ { text: 'Christmas Island', value: 'CX' },
+ { text: 'Cocos (Keeling) Islands', value: 'CC' },
+ { text: 'Colombia', value: 'CO' },
+ { text: 'Comoros', value: 'KM' },
+ { text: 'Congo', value: 'CG' },
+ { text: 'Congo, The Democratic Republic of the', value: 'CD' },
+ { text: 'Cook Islands', value: 'CK' },
+ { text: 'Costa Rica', value: 'CR' },
+ { text: "Cote D'Ivoire", value: 'CI' },
+ { text: 'Croatia', value: 'HR' },
+ { text: 'Cuba', value: 'CU' },
+ { text: 'Cyprus', value: 'CY' },
+ { text: 'Czech Republic', value: 'CZ' },
+ { text: 'Denmark', value: 'DK' },
+ { text: 'Djibouti', value: 'DJ' },
+ { text: 'Dominica', value: 'DM' },
+ { text: 'Dominican Republic', value: 'DO' },
+ { text: 'Ecuador', value: 'EC' },
+ { text: 'Egypt', value: 'EG' },
+ { text: 'El Salvador', value: 'SV' },
+ { text: 'Equatorial Guinea', value: 'GQ' },
+ { text: 'Eritrea', value: 'ER' },
+ { text: 'Estonia', value: 'EE' },
+ { text: 'Ethiopia', value: 'ET' },
+ { text: 'Falkland Islands (Malvinas)', value: 'FK' },
+ { text: 'Faroe Islands', value: 'FO' },
+ { text: 'Fiji', value: 'FJ' },
+ { text: 'Finland', value: 'FI' },
+ { text: 'France', value: 'FR' },
+ { text: 'French Guiana', value: 'GF' },
+ { text: 'French Polynesia', value: 'PF' },
+ { text: 'French Southern Territories', value: 'TF' },
+ { text: 'Gabon', value: 'GA' },
+ { text: 'Gambia', value: 'GM' },
+ { text: 'Georgia', value: 'GE' },
+ { text: 'Germany', value: 'DE' },
+ { text: 'Ghana', value: 'GH' },
+ { text: 'Gibraltar', value: 'GI' },
+ { text: 'Greece', value: 'GR' },
+ { text: 'Greenland', value: 'GL' },
+ { text: 'Grenada', value: 'GD' },
+ { text: 'Guadeloupe', value: 'GP' },
+ { text: 'Guam', value: 'GU' },
+ { text: 'Guatemala', value: 'GT' },
+ { text: 'Guernsey', value: 'GG' },
+ { text: 'Guinea', value: 'GN' },
+ { text: 'Guinea-Bissau', value: 'GW' },
+ { text: 'Guyana', value: 'GY' },
+ { text: 'Haiti', value: 'HT' },
+ { text: 'Heard Island and Mcdonald Islands', value: 'HM' },
+ { text: 'Holy See (Vatican City State)', value: 'VA' },
+ { text: 'Honduras', value: 'HN' },
+ { text: 'Hong Kong', value: 'HK' },
+ { text: 'Hungary', value: 'HU' },
+ { text: 'Iceland', value: 'IS' },
+ { text: 'India', value: 'IN' },
+ { text: 'Indonesia', value: 'ID' },
+ { text: 'Iran, Islamic Republic Of', value: 'IR' },
+ { text: 'Iraq', value: 'IQ' },
+ { text: 'Ireland', value: 'IE' },
+ { text: 'Isle of Man', value: 'IM' },
+ { text: 'Israel', value: 'IL' },
+ { text: 'Italy', value: 'IT' },
+ { text: 'Jamaica', value: 'JM' },
+ { text: 'Japan', value: 'JP' },
+ { text: 'Jersey', value: 'JE' },
+ { text: 'Jordan', value: 'JO' },
+ { text: 'Kazakhstan', value: 'KZ' },
+ { text: 'Kenya', value: 'KE' },
+ { text: 'Kiribati', value: 'KI' },
+ { text: "Korea, Democratic People'S Republic of", value: 'KP' },
+ { text: 'Korea, Republic of', value: 'KR' },
+ { text: 'Kuwait', value: 'KW' },
+ { text: 'Kyrgyzstan', value: 'KG' },
+ { text: "Lao People'S Democratic Republic", value: 'LA' },
+ { text: 'Latvia', value: 'LV' },
+ { text: 'Lebanon', value: 'LB' },
+ { text: 'Lesotho', value: 'LS' },
+ { text: 'Liberia', value: 'LR' },
+ { text: 'Libyan Arab Jamahiriya', value: 'LY' },
+ { text: 'Liechtenstein', value: 'LI' },
+ { text: 'Lithuania', value: 'LT' },
+ { text: 'Luxembourg', value: 'LU' },
+ { text: 'Macao', value: 'MO' },
+ { text: 'Macedonia, The Former Yugoslav Republic of', value: 'MK' },
+ { text: 'Madagascar', value: 'MG' },
+ { text: 'Malawi', value: 'MW' },
+ { text: 'Malaysia', value: 'MY' },
+ { text: 'Maldives', value: 'MV' },
+ { text: 'Mali', value: 'ML' },
+ { text: 'Malta', value: 'MT' },
+ { text: 'Marshall Islands', value: 'MH' },
+ { text: 'Martinique', value: 'MQ' },
+ { text: 'Mauritania', value: 'MR' },
+ { text: 'Mauritius', value: 'MU' },
+ { text: 'Mayotte', value: 'YT' },
+ { text: 'Mexico', value: 'MX' },
+ { text: 'Micronesia, Federated States of', value: 'FM' },
+ { text: 'Moldova, Republic of', value: 'MD' },
+ { text: 'Monaco', value: 'MC' },
+ { text: 'Mongolia', value: 'MN' },
+ { text: 'Montenegro', value: 'ME' },
+ { text: 'Montserrat', value: 'MS' },
+ { text: 'Morocco', value: 'MA' },
+ { text: 'Mozambique', value: 'MZ' },
+ { text: 'Myanmar', value: 'MM' },
+ { text: 'Namibia', value: 'NA' },
+ { text: 'Nauru', value: 'NR' },
+ { text: 'Nepal', value: 'NP' },
+ { text: 'Netherlands', value: 'NL' },
+ { text: 'Netherlands Antilles', value: 'AN' },
+ { text: 'New Caledonia', value: 'NC' },
+ { text: 'New Zealand', value: 'NZ' },
+ { text: 'Nicaragua', value: 'NI' },
+ { text: 'Niger', value: 'NE' },
+ { text: 'Nigeria', value: 'NG' },
+ { text: 'Niue', value: 'NU' },
+ { text: 'Norfolk Island', value: 'NF' },
+ { text: 'Northern Mariana Islands', value: 'MP' },
+ { text: 'Norway', value: 'NO' },
+ { text: 'Oman', value: 'OM' },
+ { text: 'Pakistan', value: 'PK' },
+ { text: 'Palau', value: 'PW' },
+ { text: 'Palestinian Territory, Occupied', value: 'PS' },
+ { text: 'Panama', value: 'PA' },
+ { text: 'Papua New Guinea', value: 'PG' },
+ { text: 'Paraguay', value: 'PY' },
+ { text: 'Peru', value: 'PE' },
+ { text: 'Philippines', value: 'PH' },
+ { text: 'Pitcairn', value: 'PN' },
+ { text: 'Poland', value: 'PL' },
+ { text: 'Portugal', value: 'PT' },
+ { text: 'Puerto Rico', value: 'PR' },
+ { text: 'Qatar', value: 'QA' },
+ { text: 'Reunion', value: 'RE' },
+ { text: 'Romania', value: 'RO' },
+ { text: 'Russian Federation', value: 'RU' },
+ { text: 'RWANDA', value: 'RW' },
+ { text: 'Saint Helena', value: 'SH' },
+ { text: 'Saint Kitts and Nevis', value: 'KN' },
+ { text: 'Saint Lucia', value: 'LC' },
+ { text: 'Saint Pierre and Miquelon', value: 'PM' },
+ { text: 'Saint Vincent and the Grenadines', value: 'VC' },
+ { text: 'Samoa', value: 'WS' },
+ { text: 'San Marino', value: 'SM' },
+ { text: 'Sao Tome and Principe', value: 'ST' },
+ { text: 'Saudi Arabia', value: 'SA' },
+ { text: 'Senegal', value: 'SN' },
+ { text: 'Serbia', value: 'RS' },
+ { text: 'Seychelles', value: 'SC' },
+ { text: 'Sierra Leone', value: 'SL' },
+ { text: 'Singapore', value: 'SG' },
+ { text: 'Slovakia', value: 'SK' },
+ { text: 'Slovenia', value: 'SI' },
+ { text: 'Solomon Islands', value: 'SB' },
+ { text: 'Somalia', value: 'SO' },
+ { text: 'South Africa', value: 'ZA' },
+ { text: 'South Georgia and the South Sandwich Islands', value: 'GS' },
+ { text: 'Spain', value: 'ES' },
+ { text: 'Sri Lanka', value: 'LK' },
+ { text: 'Sudan', value: 'SD' },
+ { text: 'Suriname', value: 'SR' },
+ { text: 'Svalbard and Jan Mayen', value: 'SJ' },
+ { text: 'Swaziland', value: 'SZ' },
+ { text: 'Sweden', value: 'SE' },
+ { text: 'Switzerland', value: 'CH' },
+ { text: 'Syrian Arab Republic', value: 'SY' },
+ { text: 'Taiwan, Province of China', value: 'TW' },
+ { text: 'Tajikistan', value: 'TJ' },
+ { text: 'Tanzania, United Republic of', value: 'TZ' },
+ { text: 'Thailand', value: 'TH' },
+ { text: 'Timor-Leste', value: 'TL' },
+ { text: 'Togo', value: 'TG' },
+ { text: 'Tokelau', value: 'TK' },
+ { text: 'Tonga', value: 'TO' },
+ { text: 'Trinidad and Tobago', value: 'TT' },
+ { text: 'Tunisia', value: 'TN' },
+ { text: 'Turkey', value: 'TR' },
+ { text: 'Turkmenistan', value: 'TM' },
+ { text: 'Turks and Caicos Islands', value: 'TC' },
+ { text: 'Tuvalu', value: 'TV' },
+ { text: 'Uganda', value: 'UG' },
+ { text: 'Ukraine', value: 'UA' },
+ { text: 'United Arab Emirates', value: 'AE' },
+ { text: 'United Kingdom', value: 'GB' },
+ { text: 'United States', value: 'US' },
+ { text: 'United States Minor Outlying Islands', value: 'UM' },
+ { text: 'Uruguay', value: 'UY' },
+ { text: 'Uzbekistan', value: 'UZ' },
+ { text: 'Vanuatu', value: 'VU' },
+ { text: 'Venezuela', value: 'VE' },
+ { text: 'Viet Nam', value: 'VN' },
+ { text: 'Virgin Islands, British', value: 'VG' },
+ { text: 'Virgin Islands, U.S.', value: 'VI' },
+ { text: 'Wallis and Futuna', value: 'WF' },
+ { text: 'Western Sahara', value: 'EH' },
+ { text: 'Yemen', value: 'YE' },
+ { text: 'Zambia', value: 'ZM' },
+ { text: 'Zimbabwe', value: 'ZW' },
+]
diff --git a/packages/formkit/stories/form/BasicForm.vue b/packages/formkit/stories/form/BasicForm.vue
new file mode 100644
index 0000000000..18af481be3
--- /dev/null
+++ b/packages/formkit/stories/form/BasicForm.vue
@@ -0,0 +1,70 @@
+
+
+ Carbon Sequestration Grant
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formValue }}
+
+
+
+
+
+
diff --git a/packages/formkit/stories/form/Form.stories.ts b/packages/formkit/stories/form/Form.stories.ts
new file mode 100644
index 0000000000..3418df6d08
--- /dev/null
+++ b/packages/formkit/stories/form/Form.stories.ts
@@ -0,0 +1,21 @@
+import { StoryFn } from '@storybook/vue3'
+import BasicForm from './BasicForm.vue'
+import MultiStepForm from './MultiStepForm.vue'
+
+export default {
+ title: 'Formkit Integration/Form',
+}
+
+export const Basic: StoryFn = () => ({
+ components: {
+ BasicForm
+ },
+ template: ``,
+})
+
+export const MultiStep: StoryFn = () => ({
+ components: {
+ MultiStepForm
+ },
+ template: ``,
+})
diff --git a/packages/formkit/stories/form/MultiStepForm.vue b/packages/formkit/stories/form/MultiStepForm.vue
new file mode 100644
index 0000000000..a1ce867cc5
--- /dev/null
+++ b/packages/formkit/stories/form/MultiStepForm.vue
@@ -0,0 +1,246 @@
+
+
+ Carbon Sequestration Grant
+
+
+
+
+
+
+
+ check
+
+ {{ camel2title(stepName) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'Previous step' }}
+
+
+
+ {{ 'Next step' }}
+
+
+
+
+ {{ loading ? 'Submitting...' : 'Submit Application' }}
+
+
+
+
+
+ {{ formValue }}
+
+
+
+
+
+
diff --git a/packages/formkit/stories/form/useSteps.js b/packages/formkit/stories/form/useSteps.js
new file mode 100644
index 0000000000..2be132b500
--- /dev/null
+++ b/packages/formkit/stories/form/useSteps.js
@@ -0,0 +1,69 @@
+import { reactive, toRef, ref, watch } from 'vue'
+import { getNode, createMessage } from '@formkit/core'
+
+export default function useSteps () {
+ const activeStep = ref('')
+ const steps = reactive({})
+ const visitedSteps = ref([]) // track visited steps
+
+ // NEW: watch our activeStep and store visited steps
+ // to know when to show errors
+ watch(activeStep, (newStep, oldStep) => {
+ if (oldStep && !visitedSteps.value.includes(oldStep)) {
+ visitedSteps.value.push(oldStep)
+ }
+ // NEW: trigger showing validation on fields
+ // within all visited steps
+ visitedSteps.value.forEach((step) => {
+ const node = getNode(step)
+ node.walk((n) => {
+ n.store.set(
+ createMessage({
+ key: 'submitted',
+ value: true,
+ visible: false,
+ })
+ )
+ })
+ })
+ })
+
+ const setStep = (delta) => {
+ const stepNames = Object.keys(steps)
+ const currentIndex = stepNames.indexOf(activeStep.value)
+ activeStep.value = stepNames[currentIndex + delta]
+ }
+
+ const stepPlugin = (node) => {
+ if (node.props.type === "group") {
+ // builds an object of the top-level groups
+ steps[node.name] = steps[node.name] || {}
+
+ node.on('created', () => {
+ // use 'on created' to ensure context object is available
+ steps[node.name].valid = toRef(node.context.state, 'valid')
+ })
+
+ // listen for changes in error count and store it
+ node.on('count:errors', ({ payload: count }) => {
+ steps[node.name].errorCount = count
+ })
+
+ // listen for changes in count of blocking validations messages
+ node.on('count:blocking', ({ payload: count }) => {
+ steps[node.name].blockingCount = count
+ })
+
+ // set the active tab to the 1st tab
+ if (activeStep.value === '') {
+ activeStep.value = node.name
+ }
+
+ // Stop plugin inheritance to descendant nodes
+ return false
+ }
+ }
+
+ // NEW: include visitedSteps in our return
+ return { activeStep, visitedSteps, steps, stepPlugin, setStep }
+}
diff --git a/packages/formkit/stories/form/utils.js b/packages/formkit/stories/form/utils.js
new file mode 100644
index 0000000000..b4754cfa3b
--- /dev/null
+++ b/packages/formkit/stories/form/utils.js
@@ -0,0 +1,32 @@
+export { axios, camel2title }
+
+// This is just a mock of an actual axios instance.
+const axios = {
+ post: (formData) => {
+ return new Promise((resolve, reject) => {
+ let response = { status: 200 }
+ if (formData.organizationInfo.org_name.toLowerCase().trim() !== 'formkit') {
+ response = {
+ status: 400,
+ formErrors: ['There was an error in this form, please correct and re-submit to validate.'],
+ fieldErrors: {
+ 'organizationInfo.org_name': 'Organization Name must be "FormKit", we tricked you!'
+ }
+ }
+ }
+ setTimeout(() => {
+ if (response.status === 200) {
+ resolve(response)
+ } else {
+ reject(response)
+ }
+ }, 1500)
+ })
+
+ }
+}
+
+const camel2title = (str) => str
+ .replace(/([A-Z])/g, (match) => ` ${match}`)
+ .replace(/^./, (match) => match.toUpperCase())
+ .trim()
diff --git a/packages/formkit/tsconfig.json b/packages/formkit/tsconfig.json
new file mode 100644
index 0000000000..9e18f8c4f4
--- /dev/null
+++ b/packages/formkit/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": [
+ "ES2023",
+ "dom",
+ "dom.iterable"
+ ],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "Bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+}
diff --git a/packages/ui/.storybook/main.ts b/packages/ui/.storybook/main.ts
index 4d22e2f4ae..5c5e55be32 100644
--- a/packages/ui/.storybook/main.ts
+++ b/packages/ui/.storybook/main.ts
@@ -6,7 +6,8 @@ const config: StorybookConfig = {
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
- 'storybook-dark-mode',
+ "storybook-dark-mode",
+ "@storybook/addon-storysource"
],
framework: {
name: "@storybook/vue3-vite",
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 5c9bca492b..4fa09196bb 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -62,6 +62,7 @@
"@storybook/addon-essentials": "^7.1.0",
"@storybook/addon-interactions": "^7.1.0",
"@storybook/addon-links": "^7.1.0",
+ "@storybook/addon-storysource": "^7.1.0",
"@storybook/blocks": "^7.1.0",
"@storybook/jest": "^0.2.3",
"@storybook/testing-library": "^0.0.14-next.2",
@@ -115,7 +116,7 @@
"vite": "^4.2.1",
"vite-plugin-chunk-split": "^0.4.7",
"vitest": "^1.4.0",
- "vue": "3.3.11",
+ "vue": "^3.0.4",
"vue-tsc": "^2.0.7",
"yargs": "^17.5.1"
},
diff --git a/packages/ui/src/services/vue-plugin/create-vuestic/create-vuestic.ts b/packages/ui/src/services/vue-plugin/create-vuestic/create-vuestic.ts
index c7f4f6d729..174e86e637 100644
--- a/packages/ui/src/services/vue-plugin/create-vuestic/create-vuestic.ts
+++ b/packages/ui/src/services/vue-plugin/create-vuestic/create-vuestic.ts
@@ -2,16 +2,9 @@ import type { PartialGlobalConfig } from '../../global-config/types'
import { defineVuesticPlugin, usePlugin } from '../utils'
import { GlobalConfigPlugin, VaDropdownPlugin, VaToastPlugin, VaModalPlugin, ColorConfigPlugin, BreakpointConfigPlugin, CachePlugin } from '../plugins'
import * as vuesticComponents from '../components'
-import type { VuesticComponents } from '../types/components'
import { setCurrentApp } from '../../current-app'
import { ColorsClassesPlugin } from '../../colors-classes'
-// Declare all components globally
-declare module 'vue' {
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
- export interface GlobalComponents extends VuesticComponents {}
-}
-
/**
* Globally register all vuestic components and plugins
* @notice using this method will bundle all vuestic components.
diff --git a/packages/ui/src/shims-vue.d.ts b/packages/ui/src/shims-vue.d.ts
index 1146aa1bbf..134b066fac 100644
--- a/packages/ui/src/shims-vue.d.ts
+++ b/packages/ui/src/shims-vue.d.ts
@@ -3,3 +3,10 @@
// const component: DefineComponent<{}, {}, any>
// export default component
// }
+
+import * as Vue from 'vue'
+declare module 'vue' {
+ import type { VuesticComponents } from '@/services/vue-plugin'
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ export interface GlobalComponents extends VuesticComponents {}
+}
diff --git a/yarn.lock b/yarn.lock
index d4abac1a22..5d66c95bee 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2391,6 +2391,105 @@
"@floating-ui/utils" "^0.2.8"
vue-demi ">=0.13.0"
+"@formkit/core@1.6.9", "@formkit/core@^1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/core/-/core-1.6.9.tgz#36f0ee738483c109a3749de3fe17f46791fad93f"
+ integrity sha512-Zb5OkYKMf7Rp1pd4iUMv0TJQvfgl1PdKtRRQoGiTA0XIFLB/7tcRMr1wc5isA2JS+hllfxMTh3RWF8N+64fTMg==
+ dependencies:
+ "@formkit/utils" "1.6.9"
+
+"@formkit/dev@1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/dev/-/dev-1.6.9.tgz#f8124d49577cca0024f153130e50307929bcace3"
+ integrity sha512-4ueBpZAOiKr8/LZnq3mNePCX4ZB1j1JuJscBEwugWMnDeDwCNo5XWBrng1ER/LlitTRQ3mtEBNy2Qpm0yAHlwA==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/utils" "1.6.9"
+
+"@formkit/i18n@1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/i18n/-/i18n-1.6.9.tgz#ce9e6e5f132f1ba0007ec100b686bfff76b34d98"
+ integrity sha512-8NA5bALlspCBEwInuZVgBqgQr0lDfproZdmbs2LciQpGi2B15u74JCjAkEwaKlMs+qgf/ds3QcIgUv2ztyyVEA==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/utils" "1.6.9"
+ "@formkit/validation" "1.6.9"
+
+"@formkit/inputs@1.6.9", "@formkit/inputs@^1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/inputs/-/inputs-1.6.9.tgz#1b00fb3e81f508c3e8366be4ad558067b4061f67"
+ integrity sha512-k9gjV1e5F87NxSnu13JtKb30XYt6ndx2KGHZG8Xz0etoP75yJlMaeROHHPvlxdy2gZM6qH7Ex4it51W74Wh2Eg==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/utils" "1.6.9"
+
+"@formkit/nuxt@^1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/nuxt/-/nuxt-1.6.9.tgz#be5e502f09ddd748d08917b2707f97c6884ff5da"
+ integrity sha512-G2J20hg1XVvP9l0lcclqeH6xIzVbQ1V1XS0LmVTJ3xBXL2QhXV6EUwkN6FGMjjtBJdtK1SMRmTXDc9rcLJgS1A==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/i18n" "1.6.9"
+ "@formkit/vue" "1.6.9"
+ "@nuxt/kit" "^3.10.3"
+ chokidar "^3.6.0"
+ pathe "^1.1.2"
+ unplugin "^1.9.0"
+ unplugin-formkit "^0.2.13"
+
+"@formkit/observer@1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/observer/-/observer-1.6.9.tgz#fce517d76bea3aa6c34ac840bcb706b84f0c2632"
+ integrity sha512-p3MCmzp6jwzXIuV3gI9uTJTJl+sN5689C7qf7gdrS8jb1fbX1snKiTyWA8FXOrBXu+ne5z/sA/yBWqYFTSLy8A==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/utils" "1.6.9"
+
+"@formkit/rules@1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/rules/-/rules-1.6.9.tgz#948d4895543c2b46e83f37386c3b3e7fa64723b6"
+ integrity sha512-5Vu3JACKyws1kw02qF+024WkS7L9kYZ0lmdSpsaTqg5Wf7+InsxWXFYaG6vCzqIh4Lk9NeffIzq/xyGpGxf5uQ==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/utils" "1.6.9"
+ "@formkit/validation" "1.6.9"
+
+"@formkit/themes@1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/themes/-/themes-1.6.9.tgz#71e1febe260e657c4a9aa94c179a22272d191c45"
+ integrity sha512-/UD+MehQEdcCEadt73eIBGGAMEK8ODN0yq9r9299WvQxIELCOP2MbcxuWCV/g2Vd15Xhl8YFdn4KCzQi4X7QXA==
+ dependencies:
+ "@formkit/core" "1.6.9"
+
+"@formkit/utils@1.6.9", "@formkit/utils@^1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/utils/-/utils-1.6.9.tgz#df320972b30d5cea8f416c24b446a598737d5819"
+ integrity sha512-vSFhB/Sm/A+SdwKdBi4WhJcdbePqSYRaB878Ol9HL8roTmmmgQpThvkv6EjLM6aRRP27Il5rS8XtIAIeh8vdTA==
+
+"@formkit/validation@1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/validation/-/validation-1.6.9.tgz#d355ece3c007e97553ab6b4d23ed87bf55e2b53e"
+ integrity sha512-9PGwN0ZDJt3hsrMyaL8KTG3diSQDik1OGogVG6/nFcZhWUycpeamFfXZSQ5pfzmwnvrTHsvyT0FtKitUnWWuPA==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/observer" "1.6.9"
+ "@formkit/utils" "1.6.9"
+
+"@formkit/vue@1.6.9", "@formkit/vue@^1.6.9":
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/@formkit/vue/-/vue-1.6.9.tgz#2393c49757e3c13790432c7e1e93458710ca9a10"
+ integrity sha512-WrjAtEsKnFJzxQuATWsWKMpTAyJE15PUmRh9hwEAqgTDy2yMog1gxqxfZv3rEAdIdgXNp08tWmRVnQgDIF3vAQ==
+ dependencies:
+ "@formkit/core" "1.6.9"
+ "@formkit/dev" "1.6.9"
+ "@formkit/i18n" "1.6.9"
+ "@formkit/inputs" "1.6.9"
+ "@formkit/observer" "1.6.9"
+ "@formkit/rules" "1.6.9"
+ "@formkit/themes" "1.6.9"
+ "@formkit/utils" "1.6.9"
+ "@formkit/validation" "1.6.9"
+
"@fortawesome/fontawesome-common-types@^0.2.36":
version "0.2.36"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz#b44e52db3b6b20523e0c57ef8c42d315532cb903"
@@ -4708,6 +4807,15 @@
"@storybook/global" "^5.0.0"
ts-dedent "^2.0.0"
+"@storybook/addon-storysource@^7.1.0":
+ version "7.6.20"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-7.6.20.tgz#1050136171a442765ac36b768c4c2ddb46bf2e2a"
+ integrity sha512-1/wLo/5q3efso6PaOYcAD/JJOWOX5YSN+dzidjHMMeyhdrRWcb9+yUZtZOtvOBa2FSITK+utrwY+VZRq9gfp6g==
+ dependencies:
+ "@storybook/source-loader" "7.6.20"
+ estraverse "^5.2.0"
+ tiny-invariant "^1.3.1"
+
"@storybook/addon-toolbars@7.6.17":
version "7.6.17"
resolved "https://registry.yarnpkg.com/@storybook/addon-toolbars/-/addon-toolbars-7.6.17.tgz#98c1cee88a8f5f61464d28a09648994884d7bd0a"
@@ -4814,6 +4922,18 @@
telejson "^7.2.0"
tiny-invariant "^1.3.1"
+"@storybook/channels@7.6.20":
+ version "7.6.20"
+ resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.6.20.tgz#33d8292b1b16d7f504bf751c57a792477d1c3a9e"
+ integrity sha512-4hkgPSH6bJclB2OvLnkZOGZW1WptJs09mhQ6j6qLjgBZzL/ZdD6priWSd7iXrmPiN5TzUobkG4P4Dp7FjkiO7A==
+ dependencies:
+ "@storybook/client-logger" "7.6.20"
+ "@storybook/core-events" "7.6.20"
+ "@storybook/global" "^5.0.0"
+ qs "^6.10.0"
+ telejson "^7.2.0"
+ tiny-invariant "^1.3.1"
+
"@storybook/cli@7.6.17":
version "7.6.17"
resolved "https://registry.yarnpkg.com/@storybook/cli/-/cli-7.6.17.tgz#04462c97a926e3dfcc18f3df02519effe29740e2"
@@ -4867,6 +4987,13 @@
dependencies:
"@storybook/global" "^5.0.0"
+"@storybook/client-logger@7.6.20":
+ version "7.6.20"
+ resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.6.20.tgz#1d6e93443091cccd50e269371aa786172d0c4659"
+ integrity sha512-NwG0VIJQCmKrSaN5GBDFyQgTAHLNishUPLW1NrzqTDNAhfZUoef64rPQlinbopa0H4OXmlB+QxbQIb3ubeXmSQ==
+ dependencies:
+ "@storybook/global" "^5.0.0"
+
"@storybook/codemod@7.6.17":
version "7.6.17"
resolved "https://registry.yarnpkg.com/@storybook/codemod/-/codemod-7.6.17.tgz#c93d87d74f43fd475d48edb178233e89329b72c2"
@@ -4947,6 +5074,13 @@
dependencies:
ts-dedent "^2.0.0"
+"@storybook/core-events@7.6.20":
+ version "7.6.20"
+ resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.6.20.tgz#6648d661d1c96841a4c2a710a35759b01b6a06a1"
+ integrity sha512-tlVDuVbDiNkvPDFAu+0ou3xBBYbx9zUURQz4G9fAq0ScgBOs/bpzcRrFb4mLpemUViBAd47tfZKdH4MAX45KVQ==
+ dependencies:
+ ts-dedent "^2.0.0"
+
"@storybook/core-server@7.6.17":
version "7.6.17"
resolved "https://registry.yarnpkg.com/@storybook/core-server/-/core-server-7.6.17.tgz#bf5b7a9db7abe157a14dba6279936e43efa79250"
@@ -5163,6 +5297,17 @@
memoizerific "^1.11.3"
qs "^6.10.0"
+"@storybook/source-loader@7.6.20":
+ version "7.6.20"
+ resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-7.6.20.tgz#ce559aad34093a361bc8266d9c8d30079761083c"
+ integrity sha512-AlOX5w95tajmZEsEcbYCtwtpKYW0xLV2hRzk2MZfc6XUXC9/n2jwhz1X4EKilwKGCWFUj/HAYbNc2XChS9juvg==
+ dependencies:
+ "@storybook/csf" "^0.1.2"
+ "@storybook/types" "7.6.20"
+ estraverse "^5.2.0"
+ lodash "^4.17.21"
+ prettier "^2.8.0"
+
"@storybook/telemetry@7.6.17":
version "7.6.17"
resolved "https://registry.yarnpkg.com/@storybook/telemetry/-/telemetry-7.6.17.tgz#472dd6a8d87240c1fcc01bb9d6247e134e539b5b"
@@ -5208,6 +5353,16 @@
"@types/express" "^4.7.0"
file-system-cache "2.3.0"
+"@storybook/types@7.6.20":
+ version "7.6.20"
+ resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.6.20.tgz#b8d62b30914b35e6750b1f4937da532432f02890"
+ integrity sha512-GncdY3x0LpbhmUAAJwXYtJDUQEwfF175gsjH0/fxPkxPoV7Sef9TM41jQLJW/5+6TnZoCZP/+aJZTJtq3ni23Q==
+ dependencies:
+ "@storybook/channels" "7.6.20"
+ "@types/babel__core" "^7.0.0"
+ "@types/express" "^4.7.0"
+ file-system-cache "2.3.0"
+
"@storybook/vue3-vite@^7.1.0":
version "7.6.17"
resolved "https://registry.yarnpkg.com/@storybook/vue3-vite/-/vue3-vite-7.6.17.tgz#16ec9054dbbb9b194d605366d3b36e3681e4c032"
@@ -19465,8 +19620,7 @@ string-hash@^1.1.1:
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
-"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
- name string-width-cjs
+"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -19484,6 +19638,15 @@ string-width@^1.0.1:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
+"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
@@ -19569,7 +19732,7 @@ stringify-object@3.3.0:
is-obj "^1.0.1"
is-regexp "^1.0.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -19597,6 +19760,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
dependencies:
ansi-regex "^4.1.0"
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -20670,21 +20840,11 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
-typescript@5.3.2:
+typescript@5.3.2, typescript@^4.9.3, typescript@^5:
version "5.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.2.tgz#00d1c7c1c46928c5845c1ee8d0cc2791031d4c43"
integrity sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==
-typescript@^4.9.3:
- version "4.9.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
- integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
-
-typescript@^5:
- version "5.6.3"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b"
- integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==
-
ufo@^0.8.3:
version "0.8.6"
resolved "https://registry.yarnpkg.com/ufo/-/ufo-0.8.6.tgz#c0ec89bc0e0c9fa59a683680feb0f28b55ec323b"
@@ -21004,6 +21164,14 @@ unpipe@1.0.0, unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+unplugin-formkit@^0.2.13:
+ version "0.2.13"
+ resolved "https://registry.yarnpkg.com/unplugin-formkit/-/unplugin-formkit-0.2.13.tgz#0453d5f7c128e030d7eae6351775c3dadaf704ef"
+ integrity sha512-qNHz7/0QDO0uVD5MoUZz49CI7q8cHM24RQDwbs5NfRJ6EiyZ1gBmWq9ta3QHR2nD7xacXV+yzmfDbnwlNpkzsg==
+ dependencies:
+ pathe "^1.1.1"
+ unplugin "^1.4.0"
+
unplugin-vue-router@^0.10.8:
version "0.10.8"
resolved "https://registry.yarnpkg.com/unplugin-vue-router/-/unplugin-vue-router-0.10.8.tgz#a868cb64e3c27aba98b312aa757e8cb48830b891"
@@ -21024,7 +21192,7 @@ unplugin-vue-router@^0.10.8:
unplugin "^1.12.2"
yaml "^2.5.0"
-unplugin@^1.10.0, unplugin@^1.12.2, unplugin@^1.14.1, unplugin@^1.15.0, unplugin@^1.3.1:
+unplugin@^1.10.0, unplugin@^1.12.2, unplugin@^1.14.1, unplugin@^1.15.0, unplugin@^1.3.1, unplugin@^1.4.0, unplugin@^1.9.0:
version "1.16.0"
resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.16.0.tgz#ca0f248bf8798cd752dd02e5b381223b737cef72"
integrity sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==
@@ -21668,7 +21836,7 @@ vue-tsc@2.0.7, vue-tsc@^2.0.7:
"@vue/language-core" "2.0.7"
semver "^7.5.4"
-vue@*, vue@3.3.11, vue@3.4.8, vue@3.5.12, vue@^3.0.0, vue@^3.5.12:
+vue@*, vue@3.4.8, vue@3.5.12, vue@^3.0.0, vue@^3.0.4, vue@^3.5.12:
version "3.5.12"
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.12.tgz#e08421c601b3617ea2c9ef0413afcc747130b36c"
integrity sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==
@@ -21961,8 +22129,7 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
- name wrap-ansi-cjs
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -21989,6 +22156,15 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"