There's a frequent usecase with javascript libraries where you want to decorate your components with higher order components.
For example, the material-ui library includes a styling higher-order component withStyles
.
In javascript, you would do
import { withStyles } from '@material-ui/core';
const styles = {
example: {
padding: 8
}
}
const SomeComponent = ({classes}) => <div className={classes.example}>I'm a component</div>;
export default withStyles(SomeComponent);
How can you achieve the same in Hyperstack?
First off looks like there is an issue that you have to patch. This will be fixed in the next point release: Just add this method to your Hypercomponent
base class (app/hyperstack/components/hypercomponent.rb
)
def self.to_n
Hyperstack::Internal::Component::ReactWrapper.create_native_react_class(self)
end
Now if you have the following styles:
MY_STYLES = {root: {backgroundColor: 'red'}}
and a component that you want to style:
class StyleTest < HyperComponent
param :some_param
param :classes
render do
DIV(class: classes[:root]) { some_param }
end
end
You can do so like this:
class StyledTest1 < HyperComponent
imports `Mui.withStyles(#{MY_STYLES.to_n})(#{StyleTest.to_n})`
end
What is happening is we are dropping out to JS using the backticks and calling Mui.with_styles
directly and passing it MY_STYLES
(just like in the MUI doc example). The to_n
converts from a Ruby Hash to JS object. (When passing params to components this is automatic, but not so with simple function calls.)
Then we call the resulting HOC with our StyleTest
class (also calling to_n
to convert from a Ruby class to a simple JS class.)
Finally, we import it back into a Hyperstack component class.
That is a little more work than I like so we can just add a handy helper method to our HyperComponent
class:
class HyperComponent
include Hyperstack::Component
include Hyperstack::State::Observable
param_accessor_style :accessors # this is now the prefered param style
# patch for issue: https://github.com/hyperstack-org/hyperstack/issues/153
def self.to_n
Hyperstack::Internal::Component::ReactWrapper.create_native_react_class(self)
end
# our helper macro:
def self.add_styles(style, opts = {})
imports `Mui.withStyles(#{style.to_n}, #{opts.to_n})(#{superclass.to_n})`
end
end
Now we can add styles like this:
class StyledTest2 < StyleTest
add_styles MY_STYLE
end
and now we have a new Component Class with our style in it.
For example:
class App < HyperComponent
render do
DIV do
StyledTest1(some_param: 'test 1')
StyledTest2(some_param: 'test 2')
end
end
end