npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@layerfi/components

v0.1.81

Published

Layer React Components

Downloads

4,857

Readme

Layer Financial React Components

Layer's embeddable React component library provides an out of the box accounting experience. This project emphasizes composability and brandability, allowing you to

  1. Use full page layouts we've already tested and used or layout individual components however you choose.
  2. Brand components with your company colors, fonts, and more.

All you need to get started is sandbox development credentials - reach out here if you don't have those yet!

Related links

  • Layer home: https://www.layerfi.com
  • Documentation: https://docs.layerfi.com/introduction
  • NPM: https://www.npmjs.com/package/@layerfi/components

Installation

npm install --save @layerfi/components

or

yarn install @layerfi/components

Usage

Nest the components you want to use under the LayerProvider component. You should provide the component with a few props:

  • businessId The ID of the business whose information you're showing.
  • businessAccessToken Temporary authentication token scoped to this specific business. See the getting started guide for how to fetch these tokens on your backend.
  • environment (Optional, defaults to "production") the Layer environment you're attempting to access [staging or production]
  • theme (Optional) to customize the look of components
  • onError (Optional) to get notified about exceptions
import { LayerProvider } from "@layerfi/components";
...
<LayerProvider
  businesId="..."
  businessAccessToken="..."
  environment={'staging'}
>
  {...}
</LayerProvider>

Development

In development, it's often convenient to avoid fetching business-scoped tokens. You may find it more convenient to set your sandbox clientId and clientSecret directly, which will give you access to any business in your sandbox account.

import { LayerProvider } from "@layerfi/components";
...
<LayerProvider
  businesId="..."
  appId="..."
  appSecret="..."
  environment={'staging'}
>
  {...}
</LayerProvider>

Components

Onboarding

The onboarding component can be included on an accounting landing page to prompt users to connect accounts. Onboarding landing state

After connecting accounts, the component will change into a prompt to categorize transactions. Onboarding after linking

For a business that has already been onboarded, this component will render nothing, so it's safe to leave it on the default page for all businesses.

<Onboarding onTransactionsToReviewClick={onTransactionsToReviewClick} />

This component has one primary prop: onTransactionsToReviewClick should be a function that navigates to the bank transactions to review page. For example, if the bank transaction categorization page lives on /account/bank-transactions within your app:

<Onboarding
  onTransactionsToReviewClick={() => navigate('/accounting/bank-transactions')}
/>

This prop is a function, so you can use your app's standard strategy for navigation.

Bank Accounts & Transactions

Linked Accounts

Displays all accounts connected to Layer including embedded banking, Plaid, and custom accounts.

Linked Accounts

<LinkedAccounts
  elevated={elevatedLinkedAccounts}
  showLedgerBalance={showLedgerBalance}
/>

Props:

  • asWidget: Minimized version of the component
  • elevated: Stylistic option to highlight component
  • showLedgerBalance: Flag to enable or hide the current ledger balance corresponding to this external account. Useful for reconciliation.

Transaction categorization

The transaction categorization component handles displaying both categorized transactions and the workflow for categorizing new transactions as they are imported into Layer.

TransactionCategorization

<BankTransactions asWidget />

Optional properties and useBankTransactionsContext give more control over the transactions list:

/** Using props */
<BankTransactions
  filters={{
    amount: { min: 0, max: 100 },
  }}
/>

/** Using hook */
const { setFilters } = useBankTransactionsContext()

setFilters({ amount: { min: 0, max: 10000 } })

<BankTransactions />

Reporting

Profit And Loss Chart

Profit and Loss chart

import { ProfitAndLoss } from "@layerfi/components";
…
<ProfitAndLoss>
  <ProfitAndLoss.Chart />
  <ProfitAndLoss.Summaries />
  <ProfitAndLoss.DatePicker />
  <ProfitAndLoss.Table />
</ProfitAndLoss>

Profit and Loss Summaries

import { ProfitAndLoss } from "@layerfi/components";
…
<ProfitAndLoss>
  <ProfitAndLoss.Summaries />
</ProfitAndLoss>

The P&L Summaries section supports several optional props:

  • actionable: When enabled, clicking the revenue & expense charts will open the P&L sidebar view.
  • variants: Override the size of the component; supports a small and large version.

Profit and Loss Table

Profit And Loss Table

import { ProfitAndLoss } from "@layerfi/components";
…
<ProfitAndLoss>
  <ProfitAndLoss.Table>
</ProfitAndLoss>

The P&L table supports one optional prop:

  • lockExpanded forces the table to be fully expanded showing all rows

Balance Sheet

Balance Sheet

The Balance Sheet component displays an interactive table. A default date can be passed in via the effectiveDate prop.

Statement of Cash Flows

Statement of Cash Flows

