Skip to content

Commit

Permalink
fix(ui): rebuild tabs with radix primitives, ref #4309
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed Jan 11, 2024
1 parent 0de3900 commit 3b0488e
Show file tree
Hide file tree
Showing 11 changed files with 1,086 additions and 1,428 deletions.
7 changes: 7 additions & 0 deletions .dependency-cruiser.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ module.exports = {
from: { path: '^src/inpage' },
to: { path: '^src/shared/logger' },
},
{
name: 'no-external-tab-usage',
comment: `Inpage cannot use logger, which uses unavailable APIs`,
severity: 'error',
from: { path: '^src', pathNot: ['^src/app/ui/components/tabs'] },
to: { path: '@radix-ui/react-tabs' },
},
],
options: {
doNotFollow: {
Expand Down
70 changes: 35 additions & 35 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,20 +134,21 @@
"@ledgerhq/hw-transport-webusb": "6.27.19",
"@noble/hashes": "1.3.2",
"@noble/secp256k1": "2.0.0",
"@octokit/types": "12.0.0",
"@octokit/types": "12.4.0",
"@radix-ui/colors": "3.0.0",
"@radix-ui/react-accessible-icon": "1.0.3",
"@radix-ui/react-dropdown-menu": "2.0.6",
"@radix-ui/react-select": "2.0.0",
"@radix-ui/themes": "2.0.2",
"@radix-ui/react-tabs": "1.0.4",
"@radix-ui/themes": "2.0.3",
"@reduxjs/toolkit": "1.9.6",
"@scure/base": "1.1.3",
"@scure/bip32": "1.3.2",
"@scure/bip39": "1.2.1",
"@scure/btc-signer": "1.1.0",
"@segment/analytics-next": "1.56.0",
"@sentry/react": "7.86.0",
"@sentry/tracing": "7.72.0",
"@segment/analytics-next": "1.62.1",
"@sentry/react": "7.92.0",
"@sentry/tracing": "7.92.0",
"@stacks/auth": "6.9.0",
"@stacks/blockchain-api-client": "6.3.4",
"@stacks/common": "6.8.1",
Expand Down Expand Up @@ -186,7 +187,7 @@
"chroma-js": "2.4.2",
"coinselect": "3.1.13",
"compare-versions": "4.1.3",
"css-loader": "6.8.1",
"css-loader": "6.9.0",
"dayjs": "1.11.8",
"dompurify": "3.0.6",
"dotenv": "16.3.1",
Expand All @@ -203,8 +204,8 @@
"micro-packed": "0.3.2",
"object-hash": "3.0.0",
"observable-hooks": "4.2.3",
"pino": "8.15.4",
"postcss-preset-env": "9.1.4",
"pino": "8.17.2",
"postcss-preset-env": "9.3.0",
"prism-react-renderer": "2.2.0",
"prismjs": "1.29.0",
"promise-memoize": "1.2.1",
Expand All @@ -219,11 +220,11 @@
"react-intersection-observer": "9.5.2",
"react-lottie": "1.2.3",
"react-redux": "8.1.3",
"react-router-dom": "6.20.1",
"react-router-dom": "6.21.1",
"react-virtuoso": "4.6.0",
"redux-persist": "6.0.0",
"rxjs": "7.8.1",
"style-loader": "3.3.3",
"style-loader": "3.3.4",
"ts-debounce": "4.0.0",
"url": "0.11.1",
"url-join": "5.0.0",
Expand All @@ -240,14 +241,14 @@
"@btckit/types": "0.0.19",
"@leather-wallet/prettier-config": "0.0.1",
"@leather-wallet/tokens": "0.0.2",
"@ls-lint/ls-lint": "2.1.0",
"@pandacss/dev": "0.26.1",
"@ls-lint/ls-lint": "2.2.2",
"@pandacss/dev": "0.26.2",
"@playwright/test": "1.40.1",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.11",
"@redux-devtools/cli": "3.0.2",
"@redux-devtools/remote": "0.8.1",
"@redux-devtools/cli": "4.0.0",
"@redux-devtools/remote": "0.9.1",
"@schemastore/web-manifest": "0.0.6",
"@sentry/webpack-plugin": "2.4.0",
"@sentry/webpack-plugin": "2.10.2",
"@stacks/connect-react": "22.2.0",
"@stacks/stacks-blockchain-api-types": "6.3.4",
"@storybook/addon-essentials": "7.6.7",
Expand All @@ -269,26 +270,25 @@
"@types/node": "20.8.2",
"@types/object-hash": "3.0.4",
"@types/prismjs": "1.26.1",
"@types/promise-memoize": "1.2.2",
"@types/punycode": "2.1.0",
"@types/qrcode.react": "1.0.3",
"@types/react": "18.2.24",
"@types/react-dom": "18.2.8",
"@types/promise-memoize": "1.2.4",
"@types/punycode": "2.1.3",
"@types/qrcode.react": "1.0.5",
"@types/react": "18.2.47",
"@types/react-dom": "18.2.18",
"@types/react-lottie": "1.2.7",
"@types/react-router-dom": "5.3.3",
"@types/remote-redux-devtools": "0.5.6",
"@types/styled-system__theme-get": "5.0.2",
"@types/valid-url": "1.0.5",
"@types/remote-redux-devtools": "0.5.8",
"@types/valid-url": "1.0.7",
"@types/webextension-polyfill": "0.10.4",
"@types/webpack": "5.28.3",
"@types/zxcvbn": "4.4.2",
"@types/webpack": "5.28.5",
"@types/zxcvbn": "4.4.4",
"@typescript-eslint/parser": "6.7.4",
"@vitest/coverage-istanbul": "0.34.6",
"@vitest/coverage-istanbul": "1.1.3",
"audit-ci": "6.6.1",
"base64-loader": "1.0.0",
"bip32": "4.0.0",
"blns": "2.0.4",
"browserslist": "4.22.1",
"browserslist": "4.22.2",
"chromatic": "10.2.0",
"chrome-webstore-upload-cli": "2.2.2",
"clean-webpack-plugin": "4.0.0",
Expand All @@ -300,18 +300,18 @@
"deepmerge": "4.3.1",
"dependency-cruiser": "14.1.1",
"dotenv-webpack": "8.0.1",
"esbuild": "0.19.7",
"esbuild": "0.19.11",
"esbuild-loader": "4.0.2",
"eslint-plugin-deprecation": "2.0.0",
"eslint-plugin-react": "7.33.2",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-storybook": "0.6.15",
"file-loader": "6.2.0",
"generate-json-webpack-plugin": "2.0.0",
"html-webpack-plugin": "5.5.3",
"html-webpack-plugin": "5.6.0",
"jsdom": "22.1.0",
"postcss": "8.4.31",
"postcss-loader": "7.3.3",
"postcss": "8.4.33",
"postcss-loader": "7.3.4",
"prettier": "3.0.3",
"process": "0.11.10",
"progress-bar-webpack-plugin": "2.1.0",
Expand All @@ -322,19 +322,19 @@
"storybook": "7.6.7",
"stream-browserify": "3.0.0",
"svg-url-loader": "8.0.0",
"ts-node": "10.9.1",
"ts-node": "10.9.2",
"ts-unused-exports": "10.0.1",
"tsconfig-paths-webpack-plugin": "4.1.0",
"typescript": "5.2.2",
"vitest": "0.34.6",
"typescript": "5.3.3",
"vitest": "1.1.3",
"vm-browserify": "1.1.2",
"web-ext": "7.8.0",
"web-ext-submit": "7.8.0",
"webpack": "5.89.0",
"webpack-bundle-analyzer": "4.10.1",
"webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1",
"webpack-hot-middleware": "2.25.4",
"webpack-hot-middleware": "2.26.0",
"webpack-shell-plugin": "0.5.0"
},
"resolutions": {
Expand Down
38 changes: 0 additions & 38 deletions src/app/components/tabs.tsx

This file was deleted.

55 changes: 26 additions & 29 deletions src/app/features/bitcoin-choose-fee/components/choose-fee-tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Suspense, useState } from 'react';
import { Suspense } from 'react';

import { Box, Flex, Stack, StackProps } from 'leather-styles/jsx';
import { Box, Stack, StackProps } from 'leather-styles/jsx';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { LoadingSpinner } from '@app/components/loading-spinner';
import { Tabs } from '@app/components/tabs';
import { Tabs } from '@app/ui/components/tabs/tabs';

const analyticsPath = ['/recommended', '/custom'];
enum CustomFeeTabs {
Recommended = 'recommended',
Custom = 'custom',
}

interface ChooseFeeTabsProps extends StackProps {
customFee: React.JSX.Element;
Expand All @@ -15,40 +18,34 @@ interface ChooseFeeTabsProps extends StackProps {
export function ChooseFeeTabs(props: ChooseFeeTabsProps) {
const { feesList, customFee, ...rest } = props;
const analytics = useAnalytics();
// TODO #4013: Refactor this to use routes for tabs like home-tabs
const [activeTab, setActiveTab] = useState(0);

const setActiveTabTracked = (index: number) => {
void analytics.page('view', analyticsPath[index]);
setActiveTab(index);
};

return (
<Stack flexGrow={1} gap="space.04" mt="space.02" width="100%" {...rest}>
<Tabs
tabs={[
{ slug: 'recommended', label: 'Recommended' },
{ slug: 'custom', label: 'Custom' },
]}
activeTab={activeTab}
onTabClick={setActiveTabTracked}
/>
<Flex flexGrow={1} position="relative">
{activeTab === 0 && (
<Tabs.Root
defaultValue={CustomFeeTabs.Recommended}
onValueChange={tab => void analytics.page('view', 'custom-fee-tab-' + tab)}
>
<Tabs.List>
<Tabs.Trigger value={CustomFeeTabs.Recommended} data-testid="tab-recommended">
Recommended
</Tabs.Trigger>
<Tabs.Trigger value="custom" data-testid="tab-custom">
Custom
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value={CustomFeeTabs.Recommended}>
<Suspense fallback={<LoadingSpinner pb="space.10" />}>
<Box animation="fadein" transition="transition" width="100%">
{feesList}
</Box>
<Box mt="space.05">{feesList}</Box>
</Suspense>
)}
{activeTab === 1 && (
</Tabs.Content>
<Tabs.Content value={CustomFeeTabs.Custom}>
<Suspense fallback={<LoadingSpinner pb="72px" />}>
<Box animation="fadein" transition="transition" width="100%">
<Box mt="space.05" width="100%">
{customFee}
</Box>
</Suspense>
)}
</Flex>
</Tabs.Content>
</Tabs.Root>
</Stack>
);
}
3 changes: 1 addition & 2 deletions src/app/features/errors/error-boundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import {
Component,
ComponentType,
ErrorInfo,
FunctionComponent,
PropsWithChildren,
PropsWithRef,
Expand Down Expand Up @@ -84,7 +83,7 @@ class ErrorBoundary extends Component<
this.setState(initialState);
}

componentDidCatch(error: Error, info: ErrorInfo) {
componentDidCatch(error: Error, info: any) {
this.props.onError?.(error, info);
}

Expand Down
34 changes: 12 additions & 22 deletions src/app/pages/home/components/home-tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Suspense, useCallback, useMemo } from 'react';
import { Suspense } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import { Box, Stack } from 'leather-styles/jsx';

import { RouteUrls } from '@shared/route-urls';

import { useLocationState } from '@app/common/hooks/use-location-state';
import { LoadingSpinner } from '@app/components/loading-spinner';
import { Tabs } from '@app/components/tabs';
import { Tabs } from '@app/ui/components/tabs/tabs';

interface HomeTabsProps {
children: React.ReactNode;
Expand All @@ -16,28 +15,19 @@ interface HomeTabsProps {
export function HomeTabs({ children }: HomeTabsProps) {
const navigate = useNavigate();
const location = useLocation();
const backgroundLocation = useLocationState<Location>('backgroundLocation');

const tabs = useMemo(
() => [
{ slug: RouteUrls.Home, label: 'assets' },
{ slug: `${RouteUrls.Home}${RouteUrls.Activity}`, label: 'activity' },
],
[]
);
const getActiveTab = useCallback(() => {
const path = backgroundLocation ? backgroundLocation.pathname : location?.pathname;
return tabs.findIndex(tab => tab.slug === path);
}, [tabs, backgroundLocation, location]);

const setActiveTab = useCallback(
(index: number) => navigate(tabs[index]?.slug),
[navigate, tabs]
);

return (
<Stack flexGrow={1} mt="space.05" gap="space.06">
<Tabs tabs={tabs} activeTab={getActiveTab()} onTabClick={setActiveTab} />
<Tabs.Root onValueChange={slug => navigate(slug)} defaultValue={location.pathname}>
<Tabs.List>
<Tabs.Trigger data-testid="tab-assets" value={RouteUrls.Home}>
Assets
</Tabs.Trigger>
<Tabs.Trigger data-testid="tab-activity" value={`${RouteUrls.Home}${RouteUrls.Activity}`}>
Activity
</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
<Suspense fallback={<LoadingSpinner pb="72px" />}>
<Box width="100%">{children}</Box>
</Suspense>
Expand Down
23 changes: 23 additions & 0 deletions src/app/ui/components/tabs/tabs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Meta, StoryObj } from '@storybook/react';

import { Tabs as Component } from './tabs';

const meta: Meta<typeof Component.Root> = {
component: Component.Root,
tags: ['autodocs'],
title: 'Tabs',
};

export default meta;
type Story = StoryObj<typeof Component.Root>;

export const Tabs: Story = {
render: () => (
<Component.Root>
<Component.List>
<Component.Trigger value="0">Asset</Component.Trigger>
<Component.Trigger value="1">Activity</Component.Trigger>
</Component.List>
</Component.Root>
),
};
Loading

0 comments on commit 3b0488e

Please sign in to comment.