najm-kit 0.0.19 → 0.0.21

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,123 @@ 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
+ }
231
+ function resolveThemeTokens({
232
+ preset,
233
+ mode,
234
+ accent,
235
+ explicitTokens,
236
+ configTokens,
237
+ configMode,
238
+ overrides
239
+ }) {
240
+ if (explicitTokens) return explicitTokens;
241
+ const tokenMode = mode ?? configMode;
242
+ const modeOverrides = tokenMode ? overrides?.[tokenMode] : void 0;
243
+ const tokensMatchMode = !configMode || !tokenMode || configMode === tokenMode;
244
+ const scopedTokens = tokensMatchMode ? configTokens : void 0;
245
+ if (preset) {
246
+ return { ...resolvePreset(preset), ...scopedTokens ?? {}, ...modeOverrides ?? {} };
247
+ }
248
+ if (tokenMode) {
249
+ return {
250
+ ...composePreset(tokenMode, accent ?? "neutral"),
251
+ ...scopedTokens ?? {},
252
+ ...modeOverrides ?? {}
253
+ };
254
+ }
255
+ if (scopedTokens || modeOverrides) return { ...scopedTokens ?? {}, ...modeOverrides ?? {} };
256
+ return null;
257
+ }
175
258
  var NajmThemeDepthContext = React.createContext(0);
176
259
  var NajmThemeContainerCtx = React.createContext(null);
177
- var DEFAULT_APPEARANCE = {
178
- borderDegree: "default"
179
- };
260
+ var DEFAULT_APPEARANCE = {};
180
261
  var NajmAppearanceContext = React.createContext(DEFAULT_APPEARANCE);
181
262
  function useNajmAppearance() {
182
263
  return React.useContext(NajmAppearanceContext);
183
264
  }
184
265
  function NajmThemeProvider({
266
+ config,
185
267
  preset,
186
268
  mode,
187
269
  accent,
188
270
  tokens,
189
271
  accentOnly,
190
272
  appearance,
273
+ radius,
274
+ radiusScale,
275
+ spacing,
191
276
  className,
192
277
  asChild,
193
278
  children
194
279
  }) {
195
280
  const depth = React.useContext(NajmThemeDepthContext);
196
281
  const parentAppearance = React.useContext(NajmAppearanceContext);
197
- const shouldApplyThemeTokens = Boolean(preset || mode || tokens);
282
+ const effectivePreset = preset ?? config?.preset;
283
+ const effectiveMode = mode ?? config?.mode;
284
+ const effectiveAccent = accent ?? config?.accent;
285
+ const effectiveAccentOnly = accentOnly ?? config?.accentOnly;
286
+ const effectiveRadius = radius ?? config?.radius;
287
+ const effectiveRadiusScale = radiusScale ?? config?.radiusScale ?? "shadcn";
288
+ const effectiveSpacing = spacing ?? config?.spacing;
289
+ const effectiveBorderWidth = appearance?.borderWidth ?? config?.appearance?.borderWidth;
198
290
  const resolved = React.useMemo(() => {
199
- 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]);
291
+ return resolveThemeTokens({
292
+ preset: effectivePreset,
293
+ mode: effectiveMode,
294
+ accent: effectiveAccent,
295
+ explicitTokens: tokens,
296
+ configTokens: config?.tokens,
297
+ configMode: config?.mode,
298
+ overrides: config?.overrides
299
+ });
300
+ }, [
301
+ effectivePreset,
302
+ effectiveMode,
303
+ effectiveAccent,
304
+ tokens,
305
+ config?.tokens,
306
+ config?.mode,
307
+ config?.overrides
308
+ ]);
204
309
  const style = React.useMemo(
205
- () => resolved ? tokensToStyle(resolved, accentOnly) : void 0,
206
- [resolved, accentOnly]
310
+ () => {
311
+ const tokenStyle = resolved ? tokensToStyle(resolved, effectiveAccentOnly) : void 0;
312
+ const radiusStyle = effectiveRadius !== void 0 ? radiusToStyle(effectiveRadius, effectiveRadiusScale) : void 0;
313
+ const borderWidthStyle = effectiveBorderWidth !== void 0 ? { "--border-width": effectiveBorderWidth } : void 0;
314
+ const spacingStyle = effectiveSpacing !== void 0 ? { "--spacing": effectiveSpacing } : void 0;
315
+ if (!tokenStyle && !radiusStyle && !borderWidthStyle && !spacingStyle) return void 0;
316
+ return { ...tokenStyle, ...radiusStyle, ...borderWidthStyle, ...spacingStyle };
317
+ },
318
+ [resolved, effectiveAccentOnly, effectiveRadius, effectiveRadiusScale, effectiveSpacing, effectiveBorderWidth]
207
319
  );
208
320
  const Comp = asChild ? Slot : "div";
209
321
  const [container, setContainer] = React.useState(null);
210
322
  const resolvedAppearance = React.useMemo(
211
- () => ({ ...parentAppearance, ...appearance ?? {} }),
212
- [parentAppearance, appearance]
323
+ () => ({ ...parentAppearance, ...config?.appearance ?? {}, ...appearance ?? {} }),
324
+ [parentAppearance, config?.appearance, appearance]
213
325
  );
214
326
  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
327
  Comp,
216
328
  {
217
329
  ref: setContainer,
218
- "data-najm-theme": preset ?? `${mode ?? "light"}-${accent ?? "neutral"}`,
330
+ "data-najm-theme": effectivePreset ?? `${effectiveMode ?? "light"}-${effectiveAccent ?? "neutral"}`,
219
331
  className,
220
332
  style,
221
333
  children
@@ -223,49 +335,502 @@ function NajmThemeProvider({
223
335
  ) }) }) });
224
336
  }
225
337
 
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";
338
+ // src/theme/config.ts
339
+ var MODES = ["light", "dark"];
340
+ var ACCENTS = ["neutral", "emerald", "green", "slate", "blue", "violet"];
341
+ var PRESETS = ["light", "dark", "dark-emerald", "dark-green", "dark-slate", "dark-blue", "dark-violet"];
342
+ var RADIUS_SCALES = ["shadcn", "uniform"];
343
+ var TOKEN_KEYS = [
344
+ "background",
345
+ "foreground",
346
+ "card",
347
+ "card-foreground",
348
+ "popover",
349
+ "popover-foreground",
350
+ "primary",
351
+ "primary-foreground",
352
+ "secondary",
353
+ "secondary-foreground",
354
+ "tertiary",
355
+ "tertiary-foreground",
356
+ "muted",
357
+ "muted-foreground",
358
+ "accent",
359
+ "accent-foreground",
360
+ "destructive",
361
+ "destructive-foreground",
362
+ "border",
363
+ "input",
364
+ "ring",
365
+ "sidebar",
366
+ "sidebar-foreground",
367
+ "sidebar-primary",
368
+ "sidebar-primary-foreground",
369
+ "sidebar-accent",
370
+ "sidebar-accent-foreground",
371
+ "sidebar-border",
372
+ "sidebar-ring",
373
+ "chart-1",
374
+ "chart-2",
375
+ "chart-3",
376
+ "chart-4",
377
+ "chart-5",
378
+ "radius"
379
+ ];
380
+ var ROOT_KEYS = /* @__PURE__ */ new Set([
381
+ "preset",
382
+ "mode",
383
+ "accent",
384
+ "tokens",
385
+ "overrides",
386
+ "accentOnly",
387
+ "appearance",
388
+ "radius",
389
+ "radiusScale",
390
+ "spacing"
391
+ ]);
392
+ var TOKEN_KEY_SET = new Set(TOKEN_KEYS);
393
+ var MODE_KEY_SET = new Set(MODES);
394
+ function isRecord(value) {
395
+ return typeof value === "object" && value !== null && !Array.isArray(value);
396
+ }
397
+ function assertKnownKeys(value, keys, path) {
398
+ const unknown = Object.keys(value).find((key) => !keys.has(key));
399
+ if (unknown) throw new TypeError(`Unknown ${path} property: ${unknown}`);
400
+ }
401
+ function optionalEnum(value, values, path) {
402
+ if (value === void 0) return void 0;
403
+ if (typeof value !== "string" || !values.includes(value)) {
404
+ throw new TypeError(`${path} must be one of: ${values.join(", ")}`);
243
405
  }
406
+ return value;
244
407
  }
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";
408
+ function optionalString(value, path) {
409
+ if (value === void 0) return void 0;
410
+ if (typeof value !== "string" || value.trim() === "") {
411
+ throw new TypeError(`${path} must be a non-empty string`);
412
+ }
413
+ return value;
414
+ }
415
+ function parseTokens(value) {
416
+ if (value === void 0) return void 0;
417
+ if (!isRecord(value)) throw new TypeError("theme.tokens must be an object");
418
+ assertKnownKeys(value, TOKEN_KEY_SET, "theme.tokens");
419
+ const tokens = {};
420
+ for (const key of TOKEN_KEYS) {
421
+ const token = optionalString(value[key], `theme.tokens.${key}`);
422
+ if (token !== void 0) tokens[key] = token;
423
+ }
424
+ return tokens;
425
+ }
426
+ function parseOverrides(value) {
427
+ if (value === void 0) return void 0;
428
+ if (!isRecord(value)) throw new TypeError("theme.overrides must be an object");
429
+ assertKnownKeys(value, MODE_KEY_SET, "theme.overrides");
430
+ const overrides = {};
431
+ for (const mode of MODES) {
432
+ const entry = value[mode];
433
+ if (entry === void 0) continue;
434
+ overrides[mode] = parseTokens(entry) ?? {};
435
+ }
436
+ return overrides;
437
+ }
438
+ function defineNajmThemeConfig(config) {
439
+ return config;
440
+ }
441
+ function parseNajmThemeConfig(input) {
442
+ let value = input;
443
+ if (typeof input === "string") {
444
+ try {
445
+ value = JSON.parse(input);
446
+ } catch (error) {
447
+ throw new TypeError(`Invalid theme JSON: ${error.message}`);
448
+ }
449
+ }
450
+ if (!isRecord(value)) throw new TypeError("Theme config must be an object");
451
+ assertKnownKeys(value, ROOT_KEYS, "theme");
452
+ let appearance;
453
+ if (value.appearance !== void 0) {
454
+ if (!isRecord(value.appearance)) throw new TypeError("theme.appearance must be an object");
455
+ assertKnownKeys(value.appearance, /* @__PURE__ */ new Set(["borderWidth"]), "theme.appearance");
456
+ appearance = {
457
+ borderWidth: optionalString(
458
+ value.appearance.borderWidth,
459
+ "theme.appearance.borderWidth"
460
+ )
461
+ };
255
462
  }
463
+ const accentOnly = value.accentOnly;
464
+ if (accentOnly !== void 0 && typeof accentOnly !== "boolean") {
465
+ throw new TypeError("theme.accentOnly must be a boolean");
466
+ }
467
+ const parsedAccentOnly = typeof accentOnly === "boolean" ? accentOnly : void 0;
468
+ const config = {};
469
+ const preset = optionalEnum(value.preset, PRESETS, "theme.preset");
470
+ const mode = optionalEnum(value.mode, MODES, "theme.mode");
471
+ const accent = optionalEnum(value.accent, ACCENTS, "theme.accent");
472
+ const tokens = parseTokens(value.tokens);
473
+ const overrides = parseOverrides(value.overrides);
474
+ const radius = optionalString(value.radius, "theme.radius");
475
+ const radiusScale = optionalEnum(value.radiusScale, RADIUS_SCALES, "theme.radiusScale");
476
+ const spacing = optionalString(value.spacing, "theme.spacing");
477
+ if (preset !== void 0) config.preset = preset;
478
+ if (mode !== void 0) config.mode = mode;
479
+ if (accent !== void 0) config.accent = accent;
480
+ if (tokens !== void 0) config.tokens = tokens;
481
+ if (overrides !== void 0) config.overrides = overrides;
482
+ if (parsedAccentOnly !== void 0) config.accentOnly = parsedAccentOnly;
483
+ if (appearance !== void 0) config.appearance = appearance;
484
+ if (radius !== void 0) config.radius = radius;
485
+ if (radiusScale !== void 0) config.radiusScale = radiusScale;
486
+ if (spacing !== void 0) config.spacing = spacing;
487
+ return config;
488
+ }
489
+ function stringifyNajmThemeConfig(config, space = 2) {
490
+ return JSON.stringify(config, null, space);
491
+ }
492
+ var NajmDesignContext = React.createContext({
493
+ components: {}
494
+ });
495
+ function useNajmDesign() {
496
+ return React.useContext(NajmDesignContext);
256
497
  }
