-
Notifications
You must be signed in to change notification settings - Fork 39
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
Feature: theme listener #3
Conversation
Coverage decreased (-0.3%) to 94.068% when pulling aa1cb576b7bfe084fc5e8964f1ca38a4b05dc94f on feat/theme-listener into af0faaa on dev-review. |
If |
if it doesnt, lets iterate and think of smth |
Honestly, I'm not the right person to ask about the theme functionality in glamorous. I neither developed it nor use it. @vesparny was the one who implemented it, so he probably has some thoughts :) |
I like this, seems like a good level of abstraction! |
@mxstbr nice |
@kof your turn |
src/create-theme-listener.js
Outdated
const PropTypes = require('prop-types'); | ||
const channel = require('./channel'); | ||
|
||
function createThemeListener(CHANNEL = channel) { |
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 would keep the channel lower case, because this mapping from lower to upper doesn't makes sense or look good. Knowing that its a constant doesn't give you any benefits when using in this way.
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.
its minor implementation detail, and lets discuss to change it later in separate issue
src/create-with-theme.js
Outdated
static contextTypes = themeListener.contextTypes; | ||
constructor(props) { | ||
super(props); | ||
this.themeSubscribe = themeListener.subscribe.bind(this); |
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.
Why do you need the binding? Seems like you are using arrow functions anyways.
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.
take a look again, subscribe
and unsubscribe
are using react component's this
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.
yeah, this is very implicit
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.
createThemeListener() returns basically a mixin, it would be more explicit to merge that object with the prototype of withTheme class.
Object.assign(WithTheme.prototype, themeListener)
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 dont like mixins, it allows one mixin to do too much and what is worse, allows it to do it in very implicit way
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.
theme listener is low level api for cssinjs libs authors, shall it that implicit and "easy"?
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 don't like them either. Though implementation detail over prototype here seems to me nicer/more clear than the bindings for each 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.
theme listener is low level api for cssinjs libs authors, shall it that implicit and "easy"?
Interface is ok for now like that as we don't know it better. I am just talking about how you use it, Object.assign on prototype is more explicit to me than .bind on each 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.
can you sketch the api surface?
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 discussed it in gitter and decided it current api design is good enough
src/create-with-theme.js
Outdated
|
||
function createWithTheme(CHANNEL = channel) { | ||
const themeListener = createThemeListener(CHANNEL); | ||
return Component => | ||
class withTheme extends React.Component { |
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.
class name should start with upper case
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.
why? it works
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.
sure, its just a convention everyone agreed on in javascript world. Class names upper case, instances lower.
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.
withTheme
lower case is the function you return on ln 7, which accepts a component, don't mix it up with the class name.
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.
then, it will be withTheme(Comp)
because its function, and WithTheme(Comp)
in react dev tools, and its confusing. lets stick to withTheme
because its even more against common practice to have a normal function (not a class) with capital letter
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.
All of recompose
s HoC are lowercased in both the function and the DevTools, so we're definitely fine going lowercase.
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 Redux it is Connect(Something)
react-intl (very popular as well) - InjectIntl(Something)
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.
After looking up other popular libs, UpperCase(Component) is def. a common way.
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 don't care either way, let's not bikeshed on this for ages. This shouldn't block.
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.
lets go with Capital letter then, but I will change it after pull-request will be merged
@vesparny what do you think? |
@vesparny can you take a look? |
Maybe @kwelch would have an opinion here... |
Personally, I prefer the lowercase Here is how the merging is being done in glamorous. https://github.com/paypal/glamorous/blob/afbd1e1cf106ae46dd53b89015b46649bc833155/src/theme-provider.js#L17-L20 |
@kwelch no, right now we merge outer theme and current one as well, i have tests for that |
Ah, thanks. I was only looking at within the scope of this PR. 😝 |
aa1cb57
to
1a3e027
Compare
accidentally closed this pull-request. will reopen it soon with updated implementation, tests and docs |
lgtm |
abd34df
to
79a07f9
Compare
README.md
Outdated
* `createTheming` allows you to integrate `theming` into your CSSinJS library with custom `channel` (if you need custom one). | ||
======= |
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.
Merge conflict
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, fixed
src/create-with-theme.js
Outdated
}; | ||
constructor(props) { | ||
super(props); | ||
this.state = { theme: {} }; |
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 init theme be allowed to be passed via props?
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 dunno, the same can easily be achieved by defaultProps
of Component being enhanced
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.
Good point. That works for me.
import defaultChannel from './channel'; | ||
|
||
export const channel = defaultChannel; | ||
export const withTheme = createWithTheme(); | ||
export const ThemeProvider = createThemeProvider(); | ||
export const themeListener = createThemeListener(); |
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.
Question: How can these exports be used since they all require a channel but they are invoked without one?
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.
these exports are defaulted to default channel __theming__
internally
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.
withTheme:
import channel from './channel';
export default function createWithTheme(CHANNEL = channel) {
// …
}
ThemeProvider:
import channel from './channel';
export default function createThemeProvider(CHANNEL = channel) {
// …
}
themeListener:
import channel from './channel';
export default function createThemeListener(CHANNEL = channel) {
// …
}
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 see that now. Thanks, I knew it made sense, but I didn't see the connection.
a536d30
to
69836a0
Compare
this branch has been published under |
i started to integrate it into jss, and it seems to be working. But themeListener needs to be adjusted a bit, but its a good news, because API surface will be smaller and simpler |
status update:
|
no more bindings: import { themeListener } from 'theming';
function CustomWithTheme(Component) {
return class CustomWithTheme extends React.Component {
static contextTypes = themeListener.contextTypes;
constructor(props) {
super(props);
this.state = { theme: {} };
this.setTheme = theme => this.setState({ theme });
}
componentWillMount() {
this.setTheme(themeListener.initial(this.context))
}
componentDidMount() {
this.unsubscribe = themeListener.subscribe(this.context, this.setTheme);
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { theme } = this.state;
return <Component theme={theme} {...this.props} />;
}
}
} |
published as |
What is the preferred method to map from the theme to props? For instance, if I wanted to pull stuff out of the theme and hand it to a MUI component, what would that look like? I'd like to see mapping from theme to props be a first-class operation. Something like:
Knowing that this lib will be embedded in
Maybe this already exists in this PR? |
i tried this minimalistic abstraction in react-jss and it fits quite nicely |
9b62882
to
b48e72f
Compare
```js | ||
import { themeListener } from 'theming'; | ||
|
||
function CustomWithTheme(Component) { |
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 would call it createThemedComponent
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.
LGTM
as a way to create custom High-Order Components which are supposed to react to or interact with theme updates.
as an example
withTheme
has been refactored and became very lightweight and simple: