🔷 Admix Components Library
ACL
yarn add @admixltd/admix-component-library
Subpackages list
this packages not included to @admixltd/admix-component-library
directly and should use specific import
'@admixltd/admix-component-library/Api'
'@admixltd/admix-component-library/AuthWrapper'
'@admixltd/admix-component-library/AutoComplete'
'@admixltd/admix-component-library/ChipArray'
'@admixltd/admix-component-library/Deprecated'
'@admixltd/admix-component-library/FormAtomGenerator'
'@admixltd/admix-component-library/NumericInput'
'@admixltd/admix-component-library/RecoilNexus'
'@admixltd/admix-component-library/Snackbar'
'@admixltd/admix-component-library/Table'
Usage in your project:
1. Install component-specific dependencies
List of component-specific **optional** dependencies
Deprecated
If you want to use legacy packages from deprecated section, based on antd
, you should install next packages:
They are in the deprecated section because they use direct or indirect dependence on antd, for example AdmixButton in AppDiscoveryItem.tsx
yarn add recharts antd
import { AdmixButton, AdmixBarChart, AdmixBarChartProps } from '@admixltd/admix-component-library/Deprecated'
Autocomplete , Select
To use Autocomplete
or Select
component please install:
yarn add react-window
import { AutoComplete, Select } from '@admixltd/admix-component-library/AutoComplete'
Table
To use Table
component please install:
yarn add @mui/x-data-grid react-window
import { Table } from '@admixltd/admix-component-library/Table'
NumericInput
To use NumericInput
component please install:
yarn add react-number-format
import { NumericInput } from '@admixltd/admix-component-library/NumericInput'
AuthWrapper
To use AuthWrapper
component please install:
yarn add react-cookie notistack
import { AuthWrapper } from '@admixltd/admix-component-library/AuthWrapper'
ChipArray
To use ChipArray
component please install:
yarn add react-transition-group
import { ChipArray } from '@admixltd/admix-component-library/ChipArray'
FormAtomGenerator
To use FormAtomGenerator
component please install:
yarn add recoil
import { FormAtomGenerator } from '@admixltd/admix-component-library/FormAtomGenerator'
RecoilNexus
To use RecoilNexus
component please install:
yarn add recoil
import { RecoilNexus } from '@admixltd/admix-component-library/RecoilNexus'
Snackbar
If you want use Snackbar
component please install:
yarn add notistack
import { Snackbar } from '@admixltd/admix-component-library/Snackbar'
2. Add Inter font
To use this library, please add Inter font to your project
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
Or use local Inter font copy (Preferred for ssr)
Use: https://amio.github.io/embedded-google-fonts/ to store font in one file with base64
How to use local font copy
<!-- Your html file-->
<!--suppress CommaExpressionJS -->
<script>
const fontFile = '/inter.css'
const fontFamily = `Inter`
/**
* Save font into localstorage for fast refresh
*/
;(function() {
function addFont() {
const e = document.createElement('style');
document.head.appendChild(e);
e.textContent = localStorage.preloaded_font;
}
const fontExists = !!localStorage.preloaded_font && localStorage.preloaded_font.includes(fontFamily);
if (fontExists){
addFont();
return;
}
fetch(fontFile).then(t=>t.text()).then(t=>{
localStorage.setItem('preloaded_font', t);
addFont();
});
})()
</script>
3. Use theme
If you are using `@emotion`
AdmixLibraryTheme
with your @emotion
theme
1. Merge //styles/theme.ts
import { AdmixLibraryTheme } from '@admixltd/admix-component-library'
/**
* Your styles
*/
const projectTheme = {
purple: `#DDA0DD`,
}
/**
* Override theme styles
*/
AdmixLibraryTheme.colors.primary = '#000'
AdmixLibraryTheme.colors.secondary = projectTheme.purple
/**
* Extend style-components with theme type
*/
export type ITheme = typeof AdmixLibraryTheme & typeof projectTheme
const theme = { ...AdmixLibraryTheme, ...projectTheme } as ITheme
export type PropsWithTheme<T = unknown> = T & {
theme: ITheme
}
export default theme
Theme
2. Redeclare https://emotion.sh/docs/typescript#define-a-theme
//emotion.d.ts
import "@emotion/react";
import { ITheme } from "@styles/theme";
declare module "@emotion/react" {
/**
* Should be interface not a type
*/
export interface Theme extends ITheme {
}
}
AdmixThemeProvider
and ThemeProvider
from @emotion
3.Wrap your app with //App.jsx
import { AdmixThemeProvider } from '@admixltd/admix-component-library';
import theme from 'styles/theme';
<AdmixThemeProvider theme={theme}>
<App />
</AdmixThemeProvider>
/**
* Or same without AdmixThemeProvider
*/
import { ThemeProvider as EmotionThemeProvider } from '@emotion/react'
import { createTheme, ThemeProvider as MuiThemeProvider } from '@mui/material'
import theme from 'styles/theme';
const muiTheme = createTheme({});
<MuiThemeProvider theme={muiTheme}>
<EmotionThemeProvider theme={theme}>
<App />
</EmotionThemeProvider>
</MuiThemeProvider>
If you are using `styled-components` (Not recommended anymore)
AdmixLibraryTheme
with your styled-components
theme
1. Merge //styles/theme.ts
import { AdmixLibraryTheme } from '@admixltd/admix-component-library'
/**
* Your styles
*/
const projectTheme = {
purple: `#DDA0DD`,
}
/**
* Override theme styles
*/
AdmixLibraryTheme.colors.primary = '#000'
AdmixLibraryTheme.colors.secondary = projectTheme.purple
/**
* Extend style-components with theme type
*/
export type ITheme = typeof AdmixLibraryTheme & typeof projectTheme
const theme = { ...AdmixLibraryTheme, ...projectTheme } as ITheme
export default theme
DefaultTheme
2. Redeclare https://styled-components.com/docs/api#create-a-declarations-file
//styled.d.ts
import 'styled-components'
import { ITheme } from '@styles/theme'
declare module 'styled-components' {
/**
* Should be interface not a type
*/
export interface DefaultTheme extends ITheme {}
}
AdmixThemeProvider
and ThemeProvider
from styled-components
3.Wrap your app with //App.jsx
import { AdmixThemeProvider } from '@admixltd/admix-component-library';
import { ThemeProvider } from 'styled-components';
import theme from 'styles/theme';
<AdmixThemeProvider>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</AdmixThemeProvider>
/**
* Or same without AdmixThemeProvider
*/
import { ThemeProvider as EmotionThemeProvider } from '@emotion/react'
import { createTheme, ThemeProvider as MuiThemeProvider } from '@mui/material'
import { ThemeProvider } from 'styled-components';
import theme from 'styles/theme';
const muiTheme = createTheme({});
<MuiThemeProvider theme={muiTheme}>
<EmotionThemeProvider theme={theme}>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</EmotionThemeProvider>
</MuiThemeProvider>
🎂
4. Enjoy using it, you are wonderful! Development
How to develop new ACL components
If you haven't used `yarn` before
If you haven't used yarn
before, please make sure that you install dependencies in an empty node_modules
folder
npm install --global yarn
yarn global add rimraf
Remove node_modules
recursively
rimraf node_modules
1. Install dependencies
yarn
2. Run storybook
yarn start
Build project
yarn clean && yarn build
Link projects to work locally
How to work locally with ACL
1. Start building in watch mode
yarn build-watch
dependencies
and admix-component-library
in your project package.json
file
2. Link {
"@admixltd/admix-component-library": "link:../admix-component-library/build",
"react": "link:../admix-component-library/node_modules/react",
"react-dom": "link:../admix-component-library/node_modules/react-dom",
"@emotion/react": "link:../admix-component-library/node_modules/@emotion/react",
"@emotion/styled": "link:../admix-component-library/node_modules/@emotion/styled",
"@mui/material": "link:../admix-component-library/node_modules/@mui/material",
"notistack": "link:../admix-component-library/node_modules/notistack",
"recoil": "link:../admix-component-library/node_modules/recoil"
}
Use theming
3.Snackbar usage
How to use Snackbar everywhere
notistack
package
1. Install yarn add notistack
SnackbarProvider
2. Wrap your app with SnackbarUtilsConfigurator
next to your app
3. Add import { SnackbarProvider } from 'notistack';
import { SnackbarUtilsConfigurator } from '@admixltd/admix-component-library/Snackbar';
<SnackbarProvider
maxSnack={10}
anchorOrigin={{
vertical: 'bottom', horizontal: 'right',
}}
>
<YourApp />
<SnackbarUtilsConfigurator />
</SnackbarProvider>
Snackbar
anywhere
4. Use import { Snackbar } from '@admixltd/admix-component-library/Snackbar'
Snackbar.toast('Hello world!')
Snackbar.success(<>Hello <strong>world</strong>!</>)
FormAtomGenerator usage
Generate atoms and selectors for recoil to use them in forms or in please where you need control state based on object
import { useRecoilState } from 'recoil'
import { FormAtomGenerator } from "@admixltd/admix-component-library/FormAtomGenerator";
const initialValue: FormDataProps = {
name: 'Jake',
surname: 'Smith'
}
interface FormDataProps {
name: string
surname: string
}
const {
AtomUpdater: SomeFormAtomUpdater,
DataUpdater: SomeFormDataUpdater,
DataMerger: SomeFormDataMerger,
} = FormAtomGenerator<FormDataProps>(
'SomeFormKey',
initialValue
)
const SomeComponent = () => {
/**
* Control value for specific field
*/
const [value1, setValue1] = useRecoilState(SomeFormAtomUpdater('name'))
const [value2, setValue2] = useRecoilState(SomeFormAtomUpdater('surname'))
/**
* Control array of fields ( useful for errors )
*/
const [value3, setValue3] = useRecoilState(SomeFormAtomUpdater(['name', 'surname']))
/**
* value3 - returns first non undefinened value from list of fields
* value3 = values1['name'] ?? values1['surname'] ?? values1[...]
* setValue3('SomeText') - updates current field form value3
* if value3 = values1['name'] - updates 'name'
*/
/**
* Controll all values
* setValues1 first call {x: text}
* setValues1 second call {y: text}
* ===>
* {y: text}
*/
const [values1, setValues1] = useRecoilState(SomeFormDataUpdater)
/**
* Controll all values with merge
* Merge values by parts like:
* setValues2 first call {x: text}
* setValues2 second call {y: text}
* ===>
* {x: text, y: text}
*/
const [values2, setValues2] = useRecoilState(SomeFormDataMerger)
return <></>
}
RecoilNexus usage
Easily control any recoil atom from anywhere in the app
RecoilNexus
in your RecoilRoot
1. Add import React from "react";
import { RecoilRoot } from "recoil";
import { RecoilNexus } from "@admixltd/admix-component-library/RecoilNexus";
export default function App() {
return (
<RecoilRoot>
<RecoilNexus />
{/* ... */}
</RecoilRoot>
);
}
export default App;
2. Use the following methods to get/set values passing your atom as a parameter.
| Method | Returns |
|:-------------------|:----------------------------------------------------------------------------|
| getRecoil
| getter function |
| getRecoilPromise
| getter function, returns a promise. To be used with asynchronous selectors. |
| setRecoil
| setter function, pass value to be set as second parameter |
| resetRecoil
| pass atom as parameter to reset to default value |
// Loading example
import { loadingState } from "../atoms/loadingState";
import { getRecoil, setRecoil } from "@admixltd/admix-component-library/RecoilNexus";
export default function toggleLoading() {
const loading = getRecoil(loadingState);
setRecoil(loadingState, !loading);
}
//Loader
import React from "react";
import { useRecoilValue } from "recoil";
export default function Loader() {
loading = useRecoilValue(loadingState);
return loading ? <h3>Loading...</h3> : null;
}
//Atom
import { atom } from "recoil";
export const loadingState = atom({
key: "LOADING",
default: false,
});
Helpers description
Name | Description |
---|---|
AdmixThemeProvider |
ThemeContextProver with a theme included in it for Admix component library |
AuthWrapper |
Makes child components available only after Admix authorization |
PromiseAll |
Allows you to receive a response from Promise.all as an object |
Snackbar |
Please read snackbar usage section |
RecoilNexus |
Please read RecoilNexus usage section |
FormAtomGenerator |
Please read FormAtomGenerator usage section. Generate atoms and selectors for recoil to use them in forms or in please where you need control state based on object |
Hooks description
Name | Description |
---|---|
useMerge |
Object.assign for the state, used as an analogue of useState, but without overwriting the entire state, but only part of it |
usePrevious |
Saves the state of the previous render |
useFirstRender |
Detect is first render or not |
useWindowSize |
Allows you to get the window size |
Utils description
Name | Description |
---|---|
childrenToText |
Accepts JSX and returns only the Text from it. Useful for logging |
trimUrlSlashes |
Removes unnecessary slashes from the URL |
fontLoader |
Loads the font file into the localStorage |
childrenWithProps |
Pass props to children |
ignoreRecoilErrors |
Allows you to ignore recoil errors, which are usually incorrect |
getURLSearchParameters |
Allows you to get the parameters object from the search part of the URL |
numberFormatter |
Shortens the number with formatting (K, M, G, ...)
|
transientOptions |
You need to add to emotion/styled so that attributes with $ are not passed to the component EX: const ButtonInput = styled(Button, transientOptions)<{$primaryColor?: ...}>
|
handleBlur |
Triggers a loss of focus for the user |
uniqBy |
Filters an array of objects by field (no lodash)
|
Chromatic manual deploying
npx chromatic --project-token=YOUR_TOKEN