najm-kit 0.0.19 → 0.0.20

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/index.mjs CHANGED
@@ -27,9 +27,12 @@ import { Command as Command$1 } from 'cmdk';
27
27
  import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
28
28
  import * as TogglePrimitive from '@radix-ui/react-toggle';
29
29
  import { Toaster as Toaster$1 } from 'sonner';
30
+ export { toast } from 'sonner';
30
31
  import { FormProvider, Controller, useFormContext, useForm, useFieldArray } from 'react-hook-form';
31
32
  import { defaultStyles, FileIcon } from 'react-file-icon';
32
33
  import { format } from 'date-fns';
34
+ import { HexColorPicker } from 'react-colorful';
35
+ import { converter, parse, formatHsl, formatRgb, formatHex } from 'culori';
33
36
  import { PhoneInput as PhoneInput$1, defaultCountries } from 'react-international-phone';
34
37
  import * as SliderPrimitive from '@radix-ui/react-slider';
35
38
  import { zodResolver } from '@hookform/resolvers/zod';
@@ -47,6 +50,8 @@ var lightMode = {
47
50
  "popover-foreground": "oklch(0.1445 0 0)",
48
51
  secondary: "oklch(0.9703 0 0)",
49
52
  "secondary-foreground": "oklch(0.2044 0 0)",
53
+ tertiary: "oklch(0.9676 0.007 247.897)",
54
+ "tertiary-foreground": "oklch(0.3138 0.0453 249.447)",
50
55
  muted: "oklch(0.9703 0 0)",
51
56
  "muted-foreground": "oklch(0.5555 0 0)",
52
57
  accent: "oklch(0.9703 0 0)",
@@ -54,10 +59,16 @@ var lightMode = {
54
59
  destructive: "oklch(0.6368 0.2078 25.326)",
55
60
  "destructive-foreground": "oklch(0.9848 0 0)",
56
61
  border: "oklch(0.9219 0 0)",
57
- "border-subtle": "oklch(0.9619 0 0)",
58
- "border-strong": "oklch(0.4184 0 0)",
59
62
  input: "oklch(0.9219 0 0)",
60
- radius: "0.5rem"
63
+ radius: "0.5rem",
64
+ sidebar: "oklch(0.985 0 0)",
65
+ "sidebar-foreground": "oklch(0.1445 0 0)",
66
+ "sidebar-primary": "oklch(0.2228 0.0043 286.044)",
67
+ "sidebar-primary-foreground": "oklch(0.9848 0 0)",
68
+ "sidebar-accent": "oklch(0.9703 0 0)",
69
+ "sidebar-accent-foreground": "oklch(0.2044 0 0)",
70
+ "sidebar-border": "oklch(0.9219 0 0)",
71
+ "sidebar-ring": "oklch(0.2228 0.0043 286.044)"
61
72
  };
62
73
  var darkMode = {
63
74
  background: "oklch(0.1417 0.0044 285.819)",
@@ -68,6 +79,8 @@ var darkMode = {
68
79
  "popover-foreground": "oklch(0.9683 0.0014 286.375)",
69
80
  secondary: "oklch(0.2313 0.007 285.839)",
70
81
  "secondary-foreground": "oklch(0.9203 0.0034 286.332)",
82
+ tertiary: "oklch(0.3138 0.0453 249.447)",
83
+ "tertiary-foreground": "oklch(0.8529 0.0324 248.208)",
71
84
  muted: "oklch(0.2313 0.007 285.839)",
72
85
  "muted-foreground": "oklch(0.6255 0.0171 285.896)",
73
86
  accent: "oklch(0.2313 0.007 285.839)",
@@ -75,10 +88,16 @@ var darkMode = {
75
88
  destructive: "oklch(0.6356 0.2082 25.378)",
76
89
  "destructive-foreground": "oklch(1 0 0)",
77
90
  border: "oklch(0.262 0.0085 285.799)",
78
- "border-subtle": "oklch(0.2208 0.0065 285.856)",
79
- "border-strong": "oklch(0.8294 0 0)",
80
91
  input: "oklch(0.262 0.0085 285.799)",
81
- radius: "0.5rem"
92
+ radius: "0.5rem",
93
+ sidebar: "oklch(0.205 0 0)",
94
+ "sidebar-foreground": "oklch(0.9683 0.0014 286.375)",
95
+ "sidebar-primary": "oklch(0.4865 0.2423 291.866)",
96
+ "sidebar-primary-foreground": "oklch(0.9848 0 0)",
97
+ "sidebar-accent": "oklch(0.2313 0.007 285.839)",
98
+ "sidebar-accent-foreground": "oklch(0.9683 0.0014 286.375)",
99
+ "sidebar-border": "oklch(0.262 0.0085 285.799)",
100
+ "sidebar-ring": "oklch(0.4865 0.2423 291.866)"
82
101
  };
83
102
 
84
103
  // src/theme/presets/accents.ts
@@ -88,42 +107,54 @@ var accents = {
88
107
  "primary-foreground": "oklch(0.9848 0 0)",
89
108
  ring: "oklch(0.2228 0.0043 286.044)",
90
109
  accent: "oklch(0.2747 0.006 286.001)",
91
- "accent-foreground": "oklch(0.9848 0 0)"
110
+ "accent-foreground": "oklch(0.9848 0 0)",
111
+ "sidebar-primary": "oklch(0.2228 0.0043 286.044)",
112
+ "sidebar-ring": "oklch(0.2228 0.0043 286.044)"
92
113
  },
93
114
  emerald: {
94
115
  primary: "oklch(0.6902 0.1481 162.368)",
95
116
  "primary-foreground": "oklch(1 0 0)",
96
117
  ring: "oklch(0.6902 0.1481 162.368)",
97
118
  accent: "oklch(0.3519 0.0714 164.26)",
98
- "accent-foreground": "oklch(0.9131 0.0924 171.145)"
119
+ "accent-foreground": "oklch(0.9131 0.0924 171.145)",
120
+ "sidebar-primary": "oklch(0.6902 0.1481 162.368)",
121
+ "sidebar-ring": "oklch(0.6902 0.1481 162.368)"
99
122
  },
100
123
  green: {
101
124
  primary: "oklch(0.7205 0.192 149.493)",
102
125
  "primary-foreground": "oklch(1 0 0)",
103
126
  ring: "oklch(0.7205 0.192 149.493)",
104
127
  accent: "oklch(0.333 0.0811 150.922)",
105
- "accent-foreground": "oklch(0.8958 0.096 156.121)"
128
+ "accent-foreground": "oklch(0.8958 0.096 156.121)",
129
+ "sidebar-primary": "oklch(0.7205 0.192 149.493)",
130
+ "sidebar-ring": "oklch(0.7205 0.192 149.493)"
106
131
  },
107
132
  slate: {
108
133
  primary: "oklch(0.6227 0.0463 256.82)",
109
134
  "primary-foreground": "oklch(1 0 0)",
110
135
  ring: "oklch(0.6227 0.0463 256.82)",
111
136
  accent: "oklch(0.3115 0.0245 256.824)",
112
- "accent-foreground": "oklch(0.8784 0.0141 256.711)"
137
+ "accent-foreground": "oklch(0.8784 0.0141 256.711)",
138
+ "sidebar-primary": "oklch(0.6227 0.0463 256.82)",
139
+ "sidebar-ring": "oklch(0.6227 0.0463 256.82)"
113
140
  },
114
141
  blue: {
115
142
  primary: "oklch(0.6261 0.1859 259.596)",
116
143
  "primary-foreground": "oklch(1 0 0)",
117
144
  ring: "oklch(0.6261 0.1859 259.596)",
118
145
  accent: "oklch(0.2941 0.1092 259.917)",
119
- "accent-foreground": "oklch(0.8064 0.0902 259.76)"
146
+ "accent-foreground": "oklch(0.8064 0.0902 259.76)",
147
+ "sidebar-primary": "oklch(0.6261 0.1859 259.596)",
148
+ "sidebar-ring": "oklch(0.6261 0.1859 259.596)"
120
149
  },
121
150
  violet: {
122
151
  primary: "oklch(0.4865 0.2423 291.866)",
123
152
  "primary-foreground": "oklch(1 0 0)",
124
153
  ring: "oklch(0.6016 0.2214 292.234)",
125
154
  accent: "oklch(0.2467 0.109 294.41)",
126
- "accent-foreground": "oklch(0.7817 0.1036 301.636)"
155
+ "accent-foreground": "oklch(0.7817 0.1036 301.636)",
156
+ "sidebar-primary": "oklch(0.4865 0.2423 291.866)",
157
+ "sidebar-ring": "oklch(0.6016 0.2214 292.234)"
127
158
  }
128
159
  };
129
160
 
@@ -162,7 +193,15 @@ function resolvePreset(preset) {
162
193
  const { mode, accent } = PRESET_MAP[preset];
163
194
  return composePreset(mode, accent);
164
195
  }
165
- var ACCENT_KEYS = /* @__PURE__ */ new Set(["primary", "primary-foreground", "ring", "accent", "accent-foreground"]);
196
+ var ACCENT_KEYS = /* @__PURE__ */ new Set([
197
+ "primary",
198
+ "primary-foreground",
199
+ "ring",
200
+ "accent",
201
+ "accent-foreground",
202
+ "sidebar-primary",
203
+ "sidebar-ring"
204
+ ]);
166
205
  function tokensToStyle(tokens, accentOnly) {
167
206
  const style = {};
168
207
  for (const [key, value] of Object.entries(tokens)) {
@@ -172,50 +211,85 @@ function tokensToStyle(tokens, accentOnly) {
172
211
  }
173
212
  return style;
174
213
  }
214
+ var SHADCN_RADIUS_SCALE = {
215
+ "--radius-xs": "calc(var(--radius) - 4px)",
216
+ "--radius-sm": "calc(var(--radius) - 4px)",
217
+ "--radius-md": "calc(var(--radius) - 2px)",
218
+ "--radius-lg": "var(--radius)",
219
+ "--radius-xl": "calc(var(--radius) + 4px)",
220
+ "--radius-2xl": "calc(var(--radius) + 8px)",
221
+ "--radius-3xl": "calc(var(--radius) + 12px)",
222
+ "--radius-4xl": "calc(var(--radius) + 16px)"
223
+ };
224
+ function radiusToStyle(radius, scale) {
225
+ const style = { "--radius": radius };
226
+ for (const [key, value] of Object.entries(SHADCN_RADIUS_SCALE)) {
227
+ style[key] = scale === "uniform" ? "var(--radius)" : value;
228
+ }
229
+ return style;
230
+ }
175
231
  var NajmThemeDepthContext = React.createContext(0);
176
232
  var NajmThemeContainerCtx = React.createContext(null);
177
- var DEFAULT_APPEARANCE = {
178
- borderDegree: "default"
179
- };
233
+ var DEFAULT_APPEARANCE = {};
180
234
  var NajmAppearanceContext = React.createContext(DEFAULT_APPEARANCE);
181
235
  function useNajmAppearance() {
182
236
  return React.useContext(NajmAppearanceContext);
183
237
  }
184
238
  function NajmThemeProvider({
239
+ config,
185
240
  preset,
186
241
  mode,
187
242
  accent,
188
243
  tokens,
189
244
  accentOnly,
190
245
  appearance,
246
+ radius,
247
+ radiusScale,
248
+ spacing,
191
249
  className,
192
250
  asChild,
193
251
  children
194
252
  }) {
195
253
  const depth = React.useContext(NajmThemeDepthContext);
196
254
  const parentAppearance = React.useContext(NajmAppearanceContext);
197
- const shouldApplyThemeTokens = Boolean(preset || mode || tokens);
255
+ const effectivePreset = preset ?? config?.preset;
256
+ const effectiveMode = mode ?? config?.mode;
257
+ const effectiveAccent = accent ?? config?.accent;
258
+ const effectiveTokens = tokens ?? config?.tokens;
259
+ const effectiveAccentOnly = accentOnly ?? config?.accentOnly;
260
+ const effectiveRadius = radius ?? config?.radius;
261
+ const effectiveRadiusScale = radiusScale ?? config?.radiusScale ?? "shadcn";
262
+ const effectiveSpacing = spacing ?? config?.spacing;
263
+ const effectiveBorderWidth = appearance?.borderWidth ?? config?.appearance?.borderWidth;
264
+ const shouldApplyThemeTokens = Boolean(effectivePreset || effectiveMode || effectiveTokens);
198
265
  const resolved = React.useMemo(() => {
199
266
  if (!shouldApplyThemeTokens) return null;
200
- if (tokens) return tokens;
201
- if (preset) return resolvePreset(preset);
202
- return composePreset(mode, accent ?? "neutral");
203
- }, [preset, mode, accent, tokens, shouldApplyThemeTokens]);
267
+ if (effectiveTokens) return effectiveTokens;
268
+ if (effectivePreset) return resolvePreset(effectivePreset);
269
+ return composePreset(effectiveMode, effectiveAccent ?? "neutral");
270
+ }, [effectivePreset, effectiveMode, effectiveAccent, effectiveTokens, shouldApplyThemeTokens]);
204
271
  const style = React.useMemo(
205
- () => resolved ? tokensToStyle(resolved, accentOnly) : void 0,
206
- [resolved, accentOnly]
272
+ () => {
273
+ const tokenStyle = resolved ? tokensToStyle(resolved, effectiveAccentOnly) : void 0;
274
+ const radiusStyle = effectiveRadius !== void 0 ? radiusToStyle(effectiveRadius, effectiveRadiusScale) : void 0;
275
+ const borderWidthStyle = effectiveBorderWidth !== void 0 ? { "--border-width": effectiveBorderWidth } : void 0;
276
+ const spacingStyle = effectiveSpacing !== void 0 ? { "--spacing": effectiveSpacing } : void 0;
277
+ if (!tokenStyle && !radiusStyle && !borderWidthStyle && !spacingStyle) return void 0;
278
+ return { ...tokenStyle, ...radiusStyle, ...borderWidthStyle, ...spacingStyle };
279
+ },
280
+ [resolved, effectiveAccentOnly, effectiveRadius, effectiveRadiusScale, effectiveSpacing, effectiveBorderWidth]
207
281
  );
208
282
  const Comp = asChild ? Slot : "div";
209
283
  const [container, setContainer] = React.useState(null);
210
284
  const resolvedAppearance = React.useMemo(
211
- () => ({ ...parentAppearance, ...appearance ?? {} }),
212
- [parentAppearance, appearance]
285
+ () => ({ ...parentAppearance, ...config?.appearance ?? {}, ...appearance ?? {} }),
286
+ [parentAppearance, config?.appearance, appearance]
213
287
  );
214
288
  return /* @__PURE__ */ jsx(NajmThemeDepthContext.Provider, { value: depth + 1, children: /* @__PURE__ */ jsx(NajmAppearanceContext.Provider, { value: resolvedAppearance, children: /* @__PURE__ */ jsx(NajmThemeContainerCtx.Provider, { value: container, children: /* @__PURE__ */ jsx(
215
289
  Comp,
216
290
  {
217
291
  ref: setContainer,
218
- "data-najm-theme": preset ?? `${mode ?? "light"}-${accent ?? "neutral"}`,
292
+ "data-najm-theme": effectivePreset ?? `${effectiveMode ?? "light"}-${effectiveAccent ?? "neutral"}`,
219
293
  className,
220
294
  style,
221
295
  children
@@ -223,49 +297,473 @@ function NajmThemeProvider({
223
297
  ) }) }) });
224
298
  }
225
299
 
226
- // src/theme/borders.ts
227
- function resolveBorderDegree(borderDegree, bordered, globalBorderDegree, fallback = "default") {
228
- if (borderDegree) return borderDegree;
229
- if (bordered === true) return "strong";
230
- if (bordered === false) return fallback;
231
- return globalBorderDegree ?? fallback;
232
- }
233
- function borderColorClassForDegree(degree) {
234
- switch (degree) {
235
- case "none":
236
- return "border-transparent";
237
- case "subtle":
238
- return "border-border-subtle";
239
- case "strong":
240
- return "border-border-strong";
241
- default:
242
- return "border-border";
300
+ // src/theme/config.ts
301
+ var MODES = ["light", "dark"];
302
+ var ACCENTS = ["neutral", "emerald", "green", "slate", "blue", "violet"];
303
+ var PRESETS = ["light", "dark", "dark-emerald", "dark-green", "dark-slate", "dark-blue", "dark-violet"];
304
+ var RADIUS_SCALES = ["shadcn", "uniform"];
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
+ var ROOT_KEYS = /* @__PURE__ */ new Set([
343
+ "preset",
344
+ "mode",
345
+ "accent",
346
+ "tokens",
347
+ "accentOnly",
348
+ "appearance",
349
+ "radius",
350
+ "radiusScale"
351
+ ]);
352
+ var TOKEN_KEY_SET = new Set(TOKEN_KEYS);
353
+ function isRecord(value) {
354
+ return typeof value === "object" && value !== null && !Array.isArray(value);
355
+ }
356
+ function assertKnownKeys(value, keys, path) {
357
+ const unknown = Object.keys(value).find((key) => !keys.has(key));
358
+ if (unknown) throw new TypeError(`Unknown ${path} property: ${unknown}`);
359
+ }
360
+ function optionalEnum(value, values, path) {
361
+ if (value === void 0) return void 0;
362
+ if (typeof value !== "string" || !values.includes(value)) {
363
+ throw new TypeError(`${path} must be one of: ${values.join(", ")}`);
364
+ }
365
+ return value;
366
+ }
367
+ function optionalString(value, path) {
368
+ if (value === void 0) return void 0;
369
+ if (typeof value !== "string" || value.trim() === "") {
370
+ throw new TypeError(`${path} must be a non-empty string`);
243
371
  }
372
+ return value;
373
+ }
374
+ function parseTokens(value) {
375
+ if (value === void 0) return void 0;
376
+ if (!isRecord(value)) throw new TypeError("theme.tokens must be an object");
377
+ assertKnownKeys(value, TOKEN_KEY_SET, "theme.tokens");
378
+ const tokens = {};
379
+ for (const key of TOKEN_KEYS) {
380
+ const token = optionalString(value[key], `theme.tokens.${key}`);
381
+ if (token !== void 0) tokens[key] = token;
382
+ }
383
+ return tokens;
384
+ }
385
+ function defineNajmThemeConfig(config) {
386
+ return config;
244
387
  }
245
- function inputBorderColorClassForDegree(degree) {
246
- switch (degree) {
247
- case "none":
248
- return "border-transparent";
249
- case "subtle":
250
- return "border-border-subtle";
251
- case "strong":
252
- return "border-border-strong";
253
- default:
254
- return "border-input";
388
+ function parseNajmThemeConfig(input) {
389
+ let value = input;
390
+ if (typeof input === "string") {
391
+ try {
392
+ value = JSON.parse(input);
393
+ } catch (error) {
394
+ throw new TypeError(`Invalid theme JSON: ${error.message}`);
395
+ }
255
396
  }
397
+ if (!isRecord(value)) throw new TypeError("Theme config must be an object");
398
+ assertKnownKeys(value, ROOT_KEYS, "theme");
399
+ let appearance;
400
+ if (value.appearance !== void 0) {
401
+ if (!isRecord(value.appearance)) throw new TypeError("theme.appearance must be an object");
402
+ assertKnownKeys(value.appearance, /* @__PURE__ */ new Set(["borderWidth"]), "theme.appearance");
403
+ appearance = {
404
+ borderWidth: optionalString(
405
+ value.appearance.borderWidth,
406
+ "theme.appearance.borderWidth"
407
+ )
408
+ };
409
+ }
410
+ const accentOnly = value.accentOnly;
411
+ if (accentOnly !== void 0 && typeof accentOnly !== "boolean") {
412
+ throw new TypeError("theme.accentOnly must be a boolean");
413
+ }
414
+ const parsedAccentOnly = typeof accentOnly === "boolean" ? accentOnly : void 0;
415
+ const config = {};
416
+ const preset = optionalEnum(value.preset, PRESETS, "theme.preset");
417
+ const mode = optionalEnum(value.mode, MODES, "theme.mode");
418
+ const accent = optionalEnum(value.accent, ACCENTS, "theme.accent");
419
+ const tokens = parseTokens(value.tokens);
420
+ const radius = optionalString(value.radius, "theme.radius");
421
+ const radiusScale = optionalEnum(value.radiusScale, RADIUS_SCALES, "theme.radiusScale");
422
+ if (preset !== void 0) config.preset = preset;
423
+ if (mode !== void 0) config.mode = mode;
424
+ if (accent !== void 0) config.accent = accent;
425
+ if (tokens !== void 0) config.tokens = tokens;
426
+ if (parsedAccentOnly !== void 0) config.accentOnly = parsedAccentOnly;
427
+ if (appearance !== void 0) config.appearance = appearance;
428
+ if (radius !== void 0) config.radius = radius;
429
+ if (radiusScale !== void 0) config.radiusScale = radiusScale;
430
+ return config;
431
+ }
432
+ function stringifyNajmThemeConfig(config, space = 2) {
433
+ return JSON.stringify(config, null, space);
434
+ }
435
+ var NajmDesignContext = React.createContext({
436
+ components: {}
437
+ });
438
+ function useNajmDesign() {
439
+ return React.useContext(NajmDesignContext);
440
+ }
441
+ function useNajmComponentStyle(name) {
442
+ const { components } = useNajmDesign();
443
+ return components[name];
444
+ }
445
+ var SCALE_FACTOR = {
446
+ compact: "0.95",
447
+ default: "1",
448
+ comfortable: "1.05"
449
+ };
450
+ function typographyToStyle(t) {
451
+ const style = {};
452
+ if (t.fontSans) style["--font-sans"] = t.fontSans;
453
+ if (t.fontHeading) style["--font-heading"] = t.fontHeading;
454
+ if (t.fontMono) style["--font-mono"] = t.fontMono;
455
+ if (t.baseSize) style["--font-size-base"] = t.baseSize;
456
+ if (t.lineHeight) style["--line-height-base"] = t.lineHeight;
457
+ if (t.letterSpacing) style["--letter-spacing-base"] = t.letterSpacing;
458
+ if (t.scale) style["--font-scale"] = SCALE_FACTOR[t.scale];
459
+ return style;
256
460
  }
257
- function useResolvedBorderDegree(options = {}) {
258
- const appearance = useNajmAppearance();
259
- return resolveBorderDegree(
260
- options.borderDegree,
261
- options.bordered,
262
- appearance.borderDegree,
263
- options.fallback
461
+ function layoutToStyle(layout) {
462
+ const style = {};
463
+ if (layout.pageGutter) style["--page-gutter"] = layout.pageGutter;
464
+ if (layout.sectionGap) style["--section-gap"] = layout.sectionGap;
465
+ return style;
466
+ }
467
+ function NajmDesignProvider({
468
+ config,
469
+ className,
470
+ children
471
+ }) {
472
+ const contextValue = React.useMemo(
473
+ () => ({ components: config.components ?? {}, typography: config.typography, layout: config.layout }),
474
+ [config.components, config.typography, config.layout]
475
+ );
476
+ const typographyStyle = React.useMemo(
477
+ () => config.typography ? typographyToStyle(config.typography) : void 0,
478
+ [config.typography]
479
+ );
480
+ const layoutStyle = React.useMemo(
481
+ () => config.layout ? layoutToStyle(config.layout) : void 0,
482
+ [config.layout]
264
483
  );
484
+ const providerStyle = React.useMemo(
485
+ () => ({ ...layoutStyle ?? {}, ...typographyStyle ?? {} }),
486
+ [layoutStyle, typographyStyle]
487
+ );
488
+ return /* @__PURE__ */ jsx(NajmDesignContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(NajmThemeProvider, { config: config.theme, className, children: layoutStyle || typographyStyle ? (
489
+ // `display: contents` lets design CSS variables cascade to
490
+ // children without introducing a layout box that would break height
491
+ // chains (e.g. h-full) in the consuming app.
492
+ /* @__PURE__ */ jsx("div", { style: { display: "contents", ...providerStyle }, "data-najm-design-vars": "", children })
493
+ ) : children }) });
494
+ }
495
+
496
+ // src/theme/design-types.ts
497
+ var NAJM_COMPONENT_NAMES = [
498
+ "button",
499
+ "badge",
500
+ "card",
501
+ "table",
502
+ "tabs",
503
+ "dialog",
504
+ "alert",
505
+ "sidebar",
506
+ "pageHeader",
507
+ "input",
508
+ "select",
509
+ "sheet",
510
+ "popover",
511
+ "tooltip",
512
+ "progress",
513
+ "avatar"
514
+ ];
515
+ var RADIUS_VALUE_MAP = {
516
+ none: "0",
517
+ xs: "var(--radius-xs)",
518
+ sm: "var(--radius-sm)",
519
+ md: "var(--radius-md)",
520
+ lg: "var(--radius-lg)",
521
+ xl: "var(--radius-xl)",
522
+ full: "9999px"
523
+ };
524
+ function resolveRadiusValue(radius) {
525
+ if (!radius || radius === "inherit") return void 0;
526
+ return RADIUS_VALUE_MAP[radius] ?? radius;
527
+ }
528
+
529
+ // src/theme/design-config.ts
530
+ var ROOT_KEYS2 = /* @__PURE__ */ new Set(["version", "theme", "typography", "components", "layout"]);
531
+ var TYPOGRAPHY_KEYS = /* @__PURE__ */ new Set([
532
+ "fontSans",
533
+ "fontHeading",
534
+ "fontMono",
535
+ "baseSize",
536
+ "scale",
537
+ "lineHeight",
538
+ "letterSpacing"
539
+ ]);
540
+ var LAYOUT_KEYS = /* @__PURE__ */ new Set(["pageGutter", "sectionGap"]);
541
+ var COMPONENT_KEYS = /* @__PURE__ */ new Set([
542
+ "card",
543
+ "showSectionLabels",
544
+ "showSectionSeparators",
545
+ "defaultVariant",
546
+ "defaultSize",
547
+ "density",
548
+ "radius",
549
+ "borderWidth",
550
+ "slots",
551
+ "variants"
552
+ ]);
553
+ var SLOT_KEYS = /* @__PURE__ */ new Set(["className", "radius", "borderWidth", "padding", "paddingTop"]);
554
+ var VARIANT_KEYS = /* @__PURE__ */ new Set(["use", "className", "tokens"]);
555
+ var COMPONENT_NAME_SET = new Set(NAJM_COMPONENT_NAMES);
556
+ var DENSITIES = /* @__PURE__ */ new Set(["compact", "default", "comfortable"]);
557
+ var SCALES = /* @__PURE__ */ new Set(["compact", "default", "comfortable"]);
558
+ function isRecord2(value) {
559
+ return typeof value === "object" && value !== null && !Array.isArray(value);
560
+ }
561
+ function assertKnownKeys2(value, keys, path) {
562
+ const unknown = Object.keys(value).find((key) => !keys.has(key));
563
+ if (unknown) throw new TypeError(`Unknown ${path} property: ${unknown}`);
564
+ }
565
+ function optionalString2(value, path) {
566
+ if (value === void 0) return void 0;
567
+ if (typeof value !== "string") {
568
+ throw new TypeError(`${path} must be a string`);
569
+ }
570
+ return value;
571
+ }
572
+ function optionalBoolean(value, path) {
573
+ if (value === void 0) return void 0;
574
+ if (typeof value !== "boolean") {
575
+ throw new TypeError(`${path} must be a boolean`);
576
+ }
577
+ return value;
578
+ }
579
+ function optionalEnum2(value, values, path) {
580
+ if (value === void 0) return void 0;
581
+ if (typeof value !== "string" || !values.has(value)) {
582
+ throw new TypeError(`${path} must be one of: ${[...values].join(", ")}`);
583
+ }
584
+ return value;
585
+ }
586
+ function parseTypography(value) {
587
+ if (value === void 0) return void 0;
588
+ if (!isRecord2(value)) throw new TypeError("typography must be an object");
589
+ assertKnownKeys2(value, TYPOGRAPHY_KEYS, "typography");
590
+ const cfg = {};
591
+ const fontSans = optionalString2(value.fontSans, "typography.fontSans");
592
+ const fontHeading = optionalString2(value.fontHeading, "typography.fontHeading");
593
+ const fontMono = optionalString2(value.fontMono, "typography.fontMono");
594
+ const baseSize = optionalString2(value.baseSize, "typography.baseSize");
595
+ const scale = optionalEnum2(value.scale, SCALES, "typography.scale");
596
+ const lineHeight = optionalString2(value.lineHeight, "typography.lineHeight");
597
+ const letterSpacing = optionalString2(value.letterSpacing, "typography.letterSpacing");
598
+ if (fontSans !== void 0) cfg.fontSans = fontSans;
599
+ if (fontHeading !== void 0) cfg.fontHeading = fontHeading;
600
+ if (fontMono !== void 0) cfg.fontMono = fontMono;
601
+ if (baseSize !== void 0) cfg.baseSize = baseSize;
602
+ if (scale !== void 0) cfg.scale = scale;
603
+ if (lineHeight !== void 0) cfg.lineHeight = lineHeight;
604
+ if (letterSpacing !== void 0) cfg.letterSpacing = letterSpacing;
605
+ return cfg;
606
+ }
607
+ function parseLayout(value) {
608
+ if (value === void 0) return void 0;
609
+ if (!isRecord2(value)) throw new TypeError("layout must be an object");
610
+ assertKnownKeys2(value, LAYOUT_KEYS, "layout");
611
+ const cfg = {};
612
+ const pageGutter = optionalString2(value.pageGutter, "layout.pageGutter");
613
+ const sectionGap = optionalString2(value.sectionGap, "layout.sectionGap");
614
+ if (pageGutter !== void 0) cfg.pageGutter = pageGutter;
615
+ if (sectionGap !== void 0) cfg.sectionGap = sectionGap;
616
+ return cfg;
617
+ }
618
+ function parseVariant(value, path) {
619
+ if (!isRecord2(value)) throw new TypeError(`${path} must be an object`);
620
+ assertKnownKeys2(value, VARIANT_KEYS, path);
621
+ const variant = {};
622
+ const use = optionalString2(value.use, `${path}.use`);
623
+ const className = optionalString2(value.className, `${path}.className`);
624
+ if (use !== void 0) variant.use = use;
625
+ if (className !== void 0) variant.className = className;
626
+ if (value.tokens !== void 0) {
627
+ if (!isRecord2(value.tokens)) throw new TypeError(`${path}.tokens must be an object`);
628
+ variant.tokens = value.tokens;
629
+ }
630
+ return variant;
631
+ }
632
+ function parseComponentStyle(value, path) {
633
+ if (!isRecord2(value)) throw new TypeError(`${path} must be an object`);
634
+ assertKnownKeys2(value, COMPONENT_KEYS, path);
635
+ const cfg = {};
636
+ const card = optionalBoolean(value.card, `${path}.card`);
637
+ const showSectionLabels = optionalBoolean(value.showSectionLabels, `${path}.showSectionLabels`);
638
+ const showSectionSeparators = optionalBoolean(value.showSectionSeparators, `${path}.showSectionSeparators`);
639
+ const defaultVariant = optionalString2(value.defaultVariant, `${path}.defaultVariant`);
640
+ const defaultSize = optionalString2(value.defaultSize, `${path}.defaultSize`);
641
+ const density = optionalEnum2(value.density, DENSITIES, `${path}.density`);
642
+ const radius = optionalString2(value.radius, `${path}.radius`);
643
+ const borderWidth = optionalString2(value.borderWidth, `${path}.borderWidth`);
644
+ if (card !== void 0) cfg.card = card;
645
+ if (showSectionLabels !== void 0) cfg.showSectionLabels = showSectionLabels;
646
+ if (showSectionSeparators !== void 0) cfg.showSectionSeparators = showSectionSeparators;
647
+ if (defaultVariant !== void 0) cfg.defaultVariant = defaultVariant;
648
+ if (defaultSize !== void 0) cfg.defaultSize = defaultSize;
649
+ if (density !== void 0) cfg.density = density;
650
+ if (radius !== void 0) cfg.radius = radius;
651
+ if (borderWidth !== void 0) cfg.borderWidth = borderWidth;
652
+ if (value.slots !== void 0) {
653
+ if (!isRecord2(value.slots)) throw new TypeError(`${path}.slots must be an object`);
654
+ const slots = {};
655
+ for (const [slotName, slotValue] of Object.entries(value.slots)) {
656
+ if (!isRecord2(slotValue)) throw new TypeError(`${path}.slots.${slotName} must be an object`);
657
+ assertKnownKeys2(slotValue, SLOT_KEYS, `${path}.slots.${slotName}`);
658
+ slots[slotName] = slotValue;
659
+ }
660
+ cfg.slots = slots;
661
+ }
662
+ if (value.variants !== void 0) {
663
+ if (!isRecord2(value.variants)) throw new TypeError(`${path}.variants must be an object`);
664
+ const variants = {};
665
+ for (const [variantName, variantValue] of Object.entries(value.variants)) {
666
+ variants[variantName] = parseVariant(variantValue, `${path}.variants.${variantName}`);
667
+ }
668
+ cfg.variants = variants;
669
+ }
670
+ return cfg;
671
+ }
672
+ function parseComponents(value) {
673
+ if (value === void 0) return void 0;
674
+ if (!isRecord2(value)) throw new TypeError("components must be an object");
675
+ const unknown = Object.keys(value).find((key) => !COMPONENT_NAME_SET.has(key));
676
+ if (unknown) throw new TypeError(`Unknown component name: ${unknown}`);
677
+ const components = {};
678
+ for (const [name, cfg] of Object.entries(value)) {
679
+ components[name] = parseComponentStyle(cfg, `components.${name}`);
680
+ }
681
+ return components;
682
+ }
683
+ function defineNajmDesignConfig(config) {
684
+ return config;
685
+ }
686
+ function parseNajmDesignConfig(input) {
687
+ let value = input;
688
+ if (typeof input === "string") {
689
+ try {
690
+ value = JSON.parse(input);
691
+ } catch (error) {
692
+ throw new TypeError(`Invalid design JSON: ${error.message}`);
693
+ }
694
+ }
695
+ if (!isRecord2(value)) throw new TypeError("Design config must be an object");
696
+ if (!("version" in value) && !("theme" in value)) {
697
+ return {
698
+ version: 1,
699
+ theme: parseNajmThemeConfig(value)
700
+ };
701
+ }
702
+ assertKnownKeys2(value, ROOT_KEYS2, "design");
703
+ if (value.version !== void 0 && value.version !== 1) {
704
+ throw new TypeError("design.version must be 1");
705
+ }
706
+ if (value.theme === void 0) throw new TypeError("design.theme is required");
707
+ const config = {
708
+ version: 1,
709
+ theme: parseNajmThemeConfig(value.theme)
710
+ };
711
+ const typography = parseTypography(value.typography);
712
+ if (typography !== void 0) config.typography = typography;
713
+ const components = parseComponents(value.components);
714
+ if (components !== void 0) config.components = components;
715
+ const layout = parseLayout(value.layout);
716
+ if (layout !== void 0) config.layout = layout;
717
+ return config;
718
+ }
719
+ function stringifyNajmDesignConfig(config, space = 2) {
720
+ return JSON.stringify(config, null, space);
721
+ }
722
+ function resolveVariantAlias(variants, variant) {
723
+ if (!variants) return { variant };
724
+ const seen = /* @__PURE__ */ new Set();
725
+ let current = variant;
726
+ let style = variants[current];
727
+ while (style?.use && !seen.has(current)) {
728
+ seen.add(current);
729
+ const next = style.use;
730
+ if (seen.has(next)) break;
731
+ current = next;
732
+ style = variants[current];
733
+ }
734
+ return { variant: current, style };
735
+ }
736
+
737
+ // src/theme/borders.ts
738
+ var SURFACE_BORDER_CLASSES = {
739
+ all: "najm-border border-border",
740
+ top: "najm-border-t border-border",
741
+ right: "najm-border-r border-border",
742
+ bottom: "najm-border-b border-border",
743
+ left: "najm-border-l border-border"
744
+ };
745
+ var SIDEBAR_BORDER_CLASSES = {
746
+ all: "najm-border border-sidebar-border",
747
+ top: "najm-border-t border-sidebar-border",
748
+ right: "najm-border-r border-sidebar-border",
749
+ bottom: "najm-border-b border-sidebar-border",
750
+ left: "najm-border-l border-sidebar-border"
751
+ };
752
+ var BORDER_RESET_CLASSES = {
753
+ all: "border-0",
754
+ top: "border-t-0",
755
+ right: "border-r-0",
756
+ bottom: "border-b-0",
757
+ left: "border-l-0"
758
+ };
759
+ function surfaceBorderClasses(bordered = true, side = "all") {
760
+ return bordered === false ? BORDER_RESET_CLASSES[side] : SURFACE_BORDER_CLASSES[side];
265
761
  }
266
- function surfaceBorderClasses(degree) {
267
- if (degree === "none") return "border border-transparent";
268
- return `border ${borderColorClassForDegree(degree)}`;
762
+ function sidebarBorderClasses(bordered = true, side = "all") {
763
+ return bordered === false ? BORDER_RESET_CLASSES[side] : SIDEBAR_BORDER_CLASSES[side];
764
+ }
765
+ function inputBorderClasses(bordered = true) {
766
+ return bordered === false ? "border-0" : "najm-border border-input";
269
767
  }
270
768
  var EDITABLE_INPUT_TYPES = /* @__PURE__ */ new Set([
271
769
  "text",
@@ -600,21 +1098,25 @@ var Button = React.forwardRef(
600
1098
  leftIcon,
601
1099
  rightIcon,
602
1100
  bordered,
603
- borderDegree,
604
1101
  disabled,
605
1102
  children,
606
1103
  onClick,
1104
+ style,
607
1105
  ...props
608
1106
  }, ref) => {
1107
+ const recipe = useNajmComponentStyle("button");
1108
+ const aliased = resolveVariantAlias(
1109
+ recipe?.variants,
1110
+ variant ?? recipe?.defaultVariant ?? "default"
1111
+ );
1112
+ const effVariant = variant ?? aliased.variant ?? recipe?.defaultVariant;
1113
+ const effSize = size ?? recipe?.defaultSize;
1114
+ const recipeRadius = rounded === void 0 ? resolveRadiusValue(recipe?.radius) : void 0;
1115
+ const recipeStyle = recipeRadius ? { borderRadius: recipeRadius } : void 0;
609
1116
  const [pending, setPending] = React.useState(false);
610
1117
  const isLoading = loading || pending;
611
1118
  const isDisabled = disabled || disabledWhileLoading && isLoading;
612
1119
  const Comp = asChild ? Slot : "button";
613
- const resolvedBorderDegree = useResolvedBorderDegree({
614
- borderDegree,
615
- bordered,
616
- fallback: "default"
617
- });
618
1120
  const handleClick = React.useCallback(
619
1121
  (event) => {
620
1122
  if (isDisabled) {
@@ -644,21 +1146,22 @@ var Button = React.forwardRef(
644
1146
  "data-slot": "button",
645
1147
  "data-loading": isLoading || void 0,
646
1148
  "data-disabled": isDisabled || void 0,
647
- "data-border-degree": variant === "outline" || bordered || borderDegree ? resolvedBorderDegree : void 0,
1149
+ "data-bordered": effVariant === "outline" ? "true" : bordered === false ? "false" : bordered ? "true" : void 0,
648
1150
  "aria-busy": isLoading || void 0,
649
1151
  "aria-disabled": asChild && isDisabled ? true : void 0,
650
1152
  disabled: !asChild ? isDisabled : void 0,
1153
+ style: recipeStyle ? { ...recipeStyle, ...style } : style,
651
1154
  className: cn(
652
- buttonVariants({ variant, size, rounded, fullWidth }),
653
- // Outline buttons always have a border; let the resolved degree drive its color.
654
- variant === "outline" && borderColorClassForDegree(resolvedBorderDegree),
1155
+ buttonVariants({ variant: effVariant, size: effSize, rounded, fullWidth }),
1156
+ aliased.style?.className,
1157
+ // Outline buttons always carry an input-style border.
1158
+ effVariant === "outline" && inputBorderClasses(true),
655
1159
  // Filled/ghost/plain/link/success/warning/info/soft/subtle buttons only get a
656
- // border when the consumer explicitly opts in via `bordered` or `borderDegree`.
657
- // We do NOT honor the global strong mode for these, because it would make every
658
- // filled button look outlined.
659
- variant !== "outline" && (bordered || borderDegree) && cn(
1160
+ // border when the consumer explicitly opts in via `bordered`. Global theming
1161
+ // should not outline every filled button.
1162
+ effVariant !== "outline" && bordered === true && cn(
660
1163
  "border",
661
- borderDegree ? borderColorClassForDegree(resolvedBorderDegree) : "border-muted-foreground"
1164
+ "border-muted-foreground"
662
1165
  ),
663
1166
  className
664
1167
  ),
@@ -791,9 +1294,18 @@ function Badge({
791
1294
  iconPosition = "left",
792
1295
  asChild = false,
793
1296
  children,
1297
+ style,
794
1298
  ...props
795
1299
  }) {
796
1300
  const Comp = asChild ? Slot : "span";
1301
+ const recipe = useNajmComponentStyle("badge");
1302
+ const aliased = resolveVariantAlias(
1303
+ recipe?.variants,
1304
+ variant ?? recipe?.defaultVariant ?? "default"
1305
+ );
1306
+ const effVariant = variant ?? aliased.variant ?? recipe?.defaultVariant;
1307
+ const recipeRadius = shape === void 0 ? resolveRadiusValue(recipe?.radius) : void 0;
1308
+ const recipeStyle = recipeRadius ? { borderRadius: recipeRadius, ...style } : style;
797
1309
  const resolvedColor = statusMap?.[status ?? ""] ?? color;
798
1310
  const resolvedLabel = label ?? (typeof children === "string" ? children : void 0) ?? status;
799
1311
  const content = typeof children !== "string" && children ? children : resolvedLabel ?? children;
@@ -814,6 +1326,7 @@ function Badge({
814
1326
  sizeClass,
815
1327
  className
816
1328
  ),
1329
+ style: recipeStyle,
817
1330
  ...props,
818
1331
  children: [
819
1332
  iconPosition === "left" && iconNode,
@@ -823,8 +1336,8 @@ function Badge({
823
1336
  }
824
1337
  );
825
1338
  }
826
- const classes = resolvedColor ? badgeColorVariants({ color: resolvedColor, look, size, shape }) : badgeVariants({ variant });
827
- return /* @__PURE__ */ jsxs(Comp, { "data-slot": "badge", className: cn(classes, className), ...props, children: [
1339
+ const classes = resolvedColor ? badgeColorVariants({ color: resolvedColor, look, size, shape }) : badgeVariants({ variant: effVariant });
1340
+ return /* @__PURE__ */ jsxs(Comp, { "data-slot": "badge", className: cn(classes, aliased.style?.className, className), style: recipeStyle, ...props, children: [
828
1341
  iconPosition === "left" && iconNode,
829
1342
  content,
830
1343
  iconPosition === "right" && iconNode
@@ -1136,14 +1649,13 @@ var sheetVariants = cva(
1136
1649
  }
1137
1650
  );
1138
1651
  function SheetContent({ className, portalClassName, side, children, ...props }) {
1139
- const resolvedBorderDegree = useResolvedBorderDegree();
1140
1652
  return /* @__PURE__ */ jsx(SheetPortal, { children: /* @__PURE__ */ jsxs("div", { className: portalClassName, children: [
1141
1653
  /* @__PURE__ */ jsx(SheetOverlay, {}),
1142
1654
  /* @__PURE__ */ jsxs(
1143
1655
  SheetPrimitive.Content,
1144
1656
  {
1145
1657
  "data-slot": "sheet-content",
1146
- className: cn(sheetVariants({ side }), borderColorClassForDegree(resolvedBorderDegree), className),
1658
+ className: cn(sheetVariants({ side }), className),
1147
1659
  ...props,
1148
1660
  children: [
1149
1661
  children,
@@ -1297,7 +1809,6 @@ function DialogOverlay({ className, ...props }) {
1297
1809
  }
1298
1810
  function DialogContent({ className, children, ...props }) {
1299
1811
  const portalClassName = useNPortalScope();
1300
- const resolvedBorderDegree = useResolvedBorderDegree();
1301
1812
  return /* @__PURE__ */ jsx(DialogPortal, { "data-slot": "dialog-portal", children: /* @__PURE__ */ jsxs("div", { className: portalClassName, children: [
1302
1813
  /* @__PURE__ */ jsx(DialogOverlay, {}),
1303
1814
  /* @__PURE__ */ jsxs(
@@ -1305,8 +1816,7 @@ function DialogContent({ className, children, ...props }) {
1305
1816
  {
1306
1817
  "data-slot": "dialog-content",
1307
1818
  className: cn(
1308
- "bg-card data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-sm translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-border p-6 shadow-lg duration-200",
1309
- borderColorClassForDegree(resolvedBorderDegree),
1819
+ "bg-card text-card-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-sm translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg najm-border border-border p-6 shadow-lg duration-200",
1310
1820
  className
1311
1821
  ),
1312
1822
  ...props,
@@ -2199,7 +2709,6 @@ function DropdownMenuSubContent({ className, ...props }) {
2199
2709
  }
2200
2710
  function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
2201
2711
  const container = React.useContext(NajmThemeContainerCtx);
2202
- const resolvedBorderDegree = useResolvedBorderDegree();
2203
2712
  useNajmPortalLayerStyles();
2204
2713
  return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx(
2205
2714
  DropdownMenuPrimitive.Content,
@@ -2208,7 +2717,6 @@ function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
2208
2717
  sideOffset,
2209
2718
  className: cn(
2210
2719
  "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[10000] min-w-[8rem] overflow-hidden rounded-md border border-border p-1 shadow-md",
2211
- borderColorClassForDegree(resolvedBorderDegree),
2212
2720
  className
2213
2721
  ),
2214
2722
  ...props
@@ -2279,7 +2787,6 @@ function PopoverAnchor({ ...props }) {
2279
2787
  }
2280
2788
  function PopoverContent({ className, align = "center", sideOffset = 4, ...props }) {
2281
2789
  const container = React.useContext(NajmThemeContainerCtx);
2282
- const resolvedBorderDegree = useResolvedBorderDegree();
2283
2790
  useNajmPortalLayerStyles();
2284
2791
  return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx(
2285
2792
  PopoverPrimitive.Content,
@@ -2289,7 +2796,6 @@ function PopoverContent({ className, align = "center", sideOffset = 4, ...props
2289
2796
  sideOffset,
2290
2797
  className: cn(
2291
2798
  "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[10000] w-72 origin-(--radix-popover-content-transform-origin) rounded-md border border-border p-4 shadow-md outline-none",
2292
- borderColorClassForDegree(resolvedBorderDegree),
2293
2799
  className
2294
2800
  ),
2295
2801
  ...props
@@ -2989,7 +3495,7 @@ function Avatar({
2989
3495
  children: [
2990
3496
  hasChildren ? children : hasShortcut ? /* @__PURE__ */ jsxs(Fragment, { children: [
2991
3497
  src && /* @__PURE__ */ jsx(
2992
- "img",
3498
+ AvatarPrimitive.Image,
2993
3499
  {
2994
3500
  "data-slot": "avatar-image",
2995
3501
  src,
@@ -2998,7 +3504,7 @@ function Avatar({
2998
3504
  }
2999
3505
  ),
3000
3506
  /* @__PURE__ */ jsx(
3001
- "span",
3507
+ AvatarPrimitive.Fallback,
3002
3508
  {
3003
3509
  "data-slot": "avatar-fallback",
3004
3510
  className: cn(fallbackVariants({ size, shape }), fallbackClassName),
@@ -3023,7 +3529,7 @@ function Avatar({
3023
3529
  }
3024
3530
  function AvatarImage({ className, ...props }) {
3025
3531
  return /* @__PURE__ */ jsx(
3026
- "img",
3532
+ AvatarPrimitive.Image,
3027
3533
  {
3028
3534
  "data-slot": "avatar-image",
3029
3535
  className: cn("aspect-square size-full", className),
@@ -3033,11 +3539,10 @@ function AvatarImage({ className, ...props }) {
3033
3539
  }
3034
3540
  function AvatarFallback({
3035
3541
  className,
3036
- delayMs: _delayMs,
3037
3542
  ...props
3038
3543
  }) {
3039
3544
  return /* @__PURE__ */ jsx(
3040
- "span",
3545
+ AvatarPrimitive.Fallback,
3041
3546
  {
3042
3547
  "data-slot": "avatar-fallback",
3043
3548
  className: cn("flex size-full items-center justify-center rounded-full bg-muted", className),
@@ -3867,7 +4372,6 @@ function NAvatar({
3867
4372
  const hasText = Boolean(title || subtitle || meta);
3868
4373
  const fallbackText = fallback && !title ? fallback : label ? getInitials(label) : "?";
3869
4374
  const shapeClass = SHAPE_CLASSES[shape];
3870
- const [imgLoaded, setImgLoaded] = React__default.useState(false);
3871
4375
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3", classNames?.root, className), children: [
3872
4376
  /* @__PURE__ */ jsxs(
3873
4377
  Avatar,
@@ -3879,11 +4383,10 @@ function NAvatar({
3879
4383
  {
3880
4384
  src: imageSrc,
3881
4385
  alt: alt || label,
3882
- onLoadingStatusChange: (status) => setImgLoaded(status === "loaded"),
3883
- className: cn("absolute inset-0 z-10 object-cover", classNames?.image)
4386
+ className: cn("object-cover", classNames?.image)
3884
4387
  }
3885
4388
  ),
3886
- !imgLoaded && /* @__PURE__ */ jsx(
4389
+ /* @__PURE__ */ jsx(
3887
4390
  AvatarFallback,
3888
4391
  {
3889
4392
  style: { backgroundColor: bg, color: text },
@@ -3938,18 +4441,18 @@ function NCard({
3938
4441
  noPadding = false,
3939
4442
  separator = false,
3940
4443
  bordered,
3941
- borderDegree,
3942
4444
  className,
3943
4445
  classNames,
3944
4446
  onClick
3945
4447
  }) {
3946
4448
  const isEmpty = empty ?? noData ?? false;
3947
4449
  const resolvedEmptyText = emptyText ?? noDataText ?? "No data available";
3948
- const resolvedBorderDegree = useResolvedBorderDegree({
3949
- borderDegree,
3950
- bordered,
3951
- fallback: "default"
3952
- });
4450
+ const recipe = useNajmComponentStyle("card");
4451
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
4452
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
4453
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
4454
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
4455
+ } : void 0;
3953
4456
  let actionSlot = null;
3954
4457
  let footerSlot = null;
3955
4458
  const mainChildren = [];
@@ -3968,18 +4471,16 @@ function NCard({
3968
4471
  });
3969
4472
  const hasHeader = !!(title || description || actionSlot);
3970
4473
  const iconSize = description ? "h-8 w-8" : "h-5 w-5";
3971
- const isStrong = resolvedBorderDegree === "strong";
3972
- const isNone = resolvedBorderDegree === "none";
3973
4474
  return /* @__PURE__ */ jsxs(
3974
4475
  Card,
3975
4476
  {
3976
- "data-bordered": bordered ? "true" : void 0,
3977
- "data-border-degree": resolvedBorderDegree,
4477
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
3978
4478
  onClick,
4479
+ style: recipeStyle,
3979
4480
  className: cn(
3980
4481
  "flex flex-col",
3981
4482
  !noPadding && "p-4 gap-3",
3982
- isNone ? "border-transparent" : `${borderColorClassForDegree(resolvedBorderDegree)} ${isStrong ? "shadow-none" : ""}`,
4483
+ surfaceBorderClasses(bordered),
3983
4484
  classNames?.root,
3984
4485
  className
3985
4486
  ),
@@ -4168,7 +4669,6 @@ function DefaultCard({
4168
4669
  change,
4169
4670
  onClick,
4170
4671
  bordered,
4171
- borderDegree,
4172
4672
  className,
4173
4673
  classNames
4174
4674
  }) {
@@ -4178,7 +4678,6 @@ function DefaultCard({
4178
4678
  noPadding: true,
4179
4679
  onClick,
4180
4680
  bordered,
4181
- borderDegree,
4182
4681
  className: cn(
4183
4682
  "group p-4 transition-colors",
4184
4683
  onClick && "cursor-pointer hover:border-border/60 hover:bg-accent/40",
@@ -4235,7 +4734,6 @@ function UsageCard({
4235
4734
  countLabel,
4236
4735
  onClick,
4237
4736
  bordered,
4238
- borderDegree,
4239
4737
  className,
4240
4738
  classNames
4241
4739
  }) {
@@ -4247,7 +4745,6 @@ function UsageCard({
4247
4745
  noPadding: true,
4248
4746
  onClick,
4249
4747
  bordered,
4250
- borderDegree,
4251
4748
  className: cn(
4252
4749
  "group min-h-[116px] px-4 py-4 transition-colors",
4253
4750
  onClick && "cursor-pointer hover:bg-accent/30",
@@ -4292,14 +4789,13 @@ function UsageCard({
4292
4789
  }
4293
4790
  );
4294
4791
  }
4295
- function CompactCard({ icon, label, value, unit, iconColor, onClick, bordered, borderDegree, className, classNames }) {
4792
+ function CompactCard({ icon, label, value, unit, iconColor, onClick, bordered, className, classNames }) {
4296
4793
  return /* @__PURE__ */ jsxs(
4297
4794
  NCard,
4298
4795
  {
4299
4796
  noPadding: true,
4300
4797
  onClick,
4301
4798
  bordered,
4302
- borderDegree,
4303
4799
  className: cn(
4304
4800
  !bordered && "border-0",
4305
4801
  "bg-foreground/10 p-3 shadow-none",
@@ -5118,7 +5614,7 @@ function NFolderIcon({ size = "md", className }) {
5118
5614
  return /* @__PURE__ */ jsx("span", { className: cn(dim, "inline-flex shrink-0 items-center justify-center", className), children: /* @__PURE__ */ jsx(Folder, { size: iconSize, className: "text-sky-500", fill: "currentColor", strokeWidth: 1.5 }) });
5119
5615
  }
5120
5616
  var NO_SHADE = /* @__PURE__ */ new Set(["black", "white"]);
5121
- var PRESETS = {
5617
+ var PRESETS2 = {
5122
5618
  muted: "border-muted-foreground",
5123
5619
  primary: "border-primary",
5124
5620
  accent: "border-accent",
@@ -5150,15 +5646,11 @@ var FOCUS_INTERACTIVE_BASE = "border focus-within:border-primary";
5150
5646
  var HOVER_INTERACTIVE_BASE = "hover:border-primary";
5151
5647
  var STATIC_BASE = "border";
5152
5648
  var BaseInput = React__default.forwardRef(
5153
- ({ children, variant = "default", status = "default", bordered, borderDegree, borderColor, className, disabled = false, onHover, onClick, hasIcon, ...rest }, ref) => {
5649
+ ({ children, variant = "default", status = "default", bordered, borderColor, className, disabled = false, onHover, onClick, hasIcon, ...rest }, ref) => {
5154
5650
  const isGhost = variant === "ghost";
5155
5651
  const isError = status === "error";
5156
- const resolvedBorderDegree = useResolvedBorderDegree({
5157
- borderDegree,
5158
- bordered,
5159
- fallback: "default"
5160
- });
5161
5652
  const hasExplicitColor = !!borderColor;
5653
+ const isBordered = bordered !== false;
5162
5654
  let colorClass = "";
5163
5655
  let borderClass = "";
5164
5656
  if (!isGhost) {
@@ -5166,17 +5658,17 @@ var BaseInput = React__default.forwardRef(
5166
5658
  borderClass = ERROR_BORDER;
5167
5659
  } else if (hasExplicitColor) {
5168
5660
  borderClass = `${STATIC_BASE} ${FOCUS_INTERACTIVE_BASE} ${HOVER_INTERACTIVE_BASE}`;
5169
- colorClass = PRESETS[borderColor] ?? (NO_SHADE.has(borderColor) ? `border-${borderColor}` : `border-${borderColor}-600`);
5661
+ colorClass = PRESETS2[borderColor] ?? (NO_SHADE.has(borderColor) ? `border-${borderColor}` : `border-${borderColor}-600`);
5170
5662
  } else {
5171
- const restingBorderClass = inputBorderColorClassForDegree(resolvedBorderDegree);
5172
- borderClass = resolvedBorderDegree === "default" ? `${STATIC_BASE} ${restingBorderClass} hover:border-input focus-within:border-primary/70` : `${STATIC_BASE} ${restingBorderClass} focus-within:border-primary/70`;
5663
+ const restingBorderClass = inputBorderClasses(isBordered);
5664
+ borderClass = isBordered ? `${STATIC_BASE} ${restingBorderClass} hover:border-input focus-within:border-primary/70` : restingBorderClass;
5173
5665
  }
5174
5666
  }
5175
5667
  return /* @__PURE__ */ jsx(
5176
5668
  "div",
5177
5669
  {
5178
5670
  ref,
5179
- "data-border-degree": isGhost ? void 0 : resolvedBorderDegree,
5671
+ "data-bordered": !isGhost && !isBordered ? "false" : !isGhost ? "true" : void 0,
5180
5672
  className: cn(
5181
5673
  inputVariants({ variant, status, hasIcon, disabled }),
5182
5674
  !isGhost && borderClass,
@@ -5201,33 +5693,33 @@ function resolveIcon(icon) {
5201
5693
  if (!icon) return null;
5202
5694
  return /* @__PURE__ */ jsx(NIcon, { icon, size: 16 });
5203
5695
  }
5204
- var TextInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, disabled = false, ...props }) => {
5696
+ var TextInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor, disabled = false, ...props }) => {
5205
5697
  const shouldDisplayIcon = Boolean(icon) && showIcon;
5206
5698
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5207
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2", className), disabled, children: [
5699
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), disabled, children: [
5208
5700
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5209
5701
  /* @__PURE__ */ jsx(Input, { placeholder, value, onChange: (ev) => onChange(ev.target.value), className: "p-0 border-0 shadow-none bg-transparent dark:bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 text-muted-foreground", disabled, ...props })
5210
5702
  ] });
5211
5703
  };
5212
- var NumberInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
5704
+ var NumberInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5213
5705
  const shouldDisplayIcon = Boolean(icon) && showIcon;
5214
5706
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5215
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2", className), children: [
5707
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), children: [
5216
5708
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5217
5709
  /* @__PURE__ */ jsx(Input, { type: "number", placeholder, value: value ?? "", onChange: (ev) => onChange(Number(ev.target.value)), className: "p-0 border-0 shadow-none bg-transparent dark:bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 text-muted-foreground" })
5218
5710
  ] });
5219
5711
  };
5220
- var PasswordInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
5712
+ var PasswordInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5221
5713
  const [showPassword, setShowPassword] = useState(false);
5222
5714
  const shouldDisplayIcon = Boolean(icon) && showIcon;
5223
5715
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5224
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2", className), children: [
5716
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), children: [
5225
5717
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5226
5718
  /* @__PURE__ */ jsx(Input, { type: showPassword ? "text" : "password", placeholder, value, onChange: (ev) => onChange(ev.target.value), className: "p-0 border-0 shadow-none bg-transparent dark:bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 text-muted-foreground" }),
5227
5719
  showPassword ? /* @__PURE__ */ jsx(Eye, { className: "absolute right-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground cursor-pointer", onClick: () => setShowPassword(false) }) : /* @__PURE__ */ jsx(EyeOff, { className: "absolute right-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground cursor-pointer", onClick: () => setShowPassword(true) })
5228
5720
  ] });
5229
5721
  };
5230
- var TextAreaInput = ({ value, onChange, placeholder = "", className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, rows }) => /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("items-start", className), children: /* @__PURE__ */ jsx(
5722
+ var TextAreaInput = ({ value, onChange, placeholder = "", className = "", variant = "default", status = "default", bordered, borderColor, rows }) => /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className: cn("items-start", className), children: /* @__PURE__ */ jsx(
5231
5723
  Textarea,
5232
5724
  {
5233
5725
  rows,
@@ -5244,7 +5736,7 @@ function renderItems(items) {
5244
5736
  return /* @__PURE__ */ jsx(SelectItem, { value, children: label }, value);
5245
5737
  });
5246
5738
  }
5247
- var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, iconColor, items, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, disabled = false }) => {
5739
+ var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, iconColor, items, className = "", variant = "default", status = "default", bordered, borderColor, disabled = false }) => {
5248
5740
  const shouldDisplayIcon = Boolean(icon) && showIcon && !value;
5249
5741
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5250
5742
  const displayLabel = value ? (() => {
@@ -5252,7 +5744,7 @@ var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, i
5252
5744
  return typeof found === "string" ? found : found?.label ?? value;
5253
5745
  })() : "";
5254
5746
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
5255
- /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: "pointer-events-none", children: [
5747
+ /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: "pointer-events-none", children: [
5256
5748
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5257
5749
  /* @__PURE__ */ jsx("span", { className: cn("flex-1 truncate text-sm", !displayLabel && "text-muted-foreground"), children: displayLabel || placeholder }),
5258
5750
  /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" })
@@ -5270,7 +5762,7 @@ var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, i
5270
5762
  ] }, String(value))
5271
5763
  ] });
5272
5764
  };
5273
- var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...", emptyMessage = "No results found.", value, onChange, icon, showIcon = true, iconColor, items = [], className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, disabled = false, allowFreeText = false }) => {
5765
+ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...", emptyMessage = "No results found.", value, onChange, icon, showIcon = true, iconColor, items = [], className = "", variant = "default", status = "default", bordered, borderColor, disabled = false, allowFreeText = false }) => {
5274
5766
  const [open, setOpen] = useState(false);
5275
5767
  const [query, setQuery] = useState("");
5276
5768
  const normalizedItems = items.map((item) => typeof item === "string" ? { value: item, label: item } : item);
@@ -5290,7 +5782,7 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
5290
5782
  setOpen(o);
5291
5783
  if (!o) setQuery("");
5292
5784
  }, children: [
5293
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("cursor-pointer", className), children: [
5785
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("cursor-pointer", className), children: [
5294
5786
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5295
5787
  /* @__PURE__ */ jsx("span", { className: cn("flex-1 truncate text-sm", !displayLabel && "text-muted-foreground"), children: displayLabel || placeholder }),
5296
5788
  /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })
@@ -5329,7 +5821,7 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
5329
5821
  ] }) })
5330
5822
  ] });
5331
5823
  };
5332
- var MultiSelectInput = ({ placeholder = "Select items...", value = [], onChange, icon, showIcon = true, iconColor, items, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, disabled = false, searchPlaceholder = "Search...", emptyMessage = "No items found.", maxDisplay = 3, showSearch = true }) => {
5824
+ var MultiSelectInput = ({ placeholder = "Select items...", value = [], onChange, icon, showIcon = true, iconColor, items, className = "", variant = "default", status = "default", bordered, borderColor, disabled = false, searchPlaceholder = "Search...", emptyMessage = "No items found.", maxDisplay = 3, showSearch = true }) => {
5333
5825
  const [open, setOpen] = useState(false);
5334
5826
  const shouldDisplayIcon = Boolean(icon) && showIcon && value.length === 0;
5335
5827
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
@@ -5343,7 +5835,7 @@ var MultiSelectInput = ({ placeholder = "Select items...", value = [], onChange,
5343
5835
  const displayedItems = value.slice(0, maxDisplay);
5344
5836
  const remainingCount = value.length - maxDisplay;
5345
5837
  return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
5346
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2 cursor-pointer", className, disabled && "cursor-not-allowed opacity-50"), children: [
5838
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2 cursor-pointer", className, disabled && "cursor-not-allowed opacity-50"), children: [
5347
5839
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5348
5840
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 flex-1 overflow-hidden", children: value.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: placeholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5349
5841
  displayedItems.map((itemValue) => /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "text-xs px-2 py-0.5 gap-1", children: [
@@ -5377,7 +5869,7 @@ var MultiSelectInput = ({ placeholder = "Select items...", value = [], onChange,
5377
5869
  ] });
5378
5870
  };
5379
5871
  var layoutVariants = cva("flex items-start", { variants: { layout: { column: "flex-col gap-4", row: "flex-row gap-7" } }, defaultVariants: { layout: "row" } });
5380
- var RadioGroupInput = ({ value, onChange, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, layout = "row", items }) => /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderDegree, borderColor, className, children: /* @__PURE__ */ jsx(RadioGroup2, { onValueChange: onChange, value, className: layoutVariants({ layout }), children: items.map((item) => {
5872
+ var RadioGroupInput = ({ value, onChange, className = "", variant = "default", status = "default", bordered, borderColor, layout = "row", items }) => /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className, children: /* @__PURE__ */ jsx(RadioGroup2, { onValueChange: onChange, value, className: layoutVariants({ layout }), children: items.map((item) => {
5381
5873
  const itemValue = typeof item === "string" ? item : item.value;
5382
5874
  const itemLabel = typeof item === "string" ? item : item.label;
5383
5875
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center space-y-0", children: [
@@ -5385,7 +5877,7 @@ var RadioGroupInput = ({ value, onChange, className = "", variant = "default", s
5385
5877
  /* @__PURE__ */ jsx(Label, { className: "text-sm font-normal peer-disabled:opacity-70 ml-1", children: itemLabel })
5386
5878
  ] }, itemValue);
5387
5879
  }) }) });
5388
- var CheckboxInput = ({ value, onChange, helper, label, checkboxClassName, className, variant = "default", status = "default", bordered, borderDegree, borderColor }) => /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("flex gap-2 items-center", className), children: [
5880
+ var CheckboxInput = ({ value, onChange, helper, label, checkboxClassName, className, variant = "default", status = "default", bordered, borderColor }) => /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("flex gap-2 items-center", className), children: [
5389
5881
  /* @__PURE__ */ jsx(Checkbox, { checked: value, onCheckedChange: onChange, className: cn("cursor-pointer transition-colors duration-200 border-primary", checkboxClassName) }),
5390
5882
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
5391
5883
  /* @__PURE__ */ jsx(Label, { className: "cursor-pointer text-muted-foreground", onClick: () => onChange(!value), children: label }),
@@ -5410,7 +5902,6 @@ function CheckboxGroupInput({
5410
5902
  variant = "default",
5411
5903
  status = "default",
5412
5904
  bordered,
5413
- borderDegree,
5414
5905
  borderColor,
5415
5906
  disabled = false
5416
5907
  }) {
@@ -5418,7 +5909,7 @@ function CheckboxGroupInput({
5418
5909
  const next = checked ? [...value, itemValue] : value.filter((v) => v !== itemValue);
5419
5910
  onChange(next);
5420
5911
  };
5421
- return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("flex-wrap", className), disabled, children: /* @__PURE__ */ jsx("div", { className: cn(layoutVariants2({ layout })), children: items.map((item) => {
5912
+ return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className: cn("flex-wrap", className), disabled, children: /* @__PURE__ */ jsx("div", { className: cn(layoutVariants2({ layout })), children: items.map((item) => {
5422
5913
  const itemValue = typeof item === "string" ? item : item.value;
5423
5914
  const itemLabel = typeof item === "string" ? item : item.label;
5424
5915
  const checked = value.includes(itemValue);
@@ -5435,7 +5926,7 @@ function CheckboxGroupInput({
5435
5926
  ] }, itemValue);
5436
5927
  }) }) });
5437
5928
  }
5438
- var SwitchInput = ({ value, onChange, label = "", helper, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, icon, showIcon = true, iconPosition = "label", iconColor }) => /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2 justify-between items-center", className), children: [
5929
+ var SwitchInput = ({ value, onChange, label = "", helper, className = "", variant = "default", status = "default", bordered, borderColor, icon, showIcon = true, iconPosition = "label", iconColor }) => /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2 justify-between items-center", className), children: [
5439
5930
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
5440
5931
  /* @__PURE__ */ jsxs(Label, { className: "flex items-center gap-2", children: [
5441
5932
  iconPosition === "label" && icon && showIcon && /* @__PURE__ */ jsx("span", { className: "w-4 h-4", children: resolveIcon(icon) }),
@@ -5448,10 +5939,10 @@ var SwitchInput = ({ value, onChange, label = "", helper, className = "", varian
5448
5939
  /* @__PURE__ */ jsx(Switch, { checked: value, onCheckedChange: onChange })
5449
5940
  ] })
5450
5941
  ] });
5451
- var DateInput = ({ value, onChange, placeholder = "Pick a date", className = "", icon, showIcon = true, iconColor, variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
5942
+ var DateInput = ({ value, onChange, placeholder = "Pick a date", className = "", icon, showIcon = true, iconColor, variant = "default", status = "default", bordered, borderColor }) => {
5452
5943
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5453
5944
  const toDateString = (date) => date?.toISOString().split("T")[0];
5454
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className, children: [
5945
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className, children: [
5455
5946
  /* @__PURE__ */ jsxs(Popover, { children: [
5456
5947
  /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: cn("w-full flex items-center cursor-pointer gap-2 justify-start text-left font-normal", !value && "text-foreground"), children: /* @__PURE__ */ jsx(Label, { className: "text-muted-foreground cursor-pointer", children: value ? format(typeof value === "string" ? new Date(value) : value, "PPP") : placeholder }) }) }),
5457
5948
  /* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx(Calendar, { mode: "single", selected: typeof value === "string" ? new Date(value) : value, onSelect: (date) => onChange(toDateString(date)), captionLayout: "dropdown" }) })
@@ -5466,7 +5957,7 @@ function truncateFilename(filename, maxLength = 25) {
5466
5957
  const name = extIndex !== -1 ? filename.slice(0, extIndex) : filename;
5467
5958
  return `${name.slice(0, maxLength - ext.length - 3)}...${ext}`;
5468
5959
  }
5469
- var FileInput = ({ value, onChange, placeholder = "No file chosen", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
5960
+ var FileInput = ({ value, onChange, placeholder = "No file chosen", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5470
5961
  const fileInputRef = useRef(null);
5471
5962
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5472
5963
  const displayFilename = () => {
@@ -5474,7 +5965,7 @@ var FileInput = ({ value, onChange, placeholder = "No file chosen", icon, showIc
5474
5965
  const filename = typeof value === "string" ? value.split(/[\\/]/).pop() || "" : value.name;
5475
5966
  return truncateFilename(filename);
5476
5967
  };
5477
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("flex px-0 p-0 text-muted-foreground", className), onClick: () => fileInputRef.current?.click(), children: [
5968
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("flex px-0 p-0 text-muted-foreground", className), onClick: () => fileInputRef.current?.click(), children: [
5478
5969
  /* @__PURE__ */ jsx("input", { type: "file", ref: fileInputRef, onChange: (e) => onChange(e.target.files?.[0] || null), className: "hidden" }),
5479
5970
  /* @__PURE__ */ jsxs("div", { className: "bg-muted flex h-full items-center px-3", children: [
5480
5971
  showIcon && (icon ? /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }) : /* @__PURE__ */ jsx(FileUp, { className: cn(iconProps.className) })),
@@ -5500,18 +5991,12 @@ function NUploader({
5500
5991
  listTitle = "Uploaded files",
5501
5992
  className,
5502
5993
  dropzoneClassName,
5503
- borderDegree,
5504
5994
  onFilesSelected,
5505
5995
  onCancel,
5506
5996
  onRemove
5507
5997
  }) {
5508
5998
  const inputRef = useRef(null);
5509
5999
  const [isDragging, setIsDragging] = useState(false);
5510
- const resolvedBorderDegree = useResolvedBorderDegree({
5511
- borderDegree,
5512
- fallback: "default"
5513
- });
5514
- const dropzoneBorderClass = borderColorClassForDegree(resolvedBorderDegree);
5515
6000
  const emit = useCallback(
5516
6001
  (files) => {
5517
6002
  if (!files || disabled) return;
@@ -5555,8 +6040,7 @@ function NUploader({
5555
6040
  onDragLeave,
5556
6041
  onDrop,
5557
6042
  className: cn(
5558
- "flex flex-col items-center justify-center gap-3 rounded-2xl border-2 border-dashed px-6 py-10 text-center transition-colors",
5559
- dropzoneBorderClass,
6043
+ "flex flex-col items-center justify-center gap-3 rounded-2xl border-2 border-dashed border-border px-6 py-10 text-center transition-colors",
5560
6044
  "bg-muted/40 hover:bg-muted/60",
5561
6045
  isDragging && "border-primary bg-primary/5",
5562
6046
  disabled && "cursor-not-allowed opacity-60",
@@ -5792,18 +6276,52 @@ function ImageInput({
5792
6276
  renderFileInput()
5793
6277
  ] });
5794
6278
  }
5795
- var StarRatingInput = ({ value, onChange, maxStars = 5, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
6279
+ var StarRatingInput = ({ value, onChange, maxStars = 5, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5796
6280
  const stars = Array.from({ length: maxStars }, (_, i) => /* @__PURE__ */ jsx(Star, { onClick: () => onChange(i + 1), className: cn("cursor-pointer h-8 w-8", i < value ? "fill-orange-400 text-orange-400" : "fill-[#d6d6d6] text-[#d6d6d6]") }, i));
5797
- return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2", className), children: stars });
6281
+ return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), children: stars });
5798
6282
  };
5799
6283
  var DEFAULT_COLORS = ["#222222", "#e11d48", "#ea580c", "#16a34a", "#db2777", "#2563eb", "#9333ea", "#eab308"];
5800
- var ColorArrayInput = ({ value, onChange, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, colors = DEFAULT_COLORS }) => {
6284
+ var ColorArrayInput = ({ value, onChange, className = "", variant = "default", status = "default", bordered, borderColor, colors = DEFAULT_COLORS }) => {
5801
6285
  const [selectedColor, setSelectedColor] = useState(value || "");
5802
- return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("flex flex-wrap gap-2", className), children: colors.map((color) => /* @__PURE__ */ jsx("div", { className: cn("flex h-9 w-9 items-center justify-center cursor-pointer rounded-full transition-transform hover:scale-105", selectedColor === color && "ring-2 ring-offset-2"), onClick: () => {
6286
+ return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className: cn("flex flex-wrap gap-2", className), children: colors.map((color) => /* @__PURE__ */ jsx("div", { className: cn("flex h-9 w-9 items-center justify-center cursor-pointer rounded-full transition-transform hover:scale-105", selectedColor === color && "ring-2 ring-offset-2"), onClick: () => {
5803
6287
  setSelectedColor(color);
5804
6288
  onChange(color);
5805
6289
  }, children: /* @__PURE__ */ jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-full", style: { backgroundColor: color }, children: selectedColor === color && /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-white" }) }) }, color)) });
5806
6290
  };
6291
+ var toOklch = converter("oklch");
6292
+ function parseColor(input) {
6293
+ return parse((input ?? "").trim());
6294
+ }
6295
+ function formatColor(input, format2) {
6296
+ const c = parseColor(input);
6297
+ if (!c) return input;
6298
+ switch (format2) {
6299
+ case "hex":
6300
+ return formatHex(c) ?? input;
6301
+ case "rgb":
6302
+ return formatRgb(c) ?? input;
6303
+ case "hsl":
6304
+ return formatHsl(c) ?? input;
6305
+ case "oklch": {
6306
+ const o = toOklch(c);
6307
+ if (!o) return input;
6308
+ const l = +o.l.toFixed(4);
6309
+ const ch = +(o.c ?? 0).toFixed(4);
6310
+ const h = +(o.h ?? 0).toFixed(2);
6311
+ return `oklch(${l} ${ch} ${h})`;
6312
+ }
6313
+ }
6314
+ }
6315
+ function detectFormat(input) {
6316
+ const value = (input ?? "").trim().toLowerCase();
6317
+ if (value.startsWith("oklch")) return "oklch";
6318
+ if (value.startsWith("hsl")) return "hsl";
6319
+ if (value.startsWith("rgb")) return "rgb";
6320
+ return "hex";
6321
+ }
6322
+ function toPickerHex(input) {
6323
+ return formatHex(parseColor(input) ?? parseColor("#000000")) ?? "#000000";
6324
+ }
5807
6325
  var PRESET_COLORS = [
5808
6326
  "#EF4444",
5809
6327
  "#F97316",
@@ -5826,7 +6344,14 @@ var PRESET_COLORS = [
5826
6344
  "#6B7280",
5827
6345
  "#000000"
5828
6346
  ];
5829
- function ColorPickerInput({
6347
+ var DEFAULT_FORMATS = ["hex", "rgb", "hsl", "oklch"];
6348
+ function ColorPickerInput(props) {
6349
+ if (props.mode === "popover") {
6350
+ return /* @__PURE__ */ jsx(PopoverColorPicker, { ...props });
6351
+ }
6352
+ return /* @__PURE__ */ jsx(SwatchesColorPicker, { ...props });
6353
+ }
6354
+ function SwatchesColorPicker({
5830
6355
  value = "#000000",
5831
6356
  onChange,
5832
6357
  colors = PRESET_COLORS,
@@ -5834,9 +6359,9 @@ function ColorPickerInput({
5834
6359
  variant = "default",
5835
6360
  status = "default",
5836
6361
  bordered,
5837
- borderDegree,
5838
6362
  borderColor,
5839
- disabled = false
6363
+ disabled = false,
6364
+ hideSwatches = false
5840
6365
  }) {
5841
6366
  const inputRef = useRef(null);
5842
6367
  return /* @__PURE__ */ jsxs(
@@ -5845,7 +6370,6 @@ function ColorPickerInput({
5845
6370
  variant,
5846
6371
  status,
5847
6372
  bordered,
5848
- borderDegree,
5849
6373
  borderColor,
5850
6374
  className: cn("flex-col gap-3 items-start p-3", className),
5851
6375
  disabled,
@@ -5865,14 +6389,14 @@ function ColorPickerInput({
5865
6389
  {
5866
6390
  ref: inputRef,
5867
6391
  type: "color",
5868
- value,
6392
+ value: toPickerHex(value),
5869
6393
  onChange: (e) => onChange(e.target.value),
5870
6394
  disabled,
5871
6395
  className: "sr-only"
5872
6396
  }
5873
6397
  )
5874
6398
  ] }),
5875
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: colors.map((color) => /* @__PURE__ */ jsx(
6399
+ !hideSwatches && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: colors.map((color) => /* @__PURE__ */ jsx(
5876
6400
  "button",
5877
6401
  {
5878
6402
  type: "button",
@@ -5882,7 +6406,7 @@ function ColorPickerInput({
5882
6406
  },
5883
6407
  disabled,
5884
6408
  className: cn(
5885
- "w-6 h-6 rounded-md border border-border transition-transform hover:scale-110",
6409
+ "w-6 h-6 rounded-md border border-border transition-transform hover:scale-110 cursor-pointer",
5886
6410
  value === color && "ring-2 ring-primary ring-offset-1"
5887
6411
  ),
5888
6412
  style: { backgroundColor: color },
@@ -5894,6 +6418,121 @@ function ColorPickerInput({
5894
6418
  }
5895
6419
  );
5896
6420
  }
6421
+ function PopoverColorPicker({
6422
+ value = "#000000",
6423
+ onChange,
6424
+ colors = PRESET_COLORS,
6425
+ className,
6426
+ variant = "default",
6427
+ status = "default",
6428
+ bordered,
6429
+ borderColor,
6430
+ disabled = false,
6431
+ hideSwatches = false,
6432
+ formats = DEFAULT_FORMATS,
6433
+ output = "preserve"
6434
+ }) {
6435
+ const initialFormat = formats.includes(detectFormat(value)) ? detectFormat(value) : formats[0] ?? "hex";
6436
+ const [activeFormat, setActiveFormat] = useState(initialFormat);
6437
+ const [draft, setDraft] = useState(value);
6438
+ useEffect(() => {
6439
+ setDraft(value);
6440
+ }, [value]);
6441
+ const outputFormat = output;
6442
+ const emit = (raw) => {
6443
+ if (outputFormat === "preserve") {
6444
+ onChange(raw);
6445
+ } else {
6446
+ onChange(formatColor(raw, outputFormat));
6447
+ }
6448
+ };
6449
+ const handlePickerChange = (hex) => {
6450
+ setDraft(hex);
6451
+ emit(hex);
6452
+ };
6453
+ const handleTextChange = (text) => {
6454
+ setDraft(text);
6455
+ if (parseColor(text)) emit(text);
6456
+ };
6457
+ const handleTabChange = (next) => {
6458
+ setActiveFormat(next);
6459
+ if (parseColor(draft)) setDraft(formatColor(draft, next));
6460
+ };
6461
+ const handlePreset = (color) => {
6462
+ setDraft(color);
6463
+ emit(color);
6464
+ };
6465
+ return /* @__PURE__ */ jsxs(Popover, { children: [
6466
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(
6467
+ "button",
6468
+ {
6469
+ type: "button",
6470
+ disabled,
6471
+ className: cn(
6472
+ "flex items-center gap-3 w-full rounded-md border border-border bg-background px-3 py-2 text-left cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
6473
+ status === "error" && "border-destructive",
6474
+ className
6475
+ ),
6476
+ children: [
6477
+ /* @__PURE__ */ jsx(
6478
+ "span",
6479
+ {
6480
+ className: "w-8 h-8 rounded-md border border-border shrink-0",
6481
+ style: { backgroundColor: toPickerHex(value) }
6482
+ }
6483
+ ),
6484
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground font-mono truncate", children: value })
6485
+ ]
6486
+ }
6487
+ ) }),
6488
+ /* @__PURE__ */ jsxs(PopoverContent, { className: "w-64 flex flex-col gap-3", align: "start", children: [
6489
+ /* @__PURE__ */ jsx(
6490
+ HexColorPicker,
6491
+ {
6492
+ color: toPickerHex(draft),
6493
+ onChange: handlePickerChange,
6494
+ style: { width: "100%" }
6495
+ }
6496
+ ),
6497
+ formats.length > 1 && /* @__PURE__ */ jsx("div", { className: "flex gap-1 rounded-md bg-muted p-1", children: formats.map((fmt) => /* @__PURE__ */ jsx(
6498
+ "button",
6499
+ {
6500
+ type: "button",
6501
+ onClick: () => handleTabChange(fmt),
6502
+ className: cn(
6503
+ "flex-1 rounded-sm px-1.5 py-1 text-xs font-medium uppercase cursor-pointer transition-colors",
6504
+ activeFormat === fmt ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
6505
+ ),
6506
+ children: fmt
6507
+ },
6508
+ fmt
6509
+ )) }),
6510
+ /* @__PURE__ */ jsx(
6511
+ "input",
6512
+ {
6513
+ type: "text",
6514
+ value: draft,
6515
+ onChange: (e) => handleTextChange(e.target.value),
6516
+ spellCheck: false,
6517
+ className: "w-full rounded-md border border-border bg-background px-2 py-1.5 text-sm font-mono outline-none focus-visible:ring-2 focus-visible:ring-ring"
6518
+ }
6519
+ ),
6520
+ !hideSwatches && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: colors.map((color) => /* @__PURE__ */ jsx(
6521
+ "button",
6522
+ {
6523
+ type: "button",
6524
+ onClick: () => handlePreset(color),
6525
+ className: cn(
6526
+ "w-5 h-5 rounded-md border border-border transition-transform hover:scale-110 cursor-pointer"
6527
+ ),
6528
+ style: { backgroundColor: color },
6529
+ title: color
6530
+ },
6531
+ color
6532
+ )) })
6533
+ ] })
6534
+ ] });
6535
+ }
5897
6536
  var DEFAULT_OPTIONS = [
5898
6537
  { value: 5, label: "Excellent" },
5899
6538
  { value: 4, label: "Good" },
@@ -5934,7 +6573,6 @@ function EmojiInput({
5934
6573
  variant = "default",
5935
6574
  status = "default",
5936
6575
  bordered,
5937
- borderDegree,
5938
6576
  borderColor,
5939
6577
  disabled = false
5940
6578
  }) {
@@ -5944,7 +6582,6 @@ function EmojiInput({
5944
6582
  variant,
5945
6583
  status,
5946
6584
  bordered,
5947
- borderDegree,
5948
6585
  borderColor,
5949
6586
  className: cn("gap-3 flex-wrap", className),
5950
6587
  disabled,
@@ -6016,7 +6653,6 @@ function PhoneInput({
6016
6653
  variant = "default",
6017
6654
  status = "default",
6018
6655
  bordered,
6019
- borderDegree,
6020
6656
  borderColor
6021
6657
  }) {
6022
6658
  const phoneThemeVars = {
@@ -6041,7 +6677,7 @@ function PhoneInput({
6041
6677
  "--react-international-phone-dropdown-preferred-list-divider-color": "var(--border)",
6042
6678
  "--react-international-phone-dropdown-shadow": "0 16px 40px color-mix(in oklch, var(--background), transparent 55%)"
6043
6679
  };
6044
- return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-0 overflow-visible p-0!", className), disabled, children: /* @__PURE__ */ jsx(
6680
+ return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-0 overflow-visible p-0!", className), disabled, children: /* @__PURE__ */ jsx(
6045
6681
  PhoneInput$1,
6046
6682
  {
6047
6683
  className: "w-full",
@@ -6102,7 +6738,7 @@ function PhoneInput({
6102
6738
  }
6103
6739
  ) });
6104
6740
  }
6105
- var TimeInput = ({ value = "", onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, format24 = true, showSeconds = false, disabled = false }) => {
6741
+ var TimeInput = ({ value = "", onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor, format24 = true, showSeconds = false, disabled = false }) => {
6106
6742
  const [inputValue, setInputValue] = useState(value);
6107
6743
  const [isValid, setIsValid] = useState(true);
6108
6744
  useEffect(() => {
@@ -6150,7 +6786,7 @@ var TimeInput = ({ value = "", onChange, placeholder = "", icon, showIcon = true
6150
6786
  };
6151
6787
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
6152
6788
  const currentStatus = !isValid ? "error" : status;
6153
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status: currentStatus, bordered, borderDegree, borderColor, className: cn("gap-2", className), children: [
6789
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status: currentStatus, bordered, borderColor, className: cn("gap-2", className), children: [
6154
6790
  showIcon && (icon ? /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }) : /* @__PURE__ */ jsx(Clock, { className: iconProps.className, style: iconProps.style })),
6155
6791
  /* @__PURE__ */ jsx(Input, { type: "text", placeholder: placeholder || (showSeconds ? "HH:MM:SS" : "HH:MM"), value: inputValue, onChange: (e) => handleInputChange(e.target.value), onKeyDown: (e) => {
6156
6792
  if (!/\d/.test(e.key) && !["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab"].includes(e.key)) e.preventDefault();
@@ -6579,12 +7215,11 @@ var VARIANT_PRESETS = {
6579
7215
  }
6580
7216
  };
6581
7217
  var VariantContext = createContext({ variant: "default" });
6582
- var VariantProvider = ({ variant = "default", bordered, borderDegree, children }) => /* @__PURE__ */ jsx(VariantContext.Provider, { value: { variant, bordered, borderDegree }, children });
7218
+ var VariantProvider = ({ variant = "default", bordered, children }) => /* @__PURE__ */ jsx(VariantContext.Provider, { value: { variant, bordered }, children });
6583
7219
  var useVariant = () => useContext(VariantContext).variant;
6584
7220
  var useBordered = () => useContext(VariantContext).bordered;
6585
- var useBorderDegree = () => useContext(VariantContext).borderDegree;
6586
7221
  var useVariantPreset = () => VARIANT_PRESETS[useContext(VariantContext).variant];
6587
- function NFormInner({ schema, defaultValues, onSubmit, form: externalForm, variant = "default", bordered, borderDegree, as = "form", className = "", id, devTools, children }) {
7222
+ function NFormInner({ schema, defaultValues, onSubmit, form: externalForm, variant = "default", bordered, as = "form", className = "", id, devTools, children }) {
6588
7223
  const resolver = useMemo(() => schema ? zodResolver(schema) : void 0, [schema]);
6589
7224
  const internalForm = useForm({
6590
7225
  resolver,
@@ -6616,7 +7251,7 @@ function NFormInner({ schema, defaultValues, onSubmit, form: externalForm, varia
6616
7251
  }, [form.formState.errors]);
6617
7252
  const wrapperClass = cn("flex flex-col h-full w-full gap-4", className);
6618
7253
  const submit = form.handleSubmit(onSubmit);
6619
- const inner = /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsx(VariantProvider, { variant, bordered, borderDegree, children: as === "form" ? /* @__PURE__ */ jsx("form", { id, onSubmit: submit, className: wrapperClass, autoComplete: "off", children }) : /* @__PURE__ */ jsx("div", { id, className: wrapperClass, onKeyDown: (e) => {
7254
+ const inner = /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsx(VariantProvider, { variant, bordered, children: as === "form" ? /* @__PURE__ */ jsx("form", { id, onSubmit: submit, className: wrapperClass, autoComplete: "off", children }) : /* @__PURE__ */ jsx("div", { id, className: wrapperClass, onKeyDown: (e) => {
6620
7255
  if (e.key === "Enter" && e.target.tagName !== "TEXTAREA") {
6621
7256
  e.preventDefault();
6622
7257
  void submit();
@@ -6679,7 +7314,6 @@ var FormInput = ({ name, type, formLabel, formDescription, required = false, dis
6679
7314
  const prefix = usePrefix();
6680
7315
  const preset = useVariantPreset();
6681
7316
  const contextBordered = useBordered();
6682
- const contextBorderDegree = useBorderDegree();
6683
7317
  const fieldName = prefix ? `${prefix}.${name}` : name;
6684
7318
  if (!InputComponent) return null;
6685
7319
  const getDefaultValue = () => {
@@ -6710,7 +7344,7 @@ var FormInput = ({ name, type, formLabel, formDescription, required = false, dis
6710
7344
  formLabel,
6711
7345
  required && !disabled && !readOnly && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" })
6712
7346
  ] }),
6713
- /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(InputComponent, { value: field.value ?? getDefaultValue(), onChange: handleChange, status: hasError && !isHidden ? "error" : "default", bordered: contextBordered, borderDegree: contextBorderDegree, icon: formLabel ? void 0 : icon, iconColor: formLabel ? void 0 : iconColor, disabled, readOnly, ...inputRest, className: slot.input }) }),
7347
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(InputComponent, { value: field.value ?? getDefaultValue(), onChange: handleChange, status: hasError && !isHidden ? "error" : "default", bordered: contextBordered, icon: formLabel ? void 0 : icon, iconColor: formLabel ? void 0 : iconColor, disabled, readOnly, ...inputRest, className: slot.input }) }),
6714
7348
  !hasError && !disabled && !readOnly && formDescription && /* @__PURE__ */ jsx(FormDescription, { className: slot.description, children: formDescription }),
6715
7349
  !isHidden && /* @__PURE__ */ jsx(FormMessage, { className: slot.error })
6716
7350
  ] });
@@ -7041,7 +7675,6 @@ function WizardForm({
7041
7675
  submitLabel = "Submit",
7042
7676
  variant = "default",
7043
7677
  bordered,
7044
- borderDegree,
7045
7678
  className,
7046
7679
  classNames,
7047
7680
  footerSlot
@@ -7101,7 +7734,7 @@ function WizardForm({
7101
7734
  classNames
7102
7735
  }
7103
7736
  ),
7104
- /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsx(VariantProvider, { variant, bordered, borderDegree, children: /* @__PURE__ */ jsxs(
7737
+ /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsx(VariantProvider, { variant, bordered, children: /* @__PURE__ */ jsxs(
7105
7738
  "form",
7106
7739
  {
7107
7740
  id: `step-${currentStepConfig.id}`,
@@ -7135,18 +7768,12 @@ var handler = {
7135
7768
  }
7136
7769
  };
7137
7770
  useTableStore.use = new Proxy({}, handler);
7138
- var actionButtonClass = (bordered, danger, borderClass) => cn(
7771
+ var actionButtonClass = (bordered, danger) => cn(
7139
7772
  "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors",
7140
7773
  danger ? "hover:bg-red-500/10 hover:text-red-400" : "hover:bg-muted hover:text-foreground",
7141
- bordered && `border ${borderClass ?? "border-muted-foreground"}`
7774
+ bordered && "border border-muted-foreground"
7142
7775
  );
7143
- function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButton, bordered, borderDegree }) {
7144
- const resolvedBorderDegree = useResolvedBorderDegree({
7145
- borderDegree,
7146
- bordered,
7147
- fallback: "default"
7148
- });
7149
- const borderClass = borderColorClassForDegree(resolvedBorderDegree);
7776
+ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButton, bordered }) {
7150
7777
  if (menuButton && openRowMenu) {
7151
7778
  return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center gap-1", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(
7152
7779
  "button",
@@ -7169,7 +7796,7 @@ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButto
7169
7796
  type: "button",
7170
7797
  "aria-label": "View",
7171
7798
  onClick: () => onView(row.original),
7172
- className: actionButtonClass(bordered, false, borderClass),
7799
+ className: actionButtonClass(bordered, false),
7173
7800
  children: /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5" })
7174
7801
  }
7175
7802
  ),
@@ -7179,7 +7806,7 @@ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButto
7179
7806
  type: "button",
7180
7807
  "aria-label": "Edit",
7181
7808
  onClick: () => onEdit(row.original),
7182
- className: actionButtonClass(bordered, false, borderClass),
7809
+ className: actionButtonClass(bordered, false),
7183
7810
  children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
7184
7811
  }
7185
7812
  ),
@@ -7189,7 +7816,7 @@ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButto
7189
7816
  type: "button",
7190
7817
  "aria-label": "Delete",
7191
7818
  onClick: () => onDelete(row.original),
7192
- className: actionButtonClass(bordered, true, borderClass),
7819
+ className: actionButtonClass(bordered, true),
7193
7820
  children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
7194
7821
  }
7195
7822
  )
@@ -7265,7 +7892,6 @@ var createTableStore = () => {
7265
7892
  className: "",
7266
7893
  classNames: {},
7267
7894
  bordered: void 0,
7268
- borderDegree: void 0,
7269
7895
  headerClassName: "bg-card",
7270
7896
  headerColor: "primary",
7271
7897
  showCheckbox: true,
@@ -7519,7 +8145,6 @@ function useTable() {
7519
8145
  const openRowMenu = useTableStore.use.openRowMenu();
7520
8146
  const menuButton = useTableStore.use.menuButton();
7521
8147
  const bordered = useTableStore.use.bordered();
7522
- const borderDegree = useTableStore.use.borderDegree();
7523
8148
  const CardComponent = useTableStore.use.CardComponent();
7524
8149
  const dynamicHeight = useTableStore.use.dynamicHeight();
7525
8150
  const viewMode = useTableStore.use.viewMode();
@@ -7550,14 +8175,14 @@ function useTable() {
7550
8175
  {
7551
8176
  id: "actions",
7552
8177
  header: () => isMenuActions ? null : React__default.createElement("div", { className: "flex w-full justify-start text-left" }, "Actions"),
7553
- cell: ({ row }) => React__default.createElement(TableActionCell, { row, onView, onEdit, onDelete, openRowMenu, menuButton, bordered, borderDegree }),
8178
+ cell: ({ row }) => React__default.createElement(TableActionCell, { row, onView, onEdit, onDelete, openRowMenu, menuButton, bordered }),
7554
8179
  enableSorting: false,
7555
8180
  enableHiding: false
7556
8181
  }
7557
8182
  ];
7558
8183
  }
7559
8184
  return effectiveColumns;
7560
- }, [columns, CardComponent, hasActions, onView, onEdit, onDelete, openRowMenu, menuButton, bordered, borderDegree]);
8185
+ }, [columns, CardComponent, hasActions, onView, onEdit, onDelete, openRowMenu, menuButton, bordered]);
7561
8186
  const notifyStateChange = useCallback((state) => {
7562
8187
  onStateChange?.(state);
7563
8188
  }, [onStateChange]);
@@ -7750,6 +8375,12 @@ function EditableCell({ cell, onCellEdit }) {
7750
8375
  ] });
7751
8376
  }
7752
8377
  function NTableContent({ effectiveMode }) {
8378
+ const recipe = useNajmComponentStyle("table");
8379
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
8380
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
8381
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
8382
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
8383
+ } : void 0;
7753
8384
  const table = useTableStore.use.table();
7754
8385
  const storeIsTableView = useTableStore.use.isTableView();
7755
8386
  const columns = useTableStore.use.columns();
@@ -7768,15 +8399,6 @@ function NTableContent({ effectiveMode }) {
7768
8399
  const showContent = useTableStore.use.showContent();
7769
8400
  const classNames = useTableStore.use.classNames();
7770
8401
  const bordered = useTableStore.use.bordered();
7771
- const borderDegree = useTableStore.use.borderDegree();
7772
- const resolvedBorderDegree = useResolvedBorderDegree({
7773
- borderDegree,
7774
- bordered,
7775
- fallback: "default"
7776
- });
7777
- const tableBorderClass = borderColorClassForDegree(resolvedBorderDegree);
7778
- const isStrong = resolvedBorderDegree === "strong";
7779
- const useDegreeBorder = bordered || borderDegree || resolvedBorderDegree !== "default";
7780
8402
  const showCheckbox = useTableStore.use.showCheckbox();
7781
8403
  const selectedRowId = useTableStore.use.selectedRowId();
7782
8404
  const renderSubRow = useTableStore.use.renderSubRow();
@@ -7803,16 +8425,16 @@ function NTableContent({ effectiveMode }) {
7803
8425
  NajmScroll,
7804
8426
  {
7805
8427
  axis: "both",
7806
- "data-border-degree": resolvedBorderDegree,
8428
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
7807
8429
  className: cn(
7808
8430
  "min-h-0 flex-1 overflow-hidden rounded-md bg-card",
7809
- useDegreeBorder ? `border ${tableBorderClass}` : "shadow-sm",
7810
- isStrong && "shadow-none",
8431
+ bordered === true ? surfaceBorderClasses(true) : "shadow-sm",
7811
8432
  classNames?.content
7812
8433
  ),
8434
+ style: recipeStyle,
7813
8435
  onContextMenu: handleBackgroundContextMenu,
7814
8436
  children: /* @__PURE__ */ jsxs(Table, { children: [
7815
- /* @__PURE__ */ jsx(TableHeader, { "data-ntable-table-header": true, className: cn("bg-card sticky top-0 z-10", colorStyle?.text, headerClassName, useDegreeBorder && "[&_tr]:border-border", classNames?.tableHeader), children: table.getHeaderGroups().map((hg) => /* @__PURE__ */ jsxs(TableRow, { className: cn("hover:bg-transparent", useDegreeBorder && "border-border"), children: [
8437
+ /* @__PURE__ */ jsx(TableHeader, { "data-ntable-table-header": true, className: cn("bg-card sticky top-0 z-10", colorStyle?.text, headerClassName, bordered === true && "[&_tr]:border-border", classNames?.tableHeader), children: table.getHeaderGroups().map((hg) => /* @__PURE__ */ jsxs(TableRow, { className: cn("hover:bg-transparent", bordered === true && "border-border"), children: [
7816
8438
  showCheckbox && /* @__PURE__ */ jsx(TableHead, { className: cn("w-10 text-foreground h-12 text-center", colorStyle?.bg), children: /* @__PURE__ */ jsx(
7817
8439
  Checkbox,
7818
8440
  {
@@ -7845,7 +8467,7 @@ function NTableContent({ effectiveMode }) {
7845
8467
  e.nativeEvent[ROW_CONTEXT_HANDLED] = true;
7846
8468
  onRowContextMenu(e, row.original);
7847
8469
  } : void 0,
7848
- className: cn(colorStyle?.row, classNames?.row, onRowClick && "cursor-pointer", isSelectedByRowId && "bg-primary/5 hover:bg-primary/5", useDegreeBorder && "border-border"),
8470
+ className: cn(colorStyle?.row, classNames?.row, onRowClick && "cursor-pointer", isSelectedByRowId && "bg-primary/5 hover:bg-primary/5", bordered === true && "border-border"),
7849
8471
  children: [
7850
8472
  showCheckbox && /* @__PURE__ */ jsx(TableCell, { className: "h-14 w-10 text-center", children: /* @__PURE__ */ jsx(
7851
8473
  Checkbox,
@@ -7868,7 +8490,7 @@ function NTableContent({ effectiveMode }) {
7868
8490
  },
7869
8491
  className: cn(
7870
8492
  "flex h-6 w-6 items-center justify-center rounded hover:bg-muted",
7871
- useDegreeBorder && `border ${tableBorderClass}`
8493
+ bordered === true && "border border-border"
7872
8494
  ),
7873
8495
  children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
7874
8496
  }
@@ -7889,34 +8511,32 @@ function NTableContent({ effectiveMode }) {
7889
8511
  }
7890
8512
  );
7891
8513
  }
7892
- function NDataCardShell({ row, onClick, onContextMenu, actions, children, className, showCheckbox = true, selectedRowId, openRowMenu, menuButton, bordered, borderDegree }) {
8514
+ function NDataCardShell({ row, onClick, onContextMenu, actions, children, className, showCheckbox = true, selectedRowId, openRowMenu, menuButton, bordered }) {
8515
+ const recipe = useNajmComponentStyle("table");
8516
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
8517
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
8518
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
8519
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
8520
+ } : void 0;
7893
8521
  const canExpand = row.getCanExpand();
7894
8522
  const isExpanded = canExpand && row.getIsExpanded();
7895
8523
  const isSelected = row.getIsSelected();
7896
8524
  const isHighlighted = selectedRowId != null && row.original?.id === selectedRowId;
7897
8525
  const isActive = isSelected || isHighlighted;
7898
8526
  const useMenuButton = menuButton && openRowMenu;
7899
- const resolvedBorderDegree = useResolvedBorderDegree({
7900
- borderDegree,
7901
- bordered,
7902
- fallback: "default"
7903
- });
7904
- const isStrong = resolvedBorderDegree === "strong";
7905
- const isNone = resolvedBorderDegree === "none";
7906
- const borderClass = borderColorClassForDegree(resolvedBorderDegree);
7907
8527
  return /* @__PURE__ */ jsxs(
7908
8528
  "div",
7909
8529
  {
7910
8530
  "data-row": "true",
7911
8531
  "data-row-id": row.id,
7912
- "data-border-degree": resolvedBorderDegree,
8532
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
7913
8533
  onClick,
7914
8534
  onContextMenu,
8535
+ style: recipeStyle,
7915
8536
  className: cn(
7916
8537
  "relative group w-full rounded-lg bg-card",
7917
- isNone ? "border-transparent" : `border ${borderClass}`,
7918
- isStrong && "shadow-none",
7919
- isActive && (bordered || resolvedBorderDegree !== "default" || borderDegree ? "border-primary" : "ring-2 ring-primary ring-offset-1 ring-offset-background"),
8538
+ surfaceBorderClasses(bordered),
8539
+ isActive && (bordered ? "border-primary" : "ring-2 ring-primary ring-offset-1 ring-offset-background"),
7920
8540
  onClick && "cursor-pointer",
7921
8541
  className
7922
8542
  ),
@@ -8011,7 +8631,7 @@ function NDataCardShell({ row, onClick, onContextMenu, actions, children, classN
8011
8631
  },
8012
8632
  className: cn(
8013
8633
  "absolute bottom-2 right-2 z-10 flex h-6 w-6 items-center justify-center rounded hover:bg-muted",
8014
- bordered && `border ${borderClass}`
8634
+ bordered && "border border-border"
8015
8635
  ),
8016
8636
  children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
8017
8637
  }
@@ -8048,7 +8668,6 @@ function NTableCards({ effectiveMode }) {
8048
8668
  const showContent = useTableStore.use.showContent();
8049
8669
  const classNames = useTableStore.use.classNames();
8050
8670
  const bordered = useTableStore.use.bordered();
8051
- const borderDegree = useTableStore.use.borderDegree();
8052
8671
  const renderSubRow = useTableStore.use.renderSubRow();
8053
8672
  const userGetRowCanExpand = useTableStore.use.getRowCanExpand();
8054
8673
  const handleContainerContextMenu = useCallback((e) => {
@@ -8151,7 +8770,6 @@ function NTableCards({ effectiveMode }) {
8151
8770
  openRowMenu,
8152
8771
  menuButton,
8153
8772
  bordered,
8154
- borderDegree,
8155
8773
  children: /* @__PURE__ */ jsx(
8156
8774
  CardComponent,
8157
8775
  {
@@ -8182,14 +8800,6 @@ function NTablePagination() {
8182
8800
  const setPagination = useTableStore.use.setPagination();
8183
8801
  const isPaginationControlled = useTableStore.use.isPaginationControlled();
8184
8802
  const bordered = useTableStore.use.bordered();
8185
- const borderDegree = useTableStore.use.borderDegree();
8186
- const resolvedBorderDegree = useResolvedBorderDegree({
8187
- borderDegree,
8188
- bordered,
8189
- fallback: "default"
8190
- });
8191
- const triggerBorderClass = borderColorClassForDegree(resolvedBorderDegree);
8192
- const useDegreeBorder = bordered || borderDegree || resolvedBorderDegree !== "default";
8193
8803
  if (!table || !showContent || !showPagination || viewMode === "json" || viewMode === "files") return null;
8194
8804
  const filteredRows = table.getFilteredRowModel().rows;
8195
8805
  const selectedRows = table.getFilteredSelectedRowModel().rows;
@@ -8227,8 +8837,8 @@ function NTablePagination() {
8227
8837
  /* @__PURE__ */ jsx(
8228
8838
  SelectTrigger,
8229
8839
  {
8230
- "data-border-degree": useDegreeBorder ? resolvedBorderDegree : void 0,
8231
- className: cn("h-8 w-[80px]", useDegreeBorder && triggerBorderClass),
8840
+ "data-bordered": bordered ? "true" : void 0,
8841
+ className: cn("h-8 w-[80px]", bordered && "najm-border border-border"),
8232
8842
  children: /* @__PURE__ */ jsx(SelectValue, { placeholder: pageSize })
8233
8843
  }
8234
8844
  ),
@@ -8259,28 +8869,25 @@ function NTablePagination() {
8259
8869
  function SearchFilter({ placeholder }) {
8260
8870
  const table = useTableStore.use.table();
8261
8871
  const bordered = useTableStore.use.bordered();
8262
- const borderDegree = useTableStore.use.borderDegree();
8263
8872
  if (!table) return null;
8264
8873
  const value = table.getState().globalFilter ?? "";
8265
- return /* @__PURE__ */ jsx(TextInput, { icon: Search, value, onChange: (v) => table.setGlobalFilter(v), placeholder: placeholder ?? "Search\u2026", bordered, borderDegree });
8874
+ return /* @__PURE__ */ jsx(TextInput, { icon: Search, value, onChange: (v) => table.setGlobalFilter(v), placeholder: placeholder ?? "Search\u2026", bordered });
8266
8875
  }
8267
8876
  function TextFilter({ name, placeholder }) {
8268
8877
  const table = useTableStore.use.table();
8269
8878
  const bordered = useTableStore.use.bordered();
8270
- const borderDegree = useTableStore.use.borderDegree();
8271
8879
  const column = table?.getColumn?.(name);
8272
8880
  if (!column) return null;
8273
- return /* @__PURE__ */ jsx(TextInput, { value: column.getFilterValue() ?? "", onChange: (value) => column.setFilterValue(value), placeholder, bordered, borderDegree });
8881
+ return /* @__PURE__ */ jsx(TextInput, { value: column.getFilterValue() ?? "", onChange: (value) => column.setFilterValue(value), placeholder, bordered });
8274
8882
  }
8275
8883
  function SelectFilter({ name, options, placeholder, inputType }) {
8276
8884
  const table = useTableStore.use.table();
8277
8885
  const bordered = useTableStore.use.bordered();
8278
- const borderDegree = useTableStore.use.borderDegree();
8279
8886
  const column = table?.getColumn?.(name);
8280
8887
  if (!column) return null;
8281
8888
  const allOptions = [{ value: "__clear__", label: "All" }, ...options.map((o) => typeof o === "string" ? { value: o, label: o } : o)];
8282
8889
  const InputComponent = inputType === "combobox" ? ComboboxInput : SelectInput;
8283
- return /* @__PURE__ */ jsx(InputComponent, { value: column.getFilterValue() ?? "", onChange: (value) => column.setFilterValue(value === "" || value === "__clear__" ? void 0 : value), items: allOptions, placeholder: placeholder || "Filter...", bordered, borderDegree });
8890
+ return /* @__PURE__ */ jsx(InputComponent, { value: column.getFilterValue() ?? "", onChange: (value) => column.setFilterValue(value === "" || value === "__clear__" ? void 0 : value), items: allOptions, placeholder: placeholder || "Filter...", bordered });
8284
8891
  }
8285
8892
  function defaultWrapperClass(filter) {
8286
8893
  return filter.type === "search" ? "flex-1 min-w-[160px] max-w-sm" : "w-full sm:w-40 shrink-0";
@@ -8288,7 +8895,6 @@ function defaultWrapperClass(filter) {
8288
8895
  function RenderFilter({ filter }) {
8289
8896
  const table = useTableStore.use.table();
8290
8897
  const bordered = useTableStore.use.bordered();
8291
- const borderDegree = useTableStore.use.borderDegree();
8292
8898
  if (filter.type === "search") {
8293
8899
  return /* @__PURE__ */ jsx(SearchFilter, { placeholder: filter.placeholder });
8294
8900
  }
@@ -8300,7 +8906,6 @@ function RenderFilter({ filter }) {
8300
8906
  onChange: filter.onChange,
8301
8907
  placeholder: filter.placeholder,
8302
8908
  bordered,
8303
- borderDegree,
8304
8909
  className: "w-full"
8305
8910
  }
8306
8911
  );
@@ -8314,7 +8919,6 @@ function RenderFilter({ filter }) {
8314
8919
  onChange: filter.onChange,
8315
8920
  placeholder: filter.placeholder,
8316
8921
  bordered,
8317
- borderDegree,
8318
8922
  className: "w-full"
8319
8923
  }
8320
8924
  );
@@ -8333,7 +8937,6 @@ function RenderFilter({ filter }) {
8333
8937
  showIcon: true,
8334
8938
  disabled: filter.disabled,
8335
8939
  bordered,
8336
- borderDegree,
8337
8940
  className: "w-full"
8338
8941
  }
8339
8942
  );
@@ -8349,7 +8952,6 @@ function RenderFilter({ filter }) {
8349
8952
  showIcon: true,
8350
8953
  disabled: filter.disabled,
8351
8954
  bordered,
8352
- borderDegree,
8353
8955
  className: "w-full"
8354
8956
  }
8355
8957
  );
@@ -8378,12 +8980,6 @@ function TableAddButton() {
8378
8980
  const addButtonText = useTableStore.use.addButtonText();
8379
8981
  const headerColor = useTableStore.use.headerColor();
8380
8982
  const bordered = useTableStore.use.bordered();
8381
- const borderDegree = useTableStore.use.borderDegree();
8382
- const resolvedBorderDegree = useResolvedBorderDegree({
8383
- borderDegree,
8384
- bordered,
8385
- fallback: "default"
8386
- });
8387
8983
  if (!showAddButton) return null;
8388
8984
  const accentHex = headerColor ? HEADER_HEX[headerColor] : void 0;
8389
8985
  const btnStyle = accentHex ? { backgroundColor: accentHex } : void 0;
@@ -8397,7 +8993,7 @@ function TableAddButton() {
8397
8993
  style: btnStyle,
8398
8994
  "aria-label": addButtonText || "Create",
8399
8995
  title: addButtonText || "Create",
8400
- "data-border-degree": bordered ? resolvedBorderDegree : void 0,
8996
+ "data-bordered": bordered ? "true" : void 0,
8401
8997
  className: `h-10 w-10 shrink-0 cursor-pointer flex items-center justify-center rounded-lg text-white transition-opacity ${baseCls} ${borderedCls}`,
8402
8998
  children: /* @__PURE__ */ jsx(Plus, { className: "h-5 w-5" })
8403
8999
  }
@@ -8414,7 +9010,6 @@ function TableSettingsMenu() {
8414
9010
  const cardComponent = useTableStore.use.CardComponent();
8415
9011
  const table = useTableStore.use.table();
8416
9012
  const bordered = useTableStore.use.bordered();
8417
- const borderDegree = useTableStore.use.borderDegree();
8418
9013
  if (!showViewToggle && !showColumnVisibility) return null;
8419
9014
  const allModes = ["table", "cards", "json", "files"];
8420
9015
  const filteredModes = availableModes ?? allModes;
@@ -8433,7 +9028,7 @@ function TableSettingsMenu() {
8433
9028
  const hasModes = modeItems.length > 0;
8434
9029
  const hasColumns = columns.length > 0;
8435
9030
  return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
8436
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(BaseInput, { "aria-label": "Table settings", className: "w-auto cursor-pointer px-3", bordered, borderDegree, children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-4 w-4 shrink-0 text-muted-foreground" }) }) }),
9031
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(BaseInput, { "aria-label": "Table settings", className: "w-auto cursor-pointer px-3", bordered, children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-4 w-4 shrink-0 text-muted-foreground" }) }) }),
8437
9032
  /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56 bg-card", children: [
8438
9033
  showViewToggle && hasModes && /* @__PURE__ */ jsxs(Fragment, { children: [
8439
9034
  /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex items-center gap-2", children: [
@@ -8759,7 +9354,6 @@ function NTable(props) {
8759
9354
  className: props.className ?? "",
8760
9355
  classNames: props.classNames ?? {},
8761
9356
  bordered: props.bordered,
8762
- borderDegree: props.borderDegree,
8763
9357
  headerClassName: props.headerClassName ?? "bg-card",
8764
9358
  headerColor: props.headerColor ?? "primary",
8765
9359
  showCheckbox: props.showCheckbox ?? true,
@@ -9195,7 +9789,7 @@ function NSmartPasteDialog({
9195
9789
  function NSidebarHeader({ children, collapsed, className, classNames }) {
9196
9790
  if (!children) return null;
9197
9791
  return /* @__PURE__ */ jsx("div", { className: cn(
9198
- "flex items-center h-14 min-h-14 px-4 border-b border-border/70 shrink-0 gap-2 justify-start",
9792
+ "flex items-center h-14 min-h-14 px-4 border-b border-sidebar-border/70 shrink-0 gap-2 justify-start",
9199
9793
  classNames?.sidebarHeader,
9200
9794
  className
9201
9795
  ), children });
@@ -9208,8 +9802,7 @@ function NSidebarLogo({
9208
9802
  collapsed = false
9209
9803
  }) {
9210
9804
  if (!icon && !title && !subtitle) return null;
9211
- const IconNode = React__default.isValidElement(icon) ? icon : typeof icon === "function" || typeof icon === "object" && icon !== null && "$$typeof" in icon ? React__default.createElement(icon, { className: "h-6 w-6 text-primary" }) : icon;
9212
- const collapsedCenter = collapsed ? { marginLeft: "calc(var(--rail, 4rem) / 2 - 2.25rem)" } : void 0;
9805
+ const IconNode = React__default.isValidElement(icon) ? icon : typeof icon === "function" || typeof icon === "object" && icon !== null && "$$typeof" in icon ? React__default.createElement(icon, { className: "h-6 w-6 text-sidebar-primary" }) : icon;
9213
9806
  return /* @__PURE__ */ jsxs(
9214
9807
  "button",
9215
9808
  {
@@ -9223,14 +9816,16 @@ function NSidebarLogo({
9223
9816
  IconNode && /* @__PURE__ */ jsx(
9224
9817
  "div",
9225
9818
  {
9226
- className: "size-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0",
9227
- style: collapsedCenter,
9819
+ className: cn(
9820
+ "size-10 rounded-lg bg-sidebar-primary/10 flex items-center justify-center shrink-0",
9821
+ collapsed && "ml-[calc((var(--rail,4rem)-var(--sidebar-edge-width,0px))/2-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem))]"
9822
+ ),
9228
9823
  children: IconNode
9229
9824
  }
9230
9825
  ),
9231
9826
  !collapsed && (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col ", children: [
9232
- title && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-foreground leading-tight truncate", children: title }),
9233
- subtitle && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground leading-tight truncate", children: subtitle })
9827
+ title && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-sidebar-foreground leading-tight truncate", children: title }),
9828
+ subtitle && /* @__PURE__ */ jsx("span", { className: "text-xs text-sidebar-foreground/60 leading-tight truncate", children: subtitle })
9234
9829
  ] })
9235
9830
  ]
9236
9831
  }
@@ -9265,8 +9860,8 @@ function NSidebarItem({
9265
9860
  const baseClasses = cn(
9266
9861
  "flex items-center gap-3 w-full rounded-md text-sm px-2 font-medium transition-colors h-8 text-left",
9267
9862
  depth > 0 && "pl-7",
9268
- collapsed && "pl-[calc(var(--rail,4rem)/2_-_1.5rem)]",
9269
- item.disabled ? "opacity-50 cursor-not-allowed" : active ? "cursor-pointer bg-primary text-primary-foreground" : "cursor-pointer text-muted-foreground hover:bg-accent hover:text-accent-foreground",
9863
+ collapsed && "pl-[calc((var(--rail,4rem)-var(--sidebar-edge-width,0px))/2-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem)-var(--spacing,0.25rem))]",
9864
+ item.disabled ? "opacity-50 cursor-not-allowed" : active ? "cursor-pointer bg-sidebar-primary text-sidebar-primary-foreground" : "cursor-pointer text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
9270
9865
  classNames?.sidebarItem
9271
9866
  );
9272
9867
  const handleClick = () => {
@@ -9351,10 +9946,10 @@ function NSidebarSection({
9351
9946
  "data-sidebar-section": true,
9352
9947
  className: cn(
9353
9948
  "flex flex-col gap-1",
9354
- showSectionSeparators && !isFirst && "border-t border-border/70 pt-3"
9949
+ showSectionSeparators && !isFirst && "border-t border-sidebar-border/70 pt-3"
9355
9950
  ),
9356
9951
  children: [
9357
- showSectionLabels && group.sectionLabel && (collapsed ? /* @__PURE__ */ jsx("div", { className: "h-5" }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 h-5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: [
9952
+ showSectionLabels && group.sectionLabel && (collapsed ? /* @__PURE__ */ jsx("div", { className: "h-5" }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 h-5 text-[11px] font-semibold uppercase tracking-wider text-sidebar-foreground/60", children: [
9358
9953
  showSectionIcons && group.sectionIcon && /* @__PURE__ */ jsx(group.sectionIcon, { className: "h-3.5 w-3.5 shrink-0" }),
9359
9954
  /* @__PURE__ */ jsx("span", { children: group.sectionLabel })
9360
9955
  ] })),
@@ -9385,9 +9980,10 @@ function NSidebarContent({
9385
9980
  showSectionLabels,
9386
9981
  showSectionIcons,
9387
9982
  showSectionSeparators,
9983
+ contentStyle,
9388
9984
  classNames
9389
9985
  }) {
9390
- return /* @__PURE__ */ jsx(NajmScroll, { axis: "y", className: "flex-1", children: /* @__PURE__ */ jsx("nav", { className: "flex flex-col gap-3 px-4 py-2", children: groups.map((group, gi) => /* @__PURE__ */ jsx(
9986
+ return /* @__PURE__ */ jsx(NajmScroll, { axis: "y", className: "flex-1", children: /* @__PURE__ */ jsx("nav", { className: "flex flex-col gap-3 px-4 py-2", style: contentStyle, children: groups.map((group, gi) => /* @__PURE__ */ jsx(
9391
9987
  NSidebarSection,
9392
9988
  {
9393
9989
  group,
@@ -9413,7 +10009,7 @@ function DefaultFooter({
9413
10009
  collapsed = false
9414
10010
  }) {
9415
10011
  if (!onSettings && !onLogout) return null;
9416
- const itemClass = "flex h-8 w-full cursor-pointer items-center gap-3 rounded-md px-2 text-left text-sm font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors";
10012
+ const itemClass = "flex h-8 w-full cursor-pointer items-center gap-3 rounded-md px-2 text-left text-sm font-medium text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground transition-colors";
9417
10013
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
9418
10014
  onSettings && /* @__PURE__ */ jsxs("button", { type: "button", onClick: onSettings, className: itemClass, "aria-label": settingsLabel, title: settingsLabel, children: [
9419
10015
  /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4 shrink-0" }),
@@ -9445,7 +10041,7 @@ function NSidebarFooter({
9445
10041
  const showCollapseInFooter = showCollapseButton && !isMobile;
9446
10042
  const CollapseIcon = collapsed ? PanelLeftOpen : PanelLeftClose;
9447
10043
  if (!footerContent && !showCollapseInFooter) return null;
9448
- return /* @__PURE__ */ jsxs("div", { className: cn("border-t border-border/70 px-4 py-2 shrink-0 flex flex-col gap-1", classNames?.sidebarFooter, className), children: [
10044
+ return /* @__PURE__ */ jsxs("div", { className: cn("border-t border-sidebar-border/70 px-4 py-2 shrink-0 flex flex-col gap-1", classNames?.sidebarFooter, className), children: [
9449
10045
  footerContent,
9450
10046
  showCollapseInFooter && /* @__PURE__ */ jsxs(
9451
10047
  "button",
@@ -9453,7 +10049,7 @@ function NSidebarFooter({
9453
10049
  type: "button",
9454
10050
  onClick: onToggleCollapsed,
9455
10051
  className: cn(
9456
- "flex items-center w-full cursor-pointer rounded-md text-sm font-medium transition-colors h-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
10052
+ "flex items-center w-full cursor-pointer rounded-md text-sm font-medium transition-colors h-8 text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
9457
10053
  "gap-3 px-2 text-left"
9458
10054
  ),
9459
10055
  "aria-label": collapsed ? expandLabel : collapseLabel,
@@ -9477,18 +10073,9 @@ function NSidebarMobile({
9477
10073
  hamburgerClassName,
9478
10074
  showHamburgerButton = true,
9479
10075
  children,
9480
- bordered,
9481
- borderDegree
10076
+ bordered
9482
10077
  }) {
9483
10078
  const mobileClass = mobileBreakpoint === "sm" ? "sm:hidden" : mobileBreakpoint === "lg" ? "lg:hidden" : "md:hidden";
9484
- const resolvedBorderDegree = useResolvedBorderDegree({
9485
- borderDegree,
9486
- bordered,
9487
- fallback: "default"
9488
- });
9489
- const isStrong = resolvedBorderDegree === "strong";
9490
- const isNone = resolvedBorderDegree === "none";
9491
- const mobileBorderClass = isNone ? "border-transparent" : borderColorClassForDegree(resolvedBorderDegree);
9492
10079
  return /* @__PURE__ */ jsxs(Fragment, { children: [
9493
10080
  showHamburgerButton && /* @__PURE__ */ jsx(
9494
10081
  "button",
@@ -9496,7 +10083,7 @@ function NSidebarMobile({
9496
10083
  type: "button",
9497
10084
  onClick: onOpen,
9498
10085
  className: cn(
9499
- "fixed top-3 left-3 z-50 p-2 rounded-lg bg-card border shadow-md text-muted-foreground hover:text-foreground hover:bg-accent transition-colors",
10086
+ "fixed top-3 left-3 z-50 p-2 rounded-lg bg-sidebar najm-border border-sidebar-border shadow-md text-sidebar-foreground hover:text-sidebar-accent-foreground hover:bg-sidebar-accent transition-colors",
9500
10087
  mobileClass,
9501
10088
  hamburgerClassName,
9502
10089
  open && "hidden"
@@ -9516,11 +10103,10 @@ function NSidebarMobile({
9516
10103
  /* @__PURE__ */ jsxs(
9517
10104
  "aside",
9518
10105
  {
9519
- "data-border-degree": resolvedBorderDegree,
10106
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
9520
10107
  className: cn(
9521
- "fixed inset-y-0 left-0 z-50 bg-card flex flex-col transition-transform duration-200",
9522
- // When global strong is on, we want a strong border, not a soft `border-r` edge.
9523
- isStrong ? `border ${mobileBorderClass} shadow-none` : isNone ? "border-transparent" : `border-r ${mobileBorderClass}`,
10108
+ "fixed inset-y-0 left-0 z-50 bg-sidebar text-sidebar-foreground flex flex-col transition-transform duration-200",
10109
+ sidebarBorderClasses(bordered, "right"),
9524
10110
  mobileClass,
9525
10111
  open ? "translate-x-0" : "-translate-x-full"
9526
10112
  ),
@@ -9531,7 +10117,7 @@ function NSidebarMobile({
9531
10117
  {
9532
10118
  type: "button",
9533
10119
  onClick: onClose,
9534
- className: "absolute top-3 right-3 z-10 p-1 rounded-md hover:bg-accent text-muted-foreground",
10120
+ className: "absolute top-3 right-3 z-10 p-1 rounded-md hover:bg-sidebar-accent text-sidebar-foreground/70",
9535
10121
  "aria-label": closeLabel,
9536
10122
  children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
9537
10123
  }
@@ -9567,12 +10153,11 @@ function NSidebar({
9567
10153
  defaultCollapsed = false,
9568
10154
  onCollapsedChange,
9569
10155
  showCollapseButton = true,
9570
- collapseButtonPosition = "footer",
9571
- showSectionLabels = true,
10156
+ collapseButtonPosition = "rail",
10157
+ showSectionLabels,
9572
10158
  showSectionIcons = true,
9573
- showSectionSeparators = false,
10159
+ showSectionSeparators,
9574
10160
  bordered,
9575
- borderDegree,
9576
10161
  footer,
9577
10162
  className,
9578
10163
  classNames,
@@ -9597,6 +10182,7 @@ function NSidebar({
9597
10182
  logoutLabel,
9598
10183
  widths
9599
10184
  }) {
10185
+ const recipe = useNajmComponentStyle("sidebar");
9600
10186
  const [_mobileOpen, _setMobileOpen] = useState(defaultMobileOpen);
9601
10187
  const [_collapsed, _setCollapsed] = useState(defaultCollapsed);
9602
10188
  const isControlled = mobileOpenProp !== void 0;
@@ -9606,30 +10192,68 @@ function NSidebar({
9606
10192
  if (!isControlled) _setMobileOpen(open);
9607
10193
  onMobileOpenChange?.(open);
9608
10194
  };
9609
- const handleToggleCollapsed = useCallback(() => {
9610
- const next = !collapsed;
10195
+ const [railDragging, setRailDragging] = useState(false);
10196
+ const suppressRailClickRef = useRef(false);
10197
+ const setCollapsedState = useCallback((next) => {
10198
+ if (next === collapsed) return;
9611
10199
  if (collapsedProp === void 0) _setCollapsed(next);
9612
10200
  onCollapsedChange?.(next);
9613
10201
  }, [collapsed, collapsedProp, onCollapsedChange]);
10202
+ const handleToggleCollapsed = useCallback(() => {
10203
+ setCollapsedState(!collapsed);
10204
+ }, [collapsed, setCollapsedState]);
10205
+ const handleRailPointerDown = useCallback((e) => {
10206
+ if (e.button !== 0) return;
10207
+ const startX = e.clientX;
10208
+ const startCollapsed = collapsed;
10209
+ const threshold = 24;
10210
+ let resolved = false;
10211
+ setRailDragging(true);
10212
+ const onMove = (ev) => {
10213
+ const dx = ev.clientX - startX;
10214
+ if (!resolved && !startCollapsed && dx < -threshold) {
10215
+ resolved = true;
10216
+ suppressRailClickRef.current = true;
10217
+ setCollapsedState(true);
10218
+ } else if (!resolved && startCollapsed && dx > threshold) {
10219
+ resolved = true;
10220
+ suppressRailClickRef.current = true;
10221
+ setCollapsedState(false);
10222
+ }
10223
+ };
10224
+ const onUp = (ev) => {
10225
+ window.removeEventListener("pointermove", onMove);
10226
+ window.removeEventListener("pointerup", onUp);
10227
+ setRailDragging(false);
10228
+ if (resolved || Math.abs(ev.clientX - startX) >= 4) suppressRailClickRef.current = true;
10229
+ };
10230
+ window.addEventListener("pointermove", onMove);
10231
+ window.addEventListener("pointerup", onUp);
10232
+ }, [collapsed, setCollapsedState]);
10233
+ const handleRailClick = useCallback(() => {
10234
+ if (suppressRailClickRef.current) {
10235
+ suppressRailClickRef.current = false;
10236
+ return;
10237
+ }
10238
+ handleToggleCollapsed();
10239
+ }, [handleToggleCollapsed]);
9614
10240
  const handleNavigate = useCallback((href) => {
9615
10241
  onNavigate?.(href);
9616
10242
  if (closeOnNavigate) setMobileOpen(false);
9617
10243
  }, [onNavigate, closeOnNavigate]);
9618
10244
  const groups = useMemo(() => buildGroups(navItems), [navItems]);
9619
- const resolvedBorderDegree = useResolvedBorderDegree({
9620
- borderDegree,
9621
- bordered,
9622
- fallback: "default"
9623
- });
9624
- const sidebarShellBorderClass = borderColorClassForDegree(resolvedBorderDegree);
9625
- const isStrong = resolvedBorderDegree === "strong";
9626
- const isNone = resolvedBorderDegree === "none";
9627
10245
  const desktopClass = mobileBreakpoint === "sm" ? "hidden sm:flex" : mobileBreakpoint === "lg" ? "hidden lg:flex" : "hidden md:flex";
9628
10246
  const expandedWidth = widths?.expanded ?? 240;
9629
10247
  const collapsedWidth = widths?.collapsed ?? 64;
9630
10248
  const mobileWidth = widths?.mobile ?? expandedWidth;
9631
10249
  const railVar = typeof collapsedWidth === "number" ? `${collapsedWidth}px` : collapsedWidth;
10250
+ const sidebarEdgeWidth = bordered === false ? "0px" : recipe?.borderWidth ?? "var(--border-width, 1px)";
9632
10251
  const showEdgeCollapse = showCollapseButton && collapseButtonPosition === "edge";
10252
+ const showRailCollapse = showCollapseButton && collapseButtonPosition === "rail";
10253
+ const effectiveShowSectionLabels = showSectionLabels ?? recipe?.showSectionLabels ?? true;
10254
+ const effectiveShowSectionSeparators = showSectionSeparators ?? recipe?.showSectionSeparators ?? false;
10255
+ const contentSlot = recipe?.slots?.content;
10256
+ const contentStyle = contentSlot?.paddingTop ? { paddingTop: contentSlot.paddingTop } : void 0;
9633
10257
  const defaultLogoContent = logoIcon || logoTitle || logoSubtitle ? /* @__PURE__ */ jsx(NSidebarLogo, { icon: logoIcon, title: logoTitle, subtitle: logoSubtitle, onClick: onLogoClick, collapsed }) : null;
9634
10258
  const headerContent = logo ?? defaultLogoContent;
9635
10259
  const contentProps = {
@@ -9639,9 +10263,10 @@ function NSidebar({
9639
10263
  onNavigate: handleNavigate,
9640
10264
  linkComponent,
9641
10265
  collapsed,
9642
- showSectionLabels,
10266
+ showSectionLabels: effectiveShowSectionLabels,
9643
10267
  showSectionIcons,
9644
- showSectionSeparators,
10268
+ showSectionSeparators: effectiveShowSectionSeparators,
10269
+ contentStyle,
9645
10270
  classNames
9646
10271
  };
9647
10272
  const footerProps = {
@@ -9681,25 +10306,44 @@ function NSidebar({
9681
10306
  hamburgerClassName,
9682
10307
  showHamburgerButton,
9683
10308
  bordered,
9684
- borderDegree,
9685
10309
  children: mobileInner
9686
10310
  }
9687
10311
  ),
9688
10312
  /* @__PURE__ */ jsxs(
9689
10313
  "aside",
9690
10314
  {
9691
- "data-border-degree": resolvedBorderDegree,
10315
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
9692
10316
  className: cn(
9693
10317
  desktopClass,
9694
- "relative z-10 flex flex-col h-full bg-card transition-all duration-200",
9695
- isNone ? "border-r border-transparent" : cn("border-r", sidebarShellBorderClass),
9696
- isStrong && "shadow-none",
10318
+ "relative z-10 flex flex-col h-full bg-sidebar text-sidebar-foreground transition-all duration-200",
10319
+ sidebarBorderClasses(bordered, "right"),
9697
10320
  classNames?.sidebar,
9698
10321
  className
9699
10322
  ),
9700
- style: { width: collapsed ? collapsedWidth : expandedWidth, ["--rail"]: railVar },
10323
+ style: {
10324
+ width: collapsed ? collapsedWidth : expandedWidth,
10325
+ ["--rail"]: railVar,
10326
+ ["--sidebar-edge-width"]: sidebarEdgeWidth,
10327
+ ...bordered !== false && recipe?.borderWidth ? { borderRightWidth: recipe.borderWidth } : {}
10328
+ },
9701
10329
  children: [
9702
10330
  sidebarInner,
10331
+ showRailCollapse && /* @__PURE__ */ jsxs(
10332
+ "button",
10333
+ {
10334
+ type: "button",
10335
+ "aria-label": collapsed ? expandLabel : collapseLabel,
10336
+ title: collapsed ? expandLabel : collapseLabel,
10337
+ "data-dragging": railDragging ? "true" : void 0,
10338
+ onPointerDown: handleRailPointerDown,
10339
+ onClick: handleRailClick,
10340
+ className: "group/rail absolute inset-y-0 right-0 z-20 flex w-3 translate-x-1/2 cursor-ew-resize touch-none select-none items-center justify-center border-0 bg-transparent p-0",
10341
+ children: [
10342
+ /* @__PURE__ */ jsx("span", { className: "absolute inset-y-0 right-1/2 w-0.5 translate-x-1/2 bg-sidebar-ring opacity-0 transition-opacity duration-150 group-hover/rail:opacity-100 group-data-[dragging=true]/rail:opacity-100" }),
10343
+ /* @__PURE__ */ jsx("span", { className: "relative h-9 w-1 rounded-full bg-sidebar-border transition-all duration-150 group-hover/rail:h-12 group-hover/rail:bg-sidebar-ring group-data-[dragging=true]/rail:bg-sidebar-ring" })
10344
+ ]
10345
+ }
10346
+ ),
9703
10347
  showEdgeCollapse && /* @__PURE__ */ jsx(
9704
10348
  "button",
9705
10349
  {
@@ -9707,7 +10351,7 @@ function NSidebar({
9707
10351
  onClick: handleToggleCollapsed,
9708
10352
  "aria-label": collapsed ? expandLabel : collapseLabel,
9709
10353
  title: collapsed ? expandLabel : collapseLabel,
9710
- className: "absolute right-0 top-7 z-20 flex size-6 -translate-y-1/2 translate-x-1/2 cursor-pointer items-center justify-center rounded-full border border-border bg-card text-muted-foreground shadow-sm transition-colors hover:bg-accent hover:text-foreground",
10354
+ className: "absolute right-0 top-7 z-20 flex size-6 -translate-y-1/2 translate-x-1/2 cursor-pointer items-center justify-center rounded-full border border-sidebar-border bg-sidebar text-sidebar-foreground shadow-sm transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
9711
10355
  children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronLeft, { className: "h-3.5 w-3.5" })
9712
10356
  }
9713
10357
  )
@@ -9935,6 +10579,29 @@ function NCommandPalette({
9935
10579
  ] })
9936
10580
  ] });
9937
10581
  }
10582
+ function NPageLayout({
10583
+ as: Comp = "main",
10584
+ className,
10585
+ style,
10586
+ ...props
10587
+ }) {
10588
+ const { layout } = useNajmDesign();
10589
+ const pageGutter = layout?.pageGutter ?? "var(--page-gutter, 24px)";
10590
+ const sectionGap = layout?.sectionGap ?? "var(--section-gap, 20px)";
10591
+ return /* @__PURE__ */ jsx(
10592
+ Comp,
10593
+ {
10594
+ className: cn("flex min-w-0 flex-col", className),
10595
+ style: {
10596
+ gap: sectionGap,
10597
+ paddingInline: pageGutter,
10598
+ paddingBlock: sectionGap,
10599
+ ...style
10600
+ },
10601
+ ...props
10602
+ }
10603
+ );
10604
+ }
9938
10605
  function NPageHeaderActions({ children, className }) {
9939
10606
  return /* @__PURE__ */ jsx("div", { className: cn("flex shrink-0 items-center gap-2 sm:gap-3", className), children });
9940
10607
  }
@@ -9954,11 +10621,12 @@ function getSlotElements(children, slot) {
9954
10621
  const matches = React__default.Children.toArray(children).filter((child) => isPageHeaderSlot(child, slot));
9955
10622
  return matches.length > 0 ? matches : void 0;
9956
10623
  }
9957
- function NPageHeader({ icon: Icon2, title, subtitle, actions, filters, top, search, children, className, headerClassName, bordered, borderDegree }) {
10624
+ function NPageHeader({ icon: Icon2, title, subtitle, actions, filters, top, search, children, className, headerClassName, card, bordered }) {
9958
10625
  const [internalSearch, setInternalSearch] = useState("");
10626
+ const recipe = useNajmComponentStyle("pageHeader");
9959
10627
  const searchValue = search?.value ?? internalSearch;
9960
10628
  const handleSearchChange = useCallback((e) => {
9961
- setInternalSearch(e.target.value);
10629
+ setInternalSearch(e.currentTarget.value);
9962
10630
  search?.onChange?.(e);
9963
10631
  }, [search?.onChange]);
9964
10632
  const slottedActions = getSlotElements(children, NPageHeaderActions);
@@ -9967,21 +10635,21 @@ function NPageHeader({ icon: Icon2, title, subtitle, actions, filters, top, sear
9967
10635
  const resolvedActions = slottedActions ?? actions;
9968
10636
  const resolvedFilters = slottedFilters ?? filters;
9969
10637
  const resolvedTop = slottedTop ?? top;
9970
- const resolvedBorderDegree = useResolvedBorderDegree({
9971
- borderDegree,
9972
- bordered,
9973
- fallback: "default"
9974
- });
9975
- const hasBorderShell = bordered || Boolean(borderDegree) || resolvedBorderDegree !== "default";
9976
- const isStrong = resolvedBorderDegree === "strong";
10638
+ const isCard = card ?? recipe?.card ?? bordered === true;
10639
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
10640
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
10641
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
10642
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
10643
+ } : void 0;
9977
10644
  return /* @__PURE__ */ jsxs(
9978
10645
  "div",
9979
10646
  {
9980
10647
  "data-slot": "page-header",
9981
- "data-border-degree": hasBorderShell ? resolvedBorderDegree : void 0,
10648
+ "data-card": isCard ? "true" : void 0,
10649
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
10650
+ style: recipeStyle,
9982
10651
  className: cn(
9983
- hasBorderShell ? cn("border rounded-xl bg-card shadow-none", borderColorClassForDegree(resolvedBorderDegree)) : "border-b border-border",
9984
- isStrong && "shadow-none",
10652
+ isCard ? cn("rounded-xl bg-card shadow-none", surfaceBorderClasses(true)) : cn("border-b", surfaceBorderClasses(true, "bottom").replace("najm-border-b", "najm-border-b")),
9985
10653
  className
9986
10654
  ),
9987
10655
  children: [
@@ -10044,4 +10712,4 @@ function NInspectorSheet({ open, onClose, title, children }) {
10044
10712
  ] }) });
10045
10713
  }
10046
10714
 
10047
- export { Alert, NCard as AsyncCard, Avatar, AvatarFallback, AvatarGroup, AvatarImage, AvatarStatus, Badge, BaseInput, Button, Calendar, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxGroupInput, CheckboxInput, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, ColorArrayInput, ColorPickerInput, Combobox, ComboboxInput, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, DateInput, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DynamicArray_default as DynamicArray, EmojiInput, FileImportButton, FileInput, Form, FormControl, FormDescription, FormField, FormInput, FormItem, FormLabel, FormMessage, IconButton, ImageInput, Indicator, Input, Label, LangInput, MultiSelectInput, NAlert, NAppShell, NCard as NAsyncCard, NAvatar, NBadge, NBulkActionsBar, NButton, NCard, NCardAction, NCardFooter, NCommandPalette, NConfirmDialog, NContextMenu, NDataCardShell, NDeleteDialog, NDeleteDialogContent, NDetailCard, NDetailItem, NDetailList, NDialog, NEmptyState, NErrorBoundary, NErrorState, NFileBrowser, NFileTypeIcon, NFilterBar, NFolderIcon, NForm, NFormSectionHeader, NIcon, NIndicator, NInspectorSheet, NLoadingState, NMultiDialog, NNavbar, NPageHeader, NPageHeaderActions, NPageHeaderFilters, NPageHeaderTop, NPortalScopeProvider, NProgress, NRowActions, NSection, NSectionHeader, NSectionInfo, NSectionWithInfo, NSheet, NSidebar, NSidebarContent, NSidebarFooter, NSidebarHeader, NSidebarItem, NSidebarLogo, NSidebarMobile, NSidebarSection, NSkeleton, NSkeletonCalendar, NSkeletonChart, NSkeletonDonut, NSkeletonEventList, NSkeletonWidget, NSkeletonWidgets, NSlider, NSmartPasteDialog, NSpinner, NStatCard, NStatCardSkeleton, Swap as NSwap, NTable, NTableCardRoot, NTableCards, NTableContent, NTableHeader, NTableJson, NTableLoadingSkeleton, NTablePagination, NTableRowSkeleton, NTableSkeleton, NTabs, NUploader, NViewBody, NViewToggle, NajmScroll, NajmThemeProvider, NativeSelect, NumberInput, PasswordInput, PhoneInput, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PrefixProvider, Progress, RadioGroup2 as RadioGroup, RadioGroupInput, RadioGroupItem, RepeatingFields, ScrollArea, SearchField, SearchField as SearchInput, SegmentedControl, Select, SelectContent, SelectGroup, SelectInput, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SimpleTooltip, NSkeleton as Skeleton, Slider, SliderInput, StarRatingInput, StatusPill, StepIndicator, StepsHeader, StepsProgress, Swap, SwapIndeterminate, SwapOff, SwapOn, Switch, SwitchInput, TAB_COLORS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableStoreContext, Tabs, TabsContent, TabsList, TabsTrigger, TextAreaInput, TextInput, Textarea, TimeInput, Toaster, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, VariantProvider, WizardForm, alertVariants, avatarVariants, badgeColorVariants, badgeVariants, borderColorClassForDegree, buildDefaultFileColumns, buttonVariants, cn, composePreset, createDialogStore, createTableStore, dialogVariants, formatFileBytes, formatFileRelative, getIconColorProps, indicatorVariants, inputBorderColorClassForDegree, resolveBorderDegree, resolvePreset, resolveSlot, sliderVariants, surfaceBorderClasses, swapVariants, toggleVariants, tooltipContentVariants, truncateByCharacters, useClickOutside, useContextMenu, useDebouncedValue, useDelayedLoading, useDialog, useDialogStore, useDynamicPageSize, useFormField, useFormSubmission, useInfiniteScroll, useKeyboard, useLocalStorageState, useNForm, useNPortalScope, useNajmAppearance, usePrefix, useResolvedBorderDegree, useSelection, useStepNavigation, useStorageContextMenu, useStoreSync, useTable, useTableKeyboard, useTableStore, useVariant, useVariantPreset };
10715
+ export { Alert, NCard as AsyncCard, Avatar, AvatarFallback, AvatarGroup, AvatarImage, AvatarStatus, Badge, BaseInput, Button, Calendar, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxGroupInput, CheckboxInput, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, ColorArrayInput, ColorPickerInput, Combobox, ComboboxInput, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, DateInput, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DynamicArray_default as DynamicArray, EmojiInput, FileImportButton, FileInput, Form, FormControl, FormDescription, FormField, FormInput, FormItem, FormLabel, FormMessage, IconButton, ImageInput, Indicator, Input, Label, LangInput, MultiSelectInput, NAJM_COMPONENT_NAMES, NAlert, NAppShell, NCard as NAsyncCard, NAvatar, NBadge, NBulkActionsBar, NButton, NCard, NCardAction, NCardFooter, NCommandPalette, NConfirmDialog, NContextMenu, NDataCardShell, NDeleteDialog, NDeleteDialogContent, NDetailCard, NDetailItem, NDetailList, NDialog, NEmptyState, NErrorBoundary, NErrorState, NFileBrowser, NFileTypeIcon, NFilterBar, NFolderIcon, NForm, NFormSectionHeader, NIcon, NIndicator, NInspectorSheet, NLoadingState, NMultiDialog, NNavbar, NPageHeader, NPageHeaderActions, NPageHeaderFilters, NPageHeaderTop, NPageLayout, NPortalScopeProvider, NProgress, NRowActions, NSection, NSectionHeader, NSectionInfo, NSectionWithInfo, NSheet, NSidebar, NSidebarContent, NSidebarFooter, NSidebarHeader, NSidebarItem, NSidebarLogo, NSidebarMobile, NSidebarSection, NSkeleton, NSkeletonCalendar, NSkeletonChart, NSkeletonDonut, NSkeletonEventList, NSkeletonWidget, NSkeletonWidgets, NSlider, NSmartPasteDialog, NSpinner, NStatCard, NStatCardSkeleton, Swap as NSwap, NTable, NTableCardRoot, NTableCards, NTableContent, NTableHeader, NTableJson, NTableLoadingSkeleton, NTablePagination, NTableRowSkeleton, NTableSkeleton, NTabs, NUploader, NViewBody, NViewToggle, NajmDesignProvider, NajmScroll, NajmThemeProvider, NativeSelect, NumberInput, PasswordInput, PhoneInput, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PrefixProvider, Progress, RADIUS_VALUE_MAP, RadioGroup2 as RadioGroup, RadioGroupInput, RadioGroupItem, RepeatingFields, ScrollArea, SearchField, SearchField as SearchInput, SegmentedControl, Select, SelectContent, SelectGroup, SelectInput, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SimpleTooltip, NSkeleton as Skeleton, Slider, SliderInput, StarRatingInput, StatusPill, StepIndicator, StepsHeader, StepsProgress, Swap, SwapIndeterminate, SwapOff, SwapOn, Switch, SwitchInput, TAB_COLORS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableStoreContext, Tabs, TabsContent, TabsList, TabsTrigger, TextAreaInput, TextInput, Textarea, TimeInput, Toaster, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, VariantProvider, WizardForm, alertVariants, avatarVariants, badgeColorVariants, badgeVariants, buildDefaultFileColumns, buttonVariants, cn, composePreset, createDialogStore, createTableStore, defineNajmDesignConfig, defineNajmThemeConfig, detectFormat, dialogVariants, formatColor, formatFileBytes, formatFileRelative, getIconColorProps, indicatorVariants, inputBorderClasses, parseColor, parseNajmDesignConfig, parseNajmThemeConfig, resolvePreset, resolveRadiusValue, resolveSlot, resolveVariantAlias, sidebarBorderClasses, sliderVariants, stringifyNajmDesignConfig, stringifyNajmThemeConfig, surfaceBorderClasses, swapVariants, toPickerHex, toggleVariants, tooltipContentVariants, truncateByCharacters, useClickOutside, useContextMenu, useDebouncedValue, useDelayedLoading, useDialog, useDialogStore, useDynamicPageSize, useFormField, useFormSubmission, useInfiniteScroll, useKeyboard, useLocalStorageState, useNForm, useNPortalScope, useNajmAppearance, useNajmComponentStyle, useNajmDesign, usePrefix, useSelection, useStepNavigation, useStorageContextMenu, useStoreSync, useTable, useTableKeyboard, useTableStore, useVariant, useVariantPreset };