najm-kit 2.6.3 → 2.7.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/dist/json.mjs CHANGED
@@ -1,25 +1,16 @@
1
- import * as React5 from 'react';
2
- import React5__default, { createContext, useContext, useMemo, useRef, useCallback } from 'react';
1
+ import { cn, Button } from './chunk-4DLRXB2W.mjs';
2
+ export { NTableJson } from './chunk-4DLRXB2W.mjs';
3
+ import './chunk-YBM5CTE6.mjs';
4
+ import { useMemo, useRef, useCallback } from 'react';
3
5
  import CodeMirror from '@uiw/react-codemirror';
4
6
  import { json } from '@codemirror/lang-json';
5
7
  import { keymap, EditorView, Decoration, ViewPlugin } from '@codemirror/view';
6
8
  import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
7
9
  import { tags } from '@lezer/highlight';
8
10
  import { EditorSelection, EditorState, RangeSetBuilder } from '@codemirror/state';
9
- import { clsx } from 'clsx';
10
- import { twMerge } from 'tailwind-merge';
11
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
12
- import { Slot } from '@radix-ui/react-slot';
13
- import * as LucideIcons from 'lucide-react';
14
- import { LoaderCircleIcon, Loader2, AlertCircle, ClipboardPaste, Copy, RotateCcw } from 'lucide-react';
15
- import { cva } from 'class-variance-authority';
16
- import 'overlayscrollbars';
17
- import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
11
+ import { jsx, jsxs } from 'react/jsx-runtime';
12
+ import { Loader2, AlertCircle, ClipboardPaste, Copy, RotateCcw } from 'lucide-react';
18
13
 
19
- // src/json/JsonViewer.tsx
20
- function cn(...inputs) {
21
- return twMerge(clsx(inputs));
22
- }
23
14
  var defaultJsonViewColors = {
24
15
  toolName: "#10b981",
25
16
  langCode: "#f59e0b",
@@ -174,368 +165,6 @@ function JsonViewer({ value, colors = defaultJsonViewColors, className, maxHeigh
174
165
  }
175
166
  );
176
167
  }
