npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@cmmv/formbuilder

v0.0.4

Published

Form and listing screen generator in Vue3 + Tailwindcss for CMMV

Downloads

133

Readme

Description

CMMV FormBuilder is a module designed for CMMV applications to streamline the creation and management of forms and pages. By leveraging TypeScript decorators, FormBuilder automates the generation of Vue components and forms, making development faster and more efficient.

Features

  • Schema-Based Form Generation: Define forms declaratively using TypeScript schemas.
  • Page Management: Easily generate pages tied to contracts with navigation support.
  • Dark Mode Support: Fully compatible with TailwindCSS dark mode.
  • Extensible: Custom schemas and integrations are supported.
  • Vue Integration: Outputs fully functional Vue components.

Requirements

To use the CMMV FormBuilder project, the following tools and frameworks are required:

  1. Vite: A fast frontend build tool for development and production.
  2. Vue 3: The modern framework for building interactive user interfaces.
  3. Tailwind CSS: A utility-first CSS framework.
  4. DataTables: A powerful library for table manipulation and interactivity.
# Install runtime dependencies
$ pnpm add @vueform/plugin-mask datatables.net-dt datatables.net-select datatables.net-select-dt datatables.net-vue3 sass-embedded vue-i18n vue-router @vueform/vueform concurrently

# Install development dependencies
$ pnpm add -D tailwindcss terser vite vue@3 postcss postcss-nesting

vite.config.ts

Configure Vite for Vue, TailwindCSS, and Proxy settings:

import { defineConfig } from 'vite';
import { resolve } from 'path';
import vue from '@vitejs/plugin-vue';
import postcssNesting from 'postcss-nesting';

export default defineConfig({
  envDir: './',

  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@vueform/vueform/themes/vueform/scss/index.scss";`
      }
    },
    postcss: {
      plugins: [
        postcssNesting
      ],
    },
  },

  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) => tag.includes('-')
        }
      }
    }),
  ],

  server: {
    host: true,
    port: 5000,
    cors: {
      origin: 'http://localhost:3000',
      credentials: true,
    },
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        secure: false,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },

  build: {
    target: 'esnext',
    minify: 'terser',
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'cmmv',
      fileName: (format) => `cmmv.${format}.js`,
      formats: ['es', 'cjs', 'umd', 'iife']
    },
    rollupOptions: {
      external: ['vue'],
      output: {
        globals: {
          vue: 'Vue'
        }
      }
    }
  },

  resolve: {
    alias: {
      '@': resolve(__dirname, 'public')
    }
  }
});
  1. vueform.config.ts

Configure Vueform for tailwind-based themes and locales:

import en from '@vueform/vueform/locales/en';
import tailwind from '@vueform/vueform/dist/tailwind';
import { defineConfig } from '@vueform/vueform';

export default defineConfig({
  theme: tailwind,
  locales: { en },
  locale: 'en',
});
  1. tailwind.config.ts

Configure TailwindCSS with custom paths and Vueform integration:

const defaultTheme = require('tailwindcss/defaultTheme');

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./index.html",
    "./public/**/*.{vue,js,ts,jsx,tsx}",
    './vueform.config.js',
    './node_modules/.pnpm/@vueform+vueform@*/node_modules/@vueform/vueform/themes/tailwind/**/*.vue',
    './node_modules/.pnpm/@vueform+vueform@*/node_modules/@vueform/vueform/themes/tailwind/**/*.js',
  ],
  darkMode: 'class',
  theme: {
    extend: {
      colors: {
        gray: defaultTheme.colors.gray,
      },
    },
  },
  plugins: [require('@vueform/vueform/tailwind')],
};

Updated package.json

To add the specified scripts to your package.json, include the following configuration under the scripts section of the file. This setup includes development, testing, building, and release-related commands:

"scripts": {
    "dev": "NODE_ENV=dev concurrently \"pnpm dev:server\" \"pnpm dev:client\"",
    "dev:server": "NODE_ENV=dev nodemon",
    "dev:client": "NODE_ENV=dev vite",
    "build": "vite build && tsc --emitDeclarationOnly && mv dist/src dist/types",
},

Installation

Install the package via npm or pnpm:

pnpm add @cmmv/formbuilder

Usage

To enable the FormBuilder transpiler, add it to your CMMV application's transpilers:

import { FormBuilderTranspile } from "@cmmv/formbuilder";
import { Application } from "@cmmv/core";

Application.create({
  modules: [...],
  transpilers: [FormBuilderTranspile],
});

Quick Start

  1. Create a Contract

