Skip to content

feat(gnosis-vue): add Vue 3 wrapper package with v-model support and dev example#629

Draft
marios-tsigkas with Copilot wants to merge 8 commits into
mainfrom
copilot/add-gnosis-vue-directory
Draft

feat(gnosis-vue): add Vue 3 wrapper package with v-model support and dev example#629
marios-tsigkas with Copilot wants to merge 8 commits into
mainfrom
copilot/add-gnosis-vue-directory

Conversation

Copilot AI commented Mar 10, 2026

Copy link
Copy Markdown

Description

Adds gnosis-vue/ — a new package in the monorepo that re-exports all gnosis React components as Vue 3 components via Veaury. Form components get native v-model support through a reusable factory. Includes a runnable dev-server example page.

Changes

gnosis-vue/ package scaffold

  • package.json@epignosis_llc/gnosis-vue; vue/react/react-dom as peer deps, veaury + @epignosis_llc/gnosis as runtime deps
  • tsconfig.json — ES2020 target, bundler module resolution, type-check only (noEmit: true)
  • vite.config.ts — library build via Veaury's Vite plugin + vite-plugin-dts

src/utils/withVModel.ts — reusable factory wrapping any React component with Vue's modelValue/update:modelValue convention. Four mapping presets cover all gnosis form components:

export const Input        = withVModel(ReactInput,        inputLike)    // e.target.value
export const Checkbox     = withVModel(ReactCheckbox,     checkboxLike) // e.target.checked
export const Select       = withVModel(ReactSelect,       selectLike)   // option directly
export const ToggleSwitch = withVModel(ReactToggleSwitch, toggleLike)   // isChecked boolean

withVModel is also exported so consumers can wrap additional React components themselves.

src/index.ts — single entry point:

  • 26 presentational components wrapped via applyPureReactInVue
  • 9 form components wrapped via withVModel (Input, Textarea, Select, Checkbox, CheckboxGroup, RadioButtonGroup, RadioGroup, Radio, ToggleSwitch)
  • Re-exports DefaultTheme, typeScale, and key TypeScript types from @epignosis_llc/gnosis

Dev example (index.html / src/main.ts / src/App.vue)

  • Demonstrates Button across all color variants, style variants (outline/ghost/link), sizes, and states (loading, disabled)
  • Shows Vue reactivity working through the Veaury bridge (click feedback via ref)
  • Run with cd gnosis-vue && npm install && npm run dev
Original prompt

Summary

Create a gnosis-vue/ directory inside the monorepo that exports all gnosis React components as Vue 3 components. Presentational components are wrapped via veaury's applyPureReactInVue. Form components get v-model support via a reusable withVModel factory.

Files to create

1. gnosis-vue/package.json

{
  "name": "@epignosis_llc/gnosis-vue",
  "version": "1.0.0",
  "type": "module",
  "description": "Vue 3 wrapper for the Epignosis Gnosis design system",
  "main": "dist/gnosis-vue.umd.cjs",
  "module": "dist/gnosis-vue.js",
  "types": "dist/types/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/gnosis-vue.js",
      "require": "./dist/gnosis-vue.umd.cjs"
    }
  },
  "files": ["dist"],
  "peerDependencies": {
    "vue": "^3.3.0",
    "react": ">=18.0.0",
    "react-dom": ">=18.0.0"
  },
  "dependencies": {
    "@epignosis_llc/gnosis": "^6.6.3",
    "veaury": "^2.6.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.0",
    "@vitejs/plugin-react": "^4.0.0",
    "vite": "^5.0.0",
    "vite-plugin-dts": "^3.0.0",
    "vue": "^3.4.0",
    "vue-tsc": "^2.0.0",
    "typescript": "^5.0.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview"
  }
}

2. gnosis-vue/tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "jsx": "preserve",
    "declaration": true,
    "declarationDir": "dist/types",
    "emitDeclarationOnly": false,
    "strict": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

3. gnosis-vue/vite.config.ts

import { defineConfig } from 'vite'
import veauryVitePlugins from 'veaury/vite/index.js'
import { resolve } from 'path'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [
    veauryVitePlugins({
      type: 'vue',
    }),
    dts({
      insertTypesEntry: true,
      outDir: 'dist/types',
    }),
  ],
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'GnosisVue',
      fileName: 'gnosis-vue',
    },
    rollupOptions: {
      external: ['vue', 'react', 'react-dom', '@epignosis_llc/gnosis'],
      output: {
        globals: {
          vue: 'Vue',
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    },
  },
})

4. gnosis-vue/src/utils/withVModel.ts

import { defineComponent, h, type PropType, type Component } from 'vue'
import { applyPureReactInVue } from 'veaury'

export interface VModelMapping {
  reactValueProp: string
  reactChangeProp: string
  getValueFromArgs: (...args: any[]) => any
}

export const inputLike: VModelMapping = {
  reactValueProp: 'value',
  reactChangeProp: 'onChange',
  getValueFromArgs: (e) => e.target.value,
}

export const checkboxLike: VModelMapping = {
  reactValueProp: 'checked',
  reactChangeProp: 'onChange',
  getValueFromArgs: (e) => e.target.checked,
}

export const selectLike: VModelMapping = {
  reactValueProp: 'value',
  reactChangeProp: 'onChange',
  getValueFromArgs: (option) => option,
}

export const toggleLike: VModelMapping = {
  reactValueProp: 'defaultChecked',
  reactChangeProp: 'onChange',
  getValueFromArgs: (isChecked) => isChecked,
}

export function withVModel(ReactComponent: any, mapping: VModelMapping): Component {
  const Wrapped = applyPureReactInVue(ReactComponent)

  return defineComponent({
    name: `VModel_${ReactComponent.displayName || ReactComponent.name || 'Component'}`,
    inheritAttrs: false,
    props: {
      modelValue: { type: null as unknown as PropType<any>, default: undefined },
    },
    emits: ['update:modelValue'],
    setup(props, { emit, attrs, slots }) {
      return () => {
        const bridgedProps: Record<string, any> = {
          ...attrs,
          [mapping.reactValueProp]: props.modelValue,
          [mapping.reactChangeProp]: (...args: any[]) => {
            emit('update:modelValue', mapping.getValueFromArgs(...args))
            const original = attrs[mapping.reactChangeProp]
            if (typeof original === 'function') (original as Function)(...args)
          },
        }
        return h(Wrapped, bridgedProps, slots)
      }
    },
  })
}

5. gnosis-vue/src/index.ts

import { applyPureReactInVue } from 'veaury'
import { createRoot } from 'react-dom/client'
import { setVeauryOptions } from 'veaury'
import { withVModel, inputLike, checkboxLike, selectLike, toggleLike } from './utils/withVModel'

import {
  ThemeProvider as ReactThemeProvider,
  But...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. [Learn more about Advanced Security.](https://gh.io/cca-advanced-security)

Copilot AI changed the title [WIP] Create gnosis-vue directory for Vue 3 components feat: add gnosis-vue package — Vue 3 wrappers for all gnosis components Mar 10, 2026
…nup) (#631)

* Initial plan

* Remove Storybook files from gnosis-vue directory branch

Co-authored-by: marios-tsigkas <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: marios-tsigkas <[email protected]>
Copilot AI changed the title feat: add gnosis-vue package — Vue 3 wrappers for all gnosis components feat(gnosis-vue): add Vue 3 wrapper package with v-model support and dev example Mar 10, 2026
Align gnosis-vue wrapper runtime and build configuration on this branch by moving src/index.ts, package.json, vite config, and lockfile changes without reintroducing Storybook-related files.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants