Implementation of Typescript-based React Library

“Contributing to the Applications gives me a sense of purpose and value.”

This document explains how to integrate the Design Library into a React application using Bitbucket as the package hosting platform. The integration process consists of creating new components in the UI library, setting up a deployment pipeline, consuming the design library, and updating it to newer versions.

The Checkbox component is one of the components in the UI library. It accepts the following props:

CheckboxProps.tsx
checked?: boolean;
  disabled?: boolean;
  id: string;
  errorMessage?: string;
  label: string | React.ReactElement;
  legend?: string;
  name?: string;
  onChange?: (value: boolean) => void;
  readOnly?: boolean;
  required?: boolean;
  size?: 'default' | 'large';
  successMessage?: string;
  type?: 'checkbox' | 'radio';
  validationState?: 'error' | 'warning' | 'success';
  value?: string;
  warningMessage?: string;

React App folder

//React App
src/App.js
 
import './App.css';
import {Button} from "design-library"
function App() {
  return (
	<div className='App'>
  	<Button type="primary" />
  	<Button type="secondary" />
	</div>
  );
}
 
export default App;

Importing the checkbox component now. Here design-library is my <package name>

import {Checkbox} from "new-library"

This is how our checkbox will look like when we pass “checkbox” as the type prop

(<checkbox type="checkbox" label="Agree"/>)

Similarly, this is how our Radio button will look when we pass “radio” as the type prop

(<Radio type="radio" label="Agree" />)

Our reusable checkbox Component uses Custom CSS to style our checkbox and radio button.

UI Library files

CheckboxRadio.tsx

//ui library
import React, { useEffect, useState } from 'react';
import ValidationMessage from '../ValidationMessage/ValidationMessage';
import { CheckboxRadioPropTypes, CheckboxRadioProps } from './CheckboxProps';
import './Checkbox.scss';
import { Size } from '../../constants/enums';
 
const CheckboxRadio = ({
  checked = false,
  disabled = false,
  errorMessage = '',
  id,
  value,
  label = '',
  onChange,
  required = false,
  size = Size.Default,
  successMessage,
  type,
  readOnly = false,
  validationState,
  warningMessage,
  ...restProps
}: CheckboxRadioProps) => {
  const [isChecked, setIsChecked] = useState(checked);
 
  useEffect(() => {
	setIsChecked(checked);
  }, [checked]);
 
  const handleCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
	if (onChange && !readOnly) {
  	setIsChecked(event.target.checked);
  	return onChange(event.target.checked);
	}
  };
 
  const getCheckboxClassName = () => {
	let className = `ct-${type}`;
 
	if (size === Size.Large) {
  	className = ` ct-${type}--large `;
	}
 
	if (validationState) {
  	className += ` ct-checkbox--${validationState}`;
	}
 
	return className;
  };
 
  return (
	<div>
  	<div className="ct-tabFocus checkbox-container">
    	<input
      	aria-disabled={disabled}
      	aria-describedby={validationState ? `${validationState}` : undefined}
      	aria-invalid={validationState === 'error' ? 'true' : undefined}
 	     aria-readonly={type === 'checkbox' && readOnly ? 'true' : undefined}
      	aria-required={required}
      	checked={isChecked}
      	className={getCheckboxClassName()}
      	disabled={disabled}
      	id={id}
      	value={value}
      	onChange={handleCheckboxChange}
      	readOnly={readOnly}
      	required={required}
      	type={type}
      	{...restProps}
    	/>
    	<label htmlFor={id} className={`ct-text-tertiary-10 ${size === Size.Large ? 'ct-body--tertiary' : 'ct-font-lg'}`}>
      	{label}
    	</label>
  	</div>
  	{validationState && (
    	<ValidationMessage
      	id={`${id}-${validationState}`}
      	errorMessage={errorMessage}
      	successMessage={successMessage}
      	warningMessage={warningMessage}
      	validationState={validationState}
    	/>
  	)}
	</div>
  );
};
 
CheckboxRadio.propTypes = CheckboxRadioPropTypes;
export default CheckboxRadio;

Checkbox.tsx

import './Checkbox.scss';
import React from 'react';
import CheckboxRadio from './CheckboxRadio';
import { CheckboxRadioPropTypes, CheckboxRadioProps } from './CheckboxProps';
 
type CheckboxProps = Omit<CheckboxRadioProps, 'type'>;
 
const Checkbox = (props: CheckboxProps) => {
  return <CheckboxRadio {...props} type="checkbox" />;
};
 
const { ...RestCheckboxProps } = CheckboxRadioPropTypes;
Checkbox.propTypes = RestCheckboxProps;
 
export default Checkbox;

Radio.tsx

import './Checkbox.scss';
import React from 'react';
import CheckboxRadio from './CheckboxRadio';
import { CheckboxRadioPropTypes, CheckboxRadioProps } from './CheckboxProps';
 
type RadioProps = Omit<CheckboxRadioProps, 'type'>;
 
const Radio = (props: RadioProps) => {
  return <CheckboxRadio {...props} type="radio" />;
};
 
const { ...RestCheckboxProps } = CheckboxRadioPropTypes;
 
Radio.propTypes = RestCheckboxProps;
 
export default Radio;

In UI Library we are accepting type and title.

Depending upon the Type, we are changing the class name. In this way, we can make a reusable checkbox component.