177
-
178
- // src/theme/borders.ts
179
- function inputBorderClasses(bordered = true) {
180
- return bordered === false ? "border-0" : "najm-border border-input";
181
- }
182
- function toPascalCase(value) {
183
- 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("");
184
- }
185
- function isImageSource(value) {
186
- 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);
187
- }
188
- function isComponentSource(value) {
189
- return typeof value === "function" || Boolean(value && typeof value === "object" && "$$typeof" in value);
190
- }
191
- var NIcon = ({
192
- icon = "circle",
193
- size = 24,
194
- alt = "",
195
- className,
196
- style,
197
- onClick,
198
- ...rest
199
- }) => {
200
- const dimensionStyle = {
201
- width: size,
202
- height: size,
203
- ...style
204
- };
205
- if (React5__default.isValidElement(icon)) {
206
- return React5__default.cloneElement(icon, {
207
- className: cn(className, icon.props.className),
208
- onClick,
209
- ...rest
210
- });
211
- }
212
- if (icon && typeof icon === "object" && "src" in icon) {
213
- return /* @__PURE__ */ jsx(
214
- "img",
215
- {
216
- alt: icon.alt ?? alt,
217
- className: cn("inline-block shrink-0 object-contain", className),
218
- src: icon.src,
219
- style: dimensionStyle,
220
- onClick,
221
- ...rest
222
- }
223
- );
224
- }
225
- if (isComponentSource(icon)) {
226
- const IconComponent = icon;
227
- return /* @__PURE__ */ jsx(IconComponent, { size, className, onClick, style, ...rest });
228
- }
229
- if (typeof icon === "string") {
230
- if (isImageSource(icon)) {
231
- return /* @__PURE__ */ jsx(
232
- "img",
233
- {
234
- alt,
235
- className: cn("inline-block shrink-0 object-contain", className),
236
- src: icon,
237
- style: dimensionStyle,
238
- onClick,
239
- ...rest
240
- }
241
- );
242
- }
243
- const pascalCaseIcon = toPascalCase(icon);
244
- if (LucideIcons[pascalCaseIcon]) {
245
- const LucideIcon = LucideIcons[pascalCaseIcon];
246
- return /* @__PURE__ */ jsx(LucideIcon, { size, className, onClick, style, ...rest });
247
- }
248
- return null;
249
- }
250
- return null;
251
- };
252
- NIcon.displayName = "NIcon";
253
- React5.createContext(0);
254
- React5.createContext(void 0);
255
- React5.createContext(null);
256
- var DEFAULT_APPEARANCE = {};
257
- React5.createContext(DEFAULT_APPEARANCE);
258
- var NajmDesignContext = React5.createContext({
259
- components: {}
260
- });
261
- function useNajmDesign() {
262
- return React5.useContext(NajmDesignContext);
263
- }
264
- function useNajmComponentStyle(name) {
265
- const { components } = useNajmDesign();
266
- return components[name];
267
- }
268
-
269
- // src/theme/design-types.ts
270
- var NAJM_COMPONENT_NAMES = [
271
- "button",
272
- "badge",
273
- "card",
274
- "table",
275
- "tabs",
276
- "dialog",
277
- "alert",
278
- "sidebar",
279
- "pageHeader",
280
- "input",
281
- "select",
282
- "dropdown",
283
- "sheet",
284
- "popover",
285
- "tooltip",
286
- "progress",
287
- "avatar"
288
- ];
289
- var RADIUS_VALUE_MAP = {
290
- none: "0",
291
- xs: "var(--radius-xs)",
292
- sm: "var(--radius-sm)",
293
- md: "var(--radius-md)",
294
- lg: "var(--radius-lg)",
295
- xl: "var(--radius-xl)",
296
- full: "9999px"
297
- };
298
- function resolveRadiusValue(radius) {
299
- if (!radius || radius === "inherit") return void 0;
300
- return RADIUS_VALUE_MAP[radius] ?? radius;
301
- }
302
-
303
- // src/theme/config.ts
304
- var MODES = ["light", "dark"];
305
- var TOKEN_KEYS = [
306
- "background",
307
- "foreground",
308
- "card",
309
- "card-foreground",
310
- "popover",
311
- "popover-foreground",
312
- "primary",
313
- "primary-foreground",
314
- "secondary",
315
- "secondary-foreground",
316
- "tertiary",
317
- "tertiary-foreground",
318
- "muted",
319
- "muted-foreground",
320
- "accent",
321
- "accent-foreground",
322
- "destructive",
323
- "destructive-foreground",
324
- "border",
325
- "input",
326
- "ring",
327
- "sidebar",
328
- "sidebar-foreground",
329
- "sidebar-primary",
330
- "sidebar-primary-foreground",
331
- "sidebar-accent",
332
- "sidebar-accent-foreground",
333
- "sidebar-border",
334
- "sidebar-ring",
335
- "chart-1",
336
- "chart-2",
337
- "chart-3",
338
- "chart-4",
339
- "chart-5",
340
- "radius"
341
- ];
342
- new Set(TOKEN_KEYS);
343
- new Set(MODES);
344
-
345
- // src/theme/design-config.ts
346
- new Set(NAJM_COMPONENT_NAMES);
347
- function resolveVariantAlias(variants, variant) {
348
- if (!variants) return { variant };
349
- const seen = /* @__PURE__ */ new Set();
350
- let current = variant;
351
- let style = variants[current];
352
- while (style?.use && !seen.has(current)) {
353
- seen.add(current);
354
- const next = style.use;
355
- if (seen.has(next)) break;
356
- current = next;
357
- style = variants[current];
358
- }
359
- return { variant: current, style };
360
- }
361
- var buttonVariants = cva(
362
- [
363
- "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium outline-none transition-all",
364
- "disabled:pointer-events-none disabled:opacity-50 data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
365
- "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
366
- "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
367
- "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
368
- ].join(" "),
369
- {
370
- variants: {
371
- variant: {
372
- default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
373
- 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",
374
- outline: "border border-input bg-transparent text-foreground shadow-xs hover:bg-accent hover:text-accent-foreground",
375
- secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
376
- tertiary: "bg-tertiary text-tertiary-foreground shadow-xs hover:bg-tertiary/80",
377
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
378
- link: "h-auto p-0 text-primary underline-offset-4 hover:underline",
379
- success: "bg-emerald-600 text-white shadow-xs hover:bg-emerald-700",
380
- warning: "bg-amber-400 text-slate-950 shadow-xs hover:bg-amber-500",
381
- info: "bg-sky-600 text-white shadow-xs hover:bg-sky-700",
382
- soft: "bg-primary/10 text-primary shadow-none hover:bg-primary/15",
383
- subtle: "bg-muted text-foreground shadow-none hover:bg-muted/80",
384
- plain: "bg-transparent shadow-none hover:bg-transparent"
385
- },
386
- size: {
387
- "2xs": "h-5 gap-1 px-1.5 text-[11px] [&_svg:not([class*='size-'])]:size-3",
388
- xs: "h-6 gap-1 px-2 text-xs [&_svg:not([class*='size-'])]:size-3",
389
- sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
390
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
391
- md: "h-9 px-4 py-2 has-[>svg]:px-3",
392
- lg: "h-10 px-6 has-[>svg]:px-4",
393
- xl: "h-12 px-8 text-base [&_svg:not([class*='size-'])]:size-5",
394
- "2xl": "h-14 px-10 text-base [&_svg:not([class*='size-'])]:size-5",
395
- icon: "size-9",
396
- "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
397
- "icon-sm": "size-8",
398
- "icon-lg": "size-10 [&_svg:not([class*='size-'])]:size-5",
399
- "icon-xl": "size-12 [&_svg:not([class*='size-'])]:size-5"
400
- },
401
- rounded: {
402
- none: "rounded-none",
403
- sm: "rounded-sm",
404
- default: "rounded-md",
405
- md: "rounded-md",
406
- lg: "rounded-lg",
407
- xl: "rounded-xl",
408
- "2xl": "rounded-2xl",
409
- full: "rounded-full"
410
- },
411
- fullWidth: {
412
- true: "w-full",
413
- false: ""
414
- }
415
- },
416
- defaultVariants: {
417
- variant: "default",
418
- size: "default",
419
- rounded: "default",
420
- fullWidth: false
421
- }
422
- }
423
- );
424
- function isPromiseLike(value) {
425
- return Boolean(value && typeof value.then === "function");
426
- }
427
- var defaultLoader = /* @__PURE__ */ jsx(LoaderCircleIcon, { "aria-hidden": "true", className: "animate-spin" });
428
- function renderIcon(icon) {
429
- if (!icon) return null;
430
- return /* @__PURE__ */ jsx(NIcon, { "aria-hidden": "true", icon, className: "shrink-0" });
431
- }
432
- var Button = React5.forwardRef(
433
- ({
434
- className,
435
- variant,
436
- size,
437
- rounded,
438
- fullWidth,
439
- asChild = false,
440
- loading = false,
441
- autoLoading = true,
442
- disabledWhileLoading = true,
443
- loadingText,
444
- loader = defaultLoader,
445
- loaderPosition = "left",
446
- leftIcon,
447
- rightIcon,
448
- bordered,
449
- disabled,
450
- children,
451
- onClick,
452
- style,
453
- ...props
454
- }, ref) => {
455
- const recipe = useNajmComponentStyle("button");
456
- const aliased = resolveVariantAlias(
457
- recipe?.variants,
458
- variant ?? recipe?.defaultVariant ?? "default"
459
- );
460
- const effVariant = variant ?? aliased.variant ?? recipe?.defaultVariant;
461
- const effSize = size ?? recipe?.defaultSize;
462
- const recipeRadius = rounded === void 0 ? resolveRadiusValue(recipe?.radius) : void 0;
463
- const recipeStyle = recipeRadius ? { borderRadius: recipeRadius } : void 0;
464
- const [pending, setPending] = React5.useState(false);
465
- const isLoading = loading || pending;
466
- const isDisabled = disabled || disabledWhileLoading && isLoading;
467
- const Comp = asChild ? Slot : "button";
468
- const handleClick = React5.useCallback(
469
- (event) => {
470
- if (isDisabled) {
471
- event.preventDefault();
472
- return;
473
- }
474
- const result = onClick?.(event);
475
- if (autoLoading && isPromiseLike(result)) {
476
- setPending(true);
477
- void result.then(
478
- () => setPending(false),
479
- () => setPending(false)
480
- );
481
- }
482
- },
483
- [autoLoading, isDisabled, onClick]
484
- );
485
- const child = asChild ? React5.Children.only(children) : null;
486
- const childContent = asChild && React5.isValidElement(child) ? child.props.children : children;
487
- const content = loadingText && isLoading ? loadingText : childContent;
488
- const loaderNode = isLoading ? loader : null;
489
- const leftIconNode = renderIcon(leftIcon);
490
- const rightIconNode = renderIcon(rightIcon);
491
- const showCenteredLoader = Boolean(loaderNode && loaderPosition === "center");
492
- const renderedContent = showCenteredLoader ? /* @__PURE__ */ jsxs(Fragment, { children: [
493
- /* @__PURE__ */ jsxs("span", { className: "invisible inline-flex items-center gap-2", children: [
494
- leftIconNode,
495
- content,
496
- rightIconNode
497
- ] }),
498
- /* @__PURE__ */ jsx("span", { className: "absolute inset-0 inline-flex items-center justify-center", children: loaderNode })
499
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
500
- loaderNode && loaderPosition === "left" ? loaderNode : leftIconNode,
501
- content,
502
- loaderNode && loaderPosition === "right" ? loaderNode : rightIconNode
503
- ] });
504
- const renderedChild = asChild && React5.isValidElement(child) ? React5.cloneElement(child, void 0, renderedContent) : renderedContent;
505
- return /* @__PURE__ */ jsx(
506
- Comp,
507
- {
508
- ref,
509
- "data-slot": "button",
510
- "data-loading": isLoading || void 0,
511
- "data-disabled": isDisabled || void 0,
512
- "data-bordered": effVariant === "outline" ? "true" : bordered === false ? "false" : bordered ? "true" : void 0,
513
- "aria-busy": isLoading || void 0,
514
- "aria-disabled": asChild && isDisabled ? true : void 0,
515
- disabled: !asChild ? isDisabled : void 0,
516
- style: recipeStyle ? { ...recipeStyle, ...style } : style,
517
- className: cn(
518
- buttonVariants({ variant: effVariant, size: effSize, rounded, fullWidth }),
519
- aliased.style?.className,
520
- // Outline buttons always carry an input-style border.
521
- effVariant === "outline" && inputBorderClasses(true),
522
- // Filled/ghost/plain/link/success/warning/info/soft/subtle buttons only get a
523
- // border when the consumer explicitly opts in via `bordered`. Global theming
524
- // should not outline every filled button.
525
- effVariant !== "outline" && bordered === true && cn(
526
- "border",
527
- "border-muted-foreground"
528
- ),
529
- className
530
- ),
531
- onClick: handleClick,
532
- ...props,
533
- children: renderedChild
534
- }
535
- );
536
- }
537
- );
538
- Button.displayName = "Button";
539
168
  function buildStudioTheme2(colors) {
540
169
  return EditorView.theme(
541
170
  {
@@ -955,89 +584,5 @@ function JsonEditor({
955
584
  )
956
585
  ] });
957
586
  }
958
- var TableStoreContext = createContext(null);
959
- var useTableStore = { use: {} };
960
- var handler = {
961
- get: (_, prop) => () => {
962
- const store = useContext(TableStoreContext);
963
- if (!store) throw new Error("useTableStore must be used within NTable");
964
- return store.use[prop]();
965
- }
966
- };
967
- useTableStore.use = new Proxy({}, handler);
968
- function assignRef(ref, node) {
969
- if (!ref) return;
970
- if (typeof ref === "function") ref(node);
971
- else ref.current = node;
972
- }
973
- function applyViewportLayout(node, axis) {
974
- node.style.width = "100%";
975
- node.style.height = "100%";
976
- node.style.minWidth = "0";
977
- node.style.minHeight = "0";
978
- node.style.overflowX = axis === "x" || axis === "both" ? "auto" : "hidden";
979
- node.style.overflowY = axis === "y" || axis === "both" ? "auto" : "hidden";
980
- }
981
- function najmScrollOptions(axis, autoHide, options) {
982
- return {
983
- scrollbars: { theme: "os-theme-najm", autoHide, autoHideDelay: 500, clickScroll: true },
984
- overflow: {
985
- x: axis === "x" || axis === "both" ? "scroll" : "hidden",
986
- y: axis === "y" || axis === "both" ? "scroll" : "hidden"
987
- },
988
- ...options
989
- };
990
- }
991
- function NajmScroll({ className, axis = "y", autoHide = "never", viewportRef, events, options, element, children, style, ...props }) {
992
- return /* @__PURE__ */ jsx(
993
- OverlayScrollbarsComponent,
994
- {
995
- className: cn(className),
996
- style: {
997
- ...style,
998
- overflow: "hidden",
999
- minHeight: 0,
1000
- minWidth: 0
1001
- },
1002
- element,
1003
- defer: true,
1004
- options: najmScrollOptions(axis, autoHide, options || void 0),
1005
- events: {
1006
- ...events,
1007
- initialized: (instance, ...rest) => {
1008
- const viewport = instance.elements().viewport;
1009
- applyViewportLayout(viewport, axis);
1010
- assignRef(viewportRef, viewport);
1011
- events?.initialized?.(instance, ...rest);
1012
- },
1013
- updated: (instance, ...rest) => {
1014
- applyViewportLayout(instance.elements().viewport, axis);
1015
- events?.updated?.(instance, ...rest);
1016
- },
1017
- destroyed: (instance, ...rest) => {
1018
- assignRef(viewportRef, null);
1019
- events?.destroyed?.(instance, ...rest);
1020
- }
1021
- },
1022
- ...props,
1023
- children
1024
- }
1025
- );
1026
- }
1027
- function formatJsonValue(value) {
1028
- if (typeof value === "string") return value;
1029
- try {
1030
- return JSON.stringify(value ?? null, null, 2) ?? String(value);
1031
- } catch {
1032
- return String(value);
1033
- }
1034
- }
1035
- function NTableJson() {
1036
- const viewMode = useTableStore.use.viewMode();
1037
- const renderJson = useTableStore.use.renderJson();
1038
- const jsonValue = useTableStore.use.jsonValue();
1039
- if (viewMode !== "json") return null;
1040
- 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) }) }) });
1041
- }
1042
587
 
