Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@
"changelog": "@changesets/cli/changelog",
"commit": true,
"fixed": [
["helux", "@helux/core", "@helux/openinula", "@helux/hooks", "@helux/hooks-impl", "@helux/types", "@helux/utils"]
[
"helux",
"@helux/core",
"@helux/openinula",
"@helux/hooks",
"@helux/hooks-impl",
"@helux/types",
"@helux/utils"
]
],
"linked": [],
"access": "restricted",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
# 如果配置 themeConfig.lastUpdated 为 false,则不需要添加该参数以加快检出速度
fetch-depth: 0
- name: Install pnpm
run: npm install -g pnpm@7.9.5
run: npm install -g pnpm@10.5.2
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Build helux libs
Expand Down
5 changes: 4 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ fixtures
*.yaml
*.less
.turbo
.changeset
docs
doc/src/components
./.changeset/config.json
packages/f-guard/__tests__
packages/helux-core/src/helpers/state.ts
5 changes: 5 additions & 0 deletions PUB.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@

3. 发布时执行 `pnpm changeset publish`

```bash
# 需要补充 otp 值
pnpm changeset publish --otp=xxxxxx
```

发布配置见 `.changeset/config.json` 文件
2 changes: 1 addition & 1 deletion docs/docs/api/utils/mark-raw.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { markRaw, atom } from 'helux';
const [ state, setState, ctx ] = atom({ a: { } });

setState(draft=>{
draft.a.k1 = markRaw(AComplexThridObject);
draft.a.k1 = markRaw(aComplexThirdObject);
});

function Demo(){
Expand Down
81 changes: 45 additions & 36 deletions docs/docs/playground/demos/Playground/Tools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,54 @@
*
*
*/
import React, { useCallback } from "react";
import { codeContext, setCodeContext } from "./codeContext";
import React from "react";
import { IconButton } from "./icons/IconButton";
import localforage from 'localforage';

const stControlWrap: React.CSSProperties = { width: '156px', transform: 'translateX(-105px)' };
const stWrap: React.CSSProperties = {
position: "absolute",
display: "flex",
flexDirection: "column",
padding: "8px",
boxSizing: "border-box",
backgroundColor: "transparent",
left: "50%",
top: "26px",
width: "60px",
transform: 'translateX(-15px)',
};

export const Tools: React.FC = () => {
export const Tools: React.FC<any> = (props) => {
const { mode, onControlClick, onRunClick, copyUrl, saveCode, resetCode, recoverCode } = props;
const liveBtnStyle = mode === 'live' ? { backgroundColor: 'lightskyblue' } : {};
const lagBtnStyle = mode === 'lag' ? { backgroundColor: 'lightskyblue' } : {};
const manualBtnStyle = mode === 'manual' ? { backgroundColor: 'lightskyblue' } : {};

const saveCode = useCallback(() => {
localforage.setItem(`helux_code_${codeContext.key}`, codeContext.code, (err) => {
if (err) {
console.error(err)
} else {
console.info('code is saved')
}
})
}, [])

const resetCode = useCallback(() => {
localforage.removeItem(`helux_code_${codeContext.key}`, (err) => {
if (!err) {
setCodeContext(draft => { draft.code = '' })
}
})
}, [])

return <div style={{
position: "absolute",
display: "flex",
flexDirection: "column",
padding: "8px",
boxSizing: "border-box",
backgroundColor: "transparent",
left: "50%",
top: "36px",
width: "60px",
right: "10px",
}}>
<IconButton name="save" title="保存代码" onClick={() => saveCode()} />
<IconButton name="reset" title="恢复代码" onClick={() => resetCode()} />
return <div style={stWrap}>
<div style={stControlWrap}>
<IconButton
name="实时"
title="预览区实时响应编辑器代码"
style={liveBtnStyle}
onClick={() => onControlClick('live')}
/>
<IconButton
name="延时"
title="预览区延时响应编辑器代码"
style={lagBtnStyle}
onClick={() => onControlClick('lag')}
/>
<IconButton
name="手动"
title="手动点击运行后,预览区才响应编辑器代码"
style={manualBtnStyle}
onClick={() => onControlClick('manual')}
/>
</div>
<IconButton name="重置" title="重置代码" onClick={resetCode} />
{(mode === 'manual' || mode === 'lag') && <IconButton name="保存" title="保存代码" onClick={() => saveCode()} />}
<IconButton name="恢复" title="恢复保存代码" onClick={recoverCode} />
{mode === 'manual' && <IconButton name="运行" title="运行代码" onClick={() => onRunClick?.()} />}
<IconButton name="copy" title="复制当前示例链接" onClick={() => copyUrl?.()} />
</div>
}
3 changes: 2 additions & 1 deletion docs/docs/playground/demos/Playground/codes/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ const change = () => {
// draft was already unboxed from { val: T } to T
draft.b.b1.b2 += 100;
})
console.log('dict.val.b.b1.b2 is ', dict.val.b.b1.b2);
console.log('proxy dict.val.b ', dict.val.b);
console.log('original dict.val.b ', limu.original(dict.val.b));
};

render(<button onClick={ change } > change { $(dict.val.b.b1.b2)}</button>);
Expand Down
37 changes: 22 additions & 15 deletions docs/docs/playground/demos/Playground/icons/IconButton.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { ReactNode,ButtonHTMLAttributes } from "react"
import { ReactNode, ButtonHTMLAttributes } from "react"
import { ResetIcon } from "./Reset"
import { SaveIcon } from "./Save"

export interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
name:"save" | 'reset'
export interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
name: string;
}

const icons:Record<string,ReactNode> = {
save:<SaveIcon/>,
reset:<ResetIcon/>
const defaultStyle = {
width: "52px",
height: "28x",
cursor: "pointer",
borderRadius: "12px",
textAlign: 'center',
};

const icons: Record<string, ReactNode> = {
save: <SaveIcon />,
reset: <ResetIcon />,
run: 'Run',
copy: 'Copy',
}
export const IconButton:React.FC<IconButtonProps> = (props)=>{
return <button style={{
margin:"4px",
width:"32px",
height:"32px",
padding:"8px",
cursor:"pointer",
borderRadius:"24px"
}} {...props} type="button">{icons[props.name]}</button>
export const IconButton: React.FC<IconButtonProps> = (props) => {
const { name, style, ...rest } = props;
console.log('style', style);
const uiName = icons[name] || name;
const stBtn = Object.assign({}, defaultStyle, style || {});
return <button style={stBtn} {...rest} type="button">{uiName}</button>
}
95 changes: 86 additions & 9 deletions docs/docs/playground/demos/Playground/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import React, { useCallback, useEffect } from 'react'
import { LiveProvider, LiveEditor, LiveError, LivePreview } from "react-live";
import copyTo from 'copy-to-clipboard';
import qs from "qs";
import * as prism from 'prism-react-renderer';
import * as helux from 'helux';
import { useWatch } from 'helux';
import localforage from 'localforage';
// TODO toast 无效
// import { toast } from 'react-toastify';

import ApiMenus from './ApiMenus';
import TopBar from './TopBar';
import Console from './Console';
import * as codes from './codes';
import './index.less';
// import { Tools } from './Tools';
import { Tools } from './Tools';
import { setCodeContext, codeContext } from './codeContext';
import localforage from 'localforage';

function getCode(name: any, subName: any) {
const codeDict: any = codes;
Expand Down Expand Up @@ -44,9 +47,55 @@ function loadCode(name: any, subName: any, setCode: any) {
})
}

let timer: any;

function useLogic(name = 'atom', subName = 'primitive') {
const [info, setInfo] = React.useState({ name, subName });
const [code, setCode] = React.useState(initCode);
const [mode, setMode] = React.useState('live'); // live lag manual
const [compKey, setCompKey] = React.useState(Date.now());
const codeCacheRef = React.useRef(code);

const clickRun = () => {
setCode(codeCacheRef.current);
setCompKey(Date.now());
};
const onControlClick = (mode: string) => {
setMode(mode);
};
const copyUrl = () => {
const url = `${window.location.origin}?n=${info.name}&s=${info.subName}`;
copyTo(url);
console.log('复制当前示例分享链接成功', url);
};
const saveCode = () => {
localforage.setItem(`helux_code_${info.name}_${info.subName}`, codeCacheRef.current, (err) => {
if (err) {
return console.log(err);
}
console.log('保存成功');
});
};
const changeEditorCode = (value: string) => {
codeCacheRef.current = value;
setCode(value);
setCompKey(Date.now());
};
const recoverCode = () => {
localforage.getItem(`helux_code_${info.name}_${info.subName}`, (err, value: string | null) => {
if (err) {
return alert(err.message);
}
if (!value) {
return alert('无最近保存的代码可恢复');
}
changeEditorCode(value);
});
};
const resetCode = () => {
changeEditorCode(getCode(info.name, info.subName));
console.log('重置示例代码成功');
};

useEffect(() => {
loadCode(name, subName, setCode);
Expand Down Expand Up @@ -77,12 +126,28 @@ function useLogic(name = 'atom', subName = 'primitive') {
loadCode(name, subName, setCode);
}, [info.name, info.subName]);

return { info, code, changeCode, changeSubName };
const onEditorCodeChange = (value: string) => {
if (mode !== 'lag') {
// 是手动,仅保存代码
codeCacheRef.current = value;
return;
}
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
changeEditorCode(value);
}, 1000);
};

return {
info, code, changeCode, changeSubName, onControlClick, mode, compKey, clickRun,
onEditorCodeChange, copyUrl, saveCode, resetCode, recoverCode, changeEditorCode,
};
}

