@kwantis-id3/frontend-library
TypeScript icon, indicating that this package has built-in type declarations

0.22.2 • Public • Published

Hi! This is Kwantis Frontend Library

This project contains a collection of reusable components, developed for the kwantis' software ecosystem.

To import the library inside your project, please follow the instructions below.

Installation

With npm

npm install @kwantis-id3/frontend-library

With yarn

yarn add @kwantis-id3/frontend-library

With pnpm

pnpm add @kwantis-id3/frontend-library

Note that the library uses @emotion/styled and @emotion/react as dev dependencies. Installing them in your project may cause conflicts. The library however offers its own styled utility, that can be used to create styled components.

Usage

The library has various components, each one with its own documentation. Please refer to the storybook documentation for more information.

Components List

At the moment, the library contains the following components:

  • Accordion

  • Button

  • Select (both single and multi)

  • Slider

  • InputField, can be used as

    • Datepicker
    • Timepicker
    • Datetimepicker
    • TextField
    • NumberField
    • Text alternatives (email, password, url, tel, etc.)
  • Multilevel Dropdown

  • Modal

The following are under development or on our roadmap in no particular order:

  • Label
  • Checkbox
  • Radio
  • Datepicker (supported by InputField)
  • Timepicker (supported by InputField)
  • Datetimepicker (supported by InputField)
  • Table
  • Tabs

You can find various examples of usage in the projects stories.

Theming

The library internally uses the emotion library for styling. By default, the library uses a default theme, that looks like this:

export const defaultThemeColors = {
  primary: { main: "#1d4e89", contrastText: "#ffffff" },
  secondary: { main: "#00b2ca", contrastText: "#ffffff" },
  tertiary: { main: "#7dcfb6", contrastText: "#ffffff" },
  statusOk: { main: "#00e200", contrastText: "#ffffff" },
  statusWarning: { main: "#efff00", contrastText: "#ffffff" },
  statusCritical: { main: "#ff3838", contrastText: "#ffffff" },
  statusNeutral: { main: "#7b8089", contrastText: "#ffffff" },
};

You can override the default theme by passing a custom theme to the ThemeContextProvider component, like this:

import { ThemeContextProvider } from "@kwantis-id3/frontend-library";

const customTheme = {
  primary: { main: "#1d4e89", contrastText: "#ffffff" },
  secondary: { main: "#00b2ca", contrastText: "#ffffff" },
  tertiary: { main: "#7dcfb6", contrastText: "#ffffff" },
  statusOk: { main: "#00e200", contrastText: "#ffffff" },
  statusWarning: { main: "#efff00", contrastText: "#ffffff" },
  statusCritical: { main: "#ff3838", contrastText: "#ffffff" },
  statusNeutral: { main: "#7b8089", contrastText: "#ffffff" },
};

const App = () => {
  return (
    <ThemeContextProvider theme={customTheme}>
      <YourApp />
    </ThemeContextProvider>
  );
};

To add custom properties to the theme, you can extend the ThemeColorsObject interface in a .d.ts file, like this:

import "@kwantis-id3/frontend-library";

declare module "@kwantis-id3/frontend-library" {
  interface ThemeColorsObject {
    newColor: Color;
    newColor2: Color;
  }
}

Fetching the theme from an API

In case you fetch the theme from an API, there are a couple of things you need to do to avoid complications.

1. Handling non-native theme keys

The library uses the ThemeColorsObject interface to define the theme colors. This interface is used to define the default theme, and to extend it with custom properties, as discussed in the previous section.

If you fetch the theme from an API, it is strongly advised to use a default theme containing the additional keys, and then override it with the fetched one.

Otherwise, the additional keys in the theme may be undefined, and accessing them before the theme has finished fetching will cause an error.

Here's an example on how to do it, using react query, assuming that the theme has been extended with a newColor property:

import { ThemeContextProvider, ThemeContextProps } from "@kwantis-id3/frontend-library";
import { useQuery } from "react-query";

const App = () => {
  const defaultTheme: ThemeContextProps = {
    colors: {
      primary: { main: "#cccccc", contrastText: "#cccccc" },
      secondary: { main: "#cccccc", contrastText: "#cccccc" },
      tertiary: { main: "#cccccc", contrastText: "#cccccc" },
      statusOk: { main: "#cccccc", contrastText: "#cccccc" },
      statusWarning: { main: "#cccccc", contrastText: "#cccccc" },
      statusCritical: { main: "#cccccc", contrastText: "#cccccc" },
      statusNeutral: { main: "#cccccc", contrastText: "#cccccc" },
      newColor: { main: "#cccccc", contrastText: "#cccccc" },
    }
  }

  const fetchedTheme = useQuery({
    queryKey: ["theme"],
    queryFn: getColors,
    initialData: defaultTheme,
  });

  return (
    <ThemeContextProvider theme={fetchedTheme.data}>
      {...}
    </ThemeContextProvider>
  )
}

2. Avoiding FOUC

If you fetch the theme from an API, you may experience a FOUC (Flash Of Unstyled Content) when the theme is being fetched.

This is because the default theme (either being the one native to the library, or a custom one like in the previous section) is applied before the fetched one is ready, and the two may have some differences (especially if your application needs to be deployed on various instances with different themes).

To avoid this, you have 3 possible solutions:

  1. Do not render the application until the theme is ready
  2. Store the theme in the local storage, and use it as the default theme. Please note that this approach will still show the FOUC in the following cases:
    • The user has never visited the application before
    • The user has cleared the local storage / is using a different browser or device
    • The user has visited the application before, but the theme has changed since then
  3. Use the initialData property of the useQuery hook to pass a default theme, since useQuery automatically caches the queries data. This approach will still show the FOUC in the following cases:
    • The user has never visited the application before
    • The user has cleared the local storage / is using a different browser or device
    • The user has visited the application before, but the theme has changed since then

