najm-kit 2.11.12 → 2.11.13

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.
package/CHANGELOG.md CHANGED
@@ -1,19 +1,29 @@
1
- # Changelog
2
-
3
- ## 2.11.10 - 2026-09-03
4
-
5
- - Fixed the selected numbered `NTable` pagination button inheriting the regular
6
- foreground colour over its filled primary style. The active page now keeps
7
- the primary button foreground token, which is white in the light theme.
8
- - Fixed focused invalid inputs combining a destructive border with the normal
9
- theme focus colour. `BaseInput` now keeps the visible keyboard-focus ring but
10
- colours it from the destructive token for both directly focused composite
11
- controls and wrappers whose child has `:focus-visible`.
12
- - Made the desktop and mobile sidebar use logical inline edges, spacing, border
13
- utilities, chevrons, and drag direction so the complete rail behaves
14
- correctly in both LTR and RTL layouts.
15
-
16
- ## 2.11.9 - 2026-08-30
1
+ # Changelog
2
+
3
+ ## 2.11.13 - 2026-09-04
4
+
5
+ - Fixed the documented `common.feedback.<field>` convention so all shared
6
+ loading, empty, error, forbidden, and not-found states resolve localized
7
+ labels without an application-owned `feedbackDefaults` key map. Missing
8
+ convention keys still fall back to the packaged English labels.
9
+ - Forwarded Najm i18n's missing-key fallback and language-direction resolver
10
+ through `NajmAppProvider`, keeping language changes reactive for partial
11
+ catalogs and non-Arabic RTL languages.
12
+
13
+ ## 2.11.10 - 2026-09-03
14
+
15
+ - Fixed the selected numbered `NTable` pagination button inheriting the regular
16
+ foreground colour over its filled primary style. The active page now keeps
17
+ the primary button foreground token, which is white in the light theme.
18
+ - Fixed focused invalid inputs combining a destructive border with the normal
19
+ theme focus colour. `BaseInput` now keeps the visible keyboard-focus ring but
20
+ colours it from the destructive token for both directly focused composite
21
+ controls and wrappers whose child has `:focus-visible`.
22
+ - Made the desktop and mobile sidebar use logical inline edges, spacing, border
23
+ utilities, chevrons, and drag direction so the complete rail behaves
24
+ correctly in both LTR and RTL layouts.
25
+
26
+ ## 2.11.9 - 2026-08-30
17
27
 
18
28
  - Fixed card grids that paginate client-side rendering their entire dataset on
19
29
  one page. `useTable` pinned an uncontrolled paged card list to `data.length`,
package/README.md CHANGED
@@ -352,7 +352,40 @@ Resolution order, most specific first:
352
352
  2. A literal in `feedbackDefaults.labels`.
353
353
  3. A translated `feedbackDefaults.labelKeys` value resolved through the
354
354
  provider's existing structural `t` function.
355
- 4. The current packaged English fallback, when that field has one.
355
+ 4. `` `<prefix>.<field>` `` resolved through the same `t`, where `prefix`
356
+ defaults to `common.feedback`.
357
+ 5. The current packaged English fallback, when that field has one.
358
+
359
+ #### The prefix convention
360
+
361
+ Step 4 is the reason most applications need no `feedbackDefaults` at all. Name
362
+ the nine catalog entries after the fields — `common.feedback.emptyTitle`,
363
+ `common.feedback.retryLabel`, and so on — and a provider that already has a
364
+ translator resolves every feedback state with no mapping object to write or
365
+ memoize:
366
+
367
+ ```tsx
368
+ <NajmAppProvider translations={translations} initialLanguage="fr">
369
+ <App />
370
+ </NajmAppProvider>
371
+ ```
372
+
373
+ Use `prefix` to point at a different branch, and `FeedbackKey<Prefix>` to type
374
+ a translator against exactly those nine keys:
375
+
376
+ ```tsx
377
+ import type { FeedbackKey } from 'najm-kit';
378
+
379
+ <NajmAppProvider feedbackDefaults={{ prefix: 'app.states' }}>
380
+ ```
381
+
382
+ Unlike `buildToolbarLabels` and `buildPaginationLabels`, a translator result
383
+ equal to the key it was handed is treated as *missing* here rather than
384
+ rendered. The prefix is a convention an application may never have adopted, so
385
+ an unanswered key falls through to packaged English instead of painting
386
+ `common.feedback.emptyTitle` across an empty state. The same rule applies to an
387
+ explicit `labelKeys` entry, which makes a typo in the mapping degrade to English
388
+ rather than to visible key text.
356
389
 
357
390
  Generic `NErrorState.message` and `NEmptyState.description` deliberately have
358
391
  no packaged fallback — the no-provider render must look the same as it did
@@ -217,11 +217,24 @@ interface NFeedbackDefaults {
217
217
  */
218
218
  labelKeys?: NFeedbackLabelKeys;
219
219
  /**
220
- * Catalog prefix for translated keys. Keys are read as `<prefix>.<field>`.
221
- * Defaults to `"common.feedback"`.
220
+ * Catalog prefix for translated keys, read as `<prefix>.<field>` for every
221
+ * field `labelKeys` does not name explicitly. Defaults to
222
+ * `"common.feedback"`, so an application whose catalog follows the
223
+ * convention supplies no `feedbackDefaults` at all.
224
+ *
225
+ * A prefix key the catalog does not answer falls through to packaged
226
+ * English rather than rendering the key.
222
227
  */
223
228
  prefix?: string;
224
229
  }
230
+ declare const DEFAULT_FEEDBACK_KEY_PREFIX = "common.feedback";
231
+ type DefaultFeedbackPrefix = typeof DEFAULT_FEEDBACK_KEY_PREFIX;
232
+ /**
233
+ * The nine catalog keys the feedback states read under `Prefix`, matching the
234
+ * `ToolbarKey` and `CardPaginationKey` conventions — same prefix, same
235
+ * key-per-field naming.
236
+ */
237
+ type FeedbackKey<Prefix extends string = DefaultFeedbackPrefix> = `${Prefix}.loadingLabel` | `${Prefix}.emptyTitle` | `${Prefix}.errorTitle` | `${Prefix}.errorMessage` | `${Prefix}.retryLabel` | `${Prefix}.forbiddenTitle` | `${Prefix}.forbiddenDescription` | `${Prefix}.notFoundTitle` | `${Prefix}.notFoundDescription`;
225
238
 
226
239
  /**
227
240
  * Theme and time zone, the two preferences that outlive a render.
@@ -413,4 +426,4 @@ interface NajmUIProviderProps extends Omit<NajmPreferencesProviderProps, "childr
413
426
  */
414
427
  declare function NajmUIProvider({ children, design, initialDesign, className, t, paginationKeyPrefix, toolbarKeyPrefix, dir, tableDefaults, badgeDefaults, feedbackDefaults, initialTheme, initialTimeZone, onThemeChange, onTimeZoneChange, normalizeTimeZone, }: NajmUIProviderProps): React.JSX.Element;
415
428
 
416
- export { useDocumentDirection as A, type BadgeColor as B, useNTableDefaults as C, DEFAULT_TIME_ZONE as D, useNajmPreferencesContext as E, useNajmTheme as F, useNajmTimeZone as G, useResolvedToolbarLabels as H, type NFeedbackDefaults as N, type NFeedbackLabelKeys as a, type NFeedbackLabels as b, type NajmUIProviderProps as c, type NTableToolbarLabels as d, type NIconSource as e, type BadgeShape as f, Badge as g, type BadgeIcon as h, type BadgeLook as i, type BadgeProps as j, type BadgeSize as k, type BadgeVariant as l, NBadge as m, type NBadgeDefaults as n, type NBadgeLook as o, type NBadgeProps as p, NIcon as q, type NIconProps as r, type NTableDefaults as s, NTableDefaultsProvider as t, type NajmPreferencesContextValue as u, NajmPreferencesProvider as v, type NajmPreferencesProviderProps as w, NajmUIProvider as x, badgeColorVariants as y, badgeVariants as z };
429
+ export { badgeVariants as A, type BadgeColor as B, useDocumentDirection as C, DEFAULT_FEEDBACK_KEY_PREFIX as D, useNTableDefaults as E, type FeedbackKey as F, useNajmPreferencesContext as G, useNajmTheme as H, useNajmTimeZone as I, useResolvedToolbarLabels as J, type NFeedbackDefaults as N, type NFeedbackLabelKeys as a, type NFeedbackLabels as b, type NajmUIProviderProps as c, type NTableToolbarLabels as d, type NIconSource as e, type BadgeShape as f, Badge as g, type BadgeIcon as h, type BadgeLook as i, type BadgeProps as j, type BadgeSize as k, type BadgeVariant as l, DEFAULT_TIME_ZONE as m, NBadge as n, type NBadgeDefaults as o, type NBadgeLook as p, type NBadgeProps as q, NIcon as r, type NIconProps as s, type NTableDefaults as t, NTableDefaultsProvider as u, type NajmPreferencesContextValue as v, NajmPreferencesProvider as w, type NajmPreferencesProviderProps as x, NajmUIProvider as y, badgeColorVariants as z };
@@ -3,7 +3,7 @@ import { Translations } from 'najm-i18n';
3
3
  import { F as FormDevToolsOptions, N as NBrandingInput } from '../NNotFoundState-CgU76llk.js';
4
4
  export { a as NEmptyState, b as NEmptyStateProps, c as NErrorState, d as NErrorStateProps, e as NFeedbackSurface, f as NForbiddenState, g as NForbiddenStateProps, h as NLoadingState, i as NLoadingStateProps, j as NNotFoundState, k as NNotFoundStateProps } from '../NNotFoundState-CgU76llk.js';
5
5
  import { NajmNextUIProviderProps } from './next.js';
6
- export { N as NFeedbackDefaults, a as NFeedbackLabelKeys, b as NFeedbackLabels } from '../NajmUIProvider-DSjvh4x2.js';
6
+ export { D as DEFAULT_FEEDBACK_KEY_PREFIX, F as FeedbackKey, N as NFeedbackDefaults, a as NFeedbackLabelKeys, b as NFeedbackLabels } from '../NajmUIProvider-DTyRrukg.js';
7
7
  import 'zod';
8
8
  import 'lucide-react';
9
9
  import 'next/image';
