Skip to content

Conversation

@ben-rogerson
Copy link
Owner

@ben-rogerson ben-rogerson commented Oct 18, 2020

Previously the theme import could only grab string values from your merged tailwind config.
This PR beefs up the theme import so you can now grab anything from the theme key of the merged tailwind.config.js

Some usage examples:

Grab the breakpoints

Once you've got the breakpoints, you could use them to create breakpoint helpers of your own.

import { theme } from 'twin.macro'

const breakpoints = theme`screens`

// ↓ ↓ ↓ ↓ ↓ ↓

const breakpoints = {
  "sm": "640px",
  "md": "768px",
  "lg": "1024px",
  "xl": "1280px",
};

Grab a set of colors

This is most likely to help you create custom themes on your site or app.

import { theme } from 'twin.macro'

const grayColors = theme`colors.gray`

// ↓ ↓ ↓ ↓ ↓ ↓

const grayColors = {
  "100": "#f7fafc",
  "200": "#edf2f7",
  "300": "#e2e8f0",
  "400": "#cbd5e0",
  "500": "#a0aec0",
  "600": "#718096",
  "700": "#4a5568",
  "800": "#2d3748",
  "900": "#1a202c"
};

Grab the whole merged config

You can also grab the whole merged config with an empty theme call.
The theme call will be replaced with the entire merged config so beware of the bloat this will add to your file:

import { theme } from 'twin.macro'

const wholeCombinedConfig = theme() // or theme``

// ↓ ↓ ↓ ↓ ↓ ↓

const wholeCombinedConfig = {
  "screens": {
    "sm": "640px",
    "md": "768px",
    "lg": "1024px",
    "xl": "1280px"
  },
  "colors": {
    "transparent": "transparent",
    "current": "currentColor",
    "black": "#000",
    // + 1585 more lines!
};

@tqwewe
Copy link

tqwewe commented Oct 19, 2020

The typing for the theme function currently requires you to convert to unknown before converting to any other type.

const sm = theme('screens.sm') as unknown as string;

It might be nice to update the type for theme to support a generic type to simplify the return type:

const sm = theme<string>('screens.sm');

What do people think? I think this change could be nice as it is a non-breaking change (backwards compatible) and will simplify the code.

@ben-rogerson
Copy link
Owner Author

Makes sense @acidic9, I'll squeeze it into this PR 👍

@ben-rogerson
Copy link
Owner Author

Hey @acidic9 👋

Here's the type I've arrived on:

export type ThemeFn = <T>(arg?: unknown) => string;

If you get some time, could you please check if this covers your use case?

I've tested with these cases:

import { theme } from "twin.macro";

(theme("screens.sm") as unknown) as string;
(theme("") as unknown) as string;
(theme() as unknown) as string;
theme("screens.sm") as string;
theme("") as string;
theme() as string;

theme<string>("screens.sm");
theme<string>(`screens.sm`);
theme<string>`screens.sm`;
theme<string>`screens.sm`;

theme<string>``;
theme<string>(``);
theme<string>("");
theme<string>();

theme("screens.sm");
theme`screens.sm`;
theme(`screens.sm`);

theme();
theme("");
theme``;

If all is good, I'll merge this in on Wednesday this week.

@tqwewe
Copy link

tqwewe commented Oct 26, 2020

Hi @ben-rogerson thanks for doing this! Really appreciate it.

In your theme fn type:

export type ThemeFn = <T>(arg?: unknown) => string;

I noticed that the T generic is unused in the arguments or return value and theme will always return a string.

As the theme function has been updated to support returning any part of the theme, the return type could be anything from string to object.
I think this is where the T generic could be useful for the user to tell TypeScript "I know this returns an object" by theme<object>('screens').

I was thinking the theme function type might be something like:

export type ThemeFn = <T = string>(arg?: string) => T;

This ensures the argument is a string, and defaults the return type to string unless otherwise specified.

The following would be the case in this situation:

const screenMd = theme('screens.md') // string
const screenLg = theme<number>('screens.lg') // number
const screens = theme<Record<string, string>>('screens') // { key: 'value', ... }

@ben-rogerson
Copy link
Owner Author

Thanks for the help here 👍

I'm testing that type and seeing some issues with template literals which I need to support also:

export type ThemeFn = <T = string>(arg?: string) => T;

image

Argument of type 'TemplateStringsArray' is not assignable to parameter of type 'string'.ts(2345)

I wonder if we can support template literals too?

@tqwewe
Copy link

tqwewe commented Oct 26, 2020

I see, I think it's as simple as:

export type ThemeFn = <T = string>(arg?: string | TemplateStringsArray) => T;

@ben-rogerson
Copy link
Owner Author

Looks like that fixed it :)
If nothing else turns up, I'll include this in tomorrows release.
Thanks again for your help.

@ben-rogerson ben-rogerson mentioned this pull request Oct 27, 2020
@ben-rogerson ben-rogerson merged commit 7196cd2 into master Oct 28, 2020
@ben-rogerson ben-rogerson deleted the feature/theme-object branch October 28, 2020 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants