Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Pluggable styling API #57

Open
kettanaito opened this Issue Aug 14, 2018 · 5 comments

Comments

2 participants
@kettanaito
Copy link
Owner

commented Aug 14, 2018

What

I propose to establishing a support for different CSS-in-JS libraries to help developers take benefits of Atomic layout and their favorite styling solution.

Why

  • The library operates on CSS properties Object, which can be computed into string (when needed), and shipped to any modern CiJ solution

Specification (draft)

API

Please discuss this API draft in the comments of this issue. I will keep it updated to reflect latest agreements.

A developer can specify which CiJ solution to use by providing a producer function to the produceStyles option of the Layout configuration.

/**
 * Accepts a CSS template string literal and returns a generated class name (?).
 */
type ProduceStyles = (css: string) => string

interface LayoutOptions {
  produceStyles: ProduceStyles
}

Usage

emotion

// src/App.js
import emotion from 'emotion'
import Layout from 'atomic-layout'

Layout.configure({
  produceStyles: emotion,
})

styled-components

// src/App.js
import styled from 'styled-components'
import Layout from 'atomic-layout'

Layout.configure({
  produceStyles: styled,
})

Technical details

  • Layout instance keeps produceStyles reference available globally
  • The library uses Layout.produceStyles to produce styles attached to components
// atomic-layout/src/components/Box.tsx
import React from 'react'
import Layout from '../'

const Box = Layout.produceStyles`
  // CSS string template literal
`

Q: Currently styled returns a React component. It would be nice to abstract from framework-specific return signatures, and operate with emitted class names.

@kettanaito kettanaito changed the title Support Vue Modularize styling/rendering logic Jan 25, 2019

@bitttttten

This comment has been minimized.

Copy link

commented Feb 27, 2019

Following from #122 I can think of 2 places where support needs to be added to allow the developer a possibility to configure things: how styles and class names are generated (a), and to configure which library is rendering the components (b).

#122 contains examples of a.

Just to generate some conversation, I will provide this example showcasing both:

diff --git a/src/components/Composition.tsx b/src/components/Composition.tsx
index c9905d3..dd9c7bf 100644
--- a/src/components/Composition.tsx
+++ b/src/components/Composition.tsx
-const CompositionWrapper = styled.div<CompositionProps>`
-  ${applyStyles};
-  display: ${({ inline }) => (inline ? 'inline-grid' : 'grid')};
-`
-
-const Composition: React.FunctionComponent<CompositionProps> = ({
-  children,
-  ...restProps
-}) => {
+const Composition: React.FunctionComponent<CompositionProps> = (props) => {
+  const {
+    children,
+    className,
+    inline,
+    ...restProps
+  } = props
   const areaComponents = parseTemplates(restProps)
   const hasAreaComponents = Object.keys(areaComponents).length > 0
   const childrenType = typeof children
@@ -40,11 +39,18 @@ const Composition: React.FunctionComponent<CompositionProps> = ({
   )
 
   return (
-    <CompositionWrapper {...restProps}>
+    <Layout.produceComponent.div
+      className={[
+        className, 
+        Layout.produceStyles(applyStyles(props)),
+        Layout.produceStyles`display: ${() => (inline ? 'inline-grid' : 'grid')};`
+      ].join(' ')}
+      {...restProps}
+    >
       {hasAreaComponents && hasChildrenFunction
         ? (children as ChildrenFunction)(areaComponents)
         : children}
-    </CompositionWrapper>
+    </Layout.produceComponent.div>
   )
 }

The component is moved inside render method, which is not good for performance. This was done so that the user can configure the library after imports, as it's confusing for the end dev has to run Layout.configure at a precise point in time (i.e. before importing any components).

If it's possible to keep the component back outside the render method whilst ensuring a good dev ex then that would be the approach.

@kettanaito kettanaito changed the title Modularize styling/rendering logic Pluggable styling API Mar 6, 2019

@kettanaito

This comment has been minimized.

Copy link
Owner Author

commented Mar 6, 2019

@bitttttten Hi. I will try to put up an specification of the pluggable styling solution in the description above. Please, I would be thankful for any kind of input from your side!

The first question I wonder about is what is the signature of the produceStyles function? I drafted one on top, assuming it accepts a template literal (css string) and returns a generated class name. However, I see that styled-components doesn't have such API.

@kettanaito kettanaito changed the title Pluggable styling API [RFC] Pluggable styling API Mar 6, 2019

@kettanaito kettanaito added this to the 1.0 milestone Mar 6, 2019

@bitttttten

This comment has been minimized.

Copy link

commented Mar 9, 2019

Yeah, I was thinking about styled-components and how their css api does not handle committing styles to the dom like emotion does. Here you can see my test of exactly this. More work needs to be done for styled-components.

And I was wondering about your original idea of having pre-defined plugins, especially for the use case of using a different library. I think it's pretty simple. For example, you could do:

import { Composition } from 'atomic-layout/emotion'

Which looks like:

import Layout from './Layout'
import css from 'emotion'

Layout.configure({
	produceStyles: (styles, ...rest) => css([styles], ...rest)
})

export default Layout
export { default as Box } from './components/Box'
export { default as Composition } from './components/Composition'
export { default as Only } from './components/Only'

Although this does not address any of other benefits, like decoupling atomic layout from a view library, having atomic layout emit CSS for dev's to handle at build time, and so on. It feels like inspiration should be taken from astroturf for that (not api design, but more the philosophy?).

(I am in the middle of a long weekend, so hopefully this comment is clear.. also I will probably come back with more feedback later on! 😛 )

@kettanaito kettanaito added this to In scope in Roadmap via automation Mar 14, 2019

@kettanaito kettanaito self-assigned this Apr 7, 2019

@kettanaito kettanaito referenced a pull request that will close this issue Apr 7, 2019

Open

Introduces pluggable styling API #145

0 of 2 tasks complete
@kettanaito

This comment has been minimized.

Copy link
Owner Author

commented Apr 7, 2019

Hello, @bitttttten. I've established some changes to adopt pluggable styling solution under #145. May I please ask you to checkout that branch and see if it works with emotion for you? Your feedback is highly appreciated!

@kettanaito kettanaito moved this from In scope to In progress in Roadmap Apr 10, 2019

@kettanaito

This comment has been minimized.

Copy link
Owner Author

commented Apr 10, 2019

I've updated the Pluggable styling API request with the specification of the feature. It describes the feature behavior and changes introduces by the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.