├── packages ├── devextreme-vue │ ├── .gitignore │ ├── src │ │ ├── core │ │ │ ├── __mocks__ │ │ │ │ └── templates-discovering.ts │ │ │ ├── constants.ts │ │ │ ├── strategy │ │ │ │ ├── vue2 │ │ │ │ │ └── index.ts │ │ │ │ └── vue3 │ │ │ │ │ └── index.ts │ │ │ ├── version.ts │ │ │ ├── __tests__ │ │ │ │ ├── vue-helper.ts │ │ │ │ ├── selectbox.test.ts │ │ │ │ ├── toolbar.test.ts │ │ │ │ ├── form.test.ts │ │ │ │ ├── templates-discovering.test.ts │ │ │ │ ├── data-grid.test.ts │ │ │ │ ├── button.test.ts │ │ │ │ └── textbox.test.ts │ │ │ ├── config.ts │ │ │ ├── index.ts │ │ │ ├── extension-component.ts │ │ │ ├── children-processing.ts │ │ │ └── helpers.ts │ │ ├── common │ │ │ ├── data │ │ │ │ └── custom-store.ts │ │ │ ├── charts.ts │ │ │ ├── index.ts │ │ │ └── grids.ts │ │ ├── validation-group.ts │ │ ├── load-indicator.ts │ │ ├── resizable.ts │ │ ├── speed-dial-action.ts │ │ ├── validation-summary.ts │ │ ├── drawer.ts │ │ ├── scroll-view.ts │ │ ├── button.ts │ │ ├── progress-bar.ts │ │ └── draggable.ts │ ├── tsconfig.json │ ├── jest.config.js │ ├── build.config.js │ └── package.json ├── vue2-strategy │ ├── .gitignore │ ├── src │ │ ├── core │ │ │ ├── __mocks__ │ │ │ │ └── templates-discovering.ts │ │ │ ├── errors.ts │ │ │ ├── constants.ts │ │ │ ├── config.ts │ │ │ ├── index.ts │ │ │ ├── __tests__ │ │ │ │ ├── form.test.ts │ │ │ │ └── helper.test.ts │ │ │ ├── extension-component.ts │ │ │ ├── children-processing.ts │ │ │ ├── config.test.ts │ │ │ ├── helpers.ts │ │ │ ├── templates-discovering.ts │ │ │ ├── templates-manager.ts │ │ │ └── configuration-component.ts │ │ ├── common │ │ │ ├── data │ │ │ │ └── custom-store.ts │ │ │ ├── charts.ts │ │ │ ├── index.ts │ │ │ └── grids.ts │ │ ├── validation-group.ts │ │ ├── load-indicator.ts │ │ ├── resizable.ts │ │ ├── speed-dial-action.ts │ │ ├── validation-summary.ts │ │ ├── scroll-view.ts │ │ ├── drawer.ts │ │ ├── button.ts │ │ ├── progress-bar.ts │ │ └── draggable.ts │ ├── sandbox │ │ ├── public │ │ │ ├── css │ │ │ │ └── index.css │ │ │ └── index.html │ │ ├── vue-shim.d.ts │ │ ├── main.ts │ │ ├── tsconfig.json │ │ ├── components │ │ │ ├── number-box-example.vue │ │ │ ├── example-block.vue │ │ │ ├── button-example.vue │ │ │ ├── chart-example.vue │ │ │ ├── scheduler-example.vue │ │ │ ├── accessing-instance-example.vue │ │ │ ├── tab-panel-example.vue │ │ │ ├── popup-example.vue │ │ │ ├── menu-example.vue │ │ │ ├── map-example.vue │ │ │ ├── list-example.vue │ │ │ ├── text-box-example.vue │ │ │ ├── form-example.vue │ │ │ └── validation-example.vue │ │ └── app.vue │ ├── tsconfig.json │ ├── jest.config.js │ ├── build.config.js │ ├── LICENSE │ ├── package.json │ ├── webpack.config.js │ └── gulpfile.js ├── sandbox │ ├── public │ │ ├── css │ │ │ └── index.css │ │ └── index.html │ ├── vue-shim.d.ts │ ├── main.ts │ ├── components │ │ ├── number-box-example.vue │ │ ├── example-block.vue │ │ ├── chart-example.vue │ │ ├── scheduler-example.vue │ │ ├── accessing-instance-example.vue │ │ ├── button-example.vue │ │ ├── tab-panel-example.vue │ │ ├── popup-example.vue │ │ ├── menu-example.vue │ │ ├── map-example.vue │ │ ├── text-box-example.vue │ │ ├── list-example.vue │ │ ├── form-example.vue │ │ └── validation-example.vue │ ├── tsconfig.json │ ├── package.json │ ├── app.vue │ └── webpack.config.js └── devextreme-vue-generator │ ├── tslint.json │ ├── tsconfig.json │ ├── jest.config.js │ ├── src │ ├── index-generator.test.ts │ ├── index-generator.ts │ ├── common-reexports-generator.ts │ ├── helpers.ts │ ├── template.ts │ ├── converter.ts │ ├── generator.test.ts │ └── converter.test.ts │ ├── package.json │ └── tsconfig.local.json ├── .gitmodules ├── SECURITY.md ├── .gitignore ├── .vscode └── settings.json ├── jest.config.js ├── jest.tsconfig.json ├── lerna.json ├── gulpfile.js ├── .gitattributes ├── docs ├── using-vue-cli.md └── using-webpack.md ├── .github ├── ISSUE_TEMPLATE │ ├── support-question.md │ ├── feature_request.md │ └── bug_report.md ├── workflows │ ├── autoapprove.yml │ ├── tests.yml │ ├── update-generated-code.yml │ └── codeql-analysis.yml ├── renovate.json └── ISSUE_TEMPLATE.md ├── tslint.json ├── jest.config.base.js ├── LICENSE ├── tsconfig.json ├── HOW_TO_BUILD.md ├── README.md └── package.json /packages/devextreme-vue/.gitignore: -------------------------------------------------------------------------------- 1 | npm/ 2 | -------------------------------------------------------------------------------- /packages/vue2-strategy/.gitignore: -------------------------------------------------------------------------------- 1 | npm/ 2 | -------------------------------------------------------------------------------- /packages/sandbox/public/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #222222; 3 | background-color: #ffffff; 4 | } -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/__mocks__/templates-discovering.ts: -------------------------------------------------------------------------------- 1 | export const discover = jest.fn(() => ({})); 2 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/__mocks__/templates-discovering.ts: -------------------------------------------------------------------------------- 1 | export const discover = jest.fn(() => ({})); 2 | -------------------------------------------------------------------------------- /packages/sandbox/vue-shim.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from "vue"; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/public/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #222222; 3 | background-color: #ffffff; 4 | } 5 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/errors.ts: -------------------------------------------------------------------------------- 1 | export const TEMPLATE_MULTIPLE_ROOTS_ERROR = "Template must have a single root node."; 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "devextreme"] 2 | path = devextreme 3 | url = https://github.com/DevExpress/DevExtreme.git 4 | branch = 23_2 5 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | Please refer to [DevExpress Security Policy](https://github.com/DevExpress/Shared/security/policy) 4 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/vue-shim.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from "vue"; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/launch.json 2 | .idea 3 | node_modules/ 4 | dist/ 5 | artifacts/ 6 | packages/devextreme-vue/metadata/integration-data.json 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 4, 3 | "editor.insertSpaces": true, 4 | "typescript.tsdk": "node_modules/typescript/lib" 5 | } -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "linterOptions": { 4 | "exclude": [ 5 | "dist" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('./jest.config.base.js'); 2 | 3 | module.exports = { 4 | ...base, 5 | projects: ['/packages/*/jest.config.js'], 6 | coverageDirectory: '/coverage/', 7 | }; 8 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/constants.ts: -------------------------------------------------------------------------------- 1 | const DX_TEMPLATE_WRAPPER_CLASS = "dx-template-wrapper"; 2 | const DX_REMOVE_EVENT = "dxremove"; 3 | 4 | export { 5 | DX_TEMPLATE_WRAPPER_CLASS, 6 | DX_REMOVE_EVENT 7 | }; 8 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/constants.ts: -------------------------------------------------------------------------------- 1 | const DX_TEMPLATE_WRAPPER_CLASS = "dx-template-wrapper"; 2 | const DX_REMOVE_EVENT = "dxremove"; 3 | 4 | export { 5 | DX_TEMPLATE_WRAPPER_CLASS, 6 | DX_REMOVE_EVENT 7 | }; 8 | -------------------------------------------------------------------------------- /packages/sandbox/main.ts: -------------------------------------------------------------------------------- 1 | import "devextreme/dist/css/dx.common.css"; 2 | import "devextreme/dist/css/dx.light.compact.css"; 3 | 4 | import { createApp } from 'vue'; 5 | import App from './app.vue'; 6 | 7 | createApp(App).mount('#app'); 8 | -------------------------------------------------------------------------------- /jest.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "target": "ES2019", 5 | "emitDecoratorMetadata": false // coverage broke if true 6 | }, 7 | "include": [], 8 | "exclude": ["node_modules","npm"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/common/data/custom-store.ts: -------------------------------------------------------------------------------- 1 | export { 2 | GroupItem, 3 | isGroupItemsArray, 4 | isItemsArray, 5 | isLoadResultObject, 6 | LoadResult, 7 | LoadResultObject, 8 | } from "devextreme/common/data/custom-store"; 9 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/common/data/custom-store.ts: -------------------------------------------------------------------------------- 1 | export { 2 | GroupItem, 3 | isGroupItemsArray, 4 | isItemsArray, 5 | isLoadResultObject, 6 | LoadResult, 7 | LoadResultObject, 8 | } from "devextreme/common/data/custom-store"; 9 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "independent", 6 | "npmClient": "npm", 7 | "stream": true, 8 | "nohoist": ["vue-loader", "vue-template-compiler", "@vue/test-utils", "typescript"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/devextreme-vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "skipLibCheck": true, 5 | "lib": [ 6 | "es2015", 7 | "dom" 8 | ] 9 | }, 10 | "include": [ 11 | "src/core/**/*" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/vue2-strategy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "skipLibCheck": true, 5 | "lib": [ 6 | "es2015", 7 | "dom" 8 | ] 9 | }, 10 | "include": [ 11 | "src/core/**/*" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | 4 | "compilerOptions": { 5 | "outDir": "./dist" 6 | }, 7 | 8 | "include": [ 9 | "src/**/*" 10 | ], 11 | "exclude": [ 12 | "src/**/*.test.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('../../jest.config.base.js'); 2 | const pack = require('./package'); 3 | 4 | const packageName = pack.name; 5 | 6 | module.exports = { 7 | ...base, 8 | name: packageName, 9 | displayName: packageName, 10 | }; 11 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/strategy/vue2/index.ts: -------------------------------------------------------------------------------- 1 | export function createComponent(): any { 2 | return; 3 | } 4 | 5 | export function createConfigurationComponent(): any { 6 | return; 7 | } 8 | 9 | export function createExtensionComponent(): any { 10 | return; 11 | } 12 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const tslint = require("gulp-tslint"); 3 | 4 | gulp.task('lint', () => gulp.src(['packages/*/src/**/*.ts', 'packages/**/sandbox/*/*.ts', '!**/node_modules/**/*']) 5 | .pipe(tslint({ 6 | formatter: "verbose" 7 | })) 8 | .pipe(tslint.report())); 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | .circleci text eol=lf 2 | .github text eol=lf 3 | .gitattributes text eol=lf 4 | .gitignore text eol=lf 5 | *.js text eol=lf 6 | *.json text eol=lf 7 | *.md text eol=lf 8 | *.yml text eol=lf 9 | *.vue text eol=lf 10 | *.css text eol=lf 11 | *.ts text eol=lf 12 | *.html text eol=lf 13 | -------------------------------------------------------------------------------- /docs/using-vue-cli.md: -------------------------------------------------------------------------------- 1 | # Using the DevExtreme Vue Components with Vue CLI 2 | 3 | ## Create a new Application ## 4 | 5 | Use [Vue CLI](https://cli.vuejs.org/) to create a new project. 6 | 7 | ## Add DevExtreme ## 8 | 9 | Follow the [installation](https://github.com/DevExpress/devextreme-vue#installation) section in our Readme. 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Support Question 3 | about: Questions and requests for support. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Support Question 11 | 12 | Please do not submit support requests and "How to" questions here. Navigate to our Support Center (https://devexpress.com/sc) instead. 13 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/main.ts: -------------------------------------------------------------------------------- 1 | import "devextreme/dist/css/dx.common.css"; 2 | import "devextreme/dist/css/dx.light.compact.css"; 3 | 4 | import Vue from "vue"; 5 | import App from "./app.vue"; 6 | 7 | // tslint:disable-next-line:no-unused-expression 8 | new Vue({ 9 | el: "#app", 10 | template: "", 11 | components: { App } 12 | }); 13 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "object-literal-sort-keys": false, 9 | "trailing-comma": false, 10 | "variable-name": false, 11 | "interface-name": false 12 | }, 13 | "rulesDirectory": [] 14 | } -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/version.ts: -------------------------------------------------------------------------------- 1 | import * as VueType from "vue"; 2 | const Vue = (VueType as any).default || VueType; 3 | 4 | export function getVueVersion() { 5 | const currentVersion = (Vue as any).version; 6 | return Number(currentVersion.split(".")[0]); 7 | } 8 | 9 | export function isVue3() { 10 | return getVueVersion() === 3; 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/autoapprove.yml: -------------------------------------------------------------------------------- 1 | name: Auto approve 2 | 3 | on: 4 | pull_request_target 5 | 6 | jobs: 7 | auto-approve: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: hmarr/auto-approve-action@v2 11 | if: github.actor == 'renovate-bot' || github.actor == 'renovate[bot]' 12 | with: 13 | github-token: "${{ secrets.GITHUB_TOKEN }}" 14 | -------------------------------------------------------------------------------- /packages/devextreme-vue/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('../../jest.config.base.js'); 2 | const pack = require('./package'); 3 | 4 | const packageName = pack.name; 5 | 6 | module.exports = { 7 | ...base, 8 | name: packageName, 9 | displayName: packageName, 10 | moduleNameMapper: { 11 | "^vue$": "vue/dist/vue.cjs", 12 | "^@/(.*)$": "/src/$1" 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/__tests__/vue-helper.ts: -------------------------------------------------------------------------------- 1 | import { setCompatOptions } from "../vue-helper"; 2 | 3 | describe("setCompatOptions", () => { 4 | 5 | it("set mode", () => { 6 | const component = { 7 | compatConfig: {} 8 | }; 9 | setCompatOptions(component); 10 | expect(component.compatConfig).toStrictEqual({ MODE: 3 }); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /jest.config.base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: [''], 3 | transform: { 4 | '.*': [ 5 | 'ts-jest', 6 | { 7 | diagnostics: false, 8 | }, 9 | ] 10 | }, 11 | testURL: 'http://localhost', 12 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 13 | moduleFileExtensions: [ 14 | "ts", 15 | "tsx", 16 | "js", 17 | "jsx", 18 | "json", 19 | "node" 20 | ] 21 | }; 22 | -------------------------------------------------------------------------------- /packages/vue2-strategy/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('../../jest.config.base.js'); 2 | const pack = require('./package'); 3 | 4 | const packageName = pack.name; 5 | 6 | module.exports = { 7 | ...base, 8 | name: packageName, 9 | displayName: packageName, 10 | roots: [ 11 | "/src/core" 12 | ], 13 | moduleNameMapper: { 14 | "^vue$": "vue/dist/vue.common.js", 15 | "^@/(.*)$": "/src/core/$1" 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/config.ts: -------------------------------------------------------------------------------- 1 | interface IOptions { 2 | deepWatch: boolean; 3 | } 4 | 5 | let config: IOptions = { 6 | deepWatch: false 7 | }; 8 | 9 | function setOptions(options: Partial): void { 10 | config = { ...config, ...options }; 11 | } 12 | 13 | function getOption(optionName: TName): IOptions[TName] { 14 | return config[optionName]; 15 | } 16 | 17 | export default setOptions; 18 | export { getOption }; 19 | -------------------------------------------------------------------------------- /packages/sandbox/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DevExtreme Vue Components 7 | 8 | 9 | 10 | 11 | 12 |
13 |

