Skip to content

secretlifeof/juhuui

Repository files navigation

juhuui

npm version github actions status npm downloads gzip size brotli size

⚠️ DEPRECATED ⚠️

It was a fun experience trying to create this library, but it does not fill a space. There are more innovative libraries out there than this. Like compiled-css or vanilla-extract.

UI tool intended for design systems

I made this tool wanting the best (very objective) of Styled-Components, Chakra-UI but with atomic CSS (single purpose classes). You can merge, nest and create variants.

Hopefully you will have the same joy using juhuUi as me.


Features

  • Nesting components
  • Theme (default/customizable)
  • Descriptive class names in developer mode 🍭"color-orange sm:color-blue md:color-green" 🍭
  • @media queries are written as arrays 🎨['green', 'orange', 'pink'] 🎨
  • Same shortcuts as Styled-System ⚑️'p' for padding, 'my' for [margin-top, margin-bottom], 'c' for color, 'bg' backgroundColor, etc. ⚑️
  • Extract "critical CSS" for server side rendering
  • Implement darkmode using CSS variables

Installation

yarn add juhuui

or

npm install juhuui

Usage

It needs a createElement function so it knows how build components. Add this somewhere only once in your javascript tree. This is the solution for now.

import { setup } from 'juhuui';
import { createElement } from 'react';

setup(createElement);

Inline and overwriting styled components

Juhu you can start building components.

import {
  AspectRatioBox,
  Button,
  Box,
  CircularProgress,
  Divider,
  Flex,
  Fun,
  Grid,
  Heading,
  Icon,
  IconButton,
  Input,
  Link,
  List,
  ListItem,
  Progress,
  Stack,
  Tag,
  Text,
  Textarea
} from 'juhuui';

const SayWhat = () => (
  <Flex css={{ direction: 'column' }}>
    <Box css={{ color: 'green' }}>RAINBOW</Box>
    <Fun
      css={{
        '&:hover *': {
          fill: ['red', 'yellow', 'blue']
        }
      }}
    >
      <Text>ZAUBERMOON</Text>
      <Icon name="moon" color="green" />
    </Fun>
  </Flex>
);

Styled component

All components can be created externally. This is useful for separating styles and components. Styles can be overwritten by writing them inline. Please use the 'fw' prop to forward arguments because 'fw' will be removed from the DOM. The with function takes a second argument, an array of strings to be removed from the DOM, as an alternative to 'fw'.

import { Text, Box } from 'juhuui';

const UpperCase = Text.with({
  textTransform: 'uppercase',
  c: 'orange.600'
})

<UpperCase>Hello there!</UpperCase>;

// or

const Colorful = Text.with(({fw}) => ({
  bg: fw.background,
  color: 'orange.600'
}))

<Colorful fw={{ background: 'yellow.200' }}>Orange</Colorful>;
// or overwrite styles by adding a css property inline
<Colorful css={{ backgroundColor  "red.300" }} fw={{ backgroundColor: 'yellow.200' }}>Red</Colorful>;

// or merge

const GreenBox = Box.with({ bg: 'green' })
const Red = Text.with({ color: 'red' })
const SpaceCase = Colorful.merge([GreenBox, Red]).with({ textTransform: 'uppercase' })

<SpaceCase>Invisible green</SpaceCase>
// or inline merge
<Box merge={[GreenBox, Red]}>

Create variants

Variants are a probably a necessity for a good design system.

import { Button } from 'juhuui'

const B = Button.variants({ variant: {
  green: {
    bg: 'green'
  },
  blue: {
    bg: 'blue'
  }
} }).with()

<B variant="green">GREENIE</B>

Create class names

Function for creating class names. Just for the power of freedom. Performance is better than the above. If you are looking for a tool that only creates class names we recommend a smaller tool called otion.

import { css } from 'juhuui';

const classNames = css({
  color: 'green',
  bg: ['blue.300', 'green400', 'brown.500']
});

<div classNames={classNames}></div>;

Media queries

Media queries can be written as an array of values (associated with the theme object) or by using the media key.

import { Box } from 'juhuui';

const Mercy = Box.with({
  media: {
    '(min-width: 90em)': {
      color: 'green.400',
    }
  }
  color: ['blue.300', 'green200', 'brown.500']
});

<Mercy>Merci</Mercy>;

Server side rendering

For extracting critical CSS please use the extractCss function.

Here is a short example how you would do this in Next.js. The data attributes needs to be called "data-process".

import Document, { Head, Html, Main, NextScript } from 'next/document';
import { extractCss } from 'juhuui';

export default class MyDocument extends Document {
  static async getInitialProps({ renderPage }) {
    const page = renderPage();

    const { css, data } = extractCss();
    return { ...page, css, data };
  }

  render() {
    return (
      <Html>
        <Head>
          <style
            id={'_juhuui'}
            dangerouslySetInnerHTML={{ __html: this.props.css }}
            data-process={this.props.data}
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

Options

The setup function takes a second object with options.

import { setup, theme } from 'juhuui';
import { h, forwardRef } from 'preact';

const newTheme = {
  ...theme,
  colors: {
    ...theme.colors,
    juhuui: {
      50: 'white',
      100: '#fff7eb',
      200: '#e9f8e8',
      300: '#37b311',
      800: '#07130f',
      900: '#07130f'
    }
  }
};

setup(h, {
  theme: newTheme,
  defaultFun: true, // defaults to true
  forwardRef
});

Future stuff

  • ForwardRef works for styled components not inline
  • Move theme to a different package
  • Default React/Preact versions without a need for calling setup
  • Improve type safety (! high priority. Help highly appreciated)

Benchmarks

You can test and compare it live or download the repository. All credits go to Styled-Components and Necolas for creating this.

Thanks

Thanks to all for being here and beforehand for anybody who wants to contribute either by reporting a bug or by a PR.

Any feedback is met with love and curiosity. Have fun! πŸ’š

Inspiration