ahooks#useBoolean TypeScript Examples
The following examples show how to use
ahooks#useBoolean.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: github-login.tsx From bext with MIT License | 6 votes |
LoginLink: FC = ({ children = '登录' }) => {
const [visible, { setFalse, setTrue }] = useBoolean(false);
return (
<>
<Link
underline
onClick={() => {
setTrue();
trackEvent(Events.ghLoginClick);
}}
>
{children}
</Link>
{visible ? (
<Dialog
hidden={false}
onDismiss={setFalse}
dialogContentProps={{
type: DialogType.normal,
title: '账户权限说明',
subText:
'脚本发布、更新需要仓库读写权限,请在稍后的授权登录页面中允许此权限,本站代码完全开源可放心授权,请前往更多查看。',
}}
modalProps={{ layerProps: { hostId: LAYER_HOST_ID } }}
>
<DialogFooter>
<PrimaryButton
onClick={() => (location.href = LOGIN_URL)}
text="确定登录"
/>
</DialogFooter>
</Dialog>
) : null}
</>
);
}
Example #2
Source File: index.tsx From scorpio-h5-design with MIT License | 6 votes |
function App(props: IProps) {
// TODO:组件初始值问题,暂时通过判断是否来自用户的首次输入
const [isInitial, setIsInitial] = useBoolean(true);
const { value, onChange } = props;
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
editor = new E(ref.current);
editor.config.onchange = (content:string)=>{
setIsInitial.setFalse();
onChange(content);
};
editor.create();
return () => {
editor && editor.destroy();
};
}, []);
useEffect(()=>{
if(isInitial && value && editor){
editor.txt.html(value);
}
}, [value, isInitial]);
return (
<div>
<div ref={ref}></div>
</div>
);
}
Example #3
Source File: build-preview.tsx From bext with MIT License | 5 votes |
BuildPreview: FC = () => {
const build = useBuild();
const [modalVisible, { setTrue: showModal, setFalse: hideModal }] =
useBoolean(false);
const [url, setUrl] = useState('');
const [debugWindow, setDebugWindow] = useState<Window | null>(null);
const pushScript = () => {
debugWindow?.postMessage(
{
type: 'bext/script',
payload: build,
},
'*',
);
};
return (
<div className="flex-1 flex flex-col pt-2 h-full">
<div>
<DefaultButton className="h-6 px-1 mr-2" onClick={showModal}>
调试
</DefaultButton>
<PrimaryButton className="h-6 px-1 mr-2" onClick={pushScript}>
推送脚本
</PrimaryButton>
</div>
<Modal
isOpen={modalVisible}
onDismiss={hideModal}
layerProps={{ hostId: LAYER_HOST_ID }}
>
<div className="w-[640px]">
<div className="p-4">
请先点击
<Link
href={`https://cdn.staticaly.com/gh/ikkz/bext@${BUILD_HASH}/public/lib/debug-client.user.js`}
>
此处
</Link>
安装油猴脚本,然后在下方文本框中输入需要调试的链接,点击打开。
回到开发页面后点击“推送脚本”即可让正在编写的代码在目标窗口中刷新执行。
若推送之后没有反应,请检查目标页面油猴脚本是否生效,并重新执行打开操作。
</div>
<div className="flex items-center px-4">
<TextField
className="flex-1 mr-2"
value={url}
onChange={(_, newUrl) => setUrl(newUrl || '')}
/>
<PrimaryButton
onClick={() => {
hideModal();
setDebugWindow(window.open(url));
}}
>
打开
</PrimaryButton>
</div>
</div>
</Modal>
<div className="text-sm pb-2">
脚本预览(错误警告在请按 F12 打开浏览器开发者工具查看)
</div>
<Editor
value={build}
options={{ readOnly: true }}
language="javascript"
className="flex-1"
/>
</div>
);
}
Example #4
Source File: config-setting.tsx From bext with MIT License | 4 votes |
ConfigSetting: FC = () => {
const [formKey, { inc: resetForm }] = useCounter(0);
const { draft, setDraft } = useDraft();
const [modalVisible, { setTrue: showModal, setFalse: hideModal }] =
useBoolean(false);
useEffect(() => {
if (!modalVisible) {
resetForm();
}
}, [modalVisible]);
return (
<div className="p-4">
<div className="flex items-center justify-between">
<Toggle
label="启用安装配置"
inlineLabel
checked={!!draft?.configSchema}
className="mb-0"
onChange={() =>
setDraft({
configSchema: draft?.configSchema ? undefined : DEFAULT_SCHEMA,
defaultConfig: undefined,
})
}
/>
{draft?.configSchema ? <Link onClick={showModal}>配置表单</Link> : null}
</div>
{draft?.configSchema ? (
<>
<Panel
isOpen={modalVisible}
onDismiss={hideModal}
type={PanelType.smallFluid}
headerText="配置表单"
styles={{
content: {
padding: 0,
flex: 1,
},
scrollableContent: {
minHeight: '100%',
display: 'flex',
flexDirection: 'column',
},
}}
isLightDismiss
>
{modalVisible ? <SchemaEditor /> : null}
</Panel>
<Editor
value={`// 使用示例
import config from '@bext/config';
console.log(config);
/* config = ${JSON.stringify(draft.defaultConfig, null, 2)}
具体使用方式可查看
https://bext.ketra.fun/meta/648648
*/
`}
height="200px"
language="javascript"
options={{
readOnly: true,
lineNumbers: 'off',
minimap: { enabled: false },
folding: false,
}}
/>
<Separator>配置默认值</Separator>
{draft?.configSchema ? (
<JsonSchemaForm
key={String(formKey)}
schema={draft.configSchema}
omitExtraData
liveOmit
formData={draft.defaultConfig}
onChange={({ formData }) => setDraft({ defaultConfig: formData })}
liveValidate
>
<></>
</JsonSchemaForm>
) : null}
</>
) : null}
</div>
);
}
Example #5
Source File: dev-header.tsx From bext with MIT License | 4 votes |
DevHeader: FC = () => {
const history = useHistory();
const { draft, saveDraft } = useDraft();
const [detailVisible, { setTrue: showPanel, setFalse: hidePanel }] =
useBoolean(false);
const inDev = useInDev();
useEffect(() => {
if (inDev && !draft?.id) {
showPanel();
}
}, [inDev, showPanel, draft]);
const [publishVisible, { setTrue: showPublish, setFalse: hidePublish }] =
useBoolean(false);
const theme = useTheme();
const { notify } = useNotifications();
const onDebug = async () => {
const { id, name, version, source, defaultConfig } = draft!;
if (id && name && version) {
try {
const build = await excuteCompile({
meta: {
id,
name,
version,
source: source || '',
defaultConfig,
},
});
window.ReactNativeWebView?.postMessage(
JSON.stringify({
type: 'debug',
payload: build,
}),
);
} catch (error) {
notify({
message: '编译失败,请查看控制台',
status: 'error',
});
}
} else {
notify({
message: '请填写完整 ID,名称,版本号',
status: 'warning',
});
}
};
const user = useObservableState(user$);
return (
<>
<header
className="px-6 flex items-center justify-between h-12"
style={{
borderBottom: `1px solid ${theme.semanticColors.bodyDivider}`,
}}
>
{isBextClient ? null : (
<CommandBarButton
text="返回"
iconProps={{ iconName: 'ChevronLeft' }}
className="h-8"
onClick={() => {
saveDraft();
history.goBack();
}}
/>
)}
<div>
<DefaultButton onClick={showPanel}>编辑详情</DefaultButton>
{isBextClient ? (
<DefaultButton className="ml-3" onClick={onDebug}>
调试
</DefaultButton>
) : null}
<PrimaryButton
className="ml-3"
onClick={() => {
if (user.status === 'complete') {
showPublish();
return;
}
notify({
status: 'warning',
message: '请前往更多页面登录后发布',
});
}}
>
准备发布
</PrimaryButton>
<EditDetail visible={detailVisible} hide={hidePanel} />
</div>
</header>
<Dialog
hidden={!publishVisible}
onDismiss={hidePublish}
dialogContentProps={{
type: DialogType.normal,
title: '填写版本更新信息',
}}
modalProps={{
isBlocking: false,
layerProps: { hostId: LAYER_HOST_ID },
}}
>
<PublishDialog hide={hidePublish} />
</Dialog>
</>
);
}
Example #6
Source File: install-button.tsx From bext with MIT License | 4 votes |
InstallButton: FC = () => {
const { currentMeta, metaLoading } = useMetaDetail();
const [configVisible, { setTrue: showConfig, setFalse: hideConfig }] =
useBoolean(false);
const installedChecker = useMemoizedFn((): InstallStatus => {
const box = browserMethods.call('installed', currentMeta);
if (box.code === 0) {
return box.result ? 'installed' : 'notinstalled';
}
return 'unknown';
});
const [installStatus, setInstallStatus] = useState(installedChecker);
useInterval(() => {
setInstallStatus(installedChecker);
}, 1000);
const { notify } = useNotifications();
const showUninstall =
installStatus === 'installed' && browserMethods.support('uninstall');
const onUninstall = () => {
trackEvent(Events.metaUninstall, currentMeta?.id);
console.log(
browserMethods.call('uninstall', {
...currentMeta,
author: `bext/${currentMeta?.id}`,
}),
);
};
const onInstall = (build: string) => {
trackEvent(Events.metaInstallSuccess, currentMeta?.id);
console.log(
browserMethods.call('install', {
...currentMeta,
author: `bext/${currentMeta?.id}`,
build,
}),
);
};
const { run: install, loading } = useRequest(
async () => {
const { id, name, version, source, defaultConfig } = currentMeta!;
onInstall(
await excuteCompile({
meta: { id, name, version, source, defaultConfig },
}),
);
},
{
manual: true,
onError: () =>
notify({
message: '编译失败,请点击“更多” -> “报告问题”',
status: 'error',
}),
},
);
return showUninstall ? (
<PrimaryButton
className="ml-2"
onClick={onUninstall}
disabled={metaLoading}
>
卸载
</PrimaryButton>
) : (
<>
<PrimaryButton
className="ml-2"
onClick={currentMeta?.configSchema ? showConfig : install}
text={loading ? '处理中' : '安装此版本'}
disabled={loading || metaLoading}
/>
{configVisible ? (
<ConfigInstall onInstall={onInstall} hide={hideConfig} />
) : null}
</>
);
}
Example #7
Source File: tool-sandbox.tsx From bext with MIT License | 4 votes |
ToolSandbox: FC<{
src: string;
}> = ({ src }) => {
const theme = useTheme();
const historyPush = useHistoryPush();
const [loading, { setFalse: setLoaded }] = useBoolean(true);
const ref = useRef<HTMLIFrameElement>(null);
const [jsonSchema, setJsonSchema] = useState<{
key: string;
title?: string;
schema: any;
} | null>(null);
const [formData, setFormData] = useState(null);
const [hasError, setHasError] = useState(false);
const resetForm = () => {
setJsonSchema(null);
setFormData(null);
setHasError(false);
};
const { setDraftObject } = useDraft();
useEventListener('message', (event: MessageEvent) => {
try {
const url = new URL(src);
if (![url.origin, location.origin].includes(event.origin)) {
return;
}
} catch (e) {}
const { data } = event;
switch (data.type) {
case 'bext/jsf-show':
if (data.schema) {
setJsonSchema({
key: data.key,
schema: data.schema,
});
setFormData(data.default || null);
}
break;
case 'bext/meta-install':
if (data.meta) {
browserMethods.call('install', data.meta);
}
break;
case 'bext/meta-draft':
if (data.meta) {
setDraftObject(data.meta);
historyPush(DEV_PATH);
}
break;
case 'bext/unknown-install':
copy(data.payload.build);
notify({
message: '当前浏览器不支持安装,已将脚本内容复制到剪切板',
status: 'info',
});
break;
case 'bext/notify':
if (data.payload) {
notify(data.payload);
}
break;
default:
break;
}
});
const { notify } = useNotifications();
return (
<div className="flex-1 relative">
<iframe
className="w-full h-full border-none"
onLoad={setLoaded}
src={src}
ref={ref}
/>
{loading ? (
<Spinner
className="absolute inset-0"
style={{
backgroundColor: theme.semanticColors.bodyBackground,
}}
size={SpinnerSize.large}
/>
) : null}
{jsonSchema ? (
<Dialog
hidden={false}
dialogContentProps={{
type: DialogType.normal,
title: jsonSchema.title || '选项',
}}
minWidth={400}
modalProps={{ layerProps: { hostId: LAYER_HOST_ID } }}
>
<JsonSchemaForm
schema={jsonSchema.schema}
formData={formData}
onChange={({ formData, errors }) => {
setFormData(formData);
setHasError(!!errors.length);
}}
omitExtraData
liveOmit
liveValidate
>
<></>
</JsonSchemaForm>
<DialogFooter>
<PrimaryButton
onClick={() => {
ref.current?.contentWindow?.postMessage(
{
type: 'bext/jsf-submit',
value: formData,
key: jsonSchema.key,
},
'*',
);
resetForm();
}}
text="确定"
disabled={hasError}
/>
<DefaultButton onClick={resetForm} text="取消" />
</DialogFooter>
</Dialog>
) : null}
</div>
);
}
Example #8
Source File: index.tsx From scorpio-h5-design with MIT License | 4 votes |
export default function() {
const { pageId, pageSchema, selectPage, setStateByObjectKeys } = useModel('bridge');
const addPageReq = useRequest(service.addPage, {
manual: true,
});
const editPageReq = useRequest(service.editPage, {
manual: true,
});
const [visible, { toggle }] = useBoolean(false);
const [qrcodeUrl, setQrcodeUrl] = useState('');
const save = async function() {
const dataURL = await window.postmate_mobile.get(childrenModel.CAPTURE);
if (dataURL) {
const file = dataURLtoFile(dataURL, new Date().getTime().toString());
const fileName = `${uuidv4()}.png`;
await ossClient.put(`design/${fileName}`, file);
selectPage.cover = `https://scorpio-design.lxzyl.cn/design/${fileName}`;
}
let res;
if (pageId) {
res = await editPageReq.run({
_id: pageId,
pageSchema,
});
} else {
res = await addPageReq.run({
pageSchema,
});
}
return res;
};
const onSave = async function() {
if (pageSchema.length === 0) {
return message.error('请新建页面后再保存!');
}
if (selectPage.components.length === 0) {
return message.error('至少添加一个组件后再保存!');
}
const res = await save();
const state = {
pageId: res._id,
};
setStateByObjectKeys(state);
message.success('保存成功!');
};
const onVisibleChange = async function() {
if (pageSchema.length === 0) {
return message.error('请新建页面后再操作!');
}
toggle();
await save();
const dataUrl = await QRCode.toDataURL(`${config.h5Base}?id=${pageId}`, {
margin: 0,
});
console.log('dataUrl: ', dataUrl);
setQrcodeUrl(dataUrl);
};
const overviewContent = (
<div className="overview-qrcode">
<img className="overview-qrcode-img" src={qrcodeUrl} />
</div>
);
const exportJson = function() {
const blob = new Blob([JSON.stringify(pageSchema)], { type: 'application/json' });
console.log('pageSchema: ', pageSchema);
FileSaver.saveAs(blob, `${pageSchema[0].props.title}.json`);
};
return (
<div className="design-header">
<div className="design-header-operations">
<div className="item" onClick={() => { history.push('/manage/page'); }}>
<i className="iconfont icon-shouye" />
<div className="text" >首页</div>
</div>
<div className="item" onClick={onSave}>
<i className="iconfont icon-baocun" />
<div className="text" >保存</div>
<Spin spinning={addPageReq.loading || editPageReq.loading}>
</Spin>
</div>
{/* <Popover
title="真机预览"
trigger="click"
visible={visible}
onVisibleChange={onVisibleChange}
content={overviewContent}
overlayClassName="overview-qrcode-popover"
>
<div className="item">
<i className="iconfont icon-shouji" />
<div className="text">预览</div>
</div>
</Popover> */}
<div className="item" onClick={exportJson}>
<i className="iconfont icon-json" />
<div className="text">导出</div>
</div>
{/* <div className="item">
<i className="iconfont icon-html" />
<div className="text">下载</div>
<i className="iconfont icon-new" style={{position: 'absolute', color: 'red', right: 0, top: 0}}/>
</div> */}
<div className="item" onClick={() => { window.open('https://github.com/lx544690189/scorpio-h5-design'); }}>
<i className="iconfont icon-github-fill" />
<div className="text">GITHUB</div>
</div>
</div>
</div>
);
}
Example #9
Source File: index.tsx From scorpio-h5-design with MIT License | 4 votes |
export default function() {
// @ts-expect-error
const { _id } = history.location.query;
const { setStateByObjectKeys } = useModel('bridge');
const queryPageDetailReq = useRequest(service.queryPageDetail, {
manual: true,
});
const [loading, setLoading] = useBoolean(true);
useEffect(() => {
initData();
return ()=>{
window.postmate_mobile.destroy();
};
}, []);
/**
* 初始化数据、编辑页面初始数据
*/
const initData = async function() {
setLoading.setTrue();
// 加载iframe、发送请求、更新state会导致页面短时间卡顿,延时进行这些任务
await sleep(100);
let state = {
pageId: undefined,
pageSchema: [],
selectPageIndex: -1,
selectComponentId: undefined,
};
if (_id) {
const res = await queryPageDetailReq.run({
_id,
});
state = {
pageId: res._id,
pageSchema: res.pageSchema,
selectPageIndex: 0,
selectComponentId: undefined,
};
}
setStateByObjectKeys(state, false);
await sleep(100);
const handshake = new Postmate({
container: document.getElementById('mobile-content'),
url: `${config.base}/#/mobile`,
name: 'mobile',
classListArray: ['mobile'],
});
handshake.then((child) => {
window.postmate_mobile = child;
syncState({
payload: state,
type: IMessageType.syncState,
});
// 注册事件
child.on(childrenModel.SYNC_STATE, (message) => {
setStateByObjectKeys(message, false);
});
setLoading.setFalse();
});
};
return (
<Spin
spinning={useDebounce(loading, { wait: 500 })}
wrapperClassName="blur-loading"
indicator={<Loading />}
>
<div className="design">
<Header />
<div className="side-left">
{!loading && <SideLeft />}
</div>
<div className="side-right">
{!loading && <SideRight />}
</div>
<div className="center">
<MobileSimulator loading={loading}/>
</div>
</div>
</Spin>
);
}
Example #10
Source File: index.tsx From scorpio-h5-design with MIT License | 4 votes |
export default function() {
const [isOrdering, setIsOrdering] = useBoolean(false);
const {
isDraging, pageSchema, selectPageIndex, dragingComponentIndex, selectComponent,
onDragEnter, onDragLeave, onDrop, onSelectComponent, onSortEnd, showSelectComponentBorder,
} = useModel('bridge');
let components:any[] = [];
if (pageSchema.length > 0 && selectPageIndex !== -1) {
components = pageSchema[selectPageIndex].components;
}
return (
<DragDropContext
onDragStart={()=>{
setIsOrdering.setTrue();
}}
onDragEnd={(result: DropResult)=>{
onSortEnd(result, components);
setIsOrdering.setFalse();
}}
>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
>
{components.length > 0 && components.map((item: any, index: any) => (
<Draggable key={item.uuid} draggableId={item.uuid} index={index}>
{(provided, snapshot) => (
<>
<div
className={classnames(
'h5-canvas-empty-block',
{
show: isDraging,
over: dragingComponentIndex === index,
}
)}
onDragEnter={() => { onDragEnter(index); }}
onDragLeave={() => { onDragLeave(); }}
onDragOver={(event) => { event.preventDefault(); }}
onDrop={(event)=>{onDrop(event, index);}}
/>
<div
className={classnames(
'h5-canvas-block',
{
'blur': !snapshot.isDragging && isOrdering,
'isSelected': selectComponent?.uuid === item.uuid,
'border': selectComponent?.uuid === item.uuid && showSelectComponentBorder,
}
)}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
onClick={() => { onSelectComponent(item.uuid); }}
>
<DynamicComponent
id={item._id}
uuid={item.uuid}
isSelected={selectComponent?.uuid === item.uuid}
componentProps={item.props}
containerProps={item.containerProps}
/>
</div>
</>
)}
</Draggable>
))}
{provided.placeholder}
<div
className={classnames(
'h5-canvas-empty-block',
{
show: isDraging,
over: dragingComponentIndex === components.length,
}
)}
onDragEnter={() => { onDragEnter(components.length); }}
onDragLeave={() => { onDragLeave(); }}
onDragOver={(event) => { event.preventDefault(); }}
onDrop={(event)=>{onDrop(event, components.length);}}
/>
</div>
)}
</Droppable>
</DragDropContext>
);
}