257
- function useResolvedBorderDegree(options = {}) {
258
- const appearance = useNajmAppearance();
259
- return resolveBorderDegree(
260
- options.borderDegree,
261
- options.bordered,
262
- appearance.borderDegree,
263
- options.fallback
498
+ function useNajmComponentStyle(name) {
499
+ const { components } = useNajmDesign();
500
+ return components[name];
501
+ }
502
+ var SCALE_FACTOR = {
503
+ compact: "0.95",
504
+ default: "1",
505
+ comfortable: "1.05"
506
+ };
507
+ function typographyToStyle(t) {
508
+ const style = {};
509
+ if (t.fontSans) style["--font-sans"] = t.fontSans;
510
+ if (t.fontHeading) style["--font-heading"] = t.fontHeading;
511
+ if (t.fontMono) style["--font-mono"] = t.fontMono;
512
+ if (t.baseSize) style["--font-size-base"] = t.baseSize;
513
+ if (t.lineHeight) style["--line-height-base"] = t.lineHeight;
514
+ if (t.letterSpacing) style["--letter-spacing-base"] = t.letterSpacing;
515
+ if (t.scale) style["--font-scale"] = SCALE_FACTOR[t.scale];
516
+ return style;
517
+ }
518
+ function layoutToStyle(layout) {
519
+ const style = {};
520
+ if (layout.pageGutter) style["--page-gutter"] = layout.pageGutter;
521
+ if (layout.sectionGap) style["--section-gap"] = layout.sectionGap;
522
+ return style;
523
+ }
524
+ function NajmDesignProvider({
525
+ config,
526
+ mode,
527
+ className,
528
+ children
529
+ }) {
530
+ const contextValue = React.useMemo(
531
+ () => ({ components: config.components ?? {}, typography: config.typography, layout: config.layout }),
532
+ [config.components, config.typography, config.layout]
533
+ );
534
+ const typographyStyle = React.useMemo(
535
+ () => config.typography ? typographyToStyle(config.typography) : void 0,
536
+ [config.typography]
537
+ );
538
+ const layoutStyle = React.useMemo(
539
+ () => config.layout ? layoutToStyle(config.layout) : void 0,
540
+ [config.layout]
541
+ );
542
+ const providerStyle = React.useMemo(
543
+ () => ({ ...layoutStyle ?? {}, ...typographyStyle ?? {} }),
544
+ [layoutStyle, typographyStyle]
264
545
  );
546
+ return /* @__PURE__ */ jsx(NajmDesignContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(NajmThemeProvider, { config: config.theme, mode, className, children: layoutStyle || typographyStyle ? (
547
+ // `display: contents` lets design CSS variables cascade to
548
+ // children without introducing a layout box that would break height
549
+ // chains (e.g. h-full) in the consuming app.
550
+ /* @__PURE__ */ jsx("div", { style: { display: "contents", ...providerStyle }, "data-najm-design-vars": "", children })
551
+ ) : children }) });
552
+ }
553
+
554
+ // src/theme/design-types.ts
555
+ var NAJM_COMPONENT_NAMES = [
556
+ "button",
557
+ "badge",
558
+ "card",
559
+ "table",
560
+ "tabs",
561
+ "dialog",
562
+ "alert",
563
+ "sidebar",
564
+ "pageHeader",
565
+ "input",
566
+ "select",
567
+ "sheet",
568
+ "popover",
569
+ "tooltip",
570
+ "progress",
571
+ "avatar"
572
+ ];
573
+ var RADIUS_VALUE_MAP = {
574
+ none: "0",
575
+ xs: "var(--radius-xs)",
576
+ sm: "var(--radius-sm)",
577
+ md: "var(--radius-md)",
578
+ lg: "var(--radius-lg)",
579
+ xl: "var(--radius-xl)",
580
+ full: "9999px"
581
+ };
582
+ function resolveRadiusValue(radius) {
583
+ if (!radius || radius === "inherit") return void 0;
584
+ return RADIUS_VALUE_MAP[radius] ?? radius;
585
+ }
586
+
587
+ // src/theme/design-config.ts
588
+ var ROOT_KEYS2 = /* @__PURE__ */ new Set(["version", "theme", "typography", "components", "layout"]);
589
+ var TYPOGRAPHY_KEYS = /* @__PURE__ */ new Set([
590
+ "fontSans",
591
+ "fontHeading",
592
+ "fontMono",
593
+ "baseSize",
594
+ "scale",
595
+ "lineHeight",
596
+ "letterSpacing"
597
+ ]);
598
+ var LAYOUT_KEYS = /* @__PURE__ */ new Set(["pageGutter", "sectionGap"]);
599
+ var COMPONENT_KEYS = /* @__PURE__ */ new Set([
600
+ "card",
601
+ "showSectionLabels",
602
+ "showSectionSeparators",
603
+ "defaultVariant",
604
+ "defaultSize",
605
+ "density",
606
+ "headerColor",
607
+ "headerTextColor",
608
+ "borderColor",
609
+ "radius",
610
+ "borderWidth",
611
+ "slots",
612
+ "variants"
613
+ ]);
614
+ var SLOT_KEYS = /* @__PURE__ */ new Set(["className", "radius", "borderWidth", "padding", "paddingTop"]);
615
+ var VARIANT_KEYS = /* @__PURE__ */ new Set(["use", "className", "tokens"]);
616
+ var COMPONENT_NAME_SET = new Set(NAJM_COMPONENT_NAMES);
617
+ var DENSITIES = /* @__PURE__ */ new Set(["compact", "default", "comfortable"]);
618
+ var SCALES = /* @__PURE__ */ new Set(["compact", "default", "comfortable"]);
619
+ function isRecord2(value) {
620
+ return typeof value === "object" && value !== null && !Array.isArray(value);
621
+ }
622
+ function assertKnownKeys2(value, keys, path) {
623
+ const unknown = Object.keys(value).find((key) => !keys.has(key));
624
+ if (unknown) throw new TypeError(`Unknown ${path} property: ${unknown}`);
625
+ }
626
+ function optionalString2(value, path) {
627
+ if (value === void 0) return void 0;
628
+ if (typeof value !== "string") {
629
+ throw new TypeError(`${path} must be a string`);
630
+ }
631
+ return value;
632
+ }
633
+ function optionalBoolean(value, path) {
634
+ if (value === void 0) return void 0;
635
+ if (typeof value !== "boolean") {
636
+ throw new TypeError(`${path} must be a boolean`);
637
+ }
638
+ return value;
265
639
  }
266
- function surfaceBorderClasses(degree) {
267
- if (degree === "none") return "border border-transparent";
268
- return `border ${borderColorClassForDegree(degree)}`;
640
+ function optionalEnum2(value, values, path) {
641
+ if (value === void 0) return void 0;
642
+ if (typeof value !== "string" || !values.has(value)) {
643
+ throw new TypeError(`${path} must be one of: ${[...values].join(", ")}`);
644
+ }
645
+ return value;
646
+ }
647
+ function parseTypography(value) {
648
+ if (value === void 0) return void 0;
649
+ if (!isRecord2(value)) throw new TypeError("typography must be an object");
650
+ assertKnownKeys2(value, TYPOGRAPHY_KEYS, "typography");
651
+ const cfg = {};
652
+ const fontSans = optionalString2(value.fontSans, "typography.fontSans");
653
+ const fontHeading = optionalString2(value.fontHeading, "typography.fontHeading");
654
+ const fontMono = optionalString2(value.fontMono, "typography.fontMono");
655
+ const baseSize = optionalString2(value.baseSize, "typography.baseSize");
656
+ const scale = optionalEnum2(value.scale, SCALES, "typography.scale");
657
+ const lineHeight = optionalString2(value.lineHeight, "typography.lineHeight");
658
+ const letterSpacing = optionalString2(value.letterSpacing, "typography.letterSpacing");
659
+ if (fontSans !== void 0) cfg.fontSans = fontSans;
660
+ if (fontHeading !== void 0) cfg.fontHeading = fontHeading;
661
+ if (fontMono !== void 0) cfg.fontMono = fontMono;
662
+ if (baseSize !== void 0) cfg.baseSize = baseSize;
663
+ if (scale !== void 0) cfg.scale = scale;
664
+ if (lineHeight !== void 0) cfg.lineHeight = lineHeight;
665
+ if (letterSpacing !== void 0) cfg.letterSpacing = letterSpacing;
666
+ return cfg;
667
+ }
668
+ function parseLayout(value) {
669
+ if (value === void 0) return void 0;
670
+ if (!isRecord2(value)) throw new TypeError("layout must be an object");
671
+ assertKnownKeys2(value, LAYOUT_KEYS, "layout");
672
+ const cfg = {};
673
+ const pageGutter = optionalString2(value.pageGutter, "layout.pageGutter");
674
+ const sectionGap = optionalString2(value.sectionGap, "layout.sectionGap");
675
+ if (pageGutter !== void 0) cfg.pageGutter = pageGutter;
676
+ if (sectionGap !== void 0) cfg.sectionGap = sectionGap;
677
+ return cfg;
678
+ }
679
+ function parseVariant(value, path) {
680
+ if (!isRecord2(value)) throw new TypeError(`${path} must be an object`);
681
+ assertKnownKeys2(value, VARIANT_KEYS, path);
682
+ const variant = {};
683
+ const use = optionalString2(value.use, `${path}.use`);
684
+ const className = optionalString2(value.className, `${path}.className`);
685
+ if (use !== void 0) variant.use = use;
686
+ if (className !== void 0) variant.className = className;
687
+ if (value.tokens !== void 0) {
688
+ if (!isRecord2(value.tokens)) throw new TypeError(`${path}.tokens must be an object`);
689
+ variant.tokens = value.tokens;
690
+ }
691
+ return variant;
692
+ }
693
+ function parseComponentStyle(value, path) {
694
+ if (!isRecord2(value)) throw new TypeError(`${path} must be an object`);
695
+ assertKnownKeys2(value, COMPONENT_KEYS, path);
696
+ const cfg = {};
697
+ const card = optionalBoolean(value.card, `${path}.card`);
698
+ const showSectionLabels = optionalBoolean(value.showSectionLabels, `${path}.showSectionLabels`);
699
+ const showSectionSeparators = optionalBoolean(value.showSectionSeparators, `${path}.showSectionSeparators`);
700
+ const defaultVariant = optionalString2(value.defaultVariant, `${path}.defaultVariant`);
701
+ const defaultSize = optionalString2(value.defaultSize, `${path}.defaultSize`);
702
+ const density = optionalEnum2(value.density, DENSITIES, `${path}.density`);
703
+ const headerColor = optionalString2(value.headerColor, `${path}.headerColor`);
704
+ const headerTextColor = optionalString2(value.headerTextColor, `${path}.headerTextColor`);
705
+ const borderColor = optionalString2(value.borderColor, `${path}.borderColor`);
706
+ const radius = optionalString2(value.radius, `${path}.radius`);
707
+ const borderWidth = optionalString2(value.borderWidth, `${path}.borderWidth`);
708
+ if (card !== void 0) cfg.card = card;
709
+ if (showSectionLabels !== void 0) cfg.showSectionLabels = showSectionLabels;
710
+ if (showSectionSeparators !== void 0) cfg.showSectionSeparators = showSectionSeparators;
711
+ if (defaultVariant !== void 0) cfg.defaultVariant = defaultVariant;
712
+ if (defaultSize !== void 0) cfg.defaultSize = defaultSize;
713
+ if (density !== void 0) cfg.density = density;
714
+ if (headerColor !== void 0) cfg.headerColor = headerColor;
715
+ if (headerTextColor !== void 0) cfg.headerTextColor = headerTextColor;
716
+ if (borderColor !== void 0) cfg.borderColor = borderColor;
717
+ if (radius !== void 0) cfg.radius = radius;
718
+ if (borderWidth !== void 0) cfg.borderWidth = borderWidth;
719
+ if (value.slots !== void 0) {
720
+ if (!isRecord2(value.slots)) throw new TypeError(`${path}.slots must be an object`);
721
+ const slots = {};
722
+ for (const [slotName, slotValue] of Object.entries(value.slots)) {
723
+ if (!isRecord2(slotValue)) throw new TypeError(`${path}.slots.${slotName} must be an object`);
724
+ assertKnownKeys2(slotValue, SLOT_KEYS, `${path}.slots.${slotName}`);
725
+ slots[slotName] = slotValue;
726
+ }
727
+ cfg.slots = slots;
728
+ }
729
+ if (value.variants !== void 0) {
730
+ if (!isRecord2(value.variants)) throw new TypeError(`${path}.variants must be an object`);
731
+ const variants = {};
732
+ for (const [variantName, variantValue] of Object.entries(value.variants)) {
733
+ variants[variantName] = parseVariant(variantValue, `${path}.variants.${variantName}`);
734
+ }
735
+ cfg.variants = variants;
736
+ }
737
+ return cfg;
738
+ }
739
+ function parseComponents(value) {
740
+ if (value === void 0) return void 0;
741
+ if (!isRecord2(value)) throw new TypeError("components must be an object");
742
+ const unknown = Object.keys(value).find((key) => !COMPONENT_NAME_SET.has(key));
743
+ if (unknown) throw new TypeError(`Unknown component name: ${unknown}`);
744
+ const components = {};
745
+ for (const [name, cfg] of Object.entries(value)) {
746
+ components[name] = parseComponentStyle(cfg, `components.${name}`);
747
+ }
748
+ return components;
749
+ }
750
+ function defineNajmDesignConfig(config) {
751
+ return config;
752
+ }
753
+ function parseNajmDesignConfig(input) {
754
+ let value = input;
755
+ if (typeof input === "string") {
756
+ try {
757
+ value = JSON.parse(input);
758
+ } catch (error) {
759
+ throw new TypeError(`Invalid design JSON: ${error.message}`);
760
+ }
761
+ }
762
+ if (!isRecord2(value)) throw new TypeError("Design config must be an object");
763
+ if (!("version" in value) && !("theme" in value)) {
764
+ return {
765
+ version: 1,
766
+ theme: parseNajmThemeConfig(value)
767
+ };
768
+ }
769
+ assertKnownKeys2(value, ROOT_KEYS2, "design");
770
+ if (value.version !== void 0 && value.version !== 1) {
771
+ throw new TypeError("design.version must be 1");
772
+ }
773
+ if (value.theme === void 0) throw new TypeError("design.theme is required");
774
+ const config = {
775
+ version: 1,
776
+ theme: parseNajmThemeConfig(value.theme)
777
+ };
778
+ const typography = parseTypography(value.typography);
779
+ if (typography !== void 0) config.typography = typography;
780
+ const components = parseComponents(value.components);
781
+ if (components !== void 0) config.components = components;
782
+ const layout = parseLayout(value.layout);
783
+ if (layout !== void 0) config.layout = layout;
784
+ return config;
785
+ }
786
+ function stringifyNajmDesignConfig(config, space = 2) {
787
+ return JSON.stringify(config, null, space);
788
+ }
789
+ function resolveVariantAlias(variants, variant) {
790
+ if (!variants) return { variant };
791
+ const seen = /* @__PURE__ */ new Set();
792
+ let current = variant;
793
+ let style = variants[current];
794
+ while (style?.use && !seen.has(current)) {
795
+ seen.add(current);
796
+ const next = style.use;
797
+ if (seen.has(next)) break;
798
+ current = next;
799
+ style = variants[current];
800
+ }
801
+ return { variant: current, style };
802
+ }
803
+
804
+ // src/theme/borders.ts
805
+ var SURFACE_BORDER_CLASSES = {
806
+ all: "najm-border border-border",
807
+ top: "najm-border-t border-border",
808
+ right: "najm-border-r border-border",
809
+ bottom: "najm-border-b border-border",
810
+ left: "najm-border-l border-border"
811
+ };
812
+ var SIDEBAR_BORDER_CLASSES = {
813
+ all: "najm-border border-sidebar-border",
814
+ top: "najm-border-t border-sidebar-border",
815
+ right: "najm-border-r border-sidebar-border",
816
+ bottom: "najm-border-b border-sidebar-border",
817
+ left: "najm-border-l border-sidebar-border"
818
+ };
819
+ var BORDER_RESET_CLASSES = {
820
+ all: "border-0",
821
+ top: "border-t-0",
822
+ right: "border-r-0",
823
+ bottom: "border-b-0",
824
+ left: "border-l-0"
825
+ };
826
+ function surfaceBorderClasses(bordered = true, side = "all") {
827
+ return bordered === false ? BORDER_RESET_CLASSES[side] : SURFACE_BORDER_CLASSES[side];
828
+ }
829
+ function sidebarBorderClasses(bordered = true, side = "all") {
830
+ return bordered === false ? BORDER_RESET_CLASSES[side] : SIDEBAR_BORDER_CLASSES[side];
831
+ }
832
+ function inputBorderClasses(bordered = true) {
833
+ return bordered === false ? "border-0" : "najm-border border-input";
269
834
  }
270
835
  var EDITABLE_INPUT_TYPES = /* @__PURE__ */ new Set([
271
836
  "text",
@@ -600,21 +1165,25 @@ var Button = React.forwardRef(
600
1165
  leftIcon,
601
1166
  rightIcon,
602
1167
  bordered,
603
- borderDegree,
604
1168
  disabled,
605
1169
  children,
606
1170
  onClick,
1171
+ style,
607
1172
  ...props
608
1173
  }, ref) => {
1174
+ const recipe = useNajmComponentStyle("button");
1175
+ const aliased = resolveVariantAlias(
1176
+ recipe?.variants,
1177
+ variant ?? recipe?.defaultVariant ?? "default"
1178
+ );
1179
+ const effVariant = variant ?? aliased.variant ?? recipe?.defaultVariant;
1180
+ const effSize = size ?? recipe?.defaultSize;
1181
+ const recipeRadius = rounded === void 0 ? resolveRadiusValue(recipe?.radius) : void 0;
1182
+ const recipeStyle = recipeRadius ? { borderRadius: recipeRadius } : void 0;
609
1183
  const [pending, setPending] = React.useState(false);
610
1184
  const isLoading = loading || pending;
611
1185
  const isDisabled = disabled || disabledWhileLoading && isLoading;
612
1186
  const Comp = asChild ? Slot : "button";
613
- const resolvedBorderDegree = useResolvedBorderDegree({
614
- borderDegree,
615
- bordered,
616
- fallback: "default"
617
- });
618
1187
  const handleClick = React.useCallback(
619
1188
  (event) => {
620
1189
  if (isDisabled) {
@@ -644,21 +1213,22 @@ var Button = React.forwardRef(
644
1213
  "data-slot": "button",
645
1214
  "data-loading": isLoading || void 0,
646
1215
  "data-disabled": isDisabled || void 0,
647
- "data-border-degree": variant === "outline" || bordered || borderDegree ? resolvedBorderDegree : void 0,
1216
+ "data-bordered": effVariant === "outline" ? "true" : bordered === false ? "false" : bordered ? "true" : void 0,
648
1217
  "aria-busy": isLoading || void 0,
649
1218
  "aria-disabled": asChild && isDisabled ? true : void 0,
650
1219
  disabled: !asChild ? isDisabled : void 0,
1220
+ style: recipeStyle ? { ...recipeStyle, ...style } : style,
651
1221
  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),
1222
+ buttonVariants({ variant: effVariant, size: effSize, rounded, fullWidth }),
1223
+ aliased.style?.className,
1224
+ // Outline buttons always carry an input-style border.
1225
+ effVariant === "outline" && inputBorderClasses(true),
655
1226
  // 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(
1227
+ // border when the consumer explicitly opts in via `bordered`. Global theming
1228
+ // should not outline every filled button.
1229
+ effVariant !== "outline" && bordered === true && cn(
660
1230
  "border",
661
- borderDegree ? borderColorClassForDegree(resolvedBorderDegree) : "border-muted-foreground"
1231
+ "border-muted-foreground"
662
1232
  ),
663
1233
  className
664
1234
  ),
@@ -730,41 +1300,41 @@ var badgeColorVariants = cva(
730
1300
  }
731
1301
  },
732
1302
  compoundVariants: [
733
- { color: "primary", look: "solid", class: "bg-pink-500 text-white" },
734
- { color: "primary", look: "soft", class: "bg-pink-500/10 text-pink-400 border-pink-500/20" },
735
- { color: "primary", look: ["outline", "dash"], class: "text-pink-400 border-pink-500/60" },
736
- { color: "secondary", look: "solid", class: "bg-indigo-500 text-white" },
737
- { color: "secondary", look: "soft", class: "bg-indigo-500/10 text-indigo-400 border-indigo-500/20" },
738
- { color: "secondary", look: ["outline", "dash"], class: "text-indigo-400 border-indigo-500/60" },
739
- { color: "accent", look: "solid", class: "bg-orange-500 text-white" },
740
- { color: "accent", look: "soft", class: "bg-orange-500/10 text-orange-400 border-orange-500/20" },
741
- { color: "accent", look: ["outline", "dash"], class: "text-orange-400 border-orange-500/60" },
742
- { color: "neutral", look: "solid", class: "bg-slate-500 text-white" },
743
- { color: "neutral", look: "soft", class: "bg-slate-500/10 text-slate-400 border-slate-500/20" },
744
- { color: "neutral", look: ["outline", "dash"], class: "text-slate-400 border-slate-500/60" },
745
- { color: "info", look: "solid", class: "bg-sky-500 text-white" },
746
- { color: "info", look: "soft", class: "bg-sky-500/10 text-sky-400 border-sky-500/20" },
747
- { color: "info", look: ["outline", "dash"], class: "text-sky-400 border-sky-500/60" },
748
- { color: "success", look: "solid", class: "bg-emerald-500 text-white" },
749
- { color: "success", look: "soft", class: "bg-emerald-500/10 text-emerald-400 border-emerald-500/20" },
750
- { color: "success", look: ["outline", "dash"], class: "text-emerald-400 border-emerald-500/60" },
751
- { color: "warning", look: "solid", class: "bg-amber-400 text-slate-900" },
752
- { color: "warning", look: "soft", class: "bg-amber-400/10 text-amber-400 border-amber-400/20" },
753
- { color: "warning", look: ["outline", "dash"], class: "text-amber-400 border-amber-400/60" },
754
- { color: "destructive", look: "solid", class: "bg-red-500 text-white" },
755
- { color: "destructive", look: "soft", class: "bg-red-500/10 text-red-400 border-red-500/20" },
756
- { color: "destructive", look: ["outline", "dash"], class: "text-red-400 border-red-500/60" }
1303
+ { color: "primary", look: "solid", class: "bg-primary text-primary-foreground" },
1304
+ { color: "primary", look: "soft", class: "bg-primary/10 text-primary border-primary/20" },
1305
+ { color: "primary", look: ["outline", "dash"], class: "text-primary border-primary/60" },
1306
+ { color: "secondary", look: "solid", class: "bg-secondary text-secondary-foreground" },
1307
+ { color: "secondary", look: "soft", class: "bg-secondary/10 text-secondary-foreground border-secondary/30" },
1308
+ { color: "secondary", look: ["outline", "dash"], class: "text-secondary-foreground border-secondary/40" },
1309
+ { color: "accent", look: "solid", class: "bg-accent text-accent-foreground" },
1310
+ { color: "accent", look: "soft", class: "bg-accent/10 text-accent-foreground border-accent/30" },
1311
+ { color: "accent", look: ["outline", "dash"], class: "text-accent-foreground border-accent/40" },
1312
+ { color: "neutral", look: "solid", class: "bg-neutral text-neutral-foreground" },
1313
+ { color: "neutral", look: "soft", class: "bg-neutral/10 text-neutral-foreground border-neutral/30" },
1314
+ { color: "neutral", look: ["outline", "dash"], class: "text-neutral-foreground border-neutral/40" },
1315
+ { color: "info", look: "solid", class: "bg-info text-info-foreground" },
1316
+ { color: "info", look: "soft", class: "bg-info/10 text-info border-info/20" },
1317
+ { color: "info", look: ["outline", "dash"], class: "text-info border-info/60" },
1318
+ { color: "success", look: "solid", class: "bg-success text-success-foreground" },
1319
+ { color: "success", look: "soft", class: "bg-success/10 text-success border-success/20" },
1320
+ { color: "success", look: ["outline", "dash"], class: "text-success border-success/60" },
1321
+ { color: "warning", look: "solid", class: "bg-warning text-warning-foreground" },
1322
+ { color: "warning", look: "soft", class: "bg-warning/10 text-warning border-warning/20" },
1323
+ { color: "warning", look: ["outline", "dash"], class: "text-warning border-warning/60" },
1324
+ { color: "destructive", look: "solid", class: "bg-destructive text-destructive-foreground" },
1325
+ { color: "destructive", look: "soft", class: "bg-destructive/10 text-destructive border-destructive/20" },
1326
+ { color: "destructive", look: ["outline", "dash"], class: "text-destructive border-destructive/60" }
757
1327
  ],
758
1328
  defaultVariants: { color: "primary", look: "solid", size: "md", shape: "default" }
759
1329
  }
760
1330
  );
761
1331
  var COLOR_TEXT_MAP = {
762
- success: "text-emerald-600",
763
- warning: "text-amber-500",
764
- accent: "text-orange-500",
765
- info: "text-sky-600",
766
- neutral: "text-slate-500",
767
- destructive: "text-red-600"
1332
+ success: "text-success",
1333
+ warning: "text-warning",
1334
+ accent: "text-accent-foreground",
1335
+ info: "text-info",
1336
+ neutral: "text-neutral-foreground",
1337
+ destructive: "text-destructive"
768
1338
  };
769
1339
  var SIZE_TEXT_MAP = {
770
1340
  sm: "text-xs",
@@ -791,10 +1361,19 @@ function Badge({
791
1361
  iconPosition = "left",
792
1362
  asChild = false,
793
1363
  children,
1364
+ style,
794
1365
  ...props
795
1366
  }) {
796
1367
  const Comp = asChild ? Slot : "span";
797
- const resolvedColor = statusMap?.[status ?? ""] ?? color;
1368
+ const recipe = useNajmComponentStyle("badge");
1369
+ const aliased = resolveVariantAlias(
1370
+ recipe?.variants,
1371
+ variant ?? recipe?.defaultVariant ?? "default"
1372
+ );
1373
+ const effVariant = variant ?? aliased.variant ?? recipe?.defaultVariant;
1374
+ const recipeRadius = shape === void 0 ? resolveRadiusValue(recipe?.radius) : void 0;
1375
+ const recipeStyle = recipeRadius ? { borderRadius: recipeRadius, ...style } : style;
1376
+ const resolvedColor = statusMap?.[status ?? ""] ?? color ?? "primary";
798
1377
  const resolvedLabel = label ?? (typeof children === "string" ? children : void 0) ?? status;
799
1378
  const content = typeof children !== "string" && children ? children : resolvedLabel ?? children;
800
1379
  const resolvedIcon = icon ?? (resolvedColor ? iconMap?.[resolvedColor] : void 0);
@@ -814,6 +1393,7 @@ function Badge({
814
1393
  sizeClass,
815
1394
  className
816
1395
  ),
1396
+ style: recipeStyle,
817
1397
  ...props,
818
1398
  children: [
819
1399
  iconPosition === "left" && iconNode,
@@ -823,8 +1403,8 @@ function Badge({
823
1403
  }
824
1404
  );
825
1405
  }
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: [
1406
+ const classes = resolvedColor ? badgeColorVariants({ color: resolvedColor, look, size, shape }) : badgeVariants({ variant: effVariant });
1407
+ return /* @__PURE__ */ jsxs(Comp, { "data-slot": "badge", className: cn(classes, aliased.style?.className, className), style: recipeStyle, ...props, children: [
828
1408
  iconPosition === "left" && iconNode,
829
1409
  content,
830
1410
  iconPosition === "right" && iconNode
@@ -1136,14 +1716,13 @@ var sheetVariants = cva(
1136
1716
  }
1137
1717
  );
1138
1718
  function SheetContent({ className, portalClassName, side, children, ...props }) {
1139
- const resolvedBorderDegree = useResolvedBorderDegree();
1140
1719
  return /* @__PURE__ */ jsx(SheetPortal, { children: /* @__PURE__ */ jsxs("div", { className: portalClassName, children: [
1141
1720
  /* @__PURE__ */ jsx(SheetOverlay, {}),
1142
1721
  /* @__PURE__ */ jsxs(
1143
1722
  SheetPrimitive.Content,
1144
1723
  {
1145
1724
  "data-slot": "sheet-content",
1146
- className: cn(sheetVariants({ side }), borderColorClassForDegree(resolvedBorderDegree), className),
1725
+ className: cn(sheetVariants({ side }), className),
1147
1726
  ...props,
1148
1727
  children: [
1149
1728
  children,
@@ -1297,7 +1876,6 @@ function DialogOverlay({ className, ...props }) {
1297
1876
  }
1298
1877
  function DialogContent({ className, children, ...props }) {
1299
1878
  const portalClassName = useNPortalScope();
1300
- const resolvedBorderDegree = useResolvedBorderDegree();
1301
1879
  return /* @__PURE__ */ jsx(DialogPortal, { "data-slot": "dialog-portal", children: /* @__PURE__ */ jsxs("div", { className: portalClassName, children: [
1302
1880
  /* @__PURE__ */ jsx(DialogOverlay, {}),
1303
1881
  /* @__PURE__ */ jsxs(
@@ -1305,8 +1883,7 @@ function DialogContent({ className, children, ...props }) {
1305
1883
  {
1306
1884
  "data-slot": "dialog-content",
1307
1885
  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),
1886
+ "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
1887
  className
1311
1888
  ),
1312
1889
  ...props,
@@ -2199,7 +2776,6 @@ function DropdownMenuSubContent({ className, ...props }) {
2199
2776
  }
2200
2777
  function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
2201
2778
  const container = React.useContext(NajmThemeContainerCtx);
2202
- const resolvedBorderDegree = useResolvedBorderDegree();
2203
2779
  useNajmPortalLayerStyles();
2204
2780
  return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx(
2205
2781
  DropdownMenuPrimitive.Content,
@@ -2208,7 +2784,6 @@ function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
2208
2784
  sideOffset,
2209
2785
  className: cn(
2210
2786
  "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
2787
  className
2213
2788
  ),
2214
2789
  ...props
@@ -2279,7 +2854,6 @@ function PopoverAnchor({ ...props }) {
2279
2854
  }
2280
2855
  function PopoverContent({ className, align = "center", sideOffset = 4, ...props }) {
2281
2856
  const container = React.useContext(NajmThemeContainerCtx);
2282
- const resolvedBorderDegree = useResolvedBorderDegree();
2283
2857
  useNajmPortalLayerStyles();
2284
2858
  return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx(
2285
2859
  PopoverPrimitive.Content,
@@ -2289,7 +2863,6 @@ function PopoverContent({ className, align = "center", sideOffset = 4, ...props
2289
2863
  sideOffset,
2290
2864
  className: cn(
2291
2865
  "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
2866
  className
2294
2867
  ),
2295
2868
  ...props
@@ -2989,7 +3562,7 @@ function Avatar({
2989
3562
  children: [
2990
3563
  hasChildren ? children : hasShortcut ? /* @__PURE__ */ jsxs(Fragment, { children: [
2991
3564
  src && /* @__PURE__ */ jsx(
2992
- "img",
3565
+ AvatarPrimitive.Image,
2993
3566
  {
2994
3567
  "data-slot": "avatar-image",
2995
3568
  src,
@@ -2998,7 +3571,7 @@ function Avatar({
2998
3571
  }
2999
3572
  ),
3000
3573
  /* @__PURE__ */ jsx(
3001
- "span",
3574
+ AvatarPrimitive.Fallback,
3002
3575
  {
3003
3576
  "data-slot": "avatar-fallback",
3004
3577
  className: cn(fallbackVariants({ size, shape }), fallbackClassName),
@@ -3023,7 +3596,7 @@ function Avatar({
3023
3596
  }
3024
3597
  function AvatarImage({ className, ...props }) {
3025
3598
  return /* @__PURE__ */ jsx(
3026
- "img",
3599
+ AvatarPrimitive.Image,
3027
3600
  {
3028
3601
  "data-slot": "avatar-image",
3029
3602
  className: cn("aspect-square size-full", className),
@@ -3033,11 +3606,10 @@ function AvatarImage({ className, ...props }) {
3033
3606
  }
3034
3607
  function AvatarFallback({
3035
3608
  className,
3036
- delayMs: _delayMs,
3037
3609
  ...props
3038
3610
  }) {
3039
3611
  return /* @__PURE__ */ jsx(
3040
- "span",
3612
+ AvatarPrimitive.Fallback,
3041
3613
  {
3042
3614
  "data-slot": "avatar-fallback",
3043
3615
  className: cn("flex size-full items-center justify-center rounded-full bg-muted", className),
@@ -3867,7 +4439,6 @@ function NAvatar({
3867
4439
  const hasText = Boolean(title || subtitle || meta);
3868
4440
  const fallbackText = fallback && !title ? fallback : label ? getInitials(label) : "?";
3869
4441
  const shapeClass = SHAPE_CLASSES[shape];
3870
- const [imgLoaded, setImgLoaded] = React__default.useState(false);
3871
4442
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3", classNames?.root, className), children: [
3872
4443
  /* @__PURE__ */ jsxs(
3873
4444
  Avatar,
@@ -3879,11 +4450,10 @@ function NAvatar({
3879
4450
  {
3880
4451
  src: imageSrc,
3881
4452
  alt: alt || label,
3882
- onLoadingStatusChange: (status) => setImgLoaded(status === "loaded"),
3883
- className: cn("absolute inset-0 z-10 object-cover", classNames?.image)
4453
+ className: cn("object-cover", classNames?.image)
3884
4454
  }
3885
4455
  ),
3886
- !imgLoaded && /* @__PURE__ */ jsx(
4456
+ /* @__PURE__ */ jsx(
3887
4457
  AvatarFallback,
3888
4458
  {
3889
4459
  style: { backgroundColor: bg, color: text },
@@ -3938,18 +4508,18 @@ function NCard({
3938
4508
  noPadding = false,
3939
4509
  separator = false,
3940
4510
  bordered,
3941
- borderDegree,
3942
4511
  className,
3943
4512
  classNames,
3944
4513
  onClick
3945
4514
  }) {
3946
4515
  const isEmpty = empty ?? noData ?? false;
3947
4516
  const resolvedEmptyText = emptyText ?? noDataText ?? "No data available";
3948
- const resolvedBorderDegree = useResolvedBorderDegree({
3949
- borderDegree,
3950
- bordered,
3951
- fallback: "default"
3952
- });
4517
+ const recipe = useNajmComponentStyle("card");
4518
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
4519
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
4520
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
4521
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
4522
+ } : void 0;
3953
4523
  let actionSlot = null;
3954
4524
  let footerSlot = null;
3955
4525
  const mainChildren = [];
@@ -3968,18 +4538,16 @@ function NCard({
3968
4538
  });
3969
4539
  const hasHeader = !!(title || description || actionSlot);
3970
4540
  const iconSize = description ? "h-8 w-8" : "h-5 w-5";
3971
- const isStrong = resolvedBorderDegree === "strong";
3972
- const isNone = resolvedBorderDegree === "none";
3973
4541
  return /* @__PURE__ */ jsxs(
3974
4542
  Card,
3975
4543
  {
3976
- "data-bordered": bordered ? "true" : void 0,
3977
- "data-border-degree": resolvedBorderDegree,
4544
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
3978
4545
  onClick,
4546
+ style: recipeStyle,
3979
4547
  className: cn(
3980
4548
  "flex flex-col",
3981
4549
  !noPadding && "p-4 gap-3",
3982
- isNone ? "border-transparent" : `${borderColorClassForDegree(resolvedBorderDegree)} ${isStrong ? "shadow-none" : ""}`,
4550
+ surfaceBorderClasses(bordered),
3983
4551
  classNames?.root,
3984
4552
  className
3985
4553
  ),
@@ -4168,7 +4736,6 @@ function DefaultCard({
4168
4736
  change,
4169
4737
  onClick,
4170
4738
  bordered,
4171
- borderDegree,
4172
4739
  className,
4173
4740
  classNames
4174
4741
  }) {
@@ -4178,7 +4745,6 @@ function DefaultCard({
4178
4745
  noPadding: true,
4179
4746
  onClick,
4180
4747
  bordered,
4181
- borderDegree,
4182
4748
  className: cn(
4183
4749
  "group p-4 transition-colors",
4184
4750
  onClick && "cursor-pointer hover:border-border/60 hover:bg-accent/40",
@@ -4235,7 +4801,6 @@ function UsageCard({
4235
4801
  countLabel,
4236
4802
  onClick,
4237
4803
  bordered,
4238
- borderDegree,
4239
4804
  className,
4240
4805
  classNames
4241
4806
  }) {
@@ -4247,7 +4812,6 @@ function UsageCard({
4247
4812
  noPadding: true,
4248
4813
  onClick,
4249
4814
  bordered,
4250
- borderDegree,
4251
4815
  className: cn(
4252
4816
  "group min-h-[116px] px-4 py-4 transition-colors",
4253
4817
  onClick && "cursor-pointer hover:bg-accent/30",
@@ -4292,14 +4856,13 @@ function UsageCard({
4292
4856
  }
4293
4857
  );
4294
4858
  }
4295
- function CompactCard({ icon, label, value, unit, iconColor, onClick, bordered, borderDegree, className, classNames }) {
4859
+ function CompactCard({ icon, label, value, unit, iconColor, onClick, bordered, className, classNames }) {
4296
4860
  return /* @__PURE__ */ jsxs(
4297
4861
  NCard,
4298
4862
  {
4299
4863
  noPadding: true,
4300
4864
  onClick,
4301
4865
  bordered,
4302
- borderDegree,
4303
4866
  className: cn(
4304
4867
  !bordered && "border-0",
4305
4868
  "bg-foreground/10 p-3 shadow-none",
@@ -5118,7 +5681,7 @@ function NFolderIcon({ size = "md", className }) {
5118
5681
  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
5682
  }
5120
5683
  var NO_SHADE = /* @__PURE__ */ new Set(["black", "white"]);
5121
- var PRESETS = {
5684
+ var PRESETS2 = {
5122
5685
  muted: "border-muted-foreground",
5123
5686
  primary: "border-primary",
5124
5687
  accent: "border-accent",
@@ -5150,15 +5713,11 @@ var FOCUS_INTERACTIVE_BASE = "border focus-within:border-primary";
5150
5713
  var HOVER_INTERACTIVE_BASE = "hover:border-primary";
5151
5714
  var STATIC_BASE = "border";
5152
5715
  var BaseInput = React__default.forwardRef(
5153
- ({ children, variant = "default", status = "default", bordered, borderDegree, borderColor, className, disabled = false, onHover, onClick, hasIcon, ...rest }, ref) => {
5716
+ ({ children, variant = "default", status = "default", bordered, borderColor, className, disabled = false, onHover, onClick, hasIcon, ...rest }, ref) => {
5154
5717
  const isGhost = variant === "ghost";
5155
5718
  const isError = status === "error";
5156
- const resolvedBorderDegree = useResolvedBorderDegree({
5157
- borderDegree,
5158
- bordered,
5159
- fallback: "default"
5160
- });
5161
5719
  const hasExplicitColor = !!borderColor;
5720
+ const isBordered = bordered !== false;
5162
5721
  let colorClass = "";
5163
5722
  let borderClass = "";
5164
5723
  if (!isGhost) {
@@ -5166,17 +5725,17 @@ var BaseInput = React__default.forwardRef(
5166
5725
  borderClass = ERROR_BORDER;
5167
5726
  } else if (hasExplicitColor) {
5168
5727
  borderClass = `${STATIC_BASE} ${FOCUS_INTERACTIVE_BASE} ${HOVER_INTERACTIVE_BASE}`;
5169
- colorClass = PRESETS[borderColor] ?? (NO_SHADE.has(borderColor) ? `border-${borderColor}` : `border-${borderColor}-600`);
5728
+ colorClass = PRESETS2[borderColor] ?? (NO_SHADE.has(borderColor) ? `border-${borderColor}` : `border-${borderColor}-600`);
5170
5729
  } 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`;
5730
+ const restingBorderClass = inputBorderClasses(isBordered);
5731
+ borderClass = isBordered ? `${STATIC_BASE} ${restingBorderClass} hover:border-input focus-within:border-primary/70` : restingBorderClass;
5173
5732
  }
5174
5733
  }
5175
5734
  return /* @__PURE__ */ jsx(
5176
5735
  "div",
5177
5736
  {
5178
5737
  ref,
5179
- "data-border-degree": isGhost ? void 0 : resolvedBorderDegree,
5738
+ "data-bordered": !isGhost && !isBordered ? "false" : !isGhost ? "true" : void 0,
5180
5739
  className: cn(
5181
5740
  inputVariants({ variant, status, hasIcon, disabled }),
5182
5741
  !isGhost && borderClass,
@@ -5201,33 +5760,33 @@ function resolveIcon(icon) {
5201
5760
  if (!icon) return null;
5202
5761
  return /* @__PURE__ */ jsx(NIcon, { icon, size: 16 });
5203
5762
  }
5204
- var TextInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, disabled = false, ...props }) => {
5763
+ var TextInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor, disabled = false, ...props }) => {
5205
5764
  const shouldDisplayIcon = Boolean(icon) && showIcon;
5206
5765
  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: [
5766
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), disabled, children: [
5208
5767
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5209
5768
  /* @__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
5769
  ] });
5211
5770
  };
5212
- var NumberInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
5771
+ var NumberInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5213
5772
  const shouldDisplayIcon = Boolean(icon) && showIcon;
5214
5773
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5215
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2", className), children: [
5774
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), children: [
5216
5775
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5217
5776
  /* @__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
5777
  ] });
5219
5778
  };
5220
- var PasswordInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
5779
+ var PasswordInput = ({ value, onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5221
5780
  const [showPassword, setShowPassword] = useState(false);
5222
5781
  const shouldDisplayIcon = Boolean(icon) && showIcon;
5223
5782
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5224
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-2", className), children: [
5783
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), children: [
5225
5784
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5226
5785
  /* @__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
5786
  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
5787
  ] });
5229
5788
  };
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(
5789
+ 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
5790
  Textarea,
5232
5791
  {
5233
5792
  rows,
@@ -5244,7 +5803,7 @@ function renderItems(items) {
5244
5803
  return /* @__PURE__ */ jsx(SelectItem, { value, children: label }, value);
5245
5804
  });
5246
5805
  }
5247
- var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, iconColor, items, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, disabled = false }) => {
5806
+ var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, iconColor, items, className = "", variant = "default", status = "default", bordered, borderColor, disabled = false }) => {
5248
5807
  const shouldDisplayIcon = Boolean(icon) && showIcon && !value;
5249
5808
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5250
5809
  const displayLabel = value ? (() => {
@@ -5252,7 +5811,7 @@ var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, i
5252
5811
  return typeof found === "string" ? found : found?.label ?? value;
5253
5812
  })() : "";
5254
5813
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
5255
- /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: "pointer-events-none", children: [
5814
+ /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: "pointer-events-none", children: [
5256
5815
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5257
5816
  /* @__PURE__ */ jsx("span", { className: cn("flex-1 truncate text-sm", !displayLabel && "text-muted-foreground"), children: displayLabel || placeholder }),
5258
5817
  /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" })
@@ -5270,7 +5829,7 @@ var SelectInput = ({ placeholder = "", value, onChange, icon, showIcon = true, i
5270
5829
  ] }, String(value))
5271
5830
  ] });
5272
5831
  };
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 }) => {
5832
+ 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
5833
  const [open, setOpen] = useState(false);
5275
5834
  const [query, setQuery] = useState("");
5276
5835
  const normalizedItems = items.map((item) => typeof item === "string" ? { value: item, label: item } : item);
@@ -5290,7 +5849,7 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
5290
5849
  setOpen(o);
5291
5850
  if (!o) setQuery("");
5292
5851
  }, children: [
5293
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("cursor-pointer", className), children: [
5852
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className: cn("cursor-pointer", className), children: [
5294
5853
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5295
5854
  /* @__PURE__ */ jsx("span", { className: cn("flex-1 truncate text-sm", !displayLabel && "text-muted-foreground"), children: displayLabel || placeholder }),
5296
5855
  /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })
@@ -5329,7 +5888,7 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
5329
5888
  ] }) })
5330
5889
  ] });
5331
5890
  };
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 }) => {
5891
+ 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
5892
  const [open, setOpen] = useState(false);
5334
5893
  const shouldDisplayIcon = Boolean(icon) && showIcon && value.length === 0;
5335
5894
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
@@ -5343,7 +5902,7 @@ var MultiSelectInput = ({ placeholder = "Select items...", value = [], onChange,
5343
5902
  const displayedItems = value.slice(0, maxDisplay);
5344
5903
  const remainingCount = value.length - maxDisplay;
5345
5904
  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: [
5905
+ /* @__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
5906
  shouldDisplayIcon && /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }),
5348
5907
  /* @__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
5908
  displayedItems.map((itemValue) => /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "text-xs px-2 py-0.5 gap-1", children: [
@@ -5377,7 +5936,7 @@ var MultiSelectInput = ({ placeholder = "Select items...", value = [], onChange,
5377
5936
  ] });
5378
5937
  };
5379
5938
  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) => {
5939
+ 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
5940
  const itemValue = typeof item === "string" ? item : item.value;
5382
5941
  const itemLabel = typeof item === "string" ? item : item.label;
5383
5942
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center space-y-0", children: [
@@ -5385,7 +5944,7 @@ var RadioGroupInput = ({ value, onChange, className = "", variant = "default", s
5385
5944
  /* @__PURE__ */ jsx(Label, { className: "text-sm font-normal peer-disabled:opacity-70 ml-1", children: itemLabel })
5386
5945
  ] }, itemValue);
5387
5946
  }) }) });
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: [
5947
+ 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
5948
  /* @__PURE__ */ jsx(Checkbox, { checked: value, onCheckedChange: onChange, className: cn("cursor-pointer transition-colors duration-200 border-primary", checkboxClassName) }),
5390
5949
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
5391
5950
  /* @__PURE__ */ jsx(Label, { className: "cursor-pointer text-muted-foreground", onClick: () => onChange(!value), children: label }),
@@ -5410,7 +5969,6 @@ function CheckboxGroupInput({
5410
5969
  variant = "default",
5411
5970
  status = "default",
5412
5971
  bordered,
5413
- borderDegree,
5414
5972
  borderColor,
5415
5973
  disabled = false
5416
5974
  }) {
@@ -5418,7 +5976,7 @@ function CheckboxGroupInput({
5418
5976
  const next = checked ? [...value, itemValue] : value.filter((v) => v !== itemValue);
5419
5977
  onChange(next);
5420
5978
  };
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) => {
5979
+ 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
5980
  const itemValue = typeof item === "string" ? item : item.value;
5423
5981
  const itemLabel = typeof item === "string" ? item : item.label;
5424
5982
  const checked = value.includes(itemValue);
@@ -5435,7 +5993,7 @@ function CheckboxGroupInput({
5435
5993
  ] }, itemValue);
5436
5994
  }) }) });
5437
5995
  }
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: [
5996
+ 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
5997
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
5440
5998
  /* @__PURE__ */ jsxs(Label, { className: "flex items-center gap-2", children: [
5441
5999
  iconPosition === "label" && icon && showIcon && /* @__PURE__ */ jsx("span", { className: "w-4 h-4", children: resolveIcon(icon) }),
@@ -5448,10 +6006,10 @@ var SwitchInput = ({ value, onChange, label = "", helper, className = "", varian
5448
6006
  /* @__PURE__ */ jsx(Switch, { checked: value, onCheckedChange: onChange })
5449
6007
  ] })
5450
6008
  ] });
5451
- var DateInput = ({ value, onChange, placeholder = "Pick a date", className = "", icon, showIcon = true, iconColor, variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
6009
+ var DateInput = ({ value, onChange, placeholder = "Pick a date", className = "", icon, showIcon = true, iconColor, variant = "default", status = "default", bordered, borderColor }) => {
5452
6010
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5453
6011
  const toDateString = (date) => date?.toISOString().split("T")[0];
5454
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderDegree, borderColor, className, children: [
6012
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className, children: [
5455
6013
  /* @__PURE__ */ jsxs(Popover, { children: [
5456
6014
  /* @__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
6015
  /* @__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 +6024,7 @@ function truncateFilename(filename, maxLength = 25) {
5466
6024
  const name = extIndex !== -1 ? filename.slice(0, extIndex) : filename;
5467
6025
  return `${name.slice(0, maxLength - ext.length - 3)}...${ext}`;
5468
6026
  }
5469
- var FileInput = ({ value, onChange, placeholder = "No file chosen", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
6027
+ var FileInput = ({ value, onChange, placeholder = "No file chosen", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5470
6028
  const fileInputRef = useRef(null);
5471
6029
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
5472
6030
  const displayFilename = () => {
@@ -5474,7 +6032,7 @@ var FileInput = ({ value, onChange, placeholder = "No file chosen", icon, showIc
5474
6032
  const filename = typeof value === "string" ? value.split(/[\\/]/).pop() || "" : value.name;
5475
6033
  return truncateFilename(filename);
5476
6034
  };
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: [
6035
+ 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
6036
  /* @__PURE__ */ jsx("input", { type: "file", ref: fileInputRef, onChange: (e) => onChange(e.target.files?.[0] || null), className: "hidden" }),
5479
6037
  /* @__PURE__ */ jsxs("div", { className: "bg-muted flex h-full items-center px-3", children: [
5480
6038
  showIcon && (icon ? /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }) : /* @__PURE__ */ jsx(FileUp, { className: cn(iconProps.className) })),
@@ -5500,18 +6058,12 @@ function NUploader({
5500
6058
  listTitle = "Uploaded files",
5501
6059
  className,
5502
6060
  dropzoneClassName,
5503
- borderDegree,
5504
6061
  onFilesSelected,
5505
6062
  onCancel,
5506
6063
  onRemove
5507
6064
  }) {
5508
6065
  const inputRef = useRef(null);
5509
6066
  const [isDragging, setIsDragging] = useState(false);
5510
- const resolvedBorderDegree = useResolvedBorderDegree({
5511
- borderDegree,
5512
- fallback: "default"
5513
- });
5514
- const dropzoneBorderClass = borderColorClassForDegree(resolvedBorderDegree);
5515
6067
  const emit = useCallback(
5516
6068
  (files) => {
5517
6069
  if (!files || disabled) return;
@@ -5555,8 +6107,7 @@ function NUploader({
5555
6107
  onDragLeave,
5556
6108
  onDrop,
5557
6109
  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,
6110
+ "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
6111
  "bg-muted/40 hover:bg-muted/60",
5561
6112
  isDragging && "border-primary bg-primary/5",
5562
6113
  disabled && "cursor-not-allowed opacity-60",
@@ -5792,18 +6343,52 @@ function ImageInput({
5792
6343
  renderFileInput()
5793
6344
  ] });
5794
6345
  }
5795
- var StarRatingInput = ({ value, onChange, maxStars = 5, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor }) => {
6346
+ var StarRatingInput = ({ value, onChange, maxStars = 5, className = "", variant = "default", status = "default", bordered, borderColor }) => {
5796
6347
  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 });
6348
+ return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-2", className), children: stars });
5798
6349
  };
5799
6350
  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 }) => {
6351
+ var ColorArrayInput = ({ value, onChange, className = "", variant = "default", status = "default", bordered, borderColor, colors = DEFAULT_COLORS }) => {
5801
6352
  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: () => {
6353
+ 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
6354
  setSelectedColor(color);
5804
6355
  onChange(color);
5805
6356
  }, 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
6357
  };
6358
+ var toOklch = converter("oklch");
6359
+ function parseColor(input) {
6360
+ return parse((input ?? "").trim());
6361
+ }
6362
+ function formatColor(input, format2) {
6363
+ const c = parseColor(input);
6364
+ if (!c) return input;
6365
+ switch (format2) {
6366
+ case "hex":
6367
+ return formatHex(c) ?? input;
6368
+ case "rgb":
6369
+ return formatRgb(c) ?? input;
6370
+ case "hsl":
6371
+ return formatHsl(c) ?? input;
6372
+ case "oklch": {
6373
+ const o = toOklch(c);
6374
+ if (!o) return input;
6375
+ const l = +o.l.toFixed(4);
6376
+ const ch = +(o.c ?? 0).toFixed(4);
6377
+ const h = +(o.h ?? 0).toFixed(2);
6378
+ return `oklch(${l} ${ch} ${h})`;
6379
+ }
6380
+ }
6381
+ }
6382
+ function detectFormat(input) {
6383
+ const value = (input ?? "").trim().toLowerCase();
6384
+ if (value.startsWith("oklch")) return "oklch";
6385
+ if (value.startsWith("hsl")) return "hsl";
6386
+ if (value.startsWith("rgb")) return "rgb";
6387
+ return "hex";
6388
+ }
6389
+ function toPickerHex(input) {
6390
+ return formatHex(parseColor(input) ?? parseColor("#000000")) ?? "#000000";
6391
+ }
5807
6392
  var PRESET_COLORS = [
5808
6393
  "#EF4444",
5809
6394
  "#F97316",
@@ -5826,7 +6411,14 @@ var PRESET_COLORS = [
5826
6411
  "#6B7280",
5827
6412
  "#000000"
5828
6413
  ];
5829
- function ColorPickerInput({
6414
+ var DEFAULT_FORMATS = ["hex", "rgb", "hsl", "oklch"];
6415
+ function ColorPickerInput(props) {
6416
+ if (props.mode === "popover") {
6417
+ return /* @__PURE__ */ jsx(PopoverColorPicker, { ...props });
6418
+ }
6419
+ return /* @__PURE__ */ jsx(SwatchesColorPicker, { ...props });
6420
+ }
6421
+ function SwatchesColorPicker({
5830
6422
  value = "#000000",
5831
6423
  onChange,
5832
6424
  colors = PRESET_COLORS,
@@ -5834,9 +6426,9 @@ function ColorPickerInput({
5834
6426
  variant = "default",
5835
6427
  status = "default",
5836
6428
  bordered,
5837
- borderDegree,
5838
6429
  borderColor,
5839
- disabled = false
6430
+ disabled = false,
6431
+ hideSwatches = false
5840
6432
  }) {
5841
6433
  const inputRef = useRef(null);
5842
6434
  return /* @__PURE__ */ jsxs(
@@ -5845,7 +6437,6 @@ function ColorPickerInput({
5845
6437
  variant,
5846
6438
  status,
5847
6439
  bordered,
5848
- borderDegree,
5849
6440
  borderColor,
5850
6441
  className: cn("flex-col gap-3 items-start p-3", className),
5851
6442
  disabled,
@@ -5865,14 +6456,14 @@ function ColorPickerInput({
5865
6456
  {
5866
6457
  ref: inputRef,
5867
6458
  type: "color",
5868
- value,
6459
+ value: toPickerHex(value),
5869
6460
  onChange: (e) => onChange(e.target.value),
5870
6461
  disabled,
5871
6462
  className: "sr-only"
5872
6463
  }
5873
6464
  )
5874
6465
  ] }),
5875
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: colors.map((color) => /* @__PURE__ */ jsx(
6466
+ !hideSwatches && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: colors.map((color) => /* @__PURE__ */ jsx(
5876
6467
  "button",
5877
6468
  {
5878
6469
  type: "button",
@@ -5882,7 +6473,7 @@ function ColorPickerInput({
5882
6473
  },
5883
6474
  disabled,
5884
6475
  className: cn(
5885
- "w-6 h-6 rounded-md border border-border transition-transform hover:scale-110",
6476
+ "w-6 h-6 rounded-md border border-border transition-transform hover:scale-110 cursor-pointer",
5886
6477
  value === color && "ring-2 ring-primary ring-offset-1"
5887
6478
  ),
5888
6479
  style: { backgroundColor: color },
@@ -5894,6 +6485,121 @@ function ColorPickerInput({
5894
6485
  }
5895
6486
  );
5896
6487
  }
6488
+ function PopoverColorPicker({
6489
+ value = "#000000",
6490
+ onChange,
6491
+ colors = PRESET_COLORS,
6492
+ className,
6493
+ variant = "default",
6494
+ status = "default",
6495
+ bordered,
6496
+ borderColor,
6497
+ disabled = false,
6498
+ hideSwatches = false,
6499
+ formats = DEFAULT_FORMATS,
6500
+ output = "preserve"
6501
+ }) {
6502
+ const initialFormat = formats.includes(detectFormat(value)) ? detectFormat(value) : formats[0] ?? "hex";
6503
+ const [activeFormat, setActiveFormat] = useState(initialFormat);
6504
+ const [draft, setDraft] = useState(value);
6505
+ useEffect(() => {
6506
+ setDraft(value);
6507
+ }, [value]);
6508
+ const outputFormat = output;
6509
+ const emit = (raw) => {
6510
+ if (outputFormat === "preserve") {
6511
+ onChange(raw);
6512
+ } else {
6513
+ onChange(formatColor(raw, outputFormat));
6514
+ }
6515
+ };
6516
+ const handlePickerChange = (hex) => {
6517
+ setDraft(hex);
6518
+ emit(hex);
6519
+ };
6520
+ const handleTextChange = (text) => {
6521
+ setDraft(text);
6522
+ if (parseColor(text)) emit(text);
6523
+ };
6524
+ const handleTabChange = (next) => {
6525
+ setActiveFormat(next);
6526
+ if (parseColor(draft)) setDraft(formatColor(draft, next));
6527
+ };
6528
+ const handlePreset = (color) => {
6529
+ setDraft(color);
6530
+ emit(color);
6531
+ };
6532
+ return /* @__PURE__ */ jsxs(Popover, { children: [
6533
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ jsxs(
6534
+ "button",
6535
+ {
6536
+ type: "button",
6537
+ disabled,
6538
+ className: cn(
6539
+ "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",
6540
+ status === "error" && "border-destructive",
6541
+ className
6542
+ ),
6543
+ children: [
6544
+ /* @__PURE__ */ jsx(
6545
+ "span",
6546
+ {
6547
+ className: "w-8 h-8 rounded-md border border-border shrink-0",
6548
+ style: { backgroundColor: toPickerHex(value) }
6549
+ }
6550
+ ),
6551
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground font-mono truncate", children: value })
6552
+ ]
6553
+ }
6554
+ ) }),
6555
+ /* @__PURE__ */ jsxs(PopoverContent, { className: "w-64 flex flex-col gap-3", align: "start", children: [
6556
+ /* @__PURE__ */ jsx(
6557
+ HexColorPicker,
6558
+ {
6559
+ color: toPickerHex(draft),
6560
+ onChange: handlePickerChange,
6561
+ style: { width: "100%" }
6562
+ }
6563
+ ),
6564
+ formats.length > 1 && /* @__PURE__ */ jsx("div", { className: "flex gap-1 rounded-md bg-muted p-1", children: formats.map((fmt) => /* @__PURE__ */ jsx(
6565
+ "button",
6566
+ {
6567
+ type: "button",
6568
+ onClick: () => handleTabChange(fmt),
6569
+ className: cn(
6570
+ "flex-1 rounded-sm px-1.5 py-1 text-xs font-medium uppercase cursor-pointer transition-colors",
6571
+ activeFormat === fmt ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
6572
+ ),
6573
+ children: fmt
6574
+ },
6575
+ fmt
6576
+ )) }),
6577
+ /* @__PURE__ */ jsx(
6578
+ "input",
6579
+ {
6580
+ type: "text",
6581
+ value: draft,
6582
+ onChange: (e) => handleTextChange(e.target.value),
6583
+ spellCheck: false,
6584
+ 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"
6585
+ }
6586
+ ),
6587
+ !hideSwatches && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: colors.map((color) => /* @__PURE__ */ jsx(
6588
+ "button",
6589
+ {
6590
+ type: "button",
6591
+ onClick: () => handlePreset(color),
6592
+ className: cn(
6593
+ "w-5 h-5 rounded-md border border-border transition-transform hover:scale-110 cursor-pointer"
6594
+ ),
6595
+ style: { backgroundColor: color },
6596
+ title: color
6597
+ },
6598
+ color
6599
+ )) })
6600
+ ] })
6601
+ ] });
6602
+ }
5897
6603
  var DEFAULT_OPTIONS = [
5898
6604
  { value: 5, label: "Excellent" },
5899
6605
  { value: 4, label: "Good" },
@@ -5934,7 +6640,6 @@ function EmojiInput({
5934
6640
  variant = "default",
5935
6641
  status = "default",
5936
6642
  bordered,
5937
- borderDegree,
5938
6643
  borderColor,
5939
6644
  disabled = false
5940
6645
  }) {
@@ -5944,7 +6649,6 @@ function EmojiInput({
5944
6649
  variant,
5945
6650
  status,
5946
6651
  bordered,
5947
- borderDegree,
5948
6652
  borderColor,
5949
6653
  className: cn("gap-3 flex-wrap", className),
5950
6654
  disabled,
@@ -6016,7 +6720,6 @@ function PhoneInput({
6016
6720
  variant = "default",
6017
6721
  status = "default",
6018
6722
  bordered,
6019
- borderDegree,
6020
6723
  borderColor
6021
6724
  }) {
6022
6725
  const phoneThemeVars = {
@@ -6041,7 +6744,7 @@ function PhoneInput({
6041
6744
  "--react-international-phone-dropdown-preferred-list-divider-color": "var(--border)",
6042
6745
  "--react-international-phone-dropdown-shadow": "0 16px 40px color-mix(in oklch, var(--background), transparent 55%)"
6043
6746
  };
6044
- return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderDegree, borderColor, className: cn("gap-0 overflow-visible p-0!", className), disabled, children: /* @__PURE__ */ jsx(
6747
+ return /* @__PURE__ */ jsx(BaseInput, { variant, status, bordered, borderColor, className: cn("gap-0 overflow-visible p-0!", className), disabled, children: /* @__PURE__ */ jsx(
6045
6748
  PhoneInput$1,
6046
6749
  {
6047
6750
  className: "w-full",
@@ -6102,7 +6805,7 @@ function PhoneInput({
6102
6805
  }
6103
6806
  ) });
6104
6807
  }
6105
- var TimeInput = ({ value = "", onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderDegree, borderColor, format24 = true, showSeconds = false, disabled = false }) => {
6808
+ var TimeInput = ({ value = "", onChange, placeholder = "", icon, showIcon = true, iconColor, className = "", variant = "default", status = "default", bordered, borderColor, format24 = true, showSeconds = false, disabled = false }) => {
6106
6809
  const [inputValue, setInputValue] = useState(value);
6107
6810
  const [isValid, setIsValid] = useState(true);
6108
6811
  useEffect(() => {
@@ -6150,7 +6853,7 @@ var TimeInput = ({ value = "", onChange, placeholder = "", icon, showIcon = true
6150
6853
  };
6151
6854
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
6152
6855
  const currentStatus = !isValid ? "error" : status;
6153
- return /* @__PURE__ */ jsxs(BaseInput, { variant, status: currentStatus, bordered, borderDegree, borderColor, className: cn("gap-2", className), children: [
6856
+ return /* @__PURE__ */ jsxs(BaseInput, { variant, status: currentStatus, bordered, borderColor, className: cn("gap-2", className), children: [
6154
6857
  showIcon && (icon ? /* @__PURE__ */ jsx("span", { className: iconProps.className, style: iconProps.style, children: resolveIcon(icon) }) : /* @__PURE__ */ jsx(Clock, { className: iconProps.className, style: iconProps.style })),
6155
6858
  /* @__PURE__ */ jsx(Input, { type: "text", placeholder: placeholder || (showSeconds ? "HH:MM:SS" : "HH:MM"), value: inputValue, onChange: (e) => handleInputChange(e.target.value), onKeyDown: (e) => {
6156
6859
  if (!/\d/.test(e.key) && !["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab"].includes(e.key)) e.preventDefault();
@@ -6579,12 +7282,11 @@ var VARIANT_PRESETS = {
6579
7282
  }
6580
7283
  };
6581
7284
  var VariantContext = createContext({ variant: "default" });
6582
- var VariantProvider = ({ variant = "default", bordered, borderDegree, children }) => /* @__PURE__ */ jsx(VariantContext.Provider, { value: { variant, bordered, borderDegree }, children });
7285
+ var VariantProvider = ({ variant = "default", bordered, children }) => /* @__PURE__ */ jsx(VariantContext.Provider, { value: { variant, bordered }, children });
6583
7286
  var useVariant = () => useContext(VariantContext).variant;
6584
7287
  var useBordered = () => useContext(VariantContext).bordered;
6585
- var useBorderDegree = () => useContext(VariantContext).borderDegree;
6586
7288
  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 }) {
7289
+ function NFormInner({ schema, defaultValues, onSubmit, form: externalForm, variant = "default", bordered, as = "form", className = "", id, devTools, children }) {
6588
7290
  const resolver = useMemo(() => schema ? zodResolver(schema) : void 0, [schema]);
6589
7291
  const internalForm = useForm({
6590
7292
  resolver,
@@ -6616,7 +7318,7 @@ function NFormInner({ schema, defaultValues, onSubmit, form: externalForm, varia
6616
7318
  }, [form.formState.errors]);
6617
7319
  const wrapperClass = cn("flex flex-col h-full w-full gap-4", className);
6618
7320
  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) => {
7321
+ 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
7322
  if (e.key === "Enter" && e.target.tagName !== "TEXTAREA") {
6621
7323
  e.preventDefault();
6622
7324
  void submit();
@@ -6679,7 +7381,6 @@ var FormInput = ({ name, type, formLabel, formDescription, required = false, dis
6679
7381
  const prefix = usePrefix();
6680
7382
  const preset = useVariantPreset();
6681
7383
  const contextBordered = useBordered();
6682
- const contextBorderDegree = useBorderDegree();
6683
7384
  const fieldName = prefix ? `${prefix}.${name}` : name;
6684
7385
  if (!InputComponent) return null;
6685
7386
  const getDefaultValue = () => {
@@ -6710,7 +7411,7 @@ var FormInput = ({ name, type, formLabel, formDescription, required = false, dis
6710
7411
  formLabel,
6711
7412
  required && !disabled && !readOnly && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" })
6712
7413
  ] }),
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 }) }),
7414
+ /* @__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
7415
  !hasError && !disabled && !readOnly && formDescription && /* @__PURE__ */ jsx(FormDescription, { className: slot.description, children: formDescription }),
6715
7416
  !isHidden && /* @__PURE__ */ jsx(FormMessage, { className: slot.error })
6716
7417
  ] });
@@ -7041,7 +7742,6 @@ function WizardForm({
7041
7742
  submitLabel = "Submit",
7042
7743
  variant = "default",
7043
7744
  bordered,
7044
- borderDegree,
7045
7745
  className,
7046
7746
  classNames,
7047
7747
  footerSlot
@@ -7101,7 +7801,7 @@ function WizardForm({
7101
7801
  classNames
7102
7802
  }
7103
7803
  ),
7104
- /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsx(VariantProvider, { variant, bordered, borderDegree, children: /* @__PURE__ */ jsxs(
7804
+ /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsx(VariantProvider, { variant, bordered, children: /* @__PURE__ */ jsxs(
7105
7805
  "form",
7106
7806
  {
7107
7807
  id: `step-${currentStepConfig.id}`,
@@ -7135,18 +7835,12 @@ var handler = {
7135
7835
  }
7136
7836
  };
7137
7837
  useTableStore.use = new Proxy({}, handler);
7138
- var actionButtonClass = (bordered, danger, borderClass) => cn(
7838
+ var actionButtonClass = (bordered, danger) => cn(
7139
7839
  "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors",
7140
7840
  danger ? "hover:bg-red-500/10 hover:text-red-400" : "hover:bg-muted hover:text-foreground",
7141
- bordered && `border ${borderClass ?? "border-muted-foreground"}`
7841
+ bordered && "border border-muted-foreground"
7142
7842
  );
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);
7843
+ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButton, bordered }) {
7150
7844
  if (menuButton && openRowMenu) {
7151
7845
  return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center gap-1", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(
7152
7846
  "button",
@@ -7169,7 +7863,7 @@ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButto
7169
7863
  type: "button",
7170
7864
  "aria-label": "View",
7171
7865
  onClick: () => onView(row.original),
7172
- className: actionButtonClass(bordered, false, borderClass),
7866
+ className: actionButtonClass(bordered, false),
7173
7867
  children: /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5" })
7174
7868
  }
7175
7869
  ),
@@ -7179,7 +7873,7 @@ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButto
7179
7873
  type: "button",
7180
7874
  "aria-label": "Edit",
7181
7875
  onClick: () => onEdit(row.original),
7182
- className: actionButtonClass(bordered, false, borderClass),
7876
+ className: actionButtonClass(bordered, false),
7183
7877
  children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
7184
7878
  }
7185
7879
  ),
@@ -7189,7 +7883,7 @@ function TableActionCell({ row, onView, onEdit, onDelete, openRowMenu, menuButto
7189
7883
  type: "button",
7190
7884
  "aria-label": "Delete",
7191
7885
  onClick: () => onDelete(row.original),
7192
- className: actionButtonClass(bordered, true, borderClass),
7886
+ className: actionButtonClass(bordered, true),
7193
7887
  children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
7194
7888
  }
7195
7889
  )
@@ -7265,9 +7959,10 @@ var createTableStore = () => {
7265
7959
  className: "",
7266
7960
  classNames: {},
7267
7961
  bordered: void 0,
7268
- borderDegree: void 0,
7269
7962
  headerClassName: "bg-card",
7270
- headerColor: "primary",
7963
+ headerColor: void 0,
7964
+ headerTextColor: void 0,
7965
+ borderColor: void 0,
7271
7966
  showCheckbox: true,
7272
7967
  selectedRowId: null,
7273
7968
  headerSlot: null,
@@ -7519,7 +8214,6 @@ function useTable() {
7519
8214
  const openRowMenu = useTableStore.use.openRowMenu();
7520
8215
  const menuButton = useTableStore.use.menuButton();
7521
8216
  const bordered = useTableStore.use.bordered();
7522
- const borderDegree = useTableStore.use.borderDegree();
7523
8217
  const CardComponent = useTableStore.use.CardComponent();
7524
8218
  const dynamicHeight = useTableStore.use.dynamicHeight();
7525
8219
  const viewMode = useTableStore.use.viewMode();
@@ -7550,14 +8244,14 @@ function useTable() {
7550
8244
  {
7551
8245
  id: "actions",
7552
8246
  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 }),
8247
+ cell: ({ row }) => React__default.createElement(TableActionCell, { row, onView, onEdit, onDelete, openRowMenu, menuButton, bordered }),
7554
8248
  enableSorting: false,
7555
8249
  enableHiding: false
7556
8250
  }
7557
8251
  ];
7558
8252
  }
7559
8253
  return effectiveColumns;
7560
- }, [columns, CardComponent, hasActions, onView, onEdit, onDelete, openRowMenu, menuButton, bordered, borderDegree]);
8254
+ }, [columns, CardComponent, hasActions, onView, onEdit, onDelete, openRowMenu, menuButton, bordered]);
7561
8255
  const notifyStateChange = useCallback((state) => {
7562
8256
  onStateChange?.(state);
7563
8257
  }, [onStateChange]);
@@ -7678,17 +8372,47 @@ function useTableKeyboard(options = {}) {
7678
8372
  }
7679
8373
 
7680
8374
  // src/components/table/tableColors.ts
7681
- var HEADER_COLORS = {
7682
- primary: { bg: "bg-primary/15", text: "[&_th]:text-foreground", row: "hover:bg-primary/5" },
7683
- violet: { bg: "bg-violet-600/30", text: "[&_th]:text-violet-800 dark:[&_th]:text-violet-300", row: "hover:bg-violet-500/5" },
7684
- blue: { bg: "bg-blue-600/30", text: "[&_th]:text-blue-800 dark:[&_th]:text-blue-300", row: "hover:bg-blue-500/5" },
7685
- emerald: { bg: "bg-emerald-600/30", text: "[&_th]:text-emerald-800 dark:[&_th]:text-emerald-400", row: "hover:bg-emerald-500/5" },
7686
- amber: { bg: "bg-amber-500/30", text: "[&_th]:text-amber-800 dark:[&_th]:text-amber-300", row: "hover:bg-amber-500/5" },
7687
- rose: { bg: "bg-rose-600/30", text: "[&_th]:text-rose-800 dark:[&_th]:text-rose-300", row: "hover:bg-rose-500/5" },
7688
- slate: { bg: "bg-slate-700/60", text: "[&_th]:text-slate-100 dark:[&_th]:text-slate-400", row: "hover:bg-slate-500/5" }
7689
- };
7690
- var HEADER_HEX = {
7691
- primary: "",
8375
+ var DEFAULT_TABLE_HEADER_COLOR = "var(--primary)";
8376
+ var DEFAULT_TABLE_HEADER_TEXT_COLOR = "var(--primary-foreground)";
8377
+ var DEFAULT_TABLE_BORDER_COLOR = "var(--border)";
8378
+ var THEME_COLOR_TOKENS = /* @__PURE__ */ new Set([
8379
+ "background",
8380
+ "foreground",
8381
+ "card",
8382
+ "card-foreground",
8383
+ "popover",
8384
+ "popover-foreground",
8385
+ "primary",
8386
+ "primary-foreground",
8387
+ "secondary",
8388
+ "secondary-foreground",
8389
+ "tertiary",
8390
+ "tertiary-foreground",
8391
+ "muted",
8392
+ "muted-foreground",
8393
+ "accent",
8394
+ "accent-foreground",
8395
+ "destructive",
8396
+ "destructive-foreground",
8397
+ "border",
8398
+ "input",
8399
+ "ring",
8400
+ "sidebar",
8401
+ "sidebar-foreground",
8402
+ "sidebar-primary",
8403
+ "sidebar-primary-foreground",
8404
+ "sidebar-accent",
8405
+ "sidebar-accent-foreground",
8406
+ "sidebar-border",
8407
+ "sidebar-ring",
8408
+ "chart-1",
8409
+ "chart-2",
8410
+ "chart-3",
8411
+ "chart-4",
8412
+ "chart-5"
8413
+ ]);
8414
+ var TABLE_HEADER_COLOR_PRESETS = {
8415
+ primary: DEFAULT_TABLE_HEADER_COLOR,
7692
8416
  violet: "#7c3aed",
7693
8417
  blue: "#2563eb",
7694
8418
  emerald: "#059669",
@@ -7696,6 +8420,17 @@ var HEADER_HEX = {
7696
8420
  rose: "#e11d48",
7697
8421
  slate: "#475569"
7698
8422
  };
8423
+ function resolveTableColor(value, fallback) {
8424
+ const color = value?.trim();
8425
+ if (!color) return fallback;
8426
+ if (color in TABLE_HEADER_COLOR_PRESETS) {
8427
+ return TABLE_HEADER_COLOR_PRESETS[color];
8428
+ }
8429
+ if (THEME_COLOR_TOKENS.has(color)) {
8430
+ return `var(--${color})`;
8431
+ }
8432
+ return color;
8433
+ }
7699
8434
  var ROW_CONTEXT_HANDLED = "__ntableRowContextHandled";
7700
8435
  function EditableCell({ cell, onCellEdit }) {
7701
8436
  const columnDef = cell.column.columnDef;
@@ -7750,6 +8485,12 @@ function EditableCell({ cell, onCellEdit }) {
7750
8485
  ] });
7751
8486
  }
7752
8487
  function NTableContent({ effectiveMode }) {
8488
+ const recipe = useNajmComponentStyle("table");
8489
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
8490
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
8491
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
8492
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
8493
+ } : void 0;
7753
8494
  const table = useTableStore.use.table();
7754
8495
  const storeIsTableView = useTableStore.use.isTableView();
7755
8496
  const columns = useTableStore.use.columns();
@@ -7757,7 +8498,20 @@ function NTableContent({ effectiveMode }) {
7757
8498
  const noResultsText = useTableStore.use.noResultsText();
7758
8499
  const headerClassName = useTableStore.use.headerClassName();
7759
8500
  const headerColor = useTableStore.use.headerColor();
7760
- const colorStyle = headerColor ? HEADER_COLORS[headerColor] : null;
8501
+ const headerTextColor = useTableStore.use.headerTextColor();
8502
+ const tableBorderColor = useTableStore.use.borderColor();
8503
+ const resolvedHeaderColor = resolveTableColor(headerColor, DEFAULT_TABLE_HEADER_COLOR);
8504
+ const resolvedHeaderTextColor = resolveTableColor(headerTextColor, DEFAULT_TABLE_HEADER_TEXT_COLOR);
8505
+ const resolvedBorderColor = resolveTableColor(tableBorderColor, DEFAULT_TABLE_BORDER_COLOR);
8506
+ const headerCellStyle = {
8507
+ backgroundColor: resolvedHeaderColor,
8508
+ color: resolvedHeaderTextColor
8509
+ };
8510
+ const contentStyle = recipeStyle || tableBorderColor ? {
8511
+ ...recipeStyle ?? {},
8512
+ ...tableBorderColor ? { borderColor: resolvedBorderColor } : {}
8513
+ } : void 0;
8514
+ const rowBorderStyle = tableBorderColor ? { borderColor: resolvedBorderColor } : void 0;
7761
8515
  const onRowClick = useTableStore.use.onRowClick();
7762
8516
  const onRowContextMenu = useTableStore.use.onRowContextMenu();
7763
8517
  const onBackgroundContextMenu = useTableStore.use.onBackgroundContextMenu();
@@ -7768,15 +8522,6 @@ function NTableContent({ effectiveMode }) {
7768
8522
  const showContent = useTableStore.use.showContent();
7769
8523
  const classNames = useTableStore.use.classNames();
7770
8524
  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
8525
  const showCheckbox = useTableStore.use.showCheckbox();
7781
8526
  const selectedRowId = useTableStore.use.selectedRowId();
7782
8527
  const renderSubRow = useTableStore.use.renderSubRow();
@@ -7803,29 +8548,51 @@ function NTableContent({ effectiveMode }) {
7803
8548
  NajmScroll,
7804
8549
  {
7805
8550
  axis: "both",
7806
- "data-border-degree": resolvedBorderDegree,
8551
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
7807
8552
  className: cn(
7808
8553
  "min-h-0 flex-1 overflow-hidden rounded-md bg-card",
7809
- useDegreeBorder ? `border ${tableBorderClass}` : "shadow-sm",
7810
- isStrong && "shadow-none",
8554
+ bordered === true ? surfaceBorderClasses(true) : "shadow-sm",
7811
8555
  classNames?.content
7812
8556
  ),
8557
+ style: contentStyle,
7813
8558
  onContextMenu: handleBackgroundContextMenu,
7814
8559
  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: [
7816
- showCheckbox && /* @__PURE__ */ jsx(TableHead, { className: cn("w-10 text-foreground h-12 text-center", colorStyle?.bg), children: /* @__PURE__ */ jsx(
7817
- Checkbox,
8560
+ /* @__PURE__ */ jsx(TableHeader, { "data-ntable-table-header": true, className: cn("bg-card sticky top-0 z-10", headerClassName, bordered === true && "[&_tr]:border-border", classNames?.tableHeader), children: table.getHeaderGroups().map((hg) => /* @__PURE__ */ jsxs(TableRow, { style: rowBorderStyle, className: cn("hover:bg-transparent", bordered === true && "border-border"), children: [
8561
+ showCheckbox && /* @__PURE__ */ jsx(
8562
+ TableHead,
7818
8563
  {
7819
- "aria-label": "Select all rows",
7820
- checked: table.getIsAllPageRowsSelected(),
7821
- onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value)
8564
+ className: "w-10 text-foreground h-12 text-center",
8565
+ style: headerCellStyle,
8566
+ children: /* @__PURE__ */ jsx(
8567
+ Checkbox,
8568
+ {
8569
+ "aria-label": "Select all rows",
8570
+ checked: table.getIsAllPageRowsSelected(),
8571
+ onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value)
8572
+ }
8573
+ )
7822
8574
  }
7823
- ) }),
7824
- hasExpansion && /* @__PURE__ */ jsx(TableHead, { "aria-label": "Expand column", className: cn("w-10 text-foreground h-12", colorStyle?.bg) }),
7825
- hg.headers.map((header) => /* @__PURE__ */ jsx(TableHead, { className: cn("text-foreground h-12", colorStyle?.bg), children: header.isPlaceholder ? null : /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", header.column.getCanSort() && showSorting && "cursor-pointer select-none"), onClick: header.column.getToggleSortingHandler(), children: [
7826
- flexRender(header.column.columnDef.header, header.getContext()),
7827
- header.column.getCanSort() && showSorting && /* @__PURE__ */ jsx("span", { children: getSortIcon(header.column) })
7828
- ] }) }, header.id))
8575
+ ),
8576
+ hasExpansion && /* @__PURE__ */ jsx(
8577
+ TableHead,
8578
+ {
8579
+ "aria-label": "Expand column",
8580
+ className: "w-10 text-foreground h-12",
8581
+ style: headerCellStyle
8582
+ }
8583
+ ),
8584
+ hg.headers.map((header) => /* @__PURE__ */ jsx(
8585
+ TableHead,
8586
+ {
8587
+ className: "text-foreground h-12",
8588
+ style: headerCellStyle,
8589
+ children: header.isPlaceholder ? null : /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", header.column.getCanSort() && showSorting && "cursor-pointer select-none"), onClick: header.column.getToggleSortingHandler(), children: [
8590
+ flexRender(header.column.columnDef.header, header.getContext()),
8591
+ header.column.getCanSort() && showSorting && /* @__PURE__ */ jsx("span", { children: getSortIcon(header.column) })
8592
+ ] })
8593
+ },
8594
+ header.id
8595
+ ))
7829
8596
  ] }, hg.id)) }),
7830
8597
  /* @__PURE__ */ jsx(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => {
7831
8598
  const isSelectedByRowId = Boolean(selectedRowId && row.original?.id === selectedRowId);
@@ -7845,7 +8612,8 @@ function NTableContent({ effectiveMode }) {
7845
8612
  e.nativeEvent[ROW_CONTEXT_HANDLED] = true;
7846
8613
  onRowContextMenu(e, row.original);
7847
8614
  } : void 0,
7848
- className: cn(colorStyle?.row, classNames?.row, onRowClick && "cursor-pointer", isSelectedByRowId && "bg-primary/5 hover:bg-primary/5", useDegreeBorder && "border-border"),
8615
+ style: rowBorderStyle,
8616
+ className: cn(classNames?.row, onRowClick && "cursor-pointer", isSelectedByRowId && "bg-primary/5 hover:bg-primary/5", bordered === true && "border-border"),
7849
8617
  children: [
7850
8618
  showCheckbox && /* @__PURE__ */ jsx(TableCell, { className: "h-14 w-10 text-center", children: /* @__PURE__ */ jsx(
7851
8619
  Checkbox,
@@ -7868,7 +8636,7 @@ function NTableContent({ effectiveMode }) {
7868
8636
  },
7869
8637
  className: cn(
7870
8638
  "flex h-6 w-6 items-center justify-center rounded hover:bg-muted",
7871
- useDegreeBorder && `border ${tableBorderClass}`
8639
+ bordered === true && "border border-border"
7872
8640
  ),
7873
8641
  children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
7874
8642
  }
@@ -7882,41 +8650,39 @@ function NTableContent({ effectiveMode }) {
7882
8650
  ]
7883
8651
  }
7884
8652
  ),
7885
- isExpanded && renderSubRow && /* @__PURE__ */ jsx(TableRow, { "data-expanded-row": "true", className: "bg-muted/40 hover:bg-muted/40", children: /* @__PURE__ */ jsx(TableCell, { colSpan: totalCols, className: "p-0", children: renderSubRow(row.original) }) })
8653
+ isExpanded && renderSubRow && /* @__PURE__ */ jsx(TableRow, { "data-expanded-row": "true", style: rowBorderStyle, className: "bg-muted/40 hover:bg-muted/40", children: /* @__PURE__ */ jsx(TableCell, { colSpan: totalCols, className: "p-0", children: renderSubRow(row.original) }) })
7886
8654
  ] }, row.id);
7887
- }) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length + (showCheckbox ? 1 : 0) + (hasExpansion ? 1 : 0), className: "h-16 text-center", children: noResultsText }) }) })
8655
+ }) : /* @__PURE__ */ jsx(TableRow, { style: rowBorderStyle, children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length + (showCheckbox ? 1 : 0) + (hasExpansion ? 1 : 0), className: "h-16 text-center", children: noResultsText }) }) })
7888
8656
  ] })
7889
8657
  }
7890
8658
  );
7891
8659
  }
7892
- function NDataCardShell({ row, onClick, onContextMenu, actions, children, className, showCheckbox = true, selectedRowId, openRowMenu, menuButton, bordered, borderDegree }) {
8660
+ function NDataCardShell({ row, onClick, onContextMenu, actions, children, className, showCheckbox = true, selectedRowId, openRowMenu, menuButton, bordered }) {
8661
+ const recipe = useNajmComponentStyle("table");
8662
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
8663
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
8664
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
8665
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
8666
+ } : void 0;
7893
8667
  const canExpand = row.getCanExpand();
7894
8668
  const isExpanded = canExpand && row.getIsExpanded();
7895
8669
  const isSelected = row.getIsSelected();
7896
8670
  const isHighlighted = selectedRowId != null && row.original?.id === selectedRowId;
7897
8671
  const isActive = isSelected || isHighlighted;
7898
8672
  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
8673
  return /* @__PURE__ */ jsxs(
7908
8674
  "div",
7909
8675
  {
7910
8676
  "data-row": "true",
7911
8677
  "data-row-id": row.id,
7912
- "data-border-degree": resolvedBorderDegree,
8678
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
7913
8679
  onClick,
7914
8680
  onContextMenu,
8681
+ style: recipeStyle,
7915
8682
  className: cn(
7916
8683
  "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"),
8684
+ surfaceBorderClasses(bordered),
8685
+ isActive && (bordered ? "border-primary" : "ring-2 ring-primary ring-offset-1 ring-offset-background"),
7920
8686
  onClick && "cursor-pointer",
7921
8687
  className
7922
8688
  ),
@@ -8011,7 +8777,7 @@ function NDataCardShell({ row, onClick, onContextMenu, actions, children, classN
8011
8777
  },
8012
8778
  className: cn(
8013
8779
  "absolute bottom-2 right-2 z-10 flex h-6 w-6 items-center justify-center rounded hover:bg-muted",
8014
- bordered && `border ${borderClass}`
8780
+ bordered && "border border-border"
8015
8781
  ),
8016
8782
  children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
8017
8783
  }
@@ -8048,7 +8814,6 @@ function NTableCards({ effectiveMode }) {
8048
8814
  const showContent = useTableStore.use.showContent();
8049
8815
  const classNames = useTableStore.use.classNames();
8050
8816
  const bordered = useTableStore.use.bordered();
8051
- const borderDegree = useTableStore.use.borderDegree();
8052
8817
  const renderSubRow = useTableStore.use.renderSubRow();
8053
8818
  const userGetRowCanExpand = useTableStore.use.getRowCanExpand();
8054
8819
  const handleContainerContextMenu = useCallback((e) => {
@@ -8151,7 +8916,6 @@ function NTableCards({ effectiveMode }) {
8151
8916
  openRowMenu,
8152
8917
  menuButton,
8153
8918
  bordered,
8154
- borderDegree,
8155
8919
  children: /* @__PURE__ */ jsx(
8156
8920
  CardComponent,
8157
8921
  {
@@ -8182,14 +8946,6 @@ function NTablePagination() {
8182
8946
  const setPagination = useTableStore.use.setPagination();
8183
8947
  const isPaginationControlled = useTableStore.use.isPaginationControlled();
8184
8948
  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
8949
  if (!table || !showContent || !showPagination || viewMode === "json" || viewMode === "files") return null;
8194
8950
  const filteredRows = table.getFilteredRowModel().rows;
8195
8951
  const selectedRows = table.getFilteredSelectedRowModel().rows;
@@ -8227,8 +8983,8 @@ function NTablePagination() {
8227
8983
  /* @__PURE__ */ jsx(
8228
8984
  SelectTrigger,
8229
8985
  {
8230
- "data-border-degree": useDegreeBorder ? resolvedBorderDegree : void 0,
8231
- className: cn("h-8 w-[80px]", useDegreeBorder && triggerBorderClass),
8986
+ "data-bordered": bordered ? "true" : void 0,
8987
+ className: cn("h-8 w-[80px]", bordered && "najm-border border-border"),
8232
8988
  children: /* @__PURE__ */ jsx(SelectValue, { placeholder: pageSize })
8233
8989
  }
8234
8990
  ),
@@ -8259,28 +9015,25 @@ function NTablePagination() {
8259
9015
  function SearchFilter({ placeholder }) {
8260
9016
  const table = useTableStore.use.table();
8261
9017
  const bordered = useTableStore.use.bordered();
8262
- const borderDegree = useTableStore.use.borderDegree();
8263
9018
  if (!table) return null;
8264
9019
  const value = table.getState().globalFilter ?? "";
8265
- return /* @__PURE__ */ jsx(TextInput, { icon: Search, value, onChange: (v) => table.setGlobalFilter(v), placeholder: placeholder ?? "Search\u2026", bordered, borderDegree });
9020
+ return /* @__PURE__ */ jsx(TextInput, { icon: Search, value, onChange: (v) => table.setGlobalFilter(v), placeholder: placeholder ?? "Search\u2026", bordered });
8266
9021
  }
8267
9022
  function TextFilter({ name, placeholder }) {
8268
9023
  const table = useTableStore.use.table();
8269
9024
  const bordered = useTableStore.use.bordered();
8270
- const borderDegree = useTableStore.use.borderDegree();
8271
9025
  const column = table?.getColumn?.(name);
8272
9026
  if (!column) return null;
8273
- return /* @__PURE__ */ jsx(TextInput, { value: column.getFilterValue() ?? "", onChange: (value) => column.setFilterValue(value), placeholder, bordered, borderDegree });
9027
+ return /* @__PURE__ */ jsx(TextInput, { value: column.getFilterValue() ?? "", onChange: (value) => column.setFilterValue(value), placeholder, bordered });
8274
9028
  }
8275
9029
  function SelectFilter({ name, options, placeholder, inputType }) {
8276
9030
  const table = useTableStore.use.table();
8277
9031
  const bordered = useTableStore.use.bordered();
8278
- const borderDegree = useTableStore.use.borderDegree();
8279
9032
  const column = table?.getColumn?.(name);
8280
9033
  if (!column) return null;
8281
9034
  const allOptions = [{ value: "__clear__", label: "All" }, ...options.map((o) => typeof o === "string" ? { value: o, label: o } : o)];
8282
9035
  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 });
9036
+ return /* @__PURE__ */ jsx(InputComponent, { value: column.getFilterValue() ?? "", onChange: (value) => column.setFilterValue(value === "" || value === "__clear__" ? void 0 : value), items: allOptions, placeholder: placeholder || "Filter...", bordered });
8284
9037
  }
8285
9038
  function defaultWrapperClass(filter) {
8286
9039
  return filter.type === "search" ? "flex-1 min-w-[160px] max-w-sm" : "w-full sm:w-40 shrink-0";
@@ -8288,7 +9041,6 @@ function defaultWrapperClass(filter) {
8288
9041
  function RenderFilter({ filter }) {
8289
9042
  const table = useTableStore.use.table();
8290
9043
  const bordered = useTableStore.use.bordered();
8291
- const borderDegree = useTableStore.use.borderDegree();
8292
9044
  if (filter.type === "search") {
8293
9045
  return /* @__PURE__ */ jsx(SearchFilter, { placeholder: filter.placeholder });
8294
9046
  }
@@ -8300,7 +9052,6 @@ function RenderFilter({ filter }) {
8300
9052
  onChange: filter.onChange,
8301
9053
  placeholder: filter.placeholder,
8302
9054
  bordered,
8303
- borderDegree,
8304
9055
  className: "w-full"
8305
9056
  }
8306
9057
  );
@@ -8314,7 +9065,6 @@ function RenderFilter({ filter }) {
8314
9065
  onChange: filter.onChange,
8315
9066
  placeholder: filter.placeholder,
8316
9067
  bordered,
8317
- borderDegree,
8318
9068
  className: "w-full"
8319
9069
  }
8320
9070
  );
@@ -8333,7 +9083,6 @@ function RenderFilter({ filter }) {
8333
9083
  showIcon: true,
8334
9084
  disabled: filter.disabled,
8335
9085
  bordered,
8336
- borderDegree,
8337
9086
  className: "w-full"
8338
9087
  }
8339
9088
  );
@@ -8349,7 +9098,6 @@ function RenderFilter({ filter }) {
8349
9098
  showIcon: true,
8350
9099
  disabled: filter.disabled,
8351
9100
  bordered,
8352
- borderDegree,
8353
9101
  className: "w-full"
8354
9102
  }
8355
9103
  );
@@ -8377,17 +9125,13 @@ function TableAddButton() {
8377
9125
  const showAddButton = useTableStore.use.showAddButton();
8378
9126
  const addButtonText = useTableStore.use.addButtonText();
8379
9127
  const headerColor = useTableStore.use.headerColor();
9128
+ const headerTextColor = useTableStore.use.headerTextColor();
8380
9129
  const bordered = useTableStore.use.bordered();
8381
- const borderDegree = useTableStore.use.borderDegree();
8382
- const resolvedBorderDegree = useResolvedBorderDegree({
8383
- borderDegree,
8384
- bordered,
8385
- fallback: "default"
8386
- });
8387
9130
  if (!showAddButton) return null;
8388
- const accentHex = headerColor ? HEADER_HEX[headerColor] : void 0;
8389
- const btnStyle = accentHex ? { backgroundColor: accentHex } : void 0;
8390
- const baseCls = accentHex ? "hover:opacity-90" : "bg-primary hover:bg-primary/90";
9131
+ const btnStyle = {
9132
+ backgroundColor: resolveTableColor(headerColor, DEFAULT_TABLE_HEADER_COLOR),
9133
+ color: resolveTableColor(headerTextColor, DEFAULT_TABLE_HEADER_TEXT_COLOR)
9134
+ };
8391
9135
  const borderedCls = bordered ? "border border-muted-foreground" : "";
8392
9136
  return /* @__PURE__ */ jsx(
8393
9137
  "button",
@@ -8397,8 +9141,8 @@ function TableAddButton() {
8397
9141
  style: btnStyle,
8398
9142
  "aria-label": addButtonText || "Create",
8399
9143
  title: addButtonText || "Create",
8400
- "data-border-degree": bordered ? resolvedBorderDegree : void 0,
8401
- className: `h-10 w-10 shrink-0 cursor-pointer flex items-center justify-center rounded-lg text-white transition-opacity ${baseCls} ${borderedCls}`,
9144
+ "data-bordered": bordered ? "true" : void 0,
9145
+ className: `h-10 w-10 shrink-0 cursor-pointer flex items-center justify-center rounded-lg transition-opacity hover:opacity-90 ${borderedCls}`,
8402
9146
  children: /* @__PURE__ */ jsx(Plus, { className: "h-5 w-5" })
8403
9147
  }
8404
9148
  );
@@ -8414,7 +9158,6 @@ function TableSettingsMenu() {
8414
9158
  const cardComponent = useTableStore.use.CardComponent();
8415
9159
  const table = useTableStore.use.table();
8416
9160
  const bordered = useTableStore.use.bordered();
8417
- const borderDegree = useTableStore.use.borderDegree();
8418
9161
  if (!showViewToggle && !showColumnVisibility) return null;
8419
9162
  const allModes = ["table", "cards", "json", "files"];
8420
9163
  const filteredModes = availableModes ?? allModes;
@@ -8433,7 +9176,7 @@ function TableSettingsMenu() {
8433
9176
  const hasModes = modeItems.length > 0;
8434
9177
  const hasColumns = columns.length > 0;
8435
9178
  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" }) }) }),
9179
+ /* @__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
9180
  /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56 bg-card", children: [
8438
9181
  showViewToggle && hasModes && /* @__PURE__ */ jsxs(Fragment, { children: [
8439
9182
  /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex items-center gap-2", children: [
@@ -8759,9 +9502,10 @@ function NTable(props) {
8759
9502
  className: props.className ?? "",
8760
9503
  classNames: props.classNames ?? {},
8761
9504
  bordered: props.bordered,
8762
- borderDegree: props.borderDegree,
8763
9505
  headerClassName: props.headerClassName ?? "bg-card",
8764
- headerColor: props.headerColor ?? "primary",
9506
+ headerColor: props.headerColor,
9507
+ headerTextColor: props.headerTextColor,
9508
+ borderColor: props.borderColor,
8765
9509
  showCheckbox: props.showCheckbox ?? true,
8766
9510
  selectedRowId: props.selectedRowId ?? null,
8767
9511
  headerSlot: props.headerSlot ?? null,
@@ -9195,7 +9939,7 @@ function NSmartPasteDialog({
9195
9939
  function NSidebarHeader({ children, collapsed, className, classNames }) {
9196
9940
  if (!children) return null;
9197
9941
  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",
9942
+ "flex items-center h-14 min-h-14 px-4 border-b border-sidebar-border/70 shrink-0 gap-2 justify-start",
9199
9943
  classNames?.sidebarHeader,
9200
9944
  className
9201
9945
  ), children });
@@ -9208,8 +9952,7 @@ function NSidebarLogo({
9208
9952
  collapsed = false
9209
9953
  }) {
9210
9954
  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;
9955
+ 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
9956
  return /* @__PURE__ */ jsxs(
9214
9957
  "button",
9215
9958
  {
@@ -9223,14 +9966,16 @@ function NSidebarLogo({
9223
9966
  IconNode && /* @__PURE__ */ jsx(
9224
9967
  "div",
9225
9968
  {
9226
- className: "size-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0",
9227
- style: collapsedCenter,
9969
+ className: cn(
9970
+ "size-10 rounded-lg bg-sidebar-primary/10 flex items-center justify-center shrink-0",
9971
+ 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))]"
9972
+ ),
9228
9973
  children: IconNode
9229
9974
  }
9230
9975
  ),
9231
9976
  !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 })
9977
+ title && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-sidebar-foreground leading-tight truncate", children: title }),
9978
+ subtitle && /* @__PURE__ */ jsx("span", { className: "text-xs text-sidebar-foreground/60 leading-tight truncate", children: subtitle })
9234
9979
  ] })
9235
9980
  ]
9236
9981
  }
@@ -9265,8 +10010,8 @@ function NSidebarItem({
9265
10010
  const baseClasses = cn(
9266
10011
  "flex items-center gap-3 w-full rounded-md text-sm px-2 font-medium transition-colors h-8 text-left",
9267
10012
  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",
10013
+ 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))]",
10014
+ 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
10015
  classNames?.sidebarItem
9271
10016
  );
9272
10017
  const handleClick = () => {
@@ -9351,10 +10096,10 @@ function NSidebarSection({
9351
10096
  "data-sidebar-section": true,
9352
10097
  className: cn(
9353
10098
  "flex flex-col gap-1",
9354
- showSectionSeparators && !isFirst && "border-t border-border/70 pt-3"
10099
+ showSectionSeparators && !isFirst && "border-t border-sidebar-border/70 pt-3"
9355
10100
  ),
9356
10101
  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: [
10102
+ 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
10103
  showSectionIcons && group.sectionIcon && /* @__PURE__ */ jsx(group.sectionIcon, { className: "h-3.5 w-3.5 shrink-0" }),
9359
10104
  /* @__PURE__ */ jsx("span", { children: group.sectionLabel })
9360
10105
  ] })),
@@ -9385,9 +10130,10 @@ function NSidebarContent({
9385
10130
  showSectionLabels,
9386
10131
  showSectionIcons,
9387
10132
  showSectionSeparators,
10133
+ contentStyle,
9388
10134
  classNames
9389
10135
  }) {
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(
10136
+ 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
10137
  NSidebarSection,
9392
10138
  {
9393
10139
  group,
@@ -9413,7 +10159,7 @@ function DefaultFooter({
9413
10159
  collapsed = false
9414
10160
  }) {
9415
10161
  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";
10162
+ 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
10163
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
9418
10164
  onSettings && /* @__PURE__ */ jsxs("button", { type: "button", onClick: onSettings, className: itemClass, "aria-label": settingsLabel, title: settingsLabel, children: [
9419
10165
  /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4 shrink-0" }),
@@ -9445,7 +10191,7 @@ function NSidebarFooter({
9445
10191
  const showCollapseInFooter = showCollapseButton && !isMobile;
9446
10192
  const CollapseIcon = collapsed ? PanelLeftOpen : PanelLeftClose;
9447
10193
  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: [
10194
+ 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
10195
  footerContent,
9450
10196
  showCollapseInFooter && /* @__PURE__ */ jsxs(
9451
10197
  "button",
@@ -9453,7 +10199,7 @@ function NSidebarFooter({
9453
10199
  type: "button",
9454
10200
  onClick: onToggleCollapsed,
9455
10201
  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",
10202
+ "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
10203
  "gap-3 px-2 text-left"
9458
10204
  ),
9459
10205
  "aria-label": collapsed ? expandLabel : collapseLabel,
@@ -9477,18 +10223,9 @@ function NSidebarMobile({
9477
10223
  hamburgerClassName,
9478
10224
  showHamburgerButton = true,
9479
10225
  children,
9480
- bordered,
9481
- borderDegree
10226
+ bordered
9482
10227
  }) {
9483
10228
  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
10229
  return /* @__PURE__ */ jsxs(Fragment, { children: [
9493
10230
  showHamburgerButton && /* @__PURE__ */ jsx(
9494
10231
  "button",
@@ -9496,7 +10233,7 @@ function NSidebarMobile({
9496
10233
  type: "button",
9497
10234
  onClick: onOpen,
9498
10235
  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",
10236
+ "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
10237
  mobileClass,
9501
10238
  hamburgerClassName,
9502
10239
  open && "hidden"
@@ -9516,11 +10253,10 @@ function NSidebarMobile({
9516
10253
  /* @__PURE__ */ jsxs(
9517
10254
  "aside",
9518
10255
  {
9519
- "data-border-degree": resolvedBorderDegree,
10256
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
9520
10257
  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}`,
10258
+ "fixed inset-y-0 left-0 z-50 bg-sidebar text-sidebar-foreground flex flex-col transition-transform duration-200",
10259
+ sidebarBorderClasses(bordered, "right"),
9524
10260
  mobileClass,
9525
10261
  open ? "translate-x-0" : "-translate-x-full"
9526
10262
  ),
@@ -9531,7 +10267,7 @@ function NSidebarMobile({
9531
10267
  {
9532
10268
  type: "button",
9533
10269
  onClick: onClose,
9534
- className: "absolute top-3 right-3 z-10 p-1 rounded-md hover:bg-accent text-muted-foreground",
10270
+ className: "absolute top-3 right-3 z-10 p-1 rounded-md hover:bg-sidebar-accent text-sidebar-foreground/70",
9535
10271
  "aria-label": closeLabel,
9536
10272
  children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
9537
10273
  }
@@ -9567,12 +10303,11 @@ function NSidebar({
9567
10303
  defaultCollapsed = false,
9568
10304
  onCollapsedChange,
9569
10305
  showCollapseButton = true,
9570
- collapseButtonPosition = "footer",
9571
- showSectionLabels = true,
10306
+ collapseButtonPosition = "rail",
10307
+ showSectionLabels,
9572
10308
  showSectionIcons = true,
9573
- showSectionSeparators = false,
10309
+ showSectionSeparators,
9574
10310
  bordered,
9575
- borderDegree,
9576
10311
  footer,
9577
10312
  className,
9578
10313
  classNames,
@@ -9597,6 +10332,7 @@ function NSidebar({
9597
10332
  logoutLabel,
9598
10333
  widths
9599
10334
  }) {
10335
+ const recipe = useNajmComponentStyle("sidebar");
9600
10336
  const [_mobileOpen, _setMobileOpen] = useState(defaultMobileOpen);
9601
10337
  const [_collapsed, _setCollapsed] = useState(defaultCollapsed);
9602
10338
  const isControlled = mobileOpenProp !== void 0;
@@ -9606,30 +10342,68 @@ function NSidebar({
9606
10342
  if (!isControlled) _setMobileOpen(open);
9607
10343
  onMobileOpenChange?.(open);
9608
10344
  };
9609
- const handleToggleCollapsed = useCallback(() => {
9610
- const next = !collapsed;
10345
+ const [railDragging, setRailDragging] = useState(false);
10346
+ const suppressRailClickRef = useRef(false);
10347
+ const setCollapsedState = useCallback((next) => {
10348
+ if (next === collapsed) return;
9611
10349
  if (collapsedProp === void 0) _setCollapsed(next);
9612
10350
  onCollapsedChange?.(next);
9613
10351
  }, [collapsed, collapsedProp, onCollapsedChange]);
10352
+ const handleToggleCollapsed = useCallback(() => {
10353
+ setCollapsedState(!collapsed);
10354
+ }, [collapsed, setCollapsedState]);
10355
+ const handleRailPointerDown = useCallback((e) => {
10356
+ if (e.button !== 0) return;
10357
+ const startX = e.clientX;
10358
+ const startCollapsed = collapsed;
10359
+ const threshold = 24;
10360
+ let resolved = false;
10361
+ setRailDragging(true);
10362
+ const onMove = (ev) => {
10363
+ const dx = ev.clientX - startX;
10364
+ if (!resolved && !startCollapsed && dx < -threshold) {
10365
+ resolved = true;
10366
+ suppressRailClickRef.current = true;
10367
+ setCollapsedState(true);
10368
+ } else if (!resolved && startCollapsed && dx > threshold) {
10369
+ resolved = true;
10370
+ suppressRailClickRef.current = true;
10371
+ setCollapsedState(false);
10372
+ }
10373
+ };
10374
+ const onUp = (ev) => {
10375
+ window.removeEventListener("pointermove", onMove);
10376
+ window.removeEventListener("pointerup", onUp);
10377
+ setRailDragging(false);
10378
+ if (resolved || Math.abs(ev.clientX - startX) >= 4) suppressRailClickRef.current = true;
10379
+ };
10380
+ window.addEventListener("pointermove", onMove);
10381
+ window.addEventListener("pointerup", onUp);
10382
+ }, [collapsed, setCollapsedState]);
10383
+ const handleRailClick = useCallback(() => {
10384
+ if (suppressRailClickRef.current) {
10385
+ suppressRailClickRef.current = false;
10386
+ return;
10387
+ }
10388
+ handleToggleCollapsed();
10389
+ }, [handleToggleCollapsed]);
9614
10390
  const handleNavigate = useCallback((href) => {
9615
10391
  onNavigate?.(href);
9616
10392
  if (closeOnNavigate) setMobileOpen(false);
9617
10393
  }, [onNavigate, closeOnNavigate]);
9618
10394
  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
10395
  const desktopClass = mobileBreakpoint === "sm" ? "hidden sm:flex" : mobileBreakpoint === "lg" ? "hidden lg:flex" : "hidden md:flex";
9628
10396
  const expandedWidth = widths?.expanded ?? 240;
9629
10397
  const collapsedWidth = widths?.collapsed ?? 64;
9630
10398
  const mobileWidth = widths?.mobile ?? expandedWidth;
9631
10399
  const railVar = typeof collapsedWidth === "number" ? `${collapsedWidth}px` : collapsedWidth;
10400
+ const sidebarEdgeWidth = bordered === false ? "0px" : recipe?.borderWidth ?? "var(--border-width, 1px)";
9632
10401
  const showEdgeCollapse = showCollapseButton && collapseButtonPosition === "edge";
10402
+ const showRailCollapse = showCollapseButton && collapseButtonPosition === "rail";
10403
+ const effectiveShowSectionLabels = showSectionLabels ?? recipe?.showSectionLabels ?? true;
10404
+ const effectiveShowSectionSeparators = showSectionSeparators ?? recipe?.showSectionSeparators ?? false;
10405
+ const contentSlot = recipe?.slots?.content;
10406
+ const contentStyle = contentSlot?.paddingTop ? { paddingTop: contentSlot.paddingTop } : void 0;
9633
10407
  const defaultLogoContent = logoIcon || logoTitle || logoSubtitle ? /* @__PURE__ */ jsx(NSidebarLogo, { icon: logoIcon, title: logoTitle, subtitle: logoSubtitle, onClick: onLogoClick, collapsed }) : null;
9634
10408
  const headerContent = logo ?? defaultLogoContent;
9635
10409
  const contentProps = {
@@ -9639,9 +10413,10 @@ function NSidebar({
9639
10413
  onNavigate: handleNavigate,
9640
10414
  linkComponent,
9641
10415
  collapsed,
9642
- showSectionLabels,
10416
+ showSectionLabels: effectiveShowSectionLabels,
9643
10417
  showSectionIcons,
9644
- showSectionSeparators,
10418
+ showSectionSeparators: effectiveShowSectionSeparators,
10419
+ contentStyle,
9645
10420
  classNames
9646
10421
  };
9647
10422
  const footerProps = {
@@ -9681,25 +10456,44 @@ function NSidebar({
9681
10456
  hamburgerClassName,
9682
10457
  showHamburgerButton,
9683
10458
  bordered,
9684
- borderDegree,
9685
10459
  children: mobileInner
9686
10460
  }
9687
10461
  ),
9688
10462
  /* @__PURE__ */ jsxs(
9689
10463
  "aside",
9690
10464
  {
9691
- "data-border-degree": resolvedBorderDegree,
10465
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
9692
10466
  className: cn(
9693
10467
  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",
10468
+ "relative z-10 flex flex-col h-full bg-sidebar text-sidebar-foreground transition-all duration-200",
10469
+ sidebarBorderClasses(bordered, "right"),
9697
10470
  classNames?.sidebar,
9698
10471
  className
9699
10472
  ),
9700
- style: { width: collapsed ? collapsedWidth : expandedWidth, ["--rail"]: railVar },
10473
+ style: {
10474
+ width: collapsed ? collapsedWidth : expandedWidth,
10475
+ ["--rail"]: railVar,
10476
+ ["--sidebar-edge-width"]: sidebarEdgeWidth,
10477
+ ...bordered !== false && recipe?.borderWidth ? { borderRightWidth: recipe.borderWidth } : {}
10478
+ },
9701
10479
  children: [
9702
10480
  sidebarInner,
10481
+ showRailCollapse && /* @__PURE__ */ jsxs(
10482
+ "button",
10483
+ {
10484
+ type: "button",
10485
+ "aria-label": collapsed ? expandLabel : collapseLabel,
10486
+ title: collapsed ? expandLabel : collapseLabel,
10487
+ "data-dragging": railDragging ? "true" : void 0,
10488
+ onPointerDown: handleRailPointerDown,
10489
+ onClick: handleRailClick,
10490
+ 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",
10491
+ children: [
10492
+ /* @__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" }),
10493
+ /* @__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" })
10494
+ ]
10495
+ }
10496
+ ),
9703
10497
  showEdgeCollapse && /* @__PURE__ */ jsx(
9704
10498
  "button",
9705
10499
  {
@@ -9707,7 +10501,7 @@ function NSidebar({
9707
10501
  onClick: handleToggleCollapsed,
9708
10502
  "aria-label": collapsed ? expandLabel : collapseLabel,
9709
10503
  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",
10504
+ 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
10505
  children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronLeft, { className: "h-3.5 w-3.5" })
9712
10506
  }
9713
10507
  )
@@ -9935,6 +10729,29 @@ function NCommandPalette({
9935
10729
  ] })
9936
10730
  ] });
9937
10731
  }
10732
+ function NPageLayout({
10733
+ as: Comp = "main",
10734
+ className,
10735
+ style,
10736
+ ...props
10737
+ }) {
10738
+ const { layout } = useNajmDesign();
10739
+ const pageGutter = layout?.pageGutter ?? "var(--page-gutter, 24px)";
10740
+ const sectionGap = layout?.sectionGap ?? "var(--section-gap, 20px)";
10741
+ return /* @__PURE__ */ jsx(
10742
+ Comp,
10743
+ {
10744
+ className: cn("flex min-w-0 flex-col", className),
10745
+ style: {
10746
+ gap: sectionGap,
10747
+ paddingInline: pageGutter,
10748
+ paddingBlock: sectionGap,
10749
+ ...style
10750
+ },
10751
+ ...props
10752
+ }
10753
+ );
10754
+ }
9938
10755
  function NPageHeaderActions({ children, className }) {
9939
10756
  return /* @__PURE__ */ jsx("div", { className: cn("flex shrink-0 items-center gap-2 sm:gap-3", className), children });
9940
10757
  }
@@ -9954,11 +10771,12 @@ function getSlotElements(children, slot) {
9954
10771
  const matches = React__default.Children.toArray(children).filter((child) => isPageHeaderSlot(child, slot));
9955
10772
  return matches.length > 0 ? matches : void 0;
9956
10773
  }
9957
- function NPageHeader({ icon: Icon2, title, subtitle, actions, filters, top, search, children, className, headerClassName, bordered, borderDegree }) {
10774
+ function NPageHeader({ icon: Icon2, title, subtitle, actions, filters, top, search, children, className, headerClassName, card, bordered }) {
9958
10775
  const [internalSearch, setInternalSearch] = useState("");
10776
+ const recipe = useNajmComponentStyle("pageHeader");
9959
10777
  const searchValue = search?.value ?? internalSearch;
9960
10778
  const handleSearchChange = useCallback((e) => {
9961
- setInternalSearch(e.target.value);
10779
+ setInternalSearch(e.currentTarget.value);
9962
10780
  search?.onChange?.(e);
9963
10781
  }, [search?.onChange]);
9964
10782
  const slottedActions = getSlotElements(children, NPageHeaderActions);
@@ -9967,21 +10785,21 @@ function NPageHeader({ icon: Icon2, title, subtitle, actions, filters, top, sear
9967
10785
  const resolvedActions = slottedActions ?? actions;
9968
10786
  const resolvedFilters = slottedFilters ?? filters;
9969
10787
  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";
10788
+ const isCard = card ?? recipe?.card ?? bordered === true;
10789
+ const recipeRadius = resolveRadiusValue(recipe?.radius);
10790
+ const recipeStyle = recipeRadius || recipe?.borderWidth ? {
10791
+ ...recipeRadius ? { borderRadius: recipeRadius } : {},
10792
+ ...recipe?.borderWidth ? { borderWidth: recipe.borderWidth } : {}
10793
+ } : void 0;
9977
10794
  return /* @__PURE__ */ jsxs(
9978
10795
  "div",
9979
10796
  {
9980
10797
  "data-slot": "page-header",
9981
- "data-border-degree": hasBorderShell ? resolvedBorderDegree : void 0,
10798
+ "data-card": isCard ? "true" : void 0,
10799
+ "data-bordered": bordered === false ? "false" : bordered ? "true" : void 0,
10800
+ style: recipeStyle,
9982
10801
  className: cn(
9983
- hasBorderShell ? cn("border rounded-xl bg-card shadow-none", borderColorClassForDegree(resolvedBorderDegree)) : "border-b border-border",
9984
- isStrong && "shadow-none",
10802
+ isCard ? cn("rounded-xl bg-card shadow-none", surfaceBorderClasses(true)) : cn("border-b", surfaceBorderClasses(true, "bottom").replace("najm-border-b", "najm-border-b")),
9985
10803
  className
9986
10804
  ),
9987
10805
  children: [
@@ -10044,4 +10862,4 @@ function NInspectorSheet({ open, onClose, title, children }) {
10044
10862
  ] }) });
10045
10863
  }
10046
10864
 
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 };
10865
+ 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 };