-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🎩 Initial commit of stylish-preact CSS library
- Loading branch information
0 parents
commit d499702
Showing
9 changed files
with
6,404 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Generated by `npm install` | ||
/node_modules/ | ||
|
||
# Generated by `npm run build` | ||
/lib/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Copyright 2021 Twuni | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
this software and associated documentation files (the "Software"), to deal in | ||
the Software without restriction, including without limitation the rights to | ||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
of the Software, and to permit persons to whom the Software is furnished to do | ||
so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
# 🎩 Stylish | Preact | ||
|
||
Stylish is a tiny yet capable CSS library for [Preact][4] apps. It is heavily | ||
inspired by [@emotion/styled][1] and [styled-components][2], so if you are | ||
familiar with either of those, you should quickly get the hang of Stylish. | ||
|
||
## Features | ||
|
||
* Extremely lightweight (under **1KB** gzipped, _minimal dependencies_) | ||
* Animations supported | ||
* Theme context provided right out of the box | ||
* CSS rules have access to component props | ||
* Auto-generated class names (never have to use a `className` or `style` prop again!) | ||
* Make any component stylish | ||
* No React shims needed -- built for Preact | ||
|
||
## Installing | ||
|
||
``` | ||
npm install stylish-preact | ||
``` | ||
|
||
Yarn users, you know what to do instead. | ||
|
||
## Usage | ||
|
||
Learn Stylish by example. The following examples use [htm][5] instead of | ||
[JSX][6], so they will run directly in a modern web browser, no transpilation | ||
needed. | ||
|
||
### Basic Example | ||
|
||
```javascript | ||
import { html } from 'htm/preact'; | ||
import { render } from 'preact'; | ||
import { stylish } from 'stylish-preact'; | ||
|
||
const RedText = stylish('div', ` | ||
color: red; | ||
`); | ||
|
||
render(html` | ||
<${RedText}>Hi, I'm red!<//> | ||
`, document.body); | ||
``` | ||
|
||
### Example with props | ||
|
||
```javascript | ||
import { html } from 'htm/preact'; | ||
import { render } from 'preact'; | ||
import { stylish } from 'stylish-preact'; | ||
|
||
const Tint = stylish('div', (props) => ` | ||
color: ${props.color}; | ||
`); | ||
|
||
render(html` | ||
<${Tint} color="blue">Hi, I'm blue!<//> | ||
`, document.body); | ||
``` | ||
|
||
### Example with pseudo-classes | ||
|
||
```javascript | ||
import { html } from 'htm/preact'; | ||
import { render } from 'preact'; | ||
import { stylish } from 'stylish-preact'; | ||
|
||
const HoverGreen = stylish('div', { | ||
rule: ` | ||
color: green; | ||
`, | ||
states: [':hover'] | ||
}); | ||
|
||
render(html` | ||
<${HoverGreen}>Hi, hover me to make me green!<//> | ||
`, document.body); | ||
``` | ||
|
||
### Example with animation | ||
|
||
```javascript | ||
import { keyframes, stylish } from 'stylish-preact'; | ||
|
||
import { html } from 'htm/preact'; | ||
import { render } from 'preact'; | ||
|
||
const spin = keyframes` | ||
from { | ||
transform: rotate(0deg); | ||
} | ||
to { | ||
transform: rotate(360deg); | ||
} | ||
`; | ||
|
||
const Spinner = stylish('div', ` | ||
animation: 1s infinite linear ${spin}; | ||
`); | ||
|
||
render(html` | ||
<${Spinner}>Weeeeee!<//> | ||
`, document.body); | ||
``` | ||
|
||
### Example with inheritance | ||
|
||
```javascript | ||
import { html } from 'htm/preact'; | ||
import { render } from 'preact'; | ||
import { stylish } from 'stylish-preact'; | ||
|
||
const Big = stylish('span', ` | ||
font-size: 4em; | ||
`); | ||
|
||
const BigAndBlue = stylish(Big, ` | ||
color: blue; | ||
`); | ||
|
||
render(html` | ||
<${BigAndBlue}>Hi, I'm big and blue.<//> | ||
`, document.body); | ||
``` | ||
|
||
### Example with theme | ||
|
||
```javascript | ||
import { Theme, stylish } from 'stylish-preact'; | ||
|
||
import { html } from 'htm/preact'; | ||
import { render } from 'preact'; | ||
|
||
const Logo = stylish('h1', ({ theme }) => ` | ||
color: ${theme.color.primary}; | ||
`); | ||
|
||
render(html` | ||
<${Theme.Provider} value=${{ color: { primary: 'purple' }}}> | ||
<${Logo}>Purple Power<//> | ||
<//> | ||
`, document.body); | ||
``` | ||
|
||
## Migrating from `@emotion/styled` or `styled-components`? | ||
|
||
There are some notable differences between Stylish and these two libraries. | ||
|
||
* Stylish does not support **nested** rules. It is primitive in that way. | ||
Each set of properties must be defined in its own *rule*, complete with | ||
any `media` selector and/or `states` (pseudo-classes or other criteria) | ||
applicable to that rule. | ||
|
||
* The `stylish` function behaves differently than the `styled` function | ||
for either of these two libraries. Read through the examples and usage | ||
documentation prior to reporting issues. Most notably, `stylish` should | ||
not be used as a tagged template. | ||
|
||
## API Reference | ||
|
||
### `import { Theme } from 'stylish-preact';` | ||
|
||
`Theme` is a [context][3]. To provide a theme, `<Theme.Provider value={theme}>...<//>`. | ||
This theme will be automatically injected to all stylish components. To access | ||
the theme directly, `const theme = useContext(Theme);`, just like you would any | ||
other context. | ||
|
||
The shape of the theme you define is completely up to you. Stylish does not use | ||
it directly; it only passes it through, if present, so your stylish components | ||
have access to it without having to do any additional work. | ||
|
||
### `import { keyframes } from 'stylish-preact';` | ||
|
||
The `keyframes` function can be used as a tagged template or invoked directly. | ||
Use it to define an animation. It returns the animation's *name* which can then | ||
be injected into other components to use that animation. | ||
|
||
### `import { stylish } from 'stylish-preact';` | ||
|
||
The `stylish` function creates a stylish component. It takes two arguments: | ||
|
||
#### `stylish(Component, ...)` | ||
|
||
The **first** argument *may* be the `string` name of the HTML element to | ||
serve as the component's base element. | ||
|
||
Alternatively, the **first** argument *may* be a reference to another | ||
component to extend. For example, `const Convertible = stylish(Vehicle);`. | ||
|
||
#### `stylish(..., outfit)` | ||
|
||
The **second** argument is where the whole outfit comes together. It can be a | ||
string, a function, an object, or an array of strings/functions/objects. These all define | ||
aspects of how the stylish component is dressed. | ||
|
||
##### String | ||
|
||
When `outfit` is a string, it should contain a set of static CSS properties | ||
describing the component's appearance. | ||
|
||
##### Function | ||
|
||
Whe `outfit` is a function, it should **expect** to be given the `props` given | ||
to the component when it is rendered, and should **return** a string containing | ||
the set of CSS properties describing the component's appearance. | ||
|
||
##### Object | ||
|
||
When `outfit` is an object, it should contain the following properties: | ||
|
||
* `rule` - Required. This should be either a `string` or a `function` which | ||
behaves as described above. | ||
|
||
* `media` - Optional. If present, this should be a **media selector** `string`. | ||
For example, `(max-width: 500px)`. | ||
|
||
* `states` - Optional. If present, this should be `string[]`, where each item | ||
is a suffix to be added to the component's CSS selector for this rule block. | ||
For example, a simple `:hover` or a more complex `:not(:last-of-type)::after`. | ||
|
||
##### Array | ||
|
||
When `outfit` is an array, each item in the array should conform to the above | ||
requirements depending on the type of that item (`string` vs `function` vs | ||
`object`). | ||
|
||
[1]: https://emotion.sh/docs/styled | ||
[2]: https://styled-components.com/ | ||
[3]: https://preactjs.com/guide/v10/context/ | ||
[4]: https://preactjs.com/ | ||
[5]: https://github.com/developit/htm | ||
[6]: https://reactjs.org/docs/introducing-jsx.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
<!DOCTYPE html> | ||
<html lang="en_US"> | ||
<head> | ||
<meta charset="UTF-8"/> | ||
<script async src="/node_modules/es-module-shims/dist/es-module-shims.js"></script> | ||
</head> | ||
<body> | ||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"htm": "./node_modules/htm/dist/htm.mjs", | ||
"htm/preact": "./node_modules/htm/preact/index.mjs", | ||
"preact": "./node_modules/preact/dist/preact.mjs", | ||
"preact/hooks": "./node_modules/preact/hooks/dist/hooks.mjs" | ||
} | ||
} | ||
</script> | ||
<script type="module"> | ||
import { Theme, keyframes, stylish } from './src/index.mjs'; | ||
import { html } from 'htm/preact'; | ||
import { render } from 'preact'; | ||
|
||
const energy = keyframes` | ||
0% { | ||
background-color: rgba(220, 255, 255, 0); | ||
} | ||
50% { | ||
background-color: rgba(255, 255, 220, 100%); | ||
} | ||
100% { | ||
background-color: rgba(220, 255, 255, 0); | ||
} | ||
`; | ||
|
||
const spin = keyframes` | ||
0% { | ||
transform: rotate(0deg) scale(1, 1); | ||
} | ||
50% { | ||
transform: rotate(180deg) scale(0.5, 0.5); | ||
} | ||
100% { | ||
transform: rotate(360deg) scale(1, 1); | ||
} | ||
`; | ||
|
||
const Spinning = stylish('span', ({ theme }) => ` | ||
align-items: center; | ||
animation: infinite 1s linear ${spin}; | ||
border-color: transparent; | ||
border-radius: 2px; | ||
border-style: solid; | ||
border-width: 2px; | ||
box-sizing: border-box; | ||
cursor: default; | ||
display: flex; | ||
font-size: ${theme.size / 2}px; | ||
line-height: ${theme.size}px; | ||
justify-content: center; | ||
width: ${theme.size}px; | ||
`); | ||
|
||
const Hat = stylish(Spinning, { | ||
rule: ` | ||
border-color: #0c0; | ||
`, | ||
states: [':hover'] | ||
}); | ||
|
||
const App = stylish('div', ` | ||
align-items: center; | ||
animation: infinite 1.75s ease-in-out ${energy}; | ||
bottom: 0; | ||
display: flex; | ||
flex-direction: column; | ||
height: 100%; | ||
justify-content: center; | ||
left: 0; | ||
overflow: hidden; | ||
position: absolute; | ||
right: 0; | ||
top: 0; | ||
width: 100%; | ||
`); | ||
|
||
render(html` | ||
<${Theme.Provider} value=${{ size: 48 }}> | ||
<${App}> | ||
<${Hat} title="Stylish!">🎩<//> | ||
<//> | ||
<//> | ||
`, document.body); | ||
</script> | ||
</body> | ||
</html> |
Oops, something went wrong.