Skip to content

Commit

Permalink
feat: react components
Browse files Browse the repository at this point in the history
  • Loading branch information
samsiegart committed Feb 21, 2024
1 parent 2d4c3bc commit c829ba1
Show file tree
Hide file tree
Showing 26 changed files with 9,435 additions and 216 deletions.
20 changes: 20 additions & 0 deletions packages/react-components/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ['plugin:react/recommended', 'standard-with-typescript', 'prettier'],
overrides: [],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['react'],
rules: {
'react/jsx-key': 'off',
'react/react-in-jsx-scope': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
'no-console': 'warn',
},
}
30 changes: 30 additions & 0 deletions packages/react-components/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Storybook
storybook-static

# Testing
coverage
1 change: 1 addition & 0 deletions packages/react-components/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v18.17.1
7 changes: 7 additions & 0 deletions packages/react-components/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 120,
"endOfLine": "auto"
}
1 change: 1 addition & 0 deletions packages/react-components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Agoric React Components
86 changes: 86 additions & 0 deletions packages/react-components/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"name": "@agoric/react-components",
"private": false,
"version": "0.1.0",
"repository": {
"type": "git",
"url": "https://github.com/agoric/ui-kit"
},
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/react-components.es.js",
"require": "./dist/react-components.umd.js"
},
"./dist/style.css": "./dist/style.css"
},
"engines": {
"node": "18"
},
"scripts": {
"build": "tsc && vite build",
"lint": "eslint --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx --fix",
"test": "vitest",
"test:cov": "vitest run --coverage"
},
"dependencies": {
"@cosmos-kit/core": "2.8.9",
"@cosmos-kit/react": "2.10.10",
"@interchain-ui/react": "1.21.18",
"chain-registry": "1.28.0",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@babel/core": "7.22.10",
"@headlessui/react": "^1.7.18",
"@testing-library/react": "14.0.0",
"@types/node": "20.4.9",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"@typescript-eslint/eslint-plugin": "5.60.0",
"@vitejs/plugin-react": "4.0.4",
"@vitest/coverage-v8": "0.34.1",
"autoprefixer": "10.4.14",
"babel-loader": "9.1.3",
"cosmos-kit": "^2.9.0",
"eslint": "8.46.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-standard-with-typescript": "37.0.0",
"eslint-plugin-import": "2.28.0",
"eslint-plugin-n": "16.0.1",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-react": "7.33.1",
"eslint-plugin-storybook": "0.6.13",
"jsdom": "22.1.0",
"json": "11.0.0",
"lint-staged": "13.2.3",
"postcss": "8.4.27",
"prettier": "3.0.1",
"prop-types": "15.8.1",
"storybook": "7.2.2",
"tailwindcss": "3.3.3",
"typescript": "5.1.6",
"vite": "4.4.9",
"vite-plugin-dts": "3.5.1",
"vitest": "0.34.1"
},
"peerDependencies": {
"@cosmos-kit/core": "2.8.9",
"@cosmos-kit/react": "2.10.10",
"chain-registry": "1.28.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"@interchain-ui/react": "1.21.18"
},
"files": [
"dist"
],
"lint-staged": {
"*.{ts,tsx,js,jsx,json,css,md}": [
"prettier -w"
]
}
}
6 changes: 6 additions & 0 deletions packages/react-components/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useAgoric } from '../hooks';

const truncate = (text: string, startChars: number, endChars: number) => {
const start = text.substring(0, startChars);
const end = text.substring(text.length - endChars, text.length);
return start + '...' + end;
};

export const ConnectWalletButton = ({ className }: { className?: string }) => {
const agoric = useAgoric();

return (
<button className={className} onClick={agoric.connect}>
{agoric.address ? truncate(agoric.address, 8, 7) : 'Connect Wallet'}
</button>
);
};
140 changes: 140 additions & 0 deletions packages/react-components/src/lib/components/NodeSelectorModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useContext, useState } from 'react';
import clsx from 'clsx';
import { NetworkContext } from '../context';
import BldIcon from '../icons/Bld';
import type { ChangeEvent } from 'react';

type Props = {
isChainIdEditable?: boolean;
isOpen?: boolean;
onClose: () => void;
};

