najm-kit 2.7.0 → 2.7.2

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,33 +1,66 @@
1
1
  'use client';
2
- import { NBrandingProvider } from '../chunk-IGUQGT3G.mjs';
3
- import { NajmNextUIProvider } from '../chunk-4MRUJ2ZO.mjs';
4
- import '../chunk-7F65QM43.mjs';
5
- import '../chunk-YBM5CTE6.mjs';
2
+ import { NBrandingStateProvider, NajmFormatProvider } from '../chunk-QOP7L6RD.mjs';
3
+ import { NajmNextUIProvider } from '../chunk-IRFFSAO2.mjs';
4
+ import '../chunk-USZUOJMK.mjs';
5
+ import '../chunk-KVZACF4G.mjs';
6
6
  import * as React from 'react';
7
7
  import { I18nProvider, useTranslation } from 'najm-i18n/react';
8
8
  import { jsx } from 'react/jsx-runtime';
9
9
 
10
10
  var DEFAULT_LANGUAGE_ENDPOINT = "/api/ui-language";
11
- function NajmAppUI({ children, branding, ...props }) {
12
- const { t } = useTranslation();
11
+ function NajmAppUI({
12
+ children,
13
+ branding,
14
+ initialBranding,
15
+ currency,
16
+ locale,
17
+ locales,
18
+ formatPlaceholder,
19
+ ...props
20
+ }) {
21
+ const { t, language } = useTranslation();
22
+ const resolved = locale ?? locales?.[language] ?? language;
13
23
  return /* @__PURE__ */ jsx(NajmNextUIProvider, { t, ...props, children: /* @__PURE__ */ jsx(
14
- NBrandingProvider,
24
+ NBrandingStateProvider,
15
25
  {
16
- appName: branding?.appName,
17
- logoExpanded: branding?.logoExpanded,
18
- logoCollapsed: branding?.logoCollapsed,
19
- children
26
+ branding,
27
+ initialBranding,
28
+ children: /* @__PURE__ */ jsx(
29
+ NajmFormatProvider,
30
+ {
31
+ locale: resolved,
32
+ currency,
33
+ placeholder: formatPlaceholder,
34
+ children
35
+ }
36
+ )
20
37
  }
21
38
  ) });
22
39
  }
23
- function NajmAppNoI18n({ children, branding, ...props }) {
40
+ function NajmAppNoI18n({
41
+ children,
42
+ branding,
43
+ initialBranding,
44
+ currency,
45
+ locale,
46
+ locales,
47
+ formatPlaceholder,
48
+ ...props
49
+ }) {
24
50
  return /* @__PURE__ */ jsx(NajmNextUIProvider, { ...props, children: /* @__PURE__ */ jsx(
25
- NBrandingProvider,
51
+ NBrandingStateProvider,
26
52
  {
27
- appName: branding?.appName,
28
- logoExpanded: branding?.logoExpanded,
29
- logoCollapsed: branding?.logoCollapsed,
30
- children
53
+ branding,
54
+ initialBranding,
55
+ children: /* @__PURE__ */ jsx(
56
+ NajmFormatProvider,
57
+ {
58
+ locale: locale ?? "en",
59
+ currency,
60
+ placeholder: formatPlaceholder,
61
+ children
62
+ }
63
+ )
31
64
  }
32
65
  ) });
33
66
  }
@@ -36,6 +69,8 @@ function NajmAppProvider({
36
69
  initialLanguage,
37
70
  defaultLanguage,
38
71
  languageEndpoint = DEFAULT_LANGUAGE_ENDPOINT,
72
+ appName,
73
+ initialBranding,
39
74
  ...props
40
75
  }) {
41
76
  const persistLanguage = React.useCallback(
@@ -54,7 +89,8 @@ function NajmAppProvider({
54
89
  },
55
90
  [languageEndpoint]
56
91
  );
57
- if (!translations) return /* @__PURE__ */ jsx(NajmAppNoI18n, { ...props });
92
+ const seeded = appName ? { appName, ...initialBranding } : initialBranding;
93
+ if (!translations) return /* @__PURE__ */ jsx(NajmAppNoI18n, { ...props, initialBranding: seeded });
58
94
  return /* @__PURE__ */ jsx(
59
95
  I18nProvider,
60
96
  {
@@ -62,7 +98,7 @@ function NajmAppProvider({
62
98
  initialLanguage: initialLanguage ?? defaultLanguage ?? "en",
63
99
  defaultLanguage,
64
100
  onLanguageChange: persistLanguage,
65
- children: /* @__PURE__ */ jsx(NajmAppUI, { ...props })
101
+ children: /* @__PURE__ */ jsx(NajmAppUI, { ...props, initialBranding: seeded })
66
102
  }
67
103
  );
68
104
  }
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React__default from 'react';
3
- import { N as NajmUIProviderProps } from '../NajmUIProvider-BsCoDjHH.js';
3
+ import { N as NajmUIProviderProps } from '../NajmUIProvider-ClpHD-55.js';
4
+ import '../paginationLabels-CY2PvbMj.js';
4
5
 
5
6
  interface NextLinkAdapterProps extends Record<string, any> {
6
7
  href: string;
@@ -1,3 +1,3 @@
1
- export { NajmNextUIProvider, NextLinkAdapter, useNextNavigationAdapter } from '../chunk-4MRUJ2ZO.mjs';
2
- import '../chunk-7F65QM43.mjs';
3
- import '../chunk-YBM5CTE6.mjs';
1
+ export { NajmNextUIProvider, NextLinkAdapter, useNextNavigationAdapter } from '../chunk-IRFFSAO2.mjs';
2
+ import '../chunk-USZUOJMK.mjs';
3
+ import '../chunk-KVZACF4G.mjs';
@@ -1,6 +1,4 @@
1
- import { useNajmComponentStyle } from './chunk-YBM5CTE6.mjs';
2
- import { clsx } from 'clsx';
3
- import { twMerge } from 'tailwind-merge';
1
+ import { useNajmComponentStyle, cn } from './chunk-KVZACF4G.mjs';
4
2
  import * as React2 from 'react';
5
3
  import React2__default, { createContext, useContext } from 'react';
6
4
  import * as LucideIcons from 'lucide-react';
@@ -11,9 +9,6 @@ import { cva } from 'class-variance-authority';
11
9
  import { OverlayScrollbars } from 'overlayscrollbars';
12
10
  import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
13
11
 
14
- function cn(...inputs) {
15
- return twMerge(clsx(inputs));
16
- }
17
12
  function toPascalCase(value) {
18
13
  return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[\s_-]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
19
14
  }
@@ -829,4 +824,4 @@ function NTableJson() {
829
824
  return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col min-h-0 overflow-hidden", children: renderJson?.() ?? /* @__PURE__ */ jsx(NajmScroll, { axis: "both", className: "h-full min-h-0 rounded-md border border-border bg-muted/40", children: /* @__PURE__ */ jsx("pre", { className: "p-4 font-mono text-xs leading-relaxed text-foreground", children: formatJsonValue(jsonValue) }) }) });
830
825
  }
831
826
 
832
- export { Button, NAJM_COMPONENT_NAMES, NButton, NIcon, NTableJson, NajmScroll, RADIUS_VALUE_MAP, TableStoreContext, buttonVariants, cn, defineNajmDesignConfig, defineNajmThemeConfig, inputBorderClasses, parseNajmDesignConfig, parseNajmThemeConfig, resolveRadiusValue, resolveVariantAlias, sidebarBorderClasses, stringifyNajmDesignConfig, stringifyNajmThemeConfig, surfaceBorderClasses, useNajmScrollViewport, useTableStore };
827
+ export { Button, NAJM_COMPONENT_NAMES, NButton, NIcon, NTableJson, NajmScroll, RADIUS_VALUE_MAP, TableStoreContext, buttonVariants, defineNajmDesignConfig, defineNajmThemeConfig, inputBorderClasses, parseNajmDesignConfig, parseNajmThemeConfig, resolveRadiusValue, resolveVariantAlias, sidebarBorderClasses, stringifyNajmDesignConfig, stringifyNajmThemeConfig, surfaceBorderClasses, useNajmScrollViewport, useTableStore };
@@ -0,0 +1,93 @@
1
+ import { useCallback, useSyncExternalStore } from 'react';
2
+
3
+ // src/hooks/useMediaQuery.ts
4
+ function useMediaQuery(query, serverSnapshot = false) {
5
+ const subscribe = useCallback(
6
+ (onStoreChange) => {
7
+ const media = window.matchMedia(query);
8
+ media.addEventListener("change", onStoreChange);
9
+ return () => media.removeEventListener("change", onStoreChange);
10
+ },
11
+ [query]
12
+ );
13
+ return useSyncExternalStore(
14
+ subscribe,
15
+ () => window.matchMedia(query).matches,
16
+ () => serverSnapshot
17
+ );
18
+ }
19
+ var DEFAULT_CARD_BREAKPOINT = 1024;
20
+ function useCardViewport(breakpoint = DEFAULT_CARD_BREAKPOINT) {
21
+ return useMediaQuery(`(max-width: ${breakpoint - 1}px)`);
22
+ }
23
+ function useDesktopTableMode(breakpoint = DEFAULT_CARD_BREAKPOINT) {
24
+ return useMediaQuery(`(min-width: ${breakpoint}px)`) ? "table" : "cards";
25
+ }
26
+
27
+ // src/components/table/cardPagination.ts
28
+ var DEFAULT_CARD_PAGINATION_KEY_PREFIX = "common.pagination";
29
+ function buildCardPaginationLabels(t, prefix = DEFAULT_CARD_PAGINATION_KEY_PREFIX) {
30
+ return {
31
+ loadMoreError: t(`${prefix}.loadMoreError`),
32
+ retryLabel: t(`${prefix}.retryLoadMore`),
33
+ itemsLoaded: (count) => t(`${prefix}.itemsLoaded`, { count })
34
+ };
35
+ }
36
+ function createCardPagination(state, labels = {}) {
37
+ const mode = state.mode ?? (state.cardViewport ? "infinite" : "paged");
38
+ if (mode === "paged") return { mode: "paged" };
39
+ if (mode === "all") return { mode: "all" };
40
+ return {
41
+ mode: "infinite",
42
+ hasNextPage: state.hasNextPage,
43
+ loadingMore: state.loadingMore,
44
+ loadMoreError: state.loadMoreError ? labels.loadMoreError : void 0,
45
+ onLoadMore: state.onLoadMore,
46
+ retryLabel: labels.retryLabel,
47
+ loadMoreErrorLabel: labels.loadMoreError,
48
+ itemsLoadedLabel: labels.itemsLoaded
49
+ };
50
+ }
51
+
52
+ // src/lib/pagination.ts
53
+ var DEFAULT_PAGE_SIZE = 25;
54
+ var DEFAULT_MAX_PAGE_SIZE = 100;
55
+ function toApiPage(result) {
56
+ return Array.isArray(result) ? { rows: result, total: null } : result;
57
+ }
58
+ function createOffsetPagination(pageIndex = 0, pageSize = DEFAULT_PAGE_SIZE, { maxLimit = DEFAULT_MAX_PAGE_SIZE } = {}) {
59
+ const safePageIndex = Math.max(0, Math.trunc(pageIndex));
60
+ const safePageSize = Math.min(maxLimit, Math.max(1, Math.trunc(pageSize)));
61
+ return { limit: safePageSize, offset: safePageIndex * safePageSize };
62
+ }
63
+ function getPageIndex({ limit, offset }) {
64
+ return Math.floor(Math.max(0, offset) / Math.max(1, limit));
65
+ }
66
+ async function fetchOffsetPage(fetchPage, pagination, { maxLimit = DEFAULT_MAX_PAGE_SIZE } = {}) {
67
+ const requestedLimit = Math.min(maxLimit, Math.max(1, pagination.limit));
68
+ const probeLimit = requestedLimit < maxLimit ? requestedLimit + 1 : requestedLimit;
69
+ const page = toApiPage(
70
+ await fetchPage({ limit: probeLimit, offset: pagination.offset })
71
+ );
72
+ const rows = page.rows.slice(0, requestedLimit);
73
+ const nextOffset = pagination.offset + rows.length;
74
+ if (page.total !== null) {
75
+ return {
76
+ rows,
77
+ hasNextPage: nextOffset < page.total,
78
+ nextOffset,
79
+ total: page.total
80
+ };
81
+ }
82
+ const hasNextPage = page.rows.length > requestedLimit || probeLimit === requestedLimit && page.rows.length === requestedLimit && toApiPage(await fetchPage({ limit: 1, offset: nextOffset })).rows.length > 0;
83
+ return { rows, hasNextPage, nextOffset, total: null };
84
+ }
85
+ function cleanQuery(query) {
86
+ return Object.fromEntries(
87
+ Object.entries(query).filter(
88
+ ([, value]) => value !== void 0 && value !== null && value !== ""
89
+ )
90
+ );
91
+ }
92
+
93
+ export { DEFAULT_CARD_BREAKPOINT, DEFAULT_CARD_PAGINATION_KEY_PREFIX, DEFAULT_MAX_PAGE_SIZE, DEFAULT_PAGE_SIZE, buildCardPaginationLabels, cleanQuery, createCardPagination, createOffsetPagination, fetchOffsetPage, getPageIndex, useCardViewport, useDesktopTableMode, useMediaQuery };
@@ -1,4 +1,4 @@
1
- import { NajmUIProvider } from './chunk-7F65QM43.mjs';
1
+ import { NajmUIProvider } from './chunk-USZUOJMK.mjs';
2
2
  import React from 'react';
3
3
  import { useRouter } from 'next/navigation';
4
4
  import { jsx } from 'react/jsx-runtime';
@@ -1,6 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { Slot } from '@radix-ui/react-slot';
3
3
  import { jsx } from 'react/jsx-runtime';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
4
6
 
5
7
  // src/theme/presets/modes.ts
6
8
  var lightMode = {
@@ -301,6 +303,9 @@ function NajmThemeProvider({
301
303
  }
302
304
  ) }) }) }) });