export function SimplePlayground() {
const { info, code, changeCode, changeSubName } = useLogic('quickStart', 'HelloHelux');

return (
<LiveProvider noInline={true} code={code} scope={scope} theme={prism.themes.vsDark}>
<div className="simple-playground-wrap">
Expand Down Expand Up @@ -110,9 +175,13 @@ export function SimplePlayground() {
}

export default () => {
const { info, code, changeCode, changeSubName } = useLogic(name, subName);
const {
info, code, changeCode, changeSubName, onControlClick, mode, clickRun, compKey,
onEditorCodeChange, copyUrl, saveCode, resetCode, recoverCode,
} = useLogic(name, subName);

return (
<LiveProvider noInline={true} code={code} scope={scope} theme={prism.themes.vsDark}>
<LiveProvider key={compKey} noInline={true} code={code} scope={scope} theme={prism.themes.vsDark}>
<div className="playground-wrap">
<div className="leftMenuWrap">
<ApiMenus onClick={changeCode} name={info.name} />
Expand All @@ -121,9 +190,17 @@ export default () => {
<TopBar onClick={changeSubName} name={info.name} subName={info.subName} />
<div style={{ display: "flex", height: '100%', padding: '0 2px' }}>
<div style={{ flex: "1 1 0px", height: '100%' }}>
{/* <LiveEditor style={{ flexGrow: 1 }} onChange={value => { setCodeContext(draft => { draft.code = value }) }} /> */}
<LiveEditor style={{ flexGrow: 1 }} />
{/* <Tools /> */}
{mode === 'live' && <LiveEditor style={{ flexGrow: 1 }} />}
{mode !== 'live' && <LiveEditor style={{ flexGrow: 1 }} onChange={onEditorCodeChange} />}
<Tools
onRunClick={clickRun}
onControlClick={onControlClick}
copyUrl={copyUrl}
mode={mode}
saveCode={saveCode}
resetCode={resetCode}
recoverCode={recoverCode}
/>
</div>
<div style={{ flex: "1 1 0px", height: 'calc(100vh - 118px)' }}>
<div style={{ height: '50%', padding: '12px', boxSizing: 'border-box', border: '1px solid #e8ae56' }}>
Expand Down
9 changes: 5 additions & 4 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"animated-scroll-to": "^2.3.0",
"classnames": "^2.5.0",
"console-feed": "^3.5.0",
"copy-to-clipboard": "^3.3.3",
"helux": "latest",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
Expand All @@ -70,8 +71,8 @@
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"@types/qs": "^6.9.11",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react": "18.0.0",
"@types/react-dom": "18.0.0",
"@umijs/lint": "^4.0.0",
"dumi": "^2.2.16",
"eslint": "^8.23.0",
Expand All @@ -81,8 +82,8 @@
"prettier": "^2.7.1",
"prettier-plugin-organize-imports": "^3.0.0",
"prettier-plugin-packagejson": "^2.2.18",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react": "18.0.0",
"react-dom": "18.0.0",
"stylelint": "^14.9.1"
},
"peerDependencies": {
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "helux",
"version": "5.4.6",
"version": "5.5.6",
"description": "A reactive atomic state engine for React(including React 18) and all React like, carrying dependency collection feature, supporting fine-grained updates",
"keywords": [],
"author": {
Expand All @@ -21,7 +21,8 @@
"doc": "pnpm --filter=hel-doc run build && npm run cpdoc",
"doc2": "pnpm --filter=helux-docs run docs:build",
"docs:build": "pnpm --filter=helux-docs run docs:build",
"format": "prettier --cache --write . '!./pnpm-lock.yaml' '!./doc/src/components' '!./docs' --ignore-path .prettierignore .gitignore --ignore-unknown",
"format": "prettier --cache --write .",
"format2": "prettier --cache --write . '!./pnpm-lock.yaml' '!./doc/src/components' '!./docs' --ignore-path .prettierignore .gitignore --ignore-unknown",
"limu": "pnpm i limu@latest --filter @helux/core",
"prepare": "husky install",
"release:all": "changeset publish",
Expand Down
Loading