-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: optimize example * chore: optimize evm example * chore: optimize sui、tron、cfx example * chore: optimize sui example * chore: optimize evm example
- Loading branch information
1 parent
d780526
commit e57d01c
Showing
50 changed files
with
5,447 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
|
||
const version = '2.1.20'; | ||
const version = '2.1.21'; | ||
const versionBuild = '2020-0101-1'; | ||
|
||
export default { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import React, { memo, useContext, useEffect } from 'react'; | ||
import { useAtom } from 'jotai'; | ||
import { Label } from '../ui/label'; | ||
import { ApiFormContext } from './ApiForm'; | ||
import { AutoHeightTextarea } from '../ui/textarea'; | ||
|
||
|
||
interface AutoTextAreaProps { | ||
id: string; | ||
placeholder?: string; | ||
label?: string; | ||
required?: boolean; | ||
} | ||
|
||
const TextArea = memo(({ | ||
id, | ||
placeholder, | ||
label, | ||
required | ||
}: AutoTextAreaProps) => { | ||
const context = useContext(ApiFormContext); | ||
if (!context) throw new Error('ApiField must be used within ApiForm'); | ||
|
||
const { store } = context; | ||
const [field, setField] = useAtom(store.fieldsAtom(id)); | ||
|
||
useEffect(() => { | ||
field.name = label; | ||
field.required = required; | ||
}, []); | ||
|
||
return <> | ||
<AutoHeightTextarea | ||
id={id} | ||
value={field.value} | ||
onChange={(e) => setField({ ...field, value: e.target.value })} | ||
placeholder={placeholder} | ||
disabled={field.disabled} | ||
/> | ||
{field.error && ( | ||
<div className="text-sm text-red-500">{field.error}</div> | ||
)} | ||
</> | ||
}); | ||
|
||
export interface ApiAutoTextAreaProps extends AutoTextAreaProps { | ||
id: string; | ||
} | ||
|
||
export const ApiAutoTextArea = memo(({ | ||
id, | ||
label, | ||
placeholder, | ||
required | ||
}: ApiAutoTextAreaProps) => { | ||
return ( | ||
<div> | ||
{label && ( | ||
<Label htmlFor={id}> | ||
{label} | ||
{required && <span className="text-red-500">*</span>} | ||
</Label> | ||
)} | ||
<TextArea id={id} placeholder={placeholder} label={label} required={required} /> | ||
</div> | ||
); | ||
}); | ||
|
||
ApiAutoTextArea.displayName = 'ApiAutoTextArea'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import React, { memo, useContext, useCallback, useMemo, useEffect } from 'react'; | ||
import { useAtom } from 'jotai'; | ||
import { Button } from '../ui/button'; | ||
import { ApiFormContext } from './ApiForm'; | ||
import { useValidation } from './hooks/useValidation'; | ||
import { get, isEmpty } from 'lodash'; | ||
import { toast } from '../ui/use-toast'; | ||
|
||
export interface ApiButtonProps { | ||
id: string; | ||
label: string; | ||
onClick: () => Promise<void>; | ||
validation?: { | ||
fields: string[]; | ||
validator?: (values: Record<string, { id: string; value: string; required: boolean }>) => string | undefined; | ||
}; | ||
availableDependencyFields?: string[]; | ||
} | ||
|
||
export const ApiButton = memo(({ | ||
id, | ||
label, | ||
onClick, | ||
validation, | ||
availableDependencyFields, | ||
}: ApiButtonProps) => { | ||
const context = useContext(ApiFormContext); | ||
if (!context) throw new Error('ApiButton must be used within ApiForm'); | ||
|
||
const { store } = context; | ||
const [field, setField] = useAtom(store.fieldsAtom(id)); | ||
|
||
const loading = field.extra?.loading ?? false; | ||
const result = field.extra?.result; | ||
|
||
useEffect(() => { | ||
field.name = label; | ||
}, []); | ||
|
||
const dependencyStates = availableDependencyFields?.map(fieldId => { | ||
const [field] = useAtom(store.fieldsAtom(fieldId)); | ||
return { | ||
id: fieldId, | ||
value: field.value, | ||
name: field.name | ||
}; | ||
}) ?? []; | ||
|
||
const disabledTooltip = useMemo(() => { | ||
const filterFields = dependencyStates.filter(field => | ||
(field.value == null || isEmpty(field.value)) | ||
); | ||
|
||
if (filterFields.length > 0) { | ||
return `请填写 ${filterFields.map(field => field.name ?? field.id).join(', ')}`; | ||
} | ||
return null; | ||
}, [dependencyStates]); | ||
|
||
const setResult = (value: string) => { | ||
setField({ ...field, extra: { ...field.extra, result: value } }); | ||
} | ||
|
||
const setLoading = (value: boolean) => { | ||
setField({ ...field, extra: { ...field.extra, loading: value } }); | ||
} | ||
|
||
const { validate } = useValidation({ | ||
store, | ||
validation | ||
}); | ||
|
||
const handleClick = useCallback(async () => { | ||
setResult(undefined); | ||
|
||
const { isValid, error } = validate(); | ||
if (!isValid) { | ||
setResult(error || '验证失败'); | ||
return; | ||
} | ||
|
||
try { | ||
setLoading(true); | ||
await onClick(); | ||
} catch (error) { | ||
const errorMessage = get(error, 'message', 'error') ?? JSON.stringify(error); | ||
toast({ | ||
title: '执行失败', | ||
description: errorMessage, | ||
variant: 'destructive', | ||
}); | ||
setResult(errorMessage); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}, [onClick, validate, setLoading, setResult]); | ||
|
||
return ( | ||
<div className="flex flex-col gap-1"> | ||
<Button | ||
key={id} | ||
onClick={handleClick} | ||
disabled={disabledTooltip != null} | ||
loading={loading} | ||
> | ||
{label} | ||
</Button> | ||
{disabledTooltip && <div className="text-red-500 text-sm">{disabledTooltip}</div>} | ||
{result && <div className="text-red-500 text-sm">{result}</div>} | ||
</div> | ||
); | ||
}); | ||
|
||
ApiButton.displayName = 'ApiButton'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import React, { memo, useContext, useEffect } from 'react'; | ||
import { useAtom } from 'jotai'; | ||
import { ApiFormContext } from './ApiForm'; | ||
import { Checkbox } from '../ui/checkbox'; | ||
|
||
export interface ApiCheckboxProps { | ||
id: string; | ||
label?: string; | ||
defaultChecked?: boolean; | ||
} | ||
|
||
export const ApiCheckbox = memo(({ | ||
id, | ||
label, | ||
defaultChecked | ||
}: ApiCheckboxProps) => { | ||
const context = useContext(ApiFormContext); | ||
if (!context) throw new Error('ApiField must be used within ApiForm'); | ||
|
||
const { store } = context; | ||
const [field, setField] = useAtom(store.fieldsAtom(id)); | ||
|
||
useEffect(() => { | ||
field.name = label; | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (defaultChecked) { | ||
setField({ ...field, value: defaultChecked }); | ||
} | ||
}, []); | ||
|
||
return <div className="flex items-center gap-2"> | ||
<Checkbox | ||
id={id} | ||
defaultChecked={defaultChecked} | ||
required={field.required} | ||
checked={field.value} | ||
onCheckedChange={(e) => setField({ ...field, value: e })} | ||
disabled={field.disabled} | ||
/> | ||
|
||
<label | ||
htmlFor={id} | ||
className="p-0 m-0 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" | ||
> | ||
{label} | ||
</label> | ||
|
||
{field.error && ( | ||
<div className="text-sm text-red-500">{field.error}</div> | ||
)} | ||
</div> | ||
}); | ||
|
||
ApiCheckbox.displayName = 'ApiCheckbox'; |
Oops, something went wrong.