webpack.config.js

//ui library
 
const path = require('path')
 
module.exports = {
	entry: "./src/index.ts",
	mode: "production",
	output: {
    	path: path.resolve(__dirname, "dist"),
    	filename: "index.js",
    	libraryTarget: "umd",
    	library: "make-new-library"
	},
	module: {
    	rules: [
        	{
       	     test: /\\.css/,
            	use: ["style-loader", "css-loader"]
        	},
        	{
            	test: /\\.tsx?$/,
            	use: ["babel-loader", "ts-loader"],
            	exclude: /node_modules/,
        	}
    	]
    },
	resolve: {
    	extensions: [".tsx", ".ts"]
	},
	externals: {
    	react: "react"
	}
}

tsconfig.json

{
  "compilerOptions": {
	"target": "es5",                             	
    "jsx": "react",                            	
    "module": "commonjs",                           	
    "esModuleInterop": true,                        	
    "forceConsistentCasingInFileNames": true,       	
    "strict": true,                                 	
    "skipLibCheck": true	                             
  }
}

The provided tsconfig.json file contains important configuration options for a TypeScript project. Here’s a breakdown of each option:

  • “target”: “es5”: Set the JavaScript language version for emitted JavaScript and include compatible library declarations. Specifies the JavaScript version to target for the emitted code. In this case, it targets ECMAScript 5 (ES5) compatibility.
  • “jsx”: “react”: Specify what JSX code is generated. Specifies the syntax for JSX code. This is set to “react” to indicate that the project is using React.
  • “module”: “commonjs”: Specify what module code is generated. Specifies the module code generation. It uses CommonJS modules, which are compatible with Node.js and many bundlers.
  • “esModuleInterop”: true: Emit additional JavaScript to ease support for importing CommonJS modules. This enables ‘allowSyntheticDefaultImports’ for type compatibility. Enables interoperability between CommonJS and ES modules by emitting additional JavaScript code. This simplifies importing CommonJS modules in TypeScript.
  • “forceConsistentCasingInFileNames”: true: Ensure that the casing is correct in imports. Ensures consistent casing for import statements, helping to catch potential file naming errors.
  • “strict”: true: Enable all strict type-checking options. Enables all strict type-checking options in TypeScript, enforcing stronger type safety and catching more potential errors.
  • “skipLibCheck”: true: Skip type checking all .d.ts files. Skips type checking of declaration files (.d.ts files) in the project, which can help improve build times for larger projects.

Creating New Components and Deployment Pipeline

1. Develop New Components: When new components are created in the UI library, they are committed to the repository.

2. Trigger Pipeline: Upon committing new components, an automated pipeline is triggered. This pipeline generates bundled files stored in the ‘dist’ folder.

3. Separate Bitbucket Repository: The bundled files are pushed to a separate Bitbucket repository

4. dedicated to hosting the Design Library.

Hosting UI Library

Updating the Design Library in the React Application

When a new version of the Design Library needs to be integrated into the React application, follow these steps:

1. Remove CurrentDesign Library

Remove the existing version of the Design Library package using the following command:

npm uninstall design-library

or

yarn remove design-library

2. Add Latest Version: Add the latest version of the Design Library package by running the following  command:

npm install git+https://bitbucket.org/designsystem/design-library.git

or

yarn add git+https://bitbucket.org/designsystem/design-library.git

These steps allow the React application to integrate and update the Design Library smoothly and consistently. The Design Library provides uniform styling and user interface components for the application.

If you want to host a library publicly, use npm. Otherwise, use private repositories like git.

Host:

To link my UI library with the React app locally, use these commands:

Npmyarn
To linknpm linkyarn link
To unlinknpm unlinkyarn unlink
Ui-libraryReact App
To linknpm linknpm link <package name>
To unlinknpm unlinknpm unlink <package name>

Using the Design Library

To use the Design Library in the React application hosted on Bitbucket, follow these steps:

Since the design library is hosted on Bitbucket, we need to do some extra steps to access it in React

1. Add the Design Library Package: Run the following command to add the Design Library package to your React application:

 npm install add git+https://bitbucket.org/designsystem/design-library.git

   or

 yarn add git+https://bitbucket.org/designsystem/design-library.git

 2. Import CSS Styles: Import the design library’s CSS file in your main.tsx file to ensure consistent styling across the application:

import React from 'react'

import ReactDOM from 'react-dom/client'

import App from './App.tsx'

import './index.css'

import 'design-library/cjs/index.css'

ReactDOM.createRoot(

  document.getElementById('root')!).render(

   <React.StrictMode>

       <App />

  </React.StrictMode>,)

3. Copy Assets Folder: Copy the ‘assets’ folder from the UI library repository’s ‘src/assets’ directory into the ‘public’ folder of your React application. This ensures any assets used by the components are accessible.

4. Import Components: Import components from the Design Library as needed in your application’s code:

import {Checkbox} from 'design-library';

function App() {

  return (

      <Checkbox label="Agree">

      </Checkbox>  

);}

export default App;

Conclusion

In conclusion, this document has explained how to integrate the Design Library into a React application using Bitbucket as the package hosting platform. The integration process involves developing new components in the UI library, setting up a deployment pipeline, consuming the design library, and updating it to newer versions. By following these steps, the React application can benefit from the consistent styling and user interface components provided by the Design Library.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top