Skip to content

Commit

Permalink
docs: finish for now and clean up readme
Browse files Browse the repository at this point in the history
  • Loading branch information
jquense committed Apr 27, 2021
1 parent 78e531c commit 84b25f5
Show file tree
Hide file tree
Showing 15 changed files with 723 additions and 905 deletions.
599 changes: 1 addition & 598 deletions README.md

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"build:runtime": "4c build src/runtime --no-copy-files --no-types",
"build:tools": "4c build -d lib --no-esm -- --ignore \"**/runtime/**\"",
"build": "yarn build:tools && yarn build:runtime && yarn build:pick && yarn copy:types",
"deploy-docs": "yarn --cwd www build --prefix-paths && gh-pages -d www/public",
"release": "4c release",
"start": "yarn --cwd ./example start"
},
Expand Down Expand Up @@ -57,9 +58,6 @@
"__file_snapshots__"
]
},
"author": {
"name": "4Catalyzer"
},
"author": "4Catalyzer",
"license": "MIT",
"bugs": {
Expand Down Expand Up @@ -135,6 +133,7 @@
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-ts-expect": "^2.0.0",
"gh-pages": "^3.1.0",
"html-webpack-plugin": "^5.3.1",
"husky": "^4.3.0",
"jest": "^26.6.3",
Expand Down
1 change: 0 additions & 1 deletion src/inline-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import findCacheDir from 'find-cache-dir';
import loaderUtils from 'loader-utils';

import type { ResolvedImport, Style } from './types';
import { createRequirePath } from './utils/createFilename';
import {
buildDependencyError,
collectStyles,
Expand Down
1 change: 1 addition & 0 deletions www/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
pathPrefix: '/astroturf',
plugins: [
{
resolve: 'gatsby-source-filesystem',
Expand Down
4 changes: 3 additions & 1 deletion www/src/components/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,16 @@ function CodeBlock(props: any) {
if (width !== printWidth) setPrintWidth(width);
});

const isJs = ['js', 'ts', 'tsx', 'jsx'].includes(language);

return (
<div ref={ref}>
<BaseCodBlock
{...codeProps}
theme={theme}
language={language}
code={
noFormat || printWidth == null
noFormat || printWidth == null || !isJs
? children
: prettier.format(children, {
parser: 'babel',
Expand Down
20 changes: 12 additions & 8 deletions www/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,16 @@ const NavItem = styled('a')`
left: 0;
}
&:hover {
text-decoration: none;
}
&:hover::before {
opacity: 1;
}
`;

function Layout(props: Props) {
const [expanded, setExpanded] = useState(true);
const [expanded, setExpanded] = useState(false);

return (
<MDXProvider
Expand All @@ -52,11 +55,12 @@ function Layout(props: Props) {
}}
>
<div
className="py-3 px-6 sticky top-0 bg-secondary shadow-sm border-b border-secondary-darker flex justify-between"
css={css`
@apply py-3 px-6 sticky top-0;
@media (max-width: theme(screens.md)) {
@apply bg-secondary border-b border-secondary-darker flex justify-between;
@apply;
}
`}
>
Expand All @@ -66,10 +70,9 @@ function Layout(props: Props) {
astroturf
</span>
</div>

<button
type="button"
className="focus:shadow-outline md:hidden"
className="focus:shadow-outline lg:hidden"
onClick={() => setExpanded((t) => !t)}
>
<div className="bg-white my-1" css="height: 2px; width: 1.5rem" />
Expand All @@ -87,7 +90,7 @@ function Layout(props: Props) {
align-items: flex-start;
flex-direction: column;
@media (max-width: theme(screens.md)) {
@media (max-width: theme(screens.lg)) {
display: none;
width: 100%;
Expand All @@ -99,15 +102,16 @@ function Layout(props: Props) {
${expanded &&
css`
@media (max-width: theme(screens.md)) {
@media (max-width: theme(screens.lg)) {
display: flex;
align-items: center;
}
`}
`}
>
<NavItem href="/getting-started">Getting Started</NavItem>
<NavItem href="/configuration">Configuration</NavItem>
<NavItem href="/introduction">Introduction</NavItem>
<NavItem href="/setup">Setup</NavItem>
<NavItem href="/advanced">Advanced features</NavItem>
<NavItem href="/migration">Migrating to v1</NavItem>
<NavItem href="/tooling">Tooling</NavItem>
</nav>
Expand Down
249 changes: 249 additions & 0 deletions www/src/pages/advanced.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
import Layout from '../components/Layout';

export default Layout;

## Attaching Additional Props

A common task with styled components is to map their props or set default values.
astroturf cribs from Styled Components, by including an `attrs()` api.

```jsx
import styled from 'astroturf/react';

// Provide a default `type` props
const PasswordInput = styled('input').attrs({
type: 'password',
})`
background-color: #ccc;
`;

// Map the incoming props to a new set of props
const TextOrPasswordInput = styled('input').attrs(
({ isPassword, ...props }) => ({
...props,
type: isPassword ? 'password' : 'text',
}),
)`
background-color: #ccc;
`;
```

Because `attrs()` is resolved during render you can use hooks in them! We even
do some magic in the non-function signature so that it works.

```js
const Link = styled('a').attrs((props) => ({
href: useRouter().createHref(props.to),
}))`
color: blue;
`;

// astroturf will automatically compile to a function
// when using a plain object so that the hooks
// are only evaluated during render
const Link = styled(MyLink).attrs({
router: useRouter(),
})`
color: blue;
`;
```

## "as" prop

`astroturf` supports the `as` prop to control the underlying element type at runtime.

```jsx noFormat
const Button = styled('button')`
color: red;
`;

<Button as="a" href="#link" />;
```

**This feature is only enabled by default for host components**, e.g. native DOM elements.
We do this to prevent annoying conflicts with other UI libraries like react-bootstrap or
semantic-ui which also use the the `as` prop. If you want to enable it for any styled
component you can do so via the `allowAs` option.

```js
const StyledFooter = styled(Footer, { allowAs: true })`
color: red;
`;
```

## Class composition

How you accomplish that is mostly up to your preprocessor. Leverage Sass variables,
or Less mixins, or postcss nesting polyfills, or whatever. The css you're writing
is treated exactly like a normal style file so all the tooling you're used to works as expected.
For composition, specifically around classes, you can also use
css-modules `composes` to compose styles and interpolation;

```js
// Button.js

const heavy = css`
font-weight: 900;
`;

const Title = styled('h3')`
composes: ${heavy};
font-size: 12%;
`;
```

You don't have to define everything in a `.js` file. Where it makes sense
just use normal css (or any other file type).

```scss
// mixins.scss
@mixin heavy() {
font-weight: 900;
}
```

and then:

```js
// Button.js
const Title = styled('h3')`
@import './mixins.scss';
@include heavy();
font-size: 12%;
`;
```

## Referring to other Components

One limitation to fully encapsulated styles is that it's hard to contextually style components
without them referencing each other. In astroturf you can use a component in a
selector as if it were referencing a class selector.

> Note: Referencing stylesheets or styled components from other files has a few caveats:
> [cross-file-dependencies](cross-file-dependencies)
```js
const Link = styled('a')`
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
`;

const Icon = styled('svg')`
flex: none;
transition: fill 0.25s;
width: 48px;
height: 48px;
${Link}:hover & {
fill: rebeccapurple;
}
`;
```

## Sharing values between styles and JavaScript

We've found that in practice, you rarely have to share values between the two, but there are times when it's
very convenient. Astroturf ofters two ways to do this, the first is string interpolations.

```js
const DURATION = 500;

const ColorTransition = styled('nav')`
color: red;
transition: color ${DURATION}ms;
&.blue {
color: blue;
}
`;

class App extends React.Component {
state = { blue: false };
toggle = () => {
this.setState(
(s) => ({ blue: !s.blue }),
() => {
setTimeout(() => console.log('done!'), DURATION);
},
);
};

render() {
const { blue } = this.state;
return (
<div>
<ColorTransition blue={blue} />
<button onClick={this.toggle}>Toggle Color</button>
</div>
);
}
}
```

This works great for local variables, since the compiler can determine their
value at compile time and share them. For cases when you want to share things
a bit more globally, such as in a theme, we recommend leaning on your css preprocesser again.

css-modules provides a syntax for exporting values from styles, generally
this is used for class names, but you can leverage it for whatever values you want.
Combined with something like Sass's variables it ends up being a powerful tool.

```js
const breakpointValues = css`
@import '../styles/theme';
:export {
@each $breakpoint, $px in $grid-breakpoints {
#{$breakpoint}: $px;
}
}
`;

function Responsive() {
const [isMobile, setIsMobile] = useState(false);

useLayoutEffect(() => {
setIsMobile(window.clientWidth < parseInt(breakpoints.md, 10));
}, []);

return <div>{isMobile ? 'A small screen!' : 'A big screen!'}</div>;
}
```

## Keyframes and global

Everything in `css` will be used as normal CSS Modules styles.
So, if you need to insert some CSS without isolation (like reset with [postcss-normalize](https://github.com/csstools/postcss-normalize)):

```js
css`
@import-normalize;
:global(.btn) {
background: blue;
}
`;
```

With [postcss-nested](https://github.com/postcss/postcss-nested) you can
add keyframes to specific component (and keyframes name will not be global):

```js
const Loader = styled('div')`
animation-name: rotation;
animation-duration: 1s;
animation-timing-function: linear;
animation-iteration-count: infinite;
@keyframes rotation {
to {
transform: rotate(360deg);
}
}
`;
```
Loading

0 comments on commit 84b25f5

Please sign in to comment.