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 @@ + + + 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 @@ + + + + + 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 @@ + + + + + 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 UI Logo + +

+ +

+ + FormKit Logo + +

+ +# @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 @@ + + + + + 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 @@ + + + + + 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"