diff --git a/examples/basic-project/ice.config.ts b/examples/basic-project/ice.config.ts index d66f89fc0..608d4eaca 100644 --- a/examples/basic-project/ice.config.ts +++ b/examples/basic-project/ice.config.ts @@ -17,5 +17,7 @@ export default defineConfig({ }, dropLogLevel: 'warn', plugins: [pluginAuth(), pluginRaxCompat()], - eslint: true, -}); \ No newline at end of file + // eslint: true, + ssr: false, + ssg: false, +}); diff --git a/examples/basic-project/package.json b/examples/basic-project/package.json index 9b4827416..666580d0b 100644 --- a/examples/basic-project/package.json +++ b/examples/basic-project/package.json @@ -14,7 +14,10 @@ "@ice/plugin-rax-compat": "workspace:*", "@ice/runtime": "workspace:*", "ahooks": "^3.3.8", + "rax-image": "^2.4.1", "rax-is-valid-element": "^1.0.0", + "rax-text": "^2.2.0", + "rax-view": "^2.3.0", "react": "^18.0.0", "react-dom": "^18.0.0" }, diff --git a/examples/basic-project/src/components/Logo/index.jsx b/examples/basic-project/src/components/Logo/index.jsx new file mode 100644 index 000000000..35e792908 --- /dev/null +++ b/examples/basic-project/src/components/Logo/index.jsx @@ -0,0 +1,10 @@ +import { createElement } from 'rax'; +import Image from 'rax-image'; + +import styles from './index.module.css'; + +export default (props) => { + const { uri } = props; + const source = { uri }; + return ; +}; diff --git a/examples/basic-project/src/components/Logo/index.module.css b/examples/basic-project/src/components/Logo/index.module.css new file mode 100644 index 000000000..b84be53a9 --- /dev/null +++ b/examples/basic-project/src/components/Logo/index.module.css @@ -0,0 +1,5 @@ +.logo { + width: 200rpx; + height: 180rpx; + margin-bottom: 20rpx; +} diff --git a/examples/basic-project/src/pages/index.module.css b/examples/basic-project/src/pages/index.module.css index 3dc895d63..679273d44 100644 --- a/examples/basic-project/src/pages/index.module.css +++ b/examples/basic-project/src/pages/index.module.css @@ -5,4 +5,21 @@ .data { margin-top: 10px; -} \ No newline at end of file +} + +.homeContainer { + align-items: center; + margin-top: 200rpx; +} + +.homeTitle { + font-size: 45rpx; + font-weight: bold; + margin: 20rpx 0; +} + +.homeInfo { + font-size: 36rpx; + margin: 8rpx 0; + color: #555; +} diff --git a/examples/basic-project/src/pages/rax.jsx b/examples/basic-project/src/pages/rax.jsx new file mode 100644 index 000000000..95569b150 --- /dev/null +++ b/examples/basic-project/src/pages/rax.jsx @@ -0,0 +1,18 @@ +import { createElement, forwardRef, createRef, useRef } from 'rax'; +import View from 'rax-view'; +import Text from 'rax-text'; + +import styles from './index.module.css'; + +import Logo from '@/components/Logo'; + +export default function Home() { + return ( + { console.log('view appear'); }}> + + Welcome to Your Rax App + More information about Rax + Visit https://rax.js.org + + ); +} diff --git a/packages/rax-compat/package.json b/packages/rax-compat/package.json index 606b48977..ef5958ced 100644 --- a/packages/rax-compat/package.json +++ b/packages/rax-compat/package.json @@ -45,7 +45,8 @@ "compat" ], "dependencies": { - "@swc/helpers": "^0.3.8" + "@swc/helpers": "^0.3.8", + "appear-polyfill": "^0.1.2" }, "devDependencies": { "@ice/pkg": "^1.0.0-rc.0", diff --git a/packages/rax-compat/src/create-element.ts b/packages/rax-compat/src/create-element.ts index f65c8d9a1..a82a4971e 100644 --- a/packages/rax-compat/src/create-element.ts +++ b/packages/rax-compat/src/create-element.ts @@ -1,4 +1,22 @@ -import React from 'react'; +import React, { + Attributes, + FunctionComponent, + ReactElement, + ReactNode, + RefObject, + useEffect, useRef, forwardRef, +} from 'react'; +import { isFunction } from './type'; +// @ts-ignore +import { setupAppear } from 'appear-polyfill'; + +let appearSetup = false; +function setupAppearOnce() { + if (!appearSetup) { + setupAppear(); + appearSetup = true; + } +} /** * Compat createElement for rax export. @@ -6,9 +24,56 @@ import React from 'react'; * @param type * @param props * @param children - * @param others * @returns Element */ -export function createElement(type: any, props: Object, children: any, ...others: any) { - return React.createElement(type, props, children, ...others); +export function createElement

; + children: any; onAppear?: Function; + onDisappear?: Function; +}>( + type: FunctionComponent

, + props?: Attributes & P | null, + ...children: ReactNode[]): ReactElement { + const { children: propsChildren, onAppear, onDisappear, ...rest } = props; + + rest.ref = props.ref || useRef(null); + let element: any = React.createElement(type, rest as Attributes & P | null, propsChildren, ...children); + // Polyfill onAppear and onDisappear. + if (isFunction(onAppear) || isFunction(onDisappear)) { + setupAppearOnce(); + element = React.createElement(forwardRef(AppearOrDisappear), { + onAppear: onAppear, + onDisappear: onDisappear, + ref: rest.ref, + }, element); + } + + return element; +} + +// Appear HOC Component. +function AppearOrDisappear(props: any, ref: RefObject) { + const { onAppear, onDisappear } = props; + + listen('appear', onAppear); + listen('disappear', onDisappear); + + function listen(eventName: string, handler: EventListenerOrEventListenerObject) { + if (isFunction(handler) && ref != null) { + useEffect(() => { + const { current } = ref; + if (current != null) { + current.addEventListener(eventName, handler); + } + return () => { + const { current } = ref; + if (current) { + current.removeEventListener(eventName, handler); + } + }; + }, [ref, handler]); + } + } + + return props.children; } diff --git a/packages/runtime/src/routes.tsx b/packages/runtime/src/routes.tsx index 16481d409..b4ec1e1e1 100644 --- a/packages/runtime/src/routes.tsx +++ b/packages/runtime/src/routes.tsx @@ -65,7 +65,7 @@ export async function loadRoutesData( matches.map(async (match) => { const { id } = match.route; const routeModule = routeModules[id]; - const { getData } = routeModule; + const { getData } = routeModule ?? {}; if (getData) { routesData[id] = await getData(requestContext); @@ -195,4 +195,4 @@ export function filterMatchesToLoad(prevMatches: RouteMatch[], currentMatches: R return currentMatches.filter((match, index) => { return isNew(match, index) || matchPathChanged(match, index); }); -} \ No newline at end of file +}