Skip to main content

♾️ Harmony System

At the next lines I'll explain how the default system works and How you can create or extend your one of your own:

HARMONY_SYSTEM:

First of all, I would like you to think as:

  • Flex: <Piece kind='piece' />

Small parts of your screen, everything you want to organize into a container whatever the kind of them.

  • Grid: <Piece kind='container' />

Containers or your big parts of your screen where you want to organize your small parts (flex)

So everything that you need is a piece at other hand everything that you need to organize our pieces is a container

Basic Grid:

Live Editor
const ContainerPattern = {
  order: 0,
  applyOn: (props: PieceProperties<any, any>) => props.kind === 'container',
  styles: {
    display: 'grid',
    flex: '1 1 auto',
    userSelect: 'none',
  },
};

const PiecePattern = {
  applyOn: (props) => props.kind === 'piece',
  order: 0,
  style: {
    display: 'flex',
    flex: '1 1 auto',
    userSelect: 'none',
  },
};

const Main = () => {
  return (
    <PieceProvider patterns={[ContainerPattern, PiecePattern]}>
      <Piece
        kind='container'
        contentColumns='1fr 1fr'
        contentRows='1fr 1fr'
      >
        <Piece
          kind='piece'
          atRow={1}
          atColum={1}
        >
          Hello world.
        </Piece>
        <Piece
          kind='piece'
          atRow={2}
          atColum={2}
        >
          Hello world 2.
        </Piece>
      </Piece>
    </PieceProvider>
  );
};

render(<Main />);
Result
Loading...

Align Components

function Main() {
return (
<PieceProvider patterns={HARMONY_SYSTEM}>
<Piece
kind='container'
alignItems='end'
justifyContent='end'
>
<Piece
kind='piece'
alignSelf='start'
>
Hello world
</Piece>
<Piece kind='piece'>Hello world</Piece>
</Piece>
</PieceProvider>
);
}

Reset CSS

In the system offered we count with:

const RESET = {
applyOn: 'all',
order: 0,
style: {
margin: 0,
padding: 0,
border: 0,
fontSize: '100%',
fontWeight: '400',
fontStyle: 'normal',
boxSizing: 'border-box',
fontOpticalSizing: 'auto',
listStyle: 'none',
quotes: 'none',
userSelect: 'none',
overflow: 'hidden',
},
};

You'll probably ask why put overflow: hidden for all sort of component...

<Scrollable />

Something that always broke our navigation is definitely scrolls, when we want to put it or not. For that reason I think the best solution at all is hide from everything and show when you want to with: <Scrollable />.

Then everytime you want to render something that will grow more than your avaiable space, like lists:

  • You can select the direction.
  • Customize colors to match with your style.
  • Animate: instant, smooth.
Live Editor
<PieceProvider
  theme={{
    color: 'blue',
    highlight: 'orangeblue',
  }}
  patterns={mergeSystems(HARMONY_SYSTEM, {
    order: 0,
    applyOn: (props) => props.kind === 'scrollable',
    style: (theme) => ({
      '--color': theme.color,
      '--highlight': theme.highlight,
    }),
  })}
>
  <Piece
    kind='container'
    width='500px'
  >
    <Scrollable
      horizontal
      behavior='instant' //Optional
    >
      <Piece
        as='div'
        flex='0 0 350px'
        height='50px'
        background='green'
      ></Piece>
      <Piece
        as='div'
        flex='0 0 350px'
        height='50px'
        background='blue'
      ></Piece>
    </Scrollable>
  </Piece>
</PieceProvider>
Result
Loading...

<Text />

Basic with this component you can use a text and align in all directions with flex props:

<Text
as='p'
justifyContent='center'
alignItems='center'
>
Centered
</Text>

<Media />

Sometimes you want to hide some component at some screen size:

<Media query='(min-height: 702px)'>
<Piece>Hello world</Piece>
</Media>

Now you only will see it at screens bigger than 702px.

However the element will remain at your HTML if you don't want to:

<Media
query='(min-height: 702px)'
removeFromHtml
>
<Piece>Hello world</Piece>
</Media>

And if you want to be notified when the element will be activate

<Media
query='(min-height: 702px)'
removeFromHtml
onActivate={myFunction}
>
<Piece>Hello world</Piece>
</Media>

Creating your system

You can create your own:

Live Editor
const PIECE = {
  applyOn: (props) => props.kind === 'piece',
  order: 0,
  style: {
    display: 'block',
    userSelect: 'none',
  },
};

const LIST = {
  applyOn: 'ul',
  order: 0,
  style: {
    listStyle: 'square inside',
    paddingLeft: '20px',
  },
};

const LIST_ITEM = {
  applyOn: 'li',
  order: 0,
  style: {
    color: 'orange',
    lineHeight: 1.8,
  },
};

const MyCustomCssSystem = [PIECE, LIST, LIST_ITEM];

const Main = () => {
  return (
    <PieceProvider patterns={MyCustomCssSystem}>
      <Piece as='ul'>
        <Piece as='li'>Item 1</Piece>
      </Piece>
    </PieceProvider>
  );
};

render(<Main />);
Result
Loading...

But if you want to use <Scrollable /> and other components designed for you should extend from the main system:

Compounding Systems

You can merge more than one system adding your styles to the main HARMONY_SYSTEM by importing mergeSystems look:

interface CustomTheme {
color: string;
highlight: string;
}

export const MyCustomCssSystem = mergeSystems<CustomTheme>(
HARMONY_SYSTEM,
{
applyOn: (props) => props.kind === 'scrollable',
style: ({ theme }) => ({
'--color': theme.color,
'--highlight': theme.highlight,
}),
order: 0,
},
{
applyOn: 'all',
style: {
transition: 'all 0.3s linear',
},
order: 0,
},
);

Default Properties

You're a totally able to set default properties in that schema

import { Piece, PieceProvider } from '@lizzelabs/react-harmony';
import { ReactNode } from 'react';

export interface ContainerProps {
children: ReactNode;
}

const Container = (props: ContainerProps) => {
return <Piece as='div'>{props.children}</Piece>;
};

const Main = () => {
return (
<PieceProvider
patterns={{
applyOn: 'div',
defaults: {
aria: {
'aria-hidden': true,
},
},
}}
>
<Container>
<Piece as='label'>Hello World</Piece>
</Container>
</PieceProvider>
);
};

// Now the container will be hidded from screen readers

Reference

Property

applyOn

Applies the rule on.

(props: PieceProperties) => boolean

HTML Tags ex: span, ul, div

all

Order

Priority of that style

number

Style

Css

object

Defaults

Default properties of a piece

object