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

@instill-ai/design-system

v0.84.0

Published

Instill AI's design system

Downloads

2,290

Readme

About new design system

We are undergoing a series of revamps for our design-system, which included several aspects:

  1. Compound component first approach. Under the hood, we will use Radix-UI.
  2. We are abandoning one style one prop approach due to it being too verbose to use

Info

  • We use pnpm -r publish at the root folder to publish the packages

How to use the storybook at local

  • pnpm watch:css and let it run
  • pnpm sb

How to deploy storybook

  • Because design-system relies on design-tokens, when deploy to Vercel, we need to build the package first from the root with pnpm ci-build-storybook
  • The output will be put into /packages/design-system/storybook-static, we indicate this folder in the Vercel setting

Old design system

This is a react design system builds on top of TailwindCSS with several principles:

  • Two-level component design: base-level components and exported-level components
  • One style one prop approach: The base component will expose style as props as much as possible, one prop will only have one style string

How to use

  1. Install: yarn add @instill-ai/design-system
  2. Add this package into your main project tailwind.config.js and make sure you have all the necessary style
module.exports = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx}",
    "./src/components/**/*.{js,ts,jsx,tsx}",
    "./node_modules/@instill-ai/design-system/build/*.js",
  ],
};

How to contribute

Install typescript intelligence

  • We heavily rely on typescript at this moment, before you make any contribution please install typescript intelligence.

You should write component unit-test for every base-level component

  • We haven't embodied this approach

You should check the export structure.

  • We want to abstrct away the file structure, so every component should be exported to its outer folder.
    • If it is components, you should check whether it had already been exported to @instill-ai/design-system/components before you move on to the next step

Build before publish

  • You should use yarn build script to build the latest version of design-system and change the version of it, then you could publish the package. In the future, after the official 0.1.0 release we will adapt ci for this task.

Why we choose the utility class approach.

  • The utility class is easy to write, it can deliver an application at a relatively quick pace.
  • Just CSS, there has no further abstraction users need to learn.
  • Get rid of naming overhead: We don't want to re-invent thousands of class names just to select the right element.
  • Easy to use pseudo-class: peer, hover, group...etc are all very good functionality we could leverage out of the box.

The problems we try to solve

  • Oversize comes from being over-designed:
    • Traditionally, design systems want to find a one size for all components that leads to over-desige. This may result in a huge component with hundreds of if...else conditionally rendered style.
  • Over abstraction
    • Some design systems will try to abstract every layer of element. At the first glance, this can fertilize re-usability and encapsulate the styles, but it will bring up a lot of abstraction and cause unncessary overhead for consumers.
    • They don't want to make the style as props but comes up with other naming convention which causes another layer of abstraction like type={},
    • In this article, the author have a suitable example, In our perspective the first example is harder to read than the second one, it has too many layers of abstraction that is exactly what we want to avoid.
<Box padding={5} width="320px" border="sm">
  <Stack gap={2}>
    <Image borderRadius="md" src="https://bit.ly/2k1H1t6" />
    <Row gap={2}>
      <Badge color="#702459">Plus</Badge>
      <Spacer left={2}>
        <Text size="sm" weight="bold" color="#702459">
          VERIFIED &bull; CAPE TOWN
        </Text>
      </Spacer>
    </Row>
    <Text size="xl" weight="semibold">
      Modern, Chic Penthouse with Mountain, City & Sea Views
    </Text>
    <Text>$119/night</Text>
    <Row gap={1}>
      <Icon src={MdStar} color="#ED8936" />
      <Text size="sm">
        <Text size="sm" weight="bold">
          4.84
        </Text>
        (190)
      </Text>
    </Row>
  </Stack>
</Box>
<div className="w-32 rounded p-5">
  <div className="flex">
    <img className="w-full rounded" src="https://bit.ly/2k1H1t6" />
    <div className="mt-2 flex flex-row">
      <div className="bg-mono-400 rounded px-4 py-2">
        <div className="text-mono-100">Plus</div>
      </div>
      <div className="text-pale-100 text-sm font-bold">
        VERIFIED &bull; CAPE TOWN
      </div>
    </div>
    <span className="text-xl font-semibold">
      Modern, Chic Penthouse with Mountain, City & Sea Views
    </span>
    <span className="text-xl font-semibold">$119/night</span>
    <div className="flex flex-row items-center">
      <Icon src={MdStar} color="#ED8936" />
      <span className="text-sm">
        <span className="font-bold">4.84</span>
        (190)
      </span>
    </div>
  </div>
</div>
  • Flexibility ends up with slow iteration:
    • If you adopt a single, huge component route, the first thing you need to solve is the design corner case. To fulfill these needs you may add lots of conditions or sub-components here or there in the main component, slowly but steadily your component will be hard to iterate or upgrade.
    • It's hard to read through all the dependency between these props due to they may have other meanings besides CSS styles.

The principles

