impact-nova 2.0.6 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,15 @@
1
1
  import { jsxs as f, jsx as l } from "react/jsx-runtime";
2
2
  import * as c from "react";
3
3
  import { Cross as Ne, CalendarMonth as Re, Info as Z } from "impact-nova-icons";
4
- import { format as s, isValid as C, parse as I } from "date-fns";
5
- import { cn as p, padValidDateString as $, maskDate as Y } from "../../../lib/utils.js";
4
+ import { format as r, isValid as C, parse as I } from "date-fns";
5
+ import { cn as m, padValidDateString as $, maskDate as Y } from "../../../lib/utils.js";
6
6
  import { Popover as Se, PopoverAnchor as Ce, PopoverContent as Ie } from "../popover.js";
7
7
  import { Calendar as Pe } from "../calendar.js";
8
8
  import { Tooltip as _, TooltipTrigger as F, TooltipContent as ee } from "../tooltip.js";
9
9
  import { resolveWeekSelection as We } from "../../../lib/fiscal-calendar.js";
10
10
  import { getDateFnsLocale as Ve } from "../../../i18n/getDateFnsLocale.js";
11
11
  import { useImpactNovaI18n as Ee } from "../../../i18n/ImpactNovaI18nContext.js";
12
- const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c.forwardRef(
12
+ const i = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c.forwardRef(
13
13
  ({
14
14
  value: t,
15
15
  onChange: b,
@@ -26,7 +26,7 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
26
26
  fiscalMonthPattern: B,
27
27
  fiscalYearStartMonth: O = 1,
28
28
  weekStartsOn: T = 1,
29
- disabled: i,
29
+ disabled: a,
30
30
  className: se,
31
31
  isError: D,
32
32
  size: H,
@@ -40,20 +40,20 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
40
40
  }, ie) => {
41
41
  const { locale: G, t: W } = Ee(), o = c.useMemo(() => Ve(G), [G]), J = te ?? W("datePicker.selectWeekRange"), Q = c.useRef(null), de = c.useRef(null);
42
42
  c.useRef(null), c.useRef(null), c.useImperativeHandle(ie, () => Q.current);
43
- const [r, k] = c.useState(!1), V = c.useRef(!1), [v, m] = c.useState(t), [R, u] = c.useState(t?.from ? s(t.from.startDate, n, { locale: o }) : ""), [S, x] = c.useState(a(t) ? s(a(t), n, { locale: o }) : ""), [fe, j] = c.useState(t?.from?.startDate || /* @__PURE__ */ new Date());
43
+ const [s, p] = c.useState(!1), V = c.useRef(!1), [v, u] = c.useState(t), [R, x] = c.useState(t?.from ? r(t.from.startDate, n, { locale: o }) : ""), [S, h] = c.useState(i(t) ? r(i(t), n, { locale: o }) : ""), [fe, j] = c.useState(t?.from?.startDate || /* @__PURE__ */ new Date());
44
44
  c.useEffect(() => {
45
- r || (u(t?.from ? s(t.from.startDate, n, { locale: o }) : ""), x(a(t) ? s(a(t), n, { locale: o }) : ""), m(t));
46
- }, [t, n, r, o]), c.useEffect(() => {
47
- r && (m(t), u(t?.from ? s(t.from.startDate, n, { locale: o }) : ""), x(a(t) ? s(a(t), n, { locale: o }) : ""), j(t?.from?.startDate || /* @__PURE__ */ new Date()));
48
- }, [r, t, n, o]);
45
+ s || (x(t?.from ? r(t.from.startDate, n, { locale: o }) : ""), h(i(t) ? r(i(t), n, { locale: o }) : ""), u(t));
46
+ }, [t, n, s, o]), c.useEffect(() => {
47
+ s && (u(t), x(t?.from ? r(t.from.startDate, n, { locale: o }) : ""), h(i(t) ? r(i(t), n, { locale: o }) : ""), j(t?.from?.startDate || /* @__PURE__ */ new Date()));
48
+ }, [s, t, n, o]);
49
49
  const pe = (e) => {
50
- m(e), e?.from ? (u(s(e.from.startDate, n, { locale: o })), x(s(a(e), n, { locale: o }))) : (u(""), x("")), !y && e?.from && e?.to && e.from.startDate.getTime() !== e.to.startDate.getTime() && (b?.(e), k(!1));
50
+ u(e), e?.from ? (x(r(e.from.startDate, n, { locale: o })), h(r(i(e), n, { locale: o }))) : (x(""), h("")), !y && e?.from && e?.to && e.from.startDate.getTime() !== e.to.startDate.getTime() && (b?.(e), p(!1));
51
51
  }, me = (e) => {
52
- b?.(e !== void 0 ? e : v), k(!1);
52
+ b?.(e !== void 0 ? e : v), p(!1);
53
53
  }, z = () => {
54
- m(t), u(t?.from ? s(t.from.startDate, n, { locale: o }) : ""), x(a(t) ? s(a(t), n, { locale: o }) : ""), k(!1);
54
+ u(t), x(t?.from ? r(t.from.startDate, n, { locale: o }) : ""), h(i(t) ? r(i(t), n, { locale: o }) : ""), p(!1);
55
55
  }, U = () => {
56
- m(void 0), u(""), x(""), b?.(void 0), y || k(!1);
56
+ u(void 0), x(""), h(""), b?.(void 0), y || p(!1);
57
57
  }, E = (e) => We(e, {
58
58
  calendarType: L,
59
59
  fiscalMode: K,
@@ -63,46 +63,46 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
63
63
  weekStartsOn: T
64
64
  }), ue = (e) => {
65
65
  const w = e.target.value, d = Y(w, n, R);
66
- if (u(d), d === "") {
67
- const g = { from: void 0, to: v?.to };
68
- m(g), y || b?.(g);
66
+ if (x(d), d === "") {
67
+ const k = { from: void 0, to: v?.to };
68
+ u(k), y || b?.(k);
69
69
  return;
70
70
  }
71
- const h = I(d, n, /* @__PURE__ */ new Date(), { locale: o });
72
- if (C(h) && d.length === n.length) {
73
- const N = { from: E(h), to: v?.to };
74
- m(N), x(s(a(N), n, { locale: o })), y || b?.(N);
71
+ const g = I(d, n, /* @__PURE__ */ new Date(), { locale: o });
72
+ if (C(g) && d.length === n.length) {
73
+ const N = { from: E(g), to: v?.to };
74
+ u(N), h(r(i(N), n, { locale: o })), y || b?.(N);
75
75
  }
76
76
  }, xe = (e) => {
77
77
  const w = e.target.value, d = Y(w, n, S);
78
- if (x(d), d === "") {
79
- const g = { from: v?.from, to: void 0 };
80
- m(g), y || b?.(g);
78
+ if (h(d), d === "") {
79
+ const k = { from: v?.from, to: void 0 };
80
+ u(k), y || b?.(k);
81
81
  return;
82
82
  }
83
- const h = I(d, n, /* @__PURE__ */ new Date(), { locale: o });
84
- if (C(h) && d.length === n.length) {
85
- const g = E(h), N = { from: v?.from, to: g };
86
- m(N), v?.from && u(s(v.from.startDate, n, { locale: o })), h && j(h), y || b?.(N);
83
+ const g = I(d, n, /* @__PURE__ */ new Date(), { locale: o });
84
+ if (C(g) && d.length === n.length) {
85
+ const k = E(g), N = { from: v?.from, to: k };
86
+ u(N), v?.from && x(r(v.from.startDate, n, { locale: o })), g && j(g), y || b?.(N);
87
87
  }
88
88
  }, X = () => {
89
- if (r) return;
90
- const e = $(R, n), w = $(S, n), d = I(e, n, /* @__PURE__ */ new Date(), { locale: o }), h = I(w, n, /* @__PURE__ */ new Date(), { locale: o }), g = C(d) && e.length === n.length, N = C(h) && w.length === n.length;
91
- if (!g || !N)
92
- u(t?.from ? s(t.from.startDate, n, { locale: o }) : ""), x(a(t) ? s(a(t), n, { locale: o }) : ""), m(t);
93
- else if (u(e), x(w), !y) {
94
- const De = E(d), ve = E(h);
89
+ if (s) return;
90
+ const e = $(R, n), w = $(S, n), d = I(e, n, /* @__PURE__ */ new Date(), { locale: o }), g = I(w, n, /* @__PURE__ */ new Date(), { locale: o }), k = C(d) && e.length === n.length, N = C(g) && w.length === n.length;
91
+ if (!k || !N)
92
+ x(t?.from ? r(t.from.startDate, n, { locale: o }) : ""), h(i(t) ? r(i(t), n, { locale: o }) : ""), u(t);
93
+ else if (x(e), h(w), !y) {
94
+ const De = E(d), ve = E(g);
95
95
  b?.({ from: De, to: ve });
96
96
  }
97
- }, he = t?.from ? s(t.from.startDate, n, { locale: o }) : "", ge = a(t) ? s(a(t), n, { locale: o }) : "", ke = he !== R, we = ge !== S, be = R.length === n.length && !C(I(R, n, /* @__PURE__ */ new Date(), { locale: o })), ye = S.length === n.length && !C(I(S, n, /* @__PURE__ */ new Date(), { locale: o }));
98
- return /* @__PURE__ */ f("div", { className: "flex w-full min-w-[240px] flex-col gap-[6px]", "data-component": "week-range-picker", "data-disabled": i || void 0, children: [
97
+ }, he = t?.from ? r(t.from.startDate, n, { locale: o }) : "", ge = i(t) ? r(i(t), n, { locale: o }) : "", ke = he !== R, we = ge !== S, be = R.length === n.length && !C(I(R, n, /* @__PURE__ */ new Date(), { locale: o })), ye = S.length === n.length && !C(I(S, n, /* @__PURE__ */ new Date(), { locale: o }));
98
+ return /* @__PURE__ */ f("div", { className: "flex w-full min-w-[240px] flex-col gap-[6px]", "data-component": "week-range-picker", "data-disabled": a || void 0, children: [
99
99
  /* @__PURE__ */ f("div", { className: "flex flex-col gap-[6px]", children: [
100
100
  q && /* @__PURE__ */ f(
101
101
  "label",
102
102
  {
103
- className: p(
103
+ className: m(
104
104
  "text-xs font-medium leading-[18px] text-content-tertiary",
105
- i && "opacity-70",
105
+ a && "opacity-70",
106
106
  D && "text-destructive"
107
107
  ),
108
108
  children: [
@@ -115,23 +115,23 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
115
115
  /* @__PURE__ */ f(
116
116
  "div",
117
117
  {
118
- className: p(
118
+ className: m(
119
119
  "w-full",
120
120
  P && A === "absolute" && "relative"
121
121
  ),
122
122
  children: [
123
- /* @__PURE__ */ f(Se, { open: i ? !1 : r, onOpenChange: (e) => {
124
- i || k(e);
123
+ /* @__PURE__ */ f(Se, { open: a ? !1 : s, onOpenChange: (e) => {
124
+ a || p(e);
125
125
  }, children: [
126
126
  /* @__PURE__ */ l(Ce, { asChild: !0, children: /* @__PURE__ */ f(
127
127
  "div",
128
128
  {
129
- "data-state": r ? "open" : "closed",
130
- className: p(
129
+ "data-state": s ? "open" : "closed",
130
+ className: m(
131
131
  "flex w-full items-center justify-between gap-2 rounded-md border bg-canvas-elevated px-3 text-sm shadow-sm transition-colors hover:border-brand disabled:cursor-not-allowed disabled:bg-disabled-surface disabled:text-disabled-foreground disabled:border-stroke",
132
132
  D ? "border-destructive hover:border-destructive" : "border-field",
133
133
  H === "sm" ? "h-6" : H === "md" ? "h-[28px]" : "h-8",
134
- i && "pointer-events-none opacity-100 bg-disabled-surface border-stroke text-disabled-foreground hover:border-stroke",
134
+ a && "pointer-events-none opacity-100 bg-disabled-surface border-stroke text-disabled-foreground hover:border-stroke",
135
135
  "cursor-pointer",
136
136
  se
137
137
  ),
@@ -145,15 +145,15 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
145
145
  value: R,
146
146
  onChange: ue,
147
147
  onBlur: X,
148
- onClick: (e) => r && e.stopPropagation(),
148
+ onClick: () => !a && p(!0),
149
149
  onKeyDown: (e) => {
150
- (e.key === "Enter" || e.key === "ArrowDown") && !r && !i && (e.preventDefault(), V.current = !0, k(!0)), e.key === "Escape" && r && (e.preventDefault(), z());
150
+ (e.key === "Enter" || e.key === "ArrowDown") && !s && !a && (e.preventDefault(), V.current = !0, p(!0)), e.key === "Escape" && s && (e.preventDefault(), z());
151
151
  },
152
- placeholder: r ? n : J,
153
- disabled: !!i,
152
+ placeholder: s ? n : J,
153
+ disabled: !!a,
154
154
  "aria-label": "Start Date",
155
155
  "data-field": "start",
156
- className: p(
156
+ className: m(
157
157
  "flex-1 min-w-0 bg-transparent p-0 text-sm font-medium outline-none placeholder:font-medium placeholder:text-content-empty disabled:cursor-not-allowed disabled:opacity-50",
158
158
  be ? "text-destructive" : ke ? "text-content-muted" : ""
159
159
  ),
@@ -168,15 +168,15 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
168
168
  value: S,
169
169
  onChange: xe,
170
170
  onBlur: X,
171
- onClick: (e) => r && e.stopPropagation(),
171
+ onClick: () => !a && p(!0),
172
172
  onKeyDown: (e) => {
173
- (e.key === "Enter" || e.key === "ArrowDown") && !r && !i && (e.preventDefault(), V.current = !0, k(!0)), e.key === "Escape" && r && (e.preventDefault(), z());
173
+ (e.key === "Enter" || e.key === "ArrowDown") && !s && !a && (e.preventDefault(), V.current = !0, p(!0)), e.key === "Escape" && s && (e.preventDefault(), z());
174
174
  },
175
- placeholder: r ? n : J,
176
- disabled: !!i,
175
+ placeholder: s ? n : J,
176
+ disabled: !!a,
177
177
  "aria-label": "End Date",
178
178
  "data-field": "end",
179
- className: p(
179
+ className: m(
180
180
  "flex-1 min-w-0 bg-transparent p-0 text-sm font-medium outline-none placeholder:font-medium placeholder:text-content-empty disabled:cursor-not-allowed disabled:opacity-50",
181
181
  ye ? "text-destructive" : we ? "text-content-muted" : ""
182
182
  )
@@ -184,7 +184,7 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
184
184
  )
185
185
  ] }),
186
186
  /* @__PURE__ */ f("div", { className: "flex items-center gap-1 shrink-0", children: [
187
- t?.from && !i && /* @__PURE__ */ f(_, { children: [
187
+ t?.from && !a && /* @__PURE__ */ f(_, { children: [
188
188
  /* @__PURE__ */ l(F, { asChild: !0, children: /* @__PURE__ */ l(
189
189
  "button",
190
190
  {
@@ -202,9 +202,9 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
202
202
  ] }),
203
203
  /* @__PURE__ */ f(_, { children: [
204
204
  /* @__PURE__ */ l(F, { asChild: !0, children: /* @__PURE__ */ l("button", { type: "button", tabIndex: 0, "aria-label": W("datePicker.selectWeekRange"), onClick: (e) => {
205
- e.stopPropagation(), i || k(!r);
205
+ e.stopPropagation(), a || p(!s);
206
206
  }, onKeyDown: (e) => {
207
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.stopPropagation(), i || (V.current = !0, k(!r)));
207
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.stopPropagation(), a || (V.current = !0, p(!s)));
208
208
  }, className: "inline-flex items-center justify-center bg-transparent border-none p-0 cursor-pointer", children: /* @__PURE__ */ l(Re, { className: "h-4 w-4 text-secondary-foreground" }) }) }),
209
209
  /* @__PURE__ */ l(ee, { variant: "tertiary", side: "top", children: W("datePicker.selectWeekRange") })
210
210
  ] })
@@ -248,12 +248,12 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
248
248
  }
249
249
  )
250
250
  ] }),
251
- P && A === "absolute" && /* @__PURE__ */ f("div", { className: p("absolute left-0 top-full z-10 mt-1 flex min-w-0 max-w-full items-center gap-[6px]", D && "text-destructive"), children: [
251
+ P && A === "absolute" && /* @__PURE__ */ f("div", { className: m("absolute left-0 top-full z-10 mt-1 flex min-w-0 max-w-full items-center gap-[6px]", D && "text-destructive"), children: [
252
252
  /* @__PURE__ */ l(
253
253
  Z,
254
254
  {
255
255
  size: "xs",
256
- className: p(
256
+ className: m(
257
257
  "shrink-0",
258
258
  D ? "text-destructive" : "text-content-muted"
259
259
  )
@@ -262,7 +262,7 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
262
262
  /* @__PURE__ */ l(
263
263
  "p",
264
264
  {
265
- className: p(
265
+ className: m(
266
266
  "min-w-0 text-[12px] font-medium leading-[18px] text-navigation-muted",
267
267
  D && "text-destructive"
268
268
  ),
@@ -274,12 +274,12 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
274
274
  }
275
275
  )
276
276
  ] }),
277
- P && A === "flow" && /* @__PURE__ */ f("div", { className: p("flex items-center gap-[6px]", D && "text-destructive"), children: [
277
+ P && A === "flow" && /* @__PURE__ */ f("div", { className: m("flex items-center gap-[6px]", D && "text-destructive"), children: [
278
278
  /* @__PURE__ */ l(
279
279
  Z,
280
280
  {
281
281
  size: "xs",
282
- className: p(
282
+ className: m(
283
283
  "shrink-0",
284
284
  D ? "text-destructive" : "text-content-muted"
285
285
  )
@@ -288,7 +288,7 @@ const a = (t) => t?.from ? t.to ? t.to.endDate : t.from.endDate : void 0, Ae = c
288
288
  /* @__PURE__ */ l(
289
289
  "p",
290
290
  {
291
- className: p(
291
+ className: m(
292
292
  "text-[12px] font-medium leading-[18px] text-navigation-muted",
293
293
  D && "text-destructive"
294
294
  ),
@@ -1 +1 @@
1
- export default "# Impact Nova — Real-World Patterns (from production apps)\n\nPatterns observed in apps that use Impact Nova extensively (e.g. filter UIs, data tables, sheets, empty states).\n\n---\n\n## 1. Subpath imports (tree-shaking)\n\n**Default for production apps:** use subpath imports. Production apps (e.g. mtp-mfe-itemsmart-v3) migrated to 100% subpath imports — zero barrel `from 'impact-nova'` in feature code. Barrel is OK for i18n bootstrapping only.\n\n| Use case | Import |\n|----------|--------|\n| Layout (app shell) | `import { Layout } from 'impact-nova/layout';` |\n| Sidebar | `import { Sidebar, SidebarProvider, SidebarContent } from 'impact-nova/sidebar';` |\n| Header | `import { Header, HeaderLeft, HeaderRight, HeaderTitle } from 'impact-nova/header';` |\n| Breadcrumb | `import { Breadcrumb, BreadcrumbList, BreadcrumbHeader } from 'impact-nova/breadcrumb';` |\n| Button only | `import { Button } from 'impact-nova/button';` |\n| Combobox | `import { Combobox } from 'impact-nova/combobox';` |\n| Sheet (side panel) | `import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetBody, SheetFooter } from 'impact-nova/sheet';` |\n| Filter panel | `import { FilterPanel, FilterPanelSidebar } from 'impact-nova/filter-panel';` and `FilterPanelBody`, `FilterPanelFooter` |\n| Filter strip | `import { FilterStrip } from 'impact-nova/filter-strip';` |\n| Empty state | `import { EmptyContainer, EmptyContainerImage, EmptyContainerTitle, EmptyContainerDescription, EmptyContainerAction } from 'impact-nova/empty-container';` |\n| Accordion | `import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from 'impact-nova/accordion';` |\n| Date pickers | `import { DateRangePicker } from 'impact-nova/date-picker';` or `WeekRangePicker`, `MonthRangePicker` |\n| Select | `import { Select } from 'impact-nova/select';` |\n| Data table | `import { DataTable, DataTableContent, DataTableToolbar, useDataTable } from 'impact-nova/data-table';` |\n| Progress bar | `import { ProgressBar } from 'impact-nova/progress-bar';` |\n| Virtualized list | `import { useVirtualizedList, useDebouncedValue } from 'impact-nova/virtualized';` |\n| Row selection type | `import type { RowSelectionState } from 'impact-nova/virtualized';` |\n| Alert | `import { Alert, AlertTitle, AlertDescription, AlertIcon } from 'impact-nova/alert';` |\n| Tooltip | `import { Tooltip, TooltipTrigger, TooltipContent } from 'impact-nova/tooltip';` |\n| Icons | `import { Pin, Unpin, Chart } from 'impact-nova-icons';` + `createIconResolver` for dynamic lookup |\n| AG Grid cell renderers | `import { AG_GRID_CELL_COMPONENTS, LinkCellRenderer } from 'impact-nova/ag-grid-react/cell-renderers';` |\n| Prompt | `import { Prompt } from 'impact-nova/prompt';` |\n| Radio group | `import { RadioGroup, RadioGroupItem } from 'impact-nova/radio-group';` |\n| Button group | `import { ButtonGroup } from 'impact-nova/button-group';` |\n| Smart input | `import { SmartInput as InputWrapper } from 'impact-nova/smart-input';` |\n| Chips | `import { Chip } from 'impact-nova/chips';` |\n| Loader | `import { Loader } from 'impact-nova/loader';` |\n\n---\n\n## 2. Type-only imports\n\nUse type-only imports for types to avoid pulling runtime code:\n\n```ts\nimport type { Option, MultiValue, ActionMeta } from 'impact-nova/select';\nimport type { FilterSidebarItem } from 'impact-nova/filter-panel';\nimport type { FilterItem, SavedFilterItem } from 'impact-nova/filter-strip';\nimport type { NestedListItem } from 'impact-nova/nested-list';\nimport type { FileUploadProps } from 'impact-nova/file-upload';\nimport type { BackendColDef } from 'impact-nova';\n```\n\n---\n\n## 3. Compound patterns\n\n### Filter UI (panel + strip)\n\n- **FilterPanel** + **FilterPanelSidebar** for the sliding panel; **FilterPanelBody** and **FilterPanelFooter** for content and Apply/Cancel.\n- **FilterStrip** to show applied filters (chips/tags). Types: `FilterItem`, `SavedFilterItem` from `impact-nova/filter-strip`.\n- Config drives **FilterSidebarItem** (from `impact-nova/filter-panel`); form state often with react-hook-form.\n\n### Data table + AG Grid\n\n**Mandatory (no deviation):** For DataTable or any data table using AG Grid, refer **only** to AG Grid's official documentation, follow **only** AG Grid recommended patterns, and use **only** the AG Grid API for grid operations. See resource `impact-nova://ag-grid-rules` for full rules. If the user has **ag-mcp** installed, use it for AG Grid API/docs and collaborate with this MCP for Impact Nova integration.\n\n- **DataTable**, **DataTableContent**, **DataTableSheet**, **DataTableSheetContent**, **DataTableSheetHeader**, **DataTableColumnList**, **DataTableFormatOptions** from `impact-nova/data-table`.\n- Use **processBackendColumnDefs** from `impact-nova` when column defs come from the backend; type **BackendColDef**.\n- Cell renderers: **AG_GRID_CELL_COMPONENTS** or **LinkCellRenderer** from `impact-nova/ag-grid-react/cell-renderers`; extend/wrap as needed (e.g. PlanningLinkCellRenderer).\n\n### Sheet (side panel with form)\n\n- **Sheet**, **SheetContent**, **SheetHeader**, **SheetTitle**, **SheetBody**, **SheetFooter** from `impact-nova/sheet`.\n- Use for “Match With”, “Bulk Edit”, “View Management” panels. Pair with react-hook-form for form content.\n\n### Empty state\n\n- **EmptyContainer** wrapping **EmptyContainerImage**, **EmptyContainerTitle**, **EmptyContainerDescription**, **EmptyContainerAction** (e.g. a Button to “Select filter” or “Add item”).\n- **Lazy illustrations:** When no custom `children` are passed to `EmptyContainerImage`, one random illustration loads via dynamic `import()` — only ~1 webp chunk per empty state, not all 6 upfront. Pass custom children to skip illustration loading entirely.\n\n### Tabs + NestedList + Accordion (view management)\n\n- **Tabs**, **TabsList**, **TabsTrigger**, **TabsContent** for switching sections.\n- **NestedList** with **SelectionMode**; data shape **NestedListItem** from `impact-nova/nested-list`.\n- **Accordion**, **AccordionItem**, **AccordionTrigger**, **AccordionContent** for expandable blocks (e.g. Versions & Variance).\n\n### Chart (Highcharts)\n\n- Use **Chart** from `impact-nova/chart` as the wrapper.\n- For **series, options, and configuration** refer to **Highcharts documentation** ([highcharts.com/docs](https://www.highcharts.com/docs/)); use the Highcharts API for chart behavior. Impact Nova provides the React integration and styling; options/series follow Highcharts.\n- Install: `highcharts@^12`, `highcharts-react-official@^3`, optional `highcharts-border-radius@^0.0.4`.\n\n### Toast + Alert\n\n- **toast**, **Toaster**, **useToast** from `impact-nova`; wrap app with **Toaster**.\n- **Alert**, **AlertTitle**, **AlertDescription**, **AlertIcon** from `impact-nova/alert` for inline or toast-style messages.\n\n### Command Palette & keyboard shortcuts\n\nImplementation is **more involved** than other components. Use the dedicated guide: resource **`impact-nova://command-palette`**.\n\n- **Import:** `import { CommandPaletteProvider, CommandPalette, useShortcut, useGlobalShortcut, ShortcutSettings, ShortcutScopeProvider, Kbd, useCommandPalette, useBrowserShortcuts } from 'impact-nova/command-palette';`\n- **Minimal setup:** Wrap app with `CommandPaletteProvider`; render `<CommandPalette />` once inside it (⌘K overlay). Register commands with `useShortcut` (scoped: page/module/modal) or `useGlobalShortcut` (app-wide). Use correct `scope` for priority (modal > page > module > global).\n- **Multi-table:** When multiple DataTables share the same shortcut, wrap each in `ShortcutScopeProvider` with a unique `instance` so only the focused one responds.\n- **ShortcutSettings:** AG Grid–powered panel for user customisation; put inside a Sheet (e.g. Keyboard Shortcuts settings). For AG Grid behaviour follow `impact-nova://ag-grid-rules`.\n- **Kbd:** Use `<Kbd keybinding={{ key: 'k', meta: true }} />` to show shortcut in UI. **Button trigger:** `useCommandPalette().setOpen(true)`.\n\n---\n\n## 4. App setup\n\n- **CSS once at root**: `import 'impact-nova/dist/impact-nova.css';` (e.g. in App.tsx or main.tsx).\n- **AG Grid**: Set `LicenseManager.setLicenseKey(...)` if using enterprise.\n- **Vite**: Dedupe react/ag-grid when using impact-nova to avoid dual instances. Exclude `impact-nova-icons` from `optimizeDeps` to prevent SVG asset warnings in dev:\n\n```js\noptimizeDeps: {\n exclude: ['impact-nova-icons'],\n},\nresolve: {\n dedupe: ['react', 'react-dom', 'ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react'],\n},\n```\n\n---\n\n## 5. Known workarounds\n\n- **HorizontalScroller**: If the package entry is empty in your build, add a Vite alias to `.../horizontal-scroller/horizontal-scroller.js` and a small `declare module 'impact-nova/horizontal-scroller'` for TypeScript.\n- **Chart**: Prefer `import { Chart } from 'impact-nova/chart'`. Pre-bundle Highcharts UMD modules in Vite `optimizeDeps.include` if you see interop errors in dev.\n\n---\n\n## 6. Forms and options\n\n- **Select options**: Use type **Option** (or **SelectOption**) from `impact-nova/select` for `{ value, label }` (and optional fields). **MultiValue** for multi-select.\n- **react-hook-form**: Use Impact Nova form controls (SmartInput, Select, DateRangePicker, RadioGroup, ButtonGroup, Chips, etc.) as controlled components; pass `value`/`onChange` from the form library.\n- **Validation and errors**: Show validation errors with **Alert** or field-level messages; use the form library’s error state (e.g. `formState.errors`) and optional schema validation (e.g. Zod) with react-hook-form.\n\n---\n\n## 7. Breadcrumb and toolbar\n\n- **Breadcrumb** with **BreadcrumbList**, **BreadcrumbItem**, **BreadcrumbLink**, **BreadcrumbSeparator**, **BreadcrumbPage** for table/section context.\n- **DataTableToolbar** for table toolbars (view mode, view management, filters, Update/Cancel when editing).\n\nUse these patterns so the MCP and generated code stay close to how Impact Nova is used in real apps.\n\n---\n\n## 8. Wizard (multi-step flow)\n\nUse **Wizard** for any multi-step creation or onboarding flow. Radix-style controlled state (`value` / `onValueChange`), optional split-panel layout, and `useWizard()` for flexible footers.\n\n### Import\n\n```ts\nimport {\n WizardRoot,\n WizardLayout,\n WizardSidebar,\n WizardTitle,\n WizardDescription,\n WizardMedia,\n WizardBody,\n WizardProgress,\n WizardHeader,\n WizardContent,\n WizardStep,\n WizardFooter,\n useWizard,\n} from 'impact-nova/wizard';\n```\n\n### Minimal multi-step example\n\n```tsx\nimport { useState } from 'react';\nimport {\n WizardRoot, WizardLayout,\n WizardSidebar, WizardTitle, WizardDescription, WizardMedia,\n WizardBody, WizardProgress,\n WizardContent, WizardStep, WizardHeader,\n WizardFooter,\n} from 'impact-nova/wizard';\nimport { Button } from 'impact-nova/button';\n\nexport function CreateAlertFlow() {\n const [step, setStep] = useState(1);\n\n return (\n <WizardRoot value={step} totalSteps={3} onValueChange={setStep}>\n <WizardLayout>\n <WizardSidebar>\n <WizardTitle>Create Alert</WizardTitle>\n <WizardDescription>Configure your alert step by step.</WizardDescription>\n <WizardMedia />\n </WizardSidebar>\n\n <WizardBody>\n <WizardProgress />\n <WizardContent>\n <WizardStep value={1}>\n <WizardHeader>Alert Details</WizardHeader>\n </WizardStep>\n <WizardStep value={2}>\n <WizardHeader>Configuration</WizardHeader>\n </WizardStep>\n <WizardStep value={3}>\n <WizardHeader>Review</WizardHeader>\n </WizardStep>\n </WizardContent>\n <WizardFooter>\n <Button variant=\"secondary\">Cancel</Button>\n <Button variant=\"default\">Submit</Button>\n </WizardFooter>\n </WizardBody>\n </WizardLayout>\n </WizardRoot>\n );\n}\n```\n\n### Key rules\n\n- **WizardRoot** is the context provider — every other sub-component must be a descendant.\n- Use **useWizard()** for `goNext`, `goBack`, `isFirstStep`, `isLastStep` without prop drilling.\n- **WizardStep** renders nothing when `value` doesn't match the current step — use one per step.\n- **WizardMedia** renders a default SVG when neither `src` nor `children` are provided.\n- The sidebar is hidden below the `lg` breakpoint.\n- All sub-components except **WizardRoot** are optional — compose only what you need.\n---\n\n## 9. App layout (app shell)\n\n**Use `Layout`** for the app chrome — not `DynamicLayout` (that is a grid/flex/stack utility only).\n\nFull beginner scaffold: resource **`impact-nova://layout`**.\n\n### Structure\n\n```tsx\nimport { Layout } from 'impact-nova/layout';\nimport { Sidebar, SidebarProvider } from 'impact-nova/sidebar';\nimport { Header, HeaderLeft, HeaderTitle } from 'impact-nova/header';\nimport { BreadcrumbHeader, Breadcrumb, BreadcrumbList } from 'impact-nova/breadcrumb';\nimport { FilterStrip } from 'impact-nova/filter-strip';\n\n<SidebarProvider defaultOpen={false} id=\"app-sidebar\" className=\"flex h-svh min-h-0 w-full min-w-0 overflow-hidden\">\n <Layout\n sidebar={<Sidebar collapsible=\"offcanvas\">...</Sidebar>}\n header={<Header>...</Header>}\n >\n {/* Page content — breadcrumb + filters + body */}\n <div className=\"sticky top-0 z-40 bg-canvas-wash\">\n <BreadcrumbHeader>...</BreadcrumbHeader>\n <FilterStrip ... />\n </div>\n <div className=\"p-8\">...</div>\n </Layout>\n</SidebarProvider>\n```\n\n### Key rules\n\n- **`SidebarProvider` at app root** — wraps `Layout`, not inside the sidebar slot.\n- **Breadcrumb and FilterStrip in `children`** — each page composes its own; the layout does not accept breadcrumb/filter props.\n- **Subpath imports** — `impact-nova/layout`, `impact-nova/sidebar`, `impact-nova/header`, `impact-nova/breadcrumb`, `impact-nova/filter-strip`.\n- **With React Router** — put `<Outlet />` inside `Layout` children; route pages render breadcrumb + body.\n- **With Command Palette** — `CommandPaletteProvider` at root; `<CommandPalette />` as sibling inside `SidebarProvider`. See `impact-nova://command-palette`.\n";
1
+ export default "# Impact Nova — Real-World Patterns (from production apps)\n\nPatterns observed in apps that use Impact Nova extensively (e.g. filter UIs, data tables, sheets, empty states).\n\n---\n\n## 1. Subpath imports (tree-shaking)\n\n**Default for production apps:** use subpath imports. Production apps (e.g. mtp-mfe-itemsmart-v3) migrated to 100% subpath imports — zero barrel `from 'impact-nova'` in feature code. Barrel is OK for i18n bootstrapping only.\n\n| Use case | Import |\n|----------|--------|\n| Layout (app shell) | `import { Layout } from 'impact-nova/layout';` |\n| Sidebar | `import { Sidebar, SidebarProvider, SidebarContent } from 'impact-nova/sidebar';` |\n| Header | `import { Header, HeaderLeft, HeaderRight, HeaderTitle } from 'impact-nova/header';` |\n| Breadcrumb | `import { Breadcrumb, BreadcrumbList, BreadcrumbHeader } from 'impact-nova/breadcrumb';` |\n| Button only | `import { Button } from 'impact-nova/button';` |\n| Combobox | `import { Combobox } from 'impact-nova/combobox';` |\n| Sheet (side panel) | `import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetBody, SheetFooter } from 'impact-nova/sheet';` |\n| Filter panel | `import { FilterPanel, FilterPanelSidebar } from 'impact-nova/filter-panel';` and `FilterPanelBody`, `FilterPanelFooter` |\n| Filter strip | `import { FilterStrip } from 'impact-nova/filter-strip';` |\n| Empty state | `import { EmptyContainer, EmptyContainerImage, EmptyContainerTitle, EmptyContainerDescription, EmptyContainerAction } from 'impact-nova/empty-container';` |\n| Accordion | `import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from 'impact-nova/accordion';` |\n| Date pickers | `import { DateRangePicker } from 'impact-nova/date-picker';` or `WeekRangePicker`, `MonthRangePicker` |\n| Select | `import { Select } from 'impact-nova/select';` |\n| Data table | `import { DataTable, DataTableContent, DataTableToolbar, useDataTable } from 'impact-nova/data-table';` |\n| Progress bar | `import { ProgressBar } from 'impact-nova/progress-bar';` |\n| Virtualized list | `import { useVirtualizedList, useDebouncedValue } from 'impact-nova/virtualized';` |\n| Row selection type | `import type { RowSelectionState } from 'impact-nova/virtualized';` |\n| Alert | `import { Alert, AlertTitle, AlertDescription, AlertIcon } from 'impact-nova/alert';` |\n| Tooltip | `import { Tooltip, TooltipTrigger, TooltipContent } from 'impact-nova/tooltip';` |\n| Icons | `import { Pin, Unpin, Chart } from 'impact-nova-icons';` + `createIconResolver` for dynamic lookup |\n| AG Grid cell renderers | `import { AG_GRID_CELL_COMPONENTS, LinkCellRenderer } from 'impact-nova/ag-grid-react/cell-renderers';` |\n| Prompt | `import { Prompt } from 'impact-nova/prompt';` |\n| Radio group | `import { RadioGroup, RadioGroupItem } from 'impact-nova/radio-group';` |\n| Button group | `import { ButtonGroup } from 'impact-nova/button-group';` |\n| Smart input | `import { SmartInput as InputWrapper } from 'impact-nova/smart-input';` |\n| Chips | `import { Chip } from 'impact-nova/chips';` |\n| Loader | `import { Loader } from 'impact-nova/loader';` |\n\n---\n\n## 2. Type-only imports\n\nUse type-only imports for types to avoid pulling runtime code:\n\n```ts\nimport type { Option, MultiValue, ActionMeta } from 'impact-nova/select';\nimport type { FilterSidebarItem } from 'impact-nova/filter-panel';\nimport type { FilterItem, SavedFilterItem } from 'impact-nova/filter-strip';\nimport type { NestedListItem } from 'impact-nova/nested-list';\nimport type { FileUploadProps } from 'impact-nova/file-upload';\nimport type { BackendColDef } from 'impact-nova';\n```\n\n---\n\n## 3. Compound patterns\n\n### Filter UI (panel + strip)\n\n- **FilterPanel** + **FilterPanelSidebar** for the sliding panel; **FilterPanelBody** and **FilterPanelFooter** for content and Apply/Cancel.\n- **FilterStrip** to show applied filters (chips/tags). Types: `FilterItem`, `SavedFilterItem` from `impact-nova/filter-strip`.\n- Config drives **FilterSidebarItem** (from `impact-nova/filter-panel`); form state often with react-hook-form.\n\n### Data table + AG Grid\n\n**Mandatory (no deviation):** For DataTable or any data table using AG Grid, refer **only** to AG Grid's official documentation, follow **only** AG Grid recommended patterns, and use **only** the AG Grid API for grid operations. See resource `impact-nova://ag-grid-rules` for full rules. If the user has **ag-mcp** installed, use it for AG Grid API/docs and collaborate with this MCP for Impact Nova integration.\n\n- **DataTable**, **DataTableContent**, **DataTableSheet**, **DataTableSheetContent**, **DataTableSheetHeader**, **DataTableColumnList**, **DataTableFormatOptions** from `impact-nova/data-table`.\n- Use **processBackendColumnDefs** from `impact-nova` when column defs come from the backend; type **BackendColDef**.\n- Cell renderers: **AG_GRID_CELL_COMPONENTS** or **LinkCellRenderer** from `impact-nova/ag-grid-react/cell-renderers`; extend/wrap as needed (e.g. PlanningLinkCellRenderer).\n\n### Sheet (side panel with form)\n\n- **Sheet**, **SheetContent**, **SheetHeader**, **SheetTitle**, **SheetBody**, **SheetFooter** from `impact-nova/sheet`.\n- Use for “Match With”, “Bulk Edit”, “View Management” panels. Pair with react-hook-form for form content.\n\n### Empty state\n\n- **EmptyContainer** wrapping **EmptyContainerImage**, **EmptyContainerTitle**, **EmptyContainerDescription**, **EmptyContainerAction** (e.g. a Button to “Select filter” or “Add item”).\n- **Lazy illustrations:** When no custom `children` are passed to `EmptyContainerImage`, one random illustration loads via dynamic `import()` — only ~1 webp chunk per empty state, not all 6 upfront. Pass custom children to skip illustration loading entirely.\n\n### Tabs + NestedList + Accordion (view management)\n\n- **Tabs**, **TabsList**, **TabsTrigger**, **TabsContent** for switching sections.\n- **NestedList** with **SelectionMode**; data shape **NestedListItem** from `impact-nova/nested-list`.\n- **Accordion**, **AccordionItem**, **AccordionTrigger**, **AccordionContent** for expandable blocks (e.g. Versions & Variance).\n\n### Chart (Highcharts)\n\n- Use **Chart** from `impact-nova/chart` as the wrapper.\n- For **series, options, and configuration** refer to **Highcharts documentation** ([highcharts.com/docs](https://www.highcharts.com/docs/)); use the Highcharts API for chart behavior. Impact Nova provides the React integration and styling; options/series follow Highcharts.\n- Install: `highcharts@^12`, `highcharts-react-official@^3`, optional `highcharts-border-radius@^0.0.4`.\n\n### Toast + Alert\n\n- **toast**, **Toaster**, **useToast** from `impact-nova`; wrap app with **Toaster**.\n- **Alert**, **AlertTitle**, **AlertDescription**, **AlertIcon** from `impact-nova/alert` for inline or toast-style messages.\n\n### Command Palette & keyboard shortcuts\n\nImplementation is **more involved** than other components. Use the dedicated guide: resource **`impact-nova://command-palette`**.\n\n- **Import:** `import { CommandPaletteProvider, CommandPalette, useShortcut, useGlobalShortcut, ShortcutSettings, ShortcutScopeProvider, Kbd, useCommandPalette, useBrowserShortcuts } from 'impact-nova/command-palette';`\n- **Minimal setup:** Wrap app with `CommandPaletteProvider`; render `<CommandPalette />` once inside it (⌘K overlay). Register commands with `useShortcut` (scoped: page/module/modal) or `useGlobalShortcut` (app-wide). Use correct `scope` for priority (modal > page > module > global).\n- **Multi-table:** When multiple DataTables share the same shortcut, wrap each in `ShortcutScopeProvider` with a unique `instance` so only the focused one responds.\n- **ShortcutSettings:** AG Grid–powered panel for user customisation; put inside a Sheet (e.g. Keyboard Shortcuts settings). For AG Grid behaviour follow `impact-nova://ag-grid-rules`.\n- **Kbd:** Use `<Kbd keybinding={{ key: 'k', meta: true }} />` to show shortcut in UI. **Button trigger:** `useCommandPalette().setOpen(true)`.\n\n---\n\n## 4. App setup\n\n- **CSS once at root**: `import 'impact-nova/dist/impact-nova.css';` (e.g. in App.tsx or main.tsx).\n- **AG Grid**: Set `LicenseManager.setLicenseKey(...)` if using enterprise.\n- **Vite**: Dedupe react/ag-grid when using impact-nova to avoid dual instances. Exclude `impact-nova-icons` from `optimizeDeps` to prevent SVG asset warnings in dev:\n\n```js\noptimizeDeps: {\n exclude: ['impact-nova-icons'],\n},\nresolve: {\n dedupe: ['react', 'react-dom', 'ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react'],\n},\n```\n\n---\n\n## 5. Known workarounds\n\n- **HorizontalScroller**: If the package entry is empty in your build, add a Vite alias to `.../horizontal-scroller/horizontal-scroller.js` and a small `declare module 'impact-nova/horizontal-scroller'` for TypeScript.\n- **Chart**: Prefer `import { Chart } from 'impact-nova/chart'`. Pre-bundle Highcharts UMD modules in Vite `optimizeDeps.include` if you see interop errors in dev.\n\n---\n\n## 6. Forms and options\n\n- **Select options**: Use type **Option** (or **SelectOption**) from `impact-nova/select` for `{ value, label }` (and optional fields). **MultiValue** for multi-select.\n- **react-hook-form**: Use Impact Nova form controls (SmartInput, Select, DateRangePicker, RadioGroup, ButtonGroup, Chips, etc.) as controlled components; pass `value`/`onChange` from the form library.\n- **Validation and errors**: Show validation errors with **Alert** or field-level messages; use the form library’s error state (e.g. `formState.errors`) and optional schema validation (e.g. Zod) with react-hook-form.\n\n---\n\n## 7. Breadcrumb and toolbar\n\n- **Breadcrumb** with **BreadcrumbList**, **BreadcrumbItem**, **BreadcrumbLink**, **BreadcrumbSeparator**, **BreadcrumbPage** for table/section context.\n- **DataTableToolbar** for table toolbars (view mode, view management, filters, Update/Cancel when editing).\n\nUse these patterns so the MCP and generated code stay close to how Impact Nova is used in real apps.\n\n---\n\n## 8. Wizard (multi-step flow)\n\nUse **Wizard** for any multi-step creation or onboarding flow. Radix-style controlled state (`value` / `onValueChange`), optional split-panel layout, and `useWizard()` for flexible footers.\n\n### Import\n\n```ts\nimport {\n WizardRoot,\n WizardLayout,\n WizardSidebar,\n WizardTitle,\n WizardDescription,\n WizardMedia,\n WizardBody,\n WizardProgress,\n WizardHeader,\n WizardContent,\n WizardStep,\n WizardFooter,\n useWizard,\n} from 'impact-nova/wizard';\n```\n\n### Minimal multi-step example\n\n```tsx\nimport { useState } from 'react';\nimport {\n WizardRoot, WizardLayout,\n WizardSidebar, WizardTitle, WizardDescription, WizardMedia,\n WizardBody, WizardProgress,\n WizardContent, WizardStep, WizardHeader,\n WizardFooter,\n} from 'impact-nova/wizard';\nimport { Button } from 'impact-nova/button';\n\nexport function CreateAlertFlow() {\n const [step, setStep] = useState(1);\n\n return (\n <WizardRoot value={step} totalSteps={3} onValueChange={setStep}>\n <WizardLayout>\n <WizardSidebar>\n <WizardTitle>Create Alert</WizardTitle>\n <WizardDescription>Configure your alert step by step.</WizardDescription>\n <WizardMedia />\n </WizardSidebar>\n\n <WizardBody>\n <WizardProgress />\n <WizardContent>\n <WizardStep value={1}>\n <WizardHeader>Alert Details</WizardHeader>\n </WizardStep>\n <WizardStep value={2}>\n <WizardHeader>Configuration</WizardHeader>\n </WizardStep>\n <WizardStep value={3}>\n <WizardHeader>Review</WizardHeader>\n </WizardStep>\n </WizardContent>\n <WizardFooter>\n <Button variant=\"secondary\">Cancel</Button>\n <Button variant=\"default\">Submit</Button>\n </WizardFooter>\n </WizardBody>\n </WizardLayout>\n </WizardRoot>\n );\n}\n```\n\n### Key rules\n\n- **WizardRoot** is the context provider — every other sub-component must be a descendant.\n- Use **useWizard()** for `goNext`, `goBack`, `isFirstStep`, `isLastStep` without prop drilling.\n- **WizardStep** renders nothing when `value` doesn't match the current step — use one per step.\n- **WizardMedia** renders a default SVG when neither `src` nor `children` are provided.\n- The sidebar is hidden below the `lg` breakpoint.\n- All sub-components except **WizardRoot** are optional — compose only what you need.\n---\n\n## 9. App layout (app shell)\n\n**Use `Layout`** for the app chrome — not `DynamicLayout` (that is a grid/flex/stack utility only).\n\nFull beginner scaffold: resource **`impact-nova://layout`**.\n\n### Structure\n\n```tsx\nimport { Layout } from 'impact-nova/layout';\nimport { Sidebar, SidebarProvider } from 'impact-nova/sidebar';\nimport { Header, HeaderLeft, HeaderTitle } from 'impact-nova/header';\nimport { BreadcrumbHeader, Breadcrumb, BreadcrumbList } from 'impact-nova/breadcrumb';\nimport { FilterStrip } from 'impact-nova/filter-strip';\n\n<SidebarProvider defaultOpen={false} id=\"app-sidebar\" className=\"flex h-svh min-h-0 w-full min-w-0 overflow-hidden\">\n <Layout\n sidebar={<Sidebar collapsible=\"offcanvas\">...</Sidebar>}\n header={<Header>...</Header>}\n >\n {/* Page content — Item Smart parity */}\n <PageShell>\n <PageStickyHeader pageTitle=\"...\" filterStrip={filtersApplied ? <FilterStrip ... /> : undefined} />\n {filtersApplied ? <WorkspaceBody /> : <EmptyStateView title=\"...\" primaryActionLabel=\"Select filter\" />}\n </PageShell>\n </Layout>\n</SidebarProvider>\n```\n\n### Key rules\n\n- **`SidebarProvider` at app root** — wraps `Layout`, not inside the sidebar slot.\n- **Page background** — `PageShell` → `bg-brand-subtle` (not `bg-canvas-wash` on module pages)\n- **Filter strip** — white sticky bar via `PageStickyHeader` `filterStrip` slot (`page-filter-strip` class)\n- **Tables** — `module-table-container mx-6 flex min-h-[480px] flex-1` → white `DataTable` card with shadow\n- **Subpath imports** — `impact-nova/layout`, `impact-nova/sidebar`, `impact-nova/header`, `impact-nova/breadcrumb`, `impact-nova/filter-strip`.\n- **With React Router** — put `<Outlet />` inside `Layout` children; route pages render breadcrumb + body.\n- **With Command Palette** — `CommandPaletteProvider` at root; `<CommandPalette />` as sibling inside `SidebarProvider`. See `impact-nova://command-palette`.\n\n### Premium primitives (shipped in create-impact-nova template)\n\n| Component | Role |\n|-----------|------|\n| `PageShell` | `bg-brand-subtle` + flex fill chain |\n| `PageStickyHeader` | Breadcrumb `z-30` + white filter strip slot |\n| `EmptyStateView` | Illustration + primary/secondary CTAs |\n| `SummaryMetricCard` | Dashboard KPI tiles (`border-[#C3C8D4]`, hover shadow) |\n| `module-table-container` | Table card shadow + `min-h-[480px] flex-1` fill |\n";
@@ -1 +1 @@
1
- export default "# Impact Nova — Troubleshooting\n\nCommon setup and runtime issues when using Impact Nova, and how to fix them.\n\n---\n\n## 1. Duplicate React or AG Grid (Vite)\n\n**Symptom:** \"Invalid hook call\", \"Multiple copies of React\", or AG Grid warnings about multiple instances.\n\n**Fix:** In Vite config, add `resolve.dedupe` so the app uses a single copy of React and AG Grid:\n\n```js\n// vite.config.js / vite.config.ts\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n plugins: [react()],\n resolve: {\n dedupe: ['react', 'react-dom', 'ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react'],\n },\n});\n```\n\n---\n\n## 2. Styles not applying\n\n**Symptom:** Components render but look unstyled or wrong.\n\n**Fix:**\n\n- Import Impact Nova CSS **once** at the app root, **before** your app component: \n `import 'impact-nova/dist/impact-nova.css';` \n Or, if you use **CSS or SCSS (no Tailwind)**, you can `@import 'impact-nova/dist/impact-nova.css';` in your main.css or main.scss. See installation **§5. Using Impact Nova with CSS or SCSS (no Tailwind)**.\n- Ensure your build includes the CSS (no rule excluding `node_modules/impact-nova`).\n- If using Tailwind, ensure the design system tokens aren’t overridden by a conflicting Tailwind theme.\n\n---\n\n## 3. Font (Manrope) not loading\n\n**Symptom:** Text renders in fallback font.\n\n**Fix:**\n\n- Add the Manrope link in `index.html`: \n `<link href=\"https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap\" rel=\"stylesheet\" />`\n- In global CSS or Tailwind base: \n `body { font-family: 'Manrope', sans-serif; }`\n\n---\n\n## 4. Chart component not found or wrong export\n\n**Symptom:** `import { Chart } from 'impact-nova'` fails or Chart doesn't render.\n\n**Fix:**\n\n- Use the public subpath: `import { Chart } from 'impact-nova/chart';`\n- Ensure Highcharts is installed: `npm install highcharts@^12 highcharts-react-official@^3`\n- In Vite, pre-bundle Highcharts modules in `optimizeDeps.include` if you see UMD interop errors in dev.\n\n---\n\n## 5. impact-nova-icons SVG warnings in Vite dev\n\n**Symptom:** Hundreds of \"Failed to resolve import\" warnings for `.svg` files from `impact-nova-icons` on dev startup.\n\n**Fix:** Exclude icons from dependency pre-bundling:\n\n```js\noptimizeDeps: {\n exclude: ['impact-nova-icons'],\n},\n```\n\nIf using Module Federation, add an asset URL rewrite plugin for `impact-nova-icons/dist/assets/*2.svg.js` shims.\n\n---\n\n## 6. React 19 — \"Cannot access refs during render\"\n\n**Symptom:** React 19 error about updating or reading refs during render.\n\n**Fix:** Never assign to `ref.current` during render. Use refs only in event handlers, effects, or callbacks. Prefer deriving values during render instead of mirroring props into refs.\n\n---\n\n## 7. HorizontalScroller or other subpath missing\n\n**Symptom:** Import from `impact-nova/horizontal-scroller` (or similar) fails.\n\n**Fix:**\n\n- If the package doesn’t export that subpath, add a Vite alias to the component file and a small TypeScript declaration:\n\n```js\n// vite.config\nresolve: {\n alias: {\n 'impact-nova/horizontal-scroller': resolve(__dirname, 'node_modules/impact-nova/dist/components/ui/horizontal-scroller/horizontal-scroller.js'),\n },\n},\n```\n\n```ts\n// declare module 'impact-nova/horizontal-scroller'\ndeclare module 'impact-nova/horizontal-scroller' {\n const Component: React.ComponentType<{ /* props */ }>;\n export default Component;\n}\n```\n\n---\n\n## 8. AG Grid CSS not applied (legacy container conflict)\n\n**Symptom:** AG Grid in a micro-frontend (MFE) looks wrong or unstyled; the new AG Grid theme is not applied.\n\n**Cause:** The **container** (host app) is loading legacy AG Grid CSS. Those legacy style tags conflict with the new theme, so the MFE’s AG Grid doesn’t get the correct styles.\n\n**Fix:** Apply the fix in the **container** app, not in the MFE/remote repo. In the container, when you mount the remote (e.g. in a `useEffect`), remove the legacy AG Grid style tags from the document so the new theme can apply. Example:\n\n```tsx\n// In the CONTAINER app (not in the MFE repo)\nuseEffect(() => {\n const { onParentNavigate } = mount(ref.current, {\n initialPath: history.location.pathname,\n onNavigate: ({ pathname: nextPathname }) => {\n const { pathname } = history.location;\n if (pathname !== nextPathname) {\n history.push(nextPathname);\n }\n },\n containerStore,\n routes,\n defaultHistory: history,\n });\n\n history.listen(onParentNavigate);\n\n const removeAgGridStyles = () => {\n const styleTags = document.querySelectorAll('style');\n styleTags.forEach((styleTag) => {\n const content = styleTag.textContent || styleTag.innerHTML || '';\n // Legacy AG Grid styles (--ag-legacy-styles-loaded + .ag-icon)\n const isLegacyStyles =\n content.includes('--ag-legacy-styles-loaded') && content.includes('.ag-icon');\n // Generic AG Grid selectors that override the new theme\n const hasAgGridSelectors =\n content.includes('ag-grid,ag-grid-angular') ||\n content.includes('ag-grid, ag-grid-angular') ||\n content.includes('ag-grid-ng2') ||\n content.includes('ag-grid-polymer') ||\n content.includes('ag-grid-aurelia');\n if (isLegacyStyles || hasAgGridSelectors) {\n styleTag.remove();\n }\n });\n };\n\n removeAgGridStyles();\n\n const domNode = document.getElementById('itemsmart-remote'); // or your remote mount node id\n return () => {\n unmountComponentAtNode(domNode);\n };\n}, []);\n```\n\nAdjust `mount`, `ref`, `history`, `containerStore`, `routes`, and the mount node id to match your container’s setup. The important part is calling `removeAgGridStyles()` so legacy AG Grid `<style>` tags are removed and the new theme can apply.\n\n---\n\n## 9. AG Grid license or enterprise features\n\n**Symptom:** AG Grid shows watermark or enterprise features don’t work.\n\n**Fix:** Set the license key once (e.g. in root or layout):\n\n```ts\nimport { LicenseManager } from 'ag-grid-enterprise';\n\nLicenseManager.setLicenseKey('your-license-key');\n```\n\n---\n\n## 10. i18n / locale not applied\n\n**Symptom:** Date pickers, selects, or other components show wrong locale or default English.\n\n**Fix:** Wrap the app with `ImpactNovaI18nProvider` and pass the correct `locale` (and optional `messages`):\n\n```tsx\nimport { ImpactNovaI18nProvider } from 'impact-nova';\n\n<ImpactNovaI18nProvider locale=\"de\">\n <App />\n</ImpactNovaI18nProvider>\n```\n\n---\n\n## 11. React 19 compatibility\n\n**Symptom:** Peer dependency warnings or runtime errors after adding Impact Nova.\n\n**Fix:** Impact Nova targets React 19. Upgrade React and React DOM:\n\n```bash\nnpm install react@^19 react-dom@^19\n```\n\nUse `analyze_project_for_impact_nova` with your `package.json` content to get exact recommended versions and install commands.\n\n---\n\nUse `get_installation_and_config` for full setup steps and `impact-nova://install` for the installation resource.\n";
1
+ export default "# Impact Nova — Troubleshooting\n\nCommon setup and runtime issues when using Impact Nova, and how to fix them.\n\n---\n\n## 1. Duplicate React or AG Grid (Vite)\n\n**Symptom:** \"Invalid hook call\", \"Multiple copies of React\", or AG Grid warnings about multiple instances.\n\n**Fix:** In Vite config, add `resolve.dedupe` so the app uses a single copy of React and AG Grid:\n\n```js\n// vite.config.js / vite.config.ts\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n plugins: [react()],\n resolve: {\n dedupe: ['react', 'react-dom', 'ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react'],\n },\n});\n```\n\n---\n\n## 2. Styles not applying\n\n**Symptom:** Components render but look unstyled or wrong.\n\n**Fix:**\n\n- Import Impact Nova CSS **once** at the app root, **before** your app component: \n `import 'impact-nova/dist/impact-nova.css';` \n Or, if you use **CSS or SCSS (no Tailwind)**, you can `@import 'impact-nova/dist/impact-nova.css';` in your main.css or main.scss. See installation **§5. Using Impact Nova with CSS or SCSS (no Tailwind)**.\n- Ensure your build includes the CSS (no rule excluding `node_modules/impact-nova`).\n- If using Tailwind, ensure the design system tokens aren’t overridden by a conflicting Tailwind theme.\n\n---\n\n## 3. Font (Manrope) not loading\n\n**Symptom:** Text renders in fallback font.\n\n**Fix:**\n\n- Add the Manrope link in `index.html`: \n `<link href=\"https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap\" rel=\"stylesheet\" />`\n- In global CSS or Tailwind base: \n `body { font-family: 'Manrope', sans-serif; }`\n\n---\n\n## 4. Chart component not found or wrong export\n\n**Symptom:** `import { Chart } from 'impact-nova'` fails, Chart doesn't render, or dev throws:\n\n`The requested module '.../highcharts-react-official/dist/highcharts-react.min.js' does not provide an export named 'default'`\n\n**Fix:**\n\n- Use the public subpath: `import { Chart } from 'impact-nova/chart';`\n- Ensure Highcharts is installed: `npm install highcharts@^12 highcharts-react-official@^3`\n- In Vite, add `highcharts-react-official` to `optimizeDeps.include` (the `create-impact-nova` template includes it in `HIGHCHARTS_OPTIMIZE_DEPENDENCIES`). Clear `.vite` cache and restart dev after changing config.\n\n---\n\n## 5. impact-nova-icons SVG warnings in Vite dev\n\n**Symptom:** Hundreds of \"Failed to resolve import\" warnings for `.svg` files from `impact-nova-icons` on dev startup.\n\n**Fix:** Exclude icons from dependency pre-bundling:\n\n```js\noptimizeDeps: {\n exclude: ['impact-nova-icons'],\n},\n```\n\nIf using Module Federation, add an asset URL rewrite plugin for `impact-nova-icons/dist/assets/*2.svg.js` shims.\n\n---\n\n## 6. React 19 — \"Cannot access refs during render\"\n\n**Symptom:** React 19 error about updating or reading refs during render.\n\n**Fix:** Never assign to `ref.current` during render. Use refs only in event handlers, effects, or callbacks. Prefer deriving values during render instead of mirroring props into refs.\n\n---\n\n## 7. HorizontalScroller or other subpath missing\n\n**Symptom:** Import from `impact-nova/horizontal-scroller` (or similar) fails.\n\n**Fix:**\n\n- If the package doesn’t export that subpath, add a Vite alias to the component file and a small TypeScript declaration:\n\n```js\n// vite.config\nresolve: {\n alias: {\n 'impact-nova/horizontal-scroller': resolve(__dirname, 'node_modules/impact-nova/dist/components/ui/horizontal-scroller/horizontal-scroller.js'),\n },\n},\n```\n\n```ts\n// declare module 'impact-nova/horizontal-scroller'\ndeclare module 'impact-nova/horizontal-scroller' {\n const Component: React.ComponentType<{ /* props */ }>;\n export default Component;\n}\n```\n\n---\n\n## 8. AG Grid CSS not applied (legacy container conflict)\n\n**Symptom:** AG Grid in a micro-frontend (MFE) looks wrong or unstyled; the new AG Grid theme is not applied.\n\n**Cause:** The **container** (host app) is loading legacy AG Grid CSS. Those legacy style tags conflict with the new theme, so the MFE’s AG Grid doesn’t get the correct styles.\n\n**Fix:** Apply the fix in the **container** app, not in the MFE/remote repo. In the container, when you mount the remote (e.g. in a `useEffect`), remove the legacy AG Grid style tags from the document so the new theme can apply. Example:\n\n```tsx\n// In the CONTAINER app (not in the MFE repo)\nuseEffect(() => {\n const { onParentNavigate } = mount(ref.current, {\n initialPath: history.location.pathname,\n onNavigate: ({ pathname: nextPathname }) => {\n const { pathname } = history.location;\n if (pathname !== nextPathname) {\n history.push(nextPathname);\n }\n },\n containerStore,\n routes,\n defaultHistory: history,\n });\n\n history.listen(onParentNavigate);\n\n const removeAgGridStyles = () => {\n const styleTags = document.querySelectorAll('style');\n styleTags.forEach((styleTag) => {\n const content = styleTag.textContent || styleTag.innerHTML || '';\n // Legacy AG Grid styles (--ag-legacy-styles-loaded + .ag-icon)\n const isLegacyStyles =\n content.includes('--ag-legacy-styles-loaded') && content.includes('.ag-icon');\n // Generic AG Grid selectors that override the new theme\n const hasAgGridSelectors =\n content.includes('ag-grid,ag-grid-angular') ||\n content.includes('ag-grid, ag-grid-angular') ||\n content.includes('ag-grid-ng2') ||\n content.includes('ag-grid-polymer') ||\n content.includes('ag-grid-aurelia');\n if (isLegacyStyles || hasAgGridSelectors) {\n styleTag.remove();\n }\n });\n };\n\n removeAgGridStyles();\n\n const domNode = document.getElementById('itemsmart-remote'); // or your remote mount node id\n return () => {\n unmountComponentAtNode(domNode);\n };\n}, []);\n```\n\nAdjust `mount`, `ref`, `history`, `containerStore`, `routes`, and the mount node id to match your container’s setup. The important part is calling `removeAgGridStyles()` so legacy AG Grid `<style>` tags are removed and the new theme can apply.\n\n---\n\n## 9. AG Grid license or enterprise features\n\n**Symptom:** AG Grid shows watermark or enterprise features don’t work.\n\n**Fix:** Set the license key once (e.g. in root or layout):\n\n```ts\nimport { LicenseManager } from 'ag-grid-enterprise';\n\nLicenseManager.setLicenseKey('your-license-key');\n```\n\n---\n\n## 10. i18n / locale not applied\n\n**Symptom:** Date pickers, selects, or other components show wrong locale or default English.\n\n**Fix:** Wrap the app with `ImpactNovaI18nProvider` and pass the correct `locale` (and optional `messages`):\n\n```tsx\nimport { ImpactNovaI18nProvider } from 'impact-nova';\n\n<ImpactNovaI18nProvider locale=\"de\">\n <App />\n</ImpactNovaI18nProvider>\n```\n\n---\n\n## 11. React 19 compatibility\n\n**Symptom:** Peer dependency warnings or runtime errors after adding Impact Nova.\n\n**Fix:** Impact Nova targets React 19. Upgrade React and React DOM:\n\n```bash\nnpm install react@^19 react-dom@^19\n```\n\nUse `analyze_project_for_impact_nova` with your `package.json` content to get exact recommended versions and install commands.\n\n---\n\nUse `get_installation_and_config` for full setup steps and `impact-nova://install` for the installation resource.\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "impact-nova",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Enterprise-grade React design system built with React 19, Vite, Tailwind CSS, and Radix UI. Built-in internationalization (i18n) and comprehensive UI component library for scalable, accessible, and performant applications.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",