najm-kit 2.8.2 → 2.9.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 +147 -121
- package/README.md +112 -0
- package/dist/{NajmUIProvider-BSbXaqak.d.ts → NajmUIProvider-CI_73GEp.d.ts} +5 -162
- package/dist/adapters/app.d.ts +2 -1
- package/dist/adapters/next.d.ts +2 -1
- package/dist/chunk-7H6NFBQT.mjs +75 -0
- 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 +5 -17
- package/dist/index.mjs +6 -4
- 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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// src/server/uiBootstrap.ts
|
|
2
|
+
var MISSING = Symbol("najm-kit/server: missing envelope");
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null;
|
|
5
|
+
}
|
|
6
|
+
function selectData(payload) {
|
|
7
|
+
return isRecord(payload) && "data" in payload ? payload.data : MISSING;
|
|
8
|
+
}
|
|
9
|
+
function describeThrown(value) {
|
|
10
|
+
return value instanceof Error ? `${value.name}: ${value.message}` : `non-error thrown: ${typeof value}`;
|
|
11
|
+
}
|
|
12
|
+
function createUiBootstrapLoader(config) {
|
|
13
|
+
const { fetcher, resources, onDiagnostic } = config;
|
|
14
|
+
const selectEnvelope = config.select ?? selectData;
|
|
15
|
+
const names = Object.keys(resources);
|
|
16
|
+
const report = (diagnostic) => {
|
|
17
|
+
if (!onDiagnostic) return;
|
|
18
|
+
try {
|
|
19
|
+
onDiagnostic(diagnostic);
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
async function loadOne(name) {
|
|
24
|
+
const resource = resources[name];
|
|
25
|
+
const { path } = resource;
|
|
26
|
+
const select = resource.select ?? selectEnvelope;
|
|
27
|
+
const fail = (reason, detail = {}) => {
|
|
28
|
+
report({ resource: name, reason, path, ...detail });
|
|
29
|
+
return resource.fallback();
|
|
30
|
+
};
|
|
31
|
+
let response;
|
|
32
|
+
try {
|
|
33
|
+
response = await fetcher(path);
|
|
34
|
+
} catch (cause) {
|
|
35
|
+
return fail("fetch-failed", { error: describeThrown(cause) });
|
|
36
|
+
}
|
|
37
|
+
if (!response.ok) return fail("response-not-ok", { status: response.status });
|
|
38
|
+
let payload;
|
|
39
|
+
try {
|
|
40
|
+
payload = await response.json();
|
|
41
|
+
} catch (cause) {
|
|
42
|
+
return fail("invalid-json", { error: describeThrown(cause) });
|
|
43
|
+
}
|
|
44
|
+
let data;
|
|
45
|
+
try {
|
|
46
|
+
data = select(payload);
|
|
47
|
+
} catch (cause) {
|
|
48
|
+
return fail("invalid-envelope", { error: describeThrown(cause) });
|
|
49
|
+
}
|
|
50
|
+
if (data === MISSING) return fail("invalid-envelope");
|
|
51
|
+
try {
|
|
52
|
+
const parsed = resource.parse(data);
|
|
53
|
+
if (parsed !== void 0) return parsed;
|
|
54
|
+
} catch (cause) {
|
|
55
|
+
return fail("invalid-payload", { error: describeThrown(cause) });
|
|
56
|
+
}
|
|
57
|
+
return fail("invalid-payload");
|
|
58
|
+
}
|
|
59
|
+
const loaders = Object.fromEntries(
|
|
60
|
+
names.map((name) => [name, () => loadOne(name)])
|
|
61
|
+
);
|
|
62
|
+
async function load() {
|
|
63
|
+
const pending = names.map((name) => loadOne(name));
|
|
64
|
+
const settled = await Promise.all(pending);
|
|
65
|
+
const snapshot = {};
|
|
66
|
+
names.forEach((name, index) => {
|
|
67
|
+
snapshot[name] = settled[index];
|
|
68
|
+
});
|
|
69
|
+
Object.freeze(snapshot);
|
|
70
|
+
return snapshot;
|
|
71
|
+
}
|
|
72
|
+
return { load, loadResource: (name) => loaders[name](), loaders };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { createUiBootstrapLoader };
|
|
@@ -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 };
|