create-rspeedy 0.13.5 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/index.js +36 -32
- package/package.json +5 -5
- package/template-react-js/src/App.jsx +8 -2
- package/template-react-js/src/lib/flappy.js +58 -0
- package/template-react-js/src/useFlappy.js +37 -0
- package/template-react-ts/src/App.tsx +8 -2
- package/template-react-ts/src/lib/flappy.ts +76 -0
- package/template-react-ts/src/useFlappy.ts +49 -0
- package/template-react-vitest-rltl/package.json +10 -0
- package/template-react-vitest-rltl/src/__tests__/index.test.jsx +17 -0
- package/template-react-vitest-rltl-js/lynx.config.js +0 -19
- package/template-react-vitest-rltl-js/package.json +0 -26
- package/template-react-vitest-rltl-js/src/App.jsx +0 -53
- package/template-react-vitest-rltl-js/src/__tests__/index.test.jsx +0 -102
- package/template-react-vitest-rltl-js/src/index.jsx +0 -11
- package/template-react-vitest-rltl-ts/lynx.config.ts +0 -18
- package/template-react-vitest-rltl-ts/package.json +0 -30
- package/template-react-vitest-rltl-ts/src/App.tsx +0 -55
- package/template-react-vitest-rltl-ts/src/__tests__/index.test.tsx +0 -102
- package/template-react-vitest-rltl-ts/src/index.tsx +0 -11
- package/template-react-vitest-rltl-ts/src/rspeedy-env.d.ts +0 -1
- package/template-react-vitest-rltl-ts/src/tsconfig.json +0 -15
- package/template-react-vitest-rltl-ts/tsconfig.json +0 -17
- package/template-react-vitest-rltl-ts/tsconfig.node.json +0 -21
- package/template-react-vitest-rltl-ts/vitest.config.ts +0 -9
- /package/{template-react-vitest-rltl-js → template-react-vitest-rltl}/vitest.config.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# create-rspeedy
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add optional Lynx DevTool skill. ([#2421](https://github.com/lynx-family/lynx-stack/pull/2421))
|
|
8
|
+
|
|
9
|
+
- move Vitest integration to create-rstack extraTools and merge the Vitest templates into a single incremental overlay ([#2408](https://github.com/lynx-family/lynx-stack/pull/2408))
|
|
10
|
+
|
|
11
|
+
## 0.13.6
|
|
12
|
+
|
|
3
13
|
## 0.13.5
|
|
4
14
|
|
|
5
15
|
## 0.13.4
|
package/dist/index.js
CHANGED
|
@@ -2,24 +2,18 @@
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import node_path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { checkCancel,
|
|
5
|
+
import { checkCancel, copyFolder, create, select as external_create_rstack_select } from "create-rstack";
|
|
6
6
|
const src_dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
const src_require = createRequire(import.meta.url);
|
|
8
8
|
const { devDependencies: devDependencies } = src_require('../package.json');
|
|
9
|
-
const composeTemplateName = ({ template,
|
|
10
|
-
const toolsKeys = (tools ? Object.keys(tools) : []).sort();
|
|
11
|
-
const toolsStr = toolsKeys.length > 0 ? `-${toolsKeys.join('-')}` : '';
|
|
12
|
-
return `${template}${toolsStr}-${lang}`;
|
|
13
|
-
};
|
|
9
|
+
const composeTemplateName = ({ template, lang })=>`${template}-${lang}`;
|
|
14
10
|
const TEMPLATES = [
|
|
15
11
|
{
|
|
16
12
|
template: 'react',
|
|
17
|
-
tools: {},
|
|
18
13
|
lang: 'ts'
|
|
19
14
|
},
|
|
20
15
|
{
|
|
21
16
|
template: 'react',
|
|
22
|
-
tools: {},
|
|
23
17
|
lang: 'js'
|
|
24
18
|
}
|
|
25
19
|
];
|
|
@@ -30,7 +24,10 @@ async function getTemplateName({ template }) {
|
|
|
30
24
|
if (lang && [
|
|
31
25
|
'js',
|
|
32
26
|
'ts'
|
|
33
|
-
].includes(lang))
|
|
27
|
+
].includes(lang)) {
|
|
28
|
+
if ('react' === pair[0]) return `react-${lang}`;
|
|
29
|
+
return template;
|
|
30
|
+
}
|
|
34
31
|
return `${template}-ts`;
|
|
35
32
|
}
|
|
36
33
|
const language = checkCancel(await external_create_rstack_select({
|
|
@@ -47,41 +44,48 @@ async function getTemplateName({ template }) {
|
|
|
47
44
|
}
|
|
48
45
|
]
|
|
49
46
|
}));
|
|
50
|
-
const tools = checkCancel(await multiselect({
|
|
51
|
-
message: 'Select development tools (Use <space> to select, <enter> to continue)',
|
|
52
|
-
required: false,
|
|
53
|
-
options: [
|
|
54
|
-
{
|
|
55
|
-
value: 'vitest-rltl',
|
|
56
|
-
label: 'Add ReactLynx Testing Library for unit testing'
|
|
57
|
-
}
|
|
58
|
-
],
|
|
59
|
-
initialValues: [
|
|
60
|
-
'vitest-rltl'
|
|
61
|
-
]
|
|
62
|
-
}));
|
|
63
47
|
return composeTemplateName({
|
|
64
48
|
template: 'react',
|
|
65
|
-
lang: language
|
|
66
|
-
tools: Object.fromEntries(tools.map((tool)=>[
|
|
67
|
-
tool,
|
|
68
|
-
tool
|
|
69
|
-
]))
|
|
49
|
+
lang: language
|
|
70
50
|
});
|
|
71
51
|
}
|
|
72
52
|
create({
|
|
73
53
|
root: node_path.resolve(src_dirname, '..'),
|
|
74
54
|
name: 'rspeedy',
|
|
75
|
-
templates: TEMPLATES.map(({ template,
|
|
55
|
+
templates: TEMPLATES.map(({ template, lang })=>composeTemplateName({
|
|
76
56
|
template,
|
|
77
|
-
lang
|
|
78
|
-
tools
|
|
57
|
+
lang
|
|
79
58
|
})),
|
|
80
59
|
version: devDependencies,
|
|
81
60
|
getTemplateName: getTemplateName,
|
|
61
|
+
extraTools: [
|
|
62
|
+
{
|
|
63
|
+
value: 'vitest-rltl',
|
|
64
|
+
label: 'ReactLynx Testing Library - unit testing',
|
|
65
|
+
order: 'pre',
|
|
66
|
+
when: (templateName)=>'react-js' === templateName || 'react-ts' === templateName,
|
|
67
|
+
action: ({ distFolder, addAgentsMdSearchDirs })=>{
|
|
68
|
+
const from = node_path.resolve(src_dirname, '..', 'template-react-vitest-rltl');
|
|
69
|
+
copyFolder({
|
|
70
|
+
from,
|
|
71
|
+
to: distFolder,
|
|
72
|
+
isMergePackageJson: true
|
|
73
|
+
});
|
|
74
|
+
addAgentsMdSearchDirs(from);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
extraSkills: [
|
|
79
|
+
{
|
|
80
|
+
label: 'Lynx DevTool',
|
|
81
|
+
skills: [
|
|
82
|
+
'lynx-community/skills/lynx-devtool'
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
82
86
|
mapESLintTemplate (templateName) {
|
|
83
|
-
const lang =
|
|
84
|
-
if (
|
|
87
|
+
const lang = templateName.split('-').at(-1);
|
|
88
|
+
if ('js' !== lang && 'ts' !== lang) return null;
|
|
85
89
|
switch(lang){
|
|
86
90
|
case 'js':
|
|
87
91
|
return 'react-js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-rspeedy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Create Rspeedy-powered ReactLynx apps with one command",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"webpack",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"README.md"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"create-rstack": "1.
|
|
34
|
+
"create-rstack": "1.9.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@rsbuild/plugin-type-check": "1.3.4",
|
|
38
38
|
"@lynx-js/qrcode-rsbuild-plugin": "^0.4.6",
|
|
39
|
-
"@lynx-js/react": "^0.
|
|
40
|
-
"@lynx-js/react-rsbuild-plugin": "^0.
|
|
41
|
-
"@lynx-js/rspeedy": "^0.
|
|
39
|
+
"@lynx-js/react": "^0.117.1",
|
|
40
|
+
"@lynx-js/react-rsbuild-plugin": "^0.14.0",
|
|
41
|
+
"@lynx-js/rspeedy": "^0.14.0"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=18"
|
|
@@ -4,9 +4,11 @@ import './App.css'
|
|
|
4
4
|
import arrow from './assets/arrow.png'
|
|
5
5
|
import lynxLogo from './assets/lynx-logo.png'
|
|
6
6
|
import reactLynxLogo from './assets/react-logo.png'
|
|
7
|
+
import { useFlappy } from './useFlappy.js'
|
|
7
8
|
|
|
8
9
|
export function App() {
|
|
9
10
|
const [alterLogo, setAlterLogo] = useState(false)
|
|
11
|
+
const [logoY, jump] = useFlappy()
|
|
10
12
|
|
|
11
13
|
useEffect(() => {
|
|
12
14
|
console.info('Hello, ReactLynx')
|
|
@@ -18,11 +20,15 @@ export function App() {
|
|
|
18
20
|
}, [])
|
|
19
21
|
|
|
20
22
|
return (
|
|
21
|
-
<view>
|
|
23
|
+
<view bindtap={jump}>
|
|
22
24
|
<view className='Background' />
|
|
23
25
|
<view className='App'>
|
|
24
26
|
<view className='Banner'>
|
|
25
|
-
<view
|
|
27
|
+
<view
|
|
28
|
+
className='Logo'
|
|
29
|
+
style={{ transform: `translateY(${logoY}px)` }}
|
|
30
|
+
bindtap={onTap}
|
|
31
|
+
>
|
|
26
32
|
{alterLogo
|
|
27
33
|
? <image src={reactLynxLogo} className='Logo--react' />
|
|
28
34
|
: <image src={lynxLogo} className='Logo--lynx' />}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic flappy-bird physics engine.
|
|
3
|
+
*
|
|
4
|
+
* Manages gravity, jump impulse, and a 60fps game loop.
|
|
5
|
+
* Wire it up to any UI framework by calling `jump()` on tap
|
|
6
|
+
* and reading `getY()` in the loop callback.
|
|
7
|
+
*
|
|
8
|
+
* @param {(y: number) => void} onUpdate
|
|
9
|
+
* @param {object} [options]
|
|
10
|
+
* @param {number} [options.gravity=0.6]
|
|
11
|
+
* @param {number} [options.jumpForce=-12]
|
|
12
|
+
* @param {number} [options.stackFactor=0.6]
|
|
13
|
+
* @param {number} [options.frameMs=16]
|
|
14
|
+
* @returns {{ jump: () => void, getY: () => number, destroy: () => void }}
|
|
15
|
+
*/
|
|
16
|
+
export function createFlappy(onUpdate, options = {}) {
|
|
17
|
+
const {
|
|
18
|
+
gravity = 0.6,
|
|
19
|
+
jumpForce = -12,
|
|
20
|
+
stackFactor = 0.6,
|
|
21
|
+
frameMs = 16,
|
|
22
|
+
} = options
|
|
23
|
+
|
|
24
|
+
let y = 0
|
|
25
|
+
let velocity = 0
|
|
26
|
+
let timer = null
|
|
27
|
+
|
|
28
|
+
function loop() {
|
|
29
|
+
velocity += gravity
|
|
30
|
+
y += velocity
|
|
31
|
+
if (y >= 0) {
|
|
32
|
+
y = 0
|
|
33
|
+
velocity = 0
|
|
34
|
+
timer = null
|
|
35
|
+
onUpdate(y)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
onUpdate(y)
|
|
39
|
+
timer = setTimeout(loop, frameMs)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function jump() {
|
|
43
|
+
// Stack impulse on rapid taps, clamped to one full jumpForce
|
|
44
|
+
velocity = Math.max(velocity + jumpForce * stackFactor, jumpForce)
|
|
45
|
+
if (!timer) {
|
|
46
|
+
loop()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function destroy() {
|
|
51
|
+
if (timer) {
|
|
52
|
+
clearTimeout(timer)
|
|
53
|
+
timer = null
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { jump, getY: () => y, destroy }
|
|
58
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from '@lynx-js/react'
|
|
2
|
+
|
|
3
|
+
import { createFlappy } from './lib/flappy.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* React hook for flappy-bird physics.
|
|
7
|
+
*
|
|
8
|
+
* Returns `[y, jump]` — a state value and a stable callback.
|
|
9
|
+
* The game loop runs automatically; cleanup happens on unmount.
|
|
10
|
+
* Options are read once on mount and not reactive to later changes.
|
|
11
|
+
*
|
|
12
|
+
* @param {object} [options]
|
|
13
|
+
* @returns {[number, () => void]}
|
|
14
|
+
*/
|
|
15
|
+
export function useFlappy(options) {
|
|
16
|
+
const [y, setY] = useState(0)
|
|
17
|
+
const engineRef = useRef(null)
|
|
18
|
+
|
|
19
|
+
if (engineRef.current == null) {
|
|
20
|
+
engineRef.current = createFlappy((newY) => {
|
|
21
|
+
setY(newY)
|
|
22
|
+
}, options)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
return () => {
|
|
27
|
+
engineRef.current?.destroy()
|
|
28
|
+
}
|
|
29
|
+
}, [])
|
|
30
|
+
|
|
31
|
+
const jump = useCallback(() => {
|
|
32
|
+
'background only'
|
|
33
|
+
engineRef.current?.jump()
|
|
34
|
+
}, [])
|
|
35
|
+
|
|
36
|
+
return [y, jump]
|
|
37
|
+
}
|
|
@@ -4,9 +4,11 @@ import './App.css'
|
|
|
4
4
|
import arrow from './assets/arrow.png'
|
|
5
5
|
import lynxLogo from './assets/lynx-logo.png'
|
|
6
6
|
import reactLynxLogo from './assets/react-logo.png'
|
|
7
|
+
import { useFlappy } from './useFlappy.js'
|
|
7
8
|
|
|
8
9
|
export function App() {
|
|
9
10
|
const [alterLogo, setAlterLogo] = useState(false)
|
|
11
|
+
const [logoY, jump] = useFlappy()
|
|
10
12
|
|
|
11
13
|
useEffect(() => {
|
|
12
14
|
console.info('Hello, ReactLynx')
|
|
@@ -18,11 +20,15 @@ export function App() {
|
|
|
18
20
|
}, [])
|
|
19
21
|
|
|
20
22
|
return (
|
|
21
|
-
<view>
|
|
23
|
+
<view bindtap={jump}>
|
|
22
24
|
<view className='Background' />
|
|
23
25
|
<view className='App'>
|
|
24
26
|
<view className='Banner'>
|
|
25
|
-
<view
|
|
27
|
+
<view
|
|
28
|
+
className='Logo'
|
|
29
|
+
style={{ transform: `translateY(${logoY}px)` }}
|
|
30
|
+
bindtap={onTap}
|
|
31
|
+
>
|
|
26
32
|
{alterLogo
|
|
27
33
|
? <image src={reactLynxLogo} className='Logo--react' />
|
|
28
34
|
: <image src={lynxLogo} className='Logo--lynx' />}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic flappy-bird physics engine.
|
|
3
|
+
*
|
|
4
|
+
* Manages gravity, jump impulse, and a 60fps game loop.
|
|
5
|
+
* Wire it up to any UI framework by calling `jump()` on tap
|
|
6
|
+
* and reading `getY()` in the loop callback.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface FlappyOptions {
|
|
10
|
+
/** Downward acceleration per frame (default 0.6) */
|
|
11
|
+
gravity?: number
|
|
12
|
+
/** Upward impulse per tap — negative value (default -12) */
|
|
13
|
+
jumpForce?: number
|
|
14
|
+
/** Impulse stacking factor for rapid taps (default 0.6) */
|
|
15
|
+
stackFactor?: number
|
|
16
|
+
/** Frame interval in ms (default 16 ≈ 60fps) */
|
|
17
|
+
frameMs?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type OnUpdate = (y: number) => void
|
|
21
|
+
|
|
22
|
+
export interface FlappyEngine {
|
|
23
|
+
/** Call on each tap to apply upward impulse. */
|
|
24
|
+
jump(): void
|
|
25
|
+
/** Current Y offset (0 = ground, negative = airborne). */
|
|
26
|
+
getY(): number
|
|
27
|
+
/** Stop the game loop and clean up. */
|
|
28
|
+
destroy(): void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function createFlappy(
|
|
32
|
+
onUpdate: OnUpdate,
|
|
33
|
+
options: FlappyOptions = {},
|
|
34
|
+
): FlappyEngine {
|
|
35
|
+
const {
|
|
36
|
+
gravity = 0.6,
|
|
37
|
+
jumpForce = -12,
|
|
38
|
+
stackFactor = 0.6,
|
|
39
|
+
frameMs = 16,
|
|
40
|
+
} = options
|
|
41
|
+
|
|
42
|
+
let y = 0
|
|
43
|
+
let velocity = 0
|
|
44
|
+
let timer: ReturnType<typeof setTimeout> | null = null
|
|
45
|
+
|
|
46
|
+
function loop() {
|
|
47
|
+
velocity += gravity
|
|
48
|
+
y += velocity
|
|
49
|
+
if (y >= 0) {
|
|
50
|
+
y = 0
|
|
51
|
+
velocity = 0
|
|
52
|
+
timer = null
|
|
53
|
+
onUpdate(y)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
onUpdate(y)
|
|
57
|
+
timer = setTimeout(loop, frameMs)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function jump() {
|
|
61
|
+
// Stack impulse on rapid taps, clamped to one full jumpForce
|
|
62
|
+
velocity = Math.max(velocity + jumpForce * stackFactor, jumpForce)
|
|
63
|
+
if (!timer) {
|
|
64
|
+
loop()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function destroy() {
|
|
69
|
+
if (timer) {
|
|
70
|
+
clearTimeout(timer)
|
|
71
|
+
timer = null
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { jump, getY: () => y, destroy }
|
|
76
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from '@lynx-js/react'
|
|
2
|
+
|
|
3
|
+
import { createFlappy } from './lib/flappy.js'
|
|
4
|
+
import type { FlappyEngine, FlappyOptions } from './lib/flappy.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* React hook for flappy-bird physics.
|
|
8
|
+
*
|
|
9
|
+
* Returns `[y, jump]` — a state value and a stable callback.
|
|
10
|
+
* The game loop runs automatically; cleanup happens on unmount.
|
|
11
|
+
* Options are read once on mount and not reactive to later changes.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* function Bird() {
|
|
16
|
+
* const [y, jump] = useFlappy()
|
|
17
|
+
* return (
|
|
18
|
+
* <view bindtap={jump} style={{ transform: `translateY(${y}px)` }}>
|
|
19
|
+
* <text>Tap me!</text>
|
|
20
|
+
* </view>
|
|
21
|
+
* )
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function useFlappy(
|
|
26
|
+
options?: FlappyOptions,
|
|
27
|
+
): [number, () => void] {
|
|
28
|
+
const [y, setY] = useState(0)
|
|
29
|
+
const engineRef = useRef<FlappyEngine | null>(null)
|
|
30
|
+
|
|
31
|
+
if (engineRef.current == null) {
|
|
32
|
+
engineRef.current = createFlappy((newY) => {
|
|
33
|
+
setY(newY)
|
|
34
|
+
}, options)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
return () => {
|
|
39
|
+
engineRef.current?.destroy()
|
|
40
|
+
}
|
|
41
|
+
}, [])
|
|
42
|
+
|
|
43
|
+
const jump = useCallback(() => {
|
|
44
|
+
'background only'
|
|
45
|
+
engineRef.current?.jump()
|
|
46
|
+
}, [])
|
|
47
|
+
|
|
48
|
+
return [y, jump]
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright 2024 The Lynx Authors. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
import '@testing-library/jest-dom'
|
|
5
|
+
import { expect, test } from 'vitest'
|
|
6
|
+
import { getQueriesForElement, render } from '@lynx-js/react/testing-library'
|
|
7
|
+
|
|
8
|
+
import { App } from '../App'
|
|
9
|
+
|
|
10
|
+
test('App', async () => {
|
|
11
|
+
render(<App />)
|
|
12
|
+
|
|
13
|
+
const { findByText } = getQueriesForElement(elementTree.root)
|
|
14
|
+
const element = await findByText('Tap the logo and have fun!')
|
|
15
|
+
|
|
16
|
+
expect(element).toBeInTheDocument()
|
|
17
|
+
})
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from '@lynx-js/rspeedy'
|
|
2
|
-
|
|
3
|
-
import { pluginQRCode } from '@lynx-js/qrcode-rsbuild-plugin'
|
|
4
|
-
import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'
|
|
5
|
-
|
|
6
|
-
export default defineConfig({
|
|
7
|
-
source: {
|
|
8
|
-
entry: './src/index.jsx',
|
|
9
|
-
},
|
|
10
|
-
plugins: [
|
|
11
|
-
pluginQRCode({
|
|
12
|
-
schema(url) {
|
|
13
|
-
// We use `?fullscreen=true` to open the page in LynxExplorer in full screen mode
|
|
14
|
-
return `${url}?fullscreen=true`
|
|
15
|
-
},
|
|
16
|
-
}),
|
|
17
|
-
pluginReactLynx(),
|
|
18
|
-
],
|
|
19
|
-
})
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "rspeedy-react-js",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"type": "module",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"build": "rspeedy build",
|
|
7
|
-
"dev": "rspeedy dev",
|
|
8
|
-
"preview": "rspeedy preview",
|
|
9
|
-
"test": "vitest run"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@lynx-js/react": "workspace:*"
|
|
13
|
-
},
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
"@lynx-js/preact-devtools": "^5.0.1",
|
|
16
|
-
"@lynx-js/qrcode-rsbuild-plugin": "workspace:*",
|
|
17
|
-
"@lynx-js/react-rsbuild-plugin": "workspace:*",
|
|
18
|
-
"@lynx-js/rspeedy": "workspace:*",
|
|
19
|
-
"@testing-library/jest-dom": "^6.9.1",
|
|
20
|
-
"jsdom": "^27.4.0",
|
|
21
|
-
"vitest": "^3.2.4"
|
|
22
|
-
},
|
|
23
|
-
"engines": {
|
|
24
|
-
"node": ">=18"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from '@lynx-js/react'
|
|
2
|
-
|
|
3
|
-
import './App.css'
|
|
4
|
-
import arrow from './assets/arrow.png'
|
|
5
|
-
import lynxLogo from './assets/lynx-logo.png'
|
|
6
|
-
import reactLynxLogo from './assets/react-logo.png'
|
|
7
|
-
|
|
8
|
-
export function App(props) {
|
|
9
|
-
const [alterLogo, setAlterLogo] = useState(false)
|
|
10
|
-
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
console.info('Hello, ReactLynx')
|
|
13
|
-
}, [])
|
|
14
|
-
props.onRender?.()
|
|
15
|
-
|
|
16
|
-
const onTap = useCallback(() => {
|
|
17
|
-
'background only'
|
|
18
|
-
setAlterLogo(prevAlterLogo => !prevAlterLogo)
|
|
19
|
-
}, [])
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<view>
|
|
23
|
-
<view className='Background' />
|
|
24
|
-
<view className='App'>
|
|
25
|
-
<view className='Banner'>
|
|
26
|
-
<view className='Logo' bindtap={onTap}>
|
|
27
|
-
{alterLogo
|
|
28
|
-
? <image src={reactLynxLogo} className='Logo--react' />
|
|
29
|
-
: <image src={lynxLogo} className='Logo--lynx' />}
|
|
30
|
-
</view>
|
|
31
|
-
<text className='Title'>React</text>
|
|
32
|
-
<text className='Subtitle'>on Lynx</text>
|
|
33
|
-
</view>
|
|
34
|
-
<view className='Content'>
|
|
35
|
-
<image src={arrow} className='Arrow' />
|
|
36
|
-
<text className='Description'>Tap the logo and have fun!</text>
|
|
37
|
-
<text className='Hint'>
|
|
38
|
-
Edit<text
|
|
39
|
-
style={{
|
|
40
|
-
fontStyle: 'italic',
|
|
41
|
-
color: 'rgba(255, 255, 255, 0.85)',
|
|
42
|
-
}}
|
|
43
|
-
>
|
|
44
|
-
{' src/App.tsx '}
|
|
45
|
-
</text>
|
|
46
|
-
to see updates!
|
|
47
|
-
</text>
|
|
48
|
-
</view>
|
|
49
|
-
<view style={{ flex: 1 }} />
|
|
50
|
-
</view>
|
|
51
|
-
</view>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// Copyright 2024 The Lynx Authors. All rights reserved.
|
|
2
|
-
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
-
// LICENSE file in the root directory of this source tree.
|
|
4
|
-
import '@testing-library/jest-dom'
|
|
5
|
-
import { expect, test, vi } from 'vitest'
|
|
6
|
-
import { render, getQueriesForElement } from '@lynx-js/react/testing-library'
|
|
7
|
-
|
|
8
|
-
import { App } from '../App.jsx'
|
|
9
|
-
|
|
10
|
-
test('App', async () => {
|
|
11
|
-
const cb = vi.fn()
|
|
12
|
-
|
|
13
|
-
render(
|
|
14
|
-
<App
|
|
15
|
-
onMounted={() => {
|
|
16
|
-
cb(`__MAIN_THREAD__: ${__MAIN_THREAD__}`)
|
|
17
|
-
}}
|
|
18
|
-
/>,
|
|
19
|
-
)
|
|
20
|
-
expect(cb).toBeCalledTimes(1)
|
|
21
|
-
expect(cb.mock.calls).toMatchInlineSnapshot(`
|
|
22
|
-
[
|
|
23
|
-
[
|
|
24
|
-
"__MAIN_THREAD__: false",
|
|
25
|
-
],
|
|
26
|
-
]
|
|
27
|
-
`)
|
|
28
|
-
expect(elementTree.root).toMatchInlineSnapshot(`
|
|
29
|
-
<page>
|
|
30
|
-
<view>
|
|
31
|
-
<view
|
|
32
|
-
class="Background"
|
|
33
|
-
/>
|
|
34
|
-
<view
|
|
35
|
-
class="App"
|
|
36
|
-
>
|
|
37
|
-
<view
|
|
38
|
-
class="Banner"
|
|
39
|
-
>
|
|
40
|
-
<view
|
|
41
|
-
class="Logo"
|
|
42
|
-
>
|
|
43
|
-
<image
|
|
44
|
-
class="Logo--lynx"
|
|
45
|
-
src="/src/assets/lynx-logo.png"
|
|
46
|
-
/>
|
|
47
|
-
</view>
|
|
48
|
-
<text
|
|
49
|
-
class="Title"
|
|
50
|
-
>
|
|
51
|
-
React
|
|
52
|
-
</text>
|
|
53
|
-
<text
|
|
54
|
-
class="Subtitle"
|
|
55
|
-
>
|
|
56
|
-
on Lynx
|
|
57
|
-
</text>
|
|
58
|
-
</view>
|
|
59
|
-
<view
|
|
60
|
-
class="Content"
|
|
61
|
-
>
|
|
62
|
-
<image
|
|
63
|
-
class="Arrow"
|
|
64
|
-
src="/src/assets/arrow.png"
|
|
65
|
-
/>
|
|
66
|
-
<text
|
|
67
|
-
class="Description"
|
|
68
|
-
>
|
|
69
|
-
Tap the logo and have fun!
|
|
70
|
-
</text>
|
|
71
|
-
<text
|
|
72
|
-
class="Hint"
|
|
73
|
-
>
|
|
74
|
-
Edit
|
|
75
|
-
<text
|
|
76
|
-
style="font-style:italic;color:rgba(255, 255, 255, 0.85)"
|
|
77
|
-
>
|
|
78
|
-
src/App.tsx
|
|
79
|
-
</text>
|
|
80
|
-
to see updates!
|
|
81
|
-
</text>
|
|
82
|
-
</view>
|
|
83
|
-
<view
|
|
84
|
-
style="flex:1"
|
|
85
|
-
/>
|
|
86
|
-
</view>
|
|
87
|
-
</view>
|
|
88
|
-
</page>
|
|
89
|
-
`)
|
|
90
|
-
const {
|
|
91
|
-
findByText,
|
|
92
|
-
} = getQueriesForElement(elementTree.root)
|
|
93
|
-
const element = await findByText('Tap the logo and have fun!')
|
|
94
|
-
expect(element).toBeInTheDocument()
|
|
95
|
-
expect(element).toMatchInlineSnapshot(`
|
|
96
|
-
<text
|
|
97
|
-
class="Description"
|
|
98
|
-
>
|
|
99
|
-
Tap the logo and have fun!
|
|
100
|
-
</text>
|
|
101
|
-
`)
|
|
102
|
-
})
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from '@lynx-js/rspeedy'
|
|
2
|
-
|
|
3
|
-
import { pluginQRCode } from '@lynx-js/qrcode-rsbuild-plugin'
|
|
4
|
-
import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'
|
|
5
|
-
import { pluginTypeCheck } from '@rsbuild/plugin-type-check'
|
|
6
|
-
|
|
7
|
-
export default defineConfig({
|
|
8
|
-
plugins: [
|
|
9
|
-
pluginQRCode({
|
|
10
|
-
schema(url) {
|
|
11
|
-
// We use `?fullscreen=true` to open the page in LynxExplorer in full screen mode
|
|
12
|
-
return `${url}?fullscreen=true`
|
|
13
|
-
},
|
|
14
|
-
}),
|
|
15
|
-
pluginReactLynx(),
|
|
16
|
-
pluginTypeCheck(),
|
|
17
|
-
],
|
|
18
|
-
})
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "rspeedy-react-ts",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"type": "module",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"build": "rspeedy build",
|
|
7
|
-
"dev": "rspeedy dev",
|
|
8
|
-
"preview": "rspeedy preview",
|
|
9
|
-
"test": "vitest run"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@lynx-js/react": "workspace:*"
|
|
13
|
-
},
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
"@lynx-js/preact-devtools": "^5.0.1",
|
|
16
|
-
"@lynx-js/qrcode-rsbuild-plugin": "workspace:*",
|
|
17
|
-
"@lynx-js/react-rsbuild-plugin": "workspace:*",
|
|
18
|
-
"@lynx-js/rspeedy": "workspace:*",
|
|
19
|
-
"@lynx-js/types": "3.7.0",
|
|
20
|
-
"@rsbuild/plugin-type-check": "1.3.4",
|
|
21
|
-
"@testing-library/jest-dom": "^6.9.1",
|
|
22
|
-
"@types/react": "^18.3.28",
|
|
23
|
-
"jsdom": "^27.4.0",
|
|
24
|
-
"typescript": "~5.9.3",
|
|
25
|
-
"vitest": "^3.2.4"
|
|
26
|
-
},
|
|
27
|
-
"engines": {
|
|
28
|
-
"node": ">=18"
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from '@lynx-js/react'
|
|
2
|
-
|
|
3
|
-
import './App.css'
|
|
4
|
-
import arrow from './assets/arrow.png'
|
|
5
|
-
import lynxLogo from './assets/lynx-logo.png'
|
|
6
|
-
import reactLynxLogo from './assets/react-logo.png'
|
|
7
|
-
|
|
8
|
-
export function App(props: {
|
|
9
|
-
onRender?: () => void
|
|
10
|
-
}) {
|
|
11
|
-
const [alterLogo, setAlterLogo] = useState(false)
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
console.info('Hello, ReactLynx')
|
|
15
|
-
}, [])
|
|
16
|
-
props.onRender?.()
|
|
17
|
-
|
|
18
|
-
const onTap = useCallback(() => {
|
|
19
|
-
'background only'
|
|
20
|
-
setAlterLogo(prevAlterLogo => !prevAlterLogo)
|
|
21
|
-
}, [])
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<view>
|
|
25
|
-
<view className='Background' />
|
|
26
|
-
<view className='App'>
|
|
27
|
-
<view className='Banner'>
|
|
28
|
-
<view className='Logo' bindtap={onTap}>
|
|
29
|
-
{alterLogo
|
|
30
|
-
? <image src={reactLynxLogo} className='Logo--react' />
|
|
31
|
-
: <image src={lynxLogo} className='Logo--lynx' />}
|
|
32
|
-
</view>
|
|
33
|
-
<text className='Title'>React</text>
|
|
34
|
-
<text className='Subtitle'>on Lynx</text>
|
|
35
|
-
</view>
|
|
36
|
-
<view className='Content'>
|
|
37
|
-
<image src={arrow} className='Arrow' />
|
|
38
|
-
<text className='Description'>Tap the logo and have fun!</text>
|
|
39
|
-
<text className='Hint'>
|
|
40
|
-
Edit<text
|
|
41
|
-
style={{
|
|
42
|
-
fontStyle: 'italic',
|
|
43
|
-
color: 'rgba(255, 255, 255, 0.85)',
|
|
44
|
-
}}
|
|
45
|
-
>
|
|
46
|
-
{' src/App.tsx '}
|
|
47
|
-
</text>
|
|
48
|
-
to see updates!
|
|
49
|
-
</text>
|
|
50
|
-
</view>
|
|
51
|
-
<view style={{ flex: 1 }} />
|
|
52
|
-
</view>
|
|
53
|
-
</view>
|
|
54
|
-
)
|
|
55
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// Copyright 2024 The Lynx Authors. All rights reserved.
|
|
2
|
-
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
-
// LICENSE file in the root directory of this source tree.
|
|
4
|
-
import '@testing-library/jest-dom'
|
|
5
|
-
import { expect, test, vi } from 'vitest'
|
|
6
|
-
import { render, getQueriesForElement } from '@lynx-js/react/testing-library'
|
|
7
|
-
|
|
8
|
-
import { App } from '../App.jsx'
|
|
9
|
-
|
|
10
|
-
test('App', async () => {
|
|
11
|
-
const cb = vi.fn()
|
|
12
|
-
|
|
13
|
-
render(
|
|
14
|
-
<App
|
|
15
|
-
onRender={() => {
|
|
16
|
-
cb(`__MAIN_THREAD__: ${__MAIN_THREAD__}`)
|
|
17
|
-
}}
|
|
18
|
-
/>,
|
|
19
|
-
)
|
|
20
|
-
expect(cb).toBeCalledTimes(1)
|
|
21
|
-
expect(cb.mock.calls).toMatchInlineSnapshot(`
|
|
22
|
-
[
|
|
23
|
-
[
|
|
24
|
-
"__MAIN_THREAD__: false",
|
|
25
|
-
],
|
|
26
|
-
]
|
|
27
|
-
`)
|
|
28
|
-
expect(elementTree.root).toMatchInlineSnapshot(`
|
|
29
|
-
<page>
|
|
30
|
-
<view>
|
|
31
|
-
<view
|
|
32
|
-
class="Background"
|
|
33
|
-
/>
|
|
34
|
-
<view
|
|
35
|
-
class="App"
|
|
36
|
-
>
|
|
37
|
-
<view
|
|
38
|
-
class="Banner"
|
|
39
|
-
>
|
|
40
|
-
<view
|
|
41
|
-
class="Logo"
|
|
42
|
-
>
|
|
43
|
-
<image
|
|
44
|
-
class="Logo--lynx"
|
|
45
|
-
src="/src/assets/lynx-logo.png"
|
|
46
|
-
/>
|
|
47
|
-
</view>
|
|
48
|
-
<text
|
|
49
|
-
class="Title"
|
|
50
|
-
>
|
|
51
|
-
React
|
|
52
|
-
</text>
|
|
53
|
-
<text
|
|
54
|
-
class="Subtitle"
|
|
55
|
-
>
|
|
56
|
-
on Lynx
|
|
57
|
-
</text>
|
|
58
|
-
</view>
|
|
59
|
-
<view
|
|
60
|
-
class="Content"
|
|
61
|
-
>
|
|
62
|
-
<image
|
|
63
|
-
class="Arrow"
|
|
64
|
-
src="/src/assets/arrow.png"
|
|
65
|
-
/>
|
|
66
|
-
<text
|
|
67
|
-
class="Description"
|
|
68
|
-
>
|
|
69
|
-
Tap the logo and have fun!
|
|
70
|
-
</text>
|
|
71
|
-
<text
|
|
72
|
-
class="Hint"
|
|
73
|
-
>
|
|
74
|
-
Edit
|
|
75
|
-
<text
|
|
76
|
-
style="font-style:italic;color:rgba(255, 255, 255, 0.85)"
|
|
77
|
-
>
|
|
78
|
-
src/App.tsx
|
|
79
|
-
</text>
|
|
80
|
-
to see updates!
|
|
81
|
-
</text>
|
|
82
|
-
</view>
|
|
83
|
-
<view
|
|
84
|
-
style="flex:1"
|
|
85
|
-
/>
|
|
86
|
-
</view>
|
|
87
|
-
</view>
|
|
88
|
-
</page>
|
|
89
|
-
`)
|
|
90
|
-
const {
|
|
91
|
-
findByText,
|
|
92
|
-
} = getQueriesForElement(elementTree.root!)
|
|
93
|
-
const element = await findByText('Tap the logo and have fun!')
|
|
94
|
-
expect(element).toBeInTheDocument()
|
|
95
|
-
expect(element).toMatchInlineSnapshot(`
|
|
96
|
-
<text
|
|
97
|
-
class="Description"
|
|
98
|
-
>
|
|
99
|
-
Tap the logo and have fun!
|
|
100
|
-
</text>
|
|
101
|
-
`)
|
|
102
|
-
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="@lynx-js/rspeedy/client" />
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"composite": true,
|
|
5
|
-
|
|
6
|
-
"jsx": "react-jsx",
|
|
7
|
-
"jsxImportSource": "@lynx-js/react",
|
|
8
|
-
|
|
9
|
-
"module": "ESNext",
|
|
10
|
-
"moduleResolution": "Bundler",
|
|
11
|
-
|
|
12
|
-
"noEmit": true,
|
|
13
|
-
},
|
|
14
|
-
"include": ["./**/*.ts", "./**/*.tsx"],
|
|
15
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"strict": true,
|
|
4
|
-
"isolatedModules": true,
|
|
5
|
-
"verbatimModuleSyntax": true,
|
|
6
|
-
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
"noEmit": true,
|
|
11
|
-
},
|
|
12
|
-
"references": [
|
|
13
|
-
{ "path": "./tsconfig.node.json" },
|
|
14
|
-
{ "path": "./src" },
|
|
15
|
-
],
|
|
16
|
-
"files": [],
|
|
17
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"composite": true,
|
|
5
|
-
|
|
6
|
-
// Rspeedy uses Node.js's module resolution
|
|
7
|
-
"module": "node16",
|
|
8
|
-
"moduleResolution": "node16",
|
|
9
|
-
"erasableSyntaxOnly": true,
|
|
10
|
-
|
|
11
|
-
// Node.js 18+
|
|
12
|
-
"lib": ["es2023"],
|
|
13
|
-
"target": "es2022",
|
|
14
|
-
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
},
|
|
17
|
-
"include": [
|
|
18
|
-
"./lynx.config.ts",
|
|
19
|
-
"./vitest.config.ts",
|
|
20
|
-
],
|
|
21
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { defineConfig, mergeConfig } from 'vitest/config'
|
|
2
|
-
import { createVitestConfig } from '@lynx-js/react/testing-library/vitest-config'
|
|
3
|
-
|
|
4
|
-
const defaultConfig = await createVitestConfig()
|
|
5
|
-
const config = defineConfig({
|
|
6
|
-
test: {},
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
export default mergeConfig(defaultConfig, config)
|
|
File without changes
|