# Impact Nova — Best Practices & Do's and Don'ts

## Use Impact Nova components only

**When building with Impact Nova, use the components that are present in this design system only.** The library includes a full set of UI components (forms, navigation, feedback, data display, layout, etc.). There is no need to create new custom components for standard UI—use what Impact Nova provides. Check `list_components` or the component catalog to see what's available; use `get_component` for the spec and usage of any component. Prefer composing existing Impact Nova components over building from scratch.

## Do's

1. **Use compound components** — Use subcomponents (e.g. `Dialog.Content`, `Card.Header`, `Select.Trigger`) for full control without prop drilling.
2. **Use `cn()` and Tailwind token classes** — Merge classNames with the `cn()` helper; use design token classes (e.g. `bg-brand`, `text-content`, `border-stroke`) not raw hex or arbitrary values.
3. **Use design tokens** — Prefer Tailwind theme tokens (colors, spacing, radius from the design system). No arbitrary values where a token exists.
4. **Accessibility first** — Components are built on Radix UI; preserve aria-labels, keyboard support, and screen reader compatibility. Add `aria-label` for icon-only buttons.
5. **i18n for user-facing strings** — Mount `ImpactNovaProviders` from `impact-nova/form` at app root; use `useImpactNovaI18n()` / `t()` for labels, placeholders, and button text. Override via props when needed.
6. **File naming** — Use `kebab-case.tsx` for files (e.g. `file-upload.tsx`).
7. **TypeScript** — Import and extend component props (e.g. `ButtonProps`) for type-safe wrappers.
8. **Use `variant` and `size` props** — For appearance, use the component's built-in variant and size props (e.g. `Button variant="default" size="lg"`). Add `className` only for layout (e.g. margin, gap) or intentional overrides.

## Don'ts

1. **No inline styles for token-backed values** — Don't use `style={{ color: '...' }}` or inline hex for colors that exist as tokens.
2. **Don't bypass tokens** — Avoid hardcoded spacing or colors; use Tailwind token classes.
3. **Don't skip i18n** — For any user-facing label, placeholder, or message, use the i18n context or pass overrides via props.
4. **Don't add unnecessary classNames for styling** — Components are already styled to the design standard. Use `variant` and `size` for appearance. Use `className` only for layout (e.g. `mt-4`, `flex gap-2`) or intentional overrides, not for duplicating built-in styles (e.g. don't add `rounded-lg` if the component already applies it).
5. **Don't use non-token colors** — Stick to the design token palette (primary, secondary, accent, destructive, muted, etc.).
6. **Don't create new components when Impact Nova already provides one** — The design system has the components you need. Use `list_components` / `get_component` to find and use them instead of building custom equivalents.
7. **Error and empty states** — Use **Alert** for form or API errors; use **EmptyContainer** when there is no data to show (with optional action like "Select filter" or "Add item").

## Composition over inheritance

Favor composition. Compose subcomponents rather than extending or wrapping with custom styling that overrides the design system.

## Imports

**Prefer subpath imports** in production apps for tree-shaking (~98% smaller bundles vs full barrel). Use the barrel only for i18n bootstrapping or when importing many symbols from one area in a single file.

- **Subpath (preferred)**: `import { Button } from 'impact-nova/button';`, `import { Card, CardContent } from 'impact-nova/card';`, `import { DataTable, DataTableContent, useDataTable } from 'impact-nova/data-table';`, `import { FilterPanel, FilterPanelSidebar } from 'impact-nova/filter-panel';`, `import { Combobox } from 'impact-nova/combobox';`
- **App providers**: `import { ImpactNovaProviders } from 'impact-nova/form';` — mount once at root (i18n + TooltipProvider)
- **Barrel (locale packs only)**: `import { de } from 'impact-nova';` — OK for locale packs; avoid barrel for UI components
- **Icons (required peer)**: `npm install impact-nova-icons@^0.1.1` then `import { Pin, Chart } from 'impact-nova-icons';` — use `createIconResolver` from `impact-nova-icons/resolver` for dynamic lookup. Icons are **not** exported from `impact-nova`
- **Types only**: `import type { Option } from 'impact-nova/select';`, `import type { SavedTableViewItem } from 'impact-nova/data-table';`, `import type { RowSelectionState } from 'impact-nova/virtualized';`
- **i18n hooks**: `import { useImpactNovaI18n } from 'impact-nova/i18n';`
- **Locale packs**: `import { de } from 'impact-nova/locale/de';` (also `es`, `hi`, `kn`)
- **CSS (once at root)**: `import 'impact-nova/dist/impact-nova.css';` — or split layers: `impact-nova/impact-nova-tokens.scss`, `impact-nova/impact-nova-base.scss`, `impact-nova/impact-nova-components.css`

**Vite consumers:** add `resolve.dedupe: ['react', 'react-dom', 'ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react']` to avoid dual React/AG Grid instances. Exclude `impact-nova-icons` from `optimizeDeps` to prevent SVG asset warnings. Pre-bundle Highcharts modules in `optimizeDeps.include` if using Chart.

## Truncated text tooltips (OverflowTooltip)

Use **`OverflowTooltip`** from `impact-nova/tooltip` when CSS truncation (`truncate`, `line-clamp`) may clip content and you want a tooltip **only when overflow is detected**.

```tsx
import { OverflowTooltip } from 'impact-nova/tooltip';

<OverflowTooltip content={fullLabel}>
  <span className="truncate">{fullLabel}</span>
</OverflowTooltip>
```

**Rules:**

1. **General UI** — `OverflowTooltip` or headless `useOverflowTooltip` (custom trigger via `setTriggerRef` + `onTriggerPointerEnter`).
2. **AG Grid custom cell renderers** — `useAgGridTruncationTooltip` from `impact-nova/ag-grid-react` with AG Grid's `setTooltip`. Never wrap grid cell text in `OverflowTooltip`.
3. **`focusable` defaults to `false`** — pointer-only, safe inside buttons, Select options, and comboboxes. Set `focusable` for standalone keyboard-accessible truncated labels.
4. **Do not wrap Badge globally** — apply `OverflowTooltip` at call sites when a badge label may truncate.
5. Measurement is **lazy** (pointerenter / focusin) — no mount-time ResizeObserver.

## Horizontal scroll overflow (ScrollOverflowAffordance)

For metric rails, chip rows, or any horizontal overflow content with fade edges:

```tsx
import { ScrollOverflowAffordance } from 'impact-nova/horizontal-scroller';

<ScrollOverflowAffordance contentDependency={items}>
  <div className="flex gap-2">{/* overflow children */}</div>
</ScrollOverflowAffordance>
```

Use **`HorizontalScroller`** when you have `items[]` + `renderItem`. Use **`useHorizontalScrollOverflow`** for fully custom scroll chrome.

## Calendar / week pickers

Week range, week picker, Wk gutter, dual-month join: apps should use **`WeekPicker`**, **`WeekRangePicker`**, or **`MultiWeekPicker`** from `impact-nova/date-picker`. Import `Calendar` from `impact-nova/calendar` only for custom chrome. There is no `<FiscalCalendar>` — pass `calendarKind="fiscal"`.

**Do not restyle selected days or the Wk gutter.** Selection language is built in:

- Start/end days are `rounded-lg` brand squares. Do not flatten them when a week range crosses months.
- Week **range** (`weekMode="range"`) is one connected day block plus one vertical Wk track. Dual-month panes square **only the Wk cells** at the join (last week of the first month / first week of the next).
- Week **multiple** keeps each week as its own pill.
- Gutter highlight is pane-local: a clipped Gregorian week ending on the last Monday does not paint the next month’s W01.
- Interval track tucks under the start/end buttons (Monday `pl-2` must not show accent left of the start square).

```tsx
import { WeekRangePicker } from 'impact-nova/date-picker';

<WeekRangePicker label="Reporting period" value={range} onChange={setRange} />
```

## AG Grid / Data tables (mandatory)

**When working with DataTable, or any data table that uses AG Grid:**
- **CRITICAL RULE:** If you see a table in a screenshot, or if the user asks for a table by default, you **MUST** use **Impact Nova DataTable** from `impact-nova/data-table`. **Do not build a raw AG Grid or HTML table.**
- Use **only** AG Grid's official documentation.
- Follow **only** AG Grid recommended patterns.
- Rely **only** on the AG Grid API for grid behavior. No deviation.
- If the user has **ag-mcp** installed, use it for AG Grid API and docs and combine with this MCP for Impact Nova DataTable/column/cell-renderer integration. See resource `impact-nova://ag-grid-rules` for full rules and the default table structure.