We try to solve these problems with two principles

  • Two-level component design:
    • Base-level components: The foundation of every type of component.
      • You can find them in the storybook with path: /Base
      • Base level components won't be exported to be used by exterior consumers.
      • Base components will define all the props and functions the component needs.
    • Exported-level components: Inherits all the props from a base component but may have a pre-defined style, meant to be used by the consumer.
      • You can find them in the storybook with path: /Ui
      • Exported-level components will be consumed with the limited props like onChangeInput, borderStyle, fontFamiliy, or other functional props.
      • We will limit as little style input as possible, to control the visual style of the component.
  • One style one prop
    • Every base component will expose as many styles as possible, it seldomly has pre-defined styles.
    • Every exposed style props can only have one style string, we don't accept something like styleName="font-base text-black", we will separate it as fontSize="font-base" and textColor="text-black".
// We won't do this

const square = ({ styleName, children }) => {
  return <div className={styleName}>{children}</div>;
};

// We will do this
// cn is a aggregator, it will compose two string like "hi" "yo" to "hi yo"

const square = ({ width, height, color, children }) => {
  return <div className={cn(width, height, color)}>{children}</div>;
};

How we solve above problems with the three principles

  • Oversize comes from being over-designed:
    • The base-level component will have limited condition rendering thanks to Tailwind CSS, it only needs to expose as many as style props as possible for further customization.
  • Over abstraction
    • Because we don't need to encapsulate style within layer of components just to manage bunch of css files, we can avoid over abstraction.
  • Flexibility ends up with slow iteration:
    • With the two-level component design, we make base-level components act as a single source of truth, every group of the component should only inherit the base-level component
    • The design system team doesn't need to use a single component to face all the needs, they can create the new exported-level components to achieve different corner cases. They can iterate at a relatively fast speed.

Drawbacks & Known issues

  • Dynamic styles
    • Tailwind CSS fell short at calculated style, for example, if we have a width: 80px square and we want to put a dot at around 1/3 - 10px of its width, at the first glance you may think this is easy, we can just use Just-In-Time feature. But due to Tailwind CSS's prune nature, this won't work, at compile time Tailwind CSS can't recognize the dynamic style like that.
const square = ({ width }) => {
  return (
    <div className={`w-[${width}px] relative`}>
      <div className={`dot absolute left-[${width / 3 - 10}px]`} />
    </div>
  );
};
  • Hard to integrate with 3rd party tooling
    • This is the known issue if the design system wants to adapt to another component library such as react-select. They have to come up with a method to exchange styles across different CSS frameworks because we are using utility classes, these may cause much more issues than the traditional CSS approach.

Rules

  • Don't use short-cut features of javascript, use a library like clsx or classnames
  • Include import React from "react" in every file use react(To avoid jsx-runtime specific function not compatible issue)
  • Everytime you create a new base-level component, you need to create a exported-level component inherit that base-level component to act as manual.
  • Use arbitrary number as many as possible when it comes to size related className like fontSize or lineHeight, due to we may use getTailwindClassNumber() to extract number from className, currently it not support with something like text-sm

FQA

  • I need to input so many style props in a component, why not just gave me a component and a type prop

About storybook

  • Use {...args} to set props.

Code quality

  • Every base-level component should have a test suite
  • Every base-level and exported-level component should have a story

Lesson learned

  • Don't rely on pseudo-class like disabled: or read-only:. you should pass disabled and read-only style without these pseudo-class, use simple style and apply it on container instead of input itself.
    • Caveat: TextArea may have the resizing issue
    • Placeholders have to use placeholder: pseudo-class because there don't have another simple method to programmatically address placeholder style
  • Don't use some ambiguous story like playground and default, they almost have identical style props, but Default is a fixed style.
    • Only have playground story, make default style available and users can modify as their wishes
    • Caveat: playground is using Template.bind() to construct story, its console.log is different from regular console.log
  • You may want to remove the whole args props in storybook to make the type check cleaner, but in this way user can't directly change the props' value on storybook UI

About the design of the base and exported level

  • We will always digest as many props at base level as possible, take SingleSelectBase as example, when use InputDescription component, we didn't use BasicInputDescription but InputDescriptionBase to make SingleSelectBase as flexible as possible, but here comes another problem, we need to store the same config for BasicInputDescription at BasicInputDescription and BasicSingleSelece. To solve this problem, we will export a set of BasicInputDescriptionConfig to let other component use the config and reduce the maintance overhead.

About the passThrough props

Normally we don't accept passThrough props like below. The only exception will be input related field like textarea (BasicTextArea).

In the future, we will make it has explicit type.

type FooProps = {
  id: string
}

const Foo = (props: FooProps) => {
  const {id, ...passThrough} = props

  <input {...passThrough} id={id} />
}

Todo

  • Solve accessibility issues
  • Think about memorize component
  • InputLabel cursor
  • If we bundle the design-system as package, we may re-bundle it again with duplicate style css, need to investigate this.
  • Adapt instill color into Select component
  • Enable strict type checking
  • Force every component to use Nullable prop, instead of undefined
  • Decide whether to use controlled components or not
  • Solve upload field cursor not correctly display
  • Extract onChangeInput type from BasicInputFieldAttributes to individual component