A contract is the backbone of the CMMV framework, defining fields, rules, and relationships. Below is an example of a LocalesContract:

import { 
    AbstractContract, Contract, 
    ContractField
} from '@cmmv/core';

import { 
    LocaleForm, LocalePage
} from "../views";

@Contract({
    controllerName: 'Locales',
    protoPath: 'src/protos/locales.proto',
    protoPackage: 'locales',
    viewForm: LocaleForm,
    viewPage: LocalePage
})
export class LocalesContract extends AbstractContract {
    @ContractField({
        protoType: 'string',
        unique: true,
        index: true,
    })
    code: string;

    @ContractField({
        protoType: 'string',
    })
    code3: string;

    @ContractField({
        protoType: 'int32',
    })
    codeNum: number;

    @ContractField({
        protoType: 'string',
    })
    name: number;

    @ContractField({
        protoType: 'string',
    })
    nameOriginal: number;
}
  1. Create a Form

The form specifies the structure and behavior of the input fields. Below is an example LocaleForm:

import { 
    AbstractForm, Form, 
    VueformSchema 
} from "@cmmv/formbuilder";

@Form({
    schema: VueformSchema,
    output: "public/components/localeForm.vue",
    useRPC: true
})
export class LocaleForm extends AbstractForm {
    public components = {
        title: { 
            type: "static", 
            props: {
                content: "Locale",
                tag: "h1"
            } 
        },

        code: { 
            type: "input", 
            props: {
                "input-type": "text",
                mask: { mask: 'AA', overwrite: true },
                placeholder: "$i18n.code|Code",
                rules: ["required", "max:2", "min:2"]
            } 
        },

        code3: { 
            type: "input", 
            props: {
                "input-type": "text",
                mask: { mask: 'AAA', overwrite: true },
                placeholder: "$i18n.code3|Code A3C",
                rules: ["required", "max:3", "min:3"]
            } 
        },

        codeNum: { 
            type: "input", 
            props: {
                "input-type": "number",
                mask: { mask: '000', overwrite: true },
                placeholder: "$i18n.numeric|Numeric",
                rules: ["required"]
            } 
        },

        name: { 
            type: "input", 
            props: {
                "input-type": "text",
                placeholder: "$i18n.name|Name"
            } 
        },

        nameOriginal: { 
            type: "input", 
            props: {
                "input-type": "text",
                placeholder: "$i18n.nameOriginal|Original Name"
            } 
        },

        submit: { 
            type: "button", 
            props: {
                "button-label": "Submit",
                "button-type": "submit",
                submits: true,
                full: false
            } 
        }
    }
}
  1. Create a Page

The page connects the form to the application’s router and defines the table structure for displaying data. Below is an example LocalePage:

import { DataTable } from "../interfaces";
import { AbstractPage } from "../abstracts";
import { Page } from "../decorators";
import { DefaultPageSchema } from "../schemas";

@Page({
    schema: DefaultPageSchema,
    router: "/locale",
    output: "public/components/locale.vue",
    form: "public/components/localeForm.vue",
    title: "$i18n.locale",
    role: "locale",
})
export class LocalePage extends AbstractPage {
    public override dataTable: DataTable = {
        fields: ["code", "name", "nameOriginal"],
        sortBy: "name",
        sort: "asc"
    };
}

Generated Output

After running the transpiler, the following .vue file is generated for the form:

<!-- Generated automatically by CMMV -->

<template>
    <Vueform ref="form$">
        <StaticElement  name="title" content="Locale" tag="h1" ></StaticElement >
        <TextElement name="code" input-type="text" :mask="{'mask':'AA','overwrite':true}" :placeholder="$t('code', 'Code')" :rules="['required','max:2','min:2']" ></TextElement>
        <TextElement name="code3" input-type="text" :mask="{'mask':'AAA','overwrite':true}" :placeholder="$t('code3', 'Code A3C')" :rules="['required','max:3','min:3']" ></TextElement>
        <TextElement name="codeNum" input-type="number" :mask="{'mask':'000','overwrite':true}" :placeholder="$t('numeric', 'Numeric')" :rules="['required']" ></TextElement>
        <TextElement name="name" input-type="text" :placeholder="$t('name', 'Name')" ></TextElement>
        <TextElement name="nameOriginal" input-type="text" :placeholder="$t('nameOriginal', 'Original Name')" ></TextElement>
        <ButtonElement name="submit" button-label="Submit" button-type="submit" :submits="true" :full="false" ></ButtonElement>
    </Vueform>
</template>

<script setup>
import { ref } from 'vue';
const form$ = ref(null);
...
</script>