-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial definition #1
Comments
Hi Brent! As a designer, I'm a huge fan of styled-system and all of the work you've done in this space. As an engineer, I constantly advocate for styled-system + typescript. Personally, I want to see some sort of type recommendation in theme-specification. I would love to be able to swap theme specs in and out and not worry whether widths have been defined as a |
Super excited to see this getting started! I've been thinking about this spec the last couple of days and wondering if you have any thoughts on how multiple sets of |
@souporserious I'm hoping that the idea of scales being objects means that you would have one master |
@zethussuen thanks! I think this initial spec is meant to be fairly loosely defined when it comes to what you put in the scales. That said, an extension of this spec could absolutely layer a type system on top – I think the PR here sort of leans that direction: styled-system/styled-system#432 |
Totally! That makes sense. I like settling on a key-value structure that everyone can adhere to, which right now seems great to me 👍. |
Just opened a PR for discussion about width and height properties here: #2 |
Related to @zethussuen comment, we are using TypeScript with styled-system and the way you define aliases for a scale does not work in a strictly typed context because you are applying a value to an array, which is considered an error in TS.
This way the |
@Grsmto Yeah, this spec should "work" for any language really. If you have to slightly alter what an object looks like for TS, I think that's totally valid. The aliasing example uses JS as a lingua franca to describe one possible approach to scale definition |
It's awkward that |
I'm so glad to see this discussion and repo! After reading through the spec and everyones feedback, I wrote down my thoughts. This will be a bit of a dump, apologies in advance. 1. Static definitions JSON/YMLThis has been discussed in styled-system/styled-system#432 (comment) and touched on above. To increase the specs reach and potential adoption, it's certainly worth considering embracing a baseline of everything being statically defined. While any language could be used to generate a spec-compliant static theme, it's this common output that could be consumed predictably by tooling of any language or platform. I agree with the earlier sentiment that JSON would be a good choice. However, we'd have to create or adopt a standard for referencing values. Style Dictionary solves this with a template-tag-esque approach. 2. Functions as valuesThis flies in the face of static definitions, but some scales could better be described through a function, especially when unbounded. A decent example is the I'm on the fence as I would favor static definitions. Could they reasonably co-exist? It's a little convoluted but I could see this solved using function names which map to externally defined implementations. "space": "fn:space" // gross prefix export const space = n => n * 1.5 3. Abstracting away platform specific language/conceptsConsidering how a design language can be applied across many platforms and technologies, how can we abstract away platform specific language without losing the specs simplicity and familiarity? While I don't think it's practical to have a completely generic spec, that sounds unnecessarily plain, I do wonder if we can take things a little further than where they are currently. These stand out to me as potentially CSS specific:
As for Key Reference mappings, we could make room for adding more key mappings beyond CSS. However, this has me questioning whether mappings should even be part of the spec. I'm tempted to consider that a tooling concern. I'm not sure. 4. Prior artWhat makes this unique or more capable than existing solutions? Answering this can help folks see the value. For me personally, I see a potential ecosystem enabled by this spec. Knowing I could access tooling by adhering to spec can be compelling. I'm sure there's more but here's the prior art I'm aware of:
OK, I'll stop now 😝. I hope some of that is helpful in continuing this discussion. |
Thanks @timhudson! This is super helpful!
I agree that having a statically defined theme for this spec makes a lot of sense. Personally, I'd rather avoid inventing anything like the templating in Style Dictionary – I think that can be handled by whatever generates the theme object if needed.
I think similarly, functions could be used to generate the object, but I don't think this spec has to deal with templates or functions at all. How the scales are defined should be outside of the scope here, IMO
This point I probably disagree with. While other specs may try to "bridge-the-gap" across platforms, I don't think that should be a goal here. CSS is a fine spec, and I'd rather this theme specification build on top of that base (because I think it's good). For a lot of this, it's not too difficult to translate from web terms into proprietary platform terms or ignore parts like media queries where it isn't applicable.
Yes, prior art absolutely should be documented in this project somewhere. Until I proposed this, I'd never heard of Style Dictionary, and I do mention Design Tokens (which is what the Theo implementation is based on IIRC)in my blog post. If there are any others, please feel free to open a PR to include them. |
I've been thinking a lot about dynamic theme modification lately, such as mobile sizes or high-contrast colors, but I've mostly thought of this as something acting on static tokens. I really like your suggestion above. It's a good mental model and maybe worth documenting for anyone else attempting to find where dynamic theming can fit in with static theme definitions.
I agree. I'm not concerned with using, or even favoring, CSS terminology. It's familiar, stable and in-line with typical design tokens. I'm more thinking about the concepts that don't port well to other platforms. Rather than single out any one example, it may be better to map out my thought process as I evaluate some of these keys: Is the key…
I'm particularly interested in translation and portability. This is mostly where I'm coming from. Regarding ignoring parts of the spec, the question I'm inclined to consider is how often or in how many contexts would folks ignore this key? If this number felt low, I would begin to ponder that keys value and the specs increased surface area. My feedback above isn't really actionable right now as it's focused more on thinking than actual output. But hopefully that is within the nature of this issue. |
What do people think of merging all of font tokens into a single object? // Create your initial tokens
const tokens = {
font: {
families: {
body: 'sans-serif',
heading: 'Helvetica, sans-serif',
subHeading: 'serif',
monospace: 'monospace',
},
sizes: [
12, 14, 16, 20, 24, 32
],
weights: [
200, 300, 400, 600, 700, 900
]
}
}
// Add any aliases you feel are useful
tokens.font.sizes.body = tokens.font.sizes[2]
tokens.font.sizes.h1 = tokens.font.sizes[5]
tokens.font.sizes.h2 = tokens.font.sizes[4]
tokens.font.sizes.h3 = tokens.font.sizes[3]
tokens.font.sizes.h4 = tokens.font.sizes[2]
tokens.font.sizes.h5 = tokens.font.sizes[1]
tokens.font.sizes.h6 = tokens.font.sizes[0]
tokens.font.weights.normal = tokens.font.weights[2]
tokens.font.weights.bold = tokens.font.weights[4]
tokens.font.weights.extraBold = tokens.font.weights[5] I've also been playing with a typographically based root object that includes things like // Create your initial tokens
const tokens = {
typography: {
fonts: {
body: 'sans-serif',
heading: 'Helvetica, sans-serif',
subHeading: 'serif',
monospace: 'monospace',
},
fontSizes: [
12, 14, 16, 20, 24, 32
],
fontWeights: [
200, 300, 400, 600, 700, 900
],
letterSpacings: [
1, 1.25, 1.5, 1.75, 2
]
}
}
// Add any aliases you feel are useful
tokens.typography.fontSizes.body = tokens.typography.fontSizes[2]
tokens.typography.fontSizes.h1 = tokens.typography.fontSizes[5]
tokens.typography.fontSizes.h2 = tokens.typography.fontSizes[4]
tokens.typography.fontSizes.h3 = tokens.typography.fontSizes[3]
tokens.typography.fontSizes.h4 = tokens.typography.fontSizes[2]
tokens.typography.fontSizes.h5 = tokens.typography.fontSizes[1]
tokens.typography.fontSizes.h6 = tokens.typography.fontSizes[0]
tokens.typography.fontWeights.normal = tokens.typography.fontWeights[2]
tokens.typography.fontWeights.bold = tokens.typography.fontWeights[4]
tokens.typography.fontWeights.extraBold = tokens.typography.fontWeights[5] I'd be interested to hear what others think? |
I like |
@dakebl I do like the idea of anything font-related being grouped together. I would go a step further and think about line-height pairings as well.
In terms of implementation, this feels quite verbose to type out all the time:
I would love an interface that abstracts common pairings away and allows for something like:
|
Expanding on feedback from @dakebl, I have been referring to |
as brought up in system-ui/theme-ui#85 (comment) - would CSS variables be allowed as values in the theme specification? Their types are unpredictable, but I can definitely see the need. |
Worth mentioning here again, but I would like to avoid bikeshedding on space specifically. It stems from usage like white space and negative space – it's more of a quirk with the English language IMO. Most of the other names stem from CSS properties, but in this case |
Yooo, I was wondering are units intentionally not a part of the examples in this specification or are they optional? Does this specification default to pixels? I think either way I would be happy to document it so not to confuse others. Do you think that this would support global design properties such as reading direction ( |
What's the purpose of separate keys for Some downsides:
Some upsides:
Any thoughts? |
Has there been any thoughts on splitting transitions into I also assume people don't want to add the property as they may use multiple animations on different properties e.g. This is how I am using it right now it feels a bit off: {
transitions: [
'100ms cubic-bezier(0.4, 0.22, 0.28, 1)',
'150ms cubic-bezier(0.4, 0.22, 0.28, 1)',
'300ms cubic-bezier(0.4, 0.22, 0.28, 1)'
],
} /* Output from theme specification */
:root {
--🍭-transition-1: 100ms cubic-bezier(0.4, 0.22, 0.28, 1);
}
.box {
transition: opacity var(--🍭-transition-1);
} I also have similar thoughts to the shadows and how they could or could not use color. |
@alex-page in design-system-utils which uses a tokens schema similar to system-ui, I did exactly what you describe, albeit with just one variation for the duration and timing function. See one example here const transitions = {
duration: '300ms',
timing: 'cubic-bezier(0.77, 0, 0.175, 1)',
} and its usage here transition: {
default: {
duration: transitions.duration,
timing: transitions.timing,
transition: `all ${transitions.duration} ${transitions.timing}`,
},
}, |
@Grsmto what does your theme interface look like to support aliases? |
@coreybruyere I created a export interface Scale<TValue> {
[id: string]: TValue;
} and I use it like: const fontSizes: Scale<string> = {
0: '0.75rem', // 12px
1: '0.875rem', // 14px
...
10: '3.75rem', // 60px
}; |
Thanks @Grsmto - New to TS. How are you getting intellisense hints that don't just display the interface that was defined? |
@coreybruyere I think it kinda depends of your setup, tbh TS with React in general is really complicated and with Styled-Components it's a nightmare (my opinion :) ). Basically I managed to get this by defining the type on my styled component using the styled.div<StyleProps>(({ theme }) => ({
...your styles
}); I would advice you to check the styled-components Github issues or Definitely Typed repo, there are resources there. Also that stuff I sending is a few months old, probably it changed since that, not sure. |
I was wondering this as well. One benefit of keeping things unitless is that it's easier to do math since it's just a number as opposed to a string (i.e. |
Should |
Any reason for
I believe
I'd appreciate could you provide a reason, as I'd like to understand the design decision behind it and learn from it 🙂 |
In English, space can be an uncountable noun, like it is used here. The word spaces generally means something different |
Thank you, @jxnblk. I wasn't aware of the difference. You are right, |
It's a collection of |
Agree that "space" here is a misnomer... When we're talking about typography, "space"/"spaces" usually means the whitespace characters you put between other text characters, while "spacing"/"spacings" usually refers to certain space areas that are used or existing for layout purposes. @jxnblk we should change this. |
🙂 I think this is worth repeating:
|
Here to second a desire for functions defined within the theme definition. As said above, it may slightly go against the static nature of a theme spec, but there are too many benefits to ignore, and we can still conform to certain structures Firstly, it doesn't make sense to pre-calculate values, when a function will do. Second, if you're really trying to enforce a consistent styled, it'd be great to proactively disallow illegal values. Just throw an error. This would be super helpful dev-time feedback from designers to developers. Consider, you're following a multiples of 4 design style, but the designs don't use With a fn we could easily take this to the next level: function spacing (multiple: number) {
const allowedMultiples = [1,2,3,4,5,6,8,10,12,14,18];
if (!allowedMultiples.includes(multiple)) {
throw new Error('Illegal spacing multiple, see design system guide');
}
return multiple * 4;
} |
I feel the same way as @jxnblk does with space as a base token, what could be done is with the styled system package is to add a way to override the keywords that the functions within styled system use e.g.
so on and so forth. |
Like @timhudson mentioned here, abstracting away these platform specific concepts is important, I think some customization here could be relevant for example in this situation: I recently published the first version of emotion-native-extended, which adds better 'native' support for Emotion (CSS in JSX), including responsive media queries. The whole reason I built this because I desperately wanted styled system to properly work with React Native. I had to write a specific condition though to replace the |
Hi, just saw the spec, it's great idea I've been thinking a bit, and I think your stated purpose is problematic Should this be a portable template to be used to communicate the details of a theme definition ? Should it be something that stores values that javascript programs can read and turn into css values? Either way, I think that it would be reasonable for a particular tool or css library to read the information and turn it into a spec that works for that library. This gets rid of all sorts of issues
Such a reader could have checks for unimplementable styles and be used as a tool to communicate this back to the designer Two more things
|
To piggy back off of this, if you prefer to use array's for scales instead of an object they can be typed like below: interface Scale<S> extends Array<S> {
small: S;
}
const space = [0, 8, 16, 24, 32] as Scale<number>;
space.small = space[1];
console.log(space.small); // returns `8`; If you prefer not to use the interface Scale<S> extends Array<S> {
small?: S;
}
const space: Scale<number> = [0, 8, 16, 24, 32];
space.small = space[1];
console.log(space.small); |
This issue is meant to be the canonical place for discussion about the initial scope and details of the theme specification.
The text was updated successfully, but these errors were encountered: