-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
[WIP] Proposal: Parameterized mui-themeable hoc #2509
Conversation
…ied and passed down component subtree through context
@newoga This is a very good idea, it can also drastically improve performance through memoization, but there is only one thing we will have to take care of, how would the users on this library isolate their customization? I mean what if someone wants to change only |
That's a very good question that we need to address. |
@subjectix @oliviertassinari That is true. This pull request's implementation does not currently support overriding the theme for a particular component. If you two don't mind, I'd like to work with this a little bit more to see if there's a clean way to handle that use case using this approach. |
Made these arguments as to why this PR should be considered as a comment in #2635. I can/will flesh out and clarify anything that is unclear.
|
I absolutely agree. I think
It does make more sense, but I don't know about the impact. How would the user customize the entire app as they wish in a single place?
This would pollute the props the component takes in. Also, It will be harder to maintain since any new style from the theme to want to add to the component should be added in 2 places, and removed from 2 places when you want to remove it, I'm against this one. But having the logic nearby is good. I just can't figure out a convenient way to do this. |
This is from a maintainer perspective not from a user perspective. The user would continue customizing the entire app change the textField: {
textColor: rawTheme.palette.textColor,
hintColor: rawTheme.palette.disabledColor,
floatingLabelColor: rawTheme.palette.textColor,
disabledTextColor: rawTheme.palette.disabledColor,
errorColor: Colors.red500,
focusColor: rawTheme.palette.primary1Color,
backgroundColor: 'transparent',
borderColor: rawTheme.palette.borderColor,
}, I think that code belongs in
I'm not sure I follow, how is this different than it currently is? For example, using my example above, my suggestion is that rather than the
I'm not sure I follow or maybe I'm thinking the opposite 😄. Using the example above, I'm thinking if |
Thanks for the extra bit of information but I still don't understand how we will address this question #2509 (comment). |
@newoga Sorry I misunderstood some of your points, I thought you meant... nevermind, what I thought was too sick 😅 😅 I take the full fault on this :D There is only one thing. how can we override TextField related styles Throughout the library and not just for 1 single instance of it? |
@subjectix @oliviertassinari First of all, I apologize! 😄 When I initially made this proposal, it was an extension of another PR and I never appropriately or clearly explained any of it. Sorry for all the confusion from the start. Like I said, my original proposal does not account for overriding a specific component's style across the entire library. I do have a few ideas of how this could work, but I haven't articulated them yet. One of those ideas is what @oliviertassinari alluded to:
Another approach is to allow developers to import a non-decorated version of |
I do agree with having these calculations close to their corresponding components ! I DO agree that the mapper should be close! But NOT excluded from muiTheme! Just to add another reason to why inheritance is better. you can pass a theme mapper to the constructor of MuiComponent like this: class MuiComponent extends React.Component {
constructor(p,c, options) {
if(options.themeMapper) {
this.themeMapper = options.themeMapper;
}
}
get theme() {
if(this.themeMapper) {
return this.themeMapper(this.context.muiTheme || MuiComponent.DEFAULT_THEME);
} else {
return this.context.muiTheme || MuiComponent.DEFAULT_THEME;
}
}
} then you can use it like this: // do all the heavy calculations in the same file!!
// but let the getMuiTheme RUN it
const themeCalculator = (theme) => {
// The implementation is debatable :D
theme.textField: {
color: ColorManipulator.doSomeHeavyColorCalculations(theme.baseTheme.userColor)!
// do all the other calculations necessary.
};
// Export this calculator so getMuiTheme can use this instead of it's own,
// This will let you provide calculations in the same component!
// The PICKUP can also be automated, maybe webpack magic? :D :D
export themeCalculator;
// This is a selector! and embrace yourselves!!!
// MuiComponent can memoize it <3 <3 <3
// That means, one step closer to fully optimized styling
const themeMapper = (theme) => ({
return {...theme.textField, tooltipZIndex: theme.baseTheme.zIndex.tooltip };
})
class MyComponent extends MuiComponent {
constructor(p,c) {
super(p, c, {themeMapper}); // Pass the mapper for memoization and selection.
}
render() {
// By only looking at the first two functions in this file you
// know exactly where these props come from.
this.theme.tooltipZIndex; // Profit!
this.theme.color // More Profit!!
} |
Then we will have to expose the implementation details as public API. It can really hurt maintenance 😬 |
I wish we could all get together, grab some good food, and have a nice debate! 😄 I clearly see the benefits of the inheritance approach that you proposed, but even so, I fear that using the approach is taking a step away from the general movement of the react community and not towards it. The React (and javascript community as a whole) is a constantly evolving one. I think it's also important to consider how certain design decisions affect our ability to evolve as quickly and easily as everything else easier. My initial impression from the community, including authors of React, is that composition is encouraged over inheritance and is the sole reason why I have a hesitation. That all being said, I'm fine exploring the inheritance approach in the In my opinion, our goal should be to make material-ui components that render consistently given a set of props, and nothing more. I think those components should be documented and tested well, and all of them should publicly accessible regardless of whether they decide to use theming or not. The ability to theme at the application level (or all components in a given subtree) should be considered a separate feature that is handled by high order components (or another approach), but not logically baked into the components themselves (as they would be if everything extends For example, if someone is user space decided they wanted to implement their own way on how theming works, it should literally be a matter of them wrapping material-ui components themselves and making them available in their own application. I think this is very much React-ish. In addition, if someone decided they wanted to use only
I wouldn't consider them implementation details. To me, the component's theme/styling should potentially be considered as part of it's public API. The component styles are passed through props and would be documented like any other other ordinary prop. |
You said it 😁 😁 😁
Yes!! I completely agree with composition over inheritance. But that is for extending functionality, providing abstraction and much much more!! But NOT for cross-cutting-concerns ( ref ) these cannot all be handled with composition, especially when the coupling is tight. Besides this is only an implementation detail we will discourage the users of this library with a NO-NO. and for implementation detail inheritance is the optimal decision imo. Sometime you have to resort to Platform Specific Machine Code to get the job done. I don't like doing this all over, I did it once with composition and it just sits there waiting to be merged. But I gave it way too much thought! and the best I came up with was inheritance. |
@subjectix Your arguments are fair. Let's experiment, discuss, and find out together! |
@newoga Thanks 😄 😄 Yeah I would agree with you. I can't be sure myself with no experience on how this would turn out 👍 👍 |
Not the same as sharing a meal together, but why don't you guys and Olivier get together on a google hangout or similar. @subjectix, been watching your mammoth themes overhaul from the sidelines- Amazing work! |
@mbrookes That wouldn't be a bad idea 😁
Thanks a lot ^.^ |
@subjectix @oliviertassinari @mbrookes I'm open to that! I'm in EST (but I've had my fair share of 3am nights, and I know @subjectix has had his fair share of his 😄 ). If you want to orchestrate this, let me know when is best. |
@ntgn81 Just cc'ing you here in case you're interested, want to make sure everyone is included. |
@newoga I'm in GTM +3:30 Iran, Tehran. That makes 8:30 hours difference 😁 I'm usually up at nights working on this. around this time :D so I'm alright with it. Just point me to a service and I'll make an account 😎 |
@subjectix Okay cool, I'm on Google and Skype! Let's see if @oliviertassinari can carve out some time for this! |
@newoga Yeah he seems really busy recently 😁 I hope he can attend, We must have many discussions about many decisions. not just themes. It's 3:20 AM here, I should wake up at 8:30. Farewell for now 💤 |
I have definitely time to spend so that we can find out a good solution 👍. |
@oliviertassinari Sounds good. Github needs a timezone calculator tool 😄 You're in Paris, right? You and @subjectix are only 2.5 hours apart. Maybe when you both wake up, you two can coordinate some times and let me know when is best. I should be up pretty late so I may be up too when you both wake up. |
I see 😁 Have a nice time 🍊 🎋
Aye to that! 😆 I'll leave it to @oliviertassinari and you @newoga Since I can almost always be able to chat. Both at work and at home. |
Seems like 10am Eastern, 4pm CET, 6:30pm GMT+3:30 would be sociable hours for everyone, depending where @ntgn81 is based. Just not tomorrow! ;) Might be easiest to schedule via email. Addresses are in the commit history. :) |
I am EST. Don't let me hold you guys up though. I'll try my best to be available whatever time is good for everyone. It's super hectic with all the year end stuff for me right now lol |
@newoga Think we can close this? I'm working on my react-memo to support style objects with both static styles and dynamic-memoized. |
Yes, thanks! |
This is an extension of #2493. This pull request explores approaches to not needing a
ThemeManager
at all (at least in user space).Note: Once again, just throwing this out there for discussion.
This idea is inspired react-redux. In this pull request, the
mui-themeable
component created in #2493 now accepts a mapping function that computes a calculated theme from arawTheme
object (simliar to react-redux's connect higher order component'smapStateToProps
function).For example, currently
text-field.jsx
accepts amuiTheme
object in context, then uses calculated theme provided byThemeManager
at the key oftextField
. It would get the computed result of:In this pull request's implementation, in
text-field.jsx
, you could decorate TextField like this:This means that when users supply a theme, they would only need to supply a
rawTheme
: