@whdigitalbuild/react-base-wh
v1.8.9
Published
A comprehensive React UI component library and template designed for Woh Hup applications. This package provides a standardized layout structure and a collection of reusable components built on top of Ant Design...
Readme
@whdigitalbuild/react-base-wh
A comprehensive React UI component library and template designed for Woh Hup applications. This package provides a standardized layout structure and a collection of reusable components built on top of Ant Design...
Installation
Install the package:
npm install @whdigitalbuild/react-base-wh
# or: pnpm add @whdigitalbuild/react-base-whThe
/mf-sharedsubpath (see Module Federation) is available from v1.8.0 onwards.
Peer Dependencies
Ensure the following are installed in your app so they can be shared as singletons under Module Federation:
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"antd": "^5.4.6",
"@ant-design/icons": "^5.0.1",
"dayjs": "^1.11.0"
}v1.8.0 breaking-ish change:
momentwas removed in favour ofdayjs(aligned with Ant Design 5, which usesdayjsinternally). Nothing to do unless your app relied onmomentbeing pulled in transitively via this package.
Module Federation (shared config)
For apps built with Module Federation (Rsbuild), this package is the single source of truth for shared-library versions. Import the createMfShared factory into your rsbuild.config instead of hand-writing the shared block:
// rsbuild.config.ts — REMOTE
import { pluginModuleFederation } from "@module-federation/rsbuild-plugin";
import { createMfShared } from "@whdigitalbuild/react-base-wh/mf-shared";
pluginModuleFederation({
name: "my_remote",
filename: "remoteEntry.js",
exposes: { "./App": "./src/export-app" },
shared: createMfShared({ isHost: false }), // remote → lazy
});// rsbuild.config.ts — HOST (e.g. IddApp_Main)
shared: createMfShared({ isHost: true }); // host → react / react-dom / react-query loaded eagercreateMfShared({ isHost }) returns a singleton config for: react, react-dom, @tanstack/react-query + @tanstack/query-core (both required, or the cache duplicates), zustand, dayjs, lodash, ag-grid-community / -enterprise / -react, antd, @ant-design/icons, and @whdigitalbuild/react-base-wh itself. To change a standard version fleet-wide, edit src/mf-shared.ts here and bump the package version.
The clean
@whdigitalbuild/react-base-wh/mf-sharedimport resolves without anexportsmap (via rootmf-shared.js/mf-shared.d.tsre-export stubs), so it works under classicmoduleResolution: nodeas well as bundler resolution.
v1.8.2:
react-router-domis intentionally NOT in the shared list.@module-federation/rspackauto-detects@module-federation/bridge-react(present in most of the fleet's apps) and aliasesreact-router-dom$to its own wrapper — it throws a hard build error (React-router-dom cannot be set to shared after react bridge is used) ifreact-router-domis also declared inshared. If your app does not use@module-federation/bridge-reactand you wantreact-router-domshared as a singleton, add it back yourself:{ ...createMfShared({ isHost }), 'react-router-dom': { singleton: true, requiredVersion: '^6.3.0' } }.
Usage
Main Template (MainWH)
MainWH is the primary layout component that provides the standard structure for applications, including a top bar and a collapsable left sidebar with project selection, search, and favourites.
import React from "react";
import { MainWH } from "@whdigitalbuild/react-base-wh";
const App = () => {
const routes = [
{
path: "/home",
name: "Home",
icon: <HomeOutlined />, // from @ant-design/icons
component: HomePage,
},
// ... define other routes
];
const projects = [
{ id: "All", name: "All", isAllProject: true, isFavorite: true },
{ id: "project-a", name: "Project A", isActive: true, isFavorite: true },
{ id: "project-b", name: "Project B", isFavorite: false },
{ id: "project-c", name: "Project C", isFavorite: false },
];
return (
<MainWH
routes={routes}
projects={projects}
slidesToShow={5}
showSearchProject={true}
onChangeNavigate={(route) => console.log("Navigate to:", route)}
onChangeProjectSelected={(project) => console.log("Selected:", project)}
onChangeFavoriteProject={(project) =>
console.log("Favorite toggled:", project)
}
onSearchChange={(e) => console.log(e.target.value)}
>
<div>
{/* Your Page Content Goes Here */}
<h1>Welcome to the Application</h1>
</div>
</MainWH>
);
};
export default App;MainWH Props
| Prop | Type | Description |
| ------------------------- | --------------------- | ---------------------------------------------------------------------- |
| children | ReactNode | The main content to be rendered within the layout body. |
| routes | any[] | Array of route objects for the sidebar navigation. |
| projects | any[] | List of projects to display in the project selector. |
| disableProjects | any | Props to disable project selection if needed. |
| searchText | any | Value for the top bar search input. |
| searchOptions | any[] | Options for the search input if using a select/autocomplete style. |
| leftComponent | ReactNode | Custom component to render on the left side of the top bar. |
| rightComponent | ReactNode | Custom component to render on the right side of the top bar. |
| slidesToShow | number | Number of project items visible at once in the sidebar carousel. |
| showSearchProject | boolean | Whether to show the search button in the left sidebar. |
| hiddenSave | boolean | If true, hides the save button in the top bar. Default: false |
| onChangeNavigate | (props: any) => any | Callback when a navigation item is clicked. |
| onChangeProjectSelected | (props: any) => any | Callback when a project is selected. Returns the selected project object. |
| onChangeFavoriteProject | (props: any) => any | Callback when a project's favourite status is toggled. |
| onSearchChange | (props: any) => any | Callback when search input changes. |
| onClickSearch | (props: any) => any | Callback when the search button is clicked. |
| onClickSave | (props: any) => any | Callback when the save button in the top bar is clicked. |
| styleForTopBar | CSSProperties | Custom styles for the top bar. |
| styleForLeftSideBar | CSSProperties | Custom styles for the left sidebar. |
| styleForBody | CSSProperties | Custom styles for the body container. |
Project Object Shape
| Property | Type | Description |
| -------------- | --------- | -------------------------------------------------------------------- |
| id | string | Unique identifier for the project. |
| name | string | Display name (falls back to id if not provided). |
| isAllProject | boolean | Marks as the "All" project (always shown first, cannot unfavourite). |
| isActive | boolean | If true, this project is selected by default on mount. |
| isFavorite | boolean | If true, this project starts as a favourite (shown before others). |
Using showSearchProject with Favourite Toggle
When showSearchProject is enabled, you need to handle the favourite toggle by calling your API and updating the local project list. Here is a complete example:
// API function
export async function UpdateFavoriteProjectForUser(
projectId: string,
): Promise<unknown> {
const response = await axiosClientIdd.post(
`/user-favorite-projects/update-favorite-project-for-user`,
{
projectId: projectId,
appName: "[YOUR APP NAME]",
},
);
return response.data;
}// Callback in your component
const [projectsFilter, setProjectsFilter] = useState<IProject[]>(projects);
const onChangeFavoriteProject = useCallback(
async (project: IProject) => {
try {
await UpdateFavoriteProjectForUser(project.id);
setProjectsFilter(
projectsFilter?.map((p: any) =>
p.id === project.id ? { ...p, isFavorite: !p.isFavorite } : p,
),
);
} catch (error) {
console.error("Update favorite projects failed:", error);
}
},
[projectsFilter, setProjectsFilter],
);
// Usage
<MainWH
projects={projectsFilter}
showSearchProject={true}
onChangeFavoriteProject={onChangeFavoriteProject}
// ...other props
/>;Left Sidebar Features
The left sidebar includes:
- Route Navigation: Clickable items defined via
routesprop. - Project Carousel: Vertical carousel with slide animation (Up/Down buttons) to browse projects.
- Search Panel: A Popover panel (toggled via search button) with text search, favourites section, and all projects section.
- Favourites: Projects with
isFavorite: trueare shown first. Users can toggle favourites via the star icon in the search panel. - Divider: A visual separator between favourite and non-favourite projects in the carousel.
Left Sidebar Component Structure
The left sidebar implementation is split into focused files under src/components/template/left_panel:
| File | Responsibility |
| --------------------- | ------------------------------------------------------------------------------------ |
| LeftSideBarWH.tsx | Main container. Owns active project/favourite state and wires callbacks. |
| RouteItem.tsx | Renders a single route navigation item with tooltip and active styling. |
| ProjectSwitcher.tsx | Renders the project area, including search popover, result rows, favourite toggles, and carousel. |
| types.ts | Shared TypeScript props and project helper types for the sidebar. |
ProjectSwitcher.tsx keeps its internal project subcomponents in the same file and uses a shared ProjectBaseProps interface for common project props.
TopBar Components
The package exports specialized components for the top bar actions and filters.
import {
SearchInputWH,
SearchSelectOption,
DateRangePickerWH,
StatusFilterWH
} from '@whdigitalbuild/react-base-wh';
// Example: Using the Search Input
<SearchInputWH
placeholder="Search..."
onSearch={(value) => console.log(value)}
/>
// Example: Using the Date Range Picker
<DateRangePickerWH
onChange={(dates) => console.log(dates)}
/>Available TopBar Components
Inputs & Filters:
SearchInputWH: A styled search input field.SearchSelectOption: A search component with dropdown options.DateRangePickerWH: A date range picker based on Ant Design.StatusFilterWH: A dropdown or filter component for status selection.
Icons:
AddIconWHSaveIconWHUploadIconWHFileExcelIconWHHighlightIconWHGroupExpandedIconWHHansonTableIConWH
External Dependencies
The left sidebar uses Tabler Icons via CDN. Add the following to your index.html:
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/tabler-icons.min.css"
/>License
MIT © wohhupwebdeveloper
