• Stars
    star
    485
  • Rank 90,698 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 7 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Create flexible layout and composite UI components without the need to define arbitrary custom props

macro-components

Create flexible layout and composite UI components without the need to define arbitrary custom props.

Build Status

npm i macro-components
import React from 'react'
import styled from 'styled-components'
import Macro from 'macro-components'
import { space, fontSize, color } from 'styled-system'

// Define some styled-components
const Box = styled.div`${space} ${fontSize} ${color}`
Box.displayName = 'Box'

const Image = styled.img`
  max-width: 100%;
  height: auto;
  ${space}
`
Image.displayName = 'Image'

const Heading = styled.h2`${space} ${fontSize} ${color}`
Heading.displayName = 'Heading'

const Text = styled.div`${space} ${fontSize} ${color}`
Text.displayName = 'Text'

// create a macro function with the UI components you intend to use
const macro = Macro({
  Image,
  Heading,
  Text
})

// Create a macro-component
const MediaObject = macro(({
  Image,
  Heading,
  Text
}) => (
  <Flex p={2} align='center'>
    <Box width={128}>
      {Image}
    </Box>
    <Box>
      {Heading}
      {Text}
    </Box>
  </Flex>
))
import MediaObject from './MediaObject'

// get the macro component's child components
const { Image, Heading, Text } = MediaObject

// Use the macro-component by passing the components as children
const App = props => (
  <div>
    <MediaObject>
      <Image src='kitten.png' />
      <Heading>
        Hello
      </Heading>
      <Text>
        This component keeps its tree structure but still allows for regular composition.
      </Text>
    </MediaObject>
  </div>
)

Features

  • Single component creator
  • Intended for use with libraries like styled-components & glamorous
  • Encapsulate layout structure in composable components
  • Help keep your component API surface area to a minimum
  • Works with any other React components

Note: Macro components are intended to only work with specific child components. If you're wanting to define slots, see the Alternatives section below.

Motivation

Often it's best to use React composition and props.children to create UI that is composed of multiple elements, but sometimes you might want to create larger composite components with encapsulated tree structures for layout or create Bootstrap-like UI components such as panels, cards, or alerts. This library lets you create composite components with encapsulated DOM structures without the need to define arbitrary props APIs and that work just like any other React composition.

This can help ensure that your component API surface area remains small and easier to maintain.

If you find yourself creating composite React components that don't map to data structures, as described in Thinking in React, then this module is intended for you.

Usage

Macro(componentsObject)(elementFunction)

Returns a React component with a composable API that keeps tree layout structure.

