najm-kit 2.9.0 → 2.11.0

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.
@@ -0,0 +1,480 @@
1
+ import { NajmDesignProvider, cn } from './chunk-KVZACF4G.mjs';
2
+ import * as React2 from 'react';
3
+ import React2__default from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/components/Badge/status.ts
7
+ var NAJM_STATUS_COLORS = {
8
+ active: "success",
9
+ approved: "success",
10
+ completed: "success",
11
+ confirmed: "success",
12
+ delivered: "success",
13
+ paid: "success",
14
+ published: "success",
15
+ succeeded: "success",
16
+ validated: "success",
17
+ verified: "success",
18
+ in_preparation: "warning",
19
+ in_progress: "warning",
20
+ out_for_delivery: "warning",
21
+ pending: "warning",
22
+ pending_email_verification: "warning",
23
+ pending_review: "warning",
24
+ processing: "warning",
25
+ submitted: "warning",
26
+ paused: "info",
27
+ purchased: "info",
28
+ scheduled: "info",
29
+ archived: "neutral",
30
+ cancelled: "neutral",
31
+ canceled: "neutral",
32
+ closed: "neutral",
33
+ draft: "neutral",
34
+ inactive: "neutral",
35
+ stopped: "neutral",
36
+ unknown: "neutral",
37
+ blocked: "destructive",
38
+ expired: "destructive",
39
+ failed: "destructive",
40
+ refunded: "destructive",
41
+ rejected: "destructive",
42
+ suspended: "destructive"
43
+ };
44
+ var NAJM_COLOR_TEXT_CLASSES = {
45
+ primary: "text-primary",
46
+ secondary: "text-secondary-foreground",
47
+ accent: "text-accent-foreground",
48
+ neutral: "text-muted-foreground",
49
+ info: "text-info",
50
+ success: "text-success",
51
+ warning: "text-warning",
52
+ destructive: "text-destructive"
53
+ };
54
+ function normalizeStatusToken(status) {
55
+ return status.trim().toLowerCase().replace(/[\s-]+/g, "_");
56
+ }
57
+ function lookup(map, status, normalized) {
58
+ if (!map) return void 0;
59
+ return map[status] ?? map[normalized];
60
+ }
61
+ function findStatusColor(status, statusMap) {
62
+ if (!status) return void 0;
63
+ const normalized = normalizeStatusToken(status);
64
+ return lookup(statusMap, status, normalized) ?? lookup(NAJM_STATUS_COLORS, status, normalized);
65
+ }
66
+ function resolveStatusColor(status, statusMap, fallback = "neutral") {
67
+ return findStatusColor(status, statusMap) ?? fallback;
68
+ }
69
+ function colorTextClass(color) {
70
+ return NAJM_COLOR_TEXT_CLASSES[color] ?? "text-foreground";
71
+ }
72
+ function statusTextClass(status, statusMap, fallback) {
73
+ const color = findStatusColor(status, statusMap) ?? fallback;
74
+ return color ? colorTextClass(color) : "";
75
+ }
76
+ var NTableDefaultsContext = React2__default.createContext({});
77
+ function NTableDefaultsProvider({
78
+ children,
79
+ value
80
+ }) {
81
+ return /* @__PURE__ */ jsx(NTableDefaultsContext.Provider, { value, children });
82
+ }
83
+ function useNTableDefaults() {
84
+ return React2__default.useContext(NTableDefaultsContext);
85
+ }
86
+ function useResolvedPaginationLabels(own) {
87
+ const defaults = useNTableDefaults();
88
+ const inherited = defaults.paginationLabels;
89
+ return React2__default.useMemo(
90
+ () => ({ ...inherited, ...own }),
91
+ [inherited, own]
92
+ );
93
+ }
94
+ var NajmPreferencesContext = React2.createContext(null);
95
+ var DEFAULT_TIME_ZONE = "UTC";
96
+ function isValidTimeZone(value) {
97
+ try {
98
+ new Intl.DateTimeFormat(void 0, { timeZone: value });
99
+ return true;
100
+ } catch {
101
+ return false;
102
+ }
103
+ }
104
+ function defaultNormalizeTimeZone(value) {
105
+ return isValidTimeZone(value) ? value : DEFAULT_TIME_ZONE;
106
+ }
107
+ function applyTheme(theme) {
108
+ if (typeof document === "undefined") return;
109
+ document.documentElement.classList.toggle("dark", theme === "dark");
110
+ }
111
+ function applyTimeZone(timeZone) {
112
+ if (typeof document === "undefined") return;
113
+ document.documentElement.dataset.timeZone = timeZone;
114
+ }
115
+ function NajmPreferencesProvider({
116
+ children,
117
+ initialTheme = "light",
118
+ initialTimeZone = DEFAULT_TIME_ZONE,
119
+ onThemeChange,
120
+ onTimeZoneChange,
121
+ normalizeTimeZone = defaultNormalizeTimeZone
122
+ }) {
123
+ const [theme, setThemeState] = React2.useState(initialTheme);
124
+ const [timeZone, setTimeZoneState] = React2.useState(
125
+ () => normalizeTimeZone(initialTimeZone)
126
+ );
127
+ const onThemeChangeRef = React2.useRef(onThemeChange);
128
+ const onTimeZoneChangeRef = React2.useRef(onTimeZoneChange);
129
+ const normalizeRef = React2.useRef(normalizeTimeZone);
130
+ React2.useEffect(() => {
131
+ onThemeChangeRef.current = onThemeChange;
132
+ onTimeZoneChangeRef.current = onTimeZoneChange;
133
+ normalizeRef.current = normalizeTimeZone;
134
+ });
135
+ React2.useEffect(() => {
136
+ applyTheme(theme);
137
+ applyTimeZone(timeZone);
138
+ }, []);
139
+ const setTheme = React2.useCallback(async (next) => {
140
+ setThemeState(next);
141
+ applyTheme(next);
142
+ await onThemeChangeRef.current?.(next);
143
+ }, []);
144
+ const setTimeZone = React2.useCallback(async (next) => {
145
+ const normalized = normalizeRef.current(next);
146
+ setTimeZoneState(normalized);
147
+ applyTimeZone(normalized);
148
+ await onTimeZoneChangeRef.current?.(normalized);
149
+ }, []);
150
+ const value = React2.useMemo(
151
+ () => ({ theme, setTheme, timeZone, setTimeZone }),
152
+ [theme, setTheme, timeZone, setTimeZone]
153
+ );
154
+ return /* @__PURE__ */ jsx(NajmPreferencesContext.Provider, { value, children });
155
+ }
156
+ function useNajmPreferencesContext() {
157
+ return React2.useContext(NajmPreferencesContext);
158
+ }
159
+ function usePreferencesOrThrow(hook) {
160
+ const value = React2.useContext(NajmPreferencesContext);
161
+ if (!value) {
162
+ throw new Error(
163
+ `${hook} must be rendered under a NajmUIProvider or NajmPreferencesProvider.`
164
+ );
165
+ }
166
+ return value;
167
+ }
168
+ function useNajmTheme() {
169
+ const { theme, setTheme } = usePreferencesOrThrow("useNajmTheme");
170
+ return React2.useMemo(() => ({ theme, setTheme }), [theme, setTheme]);
171
+ }
172
+ function useNajmTimeZone() {
173
+ const { timeZone, setTimeZone } = usePreferencesOrThrow("useNajmTimeZone");
174
+ return React2.useMemo(
175
+ () => ({ timeZone, setTimeZone }),
176
+ [timeZone, setTimeZone]
177
+ );
178
+ }
179
+
180
+ // src/providers/paginationLabels.ts
181
+ var DEFAULT_PAGINATION_KEY_PREFIX = "common.pagination";
182
+ function buildPaginationLabels(t, prefix = DEFAULT_PAGINATION_KEY_PREFIX) {
183
+ const key = (field) => `${prefix}.${field}`;
184
+ return {
185
+ rowsPerPage: t(key("rowsPerPage")),
186
+ pagination: t(key("pagination")),
187
+ firstPage: t(key("firstPage")),
188
+ previousPage: t(key("previousPage")),
189
+ nextPage: t(key("nextPage")),
190
+ lastPage: t(key("lastPage")),
191
+ goToPage: (page) => t(key("goToPage"), { page }),
192
+ currentPage: (page) => t(key("currentPage"), { page }),
193
+ pageOf: (page, pageCount) => t(key("pageOf"), { page, pageCount }),
194
+ pageOfUnknown: (page) => t(key("pageOfUnknown"), { page }),
195
+ rowsSelected: (selected, total) => t(key("rowsSelected"), { selected, total })
196
+ };
197
+ }
198
+ var EMPTY_DESIGN = Object.freeze({
199
+ version: 1,
200
+ theme: {},
201
+ components: {}
202
+ });
203
+ var NajmDesignEditorContext = React2.createContext(null);
204
+ function useNajmDesignEditor() {
205
+ return React2.useContext(NajmDesignEditorContext);
206
+ }
207
+ function cloneDesign(design) {
208
+ return structuredClone(design);
209
+ }
210
+ function NajmDesignEditorProvider({
211
+ children,
212
+ design,
213
+ initialDesign
214
+ }) {
215
+ const [state, setState] = React2.useState(() => ({
216
+ committed: initialDesign ?? design ?? EMPTY_DESIGN,
217
+ draft: null
218
+ }));
219
+ const beginDraft = React2.useCallback(() => {
220
+ setState(
221
+ (current) => current.draft ? current : { ...current, draft: cloneDesign(current.committed) }
222
+ );
223
+ }, []);
224
+ const setDraft = React2.useCallback((next) => {
225
+ setState((current) => ({ ...current, draft: cloneDesign(next) }));
226
+ }, []);
227
+ const cancelDraft = React2.useCallback(() => {
228
+ setState(
229
+ (current) => current.draft === null ? current : { ...current, draft: null }
230
+ );
231
+ }, []);
232
+ const setCommitted = React2.useCallback((next) => {
233
+ setState(
234
+ (current) => current.committed === next && current.draft === null ? current : { committed: next, draft: null }
235
+ );
236
+ }, []);
237
+ const value = React2.useMemo(() => {
238
+ if (design) {
239
+ return {
240
+ design,
241
+ committed: design,
242
+ draft: null,
243
+ hasDraft: false,
244
+ beginDraft: noop,
245
+ setDraft: noop,
246
+ cancelDraft: noop,
247
+ setCommitted: noop
248
+ };
249
+ }
250
+ return {
251
+ design: state.draft ?? state.committed,
252
+ committed: state.committed,
253
+ draft: state.draft,
254
+ hasDraft: state.draft !== null,
255
+ beginDraft,
256
+ setDraft,
257
+ cancelDraft,
258
+ setCommitted
259
+ };
260
+ }, [design, state, beginDraft, setDraft, cancelDraft, setCommitted]);
261
+ return /* @__PURE__ */ jsx(NajmDesignEditorContext.Provider, { value, children });
262
+ }
263
+ function noop() {
264
+ }
265
+ var NBadgeDefaultsContext = React2.createContext(null);
266
+ function NBadgeDefaultsProvider({
267
+ defaults,
268
+ t,
269
+ children
270
+ }) {
271
+ const value = React2.useMemo(
272
+ () => ({ defaults, t }),
273
+ [defaults, t]
274
+ );
275
+ return /* @__PURE__ */ jsx(NBadgeDefaultsContext.Provider, { value, children });
276
+ }
277
+ function useNBadgeDefaults() {
278
+ return React2.useContext(NBadgeDefaultsContext);
279
+ }
280
+ function resolveBadgeStatusLabel(status, defaults, t) {
281
+ if (!defaults) return void 0;
282
+ const normalized = normalizeStatusToken(status);
283
+ const literal = defaults.statusLabels?.[status] ?? defaults.statusLabels?.[normalized];
284
+ if (literal !== void 0) return literal;
285
+ const key = defaults.statusLabelKeys?.[status] ?? defaults.statusLabelKeys?.[normalized];
286
+ return key !== void 0 && t ? t(key) : void 0;
287
+ }
288
+ function mergeBadgeMaps(base, overrides) {
289
+ if (!base) return overrides;
290
+ if (!overrides) return base;
291
+ return { ...base, ...overrides };
292
+ }
293
+ var ENGLISH_FEEDBACK_LABELS = {
294
+ loadingLabel: "Loading...",
295
+ emptyTitle: "No data",
296
+ errorTitle: "Something went wrong",
297
+ retryLabel: "Try again",
298
+ forbiddenTitle: "Access denied",
299
+ forbiddenDescription: "You do not have permission to view this page.",
300
+ notFoundTitle: "Page not found",
301
+ notFoundDescription: "The requested page could not be found."
302
+ };
303
+ var NFeedbackDefaultsContext = React2.createContext(null);
304
+ function NFeedbackDefaultsProvider({
305
+ value,
306
+ children
307
+ }) {
308
+ return /* @__PURE__ */ jsx(NFeedbackDefaultsContext.Provider, { value, children });
309
+ }
310
+ function useNFeedbackDefaults() {
311
+ return React2.useContext(NFeedbackDefaultsContext);
312
+ }
313
+ var DEFAULT_FEEDBACK_KEY_PREFIX = "common.feedback";
314
+ function useResolvedFeedbackLabels() {
315
+ const ctx = useNFeedbackDefaults();
316
+ return React2.useMemo(() => resolveFeedbackLabels(ctx), [ctx]);
317
+ }
318
+ function resolveFeedbackLabels(ctx) {
319
+ const defaults = ctx?.defaults;
320
+ const t = ctx?.t;
321
+ const labels = defaults?.labels;
322
+ const labelKeys = defaults?.labelKeys;
323
+ defaults?.prefix ?? DEFAULT_FEEDBACK_KEY_PREFIX;
324
+ const pick = (field, hasFallback) => {
325
+ const literal = labels?.[field];
326
+ if (literal !== void 0) return literal;
327
+ const key = labelKeys?.[field];
328
+ if (key && t) return t(key);
329
+ if (hasFallback) return ENGLISH_FEEDBACK_LABELS[field];
330
+ return void 0;
331
+ };
332
+ return {
333
+ loadingLabel: pick("loadingLabel", true) ?? ENGLISH_FEEDBACK_LABELS.loadingLabel,
334
+ emptyTitle: pick("emptyTitle", true) ?? ENGLISH_FEEDBACK_LABELS.emptyTitle,
335
+ errorTitle: pick("errorTitle", true) ?? ENGLISH_FEEDBACK_LABELS.errorTitle,
336
+ errorMessage: pick("errorMessage", false),
337
+ retryLabel: pick("retryLabel", true) ?? ENGLISH_FEEDBACK_LABELS.retryLabel,
338
+ forbiddenTitle: pick("forbiddenTitle", true) ?? ENGLISH_FEEDBACK_LABELS.forbiddenTitle,
339
+ forbiddenDescription: pick("forbiddenDescription", true) ?? ENGLISH_FEEDBACK_LABELS.forbiddenDescription,
340
+ notFoundTitle: pick("notFoundTitle", true) ?? ENGLISH_FEEDBACK_LABELS.notFoundTitle,
341
+ notFoundDescription: pick("notFoundDescription", true) ?? ENGLISH_FEEDBACK_LABELS.notFoundDescription
342
+ };
343
+ }
344
+ function resolveFeedbackDefaultsValue(defaults, t) {
345
+ return { defaults: defaults ?? {}, t };
346
+ }
347
+ function NajmUICore({
348
+ children,
349
+ className,
350
+ t,
351
+ paginationKeyPrefix = DEFAULT_PAGINATION_KEY_PREFIX,
352
+ tableDefaults,
353
+ badgeDefaults,
354
+ feedbackDefaults
355
+ }) {
356
+ const { theme } = useNajmTheme();
357
+ const design = useNajmDesignEditor()?.design ?? EMPTY_DESIGN;
358
+ const defaults = React2.useMemo(() => {
359
+ const translated = t ? buildPaginationLabels(t, paginationKeyPrefix) : void 0;
360
+ const overrides = tableDefaults?.paginationLabels;
361
+ const paginationLabels = translated || overrides ? { ...translated, ...overrides } : void 0;
362
+ return { ...tableDefaults, paginationLabels };
363
+ }, [t, paginationKeyPrefix, tableDefaults]);
364
+ const feedbackValue = React2.useMemo(
365
+ () => resolveFeedbackDefaultsValue(feedbackDefaults, t),
366
+ [feedbackDefaults, t]
367
+ );
368
+ return /* @__PURE__ */ jsx(
369
+ NajmDesignProvider,
370
+ {
371
+ config: design,
372
+ mode: theme,
373
+ className: cn("min-h-full", className),
374
+ children: /* @__PURE__ */ jsx(NTableDefaultsProvider, { value: defaults, children: /* @__PURE__ */ jsx(NBadgeDefaultsProvider, { defaults: badgeDefaults, t, children: /* @__PURE__ */ jsx(NFeedbackDefaultsProvider, { value: feedbackValue, children }) }) })
375
+ }
376
+ );
377
+ }
378
+ function NajmUIProvider({
379
+ children,
380
+ design,
381
+ initialDesign,
382
+ className,
383
+ t,
384
+ paginationKeyPrefix,
385
+ tableDefaults,
386
+ badgeDefaults,
387
+ feedbackDefaults,
388
+ initialTheme,
389
+ initialTimeZone,
390
+ onThemeChange,
391
+ onTimeZoneChange,
392
+ normalizeTimeZone
393
+ }) {
394
+ const outerPreferences = useNajmPreferencesContext();
395
+ const core = /* @__PURE__ */ jsx(NajmDesignEditorProvider, { design, initialDesign, children: /* @__PURE__ */ jsx(
396
+ NajmUICore,
397
+ {
398
+ className,
399
+ t,
400
+ paginationKeyPrefix,
401
+ tableDefaults,
402
+ badgeDefaults,
403
+ feedbackDefaults,
404
+ children
405
+ }
406
+ ) });
407
+ if (outerPreferences) return core;
408
+ return /* @__PURE__ */ jsx(
409
+ NajmPreferencesProvider,
410
+ {
411
+ initialTheme,
412
+ initialTimeZone,
413
+ onThemeChange,
414
+ onTimeZoneChange,
415
+ normalizeTimeZone,
416
+ children: core
417
+ }
418
+ );
419
+ }
420
+
421
+ // src/lib/imageSource.ts
422
+ var INLINE_SOURCE = /^(?:data|blob):/i;
423
+ function withSrcVersion(src, version) {
424
+ if (version === null || version === void 0 || version === "") return src;
425
+ if (INLINE_SOURCE.test(src)) return src;
426
+ const separator = src.includes("?") ? "&" : "?";
427
+ return `${src}${separator}v=${encodeURIComponent(String(version))}`;
428
+ }
429
+ function normalizeImageSources(candidates, version) {
430
+ const sources = [];
431
+ for (const candidate of candidates) {
432
+ const trimmed = candidate?.trim();
433
+ if (!trimmed) continue;
434
+ const stamped = withSrcVersion(trimmed, version);
435
+ if (!sources.includes(stamped)) sources.push(stamped);
436
+ }
437
+ return sources;
438
+ }
439
+ function selectImageSource(sources, failed) {
440
+ return sources.find((source) => !failed.includes(source));
441
+ }
442
+ var NO_FAILURES = [];
443
+ function useImageChain(sources) {
444
+ const key = JSON.stringify(sources);
445
+ const [state, setState] = React2.useState(() => ({
446
+ key,
447
+ failed: NO_FAILURES,
448
+ loaded: null
449
+ }));
450
+ const fresh = { key, failed: NO_FAILURES, loaded: null };
451
+ const current = state.key === key ? state : fresh;
452
+ if (state.key !== key) setState(fresh);
453
+ const active = selectImageSource(sources, current.failed);
454
+ const markLoaded = React2.useCallback(() => {
455
+ if (active === void 0) return;
456
+ setState(
457
+ (prev) => prev.key !== key || prev.loaded === active ? prev : { ...prev, loaded: active }
458
+ );
459
+ }, [key, active]);
460
+ const markFailed = React2.useCallback(() => {
461
+ if (active === void 0) return;
462
+ setState((prev) => {
463
+ if (prev.key !== key || prev.failed.includes(active)) return prev;
464
+ return {
465
+ ...prev,
466
+ failed: [...prev.failed, active],
467
+ loaded: prev.loaded === active ? null : prev.loaded
468
+ };
469
+ });
470
+ }, [key, active]);
471
+ return {
472
+ src: active ?? sources[sources.length - 1],
473
+ exhausted: sources.length > 0 && active === void 0,
474
+ loaded: active !== void 0 && current.loaded === active,
475
+ markLoaded,
476
+ markFailed
477
+ };
478
+ }
479
+
480
+ export { DEFAULT_PAGINATION_KEY_PREFIX, DEFAULT_TIME_ZONE, EMPTY_DESIGN, NAJM_COLOR_TEXT_CLASSES, NAJM_STATUS_COLORS, NTableDefaultsProvider, NajmDesignEditorProvider, NajmPreferencesProvider, NajmUIProvider, buildPaginationLabels, colorTextClass, findStatusColor, mergeBadgeMaps, normalizeImageSources, normalizeStatusToken, resolveBadgeStatusLabel, resolveStatusColor, statusTextClass, useImageChain, useNBadgeDefaults, useNTableDefaults, useNajmDesignEditor, useNajmPreferencesContext, useNajmTheme, useNajmTimeZone, useResolvedFeedbackLabels, useResolvedPaginationLabels };
@@ -0,0 +1,117 @@
1
+ import { cn } from './chunk-KVZACF4G.mjs';
2
+ import * as React from 'react';
3
+ import { createContext, useContext } from 'react';
4
+ import { OverlayScrollbars } from 'overlayscrollbars';
5
+ import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ function assignRef(ref, node) {
9
+ if (!ref) return;
10
+ if (typeof ref === "function") ref(node);
11
+ else ref.current = node;
12
+ }
13
+ function applyViewportLayout(node, axis) {
14
+ node.style.width = "100%";
15
+ node.style.height = "100%";
16
+ node.style.minWidth = "0";
17
+ node.style.minHeight = "0";
18
+ node.style.overflowX = axis === "x" || axis === "both" ? "auto" : "hidden";
19
+ node.style.overflowY = axis === "y" || axis === "both" ? "auto" : "hidden";
20
+ }
21
+ function najmScrollOptions(axis, autoHide, options) {
22
+ return {
23
+ scrollbars: { theme: "os-theme-najm", autoHide, autoHideDelay: 500, clickScroll: true },
24
+ overflow: {
25
+ x: axis === "x" || axis === "both" ? "scroll" : "hidden",
26
+ y: axis === "y" || axis === "both" ? "scroll" : "hidden"
27
+ },
28
+ ...options
29
+ };
30
+ }
31
+ function useNajmScrollViewport({
32
+ axis = "y",
33
+ autoHide = "never",
34
+ options
35
+ } = {}) {
36
+ const hostRef = React.useRef(null);
37
+ const viewportRef = React.useRef(null);
38
+ React.useEffect(() => {
39
+ const target = hostRef.current;
40
+ const viewport = viewportRef.current;
41
+ if (!target || !viewport) return;
42
+ const instance = OverlayScrollbars(
43
+ { target, elements: { viewport } },
44
+ najmScrollOptions(axis, autoHide, options)
45
+ );
46
+ const containWheel = (event) => event.stopPropagation();
47
+ viewport.addEventListener("wheel", containWheel, { passive: true });
48
+ return () => {
49
+ viewport.removeEventListener("wheel", containWheel);
50
+ instance.destroy();
51
+ };
52
+ }, [axis, autoHide, options]);
53
+ return { hostRef, viewportRef };
54
+ }
55
+ function NajmScroll({ className, axis = "y", autoHide = "never", viewportRef, events, options, element, children, style, ...props }) {
56
+ return /* @__PURE__ */ jsx(
57
+ OverlayScrollbarsComponent,
58
+ {
59
+ className: cn(className),
60
+ style: {
61
+ ...style,
62
+ overflow: "hidden",
63
+ minHeight: 0,
64
+ minWidth: 0
65
+ },
66
+ element,
67
+ defer: true,
68
+ options: najmScrollOptions(axis, autoHide, options || void 0),
69
+ events: {
70
+ ...events,
71
+ initialized: (instance, ...rest) => {
72
+ const viewport = instance.elements().viewport;
73
+ applyViewportLayout(viewport, axis);
74
+ assignRef(viewportRef, viewport);
75
+ events?.initialized?.(instance, ...rest);
76
+ },
77
+ updated: (instance, ...rest) => {
78
+ applyViewportLayout(instance.elements().viewport, axis);
79
+ events?.updated?.(instance, ...rest);
80
+ },
81
+ destroyed: (instance, ...rest) => {
82
+ assignRef(viewportRef, null);
83
+ events?.destroyed?.(instance, ...rest);
84
+ }
85
+ },
86
+ ...props,
87
+ children
88
+ }
89
+ );
90
+ }
91
+ var TableStoreContext = createContext(null);
92
+ var useTableStore = { use: {} };
93
+ var handler = {
94
+ get: (_, prop) => () => {
95
+ const store = useContext(TableStoreContext);
96
+ if (!store) throw new Error("useTableStore must be used within NTable");
97
+ return store.use[prop]();
98
+ }
99
+ };
100
+ useTableStore.use = new Proxy({}, handler);
101
+ function formatJsonValue(value) {
102
+ if (typeof value === "string") return value;
103
+ try {
104
+ return JSON.stringify(value ?? null, null, 2) ?? String(value);
105
+ } catch {
106
+ return String(value);
107
+ }
108
+ }
109
+ function NTableJson() {
110
+ const viewMode = useTableStore.use.viewMode();
111
+ const renderJson = useTableStore.use.renderJson();
112
+ const jsonValue = useTableStore.use.jsonValue();
113
+ if (viewMode !== "json") return null;
114
+ 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) }) }) });
115
+ }
116
+
117
+ export { NTableJson, NajmScroll, TableStoreContext, useNajmScrollViewport, useTableStore };