Skip to content

Commit

Permalink
chore: optimize sui、tron、cfx example
Browse files Browse the repository at this point in the history
  • Loading branch information
ByteZhang1024 committed Nov 6, 2024
1 parent d349624 commit 9843a1f
Show file tree
Hide file tree
Showing 27 changed files with 979 additions and 317 deletions.
1 change: 1 addition & 0 deletions .github/workflows/deploy-dapp-example-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
# Next.js environment variables
echo "NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=${{ secrets.WALLET_CONNECT_PROJECT_ID }}" > ./packages/example/.env
echo "NEXT_PUBLIC_BLOCKFROST_CARDANO_PROJECT_ID=${{ secrets.BLOCKFROST_CARDANO_PROJECT_ID }}" >> ./packages/example/.env
echo "NEXT_PUBLIC_OKLINK_API_KEY=${{ secrets.OKLINK_API_KEY }}" >> ./packages/example/.env
- name: Install Dependency
env:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish-npm-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
# Next.js environment variables
echo "NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=${{ secrets.WALLET_CONNECT_PROJECT_ID }}" > ./packages/example/.env
echo "NEXT_PUBLIC_BLOCKFROST_CARDANO_PROJECT_ID=${{ secrets.BLOCKFROST_CARDANO_PROJECT_ID }}" >> ./packages/example/.env
echo "NEXT_PUBLIC_OKLINK_API_KEY=${{ secrets.OKLINK_API_KEY }}" >> ./packages/example/.env
- name: Build Example Web
run: |
Expand Down
4 changes: 3 additions & 1 deletion packages/example/.env.simple
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=xxxx
NEXT_PUBLIC_WALLET_CONNECT_RELAY_URL=wss://relay.walletconnect.com
# block frost project id
NEXT_PUBLIC_BLOCKFROST_CARDANO_PROJECT_ID=xxxx
NEXT_PUBLIC_BLOCKFROST_CARDANO_PROJECT_ID=xxxx
# oklink api key
NEXT_PUBLIC_OKLINK_API_KEY=xxxx
69 changes: 69 additions & 0 deletions packages/example/components/ApiForm/ApiAutoTextArea.tsx
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';
39 changes: 33 additions & 6 deletions packages/example/components/ApiForm/ApiButton.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { memo, useContext, useCallback } from 'react';
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 } from 'lodash';
import { get, isEmpty } from 'lodash';
import { toast } from '../ui/use-toast';

export interface ApiButtonProps {
Expand All @@ -14,13 +14,15 @@ export interface ApiButtonProps {
fields: string[];
validator?: (values: Record<string, { id: string; value: string; required: boolean }>) => string | undefined;
};
availableDependencyFields?: string[];
}

