├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .prettierignore
├── .prettierrc
├── README.md
├── README.zh-CN.md
├── package.json
├── packages
├── components
│ ├── react
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── common
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ │ └── index.js
│ │ ├── index.js
│ │ ├── package.json
│ │ └── src
│ │ │ ├── button
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ │ └── pc.jsx
│ │ │ └── countdown
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ └── pc.jsx
│ ├── renderless
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── package.json
│ │ └── src
│ │ │ ├── button
│ │ │ ├── index.js
│ │ │ ├── react.js
│ │ │ ├── solid.js
│ │ │ └── vue.js
│ │ │ └── countdown
│ │ │ ├── index.js
│ │ │ ├── react.js
│ │ │ ├── solid.js
│ │ │ └── vue.js
│ ├── solid
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── common
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ │ └── index.js
│ │ ├── index.js
│ │ ├── package.json
│ │ └── src
│ │ │ ├── button
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ │ └── pc.jsx
│ │ │ └── countdown
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ └── pc.jsx
│ ├── theme-mobile
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── package.json
│ │ └── src
│ │ │ ├── base
│ │ │ ├── basic-var.less
│ │ │ ├── index.less
│ │ │ ├── reset.less
│ │ │ └── vars.less
│ │ │ ├── button
│ │ │ ├── index.less
│ │ │ └── vars.less
│ │ │ ├── custom.less
│ │ │ └── mixins
│ │ │ └── button.less
│ ├── theme-watch
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── package.json
│ │ └── src
│ │ │ ├── base
│ │ │ ├── basic-var.less
│ │ │ ├── index.less
│ │ │ ├── reset.less
│ │ │ └── vars.less
│ │ │ ├── button
│ │ │ ├── index.less
│ │ │ └── vars.less
│ │ │ ├── custom.less
│ │ │ └── mixins
│ │ │ └── button.less
│ ├── theme
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── package.json
│ │ └── src
│ │ │ ├── base
│ │ │ ├── basic-var.less
│ │ │ ├── index.less
│ │ │ └── reset.less
│ │ │ ├── button
│ │ │ ├── index.less
│ │ │ └── vars.less
│ │ │ ├── countdown
│ │ │ ├── index.less
│ │ │ └── vars.less
│ │ │ ├── custom.less
│ │ │ └── mixins
│ │ │ └── button.less
│ └── vue
│ │ ├── README.md
│ │ ├── README.zh-CN.md
│ │ ├── button
│ │ ├── index.js
│ │ ├── package.json
│ │ └── src
│ │ │ ├── index.js
│ │ │ ├── mobile.vue
│ │ │ ├── pc.vue
│ │ │ └── watch.vue
│ │ ├── common
│ │ ├── package.json
│ │ └── src
│ │ │ ├── adapter
│ │ │ ├── index.js
│ │ │ ├── teleport.js
│ │ │ ├── utils.js
│ │ │ ├── vue2
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ └── vue3
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── csscls.js
│ │ │ └── index.js
│ │ ├── config-provider
│ │ ├── hooks
│ │ │ └── use-config.ts
│ │ ├── index.js
│ │ ├── package.json
│ │ └── src
│ │ │ └── index.vue
│ │ ├── countdown
│ │ ├── index.js
│ │ ├── package.json
│ │ └── src
│ │ │ └── pc.vue
│ │ ├── index.js
│ │ └── package.json
├── element-to-opentiny
│ ├── README.md
│ ├── README.zh-CN.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ ├── assets
│ │ │ ├── all-pages-element-to-opentiny.png
│ │ │ ├── el-button-to-tiny-button.png
│ │ │ ├── one-page-el-to-tiny.png
│ │ │ ├── vue2-element.png
│ │ │ └── vue2-to-vue3.png
│ │ └── favicon.ico
│ ├── src
│ │ ├── App.vue
│ │ ├── assets
│ │ │ └── logo.png
│ │ ├── components
│ │ │ ├── FormPage.vue
│ │ │ ├── HelloWorld.vue
│ │ │ ├── HomePage.vue
│ │ │ └── ListPage.vue
│ │ └── main.js
│ └── vite.config.js
├── home
│ ├── README.md
│ ├── README.zh-CN.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── favicon.ico
│ ├── src
│ │ ├── App.vue
│ │ ├── assets
│ │ │ └── logo.png
│ │ ├── index.css
│ │ ├── main.js
│ │ ├── router
│ │ │ └── index.js
│ │ └── views
│ │ │ ├── Home.vue
│ │ │ ├── React.vue
│ │ │ ├── Solid.vue
│ │ │ ├── Vue2.vue
│ │ │ └── Vue3.vue
│ └── vite.config.js
├── react
│ ├── README.md
│ ├── README.zh-CN.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── App.jsx
│ │ ├── main.jsx
│ │ └── style.css
│ └── vite.config.js
├── solid
│ ├── README.md
│ ├── README.zh-CN.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── App.jsx
│ │ ├── assets
│ │ │ └── solid.svg
│ │ ├── index.jsx
│ │ └── style.css
│ └── vite.config.js
├── vue2
│ ├── README.md
│ ├── README.zh-CN.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── src
│ │ ├── App.vue
│ │ ├── assets
│ │ │ └── logo.png
│ │ └── main.js
│ └── vite.config.js
└── vue3
│ ├── README.md
│ ├── README.zh-CN.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ └── vite.svg
│ ├── src
│ ├── App.vue
│ ├── DemoPoc.vue
│ ├── assets
│ │ └── vue.svg
│ ├── main.js
│ ├── style.css
│ └── views
│ │ ├── mobile.vue
│ │ ├── pc.vue
│ │ └── watch.vue
│ └── vite.config.js
├── pnpm-workspace.yaml
└── setup.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['airbnb-base'],
3 | // 指定解析器选项
4 | 'parserOptions': {
5 | ecmaVersion: 7,
6 | sourceType: 'module'
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist/
3 |
4 | vite.config.ts.timestamp*
5 | vitest.config.ts.timestamp*
6 |
7 | # local env
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 | pnpm-lock.yaml
16 | yarn.lock
17 |
18 | # Editor directories and files
19 | .idea
20 | .history
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 | *.log
27 | *.stackdump
28 |
29 | tgzs
30 | *.tgz
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | pnpm-lock.yaml
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "printWidth": 80,
5 | "trailingComma": "none",
6 | "quoteProps": "preserve",
7 | "endOfLine": "auto",
8 | "bracketSpacing": true,
9 | "jsxBracketSameLine": true,
10 | "jsxSingleQuote": false,
11 | "useTabs": false,
12 | "tabWidth": 2,
13 | "proseWrap": "preserve"
14 | }
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/cross-framework
2 |
3 | This is a demonstration of the OpenTiny cross-end and cross-framework micro-front-end project (built based on WUJIE and pnpm):
4 |
5 |
6 | ## Local startup
7 |
8 | You can run the following command in the root directory of the project to download the project dependency:
9 |
10 | ```shell
11 | pnpm i
12 | ```
13 |
14 | You can then start the case project by running the following command:
15 |
16 | ```shell
17 | pnpm dev
18 | ```
19 |
20 | You can run the following commands to open a demonstration case of a framework:
21 |
22 | ```shell
23 | pnpm dev:react
24 | # or
25 | pnpm dev:solid
26 | # or
27 | pnpm dev:vue2
28 | # or
29 | pnpm dev:vue3
30 | ```
31 |
32 | Congratulations on the success of the launch!
33 |
34 | ``` html
35 | cross-framework-component
36 | ├─ package.json
37 | ├─ packages
38 | │ ├─ components
39 | │ │ ├─ react
40 | │ │ ├─ renderless
41 | │ │ ├─ solid
42 | │ │ ├─ theme
43 | │ │ ├─ theme-mobile
44 | │ │ ├─ theme-watch
45 | │ │ └─ vue
46 | │ ├─ element-to-opentiny
47 | │ ├─ home
48 | │ ├─ react
49 | │ ├─ solid
50 | │ ├─ vue2
51 | │ └─ vue3
52 | ├─ pnpm-workspace.yaml
53 | ├─ README.md
54 | ├─ README.zh-CN.md
55 | └─ setup.js
56 |
57 | ```
58 |
--------------------------------------------------------------------------------
/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/cross-framework
2 |
3 | 这是一个演示OpenTiny跨端、跨框架的案例微前端工程(基于WUJIE和pnpm搭建):
4 |
5 |
6 | ## 本地启动
7 |
8 | 可以通过在项目根目录执行以下命令下载工程依赖:
9 |
10 | ```shell
11 | pnpm i
12 | ```
13 |
14 | 接着可以,通过运行以下命令启动基于WUJIE的微前端案例工程:
15 |
16 | ```shell
17 | pnpm dev
18 | ```
19 |
20 | 或者也可以分别通过以下命令单独打开某个框架的演示案例:
21 |
22 | ```shell
23 | pnpm dev:react
24 | # or
25 | pnpm dev:solid
26 | # or
27 | pnpm dev:vue2
28 | # or
29 | pnpm dev:vue3
30 | ```
31 |
32 | 恭喜你启动成功!🎉
33 |
34 | ``` html
35 | cross-framework-component
36 | ├─ package.json
37 | ├─ packages
38 | │ ├─ components
39 | │ │ ├─ react
40 | │ │ ├─ renderless
41 | │ │ ├─ solid
42 | │ │ ├─ theme
43 | │ │ ├─ theme-mobile
44 | │ │ ├─ theme-watch
45 | │ │ └─ vue
46 | │ ├─ element-to-opentiny
47 | │ ├─ home
48 | │ ├─ react
49 | │ ├─ solid
50 | │ ├─ vue2
51 | │ └─ vue3
52 | ├─ pnpm-workspace.yaml
53 | ├─ README.md
54 | ├─ README.zh-CN.md
55 | └─ setup.js
56 |
57 | ```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/cross-framework",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "preinstall": "npx only-allow pnpm",
8 | "dev": "node setup.js",
9 | "dev:home": "pnpm -C packages/home dev",
10 | "dev:react": "pnpm -C packages/react dev",
11 | "dev:solid": "pnpm -C packages/solid dev",
12 | "dev:vue2": "pnpm -C packages/vue2 dev",
13 | "dev:vue3": "pnpm -C packages/vue3 dev",
14 | "dev:el": "pnpm -C packages/element-to-opentiny dev"
15 | },
16 | "repository": {
17 | "type": "git"
18 | },
19 | "keywords": [],
20 | "author": "",
21 | "license": "ISC",
22 | "dependencies": {
23 | "eslint": "8.48.0"
24 | },
25 | "pnpm": {
26 | "packageExtensions": {
27 | "vue-template-compiler@2.6.14": {
28 | "peerDependencies": {
29 | "vue": "2.6.14"
30 | }
31 | },
32 | "@opentiny/vue-locale@2.9.0": {
33 | "peerDependencies": {
34 | "vue": "2.6.14"
35 | }
36 | },
37 | "@opentiny/vue-common@2.9.0": {
38 | "peerDependencies": {
39 | "vue": "2.6.14"
40 | }
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/packages/components/react/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/react
2 |
3 | This is a component library based on the React framework:
4 |
5 | ### 1. Installation
6 |
7 | Download the component library dependencies by running the following command:
8 |
9 | ```shell
10 | npm i @opentiny/react
11 | ```
12 |
13 | ### 2. Introduction and use
14 |
15 | Use the @opentiny/react component in the `App.jsx` file.
16 |
17 | ```js
18 | import { Button } from '@opentiny/react'
19 |
20 | function App() {
21 | return (
22 | <>
23 |
24 | >
25 | )
26 | }
27 |
28 | export default App
29 |
30 | ```
--------------------------------------------------------------------------------
/packages/components/react/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/react
2 |
3 | 这是一个基于React框架的组件库:
4 |
5 | ### 1. 安装
6 |
7 | 通过运行以下命令下载组件库依赖:
8 |
9 | ```shell
10 | npm i @opentiny/react
11 | ```
12 |
13 | ### 2. 引入和使用
14 |
15 | 在`App.jsx`文件中使用 @opentiny/react 组件。
16 |
17 | ```js
18 | import { Button } from '@opentiny/react'
19 |
20 | function App() {
21 | return (
22 | <>
23 |
24 | >
25 | )
26 | }
27 |
28 | export default App
29 |
30 | ```
31 |
--------------------------------------------------------------------------------
/packages/components/react/common/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/react-common",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/renderless": "workspace:~",
14 | "@opentiny/theme": "workspace:~",
15 | "classnames": "^2.3.2",
16 | "ahooks": "3.7.8",
17 | "react": "18.2.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/components/react/common/src/index.js:
--------------------------------------------------------------------------------
1 | import * as hooks from 'react'
2 | import '@opentiny/theme/base/index.less'
3 | import { useReactive } from 'ahooks' // 使用ahooks提供的useReactive抹平vue框架的响应式数据
4 |
5 | // 抹平vue框架的事件触发机制
6 | export const emit =
7 | (props) =>
8 | (evName, ...args) => {
9 | if (props[evName] && typeof props[evName] === 'function') {
10 | props[evName](...args)
11 | }
12 | }
13 |
14 | // 模拟vue框架的nextTick,等待 dom 更新后触发回调
15 | export const useNextTick = (callback) => {
16 | queueMicrotask(callback)
17 | }
18 |
19 | // emitEvent, dispath, broadcast
20 | export const emitEvent = () => {
21 | const broadcast = () => {
22 | return ''
23 | }
24 |
25 | return {
26 | dispatch: () => {
27 | return ''
28 | },
29 | broadcast
30 | }
31 | }
32 |
33 | export const useSetup = ({
34 | props, // 模板层传递过来的props属性
35 | renderless, // renderless无渲染函数
36 | extendOptions = { framework: 'React' } // 模板层传递过来的额外参数
37 | }) => {
38 | const render =
39 | typeof props.tiny_renderless === 'function'
40 | ? props.tiny_renderless
41 | : renderless
42 | const utils = {
43 | parent: {},
44 | emit: emit(props)
45 | }
46 | const sdk = render(
47 | props,
48 | { ...hooks, useReactive, useNextTick },
49 | utils,
50 | extendOptions
51 | )
52 | return {
53 | ...sdk,
54 | type: props.type ?? 'default'
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/packages/components/react/index.js:
--------------------------------------------------------------------------------
1 | import Button from '@opentiny/react-button/src/pc'
2 | import Countdown from '@opentiny/react-countdown/src/pc'
3 |
4 | export { Button, Countdown }
5 |
--------------------------------------------------------------------------------
/packages/components/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/react",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/react-button": "workspace:~",
14 | "@opentiny/react-countdown": "workspace:~"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/components/react/src/button/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/react-button",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "./src/pc.jsx",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/renderless": "workspace:~",
14 | "@opentiny/theme": "workspace:~",
15 | "@opentiny/react-common": "workspace:~"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/components/react/src/button/src/pc.jsx:
--------------------------------------------------------------------------------
1 | import renderless from '@opentiny/renderless/button/react' // renderless无渲染层
2 | import { useSetup } from '@opentiny/react-common' // 抹平不同框架的适配层
3 | import '@opentiny/theme/button/index.less' // 复用OpenTinyVue的样式文件
4 |
5 | export default function Button(props) {
6 | const {
7 | children,
8 | text,
9 | autofocus,
10 | round,
11 | circle,
12 | icon: Icon,
13 | size,
14 | nativeType = 'button'
15 | } = props
16 |
17 | const { handleClick, state, tabindex, type, $attrs } = useSetup({
18 | // 通过common适配层的useSetup处理props和renderless无渲染层
19 | props: { nativeType: 'button', resetTime: 1000, ...props },
20 | renderless
21 | })
22 |
23 | const className = [
24 | 'tiny-button',
25 | type ? 'tiny-button--' + type : '',
26 | size ? 'tiny-button--' + size : '',
27 | state.disabled ? 'is-disabled' : '',
28 | state.plain ? 'is-plain' : '',
29 | round ? 'is-round' : '',
30 | circle ? 'is-circle' : ''
31 | ]
32 | .join(' ')
33 | .trim()
34 | return (
35 |
46 | )
47 | }
48 |
--------------------------------------------------------------------------------
/packages/components/react/src/countdown/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/react-countdown",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "./src/pc.jsx",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/renderless": "workspace:~",
14 | "@opentiny/theme": "workspace:~",
15 | "@opentiny/react-common": "workspace:~"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/components/react/src/countdown/src/pc.jsx:
--------------------------------------------------------------------------------
1 | import renderless from '@opentiny/renderless/countdown/react'
2 | import { useSetup } from '@opentiny/react-common'
3 | import '@opentiny/theme/countdown/index.less'
4 |
5 | export default function Countdown(props) {
6 | const defaultProps = {
7 | deadline: 60,
8 | completeZero: true,
9 | leftSecond: 0,
10 | autoPlay: false,
11 | ignoreDay: true
12 | }
13 |
14 | const newProps = { ...defaultProps, ...props }
15 |
16 | const { state } = useSetup({
17 | props: newProps,
18 | renderless
19 | })
20 |
21 | return (
22 |
{`${state.hour}:${state.minute}:${state.second}`}
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/packages/components/renderless/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/renderless
2 |
3 | 这是一个为 OpenTiny 跨端、跨框架组件提供 renderless 无渲染逻辑的公共逻辑层项目工程。
4 | # @opentiny/renderless
5 |
6 | This is a common logic layer project that provides renderless non-rendering logic for OpenTiny cross-end and cross-framework components.
--------------------------------------------------------------------------------
/packages/components/renderless/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/renderless
2 |
3 | 这是一个为 OpenTiny 跨端、跨框架组件提供 renderless 无渲染逻辑的公共逻辑层项目工程。
4 |
--------------------------------------------------------------------------------
/packages/components/renderless/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/renderless",
3 | "version": "3.9.0",
4 | "sideEffects": false,
5 | "type": "module",
6 | "exports": {
7 | "./package.json": "./package.json",
8 | "./*": "./src/*"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/button/index.js:
--------------------------------------------------------------------------------
1 | export const handleClick =
2 | ({ emit, props, state, framework }) =>
3 | (event) => {
4 | if (props.nativeType === 'button' && props.resetTime > 0) {
5 | state.disabled = true
6 | state.timer = setTimeout(() => {
7 | state.disabled = false
8 | }, props.resetTime)
9 | }
10 |
11 | console.log(`${framework}框架代码已触发!!!!!!!!!`)
12 |
13 | emit('click', event)
14 | }
15 |
16 | export const clearTimer = (state) => () => clearTimeout(state.timer)
17 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/button/react.js:
--------------------------------------------------------------------------------
1 | import { handleClick, clearTimer } from './index'
2 |
3 | export const api = ['state', 'handleClick']
4 |
5 | export default function renderless(
6 | props,
7 | { useReactive },
8 | { emit },
9 | { framework }
10 | ) {
11 | // 利用ahooks提供的useReactive模拟vue的响应式数据,并且使用react的useRef响应式数据被重复执行定义
12 | const state = useReactive({
13 | timer: null,
14 | disabled: !!props.disabled,
15 | plain: props.plain,
16 | formDisabled: false
17 | })
18 |
19 | const api = {
20 | state,
21 | clearTimer: clearTimer(state),
22 | handleClick: handleClick({ emit, props, state, framework })
23 | }
24 |
25 | return api
26 | }
27 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/button/solid.js:
--------------------------------------------------------------------------------
1 | import { handleClick, clearTimer } from './index'
2 |
3 | export const api = ['state', 'handleClick']
4 |
5 | export default function renderless(
6 | props,
7 | { useReactive },
8 | { emit },
9 | { framework }
10 | ) {
11 | const { state, proxy } = useReactive({
12 | timer: null,
13 | disabled: !!props.disabled,
14 | plain: props.plain
15 | })
16 |
17 | const api = {
18 | state,
19 | clearTimer: clearTimer(proxy),
20 | handleClick: handleClick({ emit, props, state: proxy, framework })
21 | }
22 |
23 | return api
24 | }
25 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/button/vue.js:
--------------------------------------------------------------------------------
1 | import { handleClick, clearTimer } from './index'
2 |
3 | export const api = ['state', 'handleClick']
4 |
5 | export const renderless = (
6 | props,
7 | { computed, onBeforeUnmount, reactive, watch, inject },
8 | { emit, parent },
9 | { framework }
10 | ) => {
11 | parent.tinyForm = parent.tinyForm || inject('form', null)
12 |
13 | const state = reactive({
14 | timer: null,
15 | disabled: props.disabled,
16 | plain: computed(() => props.plain || (parent.buttonGroup || {}).plain),
17 | formDisabled: computed(() => (parent.tinyForm || {}).disabled),
18 | buttonDisabled: computed(
19 | () =>
20 | props.disabled ||
21 | state.disabled ||
22 | (parent.buttonGroup || {}).disabled ||
23 | state.formDisabled
24 | )
25 | })
26 |
27 | watch(
28 | () => props.disabled,
29 | (value) => {
30 | state.disabled = value
31 | },
32 | { immediate: true }
33 | )
34 |
35 | const api = {
36 | state,
37 | clearTimer: clearTimer(state),
38 | handleClick: handleClick({ emit, props, state, framework })
39 | }
40 |
41 | onBeforeUnmount(api.clearTimer)
42 |
43 | return api
44 | }
45 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/countdown/index.js:
--------------------------------------------------------------------------------
1 | // 格式化数字格式
2 | const formatNumber = (number, completeZero) => {
3 | if (number < 10 && completeZero) {
4 | return '0' + number
5 | } else {
6 | return number.toString()
7 | }
8 | }
9 |
10 | // 模拟setInterval
11 | export const CustomSetInterval = function (func, millisecond) {
12 | let setIntervalId
13 |
14 | if (typeof func === 'function') {
15 | setIntervalId = setTimeout(function self() {
16 | setIntervalId = setTimeout(self, millisecond)
17 |
18 | func()
19 | }, millisecond)
20 | }
21 |
22 | this.stop = () => {
23 | clearTimeout(setIntervalId)
24 | }
25 | }
26 |
27 | export const getRestTime = (state) => {
28 | // 获取剩余时间(秒)
29 | return Math.max(Math.round((state.deadlineTimestamp - Date.now()) / 1000), 0)
30 | }
31 |
32 | export const render =
33 | ({ state, props, nextTick, emit }) =>
34 | () => {
35 | const restTime = getRestTime(state)
36 | if (state.ignoreDay) {
37 | state.hour = formatNumber(
38 | Math.floor(restTime / (60 * 60)),
39 | props.completeZero
40 | )
41 | } else {
42 | state.day = formatNumber(
43 | Math.floor(restTime / (24 * 60 * 60)),
44 | props.completeZero
45 | )
46 | state.hour = formatNumber(
47 | Math.floor((restTime / (60 * 60)) % 24),
48 | props.completeZero
49 | )
50 | }
51 | state.minute = formatNumber(
52 | Math.floor((restTime / 60) % 60),
53 | props.completeZero
54 | )
55 |
56 | state.second = formatNumber(restTime % 60, props.completeZero)
57 |
58 | nextTick(() => {
59 | emit('update', {
60 | day: state.day,
61 | hour: state.hour,
62 | minute: state.minute,
63 | second: state.second,
64 | restSecond: restTime // 剩余时间(秒)
65 | })
66 | })
67 | }
68 |
69 | export const start =
70 | ({ render, state, emit, props }) =>
71 | () => {
72 | state.deadlineTimestamp = Date.now() + props.deadline * 1000
73 | if (getRestTime(state) > props.leftSecond) {
74 | state.setIntervalInstance.stop()
75 |
76 | state.setIntervalInstance = new CustomSetInterval(() => {
77 | render()
78 |
79 | if (getRestTime(state) <= props.leftSecond) {
80 | state.setIntervalInstance.stop()
81 | }
82 | }, 1000)
83 | }
84 | }
85 |
86 | export const reset =
87 | ({ state, props, renderFn }) =>
88 | () => {
89 | state.deadlineTimestamp = Date.now() + props.deadline * 1000
90 | state.setIntervalInstance.stop()
91 | renderFn()
92 | }
93 |
94 | export const init = ({ api, props }) => {
95 | const { start, reset, render } = api
96 | render()
97 | props.operate && props.operate({ start, reset })
98 | if (props.autoPlay) {
99 | start()
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/countdown/react.js:
--------------------------------------------------------------------------------
1 | import {
2 | render,
3 | start,
4 | reset,
5 | init
6 | } from './index'
7 |
8 | export const api = ['state']
9 |
10 | export default function renderless(
11 | props,
12 | { useReactive, useEffect, useNextTick: nextTick, use },
13 | { emit }
14 | ) {
15 | const state = useReactive({
16 | day: '00',
17 | hour: '00',
18 | minute: '00',
19 | second: '00',
20 | // 每秒执行(实例)
21 | setIntervalInstance: Object.freeze({ stop: () => {} }),
22 | deadlineTimestamp: Date.now() + props.deadline * 1000
23 | })
24 |
25 | const renderFn = render({ state, props, nextTick, emit })
26 |
27 | const api = {
28 | state,
29 | render: renderFn,
30 | start: start({ render: renderFn, state, emit, props }),
31 | reset: reset({ state, props, renderFn })
32 | }
33 |
34 | // 模拟vue的mounted,只会执行一次
35 | useEffect(()=> init({ api, props, state }),[])
36 |
37 |
38 | return api
39 | }
40 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/countdown/solid.js:
--------------------------------------------------------------------------------
1 | import {
2 | render,
3 | start,
4 | reset,
5 | init
6 | } from './index'
7 |
8 | export const api = ['state']
9 |
10 | export default function renderless(
11 | props,
12 | { useReactive, useNextTick: nextTick },
13 | { emit }
14 | ) {
15 | const { state, proxy } = useReactive({
16 | day: '00',
17 | hour: '00',
18 | minute: '00',
19 | second: '00',
20 | // 每秒执行(实例)
21 | setIntervalInstance: Object.freeze({ stop: () => {} }),
22 | deadlineTimestamp: Date.now() + props.deadline * 1000
23 | })
24 | const renderFn = render({ state: proxy, props, nextTick, emit })
25 |
26 | const api = {
27 | state,
28 | render: renderFn,
29 | start: start({ render: renderFn, state: proxy, emit, props }),
30 | reset: reset({ state: proxy, props, renderFn })
31 | }
32 |
33 | init({ api, props, state: proxy })
34 |
35 | return api
36 | }
37 |
--------------------------------------------------------------------------------
/packages/components/renderless/src/countdown/vue.js:
--------------------------------------------------------------------------------
1 | import {
2 | render,
3 | start,
4 | reset,
5 | init
6 | } from './index'
7 |
8 | export const api = ['state']
9 |
10 | export const renderless = (
11 | props,
12 | { onBeforeUnmount, reactive, watch },
13 | { emit, nextTick }
14 | ) => {
15 | const state = reactive({
16 | day: '00',
17 | hour: '00',
18 | minute: '00',
19 | second: '00',
20 | setIntervalInstance: Object.freeze({ stop: () => {} }),
21 | deadlineTimestamp: Date.now() + props.deadline * 1000
22 | })
23 |
24 | const renderFn = render({ state, props, nextTick, emit })
25 |
26 | const api = {
27 | state,
28 | render: renderFn,
29 | start: start({ render: renderFn, state, emit, props }),
30 | reset: reset({ state, props, renderFn })
31 | }
32 |
33 | init({ api, props, state })
34 |
35 | onBeforeUnmount(() => {
36 | state.setIntervalInstance.stop()
37 | })
38 |
39 | return api
40 | }
41 |
--------------------------------------------------------------------------------
/packages/components/solid/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/solid
2 |
3 | 这是一个基于 Solid 框架的组件库:
4 |
5 | ### 1. 安装
6 |
7 | 通过运行以下命令下载组件库依赖:
8 |
9 | ```shell
10 | npm i @opentiny/solid
11 | ```
12 |
13 | ### 2. 引入和使用
14 |
15 | 在`App.jsx`文件中使用 @opentiny/solid 组件。
16 |
17 | ```js
18 | import { Button } from '@opentiny/solid'
19 |
20 | function App() {
21 | return (
22 | <>
23 |
24 | >
25 | )
26 | }
27 |
28 | export default App
29 |
30 | ```
31 | # @opentiny/solid
32 |
33 | This is a component library based on the Solid framework:
34 |
35 | ### 1. Installation
36 |
37 | Download the component library dependencies by running the following command:
38 |
39 | ```shell
40 | npm i @opentiny/solid
41 | ```
42 |
43 | ### 2. Introduction and use
44 |
45 | Use the @opentiny/solid component in the `App.jsx` file.
46 |
47 | ```js
48 | import { Button } from '@opentiny/solid'
49 |
50 | function App() {
51 | return (
52 | <>
53 |
54 | >
55 | )
56 | }
57 |
58 | export default App
59 |
60 | ```
--------------------------------------------------------------------------------
/packages/components/solid/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/solid
2 |
3 | 这是一个基于 Solid 框架的组件库:
4 |
5 | ### 1. 安装
6 |
7 | 通过运行以下命令下载组件库依赖:
8 |
9 | ```shell
10 | npm i @opentiny/solid
11 | ```
12 |
13 | ### 2. 引入和使用
14 |
15 | 在`App.jsx`文件中使用 @opentiny/solid 组件。
16 |
17 | ```js
18 | import { Button } from '@opentiny/solid'
19 |
20 | function App() {
21 | return (
22 | <>
23 |
24 | >
25 | )
26 | }
27 |
28 | export default App
29 |
30 | ```
31 |
--------------------------------------------------------------------------------
/packages/components/solid/common/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/solid-common",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/renderless": "workspace:~",
14 | "@opentiny/theme": "workspace:~",
15 | "classnames": "^2.3.2",
16 | "solid-js": "^1.7.8"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/components/solid/common/src/index.js:
--------------------------------------------------------------------------------
1 | import * as hooks from 'solid-js'
2 | import { createSignal } from 'solid-js'
3 | import '@opentiny/theme/base/index.less'
4 |
5 | const EVENTS_PREFIX = 'on'
6 |
7 | // 处理solid事件触发机制
8 | export const emit =
9 | (props) =>
10 | (evName, ...args) => {
11 | const eventsName = `${EVENTS_PREFIX}${evName[0].toLocaleUpperCase()}${evName.slice(
12 | 1
13 | )}`
14 | if (props[eventsName] && typeof props[eventsName] === 'function') {
15 | props[eventsName](...args)
16 | }
17 | }
18 |
19 | export const useSetState = (initialState) => {
20 | const [state, setState] = createSignal(initialState, { equals: false })
21 |
22 | return [state, setState]
23 | }
24 |
25 | // props 应该不用做处理, props 都是 . 访问。
26 | export const useReactive = (staticObject) => {
27 | const [state, setState] = useSetState(staticObject)
28 |
29 | return {
30 | state,
31 | proxy: new Proxy(state(), {
32 | get(target, property) {
33 | if (typeof target[property] === 'function') {
34 | return target[property](target)
35 | } else {
36 | return target[property]
37 | }
38 | },
39 | set(target, property, value) {
40 | Reflect.set(target, property, value)
41 | setState((val) => val)
42 | return true
43 | }
44 | })
45 | }
46 | }
47 |
48 | // nextTick, 等待 dom 更新后触发回调
49 | export const useNextTick = (callback) => {
50 | queueMicrotask(callback)
51 | }
52 |
53 | // emitEvent, dispath, broadcast
54 | export const emitEvent = () => {
55 | const broadcast = () => {
56 | return ''
57 | }
58 |
59 | return {
60 | dispatch: () => {
61 | return ''
62 | },
63 | broadcast
64 | }
65 | }
66 |
67 | export const useSetup = ({
68 | props,
69 | renderless,
70 | extendOptions = { framework: 'Solid' }
71 | }) => {
72 | const render =
73 | typeof props.tiny_renderless === 'function'
74 | ? props.tiny_renderless
75 | : renderless
76 | const utils = {
77 | parent: {},
78 | emit: emit(props)
79 | }
80 | const sdk = render(
81 | props,
82 | { ...hooks, useReactive, useNextTick },
83 | utils,
84 | extendOptions
85 | )
86 | return {
87 | ...sdk,
88 | type: props.type ?? 'default'
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/packages/components/solid/index.js:
--------------------------------------------------------------------------------
1 | import Button from '@opentiny/solid-button/src/pc'
2 | import Countdown from '@opentiny/solid-countdown/src/pc'
3 |
4 | export { Button, Countdown }
5 |
--------------------------------------------------------------------------------
/packages/components/solid/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/solid",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/solid-button": "workspace:~",
14 | "@opentiny/solid-countdown": "workspace:~"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/components/solid/src/button/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/solid-button",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "./src/pc.jsx",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/renderless": "workspace:~",
14 | "@opentiny/theme": "workspace:~",
15 | "@opentiny/solid-common": "workspace:~"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/components/solid/src/button/src/pc.jsx:
--------------------------------------------------------------------------------
1 | import renderless from '@opentiny/renderless/button/solid'
2 | import { useSetup } from '@opentiny/solid-common'
3 | import '@opentiny/theme/button/index.less'
4 |
5 | export default function Button(props) {
6 | const {
7 | children,
8 | text,
9 | autofocus,
10 | round,
11 | circle,
12 | icon: Icon,
13 | size,
14 | nativeType = 'button'
15 | } = props
16 | const { handleClick, state, tabindex, type, $attrs } = useSetup({
17 | props: { nativeType: 'button', resetTime: 1000, ...props },
18 | renderless
19 | })
20 |
21 | return (
22 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/packages/components/solid/src/countdown/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/solid-countdown",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "./src/pc.jsx",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/renderless": "workspace:~",
14 | "@opentiny/theme": "workspace:~",
15 | "@opentiny/solid-common": "workspace:~"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/components/solid/src/countdown/src/pc.jsx:
--------------------------------------------------------------------------------
1 | import renderless from '@opentiny/renderless/countdown/solid'
2 | import { useSetup } from '@opentiny/solid-common'
3 | import '@opentiny/theme/countdown/index.less'
4 |
5 | export default function Countdown(props) {
6 | const defaultProps = {
7 | deadline: 60,
8 | completeZero: true,
9 | leftSecond: 0,
10 | ignoreDay: true
11 | }
12 | const { state } = useSetup({
13 | props: { ...defaultProps, ...props },
14 | renderless
15 | })
16 |
17 | return (
18 | {`${state().hour}:${
19 | state().minute
20 | }:${state().second}`}
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/theme-mobile
2 |
3 | This is a project to provide Mobile template styles for OpenTiny cross-end and cross-framework components.
--------------------------------------------------------------------------------
/packages/components/theme-mobile/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/theme-mobile
2 |
3 | 这是一个为 OpenTiny 跨端、跨框架组件提供 Mobile 模板样式的工程
4 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/theme-mobile",
3 | "version": "3.9.0",
4 | "description": "",
5 | "sideEffects": false,
6 | "dependencies": {
7 | "less": "~4.1.3"
8 | },
9 | "type": "module",
10 | "exports": {
11 | "./*": "./src/*"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/base/basic-var.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | /*基础变量定义*/
14 | :root,:host{
15 | /* 品牌色*/
16 | --ti-mobile-base-color-brand-1: #4a79fe; /* 蓝_品牌色*/
17 | --ti-mobile-base-color-brand-2: #3168f1;
18 | --ti-mobile-base-color-brand-3: #6e94fe;
19 | --ti-mobile-base-color-brand-4: #92affe;
20 | --ti-mobile-base-color-brand-5: #b7c9ff;
21 | --ti-mobile-base-color-brand-6: #95a2f8;
22 | --ti-mobile-base-color-brand-6: #ffffff;
23 |
24 | /* 1.2背景色*/
25 | --ti-mobile-base-color-bg-1: #f5f5f5; /* 深灰_背景色*/
26 | --ti-mobile-base-color-bg-2: #fafafa; /* 浅灰_背景色*/
27 | --ti-mobile-base-color-bg-3: #ffffff; /* 白色_背景色*/
28 |
29 | /* 文本、线、面等常用灰色可用颜色参考:*/
30 | --ti-mobile-base-color-common-1: #000000;
31 | --ti-mobile-base-color-common-2: #191919;
32 | --ti-mobile-base-color-common-3: #262626;
33 | --ti-mobile-base-color-common-4: #333333;
34 | --ti-mobile-base-color-common-5: #595959;
35 | --ti-mobile-base-color-common-6: #999999;
36 | --ti-mobile-base-color-common-7: #c2c2c2;
37 | --ti-mobile-base-color-common-8: #dbdbdb;
38 | --ti-mobile-base-color-common-9: #ededed;
39 | --ti-mobile-base-color-common-10: #f5f5f5;
40 | --ti-mobile-base-color-common-11: #fafafa;
41 | --ti-mobile-base-color-common-12: #ffffff;
42 | --ti-mobile-base-color-common-13: #627199;
43 |
44 | /* 功能色*/
45 | --ti-mobile-common-color-warning-figure-1: #eb4096; /* 致命警告图形色*/
46 | --ti-mobile-common-color-warning-text-1: #e61c81; /* 致命警告文字色*/
47 | --ti-mobile-common-color-warning-figure-2: #ff9c32; /* 一般告警/中性1图形色*/
48 | --ti-mobile-common-color-warning-text-2: #ff8800; /* 一般告警/中性1文字色*/
49 | --ti-mobile-common-color-warning-figure-3: #1ebe40; /* 一般告警/中性1图形色*/
50 | --ti-mobile-common-color-warning-text-3: #00b336; /* 一般告警/中性1文字色*/
51 |
52 | --ti-mobile-common-color-error-figure-1: #eb5454; /* 异常/下降/告警/驳回/退订/失败图形色*/
53 | --ti-mobile-common-color-error-text-1: #e62222; /* 异常/下降/告警/驳回/退订/失败文字色*/
54 | --ti-mobile-common-color-error-figure-2: #fccd32; /* 异常/下降/告警/驳回/退订/失败图形色*/
55 | --ti-mobile-common-color-error-text-2: #fcbe1e; /* 异常/下降/告警/驳回/退订/失败文字色*/
56 | --ti-mobile-common-color-error-figure-3: #1e8aff; /* 异常/下降/告警/驳回/退订/失败图形色*/
57 | --ti-mobile-common-color-error-text-3: #1476ff; /* 异常/下降/告警/驳回/退订/失败文字色*/
58 | --ti-mobile-common-color-error-figure-4: #c2c2c2; /* 异常/下降/告警/驳回/退订/失败图形色*/
59 | --ti-mobile-common-color-error-text-4: #999999; /* 异常/下降/告警/驳回/退订/失败文字色*/
60 |
61 | /* 图表推荐配色*/
62 | --ti-mobile-common-color-chart-1: #1476ff;
63 | --ti-mobile-common-color-chart-2: #10c7c1;
64 | --ti-mobile-common-color-chart-3: #b878f0;
65 | --ti-mobile-common-color-chart-4: #d6a981;
66 | --ti-mobile-common-color-chart-5: #c1cc7a;
67 |
68 | /* 文本色*/
69 | --ti-mobile-common-color-text-primary: var(
70 | --ti-mobile-base-color-common-2
71 | ); /* 一级文本色-重要信息/标题颜色/输入类文本颜色*/
72 | --ti-mobile-common-color-text-secondary: var(--ti-mobile-base-color-common-5); /* 二级文本色-次要信息*/
73 | --ti-mobile-common-color-text-weaken-dark: var(--ti-mobile-base-color-common-6); /* 三级文本色-弱化信息/说明文字*/
74 | --ti-mobile-common-color-text-weaken-ligtht: var(--ti-mobile-base-color-common-7); /* 文本_弱化色_浅色/提示*/
75 | --ti-mobile-common-color-text-weaken-disabled: var(--ti-mobile-base-color-common-8); /* 文本_弱化色_浅色/禁用*/
76 | --ti-mobile-common-color-text-white: var(--ti-mobile-base-color-common-12); /* 文本_白色*/
77 | --ti-mobile-common-color-text-placeholder-primary: #dbe5fc; /* placeholder_主要*/
78 | --ti-mobile-common-color-text-placeholder-gray: #acacac; /* placeholder_灰*/
79 | --ti-mobile-common-color-text-high-light: var(--ti-mobile-base-color-brand-1); /* 文本_高亮*/
80 |
81 | /* 文本链接色*/
82 | --ti-mobile-common-color-link-dark: var(--ti-mobile-base-color-common-2); /* 文本_链接__深色*/
83 | --ti-mobile-common-color-link-highlight: var(--ti-mobile-base-color-brand-1); /* 文本_链接_高亮色*/
84 | --ti-mobile-common-color-link-gray: var(--ti-mobile-base-color-common-13); /* 文本_链接_灰色加强*/
85 | --ti-mobile-common-color-link-white: var(--ti-mobile-base-color-common-12); /* 文本_链接_白色*/
86 |
87 | /* 线颜色*/
88 | --ti-mobile-common-color-line-hightlight: var(--ti-mobile-base-color-brand-1); /* 高亮_描边色*/
89 | --ti-mobile-common-color-line-dark: var(--ti-mobile-base-color-common-9); /* 深_描边色*/
90 | --ti-mobile-common-color-line-light: var(--ti-mobile-base-color-common-10); /* 浅_描边色*/
91 | --ti-mobile-common-color-line-white: var(--ti-mobile-base-color-common-12); /* 白色*/
92 |
93 | /* 蒙层色*/
94 | --ti-mobile-common-color-mask-light: rgba(0, 0, 0, 0.5); /* 蒙层_相对浅*/
95 | --ti-mobile-common-color-mask-dark: rgba(0, 0, 0, 0.75); /* 蒙层_相对深*/
96 |
97 | /* 背景色*/
98 | --ti-mobile-common-bg-color-white: var(--ti-mobile-base-color-bg-3); /* 背景_白*/
99 | --ti-mobile-common-bg-color-main: var(--ti-mobile-base-color-brand-1); /* 背景_蓝*/
100 | --ti-mobile-common-bg-color-light: var(--ti-mobile-base-color-bg-2); /* 背景_浅灰*/
101 | --ti-mobile-common-bg-color-blue-1: var(--ti-mobile-base-color-brand-2); /* 背景_蓝*/
102 | --ti-mobile-common-bg-color-disabled: #e8e8e8; /* 背景_禁用*/
103 | --ti-mobile-common-bg-color-dark-gray: var(--ti-mobile-base-color-bg-1); /* 背景_深灰*/
104 | --ti-mobile-common-bg-color-weaken: var(--ti-mobile-base-color-common-8); /* 背景_弱化色*/
105 | --ti-mobile-common-status-bg-color-success: #5bd475; /* 背景_成功/通过*/
106 | --ti-mobile-common-status-bg-color-error: #eb5454; /* 背景_失败/驳回*/
107 | --ti-mobile-common-status-bg-color-normal: #fff; /* 背景_默认*/
108 | --ti-mobile-common-status-bg-color-handing: var(--ti-mobile-base-color-brand-1); /* 背景_进行中*/
109 | }
110 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/base/index.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @import './reset.less';
14 | @import './basic-var.less';
15 | @import './vars.less';
16 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/base/reset.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @import '../custom.less';
14 |
15 | [class*=~'@{css-prefix}'] {
16 | -webkit-box-sizing: border-box;
17 | box-sizing: border-box;
18 |
19 | *:after,
20 | *:before {
21 | -webkit-box-sizing: border-box;
22 | box-sizing: border-box;
23 | }
24 |
25 | a {
26 | cursor: pointer;
27 | background-image: none;
28 | text-decoration: none;
29 | outline: none;
30 |
31 | &:focus,
32 | &:active,
33 | &:hover {
34 | outline: none;
35 | text-decoration: none;
36 | }
37 | }
38 |
39 | dl,
40 | dt,
41 | dd,
42 | ul,
43 | ol,
44 | li,
45 | th,
46 | td {
47 | margin: 0;
48 | padding: 0;
49 | }
50 |
51 | ol,
52 | ul {
53 | list-style: none;
54 | }
55 |
56 | audio,
57 | canvas,
58 | video {
59 | display: inline-block;
60 | }
61 |
62 | audio:not([controls]) {
63 | display: none;
64 | height: 0;
65 | }
66 |
67 | mark {
68 | background: #ff0;
69 | color: #000;
70 | }
71 |
72 | pre {
73 | white-space: pre-wrap;
74 | }
75 |
76 | sub,
77 | sup {
78 | font-size: 75%;
79 | line-height: 0;
80 | position: relative;
81 | vertical-align: baseline;
82 | }
83 |
84 | sup {
85 | top: -0.5em;
86 | }
87 |
88 | sub {
89 | bottom: -0.25em;
90 | }
91 |
92 | fieldset {
93 | border: 1px solid #c0c0c0;
94 | margin: 0 2px;
95 | padding: 0.35em 0.625em 0.75em;
96 | }
97 |
98 | legend {
99 | border: 0;
100 | padding: 0;
101 | }
102 |
103 | // 清除IE
104 | input::-ms-clear,
105 | input::-ms-reveal {
106 | display: none;
107 | }
108 |
109 | button::-moz-focus-inner,
110 | input::-moz-focus-inner {
111 | border: 0;
112 | padding: 0;
113 | }
114 |
115 | textarea {
116 | overflow: auto;
117 | vertical-align: top;
118 | }
119 |
120 | table {
121 | border-collapse: collapse;
122 | border-spacing: 0;
123 | }
124 |
125 | .@{css-prefix}hide {
126 | display: none;
127 | }
128 |
129 | .popper__arrow {
130 | &,
131 | &:after {
132 | position: absolute;
133 | display: block;
134 | width: 0;
135 | height: 0;
136 | border-color: transparent;
137 | border-style: solid;
138 | }
139 | }
140 |
141 | @media (min-width: 768px) {
142 | ::-webkit-scrollbar {
143 | width: 8px;
144 | height: 8px;
145 | }
146 |
147 | ::-webkit-scrollbar-track-piece {
148 | background: #fafafa;
149 | }
150 |
151 | ::-webkit-scrollbar-thumb {
152 | background: #5c6173;
153 | border-radius: 6px;
154 | }
155 |
156 | ::-webkit-scrollbar-thumb:hover {
157 | background: #999999;
158 | }
159 |
160 | ::-webkit-scrollbar-thumb:active {
161 | background: #999999;
162 | }
163 |
164 | .@{css-prefix}scrollbar::-webkit-scrollbar {
165 | width: 8px;
166 | height: 8px;
167 | }
168 |
169 | .@{css-prefix}scrollbar::-webkit-scrollbar-track-piece {
170 | background: transparent;
171 | border: 0;
172 | }
173 |
174 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb {
175 | background: #5c6173;
176 | border-radius: 4px;
177 | }
178 |
179 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb:hover {
180 | background: #999999;
181 | }
182 |
183 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb:active {
184 | background: #999999;
185 | }
186 |
187 | .@{css-prefix}min-scrollbar::-webkit-scrollbar {
188 | width: 4px;
189 | height: 4px;
190 | }
191 |
192 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-track-piece {
193 | background: transparent;
194 | border: 0;
195 | }
196 |
197 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb {
198 | background: #bfbfbf;
199 | border-radius: 2px;
200 | }
201 |
202 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb:hover {
203 | background: #999999;
204 | }
205 |
206 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb:active {
207 | background: #999999;
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/base/vars.less:
--------------------------------------------------------------------------------
1 | :root {
2 | --ti-mobile-base-color-primary-normal: #1890ff;
3 | --ti-mobile-base-color-primary-disabled: #bfbfbf;
4 | --ti-mobile-base-color-primary-hover: #40a9ff;
5 | --ti-mobile-base-color-primary-active: #096dd9;
6 | --ti-mobile-base-color-success-normal: #52c41a;
7 | --ti-mobile-base-color-success-disabled: #a6c3b9;
8 | --ti-mobile-base-color-success-hover: #73d13d;
9 | --ti-mobile-base-color-success-active: #389e0d;
10 | --ti-mobile-base-color-warning-normal: #faad14;
11 | --ti-mobile-base-color-warning-disabled: #d3c6a2;
12 | --ti-mobile-base-color-warning-hover: #ffc53d;
13 | --ti-mobile-base-color-warning-active: #ffc53d;
14 | --ti-mobile-base-color-danger-normal: #f5222d;
15 | --ti-mobile-base-color-danger-disabled: #d8bab5;
16 | --ti-mobile-base-color-danger-hover: #ff4d4f;
17 | --ti-mobile-base-color-danger-active: #cf1322;
18 | --ti-mobile-base-color-info-normal: #333333;
19 | --ti-mobile-base-color-info-disabled: #bfbfbf;
20 | --ti-mobile-base-color-info-hover: #54657e;
21 | --ti-mobile-base-color-info-active: #54657e;
22 | --ti-mobile-base-color-light: #fff;
23 | --ti-mobile-base-color-dark: #000;
24 | --ti-mobile-base-color-border: #d9d9d9;
25 | --ti-mobile-base-color-secondary: #666;
26 | --ti-mobile-base-color-placeholder: #999;
27 | --ti-mobile-base-color-hover-background: #e6f7ff;
28 | --ti-mobile-base-color-selected-background: #f5f5f5;
29 | --ti-mobile-base-color-navigation-background: #2e3243;
30 | --ti-mobile-base-radius-large: 3px;
31 | --ti-mobile-base-radius-medium: 2px;
32 | --ti-mobile-base-radius-small: 1px;
33 | --ti-mobile-base-font-family-normal: Helvetica, Arial, 'microsoft yahei';
34 | --ti-mobile-base-font-size: 12px;
35 | --ti-mobile-base-font-size-normal: 1em;
36 | --ti-mobile-base-font-size-large: 1.125em;
37 | --ti-mobile-base-font-weight-bold: 700;
38 | --ti-mobile-base-size-width-large: 130px;
39 | --ti-mobile-base-size-width-medium: 120px;
40 | --ti-mobile-base-size-width-normal: 80px;
41 | --ti-mobile-base-size-width-small: 36px;
42 | --ti-mobile-base-size-width-minor: 30px;
43 | --ti-mobile-base-size-width-mini: 24px;
44 | --ti-mobile-base-size-height-large: 48px;
45 | --ti-mobile-base-size-height-medium: 42px;
46 | --ti-mobile-base-size-height-small: 36px;
47 | --ti-mobile-base-size-height-minor: 30px;
48 | --ti-mobile-base-size-height-mini: 24px;
49 | }
50 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/button/index.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @import '../mixins/button.less';
14 | @import '../custom.less';
15 | @import './vars.less';
16 |
17 | @button-prefix-cls: ~'@{css-prefix}mobile-button';
18 | @svg-prefix-cls: ~'@{css-prefix}svg';
19 |
20 | .@{button-prefix-cls} {
21 | position: relative;
22 | margin: 0;
23 | padding: 0;
24 | height: var(--ti-mobile-button-height);
25 | line-height: var(--ti-mobile-button-height);
26 | font-size: var(--ti-mobile-button-font-size-default);
27 | -webkit-text-size-adjust: 100%;
28 | border-width: 1px;
29 | border-style: solid;
30 | border-image: initial;
31 | border-radius: 2px;
32 | padding: 0 16px;
33 | transition:
34 | border 0.3s ease 0s,
35 | color 0.3s ease 0s,
36 | background 0.3s ease 0s;
37 | cursor: pointer;
38 | outline: 0;
39 | display: inline-block;
40 | user-select: none;
41 | -webkit-appearance: none;
42 | text-align: center;
43 | box-sizing: border-box;
44 | white-space: nowrap;
45 | overflow: hidden;
46 | text-overflow: ellipsis;
47 | vertical-align: middle;
48 |
49 | &::before {
50 | position: absolute;
51 | top: 50%;
52 | left: 50%;
53 | width: 100%;
54 | height: 100%;
55 | background-color: #000;
56 | border: inherit;
57 | border-color: #000;
58 | border-radius: inherit;
59 | transform: translate(-50%, -50%);
60 | opacity: 0;
61 | content: ' ';
62 | }
63 |
64 | &::-moz-focus-inner {
65 | border: 0;
66 | }
67 |
68 | &:active,
69 | &.is-active {
70 | &::before {
71 | opacity: 0.1;
72 | }
73 | }
74 |
75 | &.is-disabled,
76 | &.is-disabled:active,
77 | &.is-disabled.is-active {
78 | cursor: not-allowed;
79 | .button-color(var(--ti-mobile-button-text-color-disabled),
80 | var(--ti-mobile-button-bg-color-disabled),
81 | var(--ti-mobile-button-bg-color-disabled));
82 | }
83 |
84 | .is-icon {
85 | fill: var(--ti-mobile-button-text-color-white);
86 | font-size: var(--ti-mobile-button-font-size-default);
87 | }
88 |
89 | &--default {
90 | .button-color(var(--ti-mobile-button-text-color-default),
91 | var(--ti-mobile-button-border-color),
92 | var(--ti-mobile-button-bg-color-default));
93 |
94 | .is-icon {
95 | fill: var(--ti-mobile-button-text-color-default);
96 | }
97 |
98 | &.is-disabled .is-icon {
99 | fill: var(--ti-mobile-button-text-color-white);
100 | }
101 | }
102 |
103 | &&--default {
104 | &.is-loading svg {
105 | fill: #666;
106 | }
107 | }
108 |
109 | &--primary {
110 | .button-type(var(--ti-mobile-button-text-color-white),
111 | var(--ti-mobile-button-bg-color-primary));
112 |
113 | &.is-plain {
114 | .button-plain(var(--ti-mobile-button-bg-color-primary));
115 | }
116 | }
117 |
118 | &--success {
119 | .button-type(var(--ti-mobile-button-text-color-white),
120 | var(--ti-mobile-button-bg-color-success));
121 |
122 | &.is-plain {
123 | .button-plain(var(--ti-mobile-button-bg-color-success));
124 | }
125 | }
126 |
127 | &--warning {
128 | .button-type(var(--ti-mobile-button-text-color-white),
129 | var(--ti-mobile-button-bg-color-warning));
130 |
131 | &.is-plain {
132 | .button-plain(var(--ti-mobile-button-bg-color-warning));
133 | }
134 | }
135 |
136 | &--danger {
137 | .button-type(var(--ti-mobile-button-text-color-white),
138 | var(--ti-mobile-button-bg-color-danger));
139 |
140 | &.is-plain {
141 | .button-plain(var(--ti-mobile-button-bg-color-danger));
142 | }
143 | }
144 |
145 | &--info {
146 | .button-type(var(--ti-mobile-button-text-color-white),
147 | var(--ti-mobile-button-bg-color-info));
148 |
149 | &.is-plain {
150 | .button-plain(var(--ti-mobile-button-bg-color-info));
151 | }
152 | }
153 |
154 | &--text {
155 | .button-text(var(--ti-mobile-button-text-color),
156 | var(--ti-mobile-button-text-color-hover),
157 | var(--ti-mobile-button-text-color-active),
158 | var(--ti-mobile-button-text-color-disabled));
159 | }
160 |
161 | &--secondary {
162 | .button-type(var(--ti-mobile-button-text-color-default),
163 | var(--ti-mobile-button-bg-color-secondary));
164 |
165 | &.is-plain {
166 | .button-plain(var(--ti-mobile-button-bg-color-secondary));
167 | }
168 | }
169 |
170 | &--default {
171 | .button-color(var(--ti-mobile-button-text-color-default),
172 | var(--ti-mobile-button-text-color-disabled),
173 | var(--ti-mobile-button-text-color-white));
174 |
175 | &.is-disabled {
176 | .button-color(var(--ti-mobile-button-text-color-disabled),
177 | var(--ti-mobile-button-text-color-disabled),
178 | var(--ti-mobile-button-bg-color-white));
179 | }
180 | }
181 |
182 | &--large {
183 | padding: 0 20px;
184 | }
185 |
186 | &--medium {
187 | padding: 0 16px;
188 | line-height: 36px;
189 |
190 | .button-size(var(--ti-mobile-button-height-medium),
191 | var(--ti-mobile-button-font-size-medium,));
192 | }
193 |
194 | &--small {
195 | padding: 0 12px;
196 | line-height: 28px;
197 |
198 | .button-size(var(--ti-mobile-button-height-small),
199 | var(--ti-mobile-button-font-size-small));
200 | }
201 |
202 | &--mini {
203 | padding: 0 8px;
204 | line-height: 22px;
205 |
206 | .button-size(var(--ti-mobile-button-height-mini),
207 | var(--ti-mobile-button-font-size-mini));
208 | }
209 |
210 | &.is-loading {
211 | position: relative;
212 | pointer-events: none;
213 |
214 | svg {
215 | fill: var(--ti-mobile-button-text-color-white);
216 | font-size: var(--ti-mobile-button-font-size-default);
217 | }
218 | }
219 |
220 | &.is-round {
221 | border-radius: 999px;
222 | }
223 | }
224 |
225 | .@{css-prefix-iconfont}-loading {
226 | margin-right: 4px;
227 | font-size: 16px;
228 | line-height: 1;
229 | animation: rotating 2s linear infinite;
230 | }
231 |
232 | @keyframes rotating {
233 | 0% {
234 | transform: rotateZ(0deg);
235 | }
236 |
237 | 100% {
238 | transform: rotateZ(360deg);
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/button/vars.less:
--------------------------------------------------------------------------------
1 | :root,:host {
2 | --ti-mobile-button-height: 42px;
3 | --ti-mobile-button-font-size-default: 16px;
4 | --ti-mobile-button-text-color-white: var(--ti-mobile-common-color-text-white, #fff);
5 | --ti-mobile-button-text-color-disabled: var(--ti-mobile-common-color-text-weaken-disabled, #dbdbdb);
6 | --ti-mobile-button-text-color-default: var(--ti-mobile-common-color-text-primary, #191919);
7 | --ti-mobile-button-border-color: var(--ti-mobile-common-color-text-weaken-disabled, #dbdbdb);
8 | --ti-mobile-button-bg-color-default: var(--ti-mobile-common-bg-color-white, #fff);
9 | --ti-mobile-button-bg-color-primary: var(--ti-mobile-common-color-error-figure-3, #1e8aff);
10 | --ti-mobile-button-bg-color-success: var(--ti-mobile-common-color-warning-figure-3, #1ebe40);
11 | --ti-mobile-button-bg-color-warning: var(--ti-mobile-common-color-error-figure-2, #fccd32);
12 | --ti-mobile-button-bg-color-danger: var(--ti-mobile-common-color-error-figure-1, #eb5454);
13 | --ti-mobile-button-bg-color-disabled: var(--ti-mobile-common-bg-color-disabled, #e8e8e8);
14 | --ti-mobile-button-bg-color-info: #333;
15 | --ti-mobile-button-height-medium: 36px;
16 | --ti-mobile-button-font-size-medium: 14px;
17 | --ti-mobile-button-height-small: 28px;
18 | --ti-mobile-button-font-size-small: 12px;
19 | --ti-mobile-button-height-mini: 22px;
20 | --ti-mobile-button-font-size-mini: 10px;
21 | --ti-mobile-button-text-color: var(--ti-mobile-common-color-link-highlight, #4a79fe);
22 | --ti-mobile-button-text-color-hover: #6e94fe;
23 | --ti-mobile-button-text-color-active: var(--ti-mobile-common-color-link-highlight, #4a79fe);
24 | }
25 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/custom.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @css-prefix: tiny-;
14 | @css-prefix-iconfont: tiny-icon;
15 |
--------------------------------------------------------------------------------
/packages/components/theme-mobile/src/mixins/button.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | .button-color(@color, @border-color, @background-color) {
14 | color: @color;
15 | border-color: @border-color;
16 | background-color: @background-color;
17 | }
18 |
19 | .button-text(@color, @hover-color, @active-color, @disabled-color) {
20 | color: @color;
21 | border-color: transparent;
22 | background-color: transparent;
23 |
24 | &:hover {
25 | color: @hover-color;
26 | border-color: transparent;
27 | background-color: transparent;
28 | }
29 |
30 | &:focus,
31 | &:active,
32 | &.is-active {
33 | color: @active-color;
34 | border-color: transparent;
35 | background-color: transparent;
36 |
37 | &::before {
38 | opacity: 0;
39 | }
40 | }
41 |
42 | &.is-disabled,
43 | &.is-disabled:active,
44 | &.is-disabled:focus,
45 | &.is-disabled:hover {
46 | color: @disabled-color;
47 | border-color: transparent;
48 | background-color: transparent;
49 | }
50 | }
51 |
52 | .button-type(@color, @normal-color) {
53 | color: @color;
54 | border-color: @normal-color;
55 | background-color: @normal-color;
56 |
57 | .is-icon {
58 | fill: @color;
59 | }
60 | }
61 |
62 | .button-size(@height, @font-size) {
63 | height: @height;
64 | line-height: @height;
65 | font-size: @font-size;
66 |
67 | .is-icon,
68 | &.is-loading svg {
69 | font-size: @font-size;
70 | }
71 | }
72 |
73 | .button-plain(@color) {
74 | color: @color;
75 | border-color: @color;
76 | background-color: transparent;
77 |
78 | .is-icon,
79 | &.is-loading svg {
80 | fill: @color;
81 | }
82 |
83 | &.is-disabled {
84 | &,
85 | &:active,
86 | &.is-active {
87 | color: #ccc;
88 | border-color: #ddd;
89 | background-color: transparent;
90 | }
91 |
92 | .is-icon,
93 | &.is-loading svg {
94 | fill: #ccc;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/theme-watch
2 |
3 | This is a project to provide Watch template styles for OpenTiny cross-end and cross-framework components.
--------------------------------------------------------------------------------
/packages/components/theme-watch/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/theme-watch
2 |
3 | 这是一个为 OpenTiny 跨端、跨框架组件提供 Watch 模板样式的工程
4 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/theme-watch",
3 | "version": "3.9.0",
4 | "description": "",
5 | "sideEffects": false,
6 | "dependencies": {
7 | "less": "~4.1.3"
8 | },
9 | "type": "module",
10 | "exports": {
11 | "./*": "./src/*"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/base/basic-var.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | /*基础变量定义*/
14 | :root,:host {
15 | /* 品牌色*/
16 | --ti-watch-base-color-brand-1: #4a79fe; /* 蓝_品牌色*/
17 | --ti-watch-base-color-brand-2: #3168f1;
18 | --ti-watch-base-color-brand-3: #6e94fe;
19 | --ti-watch-base-color-brand-4: #92affe;
20 | --ti-watch-base-color-brand-5: #b7c9ff;
21 | --ti-watch-base-color-brand-6: #95a2f8;
22 | --ti-watch-base-color-brand-6: #ffffff;
23 |
24 | /* 1.2背景色*/
25 | --ti-watch-base-color-bg-1: #f5f5f5; /* 深灰_背景色*/
26 | --ti-watch-base-color-bg-2: #fafafa; /* 浅灰_背景色*/
27 | --ti-watch-base-color-bg-3: #ffffff; /* 白色_背景色*/
28 |
29 | /* 文本、线、面等常用灰色可用颜色参考:*/
30 | --ti-watch-base-color-common-1: #000000;
31 | --ti-watch-base-color-common-2: #191919;
32 | --ti-watch-base-color-common-3: #262626;
33 | --ti-watch-base-color-common-4: #333333;
34 | --ti-watch-base-color-common-5: #595959;
35 | --ti-watch-base-color-common-6: #999999;
36 | --ti-watch-base-color-common-7: #c2c2c2;
37 | --ti-watch-base-color-common-8: #dbdbdb;
38 | --ti-watch-base-color-common-9: #ededed;
39 | --ti-watch-base-color-common-10: #f5f5f5;
40 | --ti-watch-base-color-common-11: #fafafa;
41 | --ti-watch-base-color-common-12: #ffffff;
42 | --ti-watch-base-color-common-13: #627199;
43 |
44 | /* 功能色*/
45 | --ti-watch-common-color-warning-figure-1: #eb4096; /* 致命警告图形色*/
46 | --ti-watch-common-color-warning-text-1: #e61c81; /* 致命警告文字色*/
47 | --ti-watch-common-color-warning-figure-2: #ff9c32; /* 一般告警/中性1图形色*/
48 | --ti-watch-common-color-warning-text-2: #ff8800; /* 一般告警/中性1文字色*/
49 | --ti-watch-common-color-warning-figure-3: #1ebe40; /* 一般告警/中性1图形色*/
50 | --ti-watch-common-color-warning-text-3: #00b336; /* 一般告警/中性1文字色*/
51 |
52 | --ti-watch-common-color-error-figure-1: #eb5454; /* 异常/下降/告警/驳回/退订/失败图形色*/
53 | --ti-watch-common-color-error-text-1: #e62222; /* 异常/下降/告警/驳回/退订/失败文字色*/
54 | --ti-watch-common-color-error-figure-2: #fccd32; /* 异常/下降/告警/驳回/退订/失败图形色*/
55 | --ti-watch-common-color-error-text-2: #fcbe1e; /* 异常/下降/告警/驳回/退订/失败文字色*/
56 | --ti-watch-common-color-error-figure-3: #1e8aff; /* 异常/下降/告警/驳回/退订/失败图形色*/
57 | --ti-watch-common-color-error-text-3: #1476ff; /* 异常/下降/告警/驳回/退订/失败文字色*/
58 | --ti-watch-common-color-error-figure-4: #c2c2c2; /* 异常/下降/告警/驳回/退订/失败图形色*/
59 | --ti-watch-common-color-error-text-4: #999999; /* 异常/下降/告警/驳回/退订/失败文字色*/
60 |
61 | /* 图表推荐配色*/
62 | --ti-watch-common-color-chart-1: #1476ff;
63 | --ti-watch-common-color-chart-2: #10c7c1;
64 | --ti-watch-common-color-chart-3: #b878f0;
65 | --ti-watch-common-color-chart-4: #d6a981;
66 | --ti-watch-common-color-chart-5: #c1cc7a;
67 |
68 | /* 文本色*/
69 | --ti-watch-common-color-text-primary: var(
70 | --ti-watch-base-color-common-2
71 | ); /* 一级文本色-重要信息/标题颜色/输入类文本颜色*/
72 | --ti-watch-common-color-text-secondary: var(--ti-watch-base-color-common-5); /* 二级文本色-次要信息*/
73 | --ti-watch-common-color-text-weaken-dark: var(--ti-watch-base-color-common-6); /* 三级文本色-弱化信息/说明文字*/
74 | --ti-watch-common-color-text-weaken-ligtht: var(--ti-watch-base-color-common-7); /* 文本_弱化色_浅色/提示*/
75 | --ti-watch-common-color-text-weaken-disabled: var(--ti-watch-base-color-common-8); /* 文本_弱化色_浅色/禁用*/
76 | --ti-watch-common-color-text-white: var(--ti-watch-base-color-common-12); /* 文本_白色*/
77 | --ti-watch-common-color-text-placeholder-primary: #dbe5fc; /* placeholder_主要*/
78 | --ti-watch-common-color-text-placeholder-gray: #acacac; /* placeholder_灰*/
79 | --ti-watch-common-color-text-high-light: var(--ti-watch-base-color-brand-1); /* 文本_高亮*/
80 |
81 | /* 文本链接色*/
82 | --ti-watch-common-color-link-dark: var(--ti-watch-base-color-common-2); /* 文本_链接__深色*/
83 | --ti-watch-common-color-link-highlight: var(--ti-watch-base-color-brand-1); /* 文本_链接_高亮色*/
84 | --ti-watch-common-color-link-gray: var(--ti-watch-base-color-common-13); /* 文本_链接_灰色加强*/
85 | --ti-watch-common-color-link-white: var(--ti-watch-base-color-common-12); /* 文本_链接_白色*/
86 |
87 | /* 线颜色*/
88 | --ti-watch-common-color-line-hightlight: var(--ti-watch-base-color-brand-1); /* 高亮_描边色*/
89 | --ti-watch-common-color-line-dark: var(--ti-watch-base-color-common-9); /* 深_描边色*/
90 | --ti-watch-common-color-line-light: var(--ti-watch-base-color-common-10); /* 浅_描边色*/
91 | --ti-watch-common-color-line-white: var(--ti-watch-base-color-common-12); /* 白色*/
92 |
93 | /* 蒙层色*/
94 | --ti-watch-common-color-mask-light: rgba(0, 0, 0, 0.5); /* 蒙层_相对浅*/
95 | --ti-watch-common-color-mask-dark: rgba(0, 0, 0, 0.75); /* 蒙层_相对深*/
96 |
97 | /* 背景色*/
98 | --ti-watch-common-bg-color-white: var(--ti-watch-base-color-bg-3); /* 背景_白*/
99 | --ti-watch-common-bg-color-main: var(--ti-watch-base-color-brand-1); /* 背景_蓝*/
100 | --ti-watch-common-bg-color-light: var(--ti-watch-base-color-bg-2); /* 背景_浅灰*/
101 | --ti-watch-common-bg-color-blue-1: var(--ti-watch-base-color-brand-2); /* 背景_蓝*/
102 | --ti-watch-common-bg-color-disabled: #e8e8e8; /* 背景_禁用*/
103 | --ti-watch-common-bg-color-dark-gray: var(--ti-watch-base-color-bg-1); /* 背景_深灰*/
104 | --ti-watch-common-bg-color-weaken: var(--ti-watch-base-color-common-8); /* 背景_弱化色*/
105 | --ti-watch-common-status-bg-color-success: #5bd475; /* 背景_成功/通过*/
106 | --ti-watch-common-status-bg-color-error: #eb5454; /* 背景_失败/驳回*/
107 | --ti-watch-common-status-bg-color-normal: #fff; /* 背景_默认*/
108 | --ti-watch-common-status-bg-color-handing: var(--ti-watch-base-color-brand-1); /* 背景_进行中*/
109 | }
110 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/base/index.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @import './reset.less';
14 | @import './basic-var.less';
15 | @import './vars.less';
16 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/base/reset.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @import '../custom.less';
14 |
15 | [class*=~'@{css-prefix}'] {
16 | -webkit-box-sizing: border-box;
17 | box-sizing: border-box;
18 |
19 | *:after,
20 | *:before {
21 | -webkit-box-sizing: border-box;
22 | box-sizing: border-box;
23 | }
24 |
25 | a {
26 | cursor: pointer;
27 | background-image: none;
28 | text-decoration: none;
29 | outline: none;
30 |
31 | &:focus,
32 | &:active,
33 | &:hover {
34 | outline: none;
35 | text-decoration: none;
36 | }
37 | }
38 |
39 | dl,
40 | dt,
41 | dd,
42 | ul,
43 | ol,
44 | li,
45 | th,
46 | td {
47 | margin: 0;
48 | padding: 0;
49 | }
50 |
51 | ol,
52 | ul {
53 | list-style: none;
54 | }
55 |
56 | audio,
57 | canvas,
58 | video {
59 | display: inline-block;
60 | }
61 |
62 | audio:not([controls]) {
63 | display: none;
64 | height: 0;
65 | }
66 |
67 | mark {
68 | background: #ff0;
69 | color: #000;
70 | }
71 |
72 | pre {
73 | white-space: pre-wrap;
74 | }
75 |
76 | sub,
77 | sup {
78 | font-size: 75%;
79 | line-height: 0;
80 | position: relative;
81 | vertical-align: baseline;
82 | }
83 |
84 | sup {
85 | top: -0.5em;
86 | }
87 |
88 | sub {
89 | bottom: -0.25em;
90 | }
91 |
92 | fieldset {
93 | border: 1px solid #c0c0c0;
94 | margin: 0 2px;
95 | padding: 0.35em 0.625em 0.75em;
96 | }
97 |
98 | legend {
99 | border: 0;
100 | padding: 0;
101 | }
102 |
103 | // 清除IE
104 | input::-ms-clear,
105 | input::-ms-reveal {
106 | display: none;
107 | }
108 |
109 | button::-moz-focus-inner,
110 | input::-moz-focus-inner {
111 | border: 0;
112 | padding: 0;
113 | }
114 |
115 | textarea {
116 | overflow: auto;
117 | vertical-align: top;
118 | }
119 |
120 | table {
121 | border-collapse: collapse;
122 | border-spacing: 0;
123 | }
124 |
125 | .@{css-prefix}hide {
126 | display: none;
127 | }
128 |
129 | .popper__arrow {
130 | &,
131 | &:after {
132 | position: absolute;
133 | display: block;
134 | width: 0;
135 | height: 0;
136 | border-color: transparent;
137 | border-style: solid;
138 | }
139 | }
140 |
141 | @media (min-width: 768px) {
142 | ::-webkit-scrollbar {
143 | width: 8px;
144 | height: 8px;
145 | }
146 |
147 | ::-webkit-scrollbar-track-piece {
148 | background: #fafafa;
149 | }
150 |
151 | ::-webkit-scrollbar-thumb {
152 | background: #5c6173;
153 | border-radius: 6px;
154 | }
155 |
156 | ::-webkit-scrollbar-thumb:hover {
157 | background: #999999;
158 | }
159 |
160 | ::-webkit-scrollbar-thumb:active {
161 | background: #999999;
162 | }
163 |
164 | .@{css-prefix}scrollbar::-webkit-scrollbar {
165 | width: 8px;
166 | height: 8px;
167 | }
168 |
169 | .@{css-prefix}scrollbar::-webkit-scrollbar-track-piece {
170 | background: transparent;
171 | border: 0;
172 | }
173 |
174 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb {
175 | background: #5c6173;
176 | border-radius: 4px;
177 | }
178 |
179 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb:hover {
180 | background: #999999;
181 | }
182 |
183 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb:active {
184 | background: #999999;
185 | }
186 |
187 | .@{css-prefix}min-scrollbar::-webkit-scrollbar {
188 | width: 4px;
189 | height: 4px;
190 | }
191 |
192 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-track-piece {
193 | background: transparent;
194 | border: 0;
195 | }
196 |
197 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb {
198 | background: #bfbfbf;
199 | border-radius: 2px;
200 | }
201 |
202 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb:hover {
203 | background: #999999;
204 | }
205 |
206 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb:active {
207 | background: #999999;
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/base/vars.less:
--------------------------------------------------------------------------------
1 | :root {
2 | --ti-watch-base-color-primary-normal: #1890ff;
3 | --ti-watch-base-color-primary-disabled: #bfbfbf;
4 | --ti-watch-base-color-primary-hover: #40a9ff;
5 | --ti-watch-base-color-primary-active: #096dd9;
6 | --ti-watch-base-color-success-normal: #52c41a;
7 | --ti-watch-base-color-success-disabled: #a6c3b9;
8 | --ti-watch-base-color-success-hover: #73d13d;
9 | --ti-watch-base-color-success-active: #389e0d;
10 | --ti-watch-base-color-warning-normal: #faad14;
11 | --ti-watch-base-color-warning-disabled: #d3c6a2;
12 | --ti-watch-base-color-warning-hover: #ffc53d;
13 | --ti-watch-base-color-warning-active: #ffc53d;
14 | --ti-watch-base-color-danger-normal: #f5222d;
15 | --ti-watch-base-color-danger-disabled: #d8bab5;
16 | --ti-watch-base-color-danger-hover: #ff4d4f;
17 | --ti-watch-base-color-danger-active: #cf1322;
18 | --ti-watch-base-color-info-normal: #333333;
19 | --ti-watch-base-color-info-disabled: #bfbfbf;
20 | --ti-watch-base-color-info-hover: #54657e;
21 | --ti-watch-base-color-info-active: #54657e;
22 | --ti-watch-base-color-light: #fff;
23 | --ti-watch-base-color-dark: #000;
24 | --ti-watch-base-color-border: #d9d9d9;
25 | --ti-watch-base-color-secondary: #666;
26 | --ti-watch-base-color-placeholder: #999;
27 | --ti-watch-base-color-hover-background: #e6f7ff;
28 | --ti-watch-base-color-selected-background: #f5f5f5;
29 | --ti-watch-base-color-navigation-background: #2e3243;
30 | --ti-watch-base-radius-large: 3px;
31 | --ti-watch-base-radius-medium: 2px;
32 | --ti-watch-base-radius-small: 1px;
33 | --ti-watch-base-font-family-normal: Helvetica, Arial, 'microsoft yahei';
34 | --ti-watch-base-font-size: 12px;
35 | --ti-watch-base-font-size-normal: 1em;
36 | --ti-watch-base-font-size-large: 1.125em;
37 | --ti-watch-base-font-weight-bold: 700;
38 | --ti-watch-base-size-width-large: 130px;
39 | --ti-watch-base-size-width-medium: 120px;
40 | --ti-watch-base-size-width-normal: 80px;
41 | --ti-watch-base-size-width-small: 36px;
42 | --ti-watch-base-size-width-minor: 30px;
43 | --ti-watch-base-size-width-mini: 24px;
44 | --ti-watch-base-size-height-large: 48px;
45 | --ti-watch-base-size-height-medium: 42px;
46 | --ti-watch-base-size-height-small: 36px;
47 | --ti-watch-base-size-height-minor: 30px;
48 | --ti-watch-base-size-height-mini: 24px;
49 | }
50 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/button/index.less:
--------------------------------------------------------------------------------
1 | @import '../mixins/button.less';
2 | @import '../custom.less';
3 | @import './vars.less';
4 |
5 | @button-prefix-cls: ~'@{css-prefix}watch-button';
6 | @svg-prefix-cls: ~'@{css-prefix}svg';
7 |
8 | .@{button-prefix-cls} {
9 | position: relative;
10 | width: var(--ti-watch-button-height);
11 | height: var(--ti-watch-button-height);
12 | line-height: var(--ti-watch-button-height);
13 | font-size: var(--ti-watch-button-font-size-default);
14 | border-width: 1px;
15 | border-style: solid;
16 | border-image: initial;
17 | border-radius: 100%;
18 | padding: 5px;
19 | transition:
20 | border 0.3s ease 0s,
21 | color 0.3s ease 0s,
22 | background 0.3s ease 0s;
23 | cursor: pointer;
24 | outline: 0;
25 | display: inline-block;
26 | user-select: none;
27 | text-align: center;
28 | box-sizing: border-box;
29 | white-space: nowrap;
30 | overflow: hidden;
31 | text-overflow: ellipsis;
32 | display: flex;
33 | align-items: center;
34 | justify-content: center;
35 |
36 |
37 | &::-moz-focus-inner {
38 | border: 0;
39 | }
40 |
41 | &:active,
42 | &.is-active {
43 | &::before {
44 | opacity: 0.1;
45 | }
46 | }
47 |
48 | &.is-disabled,
49 | &.is-disabled:active,
50 | &.is-disabled.is-active {
51 | cursor: not-allowed;
52 | .button-color(var(--ti-watch-button-text-color-disabled),
53 | var(--ti-watch-button-bg-color-disabled),
54 | var(--ti-watch-button-bg-color-disabled));
55 | }
56 |
57 | .is-icon {
58 | fill: var(--ti-watch-button-text-color-white);
59 | font-size: var(--ti-watch-button-font-size-default);
60 | }
61 |
62 | &--default {
63 | .button-color(var(--ti-watch-button-text-color-default),
64 | var(--ti-watch-button-border-color),
65 | var(--ti-watch-button-bg-color-default));
66 |
67 | .is-icon {
68 | fill: var(--ti-watch-button-text-color-default);
69 | }
70 |
71 | &.is-disabled .is-icon {
72 | fill: var(--ti-watch-button-text-color-white);
73 | }
74 | }
75 |
76 | &&--default {
77 | &.is-loading svg {
78 | fill: #666;
79 | }
80 | }
81 |
82 | &--primary {
83 | .button-type(var(--ti-watch-button-text-color-white),
84 | var(--ti-watch-button-bg-color-primary));
85 |
86 | &.is-plain {
87 | .button-plain(var(--ti-watch-button-bg-color-primary));
88 | }
89 | }
90 |
91 | &--success {
92 | .button-type(var(--ti-watch-button-text-color-white),
93 | var(--ti-watch-button-bg-color-success));
94 |
95 | &.is-plain {
96 | .button-plain(var(--ti-watch-button-bg-color-success));
97 | }
98 | }
99 |
100 | &--warning {
101 | .button-type(var(--ti-watch-button-text-color-white),
102 | var(--ti-watch-button-bg-color-warning));
103 |
104 | &.is-plain {
105 | .button-plain(var(--ti-watch-button-bg-color-warning));
106 | }
107 | }
108 |
109 | &--danger {
110 | .button-type(var(--ti-watch-button-text-color-white),
111 | var(--ti-watch-button-bg-color-danger));
112 |
113 | &.is-plain {
114 | .button-plain(var(--ti-watch-button-bg-color-danger));
115 | }
116 | }
117 |
118 | &--info {
119 | .button-type(var(--ti-watch-button-text-color-white),
120 | var(--ti-watch-button-bg-color-info));
121 |
122 | &.is-plain {
123 | .button-plain(var(--ti-watch-button-bg-color-info));
124 | }
125 | }
126 |
127 | &--text {
128 | .button-text(var(--ti-watch-button-text-color),
129 | var(--ti-watch-button-text-color-hover),
130 | var(--ti-watch-button-text-color-active),
131 | var(--ti-watch-button-text-color-disabled));
132 | }
133 |
134 | &--secondary {
135 | .button-type(var(--ti-watch-button-text-color-default),
136 | var(--ti-watch-button-bg-color-secondary));
137 |
138 | &.is-plain {
139 | .button-plain(var(--ti-watch-button-bg-color-secondary));
140 | }
141 | }
142 |
143 | &--default {
144 | .button-color(var(--ti-watch-button-text-color-default),
145 | var(--ti-watch-button-text-color-disabled),
146 | var(--ti-watch-button-text-color-white));
147 |
148 | &.is-disabled {
149 | .button-color(var(--ti-watch-button-text-color-disabled),
150 | var(--ti-watch-button-text-color-disabled),
151 | var(--ti-watch-button-bg-color-white));
152 | }
153 | }
154 |
155 | &--large {
156 | padding: 0 20px;
157 | }
158 |
159 | &--medium {
160 | padding: 0 16px;
161 | line-height: 36px;
162 |
163 | .button-size(var(--ti-watch-button-height-medium),
164 | var(--ti-watch-button-font-size-medium,));
165 | }
166 |
167 | &--small {
168 | padding: 0 12px;
169 | line-height: 28px;
170 |
171 | .button-size(var(--ti-watch-button-height-small),
172 | var(--ti-watch-button-font-size-small));
173 | }
174 |
175 | &--mini {
176 | padding: 0 8px;
177 | line-height: 22px;
178 |
179 | .button-size(var(--ti-watch-button-height-mini),
180 | var(--ti-watch-button-font-size-mini));
181 | }
182 |
183 | &.is-loading {
184 | position: relative;
185 | pointer-events: none;
186 |
187 | svg {
188 | fill: var(--ti-watch-button-text-color-white);
189 | font-size: var(--ti-watch-button-font-size-default);
190 | }
191 | }
192 |
193 | &.is-round {
194 | border-radius:100%;
195 | }
196 | }
197 |
198 | .@{css-prefix-iconfont}-loading {
199 | margin-right: 4px;
200 | font-size: 16px;
201 | line-height: 1;
202 | animation: rotating 2s linear infinite;
203 | }
204 |
205 | @keyframes rotating {
206 | 0% {
207 | transform: rotateZ(0deg);
208 | }
209 |
210 | 100% {
211 | transform: rotateZ(360deg);
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/button/vars.less:
--------------------------------------------------------------------------------
1 | :root,:host {
2 | --ti-watch-button-height: 36px;
3 | --ti-watch-button-font-size-default: 12px;
4 | --ti-watch-button-text-color-white: var(--ti-watch-common-color-text-white, #fff);
5 | --ti-watch-button-text-color-disabled: var(--ti-watch-common-color-text-weaken-disabled, #dbdbdb);
6 | --ti-watch-button-text-color-default: var(--ti-watch-common-color-text-primary, #191919);
7 | --ti-watch-button-border-color: var(--ti-watch-common-color-text-weaken-disabled, #dbdbdb);
8 | --ti-watch-button-bg-color-default: var(--ti-watch-common-bg-color-white, #fff);
9 | --ti-watch-button-bg-color-primary: var(--ti-watch-common-color-error-figure-3, #1e8aff);
10 | --ti-watch-button-bg-color-success: var(--ti-watch-common-color-warning-figure-3, #1ebe40);
11 | --ti-watch-button-bg-color-warning: var(--ti-watch-common-color-error-figure-2, #fccd32);
12 | --ti-watch-button-bg-color-danger: var(--ti-watch-common-color-error-figure-1, #eb5454);
13 | --ti-watch-button-bg-color-disabled: var(--ti-watch-common-bg-color-disabled, #e8e8e8);
14 | --ti-watch-button-bg-color-info: #333;
15 | --ti-watch-button-height-medium: 36px;
16 | --ti-watch-button-font-size-medium: 14px;
17 | --ti-watch-button-height-small: 28px;
18 | --ti-watch-button-font-size-small: 12px;
19 | --ti-watch-button-height-mini: 22px;
20 | --ti-watch-button-font-size-mini: 10px;
21 | --ti-watch-button-text-color: var(--ti-watch-common-color-link-highlight, #4a79fe);
22 | --ti-watch-button-text-color-hover: #6e94fe;
23 | --ti-watch-button-text-color-active: var(--ti-watch-common-color-link-highlight, #4a79fe);
24 | }
25 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/custom.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @css-prefix: tiny-;
14 | @css-prefix-iconfont: tiny-icon;
15 |
--------------------------------------------------------------------------------
/packages/components/theme-watch/src/mixins/button.less:
--------------------------------------------------------------------------------
1 | .button-color(@color, @border-color, @background-color) {
2 | color: @color;
3 | border-color: @border-color;
4 | background-color: @background-color;
5 | }
6 |
7 | .button-text(@color, @hover-color, @active-color, @disabled-color) {
8 | color: @color;
9 | border-color: transparent;
10 | background-color: transparent;
11 |
12 | &:hover {
13 | color: @hover-color;
14 | border-color: transparent;
15 | background-color: transparent;
16 | }
17 |
18 | &:focus,
19 | &:active,
20 | &.is-active {
21 | color: @active-color;
22 | border-color: transparent;
23 | background-color: transparent;
24 |
25 | &::before {
26 | opacity: 0;
27 | }
28 | }
29 |
30 | &.is-disabled,
31 | &.is-disabled:active,
32 | &.is-disabled:focus,
33 | &.is-disabled:hover {
34 | color: @disabled-color;
35 | border-color: transparent;
36 | background-color: transparent;
37 | }
38 | }
39 |
40 | .button-type(@color, @normal-color) {
41 | color: @color;
42 | border-color: @normal-color;
43 | background-color: @normal-color;
44 |
45 | .is-icon {
46 | fill: @color;
47 | }
48 | }
49 |
50 | .button-size(@height, @font-size) {
51 | height: @height;
52 | line-height: @height;
53 | font-size: @font-size;
54 |
55 | .is-icon,
56 | &.is-loading svg {
57 | font-size: @font-size;
58 | }
59 | }
60 |
61 | .button-plain(@color) {
62 | color: @color;
63 | border-color: @color;
64 | background-color: transparent;
65 |
66 | .is-icon,
67 | &.is-loading svg {
68 | fill: @color;
69 | }
70 |
71 | &.is-disabled {
72 | &,
73 | &:active,
74 | &.is-active {
75 | color: #ccc;
76 | border-color: #ddd;
77 | background-color: transparent;
78 | }
79 |
80 | .is-icon,
81 | &.is-loading svg {
82 | fill: #ccc;
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/packages/components/theme/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/theme
2 |
3 | This is a project to provide PC template styles for OpenTiny cross-end and cross-framework components.
--------------------------------------------------------------------------------
/packages/components/theme/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/theme
2 |
3 | 这是一个为 OpenTiny 跨端、跨框架组件提供 PC 模板样式的工程
4 |
--------------------------------------------------------------------------------
/packages/components/theme/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/theme",
3 | "version": "3.9.0",
4 | "description": "",
5 | "sideEffects": false,
6 | "dependencies": {
7 | "less": "~4.1.3"
8 | },
9 | "type": "module",
10 | "exports": {
11 | "./*": "./src/*"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/components/theme/src/base/index.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @import './reset.less';
14 | @import './basic-var.less';
15 |
--------------------------------------------------------------------------------
/packages/components/theme/src/base/reset.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @import '../custom.less';
14 | @import './basic-var.less';
15 |
16 | // 为了防止这些图标失去默认值,需要全局设置默认值
17 |
18 | .tiny-icon-success {
19 | fill: #5cb300;
20 | }
21 |
22 | .tiny-icon-error {
23 | fill: #f23030;
24 | }
25 |
26 | .tiny-icon-warning-triangle {
27 | fill: #ff8800;
28 | }
29 |
30 | .tiny-icon-prompt {
31 | fill: #1476ff;
32 | }
33 |
34 | .tiny-icon-text-type {
35 | fill: #9185f0;
36 | }
37 |
38 |
39 | [class*=~'@{css-prefix}'] {
40 | -webkit-box-sizing: border-box;
41 | box-sizing: border-box;
42 |
43 | *:after,
44 | *:before {
45 | -webkit-box-sizing: border-box;
46 | box-sizing: border-box;
47 | }
48 |
49 | a {
50 | cursor: pointer;
51 | background-image: none;
52 | text-decoration: none;
53 | outline: none;
54 |
55 | &:focus,
56 | &:active,
57 | &:hover {
58 | outline: none;
59 | text-decoration: none;
60 | }
61 | }
62 |
63 | dl,
64 | dt,
65 | dd,
66 | ul,
67 | ol,
68 | li,
69 | th,
70 | td {
71 | margin: 0;
72 | padding: 0;
73 | }
74 |
75 | ol,
76 | ul {
77 | list-style: none;
78 | }
79 |
80 | audio,
81 | canvas,
82 | video {
83 | display: inline-block;
84 | }
85 |
86 | audio:not([controls]) {
87 | display: none;
88 | height: 0;
89 | }
90 |
91 | mark {
92 | background: #ff0;
93 | color: #000;
94 | }
95 |
96 | pre {
97 | white-space: pre-wrap;
98 | }
99 |
100 | sub,
101 | sup {
102 | font-size: 75%;
103 | line-height: 0;
104 | position: relative;
105 | vertical-align: baseline;
106 | }
107 |
108 | sup {
109 | top: -0.5em;
110 | }
111 |
112 | sub {
113 | bottom: -0.25em;
114 | }
115 |
116 | fieldset {
117 | border: 1px solid #c0c0c0;
118 | margin: 0 2px;
119 | padding: 0.35em 0.625em 0.75em;
120 | }
121 |
122 | legend {
123 | border: 0;
124 | padding: 0;
125 | }
126 |
127 | // 清除IE
128 | input::-ms-clear,
129 | input::-ms-reveal {
130 | display: none;
131 | }
132 |
133 | button::-moz-focus-inner,
134 | input::-moz-focus-inner {
135 | border: 0;
136 | padding: 0;
137 | }
138 |
139 | textarea {
140 | overflow: auto;
141 | vertical-align: top;
142 | }
143 |
144 | table {
145 | border-collapse: collapse;
146 | border-spacing: 0;
147 | }
148 |
149 | .@{css-prefix}hide {
150 | display: none;
151 | }
152 |
153 | .popper__arrow {
154 |
155 | &,
156 | &:after {
157 | position: absolute;
158 | display: block;
159 | width: 0;
160 | height: 0;
161 | border-color: transparent;
162 | border-style: solid;
163 | }
164 | }
165 |
166 | @media (min-width: 768px) {
167 | ::-webkit-scrollbar {
168 | width: var(--ti-common-scrollbar-width);
169 | height: var(--ti-common-scrollbar-height);
170 | }
171 |
172 | ::-webkit-scrollbar-track-piece {
173 | background: var(--ti-common-scrollbar-track-piece-bg-color);
174 | }
175 |
176 | ::-webkit-scrollbar-thumb {
177 | background: var(--ti-common-scrollbar-thumb-bg-color);
178 | border-radius: var(--ti-common-scrollbar-thumb-border-radius);
179 | }
180 |
181 | ::-webkit-scrollbar-thumb:hover {
182 | background: var(--ti-common-scrollbar-thumb-hover-bg-color);
183 | }
184 |
185 | ::-webkit-scrollbar-thumb:active {
186 | background: var(--ti-common-scrollbar-thumb-active-bg-color);
187 | }
188 |
189 | .@{css-prefix}scrollbar::-webkit-scrollbar {
190 | width: 8px;
191 | height: 8px;
192 | }
193 |
194 | .@{css-prefix}scrollbar::-webkit-scrollbar-track-piece {
195 | background: transparent;
196 | border: 0;
197 | }
198 |
199 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb {
200 | background: #bfbfbf;
201 | border-radius: 4px;
202 | }
203 |
204 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb:hover {
205 | background: #999999;
206 | }
207 |
208 | .@{css-prefix}scrollbar::-webkit-scrollbar-thumb:active {
209 | background: #999999;
210 | }
211 |
212 | .@{css-prefix}min-scrollbar::-webkit-scrollbar {
213 | width: 4px;
214 | height: 4px;
215 | }
216 |
217 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-track-piece {
218 | background: transparent;
219 | border: 0;
220 | }
221 |
222 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb {
223 | background: #bfbfbf;
224 | border-radius: 2px;
225 | }
226 |
227 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb:hover {
228 | background: #999999;
229 | }
230 |
231 | .@{css-prefix}min-scrollbar::-webkit-scrollbar-thumb:active {
232 | background: #999999;
233 | }
234 | }
235 | }
--------------------------------------------------------------------------------
/packages/components/theme/src/countdown/index.less:
--------------------------------------------------------------------------------
1 | @import '../custom.less';
2 | @import './vars.less';
3 |
4 | @countdown-prefix-cls: ~'@{css-prefix}countdown__container';
5 |
6 | .@{countdown-prefix-cls} {
7 | color: var(--ti-countdown-font-color);
8 | }
9 |
--------------------------------------------------------------------------------
/packages/components/theme/src/countdown/vars.less:
--------------------------------------------------------------------------------
1 | :root,:host {
2 | --ti-countdown-font-color: #333;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/components/theme/src/custom.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | @css-prefix: tiny-;
14 | @css-prefix-iconfont: tiny-icon;
15 |
16 | // 组件前缀
17 | @button-prefix-cls: ~'@{css-prefix}button';
18 | @input-prefix-cls: ~'@{css-prefix}input';
19 | @picker-panel-prefix-cls: ~'@{css-prefix}picker-panel';
20 | @scrollbar-prefix-cls: ~'@{css-prefix}scrollbar';
21 | @svg-prefix-cls: ~'@{css-prefix}svg';
22 |
--------------------------------------------------------------------------------
/packages/components/theme/src/mixins/button.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2022 - present TinyVue Authors.
3 | * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
4 | *
5 | * Use of this source code is governed by an MIT-style license.
6 | *
7 | * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8 | * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9 | * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10 | *
11 | */
12 |
13 | .button-size(@font-size, @height, @padding, @minimal-width) {
14 | height: @height;
15 | line-height: calc(@height - 2px);
16 | font-size: @font-size;
17 | padding: 0 @padding;
18 | min-width: @minimal-width;
19 |
20 | &.is-round {
21 | border-radius: calc(@height / 2);
22 | }
23 |
24 | &.is-circle {
25 | border-radius: 50%;
26 | }
27 | }
28 |
29 | .button-circle-size(@size, @padding) {
30 | min-width: @size;
31 | min-height: @size;
32 | height: auto;
33 | line-height: 1;
34 | padding: @padding;
35 | }
36 |
37 | .button-color(@color, @border-color, @background-color) {
38 | color: @color;
39 | fill: @color;
40 | border-color: @border-color;
41 | background-color: @background-color;
42 | }
43 |
44 | .button-type(@color, @normal-bg-color, @normal-border-color,@hover-bg-color, @hover-border-color, @active-color, @disabled-color, @disabled-bg-color, @plain-text-color, @plain-hover-text-color, @plain-bg-color, @plain-hover-bg-color,@plain-border-color, @plain-hover-border-color, @plain-dis-bg-color, @disabled-border-color: @disabled-bg-color) {
45 | color: @color;
46 | fill: @color;
47 | border-color: @normal-border-color;
48 | background-color: @normal-bg-color;
49 |
50 | &:hover {
51 | color: @color;
52 | fill: @color;
53 | border-color: @hover-border-color;
54 | background-color: @hover-bg-color;
55 | }
56 |
57 | &:focus,
58 | &:active,
59 | &.is-active {
60 | color: @color;
61 | fill: @color;
62 | border-color: @active-color;
63 | background-color: @active-color;
64 | outline: 0;
65 | }
66 |
67 | &.is-disabled,
68 | &.is-disabled:active,
69 | &.is-disabled:focus,
70 | &.is-disabled:hover {
71 | color: @disabled-color;
72 | fill: @disabled-color;
73 | border-color: @disabled-border-color;
74 | background-color: @disabled-bg-color;
75 | }
76 |
77 | &.is-plain {
78 | color: @plain-text-color;
79 | fill: @plain-text-color;
80 | border-color: @plain-border-color;
81 | background-color: @plain-bg-color;
82 |
83 | &:hover {
84 | color: @plain-hover-text-color;
85 | fill: @plain-hover-text-color;
86 | border-color: @plain-hover-border-color;
87 | background-color: @plain-hover-bg-color;
88 | }
89 |
90 | &:focus,
91 | &:active,
92 | &.is-active {
93 | color: @color;
94 | fill: @color;
95 | border-color: @active-color;
96 | background-color: @active-color;
97 | outline: 0;
98 | }
99 |
100 | &.is-disabled,
101 | &.is-disabled:active,
102 | &.is-disabled:focus,
103 | &.is-disabled:hover {
104 | color: var(--ti-button-plain-disabled-text-color);
105 | fill: @disabled-bg-color;
106 | border-color: @disabled-bg-color;
107 | background-color: @plain-dis-bg-color;
108 | }
109 | }
110 | }
111 |
112 | .button-text(@color, @hover-bg-color, @active-color, @disabled-color, @hover-weight) {
113 | color: @color;
114 | font-size: var(--ti-common-font-size-1);
115 | border-color: transparent;
116 | background-color: transparent;
117 |
118 | &:hover {
119 | color: @hover-bg-color;
120 | font-weight: @hover-weight;
121 | border-color: transparent;
122 | background-color: transparent;
123 | }
124 |
125 | &:focus,
126 | &:active,
127 | &.is-active {
128 | color: @active-color;
129 | border-color: transparent;
130 | background-color: transparent;
131 | }
132 |
133 | &.is-disabled,
134 | &.is-disabled:active,
135 | &.is-disabled:focus,
136 | &.is-disabled:hover {
137 | color: @disabled-color;
138 | border-color: transparent;
139 | background-color: transparent;
140 | font-weight: normal;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/packages/components/vue/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-vue3
2 |
3 | This is a micro-frontend application based on the Vue3 framework. It mainly demonstrates the cross-end capability of OpenTiny.
4 |
5 | ## Local startup
6 |
7 | Start by running the following command:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | Congratulations on the success of the launch!
--------------------------------------------------------------------------------
/packages/components/vue/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/vue
2 |
3 | 这是一个基于 vue 框架的组件库,同时支持 Vue2 和 Vue3
4 |
5 | ### 1. 安装
6 |
7 | 执行以下命令,安装 Vue 3 版本的 @opentiny/vue 组件库:
8 |
9 | ```shell
10 | npm i @opentiny/vue@3
11 | ```
12 |
13 | 执行以下命令,安装 Vue 2 版本的 TinyVue 组件库:
14 |
15 | ```shell
16 | npm i @opentiny/vue@2
17 | ```
18 |
19 | ### 2. 引入和使用
20 |
21 | 在`App.vue`文件中使用 @opentiny/vue 组件。
22 |
23 | ```html
24 |
27 |
28 |
29 | TinyVue
30 |
31 | ```
32 |
--------------------------------------------------------------------------------
/packages/components/vue/button/index.js:
--------------------------------------------------------------------------------
1 | import Button from './src/index'
2 | import { version } from './package.json'
3 |
4 | /* istanbul ignore next */
5 | Button.install = function (Vue) {
6 | Vue.component(Button.name, Button)
7 | }
8 |
9 | Button.version = version
10 |
11 | /* istanbul ignore next */
12 | if (process.env.BUILD_TARGET === 'runtime') {
13 | if (typeof window !== 'undefined' && window.Vue) {
14 | Button.install(window.Vue)
15 | }
16 | }
17 |
18 | export default Button
19 |
--------------------------------------------------------------------------------
/packages/components/vue/button/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/vue-button",
3 | "version": "3.9.0",
4 | "description": "",
5 | "module": "index.js",
6 | "sideEffects": false,
7 | "type": "module",
8 | "dependencies": {
9 | "@opentiny/vue-common": "workspace:~",
10 | "@opentiny/theme": "workspace:~",
11 | "@opentiny/theme-mobile": "workspace:~",
12 | "@opentiny/theme-watch": "workspace:~",
13 | "@opentiny/renderless": "workspace:~"
14 | },
15 | "license": "MIT"
16 | }
17 |
--------------------------------------------------------------------------------
/packages/components/vue/button/src/index.js:
--------------------------------------------------------------------------------
1 | import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common'
2 | import PcTemplate from './pc.vue'
3 | import MobileTemplate from './mobile.vue'
4 | import WatchTemplate from './watch.vue'
5 |
6 | const template = (mode) => {
7 | if (mode === 'mobile') {
8 | return MobileTemplate
9 | } else if (mode === 'watch') {
10 | return WatchTemplate
11 | } else {
12 | return PcTemplate
13 | }
14 | }
15 |
16 | export default defineComponent({
17 | name: $prefix + 'Button',
18 | inject: {
19 | buttonGroup: {
20 | default: ''
21 | }
22 | },
23 | props: {
24 | ...$props,
25 | type: {
26 | type: String,
27 | default: 'default'
28 | },
29 | tabindex: { type: String, default: '1' },
30 | icon: {
31 | type: [Object, String],
32 | default: ''
33 | },
34 | text: {
35 | type: String,
36 | default: ''
37 | },
38 | resetTime: {
39 | type: Number,
40 | default: 1000
41 | },
42 | nativeType: {
43 | type: String,
44 | default: 'button'
45 | },
46 | size: {
47 | type: String,
48 | default: '',
49 | validator(val) {
50 | return ['large', 'medium', 'small', 'mini', ''].includes(val)
51 | }
52 | },
53 | round: Boolean,
54 | plain: Boolean,
55 | circle: Boolean,
56 | loading: Boolean,
57 | disabled: Boolean,
58 | autofocus: Boolean,
59 | buttonClass: {
60 | type: String,
61 | default: ''
62 | }
63 | },
64 | setup(props, context) {
65 | return $setup({ props, context, template })
66 | }
67 | })
68 |
--------------------------------------------------------------------------------
/packages/components/vue/button/src/mobile.vue:
--------------------------------------------------------------------------------
1 |
2 |
26 |
27 |
28 |
54 |
--------------------------------------------------------------------------------
/packages/components/vue/button/src/pc.vue:
--------------------------------------------------------------------------------
1 |
2 |
33 |
34 |
35 |
63 |
--------------------------------------------------------------------------------
/packages/components/vue/button/src/watch.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
43 |
--------------------------------------------------------------------------------
/packages/components/vue/common/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/vue-common",
3 | "private": true,
4 | "version": "3.9.0",
5 | "main": "src/index.js",
6 | "sideEffects": false,
7 | "type": "module",
8 | "dependencies": {
9 | "@opentiny/vue-locale": "~3.9.0",
10 | "@opentiny/vue-renderless": "~3.9.0",
11 | "@opentiny/theme": "workspace:~",
12 | "@opentiny/theme-mobile": "workspace:~",
13 | "tailwind-merge": "^1.8.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/adapter/index.js:
--------------------------------------------------------------------------------
1 | import vue from 'virtual:common/adapter/vue'
2 |
3 | export * from 'virtual:common/adapter/vue'
4 |
5 | export default vue
6 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/adapter/teleport.js:
--------------------------------------------------------------------------------
1 | let globalId = 0
2 |
3 | const getHasComment = (state) => (comment) => {
4 | const childNodes = Array.from(state.parent.childNodes)
5 |
6 | for (let i = 0; i < childNodes.length; i++) {
7 | if (childNodes[i].textContent === comment) {
8 | return true
9 | }
10 | }
11 | }
12 |
13 | const getGetFragment =
14 | ({ hasComment, startComment, state, endComment }) =>
15 | (commentFlag) => {
16 | const fragment = document.createDocumentFragment()
17 |
18 | commentFlag &&
19 | !hasComment(startComment) &&
20 | fragment.appendChild(document.createComment(startComment))
21 |
22 | state.nodes.forEach((node) => fragment.appendChild(node))
23 |
24 | commentFlag &&
25 | !hasComment(endComment) &&
26 | fragment.appendChild(document.createComment(endComment))
27 |
28 | return fragment
29 | }
30 |
31 | const getDisable =
32 | ({ instance, getFragment, state, startComment, endComment }) =>
33 | () => {
34 | instance.$el.appendChild(getFragment())
35 |
36 | const indices = []
37 |
38 | Array.from(state.parent.childNodes).forEach((child, i) => {
39 | if (child.nodeType === 8) {
40 | if (
41 | child.textContent === startComment ||
42 | child.textContent === endComment
43 | ) {
44 | indices.push(i)
45 | }
46 | }
47 | })
48 |
49 | const minIndex = Math.min(...indices)
50 | const maxIndex = Math.max(...indices)
51 |
52 | Array.from(state.parent.childNodes)
53 | .slice(minIndex, maxIndex + 1)
54 | .reverse()
55 | .forEach((child) => state.parent.removeChild(child))
56 |
57 | state.parent = null
58 | }
59 |
60 | const getMove =
61 | ({ state, props, disable, getFragment }) =>
62 | () => {
63 | state.waiting = false
64 | state.parent = document.querySelector(props.to)
65 |
66 | if (!state.parent) {
67 | disable()
68 | state.waiting = true
69 |
70 | return
71 | }
72 |
73 | if (props.where === 'before') {
74 | state.parent.prepend(getFragment(true))
75 | } else {
76 | state.parent.appendChild(getFragment(true))
77 | }
78 | }
79 |
80 | const getTeardownObserver = (state) => () => {
81 | if (state.observer) {
82 | state.observer.disconnect()
83 | state.observer = null
84 | }
85 | }
86 |
87 | const getOnMutations =
88 | ({ state, disable, props, move }) =>
89 | (mutations) => {
90 | let shouldMove = false
91 |
92 | for (let i = 0; i < mutations.length; i++) {
93 | const mutation = mutations[i]
94 | const filteredAddedNodes = Array.from(mutation.addedNodes).filter(
95 | (node) => !state.nodes.includes(node)
96 | )
97 |
98 | if (Array.from(mutation.removedNodes).includes(state.parent)) {
99 | disable()
100 | state.waiting = !props.disabled
101 | } else if (state.waiting && filteredAddedNodes.length > 0) {
102 | shouldMove = true
103 | }
104 | }
105 |
106 | shouldMove && move()
107 | }
108 |
109 | const getBootObserver =
110 | ({ state, onMutations }) =>
111 | () => {
112 | if (state.observer) return
113 |
114 | state.observer = new MutationObserver((mutations) => onMutations(mutations))
115 |
116 | state.observer.observe(document.body, {
117 | attributes: false,
118 | characterData: false,
119 | childList: true,
120 | subtree: true
121 | })
122 | }
123 |
124 | const getAfterUpdated =
125 | ({ state, instance, props, bootObserver, maybeMove }) =>
126 | () => {
127 | state.nodes = Array.from(instance.$el.childNodes)
128 |
129 | !props.disabled && bootObserver()
130 | maybeMove()
131 | }
132 |
133 | const getWatchDisabled =
134 | ({ disable, teardownObserver, bootObserver, move }) =>
135 | (value) => {
136 | if (value) {
137 | disable()
138 | teardownObserver()
139 |
140 | return
141 | }
142 |
143 | bootObserver()
144 | move()
145 | }
146 |
147 | export default ({
148 | reactive,
149 | watch,
150 | getCurrentInstance,
151 | onUpdated,
152 | onMounted,
153 | onBeforeUnmount,
154 | h,
155 | defineComponent
156 | }) =>
157 | defineComponent({
158 | name: 'Vue2Teleport',
159 | props: {
160 | to: { type: String, required: true },
161 | where: { type: String, default: 'after' },
162 | disabled: Boolean
163 | },
164 | setup(props) {
165 | const state = reactive({
166 | nodes: [],
167 | waiting: false,
168 | observer: null,
169 | parent: null,
170 | id: ++globalId
171 | })
172 | const instance = getCurrentInstance()?.proxy
173 | const startComment = `[${state.id}]vue2-teleporter-start`
174 | const endComment = `[${state.id}]vue2-teleporter-end`
175 |
176 | const hasComment = getHasComment(state)
177 | const getFragment = getGetFragment({
178 | hasComment,
179 | startComment,
180 | state,
181 | endComment
182 | })
183 | const disable = getDisable({
184 | instance,
185 | getFragment,
186 | state,
187 | startComment,
188 | endComment
189 | })
190 | const move = getMove({ state, props, disable, getFragment })
191 | const maybeMove = () => !props.disabled && move()
192 | const teardownObserver = getTeardownObserver(state)
193 | const onMutations = getOnMutations({ state, disable, props, move })
194 | const bootObserver = getBootObserver({ state, onMutations })
195 | const afterUpdated = getAfterUpdated({
196 | state,
197 | instance,
198 | props,
199 | bootObserver,
200 | maybeMove
201 | })
202 | const watchDisabled = getWatchDisabled({
203 | disable,
204 | teardownObserver,
205 | bootObserver,
206 | move
207 | })
208 |
209 | watch(() => props.to, maybeMove)
210 | watch(() => props.where, maybeMove)
211 | watch(() => props.disabled, watchDisabled)
212 |
213 | onUpdated(afterUpdated)
214 | onMounted(afterUpdated)
215 | onBeforeUnmount(() => {
216 | disable()
217 | teardownObserver()
218 | })
219 |
220 | return () =>
221 | h(
222 | 'div',
223 | {
224 | class: 'vue2-teleporter',
225 | style: { 'visibility:hidden;display:none;': !props.disabled }
226 | },
227 | (typeof instance?.$slots.default === 'function'
228 | ? instance.$slots.default()
229 | : instance.$slots.default) || null
230 | )
231 | }
232 | })
233 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/adapter/utils.js:
--------------------------------------------------------------------------------
1 | export const emitter = () => {
2 | let listeners = {}
3 |
4 | const on = (event, callback, once = false) => {
5 | if (event && typeof event === 'string' && typeof callback === 'function') {
6 | const callbacks = listeners[event] || []
7 |
8 | listeners[event] = callbacks
9 | callbacks.push(callback)
10 | callback.once = once
11 | }
12 | }
13 |
14 | const emitter = {
15 | emit(eventName) {
16 | const callbacks = listeners[eventName]
17 |
18 | if (callbacks) {
19 | callbacks.forEach((callback) =>
20 | callback.apply(null, [].slice.call(arguments, 1))
21 | )
22 |
23 | listeners[eventName] = callbacks.filter((callback) => !callback.once)
24 | }
25 | },
26 | on,
27 | once(event, callback) {
28 | on(event, callback, true)
29 | },
30 | off(event, callback) {
31 | if (event && typeof event === 'string') {
32 | const callbacks = listeners[event]
33 |
34 | if (typeof callback === 'function') {
35 | listeners[event] = callbacks.filter((cb) => cb !== callback)
36 | } else {
37 | delete listeners[event]
38 | }
39 | } else {
40 | listeners = {}
41 | }
42 | }
43 | }
44 |
45 | return emitter
46 | }
47 |
48 | export const bindFilter = (props, attrs = {}) => {
49 | const properties = {}
50 |
51 | for (let name in props) {
52 | if (name.indexOf('_') !== 0) {
53 | properties[name] = props[name]
54 | }
55 | }
56 |
57 | for (let name in attrs) {
58 | properties[name] = attrs[name]
59 | }
60 |
61 | return properties
62 | }
63 |
64 | /**
65 | * 根据类名生成对应的hover、active等类名
66 | *
67 | * getElementStatusClass('border-color', 'hover') // 'border-color hover:border-color-hover'
68 | * getElementStatusClass(['border-color'], ['hover', 'active']) // 'border-color hover:border-color-hover active:border-color-active'
69 | *
70 | * @method
71 | * @param {String|Array} className - 类名
72 | * @param {String|Array} status - 状态
73 | * @returns {String} - 类名拼接的字符串
74 | */
75 | export const getElementStatusClass = (className, status) => {
76 | if (!className || !status) return
77 |
78 | let classNames = []
79 | if (typeof className === 'string') {
80 | classNames.push(className)
81 | } else if (Array.isArray(className)) {
82 | classNames = className
83 | }
84 |
85 | let statusList = []
86 | if (typeof status === 'string') {
87 | statusList.push(status)
88 | } else if (Array.isArray(status)) {
89 | statusList = status
90 | }
91 |
92 | let res = []
93 | statusList.forEach((status) =>
94 | classNames.forEach((name) => res.push(`${status}:${name}-${status}`))
95 | )
96 |
97 | return classNames.concat(res).join(' ')
98 | }
99 |
100 | /**
101 | * 根据key值获取对应的classes类名配置
102 | *
103 | * getElementCssClass({ button: 'border-color' }, 'button') // 'border-color'
104 | * getElementCssClass({ button: 'border-color' }, { 'button': true }) // 'border-color'
105 | *
106 | * @method
107 | * @param {Object} classes - 类名集合
108 | * @param {String|Object} key - 状态
109 | * @returns {String} - 类名配置值
110 | */
111 | export const getElementCssClass = (classes = {}, key) => {
112 | if (typeof key === 'object') {
113 | const keys = Object.keys(key)
114 | let cls = ''
115 | keys.forEach((k) => {
116 | if (key[k] && classes[k]) cls += `${classes[k]} `
117 | })
118 | return cls
119 | } else {
120 | return classes[key] || ''
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/adapter/vue2/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import * as hooks from '@vue/composition-api'
3 | import {
4 | bindFilter,
5 | emitter,
6 | getElementCssClass,
7 | getElementStatusClass
8 | } from '../utils'
9 | import teleport from '../teleport'
10 |
11 | const Teleport = teleport(hooks)
12 |
13 | export {
14 | emitter,
15 | bindFilter,
16 | getElementCssClass,
17 | getElementStatusClass,
18 | Teleport
19 | }
20 |
21 | Vue.use(hooks.default)
22 |
23 | export const defineAsyncComponent = ({
24 | loader,
25 | loadingComponent,
26 | errorComponent,
27 | delay,
28 | timeout
29 | }) => {
30 | return () => ({
31 | component: loader(),
32 | loading: loadingComponent,
33 | error: errorComponent,
34 | delay,
35 | timeout
36 | })
37 | }
38 |
39 | export const markRaw = (ref) => ref
40 |
41 | export const renderComponent = ({
42 | view = null,
43 | component = null,
44 | props,
45 | context: { attrs, listeners: on, slots },
46 | extend = {}
47 | }) => {
48 | return () =>
49 | hooks.h(
50 | (view && view.value) || component,
51 | Object.assign(
52 | {
53 | props,
54 | attrs,
55 | [extend.isSvg ? 'nativeOn' : 'on']: on,
56 | scopedSlots: { ...slots }
57 | },
58 | extend
59 | )
60 | )
61 | }
62 |
63 | export const rootConfig = () => hooks.getCurrentInstance()?.proxy.$root
64 |
65 | export const getComponentName = () => {
66 | // 此处组件最多为两层组件,所以对多获取到父级组件即可
67 | const instance = hooks.getCurrentInstance()
68 | let componentName =
69 | instance?.vnode?.componentOptions?.Ctor?.extendOptions?.name
70 | if (!componentName) {
71 | componentName =
72 | instance?.parent?.vnode?.componentOptions?.Ctor?.extendOptions?.name
73 | }
74 |
75 | return componentName || ''
76 | }
77 |
78 | export const appContext = () => Vue
79 |
80 | export const appProperties = () => Vue.prototype
81 |
82 | export const useRouter = (instance = hooks.getCurrentInstance()?.proxy) => {
83 | return {
84 | route: instance?.$route,
85 | router: instance?.$router
86 | }
87 | }
88 |
89 | const emitEvent = (vm) => {
90 | const broadcast = (vm, componentName, eventName, params) => {
91 | vm.$children.forEach((child) => {
92 | const name = child.$options.componentName
93 |
94 | if (name === componentName) child.$emit(eventName, params)
95 | else broadcast(child, componentName, eventName, params)
96 | })
97 | }
98 |
99 | return {
100 | dispatch(componentName, eventName, params) {
101 | let parent = vm.$parent || vm.$root
102 | let name = parent.$options.componentName
103 |
104 | while (parent && (!name || name !== componentName)) {
105 | parent = parent.$parent
106 |
107 | if (parent) name = parent.$options.componentName
108 | }
109 |
110 | if (parent) parent.$emit(...[eventName].concat(params))
111 | },
112 | broadcast(componentName, eventName, params) {
113 | broadcast(vm, componentName, eventName, params)
114 | }
115 | }
116 | }
117 |
118 | const parent = (vm) => (handler) => {
119 | let parent = vm.$parent
120 | let level = 0
121 |
122 | const parentObject = (parent) => {
123 | return {
124 | level,
125 | vm: createVm({}, parent),
126 | el: parent.$el,
127 | options: parent.$options
128 | }
129 | }
130 |
131 | if (typeof handler !== 'function') return parent ? parentObject(parent) : {}
132 |
133 | level++
134 |
135 | while (parent) {
136 | if (handler(parentObject(parent))) break
137 |
138 | parent = parent.$parent
139 | level++
140 | }
141 | }
142 |
143 | const children = (vm) => (handler) => {
144 | if (typeof handler !== 'function') return generateChildren(vm.$children)
145 |
146 | let layer = 1
147 |
148 | const broadcast = ($children) => {
149 | const level = layer++
150 |
151 | if (
152 | $children.some((child) => {
153 | return handler({
154 | level,
155 | vm: createVm({}, child),
156 | el: child.$el,
157 | options: child.$options,
158 | isLevel1: level === 1
159 | })
160 | })
161 | )
162 | return
163 |
164 | $children.forEach((child) => broadcast(child.$children))
165 | }
166 |
167 | broadcast(vm.$children)
168 | }
169 |
170 | const generateChildren = ($children) => {
171 | const children = []
172 |
173 | children.refs = {}
174 |
175 | $children.forEach((child) => {
176 | const vm = createVm({}, child)
177 |
178 | children.push(vm)
179 | child.$vnode.data.ref && (children.refs[child.$vnode.data.ref] = vm)
180 | })
181 |
182 | return children
183 | }
184 |
185 | const defineProperties = (vm, instance, filter) => {
186 | for (const name in instance) {
187 | if (typeof filter === 'function' && filter(name)) continue
188 |
189 | Object.defineProperty(vm, name, {
190 | configurable: true,
191 | enumerable: true,
192 | get: () => instance[name],
193 | set: (value) => (instance[name] = value)
194 | })
195 | }
196 |
197 | return vm
198 | }
199 |
200 | const filter = (name) =>
201 | name.indexOf('$') === 0 || name.indexOf('_') === 0 || name === 'constructor'
202 |
203 | const customEmit = (context, emit) => {
204 | return function (...args) {
205 | emit.apply(context, args)
206 |
207 | // vue3 下 emit('update:modelValue') 会同时触发 input 事件,vue2 不会
208 | if (args[0] === 'update:modelValue')
209 | emit.apply(context, ['input'].concat(args.slice(1)))
210 | }
211 | }
212 |
213 | const createVm = (vm, instance, context = undefined) => {
214 | context || defineProperties(vm, instance, filter)
215 |
216 | Object.defineProperties(vm, {
217 | $attrs: { get: () => instance.$attrs },
218 | $children: { get: () => generateChildren(instance.$children) },
219 | $constants: { get: () => instance._constants },
220 | $emit: { get: () => customEmit(instance, instance.$emit) },
221 | $el: { get: () => instance.$el },
222 | $listeners: { get: () => instance.$listeners },
223 | $mode: { get: () => instance._tiny_mode },
224 | $nextTick: { get: () => hooks.nextTick },
225 | $off: { get: () => instance.$off.bind(instance) },
226 | $on: { get: () => instance.$on.bind(instance) },
227 | $once: { get: () => instance.$once.bind(instance) },
228 | $options: {
229 | get: () => ({ componentName: instance.$options.componentName })
230 | },
231 | $parent: { get: () => instance.$parent && createVm({}, instance.$parent) },
232 | $refs: { get: () => instance.$refs },
233 | $renderless: { get: () => instance.tiny_renderless },
234 | $scopedSlots: { get: () => instance.$scopedSlots },
235 | $set: { get: () => instance.$set },
236 | $slots: { get: () => instance.$scopedSlots },
237 | $template: { get: () => instance.tiny_template }
238 | })
239 |
240 | return vm
241 | }
242 |
243 | export const tools = (context, mode) => {
244 | const instance = hooks.getCurrentInstance()?.proxy
245 | const root = instance?.$root
246 | const { route, router } = useRouter(instance)
247 | const i18n = root?.$i18n
248 | const { dispatch, broadcast } = emitEvent(instance)
249 | const parentHandler = parent(instance)
250 | const childrenHandler = children(instance)
251 | const vm = createVm({}, instance, context)
252 | const emit = context.emit
253 | const parentVm = instance.$parent ? createVm({}, instance.$parent) : null
254 |
255 | const setParentAttribute = ({ name, value }) => {
256 | instance.$parent[name] = value
257 | parentVm[name] = value
258 | }
259 |
260 | const defineInstanceProperties = (props) => {
261 | Object.defineProperties(vm, props)
262 | Object.defineProperties(instance, props)
263 | }
264 |
265 | const defineParentInstanceProperties = (props) => {
266 | parentVm && Object.defineProperties(parentVm, props)
267 | }
268 |
269 | hooks.onBeforeMount(() => defineProperties(vm, instance, filter))
270 |
271 | return {
272 | vm,
273 | emit: customEmit(context, emit),
274 | emitter,
275 | route,
276 | router,
277 | dispatch,
278 | broadcast,
279 | parentHandler,
280 | childrenHandler,
281 | refs: context.refs,
282 | i18n,
283 | slots: context.slots,
284 | scopedSlots: context.slots,
285 | attrs: context.attrs,
286 | parent: parentVm,
287 | nextTick: hooks.nextTick,
288 | constants: instance?._constants,
289 | mode,
290 | isPCMode: mode === 'pc',
291 | isMobileMode: mode === 'mobile',
292 | service: instance?.$service,
293 | getService: () => instance?.$getService(vm),
294 | setParentAttribute,
295 | defineInstanceProperties,
296 | defineParentInstanceProperties
297 | }
298 | }
299 |
300 | const mapping = (content, before, after) => {
301 | if (typeof content[before] !== 'undefined') {
302 | const fn = content[before]
303 |
304 | content[after] = (el, binding, vnode) => {
305 | binding.instance = vnode.context
306 | fn(el, binding, vnode)
307 | }
308 |
309 | delete content[before]
310 | }
311 | }
312 |
313 | export const directive = (directives) => {
314 | for (const name in directives) {
315 | const content = directives[name]
316 |
317 | mapping(content, 'beforeMount', 'bind')
318 | mapping(content, 'updated', 'update')
319 | mapping(content, 'unmounted', 'unbind')
320 | }
321 |
322 | return directives
323 | }
324 |
325 | const bindVnodeData = ({ props, data, name, attr = name }) => {
326 | Object.defineProperty(props, attr, {
327 | get: () => data[name],
328 | set: (value) => (data[name] = value)
329 | })
330 | }
331 |
332 | export const parseVnode = (vnode) => {
333 | const props = {}
334 | const data =
335 | (vnode.componentOptions && vnode.componentOptions.propsData) || {}
336 |
337 | for (const name in data) bindVnodeData({ props, data, name })
338 |
339 | vnode.props = props
340 | vnode.type = { name: vnode.componentOptions && vnode.componentOptions.tag }
341 |
342 | return vnode
343 | }
344 |
345 | export const h = hooks.h
346 |
347 | export const createComponentFn = (design) => {
348 | return ({ component, propsData, el }) => {
349 | const comp = Object.assign(component, {
350 | provide: { [design.configKey]: design.configInstance }
351 | })
352 | return new (Vue.extend(comp))({ propsData, el }).$mount()
353 | }
354 | }
355 |
356 | export const defineComponent = hooks.defineComponent
357 |
358 | export default hooks
359 |
360 | export const isVue2 = true
361 |
362 | export const isVue3 = false
363 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/adapter/vue2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue2-common",
3 | "private": true,
4 | "version": "5.0.2-mf.0",
5 | "description": "",
6 | "main": "lib/index.js",
7 | "module": "index.ts",
8 | "devDependencies": {
9 | "@vue/composition-api": "~1.2.2",
10 | "vue": "~2.6.14",
11 | "vue-router": "^3.6.4"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/adapter/vue3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue3-common",
3 | "private": true,
4 | "version": "5.0.2-mf.0",
5 | "description": "",
6 | "main": "index.ts",
7 | "devDependencies": {
8 | "@vue/runtime-core": "^3.2.31",
9 | "vue": "^3.3.4"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/csscls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 简单合并 tailwind 类对象为字符串值
3 | *
4 | * @param cssClassObject tailwind 类对象
5 | * @returns string
6 | */
7 | const stringifyCssClassObject = (cssClassObject) => {
8 | const allCssClass = []
9 |
10 | Object.keys(cssClassObject).forEach(
11 | (cssClass) => cssClassObject[cssClass] && allCssClass.push(cssClass)
12 | )
13 |
14 | return allCssClass.join('\u{20}')
15 | }
16 |
17 | /**
18 | * 简单合并 tailwind 类数组为字符串值
19 | *
20 | * @param cssClassArray tailwind 类数组
21 | * @returns string
22 | */
23 | const stringifyCssClassArray = (cssClassArray) => {
24 | const allCssClass = []
25 |
26 | cssClassArray.forEach((cssClass) => {
27 | if (typeof cssClass === 'string') {
28 | allCssClass.push(cssClass)
29 | } else if (typeof cssClass === 'object') {
30 | allCssClass.push(stringifyCssClassObject(cssClass))
31 | }
32 | })
33 |
34 | return allCssClass.join('\u{20}')
35 | }
36 |
37 | /**
38 | * 简单合并 tailwind 类对象为字符串值,去重处理留给 tailwind-merge 处理
39 | *
40 | * @param {*} cssClasses tailwind 类集合
41 | * @returns string
42 | */
43 | export const stringifyCssClass = (cssClasses) => {
44 | if (!cssClasses || (Array.isArray(cssClasses) && !cssClasses.length))
45 | return ''
46 |
47 | const allCssClass = []
48 |
49 | cssClasses.forEach((cssClass) => {
50 | if (cssClass) {
51 | if (typeof cssClass === 'string') {
52 | allCssClass.push(cssClass)
53 | } else if (Array.isArray(cssClass)) {
54 | allCssClass.push(stringifyCssClassArray(cssClass))
55 | } else if (typeof cssClass === 'object') {
56 | allCssClass.push(stringifyCssClassObject(cssClass))
57 | }
58 | }
59 | })
60 |
61 | return allCssClass.join('\u{20}')
62 | }
63 |
--------------------------------------------------------------------------------
/packages/components/vue/common/src/index.js:
--------------------------------------------------------------------------------
1 | import hooks from './adapter'
2 | import {
3 | appContext,
4 | appProperties,
5 | bindFilter,
6 | createComponentFn,
7 | getElementCssClass,
8 | getElementStatusClass
9 | } from './adapter'
10 | import {
11 | defineAsyncComponent,
12 | directive,
13 | emitter,
14 | h,
15 | markRaw,
16 | Teleport
17 | } from './adapter'
18 | import {
19 | parseVnode,
20 | renderComponent,
21 | rootConfig,
22 | tools,
23 | useRouter,
24 | getComponentName
25 | } from './adapter'
26 | import { t } from '@opentiny/vue-locale'
27 | import { stringifyCssClass } from './csscls'
28 | import { twMerge } from 'tailwind-merge'
29 | import '@opentiny/theme/base/index.less'
30 |
31 | import { defineComponent, isVue2, isVue3 } from './adapter'
32 |
33 | export { version } from '../package.json'
34 |
35 | export { defineComponent, isVue2, isVue3, appProperties }
36 |
37 | export const $prefix = 'Tiny'
38 |
39 | export const $props = {
40 | tiny_mode: String,
41 | tiny_mode_root: Boolean,
42 | tiny_template: [Function, Object],
43 | tiny_renderless: Function,
44 | tiny_theme: String,
45 | tiny_chart_theme: Object
46 | }
47 |
48 | export const props = [
49 | 'tiny_mode',
50 | 'tiny_mode_root',
51 | 'tiny_template',
52 | 'tiny_renderless',
53 | '_constants',
54 | 'tiny_theme',
55 | 'tiny_chart_theme'
56 | ]
57 |
58 | export const resolveMode = (props, context) => {
59 | let isRightMode = (mode) =>
60 | ~['pc', 'mobile', 'mobile-first', 'watch'].indexOf(mode)
61 | let config = rootConfig(context)
62 | let tinyModeProp =
63 | typeof props.tiny_mode === 'string' ? props.tiny_mode : null
64 | let tinyModeInject = hooks.inject('TinyMode', null)
65 | let tinyModeGlobal = config.tiny_mode && config.tiny_mode.value
66 |
67 | if (!isRightMode(tinyModeProp)) tinyModeProp = null
68 | if (!isRightMode(tinyModeInject)) tinyModeInject = null
69 | if (!isRightMode(tinyModeGlobal)) tinyModeGlobal = null
70 |
71 | let tinyMode = tinyModeProp || tinyModeInject || tinyModeGlobal || 'pc'
72 |
73 | if (props.tiny_mode_root) {
74 | hooks.provide('TinyMode', tinyMode)
75 | }
76 |
77 | let instance = hooks.getCurrentInstance()
78 |
79 | if (isVue2) {
80 | instance = instance.proxy
81 | }
82 |
83 | Object.defineProperty(instance, '_tiny_mode', { value: tinyMode })
84 |
85 | return tinyMode
86 | }
87 |
88 | const resolveTheme = ({ props, context, utils }) => {
89 | const isRightTheme = (theme) => ~['tiny', 'saas'].indexOf(theme)
90 | const config = rootConfig(context)
91 | let tinyThemeProp =
92 | typeof props.tiny_theme === 'string' ? props.tiny_theme : null
93 | let tinyThemeInject = hooks.inject('TinyTheme', null)
94 | let tinyThemeGlobal = config.tiny_theme && config.tiny_theme.value
95 |
96 | if (!isRightTheme(tinyThemeProp)) tinyThemeProp = null
97 | if (!isRightTheme(tinyThemeInject)) tinyThemeInject = null
98 | if (!isRightTheme(tinyThemeGlobal)) tinyThemeGlobal = null
99 |
100 | const tinyTheme =
101 | tinyThemeProp || tinyThemeInject || tinyThemeGlobal || 'tiny'
102 |
103 | return (utils.vm.theme = tinyTheme)
104 | }
105 |
106 | const resolveChartTheme = ({ props, context, utils }) => {
107 | const config = rootConfig(context)
108 | let tinyChartProp =
109 | typeof props.tiny_chart_theme === 'object' ? props.tiny_chart_theme : null
110 | let tinyChartInject = hooks.inject('TinyChartTheme', null)
111 | let tinyChartGlobal = config.tiny_chart_theme && config.tiny_chart_theme.value
112 |
113 | const tinyChartTheme =
114 | tinyChartProp || tinyChartInject || tinyChartGlobal || null
115 |
116 | return (utils.vm.chart_theme = tinyChartTheme)
117 | }
118 |
119 | export const $setup = ({ props, context, template, extend = {} }) => {
120 | const view = hooks.computed(() => {
121 | if (typeof props.tiny_template !== 'undefined') return props.tiny_template
122 |
123 | const component = template(resolveMode(props, context), props)
124 |
125 | return typeof component === 'function'
126 | ? defineAsyncComponent(component)
127 | : component
128 | })
129 |
130 | initComponent()
131 |
132 | return renderComponent({ view, props, context, extend })
133 | }
134 |
135 | export const mergeClass = (...cssClasses) =>
136 | twMerge(stringifyCssClass(cssClasses))
137 |
138 | // 提供给没有renderless层的组件使用(比如TinyVuePlus组件)
139 | export const design = {
140 | configKey: Symbol('designConfigKey'),
141 | configInstance: null
142 | }
143 |
144 | // 注入规范配置
145 | export const provideDesignConfig = (designConfig) => {
146 | if (Object.keys(designConfig).length) {
147 | hooks.provide(design.configKey, designConfig)
148 | design.configInstance = designConfig
149 | }
150 | }
151 |
152 | const createComponent = createComponentFn(design)
153 |
154 | export const setup = ({
155 | props,
156 | context,
157 | renderless,
158 | api,
159 | extendOptions = { framework: isVue3 ? 'Vue3' : 'Vue2' },
160 | mono = false,
161 | classes = {}
162 | }) => {
163 | const render =
164 | typeof props.tiny_renderless === 'function'
165 | ? props.tiny_renderless
166 | : renderless
167 |
168 | // 获取组件级配置和全局配置(inject需要带有默认值,否则控制台会报警告)
169 | const globalDesignConfig = hooks.inject(design.configKey, {})
170 | const designConfig =
171 | globalDesignConfig?.components?.[getComponentName().replace($prefix, '')]
172 |
173 | const utils = {
174 | $prefix,
175 | t,
176 | ...tools(context, resolveMode(props, context)),
177 | mergeClass,
178 | designConfig,
179 | globalDesignConfig
180 | }
181 |
182 | resolveTheme({ props, context, utils })
183 | resolveChartTheme({ props, context, utils })
184 | const sdk = render(props, hooks, utils, extendOptions)
185 |
186 | // 加载全局配置,合并api
187 | if (typeof designConfig?.renderless === 'function') {
188 | Object.assign(
189 | sdk,
190 | designConfig.renderless(props, hooks, utils, sdk, extendOptions)
191 | )
192 | }
193 |
194 | const attrs = {
195 | t,
196 | vm: utils.vm,
197 | f: bindFilter,
198 | a: filterAttrs,
199 | d: utils.defineInstanceProperties,
200 | dp: utils.defineParentInstanceProperties,
201 | gcls: (key) => getElementCssClass(classes, key),
202 | m: mergeClass
203 | }
204 |
205 | /**
206 | * 修复 render 函数下 this.slots 不会动态更新的问题(vue3 环境没有问题)
207 | * 解决方法:在 instance 下注入 slots、scopedSlots
208 | * 注意:renderless 下尽量使用 vm.$refs、vm.$slots
209 | */
210 | attrs.d({
211 | slots: { get: () => utils.vm.$slots },
212 | scopedSlots: { get: () => utils.vm.$scopedSlots }
213 | })
214 |
215 | attrs.dp({
216 | slots: { get: () => utils.parent.$slots },
217 | scopedSlots: { get: () => utils.parent.$scopedSlots }
218 | })
219 |
220 | initComponent()
221 |
222 | Array.isArray(api) &&
223 | api.forEach((name) => {
224 | const value = sdk[name]
225 |
226 | if (typeof value !== 'undefined') {
227 | attrs[name] = value
228 | // 只有单层组件,才需要给setup传递: mono:true
229 | // 双层组件,需要把内层的api复制到外层,这样用户应用的ref才能拿到组件的api
230 | if (!mono) {
231 | utils.setParentAttribute({ name, value })
232 | }
233 | }
234 | })
235 |
236 | return attrs
237 | }
238 |
239 | export const svg = ({ name = 'Icon', component }) => {
240 | return (propData) =>
241 | markRaw(
242 | defineComponent({
243 | name: $prefix + name,
244 | setup: (props, context) => {
245 | const {
246 | fill,
247 | width,
248 | height,
249 | 'custom-class': customClass
250 | } = context.attrs || {}
251 | const mergeProps = Object.assign({}, props, propData || null)
252 | const mode = resolveMode(mergeProps, context)
253 | const isMobileFirst = mode === 'mobile-first'
254 | const tinyTag = { 'data-tag': isMobileFirst ? 'tiny-svg' : null }
255 | const attrs = isVue3 ? tinyTag : { attrs: tinyTag }
256 | const className = isMobileFirst
257 | ? mergeClass(
258 | 'h-4 w-4 inline-block',
259 | customClass || '',
260 | mergeProps.class || ''
261 | )
262 | : 'tiny-svg'
263 | const extend = Object.assign(
264 | {
265 | style: { fill, width, height },
266 | class: className,
267 | isSvg: true
268 | },
269 | attrs
270 | )
271 |
272 | // 解决本地运行会报大量警告的问题
273 | if (process.env.BUILD_TARGET) {
274 | extend.nativeOn = context.listeners
275 | }
276 |
277 | return renderComponent({
278 | component,
279 | props: mergeProps,
280 | context,
281 | extend
282 | })
283 | }
284 | })
285 | )
286 | }
287 |
288 | export const filterAttrs = (attrs, filters, include) => {
289 | const props = {}
290 |
291 | for (let name in attrs) {
292 | const find = filters.some((r) => new RegExp(r).test(name))
293 |
294 | if ((include && find) || (!include && !find)) {
295 | props[name] = attrs[name]
296 | }
297 | }
298 |
299 | return props
300 | }
301 |
302 | export let setupComponent = {}
303 |
304 | export const initComponent = () => {
305 | for (let name in setupComponent) {
306 | const component = setupComponent[name]
307 |
308 | if (typeof component.install === 'function') {
309 | component.install(appContext())
310 | }
311 |
312 | if (typeof component.init === 'function') {
313 | component.init(appProperties())
314 | }
315 | }
316 |
317 | setupComponent = {}
318 | }
319 |
320 | export const $install = (component) => {
321 | component.install = function (Vue) {
322 | Vue.component(component.name, component)
323 | }
324 | }
325 |
326 | export {
327 | h,
328 | hooks,
329 | directive,
330 | parseVnode,
331 | useRouter,
332 | emitter,
333 | createComponent,
334 | defineAsyncComponent,
335 | getElementStatusClass,
336 | Teleport
337 | }
338 |
339 | export default {
340 | h,
341 | directive,
342 | parseVnode,
343 | useRouter,
344 | emitter,
345 | createComponent,
346 | defineAsyncComponent,
347 | filterAttrs,
348 | initComponent,
349 | setupComponent,
350 | svg,
351 | $prefix,
352 | $props,
353 | props,
354 | $setup,
355 | setup,
356 | hooks,
357 | getElementStatusClass,
358 | $install
359 | }
360 |
--------------------------------------------------------------------------------
/packages/components/vue/config-provider/hooks/use-config.ts:
--------------------------------------------------------------------------------
1 | import type { ConfigProviderProps } from '../src/props'
2 | import { configProviderContextKey } from '../index'
3 | import { hooks } from '@opentiny/vue-common'
4 |
5 | export function useConfig(): ConfigProviderProps | {} {
6 | return hooks.inject(configProviderContextKey) ?? {}
7 | }
8 |
--------------------------------------------------------------------------------
/packages/components/vue/config-provider/index.js:
--------------------------------------------------------------------------------
1 | import ConfigProvider from './src/index.vue'
2 | import { version } from './package.json'
3 |
4 | export const configProviderContextKey = Symbol('CONFIG_PROVIDER_CONTEXT_KEY')
5 |
6 | /* istanbul ignore next */
7 | ConfigProvider.install = function (Vue) {
8 | Vue.component(ConfigProvider.name, ConfigProvider)
9 | }
10 |
11 | ConfigProvider.version = version
12 |
13 | /* istanbul ignore next */
14 | if (process.env.BUILD_TARGET === 'runtime') {
15 | if (typeof window !== 'undefined' && window.Vue) {
16 | ConfigProvider.install(window.Vue)
17 | }
18 | }
19 |
20 | export default ConfigProvider
21 |
--------------------------------------------------------------------------------
/packages/components/vue/config-provider/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/vue-config-provider",
3 | "version": "3.9.0",
4 | "main": "ndex.js",
5 | "module": "index.js",
6 | "sideEffects": false,
7 | "type": "module",
8 | "dependencies": {
9 | "@opentiny/vue-common": "workspace:~"
10 | },
11 | "license": "MIT"
12 | }
--------------------------------------------------------------------------------
/packages/components/vue/config-provider/src/index.vue:
--------------------------------------------------------------------------------
1 |
102 |
--------------------------------------------------------------------------------
/packages/components/vue/countdown/index.js:
--------------------------------------------------------------------------------
1 | import Countdown from './src/pc.vue'
2 | import { version } from './package.json'
3 |
4 | /* istanbul ignore next */
5 | Countdown.install = function (Vue) {
6 | Vue.component(Countdown.name, Countdown)
7 | }
8 |
9 | Countdown.version = version
10 |
11 | /* istanbul ignore next */
12 | if (process.env.BUILD_TARGET === 'runtime') {
13 | if (typeof window !== 'undefined' && window.Vue) {
14 | Countdown.install(window.Vue)
15 | }
16 | }
17 |
18 | export default Countdown
19 |
--------------------------------------------------------------------------------
/packages/components/vue/countdown/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/vue-countdown",
3 | "version": "3.9.0",
4 | "description": "",
5 | "module": "index.js",
6 | "sideEffects": false,
7 | "type": "module",
8 | "dependencies": {
9 | "@opentiny/vue-common": "workspace:~",
10 | "@opentiny/theme": "workspace:~",
11 | "@opentiny/renderless": "workspace:~"
12 | },
13 | "license": "MIT"
14 | }
15 |
--------------------------------------------------------------------------------
/packages/components/vue/countdown/src/pc.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 | {{ state.day }}:{{ state.hour }}:{{
10 | state.minute
11 | }}:{{ state.second }}
12 |
13 |
14 |
15 |
16 |
55 |
--------------------------------------------------------------------------------
/packages/components/vue/index.js:
--------------------------------------------------------------------------------
1 | import Button from '@opentiny/vue-button'
2 | import Countdown from '@opentiny/react-countdown'
3 | import ConfigProvider from '@opentiny/react-config-provider'
4 |
5 | export { Button, Countdown, ConfigProvider }
6 |
--------------------------------------------------------------------------------
/packages/components/vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/vue",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@opentiny/vue-button": "workspace:~",
14 | "@opentiny/vue-countdown": "workspace:~"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/README.md:
--------------------------------------------------------------------------------
1 | # element-to-opentiny
2 |
3 | This is a Vue2 project based on the ElementUI component library, using the following components of the ElementUI component library:
4 | 1. Carousel
5 | 2. Select
6 | 3. DatePicker
7 | 4. Input
8 | 5. Button
9 | 6. Table
10 | 7. Tabs
11 | 8. Form
12 | 9. TimePicker
13 | 10. Switch
14 | 11. Checkbox
15 | 12. Radio
16 |
17 | ## Development
18 |
19 | You can start by executing the following command from the root of the project:
20 |
21 | ```shell
22 | pnpm --filter element-to-opentiny dev
23 | ```
24 |
25 | Or you can execute the following command under the `packages/element-to-opentiny` sub-package project to launch:
26 |
27 | ```shell
28 | npm run dev
29 | ```
30 |
31 | The effect after startup is as follows:
32 |
33 | 
34 |
35 | Now we need to upgrade this project to a Vue3 project that uses the OpenTiny component library.
36 |
37 | It is mainly divided into the following steps:
38 |
39 | 1. Replace a component with a component of OpenTiny
40 | 2. Replace all components of a page with components of OpenTiny
41 | 3. Replace all components of the entire application with components of OpenTiny.
42 | 4. Upgrade the project from Vue2 to Vue3
43 |
44 | ## Replace a component with a component of OpenTiny
45 |
46 | Install the `@opentiny/vue@2` component library first.
47 |
48 | ```shell
49 | npm i @ opentiny/vue@2
50 | ```
51 |
52 | Import the OpenTiny Vue component library into the `main.js` file.
53 |
54 | ```ts
55 | import TinyVue from'@ opentiny/vue'
56 |
57 | Vue.use(TinyVue)
58 | ```
59 |
60 | Take the Button component of the table page as an example, replace the `el-button` with `tiny-button` in the `ListPage.vue` file.
61 |
62 | ```html
63 | Search
64 | ->
65 | Search
66 | ```
67 |
68 | The effect is as follows:
69 |
70 | 
71 |
72 | ## Replace all components of a page with components of OpenTiny
73 |
74 | Take the `ListPage` table page as an example, directly change the `el-` component prefix to `tiny-` of the entire template.
75 |
76 | The effect is as follows:
77 |
78 | 
79 |
80 | ## Replace all components of the entire application with those of OpenTiny
81 |
82 | The page involved:
83 |
84 | - HomePage: Carousel
85 | - ListPage: Select / DatePicker / Input / Button / Table
86 | - FormPage: Form / TimePicker / Switch / Checkbox / Radio
87 | - App: Tabs
88 |
89 | The replacement method is the same as the previous one. To replace `el-` with `tiny-`, you should pay attention to:
90 |
91 | - `tabs` component `tab-click -> click`, `el-tab-pane -> tiny-tab-item`
92 | - change `label` of `tab-pane` to `title` of `tab-item`
93 |
94 | The effect is as follows:
95 |
96 | 
97 |
98 | ## Upgrade the project from Vue2 to Vue3
99 |
100 | The steps are as follows:
101 |
102 | Step 1: Install gogocode
103 |
104 | ```shell
105 | npm install gogocode-cli -g
106 | ```
107 |
108 | Step 2: Convert the source code
109 |
110 | ```shell
111 | gogocode -s ./src -t gogocode-plugin-vue -o ./src
112 | ```
113 |
114 | Step 3: Upgrade dependency
115 |
116 | ```shell
117 | gogocode -s package.json -t gogocode-plugin-vue -o package.json
118 | ```
119 |
120 | Step 4: Upgrade the OpenTiny Vue component library to version 3.0
121 |
122 | ```shell
123 | npm i @ opentiny/vue@3
124 | ```
125 |
126 | The component code does not need to be modified, and the Vue2 project is smoothly upgraded to Vue3.
127 |
128 | 
129 |
130 | Congratulations on completing the upgrade!🎉
131 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # element-to-opentiny
2 |
3 | 这是一个基于 ElementUI 组件库的 Vue2 项目,使用了 ElementUI 组件库的以下组件:
4 | 1. Carousel
5 | 2. Select
6 | 3. DatePicker
7 | 4. Input
8 | 5. Button
9 | 6. Table
10 | 7. Tabs
11 | 8. Form
12 | 9. TimePicker
13 | 10. Switch
14 | 11. Checkbox
15 | 12. Radio
16 |
17 | ## 本地启动
18 |
19 | 可以通过在项目根目录执行以下命令进行启动:
20 |
21 | ```shell
22 | pnpm --filter element-to-opentiny dev`
23 | ```
24 |
25 | 或者你也可以在 `packages/element-to-opentiny` 子包项目下面执行以下命令进行启动:
26 |
27 | ```shell
28 | npm run dev
29 | ```
30 |
31 | 启动之后效果如下:
32 |
33 | 
34 |
35 | 现在我们需要将这个项目升级到使用 OpenTiny 组件库的 Vue3 项目。
36 |
37 | 主要分成以下几个步骤:
38 |
39 | 1. 将一个组件替换成 OpenTiny 的组件
40 | 2. 将一个页面的所有组件替换成 OpenTiny 的组件
41 | 3. 将整个应用的所有组件替换成 OpenTiny 的组件
42 | 4. 将项目由 Vue2 升级到 Vue3
43 |
44 | ## 将一个组件替换成 OpenTiny 的组件
45 |
46 | 先安装 `@opentiny/vue@2` 组件库。
47 |
48 | ```shell
49 | npm i @opentiny/vue@2
50 | ```
51 |
52 | 在 `main.js` 文件中引入 OpenTiny Vue 组件库。
53 |
54 | ```ts
55 | import TinyVue from '@opentiny/vue'
56 |
57 | Vue.use(TinyVue)
58 | ```
59 |
60 | 以表格页面的 Button 组件为例,将 `src/components/ListPage.vue` 文件中的 `el-button` 换成 `tiny-button`。
61 |
62 | ```html
63 | 搜索
64 | ->
65 | 搜索
66 | ```
67 |
68 | 效果如下:
69 |
70 | 
71 |
72 | ## 将一个页面的所有组件替换成 OpenTiny 的组件
73 |
74 | 以 `ListPage` 表格页面为例,直接把整个模板的 `el-` 组件前缀改成 `tiny-` 组件前缀即可。
75 |
76 | 效果如下:
77 |
78 | 
79 |
80 | ## 将整个应用的所有组件替换成 OpenTiny 的组件
81 |
82 | 涉及页面:
83 |
84 | - HomePage 首页:Carousel
85 | - ListPage 表格页面:Select、DatePicker、Input、Button、Table
86 | - FormPage 表单页面:Form、TimePicker、Switch、Checkbox、Radio
87 | - App 应用首页:Tabs
88 |
89 | 替换方式和前面的方式一样,将 `el-` 替换成 `tiny-`,需要注意:
90 |
91 | - `tabs` 组件的 `tab-click -> click`,`el-tab-pane -> tiny-tab-item`
92 | - `tab-pane` 的 `label` 改成 `tab-item` 的 `title`
93 |
94 | 效果如下:
95 |
96 | 
97 |
98 | ## 将项目由 Vue2 升级到 Vue3
99 |
100 | 步骤如下:
101 |
102 | 第一步:安装 gogocode
103 |
104 | ```shell
105 | npm install gogocode-cli -g
106 | ```
107 |
108 | 第二步:转换源码
109 |
110 | ```shell
111 | gogocode -s ./src -t gogocode-plugin-vue -o ./src
112 | ```
113 |
114 | 第三步:升级依赖
115 |
116 | ```shell
117 | gogocode -s package.json -t gogocode-plugin-vue -o package.json
118 | ```
119 |
120 | 第四步:升级 OpenTiny Vue 组件库到 3.0 版本
121 |
122 | ```shell
123 | npm i @opentiny/vue@3
124 | ```
125 |
126 | 组件代码无需做任何修改,完成 Vue2 项目平滑升级到 Vue3。
127 |
128 | 
129 |
130 | 恭喜你完成升级!🎉
131 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Vue
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "element-to-opentiny",
3 | "version": "1.0.0",
4 | "scripts": {
5 | "dev": "vite",
6 | "build": "vite build",
7 | "preview": "vite preview"
8 | },
9 | "dependencies": {
10 | "element-ui": "^2.15.13",
11 | "vue": "2.6.14",
12 | "vue-router": "^3.6.5"
13 | },
14 | "devDependencies": {
15 | "vue-template-compiler": "2.6.14",
16 | "vite-plugin-vue2": "^2.0.3",
17 | "vite": "^4.4.8"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/public/assets/all-pages-element-to-opentiny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/element-to-opentiny/public/assets/all-pages-element-to-opentiny.png
--------------------------------------------------------------------------------
/packages/element-to-opentiny/public/assets/el-button-to-tiny-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/element-to-opentiny/public/assets/el-button-to-tiny-button.png
--------------------------------------------------------------------------------
/packages/element-to-opentiny/public/assets/one-page-el-to-tiny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/element-to-opentiny/public/assets/one-page-el-to-tiny.png
--------------------------------------------------------------------------------
/packages/element-to-opentiny/public/assets/vue2-element.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/element-to-opentiny/public/assets/vue2-element.png
--------------------------------------------------------------------------------
/packages/element-to-opentiny/public/assets/vue2-to-vue3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/element-to-opentiny/public/assets/vue2-to-vue3.png
--------------------------------------------------------------------------------
/packages/element-to-opentiny/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/element-to-opentiny/public/favicon.ico
--------------------------------------------------------------------------------
/packages/element-to-opentiny/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
Vue version: {{ version }}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
43 |
44 |
55 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/element-to-opentiny/src/assets/logo.png
--------------------------------------------------------------------------------
/packages/element-to-opentiny/src/components/FormPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | -
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | 立即创建
43 | 取消
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
8 |
9 |
Installed CLI Plugins
10 |
14 |
Essential Links
15 |
22 |
Ecosystem
23 |
30 |
31 |
32 |
33 |
41 |
42 |
43 |
59 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/src/components/HomePage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/src/components/ListPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 |
14 |
19 | 搜索
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
80 |
81 |
90 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import ElementUI from 'element-ui'
3 | import 'element-ui/lib/theme-chalk/index.css'
4 | import App from './App.vue'
5 | import VueRouter from 'vue-router'
6 |
7 | Vue.use(ElementUI)
8 |
9 | const router = new VueRouter({
10 | routes: [
11 | {
12 | path: '/',
13 | redirect: '/home'
14 | },
15 | {
16 | path: '/home',
17 | component: () => import('./components/HomePage.vue')
18 | },
19 | {
20 | path: '/form',
21 | component: () => import('./components/FormPage.vue')
22 | },
23 | {
24 | path: '/list',
25 | component: () => import('./components/ListPage.vue')
26 | }
27 | ]
28 | })
29 |
30 | Vue.config.productionTip = false
31 | Vue.use(VueRouter)
32 |
33 | new Vue({
34 | router,
35 | render: (h) => h(App)
36 | }).$mount('#app')
37 |
--------------------------------------------------------------------------------
/packages/element-to-opentiny/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import { createVuePlugin } from 'vite-plugin-vue2'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [createVuePlugin()],
7 | server: {
8 | port: 2200,
9 | host: 'localhost'
10 | },
11 | define: {
12 | 'process.env': { ...process.env }
13 | }
14 | })
15 |
--------------------------------------------------------------------------------
/packages/home/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-home
2 |
3 | This is a Vue3 framework-based micro front-end (WUOUGH) main-application, which demonstrates the cross-framework capability of OpenTiny.
4 |
5 | ## Local startup
6 |
7 | Start by running the following command:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | Congratulations on the success of the launch!
--------------------------------------------------------------------------------
/packages/home/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-home
2 |
3 | 这是一个基于Vue3框架的微前端(WUJIE)主应用,主要演示OpenTiny的跨框架能力:
4 |
5 | ## 本地启动
6 |
7 | 通过运行以下命令启动:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | 恭喜你启动成功!🎉
14 |
--------------------------------------------------------------------------------
/packages/home/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OpenTiny - App
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/home/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/docs-home",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vite build",
8 | "preview": "vite preview"
9 | },
10 | "dependencies": {
11 | "vue": "^3.2.13",
12 | "vue-router": "^4.0.3",
13 | "wujie-vue3": "^1.0.18"
14 | },
15 | "devDependencies": {
16 | "@vitejs/plugin-vue": "^4.2.3",
17 | "@vitejs/plugin-vue-jsx": "^3.0.1",
18 | "vite": "^4.4.8"
19 | },
20 | "author": "",
21 | "license": "ISC"
22 | }
23 |
--------------------------------------------------------------------------------
/packages/home/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/home/public/favicon.ico
--------------------------------------------------------------------------------
/packages/home/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Home
6 |
7 | Solid
8 |
9 | React
10 |
11 | Vue2
12 |
13 | Vue3
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
50 |
51 |
150 |
--------------------------------------------------------------------------------
/packages/home/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/home/src/assets/logo.png
--------------------------------------------------------------------------------
/packages/home/src/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | font-size: 17.5px;
4 | padding: 0px;
5 | width: auto;
6 | height: 100%;
7 | position: relative;
8 | }
9 | #app {
10 | font-family: Avenir, Helvetica, Arial, sans-serif;
11 | -webkit-font-smoothing: antialiased;
12 | -moz-osx-font-smoothing: grayscale;
13 | overflow: auto;
14 | color: #2c3e50;
15 | --el-color-primary: #0239d0;
16 | }
17 |
18 | #nav {
19 | padding: 30px;
20 | text-align: center;
21 | font-size: 20px;
22 | line-height: 1;
23 | }
24 |
25 | .content {
26 | margin: 0 auto;
27 | }
28 | .content > p {
29 | margin: 30px 0;
30 | }
31 |
32 | h3 {
33 | padding-bottom: 0.3rem;
34 | border-bottom: 1px solid #eaecef;
35 | font-weight: 600;
36 | }
37 |
38 | #nav a {
39 | font-weight: bold;
40 | color: #2c3e50;
41 | }
42 |
43 | #nav a.router-link-exact-active {
44 | color: #0239d0;
45 | }
46 |
--------------------------------------------------------------------------------
/packages/home/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import WujieVue from 'wujie-vue3'
3 | import App from './App.vue'
4 | import router from './router'
5 | import './index.css'
6 |
7 | const app = createApp(App)
8 |
9 | app.use(WujieVue).use(router).mount('#app')
10 |
--------------------------------------------------------------------------------
/packages/home/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router'
2 | import Home from '../views/Home.vue'
3 | import React from '../views/React.vue'
4 | import Solid from '../views/Solid.vue'
5 | import Vue2 from '../views/Vue2.vue'
6 | import Vue3 from '../views/Vue3.vue'
7 | const basename = process.env.NODE_ENV === 'production' ? '/demo-main-vue/' : ''
8 |
9 | const routes = [
10 | {
11 | path: '/home',
12 | name: 'home',
13 | component: Home
14 | },
15 | {
16 | path: '/',
17 | redirect: '/home'
18 | },
19 | {
20 | path: '/react',
21 | name: 'react',
22 | component: React
23 | },
24 | {
25 | path: '/solid',
26 | name: 'solid',
27 | component: Solid
28 | },
29 | {
30 | path: '/vue2',
31 | name: 'vue2',
32 | component: Vue2
33 | },
34 | {
35 | path: '/vue3',
36 | name: 'vue3',
37 | component: Vue3
38 | }
39 | ]
40 |
41 | const router = createRouter({
42 | history: createWebHashHistory(),
43 | base: basename,
44 | routes
45 | })
46 |
47 | export default router
48 |
--------------------------------------------------------------------------------
/packages/home/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
42 |
43 |
69 |
--------------------------------------------------------------------------------
/packages/home/src/views/React.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
20 |
--------------------------------------------------------------------------------
/packages/home/src/views/Solid.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/packages/home/src/views/Vue2.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/packages/home/src/views/Vue3.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/packages/home/vite.config.js:
--------------------------------------------------------------------------------
1 | import vue from '@vitejs/plugin-vue'
2 |
3 | export default {
4 | resolve: {
5 | extensions: ['.js', '.jsx', '.vue']
6 | },
7 | server: {
8 | port: 5173,
9 | host: 'localhost',
10 | open: true
11 | },
12 | plugins: [vue()],
13 | define: {
14 | 'process.env': Object.assign({}, process.env)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/react/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-react
2 |
3 | This is a React framework-based micro front-end (WUOUGH) sub-application, which demonstrates the cross-framework capability of OpenTiny.
4 |
5 | ## Local startup
6 |
7 | Start by running the following command:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | Congratulations on the success of the launch!
--------------------------------------------------------------------------------
/packages/react/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-react
2 |
3 | 这是一个基于React框架的微前端(WUJIE)子应用,主要演示OpenTiny的跨框架能力:
4 |
5 | ## 本地启动
6 |
7 | 通过运行以下命令启动:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | 恭喜你启动成功!🎉
14 |
--------------------------------------------------------------------------------
/packages/react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OpenTiny - React
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/docs-react",
3 | "private": true,
4 | "version": "1.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@opentiny/react": "workspace:~",
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0",
15 | "@opentiny/react-common": "workspace:~"
16 | },
17 | "devDependencies": {
18 | "@vitejs/plugin-react": "^4.0.1",
19 | "eslint": "^8.44.0",
20 | "eslint-plugin-react-hooks": "^4.6.0",
21 | "vite": "^4.4.0",
22 | "vite-plugin-react": "^4.0.1",
23 | "vite-plugin-svgr": "^3.2.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/react/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/react/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { Button, Countdown } from '@opentiny/react'
2 | import './style.css'
3 |
4 | const operation = {
5 | start: () => { },
6 | reset: () => { }
7 | }
8 |
9 | const operate = ({ start, reset }) => {
10 | operation.start = start
11 | operation.reset = reset
12 | }
13 |
14 | function App() {
15 | return (
16 | <>
17 |
18 |
React
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | >
28 | )
29 | }
30 |
31 | export default App
32 |
--------------------------------------------------------------------------------
/packages/react/src/main.jsx:
--------------------------------------------------------------------------------
1 | // import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 |
5 | ReactDOM.createRoot(document.getElementById('root')).render()
6 |
--------------------------------------------------------------------------------
/packages/react/src/style.css:
--------------------------------------------------------------------------------
1 | html,body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | .demo-box {
6 | position: relative;
7 | overflow: hidden;
8 | }
9 |
10 | .demo-titile {
11 | width: 80px;
12 | line-height: 36px;
13 | font-size: 24px;
14 | margin: 0;
15 | padding: 0 5px;
16 | background: #999;
17 | text-align: center;
18 | color: #fefefe;
19 | position: absolute;
20 | left: 0;
21 | top: 0;
22 | }
23 |
24 | .demo-container {
25 | margin-top: 40px;
26 | }
27 |
28 | .tiny-countdown {
29 | font-size: 50px;
30 | text-align: center;
31 | }
32 | .btn-box {
33 | text-align: center;
34 | margin-top: 20px;
35 | }
36 |
37 | .tiny-countdown__container {
38 | --ti-countdown-font-color:#19caad;
39 | }
--------------------------------------------------------------------------------
/packages/react/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 | import svgr from 'vite-plugin-svgr'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react(), svgr()],
8 | server: {
9 | port: 2001,
10 | host: 'localhost'
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/packages/solid/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-solid
2 |
3 | This is a Solid framework-based micro front-end (WUOUGH) sub-application, which demonstrates the cross-framework capability of OpenTiny.
4 |
5 | ## Local startup
6 |
7 | Start by running the following command:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | Congratulations on the success of the launch!
--------------------------------------------------------------------------------
/packages/solid/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-solid
2 |
3 | 这是一个基于Solid框架的微前端(WUJIE)子应用,主要演示OpenTiny的跨框架能力:
4 |
5 | ## 本地启动
6 |
7 | 通过运行以下命令启动:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | 恭喜你启动成功!🎉
14 |
--------------------------------------------------------------------------------
/packages/solid/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OpenTiny - Solid
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/solid/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/docs-solid",
3 | "private": true,
4 | "version": "1.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "solid-js": "^1.7.8",
13 | "@opentiny/solid": "workspace:~"
14 | },
15 | "devDependencies": {
16 | "vite": "^4.4.5",
17 | "vite-plugin-solid": "^2.7.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/solid/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/solid/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { createSignal } from 'solid-js'
2 | import { Button, Countdown } from '@opentiny/solid'
3 |
4 | const operation = {
5 | start: () => { },
6 | reset: () => { },
7 | stop: () => { }
8 | }
9 |
10 | const operate = ({ start, reset }) => {
11 | operation.start = start
12 | operation.reset = reset
13 | }
14 | function App() {
15 |
16 | return (
17 | <>
18 |
19 |
Solid
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | >
30 | )
31 | }
32 |
33 | export default App
34 |
--------------------------------------------------------------------------------
/packages/solid/src/assets/solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/solid/src/index.jsx:
--------------------------------------------------------------------------------
1 | /* @refresh reload */
2 | import { render } from 'solid-js/web'
3 | import App from './App'
4 | import './style.css'
5 |
6 | const root = document.getElementById('root')
7 |
8 | render(() => , root)
9 |
--------------------------------------------------------------------------------
/packages/solid/src/style.css:
--------------------------------------------------------------------------------
1 | html,body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | .demo-box {
6 | position: relative;
7 | overflow: hidden;
8 | }
9 |
10 | .demo-titile {
11 | width: 80px;
12 | line-height: 36px;
13 | font-size: 24px;
14 | margin: 0;
15 | padding: 0 5px;
16 | background: #999;
17 | text-align: center;
18 | color: #fefefe;
19 | position: absolute;
20 | left: 0;
21 | top: 0;
22 | }
23 |
24 | .demo-container {
25 | margin-top: 40px;
26 | }
27 |
28 | .tiny-countdown {
29 | font-size: 50px;
30 | text-align: center;
31 | }
32 | .btn-box {
33 | text-align: center;
34 | margin-top: 20px;
35 | }
--------------------------------------------------------------------------------
/packages/solid/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import solid from 'vite-plugin-solid'
3 |
4 | export default defineConfig({
5 | plugins: [solid()],
6 | server: {
7 | port: 2002,
8 | host: 'localhost'
9 | }
10 | })
11 |
--------------------------------------------------------------------------------
/packages/vue2/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-vue2
2 |
3 | This is a Vue2 framework-based micro front-end (WUOUGH) sub-application, which demonstrates the cross-framework capability of OpenTiny.
4 |
5 | ## Local startup
6 |
7 | Start by running the following command:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | Congratulations on the success of the launch!
--------------------------------------------------------------------------------
/packages/vue2/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-vue2
2 |
3 | 这是一个基于Vue2框架的微前端(WUJIE)子应用,主要演示OpenTiny的跨框架能力:
4 |
5 | ## 本地启动
6 |
7 | 通过运行以下命令启动:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | 恭喜你启动成功!🎉
14 |
--------------------------------------------------------------------------------
/packages/vue2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OpenTiny - Vue2
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/vue2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/docs-vue2",
3 | "version": "1.0.0",
4 | "scripts": {
5 | "dev": "vite",
6 | "build": "vite build",
7 | "preview": "vite preview"
8 | },
9 | "dependencies": {
10 | "@opentiny/vue-button": "workspace:~",
11 | "@opentiny/vue-locale": "~2.9.0",
12 | "@opentiny/vue-countdown": "workspace:~",
13 | "vue": "2.6.14"
14 | },
15 | "devDependencies": {
16 | "vue-template-compiler": "2.6.14",
17 | "vite-plugin-vue2": "^2.0.3",
18 | "vite": "^4.4.8"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/vue2/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/vue2/public/favicon.ico
--------------------------------------------------------------------------------
/packages/vue2/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages/vue2/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Vue2
4 |
5 |
6 |
7 |
8 |
9 | Reset
10 | Start
11 |
12 |
13 |
14 |
15 |
16 |
17 |
48 |
90 |
--------------------------------------------------------------------------------
/packages/vue2/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentiny/cross-framework-component/00134876078a926367acff82536a74f3a72c1dcd/packages/vue2/src/assets/logo.png
--------------------------------------------------------------------------------
/packages/vue2/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 |
4 | Vue.config.productionTip = false
5 |
6 | new Vue({
7 | render: (h) => h(App)
8 | }).$mount('#app')
9 |
--------------------------------------------------------------------------------
/packages/vue2/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import { createVuePlugin } from 'vite-plugin-vue2'
3 | import path from 'node:path'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [createVuePlugin()],
8 | server: {
9 | port: 2003,
10 | host: 'localhost'
11 | },
12 | resolve: {
13 | alias: {
14 | 'virtual:common/adapter/vue': path.resolve(
15 | __dirname,
16 | `../components/vue/common/src/adapter/vue2/index`
17 | )
18 | }
19 | },
20 | define: {
21 | 'process.env': { ...process.env }
22 | }
23 | })
24 |
--------------------------------------------------------------------------------
/packages/vue3/README.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-vue3
2 |
3 | This is a micro-frontend application based on the Vue3 framework. It mainly demonstrates the cross-end capability of OpenTiny.
4 |
5 | ## Local startup
6 |
7 | Start by running the following command:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | Congratulations on the success of the launch!
--------------------------------------------------------------------------------
/packages/vue3/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # @opentiny/docs-vue3
2 |
3 | 这是一个基于Vue3框架的微前端(WUJIE)子应用,主要演示OpenTiny的跨端能力:
4 |
5 | ## 本地启动
6 |
7 | 通过运行以下命令启动:
8 |
9 | ```shell
10 | pnpm dev
11 | ```
12 |
13 | 恭喜你启动成功!🎉
14 |
--------------------------------------------------------------------------------
/packages/vue3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OpenTiny - Vue3
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/vue3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@opentiny/docs-vue3",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vite build",
8 | "preview": "vite preview"
9 | },
10 | "dependencies": {
11 | "@opentiny/vue-button": "workspace:~",
12 | "@opentiny/vue-config-provider": "workspace:~",
13 | "@opentiny/vue-icon": "~3.9.0",
14 | "@opentiny/vue-modal": "~3.9.0",
15 | "@opentiny/vue-checkbox": "~3.9.0",
16 | "@opentiny/vue-checkbox-group": "~3.9.0",
17 | "@opentiny/vue-countdown": "workspace:~",
18 | "@opentiny/vue-zzc-theme": "~0.0.1",
19 | "vue": "^3.2.41"
20 | },
21 | "devDependencies": {
22 | "@vitejs/plugin-vue": "^4.2.3",
23 | "vite": "^4.4.8"
24 | }
25 | }
--------------------------------------------------------------------------------
/packages/vue3/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/vue3/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
50 |
51 |
135 |
--------------------------------------------------------------------------------
/packages/vue3/src/DemoPoc.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Vue3
4 |
5 |
6 |
PC
7 |
8 |
12 |
13 |
14 |
15 | Reset
16 | Start
17 |
18 |
19 |
20 |
21 |
Mobile
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 | Reset
35 | Start
38 |
39 |
40 |
41 |
42 |
43 |
44 |
Watch
45 |
46 |
47 |
48 |
49 |
53 |
54 |
55 |
56 |
62 |
63 |
64 |
70 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
143 |
--------------------------------------------------------------------------------
/packages/vue3/src/assets/vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/vue3/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import './style.css'
3 | import App from './App.vue'
4 | import '@opentiny/vue-zzc-theme/index.css'
5 |
6 | createApp(App).mount('#app')
7 |
--------------------------------------------------------------------------------
/packages/vue3/src/views/mobile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Mobile
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 | Reset
17 | Start
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
45 |
--------------------------------------------------------------------------------
/packages/vue3/src/views/pc.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
PC
4 |
5 |
6 |
7 |
8 |
9 | Reset
10 | Start
11 |
12 |
13 |
14 |
15 |
16 |
34 |
--------------------------------------------------------------------------------
/packages/vue3/src/views/watch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Watch
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
21 |
22 |
23 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
70 |
--------------------------------------------------------------------------------
/packages/vue3/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 | import path from 'node:path'
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [vue()],
8 | server: {
9 | port: 2004,
10 | host: 'localhost',
11 | https: false,
12 | proxy: {
13 | '/api': {
14 | target: '*',
15 | changeOrigin: true
16 | }
17 | }
18 | },
19 | resolve: {
20 | alias: {
21 | 'virtual:common/adapter/vue': path.resolve(
22 | __dirname,
23 | `../components/vue/common/src/adapter/vue3/index`
24 | )
25 | }
26 | },
27 | define: {
28 | 'process.env': { ...process.env }
29 | }
30 | })
31 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - packages/**
3 |
--------------------------------------------------------------------------------
/setup.js:
--------------------------------------------------------------------------------
1 | const { exec } = require('child_process')
2 |
3 | exec('npm run dev:vue3', __dirname)
4 | exec('npm run dev:react', __dirname)
5 | exec('npm run dev:solid', __dirname)
6 | exec('npm run dev:vue2', __dirname)
7 | exec('npm run dev:home', __dirname)
8 |
9 | console.log('home', 'http://localhost:5173/')
10 | console.log('react', 'http://localhost:2001/')
11 | console.log('solid', 'http://localhost:2002/')
12 | console.log('vue2', 'http://localhost:2003/')
13 | console.log('vue3', 'http://localhost:2004/')
14 |
--------------------------------------------------------------------------------