Decomposing UI Components
This example illustrates the complexities of decomposing a UI component into a series of subcomponents that would simultaneously allow:
- Redefining the appearance of each of the subcomponents.
- Introducing new business logic while keeping styling consistent.
- Inheriting the UX of the component while changing both UI and business logic.
The src
folder contains TypeScript code for the component and corresponding interfaces, while the index.js
file contains the compiled JavaScript (please refer to tsconfig.json
for compiler settings).
The index.html
page includes a live example for each of the discussed scenarios, with a live code playgrounds for further code exploration. Feel free to view it in your browser.
The following improvements to the code are left as an exercise for the reader:
-
Make all builder functions configurable through the
SearchBox
options (instead of subclassing components and overriding builder functions) -
Make a better abstraction of the
SearchBoxComposer
internal state. Make thefindOfferById
function asynchronous -
Make rendering functions asynchronous
-
Refactor
ISearchBoxComposer
as a composition of two interfaces: one facade for interacting with aSearchBox
, and another for communication with child components. -
Create a separate composer to bridge the gap between
OfferPanelComponent
and its buttons. -
Enhance the
SearchBox.search
method to return an operation status:public search(query: string): Promise<OperationResult>
Where OperationResult is defined as:
type OperationResult = | { status: OperationResultStatus.SUCCESS; results: ISearchResult[]; } | { status: OperationResultStatus.INTERRUPTED } | { status: OperationResultStatus.FAIL; error: any; };
With the enum:
export enum OperationResultStatus { SUCCESS = 'success', FAIL = 'fail', INTERRUPTED = 'interrupted' }
-
Implement pagination for the offer list (add pagination parameters to
ICoffeeApi.search
request and response, and load new items dynamically while scrolling the offer list). -
Create a separate
ISeachBoxInput
component for the input string and the search button. Add the ability to cancel ongoing requests and include a "skeleton" animation to indicate that search results are loading. -
Localize the component by making locale and a dictionary part of the
ISearchBox
options. -
Make options mutable by exposing an
optionChange
event and implementing theComposer
's reaction to relevant option changes. -
Parameterize all extra options, content fields, actions, and events.
-
Parametrize the markups of components either by:
-
Encapsulating them in Layout entities controlled through options. Create interfaces for each layout and a VisualComponent base class for entities with layouts. Inherit SearchBox, OfferListComponent, and OfferPanelComponent from this base class.
-
Rewriting components as React / ReactNative / SwiftUI / Android View components or as UI components for other platforms of your choice.
-