diff --git a/oeps/oep-0028-content-theming-in-react.rst b/oeps/oep-0028-content-theming-in-react.rst new file mode 100644 index 000000000..fa43c6de4 --- /dev/null +++ b/oeps/oep-0028-content-theming-in-react.rst @@ -0,0 +1,282 @@ +================================== +OEP-0028: Content Theming in React +================================== + ++-----------------+----------------------------------------------------------------+ +| OEP | :doc:`OEP-0028 ` | +| | | +| | | +| | | +| | | ++-----------------+----------------------------------------------------------------+ +| Title | Content Theming in React | ++-----------------+----------------------------------------------------------------+ +| Last Modified | 2018-08-24 | ++-----------------+----------------------------------------------------------------+ +| Authors | Braden MacDonald , | +| | Taranjeet Singh | ++-----------------+----------------------------------------------------------------+ +| Arbiter | | ++-----------------+----------------------------------------------------------------+ +| Status | Draft | ++-----------------+----------------------------------------------------------------+ +| Type | Architecture | ++-----------------+----------------------------------------------------------------+ +| Created | 2018-08-17 | ++-----------------+----------------------------------------------------------------+ +| `Review Period` | 2018-08-17 - 2018-09-02 | ++-----------------+----------------------------------------------------------------+ + +Abstract +------- + +OEP-0023 [1] addresses the styling part of a theming system based on React. This proposal adds guidelines for content modification to the React based theming system. + +Context +------- + +Open edX instances frequently wish to customize not only the colors and styles of the Open edX UI, but also to add, remove, and modify significant parts of the UI to suit their use cases and branding. Doing this in a way that is understandable, clean, and easy to maintain can be a challenge unless the original UI is designed with this in mind. + +Another pain of theming systems is providing access to unrelated data to any component. It becomes important to make commonly-used data globally available to all components. + +Decision +-------- + +* We will build two types of components: + + 1. Customizable components which will be composed of others components + + 2. Internal or non-customizable components which will contain HTML and certain logic + +* We will build small modular components which will be non-customizable, stateless, contain HTML, and certain logic. A component will be defined as non customizable if it is only concerned with how things look and does not maintain any state of its own. In case they do, it will be UI state rather than data. They will be generally written as functional components, unless they need any data state or any lifecycle hook. They will receive data and callbacks via props and will have no dependencies on the rest of application. We can see an example of a smaller component ``SiteLogo``, which will later be used in a customizable component ``_Header``. + +.. code-block:: js + + const SiteLogo = (props) => { + return ( + {props.altText} + ); + } + +* We will build the complete UI out of various customizable components. These customizable components will contain small modular components, little or no HTML nor logic. A component will be termed as customizable if it contains various non customizable and reusable components. Customizable components will be concerned with how the things work and will generally maintain state. They will collect data and define callbacks, which will be passed to non customizable components via props. We can see an example of a customizable component called the ``_Header`` component, which is formed by the composition of ``SiteLogo``, ``MainNav`` and ``UserAvatar`` component. + +.. code-block:: js + + class _Header extends React.PureComponent { + render() { + return ( +
+ {this.props.logo ? this.props.logo: } + + +
+ ); + } + } + +* We will specify which components are customizable and document whether the customization is available via custom props or overriding superclass methods. We will announce breaking changes [2] if any changes are made to customizable components. Users will still be able to override components which are not explicitly marked as customizable, but edX will provide no backwards compatibility guarantees for them. + +* When creating any complex UI Component we will try to break it down into the smallest reusable components, and build the component out of these small reusable pieces via composition/inheritance. We can see this through an example where we have a theme, which has several components for a default theme. + +.. code-block:: js + + // Customizable Header + class _Header extends React.PureComponent { + render() { + return ( +
+ {this.props.logo ? this.props.logo: } + + +
+ ); + } + } + + // Customizable Main Navigation Area + class _MainNav extends React.PureComponent { + render() { + return ( + + Home + + {this.extraNavLinks} + + ); + } + get extraNavLinks() { return []; } + } + // Internal MainNavWrapper - not meant to be modified in most cases + class _MainNavWrapper extends React.PureComponent { + render() { + return ( +
+
    + {React.Children.map(this.props.children, (child) => (child ?
  • {child}
  • : null))} +
+
+ ) + } + } + + // Default Theme: + export const Header = _Header; + export const MainNav = _MainNav; + export const MainNavWrapper = _MainNavWrapper; + +Now if we want to customize our ``_Header`` component, and use ``MyCustomAnimatedLogoWidget`` instead of ``SiteLogo``, we can do it as + +.. code-block:: js + + const MyThemedHeader = (props) => { + return (
} />) + } + + // Custom theme: + export const Header = MyThemedHeader; + + +* We will provide support via props to control parts of the component when composing components. We can see this by an example of ``Button`` element + +.. code-block:: js + + class Button extends React.PureComponent { + render() { + return