diff --git a/examples/solid-docs/index.html b/examples/solid-docs/index.html new file mode 100644 index 000000000..b9a46f405 --- /dev/null +++ b/examples/solid-docs/index.html @@ -0,0 +1,13 @@ + + + + + + + Opentiny Solid 组件调试 + + +
+ + + diff --git a/examples/solid-docs/package.json b/examples/solid-docs/package.json new file mode 100644 index 000000000..a55ab94ec --- /dev/null +++ b/examples/solid-docs/package.json @@ -0,0 +1,20 @@ +{ + "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", + "@opentiny/solid": "workspace:~" + }, + "devDependencies": { + "vite": "^4.4.5", + "vite-plugin-solid": "^2.7.0", + "vite-plugin-svgr": "^3.2.0" + } +} diff --git a/examples/solid-docs/public/vite.svg b/examples/solid-docs/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/examples/solid-docs/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/solid-docs/src/App.tsx b/examples/solid-docs/src/App.tsx new file mode 100644 index 000000000..967bda74b --- /dev/null +++ b/examples/solid-docs/src/App.tsx @@ -0,0 +1,12 @@ +import { Button } from '@opentiny/solid' + +// 在这里导入组件,进行 api 调试 +function App() { + return ( +
+ +
+ ) +} + +export default App diff --git a/examples/solid-docs/src/main.css b/examples/solid-docs/src/main.css new file mode 100644 index 000000000..50154555f --- /dev/null +++ b/examples/solid-docs/src/main.css @@ -0,0 +1,4 @@ +.app { + margin: 10px; + width: 500px; +} diff --git a/examples/solid-docs/src/main.tsx b/examples/solid-docs/src/main.tsx new file mode 100644 index 000000000..2cda43153 --- /dev/null +++ b/examples/solid-docs/src/main.tsx @@ -0,0 +1,7 @@ +import { render } from 'solid-js/web' +import App from './App' +import './main.css' + +const root = document.getElementById('root') + +render(() => , root) diff --git a/examples/solid-docs/tsconfig.json b/examples/solid-docs/tsconfig.json new file mode 100644 index 000000000..a7fc6fbf2 --- /dev/null +++ b/examples/solid-docs/tsconfig.json @@ -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" }] +} diff --git a/examples/solid-docs/tsconfig.node.json b/examples/solid-docs/tsconfig.node.json new file mode 100644 index 000000000..42872c59f --- /dev/null +++ b/examples/solid-docs/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/examples/solid-docs/vite.config.ts b/examples/solid-docs/vite.config.ts new file mode 100644 index 000000000..163b240eb --- /dev/null +++ b/examples/solid-docs/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import svgr from 'vite-plugin-svgr' + +export default defineConfig({ + plugins: [solid(), svgr()] +}) diff --git a/package.json b/package.json index 5f16d7c0f..0f8922b7a 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,9 @@ "build:react-site": "pnpm --filter @opentiny/react-site build", "prettier": "prettier --config .prettierrc --write .", "// ---------- openinula 相关脚本命令 ----------": "", - "dev:openinula": "pnpm -C examples/openinula-docs run dev" + "dev:openinula": "pnpm -C examples/openinula-docs run dev", + "// ---------- solid 相关脚本命令 ----------": "", + "dev:solid": "pnpm -C examples/solid-docs run dev" }, "dependencies": { "@vue/composition-api": "1.2.2", diff --git a/packages/solid/.depcheckrc.yaml b/packages/solid/.depcheckrc.yaml new file mode 100644 index 000000000..93b829947 --- /dev/null +++ b/packages/solid/.depcheckrc.yaml @@ -0,0 +1,2 @@ +ignores: + - '@opentiny/solid*' diff --git a/packages/solid/index.ts b/packages/solid/index.ts new file mode 100644 index 000000000..91703514d --- /dev/null +++ b/packages/solid/index.ts @@ -0,0 +1,9 @@ +import Button from '@opentiny/solid-button' + +export const version = '1.0.0' + +export { Button } + +export default { + Button +} as any diff --git a/packages/solid/package.json b/packages/solid/package.json new file mode 100644 index 000000000..8e4e72fd4 --- /dev/null +++ b/packages/solid/package.json @@ -0,0 +1,16 @@ +{ + "name": "@opentiny/solid", + "version": "1.0.0", + "description": "", + "main": "index.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@opentiny/solid-common": "workspace:~", + "@opentiny/solid-button": "workspace:~" + } +} diff --git a/packages/solid/src/button/index.ts b/packages/solid/src/button/index.ts new file mode 100644 index 000000000..9bc345130 --- /dev/null +++ b/packages/solid/src/button/index.ts @@ -0,0 +1,3 @@ +import Alert from './src' + +export default Alert diff --git a/packages/solid/src/button/package.json b/packages/solid/src/button/package.json new file mode 100644 index 000000000..5eab01aa5 --- /dev/null +++ b/packages/solid/src/button/package.json @@ -0,0 +1,18 @@ +{ + "name": "@opentiny/solid-button", + "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:~", + "@opentiny/vue-theme-mobile": "workspace:~" + } +} diff --git a/packages/solid/src/button/src/index.ts b/packages/solid/src/button/src/index.ts new file mode 100644 index 000000000..764fd362c --- /dev/null +++ b/packages/solid/src/button/src/index.ts @@ -0,0 +1,11 @@ +import pc from './pc' + +export default function (props) { + const { tiny_mode = 'pc' } = props + + const S = { + pc + }[tiny_mode] + + return S(props) +} diff --git a/packages/solid/src/button/src/pc.jsx b/packages/solid/src/button/src/pc.jsx new file mode 100644 index 000000000..c198e619b --- /dev/null +++ b/packages/solid/src/button/src/pc.jsx @@ -0,0 +1,35 @@ +import { renderless } from '@opentiny/vue-renderless/button/vue' +import { useSetup } from '@opentiny/solid-common' +import '@opentiny/vue-theme/button/index.less' + +export default function Button(props) { + const { children, text, autofocus, round, circle, icon: Icon, size, nativeType = 'button' } = props + const { handleClick, state, tabindex, type, $attrs } = useSetup({ + props: { nativeType: 'button', resetTime: 1000, ...props }, + renderless + }) + + return ( + + ) +} diff --git a/packages/solid/src/common/package.json b/packages/solid/src/common/package.json new file mode 100644 index 000000000..0e36a8e6a --- /dev/null +++ b/packages/solid/src/common/package.json @@ -0,0 +1,18 @@ +{ + "name": "@opentiny/solid-common", + "version": "1.0.0", + "description": "", + "main": "src/index.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@opentiny/vue-renderless": "workspace:~", + "@opentiny/vue-theme": "workspace:~", + "classnames": "^2.3.2", + "solid-js": "^1.7.8" + } +} diff --git a/packages/solid/src/common/src/index.ts b/packages/solid/src/common/src/index.ts new file mode 100644 index 000000000..83156f642 --- /dev/null +++ b/packages/solid/src/common/src/index.ts @@ -0,0 +1,91 @@ +import * as hooks from 'solid-js' +import { createSignal, onCleanup, createMemo } from 'solid-js' +import '@opentiny/vue-theme/base/index.less' + +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 + } + 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) => { + queueMicrotask(callback) +} + +// emitEvent, dispath, broadcast +export const emitEvent = () => { + const broadcast = () => { + return '' + } + + return { + dispatch: () => { + return '' + }, + broadcast + } +} + +const computed = (callback) => { + try { + return createMemo(callback) + } catch (error) { + return [] + } +} + +export const useSetup = ({ props, renderless, extendOptions = { framework: 'Solid' } }) => { + const render = typeof props.tiny_renderless === 'function' ? props.tiny_renderless : renderless + const utils = { + parent: {}, + emit: emit(props) + } + const sdk = render( + props, + { ...hooks, reactive, computed, useNextTick, inject: () => {}, watch: () => {}, onBeforeUnmount: onCleanup }, + utils, + extendOptions + ) + + return { + ...sdk, + state: sdk.state.solidState, + type: props.type ?? 'default' + } +}