Skip to content

Instantly share code, notes, and snippets.

View colinhacks's full-sized avatar

Colin McDonnell colinhacks

View GitHub Profile

Emotion is my favorite CSS-in-JS library.

It's easy to define style classes (both inline or in separate files), compose them in powerful ways with the cx utility, sprinkle them into React components using the standard className attribute. There's no need to ever modify your markup/JSX to apply styles (as it should be!). Plus you only need to install a single module (yarn add emotion) and there's no complicated Babel plugin or config file to set up.

I'm currently building a Tailwind-style CSS-in-JS utility styling library (join my newsletter at the bottom of this page to stay updated!) and Emotion provides the perfect layer of abstraction to build upon.

Why @emotion/core is bad

Unfortunately everything I just said only applies to the vanilla emotion module (https://emotion.sh/docs/emotion), not the inexplicably-named @emotion/core module. @emotion/core is the React-focused Emotion wrapper that gives you some extra goodies, like server-side rendering and theming.

@colinhacks
colinhacks / _document.tsx
Last active January 12, 2023 16:44
How to support server-side rendering for plain "emotion" package in Next.js
// ⚠️ works with Emotion 10 only! ⚠️
// 1. `yarn add emotion-server`
// 2. copy the contents of this file into your `pages` directory
// 3. save it as `_document.tsx`
// should work out of the box
import Document, { Head, Main, NextScript } from 'next/document';
@colinhacks
colinhacks / ts_literal_json_inference.ts
Last active March 25, 2020 21:35
Generic TypeScript function that infers the literal type of any primitive, object, or tuple (literal JSON type inference)
type Primitive = string | number | boolean | null | undefined;
type Compound<U extends Primitive = Primitive> =
| U
| { [name: string]: Compound<U> }
| []
| [Compound<U>]
| [Compound<U>, ...Compound<U>[]];
type Json<U extends Primitive> = U | Compound<U>;
// this function infers the EXACT type of the value passed into it
const A = t.type({
foo: t.string,
});
const B = t.partial({
bar: t.number,
});
const C = t.intersection([A, B]);
const numList = yup
.array()
.of(yup.string())
.required();
// interpreted as a non-empty list
numList.validateSync([]); // fails
// yet the inferred type doesn't reflect this
type NumList = yup.InferType<typeof numList>;
const schema = yup.object({
asdf: yup.string(),
});
schema.validate({}); // passes
type SchemaType = yup.InferType<typeof schema>;
// returns { asdf: string }
// should be { asdf?: string }
@colinhacks
colinhacks / gist:3c5c46e6934720a5f4dae16d01dbe6da
Created March 20, 2019 16:40
Generated TypeORM query with nested relations
SELECT DISTINCT "distinctAlias"."user_id" AS "ids_User_id"
FROM (SELECT "user"."id" AS
"User_id",
"user"."createdat" AS
"User_createdAt",
"user"."updatedat" AS
"User_updatedAt",
"user"."authid" AS
"User_authId",
"user"."firstname" AS
import { typeDefs as prismaSchema } from './client/prisma-schema';
const prismaAST = gql`
${prismaSchema}
`;
/*
remove the built-in Mutation and Query objects
from the Prisma Client schema
*/