The statement of cashflows component is an interactive table displaying cash changes broken out into investing, financing, and operational activities. It is shown calculated via the standard indirect method.

Ledger

Chart of Accounts

Chart of Accounts

The chart of accounts gives direct read-and-write access into the double-entry general ledger underlying Layer's data. It exposes the list of accounts and enables users to create new accounts.

<ChartOfAccounts asWidget withDateControl withExpandAllButton />

The following props are supported

  • asWidget: Displays a more compact version.
  • withDateControl: Includes a date picker that determines the effective date of account balances displayed.
  • withExpandAllButton: Optionally displays a button to expand and collapse all sub-account lists.

Journal

Journal

The Journal component displays the full history of journal entries and allows users to create journal entries by hand as well.

A sidebar expands to display details about the invoice.

Journal sidebar

<Journal />

The follow props are supported:

  • asWidget: Compact version

Styling

You have a range of options for custom styling. In order of most simple to most control:

  1. Using the theme attribute of LayerProvider,
  2. Setting CSS variables,
  3. Overwriting CSS classes.

Using theme attribute

The theme attribute allows you to set primary light and dark colors. The component will then use your primary colors to create a cohesive color palette across all components. We won't add any new colors, just different lightness of your brand colors for accents where helpful, e.g. hover states.

<LayerProvider
  businessId="..."
  environment="..."
  theme={{
    colors: {
      // Base colors:
      dark: { h: '28', s: '26%', l: '11%' },
      light: { h: '52', s: '100%', l: '55%' },
    },
  }}
>
  {...}
</LayerProvider>

The colors can be defined in HSL, RGB or HEX:

// HSL:
colors: {
  dark: { h: '28', s: '26%', l: '11%' },
  light: { h: '52', s: '100%', l: '55%' },
},

// RGB:
colors: {
  dark: { r: '36', g: '28', b: '21' },
  light: { r: '255', g: '224', b: '27' },
},

// HEX:
colors: {
  dark: { hex: '#241C15' },
  light: { hex: '#FFE01B' },
},

CSS variables

body .Layer__component {
  --color-dark-h: 167;
  --color-dark-s: 38%;
  --color-dark-l: 15%;

  --text-color-primary: #333;
}

The full list of variables is listed in the variables.css file and contains:

// 1. BASE VARIABLES:
--color-black: #1a1a1a;
--color-white: white;

--color-info-success: hsl(145, 45%, 42%);
--color-info-success-bg: hsl(145, 59%, 86%);
--color-info-success-fg: hsl(145, 63%, 29%);

--color-info-warning: hsl(43, 100%, 44%);
--color-info-warning-bg: hsl(43, 100%, 84%);
--color-info-warning-fg: hsl(43, 88%, 26%);

--color-info-error: hsl(0 76% 50%);
--color-info-error-bg: hsl(0 83% 86%);
--color-info-error-fg: hsl(0 88% 32%);

--color-dark-h: 0;
--color-dark-s: 0%;
--color-dark-l: 7%;
--color-dark: hsl(var(--color-dark-h) var(--color-dark-s) var(--color-dark-l));

--color-light-h: 0;
--color-light-s: 0%;
--color-light-l: 90%;
--color-light: hsl(
  var(--color-light-h) var(--color-light-s) var(--color-light-l)
);

--color-base-0: #fff;
--color-base-50: hsl(var(--color-dark-h) 1% 98%);
--color-base-100: hsl(var(--color-dark-h) 1% 96%);
--color-base-200: hsl(var(--color-dark-h) 1% 94%);
--color-base-300: hsl(var(--color-dark-h) 2% 92%);
--color-base-400: var(--color-light);
--color-base-500: hsl(var(--color-dark-h) 2% 53%);
--color-base-600: hsl(var(--color-dark-h) 7% 40%);
--color-base-700: hsl(var(--color-dark-h) 9% 27%);
--color-base-800: hsl(var(--color-dark-h) 12% 20%);
--color-base-900: var(--color-dark);
--color-base-1000: hsl(var(--color-dark-h) 20% 7%);

--max-component-width: 1408px;

--base-transparent-1: hsla(220, 43%, 11%, 0.01);

--base-transparent-2: hsla(220, 43%, 11%, 0.02);

--base-transparent-4: hsla(
  var(--color-dark-h),
  var(--color-dark-s),
  var(--color-dark-l),
  0.04
);
--base-transparent-5: hsla(
  var(--color-dark-h),
  var(--color-dark-s),
  var(--color-dark-l),
  0.05
);
--base-transparent-6: hsla(
  var(--color-dark-h),
  var(--color-dark-s),
  var(--color-dark-l),
  0.06
);
--base-transparent-8: hsla(
  var(--color-dark-h),
  var(--color-dark-s),
  var(--color-dark-l),
  0.08
);
--base-transparent-10: hsla(
  var(--color-dark-h),
  var(--color-dark-s),
  var(--color-dark-l),
  0.1
);
--base-transparent-12: hsla(
  var(--color-dark-h),
  var(--color-dark-s),
  var(--color-dark-l),
  0.12
);

