forked from opentiny/tiny-vue
* feat:同步代码 * chore: 优化本地 svg 加载 Co-authored-by: however <102494131+river-xiu@users.noreply.github.com>
This commit is contained in:
parent
196ab84bee
commit
f7ca5794d3
|
@ -0,0 +1,13 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Opentiny Solid 组件调试</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "@opentiny/docs-solid",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"solid-js": "^1.7.8",
|
||||
"@opensolidtiny/solid": "~3.14.0",
|
||||
"@opensolidtiny/solid-icon": "~3.14.0",
|
||||
"@opensolidtiny/solid-common": "~3.14.0",
|
||||
"@opentiny/vue-theme": "~3.14.0",
|
||||
"@opentiny/vue-renderless": "~3.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^4.4.5",
|
||||
"vite-plugin-solid": "^2.7.0",
|
||||
"vite-plugin-inspect": "^0.7.10"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,35 @@
|
|||
import { createMutable } from 'solid-js/store'
|
||||
import { Button, Alert } from '@opensolidtiny/solid'
|
||||
import { IconActivation } from '@opensolidtiny/solid-icon'
|
||||
|
||||
// 在这里导入组件,进行 api 调试
|
||||
function App() {
|
||||
const state = createMutable({
|
||||
value: 1
|
||||
})
|
||||
const hanleClick = () => {
|
||||
state.value++
|
||||
}
|
||||
|
||||
const alertSlots = {
|
||||
title: <span>插槽标题</span>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<h1>{state.value}</h1>
|
||||
<Button onClick={hanleClick}>点击按钮</Button>
|
||||
<Button type="primary">点击按钮</Button>
|
||||
<Button type="success">点击按 钮</Button>
|
||||
<Button type="danger">点击按钮</Button>
|
||||
<Button type="danger" text={'Text'}></Button>
|
||||
<Alert description="type 为默认值 info"></Alert>
|
||||
<Alert type="warning" description="type 为默认值 info" size="large" slots={alertSlots}></Alert>
|
||||
<br />
|
||||
<br />
|
||||
<IconActivation style={{ width: '48px', height: '48px' }}></IconActivation>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
|
@ -0,0 +1,4 @@
|
|||
.app {
|
||||
margin: 10px;
|
||||
width: 500px;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { render } from 'solid-js/web'
|
||||
import App from './App'
|
||||
import './main.css'
|
||||
|
||||
const root = document.getElementById('root')
|
||||
|
||||
render(() => <App />, root)
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import solid from 'vite-plugin-solid'
|
||||
import inspectPlugin from 'vite-plugin-inspect'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [inspectPlugin(), solid()],
|
||||
define: {
|
||||
'process.env': {}
|
||||
}
|
||||
})
|
|
@ -10,11 +10,20 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"solid-js": "^1.7.8",
|
||||
"@opentiny/solid": "workspace:~"
|
||||
"@opentiny/solid": "workspace:~",
|
||||
"@opentiny/solid-common": "workspace:~",
|
||||
"@opentiny/vue-button": "workspace:~",
|
||||
"@opentiny/vue-alert": "workspace:~",
|
||||
"@opentiny/vue-badge": "workspace:~",
|
||||
"@opentiny/vue-icon": "workspace:~",
|
||||
"@opentiny/vue-switch": "workspace:~",
|
||||
"@opentiny/vue-theme": "workspace:~"
|
||||
},
|
||||
"devDependencies": {
|
||||
"fs-extra": "^11.2.0",
|
||||
"vite": "^4.4.5",
|
||||
"vite-plugin-solid": "^2.7.0",
|
||||
"vite-plugin-svgr": "^3.2.0"
|
||||
"vite-plugin-inspect": "^0.7.10",
|
||||
"@opentiny/vue-vite-template2jsx": "workspace:~"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,54 @@
|
|||
import { Button } from '@opentiny/solid'
|
||||
import { createMutable } from 'solid-js/store'
|
||||
import Button from './views/button'
|
||||
import Alert from './views/alert'
|
||||
import Icon from './views/icon'
|
||||
import Switch from './views/switch'
|
||||
import { Dynamic } from 'solid-js/web'
|
||||
import './main.less'
|
||||
|
||||
// 在这里导入组件,进行 api 调试
|
||||
function App() {
|
||||
const allViews = {
|
||||
Button,
|
||||
Alert,
|
||||
Icon,
|
||||
Switch
|
||||
}
|
||||
const state = createMutable({
|
||||
value: null,
|
||||
active: '',
|
||||
menus: ['Button', 'Alert', 'Icon', 'Switch']
|
||||
})
|
||||
|
||||
const getViewComponent = (name: string) => {
|
||||
return allViews[name] || Button
|
||||
}
|
||||
|
||||
const hashchange = () => {
|
||||
state.active = window.location.hash.replace('#/', '') || 'Button'
|
||||
state.value = getViewComponent(state.active)
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', hashchange)
|
||||
|
||||
hashchange()
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<Button>点击按钮</Button>
|
||||
<div class="app">
|
||||
<p>
|
||||
<For each={state.menus}>
|
||||
{(item) => (
|
||||
<>
|
||||
<a classList={{ 'title': true, 'active': state.active === item }} href={`#/${item}`}>
|
||||
{item}
|
||||
</a>
|
||||
<span>/</span>
|
||||
</>
|
||||
)}
|
||||
</For>
|
||||
</p>
|
||||
<br />
|
||||
<Dynamic component={state.value} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
.app {
|
||||
margin: 40px auto;
|
||||
width: 640px;
|
||||
|
||||
a.title {
|
||||
color: #39f;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin:0 10px;
|
||||
text-decoration: none;
|
||||
|
||||
&.active {
|
||||
font-weight: 600;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
import { render } from 'solid-js/web'
|
||||
import App from './App'
|
||||
import './main.css'
|
||||
|
||||
const root = document.getElementById('root')
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import TinyAlert from '@opentiny/vue-alert'
|
||||
|
||||
export default function () {
|
||||
const alertSlots = {
|
||||
title: <span>插槽标题</span>
|
||||
}
|
||||
|
||||
const alertSlots2 = {
|
||||
description: (
|
||||
<span>
|
||||
<p style="color:red;">插槽描述</p>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const alertSlots3 = {
|
||||
close: <span>插槽关闭</span>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="alert">
|
||||
<TinyAlert description="type 为默认值 info"></TinyAlert>
|
||||
<TinyAlert size="large" title="slot 自定义内容">
|
||||
<span>自定义内容</span>
|
||||
</TinyAlert>
|
||||
<br />
|
||||
<TinyAlert size="large" title="slot 自定义交互操作">
|
||||
<a href="javascript: void(0);">确定</a>
|
||||
<a href="javascript: void(0);">取消</a>
|
||||
</TinyAlert>
|
||||
<br />
|
||||
<TinyAlert type="success" title="成功" size="large" description="提交结果页用于反馈一系列操作任务的处理结果。">
|
||||
<a href="javascript: void(0);">继续提交</a>
|
||||
<a href="javascript: void(0);">取消操作</a>
|
||||
</TinyAlert>
|
||||
<br />
|
||||
<TinyAlert
|
||||
type="error"
|
||||
title="错误"
|
||||
size="large"
|
||||
description="提交结果页用于反馈一系列操作任务的处理结果。"></TinyAlert>
|
||||
<br />
|
||||
<TinyAlert type="warning" title="警告" size="large" description="提交结果页用于反馈一系列操作任务的处理结果。">
|
||||
<a href="javascript: void(0);">继续提交</a>
|
||||
<a href="javascript: void(0);">取消操作</a>
|
||||
</TinyAlert>
|
||||
<br />
|
||||
<TinyAlert type="warning" description="type 为默认值 info" size="large" slots={alertSlots}></TinyAlert>
|
||||
<br />
|
||||
<TinyAlert type="warning" title="警告" size="large" slots={alertSlots2}></TinyAlert>
|
||||
<br />
|
||||
<TinyAlert
|
||||
type="error"
|
||||
title="错误"
|
||||
size="large"
|
||||
description="关闭按钮自定义文本"
|
||||
closable={false}
|
||||
slots={alertSlots3}></TinyAlert>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import { createMutable } from 'solid-js/store'
|
||||
import TinyButton from '@opentiny/vue-button'
|
||||
import TinyIconSearch from '@opentiny/vue-icon/search/index.ts'
|
||||
|
||||
export default function () {
|
||||
const state = createMutable({
|
||||
value: 1
|
||||
})
|
||||
const hanleClick = () => {
|
||||
state.value++
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="button">
|
||||
<TinyButton>默认按钮</TinyButton>
|
||||
<TinyButton type="primary">主要按钮</TinyButton>
|
||||
<TinyButton type="success">成功按钮</TinyButton>
|
||||
<br />
|
||||
<br />
|
||||
<TinyButton type="info">信息按钮</TinyButton>
|
||||
<TinyButton type="warning">警告按钮</TinyButton>
|
||||
<TinyButton type="danger">危险按钮 </TinyButton>
|
||||
<br />
|
||||
<br />
|
||||
<TinyButton plain> 朴素按钮 </TinyButton>
|
||||
<TinyButton type="danger" text={'自定义 Text'}></TinyButton>
|
||||
<TinyButton type="primary" loading>
|
||||
加载中
|
||||
</TinyButton>
|
||||
<br />
|
||||
<br />
|
||||
<TinyButton icon={TinyIconSearch}></TinyButton>
|
||||
<TinyButton type="danger" icon={TinyIconSearch} circle></TinyButton>
|
||||
<TinyButton type="text">纯文本按钮</TinyButton>
|
||||
<br />
|
||||
<br />
|
||||
<TinyButton type="primary" size="large" plain>
|
||||
{' '}
|
||||
超大按钮{' '}
|
||||
</TinyButton>
|
||||
<TinyButton type="primary" size="medium" plain>
|
||||
{' '}
|
||||
中等按钮{' '}
|
||||
</TinyButton>
|
||||
<TinyButton type="primary" size="small" plain>
|
||||
{' '}
|
||||
小型按钮{' '}
|
||||
</TinyButton>
|
||||
<TinyButton type="primary" size="mini" plain>
|
||||
{' '}
|
||||
超小按钮{' '}
|
||||
</TinyButton>
|
||||
<br />
|
||||
<br />
|
||||
<TinyButton onClick={hanleClick}>点击事件</TinyButton> 点击计数:{state.value}
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
.icon-demo .tiny-svg {
|
||||
fill: #8994aa;
|
||||
margin: 20px 50px;
|
||||
vertical-align: middle;
|
||||
font-size: 48px;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import TinyIconActivation from '@opentiny/vue-icon/activation/index.ts'
|
||||
import TinyIconShare from '@opentiny/vue-icon/share/index.ts'
|
||||
import TinyIconDel from '@opentiny/vue-icon/del/index.ts'
|
||||
import TinyIconWriting from '@opentiny/vue-icon/writing/index.ts'
|
||||
import TinyIconAscending from '@opentiny/vue-icon/ascending/index.ts'
|
||||
import TinyIconClockWork from '@opentiny/vue-icon/clock-work/index.ts'
|
||||
import './icon.less'
|
||||
|
||||
export default function () {
|
||||
return (
|
||||
<div className="icon-demo">
|
||||
<TinyIconActivation></TinyIconActivation>
|
||||
<TinyIconShare></TinyIconShare>
|
||||
<TinyIconDel></TinyIconDel>
|
||||
<TinyIconWriting></TinyIconWriting>
|
||||
<TinyIconAscending></TinyIconAscending>
|
||||
<TinyIconClockWork></TinyIconClockWork>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import TinySwitch from '@opentiny/vue-switch'
|
||||
import { createMutable } from 'solid-js/store'
|
||||
|
||||
export default function () {
|
||||
const state = createMutable({
|
||||
value: true
|
||||
})
|
||||
|
||||
const switchSlots = {
|
||||
open: <span>打开</span>,
|
||||
close: <span>关闭</span>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="switch">
|
||||
<TinySwitch></TinySwitch>
|
||||
<br />
|
||||
<br />
|
||||
<TinySwitch modelValue={state.value}></TinySwitch>
|
||||
<br />
|
||||
<br />
|
||||
<TinySwitch modelValue={state.value} slots={switchSlots}></TinySwitch>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,7 +1,18 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import solid from 'vite-plugin-solid'
|
||||
import svgr from 'vite-plugin-svgr'
|
||||
import path from 'node:path'
|
||||
import inspectPlugin from 'vite-plugin-inspect'
|
||||
import vueTemplate2jsx from '@opentiny/vue-vite-template2jsx'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solid(), svgr()]
|
||||
plugins: [inspectPlugin(), vueTemplate2jsx(), solid({ extensions: ['.js', '.ts', '.tsx', '.jsx', '.vue'] })],
|
||||
define: {
|
||||
'process.env': {}
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve('./src'),
|
||||
'@opentiny/solid-common': path.resolve('../../packages/solid/src/common/src/index.ts')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
import { getBabelOutputPlugin } from '@rollup/plugin-babel'
|
||||
import { createRequire } from 'node:module'
|
||||
import path from 'node:path'
|
||||
import { build, defineConfig } from 'vite'
|
||||
import { getAlias, pathFromWorkspaceRoot } from '../../config/vite'
|
||||
import { external } from '../../shared/config'
|
||||
import type { Module } from '../../shared/module-utils'
|
||||
import { getAllIcons, getAllModules, getByName } from '../../shared/module-utils'
|
||||
import { logGreen, kebabCase, capitalizeKebabCase, getPatchVersion, isValidVersion } from '../../shared/utils'
|
||||
import generatePackageJsonPlugin from './rollup/generate-package-json'
|
||||
import inlineChunksPlugin from './rollup/inline-chunks'
|
||||
import replaceModuleNamePlugin from './rollup/replace-module-name'
|
||||
import solid from 'vite-plugin-solid'
|
||||
import vueTemplate2jsx from '@opentiny/vue-vite-template2jsx'
|
||||
|
||||
export const pathFromPackages = (...args) => pathFromWorkspaceRoot('packages', ...args)
|
||||
export const require = createRequire(import.meta.url)
|
||||
export const requireModules = (id: string) => require(require.resolve(pathFromWorkspaceRoot(id)))
|
||||
|
||||
// 需要打包的solid组件
|
||||
const buildComponents = ['alert', 'button']
|
||||
|
||||
export interface BaseConfig {
|
||||
buildTarget: string
|
||||
npmScope?: string
|
||||
}
|
||||
|
||||
export const getBaseConfig = ({ buildTarget }: BaseConfig) => {
|
||||
const versionTarget = isValidVersion(buildTarget) ? buildTarget : `3.${buildTarget}`
|
||||
const themeAndRenderlessVersion = isValidVersion(buildTarget) ? buildTarget : `3.${buildTarget}`
|
||||
const isThemeOrRenderless = (key) => key.includes('@opentiny/vue-theme') || key.includes('@opentiny/vue-renderless')
|
||||
|
||||
return defineConfig({
|
||||
publicDir: false,
|
||||
plugins: [
|
||||
inlineChunksPlugin({ deleteInlinedFiles: true }),
|
||||
generatePackageJsonPlugin({
|
||||
beforeWriteFile: (filePath, content) => {
|
||||
const dependencies = {}
|
||||
|
||||
Object.entries(content.dependencies).forEach(([key, value]) => {
|
||||
// dependencies里的@opentiny,统一使用:~x.x.0
|
||||
if (isThemeOrRenderless(key)) {
|
||||
dependencies[key] = getPatchVersion(themeAndRenderlessVersion)
|
||||
} else if ((value as string).includes('workspace:~')) {
|
||||
dependencies[
|
||||
key.replace('@opentiny/vue', '@opensolidtiny/solid').replace('@opentiny/solid', '@opensolidtiny/solid')
|
||||
] = getPatchVersion(versionTarget)
|
||||
} else {
|
||||
dependencies[key] = value
|
||||
}
|
||||
})
|
||||
|
||||
const matchList = ['solid-icon', 'vue-icon-saas', 'solid']
|
||||
|
||||
// 如果是主入口、svg图标或者主题规范包则直接指向相同路径
|
||||
if (matchList.includes(filePath)) {
|
||||
content.main = './index.js'
|
||||
content.module = './index.js'
|
||||
} else {
|
||||
content.main = './lib/index.js'
|
||||
content.module = './lib/index.js'
|
||||
}
|
||||
|
||||
content.name = content.name
|
||||
.replace('@opentiny/vue', '@opensolidtiny/solid')
|
||||
.replace('@opentiny/solid', '@opensolidtiny/solid')
|
||||
content.version = versionTarget
|
||||
content.dependencies = dependencies
|
||||
|
||||
delete content.devDependencies
|
||||
delete content.private
|
||||
delete content.exports
|
||||
|
||||
return {
|
||||
filePath: filePath.replace(/[\\/]lib$/, ''),
|
||||
content
|
||||
}
|
||||
}
|
||||
}),
|
||||
replaceModuleNamePlugin(versionTarget),
|
||||
vueTemplate2jsx(),
|
||||
solid({ extensions: ['.js', '.ts', '.tsx', '.jsx', '.vue'] })
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.js', '.ts', '.tsx', '.vue'],
|
||||
alias: {
|
||||
...getAlias(3, '', '')
|
||||
}
|
||||
},
|
||||
define: {
|
||||
'process.env.BUILD_TARGET': JSON.stringify('component')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function batchBuildAll({ tasks, formats, message, emptyOutDir, buildTarget, npmScope }) {
|
||||
const rootDir = pathFromPackages('')
|
||||
const outDir = path.resolve(rootDir, `dist-solid/${npmScope}`)
|
||||
await batchBuild({
|
||||
tasks,
|
||||
formats,
|
||||
message,
|
||||
emptyOutDir
|
||||
})
|
||||
|
||||
function toEntry(libs) {
|
||||
return libs.reduce((result, { libPath, path: file }) => {
|
||||
const tLibPath = libPath.replace('-lib/', '/lib/')
|
||||
result[tLibPath] = pathFromPackages(file)
|
||||
return result
|
||||
}, {})
|
||||
}
|
||||
|
||||
async function batchBuild({ tasks, formats, message, emptyOutDir }) {
|
||||
if (tasks.length === 0) return
|
||||
logGreen(`====== 开始构建 ${message} ======`)
|
||||
const entry = toEntry(tasks)
|
||||
|
||||
await build({
|
||||
configFile: false,
|
||||
...getBaseConfig({ buildTarget }),
|
||||
build: {
|
||||
emptyOutDir,
|
||||
minify: false,
|
||||
rollupOptions: {
|
||||
plugins: [
|
||||
getBabelOutputPlugin({
|
||||
presets: [['@babel/preset-env', { loose: true, modules: false }]]
|
||||
}) as any
|
||||
],
|
||||
external: (source, importer, isResolved) => {
|
||||
// vite打包入口文件或者没有解析过得包不能排除依赖
|
||||
if (isResolved || !importer) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (/vue-icon(-saas)?\/index/.test(importer)) {
|
||||
// 图标入口排除子图标
|
||||
return /^\.\//.test(source)
|
||||
}
|
||||
|
||||
// 子图标排除周边引用, 这里注意不要排除svg图标
|
||||
if (/vue-icon(-saas)?\/.+\/index/.test(importer)) {
|
||||
return !/\.svg/.test(source)
|
||||
}
|
||||
|
||||
if (/src\/index/.test(importer)) {
|
||||
// 模块入口,pc/mobile 文件要分离,同时排除 node_modules 依赖
|
||||
return /^\.\/(pc|mobile|mobile-first)/.test(source) || external(source)
|
||||
}
|
||||
|
||||
// @opentiny/vue 总入口,需要排除所有依赖
|
||||
if (/vue\/(index|pc|mobile|mobile-first)\.ts$/.test(importer)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return external(source)
|
||||
},
|
||||
output: {
|
||||
strict: false,
|
||||
manualChunks: {}
|
||||
}
|
||||
},
|
||||
lib: {
|
||||
// 这里可以多入口打包,也可以单入口打包
|
||||
entry,
|
||||
formats,
|
||||
fileName: (format, entryName) => `${entryName}.js`
|
||||
},
|
||||
outDir
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export interface BuildUiOption {
|
||||
buildTarget: string // 目标版本,必填, 不需要major位,因为需要同时打出vue2和vue3的包
|
||||
formats: string[] // 打包的格式
|
||||
clean: boolean // 是否清空build产物
|
||||
scope?: string // npm的组织名称
|
||||
min?: boolean // 是否压缩产物
|
||||
}
|
||||
|
||||
function getEntryTasks(): Module[] {
|
||||
// 读取TinyVue组件库入口文件
|
||||
return [
|
||||
{
|
||||
path: `solid/index.ts`,
|
||||
libPath: `solid/index`,
|
||||
type: 'module',
|
||||
name: kebabCase({ str: '@opensolidtiny/solid' }),
|
||||
global: capitalizeKebabCase('opentinySolid'),
|
||||
importName: '@opensolidtiny/solid'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function getSolidCommonTasks(): Module[] {
|
||||
// 读取TinyVue组件库入口文件
|
||||
return [
|
||||
{
|
||||
path: `solid/src/common/src/index.ts`,
|
||||
libPath: `common/lib/index`,
|
||||
type: 'module',
|
||||
name: kebabCase({ str: '@opensolidtiny/solid-common' }),
|
||||
global: capitalizeKebabCase('opentinySolidCommon'),
|
||||
importName: '@opensolidtiny/solid-common'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function getTasks(names: string[]): Module[] {
|
||||
// 没有指定组件,则全量构建
|
||||
if (names.length === 0) {
|
||||
return [...getAllModules(false)]
|
||||
}
|
||||
|
||||
return names
|
||||
.map((name) =>
|
||||
getByName({
|
||||
name: kebabCase({ str: name.replace('@opentiny/vue-', '') }),
|
||||
isSort: false
|
||||
})
|
||||
)
|
||||
.flat()
|
||||
}
|
||||
|
||||
/**
|
||||
* TinyVue组件打包主入口
|
||||
* @private
|
||||
* @param {string[]} names 需要打包的名字,如果不传默认打包全量组件 例如只打包alert和button两个组件 pnpm build:ui alert button
|
||||
* @param {BuildUiOption} buildUiOption 具体参数参考BuildUiOption接口
|
||||
*/
|
||||
|
||||
export async function buildSolid(
|
||||
names: string[] = [],
|
||||
{ buildTarget = '3.14.0', formats = ['es'], clean = false, scope = '@opensolidtiny' }: BuildUiOption
|
||||
) {
|
||||
// 是否清空构建目录
|
||||
let emptyOutDir = clean
|
||||
// 要构建的模块
|
||||
let tasks = getTasks(names).filter((item) => !item.path.includes('mobile'))
|
||||
|
||||
// 如果指定了打包icon或者没有传入任何组件
|
||||
if (names.some((name) => name.includes('icon')) || !names.length) {
|
||||
const icons = getAllIcons()
|
||||
icons.forEach((item) => {
|
||||
item.libPath = item.libPath.replace('vue-icon', 'solid-icon')
|
||||
})
|
||||
|
||||
tasks.push(...icons)
|
||||
}
|
||||
|
||||
// 过虑出需要打包的solid组件入口
|
||||
tasks = tasks
|
||||
.filter((item) =>
|
||||
buildComponents.some((value) => item.path.includes(`/${value}/`) || item.path.includes('vue-icon'))
|
||||
)
|
||||
.filter((item) => !item.path.includes('icon-saas'))
|
||||
|
||||
tasks.forEach((item) => {
|
||||
if (item.libPath.includes('vue-icon')) {
|
||||
item.libPath = item.libPath.replace('vue-icon', 'solid-icon')
|
||||
}
|
||||
})
|
||||
|
||||
// 打包入口文件
|
||||
if (names.length === 0 || names.some((name) => ['@opensolidtiny/solid', 'solid'].includes(name))) {
|
||||
tasks.push(...getEntryTasks(), ...getSolidCommonTasks())
|
||||
}
|
||||
|
||||
// 要构建的vue框架版本
|
||||
const message = `TINY for solid: ${JSON.stringify(names.length ? names : '全量')}`
|
||||
await batchBuildAll({ tasks, formats, message, emptyOutDir, buildTarget, npmScope: scope })
|
||||
// 确保只运行一次
|
||||
emptyOutDir = false
|
||||
}
|
|
@ -4,3 +4,4 @@ export * from './build-runtime'
|
|||
export * from './build-ui-react'
|
||||
export * from './build-entry-react'
|
||||
export * from './build-chart-theme'
|
||||
export * from './build-ui-solid'
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# vue-vite-template2jsx
|
||||
|
||||
## 一个可以将vue模板转化成jsx语法的vite插件
|
|
@ -0,0 +1,143 @@
|
|||
import { createRequire } from 'node:module'
|
||||
import { readFileSync, existsSync } from 'node:fs'
|
||||
import { transformVueTemplateToSolid } from './src/plugin.js'
|
||||
import { dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'node:path'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const indexTemplatePath = path.resolve(__dirname, './template/src/index.tss')
|
||||
const pcTemplatePath = path.resolve(__dirname, './template/src/pc.jsxs')
|
||||
|
||||
// 多模板入口模板
|
||||
const indexTemplate = readFileSync(indexTemplatePath, { encoding: 'utf-8' })
|
||||
|
||||
// PC模板入口
|
||||
const pcTemplate = readFileSync(pcTemplatePath, { encoding: 'utf-8' })
|
||||
|
||||
const matchComponentRegx = /vue\/src\/([a-z]+)\/src/
|
||||
|
||||
const fundProps = (code, findStr) => {
|
||||
let findIndex = code.indexOf(findStr)
|
||||
let props = ''
|
||||
|
||||
if (~findIndex) {
|
||||
const endStr = 'export '
|
||||
let constantsPart = code.substring(findIndex + findStr.length, code.length)
|
||||
props = constantsPart.substring(0, constantsPart.indexOf(endStr))
|
||||
}
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
const getSvgContent = (svg) => {
|
||||
return svg.substring(svg.indexOf('>') + 1, svg.length)
|
||||
}
|
||||
|
||||
const getDefaultValueFromEntry = (id) => {
|
||||
const componentMatchs = id.match(matchComponentRegx)
|
||||
const entryPath = id.replace('pc.vue', 'index.ts')
|
||||
if (existsSync(entryPath)) {
|
||||
if (componentMatchs?.[1]) {
|
||||
const code = readFileSync(entryPath, { encoding: 'utf-8' })
|
||||
let constants = fundProps(code, '$constants =') || '{}'
|
||||
let propsContent = fundProps(code, 'Props =') || fundProps(code, 'props :')
|
||||
let props = {}
|
||||
|
||||
if (propsContent) {
|
||||
const propsContentParts = propsContent.split(/\n/)
|
||||
propsContentParts.forEach((item, index) => {
|
||||
if (item.indexOf('type:') && ['Boolean', 'String', 'Number'].some((type) => item.includes(type))) {
|
||||
const name = propsContentParts[index - 1].replace(/\W/g, '')
|
||||
let value = propsContentParts[index + 1]
|
||||
|
||||
if (name && value.includes('default:')) {
|
||||
const type = /['"]/.test(value) ? 'Char' : 'Other'
|
||||
value = value.replace('default:', '').replace(/["|'|\s,]/g, '')
|
||||
props[name] = { type, value }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
$constants: constants,
|
||||
$props: props
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
$constants: '{}',
|
||||
$props: {}
|
||||
}
|
||||
}
|
||||
|
||||
export default function vueTemplate2Jsx() {
|
||||
return {
|
||||
name: '@opentiny/vue-vite-template2jsx',
|
||||
enforce: 'pre',
|
||||
transform(code, id) {
|
||||
if (id.includes('vue-icon/src')) {
|
||||
const svgName = code.match(/([a-z1-9-]+)\.svg/)
|
||||
|
||||
if (svgName && svgName[0]) {
|
||||
let svgPath
|
||||
|
||||
try {
|
||||
svgPath = require.resolve(`@opentiny/vue-theme/svgs/${svgName[0]}`)
|
||||
} catch (e) {
|
||||
svgPath = path.resolve(__dirname, `../../packages/theme/src/svgs/${svgName[0]}`)
|
||||
}
|
||||
|
||||
if (existsSync(svgPath)) {
|
||||
let svgContent = readFileSync(svgPath, { encoding: 'utf-8' })
|
||||
|
||||
if (svgContent.includes('<!--')) {
|
||||
svgContent = svgContent.replace(/<!--[\s\S]+-->/, '')
|
||||
}
|
||||
|
||||
if (svgContent.includes('<?xml')) {
|
||||
svgContent = getSvgContent(svgContent)
|
||||
}
|
||||
|
||||
if (svgContent.includes('<!DOCTYPE')) {
|
||||
svgContent = getSvgContent(svgContent)
|
||||
}
|
||||
|
||||
if (svgContent.includes('<style')) {
|
||||
svgContent = svgContent.replace(/<style[\s\S]+<\/style>/, '')
|
||||
}
|
||||
|
||||
const viewBox = svgContent.match(/viewBox="[\d|\s]+"/)?.[0] || `viewBox="0 0 24 24"`
|
||||
|
||||
return `export default function(props) {
|
||||
return (<svg style={props.style} xmlns="http://www.w3.org/2000/svg" onClick={props.onClick} ${viewBox} xml:space="preserve" class={'tiny-svg svgs-icon ' + props.class}>
|
||||
${getSvgContent(svgContent)}
|
||||
)
|
||||
}`
|
||||
}
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
if (id.includes(`src/index.ts`) && !id.includes(`common/src/index.ts`)) {
|
||||
return indexTemplate
|
||||
}
|
||||
|
||||
if (id.includes('pc.vue')) {
|
||||
const componentMatchs = id.match(matchComponentRegx)
|
||||
if (componentMatchs?.[1]) {
|
||||
const mapData = getDefaultValueFromEntry(id)
|
||||
const pcComponent = transformVueTemplateToSolid(pcTemplate, code, componentMatchs[1], mapData)
|
||||
return pcComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "@opentiny/vue-vite-template2jsx",
|
||||
"version": "1.1.5",
|
||||
"description": "A TinyVue vite import plugin",
|
||||
"main": "index.js",
|
||||
"module": "index.js",
|
||||
"author": "Tiny Vue Team",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:opentiny/tiny-vue.git"
|
||||
},
|
||||
"keywords": [
|
||||
"vite-plugin",
|
||||
"TinyVue",
|
||||
"vite"
|
||||
],
|
||||
"dependencies": {
|
||||
"lodash-es": "^4.17.21",
|
||||
"fs-extra": "^11.2.0",
|
||||
"vue-template-compiler": "2.6.14",
|
||||
"html-dom-parser": "~5.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": ">=4"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
export const builtinDirective = ['v-if', 'v-for', 'v-model', 'v-slot', 'v-else', 'v-else-if']
|
||||
export const builtinDirectivesWithoutVModel = builtinDirective.filter((x) => x !== 'v-model')
|
||||
|
||||
export const isNamedSlot = function (dObj) {
|
||||
return Object.keys(dObj.attribs).find(isSlotAttribute)
|
||||
}
|
||||
|
||||
export function getSlotName(dObj) {
|
||||
if (!dObj.attribs) return 'default'
|
||||
const attr = Object.keys(dObj.attribs).find(isSlotAttribute)
|
||||
if (!isNamedSlot(dObj)) return 'default'
|
||||
const prefix = attr.startsWith('#') ? '#' : 'v-slot:'
|
||||
return attr.split(prefix)[1]
|
||||
}
|
||||
|
||||
export function getSlotProps(dObj) {
|
||||
const attr = Object.keys(dObj.attribs).find(isSlotAttribute)
|
||||
return dObj.attribs[attr]
|
||||
}
|
||||
|
||||
export const getCondition = function (dObj) {
|
||||
return dObj.attribs['v-if'] || dObj.attribs['v-else-if']
|
||||
}
|
||||
|
||||
export function isConditional(dObj) {
|
||||
return isVIf(dObj) || isVElse(dObj) || isVElseIf(dObj)
|
||||
}
|
||||
|
||||
export function isVIf(dObj) {
|
||||
return dObj.type !== 'text' && Object.prototype.hasOwnProperty.call(dObj.attribs, 'v-if')
|
||||
}
|
||||
|
||||
export function isVElseIf(dObj) {
|
||||
return dObj.type !== 'text' && Object.prototype.hasOwnProperty.call(dObj.attribs, 'v-else-if')
|
||||
}
|
||||
|
||||
export function isVElse(dObj) {
|
||||
return dObj.type !== 'text' && Object.prototype.hasOwnProperty.call(dObj.attribs, 'v-else')
|
||||
}
|
||||
|
||||
export function isVifOrVElseIf(dObj) {
|
||||
return isVIf(dObj) || isVElseIf(dObj)
|
||||
}
|
||||
|
||||
export const isVFor = function (dObj) {
|
||||
return dObj.attribs && Object.prototype.hasOwnProperty.call(dObj.attribs, 'v-for')
|
||||
}
|
||||
|
||||
export const isSlotAttribute = function (attr) {
|
||||
return attr.startsWith('#') || attr.startsWith('v-slot')
|
||||
}
|
||||
|
||||
export function isValueAttribute(attr) {
|
||||
return !['v-if', 'v-else', 'v-else-if', 'v-for', 'v-slot'].includes(attr)
|
||||
}
|
||||
|
||||
export function isTextBlank(txt) {
|
||||
for (let i of txt) {
|
||||
if (i !== ' ' && i !== '\n') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export function getTag(dObj) {
|
||||
return dObj.name
|
||||
}
|
||||
|
||||
export function getFirstChild(dObj) {
|
||||
return dObj.children.length && dObj.children[0]
|
||||
}
|
||||
|
||||
export function isEmptyObject(dObj) {
|
||||
return dObj.type === 'text' && isTextBlank(dObj.data)
|
||||
}
|
||||
|
||||
export function isText(dObj) {
|
||||
return dObj.type === 'text'
|
||||
}
|
||||
|
||||
export function isComponent(dObj) {
|
||||
return dObj.name === 'component'
|
||||
}
|
||||
|
||||
export function isTransition(dObj) {
|
||||
return ['transition-group', 'transition'].includes(dObj.name)
|
||||
}
|
||||
|
||||
export function getText(dObj) {
|
||||
return dObj.data
|
||||
}
|
||||
|
||||
export function convertText(text) {
|
||||
return text.replace(/{{/g, '{').replace(/}}/g, '}').replace(/\$t/g, 't')
|
||||
}
|
||||
|
||||
export function setDynamicComponent(dObj) {
|
||||
let component = dObj.attribs[':is']
|
||||
dObj.attribs[':component'] = `resolveComponent(${component}, useIcons)`
|
||||
delete dObj.attribs[':is']
|
||||
dObj.name = 'Dynamic'
|
||||
}
|
||||
|
||||
export function isBindClass(attrName) {
|
||||
return attrName === ':class'
|
||||
}
|
||||
|
||||
export function isBindAll(attrName) {
|
||||
return attrName === 'v-bind'
|
||||
}
|
||||
|
||||
export function getLoopCommand(dObj) {
|
||||
const command = dObj.attribs['v-for']
|
||||
const separator = command.includes(' in ') ? ' in ' : ' of '
|
||||
const s = command.split(separator)
|
||||
return `${s[1].trim()}.map(${s[0].trim()} `
|
||||
}
|
||||
|
||||
export function isBindingAttrs(attrName) {
|
||||
return attrName.startsWith(':')
|
||||
}
|
||||
|
||||
export const toCamelCase = function (s) {
|
||||
let res = ''
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
if (i > 0 && s[i - 1] === '-') {
|
||||
res += s[i].toUpperCase()
|
||||
} else if (s[i] !== '-') res += s[i]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export function getAttrName(attrName, prefix) {
|
||||
return toCamelCase(attrName.split(prefix)[1])
|
||||
}
|
||||
|
||||
export function isEventListener(attrName) {
|
||||
return attrName.startsWith('@')
|
||||
}
|
||||
|
||||
export function getListenerName(attrName) {
|
||||
const idx = attrName.indexOf('.')
|
||||
if (idx === -1) return attrName.substr(1)
|
||||
else return attrName.substr(1, idx - 1)
|
||||
}
|
||||
|
||||
export function getModifiers(attrName) {
|
||||
let res = attrName.split('.')
|
||||
res.shift()
|
||||
return res
|
||||
}
|
||||
|
||||
export const convertEventListenerName = function (attrName) {
|
||||
const name = getListenerName(attrName)
|
||||
return toCamelCase(`on-${name}`).replace(/modelvalue/g, 'modelValue')
|
||||
}
|
||||
|
||||
export const convertListener = function (listener) {
|
||||
const isFunction = listener.includes('=>') || (!listener.includes('(') && !listener.includes('='))
|
||||
return isFunction
|
||||
? listener
|
||||
: listener.includes('$event')
|
||||
? `(v) => {${listener.replace(/\$event/g, 'v')}}`
|
||||
: `() => ${listener}`
|
||||
}
|
||||
|
||||
export const convertEventListener = function (listener, modifiers = []) {
|
||||
const eventName = convertListener(listener)
|
||||
return modifiers.length === 0
|
||||
? `${eventName}`
|
||||
: `(event) => withModifiers(event, ${eventName}, [${modifiers.map((m) => `'${m}'`).join(', ')}])`
|
||||
}
|
||||
|
||||
export const isVModel = function (attrName) {
|
||||
return attrName.startsWith('v-model')
|
||||
}
|
||||
|
||||
export const isBooleanAttrs = function (attrName) {
|
||||
return attrName === ''
|
||||
}
|
||||
|
||||
export const isRef = function (attrName) {
|
||||
return attrName === 'ref'
|
||||
}
|
||||
|
||||
export const isDynamic = function (attrName) {
|
||||
return attrName === ':is'
|
||||
}
|
||||
|
||||
export const convertRefName = function (name) {
|
||||
return toCamelCase(name)
|
||||
}
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
export const dirname = path.dirname(filename)
|
||||
|
||||
export const capitalize = function (str) {
|
||||
return typeof str === 'string' ? str.slice(0, 1).toUpperCase() + str.slice(1) : str
|
||||
}
|
||||
|
||||
export const capitalizeKebabCase = function (str, splitChar = '-') {
|
||||
return typeof str === 'string' ? str.split(splitChar).map(capitalize).join('') : str
|
||||
}
|
||||
|
||||
export const kebabCase = (str, splitChar = '-') => {
|
||||
if (!str || typeof str !== 'string') return str
|
||||
|
||||
return str
|
||||
.split('')
|
||||
.map((char, index) => {
|
||||
const charCod = char.charCodeAt(0)
|
||||
|
||||
if (charCod < 65 || charCod > 122) return char
|
||||
|
||||
return charCod >= 65 && charCod <= 90 ? (index !== 0 ? splitChar : '') + char.toLowerCase() : char
|
||||
})
|
||||
.join('')
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
import parse from 'html-dom-parser'
|
||||
import renderVueDomObject from './render.js'
|
||||
import { parseComponent } from 'vue-template-compiler'
|
||||
import { template } from 'lodash-es'
|
||||
|
||||
// 处理computed操作,如果想要具有响应式需要特殊处理
|
||||
const computedMap = {
|
||||
button: ['buttonDisabled', 'plain', 'formDisabled'],
|
||||
alert: ['getIcon', 'getTitle', 'alertClass', 'alertStyle'],
|
||||
switch: ['wrapClasses', 'isDisplayOnly', 'innerClasses']
|
||||
}
|
||||
|
||||
export const transformVueTemplateToSolid = (jsxTemplate, vueCode, componentName, mapData) => {
|
||||
const component = parseComponent(vueCode)
|
||||
|
||||
if (component.template && component.script) {
|
||||
const useCommons = [
|
||||
'useSetup',
|
||||
'getClassList',
|
||||
'mergeProps',
|
||||
'resolveComponent',
|
||||
'$prefix',
|
||||
'TransitionGroup',
|
||||
'Transition',
|
||||
't',
|
||||
'withModifiers'
|
||||
]
|
||||
const script = component.script.content
|
||||
const startStr = 'props: ['
|
||||
const sliceStr = script.substring(script.indexOf(startStr) + startStr.length)
|
||||
const props = sliceStr
|
||||
.substring(0, sliceStr.indexOf(']'))
|
||||
.replace('...props,', '')
|
||||
.replace(/[\n\s']/g, '')
|
||||
.split(',')
|
||||
|
||||
const specialVars = ['useIcons']
|
||||
const node = parse(component.template.content, { recognizeSelfClosing: true })[0]
|
||||
const renderNode = renderVueDomObject(node)
|
||||
const useApi = renderNode.useAttrs.realAttrs.filter(
|
||||
(item) => !props.includes(item) && !useCommons.includes(item) && !specialVars.includes(item)
|
||||
)
|
||||
let useProps = props.filter((item) => renderNode.useAttrs.realAttrs.includes(item))
|
||||
let jsxContent = renderNode.default.content.replace(/slots\.default/g, 'children')
|
||||
let defaultProps = []
|
||||
let importIcons = script.match(/import\s?{\s?ico.+/)
|
||||
let useIcons = '{}'
|
||||
|
||||
if (computedMap[componentName]) {
|
||||
computedMap[componentName].forEach((item) => {
|
||||
jsxContent = jsxContent.replaceAll(`state.${item}`, `state.${item}()`)
|
||||
})
|
||||
}
|
||||
|
||||
if (mapData.$props) {
|
||||
const getKeyValue = (key, props, char = '=') => {
|
||||
return `${key} ${char} ${props.type === 'Char' ? `'${props.value}'` : props.value}`
|
||||
}
|
||||
|
||||
useProps = useProps.map((item) => {
|
||||
const props = mapData.$props[item]
|
||||
if (props) {
|
||||
return getKeyValue(item, props)
|
||||
}
|
||||
|
||||
return item
|
||||
})
|
||||
|
||||
for (let key in mapData.$props) {
|
||||
const props = mapData.$props[key]
|
||||
defaultProps.push(getKeyValue(key, props, ':'))
|
||||
}
|
||||
}
|
||||
|
||||
importIcons = importIcons?.[0]
|
||||
if (importIcons) {
|
||||
importIcons = importIcons.replace(/icon/g, 'Icon')
|
||||
useIcons = importIcons.match(/\{(.+)\}/)[0] || '{}'
|
||||
}
|
||||
|
||||
const realComponet = template(jsxTemplate)({
|
||||
USEAPI: useApi.join(','),
|
||||
USEPROPS: useProps.join(','),
|
||||
JSX: jsxContent,
|
||||
NAME: componentName,
|
||||
CONSTANTS: mapData.$constants || '{}',
|
||||
DEFAULTPROPS: defaultProps.join(','),
|
||||
IMPORTICONS: importIcons,
|
||||
USEICONS: useIcons,
|
||||
USECOMMONS: useCommons.join(',')
|
||||
})
|
||||
|
||||
return realComponet
|
||||
}
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
import { cloneDeep } from 'lodash-es'
|
||||
import {
|
||||
builtinDirectivesWithoutVModel,
|
||||
isVModel,
|
||||
convertText,
|
||||
isSlotAttribute,
|
||||
isBooleanAttrs,
|
||||
isVIf,
|
||||
isVElse,
|
||||
isVFor,
|
||||
isTextBlank,
|
||||
isRef,
|
||||
convertRefName,
|
||||
getCondition,
|
||||
getTag,
|
||||
getFirstChild,
|
||||
isEmptyObject,
|
||||
isText,
|
||||
getText,
|
||||
isVElseIf,
|
||||
getLoopCommand,
|
||||
getSlotProps,
|
||||
getSlotName,
|
||||
isBindingAttrs,
|
||||
getAttrName,
|
||||
isEventListener,
|
||||
getModifiers,
|
||||
convertEventListenerName,
|
||||
convertEventListener,
|
||||
isBindClass,
|
||||
isBindAll,
|
||||
isComponent,
|
||||
setDynamicComponent,
|
||||
capitalizeKebabCase,
|
||||
isTransition
|
||||
} from './helpers.js'
|
||||
|
||||
let renderDomAttrs = []
|
||||
|
||||
const renderSlots = (slots) => {
|
||||
if (Object.keys(slots).length === 0) return ''
|
||||
let res = ` v-slots={{ `
|
||||
Object.keys(slots).forEach((slotName) => {
|
||||
let content = slots[slotName].content
|
||||
if (!content.startsWith('<>')) content = `<> ${content} </>\n`
|
||||
if (!isTextBlank(slots[slotName].content))
|
||||
res = res + `'${slotName}': (${slots[slotName].slotProps}) => ${content}, \n`
|
||||
})
|
||||
res += ` }}`
|
||||
return res
|
||||
}
|
||||
|
||||
const convertAttrs = function (attrs) {
|
||||
const res = {}
|
||||
|
||||
Object.keys(attrs).forEach((attrName) => {
|
||||
if (isSlotAttribute(attrName) || isBindAll(attrName)) return
|
||||
if (isBindingAttrs(attrName)) {
|
||||
if (isBindClass(attrName)) {
|
||||
res.classList = `{ getClassList(${attrs[attrName]}) }`
|
||||
} else {
|
||||
res[getAttrName(attrName, ':')] = `{ ${attrs[attrName]} }`
|
||||
}
|
||||
} else if (isEventListener(attrName)) {
|
||||
const eventListenerName = convertEventListenerName(attrName)
|
||||
const modifiers = getModifiers(attrName)
|
||||
const listener = convertEventListener(attrs[attrName], modifiers)
|
||||
res[eventListenerName] = `{${listener}}`
|
||||
} else if (isVModel(attrName)) {
|
||||
res[attrName] = `{${attrs[attrName]}}`
|
||||
} else if (isRef(attrName)) {
|
||||
res[attrName] = `{${convertRefName(attrs[attrName])}}`
|
||||
} else if (isBooleanAttrs(attrs[attrName])) {
|
||||
res[attrName] = ''
|
||||
} else {
|
||||
res[attrName] = `"${attrs[attrName]}"`
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
const renderAttrs = function (attrs) {
|
||||
let res = ''
|
||||
Object.keys(attrs).forEach((attrName) => {
|
||||
res += attrs[attrName] === '' ? `${attrName} ` : `${attrName}=${attrs[attrName]} ` // boolean attrs
|
||||
})
|
||||
return res === '' ? '' : ` ${res}`
|
||||
}
|
||||
|
||||
const renderDomObj = function (dObj, needWrap = true) {
|
||||
if (isEmptyObject(dObj)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (isText(dObj)) return convertText(getText(dObj))
|
||||
|
||||
if (isComponent(dObj)) {
|
||||
setDynamicComponent(dObj)
|
||||
}
|
||||
|
||||
const tagName = getTag(dObj)
|
||||
const slots = renderVueDomObject(getFirstChild(dObj))
|
||||
const attrs = convertAttrs(cloneDeep(dObj.attribs))
|
||||
let tag = tagName === 'template' ? '' : tagName
|
||||
|
||||
builtinDirectivesWithoutVModel.forEach((attr) => delete attrs[attr])
|
||||
|
||||
if (Object.keys(dObj.attribs).length) {
|
||||
renderDomAttrs.push(dObj.attribs)
|
||||
if (dObj.name === 'slot') {
|
||||
renderDomAttrs.push({ 'v-slot': `slots.${dObj.attribs.name}` })
|
||||
}
|
||||
}
|
||||
|
||||
if (tagName.indexOf('icon-') === 0) {
|
||||
tag = capitalizeKebabCase(tag)
|
||||
} else if (isTransition(dObj)) {
|
||||
tag = capitalizeKebabCase(tag)
|
||||
attrs.onExit = '{ (el, done) => { setTimeout(done, 300) } }'
|
||||
|
||||
const getRealClassName = (part) => `"${(attrs.name + part).replace(/"/g, '')}"`
|
||||
attrs.enterToClass = getRealClassName('-enter-from')
|
||||
attrs.exitActiveClass = getRealClassName('-leave-active')
|
||||
}
|
||||
|
||||
if (Object.keys(slots).length < 2) {
|
||||
let content = slots.default?.content || ''
|
||||
if (!tag) {
|
||||
let slotName = 'children'
|
||||
|
||||
if (attrs.name) {
|
||||
slotName = `slots.${attrs.name.replace(/["']/g, '')}`
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
return `\n { ${slotName} } \n`
|
||||
}
|
||||
|
||||
if (!/<[^>]+>/.test(content)) {
|
||||
content = `<span>${content}</span>`
|
||||
}
|
||||
|
||||
if (needWrap) {
|
||||
return `{ ${slotName} || ${content} }`
|
||||
}
|
||||
|
||||
return `(${slotName} || ${content})`
|
||||
}
|
||||
|
||||
return `<${tag}${renderAttrs(attrs)}> \n ${content}</${tag}>\n`
|
||||
}
|
||||
|
||||
return `<${tag}${renderAttrs(attrs)}${renderSlots(slots)}></${tag}>\n`
|
||||
}
|
||||
|
||||
const renderVIfSegment = function (first, last, nodes, isRoot) {
|
||||
const open = isRoot ? '{' : '('
|
||||
const close = isRoot ? '}' : ')'
|
||||
const domContent = renderDomObj(nodes[first], false)
|
||||
|
||||
if (first + 1 === last) {
|
||||
return `${open} \n (${getCondition(nodes[first])}) && \n ${domContent} ${close} \n`
|
||||
} else {
|
||||
if (isVElse(nodes[first + 1])) {
|
||||
return `${open} \n (${getCondition(nodes[first])}) ? \n ${domContent} : \n
|
||||
${renderDomObj(nodes[first + 1])} ${close} \n`
|
||||
} else {
|
||||
return `${open} \n (${getCondition(nodes[first])}) ? \n ${domContent} : \n
|
||||
${renderVIfSegment(first + 1, last, nodes)} ${close} \n`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const renderVFor = function (dObj) {
|
||||
return `{${getLoopCommand(dObj)} => \n ${renderDomObj(dObj)} )}`
|
||||
}
|
||||
|
||||
const renderVueDomObject = function (dObj) {
|
||||
if (!dObj) return ''
|
||||
let _dObj = cloneDeep(dObj)
|
||||
let slots = {}
|
||||
|
||||
slots.default = { slotProps: '', content: '', nodes: [] }
|
||||
|
||||
function addNode(dObj) {
|
||||
if (isEmptyObject(_dObj)) return
|
||||
const slotName = getSlotName(dObj)
|
||||
|
||||
if (dObj.name === 'slot') {
|
||||
dObj.name = 'template'
|
||||
}
|
||||
|
||||
slots[slotName] = slots[slotName] || { slotProps: getSlotProps(dObj), nodes: [] }
|
||||
slots[slotName].nodes.push(dObj)
|
||||
}
|
||||
|
||||
addNode(_dObj)
|
||||
while (_dObj.next) {
|
||||
_dObj = _dObj.next
|
||||
addNode(_dObj)
|
||||
}
|
||||
|
||||
function renderNodes(nodes) {
|
||||
let res = ''
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
if (isVIf(nodes[i])) {
|
||||
let j = i + 1
|
||||
while (j < nodes.length && isVElseIf(nodes[j])) j++
|
||||
if (j < nodes.length) {
|
||||
if (isVElse(nodes[j])) j++
|
||||
}
|
||||
res += renderVIfSegment(i, j, nodes, true)
|
||||
i = j - 1
|
||||
} else if (isVFor(nodes[i])) {
|
||||
res = res + renderVFor(nodes[i])
|
||||
} else {
|
||||
res = res + renderDomObj(nodes[i])
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
Object.keys(slots).forEach((slotName) => {
|
||||
let nodes = slots[slotName].nodes
|
||||
let content = renderNodes(nodes)
|
||||
slots[slotName].content = content
|
||||
})
|
||||
return slots
|
||||
}
|
||||
|
||||
const vueOperators = ':,v-,@'.split(',')
|
||||
const globalProps = 'true,false'.split(',')
|
||||
const charReg = /[\n\+\[\&\]!=\{\},\?\:\|]/g
|
||||
const specialProps = 'a,$attrs,state,children,slots'.split(',')
|
||||
|
||||
const getUseAttrs = function () {
|
||||
let attrs = renderDomAttrs
|
||||
.map((item) => {
|
||||
return Object.entries(item)
|
||||
.filter(([key, _]) => vueOperators.some((val) => key.indexOf(val) === 0))
|
||||
.map((arr) => arr[1])
|
||||
.map((key) =>
|
||||
key
|
||||
.replace(charReg, ' ')
|
||||
.split(' ')
|
||||
.filter((name) => name && !name.includes('-') && !name.includes("'"))
|
||||
)
|
||||
.flat()
|
||||
})
|
||||
.flat()
|
||||
.map((item) => {
|
||||
return item.split(/[\(\)]/)
|
||||
})
|
||||
.flat()
|
||||
.filter((name) => name.length && !globalProps.includes(name))
|
||||
|
||||
attrs = [...new Set(attrs)]
|
||||
|
||||
const realAttrs = [...new Set(attrs.map((attr) => attr.split('.')[0]))].filter((name) => !specialProps.includes(name))
|
||||
|
||||
return {
|
||||
attrs,
|
||||
realAttrs
|
||||
}
|
||||
}
|
||||
|
||||
export default function (dObj) {
|
||||
renderDomAttrs = []
|
||||
const component = renderVueDomObject(dObj)
|
||||
const useAttrs = getUseAttrs()
|
||||
|
||||
return {
|
||||
...component,
|
||||
useAttrs
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import <%=UPPERNAME%> from './src'
|
||||
|
||||
export default <%=UPPERNAME%>
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "@opentiny/solid-<%=NAME%>",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@opentiny/vue-renderless": "workspace:~",
|
||||
"@opentiny/solid-common": "workspace:~",
|
||||
"@opentiny/vue-theme": "workspace:~"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import pc from './pc.vue'
|
||||
|
||||
export default function (props) {
|
||||
const { tiny_mode = 'pc' } = props
|
||||
|
||||
const S = {
|
||||
pc
|
||||
}[tiny_mode]
|
||||
|
||||
return S(props)
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { renderless } from '@opentiny/vue-renderless/<%=NAME%>/vue'
|
||||
import { <%=USECOMMONS%> } from '@opentiny/solid-common'
|
||||
import '@opentiny/vue-theme/<%=NAME%>/index.less'
|
||||
<%=IMPORTICONS%>
|
||||
const useIcons = <%=USEICONS%>
|
||||
const $constants = <%=CONSTANTS%>
|
||||
export default function (props) {
|
||||
const { children, slots = {}, <%=USEPROPS%> } = props
|
||||
const { state, <%=USEAPI%> } = useSetup({
|
||||
props: mergeProps({<%=DEFAULTPROPS%>}, props),
|
||||
renderless,
|
||||
constants: $constants,
|
||||
})
|
||||
return (<><%=JSX%></>)
|
||||
}
|
|
@ -143,8 +143,10 @@
|
|||
"prettier": "prettier --config .prettierrc --write .",
|
||||
"// ---------- openinula 相关脚本命令 ----------": "",
|
||||
"dev:openinula": "pnpm -C examples/openinula-docs run dev",
|
||||
"// ---------- solid 相关脚本命令 ----------": "",
|
||||
"dev:solid": "pnpm -C examples/solid-docs run dev"
|
||||
"// ---------- 预览发布后的solid组件 ----------": "",
|
||||
"preview:solid": "pnpm -C examples/solid-demo run dev",
|
||||
"build:solid": "pnpm -C internals/cli build:solid",
|
||||
"pub:solid": "pnpm --filter=\"./packages/dist-solid/**\" publish --no-git-checks --access=public --registry=https://registry.npmjs.org"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/composition-api": "1.7.2",
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import Button from '@opentiny/solid-button'
|
||||
import Alert from '@opentiny/solid-alert'
|
||||
|
||||
export const version = '1.0.0'
|
||||
|
||||
export { Button }
|
||||
export { Button, Alert }
|
||||
|
||||
export default {
|
||||
Button
|
||||
Button,
|
||||
Alert
|
||||
} as any
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@opentiny/solid-common": "workspace:~",
|
||||
"@opentiny/solid-button": "workspace:~"
|
||||
"@opentiny/vue-button": "workspace:~",
|
||||
"@opentiny/vue-alert": "workspace:~"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
"dependencies": {
|
||||
"@opentiny/vue-renderless": "workspace:~",
|
||||
"@opentiny/vue-theme": "workspace:~",
|
||||
"classnames": "^2.3.2",
|
||||
"solid-transition-group": "0.2.3",
|
||||
"solid-js": "^1.7.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import * as hooks from 'solid-js'
|
||||
import { createSignal, onCleanup, createMemo } from 'solid-js'
|
||||
import { onCleanup, onMount, createResource, createEffect, on, mergeProps } from 'solid-js'
|
||||
import { createMutable } from 'solid-js/store'
|
||||
import { TransitionGroup, Transition } from 'solid-transition-group'
|
||||
import '@opentiny/vue-theme/base/index.less'
|
||||
|
||||
const EVENTS_PREFIX = 'on'
|
||||
|
@ -7,41 +9,12 @@ const EVENTS_PREFIX = 'on'
|
|||
// 处理solid事件触发机制
|
||||
export const emit =
|
||||
(props) =>
|
||||
(evName, ...args) => {
|
||||
const eventsName = `${EVENTS_PREFIX}${evName[0].toLocaleUpperCase()}${evName.slice(1)}`
|
||||
if (props[eventsName] && typeof props[eventsName] === 'function') {
|
||||
props[eventsName](...args)
|
||||
}
|
||||
}
|
||||
|
||||
export const useSetState = (initialState) => {
|
||||
const [state, setState] = createSignal(initialState, { equals: false })
|
||||
|
||||
return [state, setState]
|
||||
}
|
||||
|
||||
// props 应该不用做处理, props 都是 . 访问。
|
||||
export const reactive = (staticObject) => {
|
||||
const [state, setState] = useSetState(staticObject)
|
||||
|
||||
return new Proxy(state(), {
|
||||
get(target, property) {
|
||||
if (property === 'solidState') {
|
||||
return state
|
||||
(evName, ...args) => {
|
||||
const eventsName = `${EVENTS_PREFIX}${evName[0].toLocaleUpperCase()}${evName.slice(1)}`
|
||||
if (props[eventsName] && typeof props[eventsName] === 'function') {
|
||||
props[eventsName](...args)
|
||||
}
|
||||
if (typeof target[property] === 'function') {
|
||||
return target[property](target)
|
||||
} else {
|
||||
return target[property]
|
||||
}
|
||||
},
|
||||
set(target, property, value) {
|
||||
Reflect.set(target, property, value)
|
||||
setState((val) => val)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// nextTick, 等待 dom 更新后触发回调
|
||||
export const useNextTick = (callback) => {
|
||||
|
@ -62,30 +35,142 @@ export const emitEvent = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const computed = (callback) => {
|
||||
try {
|
||||
return createMemo(callback)
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
const watch = (valueFn, callback, options) => {
|
||||
createEffect(on(valueFn, callback, { defer: !options.immediate }))
|
||||
}
|
||||
|
||||
export const useSetup = ({ props, renderless, extendOptions = { framework: 'Solid' } }) => {
|
||||
export const t = (str) => str
|
||||
|
||||
const reactive = (state) => {
|
||||
const proxy = createMutable(state)
|
||||
// 暂时解决嵌套computed导致禁用问题,后期再完善
|
||||
if (proxy.formDisabled) {
|
||||
proxy.formDisabled = false
|
||||
}
|
||||
|
||||
if (proxy.disabled) {
|
||||
proxy.disabled = false
|
||||
}
|
||||
|
||||
return proxy
|
||||
}
|
||||
|
||||
export const useSetup = ({ props, renderless, extendOptions = { framework: 'Solid' }, constants }) => {
|
||||
const render = typeof props.tiny_renderless === 'function' ? props.tiny_renderless : renderless
|
||||
const utils = {
|
||||
parent: {},
|
||||
emit: emit(props)
|
||||
emit: emit(props),
|
||||
constants,
|
||||
nextTick: useNextTick,
|
||||
t,
|
||||
mode: 'pc'
|
||||
}
|
||||
const sdk = render(
|
||||
props,
|
||||
{ ...hooks, reactive, computed, useNextTick, inject: () => {}, watch: () => {}, onBeforeUnmount: onCleanup },
|
||||
{
|
||||
...hooks,
|
||||
reactive,
|
||||
computed: (callback) => {
|
||||
const [computedValue, { mutate }] = createResource(() => {
|
||||
return Promise.resolve().then(() => {
|
||||
return callback()
|
||||
})
|
||||
})
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
createEffect(() => {
|
||||
mutate(callback())
|
||||
})
|
||||
})
|
||||
|
||||
return computedValue
|
||||
},
|
||||
inject: () => { },
|
||||
watch,
|
||||
watchEffect: createEffect,
|
||||
onMounted: onMount,
|
||||
onBeforeUnmount: onCleanup
|
||||
},
|
||||
utils,
|
||||
extendOptions
|
||||
)
|
||||
|
||||
return {
|
||||
...sdk,
|
||||
state: sdk.state.solidState,
|
||||
type: props.type ?? 'default'
|
||||
}
|
||||
}
|
||||
|
||||
export const getType = (str, type = 'object') => {
|
||||
return (
|
||||
{
|
||||
'[object Number]': 'number',
|
||||
'[object String]': 'string',
|
||||
'[object Boolean]': 'boolean',
|
||||
'[object Undefined]': 'undefined',
|
||||
'[object Null]': 'null',
|
||||
'[object Array]': 'array',
|
||||
'[object Arguments]': 'arguments',
|
||||
'[object Function]': 'function',
|
||||
'[object Error]': 'error',
|
||||
'[object Date]': 'date',
|
||||
'[object RegExp]': 'regexp',
|
||||
'[object Object]': 'object'
|
||||
}[Object.prototype.toString.call(str)] === type
|
||||
)
|
||||
}
|
||||
|
||||
export const getClassList = (cls) => {
|
||||
if (getType(cls)) {
|
||||
return cls
|
||||
}
|
||||
|
||||
if (Array.isArray(cls)) {
|
||||
const classList = {}
|
||||
|
||||
cls.forEach((cls) => {
|
||||
if (!cls) return
|
||||
if (typeof cls === 'string') {
|
||||
classList[cls] = true
|
||||
} else if (typeof cls === 'object') {
|
||||
if (Array.isArray(cls)) {
|
||||
Object.assign(classList, getClassList(cls))
|
||||
} else {
|
||||
Object.assign(classList, cls)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return classList
|
||||
}
|
||||
|
||||
return {
|
||||
[cls]: true
|
||||
}
|
||||
}
|
||||
|
||||
export const capitalize = function (str) {
|
||||
return typeof str === 'string' ? str.slice(0, 1).toUpperCase() + str.slice(1) : str
|
||||
}
|
||||
|
||||
export const capitalizeKebabCase = function (str, splitChar = '-') {
|
||||
return typeof str === 'string' ? str.split(splitChar).map(capitalize).join('') : str
|
||||
}
|
||||
|
||||
export const resolveComponent = (component, useComponents) => {
|
||||
if (typeof component === 'string' && component.indexOf('icon-') === 0) {
|
||||
const componentName = capitalizeKebabCase(component)
|
||||
return useComponents[componentName] || componentName
|
||||
}
|
||||
return component
|
||||
}
|
||||
|
||||
export const $prefix = 'Tiny'
|
||||
|
||||
export const withModifiers = function (event, eventCallback, keys) {
|
||||
if (typeof eventCallback === 'function') {
|
||||
eventCallback(event);
|
||||
}
|
||||
}
|
||||
|
||||
export { mergeProps, TransitionGroup, Transition }
|
||||
|
|
|
@ -2,3 +2,4 @@ packages:
|
|||
- packages/**
|
||||
- examples/*
|
||||
- internals/*
|
||||
- solid-demo/*
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"noImplicitAny": false,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@opentiny/vue-autonavi-map": ["packages/vue/src/chart/autonavi-map"],
|
||||
"@opentiny/vue-baidu-map": ["packages/vue/src/chart/baidu-map"],
|
||||
"@opentiny/vue-chart-*": ["packages/vue/src/chart/chart-*"],
|
||||
"@opentiny/vue-*": ["packages/vue-*", "packages/vue/src/*"],
|
||||
"@opentiny/vue-renderless/types*": ["packages/renderless/types*"],
|
||||
"@opentiny/vue-renderless*": ["packages/renderless/src*"],
|
||||
"virtual:common/adapter/vue": ["packages/vue-common/src/adapter/vue3/index.ts"],
|
||||
"virtual:locale/vue": ["packages/vue-locale/src/vue3/index.ts"]
|
||||
},
|
||||
"types": ["node", "vite/client"]
|
||||
},
|
||||
"vueCompilerOptions": {
|
||||
"target": 3
|
||||
},
|
||||
"include": [
|
||||
"packages/**/*.ts",
|
||||
"packages/**/*.tsx",
|
||||
"packages/**/*.vue",
|
||||
"examples/vue3/shims-app.d.ts",
|
||||
"examples/vue3/shims-vue.d.ts"
|
||||
],
|
||||
"exclude": ["**/node_modules", "**/dist*", "**/*.md"]
|
||||
}
|
Loading…
Reference in New Issue