@moontra/moonui 6.24.0 → 6.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/cdn/moonui.css +2 -2
  2. package/dist/cdn/moonui.esm.js +12 -12
  3. package/dist/cdn/moonui.global.js +12 -12
  4. package/dist/index.d.mts +24 -6
  5. package/dist/index.d.ts +24 -6
  6. package/dist/index.js +417 -87
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +418 -89
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +1 -1
  11. package/src/__tests__/issue-544-kontrast.test.tsx +153 -145
  12. package/src/__tests__/issue-645-overlay-tab-focus.test.tsx +262 -0
  13. package/src/__tests__/issue-646-dark-scope-override.test.tsx +297 -0
  14. package/src/__tests__/issue-661-a11y.test.tsx +113 -0
  15. package/src/__tests__/issue-661-token-kontrast.test.tsx +82 -0
  16. package/src/components/ui/__tests__/accent-foreground-contrast.test.ts +197 -0
  17. package/src/components/ui/__tests__/accordion.test.tsx +6 -4
  18. package/src/components/ui/__tests__/alert.test.tsx +4 -1
  19. package/src/components/ui/__tests__/button.test.tsx +6 -1
  20. package/src/components/ui/__tests__/dark-token-contrast.test.ts +18 -18
  21. package/src/components/ui/__tests__/heading-level-policy.test.tsx +4 -4
  22. package/src/components/ui/__tests__/issue-643-card-token-parite.test.tsx +113 -0
  23. package/src/components/ui/__tests__/issue-649-button-aschild.test.tsx +199 -0
  24. package/src/components/ui/__tests__/issue-664-separator-dekoratif-rol.test.tsx +41 -0
  25. package/src/components/ui/__tests__/preset-color-shadowing.test.ts +10 -10
  26. package/src/components/ui/__tests__/primary-subtle-token.test.ts +7 -7
  27. package/src/components/ui/__tests__/progress-secondary-contrast.test.ts +38 -38
  28. package/src/components/ui/__tests__/progress-warning-error-contrast.test.ts +64 -64
  29. package/src/components/ui/__tests__/quality-group-de.test.tsx +2 -2
  30. package/src/components/ui/__tests__/responsive-color-invariance.test.ts +20 -20
  31. package/src/components/ui/__tests__/select.test.tsx +6 -1
  32. package/src/components/ui/__tests__/semantic-token-usage.test.ts +23 -23
  33. package/src/components/ui/__tests__/size-scale-convention.test.ts +10 -10
  34. package/src/components/ui/__tests__/slider-accent-contrast.test.ts +142 -136
  35. package/src/components/ui/__tests__/slider-secondary-contrast.test.ts +60 -60
  36. package/src/components/ui/__tests__/slider-warning-error-contrast.test.ts +100 -100
  37. package/src/components/ui/__tests__/switch-variant-contrast.test.tsx +103 -103
  38. package/src/components/ui/__tests__/tooltip.test.tsx +122 -0
  39. package/src/components/ui/accordion.tsx +16 -3
  40. package/src/components/ui/alert.tsx +1 -1
  41. package/src/components/ui/badge.tsx +12 -1
  42. package/src/components/ui/button.tsx +76 -18
  43. package/src/components/ui/card.tsx +59 -5
  44. package/src/components/ui/dropdown-menu.tsx +99 -5
  45. package/src/components/ui/file-upload.tsx +4 -0
  46. package/src/components/ui/index.ts +4 -1
  47. package/src/components/ui/popover-pro.tsx +41 -0
  48. package/src/components/ui/popover.tsx +162 -7
  49. package/src/components/ui/rating.tsx +24 -2
  50. package/src/components/ui/select.tsx +4 -4
  51. package/src/components/ui/simple-editor.tsx +3 -18
  52. package/src/components/ui/tabs.tsx +16 -1
  53. package/src/components/ui/textarea.tsx +6 -1
  54. package/src/components/ui/toast.tsx +17 -2
  55. package/src/components/ui/tooltip.tsx +154 -2
  56. package/src/styles/tokens.css +34 -2
package/dist/index.js CHANGED
@@ -95,7 +95,7 @@ var AccordionItem = React12__namespace.forwardRef(({ className, ...props }, ref)
95
95
  AccordionPrimitive__namespace.Item,
96
96
  {
97
97
  ref,
98
- className: cn("moonui-theme", "border-b border-gray-200 dark:border-gray-800", className),
98
+ className: cn("moonui-theme", "border-b border-border", className),
99
99
  ...props
100
100
  }
101
101
  ));