DevExtreme Vue Components

14 |
15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/index.ts: -------------------------------------------------------------------------------- 1 | import * as vue2Stategy from "./strategy/vue2/index"; 2 | import * as vue3Stategy from "./strategy/vue3/index"; 3 | import { isVue3 } from "./version"; 4 | 5 | const strategy = isVue3() ? vue3Stategy : vue2Stategy; 6 | 7 | export const createComponent = strategy.createComponent; 8 | 9 | export const createConfigurationComponent = strategy.createConfigurationComponent; 10 | 11 | export const createExtensionComponent = strategy.createExtensionComponent; 12 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DevExtreme Vue Components 7 | 8 | 9 | 10 | 11 | 12 |
13 |

DevExtreme Vue Components

14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/config.ts: -------------------------------------------------------------------------------- 1 | interface IOptions { 2 | useLegacyTemplateEngine: boolean; 3 | } 4 | 5 | let config: IOptions = { 6 | useLegacyTemplateEngine: false 7 | }; 8 | 9 | function setOptions(options: Partial): void { 10 | config = { ...config, ...options }; 11 | } 12 | 13 | function getOption(optionName: TName): IOptions[TName] { 14 | return config[optionName]; 15 | } 16 | 17 | export default setOptions; 18 | export { getOption }; 19 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/src/index-generator.test.ts: -------------------------------------------------------------------------------- 1 | import generate from "./index-generator"; 2 | 3 | it("generates", () => { 4 | expect( 5 | generate([ 6 | { name: "widget", path: "./path" }, 7 | { name: "anotherWidget", path: "./another/path" }, 8 | ]) 9 | ).toBe(EXPECTED_GENERATES); 10 | }); 11 | //#region EXPECTED_GENERATES 12 | const EXPECTED_GENERATES = ` 13 | export { widget } from "./path"; 14 | export { anotherWidget } from "./another/path"; 15 | `.trimLeft(); 16 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/src/index-generator.ts: -------------------------------------------------------------------------------- 1 | import { createTempate } from "./template"; 2 | 3 | interface IReExport { 4 | name: string; 5 | path: string; 6 | } 7 | 8 | function generate(paths: IReExport[]): string { 9 | return render(paths); 10 | } 11 | 12 | const render: (model: IReExport[]) => string = createTempate(` 13 | <#~ it :reExport #>export { <#= reExport.name #> } from "<#= reExport.path #>"; 14 | <#~#> 15 | `.trim()); 16 | 17 | export default generate; 18 | export { 19 | IReExport 20 | }; 21 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/src/common-reexports-generator.ts: -------------------------------------------------------------------------------- 1 | import { createTempate } from "./template"; 2 | 3 | const render: (model: { module: string, reexports: string[] }) => string = createTempate(` 4 | export {<#~ it.reexports :reExport #> 5 | <#= reExport #>,<#~#> 6 | } from "devextreme/<#= it.module #>"; 7 | `.trimStart()); 8 | 9 | function generate(module: string, reexports: string[]): string { 10 | const result = render({ module, reexports }); 11 | return result; 12 | } 13 | 14 | export default generate; 15 | -------------------------------------------------------------------------------- /packages/vue2-strategy/build.config.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | core: './src/core/**/*.ts', 4 | ignoredGlobs: ['!./src/core/**/*.test.ts', '!./src/core/**/__mocks__/*'], 5 | npm: { 6 | dist: './npm/', 7 | license: '../../LICENSE' 8 | }, 9 | metadataPath: '../devextreme-vue/metadata/integration-data.json', 10 | generatedComponentsDir: './src', 11 | coreComponentsDir: './src/core', 12 | indexFileName: './src/index.ts', 13 | baseComponent: './core/index', 14 | configComponent: './core/index', 15 | widgetsPackage: 'devextreme' 16 | }; 17 | -------------------------------------------------------------------------------- /packages/sandbox/components/number-box-example.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "baseUrl": ".", 6 | "outDir": "./temp", 7 | "noEmitOnError": true, 8 | "experimentalDecorators": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "noImplicitAny": true, 12 | "noImplicitReturns": true, 13 | "noImplicitThis": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "strictNullChecks": true 17 | }, 18 | "include": [ 19 | "*.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/sandbox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "baseUrl": ".", 6 | "outDir": "./temp", 7 | "noEmitOnError": true, 8 | "experimentalDecorators": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "noImplicitAny": true, 12 | "noImplicitReturns": true, 13 | "noImplicitThis": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "strictNullChecks": true 17 | }, 18 | "include": [ 19 | "*.ts" 20 | ], 21 | "exclude": [ 22 | "**/*.test.ts" 23 | ] 24 | } -------------------------------------------------------------------------------- /packages/sandbox/components/example-block.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | 26 | 33 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/number-box-example.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 29 | -------------------------------------------------------------------------------- /packages/devextreme-vue/build.config.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | src: './src/**/*.ts', 4 | ignoredGlobs: ['!./src/**/*.test.ts', '!./src/**/__mocks__/*'], 5 | npm: { 6 | dist: './npm/', 7 | strategySrc: '../vue2-strategy/npm/*', 8 | strategyDist: './npm/core/strategy/vue2', 9 | package: 'package.json', 10 | license: '../../LICENSE', 11 | readme: '../../README.md' 12 | }, 13 | metadataPath: './metadata/integration-data.json', 14 | generatedComponentsDir: './src', 15 | coreComponentsDir: './src/core', 16 | indexFileName: './src/index.ts', 17 | baseComponent: './core/index', 18 | configComponent: './core/index', 19 | widgetsPackage: 'devextreme' 20 | }; 21 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/example-block.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | 26 | 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature for devextreme-vue 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Feature request 11 | 12 | **Package versions you currently use:** 13 | 14 | devexteme version: 15 | devextreme-vue version: 16 | 17 | **Description:** 18 | 19 | 20 | **Preferred Solution:** 21 | 22 | 23 | **Alternatives:** 24 | 25 | 26 | **Additional Context:** 27 | 28 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/index.ts: -------------------------------------------------------------------------------- 1 | import * as VueType from "vue"; 2 | const Vue = VueType.default || VueType; 3 | 4 | import { DxComponent } from "./component"; 5 | import { DxConfiguration } from "./configuration-component"; 6 | import { DxExtensionComponent } from "./extension-component"; 7 | 8 | export function createComponent(config: any): any { 9 | config.extends = DxComponent(); 10 | return Vue.extend(config); 11 | } 12 | 13 | export function createConfigurationComponent(config: any): any { 14 | config.extends = DxConfiguration(); 15 | return Vue.extend(config); 16 | } 17 | 18 | export function createExtensionComponent(config: any): any { 19 | config.extends = DxExtensionComponent(); 20 | return Vue.extend(config); 21 | } 22 | -------------------------------------------------------------------------------- /packages/sandbox/components/chart-example.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 35 | -------------------------------------------------------------------------------- /packages/sandbox/components/scheduler-example.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 32 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/button-example.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 34 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/chart-example.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 35 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/scheduler-example.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 32 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/__tests__/form.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "@vue/test-utils"; 2 | 3 | import { DxForm, DxItem } from "../../form"; 4 | 5 | jest.setTimeout(1000); 6 | beforeEach(() => { 7 | jest.clearAllMocks(); 8 | }); 9 | 10 | describe("component rendering", () => { 11 | 12 | it("rendering with configuration options", () => { 13 | const vm = { 14 | template: 15 | ` 16 | 17 | `, 18 | data() { 19 | return { 20 | data: { name: "test" } 21 | }; 22 | }, 23 | components: { 24 | DxForm, 25 | DxItem 26 | } 27 | }; 28 | expect(() => mount(vm)).not.toThrow(""); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/src/helpers.ts: -------------------------------------------------------------------------------- 1 | import dasherize from "dasherize"; 2 | import { extname as getPathExtension } from "path"; 3 | 4 | export function removeExtension(path: string) { 5 | return path.slice(0, - getPathExtension(path).length); 6 | } 7 | 8 | export function removePrefix(value: string, prefix: string): string { 9 | return new RegExp(`^${prefix}`, "i").test(value) ? value.substring(prefix.length) : value; 10 | } 11 | 12 | export function toKebabCase(value: string): string { 13 | return dasherize(value); 14 | } 15 | 16 | export function uppercaseFirst(value: string): string { 17 | return value[0].toUpperCase() + value.substr(1); 18 | } 19 | 20 | export function lowercaseFirst(value: string): string { 21 | return value[0].toLowerCase() + value.substr(1); 22 | } 23 | 24 | export function compareStrings(a: string, b: string) { 25 | return a.localeCompare(b, undefined, { caseFirst: "upper" }); 26 | } 27 | -------------------------------------------------------------------------------- /packages/sandbox/components/accessing-instance-example.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 42 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/accessing-instance-example.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 42 | -------------------------------------------------------------------------------- /packages/sandbox/components/button-example.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 38 | 39 | 46 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/extension-component.ts: -------------------------------------------------------------------------------- 1 | import { VueConstructor } from "vue"; 2 | import { BaseComponent } from "./component"; 3 | 4 | interface IExtension { 5 | $_isExtension: boolean; 6 | attachTo(element: any); 7 | } 8 | 9 | interface IExtensionComponentNode { 10 | $_hasOwner: boolean; 11 | } 12 | 13 | const DxExtensionComponent = (): VueConstructor => BaseComponent().extend({ 14 | created(): void { 15 | this.$_isExtension = true; 16 | }, 17 | 18 | mounted() { 19 | this.$el.setAttribute("isExtension", "true"); 20 | if (this.$vnode && (this.$vnode.componentOptions as any as IExtensionComponentNode).$_hasOwner) { return; } 21 | 22 | this.attachTo(this.$el); 23 | }, 24 | 25 | methods: { 26 | attachTo(element: any) { 27 | this.$_createWidget(element); 28 | } 29 | } 30 | }); 31 | 32 | export { 33 | DxExtensionComponent, 34 | IExtension, 35 | IExtensionComponentNode 36 | }; 37 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "prConcurrentLimit": 2, 6 | "semanticCommits": "enabled", 7 | "rangeStrategy": "bump", 8 | "baseBranches": [ 9 | "master" 10 | ], 11 | "labels": [ 12 | "dependencies" 13 | ], 14 | "vulnerabilityAlerts": { 15 | "enabled": true, 16 | "automerge": true 17 | }, 18 | "packageRules": [ 19 | { 20 | "matchPackageNames": [ "typescript", "typescript-min" ], 21 | "matchUpdateTypes": [ "major", "minor" ], 22 | "enabled": false 23 | }, 24 | { 25 | "matchPackagePatterns": [ "*" ], 26 | "matchUpdateTypes": [ "minor", "patch" ], 27 | "automerge": true 28 | }, 29 | { 30 | "matchPackagePatterns": [ "*" ], 31 | "matchUpdateTypes": [ "major" ], 32 | "enabled": false 33 | } 34 | ], 35 | "reviewers": [ 36 | "team:devextreme-devops" 37 | ], 38 | "ignorePaths": [ 39 | ".github" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/strategy/vue3/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponent, DefineComponent } from "vue"; 2 | import { initDxComponent } from "../../component"; 3 | import { initDxConfiguration } from "../../configuration-component"; 4 | import { initDxExtensionComponent } from "../../extension-component"; 5 | import { setCompatOptions, setVModel } from "../../vue-helper"; 6 | 7 | export function createComponent(config: any): DefineComponent { 8 | config.extends = initDxComponent(); 9 | setCompatOptions(config); 10 | if (config.model) { 11 | setVModel(config); 12 | } 13 | return defineComponent(config); 14 | } 15 | 16 | export function createConfigurationComponent(config: any): DefineComponent { 17 | config.extends = initDxConfiguration(); 18 | setCompatOptions(config); 19 | return defineComponent(config); 20 | } 21 | 22 | export function createExtensionComponent(config: any): DefineComponent { 23 | config.extends = initDxExtensionComponent(); 24 | setCompatOptions(config); 25 | return defineComponent(config); 26 | } 27 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/tab-panel-example.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 39 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/common/charts.ts: -------------------------------------------------------------------------------- 1 | export { 2 | AnimationEaseMode, 3 | AnnotationType, 4 | ArgumentAxisHoverMode, 5 | AxisScaleType, 6 | ChartsAxisLabelOverlap, 7 | ChartsColor, 8 | ChartsDataType, 9 | ChartsLabelOverlap, 10 | DashStyle, 11 | DiscreteAxisDivisionMode, 12 | GradientColor, 13 | HatchDirection, 14 | LabelOverlap, 15 | LabelPosition, 16 | LegendHoverMode, 17 | LegendMarkerState, 18 | Palette, 19 | PaletteColorSet, 20 | PaletteExtensionMode, 21 | PointInteractionMode, 22 | PointSymbol, 23 | registerGradient, 24 | registerPattern, 25 | RelativePosition, 26 | ScaleBreak, 27 | ScaleBreakLineStyle, 28 | SeriesHoverMode, 29 | SeriesSelectionMode, 30 | SeriesType, 31 | ShiftLabelOverlap, 32 | TextOverflow, 33 | Theme, 34 | TimeInterval, 35 | TimeIntervalConfig, 36 | ValueErrorBarDisplayMode, 37 | ValueErrorBarType, 38 | VisualRange, 39 | VisualRangeUpdateMode, 40 | WordWrap, 41 | ZoomPanAction, 42 | } from "devextreme/common/charts"; 43 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/common/charts.ts: -------------------------------------------------------------------------------- 1 | export { 2 | AnimationEaseMode, 3 | AnnotationType, 4 | ArgumentAxisHoverMode, 5 | AxisScaleType, 6 | ChartsAxisLabelOverlap, 7 | ChartsColor, 8 | ChartsDataType, 9 | ChartsLabelOverlap, 10 | DashStyle, 11 | DiscreteAxisDivisionMode, 12 | GradientColor, 13 | HatchDirection, 14 | LabelOverlap, 15 | LabelPosition, 16 | LegendHoverMode, 17 | LegendMarkerState, 18 | Palette, 19 | PaletteColorSet, 20 | PaletteExtensionMode, 21 | PointInteractionMode, 22 | PointSymbol, 23 | registerGradient, 24 | registerPattern, 25 | RelativePosition, 26 | ScaleBreak, 27 | ScaleBreakLineStyle, 28 | SeriesHoverMode, 29 | SeriesSelectionMode, 30 | SeriesType, 31 | ShiftLabelOverlap, 32 | TextOverflow, 33 | Theme, 34 | TimeInterval, 35 | TimeIntervalConfig, 36 | ValueErrorBarDisplayMode, 37 | ValueErrorBarType, 38 | VisualRange, 39 | VisualRangeUpdateMode, 40 | WordWrap, 41 | ZoomPanAction, 42 | } from "devextreme/common/charts"; 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Developer Express Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ### Issue Type 7 | 8 | 9 | ### Description 10 | 11 | The issue is related to ... 12 | 13 | #### Steps to Reproduce 14 | 15 | 16 | #### Current Behavior 17 | 18 | #### Expected Behavior 19 | 20 | #### Demo 21 | 25 | 26 | ### Environment Details 27 | 30 | - devextreme version: 31 | - devextreme-vue version: 32 | - vue version: 33 | -------------------------------------------------------------------------------- /packages/sandbox/components/tab-panel-example.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 48 | -------------------------------------------------------------------------------- /packages/vue2-strategy/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Developer Express Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/__tests__/selectbox.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "@vue/test-utils"; 2 | import { defineComponent } from "vue"; 3 | 4 | import DxSelectBox from "../../select-box"; 5 | import DxTextBox from "../../text-box"; 6 | 7 | jest.setTimeout(1000); 8 | beforeEach(() => { 9 | jest.clearAllMocks(); 10 | }); 11 | 12 | describe("template rendering", () => { 13 | 14 | it("field template rendered", () => { 15 | const vm = defineComponent({ 16 | template: 17 | ` 18 | 21 | `, 22 | data() { 23 | return { 24 | dataSource: [{ ID: 1 }] 25 | }; 26 | }, 27 | components: { 28 | DxSelectBox, 29 | DxTextBox 30 | } 31 | }); 32 | const wrapper = mount(vm); 33 | expect(wrapper.getComponent("#component").vm.$el.children).toHaveLength(1); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/vue2-strategy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devextreme-vue2-strategy", 3 | "private": true, 4 | "version": "23.2.0", 5 | "main": "npm/index", 6 | "types": "npm/index", 7 | "files": [ 8 | "npm" 9 | ], 10 | "scripts": { 11 | "build": "gulp build", 12 | "pack": "npm run build", 13 | "test": "jest", 14 | "start": "webpack-dev-server" 15 | }, 16 | "peerDependencies": { 17 | "devextreme": "23.2-next" 18 | }, 19 | "devDependencies": { 20 | "@types/jest": "^26.0.0", 21 | "@vue/test-utils": "1.0.0-beta.29", 22 | "css-loader": "^2.1.1", 23 | "del": "^3.0.0", 24 | "devextreme-vue-generator": "^3.0.1", 25 | "gulp": "^4.0.2", 26 | "gulp-typescript": "^5.0.1", 27 | "jest": "^26.0.0", 28 | "source-map-loader": "^0.2.4", 29 | "style-loader": "^0.20.3", 30 | "ts-jest": "^26.0.0", 31 | "ts-loader": "^8.0.4", 32 | "tslint": "^5.11.0", 33 | "typescript": "^4.7.4", 34 | "url-loader": "^1.1.2", 35 | "vue": "^2.6.3", 36 | "vue-loader": "^15.0.0", 37 | "vue-template-compiler": "^2.6.3", 38 | "webpack": "^4.29.2", 39 | "webpack-cli": "^3.2.3", 40 | "webpack-dev-server": "^4.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/sandbox/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devextreme-vue-sandbox", 3 | "description": "DevExtreme Vue UI and Visualization Components", 4 | "private": true, 5 | "version": "23.2.0", 6 | "author": "Developer Express Inc.", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/DevExpress/devextreme-vue.git" 11 | }, 12 | "dependencies": { 13 | "devextreme-vue": "~23.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/jest": "^22.2.3", 17 | "@types/node": "^16.18.6", 18 | "@vue/compiler-sfc": "3.0.0", 19 | "@vue/test-utils": "^2.0.0-beta.7", 20 | "css-loader": "^2.1.1", 21 | "devextreme": "23.2-next", 22 | "minimatch": "^3.0.2", 23 | "source-map-loader": "^0.2.4", 24 | "style-loader": "^0.20.3", 25 | "ts-loader": "^8.0.4", 26 | "tsconfig-paths-webpack-plugin": "^3.3.0", 27 | "typescript": "^4.7.4", 28 | "url-loader": "^1.1.2", 29 | "vue": "^3.0.0", 30 | "vue-loader": "^16.0.0-beta.8", 31 | "vue-router": "^4.0.16", 32 | "webpack": "^4.29.2", 33 | "webpack-cli": "^3.2.3", 34 | "webpack-dev-server": "^4.0.0" 35 | }, 36 | "scripts": { 37 | "start": "webpack-dev-server" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/__tests__/toolbar.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "@vue/test-utils"; 2 | import { defineComponent } from "vue"; 3 | 4 | import DxButton from "../../button"; 5 | import DxToolbar, { DxItem } from "../../toolbar"; 6 | 7 | jest.setTimeout(1000); 8 | beforeEach(() => { 9 | jest.clearAllMocks(); 10 | }); 11 | 12 | describe("template rendering", () => { 13 | 14 | it("should render a default template only for a configuration component where it is declared", () => { 15 | const vm = defineComponent({ 16 | template: 17 | ` 18 | 19 | 22 | 23 | 24 | `, 25 | components: { 26 | DxToolbar, 27 | DxItem, 28 | DxButton 29 | } 30 | }); 31 | const wrapper = mount(vm); 32 | expect(wrapper.vm.$el.getElementsByClassName("dx-button")).toHaveLength(1); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Developer Express Inc.", 3 | "name": "devextreme-vue-generator", 4 | "version": "3.0.4", 5 | "description": "DevExtreme Vue UI and Visualization Components", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/DevExpress/devextreme-vue.git" 9 | }, 10 | "main": "dist/generator", 11 | "types": "dist/generator", 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "clean": "del-cli ./dist", 17 | "build": "npm run clean && tsc", 18 | "build:local": "npm run clean && tsc --project tsconfig.local.json", 19 | "pack": "npm run build && npm pack", 20 | "postpack": "cpy './*.tgz' dist && del-cli './*.tgz'", 21 | "test": "jest" 22 | }, 23 | "keywords": [ 24 | "vue", 25 | "devextreme", 26 | "devexpress" 27 | ], 28 | "license": "MIT", 29 | "dependencies": { 30 | "dasherize": "^2.0.0", 31 | "dot": "^1.1.3" 32 | }, 33 | "devDependencies": { 34 | "@types/dot": "^1.1.5", 35 | "@types/jest": "^26.0.24", 36 | "cpy-cli": "^4.0.0", 37 | "del-cli": "^3.0.1", 38 | "devextreme-internal-tools": "10.0.0-beta.17", 39 | "jest": "^26.6.3", 40 | "ts-jest": "^26.5.6", 41 | "typescript": "^4.7.4" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/tsconfig.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist", 4 | "baseUrl": "./packages", 5 | "paths": { 6 | "devextreme-vue-generator": [ 7 | "devextreme-vue-generator/src" 8 | ], 9 | "devextreme-vue": [ 10 | "devextreme-vue/src" 11 | ], 12 | "devextreme-vue/*": [ 13 | "devextreme-vue/src/*" 14 | ], 15 | "devextreme-vue2-strategy": [ 16 | "vue2-strategy/src/core" 17 | ] 18 | }, 19 | "skipLibCheck": true, 20 | "esModuleInterop": true, 21 | "allowSyntheticDefaultImports": true, 22 | "target": "es5", 23 | "module": "commonjs", 24 | "noEmitOnError": true, 25 | "declaration": true, 26 | "experimentalDecorators": true, 27 | "forceConsistentCasingInFileNames": true, 28 | "noFallthroughCasesInSwitch": true, 29 | "noImplicitAny": false, 30 | "noImplicitReturns": true, 31 | "noImplicitThis": true, 32 | "noUnusedLocals": true, 33 | "noUnusedParameters": true, 34 | "strictNullChecks": true, 35 | "lib": [ 36 | "esnext", 37 | "dom" 38 | ] 39 | }, 40 | "include": [ 41 | "src/**/*" 42 | ], 43 | "exclude": [ 44 | "src/**/*.test.ts", 45 | "node_modules", 46 | "dist" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/extension-component.ts: -------------------------------------------------------------------------------- 1 | import { defineComponent } from "vue"; 2 | import { IBaseComponent, initBaseComponent } from "./component"; 3 | import { getNodeOptions } from "./vue-helper"; 4 | 5 | interface IExtension { 6 | $_isExtension: boolean; 7 | $_attachTo(element: any); 8 | } 9 | 10 | interface IExtensionComponentNode { 11 | $_hasOwner: boolean; 12 | } 13 | 14 | function initDxExtensionComponent() { 15 | return defineComponent({ 16 | extends: initBaseComponent(), 17 | mounted() { 18 | this.$el.setAttribute("isExtension", "true"); 19 | const nodeOptions = getNodeOptions(this); 20 | (nodeOptions as any as IExtension).$_isExtension = true; 21 | (nodeOptions as any as IExtension).$_attachTo = this.attachTo.bind(this); 22 | if (nodeOptions && (nodeOptions as any as IExtensionComponentNode).$_hasOwner) { return; } 23 | 24 | this.attachTo(this.$el); 25 | }, 26 | 27 | methods: { 28 | attachTo(element: any) { 29 | (this as any as IBaseComponent).$_createWidget(element); 30 | } 31 | } 32 | }); 33 | } 34 | 35 | export { 36 | initDxExtensionComponent, 37 | IExtension, 38 | IExtensionComponentNode 39 | }; 40 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./packages", 4 | "paths": { 5 | "devextreme-vue-generator": [ 6 | "devextreme-vue-generator/src" 7 | ], 8 | "devextreme-vue": [ 9 | "devextreme-vue/src" 10 | ], 11 | "devextreme-vue/*": [ 12 | "devextreme-vue/src/*" 13 | ], 14 | "devextreme-vue2-strategy": [ 15 | "vue2-strategy/src/core" 16 | ] 17 | }, 18 | "esModuleInterop": true, 19 | "allowSyntheticDefaultImports": true, 20 | "target": "es5", 21 | "module": "commonjs", 22 | "noEmitOnError": true, 23 | "declaration": true, 24 | "experimentalDecorators": true, 25 | "forceConsistentCasingInFileNames": true, 26 | "noFallthroughCasesInSwitch": true, 27 | "noImplicitAny": false, 28 | "noImplicitReturns": true, 29 | "noImplicitThis": true, 30 | "noUnusedLocals": true, 31 | "noUnusedParameters": true, 32 | "strictNullChecks": true, 33 | "lib": [ 34 | "esnext", 35 | "dom" 36 | ] 37 | }, 38 | "exclude": [ 39 | "node_modules", 40 | "dist" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /packages/devextreme-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devextreme-vue", 3 | "version": "23.2.0", 4 | "description": "DevExtreme Vue UI and Visualization Components", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/DevExpress/devextreme-vue.git" 8 | }, 9 | "main": "index.js", 10 | "types": "index.d.ts", 11 | "scripts": { 12 | "clean": "gulp clean", 13 | "build": "npm run clean && gulp generate", 14 | "pack": "gulp npm.pack", 15 | "test": "jest" 16 | }, 17 | "keywords": [ 18 | "vue", 19 | "devextreme", 20 | "devexpress" 21 | ], 22 | "author": "Developer Express Inc.", 23 | "license": "MIT", 24 | "peerDependencies": { 25 | "devextreme": "23.2-next", 26 | "vue": "^2.5.16 || ^3.0.0" 27 | }, 28 | "devDependencies": { 29 | "@types/jest": "^26.0.24", 30 | "@vue/compiler-sfc": "^3.0.0", 31 | "@vue/test-utils": "2.0.0-beta.7", 32 | "del": "^3.0.0", 33 | "devextreme-vue-generator": "^3.0.3", 34 | "devextreme-vue2-strategy": "~23.2.0", 35 | "gulp": "^4.0.2", 36 | "gulp-header": "^2.0.9", 37 | "gulp-shell": "^0.6.5", 38 | "gulp-typescript": "^5.0.1", 39 | "jest": "^26.6.3", 40 | "ts-jest": "^26.5.6", 41 | "typescript": "^4.7.4", 42 | "vue": "3.0.0", 43 | "vue-router": "^4.0.16", 44 | "vue-template-compiler": "^2.6.3" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/sandbox/components/popup-example.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 52 | -------------------------------------------------------------------------------- /HOW_TO_BUILD.md: -------------------------------------------------------------------------------- 1 | # DevExtreme Vue. How to Build an Application 2 | 3 | ## DevExtreme Submodule 4 | 5 | Since we store the generated code in this repository, you need to commit a version of `devextreme` that is compatible with it. 6 | We use `git-submodule` to keep the versions of `devextreme` and `devextreme-vue` in sync. 7 | 8 | After you clone the `devextreme-vue` repository, use the following command to load the `devextreme` submodule: 9 | 10 | npm run restore-devextreme 11 | 12 | This command also resets all changes in the submodule, if any occur. 13 | 14 | To get the latest `devextreme` commits, update the submodule: 15 | 16 | npm run pull-devextreme 17 | 18 | After that, generate the code (see the last paragraph) and commit the changes in the submodule file. 19 | 20 | ## Link DevExtreme Modules 21 | 22 | To install the latest version of `devextreme` in the `node_modules` folder, run the following command: 23 | 24 | npm run link-devextreme 25 | 26 | ## Local DevExtreme Fork 27 | 28 | If you need to use your fork of `devextreme` locally instead of a submodule, change the path to `devextreme` in `package.json`, section `config`: 29 | 30 | "config": { 31 | "devextreme": "./devextreme" 32 | } 33 | 34 | ## Generate Code 35 | 36 | Generate metadata before code generation: 37 | 38 | npm run generate-metadata 39 | 40 | Then, build the packages: 41 | 42 | npm run build:packages 43 | -------------------------------------------------------------------------------- /packages/sandbox/components/menu-example.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 52 | -------------------------------------------------------------------------------- /packages/vue2-strategy/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: "./sandbox/main.ts", 3 | output: { 4 | filename: "./sandbox/public/js/app/bundle.js", 5 | }, 6 | devtool: "source-map", 7 | devServer: { 8 | port: 9900, 9 | open: true, 10 | openPage: "sandbox/public/index.html" 11 | }, 12 | resolve: { 13 | extensions: [".webpack.js", ".web.js", ".ts", ".vue", ".js"], 14 | alias: { 15 | 'vue$': 'vue/dist/vue.esm.js' 16 | } 17 | }, 18 | mode: "development", 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader', 24 | options: { 25 | esModule: true 26 | } 27 | }, 28 | { 29 | test: /\.js$/, 30 | use: "source-map-loader", 31 | enforce: "pre" 32 | }, 33 | { 34 | test: /\.tsx?$/, 35 | use: { 36 | loader: "ts-loader", 37 | options: { 38 | appendTsSuffixTo: [/\.vue$/], 39 | compilerOptions: { 40 | "noImplicitAny": false 41 | } 42 | } 43 | } 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: [ 48 | { loader: "style-loader" }, 49 | { loader: "css-loader" } 50 | ] 51 | }, 52 | { 53 | test: /\.(eot|svg|ttf|woff|woff2)$/, 54 | use: "url-loader?name=[name].[ext]" 55 | } 56 | ] 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/validation-group.ts: -------------------------------------------------------------------------------- 1 | import ValidationGroup, { Properties } from "devextreme/ui/validation_group"; 2 | import { createComponent } from "./core/index"; 3 | 4 | type AccessibleOptions = Pick; 12 | 13 | interface DxValidationGroup extends AccessibleOptions { 14 | readonly instance?: ValidationGroup; 15 | } 16 | const DxValidationGroup = createComponent({ 17 | props: { 18 | elementAttr: Object, 19 | height: [Function, Number, String], 20 | onDisposing: Function, 21 | onInitialized: Function, 22 | onOptionChanged: Function, 23 | width: [Function, Number, String] 24 | }, 25 | emits: { 26 | "update:isActive": null, 27 | "update:hoveredElement": null, 28 | "update:elementAttr": null, 29 | "update:height": null, 30 | "update:onDisposing": null, 31 | "update:onInitialized": null, 32 | "update:onOptionChanged": null, 33 | "update:width": null, 34 | }, 35 | computed: { 36 | instance(): ValidationGroup { 37 | return (this as any).$_instance; 38 | } 39 | }, 40 | beforeCreate() { 41 | (this as any).$_WidgetClass = ValidationGroup; 42 | } 43 | }); 44 | 45 | export default DxValidationGroup; 46 | export { 47 | DxValidationGroup 48 | }; 49 | import type * as DxValidationGroupTypes from "devextreme/ui/validation_group_types"; 50 | export { DxValidationGroupTypes }; 51 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/src/template.ts: -------------------------------------------------------------------------------- 1 | import { template, templateSettings } from "dot"; 2 | 3 | const defaultSettings = { 4 | ...templateSettings, 5 | conditional: /\<#\?(\?)?\s*([\s\S]*?)\s*#\>/g, 6 | define: /\<###\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)##\>/g, 7 | encode: /\<#!([\s\S]+?)#\>/g, 8 | evaluate: /\<#([\s\S]+?)#\>/g, 9 | interpolate: /\<#=([\s\S]+?)#\>/g, 10 | iterate: /\<#~\s*(?:#\>|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*#\>)/g, 11 | use: /\<##([\s\S]+?)#\>/g, 12 | strip: false, 13 | varname: "it" 14 | }; 15 | 16 | const createTempate = (templateStr: string): ((model: any) => string) => { 17 | const templateFunc = template(templateStr, defaultSettings); 18 | 19 | return (model: any) => (templateFunc(model) as string) 20 | .replace(/[\s\S]{1}\x08{1}|[\s\S]{2}\x08{2}|[\s\S]{3}\x08{3}/g, "") 21 | .replace(/\x08/, ""); 22 | }; 23 | 24 | const L0: string = `\n`; 25 | const L1: string = `\n` + tab(1); 26 | const L2: string = `\n` + tab(2); 27 | const L3: string = `\n` + tab(3); 28 | const L4: string = `\n` + tab(4); 29 | 30 | const TAB1: string = tab(1); 31 | const TAB2: string = tab(2); 32 | const TAB3: string = tab(3); 33 | const TAB4: string = tab(4); 34 | 35 | function tab(i: number): string { 36 | return Array(i * 2 + 1).join(" "); 37 | } 38 | 39 | export { 40 | createTempate, 41 | L0, 42 | L1, 43 | L2, 44 | L3, 45 | L4, 46 | TAB1, 47 | TAB2, 48 | TAB3, 49 | TAB4 50 | }; 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug in devextreme-vue 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | 18 | # Bug Report 19 | 20 | 21 | 22 | **Package versions:** 23 | 24 | devexteme version: 25 | devextreme-vue version: 26 | 27 | **Steps to reproduce:** 28 | 32 | 33 | **Current behavior:** 34 | 35 | 36 | **Expected behavior:** 37 | 38 | 39 | **Screenshots:** 40 | 41 | -------------------------------------------------------------------------------- /packages/vue2-strategy/gulpfile.js: -------------------------------------------------------------------------------- 1 | const del = require('del'); 2 | const mkdir = require('mkdirp'); 3 | const fs = require('fs'); 4 | const gulp = require('gulp'); 5 | const ts = require('gulp-typescript'); 6 | 7 | const generateSync = require('devextreme-vue-generator').default; 8 | 9 | const config = require('./build.config'); 10 | const VUE_VERSION = 2; 11 | 12 | gulp.task('build.components', gulp.series( 13 | (done) => { 14 | generateSync( 15 | JSON.parse(fs.readFileSync(config.metadataPath).toString()), 16 | config.baseComponent, 17 | config.configComponent, 18 | { 19 | componentsDir: config.generatedComponentsDir, 20 | indexFileName: config.indexFileName 21 | }, 22 | config.widgetsPackage, 23 | VUE_VERSION, 24 | true 25 | ); 26 | 27 | done(); 28 | } 29 | )); 30 | 31 | gulp.task('clean', gulp.parallel( 32 | (c) => del([`${config.generatedComponentsDir}\\*`, `!${config.coreComponentsDir}`], c), 33 | (c) => del(config.npm.dist, c) 34 | )); 35 | 36 | gulp.task('copy-helper', () => { 37 | return gulp.src('../devextreme-vue/src/core/helpers.ts') 38 | .pipe(gulp.dest('./src/core')); 39 | }); 40 | 41 | gulp.task('build.strategy', function() { 42 | return gulp.src([ 43 | config.core, 44 | ...config.ignoredGlobs 45 | ]) 46 | .pipe(ts('tsconfig.json')) 47 | .pipe(gulp.dest(config.npm.dist)) 48 | }); 49 | 50 | gulp.task('build', gulp.series( 51 | 'clean', 52 | 'copy-helper', 53 | 'build.strategy', 54 | 'build.components' 55 | )); 56 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/validation-group.ts: -------------------------------------------------------------------------------- 1 | import ValidationGroup, { Properties } from "devextreme/ui/validation_group"; 2 | import { createComponent } from "./core/index"; 3 | 4 | type AccessibleOptions = Pick; 12 | 13 | interface DxValidationGroup extends AccessibleOptions { 14 | readonly instance?: ValidationGroup; 15 | } 16 | const DxValidationGroup = createComponent({ 17 | props: { 18 | elementAttr: Object, 19 | height: [Function, Number, String], 20 | onDisposing: Function, 21 | onInitialized: Function, 22 | onOptionChanged: Function, 23 | width: [Function, Number, String] 24 | }, 25 | emits: { 26 | "update:isActive": null, 27 | "update:hoveredElement": null, 28 | "update:elementAttr": null, 29 | "update:height": null, 30 | "update:onDisposing": null, 31 | "update:onInitialized": null, 32 | "update:onOptionChanged": null, 33 | "update:width": null, 34 | }, 35 | computed: { 36 | instance(): ValidationGroup { 37 | return (this as any).$_instance; 38 | } 39 | }, 40 | beforeCreate() { 41 | (this as any).$_WidgetClass = ValidationGroup; 42 | (this as any).$_hasAsyncTemplate = true; 43 | } 44 | }); 45 | 46 | export default DxValidationGroup; 47 | export { 48 | DxValidationGroup 49 | }; 50 | import type * as DxValidationGroupTypes from "devextreme/ui/validation_group_types"; 51 | export { DxValidationGroupTypes }; 52 | -------------------------------------------------------------------------------- /packages/devextreme-vue-generator/src/converter.ts: -------------------------------------------------------------------------------- 1 | import { ICustomType, ITypeDescr } from "devextreme-internal-tools/integration-data-model"; 2 | 3 | function convertTypes( 4 | types: ITypeDescr[] | undefined | null, 5 | customTypes?: Record 6 | ): string[] | undefined { 7 | if (types === undefined || types === null || types.length === 0) { 8 | return; 9 | } 10 | 11 | if (customTypes) { 12 | types = types.concat(expandTypes(types, customTypes)); 13 | } 14 | 15 | const convertedTypes = new Set(types.map(convertType)); 16 | if (convertedTypes.has("Any")) { 17 | return; 18 | } 19 | 20 | return Array.from(convertedTypes); 21 | } 22 | 23 | function expandTypes(types: ITypeDescr[], customTypes: Record): ITypeDescr[] { 24 | const expandedTypes: ITypeDescr[] = []; 25 | types.forEach((t) => { 26 | if (t.isCustomType) { 27 | const aliases = customTypes[t.type].types; 28 | if (aliases) { 29 | expandedTypes.push(...aliases); 30 | } 31 | } 32 | }); 33 | return expandedTypes; 34 | } 35 | function convertType(typeDescr: ITypeDescr): string { 36 | switch (typeDescr.type) { 37 | case "String": 38 | case "Number": 39 | case "Boolean": 40 | case "Array": 41 | case "Object": 42 | case "Function": 43 | return typeDescr.type; 44 | } 45 | 46 | if (typeDescr.isCustomType) { 47 | return "Object"; 48 | } 49 | 50 | return "Any"; 51 | } 52 | 53 | export { convertTypes }; 54 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/common/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ApplyValueMode, 3 | AsyncRule, 4 | ButtonStyle, 5 | ButtonType, 6 | CompareRule, 7 | ComparisonOperator, 8 | CustomRule, 9 | DataStructure, 10 | DataType, 11 | Direction, 12 | DragDirection, 13 | Draggable, 14 | DragHighlight, 15 | EditorStyle, 16 | EmailRule, 17 | ExportFormat, 18 | FieldChooserLayout, 19 | FirstDayOfWeek, 20 | Format, 21 | GlobalConfig, 22 | HorizontalAlignment, 23 | HorizontalEdge, 24 | LabelMode, 25 | MaskMode, 26 | Mode, 27 | NumericRule, 28 | Orientation, 29 | PageLoadMode, 30 | PageOrientation, 31 | PatternRule, 32 | Position, 33 | PositionAlignment, 34 | RangeRule, 35 | RequiredRule, 36 | Scrollable, 37 | ScrollbarMode, 38 | ScrollDirection, 39 | ScrollMode, 40 | SearchMode, 41 | SelectAllMode, 42 | SimplifiedSearchMode, 43 | SingleMultipleAllOrNone, 44 | SingleMultipleOrNone, 45 | SingleOrMultiple, 46 | SingleOrNone, 47 | SliderValueChangeMode, 48 | Sortable, 49 | SortOrder, 50 | StoreType, 51 | StringLengthRule, 52 | SubmenuShowMode, 53 | TextBoxPredefinedButton, 54 | TextEditorButton, 55 | TextEditorButtonLocation, 56 | ToolbarItemComponent, 57 | ToolbarItemLocation, 58 | TooltipShowMode, 59 | ValidationCallbackData, 60 | ValidationMessageMode, 61 | ValidationRule, 62 | ValidationRuleType, 63 | ValidationStatus, 64 | VerticalAlignment, 65 | VerticalEdge, 66 | } from "devextreme/common"; 67 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/common/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ApplyValueMode, 3 | AsyncRule, 4 | ButtonStyle, 5 | ButtonType, 6 | CompareRule, 7 | ComparisonOperator, 8 | CustomRule, 9 | DataStructure, 10 | DataType, 11 | Direction, 12 | DragDirection, 13 | Draggable, 14 | DragHighlight, 15 | EditorStyle, 16 | EmailRule, 17 | ExportFormat, 18 | FieldChooserLayout, 19 | FirstDayOfWeek, 20 | Format, 21 | GlobalConfig, 22 | HorizontalAlignment, 23 | HorizontalEdge, 24 | LabelMode, 25 | MaskMode, 26 | Mode, 27 | NumericRule, 28 | Orientation, 29 | PageLoadMode, 30 | PageOrientation, 31 | PatternRule, 32 | Position, 33 | PositionAlignment, 34 | RangeRule, 35 | RequiredRule, 36 | Scrollable, 37 | ScrollbarMode, 38 | ScrollDirection, 39 | ScrollMode, 40 | SearchMode, 41 | SelectAllMode, 42 | SimplifiedSearchMode, 43 | SingleMultipleAllOrNone, 44 | SingleMultipleOrNone, 45 | SingleOrMultiple, 46 | SingleOrNone, 47 | SliderValueChangeMode, 48 | Sortable, 49 | SortOrder, 50 | StoreType, 51 | StringLengthRule, 52 | SubmenuShowMode, 53 | TextBoxPredefinedButton, 54 | TextEditorButton, 55 | TextEditorButtonLocation, 56 | ToolbarItemComponent, 57 | ToolbarItemLocation, 58 | TooltipShowMode, 59 | ValidationCallbackData, 60 | ValidationMessageMode, 61 | ValidationRule, 62 | ValidationRuleType, 63 | ValidationStatus, 64 | VerticalAlignment, 65 | VerticalEdge, 66 | } from "devextreme/common"; 67 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/popup-example.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevExtreme Vue UI and Visualization Components # 2 | 3 | [![Run Status](https://api.shippable.com/projects/5ab4c6354a24a207009ec636/badge?branch=master)](https://app.shippable.com/github/DevExpress/devextreme-vue) 4 | [![NPM](https://img.shields.io/npm/v/devextreme-vue.svg?maxAge=43200)](https://www.npmjs.com/package/devextreme-vue) 5 | 6 | This project allows you to use [DevExtreme components](http://js.devexpress.com/Demos/WidgetsGallery/) in [Vue](https://vuejs.org) applications. 7 | 8 | * [Documentation](https://js.devexpress.com/Documentation/Guide/Vue_Components/DevExtreme_Vue_Components/) 9 | * [Technical Demos](https://js.devexpress.com/Demos/WidgetsGallery/Demo/DataGrid/Overview/Vue/Light/) 10 | * [Responsive UI Templates](https://js.devexpress.com/Vue/Templates/UITemplates/) 11 | * [Application Template](https://js.devexpress.com/Vue/Documentation/Guide/Vue_Components/Application_Template/) 12 | 13 | ## License ## 14 | 15 | **DevExtreme Vue UI Components are released as an MIT-licensed (free and open-source) add-on to DevExtreme.** 16 | 17 | Familiarize yourself with the [DevExtreme License](https://js.devexpress.com/Licensing/). [Free trial is available!](http://js.devexpress.com/Buy/) 18 | 19 | ## Support & Feedback ## 20 | 21 | If you have questions regarding Vue functionality, consult [Vue docs](https://vuejs.org/v2/guide/). 22 | 23 | If you want to report a bug, request a feature, or ask a question, submit an [issue](https://github.com/DevExpress/devextreme-vue/issues) to this repo. Alternatively, you can contact us at the [DevExpress Support Center](https://www.devexpress.com/Support/Center) if you own an active DevExtreme license. 24 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/children-processing.ts: -------------------------------------------------------------------------------- 1 | import { VNode } from "vue"; 2 | import Configuration from "./configuration"; 3 | import { IConfigurable, IConfigurationComponent } from "./configuration-component"; 4 | 5 | function pullAllChildren(directChildren: VNode[], allChildren: VNode[], config: Configuration): void { 6 | if (!directChildren || directChildren.length === 0) { return; } 7 | 8 | pullConfigComponents(directChildren, allChildren, config); 9 | } 10 | 11 | function pullConfigComponents(children: VNode[], nodes: VNode[], ownerConfig: Configuration): void { 12 | 13 | children.forEach((node) => { 14 | nodes.push(node); 15 | if (!node.componentOptions) { return; } 16 | 17 | const configComponent = node.componentOptions.Ctor as any as IConfigurationComponent; 18 | if (!configComponent.$_optionName) { return; } 19 | 20 | const initialValues = { 21 | ...configComponent.$_predefinedProps, 22 | ...node.componentOptions.propsData 23 | }; 24 | 25 | const config = ownerConfig.createNested( 26 | configComponent.$_optionName, 27 | initialValues, 28 | configComponent.$_isCollectionItem, 29 | configComponent.$_expectedChildren 30 | ); 31 | 32 | (node.componentOptions as any as IConfigurable).$_config = config; 33 | (node.componentOptions as any as IConfigurable).$_innerChanges = {}; 34 | 35 | if (node.componentOptions.children) { 36 | pullConfigComponents(node.componentOptions.children as VNode[], nodes, config); 37 | } 38 | }); 39 | } 40 | 41 | export { 42 | pullAllChildren 43 | }; 44 | -------------------------------------------------------------------------------- /docs/using-webpack.md: -------------------------------------------------------------------------------- 1 | # Using the DevExtreme Vue Integration with Webpack 2 | 3 | ## Create a new Application ## 4 | 5 | You can use [the original Vue template on Webpack](https://github.com/vuejs-templates/webpack) or some other starter to create a new project based on Webpack. 6 | 7 | ## Add DevExtreme ## 8 | 9 | Follow the [installation](https://github.com/DevExpress/devextreme-vue#installation) section in our Readme. 10 | 11 | ## Configure Webpack Loaders for DevExtreme Stylesheets ## 12 | 13 | If you are using [the original Vue template on Webpack](https://github.com/vuejs-templates/webpack) 14 | you don't need any extra configuration, since all the required loaders are configured out-of-the-box. 15 | Otherwise, you need to make sure that all the necessary extensions are processed by the corresponding 16 | [loaders](https://webpack.github.io/docs/loaders.html) as described below. 17 | 18 | Go to *webpack.config.js* and configure loaders for css and fonts as follows: 19 | 20 | ```js 21 | ... 22 | loaders: [ 23 | ... 24 | { test: /\.css$/, loader: "style-loader!css-loader" }, 25 | { test: /\.(ttf|eot|woff)$/, loader: "file-loader?name=/[name].[ext]" } 26 | ] 27 | ... 28 | ``` 29 | 30 | Also, make sure that *style-loader*, *css-loader* and *file-loader* are installed into your project as npm dev dependencies. 31 | 32 | ## Import DevExtreme Stylesheets ## 33 | 34 | Having loaders configured, you need to import the required [DevExtreme css files](https://js.devexpress.com/Documentation/Guide/Themes/Predefined_Themes/). 35 | Go to your main .js file and import the stylesheets as follows: 36 | 37 | ```js 38 | ... 39 | import 'devextreme/dist/css/dx.common.css'; 40 | import 'devextreme/dist/css/dx.light.css'; 41 | ``` 42 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/core/config.test.ts: -------------------------------------------------------------------------------- 1 | import * as VueType from "vue"; 2 | import { DxComponent, IWidgetComponent } from "./component"; 3 | import config, { getOption } from "./config"; 4 | 5 | const Vue = VueType.default || VueType; 6 | 7 | const Widget = { 8 | option: jest.fn(), 9 | dispose: jest.fn(), 10 | on: jest.fn(), 11 | fire: jest.fn(), 12 | beginUpdate: jest.fn(), 13 | endUpdate: jest.fn(), 14 | }; 15 | 16 | const WidgetClass = jest.fn(() => Widget); 17 | 18 | const TestComponent = Vue.extend({ 19 | extends: DxComponent(), 20 | beforeCreate() { 21 | (this as any as IWidgetComponent).$_WidgetClass = WidgetClass; 22 | } 23 | }); 24 | 25 | describe("useLegacyTemplateEngine", () => { 26 | const originalValue = getOption("useLegacyTemplateEngine"); 27 | 28 | beforeEach(() => { 29 | config({ useLegacyTemplateEngine: true }); 30 | }); 31 | 32 | afterEach(() => { 33 | config({ useLegacyTemplateEngine: originalValue }); 34 | }); 35 | 36 | it("has model as scope", () => { 37 | new Vue({ 38 | template: ` 39 |
Template {{data.text}}
40 |
`, 41 | components: { 42 | TestComponent 43 | } 44 | }).$mount(); 45 | 46 | // @ts-ignore 47 | const render = WidgetClass.mock.calls[0][1].integrationOptions.templates.item.render; 48 | const renderedTemplate = render({ 49 | container: document.createElement("div"), 50 | model: { text: "with data" } 51 | }); 52 | 53 | expect(renderedTemplate.innerHTML).toBe("Template with data"); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/sandbox/components/map-example.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 62 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/__tests__/form.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "@vue/test-utils"; 2 | import { defineComponent, nextTick } from "vue"; 3 | 4 | import { DxForm, DxItem } from "../../form"; 5 | 6 | jest.setTimeout(1000); 7 | beforeEach(() => { 8 | jest.clearAllMocks(); 9 | }); 10 | 11 | describe("form", () => { 12 | 13 | it("should render config components by condition", async (done) => { 14 | const vm = defineComponent({ 15 | template: 16 | ` 20 | 24 | 27 | `, 28 | components: { 29 | DxItem, DxForm 30 | }, 31 | props: { 32 | show: { 33 | type: Boolean, 34 | default: true 35 | }, 36 | data: { 37 | type: Object, 38 | default: { 39 | FirstName: "name1", 40 | Position: "name2" 41 | } 42 | } 43 | } 44 | }); 45 | 46 | const wrapper = mount(vm); 47 | 48 | wrapper.setProps({ show: false }); 49 | 50 | nextTick(() => { 51 | wrapper.setProps({ show: true }); 52 | nextTick(() => { 53 | expect(wrapper.getComponent("#form").vm.$el 54 | .getElementsByClassName("dx-field-item-label-text")).toHaveLength(2); 55 | done(); 56 | }); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /packages/sandbox/components/text-box-example.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 64 | 65 | 71 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/load-indicator.ts: -------------------------------------------------------------------------------- 1 | import LoadIndicator, { Properties } from "devextreme/ui/load_indicator"; 2 | import { createComponent } from "./core/index"; 3 | 4 | type AccessibleOptions = Pick; 17 | 18 | interface DxLoadIndicator extends AccessibleOptions { 19 | readonly instance?: LoadIndicator; 20 | } 21 | const DxLoadIndicator = createComponent({ 22 | props: { 23 | elementAttr: Object, 24 | height: [Function, Number, String], 25 | hint: String, 26 | indicatorSrc: String, 27 | onContentReady: Function, 28 | onDisposing: Function, 29 | onInitialized: Function, 30 | onOptionChanged: Function, 31 | rtlEnabled: Boolean, 32 | visible: Boolean, 33 | width: [Function, Number, String] 34 | }, 35 | emits: { 36 | "update:isActive": null, 37 | "update:hoveredElement": null, 38 | "update:elementAttr": null, 39 | "update:height": null, 40 | "update:hint": null, 41 | "update:indicatorSrc": null, 42 | "update:onContentReady": null, 43 | "update:onDisposing": null, 44 | "update:onInitialized": null, 45 | "update:onOptionChanged": null, 46 | "update:rtlEnabled": null, 47 | "update:visible": null, 48 | "update:width": null, 49 | }, 50 | computed: { 51 | instance(): LoadIndicator { 52 | return (this as any).$_instance; 53 | } 54 | }, 55 | beforeCreate() { 56 | (this as any).$_WidgetClass = LoadIndicator; 57 | } 58 | }); 59 | 60 | export default DxLoadIndicator; 61 | export { 62 | DxLoadIndicator 63 | }; 64 | import type * as DxLoadIndicatorTypes from "devextreme/ui/load_indicator_types"; 65 | export { DxLoadIndicatorTypes }; 66 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/load-indicator.ts: -------------------------------------------------------------------------------- 1 | import LoadIndicator, { Properties } from "devextreme/ui/load_indicator"; 2 | import { createComponent } from "./core/index"; 3 | 4 | type AccessibleOptions = Pick; 17 | 18 | interface DxLoadIndicator extends AccessibleOptions { 19 | readonly instance?: LoadIndicator; 20 | } 21 | const DxLoadIndicator = createComponent({ 22 | props: { 23 | elementAttr: Object, 24 | height: [Function, Number, String], 25 | hint: String, 26 | indicatorSrc: String, 27 | onContentReady: Function, 28 | onDisposing: Function, 29 | onInitialized: Function, 30 | onOptionChanged: Function, 31 | rtlEnabled: Boolean, 32 | visible: Boolean, 33 | width: [Function, Number, String] 34 | }, 35 | emits: { 36 | "update:isActive": null, 37 | "update:hoveredElement": null, 38 | "update:elementAttr": null, 39 | "update:height": null, 40 | "update:hint": null, 41 | "update:indicatorSrc": null, 42 | "update:onContentReady": null, 43 | "update:onDisposing": null, 44 | "update:onInitialized": null, 45 | "update:onOptionChanged": null, 46 | "update:rtlEnabled": null, 47 | "update:visible": null, 48 | "update:width": null, 49 | }, 50 | computed: { 51 | instance(): LoadIndicator { 52 | return (this as any).$_instance; 53 | } 54 | }, 55 | beforeCreate() { 56 | (this as any).$_WidgetClass = LoadIndicator; 57 | (this as any).$_hasAsyncTemplate = true; 58 | } 59 | }); 60 | 61 | export default DxLoadIndicator; 62 | export { 63 | DxLoadIndicator 64 | }; 65 | import type * as DxLoadIndicatorTypes from "devextreme/ui/load_indicator_types"; 66 | export { DxLoadIndicatorTypes }; 67 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/common/grids.ts: -------------------------------------------------------------------------------- 1 | export { 2 | AdaptiveDetailRowPreparingInfo, 3 | ApplyChangesMode, 4 | ApplyFilterMode, 5 | ColumnBase, 6 | ColumnButtonBase, 7 | ColumnChooser, 8 | ColumnChooserMode, 9 | ColumnChooserSearchConfig, 10 | ColumnChooserSelectionConfig, 11 | ColumnCustomizeTextArg, 12 | ColumnFixing, 13 | ColumnFixingTexts, 14 | ColumnHeaderFilter, 15 | ColumnHeaderFilterSearchConfig, 16 | ColumnLookup, 17 | ColumnResizeMode, 18 | DataChange, 19 | DataChangeInfo, 20 | DataChangeType, 21 | DataErrorOccurredInfo, 22 | DataRenderMode, 23 | EditingBase, 24 | EditingTextsBase, 25 | EnterKeyAction, 26 | EnterKeyDirection, 27 | FilterOperation, 28 | FilterPanel, 29 | FilterPanelTexts, 30 | FilterRow, 31 | FilterRowOperationDescriptions, 32 | FilterType, 33 | GridBase, 34 | GridBaseOptions, 35 | GridsEditMode, 36 | GridsEditRefreshMode, 37 | GroupExpandMode, 38 | HeaderFilter, 39 | HeaderFilterGroupInterval, 40 | HeaderFilterSearchConfig, 41 | HeaderFilterTexts, 42 | KeyboardNavigation, 43 | KeyDownInfo, 44 | LoadPanel, 45 | NewRowInfo, 46 | NewRowPosition, 47 | Pager, 48 | PagerDisplayMode, 49 | PagerPageSize, 50 | PagingBase, 51 | RowDragging, 52 | RowDraggingTemplateData, 53 | RowInsertedInfo, 54 | RowInsertingInfo, 55 | RowKeyInfo, 56 | RowRemovedInfo, 57 | RowRemovingInfo, 58 | RowUpdatedInfo, 59 | RowUpdatingInfo, 60 | RowValidatingInfo, 61 | SavingInfo, 62 | ScrollingBase, 63 | SearchPanel, 64 | SelectedFilterOperation, 65 | SelectionBase, 66 | SelectionChangedInfo, 67 | SelectionColumnDisplayMode, 68 | Sorting, 69 | StartEditAction, 70 | StateStoreType, 71 | StateStoring, 72 | SummaryType, 73 | ToolbarPreparingInfo, 74 | } from "devextreme/common/grids"; 75 | -------------------------------------------------------------------------------- /packages/vue2-strategy/src/common/grids.ts: -------------------------------------------------------------------------------- 1 | export { 2 | AdaptiveDetailRowPreparingInfo, 3 | ApplyChangesMode, 4 | ApplyFilterMode, 5 | ColumnBase, 6 | ColumnButtonBase, 7 | ColumnChooser, 8 | ColumnChooserMode, 9 | ColumnChooserSearchConfig, 10 | ColumnChooserSelectionConfig, 11 | ColumnCustomizeTextArg, 12 | ColumnFixing, 13 | ColumnFixingTexts, 14 | ColumnHeaderFilter, 15 | ColumnHeaderFilterSearchConfig, 16 | ColumnLookup, 17 | ColumnResizeMode, 18 | DataChange, 19 | DataChangeInfo, 20 | DataChangeType, 21 | DataErrorOccurredInfo, 22 | DataRenderMode, 23 | EditingBase, 24 | EditingTextsBase, 25 | EnterKeyAction, 26 | EnterKeyDirection, 27 | FilterOperation, 28 | FilterPanel, 29 | FilterPanelTexts, 30 | FilterRow, 31 | FilterRowOperationDescriptions, 32 | FilterType, 33 | GridBase, 34 | GridBaseOptions, 35 | GridsEditMode, 36 | GridsEditRefreshMode, 37 | GroupExpandMode, 38 | HeaderFilter, 39 | HeaderFilterGroupInterval, 40 | HeaderFilterSearchConfig, 41 | HeaderFilterTexts, 42 | KeyboardNavigation, 43 | KeyDownInfo, 44 | LoadPanel, 45 | NewRowInfo, 46 | NewRowPosition, 47 | Pager, 48 | PagerDisplayMode, 49 | PagerPageSize, 50 | PagingBase, 51 | RowDragging, 52 | RowDraggingTemplateData, 53 | RowInsertedInfo, 54 | RowInsertingInfo, 55 | RowKeyInfo, 56 | RowRemovedInfo, 57 | RowRemovingInfo, 58 | RowUpdatedInfo, 59 | RowUpdatingInfo, 60 | RowValidatingInfo, 61 | SavingInfo, 62 | ScrollingBase, 63 | SearchPanel, 64 | SelectedFilterOperation, 65 | SelectionBase, 66 | SelectionChangedInfo, 67 | SelectionColumnDisplayMode, 68 | Sorting, 69 | StartEditAction, 70 | StateStoreType, 71 | StateStoring, 72 | SummaryType, 73 | ToolbarPreparingInfo, 74 | } from "devextreme/common/grids"; 75 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/menu-example.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 59 | -------------------------------------------------------------------------------- /packages/sandbox/app.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 70 | -------------------------------------------------------------------------------- /packages/vue2-strategy/sandbox/components/map-example.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 66 | -------------------------------------------------------------------------------- /packages/devextreme-vue/src/core/__tests__/templates-discovering.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "@vue/test-utils"; 2 | import { defineComponent } from "vue"; 3 | import { discover } from "../templates-discovering"; 4 | 5 | describe("templates-discovering (vue 3)", () => { 6 | 7 | it("discovers named scoped slot", () => { 8 | const template = "