<p align="center">
  <a href="https://themusecatcher.github.io/vue-amazing-ui/">
    <img width="200" src="https://themusecatcher.github.io/vue-amazing-ui/amazing-logo.svg">
  </a>
</p>

<h1 align="center">Vue Amazing UI</h1>
<p align="center">A Vue 3 Component Library</p>
<p align="center"><b>Theme Customizable, Light and Dark Themes, Written in TypeScript and SFC, Tree Shaking</b></p>
<p align="center">Kinda Interesting</p>
<p align="center">
  <a href="https://www.npmjs.com/package/vue-amazing-ui"><img src="https://img.shields.io/npm/v/vue-amazing-ui" alt="npm version"></a>
  <a href="https://www.npmjs.com/package/vue-amazing-ui"><img src="https://img.shields.io/npm/dm/vue-amazing-ui" alt="npm downloads"></a>
  <a href="https://github.com/themusecatcher/vue-amazing-ui/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/vue-amazing-ui" alt="license"></a>
</p>
<p align="center">English | <a href="README.zh-CN.md">中文</a></p>

## Documentation

[Vue Amazing UI](https://themusecatcher.github.io/vue-amazing-ui/)

## Features

- Currently, it includes `73` basic UI components and `16` utility functions, with continuous exploration and updates ongoing...
- Theme Customizable, all you need is to provide a theme color, then all the stuffs will be done by me.
- Supports light and dark themes; switch them manually, or let them follow the system theme automatically.
- By the way, they are all tree-shakable.
- All the stuff in Vue Amazing UI is written in TypeScript. It can work with your typescript project seamlessly.
- All components are single file components (`SFC`), so the source code can be used directly.
- SSR-ready.
- Ready to use out of the box, no fuss.

## Installation

```sh
pnpm add vue-amazing-ui
# or
npm install vue-amazing-ui
# or
yarn add vue-amazing-ui
# or
bun add vue-amazing-ui
```

## Use Components

**Global Registration All Components (Not Recommended)**

_No tree-shaking. Bundle will have redundant codes._

```ts
import { createApp } from 'vue'
import App from './App.vue'
import VueAmazingUI from 'vue-amazing-ui'
import 'vue-amazing-ui/css'

const app = createApp(App)
app.use(VueAmazingUI)
app.mount('#app')
```

**Global Partial Registration**

_In this form, only the imported components will be bundled._

```ts
import { createApp } from 'vue'
import App from './App.vue'
import { Button, Tag } from 'vue-amazing-ui'
// One style entry per component (recommended form): global default styles + the component's own styles + its dependency components' styles
import 'vue-amazing-ui/es/button/style'
import 'vue-amazing-ui/es/tag/style'

const app = createApp(App)
app.use(Button).use(Tag)
app.mount('#app')
```

**Local Registration**

_In this form, only the imported components will be bundled as well._

```vue
<script setup lang="ts">
import { Button, Tag } from 'vue-amazing-ui'
// One style entry per component (recommended form): global default styles + the component's own styles + its dependency components' styles
import 'vue-amazing-ui/es/button/style'
import 'vue-amazing-ui/es/tag/style'
</script>
<template>
  <Button>button</Button>
  <Tag>tag</Tag>
</template>
```

> The style entry also supports the more explicit file form `import 'vue-amazing-ui/es/button/style/index.js'`.

**Automatic On-Demand Import (Strongly Recommended)**

Use the [`unplugin-vue-components`](https://github.com/unplugin/unplugin-vue-components) plugin to automatically import components on demand. The plugin will automatically parse the components used in the template and import the components and styles.

```sh
pnpm add unplugin-vue-components -D
# or
npm install unplugin-vue-components -D
# or
yarn add unplugin-vue-components -D
# or
bun add unplugin-vue-components -D
```

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
// vue-amazing-ui on-demand import
import { VueAmazingUIResolver } from 'vue-amazing-ui'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [
        // auto import components from VueAmazingUI
        VueAmazingUIResolver({
          cjs: false // whether use commonjs build, default false
        })
      ]
    })
  ]
})
```

Then, you can directly use all components from `vue-amazing-ui` in your code.

```vue
<template>
  <Button>button</Button>
  <Tag>tag</Tag>
</template>
```

## Use Types

_All types can be directly imported and used from `vue-amazing-ui` without any additional installation._

```vue
<script setup lang="ts">
import { ref } from 'vue'
import type { ButtonProps } from 'vue-amazing-ui'
const shape = ref<ButtonProps['shape']>('default')
</script>
<template>
  <Button :shape="shape">button</Button>