@@ -33,6 +33,18 @@ interface NajmAppProviderProps extends Omit<NajmNextUIProviderProps, 't'> {
33
33
  translations?: Translations;
34
34
  initialLanguage?: string;
35
35
  defaultLanguage?: string;
36
+ /**
37
+ * Resolves a key missing from the active language against `defaultLanguage`
38
+ * instead of echoing the key. Forwarded to `najm-i18n`'s `I18nProvider`; see
39
+ * that package's "Missing-key fallback" for the full matrix.
40
+ *
41
+ * Off by default, matching the package. An application shipping an
42
+ * incomplete locale beside a complete one turns it on here rather than
43
+ * pre-merging its catalogs.
44
+ */
45
+ fallbackToDefaultLanguage?: boolean;
46
+ /** Maps a language to the writing direction applied to `<html>`. */
47
+ getLanguageDirection?: (language: string) => 'ltr' | 'rtl';
36
48
  /**
37
49
  * Where the chosen language is POSTed, as `{ language }`. Defaults to
38
50
  * `/api/ui-language`.
@@ -110,6 +122,6 @@ interface NajmAppProviderProps extends Omit<NajmNextUIProviderProps, 't'> {
110
122
  * state machine of its own above this provider. The controlled `design` and
111
123
  * `branding` props still work for applications that already do.
112
124
  */
113
- declare function NajmAppProvider({ translations, initialLanguage, defaultLanguage, languageEndpoint, appName, initialBranding, formDevTools, ...props }: NajmAppProviderProps): React.JSX.Element;
125
+ declare function NajmAppProvider({ translations, initialLanguage, defaultLanguage, fallbackToDefaultLanguage, getLanguageDirection, languageEndpoint, appName, initialBranding, formDevTools, ...props }: NajmAppProviderProps): React.JSX.Element;
114
126
 
115
127
  export { type NajmAppBranding, NajmAppProvider, type NajmAppProviderProps };
@@ -1,8 +1,8 @@
1
1
  'use client';
2
- import { FormDevToolsProvider, NBrandingStateProvider, NajmFormatProvider } from '../chunk-56JQI3VL.mjs';
3
- export { NEmptyState, NErrorState, NForbiddenState, NLoadingState, NNotFoundState } from '../chunk-56JQI3VL.mjs';
4
- import { NajmNextUIProvider } from '../chunk-VSK75GSS.mjs';
5
- import '../chunk-3J24TPLA.mjs';
2
+ import { FormDevToolsProvider, NBrandingStateProvider, NajmFormatProvider } from '../chunk-26EASWUY.mjs';
3
+ export { NEmptyState, NErrorState, NForbiddenState, NLoadingState, NNotFoundState } from '../chunk-26EASWUY.mjs';
4
+ import { NajmNextUIProvider } from '../chunk-DKHIQFXX.mjs';
5
+ export { DEFAULT_FEEDBACK_KEY_PREFIX } from '../chunk-BDQK6ECA.mjs';
6
6
  import '../chunk-M5VGBZ7R.mjs';
7
7
  import '../chunk-LK3SMYUP.mjs';
8
8
  import '../chunk-JABLSOQN.mjs';
@@ -72,6 +72,8 @@ function NajmAppProvider({
72
72
  translations,
73
73
  initialLanguage,
74
74
  defaultLanguage,
75
+ fallbackToDefaultLanguage,
76
+ getLanguageDirection,
75
77
  languageEndpoint = DEFAULT_LANGUAGE_ENDPOINT,
76
78
  appName,
77
79
  initialBranding,
@@ -104,6 +106,8 @@ function NajmAppProvider({
104
106
  translations,
105
107
  initialLanguage: initialLanguage ?? defaultLanguage ?? "en",
106
108
  defaultLanguage,
109
+ fallbackToDefaultLanguage,
110
+ getLanguageDirection,
107
111
  onLanguageChange: persistLanguage,
108
112
  children: /* @__PURE__ */ jsx(NajmAppUI, { ...props, initialBranding: seeded })
109
113
  }
@@ -1,6 +1,6 @@
1
1
  import React__default from 'react';
2
2
  import { ImageProps } from 'next/image';
3
- import { c as NajmUIProviderProps } from '../NajmUIProvider-DSjvh4x2.js';
3
+ import { c as NajmUIProviderProps } from '../NajmUIProvider-DTyRrukg.js';
4
4
  import '../design-types-Rkpt8Pg1.js';
5
5
  import '../paginationLabels-dZLSNxfo.js';
6
6
  import 'class-variance-authority/types';
@@ -1,3 +1,3 @@
1
- export { NNextImage, NajmNextUIProvider, NextLinkAdapter, useNextNavigationAdapter } from '../chunk-VSK75GSS.mjs';
2
- import '../chunk-3J24TPLA.mjs';
1
+ export { NNextImage, NajmNextUIProvider, NextLinkAdapter, useNextNavigationAdapter } from '../chunk-DKHIQFXX.mjs';
2
+ import '../chunk-BDQK6ECA.mjs';
3
3
  import '../chunk-LK3SMYUP.mjs';
@@ -1,4 +1,4 @@
1
- import { useResolvedFeedbackLabels, useNajmPreferencesContext } from './chunk-3J24TPLA.mjs';
1
+ import { useResolvedFeedbackLabels, useNajmPreferencesContext } from './chunk-BDQK6ECA.mjs';
2
2
  import { Button } from './chunk-M5VGBZ7R.mjs';
3
3
  import { useNajmDesign, cn } from './chunk-LK3SMYUP.mjs';
4
4
  import { humanizeToken, DEFAULT_PLACEHOLDER, formatRelativeTime, formatTime, formatDateTime, formatDate, formatPercent, formatNumber, formatCurrency } from './chunk-JABLSOQN.mjs';
@@ -1,6 +1,6 @@
1
1
  import { NajmDesignProvider, cn } from './chunk-LK3SMYUP.mjs';
2
- import * as React2 from 'react';
3
- import React2__default from 'react';
2
+ import * as React3 from 'react';
3
+ import React3__default from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
  import { DirectionProvider } from '@radix-ui/react-direction';
6
6
 
@@ -74,7 +74,7 @@ function statusTextClass(status, statusMap, fallback) {
74
74
  const color = findStatusColor(status, statusMap) ?? fallback;
75
75
  return color ? colorTextClass(color) : "";
76
76
  }
77
- var NTableDefaultsContext = React2__default.createContext({});
77
+ var NTableDefaultsContext = React3__default.createContext({});
78
78
  function NTableDefaultsProvider({
79
79
  children,
80
80
  value
@@ -82,12 +82,12 @@ function NTableDefaultsProvider({
82
82
  return /* @__PURE__ */ jsx(NTableDefaultsContext.Provider, { value, children });
83
83
  }
84
84
  function useNTableDefaults() {
85
- return React2__default.useContext(NTableDefaultsContext);
85
+ return React3__default.useContext(NTableDefaultsContext);
86
86
  }
87
87
  function useResolvedPaginationLabels(own) {
88
88
  const defaults = useNTableDefaults();
89
89
  const inherited = defaults.paginationLabels;
90
- return React2__default.useMemo(
90
+ return React3__default.useMemo(
91
91
  () => ({ ...inherited, ...own }),
92
92
  [inherited, own]
93
93
  );
@@ -95,12 +95,72 @@ function useResolvedPaginationLabels(own) {
95
95
  function useResolvedToolbarLabels(own) {
96
96
  const defaults = useNTableDefaults();
97
97
  const inherited = defaults.toolbarLabels;
98
- return React2__default.useMemo(
98
+ return React3__default.useMemo(
99
99
  () => ({ ...inherited, ...own }),
100
100
  [inherited, own]
101
101
  );
102
102
  }
103
- var NajmPreferencesContext = React2.createContext(null);
103
+ var ENGLISH_FEEDBACK_LABELS = {
104
+ loadingLabel: "Loading...",
105
+ emptyTitle: "No data",
106
+ errorTitle: "Something went wrong",
107
+ retryLabel: "Try again",
108
+ forbiddenTitle: "Access denied",
109
+ forbiddenDescription: "You do not have permission to view this page.",
110
+ notFoundTitle: "Page not found",
111
+ notFoundDescription: "The requested page could not be found."
112
+ };
113
+ var NFeedbackDefaultsContext = React3.createContext(null);
114
+ function NFeedbackDefaultsProvider({
115
+ value,
116
+ children
117
+ }) {
118
+ return /* @__PURE__ */ jsx(NFeedbackDefaultsContext.Provider, { value, children });
119
+ }
120
+ function useNFeedbackDefaults() {
121
+ return React3.useContext(NFeedbackDefaultsContext);
122
+ }
123
+ var DEFAULT_FEEDBACK_KEY_PREFIX = "common.feedback";
124
+ function useResolvedFeedbackLabels() {
125
+ const ctx = useNFeedbackDefaults();
126
+ return React3.useMemo(() => resolveFeedbackLabels(ctx), [ctx]);
127
+ }
128
+ function resolveFeedbackLabels(ctx) {
129
+ const defaults = ctx?.defaults;
130
+ const t = ctx?.t;
131
+ const labels = defaults?.labels;
132
+ const labelKeys = defaults?.labelKeys;
133
+ const prefix = defaults?.prefix ?? DEFAULT_FEEDBACK_KEY_PREFIX;
134
+ const translated = (key) => {
135
+ if (!t) return void 0;
136
+ const value = t(key);
137
+ return value === key ? void 0 : value;
138
+ };
139
+ const pick = (field, hasFallback) => {
140
+ const literal = labels?.[field];
141
+ if (literal !== void 0) return literal;
142
+ const key = labelKeys?.[field];
143
+ const fromCatalog = translated(key ?? `${prefix}.${field}`);
144
+ if (fromCatalog !== void 0) return fromCatalog;
145
+ if (hasFallback) return ENGLISH_FEEDBACK_LABELS[field];
146
+ return void 0;
147
+ };
148
+ return {
149
+ loadingLabel: pick("loadingLabel", true) ?? ENGLISH_FEEDBACK_LABELS.loadingLabel,
150
+ emptyTitle: pick("emptyTitle", true) ?? ENGLISH_FEEDBACK_LABELS.emptyTitle,
151
+ errorTitle: pick("errorTitle", true) ?? ENGLISH_FEEDBACK_LABELS.errorTitle,
152
+ errorMessage: pick("errorMessage", false),
153
+ retryLabel: pick("retryLabel", true) ?? ENGLISH_FEEDBACK_LABELS.retryLabel,
154
+ forbiddenTitle: pick("forbiddenTitle", true) ?? ENGLISH_FEEDBACK_LABELS.forbiddenTitle,
155
+ forbiddenDescription: pick("forbiddenDescription", true) ?? ENGLISH_FEEDBACK_LABELS.forbiddenDescription,
156
+ notFoundTitle: pick("notFoundTitle", true) ?? ENGLISH_FEEDBACK_LABELS.notFoundTitle,
157
+ notFoundDescription: pick("notFoundDescription", true) ?? ENGLISH_FEEDBACK_LABELS.notFoundDescription
158
+ };
159
+ }
160
+ function resolveFeedbackDefaultsValue(defaults, t) {
161
+ return { defaults: defaults ?? {}, t };
162
+ }
163
+ var NajmPreferencesContext = React3.createContext(null);
104
164
  var DEFAULT_TIME_ZONE = "UTC";
105
165
  function isValidTimeZone(value) {
106
166
  try {
@@ -129,44 +189,44 @@ function NajmPreferencesProvider({
129
189
  onTimeZoneChange,
130
190
  normalizeTimeZone = defaultNormalizeTimeZone
131
191
  }) {
132
- const [theme, setThemeState] = React2.useState(initialTheme);
133
- const [timeZone, setTimeZoneState] = React2.useState(
192
+ const [theme, setThemeState] = React3.useState(initialTheme);
193
+ const [timeZone, setTimeZoneState] = React3.useState(
134
194
  () => normalizeTimeZone(initialTimeZone)
135
195
  );
136
- const onThemeChangeRef = React2.useRef(onThemeChange);
137
- const onTimeZoneChangeRef = React2.useRef(onTimeZoneChange);
138
- const normalizeRef = React2.useRef(normalizeTimeZone);
139
- React2.useEffect(() => {
196
+ const onThemeChangeRef = React3.useRef(onThemeChange);
197
+ const onTimeZoneChangeRef = React3.useRef(onTimeZoneChange);
198
+ const normalizeRef = React3.useRef(normalizeTimeZone);
199
+ React3.useEffect(() => {
140
200
  onThemeChangeRef.current = onThemeChange;
141
201
  onTimeZoneChangeRef.current = onTimeZoneChange;
142
202
  normalizeRef.current = normalizeTimeZone;
143
203
  });
144
- React2.useEffect(() => {
204
+ React3.useEffect(() => {
145
205
  applyTheme(theme);
146
206
  applyTimeZone(timeZone);
147
207
  }, []);
148
- const setTheme = React2.useCallback(async (next) => {
208
+ const setTheme = React3.useCallback(async (next) => {
149
209
  setThemeState(next);
150
210
  applyTheme(next);
151
211
  await onThemeChangeRef.current?.(next);
152
212
  }, []);
153
- const setTimeZone = React2.useCallback(async (next) => {
213
+ const setTimeZone = React3.useCallback(async (next) => {
154
214
  const normalized = normalizeRef.current(next);
155
215
  setTimeZoneState(normalized);
156
216
  applyTimeZone(normalized);
157
217
  await onTimeZoneChangeRef.current?.(normalized);
158
218
  }, []);
159
- const value = React2.useMemo(
219
+ const value = React3.useMemo(
160
220
  () => ({ theme, setTheme, timeZone, setTimeZone }),
161
221
  [theme, setTheme, timeZone, setTimeZone]
162
222
  );
163
223
  return /* @__PURE__ */ jsx(NajmPreferencesContext.Provider, { value, children });
164
224
  }
165
225
  function useNajmPreferencesContext() {
166
- return React2.useContext(NajmPreferencesContext);
226
+ return React3.useContext(NajmPreferencesContext);
167
227
  }
168
228
  function usePreferencesOrThrow(hook) {
169
- const value = React2.useContext(NajmPreferencesContext);
229
+ const value = React3.useContext(NajmPreferencesContext);
170
230
  if (!value) {
171
231
  throw new Error(
172
232
  `${hook} must be rendered under a NajmUIProvider or NajmPreferencesProvider.`
@@ -176,11 +236,11 @@ function usePreferencesOrThrow(hook) {
176
236
  }
177
237
  function useNajmTheme() {
178
238
  const { theme, setTheme } = usePreferencesOrThrow("useNajmTheme");
179
- return React2.useMemo(() => ({ theme, setTheme }), [theme, setTheme]);
239
+ return React3.useMemo(() => ({ theme, setTheme }), [theme, setTheme]);
180
240
  }
181
241
  function useNajmTimeZone() {
182
242
  const { timeZone, setTimeZone } = usePreferencesOrThrow("useNajmTimeZone");
183
- return React2.useMemo(
243
+ return React3.useMemo(
184
244
  () => ({ timeZone, setTimeZone }),
185
245
  [timeZone, setTimeZone]
186
246
  );
@@ -225,10 +285,10 @@ function buildToolbarLabels(t, prefix) {
225
285
  };
226
286
  }
227
287
  function useDocumentDirection(override) {
228
- const [direction, setDirection] = React2.useState(
288
+ const [direction, setDirection] = React3.useState(
229
289
  override ?? "ltr"
230
290
  );
231
- React2.useEffect(() => {
291
+ React3.useEffect(() => {
232
292
  if (override) {
233
293
  setDirection(override);
234
294
  return;
@@ -247,9 +307,9 @@ var EMPTY_DESIGN = Object.freeze({
247
307
  theme: {},
248
308
  components: {}
249
309
  });
250
- var NajmDesignEditorContext = React2.createContext(null);
310
+ var NajmDesignEditorContext = React3.createContext(null);
251
311
  function useNajmDesignEditor() {
252
- return React2.useContext(NajmDesignEditorContext);
312
+ return React3.useContext(NajmDesignEditorContext);
253
313
  }
254
314
  function cloneDesign(design) {
255
315
  return structuredClone(design);
@@ -259,29 +319,29 @@ function NajmDesignEditorProvider({
259
319
  design,
260
320
  initialDesign
261
321
  }) {
262
- const [state, setState] = React2.useState(() => ({
322
+ const [state, setState] = React3.useState(() => ({
263
323
  committed: initialDesign ?? design ?? EMPTY_DESIGN,
264
324
  draft: null
265
325
  }));
266
- const beginDraft = React2.useCallback(() => {
326
+ const beginDraft = React3.useCallback(() => {
267
327
  setState(
268
328
  (current) => current.draft ? current : { ...current, draft: cloneDesign(current.committed) }
269
329
  );
270
330
  }, []);
271
- const setDraft = React2.useCallback((next) => {
331
+ const setDraft = React3.useCallback((next) => {
272
332
  setState((current) => ({ ...current, draft: cloneDesign(next) }));
273
333
  }, []);
274
- const cancelDraft = React2.useCallback(() => {
334
+ const cancelDraft = React3.useCallback(() => {
275
335
  setState(
276
336
  (current) => current.draft === null ? current : { ...current, draft: null }
277
337
  );
278
338
  }, []);
279
- const setCommitted = React2.useCallback((next) => {
339
+ const setCommitted = React3.useCallback((next) => {
280
340
  setState(
281
341
  (current) => current.committed === next && current.draft === null ? current : { committed: next, draft: null }
282
342
  );
283
343
  }, []);
284
- const value = React2.useMemo(() => {
344
+ const value = React3.useMemo(() => {
285
345
  if (design) {
286
346
  return {
287
347
  design,
@@ -309,20 +369,20 @@ function NajmDesignEditorProvider({
309
369
  }
310
370
  function noop() {
311
371
  }
312
- var NBadgeDefaultsContext = React2.createContext(null);
372
+ var NBadgeDefaultsContext = React3.createContext(null);
313
373
  function NBadgeDefaultsProvider({
314
374
  defaults,
315
375
  t,
316
376
  children
317
377
  }) {
318
- const value = React2.useMemo(
378
+ const value = React3.useMemo(
319
379
  () => ({ defaults, t }),
320
380
  [defaults, t]
321
381
  );
322
382
  return /* @__PURE__ */ jsx(NBadgeDefaultsContext.Provider, { value, children });
323
383
  }
324
384
  function useNBadgeDefaults() {
325
- return React2.useContext(NBadgeDefaultsContext);
385
+ return React3.useContext(NBadgeDefaultsContext);
326
386
  }
327
387
  function resolveBadgeStatusLabel(status, defaults, t) {
328
388
  if (!defaults) return void 0;
@@ -337,60 +397,6 @@ function mergeBadgeMaps(base, overrides) {
337
397
  if (!overrides) return base;
338
398
  return { ...base, ...overrides };
339
399
  }
340
- var ENGLISH_FEEDBACK_LABELS = {
341
- loadingLabel: "Loading...",
342
- emptyTitle: "No data",
343
- errorTitle: "Something went wrong",
344
- retryLabel: "Try again",
345
- forbiddenTitle: "Access denied",
346
- forbiddenDescription: "You do not have permission to view this page.",
347
- notFoundTitle: "Page not found",
348
- notFoundDescription: "The requested page could not be found."
349
- };
350
- var NFeedbackDefaultsContext = React2.createContext(null);
351
- function NFeedbackDefaultsProvider({
352
- value,
353
- children
354
- }) {
355
- return /* @__PURE__ */ jsx(NFeedbackDefaultsContext.Provider, { value, children });
356
- }
357
- function useNFeedbackDefaults() {
358
- return React2.useContext(NFeedbackDefaultsContext);
359
- }
360
- var DEFAULT_FEEDBACK_KEY_PREFIX = "common.feedback";
361
- function useResolvedFeedbackLabels() {
362
- const ctx = useNFeedbackDefaults();
363
- return React2.useMemo(() => resolveFeedbackLabels(ctx), [ctx]);
364
- }
365
- function resolveFeedbackLabels(ctx) {
366
- const defaults = ctx?.defaults;
367
- const t = ctx?.t;
368
- const labels = defaults?.labels;
369
- const labelKeys = defaults?.labelKeys;
370
- defaults?.prefix ?? DEFAULT_FEEDBACK_KEY_PREFIX;
371
- const pick = (field, hasFallback) => {
372
- const literal = labels?.[field];
373
- if (literal !== void 0) return literal;
374
- const key = labelKeys?.[field];
375
- if (key && t) return t(key);
376
- if (hasFallback) return ENGLISH_FEEDBACK_LABELS[field];
377
- return void 0;
378
- };
379
- return {
380
- loadingLabel: pick("loadingLabel", true) ?? ENGLISH_FEEDBACK_LABELS.loadingLabel,
381
- emptyTitle: pick("emptyTitle", true) ?? ENGLISH_FEEDBACK_LABELS.emptyTitle,
382
- errorTitle: pick("errorTitle", true) ?? ENGLISH_FEEDBACK_LABELS.errorTitle,
383
- errorMessage: pick("errorMessage", false),
384
- retryLabel: pick("retryLabel", true) ?? ENGLISH_FEEDBACK_LABELS.retryLabel,
385
- forbiddenTitle: pick("forbiddenTitle", true) ?? ENGLISH_FEEDBACK_LABELS.forbiddenTitle,
386
- forbiddenDescription: pick("forbiddenDescription", true) ?? ENGLISH_FEEDBACK_LABELS.forbiddenDescription,
387
- notFoundTitle: pick("notFoundTitle", true) ?? ENGLISH_FEEDBACK_LABELS.notFoundTitle,
388
- notFoundDescription: pick("notFoundDescription", true) ?? ENGLISH_FEEDBACK_LABELS.notFoundDescription
389
- };
390
- }
391
- function resolveFeedbackDefaultsValue(defaults, t) {
392
- return { defaults: defaults ?? {}, t };
393
- }
394
400
  function NajmUICore({
395
401
  children,
396
402
  className,
@@ -405,7 +411,7 @@ function NajmUICore({
405
411
  const { theme } = useNajmTheme();
406
412
  const direction = useDocumentDirection(dir);
407
413
  const design = useNajmDesignEditor()?.design ?? EMPTY_DESIGN;
408
- const defaults = React2.useMemo(() => {
414
+ const defaults = React3.useMemo(() => {
409
415
  const translated = t ? buildPaginationLabels(t, paginationKeyPrefix) : void 0;
410
416
  const overrides = tableDefaults?.paginationLabels;
411
417
  const paginationLabels = translated || overrides ? { ...translated, ...overrides } : void 0;
@@ -414,7 +420,7 @@ function NajmUICore({
414
420
  const toolbarLabels = translatedToolbar || toolbarOverrides ? { ...translatedToolbar, ...toolbarOverrides } : void 0;
415
421
  return { ...tableDefaults, paginationLabels, toolbarLabels };
416
422
  }, [t, paginationKeyPrefix, toolbarKeyPrefix, tableDefaults]);
417
- const feedbackValue = React2.useMemo(
423
+ const feedbackValue = React3.useMemo(
418
424
  () => resolveFeedbackDefaultsValue(feedbackDefaults, t),
419
425
  [feedbackDefaults, t]
420
426
  );
@@ -499,7 +505,7 @@ function selectImageSource(sources, failed) {
499
505
  var NO_FAILURES = [];
500
506
  function useImageChain(sources) {
501
507
  const key = JSON.stringify(sources);
502
- const [state, setState] = React2.useState(() => ({
508
+ const [state, setState] = React3.useState(() => ({
503
509
  key,
504
510
  failed: NO_FAILURES,
505
511
  loaded: null
@@ -508,13 +514,13 @@ function useImageChain(sources) {
508
514
  const current = state.key === key ? state : fresh;
509
515
  if (state.key !== key) setState(fresh);
510
516
  const active = selectImageSource(sources, current.failed);
511
- const markLoaded = React2.useCallback(() => {
517
+ const markLoaded = React3.useCallback(() => {
512
518
  if (active === void 0) return;
513
519
  setState(
514
520
  (prev) => prev.key !== key || prev.loaded === active ? prev : { ...prev, loaded: active }
515
521
  );
516
522
  }, [key, active]);
517
- const markFailed = React2.useCallback(() => {
523
+ const markFailed = React3.useCallback(() => {
518
524
  if (active === void 0) return;
519
525
  setState((prev) => {
520
526
  if (prev.key !== key || prev.failed.includes(active)) return prev;
@@ -534,4 +540,4 @@ function useImageChain(sources) {
534
540
  };
535
541
  }
536
542
 
537
- export { DEFAULT_PAGINATION_KEY_PREFIX, DEFAULT_TIME_ZONE, DEFAULT_TOOLBAR_KEY_PREFIX, EMPTY_DESIGN, NAJM_COLOR_TEXT_CLASSES, NAJM_STATUS_COLORS, NTableDefaultsProvider, NajmDesignEditorProvider, NajmPreferencesProvider, NajmUIProvider, buildPaginationLabels, buildToolbarLabels, colorTextClass, findStatusColor, mergeBadgeMaps, normalizeImageSources, normalizeStatusToken, resolveBadgeStatusLabel, resolveStatusColor, statusTextClass, useDocumentDirection, useImageChain, useNBadgeDefaults, useNTableDefaults, useNajmDesignEditor, useNajmPreferencesContext, useNajmTheme, useNajmTimeZone, useResolvedFeedbackLabels, useResolvedPaginationLabels, useResolvedToolbarLabels };
543
+ export { DEFAULT_FEEDBACK_KEY_PREFIX, DEFAULT_PAGINATION_KEY_PREFIX, DEFAULT_TIME_ZONE, DEFAULT_TOOLBAR_KEY_PREFIX, EMPTY_DESIGN, NAJM_COLOR_TEXT_CLASSES, NAJM_STATUS_COLORS, NTableDefaultsProvider, NajmDesignEditorProvider, NajmPreferencesProvider, NajmUIProvider, buildPaginationLabels, buildToolbarLabels, colorTextClass, findStatusColor, mergeBadgeMaps, normalizeImageSources, normalizeStatusToken, resolveBadgeStatusLabel, resolveStatusColor, statusTextClass, useDocumentDirection, useImageChain, useNBadgeDefaults, useNTableDefaults, useNajmDesignEditor, useNajmPreferencesContext, useNajmTheme, useNajmTimeZone, useResolvedFeedbackLabels, useResolvedPaginationLabels, useResolvedToolbarLabels };
@@ -1,4 +1,4 @@
1
- import { useImageChain, normalizeImageSources, NajmUIProvider } from './chunk-3J24TPLA.mjs';
1
+ import { useImageChain, normalizeImageSources, NajmUIProvider } from './chunk-BDQK6ECA.mjs';
2
2
  import React from 'react';
3
3
  import { useRouter } from 'next/navigation';
4
4
  import NextImage from 'next/image';
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import * as React$1 from 'react';
2
2
  import React__default, { RefObject, ReactNode, ComponentType, InputHTMLAttributes, Ref, ImgHTMLAttributes, CSSProperties, MouseEvent, MouseEventHandler } from 'react';
3
3
  import { a as NajmDesignConfig, f as NajmThemeProviderProps, g as NajmAppearance, e as NajmMode, h as NajmThemeConfig, i as NajmAccent, j as NajmThemeTokens, k as NajmPreset, l as NajmComponentName, m as NajmComponentStyleConfig, N as NajmComponentThemeConfig, c as NajmTypographyConfig, b as NajmLayoutConfig, n as NajmResponsiveBreakpoint, o as NajmResponsiveValue } from './design-types-Rkpt8Pg1.js';
4
4
  export { p as NAJM_COMPONENT_NAMES, q as NajmComponentRadius, r as NajmDensity, s as NajmSlotStyle, d as NajmVariantStyle, R as RADIUS_VALUE_MAP, t as resolveRadiusValue } from './design-types-Rkpt8Pg1.js';
5
- import { d as NTableToolbarLabels, e as NIconSource, B as BadgeColor, f as BadgeShape } from './NajmUIProvider-DSjvh4x2.js';
6
- export { g as Badge, h as BadgeIcon, i as BadgeLook, j as BadgeProps, k as BadgeSize, l as BadgeVariant, D as DEFAULT_TIME_ZONE, m as NBadge, n as NBadgeDefaults, o as NBadgeLook, p as NBadgeProps, N as NFeedbackDefaults, a as NFeedbackLabelKeys, b as NFeedbackLabels, q as NIcon, r as NIconProps, s as NTableDefaults, t as NTableDefaultsProvider, u as NajmPreferencesContextValue, v as NajmPreferencesProvider, w as NajmPreferencesProviderProps, x as NajmUIProvider, c as NajmUIProviderProps, y as badgeColorVariants, z as badgeVariants, A as useDocumentDirection, C as useNTableDefaults, E as useNajmPreferencesContext, F as useNajmTheme, G as useNajmTimeZone, H as useResolvedToolbarLabels } from './NajmUIProvider-DSjvh4x2.js';
5
+ import { d as NTableToolbarLabels, e as NIconSource, B as BadgeColor, f as BadgeShape } from './NajmUIProvider-DTyRrukg.js';
6
+ export { g as Badge, h as BadgeIcon, i as BadgeLook, j as BadgeProps, k as BadgeSize, l as BadgeVariant, D as DEFAULT_FEEDBACK_KEY_PREFIX, m as DEFAULT_TIME_ZONE, F as FeedbackKey, n as NBadge, o as NBadgeDefaults, p as NBadgeLook, q as NBadgeProps, N as NFeedbackDefaults, a as NFeedbackLabelKeys, b as NFeedbackLabels, r as NIcon, s as NIconProps, t as NTableDefaults, u as NTableDefaultsProvider, v as NajmPreferencesContextValue, w as NajmPreferencesProvider, x as NajmPreferencesProviderProps, y as NajmUIProvider, c as NajmUIProviderProps, z as badgeColorVariants, A as badgeVariants, C as useDocumentDirection, E as useNTableDefaults, G as useNajmPreferencesContext, H as useNajmTheme, I as useNajmTimeZone, J as useResolvedToolbarLabels } from './NajmUIProvider-DTyRrukg.js';
7
7
  import { N as NajmTranslate, c as NTablePaginationVariant, b as NTablePaginationLabels, a as NTableCardPagination } from './paginationLabels-dZLSNxfo.js';
8
8
  export { D as DEFAULT_PAGINATION_KEY_PREFIX, d as NTableInfinitePagination, e as NTableLoadMorePagination, f as buildPaginationLabels } from './paginationLabels-dZLSNxfo.js';
9
9
  export { d as defineNajmDesignConfig, p as parseNajmDesignConfig, r as resolveVariantAlias, s as stringifyNajmDesignConfig } from './design-config-D_x1GCu3.js';
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { resolveAvatarSrc } from './chunk-BEGOH366.mjs';
2
2
  export { isPlaceholderAvatar, resolveAvatarSrc } from './chunk-BEGOH366.mjs';
3
- import { NLoadingState, NErrorState, NEmptyState, useResolvedFormDevTools, useNBranding } from './chunk-56JQI3VL.mjs';
4
- export { FormDevToolsProvider, NBrandingProvider, NBrandingStateProvider, NEmptyState, NErrorState, NForbiddenState, NLoadingState, NNotFoundState, NPageLayout, NSpinner, NajmFormatProvider, buildFormFill, normalizeBranding, useNBranding, useNBrandingEditor, useNajmFormat, useNajmFormatContext } from './chunk-56JQI3VL.mjs';
5
- import { normalizeImageSources, useImageChain, useNBadgeDefaults, mergeBadgeMaps, resolveStatusColor, resolveBadgeStatusLabel, colorTextClass, useResolvedPaginationLabels, useResolvedToolbarLabels } from './chunk-3J24TPLA.mjs';
6
- export { DEFAULT_PAGINATION_KEY_PREFIX, DEFAULT_TIME_ZONE, DEFAULT_TOOLBAR_KEY_PREFIX, EMPTY_DESIGN, NAJM_COLOR_TEXT_CLASSES, NAJM_STATUS_COLORS, NTableDefaultsProvider, NajmDesignEditorProvider, NajmPreferencesProvider, NajmUIProvider, buildPaginationLabels, buildToolbarLabels, colorTextClass, findStatusColor, normalizeStatusToken, resolveStatusColor, statusTextClass, useDocumentDirection, useNTableDefaults, useNajmDesignEditor, useNajmPreferencesContext, useNajmTheme, useNajmTimeZone, useResolvedToolbarLabels } from './chunk-3J24TPLA.mjs';
3
+ import { NLoadingState, NErrorState, NEmptyState, useResolvedFormDevTools, useNBranding } from './chunk-26EASWUY.mjs';
4
+ export { FormDevToolsProvider, NBrandingProvider, NBrandingStateProvider, NEmptyState, NErrorState, NForbiddenState, NLoadingState, NNotFoundState, NPageLayout, NSpinner, NajmFormatProvider, buildFormFill, normalizeBranding, useNBranding, useNBrandingEditor, useNajmFormat, useNajmFormatContext } from './chunk-26EASWUY.mjs';
5
+ import { normalizeImageSources, useImageChain, useNBadgeDefaults, mergeBadgeMaps, resolveStatusColor, resolveBadgeStatusLabel, colorTextClass, useResolvedPaginationLabels, useResolvedToolbarLabels } from './chunk-BDQK6ECA.mjs';
6
+ export { DEFAULT_FEEDBACK_KEY_PREFIX, DEFAULT_PAGINATION_KEY_PREFIX, DEFAULT_TIME_ZONE, DEFAULT_TOOLBAR_KEY_PREFIX, EMPTY_DESIGN, NAJM_COLOR_TEXT_CLASSES, NAJM_STATUS_COLORS, NTableDefaultsProvider, NajmDesignEditorProvider, NajmPreferencesProvider, NajmUIProvider, buildPaginationLabels, buildToolbarLabels, colorTextClass, findStatusColor, normalizeStatusToken, resolveStatusColor, statusTextClass, useDocumentDirection, useNTableDefaults, useNajmDesignEditor, useNajmPreferencesContext, useNajmTheme, useNajmTimeZone, useResolvedToolbarLabels } from './chunk-BDQK6ECA.mjs';
7
7
  import { NajmScroll, useNajmScrollViewport, useTableStore, TableStoreContext, NTableJson } from './chunk-5JVFMOLI.mjs';
8
8
  export { NTableJson, NajmScroll, TableStoreContext, useTableStore } from './chunk-5JVFMOLI.mjs';
9
9
  import { inputBorderClasses, Button, NIcon, surfaceBorderClasses, buttonVariants, NButton, sidebarBorderClasses } from './chunk-M5VGBZ7R.mjs';
package/dist/theme.css CHANGED
@@ -317,10 +317,10 @@ input:autofill {
317
317
  overflow-x: auto;
318
318
  scrollbar-width: none;
319
319
  }
320
- .najm-overlay-scroll-x::-webkit-scrollbar {
321
- display: none;
322
- }
323
-
320
+ .najm-overlay-scroll-x::-webkit-scrollbar {
321
+ display: none;
322
+ }
323
+
324
324
  /* Responsive table actions stay discoverable on touch and tablet layouts.
325
325
  Fine-pointer desktops may keep the quieter hover/focus reveal treatment. */
326
326
  .ntable-card-action {
@@ -377,7 +377,7 @@ input:autofill {
377
377
  .nimage-input-compact-overlay:focus-visible {
378
378
  opacity: 1;
379
379
  }
380
- }
380
+ }
381
381
 
382
382
  /* OverlayScrollbars theme used by the <NajmScroll> component — a thin,
383
383
  translucent slate bar that floats over content with no reserved space.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-kit",
3
- "version": "2.11.12",
3
+ "version": "2.11.13",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Reusable React UI component package for Najm framework",
@@ -198,7 +198,7 @@
198
198
  "@uiw/react-codemirror": "^4.25.0",
199
199
  "@vitejs/plugin-react": "^5.2.0",
200
200
  "happy-dom": "^20.11.1",
201
- "najm-i18n": "^2.0.3",
201
+ "najm-i18n": "^2.1.0",
202
202
  "postcss": "^8.5.22",
203
203
  "react-hook-form": "^7",
204
204
  "rimraf": "^6",