@@ -105,7 +105,9 @@ var AccordionTrigger = React12__namespace.forwardRef(({ className, children, ...
105
105
  {
106
106
  ref,
107
107
  className: cn(
108
- "flex flex-1 items-center justify-between py-4 font-medium transition-all dark:text-gray-100",
108
+ // #661-17: `dark:text-gray-100` KALDIRILDI — tetikleyici artık iki temada
109
+ // da `--foreground`u miras alır (koyu temada 213 31% 91% ≈ gray-100).
110
+ "flex flex-1 items-center justify-between py-4 font-medium transition-all",
109
111
  "hover:underline hover:text-primary",
110
112
  "[&[data-state=open]>svg]:rotate-180",
111
113
  className
@@ -123,7 +125,13 @@ var AccordionContent = React12__namespace.forwardRef(({ className, children, ...
123
125
  {
124
126
  ref,
125
127
  className: cn(
126
- "overflow-hidden text-sm text-gray-700 dark:text-gray-300 transition-all",
128
+ // #661-17: ham `text-gray-700 dark:text-gray-300` → `text-foreground/80`.
129
+ // Ölçüldü (iki tema, kart zemini): açık 10.30 → 11.48, koyu 12.19 → 9.44.
130
+ // İkisi de AA'nın (4.5) çok üstünde, yani eşik geçilmiyor — `#545 ihlal
131
+ // takası` sınıfı bir gerileme YOK. `text-muted-foreground` bilerek
132
+ // SEÇİLMEDİ: açık temada 4.76'ya inip gövde metnini görünür biçimde
133
+ // soldururdu (§9 estetik değişiklik olurdu).
134
+ "overflow-hidden text-sm text-foreground/80 transition-all",
127
135
  "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
128
136
  className
129
137
  ),
@@ -140,7 +148,7 @@ var alertVariants = classVarianceAuthority.cva(
140
148
  default: "bg-background text-foreground border-border",
141
149
  primary: "bg-primary/10 text-primary border-primary/30",
142
150
  success: "bg-success/10 text-success border-success/30",
143
- warning: "bg-warning/10 text-warning border-warning/30",
151
+ warning: "bg-warning/10 text-warning-subtle-foreground border-warning/30",
144
152
  error: "bg-destructive/10 text-destructive border-destructive/30",
145
153
  // `--info` token'ı (tokens.css) blue-500 ile birebir aynı değeri
146
154
  // taşır → görsel değişiklik yok, ancak varyant artık temaya ve
@@ -428,11 +436,22 @@ var badgeVariants = classVarianceAuthority.cva(
428
436
  // aynı varyant pro pakette token'lıydı → free ve pro `primary` için
429
437
  // farklı renk üretiyordu. Artık token'a bağlı (tema/karanlık moda duyarlı).
430
438
  // `primary` VARSAYILAN varyant olduğu için görünür bir renk değişimidir.
439
+ // #646: `dark:bg-primary/90` KALDIRILDI. `primary` VARSAYILAN varyant olduğu
440
+ // için varyant verilmeyen HER `<Badge>` bu sınıfı alıyordu; `tailwind-merge`
441
+ // `dark:` önekli arka planı tüketicinin ÖNEKSİZ `bg-*` sınıfıyla aynı grupta
442
+ // görmediğinden ikisi birden hayatta kalıyor ve koyu temada `dark:` özgüllükle
443
+ // kazanıyordu. Sonuç: `<Badge className="bg-green-500/20 text-green-300">`
444
+ // koyu temada near-white zemin + açık yeşil metin = 1.10:1 (ölçüldü,
445
+ // magnetic-button "Pending"; swipe-actions'ta 6 rozet 1.10–1.48 aralığında).
446
+ // ÖNEKSİZ `bg-primary` bırakıldı: tüketici sınıfıyla AYNI grupta çakışır ve
447
+ // doğru şekilde ezilir. Rozetin kendi görünümü BOZULMAZ — koyu temada
448
+ // `bg-primary` + `text-primary-foreground` 16.16 → 19.80'e çıkar
449
+ // (yarı saydamlık kalktığı için); açık temada değişiklik yok.
431
450
  primary: [
432
451
  "border-transparent bg-primary text-primary-foreground",
433
452
  "hover:bg-primary/90",
434
453
  "focus-visible:ring-primary/30 dark:focus-visible:ring-primary/40",
435
- "dark:bg-primary/90 dark:shadow-inner dark:shadow-primary/10"
454
+ "dark:shadow-inner dark:shadow-primary/10"
436
455
  ],
437
456
  secondary: [
438
457
  "border-transparent bg-secondary text-secondary-foreground",
@@ -880,9 +899,11 @@ var buttonVariants = classVarianceAuthority.cva(
880
899
  ],
881
900
  glow: [
882
901
  "bg-blue-500 text-white",
883
- "shadow-[0_0_30px_rgba(59,130,246,0.5)]",
884
- "hover:shadow-[0_0_40px_rgba(59,130,246,0.7)]",
885
- "active:shadow-[0_0_20px_rgba(59,130,246,0.4)]",
902
+ // #664 S3: rgba(59,130,246,…) → --glow-blue-rgb (tokens.css). Değer AYNI
903
+ // (Tailwind blue-500), yalnız merkezi token'a taşındı — görsel değişiklik yok.
904
+ "shadow-[0_0_30px_rgba(var(--glow-blue-rgb),0.5)]",
905
+ "hover:shadow-[0_0_40px_rgba(var(--glow-blue-rgb),0.7)]",
906
+ "active:shadow-[0_0_20px_rgba(var(--glow-blue-rgb),0.4)]",
886
907
  "hover:bg-blue-600",
887
908
  "focus-visible:ring-blue-500/50",
888
909
  "transition-all duration-300"
@@ -911,8 +932,9 @@ var buttonVariants = classVarianceAuthority.cva(
911
932
  "bg-transparent text-green-400",
912
933
  "border-2 border-green-400",
913
934
  "hover:bg-green-400 hover:text-gray-900",
914
- "hover:shadow-[0_0_30px_rgba(74,222,128,0.6)]",
915
- "active:shadow-[0_0_15px_rgba(74,222,128,0.4)]",
935
+ // #664 S3: rgba(74,222,128,…) → --glow-green-rgb (tokens.css), piksel-özdeş.
936
+ "hover:shadow-[0_0_30px_rgba(var(--glow-green-rgb),0.6)]",
937
+ "active:shadow-[0_0_15px_rgba(var(--glow-green-rgb),0.4)]",
916
938
  "focus-visible:ring-green-400/50",
917
939
  "transition-all duration-300"
918
940
  ]
@@ -959,22 +981,40 @@ var Button = React12__namespace.forwardRef(
959
981
  rightIcon,
960
982
  children,
961
983
  disabled,
984
+ onClick,
962
985
  ...props
963
986
  }, ref) => {
964
- const Comp = asChild ? "button" : "button";
987
+ const renderAsSlot = asChild && React12__namespace.isValidElement(children);
988
+ const Comp = renderAsSlot ? reactSlot.Slot : "button";
989
+ const isDisabled = disabled || loading;
990
+ const disabledProps = renderAsSlot ? {
991
+ "aria-disabled": isDisabled || void 0,
992
+ "data-disabled": isDisabled ? "" : void 0
993
+ } : { disabled: isDisabled };
994
+ const handleClick = renderAsSlot && isDisabled ? (event) => {
995
+ event.preventDefault();
996
+ event.stopPropagation();
997
+ } : onClick;
965
998
  return /* @__PURE__ */ jsxRuntime.jsxs(
966
999
  Comp,
967
1000
  {
968
- className: cn("moonui-theme", buttonVariants({ variant, size, rounded, fullWidth, className })),
1001
+ className: cn(
1002
+ "moonui-theme",
1003
+ buttonVariants({ variant, size, rounded, fullWidth, className }),
1004
+ // `:disabled` eşleşmediği için görsel/etkileşimsel devre dışılık Slot
1005
+ // dalında açık sınıflarla verilir.
1006
+ renderAsSlot && isDisabled && "opacity-50 cursor-not-allowed pointer-events-none"
1007
+ ),
969
1008
  ref,
970
- disabled: disabled || loading,
1009
+ ...disabledProps,
971
1010
  "aria-busy": loading || void 0,
972
1011
  "data-loading": loading ? "" : void 0,
973
1012
  ...props,
1013
+ onClick: handleClick,
974
1014
  children: [
975
1015
  loading && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-4 h-4 animate-spin", "aria-hidden": "true" }),
976
1016
  !loading && leftIcon,
977
- children,
1017
+ renderAsSlot ? /* @__PURE__ */ jsxRuntime.jsx(reactSlot.Slottable, { children }) : children,
978
1018
  !loading && rightIcon
979
1019
  ]
980
1020
  }
@@ -1125,16 +1165,16 @@ var skeletonAnimation = {
1125
1165
  }
1126
1166
  };
1127
1167
  var cardVariants = classVarianceAuthority.cva(
1128
- "rounded-lg border bg-card text-card-foreground shadow-sm dark:shadow-gray-900/20 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 transition-all duration-200",
1168
+ "rounded-lg border border-border bg-card text-card-foreground shadow-sm dark:shadow-black/20 transition-all duration-200",
1129
1169
  {
1130
1170
  variants: {
1131
1171
  variant: {
1132
1172
  default: "",
1133
- outline: "border border-border shadow-none bg-transparent dark:border-gray-700 dark:bg-transparent dark:text-gray-200",
1134
- filled: "border-none bg-secondary dark:bg-gray-800 dark:text-gray-100 dark:shadow-inner dark:shadow-gray-950/10",
1135
- elevated: "border-none shadow-md dark:shadow-lg dark:shadow-gray-900/30 dark:bg-card dark:text-gray-100",
1173
+ outline: "border border-border shadow-none bg-transparent dark:bg-transparent",
1174
+ filled: "border-none bg-secondary dark:bg-muted dark:shadow-inner dark:shadow-black/10",
1175
+ elevated: "border-none shadow-md dark:shadow-lg dark:shadow-black/30 dark:bg-card",
1136
1176
  gradient: "border-none bg-gradient-to-br from-primary/5 to-primary/10 dark:from-primary/10 dark:to-primary/20",
1137
- glass: "border border-white/20 bg-white/10 backdrop-blur-md dark:border-gray-700/30 dark:bg-gray-800/10"
1177
+ glass: "border border-white/20 bg-white/10 backdrop-blur-md dark:border-white/10 dark:bg-black/10"
1138
1178
  },
1139
1179
  size: {
1140
1180
  md: "",
@@ -2336,7 +2376,76 @@ var popoverContentVariants = classVarianceAuthority.cva(
2336
2376
  }
2337
2377
  }
2338
2378
  );
2339
- var Popover = PopoverPrimitive__namespace.Root;
2379
+ var PopoverModalContext = React12__namespace.createContext(false);
2380
+ var POPOVER_TAB_STOP_SELECTOR = "a[href],button,input,select,textarea,[tabindex],audio[controls],video[controls],[contenteditable]";
2381
+ function isPopoverElementHidden(node) {
2382
+ const view = node.ownerDocument.defaultView;
2383
+ if (!view)
2384
+ return false;
2385
+ if (view.getComputedStyle(node).visibility === "hidden")
2386
+ return true;
2387
+ let current = node;
2388
+ while (current) {
2389
+ if (view.getComputedStyle(current).display === "none")
2390
+ return true;
2391
+ current = current.parentElement;
2392
+ }
2393
+ return false;
2394
+ }
2395
+ function isPopoverTabStop(node) {
2396
+ if (node.hasAttribute("data-radix-focus-guard"))
2397
+ return false;
2398
+ if (node.tabIndex < 0)
2399
+ return false;
2400
+ if (node.disabled)
2401
+ return false;
2402
+ if (node.hidden)
2403
+ return false;
2404
+ if (node.getAttribute("aria-hidden") === "true")
2405
+ return false;
2406
+ if (node.closest("[inert]"))
2407
+ return false;
2408
+ return !isPopoverElementHidden(node);
2409
+ }
2410
+ function getPopoverTabStopsWithin(container) {
2411
+ return Array.from(
2412
+ container.querySelectorAll(POPOVER_TAB_STOP_SELECTOR)
2413
+ ).filter(isPopoverTabStop);
2414
+ }
2415
+ function getPopoverTrigger(content) {
2416
+ if (!content.id)
2417
+ return null;
2418
+ const id = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(content.id) : content.id;
2419
+ return content.ownerDocument.querySelector(
2420
+ `[aria-controls="${id}"]`
2421
+ );
2422
+ }
2423
+ function getPopoverTabStopOutside(reference, content, direction) {
2424
+ const candidates = Array.from(
2425
+ content.ownerDocument.querySelectorAll(
2426
+ POPOVER_TAB_STOP_SELECTOR
2427
+ )
2428
+ ).filter((node) => !content.contains(node) && isPopoverTabStop(node));
2429
+ if (direction === "next") {
2430
+ return candidates.find(
2431
+ (node) => Boolean(
2432
+ reference.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING
2433
+ )
2434
+ ) ?? null;
2435
+ }
2436
+ let previous = null;
2437
+ for (const node of candidates) {
2438
+ const relation = reference.compareDocumentPosition(node);
2439
+ if (node === reference || relation & Node.DOCUMENT_POSITION_PRECEDING) {
2440
+ previous = node;
2441
+ } else {
2442
+ break;
2443
+ }
2444
+ }
2445
+ return previous;
2446
+ }
2447
+ var Popover = ({ modal = false, children, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(PopoverModalContext.Provider, { value: modal, children: /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { ...props, modal, children }) });
2448
+ Popover.displayName = "Popover";
2340
2449
  var PopoverTrigger = PopoverPrimitive__namespace.Trigger;
2341
2450
  var PopoverAnchor = PopoverPrimitive__namespace.Anchor;
2342
2451
  var PopoverContent = React12__namespace.forwardRef(({
@@ -2351,42 +2460,79 @@ var PopoverContent = React12__namespace.forwardRef(({
2351
2460
  closeOnInteractOutside = true,
2352
2461
  overlayBackdrop = false,
2353
2462
  sideOffset = 4,
2463
+ onKeyDown,
2354
2464
  ...props
2355
- }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2356
- overlayBackdrop && /* @__PURE__ */ jsxRuntime.jsx(
2357
- "div",
2358
- {
2359
- className: "fixed inset-0 z-40 bg-black/50"
2360
- }
2361
- ),
2362
- /* @__PURE__ */ jsxRuntime.jsx(
2363
- PopoverPrimitive__namespace.Content,
2364
- {
2365
- ref,
2366
- side,
2367
- sideOffset,
2368
- collisionPadding: 8,
2369
- onInteractOutside: (e) => {
2370
- if (!closeOnInteractOutside) {
2371
- e.preventDefault();
2372
- }
2373
- },
2374
- className: cn(
2375
- popoverContentVariants({
2376
- variant,
2377
- size,
2378
- side,
2379
- position,
2380
- radius,
2381
- shadow
2382
- }),
2383
- backdrop && "backdrop-blur-md bg-opacity-80",
2384
- className
2385
- ),
2386
- ...props
2465
+ }, ref) => {
2466
+ const isModal = React12__namespace.useContext(PopoverModalContext);
2467
+ const handleKeyDown = (event) => {
2468
+ onKeyDown?.(event);
2469
+ if (event.defaultPrevented)
2470
+ return;
2471
+ if (isModal)
2472
+ return;
2473
+ if (event.key !== "Tab")
2474
+ return;
2475
+ if (event.altKey || event.ctrlKey || event.metaKey)
2476
+ return;
2477
+ const content = event.currentTarget;
2478
+ const active = content.ownerDocument.activeElement;
2479
+ if (!active || active !== content && !content.contains(active))
2480
+ return;
2481
+ const tabStops = getPopoverTabStopsWithin(content);
2482
+ const forward = !event.shiftKey;
2483
+ const atEdge = tabStops.length === 0 ? active === content : active === (forward ? tabStops[tabStops.length - 1] : tabStops[0]);
2484
+ if (!atEdge)
2485
+ return;
2486
+ const reference = getPopoverTrigger(content) ?? content;
2487
+ const target = getPopoverTabStopOutside(
2488
+ reference,
2489
+ content,
2490
+ forward ? "next" : "previous"
2491
+ );
2492
+ event.preventDefault();
2493
+ if (target) {
2494
+ target.focus();
2495
+ } else {
2496
+ active.blur();
2387
2497
  }
2388
- )
2389
- ] }));
2498
+ };
2499
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2500
+ overlayBackdrop && /* @__PURE__ */ jsxRuntime.jsx(
2501
+ "div",
2502
+ {
2503
+ className: "fixed inset-0 z-40 bg-black/50"
2504
+ }
2505
+ ),
2506
+ /* @__PURE__ */ jsxRuntime.jsx(
2507
+ PopoverPrimitive__namespace.Content,
2508
+ {
2509
+ ref,
2510
+ side,
2511
+ sideOffset,
2512
+ collisionPadding: 8,
2513
+ onInteractOutside: (e) => {
2514
+ if (!closeOnInteractOutside) {
2515
+ e.preventDefault();
2516
+ }
2517
+ },
2518
+ onKeyDown: handleKeyDown,
2519
+ className: cn(
2520
+ popoverContentVariants({
2521
+ variant,
2522
+ size,
2523
+ side,
2524
+ position,
2525
+ radius,
2526
+ shadow
2527
+ }),
2528
+ backdrop && "backdrop-blur-md bg-opacity-80",
2529
+ className
2530
+ ),
2531
+ ...props
2532
+ }
2533
+ )
2534
+ ] });
2535
+ });
2390
2536
  PopoverContent.displayName = PopoverPrimitive__namespace.Content.displayName;
2391
2537
  var PopoverClose = PopoverPrimitive__namespace.Close;
2392
2538
  var PopoverSeparator = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -2478,7 +2624,22 @@ var tabsTriggerVariants = classVarianceAuthority.cva(
2478
2624
  variant: {
2479
2625
  default: "rounded-md data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm dark:data-[state=active]:bg-gray-900 dark:data-[state=active]:text-gray-100 dark:data-[state=active]:shadow-gray-950/10",
2480
2626
  underline: "rounded-none border-b-2 border-transparent pb-2 data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-foreground dark:data-[state=active]:border-primary/80 dark:data-[state=active]:text-gray-100",
2481
- pills: "rounded-lg bg-gray-100 hover:bg-gray-200/80 border border-gray-300 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:border-primary dark:bg-gray-800 dark:hover:bg-gray-700 dark:border-gray-700 dark:data-[state=active]:bg-primary/90 dark:data-[state=active]:text-white dark:data-[state=active]:border-primary",
2627
+ // #646: `dark:data-[state=active]:text-white` KALDIRILDI. `--primary` koyu
2628
+ // temada BİLİNÇLİ near-white'tır (tokens.css:500, #368 kararı — DEĞİŞMEZ),
2629
+ // dolayısıyla aktif pill'e açıkça beyaz metin yazmak beyaz-üstüne-beyaz
2630
+ // demekti: ölçülen 1.28:1 (gerçek tarayıcı, /docs/components/tabs, koyu tema).
2631
+ // Sınıf kalkınca öneksiz `data-[state=active]:text-primary-foreground`
2632
+ // (koyu temada near-black) devreye girer → 15.91:1. Açık temada hiçbir
2633
+ // değişiklik yok (`dark:` sınıfı orada zaten uygulanmıyordu; ölçülen 4.70:1).
2634
+ //
2635
+ // ⚠️ `dark:data-[state=active]:bg-primary/90` BİLEREK KORUNDU: onu da
2636
+ // kaldırmak #545'in "ihlal takası" tuzağına düşürüyor. Aynı varyanttaki
2637
+ // `dark:bg-gray-800` (inaktif zemin) ile `data-[state=active]:bg-primary`
2638
+ // ÖZGÜLLÜKÇE EŞİT (0,2,0); kaynak sırası nedeniyle `dark:bg-gray-800`
2639
+ // kazanıyor ve aktif pill koyu temada inaktif görünüyordu — near-black metin
2640
+ // gray-800 üstünde 1.41:1 ile YENİ bir ihlal (ölçüldü). Koyu temada aktif
2641
+ // durumun zemini bu yüzden `dark:` özgüllüğünde kalmak ZORUNDA.
2642
+ pills: "rounded-lg bg-gray-100 hover:bg-gray-200/80 border border-gray-300 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:border-primary dark:bg-gray-800 dark:hover:bg-gray-700 dark:border-gray-700 dark:data-[state=active]:bg-primary/90 dark:data-[state=active]:border-primary",
2482
2643
  cards: "rounded-md bg-muted/50 hover:bg-muted data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-md dark:bg-gray-800/50 dark:hover:bg-gray-700/50 dark:data-[state=active]:bg-gray-900 dark:data-[state=active]:text-gray-100 dark:data-[state=active]:shadow-gray-950/20",
2483
2644
  minimal: "rounded-sm bg-transparent hover:bg-muted/30 data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:underline data-[state=active]:underline-offset-4 dark:hover:bg-gray-800/30 dark:data-[state=active]:text-gray-200"
2484
2645
  },
@@ -4861,7 +5022,61 @@ function DraggableList({
4861
5022
  keyExtractor(item)
4862
5023
  )) });
4863
5024
  }
4864
- var DropdownMenu = DropdownMenuPrimitive__namespace.Root;
5025
+ var DropdownMenuCloseContext = React12__namespace.createContext(null);
5026
+ var DropdownMenu = ({
5027
+ open,
5028
+ defaultOpen,
5029
+ onOpenChange,
5030
+ children,
5031
+ ...props
5032
+ }) => {
5033
+ const [uncontrolledOpen, setUncontrolledOpen] = React12__namespace.useState(
5034
+ defaultOpen ?? false
5035
+ );
5036
+ const isControlled = open !== void 0;
5037
+ const currentOpen = isControlled ? open : uncontrolledOpen;
5038
+ const handleOpenChange = React12__namespace.useCallback(
5039
+ (nextOpen) => {
5040
+ if (!isControlled)
5041
+ setUncontrolledOpen(nextOpen);
5042
+ onOpenChange?.(nextOpen);
5043
+ },
5044
+ [isControlled, onOpenChange]
5045
+ );
5046
+ const close = React12__namespace.useCallback(() => handleOpenChange(false), [
5047
+ handleOpenChange
5048
+ ]);
5049
+ return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuCloseContext.Provider, { value: close, children: /* @__PURE__ */ jsxRuntime.jsx(
5050
+ DropdownMenuPrimitive__namespace.Root,
5051
+ {
5052
+ ...props,
5053
+ open: currentOpen,
5054
+ onOpenChange: handleOpenChange,
5055
+ children
5056
+ }
5057
+ ) });
5058
+ };
5059
+ DropdownMenu.displayName = "DropdownMenu";
5060
+ function useDropdownMenuTabDismiss(onKeyDown) {
5061
+ const close = React12__namespace.useContext(DropdownMenuCloseContext);
5062
+ return (event) => {
5063
+ onKeyDown?.(event);
5064
+ if (event.defaultPrevented)
5065
+ return;
5066
+ if (event.key !== "Tab")
5067
+ return;
5068
+ if (event.altKey || event.ctrlKey || event.metaKey)
5069
+ return;
5070
+ if (!close)
5071
+ return;
5072
+ const target = event.target;
5073
+ if (target?.closest("[data-radix-menu-content]") !== event.currentTarget) {
5074
+ return;
5075
+ }
5076
+ event.preventDefault();
5077
+ close();
5078
+ };
5079
+ }
4865
5080
  var DropdownMenuTrigger = DropdownMenuPrimitive__namespace.Trigger;
4866
5081
  var DropdownMenuGroup = DropdownMenuPrimitive__namespace.Group;
4867
5082
  var DropdownMenuPortal = DropdownMenuPrimitive__namespace.Portal;
@@ -4884,30 +5099,38 @@ var DropdownMenuSubTrigger = React12__namespace.forwardRef(({ className, inset,
4884
5099
  }
4885
5100
  ));
4886
5101
  DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive__namespace.SubTrigger.displayName;
4887
- var DropdownMenuSubContent = React12__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
4888
- DropdownMenuPrimitive__namespace.SubContent,
4889
- {
4890
- ref,
4891
- className: cn(
4892
- "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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",
4893
- className
4894
- ),
4895
- ...props
4896
- }
4897
- ));
5102
+ var DropdownMenuSubContent = React12__namespace.forwardRef(({ className, onKeyDown, ...props }, ref) => {
5103
+ const handleKeyDown = useDropdownMenuTabDismiss(onKeyDown);
5104
+ return /* @__PURE__ */ jsxRuntime.jsx(
5105
+ DropdownMenuPrimitive__namespace.SubContent,
5106
+ {
5107
+ ref,
5108
+ onKeyDown: handleKeyDown,
5109
+ className: cn(
5110
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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",
5111
+ className
5112
+ ),
5113
+ ...props
5114
+ }
5115
+ );
5116
+ });
4898
5117
  DropdownMenuSubContent.displayName = DropdownMenuPrimitive__namespace.SubContent.displayName;
4899
- var DropdownMenuContent = React12__namespace.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
4900
- DropdownMenuPrimitive__namespace.Content,
4901
- {
4902
- ref,
4903
- sideOffset,
4904
- className: cn(
4905
- "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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",
4906
- className
4907
- ),
4908
- ...props
4909
- }
4910
- ) }));
5118
+ var DropdownMenuContent = React12__namespace.forwardRef(({ className, sideOffset = 4, onKeyDown, ...props }, ref) => {
5119
+ const handleKeyDown = useDropdownMenuTabDismiss(onKeyDown);
5120
+ return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
5121
+ DropdownMenuPrimitive__namespace.Content,
5122
+ {
5123
+ ref,
5124
+ sideOffset,
5125
+ onKeyDown: handleKeyDown,
5126
+ className: cn(
5127
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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",
5128
+ className
5129
+ ),
5130
+ ...props
5131
+ }
5132
+ ) });
5133
+ });
4911
5134
  DropdownMenuContent.displayName = DropdownMenuPrimitive__namespace.Content.displayName;
