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 */}
+
```
---
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 |