najm-kit 2.8.2 → 2.10.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.
- package/CHANGELOG.md +71 -27
- package/README.md +477 -237
- package/dist/{NajmUIProvider-BSbXaqak.d.ts → NajmUIProvider-BnReyojl.d.ts} +99 -163
- package/dist/adapters/app.d.ts +5 -1
- package/dist/adapters/app.mjs +3 -3
- package/dist/adapters/next.d.ts +28 -2
- package/dist/adapters/next.mjs +2 -2
- package/dist/chunk-7H6NFBQT.mjs +75 -0
- package/dist/{chunk-IRFFSAO2.mjs → chunk-EUQOTPLV.mjs} +26 -2
- package/dist/{chunk-USZUOJMK.mjs → chunk-FDONJASN.mjs} +163 -3
- package/dist/{chunk-GHMR45H3.mjs → chunk-HML2JZXT.mjs} +1 -1
- package/dist/chunk-JUYT2ISO.mjs +404 -0
- package/dist/{chunk-6OOBAEH2.mjs → chunk-TFHWLE7N.mjs} +1 -403
- package/dist/design-config-D_x1GCu3.d.ts +17 -0
- package/dist/design-types-Rkpt8Pg1.d.ts +159 -0
- package/dist/index.d.ts +60 -77
- package/dist/index.mjs +202 -220
- package/dist/json.mjs +3 -2
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.mjs +2 -0
- package/dist/server/react.d.ts +16 -0
- package/dist/server/react.mjs +23 -0
- package/dist/server/reactClientGuard.d.ts +2 -0
- package/dist/server/reactClientGuard.mjs +4 -0
- package/dist/uiBootstrap-Ci6K5j5t.d.ts +93 -0
- package/package.json +16 -2
|
@@ -3,6 +3,76 @@ import * as React2 from 'react';
|
|
|
3
3
|
import React2__default from 'react';
|
|
4
4
|
import { jsx } from 'react/jsx-runtime';
|
|
5
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
|
+
}
|
|
6
76
|
var NTableDefaultsContext = React2__default.createContext({});
|
|
7
77
|
function NTableDefaultsProvider({
|
|
8
78
|
children,
|
|
@@ -190,12 +260,41 @@ function NajmDesignEditorProvider({
|
|
|
190
260
|
}
|
|
191
261
|
function noop() {
|
|
192
262
|
}
|
|
263
|
+
var NBadgeDefaultsContext = React2.createContext(null);
|
|
264
|
+
function NBadgeDefaultsProvider({
|
|
265
|
+
defaults,
|
|
266
|
+
t,
|
|
267
|
+
children
|
|
268
|
+
}) {
|
|
269
|
+
const value = React2.useMemo(
|
|
270
|
+
() => ({ defaults, t }),
|
|
271
|
+
[defaults, t]
|
|
272
|
+
);
|
|
273
|
+
return /* @__PURE__ */ jsx(NBadgeDefaultsContext.Provider, { value, children });
|
|
274
|
+
}
|
|
275
|
+
function useNBadgeDefaults() {
|
|
276
|
+
return React2.useContext(NBadgeDefaultsContext);
|
|
277
|
+
}
|
|
278
|
+
function resolveBadgeStatusLabel(status, defaults, t) {
|
|
279
|
+
if (!defaults) return void 0;
|
|
280
|
+
const normalized = normalizeStatusToken(status);
|
|
281
|
+
const literal = defaults.statusLabels?.[status] ?? defaults.statusLabels?.[normalized];
|
|
282
|
+
if (literal !== void 0) return literal;
|
|
283
|
+
const key = defaults.statusLabelKeys?.[status] ?? defaults.statusLabelKeys?.[normalized];
|
|
284
|
+
return key !== void 0 && t ? t(key) : void 0;
|
|
285
|
+
}
|
|
286
|
+
function mergeBadgeMaps(base, overrides) {
|
|
287
|
+
if (!base) return overrides;
|
|
288
|
+
if (!overrides) return base;
|
|
289
|
+
return { ...base, ...overrides };
|
|
290
|
+
}
|
|
193
291
|
function NajmUICore({
|
|
194
292
|
children,
|
|
195
293
|
className,
|
|
196
294
|
t,
|
|
197
295
|
paginationKeyPrefix = DEFAULT_PAGINATION_KEY_PREFIX,
|
|
198
|
-
tableDefaults
|
|
296
|
+
tableDefaults,
|
|
297
|
+
badgeDefaults
|
|
199
298
|
}) {
|
|
200
299
|
const { theme } = useNajmTheme();
|
|
201
300
|
const design = useNajmDesignEditor()?.design ?? EMPTY_DESIGN;
|
|
@@ -211,7 +310,7 @@ function NajmUICore({
|
|
|
211
310
|
config: design,
|
|
212
311
|
mode: theme,
|
|
213
312
|
className: cn("min-h-full", className),
|
|
214
|
-
children: /* @__PURE__ */ jsx(NTableDefaultsProvider, { value: defaults, children })
|
|
313
|
+
children: /* @__PURE__ */ jsx(NTableDefaultsProvider, { value: defaults, children: /* @__PURE__ */ jsx(NBadgeDefaultsProvider, { defaults: badgeDefaults, t, children }) })
|
|
215
314
|
}
|
|
216
315
|
);
|
|
217
316
|
}
|
|
@@ -223,6 +322,7 @@ function NajmUIProvider({
|
|
|
223
322
|
t,
|
|
224
323
|
paginationKeyPrefix,
|
|
225
324
|
tableDefaults,
|
|
325
|
+
badgeDefaults,
|
|
226
326
|
initialTheme,
|
|
227
327
|
initialTimeZone,
|
|
228
328
|
onThemeChange,
|
|
@@ -237,6 +337,7 @@ function NajmUIProvider({
|
|
|
237
337
|
t,
|
|
238
338
|
paginationKeyPrefix,
|
|
239
339
|
tableDefaults,
|
|
340
|
+
badgeDefaults,
|
|
240
341
|
children
|
|
241
342
|
}
|
|
242
343
|
) });
|
|
@@ -254,4 +355,63 @@ function NajmUIProvider({
|
|
|
254
355
|
);
|
|
255
356
|
}
|
|
256
357
|
|
|
257
|
-
|
|
358
|
+
// src/lib/imageSource.ts
|
|
359
|
+
var INLINE_SOURCE = /^(?:data|blob):/i;
|
|
360
|
+
function withSrcVersion(src, version) {
|
|
361
|
+
if (version === null || version === void 0 || version === "") return src;
|
|
362
|
+
if (INLINE_SOURCE.test(src)) return src;
|
|
363
|
+
const separator = src.includes("?") ? "&" : "?";
|
|
364
|
+
return `${src}${separator}v=${encodeURIComponent(String(version))}`;
|
|
365
|
+
}
|
|
366
|
+
function normalizeImageSources(candidates, version) {
|
|
367
|
+
const sources = [];
|
|
368
|
+
for (const candidate of candidates) {
|
|
369
|
+
const trimmed = candidate?.trim();
|
|
370
|
+
if (!trimmed) continue;
|
|
371
|
+
const stamped = withSrcVersion(trimmed, version);
|
|
372
|
+
if (!sources.includes(stamped)) sources.push(stamped);
|
|
373
|
+
}
|
|
374
|
+
return sources;
|
|
375
|
+
}
|
|
376
|
+
function selectImageSource(sources, failed) {
|
|
377
|
+
return sources.find((source) => !failed.includes(source));
|
|
378
|
+
}
|
|
379
|
+
var NO_FAILURES = [];
|
|
380
|
+
function useImageChain(sources) {
|
|
381
|
+
const key = JSON.stringify(sources);
|
|
382
|
+
const [state, setState] = React2.useState(() => ({
|
|
383
|
+
key,
|
|
384
|
+
failed: NO_FAILURES,
|
|
385
|
+
loaded: null
|
|
386
|
+
}));
|
|
387
|
+
const fresh = { key, failed: NO_FAILURES, loaded: null };
|
|
388
|
+
const current = state.key === key ? state : fresh;
|
|
389
|
+
if (state.key !== key) setState(fresh);
|
|
390
|
+
const active = selectImageSource(sources, current.failed);
|
|
391
|
+
const markLoaded = React2.useCallback(() => {
|
|
392
|
+
if (active === void 0) return;
|
|
393
|
+
setState(
|
|
394
|
+
(prev) => prev.key !== key || prev.loaded === active ? prev : { ...prev, loaded: active }
|
|
395
|
+
);
|
|
396
|
+
}, [key, active]);
|
|
397
|
+
const markFailed = React2.useCallback(() => {
|
|
398
|
+
if (active === void 0) return;
|
|
399
|
+
setState((prev) => {
|
|
400
|
+
if (prev.key !== key || prev.failed.includes(active)) return prev;
|
|
401
|
+
return {
|
|
402
|
+
...prev,
|
|
403
|
+
failed: [...prev.failed, active],
|
|
404
|
+
loaded: prev.loaded === active ? null : prev.loaded
|
|
405
|
+
};
|
|
406
|
+
});
|
|
407
|
+
}, [key, active]);
|
|
408
|
+
return {
|
|
409
|
+
src: active ?? sources[sources.length - 1],
|
|
410
|
+
exhausted: sources.length > 0 && active === void 0,
|
|
411
|
+
loaded: active !== void 0 && current.loaded === active,
|
|
412
|
+
markLoaded,
|
|
413
|
+
markFailed
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
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, useResolvedPaginationLabels };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useNajmPreferencesContext } from './chunk-
|
|
1
|
+
import { useNajmPreferencesContext } from './chunk-FDONJASN.mjs';
|
|
2
2
|
import { humanizeToken, DEFAULT_PLACEHOLDER, formatRelativeTime, formatTime, formatDateTime, formatDate, formatPercent, formatNumber, formatCurrency } from './chunk-JABLSOQN.mjs';
|
|
3
3
|
import * as React2 from 'react';
|
|
4
4
|
import { createContext, useContext, useMemo, useState, useCallback } from 'react';
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { useNajmComponentStyle, cn } from './chunk-KVZACF4G.mjs';
|
|
2
|
+
import { resolveVariantAlias, resolveRadiusValue } from './chunk-TFHWLE7N.mjs';
|
|
3
|
+
import * as React2 from 'react';
|
|
4
|
+
import React2__default, { createContext, useContext } from 'react';
|
|
5
|
+
import * as LucideIcons from 'lucide-react';
|
|
6
|
+
import { LoaderCircleIcon } from 'lucide-react';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
9
|
+
import { cva } from 'class-variance-authority';
|
|
10
|
+
import { OverlayScrollbars } from 'overlayscrollbars';
|
|
11
|
+
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
|
12
|
+
|
|
13
|
+
function toPascalCase(value) {
|
|
14
|
+
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("");
|
|
15
|
+
}
|
|
16
|
+
function isImageSource(value) {
|
|
17
|
+
return value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:image/") || /\.(avif|gif|jpe?g|png|svg|webp)(\?.*)?$/i.test(value);
|
|
18
|
+
}
|
|
19
|
+
function isComponentSource(value) {
|
|
20
|
+
return typeof value === "function" || Boolean(value && typeof value === "object" && "$$typeof" in value);
|
|
21
|
+
}
|
|
22
|
+
var NIcon = ({
|
|
23
|
+
icon = "circle",
|
|
24
|
+
size = 24,
|
|
25
|
+
alt = "",
|
|
26
|
+
className,
|
|
27
|
+
style,
|
|
28
|
+
onClick,
|
|
29
|
+
...rest
|
|
30
|
+
}) => {
|
|
31
|
+
const dimensionStyle = {
|
|
32
|
+
width: size,
|
|
33
|
+
height: size,
|
|
34
|
+
...style
|
|
35
|
+
};
|
|
36
|
+
if (React2__default.isValidElement(icon)) {
|
|
37
|
+
return React2__default.cloneElement(icon, {
|
|
38
|
+
className: cn(className, icon.props.className),
|
|
39
|
+
onClick,
|
|
40
|
+
...rest
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (icon && typeof icon === "object" && "src" in icon) {
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
"img",
|
|
46
|
+
{
|
|
47
|
+
alt: icon.alt ?? alt,
|
|
48
|
+
className: cn("inline-block shrink-0 object-contain", className),
|
|
49
|
+
src: icon.src,
|
|
50
|
+
style: dimensionStyle,
|
|
51
|
+
onClick,
|
|
52
|
+
...rest
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (isComponentSource(icon)) {
|
|
57
|
+
const IconComponent = icon;
|
|
58
|
+
return /* @__PURE__ */ jsx(IconComponent, { size, className, onClick, style, ...rest });
|
|
59
|
+
}
|
|
60
|
+
if (typeof icon === "string") {
|
|
61
|
+
if (isImageSource(icon)) {
|
|
62
|
+
return /* @__PURE__ */ jsx(
|
|
63
|
+
"img",
|
|
64
|
+
{
|
|
65
|
+
alt,
|
|
66
|
+
className: cn("inline-block shrink-0 object-contain", className),
|
|
67
|
+
src: icon,
|
|
68
|
+
style: dimensionStyle,
|
|
69
|
+
onClick,
|
|
70
|
+
...rest
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const pascalCaseIcon = toPascalCase(icon);
|
|
75
|
+
if (LucideIcons[pascalCaseIcon]) {
|
|
76
|
+
const LucideIcon = LucideIcons[pascalCaseIcon];
|
|
77
|
+
return /* @__PURE__ */ jsx(LucideIcon, { size, className, onClick, style, ...rest });
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
NIcon.displayName = "NIcon";
|
|
84
|
+
|
|
85
|
+
// src/theme/borders.ts
|
|
86
|
+
var SURFACE_BORDER_CLASSES = {
|
|
87
|
+
all: "najm-border border-border",
|
|
88
|
+
top: "najm-border-t border-border",
|
|
89
|
+
right: "najm-border-r border-border",
|
|
90
|
+
bottom: "najm-border-b border-border",
|
|
91
|
+
left: "najm-border-l border-border"
|
|
92
|
+
};
|
|
93
|
+
var SIDEBAR_BORDER_CLASSES = {
|
|
94
|
+
all: "najm-border border-sidebar-border",
|
|
95
|
+
top: "najm-border-t border-sidebar-border",
|
|
96
|
+
right: "najm-border-r border-sidebar-border",
|
|
97
|
+
bottom: "najm-border-b border-sidebar-border",
|
|
98
|
+
left: "najm-border-l border-sidebar-border"
|
|
99
|
+
};
|
|
100
|
+
var BORDER_RESET_CLASSES = {
|
|
101
|
+
all: "border-0",
|
|
102
|
+
top: "border-t-0",
|
|
103
|
+
right: "border-r-0",
|
|
104
|
+
bottom: "border-b-0",
|
|
105
|
+
left: "border-l-0"
|
|
106
|
+
};
|
|
107
|
+
function surfaceBorderClasses(bordered = true, side = "all") {
|
|
108
|
+
return bordered === false ? BORDER_RESET_CLASSES[side] : SURFACE_BORDER_CLASSES[side];
|
|
109
|
+
}
|
|
110
|
+
function sidebarBorderClasses(bordered = true, side = "all") {
|
|
111
|
+
return bordered === false ? BORDER_RESET_CLASSES[side] : SIDEBAR_BORDER_CLASSES[side];
|
|
112
|
+
}
|
|
113
|
+
function inputBorderClasses(bordered = true) {
|
|
114
|
+
return bordered === false ? "border-0" : "najm-border border-input";
|
|
115
|
+
}
|
|
116
|
+
var buttonVariants = cva(
|
|
117
|
+
[
|
|
118
|
+
"relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium outline-none transition-all",
|
|
119
|
+
"disabled:pointer-events-none disabled:opacity-50 data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
|
|
120
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
121
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
122
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
123
|
+
].join(" "),
|
|
124
|
+
{
|
|
125
|
+
variants: {
|
|
126
|
+
variant: {
|
|
127
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
128
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
129
|
+
outline: "border border-input bg-transparent text-foreground shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
130
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
131
|
+
tertiary: "bg-tertiary text-tertiary-foreground shadow-xs hover:bg-tertiary/80",
|
|
132
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
133
|
+
link: "h-auto p-0 text-primary underline-offset-4 hover:underline",
|
|
134
|
+
success: "bg-emerald-600 text-white shadow-xs hover:bg-emerald-700",
|
|
135
|
+
warning: "bg-amber-400 text-slate-950 shadow-xs hover:bg-amber-500",
|
|
136
|
+
info: "bg-sky-600 text-white shadow-xs hover:bg-sky-700",
|
|
137
|
+
soft: "bg-primary/10 text-primary shadow-none hover:bg-primary/15",
|
|
138
|
+
subtle: "bg-muted text-foreground shadow-none hover:bg-muted/80",
|
|
139
|
+
plain: "bg-transparent shadow-none hover:bg-transparent"
|
|
140
|
+
},
|
|
141
|
+
size: {
|
|
142
|
+
"2xs": "h-5 gap-1 px-1.5 text-[11px] [&_svg:not([class*='size-'])]:size-3",
|
|
143
|
+
xs: "h-6 gap-1 px-2 text-xs [&_svg:not([class*='size-'])]:size-3",
|
|
144
|
+
sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
145
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
146
|
+
md: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
147
|
+
lg: "h-10 px-6 has-[>svg]:px-4",
|
|
148
|
+
xl: "h-12 px-8 text-base [&_svg:not([class*='size-'])]:size-5",
|
|
149
|
+
"2xl": "h-14 px-10 text-base [&_svg:not([class*='size-'])]:size-5",
|
|
150
|
+
icon: "size-9",
|
|
151
|
+
"icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
|
|
152
|
+
"icon-sm": "size-8",
|
|
153
|
+
"icon-lg": "size-10 [&_svg:not([class*='size-'])]:size-5",
|
|
154
|
+
"icon-xl": "size-12 [&_svg:not([class*='size-'])]:size-5"
|
|
155
|
+
},
|
|
156
|
+
rounded: {
|
|
157
|
+
none: "rounded-none",
|
|
158
|
+
sm: "rounded-sm",
|
|
159
|
+
default: "rounded-md",
|
|
160
|
+
md: "rounded-md",
|
|
161
|
+
lg: "rounded-lg",
|
|
162
|
+
xl: "rounded-xl",
|
|
163
|
+
"2xl": "rounded-2xl",
|
|
164
|
+
full: "rounded-full"
|
|
165
|
+
},
|
|
166
|
+
fullWidth: {
|
|
167
|
+
true: "w-full",
|
|
168
|
+
false: ""
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
defaultVariants: {
|
|
172
|
+
variant: "default",
|
|
173
|
+
size: "default",
|
|
174
|
+
rounded: "default",
|
|
175
|
+
fullWidth: false
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
function isPromiseLike(value) {
|
|
180
|
+
return Boolean(value && typeof value.then === "function");
|
|
181
|
+
}
|
|
182
|
+
var defaultLoader = /* @__PURE__ */ jsx(LoaderCircleIcon, { "aria-hidden": "true", className: "animate-spin" });
|
|
183
|
+
function renderIcon(icon) {
|
|
184
|
+
if (!icon) return null;
|
|
185
|
+
return /* @__PURE__ */ jsx(NIcon, { "aria-hidden": "true", icon, className: "shrink-0" });
|
|
186
|
+
}
|
|
187
|
+
var Button = React2.forwardRef(
|
|
188
|
+
({
|
|
189
|
+
className,
|
|
190
|
+
variant,
|
|
191
|
+
size,
|
|
192
|
+
rounded,
|
|
193
|
+
fullWidth,
|
|
194
|
+
asChild = false,
|
|
195
|
+
loading = false,
|
|
196
|
+
autoLoading = true,
|
|
197
|
+
disabledWhileLoading = true,
|
|
198
|
+
loadingText,
|
|
199
|
+
loader = defaultLoader,
|
|
200
|
+
loaderPosition = "left",
|
|
201
|
+
leftIcon,
|
|
202
|
+
rightIcon,
|
|
203
|
+
bordered,
|
|
204
|
+
disabled,
|
|
205
|
+
children,
|
|
206
|
+
onClick,
|
|
207
|
+
style,
|
|
208
|
+
...props
|
|
209
|
+
}, ref) => {
|
|
210
|
+
const recipe = useNajmComponentStyle("button");
|
|
211
|
+
const aliased = resolveVariantAlias(
|
|
212
|
+
recipe?.variants,
|
|
213
|
+
variant ?? recipe?.defaultVariant ?? "default"
|
|
214
|
+
);
|
|
215
|
+
const effVariant = variant ?? aliased.variant ?? recipe?.defaultVariant;
|
|
216
|
+
const effSize = size ?? recipe?.defaultSize;
|
|
217
|
+
const recipeRadius = rounded === void 0 ? resolveRadiusValue(recipe?.radius) : void 0;
|
|
218
|
+
const recipeStyle = recipeRadius ? { borderRadius: recipeRadius } : void 0;
|
|
219
|
+
const [pending, setPending] = React2.useState(false);
|
|
220
|
+
const isLoading = loading || pending;
|
|
221
|
+
const isDisabled = disabled || disabledWhileLoading && isLoading;
|
|
222
|
+
const Comp = asChild ? Slot : "button";
|
|
223
|
+
const handleClick = React2.useCallback(
|
|
224
|
+
(event) => {
|
|
225
|
+
if (isDisabled) {
|
|
226
|
+
event.preventDefault();
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const result = onClick?.(event);
|
|
230
|
+
if (autoLoading && isPromiseLike(result)) {
|
|
231
|
+
setPending(true);
|
|
232
|
+
void result.then(
|
|
233
|
+
() => setPending(false),
|
|
234
|
+
() => setPending(false)
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
[autoLoading, isDisabled, onClick]
|
|
239
|
+
);
|
|
240
|
+
const child = asChild ? React2.Children.only(children) : null;
|
|
241
|
+
const childContent = asChild && React2.isValidElement(child) ? child.props.children : children;
|
|
242
|
+
const content = loadingText && isLoading ? loadingText : childContent;
|
|
243
|
+
const loaderNode = isLoading ? loader : null;
|
|
244
|
+
const leftIconNode = renderIcon(leftIcon);
|
|
245
|
+
const rightIconNode = renderIcon(rightIcon);
|
|
246
|
+
const showCenteredLoader = Boolean(loaderNode && loaderPosition === "center");
|
|
247
|
+
const renderedContent = showCenteredLoader ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
248
|
+
/* @__PURE__ */ jsxs("span", { className: "invisible inline-flex items-center gap-2", children: [
|
|
249
|
+
leftIconNode,
|
|
250
|
+
content,
|
|
251
|
+
rightIconNode
|
|
252
|
+
] }),
|
|
253
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-0 inline-flex items-center justify-center", children: loaderNode })
|
|
254
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
255
|
+
loaderNode && loaderPosition === "left" ? loaderNode : leftIconNode,
|
|
256
|
+
content,
|
|
257
|
+
loaderNode && loaderPosition === "right" ? loaderNode : rightIconNode
|
|
258
|
+
] });
|
|
259
|
+
const renderedChild = asChild && React2.isValidElement(child) ? React2.cloneElement(child, void 0, renderedContent) : renderedContent;
|
|
260
|
+
return /* @__PURE__ */ jsx(
|
|
261
|
+
Comp,
|
|
262
|
+
{
|
|
263
|
+
ref,
|
|
264
|
+
"data-slot": "button",
|
|
265
|
+
"data-loading": isLoading || void 0,
|
|
266
|
+
"data-disabled": isDisabled || void 0,
|
|
267
|
+
"data-bordered": effVariant === "outline" ? "true" : bordered === false ? "false" : bordered ? "true" : void 0,
|
|
268
|
+
"aria-busy": isLoading || void 0,
|
|
269
|
+
"aria-disabled": asChild && isDisabled ? true : void 0,
|
|
270
|
+
disabled: !asChild ? isDisabled : void 0,
|
|
271
|
+
style: recipeStyle ? { ...recipeStyle, ...style } : style,
|
|
272
|
+
className: cn(
|
|
273
|
+
buttonVariants({ variant: effVariant, size: effSize, rounded, fullWidth }),
|
|
274
|
+
aliased.style?.className,
|
|
275
|
+
// Outline buttons always carry an input-style border.
|
|
276
|
+
effVariant === "outline" && inputBorderClasses(true),
|
|
277
|
+
// Filled/ghost/plain/link/success/warning/info/soft/subtle buttons only get a
|
|
278
|
+
// border when the consumer explicitly opts in via `bordered`. Global theming
|
|
279
|
+
// should not outline every filled button.
|
|
280
|
+
effVariant !== "outline" && bordered === true && cn(
|
|
281
|
+
"border",
|
|
282
|
+
"border-muted-foreground"
|
|
283
|
+
),
|
|
284
|
+
className
|
|
285
|
+
),
|
|
286
|
+
onClick: handleClick,
|
|
287
|
+
...props,
|
|
288
|
+
children: renderedChild
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
Button.displayName = "Button";
|
|
294
|
+
var NButton = Button;
|
|
295
|
+
function assignRef(ref, node) {
|
|
296
|
+
if (!ref) return;
|
|
297
|
+
if (typeof ref === "function") ref(node);
|
|
298
|
+
else ref.current = node;
|
|
299
|
+
}
|
|
300
|
+
function applyViewportLayout(node, axis) {
|
|
301
|
+
node.style.width = "100%";
|
|
302
|
+
node.style.height = "100%";
|
|
303
|
+
node.style.minWidth = "0";
|
|
304
|
+
node.style.minHeight = "0";
|
|
305
|
+
node.style.overflowX = axis === "x" || axis === "both" ? "auto" : "hidden";
|
|
306
|
+
node.style.overflowY = axis === "y" || axis === "both" ? "auto" : "hidden";
|
|
307
|
+
}
|
|
308
|
+
function najmScrollOptions(axis, autoHide, options) {
|
|
309
|
+
return {
|
|
310
|
+
scrollbars: { theme: "os-theme-najm", autoHide, autoHideDelay: 500, clickScroll: true },
|
|
311
|
+
overflow: {
|
|
312
|
+
x: axis === "x" || axis === "both" ? "scroll" : "hidden",
|
|
313
|
+
y: axis === "y" || axis === "both" ? "scroll" : "hidden"
|
|
314
|
+
},
|
|
315
|
+
...options
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
function useNajmScrollViewport({
|
|
319
|
+
axis = "y",
|
|
320
|
+
autoHide = "never",
|
|
321
|
+
options
|
|
322
|
+
} = {}) {
|
|
323
|
+
const hostRef = React2.useRef(null);
|
|
324
|
+
const viewportRef = React2.useRef(null);
|
|
325
|
+
React2.useEffect(() => {
|
|
326
|
+
const target = hostRef.current;
|
|
327
|
+
const viewport = viewportRef.current;
|
|
328
|
+
if (!target || !viewport) return;
|
|
329
|
+
const instance = OverlayScrollbars(
|
|
330
|
+
{ target, elements: { viewport } },
|
|
331
|
+
najmScrollOptions(axis, autoHide, options)
|
|
332
|
+
);
|
|
333
|
+
const containWheel = (event) => event.stopPropagation();
|
|
334
|
+
viewport.addEventListener("wheel", containWheel, { passive: true });
|
|
335
|
+
return () => {
|
|
336
|
+
viewport.removeEventListener("wheel", containWheel);
|
|
337
|
+
instance.destroy();
|
|
338
|
+
};
|
|
339
|
+
}, [axis, autoHide, options]);
|
|
340
|
+
return { hostRef, viewportRef };
|
|
341
|
+
}
|
|
342
|
+
function NajmScroll({ className, axis = "y", autoHide = "never", viewportRef, events, options, element, children, style, ...props }) {
|
|
343
|
+
return /* @__PURE__ */ jsx(
|
|
344
|
+
OverlayScrollbarsComponent,
|
|
345
|
+
{
|
|
346
|
+
className: cn(className),
|
|
347
|
+
style: {
|
|
348
|
+
...style,
|
|
349
|
+
overflow: "hidden",
|
|
350
|
+
minHeight: 0,
|
|
351
|
+
minWidth: 0
|
|
352
|
+
},
|
|
353
|
+
element,
|
|
354
|
+
defer: true,
|
|
355
|
+
options: najmScrollOptions(axis, autoHide, options || void 0),
|
|
356
|
+
events: {
|
|
357
|
+
...events,
|
|
358
|
+
initialized: (instance, ...rest) => {
|
|
359
|
+
const viewport = instance.elements().viewport;
|
|
360
|
+
applyViewportLayout(viewport, axis);
|
|
361
|
+
assignRef(viewportRef, viewport);
|
|
362
|
+
events?.initialized?.(instance, ...rest);
|
|
363
|
+
},
|
|
364
|
+
updated: (instance, ...rest) => {
|
|
365
|
+
applyViewportLayout(instance.elements().viewport, axis);
|
|
366
|
+
events?.updated?.(instance, ...rest);
|
|
367
|
+
},
|
|
368
|
+
destroyed: (instance, ...rest) => {
|
|
369
|
+
assignRef(viewportRef, null);
|
|
370
|
+
events?.destroyed?.(instance, ...rest);
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
...props,
|
|
374
|
+
children
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
var TableStoreContext = createContext(null);
|
|
379
|
+
var useTableStore = { use: {} };
|
|
380
|
+
var handler = {
|
|
381
|
+
get: (_, prop) => () => {
|
|
382
|
+
const store = useContext(TableStoreContext);
|
|
383
|
+
if (!store) throw new Error("useTableStore must be used within NTable");
|
|
384
|
+
return store.use[prop]();
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
useTableStore.use = new Proxy({}, handler);
|
|
388
|
+
function formatJsonValue(value) {
|
|
389
|
+
if (typeof value === "string") return value;
|
|
390
|
+
try {
|
|
391
|
+
return JSON.stringify(value ?? null, null, 2) ?? String(value);
|
|
392
|
+
} catch {
|
|
393
|
+
return String(value);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
function NTableJson() {
|
|
397
|
+
const viewMode = useTableStore.use.viewMode();
|
|
398
|
+
const renderJson = useTableStore.use.renderJson();
|
|
399
|
+
const jsonValue = useTableStore.use.jsonValue();
|
|
400
|
+
if (viewMode !== "json") return null;
|
|
401
|
+
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) }) }) });
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export { Button, NButton, NIcon, NTableJson, NajmScroll, TableStoreContext, buttonVariants, inputBorderClasses, sidebarBorderClasses, surfaceBorderClasses, useNajmScrollViewport, useTableStore };
|