export const ApiButton = memo(({
id,
label,
onClick,
validation
validation,
availableDependencyFields,
}: ApiButtonProps) => {
const context = useContext(ApiFormContext);
if (!context) throw new Error('ApiButton must be used within ApiForm');
Expand All @@ -31,13 +33,37 @@ export const ApiButton = memo(({
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,
Expand Down Expand Up @@ -74,11 +100,12 @@ export const ApiButton = memo(({
<Button
key={id}
onClick={handleClick}
disabled={loading}
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>
);
Expand Down
4 changes: 4 additions & 0 deletions packages/example/components/ApiForm/ApiCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export const ApiCheckbox = memo(({
const { store } = context;
const [field, setField] = useAtom(store.fieldsAtom(id));

useEffect(() => {
field.name = label;
}, []);

useEffect(() => {
if (defaultChecked) {
setField({ ...field, value: defaultChecked });
Expand Down
15 changes: 10 additions & 5 deletions packages/example/components/ApiForm/ApiCombobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, Command
import { ChevronDownIcon, CheckIcon } from 'lucide-react';
import { cn } from '../../lib/utils';

interface IOption<T> {
export interface IOption<T> {
value: string;
label: string;
extra?: T;
Expand Down Expand Up @@ -88,6 +88,8 @@ export const ApiCombobox = forwardRef<ApiComboboxRef, ApiComboboxProps>(function
if (defaultValue) {
setField({ ...field, value: defaultValue });
}
field.name = label;
field.required = required;
}, []);

useImperativeHandle(ref, () => ({
Expand All @@ -113,13 +115,15 @@ export const ApiCombobox = forwardRef<ApiComboboxRef, ApiComboboxProps>(function
aria-expanded={open}
className="w-full justify-between"
>
{currentOption?.value
? options.find((option) => option.value === currentOption?.value)?.label
: placeholder}
<span className="truncate text-left break-all line-clamp-2">
{currentOption?.value
? options.find((option) => option.value === currentOption?.value)?.label
: placeholder}
</span>
<ChevronDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0">
<Command>
<CommandInput placeholder={placeholder} className="h-9" />
<CommandList>
Expand All @@ -129,6 +133,7 @@ export const ApiCombobox = forwardRef<ApiComboboxRef, ApiComboboxProps>(function
<CommandItem
key={option.value}
value={option.label}
className="break-all"
onSelect={(currentLabel) => {
const currentOption = options?.find(opt => opt.label === currentLabel);
setValue(currentOption?.value ?? null);
Expand Down
11 changes: 8 additions & 3 deletions packages/example/components/ApiForm/ApiField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ interface ApiInputProps {
type?: 'text' | 'number' | 'password';
hidden?: boolean;
defaultValue?: string;
label?: string;
required?: boolean;
}

const ApiInput = memo(({
id,
placeholder,
type = 'text',
hidden = false,
defaultValue
defaultValue,
label,
required
}: ApiInputProps) => {

const context = useContext(ApiFormContext);
Expand All @@ -31,6 +35,8 @@ const ApiInput = memo(({
if (defaultValue) {
setField({ ...field, value: defaultValue });
}
field.name = label;
field.required = required;
}, []);

return <>
Expand All @@ -52,7 +58,6 @@ const ApiInput = memo(({

export interface ApiFieldProps extends ApiInputProps {
id: string;
label?: string;
required?: boolean;
}

Expand All @@ -73,7 +78,7 @@ export const ApiField = memo(({
{required && <span className="text-red-500">*</span>}
</Label>
)}
<ApiInput id={id} placeholder={placeholder} hidden={hidden} defaultValue={defaultValue} />
<ApiInput id={id} placeholder={placeholder} hidden={hidden} defaultValue={defaultValue} label={label} required={required} />
</div>
);
});
Expand Down
13 changes: 11 additions & 2 deletions packages/example/components/ApiForm/ApiJsonEdit.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { memo, useContext } from 'react';
import React, { memo, useContext, useEffect } from 'react';
import { useAtom } from 'jotai';
import { Label } from '../ui/label';
import { ApiFormContext } from './ApiForm';
Expand All @@ -8,11 +8,15 @@ import JsonEditor from '../ui/jsonEditor';
interface JsonEditProps {
id: string;
placeholder?: string;
label?: string;
required?: boolean;
}

const JsonEdit = memo(({
id,
placeholder
placeholder,
label,
required
}: JsonEditProps) => {

const context = useContext(ApiFormContext);
Expand All @@ -21,6 +25,11 @@ const JsonEdit = memo(({
const { store } = context;
const [field, setField] = useAtom(store.fieldsAtom(id));

useEffect(() => {
field.name = label;
field.required = required;
}, []);

return <>
<JsonEditor
value={field.value ?? ''}
Expand Down
25 changes: 21 additions & 4 deletions packages/example/components/ApiForm/ApiSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export interface ApiSelectorProps<T = any> {
defaultValue?: string;
placeholder?: string;
onRequestOptions?: () => Promise<IOption<T>[]>
onValueChange?: (value: string | null) => void;
onOptionChange?: (option: IOption<T> | null) => void;
}

export interface ApiSelectorRef<T = any> {
Expand All @@ -34,7 +36,9 @@ export const ApiSelector = forwardRef<ApiSelectorRef, ApiSelectorProps>(function
required,
defaultValue,
placeholder,
onRequestOptions
onRequestOptions,
onValueChange,
onOptionChange
}: ApiSelectorProps<T>,
ref: React.Ref<ApiSelectorRef<T>>,
) {
Expand All @@ -54,7 +58,7 @@ export const ApiSelector = forwardRef<ApiSelectorRef, ApiSelectorProps>(function
const setOptions = useCallback((options: IOption<T>[]) => {
setField({
...field, extra: {
options: [...options]
options
}
});
}, [setField]);
Expand All @@ -63,6 +67,8 @@ export const ApiSelector = forwardRef<ApiSelectorRef, ApiSelectorProps>(function
if (defaultValue) {
setField({ ...field, value: defaultValue });
}
field.name = label;
field.required = required;
}, []);

useEffect(() => {
Expand All @@ -73,9 +79,20 @@ export const ApiSelector = forwardRef<ApiSelectorRef, ApiSelectorProps>(function
}
}, [onRequestOptions]);

const setValue = useCallback((value: string | null) => {
setField({ ...field, value });
onValueChange?.(value);
onOptionChange?.(options?.find(opt => opt.value === value) ?? null);
}, [setField, onValueChange, onOptionChange, options]);

useEffect(() => {
if (defaultValue) {
setField({ ...field, value: defaultValue });
}
}, []);

useImperativeHandle(ref, () => ({
setValue: (key: string | null) => setField({ ...field, value: key }),
setValue,
getCurrentValue: () => currentOption?.value,
getCurrentOption: () => currentOption,
getOptions: () => options,
Expand All @@ -92,7 +109,7 @@ export const ApiSelector = forwardRef<ApiSelectorRef, ApiSelectorProps>(function
<Select
defaultValue={defaultValue}
value={field.value}
onValueChange={(value) => setField({ ...field, value })}
onValueChange={setValue}
>
{placeholder && (
<SelectTrigger className="w-full">
Expand Down
4 changes: 4 additions & 0 deletions packages/example/components/ApiForm/ApiSwitch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export const ApiSwitch = memo(({
const { store } = context;
const [field, setField] = useAtom(store.fieldsAtom(id));

useEffect(() => {
field.name = label;
}, []);

useEffect(() => {
if (defaultChecked) {
setField({ ...field, value: defaultChecked });
Expand Down
Loading

0 comments on commit 9843a1f

Please sign in to comment.