const Banner = Macro({
  // pass a components object
  Heading,
  Subhead
})(({
  // the element function receives child elements
  // named according to the components object
  Heading,
  Subhead
}) => (
  <Box p={3} color='white' bg='blue'>
    {Heading}
    {Subhead}
  </Box>
)

The elementFunction argument is called with an object of elements based on the componentsObject passed to the Macro function. Using the Banner component above would look something like the following.

import Banner from './Banner'

const App = () => (
  <Banner>
    <Banner.Heading>Hello</Banner.Heading>
    <Banner.Subhead>Subhead</Banner.Subhead>
  </Banner>
)

componentsObject

The components object is used to defined which components the macro component will accept as children.

elementFunction

The element function is similar to a React component, but receives an elements object as its first argument and props as its second one. The elements object is created from its children and is intended to make encapsulating composition and element structures easier.

Within the macro component, the element function is called with the elements object and props: elementFunction(elementsObject, props).

// example
const elFunc = ({ Heading, Text, }, props) => (
  <header>
    {Heading}
    {Text}
  </header>
)

const Heading = styled.h2``
const Text = styled.div``

const componentsObj = {
  Heading,
  Text
}

const SectionHeader = Macro(componentsObj)(elFunc)

Omitting children

For any element not passed as a child to the macro component, the element function will render undefined and React will not render that element. This is useful for conditionally omitting optional children

const macro = Macro({ Icon, Text, CloseButton })

const Message = macro({
  Icon,
  Text,
  CloseButton
}) => (
  <Flex p={2} bg='lightYellow'>
    {Icon}
    {Text}
    <Box mx='auto' />
    {CloseButton}
  </Flex>
)
import Message from './Message'

const { Text, CloseButton } = Message

// Omitting the Icon child element will render Message without an icon.
const message = (
  <Message>
    <Text>{props.message}</Text>
    <CloseButton
      onClick={props.dismissMessage}
    />
  </Message>
)

Props passed to the root component

The second argument passed to the element function allows you to pass props to the root element or any other element within the component.

const macro = Macro({ Image, Text })

const Card = macro(({
  Image,
  Text
}, props) => (
  <Box p={2} bg={props.bg}>
    {Image}
    {Text}
  </Box>
))
// example usage
<Card bg='tomato'>
  <Card.Image src='kittens.png' />
  <Card.Text>Meow</Card.Text>
</Card>

Clone Component

To apply default props to the elements passed in as children, use the Clone component in an element function.

import Macro, { Clone } from 'macro-components'
import { Heading, Text } from './ui'

const macro = Macro({ Heading, Text })

const Header = macro(({ Heading, Text }) => (
  <Box p={2}>
    <Clone
      element={Heading}
      fontSize={6}
      mb={2}
    />
    <Clone
      element={Text}
      fontSize={3}
    />
  </Box>
))

Using a Component Multiple Times

To use the same component twice, give it a unique key in the componentsObject.

import React from 'react'
import Macro from 'macro-components'
import { Heading } from './ui'

const macro = Macro({
  Heading: Heading,
  Subhead: Heading
})

const Header = macro(({ Heading, Subhead }) => (
  <Box p={2}>
    {Heading}
    {Subhead}
  </Box>
))
<Header>
  <Header.Heading>Hello</Header.Heading>
  <Header.Subhead>Subhead</Header.Subhead>
</Header>

Alternatives

To create layout components that are not coupled to specific child components, using props or ordered children is probably a simpler approach.

The solutions below allow you to pass any arbitrary components as props or children.

See this discussion for more.

// using custom props
const MyLayout = ({
  left,
  right
}) => (
  <Flex>
    <Box width={128}>
      {left}
    </Box>
    <Box width={1}>
      {right}
    </Box>
  </Flex>
)

<MyLayout
  left={(
    <Image src='kitten.png' />
  )}
  right={(
    <Text>Meow</Text>
  )}
/>
// using ordered children
const Header = props => {
  const [ first, second ] = React.Children.toArray(props.children)
  return (
    <Box p={3}>
      {first}
      {second}
    </Box>
  )
}

<Header>
  <Heading>First</Heading>
  <Text>Second</Text>
</Header>
// using a children object
const Header = ({
  children: {
    left,
    right
  }
}) => (
  <Flex>
    <Box>
      {left}
    </Box>
    <Box width={1}>
      {right}
    </Box>
  </Flex>
)

<Header>
  {{
    left: (
      <Image src='kitten.png' />
    ),
    right: (
      <Text>Meow</Text>
    )
  }}
</Header>

Related

MIT License

More Repositories

1

mdx-deck

♠️ React MDX-based presentation decks
JavaScript
11,314
star
2

loading

This could take a while
CSS
3,531
star
3

colorable

Color combination contrast tester
HTML
1,958
star
4

reflexbox

Moved to https://rebassjs.org
JavaScript
1,354
star
5

fitter-happier-text

Performant, fully fluid headings
HTML
1,291
star
6

repng

React component to PNG converter
JavaScript
890
star
7

palx

🌈 Automatic UI Color Palette Generator
JavaScript
838
star
8

geomicons-open

Open Source Icons for the Web
HTML
832
star
9

ok-mdx

Browser-based MDX editor
JavaScript
761
star
10

ram

βš›οΈ React Application Manager: create and run React (and other) applications – no command line or build setup required
JavaScript
585
star
11

react-x-ray

React CSS Layout Debugger
JavaScript
571
star
12

plangular

Create custom SoundCloud players with HTML & CSS
HTML
485
star
13

shade

Gradient explorer
HTML
460
star
14

mdx-docs

πŸ“ Document and develop React components with MDX and Next.js
JavaScript
451
star
15

paths

Build and edit SVGs in the browser
JavaScript
418
star
16

tachyons-components

React UI components powered by Tachyons with a styled-components like API
JavaScript
411
star
17

mdx-go

⚑ Lightning fast MDX-based dev server for progressive documentation
JavaScript
362
star
18

microicon

SVG icon microservice
JavaScript
359
star
19

static-react

Zero-configuration CLI React static renderer
JavaScript
350
star
20

reline

React SVG line icon components
JavaScript
247
star
21

react-css-grid

React layout component based on CSS Grid Layout and built with styled-components
JavaScript
241
star
22

refunk

🎧 Simple React functional setState
JavaScript
236
star
23

hello-color

JavaScript
231
star
24

gravitons

JavaScript
218
star
25

layouts

Grab-and-go layouts for React
JavaScript
215
star
26

contrast-swatch

πŸ…°οΈ Image microservice for color contrast information
JavaScript
209
star
27

axs

Stupid simple style components for React
JavaScript
209
star
28

rgx

React grid system based on minimum and maximum widths
JavaScript
202
star
29

nano-component

Fast & simple React component styles in under 1kb
JavaScript
196
star
30

mdx-blocks

JavaScript
191
star
31

vhs

Post-Future CSS Animations
HTML
184
star
32

papercraft

Hand-coded SVG lettering
CSS
153
star
33

blog

Personal blog on design & development
HTML
146
star
34

figma-theme

Generate development-ready theme JSON files from Figma Styles
JavaScript
137
star
35

react-icons

Building SVG Icons with React
HTML
134
star
36

system-components

https://github.com/jxnblk/styled-system/tree/master/system-components
JavaScript
131
star
37

Heather

A HyperMinimal Jekyll Theme
CSS
129
star
38

rmdi

React Material Design Icons – built with Pixo, Styled Components, and Styled System
JavaScript
129
star
39

geomicons-wired

Geometric Icons
CSS
125
star
40

react-static-site-boilerplate

Demo boilerplate for generating a static site with React
HTML
115
star
41

rebranch

React context-based, conditional rendering components for A/B experiments
JavaScript
107
star
42

Ashley

A Readable & Responsive Theme for Tumblr
CSS
106
star
43

ejsx

Pure JSX templates for rendering static HTML
JavaScript
105
star
44

superbox

DEPRECATED: See https://rebassjs.org/reflexbox instead
JavaScript
102
star
45

live-doc

πŸ’« Convert markdown to live React demos
JavaScript
99
star
46

gatsby-themes

JavaScript
97
star
47

Twipster

CSS
95
star
48

css-to-object

JavaScript
92
star
49

dropbar

JavaScript
88
star
50

react-geomicons

React icon component for Geomicons Open
JavaScript
88
star
51

nano-style

React functional CSS-in-JS
JavaScript
84
star
52

horror

😱 React HTML elements with CSS-in-JS
JavaScript
78
star
53

SoundRad

A Radically Simpler & Faster SoundCloud Player
JavaScript
77
star
54

rebass-recomposed

JavaScript
77
star
55

Spectral

Click the Rainbow
JavaScript
74
star
56

skullcat

a avatar fur mrmrs
JavaScript
73
star
57

_gx

DEPRECATED Minimal responsive React grid system based on the Fab Four Technique.
HTML
73
star
58

vim-mdx-js

Vim Script
73
star
59

stepkit

JavaScript
72
star
60

bumpkit

JavaScript
70
star
61

rrx

βš›οΈ Minimal React router using higher order components
JavaScript
69
star
62

type-system

HTML
66
star
63

f0

JavaScript
65
star
64

understyle

Functional style utilities for authoring JavaScript style objects
JavaScript
60
star
65

gatsby-theme-mdx-blog

JavaScript
58
star
66

microbeats

Beats Created in Under an Hour
JavaScript
56
star
67

hypercolors

Generative hyperterm color theme
JavaScript
55
star
68

react-cxs

ϟ Alternative React.createElement function which allows style objects to be passed to the className prop to generate CSS
JavaScript
55
star
69

formula

CSS calculator for bulletproof form and button styles that always line up
JavaScript
51
star
70

reaxe

🍬 Syntactic sugar for React.createElement and JSX alternative
JavaScript
51
star
71

tempo

Responsive Grid System
CSS
48
star
72

diet-cola

A lightweight styled-components clone for creating React UI component primitives.
JavaScript
48
star
73

hyperterminator

Hyperterm theme for cybernetic organisms
JavaScript
47
star
74

react-fitter-happier-text

React component for fully fluid headings
JavaScript
46
star
75

css-scss

Convert CSS syntax to SCSS with calc, variables, and custom media queries
JavaScript
44
star
76

react-owl

πŸ¦‰ React layout component based on the lobotomized owl selector and built with styled-components
JavaScript
42
star
77

robox

Higher-order React component for adding style helper props based on understyle
JavaScript
41
star
78

monochrome

JavaScript
40
star
79

hyp

ϟ Functional UI component microlibrary with ES6 tagged template literals
JavaScript
39
star
80

superstyle

CSSOM-JS utility library
JavaScript
39
star
81

universal-components

JavaScript
38
star
82

scrs

JavaScript
38
star
83

hidden-styled

JavaScript
37
star
84

grays

HTML
35
star
85

colorable-app

Color constrast checker
JavaScript
34
star
86

principles

My principles of web design
HTML
33
star
87

object-style

JavaScript
33
star
88

redeck

DEPRECATED: see https://github.com/jxnblk/mdx-deck
JavaScript
32
star
89

react-component-permutations

Uses propTypes to create an array of React component props to display various permutations.
HTML
32
star
90

tag-hoc

React HOC to set an element's tag and remove props
JavaScript
31
star
91

cxs-components

Styled UI component primitives for React - built with cxs
JavaScript
31
star
92

kenburns

Sass mixin for Ken Burns effect background images
CSS
30
star
93

json-react

JavaScript
30
star
94

react-media-context

React higher-order component (HOC) to provide context for the currently matched media query.
JavaScript
30
star
95

watch

In case you forget what time it is
JavaScript
30
star
96

react-simple-icons

JavaScript
29
star
97

path-ast

SVG path element command parser/stringifier
JavaScript
29
star
98

simple-modular-scale

Modular scale generator based on an array of ratios
JavaScript
29
star
99

typography-system

JavaScript
28
star
100

mdx-themes

JavaScript
26
star