impact-nova 2.0.5 → 2.0.6

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,66 +1,66 @@
1
- import { jsxs as g, jsx as r } from "react/jsx-runtime";
2
- import { useRef as Xe, useState as te, useCallback as re } from "react";
3
- import { Filter as Ze, Cross as Y } from "impact-nova-icons";
1
+ import { jsxs as y, jsx as r } from "react/jsx-runtime";
2
+ import { useRef as Xe, useState as ee, useCallback as te } from "react";
3
+ import { Filter as Ze, Cross as q } from "impact-nova-icons";
4
4
  import { cn as $e } from "../../../../lib/utils.js";
5
5
  import { DatePicker as Se } from "../../date-picker/date-picker.js";
6
6
  import { MonthPicker as Ae } from "../../date-picker/month-picker.js";
7
7
  import { WeekPicker as He } from "../../date-picker/week-picker.js";
8
- import { Input as G } from "../../input.js";
8
+ import { Input as Y } from "../../input.js";
9
9
  import ze from "../../select/select.js";
10
- import { Popover as et, PopoverTrigger as tt, PopoverContent as rt, PopoverHeader as lt, PopoverTitle as nt, PopoverBody as at } from "../../popover.js";
10
+ import { Popover as et, PopoverTrigger as tt, PopoverContent as rt, PopoverHeader as nt, PopoverTitle as lt, PopoverBody as at } from "../../popover.js";
11
11
  import { useGridHeader as ot } from "./context/grid-header-context.js";
12
- import { getMultiFilterIndices as I, parseInputPattern as Be, mapOperatorToAgGrid as Ie } from "./utils/filter-utils.js";
13
- import { DEFAULT_DATE_DISPLAY_FORMAT as st, serializeWeek as it, serializeMonth as ct, serializeDate as dt, displayDateToIso as le } from "./utils/date-utils.js";
12
+ import { getMultiFilterIndices as B, parseInputPattern as Be, mapOperatorToAgGrid as Ie } from "./utils/filter-utils.js";
13
+ import { DEFAULT_DATE_DISPLAY_FORMAT as st, serializeWeek as it, serializeMonth as ct, serializeDate as dt, displayDateToIso as re } from "./utils/date-utils.js";
14
14
  import { deriveHeaderSearchCommittedState as ut } from "./derive-header-search-state.js";
15
15
  import { useImpactNovaI18n as ft } from "../../../../i18n/ImpactNovaI18nContext.js";