For case 3, the code remains unchanged from the previous section, so here's an example without react query for case 2:

import { ThemeContextProvider, ThemeContextProps } from "@kwantis-id3/frontend-library";
import React, { useEffect, useState } from "react";
import axios from "axios";

const App = () => {
  const defaultTheme: ThemeContextProps = {
    colors: {
      primary: { main: "#cccccc", contrastText: "#cccccc" },
      secondary: { main: "#cccccc", contrastText: "#cccccc" },
      tertiary: { main: "#cccccc", contrastText: "#cccccc" },
      statusOk: { main: "#cccccc", contrastText: "#cccccc" },
      statusWarning: { main: "#cccccc", contrastText: "#cccccc" },
      statusCritical: { main: "#cccccc", contrastText: "#cccccc" },
      statusNeutral: { main: "#cccccc", contrastText: "#cccccc" },
      newColor: { main: "#cccccc", contrastText: "#cccccc" },
    }
  }

  const [theme, setTheme] = React.useState(() => { //initialize state with default or localstorage value
    const localTheme = localStorage.getItem("myStoredTheme");
    if (localTheme) {
      return JSON.parse(localTheme) as ThemeContextProps;
    }
    return defaultTheme;
  });

  useEffect(() => {
    axios.get<ThemeContextProps>("theme")
    .then((response) => {
      setTheme(response.data);
      localStorage.setItem("myStoredTheme", JSON.stringify(response.data));
    })
    .catch ((error) => {
      console.log(error);
    })
  }, []);

  return (
    <ThemeContextProvider theme={theme}>
      {...}
    </ThemeContextProvider>
  )
}

The useThemeContext hook

The library exports a useThemeContext hook, that can be used to access the theme object from any component, exposing a ThemeProperties object.

import { useThemeContext } from "@kwantis-id3/frontend-library";

const MyComponent = () => {
  const theme = useThemeContext();

  useEffect(() => {
    console.log(theme);
  }, [theme]);

  return <div>...</div>;
};

Through the ThemeProperties object, you can access the theme colors either directly, or through the getColor(color: string) => Color property, that will return a valid Color based on the string parameter that it’s passed to it.

const theme = useThemeContext();
const primaryColor = theme.colors.primary.main;
// or
const primaryColor = theme.getColor("primary");

Basically, the property getColor can be used to:

  • Access the theme colors, in 2 ways:
    • Access the color directly, if the passed string is a valid key of the ThemeColorsObject interface. This is the same as accessing the color directly from the colors property, giving you access to the possible custom properties that you may have added to the theme.
    • Access the color through a path, if the passed string is a valid path of the ThemeColorsObject interface. This returns a Color object, that has only the main and contrastText properties, where main is the color that you are accessing, and contrastText is generated automatically to grant the best readability possible.
  • Generate a valid Color object, if the passed string is a valid hex code or css color function

In the latter case, the contrastText property will automatically be generated to grant the best readability possible.

If the passed string is not a valid color, the function will default to the primary color of the theme.

  const tertiartyColor = theme.getColor("tertiary");
  console.log(tertiaryColor); // { main: "#7dcfb6", contrastText: "#ffffff" }

  const tertiartyTextColor = theme.getColor("tertiary.contrastText");
  console.log(tertiaryTextColor); // { main: "#ffffff", contrastText: "#000000"}

  const fuchsia = theme.getColor("fuchsia");
  console.log(fuchsia); // { main: "fuchsia", contrastText: "#000000" }

  const rgba = theme.getColor("rgba(130, 146, 9, 0.5)");
  console.log(rgba); // { main: "rgba(130, 146, 9, 0.4)", contrastText: "#000000" }

  const notValid= theme.getColor("whatever123");
  console.log(notValid); // { main: "#1d4e89", contrastText: "#ffffff" }

The Color prop

Each component that has a color prop, accepts a string. The string can be a color name, a color path, a hex code, or a css color function.

// Color name
<Button color="primary" />

// Color path
<Button color="primary.contrastText" />

// Hex code
<Button color="#1d4e89" />

// Css color function
<Button color="rgb(29, 78, 137)" />

The styled utility and transientOptions

The library exports a styled utility, that can be used to create styled components. It works exactly like the styled utility from the @emotion/styled library, but it automatically passes the theme to the component.

import { styled } from "@kwantis-id3/frontend-library";

const StyledButton = styled.button`
  background-color: ${(props) => props.theme.colors.primary.main};
  color: ${(props) => props.theme.colors.primary.contrastText};
`;

const MyComponent = () => {
  return <StyledButton>Click me!</StyledButton>;
};

It also automatically updated if the Theme interface is extended, so you don’t have to worry about updating it manually.

If you want to create a styled component with props, you can do so using the transientOptions utility, like this:

import { styled, transientOptions } from "@kwantis-id3/frontend-library";

export const StyledDiv = styled("div", transientOptions)<{
  $bgColor: string;
}>`
  background: ${(props) => props.$bgColor};
`;

const MyComponent = () => {
  return <StyledDiv $bgColor="red">I'm red!</StyledDiv>;
};

It's important that the props defined this way are prefixed with a $ sign, to avoid conflicts with the native HTML props.

Readme

Keywords

none

Package Sidebar

Install

npm i @kwantis-id3/frontend-library

Weekly Downloads

12

Version

0.22.2

License

apache-2.0

Unpacked Size

1.13 MB

Total Files

35

Last publish

Collaborators

  • dyland_
  • giopat-kwantis