From 95692b2bcfbbf900e95258473184d787eb6a1aff Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Wed, 1 Jul 2026 17:27:53 +0700 Subject: [PATCH] feat: add ActionTools component documentation and update navigation links --- apps/docs-dev/src/.vitepress/config.mts | 1 + apps/docs-dev/src/packages/core-i18n/index.md | 73 +++++-- apps/docs-dev/src/packages/ui/ACTION-TOOLS.md | 183 ++++++++++++++++++ apps/docs-dev/src/packages/ui/index.md | 6 + 4 files changed, 245 insertions(+), 18 deletions(-) create mode 100644 apps/docs-dev/src/packages/ui/ACTION-TOOLS.md diff --git a/apps/docs-dev/src/.vitepress/config.mts b/apps/docs-dev/src/.vitepress/config.mts index 3e884b5..e114bac 100644 --- a/apps/docs-dev/src/.vitepress/config.mts +++ b/apps/docs-dev/src/.vitepress/config.mts @@ -52,6 +52,7 @@ const config = withMermaid( items: [ { text: 'Overview', link: '/packages/ui/' }, { text: 'App Layout', link: '/packages/ui/CORE-APP-SHELL' }, + { text: 'Action Tools', link: '/packages/ui/ACTION-TOOLS' }, { text: 'Form Primitives', link: '/packages/ui/FORM-COMPONENTS' }, ], }, diff --git a/apps/docs-dev/src/packages/core-i18n/index.md b/apps/docs-dev/src/packages/core-i18n/index.md index 26e72ad..23d791e 100644 --- a/apps/docs-dev/src/packages/core-i18n/index.md +++ b/apps/docs-dev/src/packages/core-i18n/index.md @@ -114,10 +114,42 @@ apps/web/src/apps/modules/booking/ └── en/booking.json ``` -### Lazy Loading & Type Safety -Register the namespace when the component mounts. To get native TypeScript autocomplete for nested keys (e.g., `header.title`), augment the global `react-i18next` types. +### Namespace Registration & Context + +To prevent unnecessary React re-renders and ensure dictionaries are loaded before the first paint, translations are registered at the module scope using `registerModuleNamespace`. + +**1. Register the Namespace in the Module Factory:** + +Call `registerModuleNamespace` at the top level of your module factory (e.g., `index.tsx`). This function is idempotent and safe to call outside the React render cycle. The namespace provided must match the `translationNamespace` defined in your module configuration. + +```tsx +// apps/web/src/apps/modules/booking/presentation/factory/index.tsx +import { EnterpriseModuleProvider } from '@repo/ui/foundations'; +import { registerModuleNamespace } from '@repo/core-i18n'; +import { BookingModuleConfig } from '../../domain/constants'; + +import bookingId from '../locales/id/booking.json'; +import bookingEn from '../locales/en/booking.json'; + +// Called once at import time — safe, idempotent, outside React render cycle. +registerModuleNamespace(BookingModuleConfig.translationNamespace, { + id: bookingId, + en: bookingEn, +}); + +export default function BookingModule() { + return ( + + {/* Routes and Pages */} + + ); +} +``` + +**2. Augment Types for Autocomplete:** + +To get native TypeScript autocomplete for nested keys (e.g., `header.title`), augment the global `react-i18next` types. -**1. Augment Types:** ```ts // apps/web/src/types/i18next.d.ts import 'react-i18next'; @@ -132,26 +164,31 @@ declare module 'react-i18next' { } ``` -**2. Use in Component:** +**3. Consume in Components:** + +Inside your pages and components, use `useEnterpriseModuleTranslationContext()` instead of the raw `useTranslation` hook. The context automatically scopes the `t` function to your module's namespace and the global `common` namespace. + +> [!WARNING] +> **Best Practice:** Do not hardcode the module namespace prefix (e.g., `t('booking:header.title')`) when using `useEnterpriseModuleTranslationContext`. The provider already scopes it. Simply use `t('header.title')`. You can still access global keys using the common prefix: `t('common:edit')`. + ```tsx -import { useEffect } from 'react'; -import { i18n, useTranslation } from '@repo/core-i18n'; -import bookingId from '../locales/id/booking.json'; -import bookingEn from '../locales/en/booking.json'; +// apps/web/src/apps/modules/booking/presentation/pages/booking.page.index.tsx +import { Title } from '@repo/ui/components'; +import { useEnterpriseModuleTranslationContext } from '@repo/ui/foundations'; -export default function BookingFeature() { - const { t } = useTranslation(['common', 'booking']); +export default function BookingPageIndex() { + const { t } = useEnterpriseModuleTranslationContext(); - useEffect(() => { - i18n.addResourceBundle('id', 'booking', bookingId, true, false); - i18n.addResourceBundle('en', 'booking', bookingEn, true, false); - }, []); - - return

