Skip to content

Commit

Permalink
NIcer entrypoints
Browse files Browse the repository at this point in the history
  • Loading branch information
JAForbes committed Dec 3, 2024
1 parent cd8cc55 commit ba9bc15
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 31 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"javascript.format.enable": false,
"typescript.format.enable": false
"typescript.format.enable": false,
"deno.enable": false
}
4 changes: 4 additions & 0 deletions lib/m.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import M from 'mithril'
import CSS from './index'
export const { css, m } = CSS(M, { server: !('document' in globalThis) })
export default m
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
"scripts": {
"test": "node --import tsx --test test/*.ts",
"dev": "node --watch --import tsx --test test/*.ts",
"build:bundle": "esbuild lib/index.ts --bundle --format=esm --sourcemap --allow-overwrite --outfile=./dist/super-mithril-css.esm.js",
"build:bundle:index": "esbuild lib/index.ts --bundle --format=esm --sourcemap --allow-overwrite --outfile=./dist/super-mithril-css.esm.js",
"build:bundle:m": "esbuild lib/index.ts --bundle --format=esm --sourcemap --allow-overwrite --outfile=./dist/mithril.esm.js",
"build:bundle": "npm run build:bundle:index && npm run build:bundle:m",
"build:types": "npx tsc -p tsconfig.test.json && npx tsc",
"build:test": "npm run test",
"build:clear": "rm -fr ./dist",
Expand Down
66 changes: 44 additions & 22 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# super-mithril-css

🎨 A simple reactive util for inline styles in mithril
🎨 A simple css-in-js solution for mithril.js

## Quick Start

```typescript
import CSS from 'super-mithril-css'
import m from 'mithril'
import {Stream} from 'super-mithril-stream'
import m, { css } from 'super-mithril-css/m'
import * as c from 'chifley'

const { css } = CSS(m)
const color = Stream('red')
const opacity = Stream(1)
const color = c('red')
const opacity = c(1)

const desktop = css('(min-width: 1000px)')

Expand All @@ -38,7 +36,7 @@ It has a few more features, but not much more than that.

## Why

We've had this built in to our internal fork of Mithril for a long time, but we're trying to extract a lot of that code into tiny libraries to share with the community.
We've had this built in to our internal fork of Mithril at [harth](harth.io) for a long time, but we're trying to extract a lot of that code into tiny libraries to share with the community.

## Tell me more

Expand All @@ -47,7 +45,7 @@ We've had this built in to our internal fork of Mithril for a long time, but we'
This is an exhaustive list of what this library does:

- Takes any interpolated values you set and makes them css variables
- If your intepolated value adheres to the (sin.js inspired) observable spec, we will subscribe to them and patch the dom without redraws
- If your intepolated value adheres to the observable spec, we will subscribe to them and patch the dom without redraws
- If its not an observable, the value is injected literally with no processing and updates whenever there is a redraw
- We automatically wrap your original CSS definition in a block with a hash selector to isolate your styles to the current scope
- We identify any `@keyframes` definitions and move them to the top level (because they don't work with the nested css spec)
Expand All @@ -57,7 +55,7 @@ This is an exhaustive list of what this library does:
- If you use `// comments` we'll fix it for you
- You can directly inject literal css text via `${css('your text')}`
- We also pretty print the styles while we parse them and compute the hash, all in one loop.
- It works in the browser and the server
- It works in the browser and on the server
- We overload the hyperscript function to allow us to inject the hash selector onto the parent and to re-order elements so attrs always comes first
- We support nesting css expressions which helps with writing handy utils

Expand Down Expand Up @@ -104,6 +102,8 @@ type Stream<T> = {
Anything not treated as a stream will be bound to the DOM on init and every redraw.
> 🤓 We will soon release our stream API _chifley_, some of the mithril community are already playing with it. If you'd like to request early access, leave a comment [here](https://mithril.zulipchat.com/#narrow/channel/324076-general/topic/New.20stream.20library!)
## Literals
By default all interpolated values in the CSS are treated as css variables. If you would like to inject literal CSS text you can call `css('your string')`.
Expand Down Expand Up @@ -142,9 +142,7 @@ Note: in order to attach the the selector the parent element on the server we ne

```typescript
import M from 'mithril'
import CSS from 'super-mithril-css'

const { m, css } = CSS(m, { server: true })
import m, { css } from 'super-mithril-css/m'
```

In the browser we also override the hyperscript function to ensure attrs written after css nodes are moved to the start of the child list.
Expand Down Expand Up @@ -200,23 +198,47 @@ One issue you may run into is using `#` as a property name, as typescript will r

## Browser support

Evergreen only. We do not make (web)apps that target older browsers and we aren't realistically able to support them without running up against their quirks day to day. We also rely and plan to rely on pretty new features to keep the codebase simple.
Evergreen only. We do not actively work on (web)apps that target older browsers and we aren't realistically able to support them without running up against their quirks day to day. We also rely and plan to rely on pretty new features to keep the codebase simple.

## Pretty printing

This library pretty prints while it is pseudo-parsing your css. At time of writing this cannot be disabled, but it wouldn't be a lot of work to change that
If it bothers you let us know.
This library pretty prints while it is pseudo-parsing your css. At time of writing this cannot be disabled, but it wouldn't be a lot of work to change that. If it bothers you let us know.

## FAQ

### What about nested css, auto units, etc
### Why does super-mithril-css export its own mithril?

This library has to inject some extra functionality into mithril's hyperscript functionality

- On the server we need to attach a generated classname to the parent element
- On the client and server we reorder args so `css` always comes after `attrs`

To make the library super simple to use and adhere to mithril's tradition of only 1 import.

### Why not use peerDeps?

We feel peer deps are bit a convoluted, if you would like to manually parameterize `m` you can do so:

```js
import M from 'mithril'
import CSS from 'super-mithril-css'

const { m, css } = CSS(M)
```

### I tried some of my css and it didn't render?

This library is fairly new, and while the parser has lots of tests and is being used in production, its definitely possible to confuse it if you are doing complex expressions across multiple lines. If you come across a situation where the parser gets confused please let us know and we'll patch it quickly.

We also welcome contributions!

This library deliberately just does the bare minimum. Native CSS really isn't that bad and we feel to deviate from the syntax even a little bit you really need to be getting a lot of bang for your buck. You should go all in or not at all.
### What do you mean by 'pseudo-parsing'?

We do automatically inject semicolons and transform comments, but that is just after reviewing many PRs seeing devs assume that will work, its not worth the friction not to support that when its so simple to implement.
css is a constantly evolving language, and we don't want to bake in any assumptions that could lead to this library not supporting future features. We also want to parse and render the css as quickly as possible. This library therefore trusts you to write correctly formatted css.

If you would like us to add some other feature ask away, but its pretty likely we'll want to just keep things vanilla for this library.
The parser detects groupings. It detects the start and end of rules. It detects when you've entered or exited a comment. It detects nested rules/blocks.

### Why do we pass in the hyperscript function as any argument
It also detects the usage of `:root` and moves in any `:root` block outside of the scoped context.
But largely, the css you write, is the css we render. This library doesn't build an AST and then print CSS from the AST, it collects groups of rules and blocks and prints them again in order.

A few reasons. The first is it is much simpler than dealing with `peerDeps`, it makes this library easier to maintain and it gives you the power to swap out mithril for your own hyperscript wrapper (something we do at [Harth](https://harth.io) to add reactivity to hyperscript directly)/
We do pretty print your css but only because this allows us to deterministically hash your styles to support client side hand off of server rendered styles.
6 changes: 2 additions & 4 deletions test/browser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import test from 'node:test'
import CSS, { pretty, sheets } from '../lib'
import { pretty, sheets } from '../lib'
import { JSDOM, VirtualConsole } from 'jsdom'
import assert from 'node:assert'

Expand All @@ -22,9 +22,7 @@ test('browser', async () => {
// just sync render, easier tests
;(globalThis as any).requestAnimationFrame = (f:any) => f()

const { default: M } = await import('mithril')

const { css, m } = CSS(M, { server: false })
const { css, default:m } = await import('../lib/m')
const desktop = css('@media(min-width: 1000px)')

const className = `css-x3m6yr`
Expand Down
6 changes: 3 additions & 3 deletions test/server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import test from 'node:test'
import assert from 'node:assert'
import hyperscript from 'mithril'
// @ts-ignore
import render from 'mithril-node-render'
import CSS, { sheets, pretty } from '../lib'
import { sheets, pretty } from '../lib'

import { JSDOM } from 'jsdom'

const assertStringEq = (a:string,b: string) => {
Expand All @@ -14,7 +14,7 @@ const assertStringEq = (a:string,b: string) => {


test('server', async () => {
const { css, m } = CSS(hyperscript, { server: true})
const { css, default: m } = await import('../lib/m')
const desktop = css('@media(min-width: 1000px)')
const rendered = await render(
m(
Expand Down

0 comments on commit ba9bc15

Please sign in to comment.