Adding Sandstone Support
In the previous part of Hello Enact!, we covered the benefits of stateless components
and introduced the kind()
factory. In this final part, we’ll discuss Higher-order Components
(HoCs) and how the @enact/sandstone/ThemeDecorator
HoC can be used to quickly and easily add Sandstone styling and features to
our application.
Higher-order Components
In the simplest sense, Higher-order Components (HoCs) are functions that accept React components and return React components. They are useful for encapsulating common behavior, markup, and property transformations, which can later be applied to other components as needed.
Enact provides several HoCs, as well as a factory method, @enact/core/hoc
, to create
your own. All Higher-order Components within Enact support an optional configuration object to
customize their behavior. The first HoC we’ll encounter is ThemeDecorator.
If you are coming from a background in frameworks that use mixins, Higher-order Components may sound similar. While they are conceptually similar, HoCs provided better encapsulation, resulting in fewer clashes between the implementations of disparate features.
Dan Abramov has offered a good perspective on the change to React to deprecate mixin support that may be informative.
ThemeDecorator
@enact/sandstone/ThemeDecorator
is a Higher-order Component that adds sandstone styling and
several add-ons that are commonly used by sandstone applications: multi-resolution support,
internationalization support, and Spotlight support.
Sandstone Styling
The first change you’ll notice after applying ThemeDecorator is the color and font changes
which come from the .sand
CSS class. Since Sandstone apps are designed to run full screen,
ThemeDecorator also applies the global utility class .enact-fit
, which uses absolute
positioning to fill the available space.
Multi-Resolution Support
Since Sandstone targets televisions that have different resolutions (720p, 1080p, 4k, and beyond!),
Enact provides a set of tools to enable scaling applications for a consistent layout across
resolutions. One part of the solution is less-plugin-resolution-independence
,
a LESS plugin that adapts pixel measurements to relative measurements. The second part is
@enact/ui/resolution
which provides the capabilities to set the correct base size for the current
resolution as well as utilities to work with resolution independent measurements in components.
On top of this, Sandstone establishes a set of screen types for our supported television resolutions that are configured for the application by ThemeDecorator.
Internationalization Support
In order to support delivery of applications to multiple locales, Enact integrates with the iLib
internationalization library through our own module, @enact/i18n
. This module provides the glue
between the two code bases to correctly load locale resources and expose the results within an Enact
app.
ThemeDecorator uses I18nDecorator, a HoC from the @enact/i18n
module, to add the appropriate CSS
classes for the locale. I18nDecorator is also responsible for passing the rtl
flag and
updateLocale
method to the app via React’s context.
Spotlight Support
Sandstone applications must support 5-way navigation and selection to allow them to be used with only a
remote control. The @enact/spotlight
module provides the logic to support this and it is bootstrapped
into a Sandstone app via ThemeDecorator and the SpotlightRootDecorator.
All Sandstone components that should be navigable via 5-way already include the necessary support out of the box. If you build your own components, you may need to add your own spotlight support using Spottable from
@enact/spotlight/Spottable
.
Updating App.js
To use a Higher-order Component you’ve imported, pass another component (or DOM node name) to the
HoC, optionally including the configuration object. For ThemeDecorator, you can opt out of
internationalization, resolution independence, or spotlight support by setting i18n
, ri
, or
spotlight
respectively to false
. For our sample application, we will use the defaults.
import ThemeDecorator from '@enact/sandstone/ThemeDecorator';
const AppBase = kind({
// omitted for brevity
});
const App = ThemeDecorator(AppBase);
export default App;
export {
App,
AppBase
};
Note: We’ve renamed the stateless component from
App
toAppBase
. The Enact framework uses this convention to distinguish between stateless components and their wrapped or stateful versions. If you need to use the stateless version of a component, it will be exported as a named export withBase
appended to the name.You may find this convention useful with your components so that module exports are predictable.
Conclusion
This section introduced ThemeDecorator, which adds key styling and features for applications targeting the TV. If you have been following along, you now have a basic Sandstone app welcoming you to Enact.
We won’t take this application any further but will use the same foundation to build out the next
sample, Kitten Browser, a basic image browsing app that will introduce
configuring components, handling events, managing data, and the components available in @enact/ui
and @enact/sandstone
.