</template>
```

## Use Functions

```vue
<script setup lang="ts">
import {
  dateFormat,
  formatNumber,
  throttle,
  debounce,
  add,
  downloadFile,
  useEventListener,
  useMutationObserver,
  useScroll,
  useFps,
  useMediaQuery,
  useResizeObserver,
  useSlotsExist,
  useOptionsSupported,
  getScrollParent,
  useScrollParent
} from 'vue-amazing-ui'
</script>
```

## Browser Support

_Modern browsers only (`Chrome` / `Edge` / `Safari` / `Firefox`). `Opera Mini`, `KaiOS` and `IE` are not supported — the first two cannot run `Vue 3`._

- Requires `Vue >= 3.4`.
- Exact minimum versions are listed in [Browser Support](https://themusecatcher.github.io/vue-amazing-ui/guide/getting-started.html).
- A few visual enhancements rely on newer `CSS` features and degrade to an equivalent base layout on older engines, with functionality and accessibility unaffected.

## Project

Tech stack: `Vue@3.5.45` + `TypeScript@5.9.3` + `Vite@7.3.7` + `Less@4.9.1`

- Get the project code

```sh
git clone https://github.com/themusecatcher/vue-amazing-ui.git
```

- Install dependencies

```sh
cd vue-amazing-ui

