mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-07 13:48:31 +08:00
commit
0678245cab
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,25 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
### Environment Info
|
||||
|
||||
- Naive UI version: (eg. 2.11.0)
|
||||
- Vue version: (eg. 3.0.11)
|
||||
- Browser Info: (eg. Chome 91)
|
||||
- System Info: (eg. Mac OS 11.2.3, Windows)
|
||||
|
||||
### Reproduction link
|
||||
|
||||
<!-- A CodeSandbox reproduction link is recommended. -->
|
||||
<!-- If CodeSandbox is not easy to reproduce your issue, please link a GitHub repo. -->
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
### What is expected?
|
||||
|
||||
### What is actually happening?
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Create new issue
|
||||
url: https://naive-ui.github.io/issue-helper/
|
||||
about: The issue which is not created via https://naive-ui.github.io/issue-helper/ will be closed immediately.
|
13
.github/ISSUE_TEMPLATE/feature_request.md
vendored
13
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,13 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## What problem does the feature solve?
|
||||
|
||||
## What does the proposed API look like?
|
||||
|
||||
## Some pictures that can demonstrate the feature.
|
@ -1,6 +1,25 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 2.11.8
|
||||
## 2.11.9 (2021-06-15)
|
||||
|
||||
### Feats
|
||||
|
||||
- `n-space` supports wai-aria.
|
||||
- `n-button-group` supports wai-aria.
|
||||
- `n-progress` supports wai-aria.
|
||||
- `n-menu` supports use `<a />` and `<router-link />` as label, closes [#84](https://github.com/TuSimple/naive-ui/issues/84).
|
||||
- `n-input-number` add `show-button` prop.
|
||||
- `n-rate` support `default` slot for icon customizing.
|
||||
- `n-rate` add color prop.
|
||||
- `n-rate` add size prop.
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix `n-card`'s `header-style` it not applied to header. [#103](https://github.com/TuSimple/naive-ui/issues/103)
|
||||
- Fix `n-dialog` misses `destroyAll` method.
|
||||
- Fix `n-data-table` misses `on-update-sorter`, `on-update-filters`, `on-update-page` and `on-update-page-size` props.
|
||||
|
||||
## 2.11.8 (2021-06-13)
|
||||
|
||||
### Feats
|
||||
|
||||
@ -12,7 +31,7 @@
|
||||
- Fix `n-form-item`'s style attribute `grid-template-columns` influence on the layout of child elements. [#93](https://github.com/TuSimple/naive-ui/pull/93)
|
||||
- Fix `n-data-table`'s prop types of `rowKey`, `rowClassName`, `rowProps`, `summary` aren't compatible with expected value.
|
||||
|
||||
## 2.11.7
|
||||
## 2.11.7 (2021-06-12)
|
||||
|
||||
### Fixes
|
||||
|
||||
@ -49,8 +68,8 @@
|
||||
- Fix `n-popover` sometimes won't sync position in manual mode.
|
||||
- Fix `n-transfer`'s empty icon is no toggling transition.
|
||||
- Fix `n-message` API option is not optional.
|
||||
- Fix `n-calendar` date calculate incorrectly
|
||||
- Fix `n-input` missing the `password` type declaration.
|
||||
- Fix `n-calendar` date calculate incorrectly.
|
||||
- Fix `n-input` misses the `password` type declaration.
|
||||
- Fix `n-menu` the type definition of `extra` property of menu and submenu.
|
||||
- Fix `n-dropdown` mouse cursor is not pointer.
|
||||
|
||||
@ -808,3 +827,7 @@ See vue3.md
|
||||
### Fixes
|
||||
|
||||
- Rails of `n-scrollbar` shadow mouse event.
|
||||
|
||||
### Features
|
||||
|
||||
- `n-date-table` add `empty` slot. [#86](https://github.com/TuSimple/naive-ui/issues/86)
|
||||
|
@ -1,6 +1,25 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 2.11.8
|
||||
## 2.11.9 (2021-06-15)
|
||||
|
||||
### Feats
|
||||
|
||||
- `n-space` 支持 wai-aria
|
||||
- `n-button-group` 支持 wai-aria
|
||||
- `n-progress` 支持 wai-aria
|
||||
- `n-menu` 支持使用 `<a />` 和 `<router-link />` 作为 label,关闭 [#84](https://github.com/TuSimple/naive-ui/issues/84)
|
||||
- `n-input-number` 新增 `show-button` 属性
|
||||
- `n-rate` 支持使用 default slot 自定义图标
|
||||
- `n-rate` 新增 color 属性
|
||||
- `n-rate` 新增 size 属性
|
||||
|
||||
### Fixes
|
||||
|
||||
- 修复 `n-card` 的 `header-style` 没有应用于 header 上 [#103](https://github.com/TuSimple/naive-ui/issues/103)
|
||||
- 修复 `n-dialog` 的 `destroyAll` 方法缺失
|
||||
- 修复 `n-data-table` 缺少 `on-update-sorter`、`on-update-filters`、`on-update-page`、`on-update-page-size` 属性
|
||||
|
||||
## 2.11.8 (2021-06-13)
|
||||
|
||||
### Feats
|
||||
|
||||
@ -12,7 +31,7 @@
|
||||
- 修复 `n-form-item` 的 `grid-template-columns` 样式属性对子元素布局的影响 [#93](https://github.com/TuSimple/naive-ui/pull/93)
|
||||
- 修复 `n-data-table` 的 `rowKey`, `rowClassName`, `rowProps`, `summary` 属性类型和期望值不兼容
|
||||
|
||||
## 2.11.7
|
||||
## 2.11.7 (2021-06-12)
|
||||
|
||||
### Fixes
|
||||
|
||||
@ -810,3 +829,7 @@
|
||||
### Fixes
|
||||
|
||||
- `n-scrollbar` 的轨道会挡住鼠标事件
|
||||
|
||||
### Features
|
||||
|
||||
- `n-data-table` 增加了 empty 插槽 [#86](https://github.com/TuSimple/naive-ui/issues/86)
|
||||
|
@ -26,7 +26,7 @@
|
||||
text
|
||||
tag="a"
|
||||
target="_blank"
|
||||
href="https://github.com/TuSimple/naive-ui/issues/new/choose"
|
||||
href="https://naive-ui.github.io/issue-helper/"
|
||||
>
|
||||
{{ t('reportBug') }}
|
||||
</n-button>
|
||||
|
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "naive-ui",
|
||||
"version": "2.11.8",
|
||||
"version": "2.11.9",
|
||||
"description": "A Vue 3 Component Library. Fairly Complete, Customizable Themes, Uses TypeScript, Not Too Slow",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
@ -22,7 +22,7 @@
|
||||
"test:cov": "cross-env NODE_ENV=test jest",
|
||||
"test:watch": "cross-env NODE_ENV=test jest ---watch --verbose --coverage",
|
||||
"gen-version": "node scripts/gen-version",
|
||||
"post-changelog": "node scripts/post-changelog",
|
||||
"release-changelog": "node scripts/release-changelog",
|
||||
"build:site:ts": "./scripts/pre-build-site/pre-build-site.sh && cross-env TUSIMPLE=true NODE_ENV=production NODE_OPTIONS=--max-old-space-size=4096 vite build && ./scripts/post-build-site/post-build-site.sh",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
@ -70,9 +70,9 @@
|
||||
"@types/jest": "^26.0.20",
|
||||
"@typescript-eslint/eslint-plugin": "^4.15.1",
|
||||
"@typescript-eslint/parser": "^4.15.1",
|
||||
"@vicons/fluent": "^0.8.0",
|
||||
"@vicons/ionicons4": "^0.8.0",
|
||||
"@vicons/ionicons5": "^0.8.0",
|
||||
"@vicons/fluent": "^0.9.0",
|
||||
"@vicons/ionicons4": "^0.9.0",
|
||||
"@vicons/ionicons5": "^0.9.0",
|
||||
"@vitejs/plugin-vue": "^1.2.1",
|
||||
"@vue/compiler-sfc": "^3.0.10",
|
||||
"@vue/eslint-config-standard": "^6.0.0",
|
||||
|
@ -1,46 +0,0 @@
|
||||
const request = require('superagent')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const inquirer = require('inquirer')
|
||||
|
||||
const { DINGTALK_TOKEN } = process.env
|
||||
|
||||
if (!DINGTALK_TOKEN) {
|
||||
console.log('No DINGTALK_TOKEN in your env.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const changelog = fs
|
||||
.readFileSync(path.resolve(__dirname, '../CHANGELOG.zh-CN.md'), 'utf-8')
|
||||
.split(/^## /gm)[1]
|
||||
.replace(/^##/gm, '')
|
||||
|
||||
const message = `变更日志 ${changelog}`
|
||||
|
||||
inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'post-changelog',
|
||||
message: `发布以下变更日志到钉钉群:\n\n${message}`
|
||||
}
|
||||
])
|
||||
.then((ans) => {
|
||||
if (ans['post-changelog']) {
|
||||
request
|
||||
.post('https://oapi.dingtalk.com/robot/send')
|
||||
.query({
|
||||
access_token: DINGTALK_TOKEN
|
||||
})
|
||||
.type('application/json')
|
||||
.send({
|
||||
msgtype: 'text',
|
||||
text: {
|
||||
content: message
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res.text)
|
||||
})
|
||||
}
|
||||
})
|
97
scripts/release-changelog.js
Normal file
97
scripts/release-changelog.js
Normal file
@ -0,0 +1,97 @@
|
||||
const request = require('superagent')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const inquirer = require('inquirer')
|
||||
|
||||
const { DINGTALK_TOKEN } = process.env
|
||||
|
||||
if (!DINGTALK_TOKEN) {
|
||||
console.log('No DINGTALK_TOKEN in your env.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const { DISCORD_TOKEN } = process.env
|
||||
|
||||
if (!DISCORD_TOKEN) {
|
||||
console.error('No DISCORD_TOKEN in your env.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
async function releaseChangelogToDingTalk () {
|
||||
const changelog = fs
|
||||
.readFileSync(path.resolve(__dirname, '../CHANGELOG.zh-CN.md'), 'utf-8')
|
||||
.split(/^## /gm)[1]
|
||||
.replace(/^##/gm, '')
|
||||
.replace(/\[([^\]]+)\]\([^)]+\)/g, '[$1]')
|
||||
|
||||
const message = `变更日志 ${changelog.trim()}\n\n完整信息见 https://github.com/TuSimple/naive-ui/blob/main/CHANGELOG.zh-CN.md\n`
|
||||
|
||||
await inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'release-changelog',
|
||||
message: `发布以下变更日志到钉钉群:\n\n${message}`
|
||||
}
|
||||
])
|
||||
.then((ans) => {
|
||||
if (ans['release-changelog']) {
|
||||
request
|
||||
.post('https://oapi.dingtalk.com/robot/send')
|
||||
.query({
|
||||
access_token: DINGTALK_TOKEN
|
||||
})
|
||||
.type('application/json')
|
||||
.send({
|
||||
msgtype: 'text',
|
||||
text: {
|
||||
content: message
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res.text)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function releaseChangelogToDiscord () {
|
||||
const changelog = fs
|
||||
.readFileSync(path.resolve(__dirname, '../CHANGELOG.en-US.md'), 'utf-8')
|
||||
.split(/^## /gm)[1]
|
||||
.replace(/^##/gm, '')
|
||||
.replace(/\[([^\]]+)\]\([^)]+\)/g, '[$1]')
|
||||
|
||||
const message = `Changelog ${changelog.trim()}\n\nSee https://github.com/TuSimple/naive-ui/blob/main/CHANGELOG.en-US.md for details.\n`
|
||||
|
||||
await inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'release-changelog',
|
||||
message: `发布以下变更日志到 Discord:\n\n${message}`
|
||||
}
|
||||
])
|
||||
.then((ans) => {
|
||||
if (ans['release-changelog']) {
|
||||
request
|
||||
.post(`https://discord.com/api/webhooks/${DISCORD_TOKEN}`)
|
||||
.type('application/json')
|
||||
.send({
|
||||
content: message
|
||||
})
|
||||
.then(() => {
|
||||
console.log('done')
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
console.log('Error happens.')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
await releaseChangelogToDingTalk()
|
||||
await releaseChangelogToDiscord()
|
||||
})()
|
@ -1,8 +0,0 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { NAvatar } from '../index'
|
||||
|
||||
describe('n-avatar', () => {
|
||||
it('should work with import on demand', () => {
|
||||
mount(NAvatar)
|
||||
})
|
||||
})
|
121
src/avatar/tests/Avatar.spec.tsx
Normal file
121
src/avatar/tests/Avatar.spec.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { NAvatar } from '../index'
|
||||
import { h, nextTick } from 'vue'
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { NIcon } from '../../icon'
|
||||
|
||||
describe('n-avatar', () => {
|
||||
// mock offsetHeight offsetWidth
|
||||
const originalOffsetHeight = Object.getOwnPropertyDescriptor(
|
||||
HTMLElement.prototype,
|
||||
'offsetHeight'
|
||||
)
|
||||
const originalOffsetWidth = Object.getOwnPropertyDescriptor(
|
||||
HTMLElement.prototype,
|
||||
'offsetWidth'
|
||||
)
|
||||
|
||||
beforeAll(() => {
|
||||
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
|
||||
get () {
|
||||
if (this.className === 'n-avatar__text') {
|
||||
return 80
|
||||
}
|
||||
return 100
|
||||
}
|
||||
})
|
||||
Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
|
||||
get () {
|
||||
if (this.className === 'n-avatar__text') {
|
||||
return 80
|
||||
}
|
||||
return 100
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
|
||||
get: () => originalOffsetHeight
|
||||
})
|
||||
Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
|
||||
get: () => originalOffsetWidth
|
||||
})
|
||||
})
|
||||
|
||||
it('should work with import on demand', () => {
|
||||
mount(NAvatar)
|
||||
})
|
||||
|
||||
it('size is string', () => {
|
||||
const wrapper = mount(NAvatar, { props: { size: 'medium' } })
|
||||
expect(wrapper.attributes('style')).toContain('--size')
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('size is number', () => {
|
||||
const wrapper = mount(NAvatar, { props: { size: 50 } })
|
||||
expect(wrapper.attributes('style')).toContain('--size: 50px;')
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('round avatar', () => {
|
||||
const wrapper = mount(NAvatar, { props: { round: true } })
|
||||
expect(wrapper.attributes('style')).toContain('--border-radius: 50%;')
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('custom style', () => {
|
||||
const wrapper = mount(NAvatar, {
|
||||
props: { style: { backgroundColor: 'red' } }
|
||||
})
|
||||
expect(wrapper.attributes('style')).toContain('background-color: red;')
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('image avatar', () => {
|
||||
const wrapper = mount(NAvatar, {
|
||||
props: {
|
||||
src: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg'
|
||||
}
|
||||
})
|
||||
expect(wrapper.find('img').exists()).toBe(true)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('icon avatar', () => {
|
||||
const wrapper = mount(NAvatar, {
|
||||
slots: {
|
||||
default: () =>
|
||||
h(NIcon, null, {
|
||||
default: () => h(CashIcon)
|
||||
})
|
||||
}
|
||||
})
|
||||
expect(wrapper.find('i').classes()).toContain('n-icon')
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('avatar adjust text', async () => {
|
||||
const AdjustAvatar = {
|
||||
data () {
|
||||
return {
|
||||
text: ''
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { text } = this as any
|
||||
return <NAvatar size="medium">{text}</NAvatar>
|
||||
}
|
||||
}
|
||||
const wrapper = mount(AdjustAvatar)
|
||||
const textNode = wrapper.find('.n-avatar__text')
|
||||
await wrapper.setData({ text: 'adjust text' })
|
||||
await nextTick()
|
||||
expect(textNode.exists()).toBe(true)
|
||||
expect(textNode.attributes('style')).toContain(
|
||||
'transform: translateX(-50%) translateY(-50%) scale(1);'
|
||||
)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
})
|
15
src/avatar/tests/__snapshots__/Avatar.spec.tsx.snap
Normal file
15
src/avatar/tests/__snapshots__/Avatar.spec.tsx.snap
Normal file
@ -0,0 +1,15 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`n-avatar avatar adjust text 1`] = `"<span class=\\"n-avatar\\" style=\\"--font-size: 14px; --border-radius: 3px; --color: rgba(204, 204, 204, 1); --bezier: cubic-bezier(.4, 0, .2, 1); --size: 34px;\\"><span class=\\"n-avatar__text\\" style=\\"transform: translateX(-50%) translateY(-50%) scale(1);\\">adjust text</span></span>"`;
|
||||
|
||||
exports[`n-avatar custom style 1`] = `"<span class=\\"n-avatar\\" style=\\"--font-size: 14px; --border-radius: 3px; --color: rgba(204, 204, 204, 1); --bezier: cubic-bezier(.4, 0, .2, 1); --size: 34px; background-color: red;\\"><span class=\\"n-avatar__text\\" style=\\"transform: translateX(-50%) translateY(-50%) scale(1);\\"></span></span>"`;
|
||||
|
||||
exports[`n-avatar icon avatar 1`] = `"<span class=\\"n-avatar\\" style=\\"--font-size: 14px; --border-radius: 3px; --color: rgba(204, 204, 204, 1); --bezier: cubic-bezier(.4, 0, .2, 1); --size: 34px;\\"><span class=\\"n-avatar__text\\" style=\\"transform: translateX(-50%) translateY(-50%) scale(1);\\"><i role=\\"img\\" class=\\"n-icon\\" style=\\"--bezier: cubic-bezier(.4, 0, .2, 1);\\"><svg xmlns=\\"http://www.w3.org/2000/svg\\" xmlns:xlink=\\"http://www.w3.org/1999/xlink\\" viewBox=\\"0 0 512 512\\"><rect x=\\"32\\" y=\\"80\\" width=\\"448\\" height=\\"256\\" rx=\\"16\\" ry=\\"16\\" transform=\\"rotate(180 256 208)\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\"></rect><path fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\" d=\\"M64 384h384\\"></path><path fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\" d=\\"M96 432h320\\"></path><circle cx=\\"256\\" cy=\\"208\\" r=\\"80\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\"></circle><path d=\\"M480 160a80 80 0 0 1-80-80\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\"></path><path d=\\"M32 160a80 80 0 0 0 80-80\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\"></path><path d=\\"M480 256a80 80 0 0 0-80 80\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\"></path><path d=\\"M32 256a80 80 0 0 1 80 80\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"32\\"></path></svg></i></span></span>"`;
|
||||
|
||||
exports[`n-avatar image avatar 1`] = `"<span class=\\"n-avatar\\" style=\\"--font-size: 14px; --border-radius: 3px; --color: rgba(204, 204, 204, 1); --bezier: cubic-bezier(.4, 0, .2, 1); --size: 34px;\\"><img src=\\"https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg\\"></span>"`;
|
||||
|
||||
exports[`n-avatar round avatar 1`] = `"<span class=\\"n-avatar\\" style=\\"--font-size: 14px; --border-radius: 50%; --color: rgba(204, 204, 204, 1); --bezier: cubic-bezier(.4, 0, .2, 1); --size: 34px;\\"><span class=\\"n-avatar__text\\" style=\\"transform: translateX(-50%) translateY(-50%) scale(1);\\"></span></span>"`;
|
||||
|
||||
exports[`n-avatar size is number 1`] = `"<span class=\\"n-avatar\\" style=\\"--font-size: 14px; --border-radius: 3px; --color: rgba(204, 204, 204, 1); --bezier: cubic-bezier(.4, 0, .2, 1); --size: 50px;\\"><span class=\\"n-avatar__text\\" style=\\"transform: translateX(-50%) translateY(-50%) scale(1);\\"></span></span>"`;
|
||||
|
||||
exports[`n-avatar size is string 1`] = `"<span class=\\"n-avatar\\" style=\\"--font-size: 14px; --border-radius: 3px; --color: rgba(204, 204, 204, 1); --bezier: cubic-bezier(.4, 0, .2, 1); --size: 34px;\\"><span class=\\"n-avatar__text\\" style=\\"transform: translateX(-50%) translateY(-50%) scale(1);\\"></span></span>"`;
|
@ -41,6 +41,7 @@ export default defineComponent({
|
||||
`${mergedClsPrefix}-button-group`,
|
||||
this.vertical && `${mergedClsPrefix}-button-group--vertical`
|
||||
]}
|
||||
role="group"
|
||||
>
|
||||
{this.$slots}
|
||||
</div>
|
||||
|
@ -184,12 +184,11 @@ export default defineComponent({
|
||||
</div>
|
||||
) : null}
|
||||
{$slots.header || this.title || this.closable ? (
|
||||
<div class={`${mergedClsPrefix}-card-header`}>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-card-header__main`}
|
||||
style={this.headerStyle}
|
||||
role="heading"
|
||||
>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-card-header`}
|
||||
style={this.headerStyle}
|
||||
>
|
||||
<div class={`${mergedClsPrefix}-card-header__main`} role="heading">
|
||||
{renderSlot($slots, 'header', {}, () => [this.title])}
|
||||
</div>
|
||||
{$slots['header-extra'] ? (
|
||||
|
@ -78,6 +78,7 @@ export default c([
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: var(--title-font-size);
|
||||
padding:
|
||||
var(--padding-top)
|
||||
var(--padding-left)
|
||||
@ -85,7 +86,6 @@ export default c([
|
||||
var(--padding-left);
|
||||
`, [
|
||||
cE('main', `
|
||||
font-size: var(--title-font-size);
|
||||
font-weight: var(--title-font-weight);
|
||||
transition: color .3s var(--bezier);
|
||||
flex: 1;
|
||||
|
@ -84,6 +84,14 @@ These methods can help you control table in an uncontrolled manner. However, it'
|
||||
| page | `(page: number) => void` | |
|
||||
| sort | `(columnKey: string \| number \| null, order: 'ascend' \| 'descend' \| false) => void` | If columnKey set to `null`, it is the same as clearSorter. |
|
||||
|
||||
## Slots
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Type | Description |
|
||||
| ----- | ---- | ---------------------------------------------- |
|
||||
| empty | `()` | Custom description when data of table is empty. |
|
||||
|
||||
## API
|
||||
|
||||
### Column Properties
|
||||
|
@ -84,6 +84,14 @@ tree
|
||||
| page | `(page: number) => void` | |
|
||||
| sort | `(columnKey: string \| number \| null, order: 'ascend' \| 'descend' \| false) => void` | 如果 columnKey 设为 `null`,那它和 clearSorter 效果一致 |
|
||||
|
||||
## Slots
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| ----- | ---- | -------------------- |
|
||||
| empty | `()` | 表格数据为空时的展示 |
|
||||
|
||||
## API
|
||||
|
||||
### Column Properties
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
PropType,
|
||||
ExtractPropTypes,
|
||||
toRef,
|
||||
renderSlot,
|
||||
CSSProperties
|
||||
} from 'vue'
|
||||
import { useConfig, useLocale, useTheme } from '../../_mixins'
|
||||
@ -80,10 +81,7 @@ export const dataTableProps = {
|
||||
type: Array as PropType<RowKey[]>,
|
||||
default: () => []
|
||||
},
|
||||
checkedRowKeys: {
|
||||
type: Array as PropType<RowKey[]>,
|
||||
default: undefined
|
||||
},
|
||||
checkedRowKeys: Array as PropType<RowKey[]>,
|
||||
singleLine: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@ -116,24 +114,28 @@ export const dataTableProps = {
|
||||
type: Number,
|
||||
default: 16
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:page': [Function, Array] as PropType<
|
||||
PaginationProps['onUpdate:page']
|
||||
>,
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
onUpdatePage: [Function, Array] as PropType<PaginationProps['onUpdate:page']>,
|
||||
'onUpdate:pageSize': [Function, Array] as PropType<
|
||||
PaginationProps['onUpdate:pageSize']
|
||||
>,
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
onUpdatePageSize: [Function, Array] as PropType<
|
||||
PaginationProps['onUpdate:pageSize']
|
||||
>,
|
||||
'onUpdate:sorter': [Function, Array] as PropType<MaybeArray<OnUpdateSorter>>,
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
onUpdateSorter: [Function, Array] as PropType<MaybeArray<OnUpdateSorter>>,
|
||||
'onUpdate:filters': [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateFilters>
|
||||
>,
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
onUpdateFilters: [Function, Array] as PropType<MaybeArray<OnUpdateFilters>>,
|
||||
'onUpdate:checkedRowKeys': [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateCheckedRowKeys>
|
||||
>,
|
||||
onUpdateCheckedRowKeys: [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateCheckedRowKeys>
|
||||
>,
|
||||
'onUpdate:expandedRowKeys': [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateExpandedRowKeys>
|
||||
>,
|
||||
@ -499,12 +501,14 @@ export default defineComponent({
|
||||
}
|
||||
]}
|
||||
>
|
||||
<NEmpty
|
||||
theme={this.mergedTheme.peers.Empty}
|
||||
themeOverrides={
|
||||
this.mergedTheme.peerOverrides.Empty
|
||||
}
|
||||
/>
|
||||
{renderSlot(this.$slots, 'empty', undefined, () => [
|
||||
<NEmpty
|
||||
theme={this.mergedTheme.peers.Empty}
|
||||
themeOverrides={
|
||||
this.mergedTheme.peerOverrides.Empty
|
||||
}
|
||||
/>
|
||||
])}
|
||||
</div>
|
||||
) : null
|
||||
}}
|
||||
|
@ -69,9 +69,11 @@ export function useCheck (
|
||||
})
|
||||
function doUpdateCheckedRowKeys (keys: RowKey[]): void {
|
||||
const {
|
||||
'onUpdate:checkedRowKeys': onUpdateCheckedRowKeys,
|
||||
'onUpdate:checkedRowKeys': _onUpdateCheckedRowKeys,
|
||||
onUpdateCheckedRowKeys,
|
||||
onCheckedRowKeysChange
|
||||
} = props
|
||||
if (_onUpdateCheckedRowKeys) call(_onUpdateCheckedRowKeys, keys)
|
||||
if (onUpdateCheckedRowKeys) call(onUpdateCheckedRowKeys, keys)
|
||||
if (onCheckedRowKeysChange) call(onCheckedRowKeysChange, keys)
|
||||
uncontrolledCheckedRowKeysRef.value = keys
|
||||
|
@ -297,9 +297,14 @@ export function useTableData (
|
||||
function mergedOnUpdatePage (page: number): void {
|
||||
const { pagination } = props
|
||||
if (pagination) {
|
||||
const { onChange, 'onUpdate:page': onUpdatePage } = pagination
|
||||
const {
|
||||
onChange,
|
||||
'onUpdate:page': _onUpdatePage,
|
||||
onUpdatePage
|
||||
} = pagination
|
||||
if (onChange) call(onChange, page)
|
||||
if (onUpdatePage) call(onUpdatePage, page)
|
||||
if (_onUpdatePage) call(_onUpdatePage, page)
|
||||
doUpdatePage(page)
|
||||
}
|
||||
}
|
||||
@ -344,7 +349,12 @@ export function useTableData (
|
||||
uncontrolledPageSizeRef.value = pageSize
|
||||
}
|
||||
function doUpdateSorter (sortState: SortState | null): void {
|
||||
const { 'onUpdate:sorter': onUpdateSorter, onSorterChange } = props
|
||||
const {
|
||||
'onUpdate:sorter': _onUpdateSorter,
|
||||
onUpdateSorter,
|
||||
onSorterChange
|
||||
} = props
|
||||
if (_onUpdateSorter) call(_onUpdateSorter, sortState)
|
||||
if (onUpdateSorter) call(onUpdateSorter, sortState)
|
||||
if (onSorterChange) call(onSorterChange, sortState)
|
||||
uncontrolledSortStateRef.value = sortState
|
||||
@ -353,8 +363,13 @@ export function useTableData (
|
||||
filters: FilterState,
|
||||
sourceColumn?: TableBaseColumn
|
||||
): void {
|
||||
const { 'onUpdate:filters': onUpdateFilters, onFiltersChange } = props
|
||||
const {
|
||||
onUpdateFilters,
|
||||
'onUpdate:filters': _onUpdateFilters,
|
||||
onFiltersChange
|
||||
} = props
|
||||
if (onUpdateFilters) call(onUpdateFilters, filters, sourceColumn)
|
||||
if (_onUpdateFilters) call(_onUpdateFilters, filters, sourceColumn)
|
||||
if (onFiltersChange) call(onFiltersChange, filters, sourceColumn)
|
||||
uncontrolledFilterStateRef.value = filters
|
||||
}
|
||||
|
@ -8,6 +8,22 @@ describe('n-data-table', () => {
|
||||
it('should work with import on demand', () => {
|
||||
mount(NDataTable)
|
||||
})
|
||||
it('show custom empty', () => {
|
||||
const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
key: 'name'
|
||||
}
|
||||
]
|
||||
const wrapper = mount(() => (
|
||||
<NDataTable columns={columns} data={[]}>
|
||||
{{
|
||||
empty: () => <div class="empty-info">empty</div>
|
||||
}}
|
||||
</NDataTable>
|
||||
))
|
||||
expect(wrapper.find('.empty-info').exists()).toEqual(true)
|
||||
})
|
||||
describe('props.columns', () => {
|
||||
it('has correct type', () => {
|
||||
interface Data {
|
||||
|
@ -26,6 +26,7 @@ export type DialogReactive = {
|
||||
} & DialogOptions
|
||||
|
||||
export interface DialogApiInjection {
|
||||
destroyAll: () => void
|
||||
create: (options: DialogOptions) => DialogReactive
|
||||
success: (options: DialogOptions) => DialogReactive
|
||||
warning: (options: DialogOptions) => DialogReactive
|
||||
@ -33,18 +34,16 @@ export interface DialogApiInjection {
|
||||
info: (options: DialogOptions) => DialogReactive
|
||||
}
|
||||
|
||||
export const dialogApiInjectionKey: InjectionKey<DialogApiInjection> = Symbol(
|
||||
'dialogApi'
|
||||
)
|
||||
export const dialogApiInjectionKey: InjectionKey<DialogApiInjection> =
|
||||
Symbol('dialogApi')
|
||||
|
||||
export interface DialogProviderInjection {
|
||||
clickedRef: Ref<boolean>
|
||||
clickPositionRef: Ref<{ x: number, y: number } | null>
|
||||
}
|
||||
|
||||
export const dialogProviderInjectionKey: InjectionKey<DialogProviderInjection> = Symbol(
|
||||
'dialogProvider'
|
||||
)
|
||||
export const dialogProviderInjectionKey: InjectionKey<DialogProviderInjection> =
|
||||
Symbol('dialogProvider')
|
||||
|
||||
interface DialogInst {
|
||||
hide: () => void
|
||||
@ -79,11 +78,14 @@ export default defineComponent({
|
||||
dialogListRef.value.push(dialogReactive)
|
||||
return dialogReactive
|
||||
}
|
||||
const typedApi = (['info', 'success', 'warning', 'error'] as Array<
|
||||
'info' | 'success' | 'warning' | 'error'
|
||||
>).map((type) => (options: DialogOptions): DialogReactive => {
|
||||
const typedApi = (
|
||||
['info', 'success', 'warning', 'error'] as Array<
|
||||
'info' | 'success' | 'warning' | 'error'
|
||||
>
|
||||
).map((type) => (options: DialogOptions): DialogReactive => {
|
||||
return create({ ...options, type })
|
||||
})
|
||||
|
||||
function handleAfterLeave (key: String): void {
|
||||
const { value: dialogList } = dialogListRef
|
||||
dialogList.splice(
|
||||
@ -91,8 +93,16 @@ export default defineComponent({
|
||||
1
|
||||
)
|
||||
}
|
||||
|
||||
function destroyAll (): void {
|
||||
Object.values(dialogInstRefs).forEach((dialogInstRef) =>
|
||||
dialogInstRef.hide()
|
||||
)
|
||||
}
|
||||
|
||||
const api = {
|
||||
create,
|
||||
destroyAll,
|
||||
info: typedApi[0],
|
||||
success: typedApi[1],
|
||||
warning: typedApi[2],
|
||||
|
@ -49,7 +49,7 @@ export default defineComponent({
|
||||
if (isGroupNode(child.rawNode)) {
|
||||
warn(
|
||||
'dropdown',
|
||||
'`group` node is allowed to be put in `group` node.'
|
||||
'`group` node is not allowed to be put in `group` node.'
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ import {
|
||||
import { VBinder, VTarget, VFollower, FollowerPlacement } from 'vueuc'
|
||||
import { useMemo } from 'vooks'
|
||||
import { ChevronRightIcon } from '../../_internal/icons'
|
||||
import { useDeferredTrue } from '../../_utils/composable'
|
||||
import { render } from '../../_utils'
|
||||
import { render, useDeferredTrue } from '../../_utils'
|
||||
import { NIcon } from '../../icon'
|
||||
import NDropdownMenu, { dropdownMenuInjectionKey } from './DropdownMenu'
|
||||
import { dropdownInjectionKey } from './Dropdown'
|
||||
|
@ -1,5 +1,72 @@
|
||||
import { VueWrapper } from '@vue/test-utils/dist/vueWrapper'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { NDropdown } from '../index'
|
||||
import { ComponentPublicInstance, h, nextTick } from 'vue'
|
||||
import { NIcon } from '../../icon'
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { NDropdown, DropdownProps } from '../index'
|
||||
|
||||
const pendingOptionClassName = 'n-dropdown-option-body n-dropdown-option-body--pending'
|
||||
const optionBodySelector = '.n-dropdown-option-body'
|
||||
const options = [
|
||||
{
|
||||
type: 'group',
|
||||
label: '主角和吃的',
|
||||
key: 'main',
|
||||
children: [
|
||||
{
|
||||
label: '杰·盖茨比',
|
||||
key: 'jay gatsby'
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
key: 'd1'
|
||||
},
|
||||
{
|
||||
label: '黛西·布坎南',
|
||||
icon () {
|
||||
return h(NIcon, null, {
|
||||
default: () => h(CashIcon)
|
||||
})
|
||||
},
|
||||
key: 'daisy buchanan',
|
||||
disabled: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
key: 'd1'
|
||||
},
|
||||
{
|
||||
label: '其他角色',
|
||||
key: 'others1',
|
||||
children: [
|
||||
{
|
||||
label: '乔丹·贝克',
|
||||
key: 'jordan baker'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const mountDropdown = ({
|
||||
onSelect,
|
||||
inverted = false,
|
||||
options: data = options
|
||||
}: DropdownProps = {}): VueWrapper<ComponentPublicInstance> => {
|
||||
return mount(NDropdown, {
|
||||
attachTo: document.body,
|
||||
props: {
|
||||
options: data,
|
||||
trigger: 'click',
|
||||
onSelect,
|
||||
inverted
|
||||
},
|
||||
slots: {
|
||||
default: () => 'star kirby'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('n-dropdown', () => {
|
||||
it('should work with import on demand', () => {
|
||||
@ -10,32 +77,125 @@ describe('n-dropdown', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('dropdown disabled', async () => {
|
||||
const onSelect = jest.fn()
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: '滨海湾金沙,新加坡',
|
||||
key: 'marina bay sands',
|
||||
disabled: true
|
||||
}
|
||||
]
|
||||
const triggerEvent = 'click'
|
||||
const wrapper = mount(NDropdown, {
|
||||
attachTo: document.body,
|
||||
props: {
|
||||
options,
|
||||
trigger: triggerEvent,
|
||||
onSelect: onSelect
|
||||
},
|
||||
slots: {
|
||||
default: () => 'star kirby'
|
||||
}
|
||||
})
|
||||
it('shows menu after click', async () => {
|
||||
const wrapper = mountDropdown()
|
||||
|
||||
const triggerNodeWrapper = wrapper.find('span')
|
||||
expect(triggerNodeWrapper.exists()).toBe(true)
|
||||
await triggerNodeWrapper.trigger(triggerEvent)
|
||||
await triggerNodeWrapper.trigger('click')
|
||||
|
||||
expect(document.querySelector('.n-dropdown')).toMatchSnapshot()
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('inverted style', async () => {
|
||||
const wrapper = mountDropdown({ inverted: true })
|
||||
|
||||
const triggerNodeWrapper = wrapper.find('span')
|
||||
expect(triggerNodeWrapper.exists()).toBe(true)
|
||||
await triggerNodeWrapper.trigger('click')
|
||||
|
||||
expect(document.querySelector('.n-dropdown')).toMatchSnapshot()
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('keyboard event', async () => {
|
||||
const onSelect = jest.fn()
|
||||
let wrapper = mountDropdown({ onSelect })
|
||||
|
||||
let triggerNodeWrapper = wrapper.find('span')
|
||||
await triggerNodeWrapper.trigger('click')
|
||||
|
||||
await triggerNodeWrapper.trigger('keydown', {
|
||||
key: 'ArrowDown'
|
||||
})
|
||||
let options = document.querySelectorAll(optionBodySelector)
|
||||
expect(options[1].className).toEqual(pendingOptionClassName)
|
||||
|
||||
await triggerNodeWrapper.trigger('keydown', {
|
||||
key: 'ArrowDown'
|
||||
})
|
||||
await triggerNodeWrapper.trigger('keydown', {
|
||||
key: 'ArrowRight'
|
||||
})
|
||||
options = document.querySelectorAll(optionBodySelector)
|
||||
expect(options.length).toBe(5)
|
||||
expect(options[3].className).toEqual(pendingOptionClassName)
|
||||
expect(options[4].className).toEqual(pendingOptionClassName)
|
||||
|
||||
await triggerNodeWrapper.trigger('keydown', {
|
||||
key: 'ArrowLeft'
|
||||
})
|
||||
options = document.querySelectorAll(optionBodySelector)
|
||||
expect(options.length).toBe(4)
|
||||
|
||||
await triggerNodeWrapper.trigger('keydown', {
|
||||
key: 'ArrowUp'
|
||||
})
|
||||
expect(options[1].className).toEqual(pendingOptionClassName)
|
||||
await triggerNodeWrapper.trigger('keyup', {
|
||||
key: 'Enter'
|
||||
})
|
||||
expect(onSelect).toHaveBeenCalledWith('jay gatsby', {
|
||||
key: 'jay gatsby',
|
||||
label: '杰·盖茨比'
|
||||
})
|
||||
|
||||
wrapper = mountDropdown({ onSelect })
|
||||
|
||||
triggerNodeWrapper = wrapper.find('span')
|
||||
await triggerNodeWrapper.trigger('click')
|
||||
await triggerNodeWrapper.trigger('keydown', {
|
||||
key: 'Escape'
|
||||
})
|
||||
expect(document.querySelector('.n-dropdown')).toBeNull()
|
||||
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('option mouse event', async () => {
|
||||
const onSelect = jest.fn()
|
||||
const wrapper = mountDropdown({ onSelect })
|
||||
|
||||
const triggerNodeWrapper = wrapper.find('span')
|
||||
expect(triggerNodeWrapper.exists()).toBe(true)
|
||||
await triggerNodeWrapper.trigger('click')
|
||||
|
||||
const options = document.querySelectorAll(optionBodySelector)
|
||||
|
||||
const mouseEnter = new Event('mouseenter')
|
||||
options[1].dispatchEvent(mouseEnter)
|
||||
await nextTick(() => {
|
||||
expect(options[1].className).toEqual(pendingOptionClassName)
|
||||
})
|
||||
|
||||
const mouseMove = new Event('mousemove')
|
||||
options[3].dispatchEvent(mouseMove)
|
||||
await nextTick(() => {
|
||||
expect(options[1].className).not.toEqual(pendingOptionClassName)
|
||||
expect(options[3].className).toEqual(pendingOptionClassName)
|
||||
})
|
||||
await (options[3] as HTMLDivElement).click()
|
||||
expect(onSelect).not.toHaveBeenCalledWith()
|
||||
|
||||
const mouseLeave = new Event('mouseleave')
|
||||
Object.defineProperty(mouseLeave, 'relatedTarget', {
|
||||
writable: false,
|
||||
value: options[1]
|
||||
})
|
||||
options[3].dispatchEvent(mouseLeave)
|
||||
await nextTick(() => {
|
||||
expect(options[3].className).not.toEqual(pendingOptionClassName)
|
||||
})
|
||||
})
|
||||
|
||||
it('dropdown disabled', async () => {
|
||||
const onSelect = jest.fn()
|
||||
const wrapper = mountDropdown({ onSelect })
|
||||
|
||||
const triggerNodeWrapper = wrapper.find('span')
|
||||
expect(triggerNodeWrapper.exists()).toBe(true)
|
||||
await triggerNodeWrapper.trigger('click')
|
||||
|
||||
const disabledMenu = document.querySelector(
|
||||
'.n-dropdown-option-body--disabled'
|
||||
|
461
src/dropdown/tests/__snapshots__/Dropdown.spec.ts.snap
Normal file
461
src/dropdown/tests/__snapshots__/Dropdown.spec.ts.snap
Normal file
@ -0,0 +1,461 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`n-dropdown inverted style 1`] = `
|
||||
<div
|
||||
class="n-popover n-dropdown n-popover--no-arrow n-popover--padded n-popover--raw"
|
||||
style="--box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --bezier: cubic-bezier(.4, 0, .2, 1); --bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --bezier-ease-out: cubic-bezier(0, 0, .2, 1); --font-size: 14px; --text-color: rgb(51, 54, 57); --color: #fff; --border-radius: 3px; --arrow-height: 6px; --arrow-offset: 10px; --arrow-offset-vertical: 10px; --padding: 8px 14px; --space: 6px; --space-arrow: 10px;"
|
||||
>
|
||||
|
||||
<div
|
||||
class="n-dropdown-menu"
|
||||
style="--bezier: cubic-bezier(.4, 0, .2, 1); --font-size: 14px; --padding: 4px 0; --border-radius: 3px; --box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --option-height: 34px; --option-prefix-width: 14px; --option-icon-prefix-width: 36px; --option-suffix-width: 14px; --option-icon-suffix-width: 32px; --option-icon-size: 16px; --divider-color: rgb(239, 239, 245); --option-opacity-disabled: 0.5; --color: rgb(0, 20, 40); --option-color-hover: #18a058; --option-color-active: #18a058; --option-text-color: #BBB; --option-text-color-hover: #FFF; --option-text-color-active: #FFF; --option-text-color-child-active: #FFF; --prefix-color: #BBB; --suffix-color: #BBB; --group-header-text-color: #AAA;"
|
||||
>
|
||||
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body n-dropdown-option-body--group"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
主角和吃的
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
杰·盖茨比
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
/>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
class="n-dropdown-divider"
|
||||
/>
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body n-dropdown-option-body--disabled"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<i
|
||||
class="n-icon"
|
||||
role="img"
|
||||
style="--bezier: cubic-bezier(.4, 0, .2, 1);"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<rect
|
||||
fill="none"
|
||||
height="256"
|
||||
rx="16"
|
||||
ry="16"
|
||||
stroke="currentColor"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
transform="rotate(180 256 208)"
|
||||
width="448"
|
||||
x="32"
|
||||
y="80"
|
||||
/>
|
||||
<path
|
||||
d="M64 384h384"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M96 432h320"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<circle
|
||||
cx="256"
|
||||
cy="208"
|
||||
fill="none"
|
||||
r="80"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M480 160a80 80 0 0 1-80-80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M32 160a80 80 0 0 0 80-80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M480 256a80 80 0 0 0-80 80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M32 256a80 80 0 0 1 80 80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
黛西·布坎南
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
/>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="n-dropdown-divider"
|
||||
/>
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
其他角色
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
>
|
||||
<i
|
||||
class="n-icon"
|
||||
role="img"
|
||||
style="--bezier: cubic-bezier(.4, 0, .2, 1);"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="n-dropdown-offset-container"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`n-dropdown shows menu after click 1`] = `
|
||||
<div
|
||||
class="n-popover n-dropdown n-popover--no-arrow n-popover--padded n-popover--raw"
|
||||
style="--box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --bezier: cubic-bezier(.4, 0, .2, 1); --bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --bezier-ease-out: cubic-bezier(0, 0, .2, 1); --font-size: 14px; --text-color: rgb(51, 54, 57); --color: #fff; --border-radius: 3px; --arrow-height: 6px; --arrow-offset: 10px; --arrow-offset-vertical: 10px; --padding: 8px 14px; --space: 6px; --space-arrow: 10px;"
|
||||
>
|
||||
|
||||
<div
|
||||
class="n-dropdown-menu"
|
||||
style="--bezier: cubic-bezier(.4, 0, .2, 1); --font-size: 14px; --padding: 4px 0; --border-radius: 3px; --box-shadow: 0 3px 6px -4px rgba(0, 0, 0, .12), 0 6px 16px 0 rgba(0, 0, 0, .08), 0 9px 28px 8px rgba(0, 0, 0, .05); --option-height: 34px; --option-prefix-width: 14px; --option-icon-prefix-width: 36px; --option-suffix-width: 14px; --option-icon-suffix-width: 32px; --option-icon-size: 16px; --divider-color: rgb(239, 239, 245); --option-opacity-disabled: 0.5; --color: #fff; --option-color-hover: rgb(243, 243, 245); --option-color-active: rgba(24, 160, 88, 0.1); --option-text-color: rgb(51, 54, 57); --option-text-color-hover: rgb(51, 54, 57); --option-text-color-active: #18a058; --option-text-color-child-active: #18a058; --prefix-color: rgb(51, 54, 57); --suffix-color: rgb(51, 54, 57); --group-header-text-color: rgb(158, 164, 170);"
|
||||
>
|
||||
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body n-dropdown-option-body--group"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
主角和吃的
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
杰·盖茨比
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
/>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
class="n-dropdown-divider"
|
||||
/>
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body n-dropdown-option-body--disabled"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<i
|
||||
class="n-icon"
|
||||
role="img"
|
||||
style="--bezier: cubic-bezier(.4, 0, .2, 1);"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<rect
|
||||
fill="none"
|
||||
height="256"
|
||||
rx="16"
|
||||
ry="16"
|
||||
stroke="currentColor"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
transform="rotate(180 256 208)"
|
||||
width="448"
|
||||
x="32"
|
||||
y="80"
|
||||
/>
|
||||
<path
|
||||
d="M64 384h384"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M96 432h320"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<circle
|
||||
cx="256"
|
||||
cy="208"
|
||||
fill="none"
|
||||
r="80"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M480 160a80 80 0 0 1-80-80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M32 160a80 80 0 0 0 80-80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M480 256a80 80 0 0 0-80 80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
<path
|
||||
d="M32 256a80 80 0 0 1 80 80"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
黛西·布坎南
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
/>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="n-dropdown-divider"
|
||||
/>
|
||||
<div
|
||||
class="n-dropdown-option"
|
||||
>
|
||||
<div
|
||||
class="n-dropdown-option-body"
|
||||
>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__prefix n-dropdown-option-body__prefix--show-icon"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__label"
|
||||
>
|
||||
其他角色
|
||||
</div>
|
||||
<div
|
||||
__dropdown-option="true"
|
||||
class="n-dropdown-option-body__suffix n-dropdown-option-body__suffix--has-submenu"
|
||||
>
|
||||
<i
|
||||
class="n-icon"
|
||||
role="img"
|
||||
style="--bezier: cubic-bezier(.4, 0, .2, 1);"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="n-dropdown-offset-container"
|
||||
>
|
||||
<!---->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
@ -5,11 +5,13 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0
|
||||
value: ref(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -8,12 +8,14 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0,
|
||||
disabled: true
|
||||
value: ref(0),
|
||||
disabled: ref(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -12,22 +12,24 @@ min-max
|
||||
size
|
||||
step
|
||||
validator
|
||||
show-button
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| bordered | `boolean` | `true` | |
|
||||
| default-value | `number \| null` | `null` | |
|
||||
| disabled | `boolean` | `false` | |
|
||||
| max | `number` | `undefined` | |
|
||||
| min | `number` | `undefined` | |
|
||||
| bordered | `boolean` | `true` | Whether to show the border. |
|
||||
| default-value | `number \| null` | `null` | Default value in uncontrolled mode. |
|
||||
| disabled | `boolean` | `false` | Whether to disable the input. |
|
||||
| max | `number` | `undefined` | The max value. |
|
||||
| min | `number` | `undefined` | The min value. |
|
||||
| placeholder | `string` | `'Please Input'` | |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | |
|
||||
| step | `number` | `1` | |
|
||||
| validator | `(value) => boolean` | `undefined` | |
|
||||
| value | `number` | `undefined` | |
|
||||
| on-blur | `(event: FocusEvent) => void` | `undefined` | |
|
||||
| on-focus | `(event: FocusEvent) => void` | `undefined` | |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | |
|
||||
| show-button | `boolean` | `true` | Whether to show buttons. |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | The size of input box. |
|
||||
| step | `number` | `1` | The number to which the current value is increased or decreased. It can be an integer or decimal. |
|
||||
| validator | `(value) => boolean` | `undefined` | Setup custom validation. |
|
||||
| value | `number` | `undefined` | Value in controlled mode. |
|
||||
| on-blur | `(event: FocusEvent) => void` | `undefined` | Callback when blur. |
|
||||
| on-focus | `(event: FocusEvent) => void` | `undefined` | Callback when focused. |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | Callback when the component's value changes. |
|
||||
|
@ -10,11 +10,13 @@ You can set min & max of it.
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: null
|
||||
value: ref(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
23
src/input-number/demos/enUS/show-button.demo.md
Normal file
23
src/input-number/demos/enUS/show-button.demo.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Hide Button
|
||||
|
||||
Use `show-button` prop to control whether to show buttons.
|
||||
|
||||
```html
|
||||
<n-space align="center">
|
||||
<n-switch v-model:value="disabled" />
|
||||
<n-input-number :show-button="disabled" v-model:value="value" />
|
||||
</n-space>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: ref(0),
|
||||
disabled: ref(true)
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
@ -11,11 +11,13 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0
|
||||
value: ref(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -5,11 +5,13 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0
|
||||
value: ref(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -5,12 +5,14 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0,
|
||||
value: ref(0),
|
||||
validator: (x) => x > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -5,11 +5,13 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0
|
||||
value: ref(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -8,12 +8,14 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0,
|
||||
disabled: true
|
||||
value: ref(0),
|
||||
disabled: ref(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -12,22 +12,24 @@ min-max
|
||||
size
|
||||
step
|
||||
validator
|
||||
show-button
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --------------- | -------------------------------- | ----------- | ---- |
|
||||
| bordered | `boolean` | `true` | |
|
||||
| default-value | `number \| null` | `null` | |
|
||||
| disabled | `boolean` | `false` | |
|
||||
| max | `number` | `undefined` | |
|
||||
| min | `number` | `undefined` | |
|
||||
| placeholder | `string` | `'请输入'` | |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | |
|
||||
| step | `number` | `1` | |
|
||||
| validator | `(value) => boolean` | `undefined` | |
|
||||
| value | `number \| null` | `undefined` | |
|
||||
| on-blur | `(event: FocusEvent) => void` | `undefined` | |
|
||||
| on-focus | `(event: FocusEvent) => void` | `undefined` | |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | |
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| bordered | `boolean` | `true` | 是否有边框 |
|
||||
| default-value | `number \| null` | `null` | 非受控模式下的默认值 |
|
||||
| disabled | `boolean` | `false` | 是否禁用 |
|
||||
| max | `number` | `undefined` | 最大值 |
|
||||
| min | `number` | `undefined` | 最小值 |
|
||||
| placeholder | `string` | `'请输入'` | |
|
||||
| show-button | `boolean` | `true` | 是否有按钮 |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | 输入框大小 |
|
||||
| step | `number` | `1` | 每次改变步数,可以为小数 |
|
||||
| validator | `(value) => boolean` | `undefined` | 设置自定义验证 |
|
||||
| value | `number \| null` | `undefined` | 受控模式下的值 |
|
||||
| on-blur | `(event: FocusEvent) => void` | `undefined` | 移除焦点的回调 |
|
||||
| on-focus | `(event: FocusEvent) => void` | `undefined` | 获取焦点的回调 |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | 组件值发生变化的回调 |
|
||||
|
@ -20,11 +20,13 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: null
|
||||
value: ref(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
23
src/input-number/demos/zhCN/show-button.demo.md
Normal file
23
src/input-number/demos/zhCN/show-button.demo.md
Normal file
@ -0,0 +1,23 @@
|
||||
# 隐藏按钮
|
||||
|
||||
使用 `show-button` 属性来控制是否展示按钮。
|
||||
|
||||
```html
|
||||
<n-space align="center">
|
||||
<n-switch v-model:value="disabled" />
|
||||
<n-input-number :show-button="disabled" v-model:value="value" />
|
||||
</n-space>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: ref(0),
|
||||
disabled: ref(true)
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
@ -11,11 +11,13 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0
|
||||
value: ref(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -5,11 +5,13 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0
|
||||
value: ref(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -5,12 +5,14 @@
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data () {
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
value: 0,
|
||||
value: ref(0),
|
||||
validator: (x) => x > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -45,6 +45,10 @@ const inputNumberProps = {
|
||||
type: Boolean as PropType<boolean | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
showButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:value': [Function, Array] as PropType<
|
||||
MaybeArray<(value: number) => void>
|
||||
@ -361,46 +365,48 @@ export default defineComponent({
|
||||
onKeydown={this.handleKeyDown}
|
||||
onMousedown={this.handleMouseDown}
|
||||
>
|
||||
{{
|
||||
suffix: () => [
|
||||
<NButton
|
||||
text
|
||||
disabled={!this.minusable || this.disabled}
|
||||
focusable={false}
|
||||
builtinThemeOverrides={this.buttonThemeOverrides}
|
||||
onClick={this.handleMinusClick}
|
||||
ref="minusButtonInstRef"
|
||||
>
|
||||
{{
|
||||
default: () => (
|
||||
<NBaseIcon clsPrefix={mergedClsPrefix}>
|
||||
{{
|
||||
default: () => <RemoveIcon />
|
||||
}}
|
||||
</NBaseIcon>
|
||||
)
|
||||
}}
|
||||
</NButton>,
|
||||
<NButton
|
||||
text
|
||||
disabled={!this.addable || this.disabled}
|
||||
focusable={false}
|
||||
builtinThemeOverrides={this.buttonThemeOverrides}
|
||||
onClick={this.handleAddClick}
|
||||
ref="addButtonInstRef"
|
||||
>
|
||||
{{
|
||||
default: () => (
|
||||
<NBaseIcon clsPrefix={mergedClsPrefix}>
|
||||
{{
|
||||
default: () => <AddIcon />
|
||||
}}
|
||||
</NBaseIcon>
|
||||
)
|
||||
}}
|
||||
</NButton>
|
||||
]
|
||||
}}
|
||||
{this.showButton
|
||||
? {
|
||||
suffix: () => [
|
||||
<NButton
|
||||
text
|
||||
disabled={!this.minusable || this.disabled}
|
||||
focusable={false}
|
||||
builtinThemeOverrides={this.buttonThemeOverrides}
|
||||
onClick={this.handleMinusClick}
|
||||
ref="minusButtonInstRef"
|
||||
>
|
||||
{{
|
||||
default: () => (
|
||||
<NBaseIcon clsPrefix={mergedClsPrefix}>
|
||||
{{
|
||||
default: () => <RemoveIcon />
|
||||
}}
|
||||
</NBaseIcon>
|
||||
)
|
||||
}}
|
||||
</NButton>,
|
||||
<NButton
|
||||
text
|
||||
disabled={!this.addable || this.disabled}
|
||||
focusable={false}
|
||||
builtinThemeOverrides={this.buttonThemeOverrides}
|
||||
onClick={this.handleAddClick}
|
||||
ref="addButtonInstRef"
|
||||
>
|
||||
{{
|
||||
default: () => (
|
||||
<NBaseIcon clsPrefix={mergedClsPrefix}>
|
||||
{{
|
||||
default: () => <AddIcon />
|
||||
}}
|
||||
</NBaseIcon>
|
||||
)
|
||||
}}
|
||||
</NButton>
|
||||
]
|
||||
}
|
||||
: null}
|
||||
</NInput>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,8 +1,19 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { NInputNumber } from '../index'
|
||||
import { NButton } from '../../button'
|
||||
|
||||
describe('n-input-number', () => {
|
||||
it('should work with import on demand', () => {
|
||||
mount(NInputNumber)
|
||||
})
|
||||
})
|
||||
|
||||
describe('n-input-number', () => {
|
||||
it('should work with `show-button` props', async () => {
|
||||
const wrapper = mount(NInputNumber)
|
||||
expect(wrapper.findComponent(NButton).exists()).toBe(true)
|
||||
|
||||
await wrapper.setProps({ showButton: false })
|
||||
expect(wrapper.findComponent(NButton).exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
@ -21,7 +21,16 @@ function renderIcon (icon) {
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
label: 'Hear the Wind Sing',
|
||||
label: () =>
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
href: 'https://en.wikipedia.org/wiki/Hear_the_Wind_Sing',
|
||||
target: '_blank',
|
||||
rel: 'noopenner noreferrer'
|
||||
},
|
||||
'Hear the Wind Sing'
|
||||
),
|
||||
key: 'hear-the-wind-sing',
|
||||
icon: renderIcon(BookIcon)
|
||||
},
|
||||
|
@ -1,6 +1,8 @@
|
||||
# Select & Routing
|
||||
|
||||
Use `@update:value` to listen to the select action of the menu. The firt argument of the callback is the `key` of the selected menu item. The second is the orginal data of the menu item. Usually you can use vue-router here to accomplish routing.
|
||||
Use `@update:value` to listen to the select action of the menu. The firt argument of the callback is the `key` of the selected menu item. The second is the orginal data of the menu item.
|
||||
|
||||
Usually you can use vue-router here to accomplish routing. Also, you can render `label` as `<router-link />` or `<a />` to set route.
|
||||
|
||||
```html
|
||||
<n-menu @update:value="handleUpdateValue" :options="menuOptions" />
|
||||
@ -21,7 +23,16 @@ function renderIcon (icon) {
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
label: 'Hear the Wind Sing',
|
||||
label: () =>
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
href: 'https://en.wikipedia.org/wiki/Hear_the_Wind_Sing',
|
||||
target: '_blank',
|
||||
rel: 'noopenner noreferrer'
|
||||
},
|
||||
'Hear the Wind Sing'
|
||||
),
|
||||
key: 'hear-the-wind-sing',
|
||||
icon: renderIcon(BookIcon)
|
||||
},
|
||||
|
@ -21,7 +21,16 @@ function renderIcon (icon) {
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
label: '且听风吟',
|
||||
label: () =>
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
href: 'https://baike.baidu.com/item/%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F',
|
||||
target: '_blank',
|
||||
rel: 'noopenner noreferrer'
|
||||
},
|
||||
'且听风吟'
|
||||
),
|
||||
key: 'hear-the-wind-sing',
|
||||
icon: renderIcon(BookIcon)
|
||||
},
|
||||
|
@ -1,6 +1,8 @@
|
||||
# 选中 & 路由
|
||||
|
||||
使用 `@update:value` 监听菜单选择变化。这个回调首个参数为选中菜单项的 `key`,第二个参数为菜单项的原数据。你通常可以在这个地方配合 vue-router 完成路由。
|
||||
使用 `@update:value` 监听菜单选择变化。这个回调首个参数为选中菜单项的 `key`,第二个参数为菜单项的原数据。
|
||||
|
||||
你通常可以在这个地方配合 vue-router 完成路由。当然,你也可以通过将 `label` 渲染为 `<router-link />` 或 `<a />` 来改变路由。
|
||||
|
||||
```html
|
||||
<n-menu @update:value="handleUpdateValue" :options="menuOptions" />
|
||||
@ -21,7 +23,16 @@ function renderIcon (icon) {
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
label: '且听风吟',
|
||||
label: () =>
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
href: 'https://baike.baidu.com/item/%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F',
|
||||
target: '_blank',
|
||||
rel: 'noopenner noreferrer'
|
||||
},
|
||||
'且听风吟'
|
||||
),
|
||||
key: 'hear-the-wind-sing',
|
||||
icon: renderIcon(BookIcon)
|
||||
},
|
||||
|
@ -227,6 +227,19 @@ export default cB('menu', `
|
||||
text-overflow: ellipsis;
|
||||
color: var(--item-text-color);
|
||||
`, [
|
||||
c('a', `
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
`, [
|
||||
c('&::before', `
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
`)
|
||||
]),
|
||||
cE('extra', `
|
||||
font-size: .93em;
|
||||
color: var(--group-text-color);
|
||||
|
@ -45,24 +45,15 @@ const paginationProps = {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
showSizePicker: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showSizePicker: Boolean,
|
||||
pageSize: Number as PropType<number>,
|
||||
defaultPageSize: Number,
|
||||
pageSizes: {
|
||||
type: Array as PropType<number[]>,
|
||||
default: () => [10]
|
||||
},
|
||||
showQuickJumper: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showQuickJumper: Boolean,
|
||||
disabled: Boolean,
|
||||
pageSlot: {
|
||||
type: Number,
|
||||
default: 9
|
||||
|
@ -66,8 +66,8 @@ export default defineComponent({
|
||||
clsPrefix
|
||||
} = props
|
||||
return (
|
||||
<div class={`${clsPrefix}-progress-content`}>
|
||||
<div class={`${clsPrefix}-progress-graph`}>
|
||||
<div class={`${clsPrefix}-progress-content`} role="none">
|
||||
<div class={`${clsPrefix}-progress-graph`} aria-hidden>
|
||||
<div class={`${clsPrefix}-progress-graph-circle`}>
|
||||
<svg viewBox="0 0 110 110">
|
||||
<g>
|
||||
@ -112,11 +112,11 @@ export default defineComponent({
|
||||
{showIndicator ? (
|
||||
<div>
|
||||
{slots.default ? (
|
||||
<div class={`${clsPrefix}-progress-custom-content`}>
|
||||
<div class={`${clsPrefix}-progress-custom-content`} role="none">
|
||||
{slots.default()}
|
||||
</div>
|
||||
) : status !== 'default' ? (
|
||||
<div class={`${clsPrefix}-progress-icon`}>
|
||||
<div class={`${clsPrefix}-progress-icon`} aria-hidden>
|
||||
<NBaseIcon clsPrefix={clsPrefix}>
|
||||
{{
|
||||
default: () => iconMap[status]
|
||||
@ -129,6 +129,7 @@ export default defineComponent({
|
||||
style={{
|
||||
color: indicatorTextColor
|
||||
}}
|
||||
role="none"
|
||||
>
|
||||
<span class={`${clsPrefix}-progress-text__percentage`}>
|
||||
{percentage}
|
||||
|
@ -92,13 +92,14 @@ export default defineComponent({
|
||||
clsPrefix
|
||||
} = props
|
||||
return (
|
||||
<div class={`${clsPrefix}-progress-content`}>
|
||||
<div class={`${clsPrefix}-progress-graph`}>
|
||||
<div class={`${clsPrefix}-progress-content`} role="none">
|
||||
<div class={`${clsPrefix}-progress-graph`} aria-hidden>
|
||||
<div
|
||||
class={[
|
||||
`${clsPrefix}-progress-graph-line`,
|
||||
{
|
||||
[`${clsPrefix}-progress-graph-line--indicator-${indicatorPlacement}`]: true
|
||||
[`${clsPrefix}-progress-graph-line--indicator-${indicatorPlacement}`]:
|
||||
true
|
||||
}
|
||||
]}
|
||||
>
|
||||
@ -145,11 +146,13 @@ export default defineComponent({
|
||||
style={{
|
||||
color: indicatorTextColor
|
||||
}}
|
||||
role="none"
|
||||
>
|
||||
{slots.default()}
|
||||
</div>
|
||||
) : status === 'default' ? (
|
||||
<div
|
||||
role="none"
|
||||
class={`${clsPrefix}-progress-icon ${clsPrefix}-progress-icon--as-text`}
|
||||
style={{
|
||||
color: indicatorTextColor
|
||||
@ -159,7 +162,7 @@ export default defineComponent({
|
||||
{unit}
|
||||
</div>
|
||||
) : (
|
||||
<div class={`${clsPrefix}-progress-icon`}>
|
||||
<div class={`${clsPrefix}-progress-icon`} aria-hidden>
|
||||
<NBaseIcon clsPrefix={clsPrefix}>
|
||||
{{ default: () => iconMap[status] }}
|
||||
</NBaseIcon>
|
||||
|
@ -73,8 +73,8 @@ export default defineComponent({
|
||||
clsPrefix
|
||||
} = props
|
||||
return (
|
||||
<div class={`${clsPrefix}-progress-content`}>
|
||||
<div class={`${clsPrefix}-progress-graph`}>
|
||||
<div class={`${clsPrefix}-progress-content`} role="none">
|
||||
<div class={`${clsPrefix}-progress-graph`} aria-hidden>
|
||||
<div class={`${clsPrefix}-progress-graph-circle`}>
|
||||
<svg viewBox={`0 0 ${viewBoxWidth} ${viewBoxWidth}`}>
|
||||
{percentage.map((p, index) => {
|
||||
|
@ -12,10 +12,7 @@ import MultipleCircle from './MultipleCircle'
|
||||
|
||||
const progressProps = {
|
||||
...(useTheme.props as ThemeProps<ProgressTheme>),
|
||||
processing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
processing: Boolean,
|
||||
type: {
|
||||
type: String as PropType<'line' | 'circle' | 'multiple-circle'>,
|
||||
default: 'line'
|
||||
@ -57,26 +54,14 @@ const progressProps = {
|
||||
type: String as PropType<'inside' | 'outside'>,
|
||||
default: 'outside'
|
||||
},
|
||||
indicatorTextColor: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
indicatorTextColor: String,
|
||||
circleGap: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
borderRadius: {
|
||||
type: [String, Number] as PropType<string | number | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
fillBorderRadius: {
|
||||
type: [String, Number] as PropType<string | number | undefined>,
|
||||
default: undefined
|
||||
}
|
||||
height: Number,
|
||||
borderRadius: [String, Number] as PropType<string | number>,
|
||||
fillBorderRadius: [String, Number] as PropType<string | number>
|
||||
} as const
|
||||
|
||||
export type ProgressProps = ExtractPublicPropTypes<typeof progressProps>
|
||||
@ -171,6 +156,10 @@ export default defineComponent({
|
||||
`${mergedClsPrefix}-progress--${status}`
|
||||
]}
|
||||
style={cssVars as CSSProperties}
|
||||
aria-valuemax={100}
|
||||
aria-valuemin={0}
|
||||
aria-valuenow={percentage as number}
|
||||
role={type === 'circle' || type === 'line' ? 'progressbar' : 'none'}
|
||||
>
|
||||
{type === 'circle' ? (
|
||||
<Circle
|
||||
|
7
src/rate/demos/enUS/color.demo.md
Normal file
7
src/rate/demos/enUS/color.demo.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Color
|
||||
|
||||
That's how disaster happens.
|
||||
|
||||
```html
|
||||
<n-rate color="#4fb233" />
|
||||
```
|
22
src/rate/demos/enUS/icon.demo.md
Normal file
22
src/rate/demos/enUS/icon.demo.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Icon
|
||||
|
||||
The content in default slot will be used as icon.
|
||||
|
||||
```html
|
||||
<n-rate>
|
||||
<n-icon size="20">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-rate>
|
||||
```
|
||||
|
||||
```js
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
```
|
@ -6,13 +6,23 @@ If you not very confident, be careful about changing star's color. That will be
|
||||
|
||||
```demo
|
||||
basic
|
||||
size
|
||||
color
|
||||
icon
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --------------- | ------------------------- | ----------- | ---- |
|
||||
| count | `number` | `5` | |
|
||||
| value | `number` | `undefined` | |
|
||||
| default-value | `number` | `0` | |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | |
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| count | `number` | `5` | |
|
||||
| value | `number` | `undefined` | |
|
||||
| default-value | `number` | `0` | |
|
||||
| size | `'small' \| 'medium' \| 'large' \| number` | `'medium'` | |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | |
|
||||
|
||||
## Slots
|
||||
|
||||
| Name | Parameters | Description |
|
||||
| ------- | ---------- | --------------------- |
|
||||
| default | `()` | The icon of the rate. |
|
||||
|
11
src/rate/demos/enUS/size.demo.md
Normal file
11
src/rate/demos/enUS/size.demo.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Size
|
||||
|
||||
Rate has `small`, `medium` and `large` size. Also you can use number to specify the size.
|
||||
|
||||
```html
|
||||
<n-space align="center">
|
||||
<n-rate size="small" />
|
||||
<n-rate size="medium" />
|
||||
<n-rate size="large" />
|
||||
</n-space>
|
||||
```
|
7
src/rate/demos/zhCN/color.demo.md
Normal file
7
src/rate/demos/zhCN/color.demo.md
Normal file
@ -0,0 +1,7 @@
|
||||
# 颜色
|
||||
|
||||
灾难就是这么发生的。
|
||||
|
||||
```html
|
||||
<n-rate color="#4fb233" />
|
||||
```
|
22
src/rate/demos/zhCN/icon.demo.md
Normal file
22
src/rate/demos/zhCN/icon.demo.md
Normal file
@ -0,0 +1,22 @@
|
||||
# 图标
|
||||
|
||||
默认插槽的内容会被用作图标。
|
||||
|
||||
```html
|
||||
<n-rate>
|
||||
<n-icon size="20">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-rate>
|
||||
```
|
||||
|
||||
```js
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
```
|
@ -6,13 +6,23 @@
|
||||
|
||||
```demo
|
||||
basic
|
||||
size
|
||||
color
|
||||
icon
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --------------- | ------------------------- | ----------- | ---- |
|
||||
| count | `number` | `5` | |
|
||||
| value | `number` | `undefined` | |
|
||||
| default-value | `number` | `0` | |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | |
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| count | `number` | `5` | |
|
||||
| value | `number` | `undefined` | |
|
||||
| default-value | `number` | `0` | |
|
||||
| size | `'small' \| 'medium' \| 'large' \| number` | `'medium'` | |
|
||||
| on-update:value | `(value: number) => void` | `undefined` | |
|
||||
|
||||
## Slots
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| ------- | ---- | ---------- |
|
||||
| default | `()` | 评分的图标 |
|
||||
|
11
src/rate/demos/zhCN/size.demo.md
Normal file
11
src/rate/demos/zhCN/size.demo.md
Normal file
@ -0,0 +1,11 @@
|
||||
# 尺寸
|
||||
|
||||
有 `small`、`medium` 和 `large` 尺寸。
|
||||
|
||||
```html
|
||||
<n-space align="center">
|
||||
<n-rate size="small" />
|
||||
<n-rate size="medium" />
|
||||
<n-rate size="large" />
|
||||
</n-space>
|
||||
```
|
@ -12,7 +12,7 @@ import { useMergedState } from 'vooks'
|
||||
import { NBaseIcon } from '../../_internal'
|
||||
import { useTheme, useFormItem, useConfig } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { call } from '../../_utils'
|
||||
import { call, createKey } from '../../_utils'
|
||||
import type { ExtractPublicPropTypes, MaybeArray } from '../../_utils'
|
||||
import { rateLight } from '../styles'
|
||||
import type { RateTheme } from '../styles'
|
||||
@ -25,18 +25,16 @@ const rateProps = {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
value: Number,
|
||||
defaultValue: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large'>,
|
||||
type: [String, Number] as PropType<number | 'small' | 'medium' | 'large'>,
|
||||
default: 'medium'
|
||||
},
|
||||
color: String,
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:value': [Function, Array] as PropType<
|
||||
MaybeArray<(value: number) => void>
|
||||
@ -95,21 +93,34 @@ export default defineComponent({
|
||||
handleClick,
|
||||
handleMouseLeave,
|
||||
cssVars: computed(() => {
|
||||
const { size } = props
|
||||
const {
|
||||
common: { cubicBezierEaseInOut },
|
||||
self: { itemColor, itemColorActive, itemSize }
|
||||
self
|
||||
} = themeRef.value
|
||||
const { itemColor, itemColorActive } = self
|
||||
let mergedSize: string
|
||||
if (typeof size === 'number') {
|
||||
mergedSize = `${size}px`
|
||||
} else {
|
||||
mergedSize = self[createKey('size', size)]
|
||||
}
|
||||
return {
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--item-color': itemColor,
|
||||
'--item-color-active': itemColorActive,
|
||||
'--item-size': itemSize
|
||||
'--item-color-active': props.color || itemColorActive,
|
||||
'--item-size': mergedSize
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { hoverIndex, mergedValue, mergedClsPrefix } = this
|
||||
const {
|
||||
hoverIndex,
|
||||
mergedValue,
|
||||
mergedClsPrefix,
|
||||
$slots: { default: defaultSlot }
|
||||
} = this
|
||||
return (
|
||||
<div
|
||||
class={`${mergedClsPrefix}-rate`}
|
||||
@ -131,9 +142,13 @@ export default defineComponent({
|
||||
onClick={() => this.handleClick(index)}
|
||||
onMouseenter={() => this.handleMouseEnter(index)}
|
||||
>
|
||||
<NBaseIcon clsPrefix={mergedClsPrefix}>
|
||||
{{ default: () => StarIcon }}
|
||||
</NBaseIcon>
|
||||
{defaultSlot ? (
|
||||
defaultSlot()
|
||||
) : (
|
||||
<NBaseIcon clsPrefix={mergedClsPrefix}>
|
||||
{{ default: () => StarIcon }}
|
||||
</NBaseIcon>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
@ -9,7 +9,10 @@ const rateDark: RateTheme = {
|
||||
return {
|
||||
itemColor: railColor,
|
||||
itemColorActive: '#CCAA33',
|
||||
itemSize: '20px'
|
||||
itemSize: '20px',
|
||||
sizeSmall: '14px',
|
||||
sizeMedium: '20px',
|
||||
sizeLarge: '24px'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ const self = (vars: ThemeCommonVars) => {
|
||||
return {
|
||||
itemColor: railColor,
|
||||
itemColorActive: '#FFCC33',
|
||||
itemSize: '20px'
|
||||
sizeSmall: '16px',
|
||||
sizeMedium: '20px',
|
||||
sizeLarge: '24px'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,22 +18,13 @@ type Align =
|
||||
|
||||
const spaceProps = {
|
||||
...(useTheme.props as ThemeProps<SpaceTheme>),
|
||||
align: {
|
||||
type: String as PropType<Align>,
|
||||
default: undefined
|
||||
},
|
||||
align: String as PropType<Align>,
|
||||
justify: {
|
||||
type: String as PropType<'start' | 'end'>,
|
||||
default: 'start'
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
vertical: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
inline: Boolean,
|
||||
vertical: Boolean,
|
||||
size: {
|
||||
type: [String, Number, Array] as PropType<
|
||||
'small' | 'medium' | 'large' | number | [number, number]
|
||||
@ -107,6 +98,7 @@ export default defineComponent({
|
||||
const lastIndex = children.length - 1
|
||||
return (
|
||||
<div
|
||||
role="none"
|
||||
class={`${mergedClsPrefix}-space`}
|
||||
style={{
|
||||
display: inline ? 'inline-flex' : 'flex',
|
||||
@ -120,6 +112,7 @@ export default defineComponent({
|
||||
>
|
||||
{children.map((child, index) => (
|
||||
<div
|
||||
role="none"
|
||||
style={[
|
||||
itemStyle as any,
|
||||
{
|
||||
|
@ -1 +1 @@
|
||||
export default '2.11.8'
|
||||
export default '2.11.9'
|
||||
|
Loading…
Reference in New Issue
Block a user