303
305
  }
306
+ function cn(...inputs) {
307
+ return twMerge(clsx(inputs));
308
+ }
304
309
  var NajmDesignContext = React.createContext({
305
310
  components: {}
306
311
  });
@@ -363,4 +368,4 @@ function NajmDesignProvider({
363
368
  ) : children }) });
364
369
  }
365
370
 
366
- export { NajmDesignProvider, NajmThemeContainerCtx, NajmThemeProvider, composePreset, resolvePreset, useNajmAppearance, useNajmComponentStyle, useNajmDesign, useNajmThemeMode };
371
+ export { NajmDesignProvider, NajmThemeContainerCtx, NajmThemeProvider, cn, composePreset, resolvePreset, useNajmAppearance, useNajmComponentStyle, useNajmDesign, useNajmThemeMode };
@@ -0,0 +1,218 @@
1
+ import { useNajmPreferencesContext } from './chunk-USZUOJMK.mjs';
2
+ import * as React from 'react';
3
+ import { createContext, useContext, useMemo, useState, useCallback } from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ function normalizeBranding(input) {
7
+ if (!input) return {};
8
+ const value = {};
9
+ const expanded = input.logoExpanded ?? input.sidebarLogoExpandedPath;
10
+ const collapsed = input.logoCollapsed ?? input.sidebarLogoCollapsedPath;
11
+ if (input.appName !== void 0) value.appName = input.appName;
12
+ if (input.logoFallback !== void 0) value.logoFallback = input.logoFallback;
13
+ if (input.logoHref !== void 0) value.logoHref = input.logoHref;
14
+ if (expanded !== void 0) value.logoExpanded = expanded;
15
+ if (collapsed !== void 0) value.logoCollapsed = collapsed;
16
+ return value;
17
+ }
18
+ var NBrandingContext = createContext(null);
19
+ function useNBranding() {
20
+ return useContext(NBrandingContext);
21
+ }
22
+ function NBrandingProvider({
23
+ children,
24
+ appName,
25
+ logoExpanded,
26
+ logoCollapsed,
27
+ logoFallback,
28
+ logoHref
29
+ }) {
30
+ const value = useMemo(
31
+ () => ({ appName, logoExpanded, logoCollapsed, logoFallback, logoHref }),
32
+ [appName, logoExpanded, logoCollapsed, logoFallback, logoHref]
33
+ );
34
+ return /* @__PURE__ */ jsx(NBrandingContext.Provider, { value, children });
35
+ }
36
+ var NBrandingEditorContext = createContext(null);
37
+ function useNBrandingEditor() {
38
+ return useContext(NBrandingEditorContext);
39
+ }
40
+ function NBrandingStateProvider({
41
+ children,
42
+ branding,
43
+ initialBranding
44
+ }) {
45
+ const [state, setState] = useState(
46
+ () => normalizeBranding(initialBranding ?? branding)
47
+ );
48
+ const setBranding = useCallback((patch) => {
49
+ const marks = normalizeBranding(patch);
50
+ setState((current) => ({ ...current, ...marks }));
51
+ }, []);
52
+ const controlled = useMemo(
53
+ () => branding ? normalizeBranding(branding) : void 0,
54
+ [branding]
55
+ );
56
+ const resolved = controlled ?? state;
57
+ const editor = useMemo(
58
+ () => ({ branding: resolved, setBranding: branding ? noop : setBranding }),
59
+ [resolved, branding, setBranding]
60
+ );
61
+ return /* @__PURE__ */ jsx(NBrandingEditorContext.Provider, { value: editor, children: /* @__PURE__ */ jsx(NBrandingProvider, { ...resolved, children }) });
62
+ }
63
+ function noop() {
64
+ }
65
+
66
+ // src/format/format.ts
67
+ var DEFAULT_PLACEHOLDER = "\u2014";
68
+ var numberFormats = /* @__PURE__ */ new Map();
69
+ var dateFormats = /* @__PURE__ */ new Map();
70
+ function numberFormat(locale, options) {
71
+ const key = `${locale}|${options ? JSON.stringify(options) : ""}`;
72
+ let format = numberFormats.get(key);
73
+ if (!format) {
74
+ format = new Intl.NumberFormat(locale, options);
75
+ numberFormats.set(key, format);
76
+ }
77
+ return format;
78
+ }
79
+ function dateFormat(locale, options) {
80
+ const key = `${locale}|${JSON.stringify(options)}`;
81
+ let format = dateFormats.get(key);
82
+ if (!format) {
83
+ format = new Intl.DateTimeFormat(locale, options);
84
+ dateFormats.set(key, format);
85
+ }
86
+ return format;
87
+ }
88
+ function minorUnitScale(locale, currency) {
89
+ const digits = numberFormat(locale, { style: "currency", currency }).resolvedOptions().maximumFractionDigits ?? 2;
90
+ return 10 ** digits;
91
+ }
92
+ function toDate(value) {
93
+ const date = value instanceof Date ? value : new Date(value);
94
+ return Number.isNaN(date.getTime()) ? null : date;
95
+ }
96
+ function isBlank(value) {
97
+ return value === null || value === void 0 || value === "";
98
+ }
99
+ function formatCurrency(minorUnits, { locale, currency, placeholder = DEFAULT_PLACEHOLDER }) {
100
+ if (!currency) {
101
+ throw new Error(
102
+ "formatCurrency requires a `currency`. Set it on NajmFormatProvider or pass it here."
103
+ );
104
+ }
105
+ if (minorUnits === null || minorUnits === void 0) return placeholder;
106
+ if (!Number.isSafeInteger(minorUnits)) return placeholder;
107
+ return numberFormat(locale, {
108
+ style: "currency",
109
+ currency
110
+ }).format(minorUnits / minorUnitScale(locale, currency));
111
+ }
112
+ function formatNumber(value, { locale, placeholder = DEFAULT_PLACEHOLDER }, options) {
113
+ if (value === null || value === void 0 || !Number.isFinite(value)) {
114
+ return placeholder;
115
+ }
116
+ return numberFormat(locale, options).format(value);
117
+ }
118
+ function formatPercent(value, config, fractionDigits = 0) {
119
+ return formatNumber(value, config, {
120
+ style: "percent",
121
+ minimumFractionDigits: fractionDigits,
122
+ maximumFractionDigits: fractionDigits
123
+ });
124
+ }
125
+ function formatDate(value, {
126
+ locale,
127
+ timeZone,
128
+ placeholder = DEFAULT_PLACEHOLDER
129
+ }, options = { dateStyle: "medium" }) {
130
+ if (isBlank(value)) return placeholder;
131
+ const date = toDate(value);
132
+ if (!date) return placeholder;
133
+ return dateFormat(locale, { ...options, timeZone }).format(date);
134
+ }
135
+ function formatDateTime(value, config, options = {
136
+ dateStyle: "short",
137
+ timeStyle: "short"
138
+ }) {
139
+ return formatDate(value, config, options);
140
+ }
141
+ function formatTime(value, config) {
142
+ return formatDate(value, config, { timeStyle: "short" });
143
+ }
144
+ var RELATIVE_UNITS = [
145
+ ["year", 31536e6],
146
+ ["month", 2592e6],
147
+ ["day", 864e5],
148
+ ["hour", 36e5],
149
+ ["minute", 6e4],
150
+ ["second", 1e3]
151
+ ];
152
+ function formatRelativeTime(value, { locale, placeholder = DEFAULT_PLACEHOLDER }, now = Date.now()) {
153
+ if (isBlank(value)) return placeholder;
154
+ const date = toDate(value);
155
+ if (!date) return placeholder;
156
+ const elapsed = date.getTime() - (now instanceof Date ? now.getTime() : now);
157
+ const format = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
158
+ for (const [unit, ms] of RELATIVE_UNITS) {
159
+ if (Math.abs(elapsed) >= ms) {
160
+ return format.format(Math.trunc(elapsed / ms), unit);
161
+ }
162
+ }
163
+ return format.format(0, "second");
164
+ }
165
+ function humanizeToken(value) {
166
+ return value.trim().replace(/[_-]+/g, " ").replace(/\s+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
167
+ }
168
+ var NajmFormatContext = React.createContext(
169
+ null
170
+ );
171
+ function NajmFormatProvider({
172
+ children,
173
+ locale,
174
+ currency,
175
+ timeZone,
176
+ placeholder = DEFAULT_PLACEHOLDER
177
+ }) {
178
+ const preferences = useNajmPreferencesContext();
179
+ const resolvedTimeZone = timeZone ?? preferences?.timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
180
+ const value = React.useMemo(() => {
181
+ const config = {
182
+ locale,
183
+ timeZone: resolvedTimeZone,
184
+ currency,
185
+ placeholder
186
+ };
187
+ return {
188
+ locale,
189
+ timeZone: resolvedTimeZone,
190
+ currency,
191
+ placeholder,
192
+ config,
193
+ money: (minorUnits) => formatCurrency(minorUnits, config),
194
+ number: (value_, options) => formatNumber(value_, config, options),
195
+ percent: (value_, digits) => formatPercent(value_, config, digits),
196
+ date: (value_, options) => formatDate(value_, config, options),
197
+ dateTime: (value_) => formatDateTime(value_, config),
198
+ time: (value_) => formatTime(value_, config),
199
+ relativeTime: (value_) => formatRelativeTime(value_, config),
200
+ humanize: humanizeToken
201
+ };
202
+ }, [locale, resolvedTimeZone, currency, placeholder]);
203
+ return /* @__PURE__ */ jsx(NajmFormatContext.Provider, { value, children });
204
+ }
205
+ function useNajmFormatContext() {
206
+ return React.useContext(NajmFormatContext);
207
+ }
208
+ function useNajmFormat() {
209
+ const value = React.useContext(NajmFormatContext);
210
+ if (!value) {
211
+ throw new Error(
212
+ "useNajmFormat must be rendered under a NajmFormatProvider or NajmAppProvider."
213
+ );
214
+ }
215
+ return value;
216
+ }
217
+
218
+ export { DEFAULT_PLACEHOLDER, NBrandingProvider, NBrandingStateProvider, NajmFormatProvider, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, formatRelativeTime, formatTime, humanizeToken, normalizeBranding, useNBranding, useNBrandingEditor, useNajmFormat, useNajmFormatContext };
@@ -1,4 +1,4 @@
1
- import { NajmDesignProvider } from './chunk-YBM5CTE6.mjs';
1
+ import { NajmDesignProvider, cn } from './chunk-KVZACF4G.mjs';
2
2
  import * as React2 from 'react';
3
3
  import React2__default from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
@@ -23,6 +23,17 @@ function useResolvedPaginationLabels(own) {
23
23
  }
24
24
  var NajmPreferencesContext = React2.createContext(null);
25
25
  var DEFAULT_TIME_ZONE = "UTC";
26
+ function isValidTimeZone(value) {
27
+ try {
28
+ new Intl.DateTimeFormat(void 0, { timeZone: value });
29
+ return true;
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+ function defaultNormalizeTimeZone(value) {
35
+ return isValidTimeZone(value) ? value : DEFAULT_TIME_ZONE;
36
+ }
26
37
  function applyTheme(theme) {
27
38
  if (typeof document === "undefined") return;
28
39
  document.documentElement.classList.toggle("dark", theme === "dark");
@@ -37,11 +48,11 @@ function NajmPreferencesProvider({
37
48
  initialTimeZone = DEFAULT_TIME_ZONE,
38
49
  onThemeChange,
39
50
  onTimeZoneChange,
40
- normalizeTimeZone
51
+ normalizeTimeZone = defaultNormalizeTimeZone
41
52
  }) {
42
53
  const [theme, setThemeState] = React2.useState(initialTheme);
43
54
  const [timeZone, setTimeZoneState] = React2.useState(
44
- () => normalizeTimeZone ? normalizeTimeZone(initialTimeZone) : initialTimeZone
55
+ () => normalizeTimeZone(initialTimeZone)
45
56
  );
46
57
  const onThemeChangeRef = React2.useRef(onThemeChange);
47
58
  const onTimeZoneChangeRef = React2.useRef(onTimeZoneChange);
@@ -61,7 +72,7 @@ function NajmPreferencesProvider({
61
72
  await onThemeChangeRef.current?.(next);
62
73
  }, []);
63
74
  const setTimeZone = React2.useCallback(async (next) => {
64
- const normalized = normalizeRef.current ? normalizeRef.current(next) : next;
75
+ const normalized = normalizeRef.current(next);
65
76
  setTimeZoneState(normalized);
66
77
  applyTimeZone(normalized);
67
78
  await onTimeZoneChangeRef.current?.(normalized);
@@ -119,26 +130,95 @@ var EMPTY_DESIGN = Object.freeze({
119
130
  theme: {},
120
131
  components: {}
121
132
  });
133
+ var NajmDesignEditorContext = React2.createContext(null);
134
+ function useNajmDesignEditor() {
135
+ return React2.useContext(NajmDesignEditorContext);
136
+ }
137
+ function cloneDesign(design) {
138
+ return structuredClone(design);
139
+ }
140
+ function NajmDesignEditorProvider({
141
+ children,
142
+ design,
143
+ initialDesign
144
+ }) {
145
+ const [state, setState] = React2.useState(() => ({
146
+ committed: initialDesign ?? design ?? EMPTY_DESIGN,
147
+ draft: null
148
+ }));
149
+ const beginDraft = React2.useCallback(() => {
150
+ setState(
151
+ (current) => current.draft ? current : { ...current, draft: cloneDesign(current.committed) }
152
+ );
153
+ }, []);
154
+ const setDraft = React2.useCallback((next) => {
155
+ setState((current) => ({ ...current, draft: cloneDesign(next) }));
156
+ }, []);
157
+ const cancelDraft = React2.useCallback(() => {
158
+ setState(
159
+ (current) => current.draft === null ? current : { ...current, draft: null }
160
+ );
161
+ }, []);
162
+ const setCommitted = React2.useCallback((next) => {
163
+ setState({ committed: next, draft: null });
164
+ }, []);
165
+ const value = React2.useMemo(() => {
166
+ if (design) {
167
+ return {
168
+ design,
169
+ committed: design,
170
+ draft: null,
171
+ hasDraft: false,
172
+ beginDraft: noop,
173
+ setDraft: noop,
174
+ cancelDraft: noop,
175
+ setCommitted: noop
176
+ };
177
+ }
178
+ return {
179
+ design: state.draft ?? state.committed,
180
+ committed: state.committed,
181
+ draft: state.draft,
182
+ hasDraft: state.draft !== null,
183
+ beginDraft,
184
+ setDraft,
185
+ cancelDraft,
186
+ setCommitted
187
+ };
188
+ }, [design, state, beginDraft, setDraft, cancelDraft, setCommitted]);
189
+ return /* @__PURE__ */ jsx(NajmDesignEditorContext.Provider, { value, children });
190
+ }
191
+ function noop() {
192
+ }
122
193
  function NajmUICore({
123
194
  children,
124
- design = EMPTY_DESIGN,
125
195
  className,
126
196
  t,
127
197
  paginationKeyPrefix = DEFAULT_PAGINATION_KEY_PREFIX,
128
198
  tableDefaults
129
199
  }) {
130
200
  const { theme } = useNajmTheme();
201
+ const design = useNajmDesignEditor()?.design ?? EMPTY_DESIGN;
131
202
  const defaults = React2.useMemo(() => {
132
203
  const translated = t ? buildPaginationLabels(t, paginationKeyPrefix) : void 0;
133
204
  const overrides = tableDefaults?.paginationLabels;
134
205
  const paginationLabels = translated || overrides ? { ...translated, ...overrides } : void 0;
135
206
  return { ...tableDefaults, paginationLabels };
136
207
  }, [t, paginationKeyPrefix, tableDefaults]);
137
- return /* @__PURE__ */ jsx(NajmDesignProvider, { config: design, mode: theme, className, children: /* @__PURE__ */ jsx(NTableDefaultsProvider, { value: defaults, children }) });
208
+ return /* @__PURE__ */ jsx(
209
+ NajmDesignProvider,
210
+ {
211
+ config: design,
212
+ mode: theme,
213
+ className: cn("min-h-full", className),
214
+ children: /* @__PURE__ */ jsx(NTableDefaultsProvider, { value: defaults, children })
215
+ }
216
+ );
138
217
  }
139
218
  function NajmUIProvider({
140
219
  children,
141
220
  design,
221
+ initialDesign,
142
222
  className,
143
223
  t,
144
224
  paginationKeyPrefix,
@@ -150,17 +230,16 @@ function NajmUIProvider({
150
230
  normalizeTimeZone
151
231
  }) {
152
232
  const outerPreferences = useNajmPreferencesContext();
153
- const core = /* @__PURE__ */ jsx(
233
+ const core = /* @__PURE__ */ jsx(NajmDesignEditorProvider, { design, initialDesign, children: /* @__PURE__ */ jsx(
154
234
  NajmUICore,
155
235
  {
156
- design,
157
236
  className,
158
237
  t,
159
238
  paginationKeyPrefix,
160
239
  tableDefaults,
161
240
  children
162
241
  }
163
- );
242
+ ) });
164
243
  if (outerPreferences) return core;
165
244
  return /* @__PURE__ */ jsx(
166
245
  NajmPreferencesProvider,
@@ -175,4 +254,4 @@ function NajmUIProvider({
175
254
  );
176
255
  }
177
256
 
178
- export { DEFAULT_PAGINATION_KEY_PREFIX, DEFAULT_TIME_ZONE, NTableDefaultsProvider, NajmPreferencesProvider, NajmUIProvider, buildPaginationLabels, useNTableDefaults, useNajmPreferencesContext, useNajmTheme, useNajmTimeZone, useResolvedPaginationLabels };
257
+ export { DEFAULT_PAGINATION_KEY_PREFIX, DEFAULT_TIME_ZONE, EMPTY_DESIGN, NTableDefaultsProvider, NajmDesignEditorProvider, NajmPreferencesProvider, NajmUIProvider, buildPaginationLabels, useNTableDefaults, useNajmDesignEditor, useNajmPreferencesContext, useNajmTheme, useNajmTimeZone, useResolvedPaginationLabels };