pnpm i
```

- Run project

```sh
pnpm dev
```

- Run docs

```sh
pnpm docs:dev
```

## Contributing

`Vue Amazing UI` grows together with its community. Whether you are adding a component, fixing a bug, or improving the docs and examples, your contribution is always welcome.

Before submitting code, please read the [Contributing Guide](CONTRIBUTING.md).

## Blogs

[My CSDN Blogs](https://themusecatcher.blog.csdn.net)

## Sponsorship

`Vue Amazing UI` is an open-source project licensed under the `MIT` license, and it is completely free to use. All work on the component library and documentation is completed by the author alone, and the development and iteration process has been challenging. For the healthy and sustainable development of the component library, your support and sponsorship are greatly appreciated.

#### [Become a Sponsor](https://themusecatcher.github.io/vue-amazing-ui/sponsor/charge.html)

## Sponsors 🫡

All sponsors will be listed here, thank you very much for your support and sponsorship ❤️

<img width="64" height="64" src="./docs/public/avatar_1.jpeg" alt="WeChat@Ant" title="WeChat@Ant" /> <a href="https://github.com/nizhensh-i" target="_blank"><img width="64" height="64" src="./docs/public/avatar_2.jpg" alt="GitHub@nizhensh-i" title="GitHub@nizhensh-i"></a> <a href="https://github.com/beijin1949" target="_blank"><img width="64" height="64" src="./docs/public/avatar_3.png" alt="GitHub@beijin1949" title="GitHub@beijin1949"></a> <a href="https://github.com/JinZemin" target="_blank"><img width="64" height="64" src="./docs/public/avatar_4.png" alt="GitHub@JinZemin" title="GitHub@JinZemin"></a> <a href="https://github.com/ye5840" target="_blank"><img width="64" height="64" src="./docs/public/avatar_5.png" alt="GitHub@ye5840" title="GitHub@ye5840"></a><img width="64" height="64" src="./docs/public/avatar_6.jpg" alt="WeChat@**洋" title="WeChat@**洋"> <img width="64" height="64" src="./docs/public/avatar_default.svg" alt="WeChat@*梦" title="WeChat@*梦"> <img width="64" height="64" src="./docs/public/avatar_default.svg" alt="Alipay@**山" title="Alipay@**山">

## Components

| Name            | Description      | Name            | Description      | Name            | Description      |
| :-------------- | :--------------- | :-------------- | :--------------- | :-------------- | :--------------- |
| Alert           | Alert            | AutoComplete    | Auto Complete    | Avatar          | Avatar           |
| BackTop         | Back to Top      | Badge           | Badge            | Breadcrumb      | Breadcrumb       |
| Button          | Button           | Calendar        | Calendar         | Card            | Card             |
| Carousel        | Carousel         | Cascader        | Cascader         | Checkbox        | Checkbox         |
| Collapse        | Collapse         | ColorPicker     | Color Picker     | Comment         | Comment          |
| ConfigProvider  | Global Config    | Countdown       | Countdown        | DatePicker      | Date Picker      |
| Descriptions    | Descriptions     | Dialog          | Dialog           | Divider         | Divider          |
| Drawer          | Drawer           | Dropdown        | Dropdown         | Ellipsis        | Text Ellipsis    |
| Empty           | Empty State      | Flex            | Flex Layout      | FloatButton     | Float Button     |
| GradientText    | Gradient Text    | Grid            | Grid             | Highlight       | Highlight Text   |
| Image           | Image            | Input           | Input            | InputNumber     | Number Input     |
| InputSearch     | Search Input     | Layout          | Layout           | List            | List             |
| LoadingBar      | Loading Bar      | Menu            | Menu             | Message         | Global Message   |
| Modal           | Modal            | Notification    | Notification     | NumberAnimation | Number Animation |
| Pagination      | Pagination       | Popconfirm      | Popconfirm       | Popover         | Popover          |
| Progress        | Progress         | QRCode          | QR Code          | Radio           | Radio            |
| Rate            | Rating           | Result          | Result           | Scrollbar       | Scrollbar        |
| Segmented       | Segmented        | Select          | Select           | Skeleton        | Skeleton         |
| Slider          | Slider           | Space           | Spacing          | Spin            | Loading          |
| Statistic       | Statistic        | Steps           | Steps            | Swiper          | Swiper           |
| Switch          | Switch           | Table           | Table            | Tabs            | Tabs             |
| Tag             | Tag              | Textarea        | Textarea         | TextScroll      | Text Scroll      |
| Timeline        | Timeline         | TimePicker      | Time Picker      | Tooltip         | Tooltip          |
| Upload          | Upload           | Video           | Video Player     | Waterfall       | Waterfall        |
| Watermark       | Watermark        |                 |                  |                 |                  |

## Functions

| Name | Description | Type |
| :-- | :-- | :-- |
| dateFormat | Format date-time string function | (value: number &#124; string &#124; Date = Date.now(), format: string = 'YYYY-MM-DD HH:mm:ss') => string |
| formatNumber | Number formatting function | (value: number &#124; string, precision: number = 2, separator: string = ',', decimal: string = '.', prefix?: string, suffix?: string) => string |
| throttle | Throttle function | (fn: Function, delay: number = 300) => Function |
| debounce | Debounce function | (fn: Function, delay: number = 300) => Function |
| add | Addition function that eliminates precision issues in JavaScript arithmetic | (num1: number, num2: number) => number |
| downloadFile | Function to download a file with a custom filename, with built-in dual download strategies for same-origin `anchor` and cross-origin `iframe`; if no filename is provided, it extracts the filename from the URL | (url: string, fileName?: string, options?: { target?: '_self' &#124; '_blank'; strategy?: 'auto' &#124; 'anchor' &#124; 'iframe' }) => Promise&lt;void&gt; |
| useEventListener | Function to add and remove event listeners using Vue lifecycle hooks | (target: HTMLElement &#124; Window &#124; Document, event: string, callback: Function) => void |
| useMutationObserver | Function to observe changes in DOM elements using `MutationObserver` | (target: Ref &#124; Ref[] &#124; HTMLElement &#124; HTMLElement[], callback: MutationCallback, options: object = {}) => { start: \() => void, stop: \() => void } |
| useScroll | Function to monitor the scroll position, direction and edges of a target in real time | (target?: MaybeRefOrGetter\<HTMLElement &#124; Window &#124; Document &#124; null>, options?: UseScrollOptions) => { x: Ref\<number>, y: Ref\<number>, maxX: Ref\<number>, maxY: Ref\<number>, isScrolling: Ref\<boolean>, direction: Ref\<'left' &#124; 'right' &#124; 'top' &#124; 'bottom' &#124; null>, atLeft: Ref\<boolean>, atRight: Ref\<boolean>, atTop: Ref\<boolean>, atBottom: Ref\<boolean>, refresh: \() => void, start: \() => void, stop: \() => void } |
| useFps | Function to monitor the browser's refresh rate (FPS) in real time | () => { fps: Ref\<number> } |
| useMediaQuery | Function to determine if the current environment matches a specified media query condition | (mediaQuery: string) => { match: Ref\<boolean> } |
| useResizeObserver | Function to observe changes in the dimensions of DOM elements using `ResizeObserver` | (target: Ref &#124; Ref[] &#124; HTMLElement &#124; HTMLElement[], callback: ResizeObserverCallback, options: object = {}) => { start: \() => void, stop: \() => void } |
| useSlotsExist | Function to watch for the existence of slots with given names, supporting single slots or an array of slots | <T extends string &#124; string[] = 'default'>(slotsName: T) => T extends string ? ComputedRef\<boolean> : Reactive\<Record\<string, boolean>> |
| useOptionsSupported | Checks if the browser supports the given event listener options | (option: 'capture' &#124; 'once' &#124; 'passive' &#124; 'signal') => { isSupported: Ref\<boolean> } |
| getScrollParent | Function to find the nearest scrollable parent element upward | (el: HTMLElement &#124; null) => HTMLElement &#124; null |
| useScrollParent | Composable to query and watch the nearest scrollable parent element and respond to viewport `resize` | (contentRef: Ref\<HTMLElement &#124; null>, onScroll: () => void, options: ScrollParentOptions = {}) => { scrollTarget: Ref\<HTMLElement &#124; null>, viewportWidth: Ref\<number>, viewportHeight: Ref\<number>, observeScroll: \() => void, cleanup: \() => void } |