1043
- export { JsonEditor, JsonViewer, NTableJson };
588
+ export { JsonEditor, JsonViewer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-kit",
3
- "version": "2.6.3",
3
+ "version": "2.7.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Reusable React UI component package for Najm framework",
@@ -27,6 +27,11 @@
27
27
  "import": "./dist/adapters/next.mjs",
28
28
  "default": "./dist/adapters/next.mjs"
29
29
  },
30
+ "./app": {
31
+ "types": "./dist/adapters/app.d.ts",
32
+ "import": "./dist/adapters/app.mjs",
33
+ "default": "./dist/adapters/app.mjs"
34
+ },
30
35
  "./package.json": "./package.json",
31
36
  "./json": {
32
37
  "types": "./dist/json.d.ts",
@@ -53,6 +58,8 @@
53
58
  "react-hook-form": "^7",
54
59
  "@hookform/resolvers": "^5",
55
60
  "zod": ">=4",
61
+ "next": ">=14",
62
+ "najm-i18n": ">=2",
56
63
  "@uiw/react-codemirror": "^4.25.0",
57
64
  "@codemirror/state": "^6.6.0",
58
65
  "@codemirror/view": "^6.42.0",
@@ -63,6 +70,12 @@
63
70
  "@lezer/highlight": "^1.2.0"
64
71
  },
65
72
  "peerDependenciesMeta": {
73
+ "next": {
74
+ "optional": true
75
+ },
76
+ "najm-i18n": {
77
+ "optional": true
78
+ },
66
79
  "@uiw/react-codemirror": {
67
80
  "optional": true
68
81
  },
@@ -143,6 +156,7 @@
143
156
  "@uiw/react-codemirror": "^4.25.0",
144
157
  "@vitejs/plugin-react": "^5.2.0",
145
158
  "happy-dom": "^20.11.1",
159
+ "najm-i18n": "^2.0.3",
146
160
  "postcss": "^8.5.22",
147
161
  "react-hook-form": "^7",
148
162
  "rimraf": "^6",