|

Progressive Refinement and Generalization of Components | by Eden Ella | Jan, 2025

Since every “building block” in your application is a component, not all components are generic and reusable. Having said that, using Bit’s tools for collaboration, teams are empowered to progressively refine and generalize components to meet diverse requirements without duplicating efforts.

Components may start as very concrete but, through collaborative iterations, transform into more generic solutions that address emerging requirements.

In this blog, we’ll explore this workflow through a story involving two teams: “CRM” and “HR.” Their journey illustrates the power of Bit in enabling seamless component refinement and reuse.

Chapter 1: The HR Team Creates the “Employee Card”

The HR team is tasked with building a sleek “Employee Card” component to display employee details. This component is intended to be used in the company’s HR platform (maintained by the HR team).

The team uses foundational UI elements shared by the “Design team,” such as buttons and typography components, as the building blocks.

The “Employee Card” becomes an effective and well-tested component that meets the HR team’s requirements.

The component example in the ‘component page’ on Bit Platform

Chapter 2: The CRM Team Discovers the “Employee Card”

The CRM team needs a “Customer Card” component to display customer details and perform common actions. This component is intended to be used in the company’s CRM platform.

While exploring shared components on Bit Platform, they found the “Employee Card” to be an almost perfect match. However, certain actions and fields are not relevant for customer details.

For instance, the “Employee Card” displays the type of contract, while the customer card needs to display whether the customer is ‘online,’ i.e., browsing the company’s online shop or ‘offline.’

Components are only built to address current needs, even though they are shared by default. The “Employee Card” was built for that specific purpose, with hardcoded values and types:

// imports…

export interface EmployeeCardProps {
contractType: ‘full-time’ | ‘part-time’ | ‘intern’;
// …

See Also  Marocannoncer: The Ultimate Platform for Buying and Selling in Morocco

}

const contractTypeColors = {
‘full-time’: ‘success’,
‘part-time’:’warning’,
intern: ‘info’
};

export const EmployeeCard = ({
avatarUrl,
// …
}: EmployeeCardProps) => {
// …

return (

// …

// …
label={`${contractType.toUpperCase()}`}
color={contractTypeColors[contractType]}
/>
// …

);
};

Chapter 3: Refining and Generalizing the Component

Rather than starting from scratch, the CRM team decides to generalize the “Employee Card” to meet their needs. They propose changes that extend the card’s functionality while ensuring backward compatibility. This involves:

  • Custom Sections: The default section displaying customer-specific information can now be replaced using a more flexible API. In this case, the ‘chip’ that displays the contract type can be used to display other values with corresponding colors.
  • Backward Compatibility: If no custom values are provided, the card defaults to displaying customer-specific fields, preserving compatibility for existing use cases. In this case, developers using the component will be able to keep using the ‘contract type’ to display the employee’s contract type, just as before.

// imports …

const contractTypeColors = {
‘full-time’: ‘success’,
‘part-time’: ‘warning’,
intern: ‘info’,
} as const;

type ContractType = typeof contractTypeColors;
/**
* the custom color-map lables can be any string,
* but the color values can only be those supported by this component
*/
type ChipColorMap = Record;

/**
* Extend the prop type to allow for custom color maps and values
* instead of the default `contractTypeColors`
*/
export interface EmployeeCardProps {
contractType: T extends ContractType ? keyof ContractType : keyof T;
/**
* Nest the props for cutomization under `options` as these are
* expected to only be used by developers extending this component
* (rather than using it directly)
*/
options?: {
chipColorMap: T;
};
// …
}

export const EmployeeCard = ({
contractType,
options,
// …
}: EmployeeCardProps) => {
/**
* Use the custom color maps and values, if available
*/
const chipColorMap = options?.chipColorMap ?? contractTypeColors;

return (

label={`${contractType.toUpperCase()}`}
color={(chipColorMap as T)[contractType]}
/>
// …

);
};

The CRM team submits a change request (similar to a “Pull Request”) to the HR team via Bit Platform. This request includes detailed documentation of the changes and previews showcasing the card’s extended functionality.

See Also  Three Approaches To Amplify Your Design Projects — Smashing Magazine

# create a new ‘lane’ (analogous to git branches)
bit lane create enable-custom-chip-values

# create a ‘snap’ (analogous to git commit)
bit snap –message “enable the display of custom values instead of contract types”

# push the ‘snap’ to Bit Platform and build a pre-release package version of it
bit export

Note that the latest “Employee Card” version is now available to any project as a pre-released package. It is not confined to the current project.

While the change request is under review, the CRM team continues to build their “Customer Card” component as a composition of the latest (modified and generalized) version of the “Employee Card.”

import {
EmployeeCard,
type EmployeeCardProps,
} from ‘@learnbit-react/generalization.employee-card’;

const statusColors = {
online: ‘success’,
offline: ‘warning’,
} as const;

type Status = typeof statusColors;

export interface CustomerCardProps
extends Omit, ‘contractType’> {
status: keyof Status;
}

export function CustomerCard({
status,
// …
}: CustomerCardProps) {
return (

contractType={status}
fullName={fullName}
startDate={startDate}
avatarUrl={avatarUrl}
options={{
chipColorMap: statusColors,
}}
/>
);
}

The “Customer Card” dependencies page (shown in Bit’s Workspace UI) reveals the new dependency:

Chapter 4: Finalizing the “Customer Card”

Once the changes to the “Employee Card” are approved by the HR team, the CRM team can install and use the new release version of it instead of the current one:

# install using bit
bit install @acme/hr.employee-card@1.1.0

# install using npm
npm i @acme/hr.employee-card@1.1.0

The generalization of the “Employee Card” opens doors for other teams. For example:

  • Rapid Development: Teams can now create specialized card components for different use cases by building on the generalized API.
  • Consistency: All card components share a unified design language and behavior, ensuring a cohesive user experience.
  • Maintainability: Updates to the generalized card propagate to all dependent components, reducing duplication and effort. To learn more, see Ripple CI.
  • Source link

    Similar Posts