Decomposing UI Components
This is the example illustrating complexities of decomposing a UI component into a series of subcomponents that would simultaneously allow to:
- Redefining the appearance of each of the subcomponent
- 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 a TypeScript code for the component and corresponding interfaces, and the index.js file contains the compiled JavaScript (check tsconfig.json for compiler settings).
The index.html page includes a living example for each of the discussed scenarios, with links pointing to external playgrounds to work through the code if needed. 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 options
-
Create a separate composer to close the gap between
OfferPanelComponentand its buttons -
Add returning an operation status from the
SearchBox.searchmethod:public search(query: string): Promise<OperationResult>Where
type OperationResult = | { status: OperationResultStatus.SUCCESS; results: ISearchResult[]; } | { status: OperationResultStatus.INTERRUPTED } | { status: OperationResultStatus.FAIL; error: any; }; export enum OperationResultStatus { SUCCESS = 'success', FAIL = 'fail', INTERRUPTED = 'interrupted' } -
Make an offer list paginated (implying adding pagination parameters to
ICoffeeApi.searchrequest and response, and dynamically loading new items while scrolling the offer list) -
Make the input string and the search button a separate
ISeachBoxInputcomponent. Add an ability to cancel the ongoing request. Add a “skeleton” animation to indicate that search results are being loading. -
Localize the component, making a locale and a dictionary a part of the
ISearchBoxoptions. -
Parametrize
contextparameter forOfferListComponentandOfferPanelComponent. Make it comprise only events needed by the component, so thatISearchBoxComposerwould be implementingIOfferListComponentContextandIOfferPanelComponentContextinterfaces. -
Make
optionsmutable (expose anoptionChangeevent and implementComposers's reaction to relevant option changes). -
Parametrize all extra options, content fields, actions and events.
-
Parametrize markups of components, either by:
- Incapsulating them in some
Layoutentities controlled through options. Create interfaces for each of the layouts. Create aVisualComponentbase class for entities that have a layout and inheritSearchBox,OfferListComponentandOfferPanelComponentfrom it, or - Rewriting components as React / ReactNative / SwiftUI / Android View component or as a UI component for any other platform of your choice.
- Incapsulating them in some