{t('booking:header.title')}

; // Autocomplete works! + return ( +
+ {t('title')} {/* Automatically resolves to booking:title */} + {/* Fallback to global common vocabulary */} +
+ ); } ``` -**3. Dynamic Variables (Interpolation):** +**4. Dynamic Variables (Interpolation):** ```json // booking.json { @@ -162,7 +199,7 @@ export default function BookingFeature() { ``` ```tsx // Inside component -

{t('booking:messages.welcome', { name: 'Firman', count: 5 })}

+

{t('messages.welcome', { name: 'Firman', count: 5 })}

``` --- diff --git a/apps/docs-dev/src/packages/ui/ACTION-TOOLS.md b/apps/docs-dev/src/packages/ui/ACTION-TOOLS.md new file mode 100644 index 0000000..df3c367 --- /dev/null +++ b/apps/docs-dev/src/packages/ui/ACTION-TOOLS.md @@ -0,0 +1,183 @@ +# ActionTools Component + +The `ActionTools` suite provides flexible, responsive, and semantic action menus and toolbars for standardizing interactions across the application. It consists of two main presentational components: `PageActions` and `RowActions`. + +These components automatically adapt to screen sizes, handle tooltip generation, and construct dropdown menus for nested actions. + +## Overview + +- **`PageActions`**: A responsive toolbar for page-level actions. On desktop, it renders a horizontal button group. On mobile, it collapses into a single "More" dropdown menu. Best used in page headers, toolbars, or detailed forms. +- **`RowActions`**: A lightweight component optimized for dense areas like data grid rows or list items. It renders standalone icon buttons or kebab menus for nested actions. Uses `React.memo` for zero overhead inside large lists. + +## Import Statement + +```tsx +import { + PageActions, + RowActions, + type PageAction, + type RowAction +} from '@repo/ui/components'; +``` + +## Usage Examples + +### 1. Page Actions (Toolbars & Headers) + +`PageActions` requires a text `label` (unless the type is `divider`). You can customize the look using Mantine's button variants and map specific intents for semantic colors. + +```tsx +import { PageActions, type PageAction } from '@repo/ui/components'; +import { Save, Printer, Trash, FileText, CheckCircle } from 'lucide-react'; + +function PageHeader() { + const actions: PageAction[] = [ + { + key: 'save', + label: 'Save Changes', + icon: , + intent: 'primary', + onClick: (key) => console.log('Clicked', key), + }, + { type: 'divider' }, + { + key: 'print', + label: 'Print', + icon: , + // Nested actions render as a dropdown menu below the main button + children: [ + { + key: 'print-original', + label: 'Print Original', + icon: , + onClick: (k) => console.log(k), + }, + { + key: 'print-copy', + label: 'Print Copy', + icon: , + onClick: (k) => console.log(k) + }, + ], + }, + { + key: 'delete', + label: 'Delete', + icon: , + intent: 'destructive', + onClick: (key) => console.log('Clicked', key), + }, + ]; + + return console.log('closed')} />; +} +``` + +### 2. Row Actions (Data Grids & Lists) + +`RowActions` are optimized for density. Text labels are optional and primarily shown inside nested dropdowns. Hover tooltips are supported. + +```tsx +import { RowActions, type RowAction } from '@repo/ui/components'; +import { Edit, CheckCircle, MoreVertical, Trash } from 'lucide-react'; +import { Table } from '@repo/ui/components'; + +function DataTable() { + const rowActions: RowAction[] = [ + { + key: 'edit', + tooltip: 'Edit Record', + icon: , + onClick: (key) => console.log('Clicked', key), + }, + { + key: 'approve', + tooltip: 'Approve', + icon: , + intent: 'success', + onClick: (key) => console.log('Clicked', key), + }, + { + key: 'more', + label: 'More Options', + icon: , + children: [ + { + key: 'delete', + label: 'Delete Record', + icon: , + intent: 'destructive', + onClick: (k) => console.log(k), + }, + ], + }, + ]; + + return ( + + + + Invoice #001 + + + + + +
+ ); +} +``` + +## Props API Reference + +### PageActions Props + +| Prop | Type | Default | Description | +|---|---|---|---| +| `actions` | `PageAction[]` | Required | Array of configured page-level actions. | +| `onClose` | `() => void` | `undefined` | Optional callback triggered when the close (X) button is clicked. | + +### RowActions Props + +| Prop | Type | Default | Description | +|---|---|---|---| +| `actions` | `RowAction[]` | `[]` | Array of configured row-level actions. | +| `showLabels` | `boolean` | `false` | If true, renders the text label alongside the icon for top-level buttons. | + +### Action Definitions + +Both `PageAction` and `RowAction` share a common base interface. + +**Base Action Properties (`BaseAction`)** + +| Property | Type | Description | +|---|---|---| +| `key` | `string` | Unique identifier. Required for 'action', optional for 'divider'. | +| `type` | `'action'` \| `'divider'` | Type of action. Defaults to 'action'. | +| `icon` | `ReactNode` | Visual representation of the action. | +| `disabled` | `boolean` | Disables interaction if set to true. | +| `intent` | `'default'` \| `'success'` \| `'warning'` \| `'destructive'` \| `'primary'` | Semantic context to determine visual emphasis (color mapping). | +| `onClick` | `(key: string) => void` | Callback triggered upon execution. | + +**`PageAction` Specific Properties** + +| Property | Type | Description | +|---|---|---| +| `label` | `string` | Text label displayed on the button. Required for 'action' type. | +| `variant` | `'filled'` \| `'light'` \| `'outline'` \| `'default'` \| `'subtle'` \| `'transparent'` | Specifies the Mantine button variant. Defaults to 'transparent' internally. | +| `children` | `PageAction[]` | Nested actions rendered as a dropdown menu below the main button. | + +**`RowAction` Specific Properties** + +| Property | Type | Description | +|---|---|---| +| `label` | `string` | Text primarily used when rendered inside a nested menu item. | +| `tooltip` | `string` | Optional text displayed on hover over the standalone icon. | +| `children` | `RowAction[]` | Nested actions that will be rendered inside a dropdown menu. | + +## Best Practices + +- **Semantic Intents:** Always map your actions to a specific `intent` (e.g., `intent: 'destructive'` for deletions). The components will automatically map these to the appropriate theme colors. +- **Nested Actions (Dropdowns):** For actions that trigger sub-actions (like multiple print options), use the `children` array property. The component automatically manages the dropdown positioning and presentation. +- **Density in Rows:** Inside lists and tables, favor `RowActions` over `PageActions` and provide a `tooltip` instead of forcing a full `label`. This keeps the UI clean and performs efficiently, especially over many rows. Keep `showLabels` as `false` (default) for a tighter grid layout unless specifically required. +- **Dividers:** Use `{ type: 'divider' }` within your actions array to visually group related buttons together. The component handles both horizontal and vertical divider logic depending on the screen size. diff --git a/apps/docs-dev/src/packages/ui/index.md b/apps/docs-dev/src/packages/ui/index.md index dfc2034..4e87df0 100644 --- a/apps/docs-dev/src/packages/ui/index.md +++ b/apps/docs-dev/src/packages/ui/index.md @@ -68,6 +68,12 @@ function UserForm() { } ``` +## 🛠️ ActionTools Component + +> **Full Documentation**: [ACTION-TOOLS.md](./ACTION-TOOLS.md) + +The `ActionTools` suite provides flexible, responsive, and semantic action menus and toolbars (`PageActions` and `RowActions`). + ## Scripts | Command | Description |