export const NodeSelectorModal = ({
onClose,
isOpen = false,
}: Props) => {
const { networkConfig, setNetworkConfig } = useContext(NetworkContext);
const defaultRest = networkConfig?.apis?.rest?.at(0);
const defaultRpc = networkConfig?.apis?.rpc?.at(0);
assert(
setNetworkConfig && defaultRest && defaultRpc,
'Network context missing',
);

const [rest, setRest] = useState(defaultRest as string);
const [rpc, setRpc] = useState(defaultRpc as string);
const [initialRest] = useState(rest);
const [initialRpc] = useState(rpc);

const isNetworkUnchanged =
(
initialRest === rest &&
initialRpc === rpc
) ||
!rpc ||
!rest;

const save = () => {
setNetworkConfig({
apis: { rpc: [rpc], rest: [rest] },
testChain: networkConfig?.testChain,
});
onClose();
};

const cancel = () => {
onClose();
setRest(initialRest);
setRpc(initialRpc);
};

const inputClasses =
'text-base text-gray-800 bg-gray-100 rounded-md border-none py-1 px-3 shadow-sm w-full box-border text-base';

return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-50" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black bg-opacity-25 backdrop-blur-sm" />
</Transition.Child>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center text-center cursor-pointer">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="overflow-visible cursor-default max-w-2xl mx-3 transform rounded-lg bg-white text-left align-middle shadow-card transition-all">
<Dialog.Title
as="div"
className="font-sans text-2xl text-white font-medium p-6 bg-[#BB2D40] rounded-t-lg flex items-center gap-1"
>
<BldIcon />
Configure Agoric Connection
</Dialog.Title>
<div className="text-gray-500 mt-4 mx-8">
<div className="text-sm max-h-96">
<p className="mb-1">RPC Endpoint:</p>
<input
className={inputClasses}
type="url"
onChange={(e: ChangeEvent<HTMLInputElement>) => {
setRpc(e.target.value);
}}
value={rpc}
/>
<p className="mb-1">API Endpoint:</p>
<input
className={inputClasses}
type="url"
onChange={(e: ChangeEvent<HTMLInputElement>) => {
setRest(e.target.value);
}}
value={rest}
/>
</div>
</div>
<div className="pt-10 pb-6 px-8">
<div className="flex justify-end gap-6">
<button
className="text-gray-500 bg-gray-100 hover:bg-gray-200 transition-colors"
onClick={cancel}
>
Cancel
</button>
<button
disabled={isNetworkUnchanged}
className={clsx(
'transition text-btn-xs flex justify-center rounded border border-transparent text-white px-16 py-3',
isNetworkUnchanged
? 'bg-gray-300 cursor-not-allowed'
: 'bg-[#BB2D40] hover:opacity-80 active:opacity-60',
)}
onClick={save}
>
Save
</button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
);
};
2 changes: 2 additions & 0 deletions packages/react-components/src/lib/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './ConnectWalletButton';
export * from './NodeSelectorModal';
49 changes: 49 additions & 0 deletions packages/react-components/src/lib/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { assets, chains } from 'chain-registry';
import type { Chain, AssetList } from '@chain-registry/types';
import type { Endpoints } from '@cosmos-kit/core';

export type ChainConfig = { chains: Chain[]; assetLists: AssetList[] };

const prettyTestChainName = (name: string) =>
name
.split('-')
.map(s => s[0].toUpperCase() + s.slice(1))
.join(' ');

const agoricChain = chains.find((chain: Chain) => {
return chain.chain_name === 'agoric';
});

export const makeChainInfo = (
chainName: string,
chainId: string,
apis: Endpoints,
) => {
assert(
agoricChain,
'Agoric missing from chain registry, cannot initiliaze test chains',
);

return {
...agoricChain,
...{
chain_id: chainId ?? chainName,
chain_name: chainName,
pretty_name: prettyTestChainName(chainName),
apis,
},
} as Chain;
};

const agoricAssetList = assets.find((assetList: AssetList) => {
return assetList.chain_name === 'agoric';
});

export const makeAssetList = (chain_name: string) => {
assert(
agoricAssetList,
'Agoric missing from chain registry, cannot initiliaze test chains',
);

return { ...agoricAssetList, chain_name };
};
Loading

0 comments on commit c829ba1

Please sign in to comment.