-
Notifications
You must be signed in to change notification settings - Fork 54
Conversation
ef76d30
to
cd28f19
Compare
const color = 'rgba(0, 0, 0, 0.6)' | ||
|
||
return { | ||
circularRadius: pxToRem(9999), | ||
padding: `0 ${pxToRem(4)} 0 ${pxToRem(4)}`, | ||
colors: mapColorsToScheme(siteVars, colorVariants => ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@layershifter fyi
speaking on the ask for inversion mechanism - we might start with a simple concept of onColor = {
light: #333, // will be used on dark background
dark: #333 // will be used on light background
} Then we might apply logic that will precompute appropriate 'on' color (dark or light one) for each color used in the user's theme. Note that if client will need to customize the 'on' colors generated, it might still be possible: // pseudo-implementation, just to provide an idea
onColor: {
light: #333, // will be used on dark background by default
dark: #333 // will be used on light background by default
// OVERRIDES
backgrounds: {
primary: <some custom color>, // will be applied for all 'primary' tints (100 - 900)
// with these variants being used where appropriate for different tints of secondary
secondary: {
light: ...
dark: ...
},
// absolute fine-tuning
pink: {
....
'600': <color for exact tint of pink>
}
}
} |
e1a2087
to
6c5a78a
Compare
43cc496
to
7a3d851
Compare
docs/src/examples/components/Label/Variations/LabelExampleColor.shorthand.tsx
Outdated
Show resolved
Hide resolved
69e7f93
to
763c2b2
Compare
src/lib/commonPropTypes.ts
Outdated
@@ -6,11 +6,39 @@ export interface CreateCommonConfig { | |||
children?: boolean | 'node' | 'element' | |||
as?: boolean | |||
className?: boolean | |||
color?: boolean | |||
color?: boolean | 'single' | 'complex' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> single
simple
might be better in conjunction with complex
what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, it should either be single | multiple
or simple | complex
(I like more the second combination)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work Marija 👍 please take a look at my comments before we merge
…his util -changed color prop interface to be similar as the content and children by receiving generic type -fix merging the default scheme values with the variables
CHANGELOG.md
Outdated
@@ -28,6 +28,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm | |||
- Add `on` and `mouseLeaveDelay` props to `Popup` component @mnajdova ([#622](https://github.com/stardust-ui/react/pull/622)) | |||
- Add Dropdown Single Selection variant @silviuavram ([#584](https://github.com/stardust-ui/react/pull/584)) | |||
- Add `MenuDivider` component and `kind` prop to the `items` inside of the `Menu` for creating different components @mnajdova ([#682](https://github.com/stardust-ui/react/pull/682)) | |||
- Add `color` prop to `Label` component @Bugaa92 ([#647](https://github.com/stardust-ui/react/pull/647)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should point to Unreleased
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, moved
const color = 'rgba(0, 0, 0, 0.6)' | ||
|
||
return { | ||
colorScheme: getColorSchemeWithCustomDefaults(siteVars.colorScheme, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about this idea, can we omit it for initial implementation?
colorScheme: {
...siteVars.colorScheme,
default: {
...siteVars.colorScheme,
foreground: color,
background: 'rgb(232, 232, 232)',
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure then how will the components define their default scheme, as in the label we have grey foreground and background, but for the button is white background and grey foreground...
src/lib/colorUtils.ts
Outdated
? { ...colorScheme.default, ...getColorSchemeFromObject(colorScheme, colorProp) } | ||
: _.get(colorScheme, colorProp as string, { | ||
...colorScheme.default, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- We don't need destruction there
_.get(colorScheme, colorProp as string, colorScheme.default)
- If we will revert the condition, we will be able to omit
as string
type of colorProp === 'string'
? _.get(colorScheme, colorProp, colorScheme.default)
: { ...colorScheme.default, ...getColorSchemeFromObject(colorScheme, colorProp) }
colors: ComplexColorPropType, | ||
): Partial<ColorScheme> => | ||
_.mapValues(colors, (color, colorName) => { | ||
// if the color scheme contains the color, then get the value from it, otherwise return the color provided |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This idea looks quite confusing to me :(
I have a definition for blue
in the color scheme, but blue
is a valid CSS color, https://www.quackit.com/css/css_color_codes.cfm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally understand your point, but I don't have better proposal at this moment. We have to allow the user somehow to define the colors by name (the ones we have in the color palette, but still if we don't have them, we would end up with the CSS color.. If they define it as hex value then it is clear, but in the other case, is kind a confusing. Still, we have to use color names for the color prop, so I don't have any other proposal at this moment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// uses `red` from schema
<Label color='red' />
// uses CSS `red`, i.e. #FF0000
<Label color={{ background: 'red' }} />
// still uses CSS colors, but you can get them from schema
<Label color={(colorSchema) => ({ background: colorSchema.red.background })} />
What about color
as function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of thoughts on this:
- not sure what would be the use cases where the user will want to use the CSS colors, when they have defined schema for which colors will use
- more-over why should the prop in our API as default returns just some CSS color - as a user would make me wonder why we have special API for that
On the other hand, I understand the confusion, but would rather not over-complicate the API now, and wait for complains if there will be any in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
totally support @mnajdova 's points
if the color scheme name collides with the CSS color name it's by design and it's expected since the developer should stick to a theme color as much as possible
if the developer reaaaally wants the actual CSS red (which is not recommended since they're supposed to work within the theme constraints), they can still use the hexcode (#FF0000)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarification, the color prop exists specifically to restrict the developer from deviating from the theme color. The color prop is by design restrictive and imprecise. It should not allow defining where or how the color is applied nor what specific color it is, just the name.
Where and how the color is applied is the job of the designer through the theme. All props should be high-level, natural language, imprecise, and void of implementation.
Think of the color
prop as used in this statement "Click on the red label." Now, imagine you ask 10 designers to draw the label. There are many ways to do this, which is exactly what we want. We want flexibility through imprecise natural language.
import { Label, ProviderConsumer, Grid } from '@stardust-ui/react' | ||
|
||
const LabelExampleColor = () => ( | ||
<Grid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Waiting for the Flex component then :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always delete as much code as possible:
- No Grid is necessary, especially since it is a very complex solution to a very simple problem (add a space).
- Lodash is not necessary to Start Case the color names, just show the prop values (more helpful as well).
- Only use top level parent components, not the directly exported children (Provider.Consumer vs ProviderConsumer)
import * as React from 'react'
-import * as _ from 'lodash'
-import { Label, ProviderConsumer, Grid } from '@stardust-ui/react'
+import { Label, Provider } from '@stardust-ui/react'
const LabelExampleColor = () => (
- <Grid
- columns="auto"
- styles={{ justifyContent: 'left', justifyItems: 'left' }}
- variables={{ gridGap: '10px' }}
- >
<ProviderConsumer
render={({ siteVariables: { colorScheme } }) =>
- _.keys(colorScheme).map(color => (
- <Label key={color} color={color} content={_.startCase(color)} />
+ Object.keys(colorScheme).map(color => (
+ <span key={color}>
+ <Label color={color} content={color} />{' '}
+ </span>
))
}
/>
- </Grid>
)
-fixed changelog
src/lib/commonPropInterfaces.ts
Outdated
background?: ColorValue | ||
border?: ColorValue | ||
shadow?: ColorValue | ||
hover?: ColorValue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as we've discussed, hover
is a questionable member here, as it rather represents a state and not a color per se. At the same time, there is no need to introduce this complication for now - as there are several options of how this issue could be addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, will remove it for now.
@@ -159,6 +159,7 @@ const renderComponent = <P extends {}>(config: RenderConfig<P>): React.ReactElem | |||
|
|||
const { | |||
siteVariables = { | |||
colorScheme: {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be great if we will be able to reduce color
members siteVariables
directly expose - currently almost each new color-related concept results in the additional prop being added, but what is more important - those props are all cohesively connected with each other, so we might want eventually to introduce a dedicated object for them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure I follow your point @kuzhelov can you please expand or offer an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kuzhelov are you suggesting having maybe one colors
object that will contain the scheme, colors and everything related to the coloring mechanism? I would really avoid that refactoring as part of this part, but I can create an issue and open PR after this one gets in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Bugaa92, sure - currently we have the following set of props being exposed by siteVariables
: colors
, contextualColors
, emphasisColors
, colorScheme
, naturalColors
, etc - there are just plenty of them, and all are aimed to describe color
concept. Here I am proposing to introduce single color
prop that will be an object with all these being assembled as props:
siteVariables = {
color: {
scheme,
contextual,
natural,
...
}
...
}
This will aid maintainability (as all closely related aspects will be semantically grouped), as well as will not pollute the siteVariables
object itself. More than that, on the client perspective it will be much cleaner to see the entire set of objects from which colors could be consumed from, as everything related to color
will be assembled under single object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...emphasisColors, | ||
...naturalColors, | ||
} | ||
|
||
const lightBackgroundColors = ['teal', 'yellow'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see this being a very brittle thing that is tricky to maintain. I would be great to inline this isLight
flag value to the color variant itself, so that in case if collection of colors will change (or even if color name will change), we won't bother about
- adding new color to the list / remove color from the list
- change the name of the color accordingly
We definitely should think on some mechanism that will introduce this ability to select foreground color depending on the background.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kuzhelov agreed, what is your proposal?
add background
as a key to the ColorVariants
type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, essentially I would propose to reconsider the set of props of the ColorVariants
type - and just add the only necessary to inline this information currently kept by lightBackgroundColors
array. It may be a background
prop, or maybe other set of props (like light
and dark
, and this will allow us to properly apply colors on top of each other).
There are several corner cases that we won't be able to cover with the naive approach, thus I would rather like to open a separate discussion around exact implementation - but generally, yes, would rather see this information as being part of the ColorVariants
type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kuzhelov got it, agreed it'd be a better way to do things and was thinking of something similar myself
@layershifter can you weigh in as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will keep a track of this in an issue together will the other proposals for improvements regarding the color mechanisms.
...emphasisColors, | ||
...naturalColors, | ||
} | ||
|
||
const lightBackgroundColors = ['orange', 'yellow', 'lightGreen', 'postOrange'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same story here - if we will be able to agree on some way to define the fact that specific color is a 'light' one, we would solve a maintainability issue and won't need to duplicate common related functionality (like isLightBackground
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see my question above:
https://github.com/stardust-ui/react/pull/647/files#r247172459
colorScheme: ColorSchemeMapping, | ||
customDefaultValues: Partial<ColorScheme>, | ||
) => { | ||
const mergedDefaultValues = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in future see this being reduced to a single concept of 'merging color schemes' - this should simplify the scheme object itself, make merging logic simpler and remove default
prop
cursor: 'pointer', | ||
const labelStyles: ComponentSlotStylesInput<LabelProps, LabelVariables> = { | ||
root: ({ props: p, variables: v }): ICSSInJSStyle => { | ||
const colors = generateColorScheme(p.color, v.colorScheme) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it, essentially, mergeColorSchemes
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, this definitely shouldn't be a user responsibility to bother about this stuff. I would expect that colors
object will be just directly consumed from the style function, like that (one of the options):
root: ({ props, variables, colors }) => ({
foreground: colors.foreground,
...
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kuzhelov
don't forget about the p.color
parameter coming from the user; generateColorScheme
takes that argument and returns the ColorScheme
object for p.color
; maybe the name is confusing and should be:
generateColorSchemeForColorProp
or something more concise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added this with the latest commit (those are merged in renderComponent). Please take a look.
@@ -55,7 +58,7 @@ class Label extends UIComponent<ReactProps<LabelProps>, any> { | |||
static className = 'ui-label' | |||
|
|||
static propTypes = { | |||
...commonPropTypes.createCommon(), | |||
...commonPropTypes.createCommon({ color: 'complex' }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commonPropTypes
abstraction is growing out of hand. We already have customPropTypes
. Also, the function calls are unnecessary.
Always try to delete as much code and work as possible. Consider this line:
...commonPropTypes.createCommon({ color: 'complex' }),
commonPropTypes
duplicates the job ofcustomPropTypes
- Requires a function call
- Requires constructing an options object (of the exact shape that the returned object will contain)
- Causes indirection, obscures implementation, and requires spreading
We can achieve this much more simply like this:
color: customPropTypes.complexColor
- No need to create or import
commonPropTypes
vscustomPropTypes
- No need to call a function (
createCommon()
) - No need to create an options object
- Is obvious as the entire implementation is explicit and simple to read
feat(label): color prop
Description
This PR:
color
prop toLabel
componentLabel
colorsLabel
color examplesLatest updates on the API (@mnajdova)
Final implementation details. The color prop in the label can receive an object containing all parts of the color scheme: foreground, background, border, hover, shadow (we may want to trim this down to different objects in each component, or if we have component that can have multiple colors inside, we can always have the scheme).
How it works
The color can be one of the following:
'primary' | 'secondary' | 'blue' | 'green' | 'grey' | 'orange' | 'pink' | 'purple' | 'teal' | 'red' | 'yellow' | string
As the blue does not exists on the color scheme, the HTML blue color will be returned. The same will be applied if the color provided is in form of a hex value.
How is the color scheme in the variables defined
The color scheme has defaultValues for all parts (foreground, background border etc), but the component defining can override this (for example the Label can define some shades of grey as defaults for the foreground and background). In order for this to work, there is an util method added called
getColorSchemeWithCustomDefaults
. Here is how the color scheme is defined inside the labelVariables:Here is how all colors available in teams theme looks like: