diff --git a/.gitignore b/.gitignore
index 2c4eac37d..23784bdab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,10 @@ vite.config.ts.*
apps/web-antd/types/components.d.ts
.history
.cursor
+
+# AI
+.agent
+.agents
+.claude
+.codex
+skills-lock.json
diff --git a/.npmrc b/.npmrc
index aeac1ae91..6d28fabf4 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,8 +1,8 @@
registry=https://registry.npmmirror.com
public-hoist-pattern[]=lefthook
public-hoist-pattern[]=eslint
-public-hoist-pattern[]=prettier
-public-hoist-pattern[]=prettier-plugin-tailwindcss
+public-hoist-pattern[]=oxfmt
+public-hoist-pattern[]=oxlint
public-hoist-pattern[]=stylelint
public-hoist-pattern[]=*postcss*
public-hoist-pattern[]=@commitlint/*
diff --git a/.prettierignore b/.prettierignore
deleted file mode 100644
index d0b0ca133..000000000
--- a/.prettierignore
+++ /dev/null
@@ -1,18 +0,0 @@
-dist
-dev-dist
-.local
-.output.js
-node_modules
-.nvmrc
-coverage
-CODEOWNERS
-.nitro
-.output
-
-
-**/*.svg
-**/*.sh
-
-public
-.npmrc
-*-lock.yaml
diff --git a/.prettierrc.mjs b/.prettierrc.mjs
deleted file mode 100644
index 3e25d2cfa..000000000
--- a/.prettierrc.mjs
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@vben/prettier-config';
diff --git a/.stylelintignore b/.stylelintignore
index f4b2db2c1..3adb33b22 100644
--- a/.stylelintignore
+++ b/.stylelintignore
@@ -2,3 +2,7 @@ dist
public
__tests__
coverage
+.codex
+.claude
+.agent
+.agents
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index f4675d576..5b7db1abe 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -2,14 +2,18 @@
"recommendations": [
// Vue 3 的语言支持
"Vue.volar",
- // 将 ESLint JavaScript 集成到 VS Code 中。
+ // 将 eslint 集成到 VS Code 中。
"dbaeumer.vscode-eslint",
+ // 将 oxlint 集成到 VS Code 中。
+ "oxc.oxc-vscode",
// Visual Studio Code 的官方 Stylelint 扩展
"stylelint.vscode-stylelint",
- // 使用 Prettier 的代码格式化程序
- "esbenp.prettier-vscode",
+ // 使用 oxfmt 的代码格式化程序
+ "oxc.oxc-vscode",
// 支持 dotenv 文件语法
"mikestead.dotenv",
+ // YAML 语言支持,供 ESLint 校验 pnpm-workspace.yaml 等文件
+ "redhat.vscode-yaml",
// 源代码的拼写检查器
"streetsidesoftware.code-spell-checker",
// Tailwind CSS 的官方 VS Code 插件
diff --git a/.vscode/settings.json b/.vscode/settings.json
index f7ae6c5ba..85b778c0e 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,6 @@
{
- "tailwindCSS.experimental.configFile": "internal/tailwind-config/src/index.ts",
+ "tailwindCSS.experimental.configFile": "packages/@core/base/design/src/css/global.css",
+ "tailwindCSS.lint.suggestCanonicalClasses": "ignore",
// workbench
"workbench.list.smoothScrolling": true,
"workbench.startupEditor": "newUntitledFile",
@@ -31,39 +32,51 @@
"editor.autoClosingOvertype": "always",
"editor.autoClosingQuotes": "beforeWhitespace",
"editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?",
+ "editor.quickSuggestions": {
+ "strings": "on"
+ },
+
+ // lint && format
+ "oxc.enable": true,
+ "oxc.typeAware": true,
+ "oxc.configPath": "oxlint.config.ts",
+ "oxc.fmt.configPath": "oxfmt.config.ts",
+ "eslint.useFlatConfig": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
+ "source.fixAll.oxc": "explicit",
"source.fixAll.stylelint": "explicit",
"source.organizeImports": "never"
},
- "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.defaultFormatter": "oxc.oxc-vscode",
"[html]": {
- "editor.defaultFormatter": "vscode.html-language-features"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[css]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[scss]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[javascript]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[typescript]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[json]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[markdown]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[jsonc]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
"[vue]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "oxc.oxc-vscode"
},
+
// extensions
"extensions.ignoreRecommendations": true,
@@ -79,6 +92,7 @@
"files.insertFinalNewline": true,
"files.simpleDialog.enable": true,
"files.associations": {
+ "*.css": "tailwindcss",
"*.ejs": "html",
"*.art": "html",
"**/tsconfig.json": "jsonc",
@@ -119,7 +133,7 @@
// search
"search.searchEditor.singleClickBehaviour": "peekDefinition",
"search.followSymlinks": false,
- // 在使用搜索功能时,将这些文件夹/文件排除在外
+ // 使用搜索功能时,将这些文件和文件夹排除在外
"search.exclude": {
"**/node_modules": true,
"**/*.log": true,
@@ -159,7 +173,7 @@
"emmet.triggerExpansionOnTab": false,
"errorLens.enabledDiagnosticLevels": ["warning", "error"],
- "errorLens.excludeBySource": ["cSpell", "Grammarly", "eslint"],
+ "errorLens.excludeBySource": ["cSpell", "Grammarly"],
"stylelint.enable": true,
"stylelint.packageManager": "pnpm",
@@ -196,7 +210,7 @@
"yaml": false
},
- "cssVariables.lookupFiles": ["packages/core/base/design/src/**/*.css"],
+ "cssVariables.lookupFiles": ["packages/@core/base/design/src/**/*.css"],
"i18n-ally.localesPaths": [
"packages/locales/src/langs",
@@ -220,8 +234,7 @@
"*.env": "$(capture).env.*",
"README.md": "README*,CHANGELOG*,LICENSE,CNAME",
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,.gitattributes,.gitignore,.gitpod.yml,.npmrc,.browserslistrc,.node-version,.git*,.tazerc.json",
- "eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,cspell.json,lefthook.yml",
- "tailwind.config.mjs": "postcss.*"
+ "oxlint.config.ts": ".eslintignore,.stylelintignore,.commitlintrc.*,stylelint.config.*,.lintstagedrc.mjs,cspell.json,lefthook.yml,oxfmt.config.*,eslint.config.*"
},
"commentTranslate.hover.enabled": false,
"commentTranslate.multiLineMerge": true,
@@ -231,7 +244,6 @@
"editor.linkedEditing": true, // 自动同步更改html标签,
"vscodeCustomCodeColor.highlightValue": "v-access", // v-access显示的颜色
"vscodeCustomCodeColor.highlightValueColor": "#CCFFFF",
- "oxc.enable": false,
"cSpell.words": [
"archiver",
"axios",
diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json
index bacca810d..bf938913f 100644
--- a/apps/web-antd/package.json
+++ b/apps/web-antd/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben/web-antd",
- "version": "2.0.0-alpha.3",
+ "version": "2.0.0-beta.1",
"homepage": "https://vben.pro",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
diff --git a/apps/web-antd/postcss.config.mjs b/apps/web-antd/postcss.config.mjs
deleted file mode 100644
index 3d8070455..000000000
--- a/apps/web-antd/postcss.config.mjs
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@vben/tailwind-config/postcss';
diff --git a/apps/web-antd/src/views/dashboard/analytics/index.vue b/apps/web-antd/src/views/dashboard/analytics/index.vue
index e428ac955..49bf4d0b7 100644
--- a/apps/web-antd/src/views/dashboard/analytics/index.vue
+++ b/apps/web-antd/src/views/dashboard/analytics/index.vue
@@ -120,10 +120,10 @@ function keepOneMessage() {
-
+
-
+
diff --git a/apps/web-antd/tailwind.config.mjs b/apps/web-antd/tailwind.config.mjs
deleted file mode 100644
index f17f556fa..000000000
--- a/apps/web-antd/tailwind.config.mjs
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@vben/tailwind-config';
diff --git a/apps/web-antd/tsconfig.json b/apps/web-antd/tsconfig.json
index 9d43c9297..fb52a54d4 100644
--- a/apps/web-antd/tsconfig.json
+++ b/apps/web-antd/tsconfig.json
@@ -2,7 +2,6 @@
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/tsconfig/web-app.json",
"compilerOptions": {
- "baseUrl": ".",
"paths": {
"#/*": ["./src/*"]
}
diff --git a/apps/web-antd/tsconfig.node.json b/apps/web-antd/tsconfig.node.json
index c2f0d86cc..36e9fb5fb 100644
--- a/apps/web-antd/tsconfig.node.json
+++ b/apps/web-antd/tsconfig.node.json
@@ -6,5 +6,5 @@
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"noEmit": false
},
- "include": ["vite.config.mts"]
+ "include": ["vite.config.ts"]
}
diff --git a/apps/web-antd/vite.config.mts b/apps/web-antd/vite.config.ts
similarity index 100%
rename from apps/web-antd/vite.config.mts
rename to apps/web-antd/vite.config.ts
diff --git a/apps/web-ele/src/types/element-plus-style-css.d.ts b/apps/web-ele/src/types/element-plus-style-css.d.ts
new file mode 100644
index 000000000..ba7a76672
--- /dev/null
+++ b/apps/web-ele/src/types/element-plus-style-css.d.ts
@@ -0,0 +1,4 @@
+declare module 'element-plus/es/components/*/style/css' {
+ const sideEffect: undefined;
+ export default sideEffect;
+}
diff --git a/cspell.json b/cspell.json
index e5cda71a1..7de2c11c5 100644
--- a/cspell.json
+++ b/cspell.json
@@ -4,33 +4,37 @@
"language": "en,en-US",
"allowCompoundWords": true,
"words": [
- "acmr",
"Alova",
+ "Gitee",
+ "Qqchat",
+ "acmr",
"antd",
"antdv",
"archiver",
"astro",
"axios",
"brotli",
- "clientid",
"cascader",
+ "chatcmpl",
+ "clientid",
"clsx",
+ "dedup",
"defu",
"demi",
"dotenv",
+ "echart",
"echarts",
"ependencies",
"esbuild",
"esno",
"etag",
"execa",
- "Gitee",
"iconify",
"iconoir",
"intlify",
"ipaddr",
- "jsencrypt",
"isequal",
+ "jsencrypt",
"jspm",
"lockb",
"logininfor",
@@ -49,20 +53,25 @@
"nuxt",
"oper",
"operlog",
+ "organisation",
+ "oxfmt",
+ "oxlint",
"pinia",
"prefixs",
"publint",
- "Qqchat",
"qrcode",
"reka",
- "ruoyi",
"rollup",
+ "ruoyi",
"shadcn",
"sonner",
"sortablejs",
"styl",
+ "tabler",
"taze",
"tdesign",
+ "tsgolint",
+ "turborepo",
"ui-kit",
"uicons",
"unplugin",
diff --git a/docs/src/en/components/common-ui/vben-alert.md b/docs/src/en/components/common-ui/vben-alert.md
new file mode 100644
index 000000000..fe2a13749
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-alert.md
@@ -0,0 +1,76 @@
+---
+outline: deep
+---
+
+# Vben Alert
+
+`Alert` provides lightweight JavaScript-driven dialogs for simple `alert`, `confirm`, and `prompt` style interactions.
+
+## Basic Usage
+
+Use `alert` for a single confirm button dialog:
+
+
+
+Use `confirm` for confirm/cancel interactions:
+
+
+
+Use `prompt` when you need simple user input:
+
+
+
+## useAlertContext
+
+If `content`, `footer`, or `icon` is rendered through a custom component, you can call `useAlertContext()` inside that component to access the current dialog actions.
+
+| Method | Description | Type |
+| ----------- | -------------------------- | ------------ |
+| `doConfirm` | trigger the confirm action | `() => void` |
+| `doCancel` | trigger the cancel action | `() => void` |
+
+## Core Types
+
+```ts
+export type IconType = 'error' | 'info' | 'question' | 'success' | 'warning';
+
+export type BeforeCloseScope = {
+ isConfirm: boolean;
+};
+
+export type AlertProps = {
+ beforeClose?: (
+ scope: BeforeCloseScope,
+ ) => boolean | Promise | undefined;
+ bordered?: boolean;
+ buttonAlign?: 'center' | 'end' | 'start';
+ cancelText?: string;
+ centered?: boolean;
+ confirmText?: string;
+ containerClass?: string;
+ content: Component | string;
+ contentClass?: string;
+ contentMasking?: boolean;
+ footer?: Component | string;
+ icon?: Component | IconType;
+ overlayBlur?: number;
+ showCancel?: boolean;
+ title?: string;
+};
+
+export type PromptProps = {
+ beforeClose?: (scope: {
+ isConfirm: boolean;
+ value: T | undefined;
+ }) => boolean | Promise | undefined;
+ component?: Component;
+ componentProps?: Recordable;
+ componentSlots?:
+ | (() => any)
+ | Recordable
+ | VNode
+ | VNodeArrayChildren;
+ defaultValue?: T;
+ modelPropName?: string;
+} & Omit;
+```
diff --git a/docs/src/en/components/common-ui/vben-api-component.md b/docs/src/en/components/common-ui/vben-api-component.md
new file mode 100644
index 000000000..f260a3791
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-api-component.md
@@ -0,0 +1,69 @@
+---
+outline: deep
+---
+
+# Vben ApiComponent
+
+`ApiComponent` is a wrapper used to attach remote-option loading behavior to an existing component while preserving the original component usage pattern.
+
+## Common Usage
+
+The current wrapper flow is:
+
+- pass the target component through `component`
+- fetch remote data through `api`
+- transform data through `beforeFetch` and `afterFetch`
+- map remote fields through `resultField`, `valueField`, `labelField`, and `childrenField`
+- pass normalized options to the target component through `optionsPropName`
+
+```vue
+
+
+
+
+
+```
+
+## Current Props
+
+| Prop | Description | Type |
+| --- | --- | --- |
+| `component` | wrapped target component | `Component` |
+| `api` | remote request function | `(arg?: any) => Promise` |
+| `params` | extra request params | `Record` |
+| `beforeFetch` | hook before request | `AnyPromiseFunction` |
+| `afterFetch` | hook after request | `AnyPromiseFunction` |
+| `visibleEvent` | event name used to lazy-load data | `string` |
+| `loadingSlot` | slot name used to render the loading icon | `string` |
+| `modelPropName` | model prop name of the wrapped component | `string` |
+| `autoSelect` | auto-pick the first / last / only option, or use a custom function | `'first' \| 'last' \| 'one' \| ((items) => item) \| false` |
+
+## Exposed Methods
+
+| Method | Description |
+| ------------------------ | -------------------------------------- |
+| `getComponentRef()` | returns the wrapped component instance |
+| `updateParam(newParams)` | merges and updates request params |
+| `getOptions()` | returns loaded options |
+| `getValue()` | returns the current bound value |
diff --git a/docs/src/en/components/common-ui/vben-count-to-animator.md b/docs/src/en/components/common-ui/vben-count-to-animator.md
new file mode 100644
index 000000000..615a417b4
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-count-to-animator.md
@@ -0,0 +1,51 @@
+---
+outline: deep
+---
+
+# Vben CountToAnimator
+
+`CountToAnimator` renders animated number transitions.
+
+## Basic Usage
+
+Use `start-val`, `end-val`, and `duration` to control the animation range and timing.
+
+
+
+## Formatting
+
+Use `prefix`, `suffix`, `separator`, and `decimal` to control how the number is displayed.
+
+
+
+## Props
+
+| Prop | Description | Type | Default |
+| --- | --- | --- | --- |
+| `startVal` | starting value | `number` | `0` |
+| `endVal` | ending value | `number` | `2021` |
+| `duration` | animation duration in ms | `number` | `1500` |
+| `autoplay` | start automatically | `boolean` | `true` |
+| `prefix` | value prefix | `string` | `''` |
+| `suffix` | value suffix | `string` | `''` |
+| `separator` | thousands separator | `string` | `','` |
+| `decimal` | decimal separator | `string` | `'.'` |
+| `color` | text color | `string` | `''` |
+| `useEasing` | enable transition preset easing | `boolean` | `true` |
+| `transition` | transition preset name | `keyof typeof TransitionPresets` | `'linear'` |
+| `decimals` | decimal places to keep | `number` | `0` |
+
+## Events
+
+| Event | Description | Type |
+| ------------ | ------------------------------- | ------------ |
+| `started` | fired when the animation starts | `() => void` |
+| `finished` | fired when the animation ends | `() => void` |
+| `onStarted` | deprecated alias of `started` | `() => void` |
+| `onFinished` | deprecated alias of `finished` | `() => void` |
+
+## Exposed Methods
+
+| Method | Description | Type |
+| ------- | --------------------------------- | ------------ |
+| `reset` | reset to `startVal` and run again | `() => void` |
diff --git a/docs/src/en/components/common-ui/vben-drawer.md b/docs/src/en/components/common-ui/vben-drawer.md
new file mode 100644
index 000000000..20b1d7ddf
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-drawer.md
@@ -0,0 +1,56 @@
+---
+outline: deep
+---
+
+# Vben Drawer
+
+`Vben Drawer` is the shared drawer wrapper used by the framework. It supports auto-height layout, loading state, connected components, and an imperative API similar to the modal API.
+
+## Basic Usage
+
+```ts
+const [Drawer, drawerApi] = useVbenDrawer({
+ // props
+ // events
+});
+```
+
+
+
+## Current Usage Notes
+
+- If you use `connectedComponent`, the inner and outer components share data through `drawerApi.setData()` and `drawerApi.getData()`.
+- Default drawer behavior can be adjusted in `apps//src/bootstrap.ts` through `setDefaultDrawerProps(...)`.
+- `setState(...)` works on `DrawerState`, not `ModalState`.
+
+## Key Props
+
+| Prop | Description | Type |
+| --- | --- | --- |
+| `appendToMain` | mount inside the main content area instead of `body` | `boolean` |
+| `connectedComponent` | connect an inner component to the drawer wrapper | `Component` |
+| `closeIconPlacement` | position of the close icon | `'left' \| 'right'` |
+| `placement` | drawer side | `'left' \| 'right' \| 'top' \| 'bottom'` |
+| `overlayBlur` | blur amount for the overlay | `number` |
+| `submitting` | lock drawer interactions while submitting | `boolean` |
+
+## Events
+
+| Event | Description | Type |
+| --- | --- | --- |
+| `onBeforeClose` | called before close; returning `false` or rejecting prevents close | `() => Promise \| boolean \| undefined` |
+| `onOpenChange` | called when open state changes | `(isOpen: boolean) => void` |
+| `onOpened` | called after open animation completes | `() => void` |
+| `onClosed` | called after close animation completes | `() => void` |
+
+## drawerApi
+
+| Method | Description |
+| ----------------------- | -------------------------------------- |
+| `setState(...)` | updates drawer state |
+| `open()` | opens the drawer |
+| `close()` | closes the drawer |
+| `setData(data)` | stores shared data |
+| `getData()` | reads shared data |
+| `lock(isLocked = true)` | locks the drawer into submitting state |
+| `unlock()` | alias for `lock(false)` |
diff --git a/docs/src/en/components/common-ui/vben-ellipsis-text.md b/docs/src/en/components/common-ui/vben-ellipsis-text.md
new file mode 100644
index 000000000..602812a07
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-ellipsis-text.md
@@ -0,0 +1,42 @@
+---
+outline: deep
+---
+
+# Vben EllipsisText
+
+`EllipsisText` displays long text with truncation, tooltip support, and optional expand/collapse behavior.
+
+## Basic Usage
+
+Pass the text through the default slot and limit the visual width with `maxWidth`.
+
+
+
+## Current Props
+
+| Prop | Description | Type | Default |
+| --- | --- | --- | --- |
+| `expand` | allow click-to-expand behavior | `boolean` | `false` |
+| `line` | max visible line count | `number` | `1` |
+| `maxWidth` | max width of the text area | `number \| string` | `'100%'` |
+| `placement` | tooltip placement | `'bottom' \| 'left' \| 'right' \| 'top'` | `'top'` |
+| `tooltip` | enable tooltip | `boolean` | `true` |
+| `tooltipWhenEllipsis` | only show tooltip when text is actually truncated | `boolean` | `false` |
+| `ellipsisThreshold` | pixel threshold used when checking truncation | `number` | `3` |
+| `tooltipBackgroundColor` | tooltip background color | `string` | `''` |
+| `tooltipColor` | tooltip text color | `string` | `''` |
+| `tooltipFontSize` | tooltip font size in px | `number` | `14` |
+| `tooltipMaxWidth` | tooltip max width in px | `number` | - |
+| `tooltipOverlayStyle` | tooltip content style | `CSSProperties` | `{ textAlign: 'justify' }` |
+
+## Events
+
+| Event | Description | Type |
+| --- | --- | --- |
+| `expandChange` | fired when expand state changes | `(isExpand: boolean) => void` |
+
+## Slots
+
+| Slot | Description |
+| --------- | ---------------------- |
+| `tooltip` | custom tooltip content |
diff --git a/docs/src/en/components/common-ui/vben-form.md b/docs/src/en/components/common-ui/vben-form.md
new file mode 100644
index 000000000..d23e869bc
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-form.md
@@ -0,0 +1,203 @@
+---
+outline: deep
+---
+
+# Vben Form
+
+`Vben Form` is the shared form abstraction used across different UI-library variants such as `Ant Design Vue`, `Element Plus`, `Naive UI`, and other adapters added inside this repository.
+
+> If some details are not obvious from the docs, check the live demos as well.
+
+## Adapter Setup
+
+Each app keeps its own adapter layer under `src/adapter/form.ts` and `src/adapter/component/index.ts`.
+
+The current adapter pattern is:
+
+- initialize the shared component adapter first
+- call `setupVbenForm(...)`
+- map special `v-model:*` prop names through `modelPropNameMap`
+- keep the form empty state aligned with the actual UI library behavior
+
+### Form Adapter Example
+
+```ts
+import type {
+ VbenFormSchema as FormSchema,
+ VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { initComponentAdapter } from './component';
+
+initComponentAdapter();
+setupVbenForm({
+ config: {
+ baseModelPropName: 'value',
+ emptyStateValue: null,
+ modelPropNameMap: {
+ Checkbox: 'checked',
+ Radio: 'checked',
+ Switch: 'checked',
+ Upload: 'fileList',
+ },
+ },
+ defineRules: {
+ required: (value, _params, ctx) => {
+ if (value === undefined || value === null || value.length === 0) {
+ return $t('ui.formRules.required', [ctx.label]);
+ }
+ return true;
+ },
+ selectRequired: (value, _params, ctx) => {
+ if (value === undefined || value === null) {
+ return $t('ui.formRules.selectRequired', [ctx.label]);
+ }
+ return true;
+ },
+ },
+});
+
+const useVbenForm = useForm;
+
+export { useVbenForm, z };
+export type VbenFormSchema = FormSchema;
+export type { VbenFormProps };
+```
+
+### Component Adapter Example
+
+```ts
+import type { Component, SetupContext } from 'vue';
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+
+import { h } from 'vue';
+
+import { globalShareState } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import {
+ AutoComplete,
+ Button,
+ Checkbox,
+ CheckboxGroup,
+ DatePicker,
+ Divider,
+ Input,
+ InputNumber,
+ InputPassword,
+ Mentions,
+ notification,
+ Radio,
+ RadioGroup,
+ RangePicker,
+ Rate,
+ Select,
+ Space,
+ Switch,
+ Textarea,
+ TimePicker,
+ TreeSelect,
+ Upload,
+} from 'ant-design-vue';
+
+const withDefaultPlaceholder = (
+ component: T,
+ type: 'input' | 'select',
+) => {
+ return (props: any, { attrs, slots }: Omit) => {
+ const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
+ return h(component, { ...props, ...attrs, placeholder }, slots);
+ };
+};
+
+export type ComponentType =
+ | 'AutoComplete'
+ | 'Checkbox'
+ | 'CheckboxGroup'
+ | 'DatePicker'
+ | 'DefaultButton'
+ | 'Divider'
+ | 'Input'
+ | 'InputNumber'
+ | 'InputPassword'
+ | 'Mentions'
+ | 'PrimaryButton'
+ | 'Radio'
+ | 'RadioGroup'
+ | 'RangePicker'
+ | 'Rate'
+ | 'Select'
+ | 'Space'
+ | 'Switch'
+ | 'Textarea'
+ | 'TimePicker'
+ | 'TreeSelect'
+ | 'Upload'
+ | BaseFormComponentType;
+
+async function initComponentAdapter() {
+ const components: Partial> = {
+ AutoComplete,
+ Checkbox,
+ CheckboxGroup,
+ DatePicker,
+ DefaultButton: (props, { attrs, slots }) => {
+ return h(Button, { ...props, attrs, type: 'default' }, slots);
+ },
+ Divider,
+ Input: withDefaultPlaceholder(Input, 'input'),
+ InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
+ InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
+ Mentions: withDefaultPlaceholder(Mentions, 'input'),
+ PrimaryButton: (props, { attrs, slots }) => {
+ return h(Button, { ...props, attrs, type: 'primary' }, slots);
+ },
+ Radio,
+ RadioGroup,
+ RangePicker,
+ Rate,
+ Select: withDefaultPlaceholder(Select, 'select'),
+ Space,
+ Switch,
+ Textarea: withDefaultPlaceholder(Textarea, 'input'),
+ TimePicker,
+ TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
+ Upload,
+ };
+
+ globalShareState.setComponents(components);
+ globalShareState.defineMessage({
+ copyPreferencesSuccess: (title, content) => {
+ notification.success({
+ description: content,
+ message: title,
+ placement: 'bottomRight',
+ });
+ },
+ });
+}
+
+export { initComponentAdapter };
+```
+
+## Basic Usage
+
+Create the form through `useVbenForm`:
+
+
+
+## Key API Notes
+
+- `useVbenForm` returns `[Form, formApi]`
+- `formApi.getFieldComponentRef()` and `formApi.getFocusedField()` are available in current versions
+- `handleValuesChange(values, fieldsChanged)` includes the second parameter in newer versions
+- `fieldMappingTime` and `scrollToFirstError` are part of the current form props
+
+## Reference
+
+For the complete Chinese API tables and more examples, see the Chinese component page if you need the full parameter matrix.
diff --git a/docs/src/en/components/common-ui/vben-modal.md b/docs/src/en/components/common-ui/vben-modal.md
new file mode 100644
index 000000000..0971c4413
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-modal.md
@@ -0,0 +1,56 @@
+---
+outline: deep
+---
+
+# Vben Modal
+
+`Vben Modal` is the shared modal wrapper used by the framework. It supports draggable behavior, fullscreen mode, auto-height handling, loading state, connected components, and an imperative API.
+
+## Basic Usage
+
+```ts
+const [Modal, modalApi] = useVbenModal({
+ // props
+ // events
+});
+```
+
+
+
+## Current Usage Notes
+
+- If you use `connectedComponent`, the inner and outer components share data through `modalApi.setData()` and `modalApi.getData()`.
+- When `connectedComponent` is present, avoid pushing extra modal props through the connected side. Prefer `useVbenModal(...)` or `modalApi.setState(...)`.
+- Default modal behavior can be adjusted in `apps//src/bootstrap.ts` through `setDefaultModalProps(...)`.
+
+## Key Props
+
+| Prop | Description | Type |
+| --- | --- | --- |
+| `appendToMain` | mount inside the main content area instead of `body` | `boolean` |
+| `connectedComponent` | connect an inner component to the modal wrapper | `Component` |
+| `animationType` | modal enter/leave animation | `'slide' \| 'scale'` |
+| `fullscreenButton` | show or hide the fullscreen toggle | `boolean` |
+| `overlayBlur` | blur amount for the overlay | `number` |
+| `submitting` | lock modal interactions while submitting | `boolean` |
+
+## Events
+
+| Event | Description | Type |
+| --- | --- | --- |
+| `onBeforeClose` | called before close; returning `false` or rejecting prevents close | `() => Promise \| boolean \| undefined` |
+| `onOpenChange` | called when open state changes | `(isOpen: boolean) => void` |
+| `onOpened` | called after open animation completes | `() => void` |
+| `onClosed` | called after close animation completes | `() => void` |
+
+## modalApi
+
+| Method | Description |
+| ----------------------- | ------------------------------------- |
+| `setState(...)` | updates modal state |
+| `open()` | opens the modal |
+| `close()` | closes the modal |
+| `setData(data)` | stores shared data |
+| `getData()` | reads shared data |
+| `lock(isLocked = true)` | locks the modal into submitting state |
+| `unlock()` | alias for `lock(false)` |
diff --git a/docs/src/en/components/common-ui/vben-vxe-table.md b/docs/src/en/components/common-ui/vben-vxe-table.md
new file mode 100644
index 000000000..2fba1dc0c
--- /dev/null
+++ b/docs/src/en/components/common-ui/vben-vxe-table.md
@@ -0,0 +1,87 @@
+---
+outline: deep
+---
+
+# Vben Vxe Table
+
+`Vben Vxe Table` wraps `vxe-table` together with `Vben Form` so you can build searchable data grids with a shared API.
+
+## Adapter Example
+
+The current renderer adapter uses `renderTableDefault(...)` for table cell rendering:
+
+```ts
+vxeUI.renderer.add('CellImage', {
+ renderTableDefault(_renderOpts, params) {
+ const { column, row } = params;
+ return h(Image, { src: row[column.field] });
+ },
+});
+
+vxeUI.renderer.add('CellLink', {
+ renderTableDefault(renderOpts) {
+ const { props } = renderOpts;
+ return h(
+ Button,
+ { size: 'small', type: 'link' },
+ { default: () => props?.text },
+ );
+ },
+});
+```
+
+## Basic Usage
+
+```vue
+
+
+
+
+
+```
+
+
+
+## GridApi
+
+| Method | Description | Type |
+| --- | --- | --- |
+| `setLoading` | update loading state | `(loading: boolean) => void` |
+| `setGridOptions` | merge new grid options | `(options: Partial) => void` |
+| `reload` | reload data and reset pagination | `(params?: Record) => void` |
+| `query` | query data while keeping the current page | `(params?: Record) => void` |
+| `grid` | `vxe-grid` instance | `VxeGridInstance` |
+| `formApi` | search form API | `FormApi` |
+| `toggleSearchForm` | toggle or force the search form visible state | `(show?: boolean) => boolean` |
+
+## Props
+
+| Prop | Description | Type |
+| --- | --- | --- |
+| `tableTitle` | table title | `string` |
+| `tableTitleHelp` | help text for the table title | `string` |
+| `class` | class for the outer container | `string` |
+| `gridClass` | class for the `vxe-grid` node | `string` |
+| `gridOptions` | `vxe-grid` options | `DeepPartial` |
+| `gridEvents` | `vxe-grid` event handlers | `DeepPartial` |
+| `formOptions` | search form options | `VbenFormProps` |
+| `showSearchForm` | whether the search form is visible | `boolean` |
+| `separator` | separator between the search form and table body | `boolean \| SeparatorOptions` |
+
+## Slots
+
+| Slot | Description |
+| ----------------- | ------------------------------------------------------- |
+| `toolbar-actions` | left side of the toolbar, near the title |
+| `toolbar-tools` | right side of the toolbar, before built-in tool buttons |
+| `table-title` | custom table title |
+
+All named slots starting with `form-` are forwarded to the search form.
diff --git a/docs/src/en/components/introduction.md b/docs/src/en/components/introduction.md
new file mode 100644
index 000000000..806ef09ff
--- /dev/null
+++ b/docs/src/en/components/introduction.md
@@ -0,0 +1,15 @@
+# Introduction
+
+::: info README
+
+This section documents the framework components, including their usage patterns, configuration points, and major APIs. If the built-in wrappers do not fit your needs, you can always use native components directly or build your own abstractions.
+
+:::
+
+## Layout Components
+
+Layout components are usually used as top-level containers inside the page content area. They provide shared layout styles and some baseline behavior.
+
+## Common Components
+
+Common components include frequently used UI building blocks such as modals, drawers, forms, and API-backed selectors. Most of them are implemented on top of shared Tailwind CSS and shadcn-vue based primitives, while still allowing each app to adapt them to its own UI library.
diff --git a/docs/src/en/components/layout-ui/page.md b/docs/src/en/components/layout-ui/page.md
new file mode 100644
index 000000000..467d30c4c
--- /dev/null
+++ b/docs/src/en/components/layout-ui/page.md
@@ -0,0 +1,29 @@
+---
+outline: deep
+---
+
+# Page
+
+`Page` is the standard top-level layout container for business pages. It provides a header area, a content area, and an optional footer area.
+
+## Props
+
+| Prop | Description | Type | Default |
+| --- | --- | --- | --- |
+| `title` | page title | `string \| slot` | - |
+| `description` | page description | `string \| slot` | - |
+| `contentClass` | class for the content area | `string` | - |
+| `headerClass` | class for the header area | `string` | - |
+| `footerClass` | class for the footer area | `string` | - |
+| `autoContentHeight` | auto-calculate the content area height from the visible layout height | `boolean` | `false` |
+| `heightOffset` | extra height offset subtracted from the content area when auto height is enabled | `number` | `0` |
+
+## Slots
+
+| Slot | Description |
+| ------------- | ------------------------- |
+| `default` | page content |
+| `title` | custom title |
+| `description` | custom description |
+| `extra` | right-side header content |
+| `footer` | footer content |
diff --git a/eslint.config.mjs b/eslint.config.mjs
index b29b567fa..63bd9adc3 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,5 +1,3 @@
-// @ts-check
-
import { defineConfig } from '@vben/eslint-config';
export default defineConfig();
diff --git a/internal/lint-configs/commitlint-config/package.json b/internal/lint-configs/commitlint-config/package.json
index 3377803d9..0fef91827 100644
--- a/internal/lint-configs/commitlint-config/package.json
+++ b/internal/lint-configs/commitlint-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben/commitlint-config",
- "version": "5.6.0",
+ "version": "5.7.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
diff --git a/internal/lint-configs/eslint-config/package.json b/internal/lint-configs/eslint-config/package.json
index e9ba6a303..db7f699ac 100644
--- a/internal/lint-configs/eslint-config/package.json
+++ b/internal/lint-configs/eslint-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben/eslint-config",
- "version": "5.6.0",
+ "version": "5.7.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -27,32 +27,22 @@
}
},
"dependencies": {
- "eslint-config-turbo": "catalog:",
- "eslint-plugin-command": "catalog:",
- "eslint-plugin-import-x": "catalog:"
+ "@vben/oxlint-config": "workspace:*"
},
"devDependencies": {
"@eslint/js": "catalog:",
- "@types/eslint": "catalog:",
"@typescript-eslint/eslint-plugin": "catalog:",
"@typescript-eslint/parser": "catalog:",
"eslint": "catalog:",
- "eslint-plugin-eslint-comments": "catalog:",
- "eslint-plugin-jsdoc": "catalog:",
"eslint-plugin-jsonc": "catalog:",
"eslint-plugin-n": "catalog:",
- "eslint-plugin-no-only-tests": "catalog:",
"eslint-plugin-perfectionist": "catalog:",
"eslint-plugin-pnpm": "catalog:",
- "eslint-plugin-prettier": "catalog:",
- "eslint-plugin-regexp": "catalog:",
"eslint-plugin-unicorn": "catalog:",
"eslint-plugin-unused-imports": "catalog:",
- "eslint-plugin-vitest": "catalog:",
"eslint-plugin-vue": "catalog:",
"eslint-plugin-yml": "catalog:",
"globals": "catalog:",
- "jsonc-eslint-parser": "catalog:",
"vue-eslint-parser": "catalog:",
"yaml-eslint-parser": "catalog:"
}
diff --git a/internal/lint-configs/eslint-config/src/configs/command.ts b/internal/lint-configs/eslint-config/src/configs/command.ts
deleted file mode 100644
index d0c902de2..000000000
--- a/internal/lint-configs/eslint-config/src/configs/command.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import createCommand from 'eslint-plugin-command/config';
-
-export async function command() {
- return [
- {
- ...createCommand(),
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/comments.ts b/internal/lint-configs/eslint-config/src/configs/comments.ts
deleted file mode 100644
index 77ccd5dde..000000000
--- a/internal/lint-configs/eslint-config/src/configs/comments.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import type { Linter } from 'eslint';
-
-import { interopDefault } from '../util';
-
-export async function comments(): Promise {
- const [pluginComments] = await Promise.all([
- // @ts-expect-error - no types
- interopDefault(import('eslint-plugin-eslint-comments')),
- ] as const);
-
- return [
- {
- plugins: {
- 'eslint-comments': pluginComments,
- },
- rules: {
- 'eslint-comments/no-aggregating-enable': 'error',
- 'eslint-comments/no-duplicate-disable': 'error',
- 'eslint-comments/no-unlimited-disable': 'error',
- 'eslint-comments/no-unused-enable': 'error',
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/disableds.ts b/internal/lint-configs/eslint-config/src/configs/disableds.ts
deleted file mode 100644
index 152b84cac..000000000
--- a/internal/lint-configs/eslint-config/src/configs/disableds.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import type { Linter } from 'eslint';
-
-export async function disableds(): Promise {
- return [
- {
- files: ['**/__tests__/**/*.?([cm])[jt]s?(x)'],
- name: 'disables/test',
- rules: {
- '@typescript-eslint/ban-ts-comment': 'off',
- 'no-console': 'off',
- },
- },
- {
- files: ['**/*.d.ts'],
- name: 'disables/dts',
- rules: {
- '@typescript-eslint/triple-slash-reference': 'off',
- },
- },
- {
- files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
- name: 'disables/js',
- rules: {
- '@typescript-eslint/explicit-module-boundary-types': 'off',
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/ignores.ts b/internal/lint-configs/eslint-config/src/configs/ignores.ts
index 0a05e9e9e..29b16ce6a 100644
--- a/internal/lint-configs/eslint-config/src/configs/ignores.ts
+++ b/internal/lint-configs/eslint-config/src/configs/ignores.ts
@@ -48,6 +48,12 @@ export async function ignores(): Promise {
'**/*.woff',
'**/.github',
'**/lefthook.yml',
+
+ '**/.agent/**',
+ '**/.agents/**',
+ '**/.codex/**',
+ '**/.claude/**',
+ '**/.cursor/**',
],
},
];
diff --git a/internal/lint-configs/eslint-config/src/configs/import.ts b/internal/lint-configs/eslint-config/src/configs/import.ts
deleted file mode 100644
index ce6cf65d9..000000000
--- a/internal/lint-configs/eslint-config/src/configs/import.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import type { Linter } from 'eslint';
-
-import * as pluginImport from 'eslint-plugin-import-x';
-
-export async function importPluginConfig(): Promise {
- return [
- {
- plugins: {
- // @ts-expect-error - This is a dynamic import
- import: pluginImport,
- },
- rules: {
- 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
- 'import/first': 'error',
- 'import/newline-after-import': 'error',
- 'import/no-duplicates': 'error',
- 'import/no-mutable-exports': 'error',
- 'import/no-named-default': 'error',
- 'import/no-self-import': 'error',
- 'import/no-unresolved': 'off',
- 'import/no-webpack-loader-syntax': 'error',
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/index.ts b/internal/lint-configs/eslint-config/src/configs/index.ts
index 50f8e1cd5..4ed3ea61e 100644
--- a/internal/lint-configs/eslint-config/src/configs/index.ts
+++ b/internal/lint-configs/eslint-config/src/configs/index.ts
@@ -1,18 +1,9 @@
-export * from './command';
-export * from './comments';
-export * from './disableds';
export * from './ignores';
-export * from './import';
export * from './javascript';
-export * from './jsdoc';
export * from './jsonc';
export * from './node';
export * from './perfectionist';
export * from './pnpm';
-export * from './prettier';
-export * from './regexp';
-export * from './test';
-export * from './turbo';
export * from './typescript';
export * from './unicorn';
export * from './vue';
diff --git a/internal/lint-configs/eslint-config/src/configs/javascript.ts b/internal/lint-configs/eslint-config/src/configs/javascript.ts
index 44cf5b6e6..2019ecdd2 100644
--- a/internal/lint-configs/eslint-config/src/configs/javascript.ts
+++ b/internal/lint-configs/eslint-config/src/configs/javascript.ts
@@ -4,7 +4,73 @@ import js from '@eslint/js';
import pluginUnusedImports from 'eslint-plugin-unused-imports';
import globals from 'globals';
+const rulesCoveredByOxlint = new Set([
+ 'constructor-super',
+ 'for-direction',
+ 'getter-return',
+ 'no-async-promise-executor',
+ 'no-case-declarations',
+ 'no-class-assign',
+ 'no-compare-neg-zero',
+ 'no-cond-assign',
+ 'no-const-assign',
+ 'no-constant-binary-expression',
+ 'no-constant-condition',
+ 'no-debugger',
+ 'no-delete-var',
+ 'no-dupe-args',
+ 'no-dupe-class-members',
+ 'no-dupe-else-if',
+ 'no-dupe-keys',
+ 'no-duplicate-case',
+ 'no-empty',
+ 'no-empty-character-class',
+ 'no-empty-pattern',
+ 'no-empty-static-block',
+ 'no-ex-assign',
+ 'no-extra-boolean-cast',
+ 'no-fallthrough',
+ 'no-func-assign',
+ 'no-global-assign',
+ 'no-import-assign',
+ 'no-invalid-regexp',
+ 'no-irregular-whitespace',
+ 'no-loss-of-precision',
+ 'no-misleading-character-class',
+ 'no-new-native-nonconstructor',
+ 'no-nonoctal-decimal-escape',
+ 'no-obj-calls',
+ 'no-prototype-builtins',
+ 'no-redeclare',
+ 'no-regex-spaces',
+ 'no-self-assign',
+ 'no-setter-return',
+ 'no-shadow-restricted-names',
+ 'no-sparse-arrays',
+ 'no-this-before-super',
+ 'no-unreachable',
+ 'no-unsafe-finally',
+ 'no-unsafe-negation',
+ 'no-unsafe-optional-chaining',
+ 'no-unused-labels',
+ 'no-unused-private-class-members',
+ 'no-unused-vars',
+ 'no-useless-backreference',
+ 'no-useless-catch',
+ 'no-useless-escape',
+ 'no-with',
+ 'require-yield',
+ 'use-isnan',
+ 'valid-typeof',
+]);
+
export async function javascript(): Promise {
+ const recommendedRules = Object.fromEntries(
+ Object.entries(js.configs.recommended.rules).filter(
+ ([ruleName]) => !rulesCoveredByOxlint.has(ruleName),
+ ),
+ );
+
return [
{
languageOptions: {
@@ -33,79 +99,11 @@ export async function javascript(): Promise {
'unused-imports': pluginUnusedImports,
},
rules: {
- ...js.configs.recommended.rules,
- 'accessor-pairs': [
- 'error',
- { enforceForClassMembers: true, setWithoutGet: true },
- ],
- 'array-callback-return': 'error',
- 'block-scoped-var': 'error',
- 'constructor-super': 'error',
- 'default-case-last': 'error',
+ ...recommendedRules,
'dot-notation': ['error', { allowKeywords: true }],
- eqeqeq: ['error', 'always'],
'keyword-spacing': 'off',
-
- 'new-cap': [
- 'error',
- { capIsNew: false, newIsCap: true, properties: true },
- ],
- 'no-alert': 'error',
- 'no-array-constructor': 'error',
- 'no-async-promise-executor': 'error',
- 'no-caller': 'error',
- 'no-case-declarations': 'error',
- 'no-class-assign': 'error',
- 'no-compare-neg-zero': 'error',
- 'no-cond-assign': ['error', 'always'],
- 'no-console': ['error', { allow: ['warn', 'error'] }],
- 'no-const-assign': 'error',
'no-control-regex': 'error',
- 'no-debugger': 'error',
- 'no-delete-var': 'error',
- 'no-dupe-args': 'error',
- 'no-dupe-class-members': 'error',
- 'no-dupe-keys': 'error',
- 'no-duplicate-case': 'error',
- 'no-empty': ['error', { allowEmptyCatch: true }],
- 'no-empty-character-class': 'error',
'no-empty-function': 'off',
- 'no-empty-pattern': 'error',
- 'no-eval': 'error',
- 'no-ex-assign': 'error',
- 'no-extend-native': 'error',
- 'no-extra-bind': 'error',
- 'no-extra-boolean-cast': 'error',
- 'no-fallthrough': 'error',
- 'no-func-assign': 'error',
- 'no-global-assign': 'error',
- 'no-implied-eval': 'error',
- 'no-import-assign': 'error',
- 'no-invalid-regexp': 'error',
- 'no-irregular-whitespace': 'error',
- 'no-iterator': 'error',
- 'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
- 'no-lone-blocks': 'error',
- 'no-loss-of-precision': 'error',
- 'no-misleading-character-class': 'error',
- 'no-multi-str': 'error',
- 'no-new': 'error',
- 'no-new-func': 'error',
- 'no-new-object': 'error',
- 'no-new-symbol': 'error',
- 'no-new-wrappers': 'error',
- 'no-obj-calls': 'error',
- 'no-octal': 'error',
- 'no-octal-escape': 'error',
- 'no-proto': 'error',
- 'no-prototype-builtins': 'error',
- 'no-redeclare': ['error', { builtinGlobals: false }],
- 'no-regex-spaces': 'error',
- 'no-restricted-globals': [
- 'error',
- { message: 'Use `globalThis` instead.', name: 'global' },
- { message: 'Use `globalThis` instead.', name: 'self' },
- ],
'no-restricted-properties': [
'error',
{
@@ -138,84 +136,9 @@ export async function javascript(): Promise {
'TSEnumDeclaration[const=true]',
'TSExportAssignment',
],
- 'no-self-assign': ['error', { props: true }],
- 'no-self-compare': 'error',
- 'no-sequences': 'error',
- 'no-shadow-restricted-names': 'error',
- 'no-sparse-arrays': 'error',
- 'no-template-curly-in-string': 'error',
- 'no-this-before-super': 'error',
- 'no-throw-literal': 'error',
'no-undef': 'off',
- 'no-undef-init': 'error',
- 'no-unexpected-multiline': 'error',
- 'no-unmodified-loop-condition': 'error',
- 'no-unneeded-ternary': ['error', { defaultAssignment: false }],
- 'no-unreachable': 'error',
'no-unreachable-loop': 'error',
- 'no-unsafe-finally': 'error',
- 'no-unsafe-negation': 'error',
- 'no-unused-expressions': [
- 'error',
- {
- allowShortCircuit: true,
- allowTaggedTemplates: true,
- allowTernary: true,
- },
- ],
- 'no-unused-vars': [
- 'error',
- {
- args: 'none',
- caughtErrors: 'none',
- ignoreRestSiblings: true,
- vars: 'all',
- },
- ],
- 'no-use-before-define': [
- 'error',
- { classes: false, functions: false, variables: false },
- ],
- 'no-useless-backreference': 'error',
- 'no-useless-call': 'error',
- 'no-useless-catch': 'error',
- 'no-useless-computed-key': 'error',
- 'no-useless-constructor': 'error',
- 'no-useless-rename': 'error',
- 'no-useless-return': 'error',
- 'no-var': 'error',
- 'no-with': 'error',
- 'object-shorthand': [
- 'error',
- 'always',
- { avoidQuotes: true, ignoreConstructors: false },
- ],
- 'one-var': ['error', { initialized: 'never' }],
- 'prefer-arrow-callback': [
- 'error',
- {
- allowNamedFunctions: false,
- allowUnboundThis: true,
- },
- ],
- 'prefer-const': [
- 'error',
- {
- destructuring: 'all',
- ignoreReadBeforeAssign: true,
- },
- ],
- 'prefer-exponentiation-operator': 'error',
-
- 'prefer-promise-reject-errors': 'error',
- 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
- 'prefer-rest-params': 'error',
- 'prefer-spread': 'error',
- 'prefer-template': 'error',
'space-before-function-paren': 'off',
- 'spaced-comment': 'error',
- 'symbol-description': 'error',
- 'unicode-bom': ['error', 'never'],
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': [
@@ -227,14 +150,6 @@ export async function javascript(): Promise {
varsIgnorePattern: '^_',
},
],
- 'use-isnan': [
- 'error',
- { enforceForIndexOf: true, enforceForSwitchCase: true },
- ],
- 'valid-typeof': ['error', { requireStringLiterals: true }],
-
- 'vars-on-top': 'error',
- yoda: ['error', 'never'],
},
},
];
diff --git a/internal/lint-configs/eslint-config/src/configs/jsdoc.ts b/internal/lint-configs/eslint-config/src/configs/jsdoc.ts
deleted file mode 100644
index 136819769..000000000
--- a/internal/lint-configs/eslint-config/src/configs/jsdoc.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import type { Linter } from 'eslint';
-
-import { interopDefault } from '../util';
-
-export async function jsdoc(): Promise {
- const [pluginJsdoc] = await Promise.all([
- interopDefault(import('eslint-plugin-jsdoc')),
- ] as const);
-
- return [
- {
- plugins: {
- jsdoc: pluginJsdoc,
- },
- rules: {
- 'jsdoc/check-access': 'warn',
- 'jsdoc/check-param-names': 'warn',
- 'jsdoc/check-property-names': 'warn',
- 'jsdoc/check-types': 'warn',
- 'jsdoc/empty-tags': 'warn',
- 'jsdoc/implements-on-classes': 'warn',
- 'jsdoc/no-defaults': 'warn',
- 'jsdoc/no-multi-asterisks': 'warn',
- 'jsdoc/require-param-name': 'warn',
- 'jsdoc/require-property': 'warn',
- 'jsdoc/require-property-description': 'warn',
- 'jsdoc/require-property-name': 'warn',
- 'jsdoc/require-returns-check': 'warn',
- 'jsdoc/require-returns-description': 'warn',
- 'jsdoc/require-yields-check': 'warn',
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/jsonc.ts b/internal/lint-configs/eslint-config/src/configs/jsonc.ts
index 4b92ff447..3f33d13ad 100644
--- a/internal/lint-configs/eslint-config/src/configs/jsonc.ts
+++ b/internal/lint-configs/eslint-config/src/configs/jsonc.ts
@@ -3,17 +3,12 @@ import type { Linter } from 'eslint';
import { interopDefault } from '../util';
export async function jsonc(): Promise {
- const [pluginJsonc, parserJsonc] = await Promise.all([
- interopDefault(import('eslint-plugin-jsonc')),
- interopDefault(import('jsonc-eslint-parser')),
- ] as const);
+ const pluginJsonc = await interopDefault(import('eslint-plugin-jsonc'));
return [
{
files: ['**/*.json', '**/*.json5', '**/*.jsonc', '*.code-workspace'],
- languageOptions: {
- parser: parserJsonc as any,
- },
+ language: 'jsonc/x',
plugins: {
jsonc: pluginJsonc as any,
},
diff --git a/internal/lint-configs/eslint-config/src/configs/node.ts b/internal/lint-configs/eslint-config/src/configs/node.ts
index f8f266436..65f81fd53 100644
--- a/internal/lint-configs/eslint-config/src/configs/node.ts
+++ b/internal/lint-configs/eslint-config/src/configs/node.ts
@@ -13,7 +13,6 @@ export async function node(): Promise {
rules: {
'n/handle-callback-err': ['error', '^(err|error)$'],
'n/no-deprecated-api': 'error',
- 'n/no-exports-assign': 'error',
'n/no-extraneous-import': [
'error',
{
@@ -23,13 +22,10 @@ export async function node(): Promise {
'vitest',
'vite',
'@vue/test-utils',
- '@vben/tailwind-config',
'@playwright/test',
],
},
],
- 'n/no-new-require': 'error',
- 'n/no-path-concat': 'error',
// 'n/no-unpublished-import': 'off',
'n/no-unsupported-features/es-syntax': [
'error',
@@ -44,6 +40,33 @@ export async function node(): Promise {
'n/process-exit-as-throw': 'error',
},
},
+ {
+ files: [
+ '**/__tests__/**/*.?([cm])[jt]s?(x)',
+ '**/*.spec.?([cm])[jt]s?(x)',
+ '**/*.test.?([cm])[jt]s?(x)',
+ '**/*.bench.?([cm])[jt]s?(x)',
+ '**/*.benchmark.?([cm])[jt]s?(x)',
+ ],
+ rules: {
+ 'n/prefer-global/process': 'off',
+ },
+ },
+ {
+ files: ['apps/backend-mock/**/**', 'docs/**/**'],
+ rules: {
+ 'n/no-extraneous-import': 'off',
+ 'n/prefer-global/buffer': 'off',
+ 'n/prefer-global/process': 'off',
+ },
+ },
+ {
+ files: ['**/**/playwright.config.ts'],
+ rules: {
+ 'n/prefer-global/buffer': 'off',
+ 'n/prefer-global/process': 'off',
+ },
+ },
{
files: [
'scripts/**/*.?([cm])[jt]s?(x)',
diff --git a/internal/lint-configs/eslint-config/src/configs/perfectionist.ts b/internal/lint-configs/eslint-config/src/configs/perfectionist.ts
index 4a7d12fe9..cb8c98c3a 100644
--- a/internal/lint-configs/eslint-config/src/configs/perfectionist.ts
+++ b/internal/lint-configs/eslint-config/src/configs/perfectionist.ts
@@ -21,41 +21,58 @@ export async function perfectionist(): Promise {
'perfectionist/sort-imports': [
'error',
{
- customGroups: {
- type: {
- 'vben-core-type': ['^@vben-core/.+'],
- 'vben-type': ['^@vben/.+'],
- 'vue-type': ['^vue$', '^vue-.+', '^@vue/.+'],
+ customGroups: [
+ {
+ selector: 'type',
+ groupName: 'vben-core-type',
+ elementNamePattern: '^@vben-core/.+',
},
- value: {
- vben: ['^@vben/.+'],
- 'vben-core': ['^@vben-core/.+'],
- vue: ['^vue$', '^vue-.+', '^@vue/.+'],
+ {
+ selector: 'type',
+ groupName: 'vben-type',
+ elementNamePattern: '^@vben/.+',
},
- },
+ {
+ selector: 'type',
+ groupName: 'vue-type',
+ elementNamePattern: ['^vue$', '^vue-.+', '^@vue/.+'],
+ },
+ {
+ groupName: 'vben',
+ elementNamePattern: '^@vben/.+',
+ },
+ {
+ groupName: 'vben-core',
+ elementNamePattern: '^@vben-core/.+',
+ },
+ {
+ groupName: 'vue',
+ elementNamePattern: ['^vue$', '^vue-.+', '^@vue/.+'],
+ },
+ ],
environment: 'node',
groups: [
- ['external-type', 'builtin-type', 'type'],
+ ['type-external', 'type-builtin', 'type-import'],
'vue-type',
'vben-type',
'vben-core-type',
- ['parent-type', 'sibling-type', 'index-type'],
- ['internal-type'],
- 'builtin',
+ ['type-parent', 'type-sibling', 'type-index'],
+ ['type-internal'],
+ 'value-builtin',
'vue',
'vben',
'vben-core',
- 'external',
- 'internal',
- ['parent', 'sibling', 'index'],
+ 'value-external',
+ 'value-internal',
+ ['value-parent', 'value-sibling', 'value-index'],
'side-effect',
'side-effect-style',
'style',
- 'object',
+ 'ts-equals-import',
'unknown',
],
internalPattern: ['^#/.+'],
- newlinesBetween: 'always',
+ newlinesBetween: 1,
order: 'asc',
type: 'natural',
},
diff --git a/internal/lint-configs/eslint-config/src/configs/pnpm.ts b/internal/lint-configs/eslint-config/src/configs/pnpm.ts
index a3b28a7f6..5fe5afbf0 100644
--- a/internal/lint-configs/eslint-config/src/configs/pnpm.ts
+++ b/internal/lint-configs/eslint-config/src/configs/pnpm.ts
@@ -3,18 +3,15 @@ import type { Linter } from 'eslint';
import { interopDefault } from '../util';
export async function pnpm(): Promise {
- const [pluginPnpm, parserPnpm, parserJsonc] = await Promise.all([
+ const [pluginPnpm, parserPnpm] = await Promise.all([
interopDefault(import('eslint-plugin-pnpm')),
interopDefault(import('yaml-eslint-parser')),
- interopDefault(import('jsonc-eslint-parser')),
] as const);
return [
{
files: ['package.json', '**/package.json'],
- languageOptions: {
- parser: parserJsonc,
- },
+ language: 'jsonc/x',
plugins: {
pnpm: pluginPnpm,
},
diff --git a/internal/lint-configs/eslint-config/src/configs/prettier.ts b/internal/lint-configs/eslint-config/src/configs/prettier.ts
deleted file mode 100644
index 3cd7af40e..000000000
--- a/internal/lint-configs/eslint-config/src/configs/prettier.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { Linter } from 'eslint';
-
-import { interopDefault } from '../util';
-
-export async function prettier(): Promise {
- const [pluginPrettier] = await Promise.all([
- interopDefault(import('eslint-plugin-prettier')),
- ] as const);
- return [
- {
- plugins: {
- prettier: pluginPrettier,
- },
- rules: {
- 'prettier/prettier': 'error',
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/regexp.ts b/internal/lint-configs/eslint-config/src/configs/regexp.ts
deleted file mode 100644
index c0f4c9f43..000000000
--- a/internal/lint-configs/eslint-config/src/configs/regexp.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import type { Linter } from 'eslint';
-
-import { interopDefault } from '../util';
-
-export async function regexp(): Promise {
- const [pluginRegexp] = await Promise.all([
- interopDefault(import('eslint-plugin-regexp')),
- ] as const);
-
- return [
- {
- plugins: {
- regexp: pluginRegexp,
- },
- rules: {
- ...pluginRegexp.configs.recommended.rules,
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/test.ts b/internal/lint-configs/eslint-config/src/configs/test.ts
deleted file mode 100644
index ddfde2b87..000000000
--- a/internal/lint-configs/eslint-config/src/configs/test.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import type { Linter } from 'eslint';
-
-import { interopDefault } from '../util';
-
-export async function test(): Promise {
- const [pluginTest, pluginNoOnlyTests] = await Promise.all([
- interopDefault(import('eslint-plugin-vitest')),
- // @ts-expect-error - no types
- interopDefault(import('eslint-plugin-no-only-tests')),
- ] as const);
-
- return [
- {
- files: [
- `**/__tests__/**/*.?([cm])[jt]s?(x)`,
- `**/*.spec.?([cm])[jt]s?(x)`,
- `**/*.test.?([cm])[jt]s?(x)`,
- `**/*.bench.?([cm])[jt]s?(x)`,
- `**/*.benchmark.?([cm])[jt]s?(x)`,
- ],
- plugins: {
- test: {
- ...pluginTest,
- rules: {
- ...pluginTest.rules,
- ...pluginNoOnlyTests.rules,
- },
- },
- },
- rules: {
- 'no-console': 'off',
- 'node/prefer-global/process': 'off',
- 'test/consistent-test-it': [
- 'error',
- { fn: 'it', withinDescribe: 'it' },
- ],
- 'test/no-identical-title': 'error',
- 'test/no-import-node-test': 'error',
- 'test/no-only-tests': 'error',
- 'test/prefer-hooks-in-order': 'error',
- 'test/prefer-lowercase-title': 'error',
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/turbo.ts b/internal/lint-configs/eslint-config/src/configs/turbo.ts
deleted file mode 100644
index bcc27eb69..000000000
--- a/internal/lint-configs/eslint-config/src/configs/turbo.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import type { Linter } from 'eslint';
-
-import { interopDefault } from '../util';
-
-export async function turbo(): Promise {
- const [pluginTurbo] = await Promise.all([
- interopDefault(import('eslint-config-turbo')),
- ] as const);
-
- return [
- {
- plugins: {
- turbo: pluginTurbo,
- },
- },
- ];
-}
diff --git a/internal/lint-configs/eslint-config/src/configs/typescript.ts b/internal/lint-configs/eslint-config/src/configs/typescript.ts
index 2f6f97650..5e4157cf2 100644
--- a/internal/lint-configs/eslint-config/src/configs/typescript.ts
+++ b/internal/lint-configs/eslint-config/src/configs/typescript.ts
@@ -2,11 +2,24 @@ import type { Linter } from 'eslint';
import { interopDefault } from '../util';
+const rulesCoveredByOxlint = new Set([
+ '@typescript-eslint/ban-ts-comment',
+ '@typescript-eslint/no-non-null-assertion',
+ '@typescript-eslint/no-unused-expressions',
+ '@typescript-eslint/no-unused-vars',
+ '@typescript-eslint/triple-slash-reference',
+]);
+
export async function typescript(): Promise {
const [pluginTs, parserTs] = await Promise.all([
interopDefault(import('@typescript-eslint/eslint-plugin')),
interopDefault(import('@typescript-eslint/parser')),
] as const);
+ const strictRules = Object.fromEntries(
+ Object.entries(pluginTs.configs.strict?.rules ?? {}).filter(
+ ([ruleName]) => !rulesCoveredByOxlint.has(ruleName),
+ ),
+ );
return [
{
@@ -30,40 +43,14 @@ export async function typescript(): Promise {
},
rules: {
...pluginTs.configs['eslint-recommended']?.overrides?.[0]?.rules,
- ...pluginTs.configs.strict?.rules,
- '@typescript-eslint/ban-ts-comment': [
- 'error',
- {
- 'ts-check': false,
- 'ts-expect-error': 'allow-with-description',
- 'ts-ignore': 'allow-with-description',
- 'ts-nocheck': 'allow-with-description',
- },
- ],
-
+ ...strictRules,
// '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
'@typescript-eslint/consistent-type-definitions': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
- '@typescript-eslint/no-empty-function': [
- 'error',
- {
- allow: ['arrowFunctions', 'functions', 'methods'],
- },
- ],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-namespace': 'off',
- '@typescript-eslint/no-non-null-assertion': 'error',
- '@typescript-eslint/no-unused-expressions': 'off',
- '@typescript-eslint/no-unused-vars': [
- 'error',
- {
- argsIgnorePattern: '^_',
- varsIgnorePattern: '^_',
- },
- ],
'@typescript-eslint/no-use-before-define': 'off',
- '@typescript-eslint/no-var-requires': 'error',
'unused-imports/no-unused-vars': 'off',
},
},
diff --git a/internal/lint-configs/eslint-config/src/configs/unicorn.ts b/internal/lint-configs/eslint-config/src/configs/unicorn.ts
index 21b19025d..6e779e3bf 100644
--- a/internal/lint-configs/eslint-config/src/configs/unicorn.ts
+++ b/internal/lint-configs/eslint-config/src/configs/unicorn.ts
@@ -2,10 +2,20 @@ import type { Linter } from 'eslint';
import { interopDefault } from '../util';
+const rulesCoveredByOxlint = new Set([
+ 'unicorn/consistent-function-scoping',
+ 'unicorn/no-process-exit',
+ 'unicorn/prefer-global-this',
+ 'unicorn/prefer-module',
+]);
+
export async function unicorn(): Promise {
- const [pluginUnicorn] = await Promise.all([
- interopDefault(import('eslint-plugin-unicorn')),
- ] as const);
+ const pluginUnicorn = await interopDefault(import('eslint-plugin-unicorn'));
+ const recommendedRules = Object.fromEntries(
+ Object.entries(pluginUnicorn.configs.recommended.rules ?? {}).filter(
+ ([ruleName]) => !rulesCoveredByOxlint.has(ruleName),
+ ),
+ );
return [
{
@@ -13,11 +23,10 @@ export async function unicorn(): Promise {
unicorn: pluginUnicorn,
},
rules: {
- ...pluginUnicorn.configs.recommended.rules,
+ ...recommendedRules,
'unicorn/better-regex': 'off',
'unicorn/consistent-destructuring': 'off',
- 'unicorn/consistent-function-scoping': 'off',
'unicorn/expiring-todo-comments': 'off',
'unicorn/filename-case': 'off',
'unicorn/import-style': 'off',
@@ -27,19 +36,9 @@ export async function unicorn(): Promise {
'unicorn/prefer-at': 'off',
'unicorn/prefer-dom-node-text-content': 'off',
'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],
- 'unicorn/prefer-global-this': 'off',
'unicorn/prefer-top-level-await': 'off',
'unicorn/prevent-abbreviations': 'off',
},
},
- {
- files: [
- 'scripts/**/*.?([cm])[jt]s?(x)',
- 'internal/**/*.?([cm])[jt]s?(x)',
- ],
- rules: {
- 'unicorn/no-process-exit': 'off',
- },
- },
];
}
diff --git a/internal/lint-configs/eslint-config/src/configs/vue.ts b/internal/lint-configs/eslint-config/src/configs/vue.ts
index 5db72992d..edd576888 100644
--- a/internal/lint-configs/eslint-config/src/configs/vue.ts
+++ b/internal/lint-configs/eslint-config/src/configs/vue.ts
@@ -128,7 +128,6 @@ export async function vue(): Promise {
},
],
'vue/one-component-per-file': 'error',
- 'vue/prefer-import-from-vue': 'error',
'vue/prefer-separate-static-class': 'error',
'vue/prefer-template': 'error',
'vue/prop-name-casing': ['error', 'camelCase'],
diff --git a/internal/lint-configs/eslint-config/src/configs/yaml.ts b/internal/lint-configs/eslint-config/src/configs/yaml.ts
index 55aa94d53..889371955 100644
--- a/internal/lint-configs/eslint-config/src/configs/yaml.ts
+++ b/internal/lint-configs/eslint-config/src/configs/yaml.ts
@@ -12,7 +12,7 @@ export async function yaml(): Promise {
{
files: ['**/*.y?(a)ml'],
plugins: {
- yaml: pluginYaml as any,
+ yaml: pluginYaml,
},
languageOptions: {
parser: parserYaml,
diff --git a/internal/lint-configs/eslint-config/src/custom-config.ts b/internal/lint-configs/eslint-config/src/custom-config.ts
index 1b51e5a5a..01a72675c 100644
--- a/internal/lint-configs/eslint-config/src/custom-config.ts
+++ b/internal/lint-configs/eslint-config/src/custom-config.ts
@@ -1,10 +1,6 @@
import type { Linter } from 'eslint';
-const restrictedImportIgnores = [
- '**/vite.config.mts',
- '**/tailwind.config.mjs',
- '**/postcss.config.mjs',
-];
+const restrictedImportIgnores = ['**/vite.config.mts'];
const customConfig: Linter.Config[] = [
// shadcn-ui 内部组件是自动生成的,不做太多限制
@@ -25,14 +21,6 @@ const customConfig: Linter.Config[] = [
ignores: restrictedImportIgnores,
rules: {
'perfectionist/sort-interfaces': 'off',
- 'perfectionist/sort-objects': 'off',
- },
- },
- {
- files: ['**/**.vue'],
- ignores: restrictedImportIgnores,
- rules: {
- 'perfectionist/sort-objects': 'off',
},
},
{
@@ -71,7 +59,6 @@ const customConfig: Linter.Config[] = [
],
},
],
- 'perfectionist/sort-interfaces': 'off',
},
},
{
@@ -145,19 +132,12 @@ const customConfig: Linter.Config[] = [
{
files: ['apps/backend-mock/**/**', 'docs/**/**'],
rules: {
- '@typescript-eslint/no-extraneous-class': 'off',
- 'n/no-extraneous-import': 'off',
- 'n/prefer-global/buffer': 'off',
- 'n/prefer-global/process': 'off',
'no-console': 'off',
- 'unicorn/prefer-module': 'off',
},
},
{
files: ['**/**/playwright.config.ts'],
rules: {
- 'n/prefer-global/buffer': 'off',
- 'n/prefer-global/process': 'off',
'no-console': 'off',
},
},
@@ -167,6 +147,12 @@ const customConfig: Linter.Config[] = [
'no-console': 'off',
},
},
+ {
+ files: ['packages/@core/base/shared/src/utils/inference.ts'],
+ rules: {
+ 'vue/prefer-import-from-vue': 'off',
+ },
+ },
];
export { customConfig };
diff --git a/internal/lint-configs/eslint-config/src/index.ts b/internal/lint-configs/eslint-config/src/index.ts
index d3bbf5754..f853781a9 100644
--- a/internal/lint-configs/eslint-config/src/index.ts
+++ b/internal/lint-configs/eslint-config/src/index.ts
@@ -1,21 +1,12 @@
import type { Linter } from 'eslint';
import {
- command,
- comments,
- disableds,
ignores,
- importPluginConfig,
javascript,
- jsdoc,
jsonc,
node,
perfectionist,
pnpm,
- prettier,
- regexp,
- test,
- turbo,
typescript,
unicorn,
vue,
@@ -36,20 +27,11 @@ async function defineConfig(config: FlatConfig[] = []) {
vue(),
javascript(),
ignores(),
- prettier(),
typescript(),
jsonc(),
- disableds(),
- importPluginConfig(),
node(),
perfectionist(),
- comments(),
- jsdoc(),
unicorn(),
- test(),
- regexp(),
- command(),
- turbo(),
yaml(),
pnpm(),
...customConfig,
diff --git a/internal/tailwind-config/build.config.ts b/internal/lint-configs/oxfmt-config/build.config.ts
similarity index 58%
rename from internal/tailwind-config/build.config.ts
rename to internal/lint-configs/oxfmt-config/build.config.ts
index 1f3c3c220..97e572c56 100644
--- a/internal/tailwind-config/build.config.ts
+++ b/internal/lint-configs/oxfmt-config/build.config.ts
@@ -3,8 +3,5 @@ import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
declaration: true,
- entries: ['src/index', './src/postcss.config'],
- rollup: {
- emitCJS: true,
- },
+ entries: ['src/index'],
});
diff --git a/internal/lint-configs/prettier-config/package.json b/internal/lint-configs/oxfmt-config/package.json
similarity index 51%
rename from internal/lint-configs/prettier-config/package.json
rename to internal/lint-configs/oxfmt-config/package.json
index 5ed785d79..3e016797e 100644
--- a/internal/lint-configs/prettier-config/package.json
+++ b/internal/lint-configs/oxfmt-config/package.json
@@ -1,28 +1,32 @@
{
- "name": "@vben/prettier-config",
- "version": "5.6.0",
+ "name": "@vben/oxfmt-config",
+ "version": "5.7.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
- "directory": "internal/lint-configs/prettier-config"
+ "directory": "internal/lint-configs/oxfmt-config"
},
"license": "MIT",
"type": "module",
+ "scripts": {
+ "stub": "pnpm unbuild --stub"
+ },
"files": [
"dist"
],
- "main": "./index.mjs",
- "module": "./index.mjs",
+ "main": "./dist/index.mjs",
+ "module": "./dist/index.mjs",
+ "types": "./dist/index.d.ts",
"exports": {
".": {
- "default": "./index.mjs"
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.mjs"
}
},
"dependencies": {
- "prettier": "catalog:",
- "prettier-plugin-tailwindcss": "catalog:"
+ "oxfmt": "catalog:"
}
}
diff --git a/internal/lint-configs/oxfmt-config/src/index.ts b/internal/lint-configs/oxfmt-config/src/index.ts
new file mode 100644
index 000000000..5f88c1809
--- /dev/null
+++ b/internal/lint-configs/oxfmt-config/src/index.ts
@@ -0,0 +1,39 @@
+import { defineConfig as defineOxfmtConfig } from 'oxfmt';
+
+type OxfmtConfig = Parameters[0];
+
+const oxfmtConfig = defineOxfmtConfig({
+ printWidth: 80,
+ proseWrap: 'never',
+ semi: true,
+ singleQuote: true,
+ sortPackageJson: false,
+ trailingComma: 'all',
+ overrides: [
+ {
+ files: [
+ '*.json',
+ '*.json5',
+ '*.jsonc',
+ '*.code-workspace',
+ '**/*.json',
+ '**/*.json5',
+ '**/*.jsonc',
+ '**/*.code-workspace',
+ ],
+ options: {
+ trailingComma: 'none',
+ },
+ },
+ ],
+});
+
+function defineConfig(config: OxfmtConfig = {}) {
+ return defineOxfmtConfig({
+ ...oxfmtConfig,
+ ...config,
+ });
+}
+
+export { defineConfig, oxfmtConfig };
+export type { OxfmtConfig };
diff --git a/internal/tailwind-config/tsconfig.json b/internal/lint-configs/oxfmt-config/tsconfig.json
similarity index 100%
rename from internal/tailwind-config/tsconfig.json
rename to internal/lint-configs/oxfmt-config/tsconfig.json
diff --git a/internal/lint-configs/oxlint-config/build.config.ts b/internal/lint-configs/oxlint-config/build.config.ts
new file mode 100644
index 000000000..97e572c56
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+ clean: true,
+ declaration: true,
+ entries: ['src/index'],
+});
diff --git a/internal/lint-configs/oxlint-config/package.json b/internal/lint-configs/oxlint-config/package.json
new file mode 100644
index 000000000..05d3bedfe
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "@vben/oxlint-config",
+ "version": "5.7.0",
+ "private": true,
+ "homepage": "https://github.com/vbenjs/vue-vben-admin",
+ "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+ "directory": "internal/lint-configs/oxlint-config"
+ },
+ "license": "MIT",
+ "type": "module",
+ "scripts": {
+ "stub": "pnpm unbuild --stub"
+ },
+ "files": [
+ "dist"
+ ],
+ "main": "./dist/index.mjs",
+ "module": "./dist/index.mjs",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.mjs"
+ }
+ },
+ "dependencies": {
+ "@eslint-community/eslint-plugin-eslint-comments": "catalog:",
+ "eslint-plugin-better-tailwindcss": "catalog:",
+ "eslint-plugin-command": "catalog:",
+ "oxlint": "catalog:"
+ }
+}
diff --git a/internal/lint-configs/oxlint-config/src/configs/command.ts b/internal/lint-configs/oxlint-config/src/configs/command.ts
new file mode 100644
index 000000000..1a3498cb4
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/command.ts
@@ -0,0 +1,15 @@
+import type { OxlintConfig } from 'oxlint';
+
+const command: OxlintConfig = {
+ jsPlugins: [
+ {
+ name: 'command',
+ specifier: 'eslint-plugin-command',
+ },
+ ],
+ rules: {
+ 'command/command': 'error',
+ },
+};
+
+export { command };
diff --git a/internal/lint-configs/oxlint-config/src/configs/comments.ts b/internal/lint-configs/oxlint-config/src/configs/comments.ts
new file mode 100644
index 000000000..09c0d012e
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/comments.ts
@@ -0,0 +1,18 @@
+import type { OxlintConfig } from 'oxlint';
+
+const comments: OxlintConfig = {
+ jsPlugins: [
+ {
+ name: 'eslint-comments',
+ specifier: '@eslint-community/eslint-plugin-eslint-comments',
+ },
+ ],
+ rules: {
+ 'eslint-comments/no-aggregating-enable': 'error',
+ 'eslint-comments/no-duplicate-disable': 'error',
+ 'eslint-comments/no-unlimited-disable': 'error',
+ 'eslint-comments/no-unused-enable': 'error',
+ },
+};
+
+export { comments };
diff --git a/internal/lint-configs/oxlint-config/src/configs/ignores.ts b/internal/lint-configs/oxlint-config/src/configs/ignores.ts
new file mode 100644
index 000000000..858a3cd73
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/ignores.ts
@@ -0,0 +1,17 @@
+import type { OxlintConfig } from 'oxlint';
+
+const ignores: OxlintConfig = {
+ ignorePatterns: [
+ '**/dist/**',
+ '**/node_modules/**',
+ 'docs/**',
+ 'playground/public/**',
+ '**/*.json',
+ '**/*.md',
+ '**/*.svg',
+ '**/*.yaml',
+ '**/*.yml',
+ ],
+};
+
+export { ignores };
diff --git a/internal/lint-configs/oxlint-config/src/configs/import.ts b/internal/lint-configs/oxlint-config/src/configs/import.ts
new file mode 100644
index 000000000..8e719ad48
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/import.ts
@@ -0,0 +1,18 @@
+import type { OxlintConfig } from 'oxlint';
+
+const importPluginConfig: OxlintConfig = {
+ rules: {
+ 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
+ 'import/first': 'error',
+ 'import/no-duplicates': 'error',
+ 'import/no-mutable-exports': 'error',
+ 'import/no-named-as-default': 'off',
+ 'import/no-named-as-default-member': 'off',
+ 'import/no-named-default': 'error',
+ 'import/no-self-import': 'error',
+ 'import/no-unassigned-import': 'off',
+ 'import/no-webpack-loader-syntax': 'error',
+ },
+};
+
+export { importPluginConfig };
diff --git a/internal/lint-configs/oxlint-config/src/configs/index.ts b/internal/lint-configs/oxlint-config/src/configs/index.ts
new file mode 100644
index 000000000..361ced9a2
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/index.ts
@@ -0,0 +1,96 @@
+import type { OxlintConfig } from 'oxlint';
+
+import { defineConfig as defineOxlintConfig } from 'oxlint';
+
+import { command } from './command';
+import { comments } from './comments';
+import { ignores } from './ignores';
+import { importPluginConfig } from './import';
+import { javascript } from './javascript';
+import { node } from './node';
+import { overrides } from './overrides';
+import { plugins } from './plugins';
+import { tailwindcss } from './tailwindcss';
+import { test } from './test';
+import { typescript } from './typescript';
+import { unicorn } from './unicorn';
+import { vue } from './vue';
+
+function mergeOxlintConfigs(...configs: OxlintConfig[]): OxlintConfig {
+ const merged: OxlintConfig = {};
+
+ for (const config of configs) {
+ merged.categories =
+ merged.categories && config.categories
+ ? { ...merged.categories, ...config.categories }
+ : (config.categories ?? merged.categories);
+ merged.env =
+ merged.env && config.env
+ ? { ...merged.env, ...config.env }
+ : (config.env ?? merged.env);
+ merged.globals =
+ merged.globals && config.globals
+ ? { ...merged.globals, ...config.globals }
+ : (config.globals ?? merged.globals);
+ merged.ignorePatterns = [
+ ...(merged.ignorePatterns ?? []),
+ ...(config.ignorePatterns ?? []),
+ ];
+ merged.jsPlugins = [
+ ...new Set([...(merged.jsPlugins ?? []), ...(config.jsPlugins ?? [])]),
+ ];
+ merged.overrides = [
+ ...(merged.overrides ?? []),
+ ...(config.overrides ?? []),
+ ];
+ merged.plugins = [
+ ...new Set([...(merged.plugins ?? []), ...(config.plugins ?? [])]),
+ ];
+ merged.rules =
+ merged.rules && config.rules
+ ? { ...merged.rules, ...config.rules }
+ : (config.rules ?? merged.rules);
+ merged.settings =
+ merged.settings && config.settings
+ ? { ...merged.settings, ...config.settings }
+ : (config.settings ?? merged.settings);
+ }
+
+ return merged;
+}
+
+const oxlintConfig = defineOxlintConfig(
+ mergeOxlintConfigs(
+ javascript,
+ command,
+ comments,
+ ignores,
+ plugins,
+ importPluginConfig,
+ node,
+ overrides,
+ tailwindcss,
+ test,
+ typescript,
+ unicorn,
+ vue,
+ ),
+);
+
+export {
+ command,
+ comments,
+ ignores,
+ importPluginConfig,
+ javascript,
+ mergeOxlintConfigs,
+ node,
+ overrides,
+ oxlintConfig,
+ plugins,
+ tailwindcss,
+ test,
+ typescript,
+ unicorn,
+ vue,
+};
diff --git a/internal/lint-configs/oxlint-config/src/configs/javascript.ts b/internal/lint-configs/oxlint-config/src/configs/javascript.ts
new file mode 100644
index 000000000..4ea37891c
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/javascript.ts
@@ -0,0 +1,156 @@
+import type { OxlintConfig } from 'oxlint';
+
+const javascript: OxlintConfig = {
+ categories: {
+ correctness: 'error',
+ suspicious: 'warn',
+ },
+ env: {
+ browser: true,
+ es2021: true,
+ node: true,
+ },
+ globals: {
+ document: 'readonly',
+ navigator: 'readonly',
+ window: 'readonly',
+ },
+ rules: {
+ 'accessor-pairs': [
+ 'error',
+ {
+ enforceForClassMembers: true,
+ setWithoutGet: true,
+ },
+ ],
+ 'array-callback-return': 'error',
+ 'block-scoped-var': 'error',
+ 'default-case-last': 'error',
+ eqeqeq: ['error', 'always'],
+ 'eslint/no-unreachable': 'error',
+ 'new-cap': [
+ 'error',
+ {
+ capIsNew: false,
+ newIsCap: true,
+ properties: true,
+ },
+ ],
+ 'no-alert': 'error',
+ 'no-array-constructor': 'error',
+ 'no-caller': 'error',
+ 'no-case-declarations': 'error',
+ 'no-console': ['error', { allow: ['warn', 'error'] }],
+ 'no-control-regex': 'off',
+ 'no-debugger': 'error',
+ 'no-empty': ['error', { allowEmptyCatch: true }],
+ 'no-fallthrough': 'error',
+ 'no-new-func': 'error',
+ 'no-new-object': 'error',
+ 'no-new-symbol': 'error',
+ 'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
+ 'no-lone-blocks': 'error',
+ 'no-multi-str': 'error',
+ 'no-octal': 'error',
+ 'no-octal-escape': 'error',
+ 'no-proto': 'error',
+ 'no-prototype-builtins': 'error',
+ 'no-redeclare': ['error', { builtinGlobals: false }],
+ 'no-regex-spaces': 'error',
+ 'no-self-compare': 'error',
+ 'no-sequences': 'error',
+ 'no-shadow': 'off',
+ 'no-shadow-restricted-names': 'error',
+ 'eslint/no-empty-function': [
+ 'error',
+ {
+ allow: ['arrowFunctions', 'functions', 'methods'],
+ },
+ ],
+ 'no-template-curly-in-string': 'error',
+ 'no-throw-literal': 'error',
+ 'no-undef-init': 'error',
+ 'no-unused-expressions': [
+ 'error',
+ {
+ allowShortCircuit: true,
+ allowTaggedTemplates: true,
+ allowTernary: true,
+ },
+ ],
+ 'eslint/no-unused-vars': [
+ 'error',
+ {
+ argsIgnorePattern: '^_',
+ varsIgnorePattern: '^_',
+ },
+ ],
+ 'no-var': 'error',
+ 'no-eval': 'error',
+ 'no-iterator': 'error',
+ 'no-new-wrappers': 'error',
+ 'no-restricted-globals': [
+ 'error',
+ { message: 'Use `globalThis` instead.', name: 'global' },
+ { message: 'Use `globalThis` instead.', name: 'self' },
+ ],
+ 'no-useless-call': 'error',
+ 'no-useless-computed-key': 'error',
+ 'no-useless-constructor': 'error',
+ 'no-useless-return': 'error',
+ 'object-shorthand': [
+ 'error',
+ 'always',
+ {
+ avoidQuotes: true,
+ ignoreConstructors: false,
+ },
+ ],
+ 'one-var': ['error', { initialized: 'never' }],
+ 'prefer-const': [
+ 'error',
+ {
+ destructuring: 'all',
+ ignoreReadBeforeAssign: true,
+ },
+ ],
+ 'eslint/prefer-arrow-callback': [
+ 'error',
+ {
+ allowNamedFunctions: false,
+ allowUnboundThis: true,
+ },
+ ],
+ 'prefer-exponentiation-operator': 'error',
+ 'prefer-promise-reject-errors': 'error',
+ 'eslint/prefer-regex-literals': [
+ 'error',
+ {
+ disallowRedundantWrapping: true,
+ },
+ ],
+ 'prefer-rest-params': 'error',
+ 'prefer-spread': 'error',
+ 'prefer-template': 'error',
+ 'spaced-comment': 'error',
+ 'symbol-description': 'error',
+ 'unicode-bom': ['error', 'never'],
+ 'use-isnan': [
+ 'error',
+ {
+ enforceForIndexOf: true,
+ enforceForSwitchCase: true,
+ },
+ ],
+ 'valid-typeof': [
+ 'error',
+ {
+ requireStringLiterals: true,
+ },
+ ],
+ 'vars-on-top': 'error',
+ yoda: ['error', 'never'],
+ },
+};
+
+export { javascript };
diff --git a/internal/lint-configs/oxlint-config/src/configs/node.ts b/internal/lint-configs/oxlint-config/src/configs/node.ts
new file mode 100644
index 000000000..24aa08dfa
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/node.ts
@@ -0,0 +1,11 @@
+import type { OxlintConfig } from 'oxlint';
+
+const node: OxlintConfig = {
+ rules: {
+ 'node/no-exports-assign': 'error',
+ 'node/no-new-require': 'error',
+ 'node/no-path-concat': 'error',
+ },
+};
+
+export { node };
diff --git a/internal/lint-configs/oxlint-config/src/configs/overrides.ts b/internal/lint-configs/oxlint-config/src/configs/overrides.ts
new file mode 100644
index 000000000..c8838feb1
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/overrides.ts
@@ -0,0 +1,98 @@
+import type { OxlintConfig } from 'oxlint';
+
+const overrides: OxlintConfig = {
+ overrides: [
+ {
+ files: ['*.d.ts', '**/*.d.ts'],
+ rules: {
+ 'import/no-unassigned-import': 'off',
+ 'typescript/triple-slash-reference': 'off',
+ },
+ },
+ {
+ files: [
+ '**/__tests__/**/*.js',
+ '**/__tests__/**/*.cjs',
+ '**/__tests__/**/*.mjs',
+ '**/__tests__/**/*.jsx',
+ '**/__tests__/**/*.ts',
+ '**/__tests__/**/*.cts',
+ '**/__tests__/**/*.mts',
+ '**/__tests__/**/*.tsx',
+ '**/*.spec.js',
+ '**/*.spec.cjs',
+ '**/*.spec.mjs',
+ '**/*.spec.jsx',
+ '**/*.spec.ts',
+ '**/*.spec.cts',
+ '**/*.spec.mts',
+ '**/*.spec.tsx',
+ '**/*.test.js',
+ '**/*.test.cjs',
+ '**/*.test.mjs',
+ '**/*.test.jsx',
+ '**/*.test.ts',
+ '**/*.test.cts',
+ '**/*.test.mts',
+ '**/*.test.tsx',
+ '**/*.bench.js',
+ '**/*.bench.cjs',
+ '**/*.bench.mjs',
+ '**/*.bench.jsx',
+ '**/*.bench.ts',
+ '**/*.bench.cts',
+ '**/*.bench.mts',
+ '**/*.bench.tsx',
+ '**/*.benchmark.js',
+ '**/*.benchmark.cjs',
+ '**/*.benchmark.mjs',
+ '**/*.benchmark.jsx',
+ '**/*.benchmark.ts',
+ '**/*.benchmark.cts',
+ '**/*.benchmark.mts',
+ '**/*.benchmark.tsx',
+ ],
+ rules: {
+ 'no-console': 'off',
+ },
+ },
+ {
+ files: ['packages/@core/base/shared/src/utils/inference.ts'],
+ rules: {
+ 'vue/prefer-import-from-vue': 'off',
+ },
+ },
+ {
+ files: ['packages/@core/ui-kit/menu-ui/src/sub-menu.vue'],
+ rules: {
+ 'import/no-self-import': 'off',
+ },
+ },
+ {
+ files: [
+ 'scripts/**/*.js',
+ 'scripts/**/*.cjs',
+ 'scripts/**/*.mjs',
+ 'scripts/**/*.jsx',
+ 'scripts/**/*.ts',
+ 'scripts/**/*.cts',
+ 'scripts/**/*.mts',
+ 'scripts/**/*.tsx',
+ 'internal/**/*.js',
+ 'internal/**/*.cjs',
+ 'internal/**/*.mjs',
+ 'internal/**/*.jsx',
+ 'internal/**/*.ts',
+ 'internal/**/*.cts',
+ 'internal/**/*.mts',
+ 'internal/**/*.tsx',
+ ],
+ rules: {
+ 'no-console': 'off',
+ 'unicorn/no-process-exit': 'off',
+ },
+ },
+ ],
+};
+
+export { overrides };
diff --git a/internal/lint-configs/oxlint-config/src/configs/plugins.ts b/internal/lint-configs/oxlint-config/src/configs/plugins.ts
new file mode 100644
index 000000000..8b6f3dd17
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/plugins.ts
@@ -0,0 +1,7 @@
+import type { OxlintConfig } from 'oxlint';
+
+const plugins: OxlintConfig = {
+ plugins: ['import', 'node', 'oxc', 'typescript', 'unicorn', 'vitest', 'vue'],
+};
+
+export { plugins };
diff --git a/internal/lint-configs/oxlint-config/src/configs/tailwindcss.ts b/internal/lint-configs/oxlint-config/src/configs/tailwindcss.ts
new file mode 100644
index 000000000..c24e5c865
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/tailwindcss.ts
@@ -0,0 +1,50 @@
+import type { OxlintConfig } from 'oxlint';
+
+import eslintPluginBetterTailwindcss from 'eslint-plugin-better-tailwindcss';
+import { getDefaultSelectors } from 'eslint-plugin-better-tailwindcss/defaults';
+import { SelectorKind } from 'eslint-plugin-better-tailwindcss/types';
+
+const selectors = [
+ ...getDefaultSelectors(),
+ {
+ kind: SelectorKind.Attribute,
+ match: [{ type: 'objectValues' }],
+ name: '^classNames$',
+ },
+];
+
+const settings = {
+ entryPoint: 'packages/@core/base/design/src/css/global.css',
+ selectors,
+};
+
+const tailwindcss: OxlintConfig = {
+ // Generated shadcn-ui internals are intentionally left unmanaged.
+ ignorePatterns: ['packages/@core/ui-kit/shadcn-ui/**/*'],
+ jsPlugins: [
+ {
+ name: 'better-tailwindcss',
+ specifier: 'eslint-plugin-better-tailwindcss',
+ },
+ ],
+ rules: {
+ ...eslintPluginBetterTailwindcss.configs.recommended.rules,
+ 'better-tailwindcss/enforce-consistent-class-order': [
+ 'error',
+ {
+ detectComponentClasses: true,
+ unknownClassOrder: 'asc',
+ unknownClassPosition: 'start',
+ },
+ ],
+ // Let Prettier own wrapping decisions to avoid ping-pong formatting.
+ 'better-tailwindcss/enforce-consistent-line-wrapping': 'off',
+ 'better-tailwindcss/no-unknown-classes': 'off',
+ },
+ settings: {
+ 'better-tailwindcss': settings,
+ 'eslint-plugin-better-tailwindcss': settings,
+ },
+};
+
+export { tailwindcss };
diff --git a/internal/lint-configs/oxlint-config/src/configs/test.ts b/internal/lint-configs/oxlint-config/src/configs/test.ts
new file mode 100644
index 000000000..a7470eb6a
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/test.ts
@@ -0,0 +1,23 @@
+import type { OxlintConfig } from 'oxlint';
+
+const test: OxlintConfig = {
+ rules: {
+ 'jest/no-conditional-expect': 'off',
+ 'jest/require-to-throw-message': 'off',
+ 'vitest/consistent-test-it': [
+ 'error',
+ {
+ fn: 'it',
+ withinDescribe: 'it',
+ },
+ ],
+ 'vitest/hoisted-apis-on-top': 'off',
+ 'vitest/no-focused-tests': 'error',
+ 'vitest/no-identical-title': 'error',
+ 'vitest/no-import-node-test': 'error',
+ 'vitest/prefer-hooks-in-order': 'error',
+ 'vitest/prefer-lowercase-title': 'error',
+ },
+};
+
+export { test };
diff --git a/internal/lint-configs/oxlint-config/src/configs/typescript.ts b/internal/lint-configs/oxlint-config/src/configs/typescript.ts
new file mode 100644
index 000000000..e2db0b892
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/typescript.ts
@@ -0,0 +1,28 @@
+import type { OxlintConfig } from 'oxlint';
+
+const typescript: OxlintConfig = {
+ rules: {
+ 'typescript/ban-ts-comment': 'error',
+ // Keep the first type-aware rollout conservative. These rules currently
+ // produce high-volume diagnostics and need file-by-file cleanup later.
+ 'typescript/await-thenable': 'off',
+ 'typescript/no-base-to-string': 'off',
+ 'typescript/no-duplicate-type-constituents': 'off',
+ 'typescript/no-floating-promises': 'off',
+ 'typescript/no-misused-spread': 'off',
+ 'typescript/no-non-null-assertion': 'error',
+ 'typescript/no-redundant-type-constituents': 'off',
+ 'typescript/no-unnecessary-boolean-literal-compare': 'off',
+ 'typescript/no-unnecessary-type-assertion': 'off',
+ 'typescript/no-unnecessary-type-arguments': 'off',
+ 'typescript/no-unnecessary-template-expression': 'off',
+ 'typescript/no-unsafe-enum-comparison': 'off',
+ 'typescript/no-unsafe-type-assertion': 'off',
+ 'typescript/no-var-requires': 'error',
+ 'typescript/restrict-template-expressions': 'off',
+ 'typescript/triple-slash-reference': 'error',
+ 'typescript/unbound-method': 'off',
+ },
+};
+
+export { typescript };
diff --git a/internal/lint-configs/oxlint-config/src/configs/unicorn.ts b/internal/lint-configs/oxlint-config/src/configs/unicorn.ts
new file mode 100644
index 000000000..b72af15a0
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/unicorn.ts
@@ -0,0 +1,14 @@
+import type { OxlintConfig } from 'oxlint';
+
+const unicorn: OxlintConfig = {
+ rules: {
+ 'unicorn/consistent-function-scoping': 'off',
+ 'unicorn/no-process-exit': 'error',
+ 'unicorn/no-single-promise-in-promise-methods': 'off',
+ 'unicorn/no-useless-spread': 'off',
+ 'unicorn/prefer-global-this': 'off',
+ 'unicorn/prefer-module': 'error',
+ },
+};
+
+export { unicorn };
diff --git a/internal/lint-configs/oxlint-config/src/configs/vue.ts b/internal/lint-configs/oxlint-config/src/configs/vue.ts
new file mode 100644
index 000000000..172507d69
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/configs/vue.ts
@@ -0,0 +1,9 @@
+import type { OxlintConfig } from 'oxlint';
+
+const vue: OxlintConfig = {
+ rules: {
+ 'vue/prefer-import-from-vue': 'error',
+ },
+};
+
+export { vue };
diff --git a/internal/lint-configs/oxlint-config/src/index.ts b/internal/lint-configs/oxlint-config/src/index.ts
new file mode 100644
index 000000000..b890cb0d3
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/src/index.ts
@@ -0,0 +1,21 @@
+import type { OxlintConfig } from 'oxlint';
+
+import { defineConfig as defineOxlintConfig } from 'oxlint';
+
+import { mergeOxlintConfigs, oxlintConfig } from './configs';
+
+type VbenOxlintConfig = Omit & {
+ extends?: OxlintConfig[];
+};
+
+function defineConfig(config: VbenOxlintConfig = {}) {
+ const { extends: extendedConfigs = [], ...restConfig } = config;
+
+ return defineOxlintConfig(
+ mergeOxlintConfigs(oxlintConfig, ...extendedConfigs, restConfig),
+ );
+}
+
+export { defineConfig, oxlintConfig };
+export * from './configs';
+export type { OxlintConfig, VbenOxlintConfig };
diff --git a/internal/lint-configs/oxlint-config/tsconfig.json b/internal/lint-configs/oxlint-config/tsconfig.json
new file mode 100644
index 000000000..b2ec3b61e
--- /dev/null
+++ b/internal/lint-configs/oxlint-config/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "extends": "@vben/tsconfig/node.json",
+ "include": ["src"],
+ "exclude": ["node_modules"]
+}
diff --git a/internal/lint-configs/prettier-config/index.mjs b/internal/lint-configs/prettier-config/index.mjs
deleted file mode 100644
index f6a20c8b4..000000000
--- a/internal/lint-configs/prettier-config/index.mjs
+++ /dev/null
@@ -1,18 +0,0 @@
-export default {
- endOfLine: 'auto',
- overrides: [
- {
- files: ['*.json5'],
- options: {
- quoteProps: 'preserve',
- singleQuote: false,
- },
- },
- ],
- plugins: ['prettier-plugin-tailwindcss'],
- printWidth: 80,
- proseWrap: 'never',
- semi: true,
- singleQuote: true,
- trailingComma: 'all',
-};
diff --git a/internal/lint-configs/stylelint-config/index.mjs b/internal/lint-configs/stylelint-config/index.mjs
index 47cd12d81..1395d5ec0 100644
--- a/internal/lint-configs/stylelint-config/index.mjs
+++ b/internal/lint-configs/stylelint-config/index.mjs
@@ -36,12 +36,7 @@ export default {
files: ['*.scss', '**/*.scss'],
},
],
- plugins: [
- 'stylelint-order',
- '@stylistic/stylelint-plugin',
- 'stylelint-prettier',
- 'stylelint-scss',
- ],
+ plugins: ['stylelint-order', '@stylistic/stylelint-plugin', 'stylelint-scss'],
rules: {
'at-rule-no-deprecated': null,
'at-rule-no-unknown': [
@@ -67,6 +62,12 @@ export default {
'use',
'forward',
'return',
+ 'reference',
+ 'plugin',
+ 'source',
+ 'theme',
+ 'utility',
+ 'custom-variant',
],
},
],
@@ -100,7 +101,6 @@ export default {
],
{ severity: 'error' },
],
- 'prettier/prettier': true,
'rule-empty-line-before': [
'always',
{
@@ -130,12 +130,18 @@ export default {
'use',
'forward',
'return',
+ 'reference',
+ 'plugin',
+ 'source',
+ 'theme',
+ 'utility',
+ 'custom-variant',
],
},
],
'scss/operator-no-newline-after': null,
'selector-class-pattern':
- '^(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:[.+])?$',
+ '^-?(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:[.+])?$',
'selector-not-notation': null,
},
diff --git a/internal/lint-configs/stylelint-config/package.json b/internal/lint-configs/stylelint-config/package.json
index 4d0c26fc6..110795437 100644
--- a/internal/lint-configs/stylelint-config/package.json
+++ b/internal/lint-configs/stylelint-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben/stylelint-config",
- "version": "5.6.0",
+ "version": "5.7.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -31,13 +31,11 @@
"postcss": "catalog:",
"postcss-html": "catalog:",
"postcss-scss": "catalog:",
- "prettier": "catalog:",
"stylelint": "catalog:",
"stylelint-config-recommended": "catalog:",
"stylelint-config-recommended-scss": "catalog:",
"stylelint-config-recommended-vue": "catalog:",
"stylelint-config-standard": "catalog:",
- "stylelint-order": "catalog:",
- "stylelint-prettier": "catalog:"
+ "stylelint-order": "catalog:"
}
}
diff --git a/internal/node-utils/package.json b/internal/node-utils/package.json
index f8add8b4e..40a017f14 100644
--- a/internal/node-utils/package.json
+++ b/internal/node-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben/node-utils",
- "version": "5.6.0",
+ "version": "5.7.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -37,7 +37,6 @@
"find-up": "catalog:",
"ora": "catalog:",
"pkg-types": "catalog:",
- "prettier": "catalog:",
"rimraf": "catalog:"
}
}
diff --git a/internal/node-utils/src/formatter.ts b/internal/node-utils/src/formatter.ts
new file mode 100644
index 000000000..78c6be0b9
--- /dev/null
+++ b/internal/node-utils/src/formatter.ts
@@ -0,0 +1,13 @@
+import fs from 'node:fs/promises';
+
+import { execa } from 'execa';
+
+async function formatFile(filepath: string) {
+ await execa('oxfmt', [filepath], {
+ stdio: 'inherit',
+ });
+
+ return await fs.readFile(filepath, 'utf8');
+}
+
+export { formatFile };
diff --git a/internal/node-utils/src/index.ts b/internal/node-utils/src/index.ts
index 2e39ccff6..ff50289bf 100644
--- a/internal/node-utils/src/index.ts
+++ b/internal/node-utils/src/index.ts
@@ -1,12 +1,12 @@
export * from './constants';
export * from './date';
+export { formatFile } from './formatter';
export * from './fs';
export * from './git';
export { add as gitAdd, getStagedFiles } from './git';
export { generatorContentHash } from './hash';
export * from './monorepo';
export { toPosixPath } from './path';
-export { prettierFormat } from './prettier';
export * from './spinner';
export type { Package } from '@manypkg/get-packages';
export { default as colors } from 'chalk';
diff --git a/internal/node-utils/src/prettier.ts b/internal/node-utils/src/prettier.ts
deleted file mode 100644
index 1e1525db1..000000000
--- a/internal/node-utils/src/prettier.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import fs from 'node:fs/promises';
-
-import { format, getFileInfo, resolveConfig } from 'prettier';
-
-async function prettierFormat(filepath: string) {
- const prettierOptions = await resolveConfig(filepath, {});
-
- const fileInfo = await getFileInfo(filepath);
-
- const input = await fs.readFile(filepath, 'utf8');
- const output = await format(input, {
- ...prettierOptions,
- parser: fileInfo.inferredParser as any,
- });
- if (output !== input) {
- await fs.writeFile(filepath, output, 'utf8');
- }
- return output;
-}
-
-export { prettierFormat };
diff --git a/internal/tailwind-config/package.json b/internal/tailwind-config/package.json
deleted file mode 100644
index 16016fd0d..000000000
--- a/internal/tailwind-config/package.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "name": "@vben/tailwind-config",
- "version": "5.6.0",
- "private": true,
- "homepage": "https://github.com/vbenjs/vue-vben-admin",
- "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
- "directory": "internal/tailwind-config"
- },
- "license": "MIT",
- "type": "module",
- "scripts": {
- "stub": "pnpm unbuild --stub"
- },
- "files": [
- "dist"
- ],
- "main": "./dist/index.mjs",
- "module": "./dist/index.mjs",
- "types": "./dist/index.d.ts",
- "typesVersions": {
- "*": {
- "*": [
- "./dist/*",
- "./*"
- ]
- }
- },
- "exports": {
- ".": {
- "types": "./src/index.ts",
- "import": "./dist/index.mjs",
- "require": "./dist/index.cjs"
- },
- "./postcss": {
- "types": "./src/postcss.config.ts",
- "import": "./dist/postcss.config.mjs",
- "require": "./dist/postcss.config.cjs",
- "default": "./dist/postcss.config.mjs"
- },
- "./*": "./*"
- },
- "peerDependencies": {
- "tailwindcss": "^3.4.3"
- },
- "dependencies": {
- "@iconify/json": "catalog:",
- "@iconify/tailwind": "catalog:",
- "@manypkg/get-packages": "catalog:",
- "@tailwindcss/nesting": "catalog:",
- "@tailwindcss/typography": "catalog:",
- "autoprefixer": "catalog:",
- "cssnano": "catalog:",
- "jiti": "catalog:",
- "postcss": "catalog:",
- "postcss-antd-fixes": "catalog:",
- "postcss-import": "catalog:",
- "postcss-preset-env": "catalog:",
- "tailwindcss": "catalog:",
- "tailwindcss-animate": "catalog:"
- },
- "devDependencies": {
- "@types/postcss-import": "catalog:"
- }
-}
diff --git a/internal/tailwind-config/src/index.ts b/internal/tailwind-config/src/index.ts
deleted file mode 100644
index 17fae7dc4..000000000
--- a/internal/tailwind-config/src/index.ts
+++ /dev/null
@@ -1,266 +0,0 @@
-import type { Config } from 'tailwindcss';
-
-import path from 'node:path';
-
-import { addDynamicIconSelectors } from '@iconify/tailwind';
-import { getPackagesSync } from '@manypkg/get-packages';
-import typographyPlugin from '@tailwindcss/typography';
-import animate from 'tailwindcss-animate';
-
-import { enterAnimationPlugin } from './plugins/entry';
-
-// import defaultTheme from 'tailwindcss/defaultTheme';
-
-const { packages } = getPackagesSync(process.cwd());
-
-const tailwindPackages: string[] = [];
-
-packages.forEach((pkg) => {
- // apps目录下和 @vben-core/tailwind-ui 包需要使用到 tailwindcss ui
- // if (fs.existsSync(path.join(pkg.dir, 'tailwind.config.mjs'))) {
- tailwindPackages.push(pkg.dir);
- // }
-});
-
-const shadcnUiColors = {
- accent: {
- DEFAULT: 'hsl(var(--accent))',
- foreground: 'hsl(var(--accent-foreground))',
- hover: 'hsl(var(--accent-hover))',
- lighter: 'has(val(--accent-lighter))',
- },
- background: {
- deep: 'hsl(var(--background-deep))',
- DEFAULT: 'hsl(var(--background))',
- },
- border: {
- DEFAULT: 'hsl(var(--border))',
- },
- card: {
- DEFAULT: 'hsl(var(--card))',
- foreground: 'hsl(var(--card-foreground))',
- },
- destructive: {
- ...createColorsPalette('destructive'),
- DEFAULT: 'hsl(var(--destructive))',
- },
-
- foreground: {
- DEFAULT: 'hsl(var(--foreground))',
- },
-
- input: {
- background: 'hsl(var(--input-background))',
- DEFAULT: 'hsl(var(--input))',
- },
- muted: {
- DEFAULT: 'hsl(var(--muted))',
- foreground: 'hsl(var(--muted-foreground))',
- },
- popover: {
- DEFAULT: 'hsl(var(--popover))',
- foreground: 'hsl(var(--popover-foreground))',
- },
- primary: {
- ...createColorsPalette('primary'),
- DEFAULT: 'hsl(var(--primary))',
- },
-
- ring: 'hsl(var(--ring))',
- secondary: {
- DEFAULT: 'hsl(var(--secondary))',
- desc: 'hsl(var(--secondary-desc))',
- foreground: 'hsl(var(--secondary-foreground))',
- },
-};
-
-const customColors = {
- green: {
- ...createColorsPalette('green'),
- foreground: 'hsl(var(--success-foreground))',
- },
- header: {
- DEFAULT: 'hsl(var(--header))',
- },
- heavy: {
- DEFAULT: 'hsl(var(--heavy))',
- foreground: 'hsl(var(--heavy-foreground))',
- },
- main: {
- DEFAULT: 'hsl(var(--main))',
- },
- overlay: {
- content: 'hsl(var(--overlay-content))',
- DEFAULT: 'hsl(var(--overlay))',
- },
- red: {
- ...createColorsPalette('red'),
- foreground: 'hsl(var(--destructive-foreground))',
- },
- sidebar: {
- deep: 'hsl(var(--sidebar-deep))',
- DEFAULT: 'hsl(var(--sidebar))',
- },
- success: {
- ...createColorsPalette('success'),
- DEFAULT: 'hsl(var(--success))',
- },
- warning: {
- ...createColorsPalette('warning'),
- DEFAULT: 'hsl(var(--warning))',
- },
- yellow: {
- ...createColorsPalette('yellow'),
- foreground: 'hsl(var(--warning-foreground))',
- },
-};
-
-export default {
- content: [
- './index.html',
- ...tailwindPackages.map((item) =>
- path.join(item, 'src/**/*.{vue,js,ts,jsx,tsx,svelte,astro,html}'),
- ),
- ],
- darkMode: 'selector',
- plugins: [
- animate,
- typographyPlugin,
- addDynamicIconSelectors(),
- enterAnimationPlugin,
- ],
- prefix: '',
- safelist: ['dark'],
- theme: {
- container: {
- center: true,
- padding: '2rem',
- screens: {
- '2xl': '1400px',
- },
- },
- extend: {
- animation: {
- 'accordion-down': 'accordion-down 0.2s ease-out',
- 'accordion-up': 'accordion-up 0.2s ease-out',
- 'collapsible-down': 'collapsible-down 0.2s ease-in-out',
- 'collapsible-up': 'collapsible-up 0.2s ease-in-out',
- float: 'float 5s linear 0ms infinite',
- },
-
- animationDuration: {
- '2000': '2000ms',
- '3000': '3000ms',
- },
- borderRadius: {
- lg: 'var(--radius)',
- md: 'calc(var(--radius) - 2px)',
- sm: 'calc(var(--radius) - 4px)',
- xl: 'calc(var(--radius) + 4px)',
- },
- boxShadow: {
- float: `0 6px 16px 0 rgb(0 0 0 / 8%),
- 0 3px 6px -4px rgb(0 0 0 / 12%),
- 0 9px 28px 8px rgb(0 0 0 / 5%)`,
- },
- colors: {
- ...customColors,
- ...shadcnUiColors,
- },
- fontFamily: {
- sans: [
- 'var(--font-family)',
- // ...defaultTheme.fontFamily.sans
- ],
- },
- keyframes: {
- 'accordion-down': {
- from: { height: '0' },
- to: { height: 'var(--reka-accordion-content-height)' },
- },
- 'accordion-up': {
- from: { height: 'var(--reka-accordion-content-height)' },
- to: { height: '0' },
- },
- 'collapsible-down': {
- from: { height: '0' },
- to: { height: 'var(--reka-collapsible-content-height)' },
- },
- 'collapsible-up': {
- from: { height: 'var(--reka-collapsible-content-height)' },
- to: { height: '0' },
- },
- float: {
- '0%': { transform: 'translateY(0)' },
- '50%': { transform: 'translateY(-20px)' },
- '100%': { transform: 'translateY(0)' },
- },
- },
- zIndex: {
- '100': '100',
- '1000': '1000',
- },
- },
- },
-} as Config;
-
-function createColorsPalette(name: string) {
- // backgroundLightest: '#EFF6FF', // Tailwind CSS 默认的 `blue-50`
- // backgroundLighter: '#DBEAFE', // Tailwind CSS 默认的 `blue-100`
- // backgroundLight: '#BFDBFE', // Tailwind CSS 默认的 `blue-200`
- // borderLight: '#93C5FD', // Tailwind CSS 默认的 `blue-300`
- // border: '#60A5FA', // Tailwind CSS 默认的 `blue-400`
- // main: '#3B82F6', // Tailwind CSS 默认的 `blue-500`
- // hover: '#2563EB', // Tailwind CSS 默认的 `blue-600`
- // active: '#1D4ED8', // Tailwind CSS 默认的 `blue-700`
- // backgroundDark: '#1E40AF', // Tailwind CSS 默认的 `blue-800`
- // backgroundDarker: '#1E3A8A', // Tailwind CSS 默认的 `blue-900`
- // backgroundDarkest: '#172554', // Tailwind CSS 默认的 `blue-950`
-
- // • backgroundLightest (#EFF6FF): 适用于最浅的背景色,可能用于非常轻微的阴影或卡片的背景。
- // • backgroundLighter (#DBEAFE): 适用于略浅的背景色,通常用于次要背景或略浅的区域。
- // • backgroundLight (#BFDBFE): 适用于浅色背景,可能用于输入框或表单区域的背景。
- // • borderLight (#93C5FD): 适用于浅色边框,可能用于输入框或卡片的边框。
- // • border (#60A5FA): 适用于普通边框,可能用于按钮或卡片的边框。
- // • main (#3B82F6): 适用于主要的主题色,通常用于按钮、链接或主要的强调色。
- // • hover (#2563EB): 适用于鼠标悬停状态下的颜色,例如按钮悬停时的背景色或边框色。
- // • active (#1D4ED8): 适用于激活状态下的颜色,例如按钮按下时的背景色或边框色。
- // • backgroundDark (#1E40AF): 适用于深色背景,可能用于主要按钮或深色卡片背景。
- // • backgroundDarker (#1E3A8A): 适用于更深的背景,通常用于头部导航栏或页脚。
- // • backgroundDarkest (#172554): 适用于最深的背景,可能用于非常深色的区域或极端对比色。
-
- return {
- 50: `hsl(var(--${name}-50))`,
- 100: `hsl(var(--${name}-100))`,
- 200: `hsl(var(--${name}-200))`,
- 300: `hsl(var(--${name}-300))`,
- 400: `hsl(var(--${name}-400))`,
- 500: `hsl(var(--${name}-500))`,
- 600: `hsl(var(--${name}-600))`,
- 700: `hsl(var(--${name}-700))`,
- // 800: `hsl(var(--${name}-800))`,
- // 900: `hsl(var(--${name}-900))`,
- // 950: `hsl(var(--${name}-950))`,
- // 激活状态下的颜色,适用于按钮按下时的背景色或边框色。
- active: `hsl(var(--${name}-700))`,
- // 浅色背景,适用于输入框或表单区域的背景。
- 'background-light': `hsl(var(--${name}-200))`,
- // 适用于略浅的背景色,通常用于次要背景或略浅的区域。
- 'background-lighter': `hsl(var(--${name}-100))`,
- // 最浅的背景色,适用于非常轻微的阴影或卡片的背景。
- 'background-lightest': `hsl(var(--${name}-50))`,
- // 适用于普通边框,可能用于按钮或卡片的边框。
- border: `hsl(var(--${name}-400))`,
- // 浅色边框,适用于输入框或卡片的边框。
- 'border-light': `hsl(var(--${name}-300))`,
- foreground: `hsl(var(--${name}-foreground))`,
- // 鼠标悬停状态下的颜色,适用于按钮悬停时的背景色或边框色。
- hover: `hsl(var(--${name}-600))`,
- // 主色文本
- text: `hsl(var(--${name}-500))`,
- // 主色文本激活态
- 'text-active': `hsl(var(--${name}-700))`,
- // 主色文本悬浮态
- 'text-hover': `hsl(var(--${name}-600))`,
- };
-}
diff --git a/internal/tailwind-config/src/module.d.ts b/internal/tailwind-config/src/module.d.ts
deleted file mode 100644
index a3996533f..000000000
--- a/internal/tailwind-config/src/module.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-declare module '@tailwindcss/nesting' {
- export default any;
-}
diff --git a/internal/tailwind-config/src/plugins/entry.ts b/internal/tailwind-config/src/plugins/entry.ts
deleted file mode 100644
index 0d8e8ec80..000000000
--- a/internal/tailwind-config/src/plugins/entry.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import plugin from 'tailwindcss/plugin.js';
-
-const enterAnimationPlugin = plugin(({ addUtilities }) => {
- const maxChild = 5;
- const utilities: Record = {};
- for (let i = 1; i <= maxChild; i++) {
- const baseDelay = 0.1;
- const delay = `${baseDelay * i}s`;
-
- utilities[`.enter-x:nth-child(${i})`] = {
- animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`,
- opacity: '0',
- transform: `translateX(50px)`,
- };
-
- utilities[`.enter-y:nth-child(${i})`] = {
- animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`,
- opacity: '0',
- transform: `translateY(50px)`,
- };
-
- utilities[`.-enter-x:nth-child(${i})`] = {
- animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`,
- opacity: '0',
- transform: `translateX(-50px)`,
- };
-
- utilities[`.-enter-y:nth-child(${i})`] = {
- animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`,
- opacity: '0',
- transform: `translateY(-50px)`,
- };
- }
-
- // 添加动画关键帧
- addUtilities(utilities);
- addUtilities({
- '@keyframes enter-x-animation': {
- to: {
- opacity: '1',
- transform: 'translateX(0)',
- },
- },
- '@keyframes enter-y-animation': {
- to: {
- opacity: '1',
- transform: 'translateY(0)',
- },
- },
- });
-});
-
-export { enterAnimationPlugin };
diff --git a/internal/tailwind-config/src/postcss.config.ts b/internal/tailwind-config/src/postcss.config.ts
deleted file mode 100644
index 43309346b..000000000
--- a/internal/tailwind-config/src/postcss.config.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import config from '.';
-
-export default {
- plugins: {
- ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
- // Specifying the config is not necessary in most cases, but it is included
- autoprefixer: {},
- // 修复 element-plus 和 antdv-next 的样式和tailwindcss冲突问题
- 'postcss-antd-fixes': { prefixes: ['ant', 'el'] },
- 'postcss-import': {},
- 'postcss-preset-env': {},
- tailwindcss: { config },
- 'tailwindcss/nesting': {},
- },
-};
diff --git a/internal/tsconfig/base.json b/internal/tsconfig/base.json
index 1e45a7843..132806b51 100644
--- a/internal/tsconfig/base.json
+++ b/internal/tsconfig/base.json
@@ -8,7 +8,6 @@
"moduleDetection": "force",
"experimentalDecorators": true,
- "baseUrl": ".",
"module": "ESNext",
"moduleResolution": "node",
diff --git a/internal/tsconfig/node.json b/internal/tsconfig/node.json
index 01bde7a78..409dd7268 100644
--- a/internal/tsconfig/node.json
+++ b/internal/tsconfig/node.json
@@ -5,7 +5,6 @@
"compilerOptions": {
"composite": false,
"lib": ["ESNext"],
- "baseUrl": "./",
"moduleResolution": "bundler",
"types": ["node"],
"noImplicitAny": true
diff --git a/internal/tsconfig/package.json b/internal/tsconfig/package.json
index 59bff7ca1..6370b3aa8 100644
--- a/internal/tsconfig/package.json
+++ b/internal/tsconfig/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben/tsconfig",
- "version": "5.6.0",
+ "version": "5.7.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
diff --git a/internal/vite-config/package.json b/internal/vite-config/package.json
index 445cbf248..d8e87d11b 100644
--- a/internal/vite-config/package.json
+++ b/internal/vite-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben/vite-config",
- "version": "5.6.0",
+ "version": "5.7.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
@@ -29,6 +29,7 @@
"dependencies": {
"@intlify/unplugin-vue-i18n": "catalog:",
"@jspm/generator": "catalog:",
+ "@tailwindcss/vite": "catalog:",
"archiver": "catalog:",
"cheerio": "catalog:",
"get-port": "catalog:",
@@ -50,6 +51,7 @@
"rollup": "catalog:",
"rollup-plugin-visualizer": "catalog:",
"sass": "catalog:",
+ "sass-embedded": "catalog:",
"vite": "catalog:",
"vite-plugin-compression": "catalog:",
"vite-plugin-dts": "catalog:",
diff --git a/internal/vite-config/src/config/application.ts b/internal/vite-config/src/config/application.ts
index f437082e5..3c10408ad 100644
--- a/internal/vite-config/src/config/application.ts
+++ b/internal/vite-config/src/config/application.ts
@@ -6,7 +6,7 @@ import path, { relative } from 'node:path';
import { findMonorepoRoot } from '@vben/node-utils';
-import { NodePackageImporter } from 'sass';
+import { NodePackageImporter } from 'sass-embedded';
import { defineConfig, loadEnv, mergeConfig } from 'vite';
import { defaultImportmapOptions, getDefaultPwaOptions } from '../options';
@@ -58,7 +58,7 @@ function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
const applicationConfig: UserConfig = {
base,
build: {
- rollupOptions: {
+ rolldownOptions: {
output: {
assetFileNames: '[ext]/[name]-[hash].[ext]',
chunkFileNames: 'js/[name]-[hash].js',
@@ -67,20 +67,18 @@ function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
manualChunks: {
'antdv-next': ['antdv-next'],
},
+ minify: isBuild
+ ? {
+ compress: {
+ dropDebugger: true,
+ },
+ }
+ : false,
},
},
target: 'es2015',
},
css: createCssOptions(injectGlobalScss),
- esbuild: {
- drop: isBuild
- ? [
- // 'console',
- 'debugger',
- ]
- : [],
- legalComments: 'none',
- },
plugins,
server: {
host: true,
@@ -96,10 +94,7 @@ function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
},
};
- const mergedCommonConfig = mergeConfig(
- await getCommonConfig(),
- applicationConfig,
- );
+ const mergedCommonConfig = mergeConfig(await getCommonConfig(), applicationConfig);
return mergeConfig(mergedCommonConfig, vite);
});
}
diff --git a/internal/vite-config/src/config/library.ts b/internal/vite-config/src/config/library.ts
index 08b813520..623229fcd 100644
--- a/internal/vite-config/src/config/library.ts
+++ b/internal/vite-config/src/config/library.ts
@@ -40,7 +40,7 @@ function defineLibraryConfig(userConfigPromise?: DefineLibraryOptions) {
fileName: () => 'index.mjs',
formats: ['es'],
},
- rollupOptions: {
+ rolldownOptions: {
external: (id) => {
return externalPackages.some(
(pkg) => id === pkg || id.startsWith(`${pkg}/`),
diff --git a/internal/vite-config/src/plugins/index.ts b/internal/vite-config/src/plugins/index.ts
index da08db4b8..114d4d837 100644
--- a/internal/vite-config/src/plugins/index.ts
+++ b/internal/vite-config/src/plugins/index.ts
@@ -8,6 +8,7 @@ import type {
} from '../typing';
import viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
+import tailwindcss from '@tailwindcss/vite';
import viteVue from '@vitejs/plugin-vue';
import viteVueJsx from '@vitejs/plugin-vue-jsx';
import { visualizer as viteVisualizerPlugin } from 'rollup-plugin-visualizer';
@@ -25,6 +26,7 @@ import { viteMetadataPlugin } from './inject-metadata';
import { viteLicensePlugin } from './license';
import { viteNitroMockPlugin } from './nitro-mock';
import { vitePrintPlugin } from './print';
+import { viteTailwindReferencePlugin } from './tailwind-reference';
import { viteVxeTableImportsPlugin } from './vxe-table';
/**
@@ -60,6 +62,8 @@ async function loadCommonPlugins(
},
}),
viteVueJsx(),
+ viteTailwindReferencePlugin(),
+ tailwindcss(),
],
},
@@ -73,11 +77,13 @@ async function loadCommonPlugins(
},
{
condition: isBuild && !!visualizer,
- plugins: () => [viteVisualizerPlugin({
+ plugins: () => [
+ viteVisualizerPlugin({
filename: './node_modules/.cache/visualizer/stats.html',
gzipSize: true,
open: true,
- })],
+ }) as PluginOption,
+ ],
},
];
}
diff --git a/internal/vite-config/src/plugins/tailwind-reference.ts b/internal/vite-config/src/plugins/tailwind-reference.ts
new file mode 100644
index 000000000..8c3185125
--- /dev/null
+++ b/internal/vite-config/src/plugins/tailwind-reference.ts
@@ -0,0 +1,40 @@
+import type { Plugin } from 'vite';
+
+const REFERENCE_LINE = '@reference "@vben-core/design/theme";\n';
+
+/**
+ * Auto-inject @reference into Vue SFC
diff --git a/packages/@core/ui-kit/menu-ui/src/sub-menu.vue b/packages/@core/ui-kit/menu-ui/src/sub-menu.vue
index e4d471fb0..f84e5f818 100644
--- a/packages/@core/ui-kit/menu-ui/src/sub-menu.vue
+++ b/packages/@core/ui-kit/menu-ui/src/sub-menu.vue
@@ -4,7 +4,6 @@ import type { MenuRecordRaw } from '@vben-core/typings';
import { computed } from 'vue';
import { MenuBadge, MenuItem, SubMenu as SubMenuComp } from './components';
-// eslint-disable-next-line import/no-self-import
import SubMenu from './sub-menu.vue';
interface Props {
@@ -41,6 +40,7 @@ const hasChildren = computed(() => {
:badge-variants="menu.badgeVariants"
:icon="menu.icon"
:path="menu.path"
+ :query="menu.query"
>
{{ menu.name }}
diff --git a/packages/@core/ui-kit/menu-ui/src/types.ts b/packages/@core/ui-kit/menu-ui/src/types.ts
index b1f16f8b5..db0964b3b 100644
--- a/packages/@core/ui-kit/menu-ui/src/types.ts
+++ b/packages/@core/ui-kit/menu-ui/src/types.ts
@@ -1,6 +1,7 @@
-import type { MenuRecordBadgeRaw, ThemeModeType } from '@vben-core/typings';
import type { Component, Ref } from 'vue';
+import type { MenuRecordBadgeRaw, Recordable, ThemeModeType } from '@vben-core/typings';
+
interface MenuProps {
/**
* @zh_CN 是否开启手风琴模式
@@ -90,12 +91,17 @@ interface MenuItemProps extends MenuRecordBadgeRaw {
* @zh_CN menuitem 名称
*/
path: string;
+ /**
+ * @zh_CN 菜单所携带的参数
+ */
+ query?: Recordable;
}
interface MenuItemRegistered {
active: boolean;
parentPaths: string[];
path: string;
+ query?: Recordable;
}
interface MenuItemClicked {
diff --git a/packages/@core/ui-kit/menu-ui/tailwind.config.mjs b/packages/@core/ui-kit/menu-ui/tailwind.config.mjs
deleted file mode 100644
index f17f556fa..000000000
--- a/packages/@core/ui-kit/menu-ui/tailwind.config.mjs
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@vben/tailwind-config';
diff --git a/packages/@core/ui-kit/popup-ui/package.json b/packages/@core/ui-kit/popup-ui/package.json
index 338da305f..fb885d3a5 100644
--- a/packages/@core/ui-kit/popup-ui/package.json
+++ b/packages/@core/ui-kit/popup-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben-core/popup-ui",
- "version": "5.6.0",
+ "version": "5.7.0",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
diff --git a/packages/@core/ui-kit/popup-ui/postcss.config.mjs b/packages/@core/ui-kit/popup-ui/postcss.config.mjs
deleted file mode 100644
index 3d8070455..000000000
--- a/packages/@core/ui-kit/popup-ui/postcss.config.mjs
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@vben/tailwind-config/postcss';
diff --git a/packages/@core/ui-kit/popup-ui/src/alert/alert.vue b/packages/@core/ui-kit/popup-ui/src/alert/alert.vue
index 6b52a1121..57af6ac37 100644
--- a/packages/@core/ui-kit/popup-ui/src/alert/alert.vue
+++ b/packages/@core/ui-kit/popup-ui/src/alert/alert.vue
@@ -147,7 +147,7 @@ async function handleOpenChange(val: boolean) {
:class="
cn(
containerClass,
- 'left-0 right-0 mx-auto flex max-h-[80%] flex-col p-0 duration-300 sm:w-[520px] sm:max-w-[80%] sm:rounded-[var(--radius)]',
+ 'inset-x-0 mx-auto flex max-h-[80%] flex-col p-0 duration-300 sm:w-130 sm:max-w-[80%] sm:rounded-(--radius)',
{
'border border-border': bordered,
'shadow-3xl': !bordered,
@@ -174,7 +174,7 @@ async function handleOpenChange(val: boolean) {
-
+
diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts b/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts
index 365a2e4a0..8420bb9cb 100644
--- a/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts
+++ b/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts
@@ -13,21 +13,20 @@ vi.mock('@vben-core/shared/store', () => {
return this._state;
}
private _state: DrawerState;
+ private subscribers: Array<(state: DrawerState) => void> = [];
- private options: any;
-
- constructor(initialState: DrawerState, options: any) {
+ constructor(initialState: DrawerState) {
this._state = initialState;
- this.options = options;
- }
-
- batch(cb: () => void) {
- cb();
}
setState(fn: (prev: DrawerState) => DrawerState) {
this._state = fn(this._state);
- this.options.onUpdate();
+ this.subscribers.forEach((sub) => sub(this._state));
+ }
+
+ subscribe(fn: (state: DrawerState) => void) {
+ this.subscribers.push(fn);
+ return { unsubscribe: () => {} };
}
},
};
diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts b/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts
index c97108f92..e77dc47d2 100644
--- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts
+++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts
@@ -56,23 +56,18 @@ export class DrawerApi {
title: '',
};
- this.store = new Store
(
- {
- ...defaultState,
- ...storeState,
- },
- {
- onUpdate: () => {
- const state = this.store.state;
- if (state?.isOpen === this.state?.isOpen) {
- this.state = state;
- } else {
- this.state = state;
- this.api.onOpenChange?.(!!state?.isOpen);
- }
- },
- },
- );
+ this.store = new Store({
+ ...defaultState,
+ ...storeState,
+ });
+
+ this.store.subscribe((state) => {
+ const prevIsOpen = this.state?.isOpen;
+ this.state = state;
+ if (state?.isOpen !== prevIsOpen) {
+ this.api.onOpenChange?.(!!state?.isOpen);
+ }
+ });
this.state = this.store.state;
this.api = {
onBeforeClose,
diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue
index ef7efbcb4..f04dc9777 100644
--- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue
+++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue
@@ -186,9 +186,9 @@ const getForceMount = computed(() => {
{
v-if="showHeader"
:class="
cn(
- '!flex flex-row items-center justify-between border-b px-6 py-5',
+ 'flex! flex-row items-center justify-between border-b px-6 py-5',
headerClass,
{
'px-4 py-3': closable,
@@ -225,7 +225,7 @@ const getForceMount = computed(() => {
v-if="closable && closeIconPlacement === 'left'"
as-child
:disabled="submitting"
- class="ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none data-[state=open]:bg-secondary"
+ class="ml-0.5 cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary"
>
@@ -235,7 +235,7 @@ const getForceMount = computed(() => {
@@ -266,7 +266,7 @@ const getForceMount = computed(() => {
v-if="closable && closeIconPlacement === 'right'"
as-child
:disabled="submitting"
- class="ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none data-[state=open]:bg-secondary"
+ class="ml-0.5 cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary"
>
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts b/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts
index aa5a6329c..1bc615923 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts
+++ b/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts
@@ -8,25 +8,25 @@ vi.mock('@vben-core/shared/store', () => {
return {
isFunction: (fn: any) => typeof fn === 'function',
Store: class {
- private _state: ModalState;
- private options: any;
-
- constructor(initialState: ModalState, options: any) {
- this._state = initialState;
- this.options = options;
+ get state() {
+ return this._state;
}
+ private _state: ModalState;
- batch(cb: () => void) {
- cb();
+ private subscribers: Array<(state: ModalState) => void> = [];
+
+ constructor(initialState: ModalState) {
+ this._state = initialState;
}
setState(fn: (prev: ModalState) => ModalState) {
this._state = fn(this._state);
- this.options.onUpdate();
+ this.subscribers.forEach((sub) => sub(this._state));
}
- get state() {
- return this._state;
+ subscribe(fn: (state: ModalState) => void) {
+ this.subscribers.push(fn);
+ return { unsubscribe: () => {} };
}
},
};
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts b/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
index 9d879da26..74758913d 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
+++ b/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
@@ -62,25 +62,19 @@ export class ModalApi {
animationType: 'slide',
};
- this.store = new Store(
- {
- ...defaultState,
- ...storeState,
- },
- {
- onUpdate: () => {
- const state = this.store.state;
+ this.store = new Store({
+ ...defaultState,
+ ...storeState,
+ });
- // 每次更新状态时,都会调用 onOpenChange 回调函数
- if (state?.isOpen === this.state?.isOpen) {
- this.state = state;
- } else {
- this.state = state;
- this.api.onOpenChange?.(!!state?.isOpen);
- }
- },
- },
- );
+ this.store.subscribe((state) => {
+ // 每次更新状态时,都会调用 onOpenChange 回调函数
+ const prevIsOpen = this.state?.isOpen;
+ this.state = state;
+ if (state?.isOpen !== prevIsOpen) {
+ this.api.onOpenChange?.(!!state?.isOpen);
+ }
+ });
this.state = this.store.state;
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
index fa41344ee..4debaff4b 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
+++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
@@ -1,6 +1,6 @@
import type { Component, Ref } from 'vue';
-import type { MaybePromise } from '@vben-core/typings';
+import type { ClassType, MaybePromise } from '@vben-core/typings';
import type { ModalApi } from './modal-api';
@@ -30,7 +30,7 @@ export interface ModalProps {
*/
centered?: boolean;
- class?: string;
+ class?: ClassType;
/**
* 是否显示右上角的关闭按钮
@@ -60,7 +60,7 @@ export interface ModalProps {
* 确定按钮文字
*/
confirmText?: string;
- contentClass?: string;
+ contentClass?: ClassType;
/**
* 弹窗描述
*/
@@ -79,7 +79,7 @@ export interface ModalProps {
* @default true
*/
footer?: boolean;
- footerClass?: string;
+ footerClass?: ClassType;
/**
* 是否全屏
* @default false
@@ -95,7 +95,7 @@ export interface ModalProps {
* @default true
*/
header?: boolean;
- headerClass?: string;
+ headerClass?: ClassType;
/**
* 弹窗是否显示
* @default false
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
index e93e4c12d..f63d86018 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
+++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
@@ -240,14 +240,13 @@ function handleClosed() {
:append-to="getAppendTo"
:class="
cn(
- 'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col p-0',
- shouldFullscreen ? 'sm:rounded-none' : 'sm:rounded-[var(--radius)]',
+ 'inset-x-0 top-[10vh] mx-auto flex max-h-[80%] w-130 flex-col p-0',
+ shouldFullscreen ? 'sm:rounded-none' : 'sm:rounded-(--radius)',
modalClass,
{
'border border-border': bordered,
'shadow-3xl': !bordered,
- 'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':
- shouldFullscreen,
+ 'top-0 left-0 size-full max-h-full translate-0!': shouldFullscreen,
'top-1/2': centered && !shouldFullscreen,
'duration-300': !dragging,
hidden: isClosed,
@@ -320,7 +319,7 @@ function handleClosed() {
diff --git a/packages/@core/ui-kit/popup-ui/tailwind.config.mjs b/packages/@core/ui-kit/popup-ui/tailwind.config.mjs
deleted file mode 100644
index f17f556fa..000000000
--- a/packages/@core/ui-kit/popup-ui/tailwind.config.mjs
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@vben/tailwind-config';
diff --git a/packages/@core/ui-kit/shadcn-ui/components.json b/packages/@core/ui-kit/shadcn-ui/components.json
index b497f43c3..dcb1940fb 100644
--- a/packages/@core/ui-kit/shadcn-ui/components.json
+++ b/packages/@core/ui-kit/shadcn-ui/components.json
@@ -3,12 +3,11 @@
"style": "new-york",
"typescript": true,
"tailwind": {
- "config": "tailwind.config.mjs",
+ "config": "",
"css": "src/assets/index.css",
"baseColor": "slate",
"cssVariables": true
},
- "framework": "vite",
"aliases": {
"components": "@vben-core/shadcn-ui/components",
"utils": "@vben-core/shared/utils"
diff --git a/packages/@core/ui-kit/shadcn-ui/package.json b/packages/@core/ui-kit/shadcn-ui/package.json
index dacb41abf..f4f0136a1 100644
--- a/packages/@core/ui-kit/shadcn-ui/package.json
+++ b/packages/@core/ui-kit/shadcn-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@vben-core/shadcn-ui",
- "version": "5.6.0",
+ "version": "5.7.0",
"#main": "./dist/index.mjs",
"#module": "./dist/index.mjs",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
@@ -41,6 +41,7 @@
},
"dependencies": {
"@vben-core/composables": "workspace:*",
+ "@vben-core/design": "workspace:*",
"@vben-core/icons": "workspace:*",
"@vben-core/shared": "workspace:*",
"@vben-core/typings": "workspace:*",
diff --git a/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs b/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs
deleted file mode 100644
index 3d8070455..000000000
--- a/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@vben/tailwind-config/postcss';
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue b/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue
index 2b2ed2f2f..1db522bcd 100644
--- a/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue
@@ -60,7 +60,7 @@ const rootStyle = computed(() => {
@@ -69,7 +69,7 @@ const rootStyle = computed(() => {
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue b/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue
index 8da6cde42..9c9708502 100644
--- a/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue
@@ -32,7 +32,7 @@ const { handleClick, visible } = useBackTop(props);
{{ item.title }}
@@ -50,12 +50,14 @@ function handleClick(index: number, path?: string) {
diff --git a/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue b/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue
index a573f4490..fa2712f75 100644
--- a/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue
+++ b/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue
@@ -81,7 +81,7 @@ function onMouseDown(e: MouseEvent, tab: TabConfig) {