提交 6c6ba5ca 编写于 作者: S songchenglin3

feat: 拉取主分支

......@@ -14,6 +14,7 @@ package-lock.json
/src/packages/nutui.ts
/src/packages/nutui.react.ts
/src/packages/nutui.*.ts
/src/sites/doc/docs.ts
/tsc/test
......
{
"name": "nutui-react",
"version": "1.0.0",
"main": "dist/nutui.react.umd.js",
"module": "dist/nutui.react.es.js",
"name": "@nutui/nutui-react",
"version": "0.1.0",
"style": "dist/style.css",
"typings": "dist/types/src/packages/nutui.react.d.ts",
"main": "dist/nutui.react.umd.js",
"module": "dist/esm/nutui-react.es.js",
"typings": "dist/esm/types/src/packages/nutui.react.d.ts",
"sideEffects": [
"*.scss",
"dist/esm/**/style/*",
"dist/style.css"
],
"description": "京东风格的轻量级移动端 React 组件库",
"keywords": [
"nutui",
"nutui2",
......@@ -18,6 +24,10 @@
],
"author": "jdcfe",
"license": "MIT",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"files": [
"dist",
"README.md",
......@@ -27,12 +37,20 @@
],
"scripts": {
"add": "node scripts/createComponentMode.js",
"generate:types": "tsc && npm run replace:types",
"generate:file": "node scripts/generate-nutui.js",
"generate:loader-style": "node scripts/generate-loader-style.js",
"replace:scss": "node scripts/replace-scss.js",
"replace:types": "node scripts/replace-types.js",
"generate:themes": "node scripts/generate-themes.js",
"checked": "npm run generate:file && tsc",
"dev": "npm run checked && vite --open --force",
"build": "npm run checked && vite build --config vite.config.build.ts && tsc && npm run generate:themes",
"build:css": "npm run generate:themes && vite build --config vite.config.build.css.ts && npm run build:replace",
"build:replace": "npm run replace:scss",
"build:esm": "npx rollup -c rollup.config.es.js",
"build": "npm run checked && vite build --config vite.config.build.ts && npm run build:esm && npm run build:css && npm run generate:types && npm run generate:loader-style",
"build:site": "npm run checked && vite build --config vite.config.build.site.ts",
"publish:beta": "npm publish --tag beta",
"prepare": "husky install"
},
"lint-staged": {
......@@ -42,27 +60,43 @@
"*.{js,css,md}": "prettier --write"
},
"dependencies": {
"@babel/runtime": "^7.16.5",
"@bem-react/classname": "^1.5.10",
"@react-spring/web": "^9.3.2",
"@use-gesture/react": "^10.2.4",
"classnames": "^2.3.1"
"classnames": "^2.3.1",
"react-router-dom": "^5.2.0",
"react-transition-group": "^4.4.2"
},
"devDependencies": {
"@babel/preset-react": "^7.13.13",
"@babel/plugin-proposal-class-properties": "^7.16.5",
"@babel/plugin-proposal-object-rest-spread": "^7.16.5",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.16.5",
"@babel/preset-env": "^7.16.5",
"@babel/preset-react": "^7.16.5",
"@babel/preset-typescript": "^7.16.5",
"@commitlint/cli": "^12.1.4",
"@commitlint/config-conventional": "^12.1.4",
"@loadable/component": "^5.15.0",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.1.1",
"@rollup/plugin-typescript": "^8.3.0",
"@types/loadable__component": "^5.13.3",
"@types/node": "^15.3.1",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"@types/react-syntax-highlighter": "^13.5.2",
"@types/react-transition-group": "^4.4.4",
"@typescript-eslint/eslint-plugin": "^4.24.0",
"@typescript-eslint/parser": "^4.24.0",
"@vitejs/plugin-react": "^1.1.3",
"@vitejs/plugin-react-refresh": "^1.3.1",
"autoprefixer": "^10.4.0",
"axios": "^0.21.1",
"babel-plugin-react-scoped-css": "^1.1.1",
"eslint": "^7.26.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-config-prettier": "^8.3.0",
......@@ -71,20 +105,26 @@
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.2.0",
"fs-extra": "^10.0.0",
"glob": "^7.2.0",
"husky": "^6.0.0",
"inquirer": "^8.0.0",
"lint-staged": "^11.0.0",
"map-stream": "0.0.7",
"marked": "^2.0.3",
"postcss-import": "^14.0.2",
"postcss-modules": "^4.2.2",
"prettier": "2.3.0",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"react-router-dom": "^5.2.0",
"react-transition-group": "^4.4.2",
"sass": "^1.32.13",
"react-markdown": "^7.1.2",
"react-syntax-highlighter": "^15.4.5",
"remark-directive": "^2.0.1",
"remark-gfm": "^3.0.1",
"sass": "^1.45.0",
"shelljs": "^0.8.4",
"typescript": "^4.1.2",
"unist-util-visit": "^4.1.0",
"vinyl-fs": "^3.0.3",
"vite": "^2.1.5",
"vite-plugin-markdown": "^2.0.2"
"vite": "^2.1.5"
}
}
import commonjs from '@rollup/plugin-commonjs'
import typescript from '@rollup/plugin-typescript'
import { getBabelOutputPlugin } from '@rollup/plugin-babel'
const path = require('path')
const config = require('./src/config.json')
const entries = { 'nutui-react.es': path.join(__dirname, `./src/packages/nutui.react.build.ts`) }
const outputEntries = {}
config.nav.map((item) => {
item.packages.forEach((element) => {
let { name, show, type, exportEmpty } = element
if (show || exportEmpty) {
outputEntries[`./${name.toLowerCase()}`] = `./${name}`
entries[name] = path.join(__dirname, `./src/packages/${name.toLowerCase()}/index.ts`)
}
})
})
export default {
input: entries,
external: (id, parent) =>
/^react/.test(id) || /^react\-dom/.test(id) || (/^\@\/packages\/\w+$/.test(id) && !!parent),
output: {
format: 'esm',
dir: './dist/esm',
name: '[entryName].js',
paths: (id) => {
return /@\/packages/.test(id) ? outputEntries[id.replace('@/packages/', './')] + '.js' : id
},
},
plugins: [
commonjs(),
typescript(),
getBabelOutputPlugin({
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-syntax-dynamic-import',
],
}),
],
}
const config = require('../src/config.json')
const path = require('path')
const fs = require('fs-extra')
let importScssStr = `\n`
config.nav.map((item) => {
item.packages.forEach((element) => {
let { name, show, exportEmpty } = element
const nameLowerCase = name.toLowerCase()
const file = path.resolve(process.cwd(), `dist/esm/${name}/style/index.js`)
if (show || exportEmpty) {
importScssStr = `import '../../../packages/${nameLowerCase}/${nameLowerCase}.scss'`
fs.outputFileSync(file, importScssStr)
}
})
})
const package = require('../package.json')
// generate nutui.react.ts file for dev or build
const config = require('../src/config.json')
const path = require('path')
const fs = require('fs-extra')
let importStr = ``
let importMarkdownStr = ``
let importScssStr = `\n`
const packages = []
const mds = []
config.nav.map((item) => {
item.packages.forEach((element) => {
let { name, show, type } = element
if (show) {
importStr += `import ${name} from './${name.toLowerCase()}';\n`
let { name, show, type, exportEmpty } = element
if (show || exportEmpty) {
importStr += `import ${name} from '@/packages/${name.toLowerCase()}';\n`
importScssStr += `import '@/packages/${name.toLowerCase()}/${name.toLowerCase()}.scss';\n`
packages.push(name)
}
if (show) {
importMarkdownStr += `import ${name} from '@/packages/${name.toLowerCase()}/doc.md?raw';\n`
mds.push(name)
}
})
})
let fileStr = `${importStr}
let fileStrBuild = `${importStr}
export { ${packages.join(',')} };`
fs.outputFile(
path.resolve(__dirname, '../src/packages/nutui.react.build.ts'),
fileStrBuild,
'utf8',
(error) => {
if (error) throw error
}
)
let fileStr = `${importStr}
${importScssStr}
export { ${packages.join(',')} };`
fs.outputFile(
path.resolve(__dirname, '../src/packages/nutui.react.ts'),
fileStr,
......@@ -25,3 +46,12 @@ fs.outputFile(
if (error) throw error
}
)
let mdFileStr = `${importMarkdownStr}
export const routers = [${mds.map((m) => `'${m}'`)}]
export const raws = {${mds.join(',')}}
`
fs.outputFile(path.resolve(__dirname, '../src/sites/doc/docs.ts'), mdFileStr, 'utf8', (error) => {
if (error) throw error
})
const config = require('../src/config.json')
const path = require('path')
const fs = require('fs-extra')
let fileStr = `@import '../variables.scss';\n`
const glob = require('glob')
const componetsScss = glob.sync('./src/packages/**/*.scss')
let tasks = []
componetsScss.map((cs) => {
console.log(cs)
if (cs.indexOf('demo.scss') > -1) return
tasks.push(
fs
.copy(
path.resolve(__dirname, `.${cs}`),
path.resolve(__dirname, `../dist`, `${cs.replace('./src/', '')}`)
)
.catch((error) => {})
)
})
let fileStr = `@import '../variables.scss';\n`
config.nav.map((item) => {
item.packages.forEach((element) => {
let folderName = element.name.toLowerCase()
tasks.push(
fs
.copy(
path.resolve(__dirname, `../src/packages/${folderName}/${folderName}.scss`),
path.resolve(__dirname, `../dist/packages/${folderName}/index.scss`)
)
.then((success) => {
fileStr += `@import '../../packages/${folderName}/index.scss';\n`
})
.catch((error) => {})
)
fileStr += `@import '../../packages/${folderName}/${folderName}.scss';\n`
// tasks.push(
// fs
// .copy(
// path.resolve(__dirname, `../src/packages/${folderName}/${folderName}.scss`),
// path.resolve(__dirname, `../dist/packages/${folderName}/${folderName}.scss`)
// )
// .then((success) => {
// fileStr += `@import '@/packages/${folderName}/${folderName}.scss';\n`
// })
// .catch((error) => {})
// )
})
})
......
const config = require('../src/config.json');
const path = require('path');
const fs = require('fs-extra');
const config = require('../src/config.json')
const path = require('path')
const fs = require('fs-extra')
let importStr = `import { App } from 'vue';
declare class UIComponent {
static install(vue: App): void;
}\n`;
const packages = [];
config.nav.map(item => {
item.packages.forEach(element => {
let { name, show } = element;
if (show) {
importStr += `declare class ${name} extends UIComponent {}\n`;
packages.push(name);
}\n`
const packages = []
config.nav.map((item) => {
item.packages.forEach((element) => {
let { name, show, exportEmpty, type } = element
if (show || exportEmpty) {
importStr += `declare class ${name} extends UIComponent {}\n`
packages.push(name)
}
});
});
})
})
let installFunction = `
export interface InstallationOptions {
locale?: any;
......@@ -26,23 +26,18 @@ declare const _default: {
install: typeof install;
version: string;
};
export default _default;`;
let fileStr = importStr + installFunction;
fs.outputFile(
path.resolve(__dirname, '../dist/nutui.d.ts'),
fileStr,
'utf8',
error => {
// logger.success(`${package_config_path} 文件写入成功`);
}
);
export default _default;`
let fileStr = importStr + installFunction
fs.outputFile(path.resolve(__dirname, '../dist/nutui.d.ts'), fileStr, 'utf8', (error) => {
// logger.success(`${package_config_path} 文件写入成功`);
})
fs.outputFile(
path.resolve(__dirname, '../dist/index.d.ts'),
`import * as NutUI from './nutui';
export default NutUI;
export * from './nutui';`,
'utf8',
error => {
(error) => {
// logger.success(`${package_config_path} 文件写入成功`);
}
);
)
// replace scss alias for build
const package = require('../package.json')
const vfs = require('vinyl-fs')
const map = require('map-stream')
const dest_docs = './dist/packages'
const correctionImport = function (file, cb) {
const contents = file.contents
.toString()
.replaceAll('@/packages', `${package.name}/dist/packages`)
.replaceAll('@/styles', `${package.name}/dist/styles`)
file.contents = Buffer.from(contents, 'utf8')
cb(null, file)
}
vfs
.src(['./src/packages/**/*.scss', '!./src/packages/**/demo.scss'])
.pipe(map(correctionImport))
.pipe(vfs.dest(dest_docs))
.on('end', () => {})
// replace types alias for build
const vfs = require('vinyl-fs')
const map = require('map-stream')
const dest_docs = './dist/esm/types/src/packages'
vfs
.src(['./dist/esm/types/src/packages/nutui.react.d.ts'])
.pipe(
map((file, cb) => {
const contents = file.contents
.toString()
.replaceAll('@/packages', `.`)
.replace(/import\s(.*)?\.scss\'\;[\t\n]/g, '')
file.contents = Buffer.from(contents, 'utf8')
cb(null, file)
})
)
.pipe(vfs.dest(dest_docs, { overwrite: true }))
.on('end', () => {})
vfs
.src(['./dist/esm/types/src/packages/**/*.d.ts', '!./dist/esm/types/src/packages/*.d.ts'])
.pipe(
map((file, cb) => {
const contents = file.contents.toString().replaceAll('@/packages', `..`)
file.contents = Buffer.from(contents, 'utf8')
cb(null, file)
})
)
.pipe(vfs.dest(dest_docs, { overwrite: true }))
.on('end', () => {})
......@@ -12,7 +12,7 @@ const tmp = '/tmp'
const repo = 'nutui-docs'
const base = process.cwd()
const components = path.join(base, 'src/packages')
const dest_docs = path.join(tmp, `${repo}/src/doc_react/docs`)
const dest_docs = path.join(tmp, `${repo}/src/docs_react/docs`)
async function sync_docs() {
const rm_dest_result = await rm(path.join(tmp, repo), {
......
const fileRegex = /demo\.tsx$/
export default function viteDemoPlugin() {
return {
name: 'viteDemoPlugin',
configureServer(server) {
server.middlewares.use((req, res, next) => {
// custom handle request...
if (req.url.indexOf('demo.scss') > -1) {
req.redirect(req.url.replace('demo.scss', 'demo.module.scss'))
}
next()
})
},
transform(src, id) {
if (fileRegex.test(id)) {
return {
code: src,
map: null, // 如果可行将提供 source map
}
}
},
}
}
{
"versions": [
{
"name": "1.x",
"link": "/1x/"
},
{
"name": "2.x",
"link": "/"
},
{
"name": "3.x",
"link": "/3x/"
},
{
"name": "nutui-jdl",
"link": "/jdl/"
},
{
"name": "nutui-react",
"link": "https://github.com/jdf2e/nutui/tree/nutui-react"
}
],
"header": [
{
"name": "guide",
"cName": "指南",
"path": "/intro"
},
{
"name": "intro",
"cName": "组件",
"path": "/intro"
},
{
"name": "example",
"cName": "示例",
"path": "/"
},
{
"name": "resource",
"cName": "资源",
"path": "/resource"
}
],
"docs": {
"name": "指南",
"packages": [
{
"name": "intro",
"name": "intro-react",
"cName": "介绍",
"show": true
},
{
"name": "start",
"name": "start-react",
"cName": "快速上手",
"show": true
},
{
"name": "theme",
"name": "theme-react",
"cName": "主题定制",
"show": true
},
......@@ -72,7 +28,7 @@
"show": true
},
{
"name": "https://github.com/jdf2e/nutui/releases",
"name": "https://github.com/jdf2e/nutui-react/releases",
"cName": "更新日志",
"show": true,
"isLink": true
......@@ -84,7 +40,7 @@
"name": "基础组件",
"packages": [
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Avatar",
"type": "component",
"cName": "头像",
......@@ -94,7 +50,7 @@
"author": "junjun"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Button",
"type": "component",
"cName": "按钮",
......@@ -104,27 +60,38 @@
"author": ""
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Cell",
"type": "component",
"cName": "列表组件",
"cName": "单元格",
"desc": "列表项,可组成列表",
"sort": 2,
"show": true,
"author": "songsong"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "CellGroup",
"type": "component",
"cName": "单元格",
"desc": "列表项,可组成列表",
"sort": 2,
"show": false,
"exportEmpty": true,
"author": "songsong"
},
{
"version": "0.1.0",
"name": "Icon",
"type": "component",
"cName": "图标组件",
"desc": "图标",
"cName": "图标",
"desc": "基于 IconFont 字体的图标集",
"sort": 1,
"show": true,
"author": "oasis-cloud"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Price",
"type": "component",
"cName": "价格",
......@@ -134,7 +101,7 @@
"author": "songsong"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Overlay",
"type": "component",
"cName": "遮罩层",
......@@ -144,7 +111,7 @@
"author": "junjun"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Divider",
"type": "component",
"cName": "分割线",
......@@ -159,7 +126,7 @@
"name": "布局组件",
"packages": [
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Layout",
"type": "component",
"cName": "布局",
......@@ -169,23 +136,25 @@
"author": "yushuang24"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Row",
"type": "component",
"cName": "行",
"desc": "布局组件中的行",
"sort": 2,
"show": true,
"show": false,
"exportEmpty": true,
"author": "yushuang24"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Col",
"type": "component",
"cName": "列",
"desc": "布局组件中的列",
"sort": 3,
"show": true,
"show": false,
"exportEmpty": true,
"author": "yushuang24"
}
]
......@@ -194,7 +163,7 @@
"name": "操作反馈",
"packages": [
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Drag",
"type": "component",
"cName": "拖拽",
......@@ -204,7 +173,7 @@
"author": "songsong"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Collapse",
"type": "component",
"cName": "折叠面板",
......@@ -214,7 +183,7 @@
"author": "zhenyulei"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Toast",
"type": "component",
"cName": "吐司",
......@@ -224,7 +193,7 @@
"author": "VickyYe"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "BackTop",
"type": "component",
"cName": "返回顶部",
......@@ -234,7 +203,7 @@
"author": "vickyYe"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Range",
"type": "component",
"cName": "区间选择器",
......@@ -244,7 +213,7 @@
"author": "vickyYe"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Infiniteloading",
"type": "component",
"cName": "滚动加载",
......@@ -254,7 +223,7 @@
"author": "swag~jun"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Steps",
"type": "component",
"cName": "步骤条",
......@@ -264,17 +233,28 @@
"author": "swag~jun"
},
{
"version": "1.0.0",
"version": "3.0.0",
"name": "Step",
"sort": 17,
"cName": "步骤条子组件",
"type": "component",
"show": false,
"exportEmpty": true,
"desc": "步骤条子组件",
"author": "swag~jun"
},
{
"version": "0.1.0",
"name": "CircleProgress",
"type": "component",
"cName": "进度条",
"cName": "环形进度条",
"desc": "展示操作或任务的当前进度。",
"sort": 7,
"show": true,
"author": "swag~jun"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Popup",
"sort": 9,
"cName": "弹出层",
......@@ -284,7 +264,7 @@
"author": "szg2008"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "ActionSheet",
"type": "component",
"cName": "动作面板",
......@@ -294,17 +274,17 @@
"author": "dsj"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "NoticeBar",
"type": "component",
"cName": "告栏",
"cName": "告栏",
"desc": "用于循环播放展示一组消息通知。",
"sort": 11,
"show": true,
"author": "vickyYe"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Notify",
"type": "component",
"cName": "消息通知",
......@@ -314,17 +294,17 @@
"author": "vickyYE"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Dialog",
"type": "component",
"cName": "对话框",
"desc": "对话框",
"desc": "模态对话框",
"sort": 12,
"show": true,
"author": "yangjinjun3"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Switch",
"type": "component",
"cName": "开关",
......@@ -334,14 +314,36 @@
"author": "dsj"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "CollapseItem",
"type": "component",
"cName": "折叠面板子组件",
"desc": "折叠面板的子组件",
"sort": 13,
"show": false,
"exportEmpty": true,
"author": "zhenyulei"
},
{
"version": "1.0.0",
"name": "Swiper",
"type": "component",
"cName": "轮播",
"desc": "轮播组件",
"sort": 14,
"show": true,
"author": "liukun"
},
{
"version": "1.0.0",
"name": "SwiperItem",
"type": "component",
"cName": "轮播子组件",
"desc": "轮播子组件",
"sort": 14,
"show": false,
"exportEmpty": true,
"author": "liukun"
}
]
},
......@@ -349,27 +351,38 @@
"name": "导航组件",
"packages": [
{
"version": "1.0.0",
"version": "0.1.0",
"name": "NavBar",
"type": "component",
"cName": "导航组件",
"cName": "头部导航",
"desc": "提供导航功能。",
"sort": 1,
"show": true,
"author": "dsj"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Tabbar",
"type": "component",
"cName": "标签栏组件",
"cName": "标签栏",
"desc": "底部导航常用场景",
"sort": 2,
"show": true,
"author": "dsj"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "TabbarItem",
"sort": 2,
"cName": "标签栏子组件",
"type": "component",
"show": false,
"exportEmpty": true,
"desc": "标签栏子组件",
"author": "dsj"
},
{
"version": "0.1.0",
"name": "InputNumber",
"type": "component",
"cName": "数字输入框",
......@@ -379,7 +392,7 @@
"author": "swag~jun"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Elevator",
"type": "component",
"cName": "电梯楼层",
......@@ -389,7 +402,7 @@
"author": "songsong"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "FixedNav",
"type": "component",
"cName": "悬浮导航",
......@@ -399,10 +412,10 @@
"author": "Ymm0008"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Pagination",
"type": "component",
"cName": "分页组件",
"cName": "分页",
"desc": "当数据量较多时,采用分页的形式分隔长列表。",
"sort": 6,
"show": true,
......@@ -414,7 +427,7 @@
"name": "数据录入",
"packages": [
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Rate",
"type": "component",
"cName": "评分",
......@@ -424,7 +437,7 @@
"author": "dsj"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Uploader",
"type": "component",
"cName": "上传",
......@@ -434,7 +447,7 @@
"author": "swag~jun"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Input",
"type": "component",
"cName": "输入框",
......@@ -444,7 +457,7 @@
"author": "VickyYe"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "TextArea",
"type": "component",
"cName": "文本域",
......@@ -454,8 +467,8 @@
"author": "VickyYe"
},
{
"version": "1.0.0",
"name": "CheckBox",
"version": "0.1.0",
"name": "Checkbox",
"type": "component",
"cName": "复选按钮",
"desc": "多选按钮用于选择。",
......@@ -464,7 +477,18 @@
"author": "oasis"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "CheckboxGroup",
"type": "component",
"cName": "多选按钮组",
"desc": "多选按钮组",
"sort": 11,
"show": false,
"exportEmpty": true,
"author": "oasis"
},
{
"version": "0.1.0",
"name": "Tag",
"type": "component",
"cName": "标签",
......@@ -474,7 +498,17 @@
"author": "lzz"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Popover",
"type": "component",
"cName": "气泡弹出框",
"desc": "气泡弹出框",
"sort": 19,
"show": true,
"author": "lzz"
},
{
"version": "0.1.0",
"name": "Badge",
"type": "component",
"cName": "徽标",
......@@ -484,7 +518,7 @@
"author": "lzz"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "AnimatingNumbers",
"type": "component",
"cName": "数字动画",
......@@ -494,7 +528,7 @@
"author": "songsong"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Radio",
"type": "component",
"cName": "单选按钮",
......@@ -504,21 +538,22 @@
"author": "oasis"
},
{
"version": "1.0.0",
"name": "Picker",
"version": "0.1.0",
"name": "RadioGroup",
"type": "component",
"cName": "选择器",
"desc": "提供多个选项集合供用户选择其中一项。",
"cName": "单选按钮组",
"desc": "单选按钮组",
"sort": 10,
"show": true,
"author": "dsj"
"exportEmpty": true,
"show": false,
"author": "oasis"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "ShortPassword",
"type": "component",
"cName": "短密码",
"desc": "",
"desc": "短密码输入框",
"sort": 10,
"show": true,
"author": "Drjingfubo"
......@@ -531,6 +566,26 @@
"sort": 10,
"show": true,
"author": "szg2008"
},
{
"name": "CalendarItem",
"type": "component",
"cName": "日历",
"desc": "日历,可平铺/弹窗展示",
"sort": 10,
"show": false,
"exportEmpty": true,
"author": "szg2008"
},
{
"version": "1.0.0",
"name": "Picker",
"type": "component",
"cName": "选择器",
"desc": "提供多个选项集合供用户选择其中一项。",
"sort": 10,
"show": true,
"author": "dsj"
}
]
},
......@@ -538,17 +593,17 @@
"name": "特色组件",
"packages": [
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Signature",
"type": "component",
"cName": "签",
"cName": "签",
"desc": "基于Canvas的签名组件",
"sort": 1,
"show": true,
"author": "songsong"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Barrage",
"type": "component",
"cName": "弹幕",
......@@ -558,10 +613,10 @@
"author": "swag~jun"
},
{
"version": "1.0.0",
"version": "0.1.0",
"name": "Address",
"type": "component",
"cName": "地址组件",
"cName": "地址",
"desc": "地址组件",
"sort": 3,
"show": true,
......
@import '../popup/popup.scss';
.nut-actionsheet {
display: block;
.nut-actionsheet__title {
......
import React, { FunctionComponent, useState, useEffect } from 'react'
import Popup from '@/packages/popup'
import './actionsheet.scss'
import bem from '@/utils/bem'
export type ItemType<T> = { [key: string]: T }
......
@import '../icon/icon.scss';
@import '../popup/popup.scss';
@import '../elevator/elevator.scss';
.nut-address {
display: block;
&__header {
......
......@@ -4,7 +4,6 @@ import Popup from '@/packages/popup'
import bem from '@/utils/bem'
import { ExistRender } from './existRender'
import { CustomRender } from './customRender'
import './address.scss'
export interface RegionData {
name?: string
......
......@@ -2,7 +2,6 @@ import React, { FunctionComponent, useEffect, useState, useRef } from 'react'
import Icon from '@/packages/icon'
import bem from '@/utils/bem'
import Elevator from '@/packages/elevator'
import './address.scss'
import { RegionData } from './address'
interface CustomRegionData {
......
# Address组件
# Address 地址
### 介绍
按需加载请加载对应依赖组件 Icon Popup Elevator
地址选择
### 安装
``` javascript
......
import React, { FunctionComponent, useEffect, useState, useRef } from 'react'
import Icon from '@/packages/icon'
import bem from '@/utils/bem'
import './address.scss'
import { AddressList } from './address'
export interface ExistRenderProps {
......
@import '@/packages/animatingnumbers/countup.scss';
.nut-animatingnumbers {
}
import React, { FunctionComponent, Component } from 'react'
import './animatingnumbers.scss'
import { CountUp } from './countup'
......
import React, { CSSProperties, FunctionComponent, useEffect, useRef, useState } from 'react'
import './countup.scss'
import bem from '@/utils/bem'
export interface CountUpProps {
......
# AnimatingNumbers 组件
# AnimatingNumbers 数字动画
### 介绍
......
import React, { FunctionComponent, MouseEventHandler } from 'react'
import Icon from '@/packages/icon'
import classNames from 'classnames'
import './avatar.scss'
export interface AvatarProps {
size: AvatarSize
......
@import '../icon/icon.scss';
.nut-backtop {
display: none;
position: fixed;
......
import React, {
FunctionComponent,
useLayoutEffect,
useEffect,
useState,
useRef,
CSSProperties,
} from 'react'
import './backtop.scss'
import Icon from '../icon'
import classNames from 'classnames'
import React, { FunctionComponent, useEffect, useState, CSSProperties } from 'react'
import Icon from '@/packages/icon'
declare const window: any
export interface BackTopProps {
className?: string
......
# BackTop 组件
# BackTop 返回顶部
### 介绍
......
......@@ -5,7 +5,7 @@ import React, {
useEffect,
useState,
} from 'react'
import './badge.scss'
import Icon from '@/packages/icon'
export interface BadgeProps {
value: any
......
import React, { ForwardRefRenderFunction, useEffect, useRef, useImperativeHandle } from 'react'
import classNames from 'classnames'
import bem from '@/utils/bem'
import './barrage.scss'
export interface BarrageProps {
className: string
......
.nut-cell,
.nut-barrage {
.barrage-demo-wrap,
.barrage-demo {
padding: 20px 0;
height: 150px;
}
......@@ -2,7 +2,7 @@ import React, { useRef } from 'react'
import Cell from '@/packages/cell'
import { Barrage } from './barrage'
import Button from '@/packages/button'
import './demo.scss'
import './demo.scss?module'
interface barrageRefState {
add: (word: string) => void
......@@ -21,8 +21,8 @@ const BarrageDemo = () => {
<>
<div className="demo">
<h2>基础用法</h2>
<Cell>
<Barrage ref={barrageRef} barrageList={list}></Barrage>
<Cell className={'barrage-demo-wrap'}>
<Barrage className={'barrage-demo'} ref={barrageRef} barrageList={list}></Barrage>
</Cell>
<div className="test" style={{ textAlign: 'center' }}>
<Button type="danger" onClick={addBarrage}>
......
@import '../icon/icon.scss';
.nut-button {
position: relative;
display: inline-block;
......
import React, { CSSProperties, FunctionComponent, useEffect, useState } from 'react'
import './button.scss'
import Icon from '@/packages/icon'
export interface ButtonProps {
className: string
......
......@@ -196,3 +196,4 @@
}
}
}
@import '@/packages/calendaritem/calendaritem.scss';
......@@ -2,7 +2,6 @@ import React, { FunctionComponent } from 'react'
import Popup from '@/packages/popup'
import CalendarItem from '@/packages/calendaritem'
import Utils from '@/utils/date'
import './calendar.scss'
export interface CalendarProps {
type?: string
......
import React, { FunctionComponent, useState, useEffect, useRef } from 'react'
import bem from '@/utils/bem'
import classNames from 'classnames'
import './calendaritem.scss'
import Utils from '@/utils/date'
import requestAniFrame from '../../utils/raf'
import requestAniFrame from '@/utils/raf'
type InputDate = string | string[]
......
import React, { FunctionComponent, CSSProperties, ReactNode } from 'react'
import { useHistory } from 'react-router-dom'
import './cell.scss'
import bem from '@/utils/bem'
import { Icon } from '../icon/icon'
......
import React, { FunctionComponent } from 'react'
import './cellgroup.scss'
import bem from '@/utils/bem'
export interface CellGroupProps {
......
@import '@/packages/icon/icon.scss';
.nut-checkbox {
display: flex;
align-items: center;
......
import React, { FunctionComponent, useEffect, useState } from 'react'
import Icon from '../icon'
import { CheckboxGroup } from '@/packages/checkboxgroup/checkboxgroup'
import './checkbox.scss'
import CheckboxGroup from '@/packages/checkboxgroup'
import bem from '@/utils/bem'
export interface CheckBoxProps {
......
......@@ -7,7 +7,7 @@
### 安装
``` ts
import { Checkbox,CheckBoxGroup,Icon } from '@nutui/nutui-react';
import { Checkbox, CheckBoxGroup } from '@nutui/nutui-react';
```
......
import React, { FunctionComponent, useEffect, useImperativeHandle, useState } from 'react'
import '../checkbox/checkbox.scss'
import bem from '@/utils/bem'
export interface CheckBoxGroupProps {
......
import { CheckboxGroup } from './checkboxgroup'
export default CheckboxGroup
import React, { FunctionComponent } from 'react'
import bem from '@/utils/bem'
import classNames from 'classnames'
import './circleprogress.scss'
export interface CircleProgressProps {
strokeInnerWidth: string | number
......
......@@ -15,10 +15,10 @@
@for $i from 1 through 24 {
.nut-col-offset-#{$i} {
margin-left: 100/ 24 * $i * 1%;
margin-left: calc(100 / 24) * $i * 1%;
}
.nut-col-#{$i} {
width: 100/ 24 * $i * 1%;
width: calc(100 / 24) * $i * 1%;
}
}
import React, { FunctionComponent, useEffect, useState, CSSProperties, useContext } from 'react'
import { DataContext } from '@/packages/row/UserContext'
import './col.scss'
export interface ColProps {
span: string | number
......
@import '@/packages/collapseitem/collapseitem.scss';
import React, { FunctionComponent, useEffect, useState, memo } from 'react'
import './collapse.scss'
import bem from '@/utils/bem'
export interface CollapseProps {
......
# Collapse组件
# Collapse 折叠面板
### 介绍
......
import React, { FunctionComponent, useEffect, useState, useCallback } from 'react'
import './collapseItem.scss'
import bem from '@/utils/bem'
import Icon from '../icon'
......
import React, { ForwardRefRenderFunction, HTMLAttributes, forwardRef } from 'react'
import classNames from 'classnames'
import Button from '@/packages/button'
import './dialog.scss'
import { DialogWrapper } from './DialogWrapper'
import confirm from './Confirm'
import { DialogProps, DialogReturnProps, DialogComponent, ConfirmProps } from './config'
......
......@@ -8,7 +8,9 @@
### 安装
`import { Dialog } from 'nutui-react'`
```js
import { Dialog } from '@nutui/nutui-react'
```
## 代码演示
......@@ -101,6 +103,6 @@ return <>
| 事件名 | 说明 | 回调参数 |
|--------|----------------|--------------|
| onOk | 确定按钮回调 | (e?: MouseEvent) => Promise<any> | void |
| onOk | 确定按钮回调 | (e?: MouseEvent) => Promise | void |
| onCancel | 取消按钮回调 | () => void |
| onClosed | 关闭回调,任何情况关闭弹窗都会触发 | Function |
import React, { FunctionComponent } from 'react'
import './divider.scss'
import bem from '@/utils/bem'
import classNames from 'classnames'
......
......@@ -60,6 +60,7 @@ const bottom = () => {
### Props
| 参数 | 说明 | 类型 | 默认值 |
| --------------- | ----------------------------- | ------- | ------ |
| attract | 是否开启自动吸边 | Boolean | false |
| direction | 拖拽元素的拖拽方向限制,**x**/**y**/**all**三选一 | String |'all' |
| direction | 拖拽元素的拖拽方向限制,x、y、all三选一 | String |'all' |
| boundary | 拖拽元素的拖拽边界 | Object | {top: 0,left: 0,right: 0,bottom: 0} |
import React, { FunctionComponent, useRef, useEffect, useState } from 'react'
import './elevator.scss'
import bem from '@/utils/bem'
export interface ElevatorProps {
......
......@@ -4,8 +4,6 @@ import bem from '@/utils/bem'
import classNames from 'classnames'
import { Overlay } from '../overlay/overlay'
import './fixednav.scss'
type Direction = 'right' | 'left'
type Position = {
top?: string
......
# Icon 图标组件
# Icon 图标
### 介绍
......
import React, { FunctionComponent, ReactHTML } from 'react'
import bem from '@/utils/bem'
import './icon.scss'
interface IconProps {
name: string
......
......@@ -2,7 +2,6 @@ import React, { useState, useEffect, useRef, FunctionComponent } from 'react'
import bem from '@/utils/bem'
import classNames from 'classnames'
import Icon from '@/packages/icon'
import './infiniteloading.scss'
export interface InfiniteloadingProps {
hasMore: boolean
......
# Input 输入框组件
# Input 输入框
### 介绍
......
import React, { CSSProperties, FunctionComponent, useEffect, useState } from 'react'
import './input.scss'
import bem from '@/utils/bem'
import { formatNumber } from './util'
import Icon from '../icon'
import Icon from '@/packages/icon'
import classNames from 'classnames'
export interface InputProps {
......
......@@ -2,7 +2,6 @@ import React, { useState, useEffect, FunctionComponent, ChangeEvent, FocusEvent
import Icon from '@/packages/icon'
import classNames from 'classnames'
import bem from '@/utils/bem'
import './inputnumber.scss'
export interface InputNumberProps {
disabled: boolean
......
# Layout布局
# Layout 布局
### 介绍
......
import React, { FunctionComponent } from 'react'
import './layout.scss'
export interface LayoutProps {}
const defaultProps = {} as LayoutProps
......
import React, { FunctionComponent } from 'react'
import Icon from '../icon'
import bem from '@/utils/bem'
import './navbar.scss'
import classNames from 'classnames'
export interface NavBarProps {
......
# NoticeBar告栏
# NoticeBar告栏
### 介绍
......
......@@ -7,7 +7,7 @@ import React, {
MouseEvent,
CSSProperties,
} from 'react'
import './noticebar.scss'
import { number } from 'prop-types'
import Icon from '../icon'
import bem from '@/utils/bem'
......
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import bem from '@/utils/bem'
import './notify.scss'
import classNames from 'classnames'
import { CSSTransition } from 'react-transition-group'
export interface NotificationProps {
......
# Overlay 组件
# Overlay 遮罩层
### 介绍
......
import React, { FunctionComponent, MouseEventHandler, useEffect, useRef, useState } from 'react'
import bem from '@/utils/bem'
import classNames from 'classnames'
import './overlay.scss'
export interface OverlayProps {
zIndex: number
......
import React, { useState } from 'react'
import { Pagination } from './pagination'
import Pagination from '@/packages/pagination'
import Icon from '@/packages/icon'
const PaginationDemo = () => {
const [currentPage1, setCurrent1] = useState(1)
......
import React, { FunctionComponent, useEffect, useState } from 'react'
import Icon from '../icon'
import './pagination.scss'
import bem from '@/utils/bem'
export interface PaginationProps {
defaultValue: number
......
# Picker选择器
# Picker 选择器
### 介绍
......
import Picker from './picker'
import './picker.scss'
export default Picker
@import '../popup/popup.scss';
.nut-picker {
background-color: #fff;
width: 100%;
......
......@@ -6,7 +6,6 @@ import React, {
useImperativeHandle,
ForwardRefRenderFunction,
} from 'react'
import './picker.scss'
import Popup from '@/packages/popup'
import PickerSlot from './pickerSlot'
import bem from '@/utils/bem'
......
@import '@/packages/icon/icon.scss';
.popBox {
// background: skyblue;
// // background: #fff;
......
......@@ -8,7 +8,6 @@ import React, {
} from 'react'
import Trigger from './Trigger'
import ReactDOM from 'react-dom'
import './popover.scss'
import Icon from '@/packages/icon'
export interface PopoverProps {
list: Array<any>
......
<!--
* @Author: your name
* @Date: 2021-12-01 09:41:23
* @LastEditTime: 2021-12-28 09:50:26
* @LastEditors: your name
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
* @FilePath: /nutui-react/src/packages/popup/doc.md
-->
# Popup 弹出层
### 介绍
......
@import '../icon/icon.scss';
@import '../overlay/overlay.scss';
.popup-slide {
&-center-enter,
&-center-exit {
......
......@@ -12,7 +12,7 @@ import Icon from '@/packages/icon'
import Overlay from '@/packages/overlay'
import classNames from 'classnames'
import bem from '@/utils/bem'
import './popup.scss'
import { EnterHandler, ExitHandler } from 'react-transition-group/Transition'
interface PopupProps extends OverlayProps {
......
# Price 商品价格
# Price 价格
### 介绍
......
import React, { FunctionComponent } from 'react'
import './price.scss'
import bem from '@/utils/bem'
export interface PriceProps {
......
......@@ -16,14 +16,16 @@ const RadioDemo = () => {
return (
<>
<div className="demo full">
<CellGroup title="基本用法">
<h2>基本用法</h2>
<CellGroup>
<Cell>
<Radio checked={checked1} value="1">
选项1
</Radio>
</Cell>
</CellGroup>
<CellGroup title="基本用法">
<h2>基本用法</h2>
<CellGroup>
<Cell>
<RadioGroup value={'1'}>
<Radio value="1">选项1</Radio>
......@@ -56,7 +58,8 @@ const RadioDemo = () => {
</RadioGroup>
</Cell>
</CellGroup>
<CellGroup title="水平使用">
<h2>水平使用</h2>
<CellGroup>
<Cell>
<RadioGroup value="1" direction="horizontal">
<Radio value="1">选项1</Radio>
......@@ -85,7 +88,8 @@ const RadioDemo = () => {
</RadioGroup>
</Cell>
</CellGroup>
<CellGroup title="自定义尺寸">
<h2>自定义尺寸</h2>
<CellGroup>
<Cell>
<RadioGroup value="2">
<Radio value="1" iconSize="24">
......@@ -97,7 +101,8 @@ const RadioDemo = () => {
</RadioGroup>
</Cell>
</CellGroup>
<CellGroup title="Radio自定义图标">
<h2>Radio自定义图标</h2>
<CellGroup>
<Cell>
<RadioGroup value="1">
<Radio value="1" iconName="checklist" icon-active-name="checklist">
......@@ -109,7 +114,8 @@ const RadioDemo = () => {
</RadioGroup>
</Cell>
</CellGroup>
<CellGroup title="触发事件">
<h2>触发事件</h2>
<CellGroup>
<Cell>
<RadioGroup value={radioVal} onChange={handleChange}>
<Radio value={1}>触发事件</Radio>
......
import React, { FunctionComponent, MouseEventHandler, useContext, useEffect, useState } from 'react'
import Icon from '../icon'
import './radio.scss'
import RadioContext from './context'
import { RadioGroup } from '@/packages/radio/radiogroup'
import RadioGroup from '@/packages/radiogroup'
type Shape = 'button' | 'round'
type Position = 'right' | 'left'
......
import { RadioGroup } from './radiogroup'
export default RadioGroup
import React, { FunctionComponent, useEffect, useImperativeHandle, useState } from 'react'
import RadioContext from './context'
import './radiogroup.scss'
import RadioContext from '../radio/context'
import bem from '@/utils/bem'
type Position = 'left' | 'right'
......
import React, { useState } from 'react'
import { Range } from './range'
import { Cell } from '../cell/cell'
import './custom.scss'
import Toast from '../toast'
const RangeDemo = () => {
......
......@@ -7,7 +7,7 @@ import React, {
ReactNode,
CSSProperties,
} from 'react'
import './range.scss'
import bem from '@/utils/bem'
import { useTouch } from '../../utils/useTouch'
import { useRect } from '../../utils/useRect'
......
# Rate组件
# Rate 评分
### 介绍
......
import React, { FunctionComponent, useEffect, useState } from 'react'
import './rate.scss'
import bem from '@/utils/bem'
import Icon from '../icon'
......
import React, { FunctionComponent } from 'react'
import { DataContext } from './UserContext'
import './row.scss'
export interface RowProps {
type: string
......
# ShortPassword组件
# ShortPassword 短密码
### 介绍
短密码输入框,可用于输入密码、短信验证码等
### 安装
import { ShortPassword } from '@nutui/nutui-react';
```js
import { Shortpassword } from '@nutui/nutui-react';
```
## 代码演示
### 基础用法
```tsx
const ShortPassword = () => {
const Shortpassword = () => {
const [visible,setVisible] = useState(false)
const [value,setValue] = useState('')
cosnt change = (value)=>{
......@@ -20,7 +22,7 @@ const ShortPassword = () => {
}
return
<>
<ShortPassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)}></ShortPassword>
<Shortpassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)}></Shortpassword>
</>
}
......@@ -28,7 +30,7 @@ const ShortPassword = () => {
### 显示按钮组
```tsx
const ShortPassword = () => {
const Shortpassword = () => {
const [visible,setVisible] = useState(false)
const [value,setValue] = useState('')
cosnt change = (value)=>{
......@@ -36,7 +38,7 @@ const ShortPassword = () => {
}
return
<>
<ShortPassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)} noButton={false}></ShortPassword>
<Shortpassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)} noButton={false}></Shortpassword>
</>
}
......@@ -44,7 +46,7 @@ const ShortPassword = () => {
### 自定义密码长度4
```tsx
const ShortPassword = () => {
const Shortpassword = () => {
const [visible,setVisible] = useState(false)
const [value,setValue] = useState('')
cosnt change = (value)=>{
......@@ -52,14 +54,14 @@ const ShortPassword = () => {
}
return
<>
<ShortPassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)} length={4}></ShortPassword>
<Shortpassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)} length={4}></Shortpassword>
</>
}
```
### 忘记密码提示语事件回调
```tsx
const ShortPassword = () => {
const Shortpassword = () => {
const [visible,setVisible] = useState(false)
const [value,setValue] = useState('')
const onTips = ()=>{
......@@ -70,7 +72,7 @@ const ShortPassword = () => {
}
return
<>
<ShortPassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)} onTips={()=>onTips()}></ShortPassword>
<Shortpassword visible={visible} modelValue={value} onClose={()=>setVisible(false)} change={(value)=>change(value)} onTips={()=>onTips()}></Shortpassword>
</>
}
......
@import '../icon/icon.scss';
@import '../popup/popup.scss';
.nut-shortpassword {
&__title {
line-height: 1;
......
......@@ -2,7 +2,6 @@ import React, { CSSProperties, FunctionComponent, useEffect, useRef, useState }
import bem from '@/utils/bem'
import Popup from '@/packages/popup'
import Icon from '@/packages/icon'
import './shortpassword.scss'
export interface ShortPasswordProps {
title: string
......
# Signature 组件
# Signature 签名
### 介绍
......
import React, { FunctionComponent, useRef, useState, useEffect } from 'react'
import './signature.scss'
import { Button } from '../button/button'
import bem from '@/utils/bem'
......
......@@ -3,7 +3,6 @@ import { DataContext } from '@/packages/steps/UserContext'
import bem from '@/utils/bem'
import classNames from 'classnames'
import Icon from '@/packages/icon'
import './step.scss'
export interface StepProps {
title: string
......
......@@ -2,7 +2,6 @@ import React, { useState, FunctionComponent } from 'react'
import { DataContext } from './UserContext'
import bem from '@/utils/bem'
import classNames from 'classnames'
import './steps.scss'
export interface StepsProps {
current: number
......
import { createContext } from 'react'
export const DataContext = createContext({})
.demo-box {
.nut-swiper {
height: 150px;
img {
width: 100%;
height: 100%;
}
}
.page {
position: absolute;
bottom: 0;
right: 0;
width: 46px;
height: 22px;
background: rgba(0, 0, 0, 0.33);
border-radius: 22px;
text-align: center;
color: #fff;
font-size: 14px;
}
}
import React, { useState } from 'react'
import SwiperItem from '@/packages/swiperitem'
import Swiper from '@/packages/swiper'
import '@/packages/swiper/demo.scss'
const SwiperDemo = () => {
let swiperRef = React.useRef<any>(null)
const [height, setHeight] = useState<any>(150)
const [paginationColor, setPaginationColor] = useState<string>('#426543')
const [initPage1, setInitPage1] = useState<any>(0)
const [initPage2, setInitPage2] = useState<any>(0)
const [initPage3, setInitPage3] = useState<any>(0)
const [initPage4, setInitPage4] = useState<any>(0)
const [current, setCurrent] = useState(1)
const list = [
'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
'https://storage.360buyimg.com/jdc-article/fristfabu.jpg',
]
const onChange = (e: number) => {
// console.log(e)
}
const btn = (e: any) => {
;(swiperRef.current as any).next()
// setInitPage((v:any)=>v-1);
}
return (
<div className="demo padding">
<h2>基本用法</h2>
<div className="demo-box" style={{ height: 150 }}>
<Swiper
ref={swiperRef}
height={height}
paginationColor={paginationColor}
autoPlay="2000"
initPage={initPage1}
onChange={onChange}
paginationVisible={true}
>
{list.map((item) => {
return (
<SwiperItem key={item}>
<img src={item} alt="" />
</SwiperItem>
)
})}
</Swiper>
</div>
<h2>自定义大小</h2>
<div className="demo-box" style={{ height: 150 }}>
<Swiper initPage={initPage2} width="300" loop={false}>
{list.map((item) => {
return (
<SwiperItem key={item}>
<img src={item} alt="" />
</SwiperItem>
)
})}
</Swiper>
</div>
<h2>自定义指示器</h2>
<div className="demo-box" style={{ height: 150 }}>
<Swiper
loop={true}
initPage={initPage3}
onChange={(e) => setCurrent(e + 1)}
pageContent={<div className="page"> {current}/4 </div>}
>
{list.map((item) => {
return (
<SwiperItem key={item}>
<img src={item} alt="" />
</SwiperItem>
)
})}
</Swiper>
</div>
<h2>垂直方向</h2>
<div className="demo-box" style={{ height: 150 }}>
<Swiper
loop={true}
initPage={initPage4}
direction="vertical"
autoPlay="3000"
height="150"
paginationVisible={true}
>
{list.map((item) => {
return (
<SwiperItem key={item}>
<img src={item} alt="" />
</SwiperItem>
)
})}
</Swiper>
</div>
</div>
)
}
export default SwiperDemo
# Swiper 轮播
### 介绍
常用于一组图片或卡片轮播,当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现。
### 安装
```javascript
import { Swiper,SwiperItem } from '@nutui/nutui-react';
```
## 代码演示
### 基础用法
`autoPlay` 自动轮播的时长
`initPage` 初始索引值
`paginationVisible` 是否显示分页指示器
`paginationColor` 指示器颜色自定义
`onChange` 当卡片发生变化
```html
<Swiper
height={height}
paginationColor={"#426543"}
autoPlay="3000"
initPage={initPage1}
paginationVisible={true}
onChange={onChange}
>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/welcomenutui.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/fristfabu.jpg" alt="" />
</SwiperItem>
</Swiper>
```
``` javascript
import React, { useState } from 'react'
import { Swiper,SwiperItem } from '@nutui/nutui-react';
const SwiperDemo = () => {
const [initPage1, setInitPage1] = useState(0)
const onChange = (e) => {
// do something
}
}
```
### 自定义大小
`width` 自定义轮播大小
```html
<Swiper
width={300}
initPage={initPage2}
loop={false}
>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/welcomenutui.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/fristfabu.jpg" alt="" />
</SwiperItem>
</Swiper>
```
### 自定义分页指示器
`pageContent` 表示自定义指示器
```html
<Swiper
initPage={initPage3}
loop={true}
onChange={onChange3}
pageContent={<div className="page"> {current}/4 </div>}
>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/welcomenutui.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/fristfabu.jpg" alt="" />
</SwiperItem>
</Swiper>
```
``` javascript
import React, { useState } from 'react'
import { Swiper,SwiperItem } from '@nutui/nutui-react';
const SwiperDemo = () => {
const [initPage3, setInitPage3] = useState(0)
const [current, setCurrent] = useState(1)
const onChange3 = (e) => {
setCurrent(e + 1)
}
}
```
### 垂直方向
`direction` 自定义轮播方向
```html
<Swiper
loop={true}
initPage={initPage4}
direction="vertical"
autoPlay="3000"
height="150"
paginationVisible={true}
>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/welcomenutui.jpg" alt="" />
</SwiperItem>
<SwiperItem >
<img src="https://storage.360buyimg.com/jdc-article/fristfabu.jpg" alt="" />
</SwiperItem>
</Swiper>
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ----------------- | -------------------------------------- | ------------------------- | ----------------- |
| width | 轮播卡片的宽度 | Number \| String | window.innerWidth |
| height | 轮播卡片的高度 | String \| Number | 0 |
| direction | 轮播方向,可选值`horizontal`,`vertical` | String | 'horizontal' |
| paginationVisible | 分页指示器是否展示 | Boolean | false |
| paginationColor | 分页指示器选中的颜色 | String | '#fff' |
| loop | 是否循环轮播 | Boolean | true |
| duration | 动画时长(单位是ms) | Number \| String | 500 |
| autoPlay | 自动轮播时长,0表示不会自动轮播 | Number \| String | 0 |
| initPage | 初始化索引值 | Number \| String | 0 |
| touchable | 是否可触摸滑动 | Boolean | true |
| pageContent | 自定义指示器 | String \| React.ReactNode | - |
| isPreventDefault | 滑动过程中是否禁用默认事件 | Boolean | true |
| isStopPropagation | 滑动过程中是否禁止冒泡 | Boolean | true |
### Events
| 事件名 | 说明 | 回调参数 |
| -------- | ---------------- | --------------- |
| onChange | 卡片切换后的回调 | 当前索引值index |
### API
| 事件名 | 说明 | 参数 |
| ------ | -------------- | ------------ |
| prev | 切换到上一页 | - |
| next | 切换到下一页 | - |
| to | 切换到指定轮播 | index:number |
\ No newline at end of file
import { Swiper } from './swiper'
export default Swiper
.nut-swiper {
position: relative;
z-index: 1;
display: flex;
transition-property: transform;
box-sizing: content-box;
overflow: hidden;
&__inner {
display: flex;
height: 100%;
}
&__vertical {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
}
&__pagination {
display: flex;
position: absolute;
left: 50%;
bottom: 12px;
transform: translateX(-50%);
i {
width: 8px;
height: 3px;
margin-right: 7px;
border-radius: 2px;
&:last-child {
margin-right: 0;
}
}
}
&__pagination-vertical {
top: 50%;
left: 12px;
bottom: auto;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
transform: translateY(-50%);
i {
margin-bottom: 5px;
}
}
}
import React, {
useState,
FunctionComponent,
useEffect,
useRef,
TouchEvent,
forwardRef,
useMemo,
} from 'react'
import { DataContext } from './UserContext'
import bem from '@/utils/bem'
import classNames from 'classnames'
export type SwiperRef = {
to: (index: number) => void
next: () => void
prev: () => void
}
interface SwiperProps {
width: number | string
height: number | string
duration: number | string
initPage: number | string
autoPlay: number | string
direction: 'horizontal' | 'vertical'
paginationColor: string
paginationVisible: boolean
loop: boolean
touchable: boolean
isPreventDefault: boolean
isStopPropagation: boolean
className?: string
style?: React.CSSProperties
pageContent?: React.ReactNode
onChange?: (currPage: number) => void
}
const defaultProps = {
width: window.innerWidth,
height: 0,
duration: 500,
initPage: 0,
autoPlay: 0,
direction: 'horizontal',
paginationColor: '#fff',
paginationVisible: false,
loop: true,
touchable: true,
isPreventDefault: true,
isStopPropagation: true,
className: '',
} as SwiperProps
type Parent = {
propSwiper: SwiperProps
size?: number | string
}
const DISTANCE = 5
export const Swiper = React.forwardRef<
SwiperRef,
Partial<SwiperProps> & Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>
>((props, ref) => {
const propSwiper = { ...defaultProps, ...props }
const {
children,
direction,
className,
pageContent,
onChange,
initPage,
paginationColor,
paginationVisible,
touchable,
isPreventDefault,
isStopPropagation,
autoPlay,
...rest
} = propSwiper
const container = useRef<any>(null)
const innerRef = useRef<any>(null)
const _swiper = useRef<any>({
moving: false,
autoplayTimer: null,
width: 0,
height: 0,
offset: 0,
size: 0,
})
const childsRefs: any = []
const isVertical = direction === 'vertical'
let [rect, setRect] = useState(null as DOMRect | null)
let [active, setActive] = useState(0)
let [width, setWidth] = useState(0)
let [height, setHeight] = useState(0)
let [offset, setOffset] = useState(0)
let [ready, setReady] = useState(false)
let size = isVertical ? height : width
let [touch, setTouch] = useState({
startX: 0,
startY: 0,
deltaX: 0,
deltaY: 0,
offsetX: 0,
offsetY: 0,
stateDirection: '',
delta: 0,
touchTime: 0,
})
const [childs, setChilds] = useState([])
let [touchTime, setTouchTime] = useState<any>('')
let childCount = (children as any[]).length
for (let i = 0; i < childCount; i++) {
childsRefs.push(useRef<any>(null))
}
let trackSize = childCount * Number(size)
const getChildren = () => {
const childs: any = []
React.Children.toArray(children).forEach((child: any, index) => {
if (child.type && child.type.displayName === 'NutSwiperItem') {
childs.push(React.cloneElement(child, { ref: childsRefs[index], key: 'item_' + index }))
}
})
return childs
}
// 父组件参数传入子组件item
const parent: Parent = {
propSwiper,
size,
}
const minOffset = (() => {
if (rect) {
const base = isVertical ? rect.height : rect.width
return base - Number(size) * childCount
}
return 0
})()
// 清除定时器
const stopAutoPlay = () => {
clearTimeout(_swiper.current.autoplayTimer)
_swiper.current.autoplayTimer = null
}
// 定时轮播
const autoplay = () => {
if (propSwiper.autoPlay <= 0 || childCount <= 1) return
stopAutoPlay()
_swiper.current.autoplayTimer = setTimeout(() => {
next()
autoplay()
}, Number(propSwiper.autoPlay))
}
// 重置首尾位置信息
const resettPosition = () => {
_swiper.current.moving = true
if (active <= -1) {
move({ pace: childCount })
}
if (active >= childCount) {
move({ pace: -childCount })
}
}
// 上一页
const prev = () => {
resettPosition()
touchReset()
requestFrame(() => {
requestFrame(() => {
_swiper.current.moving = false
move({
pace: -1,
isEmit: true,
})
})
})
}
// 下一页
const next = () => {
resettPosition()
touchReset()
requestFrame(() => {
requestFrame(() => {
_swiper.current.moving = false
move({
pace: 1,
isEmit: true,
})
})
})
}
// 前往指定页
const to = (index: number) => {
resettPosition()
touchReset()
requestFrame(() => {
requestFrame(() => {
_swiper.current.moving = false
let targetIndex
if (props.loop && childCount === index) {
targetIndex = active === 0 ? 0 : index
} else {
targetIndex = index % childCount
}
move({
pace: targetIndex - active,
isEmit: true,
})
})
})
}
// 切换方法
const move = ({ pace = 0, offset = 0, isEmit = false, movingStatus = false }) => {
if (childCount <= 1) return
const targetActive = getActive(pace)
// 父级容器偏移量
const targetOffset = getOffset(targetActive, offset)
// 如果循环,调整开头结尾图片位置
if (props.loop) {
if (Array.isArray(children) && children[0] && targetOffset !== minOffset) {
const rightBound = targetOffset < minOffset
childsRefs[0].current.changeOffset(rightBound ? trackSize : 0)
}
if (Array.isArray(children) && children[childCount - 1] && targetOffset !== 0) {
const leftBound = targetOffset > 0
childsRefs[childCount - 1].current.changeOffset(leftBound ? -trackSize : 0)
}
}
if (isEmit && active !== targetActive) {
props.onChange && props.onChange((targetActive + childCount) % childCount)
}
active = targetActive
offset = targetOffset
setActive(targetActive)
setOffset(targetOffset)
getStyle(targetOffset)
}
// 确定当前active 元素
const getActive = (pace: number) => {
if (pace) {
let _active = active + pace
if (props.loop) {
return range(_active, -1, childCount)
}
return range(_active, 0, childCount - 1)
}
return active
}
// 计算位移
const getOffset = (active: number, offset = 0) => {
let currentPosition = active * Number(size)
if (!props.loop) {
currentPosition = Math.min(currentPosition, -minOffset)
}
let targetOffset = offset - currentPosition
if (!props.loop) {
targetOffset = range(targetOffset, minOffset, 0)
}
return targetOffset
}
// 浏览器 帧 事件
const requestFrame = (fn: FrameRequestCallback) => {
window.requestAnimationFrame.call(window, fn)
}
// 取值 方法
const range = (num: number, min: number, max: number) => {
return Math.min(Math.max(num, min), max)
}
const getDirection = (x: number, y: number) => {
if (x > y && x > DISTANCE) return 'horizontal'
if (y > x && y > DISTANCE) return 'vertical'
return ''
}
// 重置 全部位移信息
const touchReset = () => {
touch.startX = 0
touch.startY = 0
touch.deltaX = 0
touch.deltaY = 0
touch.offsetX = 0
touch.offsetY = 0
touch.delta = 0
touch.stateDirection = ''
touch.touchTime = 0
}
// 触摸事件开始
const touchStart = (e: TouchEvent) => {
touchReset()
touch.startX = e.touches[0].clientX
touch.startY = e.touches[0].clientY
}
// 触摸事件移动
const touchMove = (e: TouchEvent) => {
touch.deltaX = e.touches[0].clientX - touch.startX
touch.deltaY = e.touches[0].clientY - touch.startY
touch.offsetX = Math.abs(touch.deltaX)
touch.offsetY = Math.abs(touch.deltaY)
touch.delta = isVertical ? touch.deltaY : touch.deltaX
if (!touch.stateDirection) {
touch.stateDirection = getDirection(touch.offsetX, touch.offsetY)
}
}
const b = bem('swiper')
const classes = classNames(b(''))
const contentClass = classNames({
[`${b('inner')}`]: true,
[`${b('vertical')}`]: isVertical,
})
const getStyle = (moveOffset = offset) => {
let target = innerRef.current
target.style.transform = `translate3D${
!isVertical ? `(${moveOffset}px,0,0)` : `(0,${moveOffset}px,0)`
}`
target.style.transitionDuration = `${_swiper.current.moving ? 0 : props.duration}ms`
target.style[isVertical ? 'height' : 'width'] = `${Number(size) * childCount}px`
target.style[isVertical ? 'width' : 'height'] = `${isVertical ? width : height}px`
}
const onTouchStart = (e: TouchEvent) => {
if (props.isPreventDefault) e.preventDefault()
if (props.isStopPropagation) e.stopPropagation()
if (!props.touchable) return
touchStart(e)
touch.touchTime = Date.now()
stopAutoPlay()
resettPosition()
}
const onTouchMove = (e: TouchEvent) => {
if (props.touchable && _swiper.current.moving) {
touchMove(e)
if (touch.stateDirection === props.direction) {
move({
offset: touch.delta,
})
}
}
}
const onTouchEnd = (e: TouchEvent) => {
if (!props.touchable || !_swiper.current.moving) return
const speed = touch.delta / (Date.now() - touch.touchTime)
const isShouldMove = Math.abs(speed) > 0.3 || Math.abs(touch.delta) > +(size / 2).toFixed(2)
let pace = 0
_swiper.current.moving = false
if (isShouldMove && touch.stateDirection === props.direction) {
const offset = isVertical ? touch.offsetY : touch.offsetX
if (props.loop) {
pace = offset > 0 ? (touch.delta > 0 ? -1 : 1) : 0
} else {
pace = -Math[touch.delta > 0 ? 'ceil' : 'floor'](touch.delta / size)
}
move({
pace,
isEmit: true,
})
} else if (touch.delta) {
move({ pace: 0 })
} else {
getStyle()
}
autoplay()
}
useEffect(() => {
_swiper.current.activePagination = (active + childCount) % childCount
}, [active])
const init = (active: number = +propSwiper.initPage) => {
let rect = container.current.getBoundingClientRect()
let _active = Math.max(Math.min(childCount - 1, active), 0)
let _width = propSwiper.width ? +propSwiper.width : rect.width
let _height = propSwiper.height ? +propSwiper.height : rect.height
size = isVertical ? _height : _width
trackSize = childCount * Number(size)
let targetOffset = getOffset(_active)
_swiper.current.moving = true
if (ready) {
_swiper.current.moving = false
}
setRect(rect)
setActive(_active)
setWidth(_width)
setHeight(_height)
setOffset(targetOffset)
setReady(true)
}
useEffect(() => {
if (ready) {
getStyle()
}
}, [isVertical, width, height, offset, ready])
useEffect(() => {
if (ready) {
stopAutoPlay()
autoplay()
}
return () => {
setReady(false)
}
}, [ready])
useEffect(() => {
setChilds(getChildren())
}, [children])
useEffect(() => {
init()
}, [propSwiper.initPage])
useEffect(() => {
let target = container.current
target.addEventListener('touchstart', onTouchStart, false)
target.addEventListener('touchmove', onTouchMove, false)
target.addEventListener('touchend', onTouchEnd, false)
return () => {
target.removeEventListener('touchstart', onTouchStart, false)
target.removeEventListener('touchmove', onTouchMove, false)
target.removeEventListener('touchend', onTouchEnd, false)
}
})
React.useImperativeHandle(ref, () => ({
to,
next,
prev,
}))
return (
<DataContext.Provider value={parent}>
<div className={`${classes} ${className}`} ref={container} {...rest}>
<div className={contentClass} ref={innerRef}>
{childs}
</div>
{propSwiper.paginationVisible && !('pageContent' in propSwiper) ? (
<div
className={classNames({
[`${b('pagination')}`]: true,
[`${b('pagination-vertical')}`]: isVertical,
})}
>
{childs.map((item, index) => {
return (
<i
style={{
backgroundColor:
(active + childCount) % childCount === index
? propSwiper.paginationColor
: '#ddd',
}}
key={index}
/>
)
})}
</div>
) : (
<div>{pageContent}</div>
)}
</div>
</DataContext.Provider>
)
})
Swiper.defaultProps = defaultProps
Swiper.displayName = 'NutSwiper'
import { SwiperItem } from './swiperitem'
export default SwiperItem
.nut-swiper-item {
height: 100%;
}
import React, {
useState,
FunctionComponent,
useContext,
useEffect,
useImperativeHandle,
} from 'react'
import { DataContext } from '@/packages/swiper/UserContext'
import bem from '@/utils/bem'
import classNames from 'classnames'
interface SwiperItemProps {
direction?: string
size?: 0
}
interface IStyle {
width?: string
height?: string
transform?: string
}
const defaultProps = {
direction: 'horizontal',
} as SwiperItemProps
export const SwiperItem = React.forwardRef<
HTMLDivElement,
Partial<SwiperItemProps> & React.HTMLAttributes<HTMLDivElement>
>((props, ref) => {
const _props = { ...defaultProps, ...props }
const { children, direction, size } = _props
const parent: any = useContext(DataContext)
const [offset, setOffset] = useState(0)
const b = bem('swiper-item')
const classes = classNames(b(''))
useImperativeHandle<HTMLDivElement, any>(ref, () => ({
changeOffset: (num: number) => {
setOffset(num)
},
}))
const style = () => {
const style: IStyle = {}
const _direction = parent?.propSwiper.direction || direction
const _size = parent?.size || size
if (_size) {
style[_direction === 'horizontal' ? 'width' : 'height'] = `${_size}px`
}
if (offset) {
style['transform'] = `translate3D${
_direction === 'horizontal' ? `(${offset}px,0,0)` : `(0,${offset}px,0)`
}`
}
return style
}
return (
<div className={classes} style={style()}>
{children}
</div>
)
})
SwiperItem.defaultProps = defaultProps
SwiperItem.displayName = 'NutSwiperItem'
# Switch组件
# Switch 开关
### 介绍
......
import React, { FunctionComponent, useState, useEffect } from 'react'
import './switch.scss'
import bem from '@/utils/bem'
export interface SwitchProps {
......
# Tabbar组件
# Tabbar 标签栏
### 介绍
......
import React, { FunctionComponent, ReactComponentElement, useState } from 'react'
import './tabbar.scss'
import bem from '@/utils/bem'
import { TabbarItem } from '../tabbaritem/tabbarItem'
import TabbarItem from '@/packages/tabbaritem'
export interface TabbarProps {
visible: number | string
......
import { TabbarItem } from './tabbarItem'
export default TabbarItem
import React, { FunctionComponent, useEffect } from 'react'
import './tabbaritem.scss'
import bem from '@/utils/bem'
import Icon from '../icon'
......
......@@ -5,7 +5,7 @@ import React, {
useEffect,
useState,
} from 'react'
import './tag.scss'
import classNames from 'classnames'
import Icon from '@/packages/icon'
export interface TagProps {
......
import React, { FunctionComponent, useEffect, useState, CSSProperties } from 'react'
import './textarea.scss'
import bem from '@/utils/bem'
export interface TextAreaProps {
......
......@@ -2,7 +2,7 @@ import * as React from 'react'
import * as ReactDOM from 'react-dom'
import bem from '@/utils/bem'
import Icon from '../icon/index'
import './toast.scss'
import classNames from 'classnames'
export interface NotificationProps {
id?: string
......
# Toast 组件
# Toast 吐司
### 介绍
......
......@@ -8,7 +8,6 @@ import Icon from '@/packages/icon'
import { Upload, UploadOptions } from './upload'
import classNames from 'classnames'
import bem from '@/utils/bem'
import './uploader.scss'
export interface UploaderProps {
url: string
......
code {
position: relative;
display: block;
padding: 16px;
overflow-x: auto;
color: $nutui-doc-code-color;
font-weight: 400;
font-size: 14px;
font-family: $nutui-doc-code-font-family;
line-height: 26px;
white-space: pre-wrap;
word-wrap: break-word;
-webkit-font-smoothing: auto;
background-color: #fafafa;
border-radius: 16px;
}
pre {
margin: 20px 0 0;
+ p {
margin-top: 20px;
}
}
.hljs {
display: block;
padding: 30px;
overflow-x: auto;
background: #f7f8fa;
}
.hljs-comment,
.hljs-quote {
color: #a0a1a7;
font-style: italic;
}
.hljs-doctag,
.hljs-formula,
.hljs-keyword {
color: #a626a4;
}
.hljs-deletion,
.hljs-name,
.hljs-section,
.hljs-selector-tag,
.hljs-subst {
color: #e45649;
}
.hljs-literal {
color: #0184bb;
}
.hljs-addition,
.hljs-attribute,
.hljs-meta-string,
.hljs-regexp,
.hljs-string {
color: #50a14f;
}
.hljs-built_in,
.hljs-class .hljs-title {
color: #c18401;
}
.hljs-attr,
.hljs-number,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-pseudo,
.hljs-template-variable,
.hljs-type,
.hljs-variable {
color: #986801;
}
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-symbol,
.hljs-title {
color: #4078f2;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: 700;
}
.hljs-link {
text-decoration: underline;
}
@import 'highlight.scss';
.doc-content-document {
position: relative;
background: #fff;
padding-top: 48px;
padding-bottom: 48px;
padding-left: 40px;
padding-right: 445px;
.card {
margin-bottom: 24px;
padding: 24px;
background-color: #fff;
border-radius: $nutui-doc-border-radius;
box-shadow: 0 8px 12px #ebedf0;
}
a {
margin: 0 1px;
color: $nutui-doc-blue;
-webkit-font-smoothing: auto;
&:hover {
color: darken($nutui-doc-blue, 10%);
}
&:active {
color: darken($nutui-doc-blue, 20%);
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: $nutui-doc-black;
font-weight: bold;
line-height: 1.5;
&[id] {
cursor: pointer;
}
}
h1 {
margin: 0 0 30px;
font-size: 30px;
cursor: #1a1a1a;
font-weight: bold;
position: relative;
margin-bottom: 56px;
&:after {
content: '';
position: absolute;
bottom: -26px;
left: 16px;
width: 44px;
height: 17px;
background: url('https://img10.360buyimg.com/imagetools/jfs/t1/136135/19/14659/946/5fa20aa8E33a9aa26/d329fbe669171208.png');
background-size: 100% 100%;
}
}
h2 {
margin: 45px 0 20px;
font-size: 24px;
}
h3 {
margin: 16px 0px;
font-weight: 600;
font-size: 20px;
}
h4 {
margin: 24px 0 12px;
font-weight: 600;
font-size: 16px;
}
h5 {
margin: 24px 0 12px;
font-weight: 600;
font-size: 15px;
}
p {
color: $nutui-doc-text-color;
font-size: 14px;
line-height: 22px;
}
strong {
margin: 24px 0 12px;
font-weight: bold;
font-size: 14px;
color: #333;
}
table {
width: 100%;
margin-top: 12px;
color: $nutui-doc-text-color;
font-size: 14px;
line-height: 1.5;
border-collapse: collapse;
border: 1px solid #eee;
th {
padding: 8px 20px;
font-weight: 600;
text-align: left;
border-left: 1px solid #e9e9e9;
background-color: #f7f8fa;
// &:first-child {
// padding-left: 0;
// }
&:last-child {
padding-right: 0;
}
}
td {
padding: 8px 20px;
border-top: 1px solid $nutui-doc-code-background-color;
border-left: 1px solid #e9e9e9;
&:first-child {
// padding-left: 0;
border-left: 0px;
// version tag
code {
margin: 0;
padding: 2px 6px;
color: $nutui-doc-blue;
font-weight: 600;
font-size: 11px;
background-color: fade($nutui-doc-blue, 10%);
border-radius: 20px;
}
}
&:last-child {
padding-right: 0;
}
}
em {
color: $nutui-doc-red;
font-size: 14px;
font-family: $nutui-doc-code-font-family;
font-style: normal;
-webkit-font-smoothing: auto;
}
}
ul li,
ol li {
position: relative;
margin: 5px 0 5px 10px;
padding-left: 15px;
color: $nutui-doc-text-color;
font-size: 15px;
line-height: 26px;
&::before {
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
width: 6px;
height: 6px;
margin-top: 10px;
border: 1px solid $nutui-doc-dark-grey;
border-radius: 50%;
content: '';
}
}
hr {
margin: 30px 0;
border: 0 none;
border-top: 1px solid #eee;
}
p > code,
li > code,
table code {
display: inline;
margin: 0 2px;
padding: 2px 5px;
font-size: 14px;
font-family: inherit;
word-break: keep-all;
background-color: $nutui-doc-background-color;
border-radius: 4px;
-webkit-font-smoothing: antialiased;
}
p > code {
font-size: 14px;
}
section {
padding: 24px;
overflow: hidden;
}
blockquote {
margin: 16px 0px;
padding: 16px;
background-color: #fff4f0;
border-left: 6px solid #fa192c;
border-radius: 3px;
p {
color: #1a1a1a;
}
}
img {
// width: 100%;
// margin: 16px 0;
// border-radius: $nutui-doc-border-radius;
}
&--changelog,
&--changelog-v3 {
strong {
display: block;
margin: 24px 0 12px;
font-weight: 600;
font-size: 15px;
}
h3 {
+ p code {
margin: 0;
}
a {
color: inherit;
font-size: 20px;
}
}
}
.handle-part {
height: 50px;
display: flex;
justify-content: flex-end;
align-items: center;
.online-btn {
display: block;
color: #5555e2;
background-color: #fff;
font-size: 14px;
cursor: pointer;
&:hover {
color: blue;
text-decoration: underline;
}
}
}
}
@charset "utf-8";
html,
body,
div,
span,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
em,
img,
s,
strong,
b,
u,
i,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
section,
time,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-family: PingFang SC, Microsoft YaHei, Helvetica, Hiragino Sans GB, SimSun, sans-serif;
-webkit-overflow-scrolling: touch;
}
/* ios默认文本框阴影 */
input[type='text'],
textarea {
-webkit-appearance: none;
}
/* 低版本安卓文本框层级问题 */
input:focus {
-webkit-user-modify: read-write-plaintext-only;
}
// 清除谷歌浏览器下的 search 叉号
input::-webkit-search-cancel-button {
display: none;
}
ol,
ul {
list-style: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
* {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-tap-highlight-color: transparent;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
html,
body,
a,
button,
input {
outline: 0 none;
border: 0;
text-decoration: none;
}
img {
border: 0 none;
vertical-align: bottom;
-ms-interpolation-mode: bicubic;
}
[v-cloak] {
display: none;
}
html,
body {
height: 100%;
width: 100%;
background: #fff;
}
// doc
$doc-default-color: #fa2c19;
$doc-default-primary-bg: linear-gradient(
135deg,
rgba(250, 25, 44, 1) 0%,
rgba(250, 39, 40, 1) 45%,
rgba(250, 56, 31, 1) 83%,
rgba(250, 63, 25, 1) 100%
);
// clolr
// 红色
$theme-red: #fa2c19;
$theme-red-word: #fff;
$theme-red-border: #fff;
$theme-red-input: #fff;
$theme-red-actice: #fff;
$theme-red-select-border: #f0f2f5;
$theme-red-select-word: #666;
$theme-red-select-bg: #fff;
$theme-red-header-bg: url('../../assets/images/header-bg.png');
$theme-red-footer-word1: #1a1a1a;
$theme-red-footer-word2: #666;
$theme-red-footer-word3: #1d1d21;
$theme-red-footer-word4: #808080;
$theme-red-footer-bg: #fff;
$theme-red-footer-border: #eaf0fb;
$theme-red-gradient: linear-gradient(
135deg,
rgba(250, 44, 25, 1) 0%,
rgba(250, 63, 25, 1) 45%,
rgba(250, 89, 25, 1) 83%,
rgba(250, 100, 25, 1) 100%
);
// 白色
$theme-white: #fff;
$theme-white-word: #1a1a1a;
$theme-white-input: #ccc;
$theme-white-border: #d8d8d8;
$theme-white-actice: #fa2c19;
$theme-white-select-border: #f0f2f5;
$theme-white-select-word: #666;
$theme-white-select-bg: #fff;
$theme-white-box-border: #f5f5f5;
$theme-white-footer-word1: #1a1a1a;
$theme-white-footer-word2: #666;
$theme-white-footer-word3: #1d1d21;
$theme-white-footer-word4: #808080;
$theme-white-footer-hover: #fa2c19;
$theme-white-footer-bg: #fff;
$theme-white-footer-border: #eaf0fb;
$theme-white-theme-border: #f5f6f7;
$theme-white-circle: #fff;
$theme-white-circle-border: #e5e5e5;
$theme-white-index-desc: #959fb1;
// 黑色
$theme-black-word: #ccc;
$theme-black-input: #ccc;
$theme-black-border: #d8d8d8;
$theme-black-actice: #fff;
$theme-black-select-bg: #1d1d1d;
$theme-black-select-border: #c1c1c3;
$theme-black-select-hover: #797a7b;
$theme-black-select-word: #fff;
$theme-black-box-border: #6b5554;
$theme-black-footer-word1: #fff;
$theme-black-footer-word2: #f5f5f5;
$theme-black-footer-word3: #f5f5f5;
$theme-black-footer-word4: #808080;
$theme-black-footer-hover: #fa2c19;
$theme-black-footer-bg: #1d1d21;
$theme-black-footer-border: transparent;
$theme-black-theme-border: #666;
$theme-black-circle: #1a1a1a;
// header
$doc-default-header-color: $white;
$doc-header-height: 64px;
$doc-header-bg: url('../../assets/images/header-bg.png') no-repeat;
// nav
$doc-default-nav-bg: $white;
$doc-default-nav-color: $title-color;
// footer
// $doc-default-header-color: $white;
// $doc-footer-height: 73px;
// home
$theme-black-content-bg: #060506;
//markdown-add-style
$nutui-doc-black: #323233;
$nutui-doc-blue: #1989fa;
$nutui-doc-purple: #8080ff;
$nutui-doc-fuchsia: #a7419e;
$nutui-doc-red: #fa2400;
$nutui-doc-text-color: #666666;
$nutui-doc-text-light-blue: rgba(69, 90, 100, 0.6);
$nutui-doc-background-color: #f7f8fa;
$nutui-doc-grey: #999;
$nutui-doc-dark-grey: #666;
$nutui-doc-light-grey: #ccc;
$nutui-doc-border-color: #f1f4f8;
$nutui-doc-code-color: #58727e;
$nutui-doc-code-background-color: #f1f4f8;
$nutui-doc-code-font-family: 'Source Code Pro', 'Monaco', 'Inconsolata', monospace;
$nutui-doc-padding: 24px;
$nutui-doc-row-max-width: 1680px;
$nutui-doc-nav-width: 220px;
$nutui-doc-border-radius: 20px;
src/sites/assets/images/vx-code.png

35.1 KB | W: | H:

src/sites/assets/images/vx-code.png

108.2 KB | W: | H:

src/sites/assets/images/vx-code.png
src/sites/assets/images/vx-code.png
src/sites/assets/images/vx-code.png
src/sites/assets/images/vx-code.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -30,54 +30,71 @@ pre {
background: #f7f8fa;
}
.hljs-subst {
color: $nutui-doc-code-color;
.hljs-comment,
.hljs-quote {
color: #a0a1a7;
font-style: italic;
}
.hljs-string,
.hljs-meta,
.hljs-symbol,
.hljs-template-tag,
.hljs-template-variable,
.hljs-addition {
color: $nutui-doc-green;
.hljs-doctag,
.hljs-formula,
.hljs-keyword {
color: #a626a4;
}
.hljs-comment,
.hljs-quote {
color: #999;
.hljs-deletion,
.hljs-name,
.hljs-section,
.hljs-selector-tag,
.hljs-subst {
color: #e45649;
}
.hljs-params,
.hljs-keyword,
.hljs-attribute {
color: $nutui-doc-purple;
.hljs-literal {
color: #0184bb;
}
.hljs-deletion,
.hljs-variable,
.hljs-number,
.hljs-addition,
.hljs-attribute,
.hljs-meta-string,
.hljs-regexp,
.hljs-literal,
.hljs-bullet,
.hljs-link {
color: #eb6f6f;
.hljs-string {
color: #50a14f;
}
.hljs-attr,
.hljs-selector-tag,
.hljs-title,
.hljs-section,
.hljs-built_in,
.hljs-doctag,
.hljs-class .hljs-title {
color: #c18401;
}
.hljs-attr,
.hljs-number,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-pseudo,
.hljs-template-variable,
.hljs-type,
.hljs-name,
.hljs-variable {
color: #986801;
}
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-selector-class,
.hljs-strong {
color: #4994df;
.hljs-symbol,
.hljs-title {
color: #4078f2;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: 700;
}
.hljs-link {
text-decoration: underline;
}
......@@ -145,7 +145,7 @@
}
em {
color: $nutui-doc-green;
color: $nutui-doc-red;
font-size: 14px;
font-family: $nutui-doc-code-font-family;
font-style: normal;
......@@ -210,6 +210,7 @@
padding: 16px;
background-color: #fff4f0;
border-left: 6px solid #fa192c;
border-radius: 3px;
p {
color: #1a1a1a;
}
......
......@@ -91,7 +91,7 @@ $nutui-doc-black: #323233;
$nutui-doc-blue: #1989fa;
$nutui-doc-purple: #8080ff;
$nutui-doc-fuchsia: #a7419e;
$nutui-doc-green: #4fc08d;
$nutui-doc-red: #fa2400;
$nutui-doc-text-color: #666666;
$nutui-doc-text-light-blue: rgba(69, 90, 100, 0.6);
$nutui-doc-background-color: #f7f8fa;
......@@ -101,8 +101,7 @@ $nutui-doc-light-grey: #ccc;
$nutui-doc-border-color: #f1f4f8;
$nutui-doc-code-color: #58727e;
$nutui-doc-code-background-color: #f1f4f8;
$nutui-doc-code-font-family: 'Source Code Pro', 'Monaco', 'Inconsolata',
monospace;
$nutui-doc-code-font-family: 'Source Code Pro', 'Monaco', 'Inconsolata', monospace;
$nutui-doc-padding: 24px;
$nutui-doc-row-max-width: 1680px;
$nutui-doc-nav-width: 220px;
......
const ua = navigator.userAgent.toLowerCase()
const isMobile = /ios|iphone|ipod|ipad|android/.test(ua)
export { isMobile }
#app {
::selection {
background: $doc-default-color;
color: #fff;
}
#doc {
background: #fff;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
padding-top: $doc-header-height;
}
#nav {
position: fixed;
z-index: 10;
left: 0;
right: 0;
height: 57px;
line-height: 57px;
text-align: center;
background: white;
font-weight: bold;
font-size: 20px;
color: rgba(51, 51, 51, 1);
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.07);
.back {
.doc {
&-content {
margin-left: 290px;
display: flex;
flex-direction: column;
&-document {
min-height: 800px;
}
&-tabs {
position: absolute;
left: 0;
height: 100%;
width: 50px;
right: 445px;
top: 48px;
display: flex;
height: 50px;
align-items: center;
justify-content: center;
cursor: pointer;
}
}
.demo {
height: 100%;
background: #f7f8fa;
overflow-x: hidden;
overflow-y: auto;
padding: 57px 17px 0 17px;
&.full {
padding: 57px 0 0 0;
h2 {
padding-left: 17px;
margin-bottom: 20px;
z-index: 1;
.tab-item {
position: relative;
padding: 10px 25px;
height: 100%;
cursor: pointer;
font-size: 16px;
color: #323232;
text-align: center;
border-radius: 4px;
&.cur {
color: #fa2c19;
&:after {
content: ' ';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 3px;
background-color: #fa2c19;
}
}
&:hover {
background-color: #f7f8fa;
}
}
}
&.bg-w {
background: #fff;
}
&::-webkit-scrollbar {
width: 0;
background: transparent;
}
> h2 {
margin-top: 30px;
margin-bottom: 10px;
font-size: 14px;
color: rgba(144, 156, 164, 1);
padding: 0 10px;
font-weight: normal;
}
> p {
font-size: 12px;
}
.card {
padding: 25px 18px;
background: rgba(255, 255, 255, 1);
}
}
}
import React, { FunctionComponent } from 'react'
import React from 'react'
import { HashRouter, Switch, Route } from 'react-router-dom'
import './App.scss'
import remarkGfm from 'remark-gfm'
import { routers, raws } from './docs'
import { visit } from 'unist-util-visit'
import ReactMarkdown from 'react-markdown'
import Nav from '@/sites/doc/components/nav'
import remarkDirective from 'remark-directive'
import Header from '@/sites/doc/components/header'
import Demoblock from '@/sites/doc/components/demoblock'
import DemoPreview from '@/sites/doc/components/demo-preview'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import routes from './router'
function myRemarkPlugin() {
return (tree: any) => {
visit(tree, (node) => {
if (node.type === 'containerDirective') {
if (node.name !== 'demo') return
const Dynamic: FunctionComponent<any> = ({ code, ...rest }: any) => {
return <div dangerouslySetInnerHTML={{ __html: code }}></div>
const data = node.data || (node.data = {})
data.hName = 'div'
data.hProperties = {
class: 'demo',
}
}
})
}
}
const App = () => {
return (
<div id="nav">
<div className="back"></div>
<div>
<HashRouter>
<Switch>
{routes.map((item: any, index: number) => {
return (
<Route
key={index}
path={item.path}
component={(props: any) => <Dynamic code={item.component.html} {...props} />}
/>
)
})}
</Switch>
<Header></Header>
<Nav></Nav>
<div className="doc-content">
<div className="doc-content-document">
<Switch>
{routers.map((ru, k) => {
return (
<Route key={k} path={`/${ru}`}>
<ReactMarkdown
children={raws[ru]}
remarkPlugins={[remarkGfm, remarkDirective, myRemarkPlugin]}
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '')
return !inline && match ? (
<Demoblock text={String(children).replace(/\n$/, '')}>
<SyntaxHighlighter
children={String(children).replace(/\n$/, '')}
language={match[1]}
PreTag="div"
{...props}
/>
</Demoblock>
) : (
<code className={className} {...props}>
{children}
</code>
)
},
}}
/>
</Route>
)
})}
</Switch>
</div>
<div className="markdown-body">
<DemoPreview></DemoPreview>
</div>
</div>
</HashRouter>
</div>
)
......
.doc {
&-demo-preview {
height: 667px;
width: 375px;
position: fixed;
right: 30px;
top: 100px;
box-shadow: #ebedf0 0 4px 12px;
border-radius: 12px;
overflow: hidden;
iframe {
height: 100%;
width: 100%;
}
}
}
import React, { useState } from 'react'
import './demo-preview.scss'
import { useHistory } from 'react-router-dom'
const DemoPreview = () => {
const history = useHistory()
const [URL, setURL] = useState(history.location.pathname)
history.listen((location) => {
setURL(location.pathname)
})
return (
<div className="doc-demo-preview">
<iframe src={`/react/demo.html#${URL}`} frameBorder="0"></iframe>
</div>
)
}
export default DemoPreview
import DemoPreview from '@/sites/doc/components/demo-preview/demo-preview'
export default DemoPreview
import React from 'react'
interface A {
text: string
}
const DemoBlock: React.FunctionComponent<A> = (props) => {
console.log(props.children)
return (
<>
{props.children}
{props.text}
xxxx
</>
)
}
export default DemoBlock
import DemoBlock from './demoblock'
export default DemoBlock
.doc {
&-header {
position: fixed;
z-index: 2;
top: 0;
left: 0;
right: 0;
min-width: 1300px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
height: $doc-header-height;
line-height: $doc-header-height;
text-align: left;
padding: 0 50px;
font-size: 20px;
}
}
.header {
&-logo {
position: relative;
display: inline-block;
width: 240px;
height: 64px;
.logo-link {
width: 120px;
height: 46px;
vertical-align: middle;
position: absolute;
top: 50%;
margin-top: -23px;
}
.logo-border {
width: 1px;
height: 26px;
position: absolute;
right: 0;
top: 50%;
margin-top: -13px;
}
.version {
position: absolute;
right: 70px;
font-size: 14px;
}
}
&-nav {
display: flex;
justify-content: space-between;
align-items: center;
float: right;
width: calc(100% - 240px);
min-width: 900px;
padding: 0 40px;
> a {
color: #fff;
}
.nav-box {
margin-right: 140px;
.nav-list {
min-width: 490px;
display: flex;
list-style: none;
align-items: center;
justify-content: space-around;
}
.nav-item {
position: relative;
margin-right: 30px;
font-size: 14px;
height: 63px;
line-height: 63px;
text-align: center;
cursor: pointer;
flex-shrink: 0;
a {
display: inline-block;
line-height: 64px;
}
// overflow: hidden;
&.active {
font-weight: bold;
&:after {
content: '';
display: inline-block;
width: 35px;
height: 13px;
position: absolute;
bottom: 3px;
left: 50%;
margin-left: -17.5px;
background: url('../../assets/images/item-active.png');
}
}
&:last-of-type {
margin-right: 0;
}
}
.user-link {
display: inline-block;
width: 26px;
height: 26px;
vertical-align: middle;
background-repeat: no-repeat;
background-image: url('../../assets/images/icon-user.png');
background-size: 26px;
&.gitee {
margin-left: 8px;
background-image: url('../../assets/images/icon-gitee.png');
}
}
}
}
}
.header-select {
&-box {
position: relative;
display: inline-block;
vertical-align: middle;
outline: 0;
}
&-hd {
min-width: 77px;
height: 28px;
padding: 0 30px 0 15px;
line-height: 26px;
font-size: 14px;
color: $theme-red-word;
background-position: right 15px top 12px;
background-size: 8px 5px;
background-repeat: no-repeat;
border-radius: 14px;
}
&-bd {
position: absolute;
top: 30px;
left: 50%;
margin-left: -60px;
border-radius: 3px;
overflow: hidden;
}
&-item {
width: 120px;
height: 28px;
padding: 0 12px;
line-height: 26px;
font-size: 14px;
border-width: 0px 1px 1px;
border-style: solid;
cursor: pointer;
&:first-of-type {
border-top-width: 1px;
}
}
}
// 颜色
.doc-header {
// 红色
&-red {
background-image: $theme-red-header-bg;
color: $theme-red-word;
.header {
&-logo {
.logo-link {
background: url('../../assets/images/logo-header-white.png') no-repeat center/100%;
}
.logo-border {
background: $theme-red-border;
}
}
&-nav {
.search-box {
.search-input {
color: $theme-red-word;
background-position: 0 0;
&::-webkit-input-placeholder {
color: $theme-red-input;
}
}
}
.nav-box {
.nav-item {
color: $theme-red-word;
a {
color: $theme-red-word;
}
&.active {
color: $theme-red-actice;
&:after {
background-position: 0 0;
}
a {
color: $theme-red-actice;
}
}
}
.user-link {
background-position: 0 0;
// &:hover {
// background-position: -26px 0;
// }
}
}
}
}
.header-select {
&-box {
&.select-down {
.header-select-hd {
background-image: url('../../assets/images/icon-select-white-down.png');
}
}
&.select-up {
.header-select-hd {
background-image: url('../../assets/images/icon-select-white-up.png');
}
}
}
&-hd {
color: $theme-red-word;
border: 1px solid $theme-white-select-border;
}
&-bd {
color: $theme-white-select-word;
}
&-item {
border-color: $theme-red-select-border;
background-color: $theme-red-select-bg;
&:hover {
color: $theme-red;
}
}
}
}
// 白色
&-white {
background: $white;
color: $theme-white-word;
border-bottom: 1px solid $theme-white-box-border;
.header {
&-logo {
.logo-link {
background: url('../../assets/images/logo-header-red.png') no-repeat center/100%;
}
.logo-border {
background: $theme-white-border;
}
}
&-nav {
.search-box {
.search-input {
color: $theme-white-word;
background-position: 0 -22px;
&::-webkit-input-placeholder {
color: $theme-white-input;
}
}
}
.nav-box {
.nav-item {
color: $theme-white-word;
a {
color: $theme-white-word;
}
&.active {
color: $theme-white-actice;
&:after {
background-position: 0 -13px;
}
a {
color: $theme-white-actice;
}
}
}
.user-link {
background-position: 0 -25px;
// &:hover {
// background-position: -26px -25px;
// }
}
}
}
}
.header-select {
&-box {
&.select-down {
.header-select-hd {
background-image: url('../../assets/images/icon-select-gray-down.png');
}
}
&.select-up {
.header-select-hd {
background-image: url('../../assets/images/icon-select-gray-up.png');
}
}
}
&-hd {
color: $theme-white-select-word;
border: 1px solid $theme-white-select-border;
}
&-bd {
color: $theme-white-select-word;
}
&-item {
border-color: $theme-white-select-border;
background-color: $theme-white-select-bg;
&:hover {
color: $theme-white-actice;
}
}
}
}
// 黑色
&-black {
background: $black;
color: $theme-black-word;
border-bottom: 1px solid $theme-black-box-border;
.header {
&-logo {
.logo-link {
background: url('../../assets/images/logo-header-red.png') no-repeat center/100%;
}
.logo-border {
background: $theme-black-border;
}
}
&-nav {
.search-box {
.search-input {
color: $theme-black-word;
background-position: 0 -44px;
&::-webkit-input-placeholder {
color: $theme-black-input;
}
}
}
.nav-box {
.nav-item {
color: $theme-black-word;
a {
color: $theme-black-word;
}
&.active {
color: $theme-black-actice;
&:after {
background-position: 0 -13px;
}
a {
color: $theme-black-actice;
}
}
}
.user-link {
background-position: 0 -51px;
// &:hover {
// background-position: -26px -51px;
// }
}
}
}
}
.header-select {
&-box {
&.select-down {
.header-select-hd {
background-image: url('../../assets/images/icon-select-white-down.png');
}
}
&.select-up {
.header-select-hd {
background-image: url('../../assets/images/icon-select-white-up.png');
}
}
}
&-hd {
color: $theme-black-select-word;
background-color: $theme-black-select-bg;
border: 1px solid $theme-black-select-border;
}
&-bd {
color: $theme-black-select-word;
}
&-item {
background-color: $theme-black-select-bg;
border-color: $theme-black-select-bg;
&:hover {
background-color: $theme-black-select-hover;
border-color: $theme-black-select-hover;
}
}
}
}
}
// 下拉列表选择动画效果
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
import React, { useEffect } from 'react'
import { nav } from '@/config.json'
// @ts-ignore
import { version } from '/package.json'
import './header.scss'
import { useHistory } from 'react-router-dom'
const Header = () => {
const history = useHistory()
const toHome = () => {
history.replace('/')
}
useEffect(() => {
let packages = [] as any[]
nav.forEach((item) => {
packages.push(...item.packages)
})
}, [])
return (
<div className="doc-header doc-header-black">
<div className="header-logo">
<a className="logo-link" href="#/" onClick={toHome}></a>
<span className="logo-border"></span>
<span className="version">{version}</span>
</div>
<div className="header-nav">
<a href="https//github.com/jdf2e/nutui-docs" target="_blank">
当前环境:development ,代码 PR 合并后,文档会自动同步至 https//github.com/jdf2e/nutui-docs
</a>
</div>
</div>
)
}
export default Header
import Header from '@/sites/doc/components/header/header'
export default Header
import Nav from '@/sites/doc/components/nav/nav'
export default Nav
.doc {
&-nav {
position: fixed;
top: $doc-header-height + 50;
left: 0;
bottom: 0;
z-index: 1;
background: $white;
width: 290px;
border-right: 1px solid #eee;
overflow: auto;
padding-left: 35px;
ol {
&.introduce {
padding-left: 5px;
li {
cursor: pointer;
&:hover {
color: $doc-default-color;
}
}
}
li {
height: 48px;
line-height: 48px;
font-size: 14px;
color: $doc-default-nav-color;
font-weight: bold;
position: relative;
&.active {
}
}
.selected {
li {
&::before {
position: absolute;
content: '';
left: 0;
top: 50%;
width: 22px;
margin-top: -5px;
height: 10px;
transform: rotate(90deg);
background: url(https://img10.360buyimg.com/imagetools/jfs/t1/136135/19/14659/946/5fa20aa8E33a9aa26/d329fbe669171208.png)
no-repeat;
background-size: 100% 100%;
}
}
}
> ul {
li {
padding-left: 29px;
cursor: pointer;
&:hover {
a {
color: $doc-default-color;
}
}
a {
&.router-link-active,
&.active {
color: $doc-default-color !important;
}
&:hover {
color: $doc-default-color;
&:visited {
color: $doc-default-color;
}
}
&:link,
&:visited {
color: $title-color;
}
height: 100%;
b {
font-weight: normal;
font-size: 12px;
}
}
}
}
}
}
}
import React, { useState } from 'react'
import { nav } from '@/config.json'
import { NavLink } from 'react-router-dom'
import './nav.scss'
const Nav = () => {
const [cNav] = useState<any>(nav)
return (
<div className="doc-nav">
<ol>
{cNav.map((cn: any) => {
return (
<>
<li>{cn.name}</li>
<ul>
{cn.packages.map((cp: any) => {
if (!cp.show) return null
return (
<NavLink key={'navlink' + cp.name} activeClassName="selected" to={cp.name}>
<li>
{cp.name}&nbsp;&nbsp;<b>{cp.cName}</b>
</li>
</NavLink>
)
})}
</ul>
</>
)
})}
</ol>
</div>
)
}
export default Nav
import './App.scss'
import React, { FunctionComponent, PropsWithChildren } from 'react'
import { HashRouter, Switch, Route } from 'react-router-dom'
import { HashRouter, Switch, Route, Redirect } from 'react-router-dom'
import loadable, { LoadableComponent } from '@loadable/component'
import routes from './router'
import Links from './Links'
import logo from '@/sites/assets/images/logo-red.png'
const WithNavRouter = (C: LoadableComponent<any>) => {
const WithNav: FunctionComponent = (props: PropsWithChildren<any>) => {
......@@ -14,27 +14,44 @@ const WithNavRouter = (C: LoadableComponent<any>) => {
<div className="back"></div>
{props.location.pathname.replace('/', '')}
</div>
<C />
<C key={Math.random()} />
</>
)
}
return WithNav
}
const App = () => {
return (
<>
<HashRouter>
<Switch>
<Route path="/" exact>
<div className="index-components">
<Links />
<div className="index">
<div className="index-header">
<img src={logo} alt="" srcSet="" />
<div className="info">
<h1>NutUI-React</h1>
<p>京东风格的轻量级移动端 React 组件库</p>
</div>
</div>
<div className="index-components">
<Links />
</div>
</div>
</Route>
{routes.map((item: any, index: number) => {
const C = loadable(item.component)
return <Route key={index} path={item.path} component={WithNavRouter(C)} />
})}
<Route path="*">
<Redirect
to={{
pathname: '/',
}}
/>
</Route>
</Switch>
</HashRouter>
</>
......
@import '@/sites/assets/styles/reset.scss';
.index {
height: 100%;
width: 100%;
......
......@@ -12,13 +12,15 @@ const Links = () => {
<ol key={nav.name}>
<li>{nav.name}</li>
<ul>
{nav.packages.map((com) => (
<li key={com.name}>
<Link key={com.name} to={`${com.name}`}>
{com.name}
</Link>
</li>
))}
{nav.packages.map((com) =>
com.show ? (
<li key={com.name}>
<Link key={com.name} to={`${com.name}`}>
{com.name}
</Link>
</li>
) : null
)}
</ul>
</ol>
))}
......
......@@ -3,4 +3,5 @@ import ReactDOM from 'react-dom'
import App from './App'
import '@/sites/assets/styles/reset.scss'
import('../../packages/nutui.react')
ReactDOM.render(<App />, document.querySelector('#app'))
const modulesPage = import.meta.glob('/src/packages/**/demo.tsx')
const routes: any[] = []
for (const path in modulesPage) {
let name = (/packages\/(.*)\/demo.tsx/.exec(path) as any[])[1]
......
......@@ -6,8 +6,8 @@
"types": ["vite/client"],
"allowJs": false,
"declaration": true,
"declarationDir": "./dist/esm/types",
"emitDeclarationOnly": true,
"declarationDir": "./dist/types",
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
......@@ -19,11 +19,10 @@
"isolatedModules": true,
"jsx": "react",
"lib": ["esnext", "dom"],
"outDir": "./tsc/test",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx"],
"exclude": ["./node_modules/*", "src/sites/*"]
"exclude": ["./node_modules/*", "src/sites/*", "src/**/demo.tsx"]
}
import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
import path from 'path'
import config from './package.json'
const atImport = require('postcss-import')
const banner = `/*!
* ${config.name} v${config.version} ${new Date()}
* (c) 2021 @jdf2e.
* Released under the MIT License.
*/`
const resolve = path.resolve
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
},
css: {
preprocessorOptions: {
scss: {
charset: false,
// example : additionalData: `@import "./src/design/styles/variables";`
// dont need include file extend .scss
additionalData: `@import "@/styles/variables.scss";`,
},
postcss: {
plugins: [atImport({ path: path.join(__dirname, 'src`') })],
},
},
},
plugins: [reactRefresh()],
build: {
emptyOutDir: false,
rollupOptions: {
output: {
banner,
},
},
lib: {
entry: './dist/styles/themes/default.scss',
formats: ['es'],
name: 'style',
fileName: 'style',
},
},
})
import { defineConfig } from 'vite'
import path from 'path'
import config from './package.json'
import configPkg from './src/config.json'
import reactRefresh from '@vitejs/plugin-react-refresh'
const banner = `/*!
* ${config.name} v${config.version} ${new Date()}
* (c) 2021 @jdf2e.
* Released under the MIT License.
*/`
let input: any = {}
configPkg.nav.map((item) => {
item.packages.forEach((element) => {
let { name, show, type, exportEmpty } = element as any
if (show || exportEmpty) {
input[name] = `./src/packages/${name.toLowerCase()}/index.ts`
}
})
})
const resolve = path.resolve
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
},
plugins: [reactRefresh()],
build: {
emptyOutDir: false,
rollupOptions: {
input,
// 请确保外部化那些你的库中不需要的依赖
external: ['react', 'react-dom'],
output: {
banner,
dir: path.resolve(__dirname, './dist/packages/_es'),
entryFileNames: '[name].js',
},
},
lib: {
entry: '',
name: 'index',
formats: ['es'],
},
},
})
import { defineConfig } from 'vite'
import config from './package.json'
import reactRefresh from '@vitejs/plugin-react-refresh'
import mdPlugin, { Mode } from 'vite-plugin-markdown'
import path from 'path'
const atImport = require('postcss-import')
const resolve = path.resolve
// https://vitejs.dev/config/
......@@ -14,6 +14,7 @@ export default defineConfig({
css: {
preprocessorOptions: {
scss: {
charset: false,
// example : additionalData: `@import "./src/design/styles/variables";`
// dont need include file extend .scss
additionalData: `@import "@/styles/variables.scss";@import "@/sites/assets/styles/variables.scss";`,
......@@ -21,6 +22,7 @@ export default defineConfig({
},
postcss: {
plugins: [
atImport({ path: path.join(__dirname, 'src`') }),
require('autoprefixer')({
overrideBrowserslist: [
'> 0.5%',
......@@ -33,15 +35,13 @@ export default defineConfig({
],
},
},
plugins: [reactRefresh(), mdPlugin({ mode: [Mode.HTML] })],
plugins: [reactRefresh()],
build: {
target: 'es2015',
outDir: './dist/1x/',
// assetsDir: config.version,
cssCodeSplit: true,
rollupOptions: {
input: {
// doc: resolve(__dirname, 'demo.html'),
mobile: resolve(__dirname, 'demo.html'),
},
output: {
......
......@@ -21,12 +21,26 @@ export default defineConfig({
charset: false,
// example : additionalData: `@import "./src/design/styles/variables";`
// dont need include file extend .scss
additionalData: `@import "@/styles/variables.scss";@import "@/sites/assets/styles/variables.scss";`,
additionalData: `@import "@/styles/variables.scss";`,
},
postcss: {
plugins: [
require('autoprefixer')({
overrideBrowserslist: [
'> 0.5%',
'last 2 versions',
'ie > 11',
'iOS >= 10',
'Android >= 5',
],
}),
],
},
},
},
plugins: [reactRefresh()],
build: {
emptyOutDir: true,
rollupOptions: {
// 请确保外部化那些你的库中不需要的依赖
external: ['react', 'react-dom'],
......@@ -40,7 +54,7 @@ export default defineConfig({
},
},
lib: {
entry: 'src/packages/nutui.react.ts',
entry: 'src/packages/nutui.react.build.ts',
name: 'nutui.react',
fileName: 'nutui.react',
formats: ['es', 'umd'],
......
import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
import mdPlugin, { Mode } from 'vite-plugin-markdown'
const atImport = require('postcss-import')
import path from 'path'
const resolve = path.resolve
const resolve = path.resolve
// https://vitejs.dev/config/
export default defineConfig({
base: '/react/',
resolve: {
alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
},
......@@ -16,7 +18,10 @@ export default defineConfig({
// dont need include file extend .scss
additionalData: `@import "@/styles/variables.scss";@import "@/sites/assets/styles/variables.scss";`,
},
postcss: {
plugins: [atImport({ path: path.join(__dirname, 'src`') })],
},
},
},
plugins: [reactRefresh(), mdPlugin({ mode: [Mode.HTML] })],
plugins: [reactRefresh()],
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册