4912
5135
  var DropdownMenuItem = React12__namespace.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
4913
5136
  DropdownMenuPrimitive__namespace.Item,
@@ -5391,6 +5614,10 @@ var FileUpload = React12__namespace.default.forwardRef(
5391
5614
  {
5392
5615
  className: cn(
5393
5616
  "relative border-2 border-dashed rounded-lg p-8 text-center transition-colors",
5617
+ // #661-2: dosya girdisi `opacity-0` ile tum alani kapliyor; klavyeyle
5618
+ // Tab'landiginda HICBIR gorsel iz yoktu (WCAG 2.4.7). Odak halkasi
5619
+ // sarmalayiciya `focus-within` ile bagli — kutunun kendisi odaklanamaz.
5620
+ "focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
5394
5621
  isDragOver && "border-primary bg-primary/5",
5395
5622
  disabled && "opacity-50 cursor-not-allowed",
5396
5623
  !disabled && "hover:border-primary/50 cursor-pointer"
@@ -6306,7 +6533,7 @@ var selectTriggerVariants = classVarianceAuthority.cva(
6306
6533
  );
6307
6534
  var SelectTrigger = React12__namespace.forwardRef(({ className, children, variant, size, error, success, loading, leftIcon, rightIcon, ...props }, ref) => {
6308
6535
  const icerikId = React12__namespace.useId();
6309
- const adVerilmis = props["aria-label"] != null || props["aria-labelledby"] != null;
6536
+ const isNamed = props["aria-label"] != null || props["aria-labelledby"] != null;
6310
6537
  return /* @__PURE__ */ jsxRuntime.jsxs(
6311
6538
  SelectPrimitive__namespace.Trigger,
6312
6539
  {
@@ -6325,7 +6552,7 @@ var SelectTrigger = React12__namespace.forwardRef(({ className, children, varian
6325
6552
  "data-error": error ? true : void 0,
6326
6553
  "data-success": success ? true : void 0,
6327
6554
  "data-loading": loading ? true : void 0,
6328
- "aria-labelledby": adVerilmis ? props["aria-labelledby"] : icerikId,
6555
+ "aria-labelledby": isNamed ? props["aria-labelledby"] : icerikId,
6329
6556
  children: [
6330
6557
  /* @__PURE__ */ jsxRuntime.jsxs("div", { id: icerikId, className: "flex items-center flex-1 gap-2", children: [
6331
6558
  leftIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center text-muted-foreground", children: leftIcon }),
@@ -6433,8 +6660,8 @@ var SelectItem = React12__namespace.forwardRef(({ className, children, variant =
6433
6660
  variant === "default" && "focus:bg-accent focus:text-accent-foreground dark:focus:bg-gray-700 dark:focus:text-gray-100",
6434
6661
  variant === "subtle" && "focus:bg-gray-100 dark:focus:bg-gray-800 focus:text-foreground dark:focus:text-gray-200",
6435
6662
  variant === "destructive" && "text-error dark:text-red-400 focus:bg-error/10 dark:focus:bg-red-900/20 focus:text-error dark:focus:text-red-300",
6436
- variant === "success" && "text-success dark:text-green-400 focus:bg-success/10 dark:focus:bg-green-900/20 focus:text-success dark:focus:text-green-300",
6437
- variant === "warning" && "text-warning dark:text-yellow-400 focus:bg-warning/10 dark:focus:bg-yellow-900/20 focus:text-warning dark:focus:text-yellow-300",
6663
+ variant === "success" && "text-success focus:bg-success/10 focus:text-success",
6664
+ variant === "warning" && "text-warning-700 dark:text-warning-500 focus:bg-warning/10 focus:text-warning-700 dark:focus:text-warning-500",
6438
6665
  className
6439
6666
  ),
6440
6667
  ...props,
@@ -7207,8 +7434,100 @@ var tooltipVariants = classVarianceAuthority.cva(
7207
7434
  }
7208
7435
  }
7209
7436
  );
7210
- var Tooltip = TooltipPrimitive__namespace.Root;
7211
- var TooltipTrigger = TooltipPrimitive__namespace.Trigger;
7437
+ var TooltipFocusHoldContext = React12__namespace.createContext(null);
7438
+ function isKeyboardFocus(element) {
7439
+ if (!element)
7440
+ return false;
7441
+ try {
7442
+ return element.matches(":focus-visible");
7443
+ } catch {
7444
+ return true;
7445
+ }
7446
+ }
7447
+ var Tooltip = ({
7448
+ open,
7449
+ defaultOpen,
7450
+ onOpenChange,
7451
+ children,
7452
+ ...props
7453
+ }) => {
7454
+ const isControlled = open !== void 0;
7455
+ const [uncontrolledOpen, setUncontrolledOpen] = React12__namespace.useState(defaultOpen ?? false);
7456
+ const resolvedOpen = isControlled ? open : uncontrolledOpen;
7457
+ const isFocusHeldRef = React12__namespace.useRef(false);
7458
+ const hold = React12__namespace.useCallback(() => {
7459
+ isFocusHeldRef.current = true;
7460
+ }, []);
7461
+ const release = React12__namespace.useCallback(() => {
7462
+ isFocusHeldRef.current = false;
7463
+ }, []);
7464
+ const setOpen = React12__namespace.useCallback(
7465
+ (next) => {
7466
+ if (!isControlled)
7467
+ setUncontrolledOpen(next);
7468
+ onOpenChange?.(next);
7469
+ },
7470
+ [isControlled, onOpenChange]
7471
+ );
7472
+ const handleOpenChange = React12__namespace.useCallback(
7473
+ (next) => {
7474
+ if (!next && isFocusHeldRef.current)
7475
+ return;
7476
+ setOpen(next);
7477
+ },
7478
+ [setOpen]
7479
+ );
7480
+ React12__namespace.useEffect(() => {
7481
+ if (!resolvedOpen)
7482
+ return;
7483
+ const handleEscape = (event) => {
7484
+ if (event.key !== "Escape")
7485
+ return;
7486
+ isFocusHeldRef.current = false;
7487
+ setOpen(false);
7488
+ };
7489
+ document.addEventListener("keydown", handleEscape, true);
7490
+ return () => document.removeEventListener("keydown", handleEscape, true);
7491
+ }, [resolvedOpen, setOpen]);
7492
+ const focusHold = React12__namespace.useMemo(
7493
+ () => ({ hold, release }),
7494
+ [hold, release]
7495
+ );
7496
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipFocusHoldContext.Provider, { value: focusHold, children: /* @__PURE__ */ jsxRuntime.jsx(
7497
+ TooltipPrimitive__namespace.Root,
7498
+ {
7499
+ ...props,
7500
+ open: resolvedOpen,
7501
+ onOpenChange: handleOpenChange,
7502
+ children
7503
+ }
7504
+ ) });
7505
+ };
7506
+ Tooltip.displayName = "Tooltip";
7507
+ var TooltipTrigger = React12__namespace.forwardRef(({ onFocus, onBlur, onPointerDown, ...props }, ref) => {
7508
+ const focusHold = React12__namespace.useContext(TooltipFocusHoldContext);
7509
+ return /* @__PURE__ */ jsxRuntime.jsx(
7510
+ TooltipPrimitive__namespace.Trigger,
7511
+ {
7512
+ ref,
7513
+ ...props,
7514
+ onFocus: (event) => {
7515
+ if (isKeyboardFocus(event.currentTarget))
7516
+ focusHold?.hold();
7517
+ onFocus?.(event);
7518
+ },
7519
+ onBlur: (event) => {
7520
+ focusHold?.release();
7521
+ onBlur?.(event);
7522
+ },
7523
+ onPointerDown: (event) => {
7524
+ focusHold?.release();
7525
+ onPointerDown?.(event);
7526
+ }
7527
+ }
7528
+ );
7529
+ });
7530
+ TooltipTrigger.displayName = TooltipPrimitive__namespace.Trigger.displayName;
7212
7531
  var TooltipArrow = React12__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
7213
7532
  TooltipPrimitive__namespace.Arrow,
7214
7533
  {
@@ -8587,7 +8906,7 @@ var Textarea = React12__namespace.forwardRef(
8587
8906
  children: errorMessage || successMessage
8588
8907
  }
8589
8908
  ),
8590
- showCharCount && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground dark:text-gray-500 ml-auto", children: [
8909
+ showCharCount && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground ml-auto", children: [
8591
8910
  currentLength,
8592
8911
  maxLength !== void 0 && ` / ${maxLength}`
8593
8912
  ] })
@@ -8934,6 +9253,12 @@ var Rating = React12__namespace.forwardRef(
8934
9253
  },
8935
9254
  [readOnly, max, currentValue, step, commit]
8936
9255
  );
9256
+ const reactId = React12__namespace.useId();
9257
+ const optionId = React12__namespace.useCallback(
9258
+ (optionValue) => `${reactId}-option-${String(optionValue).replace(".", "-")}`,
9259
+ [reactId]
9260
+ );
9261
+ const activeValue = currentValue >= step && currentValue <= max ? currentValue : step;
8937
9262
  const renderIcon = (filled) => {
8938
9263
  if (React12__namespace.isValidElement(icon)) {
8939
9264
  const element = icon;
@@ -8963,6 +9288,7 @@ var Rating = React12__namespace.forwardRef(
8963
9288
  "aria-label": ariaLabel,
8964
9289
  "aria-orientation": "horizontal",
8965
9290
  "aria-readonly": readOnly || void 0,
9291
+ "aria-activedescendant": readOnly ? void 0 : optionId(activeValue),
8966
9292
  tabIndex: readOnly ? void 0 : 0,
8967
9293
  onKeyDown: handleKeyDown,
8968
9294
  onMouseLeave: () => setHoverValue(null),
@@ -8985,7 +9311,7 @@ var Rating = React12__namespace.forwardRef(
8985
9311
  "span",
8986
9312
  {
8987
9313
  "aria-hidden": "true",
8988
- className: "pointer-events-none absolute left-0 top-0 h-full overflow-hidden text-amber-400",
9314
+ className: "pointer-events-none absolute left-0 top-0 h-full overflow-hidden text-[rgb(var(--rating-star-rgb))]",
8989
9315
  style: { width: `${fraction * 100}%` },
8990
9316
  children: renderIcon(true)
8991
9317
  }
@@ -8996,6 +9322,7 @@ var Rating = React12__namespace.forwardRef(
8996
9322
  {
8997
9323
  type: "button",
8998
9324
  role: "radio",
9325
+ id: optionId(halfValue),
8999
9326
  "aria-checked": currentValue === halfValue,
9000
9327
  "aria-label": `${halfValue} stars`,
9001
9328
  tabIndex: -1,
@@ -9009,6 +9336,7 @@ var Rating = React12__namespace.forwardRef(
9009
9336
  {
9010
9337
  type: "button",
9011
9338
  role: "radio",
9339
+ id: optionId(starValue),
9012
9340
  "aria-checked": currentValue === starValue,
9013
9341
  "aria-label": `${starValue} stars`,
9014
9342
  tabIndex: -1,
@@ -9023,6 +9351,7 @@ var Rating = React12__namespace.forwardRef(
9023
9351
  {
9024
9352
  type: "button",
9025
9353
  role: "radio",
9354
+ id: optionId(starValue),
9026
9355
  "aria-checked": currentValue === starValue,
9027
9356
  "aria-label": `${starValue} ${starValue === 1 ? "star" : "stars"}`,
9028
9357
  tabIndex: -1,
@@ -9630,6 +9959,7 @@ exports.moonUIInputOTPSlotVariants = inputOTPSlotVariants;
9630
9959
  exports.moonUIKbdVariants = kbdVariants;
9631
9960
  exports.moonUIPopoverContentVariants = popoverContentVariants;
9632
9961
  exports.moonUIRatingVariants = ratingVariants;
9962
+ exports.moonUISeparatorVariants = separatorVariants;
9633
9963
  exports.moonUISkeletonVariants = skeletonVariants;
9634
9964
  exports.moonUISpinnerVariants = spinnerVariants;
9635
9965
  exports.moonUIToggleVariants = toggleVariants;