16
16
  const kt = ({
17
- column: k,
18
- api: v,
17
+ column: w,
18
+ api: x,
19
19
  onClose: ne,
20
- handleInlineSearch: ae,
21
- handleClearSearchInline: oe,
22
- onAdvanceSearchClick: se,
23
- toggleAdvanceSearch: ie,
20
+ handleInlineSearch: le,
21
+ handleClearSearchInline: ae,
22
+ onAdvanceSearchClick: oe,
23
+ toggleAdvanceSearch: se,
24
24
  advanceSearchEnabled: We = !1,
25
- selectOptions: V,
25
+ selectOptions: G,
26
26
  isMultiSelect: C,
27
27
  onSelectScrollToBottom: Oe,
28
28
  onSelectSearchChange: Re,
29
- onSelectOpen: ce,
30
- isLoadingSelect: de,
29
+ onSelectOpen: ie,
30
+ isLoadingSelect: ce,
31
31
  enableSpaceSplitting: je = !1,
32
32
  enableBooleanParsing: Ee = !1,
33
33
  enableDateParsing: qe = !1
34
34
  }) => {
35
- const { t: i } = ft(), n = k.getColDef(), d = k.getColId(), L = n?.filter || "agTextColumnFilter", M = L === "agDateColumnFilter", _ = L === "agSetColumnFilter" || V && V.length > 0 || n?.cellDataType === "boolean", U = n?.headerComponentParams?.datePickerVariant || "date", W = M && U === "month", O = M && U === "week", c = n?.headerComponentParams?.fiscalConfig, y = n?.headerComponentParams?.dateDisplayFormat || st, ue = ot(), J = Xe(null), fe = ut({
36
- api: v,
35
+ const { t: i } = ft(), l = w.getColDef(), d = w.getColId(), V = l?.filter || "agTextColumnFilter", M = V === "agDateColumnFilter", L = V === "agSetColumnFilter" || G && G.length > 0 || l?.cellDataType === "boolean", _ = l?.headerComponentParams?.datePickerVariant || "date", I = M && _ === "month", W = M && _ === "week", c = l?.headerComponentParams?.fiscalConfig, b = l?.headerComponentParams?.dateDisplayFormat || st, de = ot(), U = Xe(null), ue = ut({
36
+ api: x,
37
37
  colId: d,
38
- colDef: n,
38
+ colDef: l,
39
39
  isDateFilter: M,
40
- isMonthVariant: W,
41
- isWeekVariant: O,
42
- datePickerVariant: U,
43
- dateDisplayFormat: y
44
- }), [K, Q] = te(null), [Ye, D] = te(!1), S = (e) => Ye && K && K[e] !== void 0 ? K[e] : fe[e], X = S("searchText"), R = S("dateDisplayString"), pe = S("selectedDate"), he = S("selectedMonth"), me = S("selectedWeek"), A = (e) => {
45
- Q((t) => ({ ...fe, ...t, ...e }));
46
- }, x = () => D(!0), b = () => {
47
- D(!1), Q(null);
48
- }, N = (e, t) => {
49
- const a = (l) => l.replace(/[^0-9.\-+eE]/g, ""), s = (l, z) => {
50
- const w = Be(
51
- l,
40
+ isMonthVariant: I,
41
+ isWeekVariant: W,
42
+ datePickerVariant: _,
43
+ dateDisplayFormat: b
44
+ }), [J, K] = ee(null), [Ye, fe] = ee(!1), k = (e) => Ye && J && J[e] !== void 0 ? J[e] : ue[e], Q = k("searchText"), O = k("dateDisplayString"), pe = k("selectedDate"), he = k("selectedMonth"), me = k("selectedWeek"), S = (e) => {
45
+ K((t) => ({ ...ue, ...t, ...e }));
46
+ }, p = () => fe(!0), h = () => {
47
+ fe(!1), K(null);
48
+ }, D = (e, t) => {
49
+ const a = (n) => n.replace(/[^0-9.\-+eE]/g, ""), s = (n, H) => {
50
+ const P = Be(
51
+ n,
52
52
  je,
53
53
  Ee,
54
54
  qe
55
55
  );
56
56
  if (console.log("[HeaderSearchInput] Pattern Debug:", {
57
- input: l,
58
- filterType: z,
59
- parsed: w
60
- }), w.conditions.length === 0) return null;
57
+ input: n,
58
+ filterType: H,
59
+ parsed: P
60
+ }), P.conditions.length === 0) return null;
61
61
  const we = (u) => {
62
62
  let F = Ie(u.operator);
63
- if (z === "number") {
63
+ if (H === "number") {
64
64
  const ke = parseFloat(a(u.value));
65
65
  return ["contains", "notContains", "startsWith", "endsWith"].includes(
66
66
  F
@@ -78,18 +78,18 @@ const kt = ({
78
78
  filterType: "text"
79
79
  };
80
80
  };
81
- let B = null;
82
- if (w.conditions.length === 1)
83
- B = we(w.conditions[0]);
81
+ let z = null;
82
+ if (P.conditions.length === 1)
83
+ z = we(P.conditions[0]);
84
84
  else {
85
- const u = w.conditions.map(we).filter((F) => F !== null);
86
- u.length === 0 ? B = null : u.length === 1 ? B = u[0] : B = {
87
- filterType: z,
88
- operator: w.logic,
85
+ const u = P.conditions.map(we).filter((F) => F !== null);
86
+ u.length === 0 ? z = null : u.length === 1 ? z = u[0] : z = {
87
+ filterType: H,
88
+ operator: P.logic,
89
89
  conditions: u
90
90
  };
91
91
  }
92
- return B;
92
+ return z;
93
93
  };
94
94
  let o = null;
95
95
  if (!(e === null || e === "" || Array.isArray(e) && e.length === 0))
@@ -99,67 +99,67 @@ const kt = ({
99
99
  filterType: "set"
100
100
  };
101
101
  else if (t === "date")
102
- if (O && e && typeof e == "object" && "startDate" in e && "endDate" in e) {
103
- const l = it(e);
102
+ if (W && e && typeof e == "object" && "startDate" in e && "endDate" in e) {
103
+ const n = it(e);
104
104
  o = {
105
105
  type: "inRange",
106
- dateFrom: l.dateFrom,
107
- dateTo: l.dateTo,
106
+ dateFrom: n.dateFrom,
107
+ dateTo: n.dateTo,
108
108
  filterType: "date"
109
109
  };
110
- } else if (W && e && typeof e == "object" && "month" in e && "year" in e) {
111
- const l = ct(e);
110
+ } else if (I && e && typeof e == "object" && "month" in e && "year" in e) {
111
+ const n = ct(e);
112
112
  o = {
113
113
  type: "inRange",
114
- dateFrom: l.dateFrom,
115
- dateTo: l.dateTo,
114
+ dateFrom: n.dateFrom,
115
+ dateTo: n.dateTo,
116
116
  filterType: "date"
117
117
  };
118
118
  } else {
119
- const l = e instanceof Date ? dt(e) : null;
120
- o = l ? { type: "equals", dateFrom: l, filterType: "date" } : null;
119
+ const n = e instanceof Date ? dt(e) : null;
120
+ o = n ? { type: "equals", dateFrom: n, filterType: "date" } : null;
121
121
  }
122
122
  else {
123
- const l = n.filter === "agMultiColumnFilter" ? I(n) : null, z = l ? l.text !== -1 ? "text" : "number" : L === "agNumberColumnFilter" ? "number" : "text";
124
- o = s(String(e), z);
123
+ const n = l.filter === "agMultiColumnFilter" ? B(l) : null, H = n ? n.text !== -1 ? "text" : "number" : V === "agNumberColumnFilter" ? "number" : "text";
124
+ o = s(String(e), H);
125
125
  }
126
- const f = n.filter === "agMultiColumnFilter" ? I(n) : null, T = f ? t === "text" ? f.text !== -1 ? f.text : f.number : t === "set" ? f.set : f.date : 0;
127
- $(o, T);
128
- }, Z = (e) => {
129
- if (ae) {
130
- ae(Array.isArray(e) ? e.join(",") : e);
126
+ const f = l.filter === "agMultiColumnFilter" ? B(l) : null, T = f ? t === "text" ? f.text !== -1 ? f.text : f.number : t === "set" ? f.set : f.date : 0;
127
+ Z(o, T);
128
+ }, X = (e) => {
129
+ if (le) {
130
+ le(Array.isArray(e) ? e.join(",") : e);
131
131
  return;
132
132
  }
133
- N(e, M ? "date" : "text");
133
+ D(e, M ? "date" : "text");
134
134
  }, ge = (e) => {
135
135
  const t = e.target.value;
136
- A({ searchText: t }), Z(t);
136
+ S({ searchText: t }), X(t);
137
137
  }, ve = (e) => {
138
- A({ selectedDate: e }), Z(e);
138
+ S({ selectedDate: e }), X(e);
139
139
  }, ye = (e) => {
140
- A({ selectedMonth: e }), N(e || null, "date");
140
+ S({ selectedMonth: e }), D(e || null, "date");
141
141
  }, xe = (e) => {
142
- A({ selectedWeek: e }), N(e || null, "date");
142
+ S({ selectedWeek: e }), D(e || null, "date");
143
143
  }, Ge = (e) => {
144
144
  if (!e.trim()) return null;
145
145
  const t = Be(e, !1, !1, !1);
146
146
  if (t.conditions.length === 0) return null;
147
147
  const a = (o) => {
148
- let m = Ie(o.operator);
148
+ let v = Ie(o.operator);
149
149
  if (["contains", "notContains", "startsWith", "endsWith"].includes(
150
- m
151
- ) && (m = m === "notContains" ? "notEqual" : "equals"), o.operator === "inRange") {
152
- let T = le(o.value, y), l = le(o.valueTo || "", y);
153
- return !T || !l ? null : (T > l && ([T, l] = [l, T]), {
150
+ v
151
+ ) && (v = v === "notContains" ? "notEqual" : "equals"), o.operator === "inRange") {
152
+ let T = re(o.value, b), n = re(o.valueTo || "", b);
153
+ return !T || !n ? null : (T > n && ([T, n] = [n, T]), {
154
154
  type: "inRange",
155
155
  dateFrom: T,
156
- dateTo: l,
156
+ dateTo: n,
157
157
  filterType: "date"
158
158
  });
159
159
  }
160
- const f = le(o.value, y);
160
+ const f = re(o.value, b);
161
161
  return f ? {
162
- type: m,
162
+ type: v,
163
163
  dateFrom: f,
164
164
  filterType: "date"
165
165
  } : null;
@@ -172,47 +172,47 @@ const kt = ({
172
172
  operator: t.logic,
173
173
  conditions: s
174
174
  };
175
- }, $ = re(
175
+ }, Z = te(
176
176
  (e, t) => {
177
- const a = v.getFilterModel(), s = { ...a };
178
- if (n.filter === "agMultiColumnFilter") {
177
+ const a = x.getFilterModel(), s = { ...a };
178
+ if (l.filter === "agMultiColumnFilter") {
179
179
  if (t === -1) return;
180
- const o = a[d], m = o && o.filterType === "multi" ? [...o.filterModels || []] : Array(n.filterParams?.filters?.length || 1).fill(null);
181
- m[t] = e, m.every((f) => f === null) ? delete s[d] : s[d] = {
180
+ const o = a[d], v = o && o.filterType === "multi" ? [...o.filterModels || []] : Array(l.filterParams?.filters?.length || 1).fill(null);
181
+ v[t] = e, v.every((f) => f === null) ? delete s[d] : s[d] = {
182
182
  filterType: "multi",
183
- filterModels: m
183
+ filterModels: v
184
184
  };
185
185
  } else
186
186
  e ? s[d] = e : delete s[d];
187
- v.setFilterModel(s), v.onFilterChanged();
187
+ x.setFilterModel(s), x.onFilterChanged();
188
188
  },
189
- [v, d, n]
190
- ), be = re(
189
+ [x, d, l]
190
+ ), be = te(
191
191
  (e) => {
192
- const t = n.filter === "agMultiColumnFilter" ? I(n).date : 0;
193
- $(e, t);
192
+ const t = l.filter === "agMultiColumnFilter" ? B(l).date : 0;
193
+ Z(e, t);
194
194
  },
195
- [n, $]
195
+ [l, Z]
196
196
  ), Fe = (e) => {
197
197
  const t = e.target.value.replace(/[^0-9/\-!=><+,~]/g, "");
198
- if (A({ dateDisplayString: t }), !t.trim()) {
198
+ if (S({ dateDisplayString: t }), !t.trim()) {
199
199
  be(null);
200
200
  return;
201
201
  }
202
202
  const a = Ge(t);
203
203
  a && be(a);
204
- }, ee = () => {
205
- Q(null), Z(""), oe && oe();
206
- }, j = (e) => {
207
- N(e, "set");
208
- }, E = V || (n?.cellDataType === "boolean" ? [
204
+ }, $ = () => {
205
+ K(null), X(""), ae && ae();
206
+ }, R = (e) => {
207
+ D(e, "set");
208
+ }, j = G || (l?.cellDataType === "boolean" ? [
209
209
  { label: i("gridHeader.true"), value: "true" },
210
210
  { label: i("gridHeader.false"), value: "false" }
211
- ] : []), Ce = re(() => {
212
- const e = v.getFilterModel()[d];
211
+ ] : []), Ce = te(() => {
212
+ const e = x.getFilterModel()[d];
213
213
  if (!e) return [];
214
214
  if ("filterType" in e && e.filterType === "multi" && e.filterModels) {
215
- const a = I(k.getColDef()).set;
215
+ const a = B(w.getColDef()).set;
216
216
  if (a !== -1) {
217
217
  const s = e.filterModels[a];
218
218
  if (s?.filterType === "set" && s.values)
@@ -225,29 +225,29 @@ const kt = ({
225
225
  return [String(e.filter)];
226
226
  }
227
227
  return [];
228
- }, [v, d, k]), [q, H] = te(null), Me = () => {
229
- const e = q !== null ? q : Ce();
230
- return C ? E.filter((t) => e.includes(t.value)) : E.find((t) => e.includes(t.value)) || null;
228
+ }, [x, d, w]), [E, A] = ee(null), Me = () => {
229
+ const e = E !== null ? E : Ce();
230
+ return C ? j.filter((t) => e.includes(t.value)) : j.find((t) => e.includes(t.value)) || null;
231
231
  }, Te = (e) => {
232
232
  let t = [];
233
233
  if (Array.isArray(e) ? t = e.map((a) => a.value) : e && typeof e == "object" && "value" in e && (t = [e.value]), !C) {
234
- j(t), e && ne();
234
+ R(t), e && ne();
235
235
  return;
236
236
  }
237
- H(t);
237
+ A(t);
238
238
  }, Ve = () => {
239
- j([]), H([]);
239
+ R([]), A([]);
240
240
  }, Le = (e) => {
241
241
  if (C) {
242
242
  if (e !== void 0) {
243
243
  let t = [];
244
- Array.isArray(e) ? t = e.map((a) => a.value) : e && typeof e == "object" && "value" in e ? t = [e.value] : e === null && (t = []), j(t), H(null);
244
+ Array.isArray(e) ? t = e.map((a) => a.value) : e && typeof e == "object" && "value" in e ? t = [e.value] : e === null && (t = []), R(t), A(null);
245
245
  return;
246
246
  }
247
- q !== null && (j(q), H(null));
247
+ E !== null && (R(E), A(null));
248
248
  }
249
249
  }, _e = () => {
250
- H(Ce()), ce && ce();
250
+ A(Ce()), ie && ie();
251
251
  }, Ue = () => We ? /* @__PURE__ */ r(
252
252
  "svg",
253
253
  {
@@ -259,7 +259,7 @@ const kt = ({
259
259
  width: "18",
260
260
  height: "18",
261
261
  onClick: (e) => {
262
- e.stopPropagation(), J.current && J.current.blur(), se ? se(k) : ie ? ie(d) : ue && ue.openAdvancedFilter(d);
262
+ e.stopPropagation(), U.current && U.current.blur(), oe ? oe(w) : se ? se(d) : de && de.openAdvancedFilter(d);
263
263
  },
264
264
  children: /* @__PURE__ */ r("path", { d: "M3 17v2h6v-2H3zM3 5v2h10V5H3zm10 16v-2h8v-2h-8v-2h-2v6h2zM7 9v2H3v2h4v2h2V9H7zm14 4v-2H11v2h10zm-6-4h2V7h4V5h-4V3h-2v6z" })
265
265
  }
@@ -268,23 +268,23 @@ const kt = ({
268
268
  {
269
269
  onClick: ne,
270
270
  className: "cursor-pointer shrink-0 text-brand hover:text-brand-strong",
271
- children: /* @__PURE__ */ r(Y, { size: "xs" })
271
+ children: /* @__PURE__ */ r(q, { size: "xs" })
272
272
  }
273
- ), P = n.filter === "agMultiColumnFilter", p = I(n);
274
- let h = "text";
275
- P ? h = p.set !== -1 ? "set" : p.date !== -1 ? "date" : "text" : _ ? h = "set" : M && (h = "date");
276
- const Ke = P ? p.text !== -1 || p.number !== -1 : !M && !_, De = P ? p.set !== -1 : _, Ne = P ? p.date !== -1 : M, Qe = v.getFilterModel()[d], Pe = P && Qe?.filterModels?.some((e, t) => {
277
- const a = t === p.text || t === p.number ? "text" : t === p.set ? "set" : "date";
278
- return e !== null && a !== h;
273
+ ), N = l.filter === "agMultiColumnFilter", m = B(l);
274
+ let g = "text";
275
+ N ? g = m.set !== -1 ? "set" : m.date !== -1 ? "date" : "text" : L ? g = "set" : M && (g = "date");
276
+ const Ke = N ? m.text !== -1 || m.number !== -1 : !M && !L, De = N ? m.set !== -1 : L, Ne = N ? m.date !== -1 : M, Qe = x.getFilterModel()[d], Pe = N && Qe?.filterModels?.some((e, t) => {
277
+ const a = t === m.text || t === m.number ? "text" : t === m.set ? "set" : "date";
278
+ return e !== null && a !== g;
279
279
  });
280
- return /* @__PURE__ */ g("div", { className: "ag-header-cell-label flex items-center gap-1 w-full bg-brand-tint px-1 py-2 ag-header-cell-search-active h-full", children: [
281
- h === "set" && De ? /* @__PURE__ */ r(
280
+ return /* @__PURE__ */ y("div", { className: "ag-header-cell-label flex items-center gap-1 w-full bg-brand-tint px-1 py-2 ag-header-cell-search-active h-full", children: [
281
+ g === "set" && De ? /* @__PURE__ */ r(
282
282
  ze,
283
283
  {
284
- options: E,
284
+ options: j,
285
285
  value: Me(),
286
286
  onChange: Te,
287
- isMulti: C !== void 0 ? C : n?.cellDataType !== "boolean",
287
+ isMulti: C !== void 0 ? C : l?.cellDataType !== "boolean",
288
288
  placeholder: i("filter.select"),
289
289
  className: "w-full bg-canvas-elevated",
290
290
  parentClassName: "flex-1 min-w-0",
@@ -296,38 +296,38 @@ const kt = ({
296
296
  onMenuScrollToBottom: Oe,
297
297
  onInputChange: Re,
298
298
  onClearAll: Ve,
299
- isLoading: de,
300
- onFocus: x,
301
- onBlur: b
299
+ isLoading: ce,
300
+ onFocus: p,
301
+ onBlur: h
302
302
  }
303
- ) : h === "date" && Ne ? R ? /* @__PURE__ */ r(
304
- G,
303
+ ) : g === "date" && Ne ? O ? /* @__PURE__ */ r(
304
+ Y,
305
305
  {
306
- value: R,
306
+ value: O,
307
307
  onChange: Fe,
308
308
  placeholder: i("filter.search"),
309
309
  className: "w-full bg-canvas-elevated",
310
310
  autoFocus: !0,
311
- onFocus: x,
312
- onBlur: b,
311
+ onFocus: p,
312
+ onBlur: h,
313
313
  suffix: /* @__PURE__ */ r(
314
314
  "button",
315
315
  {
316
316
  onClick: (e) => {
317
- e.stopPropagation(), ee();
317
+ e.stopPropagation(), $();
318
318
  },
319
319
  className: "cursor-pointer text-navigation-muted hover:text-brand-variant-hover",
320
- children: /* @__PURE__ */ r(Y, { size: "xs" })
320
+ children: /* @__PURE__ */ r(q, { size: "xs" })
321
321
  }
322
322
  )
323
323
  }
324
- ) : O ? /* @__PURE__ */ r(
324
+ ) : W ? /* @__PURE__ */ r(
325
325
  He,
326
326
  {
327
327
  value: me || void 0,
328
328
  onChange: (e) => xe(e || null),
329
329
  placeholder: i("datePicker.selectWeek"),
330
- format: y,
330
+ format: b,
331
331
  minDate: /* @__PURE__ */ new Date("2000-01-01"),
332
332
  maxDate: /* @__PURE__ */ new Date("2100-12-31"),
333
333
  className: "w-full bg-canvas-elevated",
@@ -339,7 +339,7 @@ const kt = ({
339
339
  fiscalYearStartMonth: c?.fiscalYearStartMonth,
340
340
  weekStartsOn: c?.weekStartsOn
341
341
  }
342
- ) : W ? /* @__PURE__ */ r(
342
+ ) : I ? /* @__PURE__ */ r(
343
343
  Ae,
344
344
  {
345
345
  value: he || void 0,
@@ -349,8 +349,8 @@ const kt = ({
349
349
  maxDate: /* @__PURE__ */ new Date("2100-12-31"),
350
350
  className: "w-full bg-canvas-elevated",
351
351
  showFooter: !1,
352
- onFocus: x,
353
- onBlur: b
352
+ onFocus: p,
353
+ onBlur: h
354
354
  }
355
355
  ) : /* @__PURE__ */ r(
356
356
  Se,
@@ -358,40 +358,40 @@ const kt = ({
358
358
  value: pe || void 0,
359
359
  onChange: (e) => ve(e || null),
360
360
  placeholder: i("filter.selectDate"),
361
- format: y,
361
+ format: b,
362
362
  minDate: /* @__PURE__ */ new Date("2000-01-01"),
363
363
  maxDate: /* @__PURE__ */ new Date("2100-12-31"),
364
364
  className: "w-full bg-canvas-elevated",
365
365
  weekStartsOn: c?.weekStartsOn,
366
- onFocus: x,
367
- onBlur: b
366
+ onFocus: p,
367
+ onBlur: h
368
368
  }
369
369
  ) : /* @__PURE__ */ r(
370
- G,
370
+ Y,
371
371
  {
372
- value: X,
372
+ value: Q,
373
373
  onChange: ge,
374
374
  placeholder: i("filter.search"),
375
375
  type: "text",
376
376
  autoFocus: !0,
377
- ref: J,
378
- onFocus: x,
379
- onBlur: b,
380
- suffix: X && /* @__PURE__ */ r(
377
+ ref: U,
378
+ onFocus: p,
379
+ onBlur: h,
380
+ suffix: Q && /* @__PURE__ */ r(
381
381
  "button",
382
382
  {
383
383
  onClick: (e) => {
384
- e.stopPropagation(), ee();
384
+ e.stopPropagation(), $();
385
385
  },
386
386
  className: "cursor-pointer text-navigation-muted hover:text-brand-variant-hover",
387
- children: /* @__PURE__ */ r(Y, { size: "xs" })
387
+ children: /* @__PURE__ */ r(q, { size: "xs" })
388
388
  }
389
389
  )
390
390
  }
391
391
  ),
392
- /* @__PURE__ */ g("div", { className: "flex items-center gap-1.5 shrink-0", children: [
393
- P && /* @__PURE__ */ g(et, { children: [
394
- /* @__PURE__ */ r(tt, { asChild: !0, children: /* @__PURE__ */ g(
392
+ /* @__PURE__ */ y("div", { className: "flex items-center gap-1.5 shrink-0", children: [
393
+ N && /* @__PURE__ */ y(et, { children: [
394
+ /* @__PURE__ */ r(tt, { asChild: !0, children: /* @__PURE__ */ y(
395
395
  "button",
396
396
  {
397
397
  type: "button",
@@ -412,67 +412,67 @@ const kt = ({
412
412
  ]
413
413
  }
414
414
  ) }),
415
- /* @__PURE__ */ g(rt, { align: "end", className: "w-[300px]", children: [
416
- /* @__PURE__ */ r(lt, { children: /* @__PURE__ */ r(nt, { children: i("gridHeader.activeFilters") }) }),
417
- /* @__PURE__ */ g(at, { className: "flex flex-col gap-4", children: [
418
- h !== "text" && Ke && /* @__PURE__ */ g("div", { className: "flex flex-col gap-1.5", children: [
415
+ /* @__PURE__ */ y(rt, { align: "end", className: "w-[300px]", children: [
416
+ /* @__PURE__ */ r(nt, { children: /* @__PURE__ */ r(lt, { children: i("gridHeader.activeFilters") }) }),
417
+ /* @__PURE__ */ y(at, { className: "flex flex-col gap-4", children: [
418
+ g !== "text" && Ke && /* @__PURE__ */ y("div", { className: "flex flex-col gap-1.5", children: [
419
419
  /* @__PURE__ */ r("span", { className: "text-xs font-semibold text-content-tertiary", children: i("gridHeader.textSearch") }),
420
420
  /* @__PURE__ */ r(
421
- G,
421
+ Y,
422
422
  {
423
- value: X,
423
+ value: Q,
424
424
  onChange: ge,
425
425
  placeholder: i("filter.searchPlaceholder"),
426
426
  className: "bg-canvas-elevated",
427
- onFocus: () => D(!0),
428
- onBlur: () => D(!1)
427
+ onFocus: p,
428
+ onBlur: h
429
429
  }
430
430
  )
431
431
  ] }),
432
- h !== "set" && De && /* @__PURE__ */ g("div", { className: "flex flex-col gap-1.5", children: [
432
+ g !== "set" && De && /* @__PURE__ */ y("div", { className: "flex flex-col gap-1.5", children: [
433
433
  /* @__PURE__ */ r("span", { className: "text-xs font-semibold text-content-tertiary", children: i("gridHeader.selectionFilter") }),
434
434
  /* @__PURE__ */ r(
435
435
  ze,
436
436
  {
437
- options: E,
437
+ options: j,
438
438
  value: Me(),
439
439
  onChange: Te,
440
- isMulti: C !== void 0 ? C : n?.cellDataType !== "boolean",
440
+ isMulti: C !== void 0 ? C : l?.cellDataType !== "boolean",
441
441
  placeholder: i("filter.select"),
442
442
  className: "w-full bg-canvas-elevated",
443
- isLoading: de,
444
- onFocus: () => D(!0),
445
- onBlur: () => D(!1)
443
+ isLoading: ce,
444
+ onFocus: p,
445
+ onBlur: h
446
446
  }
447
447
  )
448
448
  ] }),
449
- h !== "date" && Ne && /* @__PURE__ */ g("div", { className: "flex flex-col gap-1.5", children: [
449
+ g !== "date" && Ne && /* @__PURE__ */ y("div", { className: "flex flex-col gap-1.5", children: [
450
450
  /* @__PURE__ */ r("span", { className: "text-xs font-semibold text-content-tertiary", children: i("gridHeader.dateFilter") }),
451
- R ? /* @__PURE__ */ r(
452
- G,
451
+ O ? /* @__PURE__ */ r(
452
+ Y,
453
453
  {
454
- value: R,
454
+ value: O,
455
455
  onChange: Fe,
456
456
  className: "w-full bg-canvas-elevated",
457
- onFocus: x,
458
- onBlur: b,
457
+ onFocus: p,
458
+ onBlur: h,
459
459
  suffix: /* @__PURE__ */ r(
460
460
  "button",
461
461
  {
462
462
  onClick: (e) => {
463
- e.stopPropagation(), ee();
463
+ e.stopPropagation(), $();
464
464
  },
465
465
  className: "cursor-pointer text-navigation-muted hover:text-brand-variant-hover",
466
- children: /* @__PURE__ */ r(Y, { size: "xs" })
466
+ children: /* @__PURE__ */ r(q, { size: "xs" })
467
467
  }
468
468
  )
469
469
  }
470
- ) : O ? /* @__PURE__ */ r(
470
+ ) : W ? /* @__PURE__ */ r(
471
471
  He,
472
472
  {
473
473
  value: me || void 0,
474
474
  onChange: (e) => xe(e || null),
475
- format: y,
475
+ format: b,
476
476
  className: "w-full bg-canvas-elevated",
477
477
  showFooter: !1,
478
478
  calendarType: c?.calendarType,
@@ -482,26 +482,26 @@ const kt = ({
482
482
  fiscalYearStartMonth: c?.fiscalYearStartMonth,
483
483
  weekStartsOn: c?.weekStartsOn
484
484
  }
485
- ) : W ? /* @__PURE__ */ r(
485
+ ) : I ? /* @__PURE__ */ r(
486
486
  Ae,
487
487
  {
488
488
  value: he || void 0,
489
489
  onChange: (e) => ye(e || null),
490
490
  className: "w-full bg-canvas-elevated",
491
491
  showFooter: !1,
492
- onFocus: x,
493
- onBlur: b
492
+ onFocus: p,
493
+ onBlur: h
494
494
  }
495
495
  ) : /* @__PURE__ */ r(
496
496
  Se,
497
497
  {
498
498
  value: pe || void 0,
499
499
  onChange: (e) => ve(e || null),
500
- format: y,
500
+ format: b,
501
501
  className: "w-full bg-canvas-elevated",
502
502
  weekStartsOn: c?.weekStartsOn,
503
- onFocus: x,
504
- onBlur: b
503
+ onFocus: p,
504
+ onBlur: h
505
505
  }
506
506
  )
507
507
  ] })
@@ -11,13 +11,13 @@ import { GridHeaderContext as Ae } from "./headers/context/grid-header-context.j
11
11
  import { convertToAgGridFilterModel as Re, getMultiFilterIndices as Ge, convertFromAgGridFilterModel as ke } from "./headers/utils/filter-utils.js";
12
12
  import { ColumnSettingsMenu as je } from "./headers/column-menu/column-settings-menu.js";
13
13
  import { AG_GRID_VALUE_FORMATTERS as we } from "./value-formatters.js";
14
- import { useGridAutoSizeStrategyOnResize as Te } from "./useGridAutoSizeStrategyOnResize.js";
14
+ import { useGridAutoSizeStrategyOnResize as Ie } from "./useGridAutoSizeStrategyOnResize.js";
15
15
  /* empty css */
16
16
  import { refreshGridAutoSizeStrategy as et } from "./refreshGridAutoSizeStrategy.js";
17
17
  import { subscribeGridApiEvent as rt, subscribeGridApiEvents as nt } from "./grid-api-event-subscription.js";
18
- const Pe = me(() => import("./headers/advanced-filter/advanced-filter-dialog.js"));
18
+ const Te = me(() => import("./headers/advanced-filter/advanced-filter-dialog.js"));
19
19
  Ce.registerModules([ye, be, ve]);
20
- const F = "", O = "";
20
+ const F = "", H = "";
21
21
  function K(i) {
22
22
  return i.getColumns()?.some((n) => n.getColDef().headerCheckboxSelection) ?? !1;
23
23
  }
@@ -35,18 +35,18 @@ const U = (i) => {
35
35
  l.push("");
36
36
  continue;
37
37
  }
38
- const a = i[m];
39
- if (a == null) {
38
+ const u = i[m];
39
+ if (u == null) {
40
40
  l.push("");
41
41
  continue;
42
42
  }
43
- if (typeof a == "object" && "value" in a) {
44
- const c = a.value;
43
+ if (typeof u == "object" && "value" in u) {
44
+ const c = u.value;
45
45
  l.push(c == null ? "" : String(c));
46
46
  continue;
47
47
  }
48
- if (typeof a != "object") {
49
- l.push(String(a));
48
+ if (typeof u != "object") {
49
+ l.push(String(u));
50
50
  continue;
51
51
  }
52
52
  l.push("");
@@ -74,18 +74,18 @@ function Qe({
74
74
  defaultColGroupDef: l,
75
75
  columnDefs: h,
76
76
  valueFormatters: m,
77
- onGridReady: a,
77
+ onGridReady: u,
78
78
  onGridPreDestroyed: c,
79
79
  onFilterChanged: b,
80
80
  onSelectionChanged: C,
81
81
  onModelUpdated: M,
82
- ensureDomOrder: T = !0,
83
- autoSizeStrategy: P,
82
+ ensureDomOrder: I = !0,
83
+ autoSizeStrategy: T,
84
84
  ...g
85
85
  }) {
86
- const u = S(null), I = S(null), [D, L] = w(null);
87
- Te(D, I, P);
88
- const [J, N] = w(!1), [X, _] = w(null), [B, V] = w(!1), E = S(null), H = S(null), A = S(null), Q = f(() => [], []), Y = y(() => ({
86
+ const a = S(null), O = S(null), [P, L] = w(null);
87
+ Ie(P, O, T);
88
+ const [B, N] = w(!1), [J, _] = w(null), [X, V] = w(!1), E = S(null), D = S(null), A = S(null), Q = f(() => [], []), Y = y(() => ({
89
89
  numericColumn: {
90
90
  cellClass: "ag-right-aligned-cell",
91
91
  headerClass: "ag-right-aligned-header",
@@ -108,14 +108,14 @@ function Qe({
108
108
  }
109
109
  }), []), R = y(() => ({
110
110
  openSearch: (e) => {
111
- if (!u.current) return;
112
- const t = u.current.getGridOption("context") || {};
113
- u.current.setGridOption("context", { ...t, activeSearchColumnId: e }), u.current.refreshHeader();
111
+ if (!a.current) return;
112
+ const t = a.current.getGridOption("context") || {};
113
+ a.current.setGridOption("context", { ...t, activeSearchColumnId: e }), a.current.refreshHeader();
114
114
  },
115
115
  closeSearch: () => {
116
- if (!u.current) return;
117
- const e = u.current.getGridOption("context") || {};
118
- u.current.setGridOption("context", { ...e, activeSearchColumnId: null }), u.current.refreshHeader();
116
+ if (!a.current) return;
117
+ const e = a.current.getGridOption("context") || {};
118
+ a.current.setGridOption("context", { ...e, activeSearchColumnId: null }), a.current.refreshHeader();
119
119
  },
120
120
  openAdvancedFilter: (e) => {
121
121
  _(e || null), N(!0);
@@ -124,15 +124,15 @@ function Qe({
124
124
  N(!1), _(null);
125
125
  },
126
126
  applyAdvancedFilter: (e) => {
127
- if (!u.current) return;
127
+ if (!a.current) return;
128
128
  const t = Re(e);
129
- u.current.setFilterModel(t), u.current.onFilterChanged(), u.current.refreshHeader();
129
+ a.current.setFilterModel(t), a.current.onFilterChanged(), a.current.refreshHeader();
130
130
  },
131
131
  openMenu: (e, t, o = "column") => {
132
- E.current = e, H.current = t, A.current = o, V(!0);
132
+ E.current = e, D.current = t, A.current = o, V(!0);
133
133
  },
134
134
  closeMenu: () => {
135
- E.current = null, H.current = null, A.current = null, V(!1);
135
+ E.current = null, D.current = null, A.current = null, V(!1);
136
136
  },
137
137
  // Getters read from refs - O(1) per header, no memory allocation
138
138
  get activeMenuColumnId() {
@@ -142,17 +142,17 @@ function Qe({
142
142
  return A.current;
143
143
  }
144
144
  }), []), Z = f((e) => {
145
- u.current = e.api, L(e.api);
145
+ a.current = e.api, L(e.api);
146
146
  const t = e.api.getGridOption("context") || {};
147
- e.api.setGridOption("context", { ...t, activeSearchColumnId: null }), a && a(e);
148
- }, [a]), ee = f(
147
+ e.api.setGridOption("context", { ...t, activeSearchColumnId: null }), u && u(e);
148
+ }, [u]), ee = f(
149
149
  (e) => {
150
- u.current = null, L(null), c?.(e);
150
+ a.current = null, L(null), c?.(e);
151
151
  },
152
152
  [c]
153
153
  ), te = f(
154
154
  (e) => {
155
- e.api.refreshHeader(), b?.(e);
155
+ e.api.getGridOption("context")?.activeSearchColumnId || e.api.refreshHeader(), b?.(e);
156
156
  },
157
157
  [b]
158
158
  ), re = f(
@@ -167,7 +167,7 @@ function Qe({
167
167
  [M]
168
168
  );
169
169
  ge(() => {
170
- const e = I.current;
170
+ const e = O.current;
171
171
  if (!e) return;
172
172
  const t = (o) => {
173
173
  if (o.key !== "Enter" && o.key !== " ") return;
@@ -227,11 +227,11 @@ function Qe({
227
227
  const d = o[0]?.field?.split(".").pop(), x = d ? t[d] : void 0;
228
228
  return x && typeof x == "object" && "value" in x ? x.value ?? "" : r[0];
229
229
  }
230
- return O + r.join(F);
230
+ return H + r.join(F);
231
231
  }
232
232
  const s = Object.entries(t).map(([, r]) => r && typeof r == "object" && "value" in r ? r.value : typeof r != "object" && typeof r < "u" ? r : null).filter((r) => r != null);
233
233
  return s.length === 0 ? "" : s.length === 1 ? s[0] : s.join(F);
234
- }, []), ue = f((e) => {
234
+ }, []), ae = f((e) => {
235
235
  if (typeof e.value == "string") {
236
236
  const t = e.value.trim();
237
237
  if (t.startsWith("{") || t.startsWith("["))
@@ -242,9 +242,9 @@ function Qe({
242
242
  }
243
243
  }
244
244
  return e.value;
245
- }, []), ae = f((e) => {
245
+ }, []), ue = f((e) => {
246
246
  const t = e?.data ?? "";
247
- if (!t.includes(F) && !t.includes(O)) {
247
+ if (!t.includes(F) && !t.includes(H)) {
248
248
  $(t);
249
249
  return;
250
250
  }
@@ -256,7 +256,7 @@ function Qe({
256
256
  o.push("");
257
257
  continue;
258
258
  }
259
- const k = d.split(" ").map((p) => p.startsWith(O) ? { isSplit: !0, slots: p.slice(1).split(F) } : { isSplit: !1, slots: p.split(F) }), W = Math.max(1, ...k.map((p) => p.slots.length));
259
+ const k = d.split(" ").map((p) => p.startsWith(H) ? { isSplit: !0, slots: p.slice(1).split(F) } : { isSplit: !1, slots: p.split(F) }), W = Math.max(1, ...k.map((p) => p.slots.length));
260
260
  if (W === 1) {
261
261
  o.push(k.map((p) => p.slots[0] ?? "").join(" "));
262
262
  continue;
@@ -298,7 +298,7 @@ function Qe({
298
298
  ...g.defaultExcelExportParams ?? {}
299
299
  }), [G, g.defaultExcelExportParams]);
300
300
  return /* @__PURE__ */ fe(Ae.Provider, { value: R, children: [
301
- /* @__PURE__ */ v("div", { ref: I, style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ v(
301
+ /* @__PURE__ */ v("div", { ref: O, style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ v(
302
302
  xe,
303
303
  {
304
304
  theme: Se,
@@ -313,16 +313,16 @@ function Qe({
313
313
  onModelUpdated: ne,
314
314
  components: ie,
315
315
  processCellForClipboard: se,
316
- processCellFromClipboard: ue,
317
- sendToClipboard: ae,
318
- ensureDomOrder: T,
316
+ processCellFromClipboard: ae,
317
+ sendToClipboard: ue,
318
+ ensureDomOrder: I,
319
319
  suppressHeaderFocus: !1,
320
320
  suppressFocusAfterRefresh: !0,
321
321
  suppressGroupRowsSticky: !0,
322
322
  hidePaddedHeaderRows: !0,
323
323
  suppressServerSideFullWidthLoadingRow: !0,
324
324
  columnTypes: Y,
325
- autoSizeStrategy: P,
325
+ autoSizeStrategy: T,
326
326
  ...g,
327
327
  defaultCsvExportParams: ce,
328
328
  defaultExcelExportParams: de,
@@ -331,29 +331,29 @@ function Qe({
331
331
  ) }),
332
332
  i,
333
333
  /* @__PURE__ */ v(
334
- Ie,
334
+ Oe,
335
335
  {
336
- isOpen: J,
337
- columnId: X,
338
- gridApi: D,
336
+ isOpen: B,
337
+ columnId: J,
338
+ gridApi: P,
339
339
  onClose: R.closeAdvancedFilter,
340
340
  onApply: R.applyAdvancedFilter
341
341
  }
342
342
  ),
343
343
  /* @__PURE__ */ v(
344
- De,
344
+ Pe,
345
345
  {
346
- isOpen: B,
346
+ isOpen: X,
347
347
  columnId: E.current,
348
- gridApi: D,
349
- anchor: H.current,
348
+ gridApi: P,
349
+ anchor: D.current,
350
350
  variant: A.current,
351
351
  onClose: R.closeMenu
352
352
  }
353
353
  )
354
354
  ] });
355
355
  }
356
- function Ie({
356
+ function Oe({
357
357
  isOpen: i,
358
358
  columnId: n,
359
359
  gridApi: l,
@@ -361,11 +361,11 @@ function Ie({
361
361
  onApply: m
362
362
  }) {
363
363
  if (!i || !n || !l) return null;
364
- const a = l.getColumn(n);
365
- if (!a) return null;
366
- const c = a.getColDef(), b = c.headerComponentParams, C = Ge(c), M = C.text !== -1 || C.number !== -1 || C.date !== -1, T = C.set !== -1, g = c.filter === "agMultiColumnFilter" && (M || T) ? "multi" : c.filter === "agNumberColumnFilter" ? "number" : c.filter === "agDateColumnFilter" ? "date" : c.filter === "agSetColumnFilter" || b?.selectOptions ? "select" : "text", u = ke(l.getFilterModel());
364
+ const u = l.getColumn(n);
365
+ if (!u) return null;
366
+ const c = u.getColDef(), b = c.headerComponentParams, C = Ge(c), M = C.text !== -1 || C.number !== -1 || C.date !== -1, I = C.set !== -1, g = c.filter === "agMultiColumnFilter" && (M || I) ? "multi" : c.filter === "agNumberColumnFilter" ? "number" : c.filter === "agDateColumnFilter" ? "date" : c.filter === "agSetColumnFilter" || b?.selectOptions ? "select" : "text", a = ke(l.getFilterModel());
367
367
  return /* @__PURE__ */ v(he, { fallback: null, children: /* @__PURE__ */ v(
368
- Pe,
368
+ Te,
369
369
  {
370
370
  isOpen: i,
371
371
  onClose: h,
@@ -375,18 +375,18 @@ function Ie({
375
375
  columnType: g,
376
376
  selectOptions: b?.selectOptions,
377
377
  isMultiSelect: b?.isMultiSelect,
378
- initialModel: u,
378
+ initialModel: a,
379
379
  api: l
380
380
  }
381
381
  ) });
382
382
  }
383
- function De({
383
+ function Pe({
384
384
  isOpen: i,
385
385
  columnId: n,
386
386
  gridApi: l,
387
387
  anchor: h,
388
388
  variant: m,
389
- onClose: a
389
+ onClose: u
390
390
  }) {
391
391
  return !i || !n || !l ? null : /* @__PURE__ */ v(
392
392
  je,
@@ -396,7 +396,7 @@ function De({
396
396
  gridApi: l,
397
397
  anchor: h,
398
398
  variant: m || "column",
399
- onClose: a
399
+ onClose: u
400
400
  }
401
401
  );
402
402
  }
@@ -4,6 +4,7 @@ import { getDefaultClassNames as Ke, DayPicker as We } from "react-day-picker";
4
4
  import { ChevronRight as oe } from "impact-nova-icons";
5
5
  import { cn as m } from "../../lib/utils.js";
6
6
  import { Button as O } from "./button.js";
7
+ import "./button-variants.js";
7
8
  import me from "./select/select.js";
8
9
  import { FISCAL_PATTERNS as Ge, resolveWeekSelection as qe } from "../../lib/fiscal-calendar.js";
9
10
  import { getIntlLocale as Je, getDateFnsLocale as Qe } from "../../i18n/getDateFnsLocale.js";
@@ -32,7 +33,7 @@ function Ve({ children: A }) {
32
33
  }
33
34
  );
34
35
  }
35
- function ut({
36
+ function ft({
36
37
  className: A,
37
38
  classNames: B,
38
39
  showOutsideDays: p = !1,
@@ -892,6 +893,6 @@ function et({
892
893
  );
893
894
  }
894
895
  export {
895
- ut as Calendar,
896
+ ft as Calendar,
896
897
  et as CalendarDayButton
897
898
  };
@@ -1 +1 @@
1
- export default "# Install and configure Impact Nova\n\nUse these steps to add Impact Nova to an existing project. Run the commands in your project root and apply the code changes to your entry file and layout.\n\n## 0. Scaffold a new app (recommended)\n\n**Pre-publish (local monorepo):** scaffold links `impact-nova` via `file:` no npm publish required.\n\n```bash\n# from impact-nova repo (after npm run build at repo root)\nnpx create-impact-nova my-dashboard\ncd my-dashboard\nnpm run dev\n```\n\nMCP: **`scaffold_impact_nova_app`** with `projectName` (defaults to local `file:` impact-nova).\n\n**After publish:** add `--from-npm` to CLI or `usePublishedPackages: true` in MCP.\n\n```bash\nnpx create-impact-nova my-dashboard --from-npm\n```\n\nIncludes Tailwind, Layout, AG Grid DataTable, Highcharts Chart, FilterStrip, and sample Dashboard + Items pages.\n\n**Local link in an existing app** (manual):\n\n```bash\nnpm install impact-nova@file:../path-to-impact-nova-repo\n```\n\nRun `npm run build` in the impact-nova repo after design-system changes.\n\n## 1. Install the package and peer dependencies\n\n```bash\nnpm install impact-nova impact-nova-icons\nnpm install react@^19 react-dom@^19\n```\n\n**Required peers:** `react@^19`, `react-dom@^19`, `impact-nova-icons@^0.1.1`\n\n**Optional peers** (install when you use these features):\n\n| Package | Version | When needed |\n|---------|---------|-------------|\n| `ag-grid-react` | `35.0.1` | DataTable / AG Grid |\n| `ag-grid-enterprise` | `35.0.1` | Enterprise grid features |\n| `highcharts` | `^12` | Chart component |\n| `highcharts-react-official` | `^3` | Chart component |\n| `highcharts-border-radius` | `^0.0.4` | Rounded chart corners |\n| `@tanstack/react-table` | `^8.20` | Optional table utilities |\n\nIf you use AG Grid or Highcharts in your app, also install:\n\n```bash\nnpm install ag-grid-react@35.0.1 ag-grid-enterprise@35.0.1\n# Optional, for charts:\nnpm install highcharts@^12 highcharts-react-official@^3 highcharts-border-radius@^0.0.4\n```\n\n## 2. Import styles in your root entry\n\nIn your app root (e.g. `main.tsx`, `App.tsx`, or `layout.tsx`), **import the CSS before your app component**:\n\n```tsx\nimport 'impact-nova/dist/impact-nova.css';\nimport App from './App';\n// ... rest of your bootstrap\n```\n\n## 3. Add Manrope font (recommended)\n\nIn your `index.html` or layout:\n\n```html\n<link href=\"https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap\" rel=\"stylesheet\" />\n```\n\nIn your global CSS or Tailwind base:\n\n```css\n@layer base {\n body {\n font-family: 'Manrope', sans-serif;\n }\n}\n```\n\n## 4. Wrap your app with i18n (recommended)\n\nWrap your app with `ImpactNovaI18nProvider` so date pickers, selects, and other components use the correct locale and labels:\n\n```tsx\nimport { ImpactNovaI18nProvider } from 'impact-nova';\n\nfunction Root() {\n return (\n <ImpactNovaI18nProvider locale=\"en\">\n <App />\n </ImpactNovaI18nProvider>\n );\n}\n```\n\nFor another locale, use a locale pack:\n\n```tsx\nimport { ImpactNovaI18nProvider } from 'impact-nova';\nimport { de } from 'impact-nova/locale/de';\n\n<ImpactNovaI18nProvider locale=\"de\" messages={de}>\n <App />\n</ImpactNovaI18nProvider>\n```\n\n## 5. Subpath imports (recommended)\n\nPrefer subpath imports in feature code for tree-shaking:\n\n```tsx\nimport { Button } from 'impact-nova/button';\nimport { Card, CardContent } from 'impact-nova/card';\nimport { DataTable, DataTableContent, useDataTable } from 'impact-nova/data-table';\nimport { CheckCircle } from 'impact-nova-icons';\n```\n\nThe barrel `import { Button } from 'impact-nova'` still works but pulls a larger module graph. Use subpaths in production apps.\n\n## 6. Using Impact Nova with CSS or SCSS (no Tailwind)\n\nIf your app uses **plain CSS or SCSS** and does **not** use Tailwind, you can still use Impact Nova. Tailwind is optional. Impact Nova ships a single built CSS file (no SCSS source).\n\n- **Import the library CSS** in your app root (e.g. `main.tsx`, `App.tsx`):\n ```tsx\n import 'impact-nova/dist/impact-nova.css';\n ```\n **CSS split exports** (optional, for layered theming): `impact-nova/impact-nova-tokens.scss`, `impact-nova/impact-nova-base.scss`, `impact-nova/impact-nova-components.css`\n Or from your main stylesheet: `@import 'impact-nova/dist/impact-nova.css';` in your main.css or main.scss.\n- **Component styling** comes from Impact Nova's CSS. Use each component's `variant` and `size` props; no Tailwind classes are required.\n- **Your layout and spacing** stay in your CSS or SCSS (margins, padding, flexbox, grid). Use your usual class names; the design system does not require Tailwind utilities.\n- **Manrope font:** Add the font link in `index.html` and in your CSS/SCSS set `body { font-family: 'Manrope', sans-serif; }` (see section 3).\n- **Summary:** No Tailwind, no Tailwind config. Load `impact-nova.css` once; use components with their props; use your existing CSS/SCSS for the rest.\n\n## 7. Using Impact Nova with Webpack\n\nIf your app is built with **Webpack** (including Create React App, which uses Webpack):\n\n- **CSS import:** Webpack will bundle the library CSS as long as you have a rule for `.css`. Ensure your config includes something like:\n ```js\n module: {\n rules: [\n {\n test: /\\.css$/,\n use: ['style-loader', 'css-loader'],\n // or with MiniCssExtractPlugin:\n // use: [MiniCssExtractPlugin.loader, 'css-loader'],\n },\n // ... other rules (e.g. for .tsx, .js)\n ],\n },\n ```\n Then in your root component or entry:\n ```tsx\n import 'impact-nova/dist/impact-nova.css';\n ```\n- **Create React App (CRA):** No extra config. Add `import 'impact-nova/dist/impact-nova.css';` in `index.tsx` or `App.tsx`.\n- **Dedupe React / AG Grid:** If you see “multiple copies of React” or AG Grid issues, use Webpack’s `resolve.alias` so the app uses a single version:\n ```js\n resolve: {\n alias: {\n react: path.resolve(__dirname, 'node_modules/react'),\n 'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),\n // If using AG Grid:\n 'ag-grid-react': path.resolve(__dirname, 'node_modules/ag-grid-react'),\n 'ag-grid-community': path.resolve(__dirname, 'node_modules/ag-grid-community'),\n 'ag-grid-enterprise': path.resolve(__dirname, 'node_modules/ag-grid-enterprise'),\n },\n },\n ```\n- **Tailwind + Webpack:** If you use Tailwind, add the Impact Nova preset and include the package in `content` (see section 7 below).\n\n## 8. Optional: extend Tailwind with Impact Nova preset\n\nIf your project uses Tailwind and you want the same theme (colors, radius), extend your `tailwind.config.js` with the preset from the package:\n\n```js\n// tailwind.config.js\nimport impactNovaPreset from 'impact-nova/tailwind.config.js';\n\nexport default {\n presets: [impactNovaPreset],\n content: [\n './index.html',\n './src/**/*.{js,ts,jsx,tsx}',\n './node_modules/impact-nova/dist/**/*.js',\n ],\n // ... rest of your config\n};\n```\n\n## Summary checklist\n\n- [ ] `npm install impact-nova impact-nova-icons` (and react, react-dom; optional: ag-grid, highcharts)\n- [ ] `import 'impact-nova/dist/impact-nova.css'` in root entry (or @import in main.css/main.scss if using CSS or SCSS without Tailwind; see §6)\n- [ ] Add Manrope font link and body font-family\n- [ ] Wrap app with `<ImpactNovaI18nProvider locale=\"en\">`\n- [ ] Use subpath imports in feature code (see §5)\n- [ ] (Optional) Add Tailwind preset and content path for impact-nova\n- [ ] **Webpack:** Ensure a CSS rule (style-loader + css-loader) and, if needed, resolve.alias for React/AG Grid\n\nAfter this, import components via subpaths: `import { Button } from 'impact-nova/button';`\n\n## 9. Dashboard app shell (optional)\n\nTo scaffold a full dashboard (sidebar, header, breadcrumb, filters), read resource **`impact-nova://layout`** or call `get_real_world_patterns` with `topic: \"layout\"`. Use `Layout` from `impact-nova/layout` — not `DynamicLayout` (grid/flex utility only).\n";
1
+ export default "# Install and configure Impact Nova\n\nUse these steps to add Impact Nova to an existing project. Run the commands in your project root and apply the code changes to your entry file and layout.\n\n## 0. Scaffold a new app (recommended)\n\n**`create-impact-nova@^1.0.0`** is on npm. Scaffold auto-detects dependency mode:\n\n| Where you run | `impact-nova` dependency |\n|---------------|--------------------------|\n| Published CLI / MCP (outside monorepo) | `^2.0.5` from npm |\n| Inside impact-nova monorepo | `file:` link to repo root |\n\n```bash\nnpx create-impact-nova my-dashboard\ncd my-dashboard\nnpm run dev\n```\n\nMCP: **`scaffold_impact_nova_app`** with `projectName` and optional `modules[]` from the user prompt.\n\n**Overrides:** CLI `--from-npm` · `--link-monorepo` · MCP `usePublishedPackages: true | false`\n\n```bash\nnpx create-impact-nova my-dashboard --from-npm\n```\n\nBase template is shell-only (Home + shared primitives). Feature pages come from recipes see `create-impact-nova/recipes/README.md`.\n\n**Local link in an existing app** (manual):\n\n```bash\nnpm install impact-nova@file:../path-to-impact-nova-repo\n```\n\nRun `npm run build` in the impact-nova repo after design-system changes.\n\n## 1. Install the package and peer dependencies\n\n```bash\nnpm install impact-nova impact-nova-icons\nnpm install react@^19 react-dom@^19\n```\n\n**Required peers:** `react@^19`, `react-dom@^19`, `impact-nova-icons@^0.1.1`\n\n**Optional peers** (install when you use these features):\n\n| Package | Version | When needed |\n|---------|---------|-------------|\n| `ag-grid-react` | `35.0.1` | DataTable / AG Grid |\n| `ag-grid-enterprise` | `35.0.1` | Enterprise grid features |\n| `highcharts` | `^12` | Chart component |\n| `highcharts-react-official` | `^3` | Chart component |\n| `highcharts-border-radius` | `^0.0.4` | Rounded chart corners |\n| `@tanstack/react-table` | `^8.20` | Optional table utilities |\n\nIf you use AG Grid or Highcharts in your app, also install:\n\n```bash\nnpm install ag-grid-react@35.0.1 ag-grid-enterprise@35.0.1\n# Optional, for charts:\nnpm install highcharts@^12 highcharts-react-official@^3 highcharts-border-radius@^0.0.4\n```\n\n## 2. Import styles in your root entry\n\nIn your app root (e.g. `main.tsx`, `App.tsx`, or `layout.tsx`), **import the CSS before your app component**:\n\n```tsx\nimport 'impact-nova/dist/impact-nova.css';\nimport App from './App';\n// ... rest of your bootstrap\n```\n\n## 3. Add Manrope font (recommended)\n\nIn your `index.html` or layout:\n\n```html\n<link href=\"https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap\" rel=\"stylesheet\" />\n```\n\nIn your global CSS or Tailwind base:\n\n```css\n@layer base {\n body {\n font-family: 'Manrope', sans-serif;\n }\n}\n```\n\n## 4. Wrap your app with i18n (recommended)\n\nWrap your app with `ImpactNovaI18nProvider` so date pickers, selects, and other components use the correct locale and labels:\n\n```tsx\nimport { ImpactNovaI18nProvider } from 'impact-nova';\n\nfunction Root() {\n return (\n <ImpactNovaI18nProvider locale=\"en\">\n <App />\n </ImpactNovaI18nProvider>\n );\n}\n```\n\nFor another locale, use a locale pack:\n\n```tsx\nimport { ImpactNovaI18nProvider } from 'impact-nova';\nimport { de } from 'impact-nova/locale/de';\n\n<ImpactNovaI18nProvider locale=\"de\" messages={de}>\n <App />\n</ImpactNovaI18nProvider>\n```\n\n## 5. Subpath imports (recommended)\n\nPrefer subpath imports in feature code for tree-shaking:\n\n```tsx\nimport { Button } from 'impact-nova/button';\nimport { Card, CardContent } from 'impact-nova/card';\nimport { DataTable, DataTableContent, useDataTable } from 'impact-nova/data-table';\nimport { CheckCircle } from 'impact-nova-icons';\n```\n\nThe barrel `import { Button } from 'impact-nova'` still works but pulls a larger module graph. Use subpaths in production apps.\n\n## 6. Using Impact Nova with CSS or SCSS (no Tailwind)\n\nIf your app uses **plain CSS or SCSS** and does **not** use Tailwind, you can still use Impact Nova. Tailwind is optional. Impact Nova ships a single built CSS file (no SCSS source).\n\n- **Import the library CSS** in your app root (e.g. `main.tsx`, `App.tsx`):\n ```tsx\n import 'impact-nova/dist/impact-nova.css';\n ```\n **CSS split exports** (optional, for layered theming): `impact-nova/impact-nova-tokens.scss`, `impact-nova/impact-nova-base.scss`, `impact-nova/impact-nova-components.css`\n Or from your main stylesheet: `@import 'impact-nova/dist/impact-nova.css';` in your main.css or main.scss.\n- **Component styling** comes from Impact Nova's CSS. Use each component's `variant` and `size` props; no Tailwind classes are required.\n- **Your layout and spacing** stay in your CSS or SCSS (margins, padding, flexbox, grid). Use your usual class names; the design system does not require Tailwind utilities.\n- **Manrope font:** Add the font link in `index.html` and in your CSS/SCSS set `body { font-family: 'Manrope', sans-serif; }` (see section 3).\n- **Summary:** No Tailwind, no Tailwind config. Load `impact-nova.css` once; use components with their props; use your existing CSS/SCSS for the rest.\n\n## 7. Using Impact Nova with Webpack\n\nIf your app is built with **Webpack** (including Create React App, which uses Webpack):\n\n- **CSS import:** Webpack will bundle the library CSS as long as you have a rule for `.css`. Ensure your config includes something like:\n ```js\n module: {\n rules: [\n {\n test: /\\.css$/,\n use: ['style-loader', 'css-loader'],\n // or with MiniCssExtractPlugin:\n // use: [MiniCssExtractPlugin.loader, 'css-loader'],\n },\n // ... other rules (e.g. for .tsx, .js)\n ],\n },\n ```\n Then in your root component or entry:\n ```tsx\n import 'impact-nova/dist/impact-nova.css';\n ```\n- **Create React App (CRA):** No extra config. Add `import 'impact-nova/dist/impact-nova.css';` in `index.tsx` or `App.tsx`.\n- **Dedupe React / AG Grid:** If you see “multiple copies of React” or AG Grid issues, use Webpack’s `resolve.alias` so the app uses a single version:\n ```js\n resolve: {\n alias: {\n react: path.resolve(__dirname, 'node_modules/react'),\n 'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),\n // If using AG Grid:\n 'ag-grid-react': path.resolve(__dirname, 'node_modules/ag-grid-react'),\n 'ag-grid-community': path.resolve(__dirname, 'node_modules/ag-grid-community'),\n 'ag-grid-enterprise': path.resolve(__dirname, 'node_modules/ag-grid-enterprise'),\n },\n },\n ```\n- **Tailwind + Webpack:** If you use Tailwind, add the Impact Nova preset and include the package in `content` (see section 7 below).\n\n## 8. Optional: extend Tailwind with Impact Nova preset\n\nIf your project uses Tailwind and you want the same theme (colors, radius), extend your `tailwind.config.js` with the preset from the package:\n\n```js\n// tailwind.config.js\nimport impactNovaPreset from 'impact-nova/tailwind.config.js';\n\nexport default {\n presets: [impactNovaPreset],\n content: [\n './index.html',\n './src/**/*.{js,ts,jsx,tsx}',\n './node_modules/impact-nova/dist/**/*.js',\n ],\n // ... rest of your config\n};\n```\n\n## Summary checklist\n\n- [ ] `npm install impact-nova impact-nova-icons` (and react, react-dom; optional: ag-grid, highcharts)\n- [ ] `import 'impact-nova/dist/impact-nova.css'` in root entry (or @import in main.css/main.scss if using CSS or SCSS without Tailwind; see §6)\n- [ ] Add Manrope font link and body font-family\n- [ ] Wrap app with `<ImpactNovaI18nProvider locale=\"en\">`\n- [ ] Use subpath imports in feature code (see §5)\n- [ ] (Optional) Add Tailwind preset and content path for impact-nova\n- [ ] **Webpack:** Ensure a CSS rule (style-loader + css-loader) and, if needed, resolve.alias for React/AG Grid\n\nAfter this, import components via subpaths: `import { Button } from 'impact-nova/button';`\n\n## 9. Dashboard app shell (optional)\n\nTo scaffold a full dashboard (sidebar, header, breadcrumb, filters), read resource **`impact-nova://layout`** or call `get_real_world_patterns` with `topic: \"layout\"`. Use `Layout` from `impact-nova/layout` — not `DynamicLayout` (grid/flex utility only).\n";
@@ -1 +1 @@
1
- export default "# Impact Nova — baseline\n\nUse **Impact Nova** design-system components and tokens. Prefer subpath imports (e.g. `impact-nova/button`) when you only need a few modules. For live component lists, specs, and codegen, use the **impact-nova-mcp** MCP server (see npm `impact-nova-mcp`). Browse **Storybook**: https://impact-nova.iaproducts.ai/\n\n## Peer dependency summary\n\n```json\n{\n \"impactNova\": {\n \"package\": \"impact-nova\",\n \"recommendedVersion\": \"^2.0.5\",\n \"description\": \"Design system package — ESM with 90+ subpath exports\"\n },\n \"localDevelopment\": {\n \"defaultScaffoldDependency\": \"file:<relative-path-to-impact-nova-repo-root>\",\n \"description\": \"Until packages are on npm, create-impact-nova scaffolds with file: link to the monorepo. Rebuild impact-nova (npm run build) after DS changes.\",\n \"cliFlagForNpm\": \"--from-npm\",\n \"mcpScaffoldFlag\": \"usePublishedPackages: true\"\n },\n \"mandatoryRules\": {\n \"componentsOnly\": \"Use Impact Nova components only — never create new custom UI components\",\n \"tables\": \"Any table/grid/spreadsheet → DataTable from impact-nova/data-table (not HTML table, not raw ag-grid-react)\",\n \"validateBeforeDone\": \"Call validate_usage on generated UI code\",\n \"resource\": \"impact-nova://design-system-mandate\"\n },\n \"requiredPeers\": [\n {\n \"package\": \"react\",\n \"recommendedVersion\": \"^19.0.0\",\n \"description\": \"React 19 required\"\n },\n {\n \"package\": \"react-dom\",\n \"recommendedVersion\": \"^19.0.0\",\n \"description\": \"React DOM 19 required\"\n },\n {\n \"package\": \"impact-nova-icons\",\n \"recommendedVersion\": \"^0.1.1\",\n \"description\": \"Icons peer — not bundled in impact-nova\"\n }\n ],\n \"optionalPeers\": [\n {\n \"package\": \"ag-grid-react\",\n \"recommendedVersion\": \"35.0.1\",\n \"description\": \"For DataTable and grid components; use exact version to match Impact Nova\"\n },\n {\n \"package\": \"ag-grid-enterprise\",\n \"recommendedVersion\": \"35.0.1\",\n \"description\": \"Required if using ag-grid-react with enterprise features\"\n },\n {\n \"package\": \"highcharts\",\n \"recommendedVersion\": \"^12.0.0\",\n \"description\": \"For Chart component\"\n },\n {\n \"package\": \"highcharts-react-official\",\n \"recommendedVersion\": \"^3.0.0\",\n \"description\": \"For Chart component\"\n },\n {\n \"package\": \"highcharts-border-radius\",\n \"recommendedVersion\": \"^0.0.4\",\n \"description\": \"Optional Highcharts plugin for rounded corners\"\n },\n {\n \"package\": \"@tanstack/react-table\",\n \"recommendedVersion\": \"^8.20.0\",\n \"description\": \"Optional table utilities\"\n }\n ]\n}\n```\n";
1
+ export default "# Impact Nova — baseline\n\nUse **Impact Nova** design-system components and tokens. Prefer subpath imports (e.g. `impact-nova/button`) when you only need a few modules. For live component lists, specs, and codegen, use the **impact-nova-mcp** MCP server (see npm `impact-nova-mcp`). Browse **Storybook**: https://impact-nova.iaproducts.ai/\n\n## Peer dependency summary\n\n```json\n{\n \"impactNova\": {\n \"package\": \"impact-nova\",\n \"recommendedVersion\": \"^2.0.5\",\n \"description\": \"Design system package — ESM with 90+ subpath exports\"\n },\n \"createImpactNova\": {\n \"package\": \"create-impact-nova\",\n \"recommendedVersion\": \"^1.0.0\",\n \"description\": \"Vite + React scaffold with recipe-based modules\"\n },\n \"localDevelopment\": {\n \"defaultScaffoldDependency\": \"auto\",\n \"description\": \"create-impact-nova auto-detects: file: link when run inside the impact-nova monorepo; npm (^2.0.5) otherwise. CLI: --from-npm or --link-monorepo to override. Rebuild impact-nova (npm run build) after DS changes when using file: link.\",\n \"cliFlagForNpm\": \"--from-npm\",\n \"cliFlagForMonorepo\": \"--link-monorepo\",\n \"mcpScaffoldFlag\": \"usePublishedPackages: true | false (omit for auto-detect)\"\n },\n \"mandatoryRules\": {\n \"componentsOnly\": \"Use Impact Nova components only — never create new custom UI components\",\n \"tables\": \"Any table/grid/spreadsheet → DataTable from impact-nova/data-table (not HTML table, not raw ag-grid-react)\",\n \"validateBeforeDone\": \"Call validate_usage on generated UI code\",\n \"resource\": \"impact-nova://design-system-mandate\"\n },\n \"requiredPeers\": [\n {\n \"package\": \"react\",\n \"recommendedVersion\": \"^19.0.0\",\n \"description\": \"React 19 required\"\n },\n {\n \"package\": \"react-dom\",\n \"recommendedVersion\": \"^19.0.0\",\n \"description\": \"React DOM 19 required\"\n },\n {\n \"package\": \"impact-nova-icons\",\n \"recommendedVersion\": \"^0.1.1\",\n \"description\": \"Icons peer — not bundled in impact-nova\"\n }\n ],\n \"optionalPeers\": [\n {\n \"package\": \"ag-grid-react\",\n \"recommendedVersion\": \"35.0.1\",\n \"description\": \"For DataTable and grid components; use exact version to match Impact Nova\"\n },\n {\n \"package\": \"ag-grid-enterprise\",\n \"recommendedVersion\": \"35.0.1\",\n \"description\": \"Required if using ag-grid-react with enterprise features\"\n },\n {\n \"package\": \"highcharts\",\n \"recommendedVersion\": \"^12.0.0\",\n \"description\": \"For Chart component\"\n },\n {\n \"package\": \"highcharts-react-official\",\n \"recommendedVersion\": \"^3.0.0\",\n \"description\": \"For Chart component\"\n },\n {\n \"package\": \"highcharts-border-radius\",\n \"recommendedVersion\": \"^0.0.4\",\n \"description\": \"Optional Highcharts plugin for rounded corners\"\n },\n {\n \"package\": \"@tanstack/react-table\",\n \"recommendedVersion\": \"^8.20.0\",\n \"description\": \"Optional table utilities\"\n }\n ]\n}\n```\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "impact-nova",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
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",