// 2. BASE CUSTOMIZATION
--color-primary: var(--color-dark);
--color-accent: var(--color-light);
--color-secondary: var(--color-base);
--color-success: var(--color-info-success);
--color-danger: var(--color-info-error);
--color-danger-dark: hsl(349, 30%, 30%);
--color-danger-light: hsla(
  var(--color-info-error-h),
  var(--color-info-error-s),
  var(--color-info-error-l),
  0.4
);
--text-color-primary: var(--color-dark);
--text-color-secondary: var(--color-base-600);
--bg-element-focus: var(--color-base-50);

// 3. EXTENDED CUSTOMIZATION
--font-family: 'InterVariable', 'Inter', sans-serif;
--font-family-numeric: 'InterVariable', 'Inter', sans-serif;
--text-xs: 11px;
--text-sm: 12px;
--text-md: 14px;
--text-lg: 16px;
--text-heading: 24px;
--text-heading-sm: 16px;
--font-weight-normal: 460;
--font-weight-bold: 540;
--spacing-4xs: 2px;
--spacing-3xs: 4px;
--spacing-2xs: 6px;
--spacing-xs: 8px;
--spacing-sm: 12px;
--spacing-md: 16px;
--spacing-lm: 20px;
--spacing-lg: 24px;
--spacing-xl: 32px;
--spacing-2xl: 36px;
--spacing-3xl: 40px;
--spacing-5xl: 52px;
--bg-color: var(--color-white);
--border-color: var(--color-base-200);
--border-radius-4xs: 2px;
--border-radius-3xs: 4px;
--border-radius-2xs: 6px;
--border-radius-xs: 8px;
--border-radius-sm: 12px;
--border-radius: 16px;
--border-radius-5xl: 52px;

--text-color-transaction-credit: var(--color-info-success);
--text-color-varying-amount: var(--color-base-700);

--input-border-radius: var(--border-radius-2xs);
--input-font-size: var(--text-md);
--input-border-color: var(--color-base-300);
--input-placeholder-color: var(--color-base-500);

--label-color: var(--color-base-700);

--btn-font-size: var(--text-md);
--btn-border-radius: var(--border-radius-2xs);
--btn-color: var(--color-black);
--btn-bg-color: var(--color-white);
--btn-color-primary: var(--color-white);
--btn-bg-color-primary: var(--color-black);
--btn-color-hover: var(--color-white);
--btn-bg-color-hover: var(--color-primary);
--btn-color-icon: var(--color-black);
--btn-bg-color-icon: var(--color-base-50);
--btn-color-icon-hover: var(--color-primary);
--btn-bg-color-icon-hover: var(--color-accent);
--btn-secondary-color: var(--color-black);
--btn-secondary-bg-color: var(--color-white);

--badge-color: var(--color-base-900);
--badge-fg-color: var(--color-base-900);
--badge-bg-color: var(--color-base-400);

--badge-color-success: var(--color-info-success);
--badge-fg-color-success: var(--color-info-success-fg);
--badge-bg-color-success: var(--color-info-success-bg);

--badge-color-warning: var(--color-info-warning);
--badge-fg-color-warning: var(--color-info-warning-fg);
--badge-bg-color-warning: var(--color-info-warning-bg);

--badge-color-error: var(--color-info-error);
--badge-fg-color-error: var(--color-info-error-fg);
--badge-bg-color-error: var(--color-info-error-bg);

--badge-border-radius: var(--border-radius-sm);

--table-bg: var(--color-white);

--tooltip-color: var(--color-white);
--tooltip-bg-color: var(--color-base-800);

--bar-color-income: var(--color-base-400);
--bar-color-expenses: var(--color-base-900);

--chart-indicator-color: var(--color-base-700);

CSS classes

For fine grained control, you can override specific classes. We recommend using your browser dev tools to find the component you want to restyle and override that specific class with a higher priority CSS rule.

body .Layer__table-cell-content {
  background: white;
}

body .Layer__bank-transaction-row .Layer__table-cell-content {
  background: gray;
}

Error callback

Use onError property on <LayerProvider /> to get notified about all exceptions:

<LayerProvider
  businessId="..."
  environment="..."
  appId="..."
  onError={err => console.log('My error callback', err)}
>
  {...}
</LayerProvider>

...or on the specific component:

<BankTransactions onError={e => console.log('My callback:', e)} />