diff --git a/CLAUDE.md b/CLAUDE.md index 48f85e0a4..190b21a94 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,163 +1,68 @@ -# CLAUDE.md +# JS Monorepo -This file provides guidance to Claude Code when working in the js/ directory. +TypeScript monorepo for Lightning Network SDKs and internal applications. Yarn workspaces + Turbo. -## Overview +## Quick Reference -JavaScript/TypeScript monorepo for Lightspark's Lightning Network and UMA services. Public SDKs, internal applications, and shared packages using Yarn workspaces + Turbo. +| Action | Command | +|--------|---------| +| Install | `yarn` | +| Start apps | `yarn start site uma-bridge ops` | +| Build | `yarn build` | +| Test | `yarn test` | +| Lint + format | `yarn lint && yarn format` | +| Full checks | `yarn checks` | +| GraphQL regen | `yarn gql-codegen` | +| Clean all | `yarn clean-all` | ## Structure -- **packages/** - Shared libraries - - **core/** - Auth, utilities - - **lightspark-sdk/** - Public Lightning SDK - - **ui/** - React components, design system - - **private/** - Internal utilities, GraphQL clients -- **apps/examples/** - Public examples and CLI tools -- **apps/private/** - Internal apps (site, ops, uma-bridge) - -## Essential Commands - -### Setup -```bash -nvm use || nvm install # Match Node version -corepack enable && corepack prepare --activate # Enable Yarn -yarn # Install all workspace dependencies ``` - -### Development Workflow -```bash -# Start applications -yarn start site uma-bridge ops # Specific apps (@lightsparkdev/ prefix implied) -yarn start private # All private apps -yarn start examples # All examples - -# Code quality -yarn lint && yarn format # Lint + Prettier -yarn checks # Full validation: deps, lint, format, test, circular-deps - -# Building -yarn build # Build all workspaces with Turbo caching -yarn build --force # Rebuild without cache - -# Testing -yarn test # Run all tests -yarn workspace @lightsparkdev/ui test # Test specific workspace - -# GraphQL codegen -yarn gql-codegen # Regenerate TypeScript types from schemas +packages/ + core/ # Auth, utilities + lightspark-sdk/ # Public Lightning SDK + ui/ # React components + private/ # Internal utilities +apps/ + examples/ # Public examples + private/ # Internal apps (site, ops, uma-bridge) ``` -### Workspace Targeting +## Workspace Commands + ```bash -# From repo root +# Target specific workspace yarn workspace @lightsparkdev/ -# From workspace directory -cd apps/private/uma-bridge && yarn start +# Examples +yarn workspace @lightsparkdev/uma-bridge start +yarn workspace @lightsparkdev/ui test ``` -## Architecture & Patterns +## Code Patterns -### Monorepo Management -- **Yarn workspaces** with workspace protocol (`"@lightsparkdev/ui": "*"`) -- **Turbo** orchestrates builds with caching and parallelization +### Dependencies +- Use workspace protocol for internal deps: `"@lightsparkdev/ui": "*"` - Shared configs: `@lightsparkdev/{tsconfig,eslint-config}` -- Build artifacts in `dist/`, ignored by git ### GraphQL -- TypeScript types auto-generated via GraphQL Code Generator -- Schema variants per API surface (internal, third-party) -- Fragments/operations defined per app -- Real-time subscriptions for transaction updates -- **After Python schema changes**: run `yarn gql-codegen` from root - -### React Stack -- **Vite** - Dev server and bundler -- **Emotion** - CSS-in-JS styling -- **React Router** - Navigation -- **React Query** - Server state -- **Zustand** - Client state - -### Testing -- **Jest** - Unit/integration tests -- **React Testing Library** - Component tests -- **Cypress** - E2E tests -- Tests colocated with source (`.test.ts`, `.spec.ts`) - -## Configuration Files - -- **turbo.json** - Build pipeline, task dependencies, caching -- **package.json** (root) - Workspace definitions, scripts -- **packages/eslint-config/** - Shared linting rules -- **packages/tsconfig/** - TypeScript presets - -## Code Standards - -- **TypeScript strict mode** enabled -- **ESLint** extends shared configs -- **Prettier** with import organization -- **Circular dependency detection** via madge -- **Prefer Edit tool** over inline rewrites for existing code - -## Common Task Workflows - -### Adding New Package -1. Create directory in `packages/` or `apps/` -2. Add workspace reference in root `package.json` -3. Create `package.json` with dependencies (use workspace protocol for internal deps) -4. Add build config to `turbo.json` if needed -5. Run `yarn` to link workspace - -### GraphQL Type Updates -After Python backend schema changes: -```bash -yarn gql-codegen # All workspaces -yarn workspace @lightsparkdev/uma-bridge gql-codegen # Specific app -``` - -### Debugging Build Issues -```bash -yarn clean-all # Remove dist/ and caches -yarn build --force # Bypass Turbo cache -yarn clean-resolve # Nuclear option: reset lockfile -``` - -### UMA Bridge Development +After Python schema changes: ```bash -# Lint bridge + UI package -yarn run lint --filter=@lightsparkdev/ui --filter=@lightsparkdev/uma-bridge - -# Start with Vite dev server (proxy configured for backend) -yarn workspace @lightsparkdev/uma-bridge start +yarn gql-codegen # All workspaces +yarn workspace @lightsparkdev/uma-bridge gql-codegen # Specific ``` -Integrates with: Plaid, Tazapay, Striga, other payment providers - ### Adding Dependencies ```bash -# Workspace-specific -yarn workspace @lightsparkdev/ add - -# Root-level (affects all workspaces) -yarn add -W +yarn workspace @lightsparkdev/ add # To workspace +yarn add -W # Root level ``` -## Release Process - -**Public packages** (SDK, core utilities): -- Changesets for version management -- Copybara syncs to public repo on main merge -- Release PR auto-created -- Merge Release PR → npm publish - -**Private packages** (`packages/private/`, `apps/private/`): -- Not published to npm -- Versioned internally only - ## Troubleshooting -**Import errors**: Check workspace dependencies use `"*"` not version numbers -**Type errors after GraphQL changes**: Run `yarn gql-codegen` -**Stale build artifacts**: `yarn clean-all && yarn build` -**Turbo cache issues**: Add `--force` flag to bypass cache \ No newline at end of file +| Issue | Fix | +|-------|-----| +| Import errors | Check deps use `"*"` not versions | +| Type errors after GraphQL | `yarn gql-codegen` | +| Stale builds | `yarn clean-all && yarn build` | +| Cache issues | `yarn build --force` | diff --git a/apps/examples/ui-test-app/src/tests/CodeInput.test.tsx b/apps/examples/ui-test-app/src/tests/CodeInput.test.tsx index 249173fdc..e256b83ee 100644 --- a/apps/examples/ui-test-app/src/tests/CodeInput.test.tsx +++ b/apps/examples/ui-test-app/src/tests/CodeInput.test.tsx @@ -1,6 +1,7 @@ import { jest } from "@jest/globals"; import { CodeInput } from "@lightsparkdev/ui/components/CodeInput/CodeInput"; import { fireEvent, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import { render } from "./render"; describe("CodeInput", () => { @@ -8,10 +9,13 @@ describe("CodeInput", () => { const mockClipboardReadWithoutNumbers = jest.fn(() => Promise.resolve("sdkjfnsd"), ); - Object.assign(navigator, { - clipboard: { + // `userEvent.setup()` may install `navigator.clipboard` as a getter-only prop. + // Use `defineProperty` so this mock is resilient regardless of that setup. + Object.defineProperty(navigator, "clipboard", { + value: { readText: mockClipboardReadWithoutNumbers, }, + configurable: true, }); }); @@ -134,4 +138,61 @@ describe("CodeInput", () => { expect(inputFields[3]).toHaveValue(null); expect(inputFields[2]).toHaveFocus(); }); + + it("redirects focus to first empty input when clicking on empty input in unified variant", async () => { + const user = userEvent.setup(); + render(); + const inputFields = screen.getAllByRole("textbox"); + expect(inputFields).toHaveLength(6); + + // Enter some digits in the first two positions + fireEvent.keyDown(inputFields[0], { key: "1" }); + fireEvent.keyDown(inputFields[1], { key: "2" }); + + // Now focus should be on the third input (index 2) + expect(inputFields[2]).toHaveFocus(); + + // Simulate clicking on the 5th input (index 4) - an empty position + // onMouseDown should redirect focus to the first empty input (index 2) + await user.click(inputFields[4]); + expect(inputFields[2]).toHaveFocus(); + }); + + it("allows clicking on any filled input in unified variant", async () => { + const user = userEvent.setup(); + render(); + const inputFields = screen.getAllByRole("textbox"); + + // Enter some digits + fireEvent.keyDown(inputFields[0], { key: "1" }); + fireEvent.keyDown(inputFields[1], { key: "2" }); + fireEvent.keyDown(inputFields[2], { key: "3" }); + + // Focus should be on the 4th input (index 3) + expect(inputFields[3]).toHaveFocus(); + + // Clicking on a filled input (index 1) should work normally - no redirect + await user.click(inputFields[1]); + expect(inputFields[1]).toHaveFocus(); + + // Can also click on index 0 + await user.click(inputFields[0]); + expect(inputFields[0]).toHaveFocus(); + + // Can also click on index 2 + await user.click(inputFields[2]); + expect(inputFields[2]).toHaveFocus(); + }); + + it("focuses first input when all inputs are empty in unified variant", () => { + render(); + const inputFields = screen.getAllByRole("textbox"); + + // Blur the auto-focused first input + fireEvent.blur(inputFields[0]); + + // Click on a middle input when all are empty + fireEvent.mouseDown(inputFields[3]); + expect(inputFields[0]).toHaveFocus(); + }); }); diff --git a/packages/core/src/utils/currency.ts b/packages/core/src/utils/currency.ts index 56b40a2a0..35bfe585c 100644 --- a/packages/core/src/utils/currency.ts +++ b/packages/core/src/utils/currency.ts @@ -43,6 +43,9 @@ export const CurrencyUnit = { XAF: "XAF", MWK: "MWK", RWF: "RWF", + ZMW: "ZMW", + AED: "AED", + GTQ: "GTQ", USDT: "USDT", USDC: "USDC", @@ -58,6 +61,7 @@ export const CurrencyUnit = { Gbp: "GBP", Inr: "INR", Brl: "BRL", + Aed: "AED", Usdt: "USDT", Usdc: "USDC", } as const; @@ -110,6 +114,9 @@ const standardUnitConversionObj = { [CurrencyUnit.XAF]: (v: number) => v, [CurrencyUnit.MWK]: (v: number) => v, [CurrencyUnit.RWF]: (v: number) => v, + [CurrencyUnit.ZMW]: (v: number) => v, + [CurrencyUnit.AED]: (v: number) => v, + [CurrencyUnit.GTQ]: (v: number) => v, [CurrencyUnit.USDT]: (v: number) => v, [CurrencyUnit.USDC]: (v: number) => v, }; @@ -161,6 +168,9 @@ const CONVERSION_MAP = { [CurrencyUnit.XAF]: toBitcoinConversion, [CurrencyUnit.MWK]: toBitcoinConversion, [CurrencyUnit.RWF]: toBitcoinConversion, + [CurrencyUnit.ZMW]: toBitcoinConversion, + [CurrencyUnit.AED]: toBitcoinConversion, + [CurrencyUnit.GTQ]: toBitcoinConversion, [CurrencyUnit.USDT]: toBitcoinConversion, [CurrencyUnit.USDC]: toBitcoinConversion, }, @@ -196,6 +206,9 @@ const CONVERSION_MAP = { [CurrencyUnit.XAF]: toMicrobitcoinConversion, [CurrencyUnit.MWK]: toMicrobitcoinConversion, [CurrencyUnit.RWF]: toMicrobitcoinConversion, + [CurrencyUnit.ZMW]: toMicrobitcoinConversion, + [CurrencyUnit.AED]: toMicrobitcoinConversion, + [CurrencyUnit.GTQ]: toMicrobitcoinConversion, [CurrencyUnit.USDT]: toMicrobitcoinConversion, [CurrencyUnit.USDC]: toMicrobitcoinConversion, }, @@ -231,6 +244,9 @@ const CONVERSION_MAP = { [CurrencyUnit.XAF]: toMillibitcoinConversion, [CurrencyUnit.MWK]: toMillibitcoinConversion, [CurrencyUnit.RWF]: toMillibitcoinConversion, + [CurrencyUnit.ZMW]: toMillibitcoinConversion, + [CurrencyUnit.AED]: toMillibitcoinConversion, + [CurrencyUnit.GTQ]: toMillibitcoinConversion, [CurrencyUnit.USDT]: toMillibitcoinConversion, [CurrencyUnit.USDC]: toMillibitcoinConversion, }, @@ -266,6 +282,9 @@ const CONVERSION_MAP = { [CurrencyUnit.XAF]: toMillisatoshiConversion, [CurrencyUnit.MWK]: toMillisatoshiConversion, [CurrencyUnit.RWF]: toMillisatoshiConversion, + [CurrencyUnit.ZMW]: toMillisatoshiConversion, + [CurrencyUnit.AED]: toMillisatoshiConversion, + [CurrencyUnit.GTQ]: toMillisatoshiConversion, [CurrencyUnit.USDT]: toMillisatoshiConversion, [CurrencyUnit.USDC]: toMillisatoshiConversion, }, @@ -301,6 +320,9 @@ const CONVERSION_MAP = { [CurrencyUnit.XAF]: toNanobitcoinConversion, [CurrencyUnit.MWK]: toNanobitcoinConversion, [CurrencyUnit.RWF]: toNanobitcoinConversion, + [CurrencyUnit.ZMW]: toNanobitcoinConversion, + [CurrencyUnit.AED]: toNanobitcoinConversion, + [CurrencyUnit.GTQ]: toNanobitcoinConversion, [CurrencyUnit.USDT]: toNanobitcoinConversion, [CurrencyUnit.USDC]: toNanobitcoinConversion, }, @@ -336,6 +358,9 @@ const CONVERSION_MAP = { [CurrencyUnit.XAF]: toSatoshiConversion, [CurrencyUnit.MWK]: toSatoshiConversion, [CurrencyUnit.RWF]: toSatoshiConversion, + [CurrencyUnit.ZMW]: toSatoshiConversion, + [CurrencyUnit.AED]: toSatoshiConversion, + [CurrencyUnit.GTQ]: toSatoshiConversion, [CurrencyUnit.USDT]: toSatoshiConversion, [CurrencyUnit.USDC]: toSatoshiConversion, }, @@ -364,6 +389,9 @@ const CONVERSION_MAP = { [CurrencyUnit.XAF]: standardUnitConversionObj, [CurrencyUnit.MWK]: standardUnitConversionObj, [CurrencyUnit.RWF]: standardUnitConversionObj, + [CurrencyUnit.ZMW]: standardUnitConversionObj, + [CurrencyUnit.AED]: standardUnitConversionObj, + [CurrencyUnit.GTQ]: standardUnitConversionObj, [CurrencyUnit.USDT]: standardUnitConversionObj, [CurrencyUnit.USDC]: standardUnitConversionObj, }; @@ -452,6 +480,9 @@ export type CurrencyMap = { [CurrencyUnit.XAF]: number; [CurrencyUnit.MWK]: number; [CurrencyUnit.RWF]: number; + [CurrencyUnit.ZMW]: number; + [CurrencyUnit.AED]: number; + [CurrencyUnit.GTQ]: number; [CurrencyUnit.USDT]: number; [CurrencyUnit.USDC]: number; [CurrencyUnit.FUTURE_VALUE]: number; @@ -490,6 +521,9 @@ export type CurrencyMap = { [CurrencyUnit.XAF]: string; [CurrencyUnit.MWK]: string; [CurrencyUnit.RWF]: string; + [CurrencyUnit.ZMW]: string; + [CurrencyUnit.AED]: string; + [CurrencyUnit.GTQ]: string; [CurrencyUnit.USDT]: string; [CurrencyUnit.USDC]: string; [CurrencyUnit.FUTURE_VALUE]: string; @@ -709,6 +743,9 @@ function convertCurrencyAmountValues( xaf: CurrencyUnit.XAF, mwk: CurrencyUnit.MWK, rwf: CurrencyUnit.RWF, + zmw: CurrencyUnit.ZMW, + aed: CurrencyUnit.AED, + gtq: CurrencyUnit.GTQ, mibtc: CurrencyUnit.MICROBITCOIN, mlbtc: CurrencyUnit.MILLIBITCOIN, nbtc: CurrencyUnit.NANOBITCOIN, @@ -792,6 +829,9 @@ export function mapCurrencyAmount( xaf, mwk, rwf, + zmw, + aed, + gtq, usdt, usdc, } = convertCurrencyAmountValues(unit, value, unitsPerBtc, conversionOverride); @@ -825,6 +865,9 @@ export function mapCurrencyAmount( [CurrencyUnit.XAF]: xaf, [CurrencyUnit.MWK]: mwk, [CurrencyUnit.RWF]: rwf, + [CurrencyUnit.ZMW]: zmw, + [CurrencyUnit.AED]: aed, + [CurrencyUnit.GTQ]: gtq, [CurrencyUnit.MICROBITCOIN]: mibtc, [CurrencyUnit.MILLIBITCOIN]: mlbtc, [CurrencyUnit.NANOBITCOIN]: nbtc, @@ -956,6 +999,18 @@ export function mapCurrencyAmount( value: rwf, unit: CurrencyUnit.RWF, }), + [CurrencyUnit.ZMW]: formatCurrencyStr({ + value: zmw, + unit: CurrencyUnit.ZMW, + }), + [CurrencyUnit.AED]: formatCurrencyStr({ + value: aed, + unit: CurrencyUnit.AED, + }), + [CurrencyUnit.GTQ]: formatCurrencyStr({ + value: gtq, + unit: CurrencyUnit.GTQ, + }), [CurrencyUnit.USDT]: formatCurrencyStr({ value: usdt, unit: CurrencyUnit.USDT, @@ -1086,6 +1141,12 @@ export const abbrCurrencyUnit = (unit: CurrencyUnitType) => { return "MWK"; case CurrencyUnit.RWF: return "RWF"; + case CurrencyUnit.ZMW: + return "ZMW"; + case CurrencyUnit.AED: + return "AED"; + case CurrencyUnit.GTQ: + return "GTQ"; } return "Unsupported CurrencyUnit"; }; diff --git a/packages/ui/src/components/CardForm/CardForm.tsx b/packages/ui/src/components/CardForm/CardForm.tsx index d9e512c39..1a3779a04 100644 --- a/packages/ui/src/components/CardForm/CardForm.tsx +++ b/packages/ui/src/components/CardForm/CardForm.tsx @@ -460,6 +460,7 @@ const CardFormContentFull = styled.div<{ paddingBottom?: number | undefined }>` flex-direction: column; align-self: center; height: 100%; + width: 100%; padding-bottom: ${({ paddingBottom }) => paddingBottom ?? 0}px; `; diff --git a/packages/ui/src/components/CardPage.tsx b/packages/ui/src/components/CardPage.tsx index 8846e4fdc..1957b5880 100644 --- a/packages/ui/src/components/CardPage.tsx +++ b/packages/ui/src/components/CardPage.tsx @@ -28,6 +28,7 @@ type Props = { maxContentWidth?: number; rightContent?: React.ReactNode; preHeaderContent?: React.ReactNode; + headerRightContent?: React.ReactNode; expandRight?: boolean; id?: string; }; @@ -43,6 +44,9 @@ export function CardPage(props: Props) { {props.title} + {props.headerRightContent && ( + {props.headerRightContent} + )} ) : null; @@ -350,6 +354,11 @@ const CardPageHeader = styled.div<{ headerMarginBottom?: number }>` } `; +const CardPageHeaderRight = styled.div` + display: flex; + align-items: center; +`; + export const CardPageContent = styled.div` ${({ maxContentWidth, diff --git a/packages/ui/src/components/CodeInput/CodeInput.tsx b/packages/ui/src/components/CodeInput/CodeInput.tsx index e5e38d02a..b6af4a32d 100644 --- a/packages/ui/src/components/CodeInput/CodeInput.tsx +++ b/packages/ui/src/components/CodeInput/CodeInput.tsx @@ -331,6 +331,27 @@ export function CodeInput({ const inputsPerGroup = Math.ceil(codeLength / 2); + /** + * When clicking on the unified code input container, handle focus appropriately + * Uses onMouseDown instead of onClick because mousedown fires before focus, + * allowing us to prevent the default focus behavior and redirect to the correct input. + */ + const onContainerMouseDown = useCallback( + (event: React.MouseEvent) => { + const target = event.target as HTMLInputElement; + const isClickingFilledInput = + target.tagName === "INPUT" && inputState[target.id]?.value !== ""; + if (!isClickingFilledInput) { + event.preventDefault(); + const firstEmptyIndex = codeFromInputState(inputState).length; + const targetIndex = + firstEmptyIndex < codeLength ? firstEmptyIndex : codeLength - 1; + getRef(getInputId(targetIndex), inputRefs)?.focus(); + } + }, + [codeLength, getInputId, inputState, inputRefs], + ); + const inputs = []; for (let i = 0; i < codeLength; i += 1) { const inputId = getInputId(i); @@ -413,7 +434,11 @@ export function CodeInput({ } if (variant === "unified") { - return {inputs}; + return ( + + {inputs} + + ); } return ( diff --git a/packages/ui/src/components/DataManagerTable/AppliedButtonsContainer.tsx b/packages/ui/src/components/DataManagerTable/AppliedButtonsContainer.tsx new file mode 100644 index 000000000..780d7b8db --- /dev/null +++ b/packages/ui/src/components/DataManagerTable/AppliedButtonsContainer.tsx @@ -0,0 +1,14 @@ +import styled from "@emotion/styled"; +import { Spacing } from "../../styles/tokens/spacing.js"; +import { ButtonSelector } from "../Button.js"; + +export const AppliedButtonsContainer = styled.div` + margin-top: ${Spacing.px.sm}; + display: flex; + gap: ${Spacing.px.xs}; + flex-wrap: wrap; + + ${ButtonSelector()} { + max-width: 100%; + } +`; diff --git a/packages/ui/src/components/DataManagerTable/EnumFilter.tsx b/packages/ui/src/components/DataManagerTable/EnumFilter.tsx index 31e149ab6..6b435c91d 100644 --- a/packages/ui/src/components/DataManagerTable/EnumFilter.tsx +++ b/packages/ui/src/components/DataManagerTable/EnumFilter.tsx @@ -1,9 +1,8 @@ -import styled from "@emotion/styled"; import { ensureArray } from "@lightsparkdev/core"; -import { Spacing } from "../../styles/tokens/spacing.js"; import { z } from "../../styles/z-index.js"; import { Button } from "../Button.js"; import Select from "../Select.js"; +import { AppliedButtonsContainer } from "./AppliedButtonsContainer.js"; import { Filter, type FilterState } from "./Filter.js"; import { FilterType, type EnumFilterValue } from "./filters.js"; @@ -105,10 +104,3 @@ export const EnumFilter = ({ ); }; - -const AppliedButtonsContainer = styled.div` - margin-top: ${Spacing.px.sm}; - display: flex; - gap: ${Spacing.px.xs}; - flex-wrap: wrap; -`; diff --git a/packages/ui/src/components/DataManagerTable/IdFilter.tsx b/packages/ui/src/components/DataManagerTable/IdFilter.tsx index ffd45f31d..d9a8d2819 100644 --- a/packages/ui/src/components/DataManagerTable/IdFilter.tsx +++ b/packages/ui/src/components/DataManagerTable/IdFilter.tsx @@ -1,7 +1,6 @@ -import styled from "@emotion/styled"; -import { Spacing } from "../../styles/tokens/spacing.js"; import { Button } from "../Button.js"; import { TextInput } from "../TextInput.js"; +import { AppliedButtonsContainer } from "./AppliedButtonsContainer.js"; import { Filter, type FilterState } from "./Filter.js"; import { FilterType } from "./filters.js"; @@ -148,10 +147,3 @@ export const IdFilter = ({ ); }; - -const AppliedButtonsContainer = styled.div` - margin-top: ${Spacing.px.sm}; - display: flex; - gap: ${Spacing.px.xs}; - flex-wrap: wrap; -`; diff --git a/packages/ui/src/components/DataManagerTable/StringFilter.tsx b/packages/ui/src/components/DataManagerTable/StringFilter.tsx index 79a9d842c..d6eb6666a 100644 --- a/packages/ui/src/components/DataManagerTable/StringFilter.tsx +++ b/packages/ui/src/components/DataManagerTable/StringFilter.tsx @@ -1,7 +1,6 @@ -import styled from "@emotion/styled"; -import { Spacing } from "../../styles/tokens/spacing.js"; import { Button } from "../Button.js"; import { TextInput } from "../TextInput.js"; +import { AppliedButtonsContainer } from "./AppliedButtonsContainer.js"; import { Filter, type FilterState } from "./Filter.js"; import { FilterType } from "./filters.js"; @@ -82,10 +81,3 @@ export const StringFilter = ({ ); }; - -const AppliedButtonsContainer = styled.div` - margin-top: ${Spacing.px.sm}; - display: flex; - gap: ${Spacing.px.xs}; - flex-wrap: wrap; -`; diff --git a/packages/ui/src/icons/central/BankSolid.tsx b/packages/ui/src/icons/central/BankSolid.tsx new file mode 100644 index 000000000..716f15e8b --- /dev/null +++ b/packages/ui/src/icons/central/BankSolid.tsx @@ -0,0 +1,18 @@ +export function BankSolid() { + return ( + + + + ); +} diff --git a/packages/ui/src/icons/central/index.tsx b/packages/ui/src/icons/central/index.tsx index 44f5028dd..fe01e739c 100644 --- a/packages/ui/src/icons/central/index.tsx +++ b/packages/ui/src/icons/central/index.tsx @@ -16,6 +16,7 @@ export { ArrowUpRight as CentralArrowUpRight } from "./ArrowUpRight.js"; export { At as CentralAt } from "./At.js"; export { Bank as CentralBank } from "./Bank.js"; export { BankBold as CentralBankBold } from "./BankBold.js"; +export { BankSolid as CentralBankSolid } from "./BankSolid.js"; export { BarsThree as CentralBarsThree } from "./BarsThree.js"; export { Bell as CentralBell } from "./Bell.js"; export { Bell2 as CentralBell2 } from "./Bell2.js";