@ahmetilhn/hanui 2.0.2 → 2.0.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/theme/palette.ts","../src/theme/tokens.ts","../src/helpers/theme.helper.ts","../src/theme/context.ts","../src/theme/HanuiProvider.tsx","../src/theme/initHanui.ts","../src/hooks/useAnnounce.ts","../src/hooks/useHanuiTheme.ts","../src/helpers/scroll.helper.ts","../src/hooks/useListboxNavigation.ts","../src/hooks/usePositioning.ts","../src/hooks/useVirtualList.ts","../src/hooks/useScrollLock.ts","../src/hooks/useSheetViewport.ts","../src/enums/ui-variant.enum.ts","../src/enums/ui-size.enum.ts","../src/constants/breakpoint.constants.ts","../src/helpers/text.helper.ts","../src/helpers/focus.helper.ts","../src/helpers/class-name.helper.ts","../src/helpers/component.helper.ts","../src/components/Link/index.tsx","../src/helpers/label.helper.ts","../src/components/Spinner/index.tsx","../src/components/Button/index.tsx","../src/components/IconButton/index.tsx","../src/components/TextLink/index.tsx","../src/components/Tooltip/index.tsx","../src/components/Menu/index.tsx","../src/components/Popover/index.tsx","../src/components/Chip/index.tsx","../src/components/ChipGroup/index.tsx","../src/components/BottomSheet/index.tsx","../src/components/Combobox/index.tsx","../src/components/SegmentedControl/index.tsx","../src/components/Select/index.tsx","../src/components/Checkbox/index.tsx","../src/components/Switch/index.tsx","../src/components/Radio/index.tsx","../src/components/RadioCard/index.tsx","../src/components/RangeSlider/index.tsx","../src/components/RatingInput/index.tsx","../src/components/QuantityStepper/index.tsx","../src/components/TableCheckbox/index.tsx","../src/components/Input/index.tsx","../src/components/TagInput/index.tsx","../src/components/Textarea/index.tsx","../src/components/DateField/index.tsx","../src/components/Field/index.tsx","../src/components/Progress/index.tsx","../src/components/FileUpload/index.tsx","../src/components/Alert/index.tsx","../src/components/Avatar/index.tsx","../src/components/Badge/index.tsx","../src/components/Breadcrumb/index.tsx","../src/components/Card/index.tsx","../src/components/Carousel/index.tsx","../src/components/CopyField/index.tsx","../src/components/Divider/index.tsx","../src/components/Directory/index.tsx","../src/components/EmptyState/index.tsx","../src/components/PageHeader/index.tsx","../src/components/Panel/index.tsx","../src/components/Price/index.tsx","../src/components/Rating/index.tsx","../src/components/SectionHeader/index.tsx","../src/components/ScrollArea/index.tsx","../src/components/Skeleton/index.tsx","../src/components/Stat/index.tsx","../src/components/Toast/index.tsx","../src/components/Accordion/index.tsx","../src/components/Steps/index.tsx","../src/components/Tabs/index.tsx","../src/components/Tile/index.tsx","../src/components/Timeline/index.tsx","../src/components/Modal/index.tsx","../src/components/CommandPalette/index.tsx","../src/components/ConfirmDialog/index.tsx","../src/components/Drawer/index.tsx","../src/components/PromptDialog/index.tsx","../src/components/Table/index.tsx","../src/components/DataTable/index.tsx","../src/components/FilterBar/index.tsx","../src/components/Pagination/index.tsx"],"sourcesContent":["/**\n * HAM PALET — kütüphanenin TEK hex kaynağı.\n *\n * <p>Başka hiçbir dosyada birebir renk değeri yazılmaz. Zincir:\n *\n * <pre>\n * theme/palette.ts → ham hex (yalnızca burada)\n * theme/tokens.ts → anlamsal token adı → hex eşlemesi (açık + koyu)\n * styles/_tokens.generated.scss → `:root` ve `[data-hanui-theme]` yayını\n * styles/_colors.generated.scss → bileşenlerin gördüğü SCSS sözleşmesi\n * </pre>\n *\n * <p>Son iki dosya `scripts/build-tokens.mjs` tarafından ÜRETİLİR. Elle\n * yazıldıklarında TypeScript tarafındaki token listesiyle ayrışıyorlar ve\n * ayrışma sessiz: bir bileşen var olmayan bir değişkeni okuyup rengi\n * kaybediyor, derleme yine yeşil dönüyordu.\n */\n\n// --- Nötr eksen -------------------------------------------------------\n// Serin gri-mavi. Sıcak kum tonundan ayrıldık: ürün fotoğrafları ağırlıkla\n// metal ve siyah plastik; sıcak zemin onları sarartıp kirli gösteriyordu.\nexport const NEUTRAL = {\n n0: '#ffffff',\n n25: '#fafbfc',\n n50: '#f6f7f9',\n n100: '#eef0f4',\n n150: '#e7eaef',\n n200: '#e2e6ec',\n /** Kart/girdi kenarı — `n200` sayfadan ayrılmıyordu. */\n n250: '#d6dce4',\n n300: '#c9d0da',\n n400: '#aab3c0',\n n500: '#8a94a3',\n /**\n * İkincil metnin okunur tabanı.\n *\n * ÖLÇÜLDÜ (birinci düzeltme): `text-3` `n500`'dü ve beyaz üzerinde 3,2:1\n * veriyor; üstü çizili fiyat, yer tutucu ve yardım metni gövde metni\n * sayıldığı için WCAG 1.4.3'ün 4,5:1 eşiğini GEÇMİYORDU. Aynı ton açısında\n * aydınlık düşürüldü: `#6b7583`, beyaz üzerinde 4,67:1.\n *\n * ÖLÇÜLDÜ (ikinci düzeltme, `scripts/check-contrast.mjs`): o değer yalnızca\n * BEYAZ üzerinde ölçülmüştü. Gerçekte aynı metin dört yüzeyin üzerine\n * düşüyor ve beyaz onların en açığı: `page` üzerinde 4,36:1, `surface-2`\n * üzerinde (cip sayacı, pasif girdi) 3,94:1 — yani ölçüm yapılan yer\n * dışındaki her yerde ihlal. Yüzeylerin en KOYUSU (`surface-2`) eşiği\n * belirler: `#626c7a` orada 4,67:1.\n *\n * <p>Bedeli açık: `n600` ile arasındaki fark daraldı (sayfa üzerinde 5,60'a\n * karşı 4,97). Üç kademeli soluk metin merdiveni bu paletin taşıyabileceğinin\n * sınırında; kademe sayısı bir tasarım kararıdır ve görsel dil fazında\n * yeniden görülür. Ama \"görünür ama okunmayan\" bir ton, kademesi bol bir\n * merdivenden kötüdür.\n */\n n550: '#626c7a',\n n600: '#5a6472',\n n700: '#3a424f',\n n800: '#232a35',\n n900: '#11151b',\n} as const;\n\n// --- Grafit -----------------------------------------------------------\n// Üst bant, alt bilgi, tablo başlıkları, teknik bloklar ve BİRİNCİL EYLEM.\nexport const GRAPHITE = {\n base: '#1f2937',\n two: '#2b3646',\n three: '#3a4658',\n /** Koyu temada üst bant; sayfadan koyu kalmalı. */\n ink: '#12161d',\n inkTwo: '#1c222b',\n} as const;\n\n// --- Amber ------------------------------------------------------------\n// EKRANDAKİ TEK DOYGUN TURUNCU: dönüşüm eylemi (\"sepete ekle\"). Başka\n// hiçbir yerde dolgu olarak kullanılmaz.\nexport const AMBER = {\n base: '#f59e0b',\n hover: '#d98706',\n active: '#b87205',\n /** Pasif dönüşüm düğmesi; saydamlık değil KENDİ dolgusu. */\n soft: '#f8cd80',\n dark: '#fbbf24',\n darkHover: '#f0af12',\n /** Amber üzerinde metin — beyaz 2,3:1'de kalıyor, okunmuyor. */\n on: '#291500',\n} as const;\n\n// --- Mavi -------------------------------------------------------------\n// Gezinme ve keşif: bağlantı, etkin filtre, odak halkası. Amber ile\n// çarpışmaz çünkü işleri farklı.\nexport const BLUE = {\n base: '#2f6fed',\n hover: '#1d54c4',\n active: '#17439c',\n /** Gövde metni içi bağlantı — `base` 16px'te 4,55:1. */\n text: '#1d54c4',\n tint: '#eaf1fe',\n line: '#bcd2fb',\n dark: '#5b93ff',\n darkHover: '#7aa8ff',\n darkTint: '#16243c',\n darkLine: '#2a3f63',\n} as const;\n\n/**\n * MARKA ANKORLARI: kırmızı ve yeşil.\n *\n * <p>Aşağıdaki iki hex, kendi ailelerinin TEK KAYNAĞIDIR. Ailedeki her ton\n * (tint zemini, kenarlık, metin, koyu tema karşılığı) HSL uzayında bu iki\n * değerden türetildi: ton açısı ve doygunluk korunur, yalnızca aydınlık\n * kaydırılır. Yeni bir kırmızı/yeşil ton gerektiğinde gözle seçilmez —\n * buradan türetilir, yoksa aile zamanla dağılır.\n *\n * <p>⚠ ANKORLAR METİN RENGİ DEĞİLDİR. `green` beyaz üzerinde 2,22:1 —\n * gövde metni olarak WCAG'i geçmez. Bu yüzden aile iki katmanlı: ankor\n * İKON ve DOLGU için, ondan türetilen koyu ton METİN için.\n */\nexport const ANCHOR = {\n red: '#dc2626',\n green: '#34c759',\n} as const;\n\n/**\n * DURUM RENKLERİ.\n *\n * <p>Kural: TINT ZEMİN + KOYU METİN + eşleşen hairline. Asla doygun dolgu —\n * doygun dolgu \"tıklanabilir\" demektir ve durum etiketi tıklanabilir değildir.\n *\n * <p>Kenarlık tonları bir kademe koyulaştırıldı: rozetler \"kutu\" olarak\n * okunmalı; daha açık çizgiler tint zeminin üzerinde kaybolup yan yana duran\n * iki rozeti tek bir lekeye çeviriyordu.\n */\nexport const STATUS = {\n /* Yeşil ailesi `ANCHOR.green`den türetildi (L +44 / S −24, L +33 / S −14). */\n okBg: '#e8f4eb',\n /** 5,58:1 tint üzerinde — metin katmanı. */\n okFg: '#1d6e31',\n okLine: '#a8dcb7',\n okBgDark: '#122817',\n /** Koyu zeminde ankorun kendisi okunuyor (7,05:1). */\n okFgDark: '#34c759',\n okLineDark: '#22542f',\n\n warnBg: '#fdf0dd',\n warnFg: '#7a3e02',\n warnLine: '#ebc687',\n warnBgDark: '#2c2008',\n warnFgDark: '#f5c86b',\n warnLineDark: '#55401a',\n\n offBg: '#f1f2f5',\n offFg: '#3a424f',\n offLine: '#ccd2db',\n offBgDark: '#212630',\n offFgDark: '#a3adbb',\n offLineDark: '#333b47',\n\n /*\n * Kırmızı ailesi `ANCHOR.red`den türetildi. Önceki `badFg` (#7f1d1d) bir\n * bordoydu: favori kalbi ve olumsuz rozet ekranda kirli/kahverengi\n * okunuyordu. Aynı ton açısında kalıp aydınlığı açmak rengi hem canlı hem\n * okunur yapıyor.\n */\n badBg: '#f8ebeb',\n /** 5,45:1 tint üzerinde. */\n badFg: '#bb1e1e',\n badLine: '#e6a6a6',\n badBgDark: '#310f0f',\n /** 6,03:1 koyu tint üzerinde. */\n badFgDark: '#e97575',\n badLineDark: '#621b1b',\n\n /** Birincil / orijinal sınıflandırma tonu. */\n oemBg: '#eaf1fe',\n oemFg: '#16305c',\n oemLine: '#a9c6f9',\n oemBgDark: '#152139',\n oemFgDark: '#9dc0ff',\n oemLineDark: '#27395c',\n\n /** İkincil / muadil sınıflandırma tonu. */\n altBg: '#eeebfa',\n altFg: '#2e2661',\n altLine: '#c0b6ea',\n altBgDark: '#1d1a33',\n altFgDark: '#bfb3f5',\n altLineDark: '#332d56',\n} as const;\n\n/**\n * YIKICI EYLEM DOLGUSU (silme onayı).\n *\n * <p>Durum tinti DEĞİL, gerçek bir düğme. Ankorun kendisi: beyaz metinle\n * 4,83:1. Aynı kırmızıyı taşımaları kullanıcının uyarı etiketine tıklamayı\n * denemesine yol açıyordu.\n */\nexport const DANGER_SOLID = {\n base: '#dc2626',\n hover: '#bb1e1e',\n dark: '#e45b5b',\n darkHover: '#ef7a72',\n onDark: '#1a0b0a',\n} as const;\n\n/**\n * İKON DOLGULARI — favori kalbi, kopyalandı tiki gibi METİN OLMAYAN,\n * doygun kalması gereken yerler. Eşik WCAG 1.4.11: grafik öğesi 3:1.\n *\n * <p>⚠ BU DOSYA BİR ZAMANLAR \"hepsi geçiyor\" DİYORDU VE GEÇMİYORLARDI.\n * `scripts/check-contrast.mjs` yazıldığında ölçüldü: ankorun kendisi\n * (`#34c759`) beyaz üzerinde 2,21:1, `surface-2` üzerinde 1,94:1 — grafik\n * eşiğinin yarısı. `CopyField`in \"kopyalandı\" tiki tam olarak bu tonda\n * çiziliyor ve tik, kopyalamanın başarılı olduğunu söyleyen TEK görsel\n * sinyaldi (metin `visually-hidden`). Yeşil ailesinin ikon katmanı bu yüzden\n * ankordan ayrıldı: ton açısı ve doygunluk korunarak aydınlık düşürüldü.\n *\n * <h3>Açık temada bu aile ESNEK DEĞİL</h3>\n * `green` iki eşiğin arasına sıkışır: bir ikon olarak açık yüzeyden ayrılmak\n * için KOYU olmalı (3:1), üzerine metin binecekse o metne yer bırakacak kadar\n * AÇIK kalmalı (4,5:1). Bant dar ve `#299d46` içinde duruyor: `surface-2`\n * üzerinde 3,06:1, `onGreen` ile 4,56:1.\n *\n * <p>Bunun bir sonucu var: <strong>metin taşıyan bir yeşil dolgunun hover'ı\n * dolguyu koyulaştıramaz.</strong> Bir kademe koyulaşan her ton `onGreen`i\n * 4,5'in altına düşürüyor (en koyu mürekkeple bile 4,47:1). `greenHover` bu\n * yüzden yalnızca İKON hover'ıdır; metin taşıyan bir yüzeyin hover'ı\n * kenarlıkta ya da gölgede anlatılır. Kütüphane bugün yeşil dolgu üzerine\n * metin çizmiyor; `onGreen` tüketici için duruyor ve sözleşmesi `green` ile.\n *\n * <p>Koyu tema sıkışık değil: orada zemin koyu, ikon açık ve iki eşik aynı\n * yöne çekiyor.\n */\nexport const ACCENT = {\n red: '#dc2626',\n redDark: '#e35252',\n /** 3,06:1 `surface-2` üzerinde — ailenin ikon katmanı, ankor değil. */\n green: '#299d46',\n greenDark: '#4cd76c',\n /** İKON hover'ı; metin taşıyan dolgunun hover'ı değil (yukarıdaki not). */\n greenHover: '#23883c',\n greenHoverDark: '#63e084',\n /** Yeşil dolgu üzerindeki metin. BEYAZ DEĞİL: `green` üzerinde 3,50:1. */\n onGreen: '#06280f',\n} as const;\n\n/**\n * İNDİRİM / OLUMLU DEĞİŞİM ETİKETİ.\n *\n * <p>Fiyat SİYAH kalır; rozet YEŞİL — kazancı kırmızı ile işaretlemek\n * \"uyarı\" gibi okunuyordu, oysa indirim iyi haber.\n */\nexport const SALE = {\n bg: '#e8f4eb',\n fg: '#1d6e31',\n bgDark: '#122817',\n fgDark: '#34c759',\n} as const;\n\n/**\n * YILDIZ ALTINI.\n *\n * <p>Amber ailesinden AYRI kalır (amber yalnızca dönüşüm eylemi), ama eski\n * uyarı tonu (#7a3e02) bir kahverengiydi ve puan yıldızları kirli\n * görünüyordu. Bu ton sıcaklığı korur, doygun turuncuyla yarışmaz ve tek\n * başına bir dolgu olarak okunmaz.\n */\nexport const STAR = {\n /** 5,23:1 beyaz üzerinde. */\n light: '#9a5f04',\n /** 9,82:1 koyu zemin üzerinde. */\n dark: '#f0b429',\n} as const;\n","import {\n ACCENT,\n AMBER,\n BLUE,\n DANGER_SOLID,\n GRAPHITE,\n NEUTRAL,\n SALE,\n STAR,\n STATUS,\n} from './palette';\n\n/**\n * TEMA TOKEN'LARI.\n *\n * <p>Her anahtar bir CSS özel özelliğine karşılık gelir: `page` →\n * `--hanui-page`. Bileşenler SCSS tarafında yalnızca bu adları görür ve hepsi\n * bir `var(--hanui-…)` işaret eder.\n *\n * <h3>Neden CSS değişkeni, neden SCSS değişkeni değil</h3>\n * Açık/koyu tema ÇALIŞMA ZAMANINDA değişir; SCSS değişkeni derleme anında\n * sabitlenir ve tek derlemeden iki tema çıkmaz. Bunun iki sonucu var:\n *\n * <ol>\n * <li>Renk üzerinde SCSS renk fonksiyonu ÇALIŞMAZ (`rgba($surface, .9)`\n * derlenmez). Gereken her saydam değer hazır token olarak durur:\n * `scrim`, `glass`, `ring`, `track`, `glow-1`…</li>\n * <li>`prefers-color-scheme` ile renk SEÇİLMEZ. Tema `data-hanui-theme`\n * üzerinden gelir; medya sorgusu kullanıcının açık seçimini görmez —\n * yalnızca hiç seçim yapılmadığında yedek olarak devreye girer.</li>\n * </ol>\n */\n\n/** Hex rengi `rgba(...)` dizesine çevirir. Renk fonksiyonu üretim ANINDA çalışır. */\nconst alpha = (hex: string, value: number): string => {\n const normalized = hex.replace('#', '');\n const full =\n normalized.length === 3\n ? normalized\n .split('')\n .map(character => character + character)\n .join('')\n : normalized;\n\n const red = parseInt(full.slice(0, 2), 16);\n const green = parseInt(full.slice(2, 4), 16);\n const blue = parseInt(full.slice(4, 6), 16);\n\n return `rgba(${red}, ${green}, ${blue}, ${value})`;\n};\n\nconst BLACK = '#000000';\n\n/**\n * AÇIK TEMA — varsayılan.\n *\n * <p>Bilgi yoğunluğu yüksek ekranlarda açık zeminde okunurluk daha yüksek.\n */\nexport const LIGHT_THEME = {\n // --- Yüzey ---\n page: NEUTRAL.n50,\n surface: NEUTRAL.n0,\n 'surface-2': NEUTRAL.n100,\n 'surface-3': NEUTRAL.n150,\n 'surface-inset': NEUTRAL.n25,\n\n // --- Kenarlık ---\n border: NEUTRAL.n250,\n 'border-strong': NEUTRAL.n300,\n\n // --- Metin ---\n text: NEUTRAL.n900,\n 'text-2': NEUTRAL.n600,\n 'text-3': NEUTRAL.n550,\n\n // --- Grafit: bant, alt bilgi, tablo başlığı, teknik blok ---\n graphite: GRAPHITE.base,\n 'graphite-2': GRAPHITE.two,\n 'graphite-3': GRAPHITE.three,\n\n /*\n * BİRİNCİL EYLEM (dolgulu, nötr).\n *\n * `action` grafittir, amber DEĞİL. Amber tek bir dönüşüm noktasına\n * ayrılmıştır; her dolu düğmeyi amber yapmak o tekilliği yok eder ve\n * kullanıcı hangi turuncunun dönüşüm olduğunu bilemez.\n */\n action: GRAPHITE.base,\n 'action-hover': GRAPHITE.two,\n 'action-active': GRAPHITE.three,\n 'on-action': NEUTRAL.n0,\n /** Pasif dolgu; saydamlık DEĞİL kendi rengi (bkz. Button `:disabled`). */\n 'action-soft': NEUTRAL.n300,\n\n // --- Dönüşüm eylemi: ekrandaki tek doygun turuncu ---\n amber: AMBER.base,\n 'amber-hover': AMBER.hover,\n 'amber-active': AMBER.active,\n 'amber-soft': AMBER.soft,\n 'on-amber': AMBER.on,\n\n // --- Mavi: gezinme ve keşif ---\n blue: BLUE.base,\n 'blue-hover': BLUE.hover,\n 'blue-active': BLUE.active,\n 'blue-text': BLUE.text,\n 'blue-tint': BLUE.tint,\n 'blue-line': BLUE.line,\n\n // --- Durum: tint zemin + koyu metin + eşleşen hairline ---\n 'ok-bg': STATUS.okBg,\n 'ok-fg': STATUS.okFg,\n 'ok-line': STATUS.okLine,\n\n 'warn-bg': STATUS.warnBg,\n 'warn-fg': STATUS.warnFg,\n 'warn-line': STATUS.warnLine,\n\n 'off-bg': STATUS.offBg,\n 'off-fg': STATUS.offFg,\n 'off-line': STATUS.offLine,\n\n 'bad-bg': STATUS.badBg,\n 'bad-fg': STATUS.badFg,\n 'bad-line': STATUS.badLine,\n\n 'oem-bg': STATUS.oemBg,\n 'oem-fg': STATUS.oemFg,\n 'oem-line': STATUS.oemLine,\n\n 'alt-bg': STATUS.altBg,\n 'alt-fg': STATUS.altFg,\n 'alt-line': STATUS.altLine,\n\n 'sale-bg': SALE.bg,\n 'sale-fg': SALE.fg,\n\n // --- İkon vurguları: METİN DEĞİL (WCAG grafik eşiği 3:1) ---\n 'red-accent': ACCENT.red,\n 'green-accent': ACCENT.green,\n 'green-accent-hover': ACCENT.greenHover,\n 'on-green': ACCENT.onGreen,\n star: STAR.light,\n\n // --- Yıkıcı eylem: durum tinti DEĞİL, gerçek bir dolgu ---\n 'danger-solid': DANGER_SOLID.base,\n 'danger-solid-hover': DANGER_SOLID.hover,\n 'on-danger': NEUTRAL.n0,\n\n /*\n * ÜST BANT / ALT BİLGİ / KAHRAMAN BÖLÜMÜ.\n *\n * BU TOKEN'LAR TEMAYI İZLER: açık temada her yer açık, koyu temada her yer\n * koyu. Ayrı bir ad kümesi olarak kalıyorlar çünkü bantların KENDİ yüzey\n * merdiveni var: üst bant sayfadan bir kademe yükselir (beyaz zemin, gri\n * sayfa üzerinde), alt bilgi bir kademe çöker. Bunu `surface` ile yazmak\n * iki bandı sayfayla aynı tonda bırakıyordu.\n */\n 'nav-bg': NEUTRAL.n0,\n 'nav-bg-2': NEUTRAL.n100,\n 'nav-fg': NEUTRAL.n900,\n 'nav-fg-2': NEUTRAL.n600,\n /*\n * `n500` DEĞİL. Ölçüldü: `n500` üst bandın beyaz zemininde 3,06:1, alt\n * bilginin `n100` zemininde 2,68:1 veriyordu — yani bandın en soluk metni\n * (telif satırı, yardımcı bağlantılar) hiçbir yerde gövde metni eşiğini\n * geçmiyordu. Sayfa tarafındaki karşılığıyla (`text-3`) aynı tona bağlandı:\n * ikisi aynı işi yapıyor ve ayrı tutulmalarının tek sebebi bandın kendi\n * yüzey merdiveniydi, kendi okunurluk kuralı değil.\n */\n 'nav-fg-3': NEUTRAL.n550,\n 'nav-line': NEUTRAL.n200,\n 'nav-line-strong': NEUTRAL.n300,\n 'nav-hover': NEUTRAL.n100,\n 'footer-bg': NEUTRAL.n100,\n\n // --- Gölge: nötr-serin (sıcak gölge serin gri zeminde kirli durur) ---\n 'shadow-xs': `0 1px 2px ${alpha(NEUTRAL.n900, 0.05)}`,\n 'shadow-sm': `0 1px 2px ${alpha(NEUTRAL.n900, 0.05)}, 0 1px 3px ${alpha(NEUTRAL.n900, 0.04)}`,\n 'shadow-md': `0 2px 4px ${alpha(NEUTRAL.n900, 0.04)}, 0 6px 16px ${alpha(NEUTRAL.n900, 0.07)}`,\n 'shadow-lg': `0 4px 8px ${alpha(NEUTRAL.n900, 0.05)}, 0 16px 32px ${alpha(NEUTRAL.n900, 0.1)}`,\n 'shadow-xl': `0 8px 16px ${alpha(NEUTRAL.n900, 0.06)}, 0 28px 56px ${alpha(NEUTRAL.n900, 0.13)}`,\n /** Yapışkan alt bar; gölge YUKARI düşer. */\n 'shadow-up': `0 -2px 4px ${alpha(NEUTRAL.n900, 0.03)}, 0 -8px 24px ${alpha(NEUTRAL.n900, 0.08)}`,\n\n /** Odak halkası MAVİ: odak bir gezinme olayıdır, bir dönüşüm değil. */\n ring: `0 0 0 3px ${alpha(BLUE.base, 0.28)}`,\n 'ring-color': BLUE.base,\n 'ring-danger': `0 0 0 3px ${alpha(DANGER_SOLID.base, 0.24)}`,\n 'ring-ok': `0 0 0 4px ${alpha(STATUS.okFg, 0.16)}`,\n\n // --- Örtü ve cam: görsel üzerine binen yüzeyler ---\n /*\n * %55 DEĞİL. Örtü yalnızca kip pencerenin arkasını karartmıyor; `on-scrim`\n * onun üzerine yazılan metnin rengi ve o metin AÇIK temada bir sayfanın\n * üstüne düşüyor. Ölçüldü: %55 örtü `page` üzerine düzlendiğinde beyaz metin\n * 4,27:1 — gövde metni eşiğinin altında. %60'ta 5,01:1.\n *\n * <p>Koyu temada sorun yok (20:1); ölçüyü belirleyen açık tema.\n */\n scrim: alpha(NEUTRAL.n900, 0.6),\n 'scrim-soft': alpha(NEUTRAL.n900, 0.32),\n glass: alpha(NEUTRAL.n0, 0.92),\n 'glass-solid': NEUTRAL.n0,\n 'on-scrim': NEUTRAL.n0,\n\n // --- İskelet ve dönen gösterge ---\n 'skeleton-a': NEUTRAL.n100,\n 'skeleton-b': NEUTRAL.n25,\n track: alpha(NEUTRAL.n900, 0.12),\n\n /** Görsel yer tutucu (medya yoksa). */\n 'media-bg': NEUTRAL.n100,\n\n /*\n * Vurgu bloğundaki ışık lekeleri. Açık temada ZEMİN DE AÇIK olduğu için\n * lekeler çok daha hafif: koyu bant için ayarlanmış %22 opaklık açık\n * zeminde lekeyi kirli bir dasa çeviriyordu.\n */\n 'glow-1': alpha(BLUE.base, 0.1),\n 'glow-2': alpha(BLUE.base, 0.06),\n 'glow-amber': alpha(AMBER.base, 0.09),\n} as const;\n\n/**\n * KOYU TEMA.\n *\n * <p>Yüzey merdiveni açık temanın AYNISI DEĞİL, tersi: koyu temada yükselen\n * yüzey AÇILIR (`surface` > `page`), çünkü ışık yukarıdan gelir. Aynı sırayı\n * korumak kartları sayfaya gömüyordu.\n */\nexport const DARK_THEME: Record<keyof typeof LIGHT_THEME, string> = {\n page: '#0e1116',\n surface: '#171b22',\n 'surface-2': '#1f242d',\n 'surface-3': '#262c36',\n 'surface-inset': '#13171d',\n\n border: '#262c36',\n 'border-strong': '#363e4a',\n\n text: '#e7eaee',\n 'text-2': '#9aa4b2',\n /*\n * Açık temanın `text-3`ü ile AYNI HEX DEĞİL, olamaz da: koyu temada aynı ton\n * zeminden uzaklaşmaz, yaklaşır. Ölçüldü: `#6b7583` `surface` üzerinde\n * 3,69:1 ve `surface-2` üzerinde 3,25:1 — yer tutucu ve üstü çizili fiyat\n * koyu temada okunmuyordu. `#818b99` yüzeylerin en açığında (`surface-2`)\n * 4,51:1.\n */\n 'text-3': '#818b99',\n\n graphite: GRAPHITE.ink,\n 'graphite-2': GRAPHITE.inkTwo,\n 'graphite-3': GRAPHITE.two,\n\n /*\n * Koyu temada grafit dolgu sayfadan ayırt edilemez. Birincil eylem AÇIK bir\n * nötr yüzeye döner — koyu zeminde en yüksek vurgu budur.\n */\n action: NEUTRAL.n150,\n 'action-hover': NEUTRAL.n0,\n 'action-active': NEUTRAL.n300,\n 'on-action': NEUTRAL.n900,\n 'action-soft': '#414a58',\n\n amber: AMBER.dark,\n 'amber-hover': AMBER.darkHover,\n 'amber-active': AMBER.base,\n 'amber-soft': '#6d5316',\n 'on-amber': AMBER.on,\n\n blue: BLUE.dark,\n 'blue-hover': BLUE.darkHover,\n 'blue-active': BLUE.base,\n 'blue-text': BLUE.dark,\n 'blue-tint': BLUE.darkTint,\n 'blue-line': BLUE.darkLine,\n\n 'ok-bg': STATUS.okBgDark,\n 'ok-fg': STATUS.okFgDark,\n 'ok-line': STATUS.okLineDark,\n\n 'warn-bg': STATUS.warnBgDark,\n 'warn-fg': STATUS.warnFgDark,\n 'warn-line': STATUS.warnLineDark,\n\n 'off-bg': STATUS.offBgDark,\n 'off-fg': STATUS.offFgDark,\n 'off-line': STATUS.offLineDark,\n\n 'bad-bg': STATUS.badBgDark,\n 'bad-fg': STATUS.badFgDark,\n 'bad-line': STATUS.badLineDark,\n\n 'oem-bg': STATUS.oemBgDark,\n 'oem-fg': STATUS.oemFgDark,\n 'oem-line': STATUS.oemLineDark,\n\n 'alt-bg': STATUS.altBgDark,\n 'alt-fg': STATUS.altFgDark,\n 'alt-line': STATUS.altLineDark,\n\n 'sale-bg': SALE.bgDark,\n 'sale-fg': SALE.fgDark,\n\n 'red-accent': ACCENT.redDark,\n 'green-accent': ACCENT.greenDark,\n 'green-accent-hover': ACCENT.greenHoverDark,\n 'on-green': ACCENT.onGreen,\n star: STAR.dark,\n\n 'danger-solid': DANGER_SOLID.dark,\n 'danger-solid-hover': DANGER_SOLID.darkHover,\n 'on-danger': DANGER_SOLID.onDark,\n\n /* Koyu temada bant sayfadan daha KOYU: aynı tonda olsa yüzüyor görünüyor. */\n 'nav-bg': GRAPHITE.ink,\n 'nav-bg-2': GRAPHITE.inkTwo,\n 'nav-fg': '#e7eaee',\n 'nav-fg-2': '#9aa4b2',\n /* Açık temadaki kardeşiyle aynı gerekçe: bandın en soluk metni de metindir. */\n 'nav-fg-3': '#818b99',\n 'nav-line': '#262c36',\n 'nav-line-strong': '#363e4a',\n 'nav-hover': alpha(NEUTRAL.n0, 0.07),\n 'footer-bg': GRAPHITE.ink,\n\n /*\n * Koyu zeminde gölge okunmaz; derinlik daha çok kenarlıkla kurulur.\n * Gölgeler yine de KORUNUR ama daha derin: modal ve açılır liste yüzeyin\n * üzerinde durmalı.\n */\n 'shadow-xs': `0 1px 2px ${alpha(BLACK, 0.4)}`,\n 'shadow-sm': `0 1px 2px ${alpha(BLACK, 0.4)}, 0 1px 3px ${alpha(BLACK, 0.3)}`,\n 'shadow-md': `0 2px 4px ${alpha(BLACK, 0.35)}, 0 6px 16px ${alpha(BLACK, 0.45)}`,\n 'shadow-lg': `0 4px 8px ${alpha(BLACK, 0.4)}, 0 16px 32px ${alpha(BLACK, 0.55)}`,\n 'shadow-xl': `0 8px 16px ${alpha(BLACK, 0.45)}, 0 28px 56px ${alpha(BLACK, 0.6)}`,\n 'shadow-up': `0 -2px 4px ${alpha(BLACK, 0.3)}, 0 -8px 24px ${alpha(BLACK, 0.45)}`,\n\n ring: `0 0 0 3px ${alpha(BLUE.dark, 0.36)}`,\n 'ring-color': BLUE.dark,\n 'ring-danger': `0 0 0 3px ${alpha(DANGER_SOLID.dark, 0.32)}`,\n 'ring-ok': `0 0 0 4px ${alpha(STATUS.okFgDark, 0.2)}`,\n\n scrim: alpha(BLACK, 0.68),\n 'scrim-soft': alpha(BLACK, 0.45),\n glass: alpha('#1f242d', 0.92),\n 'glass-solid': '#1f242d',\n 'on-scrim': NEUTRAL.n0,\n\n 'skeleton-a': '#1f242d',\n 'skeleton-b': '#262c36',\n track: alpha(NEUTRAL.n0, 0.14),\n\n 'media-bg': '#1f242d',\n\n 'glow-1': alpha(BLUE.base, 0.2),\n 'glow-2': alpha(BLUE.dark, 0.1),\n 'glow-amber': alpha(AMBER.dark, 0.12),\n};\n\n/**\n * ÖLÇÜ TOKEN'LARI — temadan bağımsız, çalışma zamanında EZİLEBİLİR.\n *\n * <h3>Neden bunlar da CSS değişkeni</h3>\n * Bir zamanlar yalnızca renkler ve font aileleri çalışma zamanında\n * eziliyordu; yarıçap, boşluk, süre ve tipografi ölçeği `_variables.scss`\n * içinde SCSS sabitiydi. Sonucu şuydu: bir tüketici markasının RENGİNİ\n * verebiliyor ama YUVARLAKLIĞINI veremiyordu. Oysa bir markayı tanınır kılan\n * şeylerin listesinde yarıçap renkten sonra gelir — keskin köşeli bir\n * kurumsal panelle yumuşak köşeli bir vitrin aynı pakete aynı derecede\n * ihtiyaç duyuyor. Aynısı bilgi yoğunluğu (boşluk ölçeği) ve hareket süresi\n * için de geçerli.\n *\n * <h3>SCSS sabiti olarak KALANLAR ve nedenleri</h3>\n * <ul>\n * <li><b>Kırılma noktaları</b> — `@media (max-width: var(--x))` GEÇERSİZ\n * CSS. Medya sorgusu özel özellik okuyamaz; taşınsalardı bütün duyarlı\n * yerleşim sessizce çökerdi.</li>\n * <li><b>Katman (`z-*`)</b> — bir yığılma bağlamı sayısı, marka kararı\n * değil. Tüketicinin ezmesi gereken bir şey değil; ezerse kip pencere\n * perdenin altında kalır.</li>\n * <li><b>Ağırlık, harf aralığı, kapsayıcı genişlikleri, sayfa dolgusu</b> —\n * ölçek değil tekil değer; ezme ihtiyacı ölçülmedi. Gerektiğinde\n * buraya taşınabilir, ters yön (geri alma) kırıcıdır.</li>\n * </ul>\n *\n * <h3>Değerler DİZE, sayı değil</h3>\n * `'4px'` yazılıyor çünkü çıktı doğrudan bir CSS bildirimi. Sayı tutulup\n * birim sonradan eklenseydi, `radius-pill` (999px) ile `leading-normal`\n * (birimsiz 1.62) aynı listede duramazdı.\n */\nexport const METRIC_TOKENS = {\n // --- Yarıçap ---\n // Küçük öğeler ile büyük yüzeyler aynı yarıçapı PAYLAŞMAZ: küçük bir öğede\n // 12px onu şişman gösterir, büyük bir kartta 6px keskin ve ucuz görünür.\n 'radius-xs': '4px',\n 'radius-sm': '6px',\n 'radius-md': '8px',\n 'radius-lg': '12px',\n 'radius-xl': '16px',\n 'radius-pill': '999px',\n\n // --- Boşluk ---\n 'space-0': '0',\n 'space-1': '4px',\n 'space-2': '8px',\n 'space-3': '12px',\n 'space-4': '16px',\n 'space-5': '24px',\n 'space-6': '32px',\n 'space-7': '48px',\n 'space-8': '64px',\n 'space-9': '96px',\n\n /*\n * --- Tipografi ölçeği ---\n *\n * ÖLÇÜLDÜ: kaynak tasarım sisteminde `font-size` bildirimlerinin %67'si\n * 14 px ve altındaydı; arayüz varsayılanı, uzun süre ekrana bakan bir\n * kullanıcıda \"okunabilir ama yorucu\" eşiğinde duruyordu. Düzeltme TOKEN\n * düzeyinde yapıldı: yüzlerce dosyaya tek tek girmek yerine ölçek\n * kaydırıldı, böylece oranlar ve ritim korundu. Üst basamaklar (19/23/29…)\n * DEĞİŞMEDİ — onlar zaten yeterince büyüktü.\n */\n 'font-size-2xs': '12px',\n 'font-size-xs': '13px',\n 'font-size-sm': '15px',\n 'font-size-base': '16px',\n 'font-size-body': '17px',\n 'font-size-lg': '19px',\n 'font-size-xl': '23px',\n 'font-size-2xl': '29px',\n 'font-size-3xl': '37px',\n 'font-size-4xl': '47px',\n\n // Satır yüksekliği: başlıkta sıkı, metinde rahat. `leading-normal` 1.55'ten\n // 1.62'ye çıktı — 16 px gövde metninde en belirgin okunurluk kazanımı burada.\n 'leading-none': '1',\n 'leading-tight': '1.16',\n 'leading-snug': '1.35',\n 'leading-normal': '1.62',\n 'leading-relaxed': '1.75',\n\n /*\n * --- İkon ölçüsü ---\n *\n * İkonlar ölçülerini `1em` ile kapsayıcının `font-size` değerinden alır ve\n * o değer METİN için seçilmiştir: 15 px'lik bir arayüz puntosunda simge,\n * 16'lık viewBox'ın ~14 px'lik çizim alanına düşüyor ve 40 px'lik bir\n * `IconButton`ın ortasında bir nokta gibi duruyordu. Ölçek Bootstrap\n * Icons'ın 16 px'lik ızgarasının katlarına yakın durur; ara değerler\n * (17, 19) simgeyi yarım piksele oturtup bulanıklaştırıyordu.\n */\n 'icon-xs': '14px',\n 'icon-sm': '16px',\n 'icon-md': '18px',\n 'icon-lg': '20px',\n 'icon-xl': '24px',\n\n // --- Hareket ---\n // 200 ms üzerindeki geçişler tıklama ile sonuç arasında görünür bir gecikme\n // yaratır ve arayüz yavaş hissedilir.\n 'duration-instant': '80ms',\n 'duration-fast': '140ms',\n 'duration-normal': '200ms',\n 'duration-slow': '320ms',\n\n 'ease-out': 'cubic-bezier(0.22, 1, 0.36, 1)',\n 'ease-in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',\n 'ease-spring': 'cubic-bezier(0.34, 1.4, 0.64, 1)',\n\n /*\n * DÖNGÜ SÜRELERİ — geçiş ölçeğinden AYRI.\n *\n * `duration-*` ölçeği bir A→B geçişini ölçüyor ve tavanı 320 ms: onun\n * üstünde tıklama ile sonuç arasında görünür bir gecikme oluşuyor. Sürekli\n * dönen bir gösterge ise bir geçiş değil; 320 ms'lik bir dönüş baş\n * döndürücü, 140 ms'lik bir parıltı da titreşim gibi okunuyor.\n *\n * <p>Ayrı isim vermenin sebebi ölçekten kaçmak değil, ölçeği KORUMAK:\n * `Spinner` `0.7s`, iskelet parıltısı `1.4s` yazıyordu ve ikisi de hiçbir\n * yerde açıklanmamış ham değerlerdi. Ham süre artık lint hatası\n * (`stylelint.config.mjs`); bu iki değerin de bir adı var.\n */\n 'duration-spin': '700ms',\n 'duration-shimmer': '1400ms',\n} as const;\n\n/**\n * YOĞUN (compact) KİP — `<html data-hanui-density=\"compact\">`.\n *\n * <h3>Gerekçe ölçülü</h3>\n * Aynı bileşenleri iki uygulama kullanıyor: vitrin bir ekranda 8 satır,\n * operasyon paneli 80 satır gösteriyor. Vitrin için doğru olan ferahlık,\n * panelde kullanıcıyı kaydırmaya mahkûm ediyor; panel için doğru olan\n * sıkılık vitrinde ucuz duruyor. İkisini tek ölçekle karşılamanın yolu yok.\n *\n * <h3>Yalnızca boşluk ve punto iner — ÖLÇEĞİN TAMAMI DEĞİL</h3>\n * `space-0` ve `space-1` sabit kalır: 4 px'in altına inen bir boşluk kademesi\n * bir boşluk değil bir çizim hatası. Yarıçap da sabit kalır — yuvarlaklık\n * yoğunluğun değil markanın işi.\n *\n * <h3>DOKUNMA HEDEFİ KÜÇÜLMEZ</h3>\n * `tap-target` görünmez bir örtü çiziyor ve ölçüsü (44 px) buraya girmiyor:\n * yoğun kip bilgi yoğunluğunu artırmak içindir, dokunulabilirliği düşürmek\n * için değil (WCAG 2.5.8). Görsel kutu küçülür, hedef küçülmez.\n */\nexport const COMPACT_DENSITY = {\n 'space-2': '6px',\n 'space-3': '8px',\n 'space-4': '12px',\n 'space-5': '16px',\n 'space-6': '24px',\n 'space-7': '32px',\n\n 'font-size-2xs': '11px',\n 'font-size-xs': '12px',\n 'font-size-sm': '13px',\n 'font-size-base': '15px',\n 'font-size-body': '16px',\n\n 'leading-normal': '1.5',\n 'leading-relaxed': '1.6',\n} as const satisfies Partial<Record<keyof typeof METRIC_TOKENS, string>>;\n\n/** Token adları — `LIGHT_THEME`den türetilir, elle listelenmez. */\nexport type HanuiToken = keyof typeof LIGHT_THEME;\n\n/** Ölçü token adları — `METRIC_TOKENS`ten türetilir. */\nexport type HanuiMetricToken = keyof typeof METRIC_TOKENS;\n\n/** Ölçü ezmeleri. Kısmî verilebilir; verilmeyen her ölçü varsayılanında kalır. */\nexport type HanuiMetrics = Partial<Record<HanuiMetricToken, string>>;\n\n/**\n * Bilgi yoğunluğu. `default` vitrin, `compact` operasyon paneli.\n *\n * <p>Seçim `<html data-hanui-density>` ile taşınır — tıpkı tema gibi, ve aynı\n * sebeple: bir ölçek kararı tek bir React ağacının değil BELGENİN kararıdır;\n * portal ile gövdeye taşınan kip pencere de aynı yoğunlukta olmalı.\n */\nexport type HanuiDensity = 'default' | 'compact';\n\n/** Bir temanın token → değer eşlemesi. Kısmî verilebilir; eksikler varsayılandan gelir. */\nexport type HanuiThemeTokens = Partial<Record<HanuiToken, string>>;\n\n/** Bir temanın TAM eşlemesi. */\nexport type HanuiResolvedTokens = Record<HanuiToken, string>;\n\n/**\n * ÇÖZÜLMÜŞ tema — ekranda gerçekten hangisi çizili.\n *\n * <p>Burada `system` YOKTUR ve olamaz: `system` bir tercih, bir tema değil.\n * Çözüldüğünde ya açık ya koyu olur ve bileşenlerin gördüğü şey o. İkisini tek\n * tipte toplamak, `scheme === 'system'` yazan bir tüketiciye hangi renklerin\n * çizildiğini hâlâ söylemiyordu.\n */\nexport type HanuiColorScheme = 'light' | 'dark';\n\n/**\n * Kullanıcının SEÇİMİ. `system` = açık bir seçim yok, işletim sistemi tercihi\n * izlenir (`prefers-color-scheme`).\n *\n * <h3>Bu tip neden sonradan eklendi</h3>\n * `HanuiColorScheme`in JSDoc'u \"`system` işletim sistemi tercihini izler\"\n * diyordu ama tipte `system` YOKTU — belge bir yeteneği anlatıyor, tip onu\n * yasaklıyordu. İki çözüm vardı: cümleyi silmek ya da yeteneği gerçekten\n * eklemek. İkincisi seçildi çünkü eksik olan gerçek bir davranıştı: üç\n * durumlu tema anahtarı (Açık / Koyu / Sistem) yaygın bir kalıp ve kütüphane\n * onu kuramıyordu — `system`e dönmenin yolu özniteliği ELLE silmekti ve bunu\n * tüketicinin bilmesi gerekiyordu.\n *\n * <p>Ekleme KIRICI DEĞİL: `scheme` hâlâ çözülmüş değeri döndürüyor, yalnızca\n * `preference` alanı ve `setScheme('system')` girişi eklendi.\n */\nexport type HanuiColorPreference = HanuiColorScheme | 'system';\n\n/**\n * Yazı tipi ailesi sözleşmesi.\n *\n * <p>Üç rol ayrı: başlık (≥19 px), arayüz metni (11–16 px) ve teknik veri\n * (kod, seri numarası, tutar). KÜÇÜK ARAYÜZ METNİ BAŞLIK FONTUNU KULLANMAZ —\n * grotesk başlık yüzleri 12–14 px yarı-kalında sıkışıp okunurluğu düşürüyor\n * ve düğme etiketleri bir arayüzün en çok okunan kısa metinleri.\n *\n * <p>Kütüphane font YÜKLEMEZ: değerler `font-family` dizesi olarak geçer ve\n * yüklemeyi (next/font, @font-face, CDN) tüketici yapar. Bir UI paketinin\n * ağdan font çekmesi, tüketicinin ölçemediği bir istek demek.\n */\nexport type HanuiFonts = Partial<{\n heading: string;\n body: string;\n mono: string;\n}>;\n\n/** Kütüphanenin varsayılan font yığınları — hepsi sistem fontlarına iner. */\nexport const DEFAULT_FONTS: Required<HanuiFonts> = {\n heading: \"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\",\n body: \"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\",\n mono: \"ui-monospace, 'SF Mono', Menlo, Consolas, monospace\",\n};\n\n/**\n * Dışarıdan verilebilecek tema yapılandırması.\n *\n * @example\n * initHanui({\n * theme: {\n * light: { blue: '#0d6efd', 'blue-text': '#0a58ca' },\n * dark: { blue: '#6ea8fe' },\n * fonts: { heading: 'Archivo, sans-serif' },\n * },\n * });\n */\nexport type HanuiThemeConfig = Partial<{\n light: HanuiThemeTokens;\n dark: HanuiThemeTokens;\n fonts: HanuiFonts;\n /**\n * Ölçü ezmeleri — yarıçap, boşluk, punto, süre.\n *\n * <p>Renk gibi tema başına DEĞİL tek blokta: bir markanın yuvarlaklığı açık\n * temada 12 px, koyu temada 8 px olmaz. Ayrı verilebilseydi iki değerin\n * ayrışması kaçınılmazdı ve fark yalnızca tema değiştirildiğinde\n * görünürdü — yani neredeyse hiç.\n *\n * @example\n * initHanui({ theme: { metrics: { 'radius-md': '2px', 'radius-lg': '4px' } } });\n */\n metrics: HanuiMetrics;\n}>;\n","import { isClient } from '@ahmetilhn/handy-utils';\n\nimport {\n DARK_THEME,\n DEFAULT_FONTS,\n LIGHT_THEME,\n type HanuiColorScheme,\n type HanuiResolvedTokens,\n type HanuiThemeConfig,\n} from '../theme/tokens';\n\n/** CSS özel özelliği öneki — `_tokens.generated.scss` ile aynı olmak zorunda. */\nexport const TOKEN_PREFIX = '--hanui-';\n\n/** Ezme kurallarını taşıyan `<style>` etiketinin kimliği. */\nexport const THEME_STYLE_ID = 'hanui-theme-overrides';\n\n/** Temanın taşındığı öznitelik. `<html data-hanui-theme=\"dark\">`. */\nexport const THEME_ATTRIBUTE = 'data-hanui-theme';\n\n/**\n * Bilgi yoğunluğunun taşındığı öznitelik.\n * `<html data-hanui-density=\"compact\">`.\n *\n * <p>Tema gibi BELGE düzeyinde: portal ile gövdeye taşınan kip pencere de aynı\n * yoğunlukta olmalı ve bir React ağacına bağlanan değer onu kapsamıyor.\n */\nexport const DENSITY_ATTRIBUTE = 'data-hanui-density';\n\n/** Geçiş animasyonlarını tek kare boyunca kapatan sınıf (bkz. `base.scss`). */\nexport const THEME_SWITCHING_CLASS = 'hanui-theme-switching';\n\n/** Verilen şemanın tam token eşlemesi — ezmeler uygulanmış hâliyle. */\nexport const resolveTokens = (\n scheme: HanuiColorScheme,\n config?: HanuiThemeConfig,\n): HanuiResolvedTokens => {\n const base = scheme === 'dark' ? DARK_THEME : LIGHT_THEME;\n const overrides = (scheme === 'dark' ? config?.dark : config?.light) ?? {};\n\n return { ...base, ...overrides };\n};\n\n/**\n * Yapılandırmayı CSS metnine çevirir.\n *\n * <h3>Neden yalnızca EZİLEN token'lar yazılıyor</h3>\n * Tam eşlemeyi yazmak da çalışırdı ama iki bedeli var: çıktı 90 satır yerine\n * 4 satır olurdu ve daha önemlisi, kütüphane bir sonraki sürümde bir token'ın\n * varsayılanını değiştirdiğinde tüketicinin sayfası ESKİ değeri yazmaya devam\n * ederdi — üstelik ezmediği bir token için. Ezmeler ne ise o yazılır.\n *\n * <h3>Neden `<style>`, neden satır içi stil değil</h3>\n * Satır içi stil yalnızca `<html>` üzerinde durur ve `[data-hanui-theme]`\n * seçicisinden daha yüksek özgüllüktedir: kullanıcı temayı değiştirdiğinde\n * ezmeler HER İKİ temada da aynı kalıyordu. Ayrı bir kural bloğu, açık ve\n * koyu ezmeleri kendi seçicilerine bağlar.\n */\nexport const buildThemeCss = (config: HanuiThemeConfig): string => {\n const blocks: string[] = [];\n\n const declarations = (tokens: Record<string, string>, indent = ' ') =>\n Object.entries(tokens)\n .map(([name, value]) => `${indent}${TOKEN_PREFIX}${name}: ${value};`)\n .join('\\n');\n\n const fonts = config.fonts ?? {};\n const fontEntries = Object.entries(fonts).filter(([, value]) => Boolean(value)) as [\n keyof typeof DEFAULT_FONTS,\n string,\n ][];\n\n if (fontEntries.length > 0)\n blocks.push(\n `:root {\\n${fontEntries\n .map(([role, stack]) => ` ${TOKEN_PREFIX}font-${role}: ${stack};`)\n .join('\\n')}\\n}`,\n );\n\n /*\n * OLCU EZMELERI TEMA BASINA DEGIL, TEK BLOKTA.\n *\n * Bir markanin yuvarlakligi acik temada 12 px, koyu temada 8 px olmaz. Ayri\n * verilebilseydi iki degerin ayrismasi kacinilmazdi ve fark yalnizca tema\n * degistirildiginde gorunurdu — yani neredeyse hic.\n *\n * `:root` YETERLI: renk ezmelerinde iki secici gerekiyordu cunku uretilmis\n * koyu blok `[data-hanui-theme='dark']` ile ozgullukte yarisiyor. Olcuye\n * karsilik gelen uretilmis blok ise `:root` (base-tokens) — esit ozgulluk,\n * kaynak sirasi kazandiriyor ve bu etiket `<head>`in SONUNA ekleniyor.\n *\n * TEK ISTISNA yogun kip: `[data-hanui-density='compact']` daha yuksek\n * ozgullukte ve ezmeyi yener. Ezme orada da gecerli olsun diye ayni govde\n * ikinci kez, o secici altinda yaziliyor — aksi halde tuketicinin verdigi\n * `space-4`, compact acilir acilmaz kutuphanenin varsayilanina donuyordu.\n */\n const metrics = config.metrics ?? {};\n\n if (Object.keys(metrics).length > 0) {\n const body = declarations(metrics as Record<string, string>);\n blocks.push(`:root {\\n${body}\\n}`);\n blocks.push(`:root[${DENSITY_ATTRIBUTE}='compact'] {\\n${body}\\n}`);\n }\n\n /*\n * Acik tema iki secicide birden yazilir: `:root` (varsayilan) ve\n * `:root[data-hanui-theme='light']` (kullanicinin acik secimi). Yalnizca\n * `:root` yazilsaydi, sistem tercihi koyu olan bir cihazda acik temayi ELLE\n * secen kullanicida ezmeler dusuyordu — cunku uretilmis koyu blok\n * `:root:not([data-hanui-theme])` degil `[data-hanui-theme='light']` ile\n * yarisiyor ve ozgullukte kazaniyor.\n */\n if (config.light && Object.keys(config.light).length > 0) {\n const body = declarations(config.light);\n blocks.push(`:root {\\n${body}\\n}`);\n blocks.push(`:root[${THEME_ATTRIBUTE}='light'] {\\n${body}\\n}`);\n }\n\n if (config.dark && Object.keys(config.dark).length > 0) {\n const body = declarations(config.dark);\n blocks.push(`:root[${THEME_ATTRIBUTE}='dark'] {\\n${body}\\n}`);\n blocks.push(\n `@media (prefers-color-scheme: dark) {\\n :root:not([${THEME_ATTRIBUTE}]) {\\n${declarations(\n config.dark,\n ' ',\n )}\\n }\\n}`,\n );\n }\n\n return blocks.join('\\n\\n');\n};\n\n/**\n * Ezmeleri belgeye yazar. Aynı `<style>` etiketi tekrar kullanılır: her\n * çağrıda yeni bir etiket eklemek, birbirini ezen onlarca blok bırakıyordu.\n *\n * <p>Etiket `<head>`in SONUNA eklenir — paket CSS'i ondan önce yüklenmiş\n * olmalı ki eşit özgüllükte ezme kazansın.\n */\nexport const applyThemeConfig = (config: HanuiThemeConfig | undefined): void => {\n if (!isClient()) return;\n\n const css = config ? buildThemeCss(config) : '';\n const existing = document.getElementById(THEME_STYLE_ID);\n\n if (css === '') {\n existing?.remove();\n return;\n }\n\n const element = existing ?? document.createElement('style');\n element.id = THEME_STYLE_ID;\n element.textContent = css;\n\n if (!existing) document.head.appendChild(element);\n};\n","'use client';\n\nimport { createContext, useContext } from 'react';\n\nimport type { HanuiLinkComponent } from '../types/link.type';\nimport type { HanuiLabels } from './labels';\nimport type { HanuiThemeConfig } from './tokens';\n\nexport type HanuiContextValue = {\n /**\n * Tüketicinin yönlendiricisi (`next/link`, `react-router`ın `Link`i…).\n *\n * <p>Verilmezse ham `<a>` çizilir ve gezinme tam sayfa yenilemesi olur.\n * Bir bileşen kütüphanesi kendi yönlendiricisini SEÇEMEZ: `next/link`\n * import etmek paketi Next'e bağlar, `react-router` import etmek başka bir\n * uygulamayı kırar. Karar tüketicinin.\n */\n linkComponent?: HanuiLinkComponent;\n /** Uygulanan tema ezmeleri. Salt okunur; değiştirmek için `HanuiProvider`. */\n theme?: HanuiThemeConfig;\n /**\n * Arayüz metinleri. Bir bileşen metnini prop olarak almadıysa buradan okur\n * (bkz. `theme/labels.ts`).\n */\n labels?: HanuiLabels;\n};\n\nconst HanuiContext = createContext<HanuiContextValue>({});\n\n/**\n * Sağlayıcı ZORUNLU DEĞİL.\n *\n * <p>Sağlayıcısız kullanımda bağlantılar ham `<a>` olur ve tema\n * varsayılanlarda kalır — yani paket `import` edilip hiçbir kurulum\n * yapılmadan çalışır. Sağlayıcıyı zorunlu kılmak, tek bir `Badge` kullanmak\n * isteyen bir tüketiciyi de kök yerleşimi değiştirmeye zorluyordu.\n */\nexport const useHanui = (): HanuiContextValue => useContext(HanuiContext);\n\nexport default HanuiContext;\n","'use client';\n\nimport { type FC, type ReactNode, useEffect, useMemo, useRef } from 'react';\n\nimport { applyThemeConfig } from '../helpers/theme.helper';\nimport type { HanuiLinkComponent } from '../types/link.type';\nimport HanuiContext from './context';\nimport type { HanuiLabels } from './labels';\nimport type { HanuiThemeConfig } from './tokens';\n\ntype Props = {\n children: ReactNode;\n /**\n * Tema ezmeleri. Yalnızca DEĞİŞTİRİLEN token'lar verilir; verilmeyen her\n * token varsayılanında kalır.\n *\n * <p>Nesne referansı her render'da yeniden üretilirse (satır içi nesne\n * literali) `<style>` etiketi de her render'da yeniden yazılır. Bileşen\n * bunu içerik karşılaştırmasıyla engeller ama yine de sabit bir referans\n * (modül düzeyinde tanımlı bir nesne) tercih edilmeli.\n */\n theme?: HanuiThemeConfig;\n /**\n * Tüketicinin bağlantı bileşeni. Verilmezse ham `<a>` çizilir.\n *\n * @example\n * import NextLink from 'next/link';\n * <HanuiProvider linkComponent={NextLink}>…</HanuiProvider>\n */\n linkComponent?: HanuiLinkComponent;\n /**\n * Arayüz metinleri — bir kez, burada.\n *\n * <p>Kütüphane hiçbir dilde metin uydurmaz ama aynı \"Kapat\" dizesini yüz\n * çağrı yerine dağıtmak da doğru değildi: biri değiştiğinde doksan dokuzu\n * eski kalıyordu. Çözümleme sırası prop → buradaki config; ikisi de yoksa\n * geliştirme kipinde konsola uyarı düşer.\n *\n * <p>Öğeye ÖZGÜ metinler buraya girmez (`Modal.title`,\n * `ConfirmDialog.confirmLabel`, `IconButton.label`); onlar prop olarak\n * zorunlu kalır çünkü her çağrı yerinde farklıdır.\n */\n labels?: HanuiLabels;\n};\n\n/**\n * Kütüphane sağlayıcısı.\n *\n * <h3>İki iş yapar, üçüncüsünü YAPMAZ</h3>\n * <ol>\n * <li>Tema ezmelerini belgeye yazar (`<style id=\"hanui-theme-overrides\">`).</li>\n * <li>Yönlendirici bileşenini bileşen ağacına dağıtır.</li>\n * <li><strong>Açık/koyu seçimini YÖNETMEZ.</strong></li>\n * </ol>\n *\n * <h3>Neden tema seçimi burada değil</h3>\n * Seçim `<html data-hanui-theme>` üzerinde taşınır ve o özniteliğin\n * <em>boyamadan önce</em> yazılması gerekir: React ağacı monte olduktan sonra\n * yazıldığında koyu tema seçmiş kullanıcı bir kare beyaz ekran görüyor. Doğru\n * yer, sunucudan gelen HTML'in `<head>`ine konan satır içi bir betik — ve\n * oraya yazmak tüketicinin çatısının işi (Next'te `app/layout.tsx`, Vite'ta\n * `index.html`). Sağlayıcı ondan sonra monte oluyor; oraya koymak sorunu\n * çözmüyor, gizliyor.\n *\n * <p>`useHanuiTheme` kancası seçimi <em>değiştirmek</em> için var; ilk değeri\n * yazmak için değil. README \"Tema\" bölümünde hazır betik duruyor.\n *\n * @example\n * <HanuiProvider linkComponent={NextLink} theme={{ light: { blue: '#0d6efd' } }}>\n * <App />\n * </HanuiProvider>\n */\nconst HanuiProvider: FC<Props> = ({ children, theme, linkComponent, labels }) => {\n /*\n * `JSON.stringify` bagimlilik anahtari olarak kullaniliyor: cagiran taraf\n * neredeyse her zaman satir ici bir nesne literali veriyor ve referans her\n * render'da degisiyor. Referansa baglansaydi `<style>` etiketi saniyede\n * onlarca kez yeniden yazilirdi.\n */\n const themeKey = useMemo(() => (theme ? JSON.stringify(theme) : ''), [theme]);\n\n useEffect(() => {\n applyThemeConfig(theme);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [themeKey]);\n\n /*\n * `theme` bir REFERANSTAN okunur, bagimliliktan degil.\n *\n * Cagiran taraf neredeyse her zaman satir ici bir nesne literali veriyor ve\n * referans her render'da degisiyor; `theme`i bagimliliga koymak memo'yu ise\n * yaramaz hale getirip tuketicideki her bileseni bos yere yeniden cizerdi.\n * Kimlik yerine ICERIK izleniyor (`themeKey`) — ve memo'nun icinde `theme`e\n * dogrudan dokunulmadigi icin denetci de dogru: eksik bir bagimlilik yok.\n */\n const themeRef = useRef(theme);\n themeRef.current = theme;\n\n const value = useMemo(\n () => ({ theme: themeRef.current, linkComponent, labels }),\n /* `themeKey` denetciye GEREKSIZ gorunuyor cunku memo'nun govdesinde\n gecmiyor — ama tam da isi bu: temanin ICERIGI degistiginde yeni bir\n nesne uretilmesini saglayan tetik o. Cikarilirsa tema ezmesi degisse\n de tuketiciler eski degeri gorurdu. */\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [themeKey, linkComponent, labels],\n );\n\n return <HanuiContext.Provider value={value}>{children}</HanuiContext.Provider>;\n};\n\nexport default HanuiProvider;\n","import { isClient } from '@ahmetilhn/handy-utils';\n\nimport { applyThemeConfig, DENSITY_ATTRIBUTE, THEME_ATTRIBUTE } from '../helpers/theme.helper';\nimport type { HanuiColorScheme, HanuiDensity, HanuiThemeConfig } from './tokens';\n\nexport type InitHanuiOptions = Partial<{\n /** Tema ve ölçü ezmeleri. Yalnızca değiştirilen token'lar verilir. */\n theme: HanuiThemeConfig;\n /**\n * Başlangıç şeması. Verilmezse `<html data-hanui-theme>` neyse o kalır;\n * o da yoksa sistem tercihi (`prefers-color-scheme`) devreye girer.\n */\n colorScheme: HanuiColorScheme;\n /**\n * Bilgi yoğunluğu. Verilmezse `<html data-hanui-density>` neyse o kalır;\n * o da yoksa `default`.\n *\n * <p>Uygulama başına SABİT bir karar olduğunda (operasyon paneli her zaman\n * `compact`) buradan verilir; kullanıcıya seçtiren bir uygulama özniteliği\n * kendisi yazar.\n */\n density: HanuiDensity;\n}>;\n\n/**\n * Kütüphaneyi <strong>React ağacının dışından</strong> yapılandırır.\n *\n * <h3>Ne zaman bu, ne zaman `HanuiProvider`</h3>\n * `HanuiProvider` React'in içinde yaşıyor ve yönlendirici bileşenini de\n * taşıyor — normal yol o. Bu fonksiyon iki durum için:\n *\n * <ul>\n * <li><strong>Boyamadan önce çalışması gereken tema.</strong> Sağlayıcı\n * ağaç monte olduktan sonra yazıyor; koyu tema seçmiş bir kullanıcı o\n * ana kadar beyaz ekran görüyor. `<head>` içindeki satır içi bir\n * betikten çağrıldığında ezmeler ilk boyamadan önce yerinde olur.</li>\n * <li><strong>React kullanmayan bir kabuk.</strong> Tasarım token'ları\n * yalnızca CSS; bir e-posta önizlemesi ya da Storybook temasında\n * bileşen ağacı olmadan da gerekiyor.</li>\n * </ul>\n *\n * <p>İkisi birlikte kullanılabilir: aynı `<style>` etiketini paylaşırlar ve\n * son çağrı kazanır.\n *\n * @example\n * // app/layout.tsx — <head> içine, boyamadan önce.\n * <script dangerouslySetInnerHTML={{ __html: `\n * document.documentElement.dataset.hanuiTheme =\n * localStorage.getItem('theme') ?? 'light';\n * ` }} />\n */\nexport const initHanui = (options: InitHanuiOptions = {}): void => {\n applyThemeConfig(options.theme);\n\n if (!isClient()) return;\n\n if (options.colorScheme)\n document.documentElement.setAttribute(THEME_ATTRIBUTE, options.colorScheme);\n\n if (options.density) document.documentElement.setAttribute(DENSITY_ATTRIBUTE, options.density);\n};\n\nexport default initHanui;\n","'use client';\n\nimport { useCallback } from 'react';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\n/** Duyurunun aciliyeti. */\nexport type AnnouncePoliteness = 'polite' | 'assertive';\n\n/**\n * EKRAN OKUYUCU DUYURU MERKEZİ.\n *\n * <h3>Sorun: görsel geri bildirimin sesli karşılığı yoktu</h3>\n * Asenkron bir sonuç ekranda görünüyor ama ekran okuyucuya HİÇ ulaşmıyordu:\n * filtre uygulanıp liste 48 ürüne düştüğünde, sepete ekleme başarılı\n * olduğunda, form gönderimi hata verdiğinde. Gören kullanıcı sonucu bir\n * bakışta alıyor; ekran okuyucu kullanıcısı odağı olmayan bir yerde değişen\n * içeriği fark etmiyor — imleci oraya götürmedikçe.\n *\n * <p>Kütüphanede yalnızca `CopyField` kendi başına duyuruyordu ve o da kendi\n * `aria-live` bölgesini kendisi çiziyordu. Aynı deseni her bileşene kopyalamak\n * sayfada onlarca canlı bölge demek — ve birden fazla canlı bölge, ekran\n * okuyucuların duyuruları BİRLEŞTİRİP sırayla okumasına ya da tamamen\n * atlamasına yol açıyor.\n *\n * <h3>Bölge sağlayıcıda DEĞİL, belgede</h3>\n * `HanuiProvider` zorunlu değil (bkz. `theme/context.ts`): tek bir `Badge`\n * kullanmak isteyen tüketici kök yerleşimini değiştirmek zorunda kalmasın.\n * Duyuru bölgesi sağlayıcıya bağlansaydı, sağlayıcısız kullanımda hiçbir şey\n * duyurulmazdı — üstelik sessizce. Bölge ilk çağrıda belgeye eklenir ve\n * uygulamanın ömrü boyunca orada kalır; DOM'a eklenen bir canlı bölgenin\n * duyurusu güvenilmez, önceden var olması gerekir.\n *\n * <h3>Neden iki ayrı bölge</h3>\n * `polite` sıradaki cümleyi bekler, `assertive` kullanıcının okuduğu şeyi\n * BÖLER. Tek bir bölgede `aria-live` değerini değiştirmek işe yaramıyor:\n * değişiklik bir sonraki duyuruda değil, o anda okunmakta olanda etkili\n * olmuyor. Hata için `assertive` (kullanıcı yanlış bir işe devam ediyor\n * olabilir), geri kalan her şey için `polite`.\n *\n * @example\n * const announce = useAnnounce();\n * announce(`${count} ürün bulundu`);\n * announce('Kart reddedildi', 'assertive');\n */\n\nconst REGION_ID = 'hanui-live-region';\n\n/** Bölgeyi bulur; yoksa oluşturur. */\nconst getRegion = (politeness: AnnouncePoliteness): HTMLElement | null => {\n if (!isClient()) return null;\n\n const id = `${REGION_ID}-${politeness}`;\n const existing = document.getElementById(id);\n if (existing) return existing;\n\n const region = document.createElement('div');\n region.id = id;\n region.setAttribute('aria-live', politeness);\n /* `aria-atomic` — bolge her degistiginde TAMAMI okunur. Kapali\n birakildiginda ekran okuyucular yalnizca DEGISEN kelimeleri okuyor ve\n \"48 urun bulundu\" ile \"12 urun bulundu\" arasinda yalnizca sayi\n duyuruluyordu. */\n region.setAttribute('aria-atomic', 'true');\n /* Gorsel olarak gizli ama DOM'da: `display: none` ya da `hidden` bolgeyi\n erisilebilirlik agacindan da cikarir ve hicbir sey duyurulmaz. */\n region.className = 'hanui-visually-hidden';\n\n document.body.appendChild(region);\n return region;\n};\n\n/**\n * AYNI metni arka arkaya duyurmak.\n *\n * <p>Bölgenin metni değişmediğinde ekran okuyucu hiçbir şey okumaz: \"Kopyalandı\"\n * ikinci kez basıldığında sessiz kalıyordu. Metin önce boşaltılıp bir kare\n * sonra yazılıyor — değişiklik böylece gerçekten bir değişiklik oluyor.\n */\nconst write = (region: HTMLElement, message: string): void => {\n region.textContent = '';\n\n window.requestAnimationFrame(() => {\n region.textContent = message;\n });\n};\n\n/**\n * Duyuru fonksiyonu döndürür. Referans SABİT: bağımlılık dizisine güvenle\n * konur, her render'da yeni bir kapanış üretip etkileri tetiklemez.\n */\nconst useAnnounce = (): ((message: string, politeness?: AnnouncePoliteness) => void) =>\n useCallback((message: string, politeness: AnnouncePoliteness = 'polite') => {\n const trimmed = message.trim();\n /* Bos duyuru bolgeyi temizler ve bir sonraki gercek duyuruyu bastirir. */\n if (trimmed === '') return;\n\n const region = getRegion(politeness);\n if (region) write(region, trimmed);\n }, []);\n\nexport default useAnnounce;\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { THEME_ATTRIBUTE, THEME_SWITCHING_CLASS } from '../helpers/theme.helper';\nimport type { HanuiColorPreference, HanuiColorScheme } from '../theme/tokens';\n\n/** Sistem tercihini okur. Betik hiç çalışmamışsa ilk değer buradan gelir. */\nconst readSystemScheme = (): HanuiColorScheme =>\n isClient() && window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n\n/**\n * `<html>` üzerindeki AÇIK seçim; öznitelik yoksa `system`.\n *\n * <p>Özniteliğin yokluğu bir eksiklik değil bir DEĞER: \"sistemi izle\".\n */\nconst readPreference = (): HanuiColorPreference => {\n if (!isClient()) return 'system';\n\n const attribute = document.documentElement.getAttribute(THEME_ATTRIBUTE);\n return attribute === 'dark' || attribute === 'light' ? attribute : 'system';\n};\n\ntype ThemeState = {\n /**\n * ÇÖZÜLMÜŞ tema — ekranda çizili olan. `preference` `system` iken bu alan\n * işletim sisteminin o anki tercihini taşır.\n */\n scheme: HanuiColorScheme;\n /**\n * Kullanıcının SEÇİMİ. Üç durumlu bir tema anahtarı (Açık / Koyu / Sistem)\n * bunu okur; `scheme` okunsaydı \"Sistem\" seçiliyken düğme \"Koyu\"yu işaretli\n * gösterirdi.\n */\n preference: HanuiColorPreference;\n /** `'system'` verildiğinde AÇIK seçim silinir ve sistem tercihi izlenir. */\n setScheme: (preference: HanuiColorPreference) => void;\n /** Açık ↔ koyu. `system` iken ÇÖZÜLMÜŞ değerin tersine geçer. */\n toggle: () => void;\n /**\n * Sunucu çıktısında ve hidrasyondan önceki ilk karede `false`.\n *\n * <p>Tema anahtarı bunu bekler: sunucu hangi temanın seçili olduğunu\n * bilmiyor ve bir tahminle çizilen anahtar, doğru tahmin edilse bile\n * hidrasyonda uyuşmazlık üretiyordu. Anahtar hazır olana kadar\n * `aria-hidden` bir yer tutucu çizilir.\n */\n isReady: boolean;\n};\n\n/**\n * Açık/koyu seçimini okur ve değiştirir.\n *\n * <h3>KALICILIK BU KANCANIN İŞİ DEĞİL</h3>\n * Seçimi nereye yazacağı tüketicinin kararı: `localStorage`, bir çerez (SSR'da\n * okunabilmesi için), kullanıcı profili. Kütüphane `localStorage`a yazsaydı\n * sunucu tarafı onu okuyamayacağı için ilk boyama yine yanlış temada\n * olurdu — ve tüketici kendi çerezini kullanmak istediğinde iki kaynak\n * çatışırdı.\n *\n * <h3>Geçiş tek karede kapatılır</h3>\n * Şema değişirken `<html>` bir kare boyunca `hanui-theme-switching` sınıfını\n * taşır. Sınıfsız hâlde her yüzey aynı anda ama FARKLI sürelerde animasyon\n * yapıyordu (kart gölgesi 140 ms, sayfa zemini 200 ms) ve geçiş dalgalı\n * görünüyordu. Ani geçiş, dalgalı geçişten iyi.\n *\n * @example\n * const { scheme, toggle, isReady } = useHanuiTheme();\n *\n * useEffect(() => {\n * if (isReady) localStorage.setItem('theme', scheme);\n * }, [scheme, isReady]);\n */\nconst useHanuiTheme = (): ThemeState => {\n /*\n * Ilk deger SABIT 'light': sunucuda `document` yok ve istemcideki gercek\n * degeri ilk render'da okumak hidrasyon uyusmazligi uretiyordu (sunucu\n * \"light\" cizdi, istemci \"dark\" okudu). Gercek deger monte olduktan sonra\n * yaziliyor ve `isReady` o ana kadar false kaliyor.\n */\n const [preference, setPreferenceState] = useState<HanuiColorPreference>('light');\n const [systemScheme, setSystemScheme] = useState<HanuiColorScheme>('light');\n const [isReady, setIsReady] = useState(false);\n\n useEffect(() => {\n setPreferenceState(readPreference());\n setSystemScheme(readSystemScheme());\n setIsReady(true);\n }, []);\n\n /*\n * Sistem tercihi HER ZAMAN izlenir, `preference` ne olursa olsun.\n *\n * Once dinleyici `preference === 'system'` iken yaziyordu ve kullanici\n * \"Koyu\"dan \"Sistem\"e dondugunde elde guncel bir sistem degeri yoktu: kanca\n * ilk montajdaki degeri hatirliyor, aradaki degisimi kacirmis oluyordu.\n * Olcum ucuz (tek bir medya sorgusu dinleyicisi); karar ise cozumleme\n * sirasinda veriliyor.\n */\n useEffect(() => {\n if (!isClient() || !window.matchMedia) return;\n\n const query = window.matchMedia('(prefers-color-scheme: dark)');\n const handleChange = () => setSystemScheme(readSystemScheme());\n\n query.addEventListener('change', handleChange);\n return () => query.removeEventListener('change', handleChange);\n }, []);\n\n const scheme: HanuiColorScheme = preference === 'system' ? systemScheme : preference;\n\n const setScheme = useCallback((next: HanuiColorPreference) => {\n if (!isClient()) return;\n\n const root = document.documentElement;\n\n root.classList.add(THEME_SWITCHING_CLASS);\n\n /* `system` bir DEGER degil, degerin YOKLUGU: oznitelik silinir ve\n `_tokens.generated.scss` icindeki `:not([data-hanui-theme])` sorgusu\n devreye girer. `data-hanui-theme=\"system\"` yazilsaydi o sorgu eslesmez\n ve sayfa acik temada kalirdi. */\n if (next === 'system') root.removeAttribute(THEME_ATTRIBUTE);\n else root.setAttribute(THEME_ATTRIBUTE, next);\n\n setPreferenceState(next);\n\n /*\n * Sinif BIR SONRAKI karede kaldirilir. Ayni karede kaldirilsaydi tarayici\n * hicbir zaman gecissiz bir boyama yapmayacak ve sinifin varligi hicbir\n * ise yaramayacakti.\n */\n window.requestAnimationFrame(() => {\n window.requestAnimationFrame(() => root.classList.remove(THEME_SWITCHING_CLASS));\n });\n }, []);\n\n const toggle = useCallback(\n () => setScheme(scheme === 'dark' ? 'light' : 'dark'),\n [scheme, setScheme],\n );\n\n return { scheme, preference, setScheme, toggle, isReady };\n};\n\nexport default useHanuiTheme;\n","/**\n * Kaydırma yardımcıları.\n *\n * <h3>Neden `scrollIntoView` doğrudan çağrılmıyor</h3>\n * jsdom `Element.prototype.scrollIntoView`u UYGULAMIYOR ve çağrı bir\n * `TypeError` atıyor. Bedeli kütüphanenin kendi testleri değil, TÜKETİCİNİN\n * testleri: `Tabs` çizen bir bileşen ölçüldüğünde `E.scrollIntoView is not a\n * function` ile düşüyordu — kırılan yer kullanıcının kodu, sebebi ise\n * kütüphanenin ekranı kaydırma girişimi. Test ortamı için tüketiciye\n * `Element.prototype.scrollIntoView = jest.fn()` yazdırmak, kütüphanenin\n * eksiğini her tüketicinin kurulum dosyasına dağıtmak olurdu.\n *\n * <p>Aynı koruma gerçek tarayıcılarda da işe yarıyor: `scrollIntoView` eski\n * WebView'larda seçenek nesnesini yok sayıyor ama VAR; burada ölçülen şey\n * fonksiyonun varlığı, davranışı değil.\n */\n\n/** Öğeyi görünür alana kaydırır; ortam desteklemiyorsa sessizce geçer. */\nexport const scrollIntoViewIfPossible = (\n element: Element | null | undefined,\n options?: ScrollIntoViewOptions,\n): void => {\n if (typeof element?.scrollIntoView === 'function') element.scrollIntoView(options);\n};\n","'use client';\n\nimport { type KeyboardEvent, type RefObject, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { scrollIntoViewIfPossible } from '../helpers/scroll.helper';\n\nexport type ListboxNavigationOptions = {\n /** Seçenek sayısı. Liste süzüldüğünde değişir. */\n count: number;\n isOpen: boolean;\n /** Açılışta etkin olacak dizin — genellikle seçili olan. */\n initialIndex?: number;\n /** `Enter` / `Space` ile seçildiğinde. */\n onSelect: (index: number) => void;\n onClose: () => void;\n};\n\nexport type ListboxNavigation<T extends HTMLElement = HTMLElement> = {\n activeIndex: number;\n setActiveIndex: (index: number) => void;\n /**\n * Etkin seçeneği görünür alanda tutmak için LİSTEYE bağlanır.\n *\n * <p>Tip parametresi çağıran taraf için: `Select` bu referansı `<ul>`e\n * veriyor ve panel açıldığında `focus()` çağırıyor. `HTMLElement`e sabitlense\n * çağıran ikinci bir referans tutmak ve ikisini elle eşlemek zorunda kalırdı.\n */\n listRef: RefObject<T | null>;\n handleKeyDown: (event: KeyboardEvent<HTMLElement>) => void;\n};\n\n/**\n * LISTBOX KLAVYE GEZİNMESİ — `Select` ve `Combobox`ın ortak modeli.\n *\n * <h3>Neden bir kanca</h3>\n * İki bileşen aynı klavye modelini <strong>kopya kod</strong> olarak\n * taşıyordu: `ArrowDown`/`ArrowUp` uçlarda dönme, `Home`/`End`, `Enter` ile\n * seçme, `Escape` ile kapatma, `Tab` ile kapatıp gezinmeye devam etme ve\n * etkin seçeneği görünür alanda tutma. Altı davranış, iki yerde. Kopya kod\n * ayrışmaya açık ve ayrışma sessiz: bir bileşende `Home` çalışıp diğerinde\n * çalışmadığında hiçbir test kırılmıyordu — ikisinin de kendi testi vardı ve\n * ikisi de kendi davranışını doğruluyordu.\n *\n * <p>Kanca yalnızca <strong>gezinmeyi</strong> taşıyor. Açılma kararı (panel\n * mi alt sayfa mı), filtreleme ve seçim sözleşmesi (`value`/`onChange`) hâlâ\n * bileşenlerin: ikisi orada gerçekten farklı ve tek bir kancaya toplamak\n * `Select`e hiç kullanmayacağı arama koduna taşıtırdı.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin seçenek; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>etkin seçeneği seçer</td></tr>\n * <tr><td>`Escape`</td><td>kapatır</td></tr>\n * <tr><td>`Tab`</td><td>kapatır, gezinme SÜRER (`preventDefault` yok)</td></tr>\n * </table>\n *\n * <p>`Space` yalnızca `hasSpaceSelect` ile: `Combobox`ın arama kutusunda boşluk\n * bir KARAKTER ve onu seçime çevirmek \"fren balatası\" yazmayı imkânsız\n * kılıyordu.\n */\nconst useListboxNavigation = <T extends HTMLElement = HTMLElement>(\n { count, isOpen, initialIndex = 0, onSelect, onClose }: ListboxNavigationOptions,\n { hasSpaceSelect = false } = {},\n): ListboxNavigation<T> => {\n const [activeIndex, setActiveIndex] = useState(initialIndex);\n const listRef = useRef<T | null>(null);\n\n /* Panel her acildiginda etkin secenek SECILI olandan baslar; kullanici\n listeyi bastan taramak zorunda kalmaz. */\n useEffect(() => {\n if (isOpen) setActiveIndex(initialIndex);\n }, [isOpen, initialIndex]);\n\n /*\n * Liste SUZULDUGUNDE etkin dizin listenin disinda kalabiliyor: uc secenek\n * gorunurken `activeIndex` 7'de kaldiginda `Enter` hicbir sey secmiyordu.\n */\n useEffect(() => {\n setActiveIndex(current => (current >= count ? Math.max(0, count - 1) : current));\n }, [count]);\n\n /* Etkin secenek gorunur alanin disina cikmamali. */\n useEffect(() => {\n if (!isOpen) return;\n scrollIntoViewIfPossible(listRef.current?.querySelector(`[data-index=\"${activeIndex}\"]`), {\n block: 'nearest',\n });\n }, [activeIndex, isOpen, count]);\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLElement>) => {\n const lastIndex = count - 1;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActiveIndex(current => (current >= lastIndex ? 0 : current + 1));\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n setActiveIndex(current => (current <= 0 ? lastIndex : current - 1));\n break;\n\n case 'Home':\n event.preventDefault();\n setActiveIndex(0);\n break;\n\n case 'End':\n event.preventDefault();\n setActiveIndex(lastIndex);\n break;\n\n case ' ':\n case 'Enter': {\n /* Arama kutusunda BOSLUK bir KARAKTER: onu secime cevirmek \"fren\n balatasi\" yazmayi imkansiz kiliyordu. `Enter` her iki kipte de\n secer. */\n if (event.key === ' ' && !hasSpaceSelect) break;\n\n event.preventDefault();\n if (count > 0) onSelect(activeIndex);\n break;\n }\n\n case 'Escape':\n event.preventDefault();\n onClose();\n break;\n\n case 'Tab':\n /* Kapatir ama varsayilan gezinme SURER. */\n onClose();\n break;\n\n default:\n break;\n }\n },\n [activeIndex, count, hasSpaceSelect, onClose, onSelect],\n );\n\n return { activeIndex, setActiveIndex, listRef, handleKeyDown };\n};\n\nexport default useListboxNavigation;\n","'use client';\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\n/** Yüzeyin tercih ettiği kenar. Yer yoksa karşıtına düşer. */\nexport type PositionSide = 'top' | 'bottom' | 'left' | 'right';\n\n/** Tercih edilen kenar boyunca hizalama. */\nexport type PositionAlign = 'start' | 'center' | 'end';\n\nexport type PositioningOptions = {\n side?: PositionSide;\n align?: PositionAlign;\n /** Tetikleyici ile yüzey arasındaki boşluk (px). */\n offset?: number;\n /** Görünüm alanının kenarından bırakılacak asgari pay (px). */\n padding?: number;\n /** Kapalıyken ölçüm yapılmaz ve dinleyici kurulmaz. */\n isOpen: boolean;\n};\n\nexport type PositioningState = {\n /** Yüzeye uygulanacak stil — `position: fixed` + hesaplanmış koordinat. */\n style: { position: 'fixed'; top: number; left: number };\n /** ÇÖZÜLMÜŞ kenar: çarpışma yüzünden tercih edilenin karşıtı olabilir. */\n side: PositionSide;\n /** İlk ölçüm yapıldı mı. Yapılmadan çizilen yüzey sol üst köşede parlıyor. */\n isPositioned: boolean;\n};\n\nconst OPPOSITE: Record<PositionSide, PositionSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\n/** Bir sayıyı [min, max] aralığına kırpar. */\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\ntype Rect = { top: number; left: number; width: number; height: number };\n\n/** Verilen kenarda yüzeyin sol-üst köşesi nereye düşer. */\nconst place = (\n anchor: Rect,\n surface: { width: number; height: number },\n side: PositionSide,\n align: PositionAlign,\n offset: number,\n): { top: number; left: number } => {\n const isVertical = side === 'top' || side === 'bottom';\n\n /* Ana eksen: tetikleyicinin disinda, `offset` kadar uzakta. */\n const main = {\n top: anchor.top - surface.height - offset,\n bottom: anchor.top + anchor.height + offset,\n left: anchor.left - surface.width - offset,\n right: anchor.left + anchor.width + offset,\n }[side];\n\n /* Capraz eksen: hizalama. */\n const crossStart = isVertical ? anchor.left : anchor.top;\n const crossSize = isVertical ? anchor.width : anchor.height;\n const surfaceSize = isVertical ? surface.width : surface.height;\n\n const cross = {\n start: crossStart,\n center: crossStart + crossSize / 2 - surfaceSize / 2,\n end: crossStart + crossSize - surfaceSize,\n }[align];\n\n return isVertical ? { top: main, left: cross } : { top: cross, left: main };\n};\n\n/** Yüzey görünüm alanına sığıyor mu (yalnızca ana eksende). */\nconst fits = (\n position: { top: number; left: number },\n surface: { width: number; height: number },\n side: PositionSide,\n padding: number,\n viewport: { width: number; height: number },\n): boolean =>\n ({\n top: position.top >= padding,\n bottom: position.top + surface.height <= viewport.height - padding,\n left: position.left >= padding,\n right: position.left + surface.width <= viewport.width - padding,\n })[side];\n\n/**\n * ÇARPIŞMAYA DUYARLI KONUMLANDIRMA — `Tooltip`, `Popover`, `Menu` ve açılır\n * listelerin ortak temeli.\n *\n * <h3>Neden var: `position: absolute` yetmiyordu</h3>\n * `Tooltip` balonu tetikleyicinin içinde, `position: absolute` ile duruyordu.\n * Üç somut sonucu vardı:\n *\n * <ul>\n * <li><b>Kırpılma.</b> `overflow: hidden` taşıyan her kapsayıcı (kart,\n * tablo kaydırma kutusu, `Panel`) balonu kesiyordu. Bir tablo hücresinde\n * ipucu görünmüyordu — hiç.</li>\n * <li><b>Taşma.</b> Ekranın sağ kenarındaki bir tetikleyicinin balonu\n * görünüm alanının dışına çıkıyor, yatay kaydırma açıyordu.</li>\n * <li><b>Yığılma bağlamı.</b> `transform` taşıyan bir ata (`Card` hover\n * animasyonu) yeni bir yığılma bağlamı açıyor ve `z-index` orada\n * hapsoluyordu; balon kendi kartının altında kalıyordu.</li>\n * </ul>\n *\n * <p>Çözüm portal + `position: fixed`: yüzey gövdeye taşınır, koordinat\n * görünüm alanına göre hesaplanır. Kırpılacak bir kapsayıcı ve yarışılacak bir\n * yığılma bağlamı kalmaz.\n *\n * <h3>Neden yeni bir bağımlılık YOK</h3>\n * `floating-ui` bu işi yapıyor ve iyi yapıyor; ama paketin tek çalışma zamanı\n * bağımlılığının ikon seti olması bilinçli bir karar (bkz. README). Burada\n * ihtiyaç duyulan şey o kütüphanenin küçük bir alt kümesi: bir kenar, bir\n * hizalama ve karşıt kenara düşme. Ok konumlandırma, otomatik yerleşim\n * (`autoPlacement`), sanal öğe ve middleware zinciri gerekmiyor — ve\n * gerektiğinde eklenecek yer burası.\n *\n * <h3>CSS Anchor Positioning neden kullanılmıyor</h3>\n * Denendi ve BUGÜN kullanılamıyor: `anchor-name` / `position-anchor` yalnızca\n * Chromium'da var (Safari ve Firefox'ta bayrak arkasında bile değil). İki\n * kod yolu tutmak — biri modern tarayıcıda, biri yedekte — konumlandırmayı iki\n * kez yazmak ve ikisinin ayrışmasını beklemek demek. Ölçüm tabanlı yol her\n * yerde çalışıyor; tarayıcı desteği geldiğinde geçiş TEK dosyada.\n *\n * <h3>Ölçüm ne zaman yenileniyor</h3>\n * Açılışta, pencere yeniden boyutlandığında ve <em>herhangi bir atanın</em>\n * kaydırılmasında. Sonuncusu için `capture: true` ile belge düzeyinde tek bir\n * dinleyici: kaydırma olayı baloncuklanmıyor ve her ata için ayrı dinleyici\n * kurmak, derin bir ağaçta onlarca dinleyici demekti.\n */\nconst usePositioning = (\n anchorRef: { current: HTMLElement | null },\n surfaceRef: { current: HTMLElement | null },\n { side = 'top', align = 'center', offset = 8, padding = 8, isOpen }: PositioningOptions,\n): PositioningState => {\n const [state, setState] = useState<PositioningState>({\n style: { position: 'fixed', top: 0, left: 0 },\n side,\n isPositioned: false,\n });\n\n /* Olcum her karede yeniden planlanmasin: kaydirma sirasinda saniyede\n onlarca olay dusuyor ve her biri bir yerlesim okumasi. */\n const frameRef = useRef(0);\n\n const measure = useCallback(() => {\n const anchor = anchorRef.current;\n const surface = surfaceRef.current;\n if (!anchor || !surface) return;\n\n const anchorRect = anchor.getBoundingClientRect();\n const surfaceRect = surface.getBoundingClientRect();\n const viewport = { width: window.innerWidth, height: window.innerHeight };\n\n /*\n * KENAR SECIMI: tercih edilen kenar sigmiyorsa KARSITI denenir; o da\n * sigmiyorsa tercih edilene donulur ve kirpma devreye girer. Ucuncu bir\n * kenara (dikeyden yataya) atlamak YOK — bir ipucu bir anda saga zipladiginda\n * kullanici onu tetikleyiciyle iliskilendiremiyor.\n */\n const preferred = place(anchorRect, surfaceRect, side, align, offset);\n const resolvedSide = fits(preferred, surfaceRect, side, padding, viewport)\n ? side\n : fits(\n place(anchorRect, surfaceRect, OPPOSITE[side], align, offset),\n surfaceRect,\n OPPOSITE[side],\n padding,\n viewport,\n )\n ? OPPOSITE[side]\n : side;\n\n const placed = place(anchorRect, surfaceRect, resolvedSide, align, offset);\n\n /* Capraz eksende KIRPMA: ekranin sag ucundaki bir tetikleyicinin balonu\n disari tasmak yerine kenara yaslanir. */\n setState({\n style: {\n position: 'fixed',\n top: Math.round(clamp(placed.top, padding, viewport.height - surfaceRect.height - padding)),\n left: Math.round(clamp(placed.left, padding, viewport.width - surfaceRect.width - padding)),\n },\n side: resolvedSide,\n isPositioned: true,\n });\n }, [anchorRef, surfaceRef, side, align, offset, padding]);\n\n const schedule = useCallback(() => {\n if (frameRef.current) return;\n frameRef.current = window.requestAnimationFrame(() => {\n frameRef.current = 0;\n measure();\n });\n }, [measure]);\n\n /*\n * `useLayoutEffect`: olcum BOYAMADAN once yapilmali. `useEffect` ile\n * yuzey bir kare boyunca (0, 0) noktasinda — ekranin sol ust kosesinde —\n * cizilip sonra yerine ziplyordu.\n */\n const useIsomorphicLayoutEffect = isClient() ? useLayoutEffect : useEffect;\n\n useIsomorphicLayoutEffect(() => {\n if (!isOpen) {\n setState(current => (current.isPositioned ? { ...current, isPositioned: false } : current));\n return;\n }\n\n measure();\n\n window.addEventListener('resize', schedule);\n /* `capture: true` — kaydirma olayi BALONCUKLANMAZ; yakalama evresinde\n dinlemek, tetikleyicinin kaydirilan HER atasini tek dinleyiciyle\n kapsar. */\n document.addEventListener('scroll', schedule, true);\n\n /* Yuzeyin kendi olcusu degisebiliyor (icerik geldi, liste suzuldu) ve\n degistiginde konum yanlis kalir. */\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);\n if (observer && surfaceRef.current) observer.observe(surfaceRef.current);\n if (observer && anchorRef.current) observer.observe(anchorRef.current);\n\n return () => {\n window.removeEventListener('resize', schedule);\n document.removeEventListener('scroll', schedule, true);\n observer?.disconnect();\n\n if (frameRef.current) {\n window.cancelAnimationFrame(frameRef.current);\n frameRef.current = 0;\n }\n };\n }, [isOpen, measure, schedule, anchorRef, surfaceRef]);\n\n return state;\n};\n\nexport default usePositioning;\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type VirtualRange = {\n /** Çizilecek ilk öğenin dizini. */\n start: number;\n /** Çizilecek son öğenin dizini (dahil DEĞİL). */\n end: number;\n /** Listenin gerçek toplam yüksekliği — kaydırma çubuğu doğru boyda olmalı. */\n totalHeight: number;\n /** Görünen ilk öğenin üstünde bırakılacak boşluk. */\n offset: number;\n};\n\n/**\n * SANALLAŞTIRMA — yalnızca görünen satırları çiz.\n *\n * <h3>Ölçülen sorun</h3>\n * 1121 markalı bir `Combobox` listesinde DOM 1121 satır taşıyordu. Panel\n * açılışı mobilde gözle görülür şekilde donuyor, her tuş vuruşunda liste\n * yeniden çiziliyordu. Ekran okuyucu tarafında da bedeli var: 1121 öğelik bir\n * `listbox`ta gezinmek pratikte imkânsız.\n *\n * <h3>Neden kütüphane içinde</h3>\n * `react-window` / `@tanstack/virtual` bu işi yapıyor ve iyi yapıyor; ama\n * paketin tek çalışma zamanı bağımlılığının ikon seti olması bilinçli bir\n * karar. Burada gereken şey o kütüphanelerin küçük bir alt kümesi: SABİT\n * yükseklikli satırlar, tek eksen, yatay yok, değişken yükseklik yok.\n *\n * <h3>SABİT satır yüksekliği — ve bu bir kısıt</h3>\n * Değişken yükseklikli sanallaştırma her satırın ölçülmesini ve bir konum\n * haritası tutulmasını gerektiriyor. Açılır liste satırları zaten sabit\n * yükseklikte (`min-height` + tek satır metin); ikincil satır taşıyan\n * seçeneklerde ölçü `rowHeight` ile verilir.\n *\n * <h3>`overscan` neden var</h3>\n * Yalnızca görünen satırlar çizilseydi hızlı kaydırmada alt kenarda bir kare\n * boyunca boşluk görünüyordu — tarayıcı kaydırma olayını boyamadan sonra\n * veriyor. Görünür alanın üstüne ve altına birkaç satır fazladan çizilir.\n *\n * <h3>Klavye gezinmesiyle ilişkisi</h3>\n * Etkin seçeneği görünür tutan `scrollIntoView`, o seçenek ÇİZİLMEMİŞSE\n * çalışmaz. `scrollToIndex` bu yüzden var: klavyeyle listenin dibine giden\n * kullanıcı için konum önce hesaplanır, satır sonra çizilir.\n */\nconst useVirtualList = (\n count: number,\n { rowHeight = 40, overscan = 6, isEnabled = true } = {},\n) => {\n const scrollRef = useRef<HTMLElement | null>(null);\n const [range, setRange] = useState<VirtualRange>({\n start: 0,\n end: count,\n totalHeight: count * rowHeight,\n offset: 0,\n });\n\n const measure = useCallback(() => {\n const node = scrollRef.current;\n\n /*\n * KAPALIYKEN VE OLCUM YOKKEN TAM LISTE.\n *\n * Kutu daha olculmemisken (ilk kare, `display: none`) `clientHeight` 0\n * doner ve sifir satir cizilirdi: liste bir kare boyunca BOS gorunuyor,\n * ekran okuyucu da o karede \"0 secenek\" diyordu.\n */\n if (!isEnabled || !node || node.clientHeight === 0) {\n setRange({ start: 0, end: count, totalHeight: count * rowHeight, offset: 0 });\n return;\n }\n\n const visibleCount = Math.ceil(node.clientHeight / rowHeight);\n const first = Math.floor(node.scrollTop / rowHeight);\n\n const start = Math.max(0, first - overscan);\n const end = Math.min(count, first + visibleCount + overscan);\n\n setRange({ start, end, totalHeight: count * rowHeight, offset: start * rowHeight });\n }, [count, isEnabled, overscan, rowHeight]);\n\n useEffect(() => {\n const node = scrollRef.current;\n if (!node) return;\n\n measure();\n node.addEventListener('scroll', measure, { passive: true });\n\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure);\n observer?.observe(node);\n\n return () => {\n node.removeEventListener('scroll', measure);\n observer?.disconnect();\n };\n }, [measure]);\n\n /**\n * Verilen dizini görünür alana getirir.\n *\n * <p>`scrollIntoView` çizilmemiş bir satırda çalışmıyor; klavyeyle listenin\n * dibine giden kullanıcı için konum önce hesaplanmak zorunda.\n */\n const scrollToIndex = useCallback(\n (index: number) => {\n const node = scrollRef.current;\n if (!node || !isEnabled) return;\n\n const top = index * rowHeight;\n const bottom = top + rowHeight;\n\n if (top < node.scrollTop) node.scrollTop = top;\n else if (bottom > node.scrollTop + node.clientHeight)\n node.scrollTop = bottom - node.clientHeight;\n },\n [isEnabled, rowHeight],\n );\n\n return { scrollRef, range, scrollToIndex, measure };\n};\n\nexport default useVirtualList;\n","'use client';\n\nimport { useEffect } from 'react';\n\n/**\n * SAYFA KAYDIRMA KİLİDİ — sayaçlı, tek yerde.\n *\n * <h3>Neden bir kanca, neden bileşenin içinde iki satır değil</h3>\n * `Modal` ve `BottomSheet` kilidi kendi başlarına yazıyordu:\n *\n * <pre>\n * const previous = document.body.style.overflow;\n * document.body.style.overflow = 'hidden';\n * return () => { document.body.style.overflow = previous; };\n * </pre>\n *\n * <p>Tek pencerede doğru; İÇ İÇE iki pencerede değil. `Select` bir kip\n * pencerenin içinde açıldığında (`Modal` → `BottomSheet`) sıra şu:\n * dış pencere `''` kaydeder ve `hidden` yazar; iç panel `'hidden'` kaydeder ve\n * `hidden` yazar; iç panel kapanınca kaydettiği `'hidden'`i geri yazar — buraya\n * kadar tesadüfen doğru. Ama React sökme sırası her zaman bu değil: iki panel\n * aynı commit'te kapandığında DIŞ pencerenin temizliği önce koşabiliyor ve\n * `''` yazıyor; iç panel hâlâ açıkken kilit AÇILIYOR ve kullanıcı panelin\n * arkasındaki listeyi kaydırıyordu.\n *\n * <p>Sayaç bunu yapısal olarak imkânsız kılıyor: kilit ilk açılışta yazılır,\n * SON kapanışta kaldırılır, arada kim ne yaparsa yapsın.\n *\n * <h3>Kaydırma çubuğu ve yatay sıçrama</h3>\n * `overflow: hidden` kaydırma çubuğunu da götürüyor ve sayfa o çubuğun\n * genişliği kadar (macOS dışında ~15 px) YATAY OLARAK SIÇRIYOR: pencere\n * açılınca arkadaki bütün içerik sağa kayıyor, kapanınca geri geliyordu.\n * `scrollbar-gutter: stable` çubuğun yerini kalıcı olarak ayırıyor —\n * desteklemeyen tarayıcıda ölçülen genişlik dolgu olarak yazılıyor.\n *\n * <h3>iOS</h3>\n * Safari'de `overflow: hidden` gövdeyi durdurmaya YETMİYOR: dokunmatik\n * kaydırma arkadaki belgeye sızıyor (\"scroll chaining\"). Gövde\n * `position: fixed` ile sabitlenir ve kaydırma konumu `top` ile korunur;\n * kilit kalkarken tam olarak aynı yere geri dönülür — korunmasaydı pencere\n * kapandığında kullanıcı sayfanın başına düşerdi.\n *\n * @param isLocked Kilit bu örnek için etkin mi.\n */\n\n/* Kac tane acik panel var. Modul duzeyinde: kilit BELGENIN durumu, bir React\n agacinin degil. */\nlet lockCount = 0;\n\n/** Kilit yazılmadan önceki hâl — SON kapanışta buradan geri yüklenir. */\nlet previous: {\n overflow: string;\n position: string;\n top: string;\n width: string;\n paddingRight: string;\n scrollY: number;\n} | null = null;\n\n/** iOS Safari mi? Gövdeyi sabitleme bedeli yalnızca orada ödenir. */\nconst isIOS = (): boolean =>\n /iP(hone|ad|od)/.test(navigator.platform) ||\n (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);\n\nconst lock = (): void => {\n lockCount += 1;\n if (lockCount > 1) return;\n\n const { body, style: rootStyle } = { body: document.body, style: document.documentElement.style };\n const scrollY = window.scrollY;\n\n previous = {\n overflow: body.style.overflow,\n position: body.style.position,\n top: body.style.top,\n width: body.style.width,\n paddingRight: body.style.paddingRight,\n scrollY,\n };\n\n /*\n * Cubugun genisligi: `scrollbar-gutter` desteklenmiyorsa dolgu olarak\n * yazilir. Destekleniyorsa olcum 0 cikar ve dolgu yazilmaz.\n */\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n if (scrollbarWidth > 0) body.style.paddingRight = `${scrollbarWidth}px`;\n\n rootStyle.setProperty('scrollbar-gutter', 'stable');\n body.style.overflow = 'hidden';\n\n if (isIOS()) {\n body.style.position = 'fixed';\n body.style.top = `${-scrollY}px`;\n body.style.width = '100%';\n }\n};\n\nconst unlock = (): void => {\n lockCount = Math.max(0, lockCount - 1);\n if (lockCount > 0 || !previous) return;\n\n const { body } = document;\n const { scrollY } = previous;\n\n body.style.overflow = previous.overflow;\n body.style.position = previous.position;\n body.style.top = previous.top;\n body.style.width = previous.width;\n body.style.paddingRight = previous.paddingRight;\n document.documentElement.style.removeProperty('scrollbar-gutter');\n\n previous = null;\n\n /* Govde sabitlenmisken kaydirma konumu sifirlaniyor; geri yazilmazsa\n kullanici pencereyi kapattiginda sayfanin en basina duser. */\n window.scrollTo(0, scrollY);\n};\n\nconst useScrollLock = (isLocked = true): void => {\n useEffect(() => {\n if (!isLocked) return;\n\n lock();\n return unlock;\n }, [isLocked]);\n};\n\nexport default useScrollLock;\n","'use client';\n\nimport { useEffect } from 'react';\n\n/** Panelin kaplayabilecegi en fazla yukseklik — GORUNEN alanin yuksekligi. */\nconst HEIGHT_VAR = '--hanui-sheet-height';\n\n/** Panelin dibinin, yerlesim gorunum alaninin dibinden ne kadar yukarida duracagi. */\nconst INSET_VAR = '--hanui-sheet-inset-bottom';\n\n/*\n * Tek olcum, tek dinleyici.\n *\n * Ayni anda birden fazla alt sayfa acilabiliyor (filtre panelinin icindeki bir\n * secim kutusu gibi). Her biri kendi dinleyicisini kursaydi ayni karede ayni\n * degeri birkac kez yazacak, ustelik ustteki panel kapandiginda alttaki hala\n * acikken degiskenler silinecekti. Sayac sifirlanmadan hicbir sey kaldirilmaz.\n */\nlet openCount = 0;\nlet frame = 0;\n\n/**\n * Gorsel gorunum alanini olcup CSS degiskenlerine yazar.\n *\n * `window.innerHeight` YERLESIM gorunum alanidir: iOS'ta adres cubugu\n * daralmis kabul edilerek hesaplanir ve klavye onu hic kucultmez.\n * `visualViewport` ise gercekten GORUNEN alandir. Ikisinin farki, ekranin\n * dibinde kullanicinin goremedigi seridin yuksekligi: klavye, tarayicinin alt\n * cubugu ya da adres cubugu genisken asagi tasan bolum.\n *\n * `position: fixed; bottom: 0` yerlesim gorunum alanina gore hizalanir — yani\n * o seridin ALTINA. Panel bu yuzden dibinden kirpik goruluyordu; kisa bir\n * panel (alti secenekli bir liste) neredeyse yarisini kaybederken ekranin\n * cogunu kaplayan bir panel ayni kaymayi gorunur kilmiyordu.\n */\n/**\n * MAKUL EN KÜÇÜK GÖRÜNÜM ALANI.\n *\n * <p>Bunun altındaki bir ölçüm bir görünüm alanı değil, GEÇİCİ BİR HÂL:\n * klavye açılırken/kapanırken, sayfa arka plana alınıp geri gelirken ve\n * `<dialog>` üst katmana girerken `visualViewport.height` bir kare boyunca\n * absürt küçük değerler raporluyor.\n *\n * <p>ÖLÇÜLDÜ (`e2e` sondası): değişkene 120 px yazıldığında panelin tamamı\n * 96 px'e iniyor — 57 px başlık + <strong>39 px gövde</strong>, yani listenin\n * yarım satırı görünen bir kaydırma yarığı. Bu, gerçek cihazda bildirilen\n * hatanın birebir görüntüsü.\n */\nconst MIN_VIEWPORT_HEIGHT = 240;\n\nconst measure = () => {\n const viewport = window.visualViewport;\n if (!viewport) return;\n\n /*\n * ABSURT OLCUM YAZILMAZ.\n *\n * Once her deger kosulsuz yaziliyordu ve tek bir gecici kare paneli\n * kullanilamaz hale getirmeye yetiyordu. Daha kotusu KALICIYDI: yanlis\n * deger ancak bir sonraki `resize` ile duzeliyor, o olay gelmezse panel\n * kapanana kadar oyle kaliyordu.\n *\n * Olcum atlandiginda ONCEKI dogru deger yerinde kalir; hicbir olcum\n * yapilmadiysa CSS yedegi (`100dvh`) devrede.\n */\n if (viewport.height < MIN_VIEWPORT_HEIGHT) return;\n\n const covered = window.innerHeight - viewport.height - viewport.offsetTop;\n const root = document.documentElement;\n\n root.style.setProperty(INSET_VAR, `${Math.max(0, Math.round(covered))}px`);\n root.style.setProperty(HEIGHT_VAR, `${Math.round(viewport.height)}px`);\n};\n\n/**\n * Kare başına bir ölçüm: klavye açılırken `resize` ve `scroll` ard arda\n * düşüyor ve her ölçüm bir yerleşim okuması.\n *\n * <h3>Kare bayrağı NEDEN sıfırlanabilir olmak zorunda</h3>\n * Bayrak yalnızca `requestAnimationFrame` geri çağrısında sıfırlanıyordu.\n * O geri çağrı ÇALIŞMAYABİLİR: tarayıcı sekme arka plandayken kareleri\n * durduruyor, iOS bunu üst katman geçişlerinde de yapıyor. Kare hiç\n * gelmediğinde bayrak sonsuza kadar dolu kalıyor ve <strong>sonraki her\n * ölçüm sessizce atlanıyordu</strong> — panel, o an ne ölçüldüyse orada\n * donuyordu. Panel açılırken bayrak elle sıfırlanıyor (bkz. kancanın\n * gövdesi).\n */\nconst schedule = () => {\n if (frame) return;\n frame = window.requestAnimationFrame(() => {\n frame = 0;\n measure();\n });\n};\n\n/** Bekleyen kareyi iptal eder ve bayrağı serbest bırakır. */\nconst cancelScheduled = () => {\n if (!frame) return;\n window.cancelAnimationFrame(frame);\n frame = 0;\n};\n\n/**\n * Alt sayfayi <strong>gorunen</strong> alana yaslar.\n *\n * <h3>Neden `dvh` ve `env()` yetmiyor</h3>\n * `dvh` tarayici cubuklarini hesaba katar ama <em>klavyeyi katmaz</em>;\n * `env(safe-area-inset-bottom)` ise cihazin centik/ana ekran cubugu payidir, o\n * da klavyeden habersiz. iOS'ta klavye acildiginda yerlesim gorunum alani hic\n * degismez: panel oldugu yerde durur, klavye uzerine biner ve alt yarisi —\n * arama kutusuyla birlikte — erisilemez hale gelir.\n *\n * <h3>Android'de ne oluyor</h3>\n * Tuketici `interactiveWidget: 'resizes-content'` verdiginde orada klavye\n * yerlesim alanini da kuculttugu icin fark sifir cikar ve bu kanca hicbir sey\n * degistirmez. Duzeltme iOS icindir, ama olcum platformdan bagimsiz dogru.\n *\n * <h3>Degiskenler `<html>` uzerinde</h3>\n * Panelin kendisine yazilamaz: `::backdrop` ve `<dialog>` ust katmandadir,\n * ayrica ayni degeri iki farkli panel paylasiyor. Kok ogeye yazmak tek kaynak\n * birakir.\n *\n * @param isActive Panel acik mi. Yalnizca acikken olculur: kendisi yalnizca\n * acikken cizilen bir panel varsayilani kullanir, ama sayfa boyunca DOM'da\n * duran bir panel bayraksiz cagirdiginda her kullanicida iki gorunum alani\n * dinleyicisi bos yere acik kaliyordu.\n */\nconst useSheetViewport = (isActive = true) => {\n useEffect(() => {\n if (!isActive) return;\n\n const viewport = window.visualViewport;\n if (!viewport) return;\n\n openCount += 1;\n\n if (openCount === 1) {\n viewport.addEventListener('resize', schedule);\n viewport.addEventListener('scroll', schedule);\n window.addEventListener('orientationchange', schedule);\n }\n\n /*\n * Bekleyen kare IPTAL edilir ve olcum SENKRON yapilir.\n *\n * Onceki panelden kalmis, hicbir zaman calismamis bir kare bayragi\n * sonraki her olcumu susturuyordu (bkz. `schedule`). Panel her acildiginda\n * bayrak serbest birakiliyor ve deger o anda yeniden okunuyor: acilan\n * panel HER ZAMAN taze bir olcumle basliyor.\n */\n cancelScheduled();\n measure();\n\n return () => {\n openCount -= 1;\n if (openCount > 0) return;\n\n viewport.removeEventListener('resize', schedule);\n viewport.removeEventListener('scroll', schedule);\n window.removeEventListener('orientationchange', schedule);\n\n cancelScheduled();\n\n /* Degiskenler SILINIR, sifirlanmaz: yedek deger CSS'te\n (`var(…, 0px)` / `var(…, 100dvh)`) ve panel kapaliyken dogru olan o. */\n document.documentElement.style.removeProperty(INSET_VAR);\n document.documentElement.style.removeProperty(HEIGHT_VAR);\n };\n }, [isActive]);\n};\n\nexport default useSheetViewport;\n","/**\n * Düğme ve eylem varyantları.\n *\n * <p>Sıra bir <strong>vurgu hiyerarşisi</strong>dir: bir ekranda tek bir\n * `PRIMARY` bulunur. İki dolu düğme yan yana durduğunda hiçbiri öne çıkmaz ve\n * kullanıcı hangisinin beklenen eylem olduğunu bilemez.\n *\n * <h3>Doygun dolgu = tıklanabilir</h3>\n * Bu kuralın karşılığı: durum etiketleri (rozet, uyarı) her zaman tint\n * zeminlidir, eylemler her zaman dolgulu veya çerçevelidir. İkisi karışırsa\n * kullanıcı bir durum etiketine tıklamayı dener.\n */\nenum UIVariant {\n /**\n * Ekranın tek beklenen eylemi: <strong>nötr grafit</strong> dolgu.\n *\n * <p>`CART` DEĞİL. Doygun turuncu tek bir dönüşüm noktasına ayrıldı; her\n * dolu düğmeyi o renge boyamak tekilliği yok eder ve kullanıcı hangi\n * turuncunun dönüşüm olduğunu bilemez.\n */\n PRIMARY = 'PRIMARY',\n /**\n * <strong>Dönüşüm eylemi — ve yalnızca o.</strong>\n *\n * <p>Ekranda görünen tek doygun turuncu. Favori, karşılaştır, paylaş,\n * filtrele hepsi nötr veya mavidir. Bir kampanya bandında bu ton\n * kullanılırsa o ekranda dönüşüm düğmesi `PRIMARY`'ye çevrilir — ikisi aynı\n * anda olmaz.\n *\n * <p>Adı domain'den geliyor (kaynak sistemde \"sepete ekle\") ve\n * kasıtlı korundu: bir ekranda kaç tane olabileceğini adın kendisi\n * söylüyor. `ACCENT` deseydi hiyerarşi bilgisi kaybolurdu.\n */\n CART = 'CART',\n /** Nötr ikincil eylem: gri kenarlık, koyu metin (\"Vazgeç\"). */\n SECONDARY = 'SECONDARY',\n /**\n * Mavi çerçeveli eylem — teşvik edilen ama birincil olmayan gezinme\n * (\"Tümünü gör\").\n *\n * <p>Çerçeveli, dolgulu değil: mavi gezinme ve keşif rengidir; dolu mavi\n * düğme onu bir dönüşüm noktası gibi gösterip `CART` ile yarışıyordu.\n */\n OUTLINE = 'OUTLINE',\n /** Vurgu bandı içindeki eylem: bandın kendi yüzey merdivenini kullanır. */\n DARK = 'DARK',\n /** Nötr yüzey dolgusu; kart içi ikincil eylem. */\n LIGHT = 'LIGHT',\n /** Zeminsiz eylem: araç çubuğu ve satır içi ikincil işler. */\n GHOST = 'GHOST',\n /** Yıkıcı eylem: silme onayı. Durum tinti değil, gerçek bir dolgu. */\n DANGER = 'DANGER',\n}\n\nexport default UIVariant;\n","/**\n * Ölçü basamakları.\n *\n * <p>`MEDIUM` ve `LARGE` dokunma hedefi kuralına uyar (WCAG 2.5.8, ≥44 px).\n * `SMALL` yoğun şeritler içindir ve orada görsel kutu küçülür ama tıklanabilir\n * alan `tap-target` ile korunur.\n */\nenum UISize {\n SMALL = 'SMALL',\n MEDIUM = 'MEDIUM',\n LARGE = 'LARGE',\n}\n\nexport default UISize;\n","/**\n * Kırılma noktaları — `styles/_variables.scss` içindeki `$breakpoint-*` ile\n * <strong>aynı</strong> değerler.\n *\n * <p>Kararı normalde CSS verir; bu sabitler yalnızca <em>JavaScript'in de\n * bilmek zorunda olduğu</em> tek durum için var: kipsel bir panel\n * (`<dialog>`) açıkken pencere büyütüldüğünde. `showModal()` sayfanın geri\n * kalanını inert bırakır ve bu, panelin çizilip çizilmediğine değil kipsel\n * olmasına bağlıdır — CSS onu gizlese bile sayfa tıklanamaz kalır. Panel bu\n * yüzden kırılma noktası aşıldığında JavaScript ile kapatılır.\n *\n * <p>Değerler iki yerde durduğu için ayrışabilir. Ayrışırlarsa panel yanlış\n * genişlikte kapanır; CSS tarafı her zaman kazanır, buradaki değer ona\n * uydurulur.\n */\nexport const MOBILE_BREAKPOINT = 640;\n\nexport const TABLET_PORTRAIT_BREAKPOINT = 768;\n\nexport const TABLET_BREAKPOINT = 1024;\n\n/** Kenar çubuğu ekranda olduğu için filtre paneli bu ölçünün üstünde gizlenir. */\nexport const ABOVE_TABLET_MEDIA_QUERY = `(min-width: ${TABLET_BREAKPOINT + 1}px)`;\n\n/** Seçim kutusunun alt sayfası yalnızca bu ölçünün altında kullanılır. */\nexport const ABOVE_MOBILE_MEDIA_QUERY = `(min-width: ${MOBILE_BREAKPOINT + 1}px)`;\n","/**\n * Metin normalizasyonu — aksan ve büyük/küçük harf duyarsız arama.\n *\n * <p>{@link matchesSearch} `Combobox`ın yerel filtresidir. Sunucu araması\n * (`onSearch`) verildiğinde bileşen hiç filtrelemez; bu yol yalnızca elde\n * duran bir listeyi taramak için.\n */\n\n/**\n * Serbest metin arama anahtarı: ASCII, küçük harf, tek boşlukla ayrılmış.\n *\n * <h3>Neden aksan sökülüyor</h3>\n * Kullanıcı \"sisli\" yazdığında \"Şişli\" bulunmalı. Doğru aksanı yakalamak\n * zorunda kalmak — özellikle mobil klavyede — aramayı bitiren bir sürtünme.\n *\n * <h3>Türkçe `İ` özel durumu</h3>\n * `toLowerCase()`ten <em>önce</em> `İ → i` eşlenir: varsayılan küçültme\n * \"İSTANBUL\"u \"i̇stanbul\" (birleşik nokta ile) yapıyor ve eşleşmeyi\n * kaçırıyordu. Aynı sorun `ı` için ters yönde yok — o zaten tek kod noktası.\n *\n * <p>Latin-1 aksanları (`é`, `ñ`, `ü`…) `NFD` ayrıştırması + birleştirici\n * işaret temizliğiyle sökülür; Türkçe harfler bu yolla çözülmediği için\n * (`ı` ve `İ` ayrı kod noktaları) önce elle eşlenir.\n */\nexport const normalizeSearchTerm = (value: string): string =>\n value\n .replace(/İ/g, 'i')\n .replace(/I/g, 'i')\n .replace(/ı/g, 'i')\n .toLowerCase()\n .normalize('NFD')\n /* Birlestirici aksan isaretleri (U+0300–U+036F). */\n .replace(/[\\u0300-\\u036f]/g, '')\n /* NFD'nin ayristirmadigi harfler: her biri tek kod noktasi. */\n .replace(/ş/g, 's')\n .replace(/ğ/g, 'g')\n .replace(/ç/g, 'c')\n .replace(/ø/g, 'o')\n .replace(/æ/g, 'ae')\n .replace(/ß/g, 'ss')\n .replace(/đ/g, 'd')\n .replace(/ł/g, 'l')\n .replace(/\\s+/g, ' ')\n .trim();\n\n/**\n * Aranan metin, hedefin içinde geçiyor mu?\n *\n * <p>Aramanın tek kapısı burasıdır: her liste kendi `includes` çağrısını\n * yazdığında biri normalizasyonu atlıyor ve o listede aksanlı arama\n * çalışmıyordu.\n */\nexport const matchesSearch = (haystack: string, needle: string): boolean =>\n normalizeSearchTerm(haystack).includes(normalizeSearchTerm(needle));\n","/**\n * Kipsel panel açılırken ekran klavyesinin kendiliğinden açılmasını engeller.\n *\n * <h3>Sorun</h3>\n * `showModal()` odağı panelin <strong>ilk odaklanabilir öğesine</strong> taşır\n * (HTML \"dialog focusing steps\"). O öğe bir metin alanıysa telefonda klavye\n * kendiliğinden açılır: alt sayfa yarı yüksekliğe sıkışır, liste kısalır ve\n * kullanıcı yazmak istemediği hâlde önce klavyeyi kapatmak zorunda kalır.\n *\n * <h3>Neden odak tümüyle bırakılmıyor</h3>\n * Odağı panelin dışında bırakmak kip semantiğini bozar: odak tuzağı çalışmaz,\n * Escape panele ulaşmaz ve ekran okuyucu paneli hiç duyurmaz. Odak panelin\n * KENDİSİNE alınır — kip davranışı durur, klavye açılmaz.\n */\n\n/** Odaklanınca ekran klavyesi AÇMAYAN giriş türleri. */\nconst NON_TEXT_INPUT_TYPES = new Set([\n 'button',\n 'checkbox',\n 'color',\n 'file',\n 'hidden',\n 'image',\n 'radio',\n 'range',\n 'reset',\n 'submit',\n]);\n\n/** Odaklanınca mobilde ekran klavyesini açacak bir öğe mi? */\nexport const isKeyboardOpeningElement = (element: Element | null): boolean => {\n if (!(element instanceof HTMLElement)) return false;\n\n /* `isContentEditable` mirasi da kapsar (duzenlenebilir bolgenin ICINDEKI\n oge), ama jsdom onu uygulamiyor ve her zaman false donuyor; oznitelik\n kontrolu testte de gecerli olan yedek. */\n if (element.isContentEditable) return true;\n const editable = element.getAttribute('contenteditable');\n if (editable === '' || editable === 'true' || editable === 'plaintext-only') return true;\n\n const tagName = element.tagName;\n if (tagName === 'TEXTAREA') return true;\n if (tagName !== 'INPUT') return false;\n\n return !NON_TEXT_INPUT_TYPES.has((element as HTMLInputElement).type);\n};\n\n/**\n * `showModal()` ÇAĞRILDIKTAN SONRA çağrılır. Odak bir metin alanına düştüyse\n * panelin kendisine geri alınır; düşmediyse hiçbir şey yapılmaz.\n */\nexport const preventAutoKeyboard = (dialog: HTMLDialogElement): void => {\n const active = dialog.ownerDocument.activeElement;\n if (!dialog.contains(active) || !isKeyboardOpeningElement(active)) return;\n\n (active as HTMLElement).blur();\n // `<dialog>` varsayılan olarak odaklanabilir değil; odağı alabilmesi için\n // sıra dışı bırakılır (Tab ile gezinmede görünmez, `focus()` ile alınır).\n dialog.tabIndex = -1;\n dialog.focus({ preventScroll: true });\n};\n\n/**\n * ODAK GERİ DÖNÜŞÜ.\n *\n * <p>Kipsel bir yüzey kapandığında odak, onu AÇAN öğeye dönmeli. Dönmezse\n * odak `<body>`ye düşer ve klavye kullanıcısı sayfanın en başına gider —\n * yirmi kez Tab'ladığı bir listede seçim yapan kullanıcı, seçimden sonra\n * yeniden yirmi kez Tab'lamak zorunda kalıyordu.\n *\n * <p>Açan öğeyi çağıranın hatırlaması gerekiyor: kapanış anında\n * `document.activeElement` çoktan panelin içindeki bir şey. {@link captureFocus}\n * açılışta çağrılır, döndürdüğü fonksiyon kapanışta.\n *\n * @returns Odağı geri veren fonksiyon.\n */\nexport const captureFocus = (): (() => void) => {\n const previous = typeof document === 'undefined' ? null : document.activeElement;\n\n return () => {\n if (!(previous instanceof HTMLElement)) return;\n\n /*\n * Oge hala BELGEDE mi: acan dugme, panel kapanirken DOM'dan kalkmis\n * olabilir (bir satiri silen onay penceresi, satirla birlikte dugmeyi de\n * goturuyor). Kalkmis bir ogeye `focus()` sessizce hicbir sey yapmiyor ve\n * odak yine `<body>`ye dusuyordu; cagiran taraf bunu bilip alternatif bir\n * hedef verebilmeli.\n */\n if (!previous.isConnected) return;\n\n /* `preventScroll` — odaklanan oge gorunum alaninin disindaysa tarayici\n sayfayi oraya kaydiriyor ve kullanici kapattigi pencerenin yerine bambaska\n bir yere bakiyordu. */\n previous.focus({ preventScroll: true });\n };\n};\n\n/** Odaklanabilir öğelerin seçicisi — `inert` ve `disabled` olanlar hariç. */\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not(:disabled)',\n 'input:not(:disabled)',\n 'select:not(:disabled)',\n 'textarea:not(:disabled)',\n '[tabindex]:not([tabindex=\"-1\"])',\n]\n .map(selector => `${selector}:not([inert]):not([aria-hidden=\"true\"])`)\n .join(', ');\n\n/**\n * Panelin İLK ANLAMLI öğesine odaklanır.\n *\n * <h3>\"Anlamlı\" ne demek: kapatma düğmesi DEĞİL</h3>\n * `showModal()` odağı DOM sırasındaki ilk odaklanabilir öğeye taşıyor ve o\n * öğe neredeyse her zaman başlıktaki kapatma düğmesi oluyor. Ekran okuyucu\n * pencereyi \"Kapat, düğme\" diye açıyor — kullanıcının duyduğu ilk şey,\n * pencerenin ne olduğu değil ondan nasıl kaçılacağı.\n *\n * <p>Bu fonksiyon `[data-hanui-autofocus]` işaretli öğeyi arar, yoksa\n * kapatma düğmesi DIŞINDAKİ ilk odaklanabilir öğeyi, o da yoksa panelin\n * kendisini odaklar. Panelin kendisi son çare: odağı panelin dışında bırakmak\n * kip semantiğini bozar (odak tuzağı çalışmaz, `Escape` panele ulaşmaz).\n *\n * @param container Odak aranacak kök.\n * @param skipSelector Atlanacak öğe (varsayılan: kapatma düğmesi).\n */\nexport const focusFirstMeaningful = (\n container: HTMLElement,\n skipSelector = '[data-hanui-close]',\n): void => {\n const explicit = container.querySelector<HTMLElement>('[data-hanui-autofocus]');\n if (explicit) {\n explicit.focus({ preventScroll: true });\n return;\n }\n\n const candidates = [...container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)];\n const target = candidates.find(element => !element.matches(skipSelector)) ?? candidates[0];\n\n if (target) {\n target.focus({ preventScroll: true });\n return;\n }\n\n container.tabIndex = -1;\n container.focus({ preventScroll: true });\n};\n\n/**\n * KİPSEL YIĞIN — üst üste binen paneller.\n *\n * <p>Aynı anda iki kipsel yüzey açılabiliyor: bir onay penceresinin içindeki\n * seçim kutusu, filtre panelinin içindeki alt sayfa. `<dialog>` üst katmanda\n * (top layer) yaşadığı için görsel sıra tarayıcıdan geliyor — ama `Escape`\n * ve odak geri dönüşü İKİSİNE de ulaşıyordu: bir `Escape` her iki paneli\n * birden kapatıyordu.\n *\n * <p>Yığın, \"en üstteki kim\" sorusuna tek bir cevap veriyor. Kapanış olayını\n * yalnızca en üstteki işler.\n */\nconst modalStack: symbol[] = [];\n\n/** Yığına katılır; dönen fonksiyon çıkarır. */\nexport const pushModal = (): { token: symbol; pop: () => void } => {\n const token = Symbol('hanui-modal');\n modalStack.push(token);\n\n return {\n token,\n pop: () => {\n const index = modalStack.indexOf(token);\n if (index >= 0) modalStack.splice(index, 1);\n },\n };\n};\n\n/** Verilen panel yığının EN ÜSTÜNDE mi. */\nexport const isTopModal = (token: symbol): boolean => modalStack[modalStack.length - 1] === token;\n\n/** Yalnızca test içindir: modül düzeyindeki yığın testler arasında sızmamalı. */\nexport const resetModalStack = (): void => {\n modalStack.length = 0;\n};\n","/** Sınıf birleştiricinin kabul ettiği değerler. */\nexport type ClassValue = string | false | null | undefined;\n\n/**\n * Sınıf adı birleştirici.\n *\n * <h3>Neden `clsx` değil</h3>\n * Kaynak tasarım sistemi `clsx` kullanıyordu ve orada doğruydu — bir\n * uygulamada 500 baytlık bir bağımlılık bedava. Bir <em>kütüphanede</em> aynı\n * bağımlılık tüketicinin ağacına ineriyor ve `clsx`ın desteklediği yedi\n * girdi biçiminden (nesne, iç içe dizi, sayı…) burada yalnızca ikisi\n * kullanılıyor: dize ve koşullu dize.\n *\n * <p>Bilerek DAR: nesne biçimi (`{ active: true }`) desteklenmez. Desteklemek\n * çağrı yerlerinde iki ayrı yazım stiline yol açıyor ve hangisinin kullanıldığı\n * dosyadan dosyaya değişiyordu.\n */\nexport const cx = (...values: ClassValue[]): string => {\n let result = '';\n\n for (const value of values) {\n if (!value) continue;\n result = result === '' ? value : `${result} ${value}`;\n }\n\n return result;\n};\n","/**\n * DevTools adı — modül düzeyinde YAN ETKİ bırakmadan.\n *\n * <h3>Neden `X.displayName = 'X'` değil</h3>\n * Bileşenler `memo(forwardRef(…))` ile dışa veriliyor ve bu sarmalayıcıların\n * kendi adı yok: React DevTools onları \"Memo(ForwardRef)\" diye gösterir. Ad bu\n * yüzden ayrıca yazılıyordu — ama modül düzeyindeki bir ÖZELLİK ATAMASI\n * bundler için yan etkili bir ifade ve silinemez.\n *\n * <p>ÖLÇÜLDÜ (`npm run size`): yalnızca `Badge` import eden bir uygulama\n * <strong>20,7 kB</strong> indiriyordu — paketin tamamı 21,8 kB. Yirmi tane\n * `displayName` ataması, zincirleriyle birlikte neredeyse her bileşeni ayakta\n * tutuyordu: `Button.displayName = 'Button'` satırı `Button`ı, o da\n * `Spinner`ı, `HanuiLink`i ve sınıf yardımcısını çağırıyor. Ağaç sallama\n * \"çalışmıyor\" değildi; sallanacak dal bırakılmamıştı.\n *\n * <p>Atama bir ÇAĞRIYA dönüştüğünde `/*#__PURE__*` işaretlenebiliyor ve\n * kullanılmayan bileşenle birlikte adı da düşüyor. Aynı ölçüm sonrasında:\n * `Badge` 2,71 kB, `Button` 3,34 kB.\n *\n * <p>Alternatif — iç fonksiyonu adlandırmak\n * (`forwardRef(function Button(…) {…})`) — de doğru olurdu ve yan etkisi yok;\n * yirmi bileşende ok fonksiyonunu gövdeli fonksiyona çevirmek, ölçülen kazancı\n * değiştirmeyen ama her dosyayı elleyen bir değişiklik olurdu. Tek satırlık bu\n * yardımcı aynı sonucu veriyor.\n *\n * @example\n * export default memo(named(Button, 'Button')) as typeof Button;\n */\nexport const named = <TComponent extends object>(\n component: TComponent,\n displayName: string,\n): TComponent => Object.assign(component, { displayName });\n","'use client';\n\nimport type { AnchorHTMLAttributes, FC } from 'react';\n\nimport { useHanui } from '../../theme/context';\nimport type { HanuiLinkProps } from '../../types/link.type';\n\n/**\n * Kütüphanenin İÇ bağlantı öğesi.\n *\n * <p>Sağlayıcıya bir `linkComponent` verilmişse ona, verilmemişse ham `<a>`ya\n * çizilir. Böylece bir bağlantı taşıyan her bileşen (`Button href`, `Chip`,\n * `Breadcrumb`, `Pagination`, `TextLink`, `Directory`, `Tile`) yönlendirici\n * kararını TEK yerden alır.\n *\n * <p>Bileşenler bunu doğrudan dışa vermez: tüketici zaten kendi Link'ini\n * kullanır. Dışa vermek \"hanui'nin Link'i\" diye üçüncü bir kavram üretirdi.\n *\n * <h3>Neden `forwardRef` değil</h3>\n * `HanuiLinkProps` yönlendiriciye özgü ek props için bir indeks imzası\n * taşıyor ve `forwardRef`in `PropsWithoutRef` eşlemesi o imzayı açıkça\n * bildirilmiş `children`ın üstüne geçirip tipini `unknown`a düşürüyordu. Ref'e\n * ihtiyaç da yok: hiçbir çağrı yeri bu öğeye ref vermiyor, verecek olan\n * tüketicinin kendi Link'i.\n */\nconst HanuiLink: FC<HanuiLinkProps> = ({ children, ...rest }) => {\n const { linkComponent: LinkComponent } = useHanui();\n\n if (LinkComponent) return <LinkComponent {...(rest as HanuiLinkProps)}>{children}</LinkComponent>;\n\n /*\n * Yonlendirici yoksa ham `<a>`. `rest` indeks imzasi tasiyor (yonlendiriciye\n * ozgu props icin); DOM'a giderken anchor sozlesmesine daraltilir —\n * tanimadigi bir ozniteligi React zaten oldugu gibi geciriyor.\n */\n return <a {...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}>{children}</a>;\n};\n\nexport default HanuiLink;\n","/**\n * Metin çözümlemesi: prop → sağlayıcı config'i → geliştirme uyarısı.\n *\n * <p>Sözleşme `theme/labels.ts` içinde anlatıldı. Buradaki tek iş, eksik bir\n * metni SESSİZ bırakmamak: `aria-label`ı olmayan bir kapatma düğmesi ekran\n * okuyucuda \"düğme\" diye okunur ve bu, ekranda hiçbir iz bırakmayan bir\n * erişilebilirlik hatası. Derleyici bunu göremiyor (sağlayıcı çalışma\n * zamanında), o yüzden geliştirme kipinde konsola iniyor.\n */\n\n/*\n * Uyari ANAHTAR BASINA bir kez verilir.\n *\n * Uyari her render'da yazilsaydi, listedeki yirmi satirin her biri icin ayni\n * satir konsola dusuyor ve gercek hatalar o gurultunun icinde kayboluyordu.\n */\nconst warned = new Set<string>();\n\n/** Uyarı durumu testler arasında sızmamalı; her test kendi durumundan başlar. */\nexport const resetLabelWarnings = (): void => warned.clear();\n\n/**\n * Verilen metni çözer.\n *\n * @param key Uyarıda gösterilecek yol (`Modal.closeLabel`).\n * @param values Öncelik sırasına göre adaylar: prop önce, config sonra.\n */\nexport const resolveLabel = (key: string, ...values: (string | undefined)[]): string => {\n for (const value of values) if (value !== undefined) return value;\n\n if (process.env.NODE_ENV !== 'production' && !warned.has(key)) {\n warned.add(key);\n console.error(\n `[hanui] Eksik metin: ${key}. Prop olarak geçin ya da ` +\n '<HanuiProvider labels={…}> içinde bir kez tanımlayın. ' +\n 'Metinsiz bırakılan öğe ekran okuyucuda adsız kalır.',\n );\n }\n\n return '';\n};\n\n/**\n * Biçimlendirici çözümü — değere bağlı metinler için.\n *\n * <p>`CopyField`in \"SP-123 kopyala\"sı ve `Rating`in \"5 üzerinden 4,5\"i bir\n * dize olamaz: içine değer giriyor. Config bir fonksiyon taşır.\n */\nexport const resolveFormatter = <TArgs extends unknown[]>(\n key: string,\n formatter: Formatter<TArgs> | undefined,\n ...args: TArgs\n): string => {\n if (formatter) return formatter(...args);\n\n return resolveLabel(key);\n};\n\ntype Formatter<TArgs extends unknown[]> = (...args: TArgs) => string;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n size?: 'sm' | 'md' | 'lg';\n /**\n * Ekran okuyucuya okunacak metin; görsel olarak gizli.\n *\n * <p>Verilmezse `labels.loading` okunur. Boş dizeye BİLİNÇLİ olarak izin\n * verilir: göstergenin <em>zaten adı olan</em> bir öğenin içinde durduğu\n * yerlerde (yükleniyor durumundaki bir düğme) duyurmak tekrar üretiyor.\n * `label=\"\"` orada doğru olan ve config'i de bastırır.\n */\n label?: string;\n className?: string;\n};\n\n/**\n * Yükleme göstergesi.\n *\n * <p>İskelet (`Skeleton`) tercih edilir; bu bileşen yalnızca <em>şekli\n * bilinmeyen</em> bir bekleme için — düğme içi işlem veya belirsiz süreli bir\n * sorgu gibi.\n */\nconst Spinner: FC<Props> = ({ size = 'md', label, className }) => {\n const { labels } = useHanui();\n\n return (\n <span className={cx(styles.spinner, styles[`spinner--${size}`], className)} role=\"status\">\n <span className={styles.spinner__label}>\n {label ?? resolveLabel('Spinner.label', labels?.loading)}\n </span>\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Spinner) as typeof Spinner;\n","'use client';\n\nimport { type ButtonHTMLAttributes, forwardRef, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport type { CommonElementProps } from '../../types/common-element-props.type';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\nimport Spinner from '../Spinner';\n\nimport styles from './index.module.scss';\n\ntype BaseProps = Partial<{\n variant: UIVariant;\n size: UISize;\n isLoading: boolean;\n isFullWidth: boolean;\n startIcon: ReactNode;\n endIcon: ReactNode;\n}> &\n CommonElementProps;\n\ntype Props = BaseProps &\n ButtonHTMLAttributes<HTMLButtonElement> & {\n /** Verilirse düğme bir bağlantı olarak çizilir. */\n href?: string;\n /**\n * Uygulama dışına çıkan bağlantı: yeni sekmede açılır ve yönlendirici\n * devreye girmez.\n */\n isExternal?: boolean;\n /** Yönlendiriciye geçirilecek ek props (`{ scroll: false }`, `{ replace: true }`). */\n linkProps?: HanuiLinkExtraProps;\n };\n\n/**\n * Düğme.\n *\n * <h3>Yüklenirken içerik korunur</h3>\n * Metin dönen çarkla DEĞİŞTİRİLMEZ, yanına eklenir ve düğme genişliği\n * sabitlenir. Metni değiştirmek düğmeyi daraltıp yerleşimi kaydırıyordu ve\n * kullanıcı neye tıkladığını kaybediyordu.\n *\n * <h3>Bağlantı mı düğme mi</h3>\n * `href` verilirse `<a>` çizilir. Görsel olarak düğme gibi duran bir\n * bağlantının gerçekten `<a>` olması gerekir: orta tuşla yeni sekmede\n * açılması ve tarayıcı geçmişine girmesi beklenen davranıştır.\n *\n * <p>`isExternal` ile birlikte yönlendirici DEĞİL ham `<a>` çizilir ve\n * `target=\"_blank\"` + `rel=\"noopener noreferrer\"` eklenir. Uygulama dışı bir\n * adres için yönlendiriciyi araya sokmak anlamsız; `rel` ise zorunlu —\n * `noopener` olmadan açılan sekme `window.opener` üzerinden bu sayfaya\n * erişebiliyor. Düğme benzeri dış bağlantı elle `<a>` olarak yazılmasın diye\n * burada: elle yazılan her bağlantı odak halkasını ve durum matrisini yeniden\n * kurmak zorunda kalıyordu.\n *\n * @example\n * <Button variant={UIVariant.PRIMARY} isLoading={isSaving} onClick={save}>\n * Kaydet\n * </Button>\n */\nconst Button = /*#__PURE__*/ forwardRef<HTMLButtonElement, Props>(\n (\n {\n variant = UIVariant.PRIMARY,\n size = UISize.MEDIUM,\n isLoading,\n isFullWidth,\n startIcon,\n endIcon,\n className,\n children,\n disabled,\n href,\n isExternal,\n linkProps,\n testId,\n ...rest\n },\n ref,\n ) => {\n const classNames = cx(\n styles.button,\n styles[`button--${variant.toLowerCase()}`],\n styles[`button--${size.toLowerCase()}`],\n isFullWidth && styles['button--full'],\n isLoading && styles['button--loading'],\n className,\n );\n\n const content = (\n <>\n {isLoading && <Spinner size=\"sm\" className={styles.button__spinner} label=\"\" />}\n {!isLoading && startIcon && <span className={styles.button__icon}>{startIcon}</span>}\n <span className={styles.button__label}>{children}</span>\n {endIcon && <span className={styles.button__icon}>{endIcon}</span>}\n </>\n );\n\n if (href && isExternal)\n return (\n <a\n href={href}\n className={classNames}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={rest['aria-label']}\n data-testid={testId}\n >\n {content}\n </a>\n );\n\n if (href)\n return (\n <HanuiLink href={href} className={classNames} data-testid={testId} {...linkProps}>\n {content}\n </HanuiLink>\n );\n\n return (\n <button\n ref={ref}\n className={classNames}\n disabled={disabled || isLoading}\n aria-busy={isLoading}\n data-testid={testId}\n {...rest}\n >\n {content}\n </button>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Button, 'Button')) as typeof Button;\n","'use client';\n\nimport { type ButtonHTMLAttributes, forwardRef, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\nexport type IconButtonVariant = 'ghost' | 'outline' | 'solid' | 'cart' | 'danger';\n\ntype Props = ButtonHTMLAttributes<HTMLButtonElement> & {\n icon: ReactNode;\n /** Görsel etiketi olmayan düğmenin erişilebilir adı — ZORUNLU. */\n label: string;\n /**\n * `cart` <strong>yalnızca dönüşüm eyleminde</strong> kullanılır — ekranda\n * görünen tek doygun turuncu odur. Nötr dolgu için `solid`.\n */\n variant?: IconButtonVariant;\n size?: 'sm' | 'md';\n /** Verilirse öğe bir bağlantı olarak çizilir. */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n testId?: string;\n};\n\n/**\n * Yalnızca ikon taşıyan düğme.\n *\n * <p>`label` <strong>zorunlu</strong>: görsel etiketi olmayan bir düğme\n * `aria-label` olmadan ekran okuyucuda \"düğme\" diye okunur. Zorunlu tutmak,\n * unutulmasını derleme zamanında engeller.\n *\n * <p>Dokunma hedefi 44×44 px'ten küçük olamaz (WCAG 2.5.8) — görsel kutu daha\n * küçük olsa bile tıklanabilir alan korunur.\n *\n * <h3>`href` verilince `<a>` çizilir</h3>\n * Bir tablo satırının \"düzenle\" simgesi görsel olarak düğme ama davranışı\n * bağlantı: orta tuşla yeni sekmede açılması, adresinin kopyalanabilmesi ve\n * tarayıcı geçmişine girmesi beklenen davranış. `onClick` + `router.push` ile\n * yazıldığında bunların hiçbiri çalışmıyordu.\n *\n * <p>Bağlantı kipinde `disabled` YOKTUR — `<a>` etiketinin devre dışı hâli\n * yok ve `aria-disabled` tıklamayı engellemez. Erişilemez olması gereken bir\n * eylem hiç çizilmez.\n */\nconst IconButton = /*#__PURE__*/ forwardRef<HTMLButtonElement, Props>(\n (\n {\n icon,\n label,\n variant = 'ghost',\n size = 'md',\n className,\n type = 'button',\n href,\n linkProps,\n testId,\n ...rest\n },\n ref,\n ) => {\n const classNames = cx(\n styles.iconButton,\n styles[`iconButton--${variant}`],\n styles[`iconButton--${size}`],\n className,\n );\n\n if (href)\n return (\n <HanuiLink\n href={href}\n className={classNames}\n aria-label={label}\n title={rest.title ?? label}\n data-testid={testId}\n {...linkProps}\n >\n {icon}\n </HanuiLink>\n );\n\n return (\n <button\n ref={ref}\n type={type}\n className={classNames}\n aria-label={label}\n title={label}\n data-testid={testId}\n {...rest}\n >\n {icon}\n </button>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(IconButton, 'IconButton'),\n) as typeof IconButton;\n","import { type AnchorHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { ArrowRight } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {\n href: string;\n children: ReactNode;\n /** Sonda ok gösterilir — \"devam et\" anlamı taşıyan bağlantılarda. */\n hasArrow?: boolean;\n tone?: 'brand' | 'muted';\n size?: 'sm' | 'md';\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n};\n\n/**\n * Metin bağlantısı.\n *\n * <h3>Ok bir süs değil</h3>\n * Sondaki ok yalnızca <em>gezinme</em> bağlantılarında kullanılır (\"Tümünü gör\n * →\"). Bir eylemi tetikleyen bağlantıya ok koymak, kullanıcıya başka bir\n * sayfaya gideceğini söyler ve beklentiyi yanıltır.\n *\n * <p>Ok, üzerine gelindiğinde <strong>ilerler</strong>: hareket, bağlantının\n * götürdüğü yönü fiziksel olarak sezdirir.\n *\n * <h3>Alt çizgi hover'da eklenir, kaldırılmaz</h3>\n * Sürekli altı çizili bağlantılar yoğun bir liste sayfasında görsel gürültü\n * yaratıyordu. Ama alt çizginin <em>hiç</em> olmaması bağlantıyı düz metinden\n * ayırt edilemez kılar; renk tek başına yeterli değil (WCAG 1.4.1). Çözüm:\n * renk her zaman, alt çizgi etkileşimde.\n */\nconst TextLink = ({\n href,\n children,\n hasArrow,\n tone = 'brand',\n size = 'md',\n className,\n linkProps,\n ...rest\n}: Props) => (\n <HanuiLink\n href={href}\n className={cx(styles.link, styles[`link--${tone}`], styles[`link--${size}`], className)}\n {...linkProps}\n {...rest}\n >\n <span className={styles.link__label}>{children}</span>\n {/*\n * Ok DOLU DEĞİL: Bootstrap Icons'ta uzun okun dolu bir eşi yok ve dolu\n * caret bir \"devam\" oku değil, bir açılır menü işareti okunuyor.\n */}\n {hasArrow && <ArrowRight aria-hidden className={styles.link__arrow} />}\n </HanuiLink>\n);\n\nexport default /*#__PURE__*/ memo(TextLink) as typeof TextLink;\n","'use client';\n\nimport {\n memo,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport usePositioning, { type PositionSide } from '../../hooks/usePositioning';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Balonda gösterilecek açıklama. */\n content: ReactNode;\n /** Açıklamanın bağlandığı öğe — düğme, ikon, etiket. */\n children: ReactNode;\n /**\n * Tercih edilen kenar. Yer yoksa KARŞITINA düşer; üçüncü bir kenara\n * atlamaz (bkz. `usePositioning`).\n */\n side?: PositionSide;\n /**\n * Açılma gecikmesi (ms). Fare bir araç çubuğunun üzerinden geçerken sıfır\n * gecikme, art arda beş balon açıp kapatıyordu.\n */\n openDelay?: number;\n /**\n * @deprecated `side` kullanın. Bu prop bir sonraki büyük sürümde kalkacak.\n *\n * <p>Ad değişti çünkü davranış değişti: `position` SABİT bir kenar\n * yazıyordu ve balon oraya sığmadığında görünüm alanının dışına taşıyordu.\n * `side` yalnızca TERCİH — yer yoksa karşıt kenara düşülüyor. Aynı adı\n * korumak, artık doğru olmayan bir sözü sürdürmek olurdu.\n */\n position?: 'top' | 'bottom';\n className?: string;\n};\n\n/** Balonun kapanmadan önce beklediği süre — imlecin balona ulaşması için. */\nconst CLOSE_DELAY = 120;\n\n/** Dokunmatikte balonu açan basma süresi. Daha kısası kaydırma jestini yakalıyordu. */\nconst LONG_PRESS_DELAY = 500;\n\n/**\n * İpucu balonu.\n *\n * <h3>Neden native `title` yetmiyor</h3>\n * Tarayıcının `title` özniteliği <strong>dokunmatikte hiç görünmez</strong>,\n * gecikmesi ayarlanamaz ve biçimlendirilemez. Trafiğin ağırlığı mobil olan\n * bir arayüzde \"üzerine gelince açıklama çıkar\" demek, kullanıcıların çoğu\n * için açıklamanın hiç olmaması demek.\n *\n * <h3>Balon PORTAL ile gövdede</h3>\n * Önce tetikleyicinin içinde `position: absolute` ile duruyordu ve üç yerde\n * birden bozuluyordu: `overflow: hidden` taşıyan bir kapsayıcının içinde\n * (kart, tablo hücresi, `Panel`) KIRPILIYOR, ekranın kenarında görünüm\n * alanının dışına TAŞIYOR, `transform` taşıyan bir atanın altında yığılma\n * bağlamına HAPSOLUYORDU. Konum artık `usePositioning` ile ölçülüyor;\n * gerekçenin tamamı orada.\n *\n * <h3>Neden yalnızca AÇIKLAMA taşır</h3>\n * Balonda <em>yalnızca</em> yardımcı metin durur — bağlantı, düğme veya\n * okunması zorunlu bir bilgi değil. İçine bir eylem konsaydı ona erişmenin\n * yolu olmazdı: balon `pointer-events: none` ve klavyeyle içine girilemiyor.\n * Eylem taşıyan yüzey `Popover`ın işi; kalıcı olması gereken metin `Field`ın\n * `hint`i.\n *\n * <h3>Dokunmatik: uzun basma</h3>\n * Dokunmatikte `hover` yok — ipucu orada hiç açılmıyordu. Uzun basma balonu\n * açar; ekranın herhangi bir yerine dokunmak kapatır. Bağlam menüsü\n * bastırılır: uzun basmada iOS'ta seçim büyüteci, Android'de kopyala menüsü\n * çıkıyor ve ikisi de balonun üstüne biniyordu.\n *\n * <h3>Kapanma toleransı</h3>\n * İmleç tetikleyiciden çıkar çıkmaz kapatmak, balonun kendisine ulaşmayı\n * imkânsız kılıyordu (metin seçilemiyor). Kapanış {@link CLOSE_DELAY} kadar\n * bekletilir ve bu sürede balona giren imleç onu açık tutar.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>tetikleyiciye gelince GECİKMESİZ açılır</td></tr>\n * <tr><td>`Escape`</td><td>kapatır; odak tetikleyicide kalır</td></tr>\n * </table>\n * Gecikme fare için var; Tab ile gelen kullanıcı zaten bilinçli olarak orada\n * duruyor.\n */\nconst Tooltip = ({ content, children, side, position, openDelay = 300, className }: Props) => {\n const [isOpen, setIsOpen] = useState(false);\n const id = useId();\n\n /* Eski prop bir surum boyunca calisir; `side` verilmisse o kazanir. */\n const resolvedSide: PositionSide = side ?? position ?? 'top';\n\n const anchorRef = useRef<HTMLSpanElement>(null);\n const bubbleRef = useRef<HTMLSpanElement>(null);\n const timerRef = useRef(0);\n const longPressRef = useRef(0);\n\n const positioning = usePositioning(anchorRef, bubbleRef, {\n side: resolvedSide,\n align: 'center',\n isOpen,\n });\n\n const clearTimer = useCallback(() => {\n if (timerRef.current) window.clearTimeout(timerRef.current);\n timerRef.current = 0;\n }, []);\n\n const open = useCallback(\n (delay: number) => {\n clearTimer();\n timerRef.current = window.setTimeout(() => setIsOpen(true), delay);\n },\n [clearTimer],\n );\n\n const close = useCallback(\n (delay: number = CLOSE_DELAY) => {\n clearTimer();\n timerRef.current = window.setTimeout(() => setIsOpen(false), delay);\n },\n [clearTimer],\n );\n\n useEffect(() => clearTimer, [clearTimer]);\n\n /*\n * Escape BELGE duzeyinde dinleniyor.\n *\n * Sarmalayicida dinlemek yetmiyordu: balon acikken odak tetikleyicide\n * OLMAYABILIR (fareyle acilmis bir ipucu) ve o durumda tus olayi hic\n * sarmalayiciya ulasmiyor, ipucu ekranda asili kaliyordu.\n */\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') close(0);\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, close]);\n\n /* Dokunmatikte ekranin herhangi bir yerine dokunmak kapatir: balonun kendi\n kapatma yolu yok ve `pointer-events: none` oldugu icin ona da\n dokunulamiyor. */\n useEffect(() => {\n if (!isOpen) return;\n\n const handlePointerDown = (event: globalThis.PointerEvent) => {\n if (event.pointerType === 'mouse') return;\n if (anchorRef.current?.contains(event.target as Node)) return;\n close(0);\n };\n\n document.addEventListener('pointerdown', handlePointerDown);\n return () => document.removeEventListener('pointerdown', handlePointerDown);\n }, [isOpen, close]);\n\n const cancelLongPress = () => {\n if (longPressRef.current) window.clearTimeout(longPressRef.current);\n longPressRef.current = 0;\n };\n\n const handlePointerDown = (event: ReactPointerEvent) => {\n if (event.pointerType === 'mouse') return;\n longPressRef.current = window.setTimeout(() => setIsOpen(true), LONG_PRESS_DELAY);\n };\n\n return (\n <>\n <span\n ref={anchorRef}\n className={cx(styles.tooltip, className)}\n onPointerEnter={event => event.pointerType === 'mouse' && open(openDelay)}\n onPointerLeave={event => {\n cancelLongPress();\n if (event.pointerType === 'mouse') close();\n }}\n onPointerDown={handlePointerDown}\n onPointerUp={cancelLongPress}\n onPointerCancel={cancelLongPress}\n onFocus={() => open(0)}\n onBlur={() => close(0)}\n onContextMenu={event => {\n if (isOpen || longPressRef.current) event.preventDefault();\n }}\n >\n <span aria-describedby={isOpen ? id : undefined} className={styles.tooltip__trigger}>\n {children}\n </span>\n </span>\n\n {/*\n Balon DOM'da yalnizca ACIKKEN: kapaliyken de birakip gizlemek, ekran\n okuyucunun onu `aria-describedby` olmadan da bulup okumasina yol\n aciyordu.\n */}\n {isOpen &&\n isClient() &&\n createPortal(\n <span\n ref={bubbleRef}\n id={id}\n role=\"tooltip\"\n className={cx(styles.bubble, styles[`bubble--${positioning.side}`])}\n style={{\n ...positioning.style,\n /* Olculmeden cizilen balon bir kare boyunca sol ust kosede\n parliyordu. */\n visibility: positioning.isPositioned ? 'visible' : 'hidden',\n }}\n /* Imlec balona giderken tetikleyiciden cikiyor; balon uzerindeyken\n kapanis iptal edilir ve metin secilebilir kalir. */\n onPointerEnter={clearTimer}\n onPointerLeave={() => close()}\n >\n {content}\n </span>,\n document.body,\n )}\n </>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Tooltip, 'Tooltip')) as typeof Tooltip;\n","'use client';\n\nimport {\n cloneElement,\n isValidElement,\n type KeyboardEvent,\n memo,\n type MouseEvent,\n type ReactElement,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { captureFocus } from '../../helpers/focus.helper';\nimport usePositioning, { type PositionAlign, type PositionSide } from '../../hooks/usePositioning';\n\nimport styles from './index.module.scss';\n\nexport type MenuItem = {\n id: string;\n label: string;\n icon?: ReactNode;\n onSelect: () => void;\n isDisabled?: boolean;\n /** Geri alınamaz eylem: yıkıcı tonda çizilir. */\n isDanger?: boolean;\n};\n\ntype Props = {\n /** Tetikleyici. TEK öğe; bileşen ona `ref` ve ARIA ekliyor. */\n trigger: ReactElement;\n items: MenuItem[];\n /** Menünün erişilebilir adı (\"Satır eylemleri\"). ZORUNLU. */\n label: string;\n side?: PositionSide;\n align?: PositionAlign;\n className?: string;\n testId?: string;\n};\n\n/** Pasif olmayan seçeneklerin dizinleri. */\nconst enabledIndexes = (items: MenuItem[]): number[] =>\n items.map((item, index) => (item.isDisabled ? -1 : index)).filter(index => index >= 0);\n\n/**\n * Menü — bir listeden EYLEM seçme.\n *\n * <h3>{@link Select} ile farkı: seçim mi eylem mi</h3>\n * Görsel olarak benzerler; ayrım seçilen şeyin ne olduğunda:\n *\n * <ul>\n * <li>`Select` bir DEĞER seçer. Seçim kalıcıdır, tetikleyicide görünür ve\n * geri alınabilir. ARIA rolü `listbox`.</li>\n * <li><b>`Menu` bir EYLEM çalıştırır.</b> \"Sil\", \"Kopyala\", \"Dışa aktar\".\n * Seçilen şey hatırlanmaz; menü kapanır ve iş yapılır. ARIA rolü\n * `menu`.</li>\n * </ul>\n *\n * <p>Ayrım ekran okuyucuda duyuluyor: `listbox` \"3 seçenekten 2.'si seçili\"\n * der, `menu` \"menü, 3 öğe\" der. Eylem listesini `listbox` olarak sunmak,\n * kullanıcıya kalıcı bir seçim yaptığını söylüyordu.\n *\n * <h3>Odak GERÇEKTEN taşınır</h3>\n * `Select` odağı tetikleyicide tutup etkin seçeneği `aria-activedescendant`\n * ile bildiriyor; menüde bu YANLIŞ olurdu. APG menü deseni gerçek odak\n * istiyor çünkü menü öğeleri düğme gibi davranıyor — ve harfe atlama\n * (type-ahead) yalnızca odaklanmış bir öğe üzerinde anlamlı.\n *\n * <h3>Klavye (APG: menu button)</h3>\n * <table>\n * <tr><td>`Enter` / `Space` / `ArrowDown`</td><td>tetikleyicide: açar, İLK öğeye odaklanır</td></tr>\n * <tr><td>`ArrowUp`</td><td>tetikleyicide: açar, SON öğeye odaklanır</td></tr>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>öğeler arasında; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son öğe</td></tr>\n * <tr><td>harf</td><td>o harfle başlayan ilk öğeye atlar</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>öğeyi çalıştırır ve menüyü kapatır</td></tr>\n * <tr><td>`Escape` / `Tab`</td><td>kapatır, odak TETİKLEYİCİYE döner</td></tr>\n * </table>\n */\nconst Menu = ({\n trigger,\n items,\n label,\n side = 'bottom',\n align = 'start',\n className,\n testId,\n}: Props) => {\n const id = useId();\n const anchorRef = useRef<HTMLElement>(null);\n const surfaceRef = useRef<HTMLDivElement>(null);\n const restoreRef = useRef<(() => void) | null>(null);\n /* Harfe atlama tamponu: art arda basilan harfler tek bir arama olur. */\n const typedRef = useRef({ text: '', at: 0 });\n\n const [isOpen, setIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(0);\n\n const positioning = usePositioning(anchorRef, surfaceRef, { side, align, isOpen });\n const enabled = enabledIndexes(items);\n\n const open = useCallback(\n (target: 'first' | 'last') => {\n if (enabled.length === 0) return;\n restoreRef.current = captureFocus();\n setActiveIndex(target === 'first' ? enabled[0] : enabled[enabled.length - 1]);\n setIsOpen(true);\n },\n [enabled],\n );\n\n const close = useCallback(() => {\n setIsOpen(false);\n /* Odak TETIKLEYICIYE doner: donmezse `<body>`ye duser ve klavye\n kullanicisi sayfanin en basina giderdi. */\n restoreRef.current?.();\n restoreRef.current = null;\n }, []);\n\n /* Etkin oge GERCEKTEN odaklanir (APG menu deseni). */\n useEffect(() => {\n if (!isOpen) return;\n surfaceRef.current\n ?.querySelector<HTMLElement>(`[data-index=\"${activeIndex}\"]`)\n ?.focus({ preventScroll: true });\n }, [isOpen, activeIndex]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n const target = event.target as Node;\n if (surfaceRef.current?.contains(target) || anchorRef.current?.contains(target)) return;\n close();\n };\n\n document.addEventListener('mousedown', handlePointerDown);\n return () => document.removeEventListener('mousedown', handlePointerDown);\n }, [isOpen, close]);\n\n const step = (offset: number) => {\n const position = enabled.indexOf(activeIndex);\n const next = (position + offset + enabled.length) % enabled.length;\n setActiveIndex(enabled[next]);\n };\n\n /** Harfe atlama: 500 ms içinde basılan harfler tek bir arama. */\n const jumpToLetter = (key: string) => {\n const now = Date.now();\n const buffer = now - typedRef.current.at > 500 ? key : typedRef.current.text + key;\n typedRef.current = { text: buffer, at: now };\n\n const match = enabled.find(index =>\n items[index].label.toLocaleLowerCase('tr').startsWith(buffer.toLocaleLowerCase('tr')),\n );\n\n if (match !== undefined) setActiveIndex(match);\n };\n\n const handleMenuKeyDown = (event: KeyboardEvent) => {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n step(1);\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n step(-1);\n break;\n\n case 'Home':\n event.preventDefault();\n setActiveIndex(enabled[0]);\n break;\n\n case 'End':\n event.preventDefault();\n setActiveIndex(enabled[enabled.length - 1]);\n break;\n\n case 'Escape':\n event.preventDefault();\n close();\n break;\n\n case 'Tab':\n /* Menu KAPANIR ama gezinme SURER: kullanici menuden cikip sayfaya\n devam ediyor. `preventDefault` yok. */\n close();\n break;\n\n default:\n if (event.key.length === 1 && !event.metaKey && !event.ctrlKey) jumpToLetter(event.key);\n }\n };\n\n const handleTriggerKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n open('last');\n return;\n }\n\n if (['ArrowDown', 'Enter', ' '].includes(event.key)) {\n event.preventDefault();\n open('first');\n }\n };\n\n if (!isValidElement(trigger)) return null;\n\n const triggerProps = trigger.props as Record<string, unknown>;\n\n const anchor = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: anchorRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n 'aria-controls': isOpen ? id : undefined,\n onClick: (event: MouseEvent) => {\n (triggerProps.onClick as ((event: MouseEvent) => void) | undefined)?.(event);\n if (isOpen) close();\n else open('first');\n },\n onKeyDown: (event: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((event: KeyboardEvent) => void) | undefined)?.(event);\n if (!isOpen) handleTriggerKeyDown(event);\n },\n });\n\n return (\n <>\n {anchor}\n\n {isOpen &&\n isClient() &&\n createPortal(\n <div\n ref={surfaceRef}\n id={id}\n role=\"menu\"\n aria-label={label}\n className={cx(styles.menu, styles[`menu--${positioning.side}`], className)}\n style={{\n ...positioning.style,\n visibility: positioning.isPositioned ? 'visible' : 'hidden',\n }}\n data-testid={testId}\n onKeyDown={handleMenuKeyDown}\n >\n {items.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"menuitem\"\n data-index={index}\n /*\n * DONEN `tabindex`: menu Tab sirasinda TEK durak. Her oge\n * odaklanabilir olsaydi sekiz ogeli bir menude klavye\n * kullanicisi sayfaya donmek icin sekiz kez Tab'liyordu.\n */\n tabIndex={index === activeIndex ? 0 : -1}\n disabled={item.isDisabled}\n className={cx(styles.menu__item, item.isDanger && styles['menu__item--danger'])}\n onClick={() => {\n item.onSelect();\n close();\n }}\n /* Fare imleci ogenin uzerindeyken etkin oge de oraya tasinir;\n iki ayri vurgu kullaniciyi sasirtiyordu. */\n onMouseEnter={() => !item.isDisabled && setActiveIndex(index)}\n >\n {item.icon && (\n <span className={styles.menu__icon} aria-hidden>\n {item.icon}\n </span>\n )}\n {item.label}\n </button>\n ))}\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Menu, 'Menu')) as typeof Menu;\n","'use client';\n\nimport {\n cloneElement,\n isValidElement,\n memo,\n type ReactElement,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { captureFocus, focusFirstMeaningful } from '../../helpers/focus.helper';\nimport usePositioning, { type PositionAlign, type PositionSide } from '../../hooks/usePositioning';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /**\n * Tetikleyici. TEK bir öğe olmak zorunda: bileşen ona `ref`, `onClick` ve\n * `aria-expanded` ekliyor.\n */\n trigger: ReactElement;\n children: ReactNode;\n /** Yüzeyin erişilebilir adı. ZORUNLU — adsız bir bölge \"grup\" diye okunur. */\n label: string;\n side?: PositionSide;\n align?: PositionAlign;\n /** Kontrollü kullanım. Verilmezse bileşen durumu kendisi tutar. */\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n className?: string;\n testId?: string;\n};\n\n/**\n * Popover — <strong>eylem taşıyabilen</strong>, odaklanabilir yüzey.\n *\n * <h3>{@link Tooltip} ile farkı: içine ne konabildiği</h3>\n * İkisi de tetikleyiciye yapışan bir yüzey açıyor; ayrım içeriğin\n * ERİŞİLEBİLİR olup olmamasında:\n *\n * <ul>\n * <li>`Tooltip` yalnızca AÇIKLAMA taşır. `pointer-events: none` ve klavyeyle\n * içine girilemez — içine bir bağlantı konsa ona ulaşmanın yolu olmazdı\n * (fare balona giderken tetikleyiciden çıkıyor).</li>\n * <li><b>`Popover` odak alır.</b> Açıldığında odak içeri girer, `Escape`\n * kapatır ve odak tetikleyiciye döner. Bağlantı, düğme, kısa bir form\n * konabilir.</li>\n * </ul>\n *\n * <h3>Kipsel DEĞİL</h3>\n * Arka plan tıklanabilir kalır ve sayfa kaydırılabilir. Kararı bekleyen,\n * kaçınılmaz bir seçim `Modal`ın işi; popover yardımcı bir yüzey ve\n * kullanıcıyı hapsetmemeli. Bu yüzden `<dialog>` DEĞİL portal + `usePositioning`:\n * `showModal()` arka planı inert bırakıyor, `<dialog open>` (kipsiz) ise üst\n * katmana hiç girmiyor ve `z-index` yarışına dönüyordu.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Enter` / `Space`</td><td>tetikleyicide: açar</td></tr>\n * <tr><td>`Escape`</td><td>kapatır, odak TETİKLEYİCİYE döner</td></tr>\n * <tr><td>`Tab`</td><td>yüzeyin içinde gezinir; dışına çıkınca KAPANIR</td></tr>\n * </table>\n * Odak tuzağı YOK — kipsel olmayan bir yüzeyde odağı hapsetmek, kullanıcıyı\n * sayfadan koparır. Odak dışarı çıktığında yüzey kapanır.\n */\nconst Popover = ({\n trigger,\n children,\n label,\n side = 'bottom',\n align = 'start',\n isOpen: controlledOpen,\n onOpenChange,\n className,\n testId,\n}: Props) => {\n const id = useId();\n const anchorRef = useRef<HTMLElement>(null);\n const surfaceRef = useRef<HTMLDivElement>(null);\n const restoreRef = useRef<(() => void) | null>(null);\n\n const [uncontrolledOpen, setUncontrolledOpen] = useState(false);\n const isControlled = controlledOpen !== undefined;\n const isOpen = isControlled ? controlledOpen : uncontrolledOpen;\n\n const positioning = usePositioning(anchorRef, surfaceRef, { side, align, isOpen });\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setUncontrolledOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n /* Acilista odak ICERI girer, kapanista TETIKLEYICIYE doner. */\n useEffect(() => {\n if (!isOpen) return;\n\n restoreRef.current = captureFocus();\n const surface = surfaceRef.current;\n if (surface) focusFirstMeaningful(surface);\n\n return () => {\n restoreRef.current?.();\n restoreRef.current = null;\n };\n }, [isOpen]);\n\n /* Escape ve DISARI tiklama. Ikisi de belge duzeyinde: odak yuzeyin icinde\n olmayabilir (fareyle acilmis bir popover). */\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false);\n };\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n const target = event.target as Node;\n if (surfaceRef.current?.contains(target)) return;\n if (anchorRef.current?.contains(target)) return;\n setOpen(false);\n };\n\n document.addEventListener('keydown', handleKeyDown);\n /* `mousedown`: `click` beklerken kullanici surukleyerek secim yaparsa\n yuzey kapanmiyordu. */\n document.addEventListener('mousedown', handlePointerDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('mousedown', handlePointerDown);\n };\n }, [isOpen, setOpen]);\n\n if (!isValidElement(trigger)) return null;\n\n const triggerProps = trigger.props as Record<string, unknown>;\n\n const anchor = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: anchorRef,\n 'aria-expanded': isOpen,\n 'aria-haspopup': 'dialog',\n 'aria-controls': isOpen ? id : undefined,\n onClick: (event: React.MouseEvent) => {\n (triggerProps.onClick as ((event: React.MouseEvent) => void) | undefined)?.(event);\n setOpen(!isOpen);\n },\n });\n\n return (\n <>\n {anchor}\n\n {isOpen &&\n isClient() &&\n createPortal(\n <div\n ref={surfaceRef}\n id={id}\n /*\n * `role=\"dialog\"` ama `aria-modal` YOK: yuzey kipsel degil ve\n * `aria-modal=\"true\"` yazmak ekran okuyucuya sayfanin geri\n * kalaninin erisilemez oldugunu soyluyordu — oysa erisilebilir.\n */\n role=\"dialog\"\n aria-label={label}\n className={cx(styles.popover, styles[`popover--${positioning.side}`], className)}\n style={{\n ...positioning.style,\n visibility: positioning.isPositioned ? 'visible' : 'hidden',\n }}\n data-testid={testId}\n /* Odak yuzeyin DISINA ciktiginda kapanir: kipsel olmayan bir\n yuzeyde odagi hapsetmek kullaniciyi sayfadan koparirdi. */\n onBlur={event => {\n if (event.currentTarget.contains(event.relatedTarget as Node)) return;\n if (anchorRef.current?.contains(event.relatedTarget as Node)) return;\n setOpen(false);\n }}\n >\n {children}\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Popover, 'Popover')) as typeof Popover;\n","'use client';\n\nimport { type ButtonHTMLAttributes, forwardRef, memo, type ReactNode } from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\nexport type ChipSize = 'sm' | 'md';\n\ntype Props = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> & {\n /** Görünen metin. Yalnız ikon taşıyan çipte verilmez; `label` zorunlu olur. */\n children?: ReactNode;\n /** Metnin solundaki ikon. */\n icon?: ReactNode;\n /** Metnin sağındaki ikon (ok, çarpı). */\n endIcon?: ReactNode;\n /** Sağda gösterilen sonuç adedi. */\n count?: number;\n isSelected?: boolean;\n size?: ChipSize;\n /**\n * Erişilebilir ad. Görünür metin yoksa <strong>zorunlu</strong>: yalnız ikon\n * taşıyan bir çip ekran okuyucuda \"düğme\" diye okunur.\n */\n label?: string;\n /** Verilirse çip bir bağlantı olarak çizilir. */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n /**\n * Grup içindeki ARIA rolü. Tek seçimli gruplarda `radio`, çok seçimlide\n * verilmez — {@link ChipGroup} bunu kendisi ayarlar; elle kullanımda\n * `aria-pressed` üretilir.\n */\n role?: 'radio';\n testId?: string;\n};\n\n/**\n * Çip — seçilebilir etiket.\n *\n * <h3>Tasarım sisteminin en çok tekrarlanan öğesi</h3>\n * Kategori seçimi, hızlı filtre, sıralama tercihi, görünüm anahtarı: hepsi\n * aynı öğe. Ayrı ayrı düğme stilleri yazmak yerine tek çip kullanılır;\n * böylece seçili durumun nasıl göründüğü uygulamanın her yerinde aynıdır.\n *\n * <h3>Seçili durum üç sinyalle birden bildirilir</h3>\n * Kenarlık + metin rengi + ikon rengi <em>birlikte</em> değişir. Yalnızca\n * zemini doldurmak (renk tek başına, WCAG 1.4.1) renk körü kullanıcı için\n * ayırt edilemez olurdu; ayrıca dolu zemin çipi düğmeye benzetip \"buraya\n * tıkla\" gibi okutuyordu — oysa çip bir <em>durum</em> gösterir.\n *\n * <h3>Neden `aria-pressed`, `disabled` değil</h3>\n * Seçili çip pasifleştirilmez: kullanıcı seçimini geri alabilmeli. Basılı\n * düğme semantiği (`aria-pressed`) ekran okuyucuya \"seçili, kapatılabilir\"\n * bilgisini verir.\n */\nconst Chip = /*#__PURE__*/ forwardRef<HTMLButtonElement, Props>(\n (\n {\n children,\n icon,\n endIcon,\n count,\n isSelected,\n size = 'md',\n label,\n href,\n linkProps,\n className,\n type = 'button',\n role,\n testId,\n ...rest\n },\n ref,\n ) => {\n const classNames = cx(\n styles.chip,\n styles[`chip--${size}`],\n isSelected && styles['chip--selected'],\n !children && styles['chip--iconOnly'],\n className,\n );\n\n const content = (\n <>\n {icon && (\n <span className={styles.chip__icon} aria-hidden>\n {icon}\n </span>\n )}\n {children && <span className={styles.chip__label}>{children}</span>}\n {isDefined(count) && <span className={styles.chip__count}>{count}</span>}\n {endIcon && (\n <span className={styles.chip__icon} aria-hidden>\n {endIcon}\n </span>\n )}\n </>\n );\n\n if (href)\n return (\n <HanuiLink\n href={href}\n className={classNames}\n aria-label={children ? undefined : label}\n aria-current={isSelected ? 'page' : undefined}\n title={children ? undefined : label}\n data-testid={testId}\n {...linkProps}\n >\n {content}\n </HanuiLink>\n );\n\n return (\n <button\n ref={ref}\n type={type}\n role={role}\n className={classNames}\n aria-label={children ? undefined : label}\n title={children ? undefined : label}\n data-testid={testId}\n // Tek seçimli grupta radyo semantiği, aksi halde basılı düğme.\n {...(role === 'radio'\n ? { 'aria-checked': Boolean(isSelected) }\n : { 'aria-pressed': Boolean(isSelected) })}\n {...rest}\n >\n {content}\n </button>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Chip, 'Chip')) as typeof Chip;\n","'use client';\n\nimport { type KeyboardEvent, memo, type ReactNode, useRef } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport Chip, { type ChipSize } from '../Chip';\n\nimport styles from './index.module.scss';\n\nexport type ChipOption<T extends string = string> = {\n value: T;\n label: string;\n icon?: ReactNode;\n count?: number;\n isDisabled?: boolean;\n};\n\ntype BaseProps<T extends string> = {\n options: ChipOption<T>[];\n /** Grubun erişilebilir adı (\"Sıralama\", \"Kalite\"). */\n label: string;\n size?: ChipSize;\n /** Taşan çipleri alta sarmak yerine yatay kaydırır (mobil filtre şeridi). */\n isScrollable?: boolean;\n className?: string;\n};\n\ntype SingleProps<T extends string> = BaseProps<T> & {\n isMultiple?: false;\n value: T | null;\n /** Seçili çipe tekrar basılırsa `null` gelir — seçim geri alınabilir. */\n onChange: (value: T | null) => void;\n};\n\ntype MultipleProps<T extends string> = BaseProps<T> & {\n isMultiple: true;\n value: T[];\n onChange: (value: T[]) => void;\n};\n\ntype Props<T extends string> = SingleProps<T> | MultipleProps<T>;\n\n/**\n * Çip grubu — açılır liste yerine tek dokunuşla seçim.\n *\n * <h3>Ne zaman çip grubu, ne zaman açılır liste</h3>\n * Seçenek sayısı azsa (kabaca 7'ye kadar) ve seçenekler ekranda durabiliyorsa\n * çip grubu kullanılır: kullanıcı listeyi <em>açmadan</em> hem seçenekleri hem\n * de hangisinin seçili olduğunu görür — açılır listede bu bilgi iki tıklama\n * arkasındadır. 5–20 seçenek için {@link Select}, 20+ için {@link Combobox}.\n *\n * <h3>Tek seçim radyo grubudur</h3>\n * Tek seçimli grup `role=\"radiogroup\"` alır ve çipler `role=\"radio\"` olur.\n * Görsel olarak radyo düğmesi gibi durmasalar da davranış aynıdır; ekran\n * okuyucu \"3 seçenekten 2.'si\" diye okur. Yalnız `aria-pressed` kullanmak,\n * seçeneklerin birbirini dışladığı bilgisini kaybettiriyordu.\n *\n * <h3>Gezinme tabindex'i dolaşır (roving tabindex)</h3>\n * Radyo grubunda Tab tuşu <strong>gruba</strong> girer, seçenekler arasında ok\n * tuşlarıyla gezilir. Her çipin ayrı ayrı Tab durağı olması, 7 seçenekli bir\n * filtrede klavye kullanıcısını 7 kez Tab'lamaya zorluyordu.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowDown`</td><td>sonraki seçenek; uçlarda DÖNER</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowUp`</td><td>önceki seçenek</td></tr>\n * </table>\n * ÇOKLU seçimde ok tuşu YOKTUR: orada her çip bağımsız bir onay kutusu ve\n * `Tab` ile gezilir — ok tuşuyla gezinmek seçimi de değiştirirdi, oysa\n * radyo grubunun aksine burada gezinmek seçmek demek değil. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst ChipGroup = <T extends string>({\n options,\n label,\n size = 'md',\n isScrollable,\n className,\n ...selection\n}: Props<T>) => {\n const listRef = useRef<HTMLDivElement>(null);\n\n const isSelected = (value: T) =>\n selection.isMultiple ? selection.value.includes(value) : selection.value === value;\n\n const handleSelect = (value: T) => {\n if (selection.isMultiple) {\n const next = selection.value.includes(value)\n ? selection.value.filter(item => item !== value)\n : [...selection.value, value];\n selection.onChange(next);\n return;\n }\n\n // Seçili çipe tekrar basmak seçimi kaldırır: \"hepsi\" seçeneği olmayan\n // filtrelerde kullanıcının geri dönebileceği tek yol bu.\n selection.onChange(selection.value === value ? null : value);\n };\n\n /** Ok tuşlarıyla gezinme; başta/sonda döner (yalnızca tek seçimde). */\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (selection.isMultiple) return;\n\n const offset =\n event.key === 'ArrowRight' || event.key === 'ArrowDown'\n ? 1\n : event.key === 'ArrowLeft' || event.key === 'ArrowUp'\n ? -1\n : 0;\n if (offset === 0) return;\n\n event.preventDefault();\n\n const enabled = options.filter(option => !option.isDisabled);\n if (enabled.length === 0) return;\n\n const currentIndex = enabled.findIndex(option => option.value === selection.value);\n const next = enabled[(currentIndex + offset + enabled.length) % enabled.length];\n\n selection.onChange(next.value);\n listRef.current?.querySelector<HTMLButtonElement>(`[data-chip-value=\"${next.value}\"]`)?.focus();\n };\n\n // Roving tabindex: seçili çip tabbable; hiçbiri seçili değilse ilki.\n const tabbableValue = selection.isMultiple\n ? null\n : (selection.value ?? options.find(option => !option.isDisabled)?.value ?? null);\n\n return (\n <div\n ref={listRef}\n className={cx(styles.group, isScrollable && styles['group--scrollable'], className)}\n role={selection.isMultiple ? 'group' : 'radiogroup'}\n aria-label={label}\n onKeyDown={handleKeyDown}\n >\n {options.map(option => (\n <Chip\n key={option.value}\n size={size}\n icon={option.icon}\n count={option.count}\n isSelected={isSelected(option.value)}\n disabled={option.isDisabled}\n role={selection.isMultiple ? undefined : 'radio'}\n tabIndex={selection.isMultiple || option.value === tabbableValue ? 0 : -1}\n data-chip-value={option.value}\n onClick={() => handleSelect(option.value)}\n >\n {option.label}\n </Chip>\n ))}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(ChipGroup) as typeof ChipGroup;\n","'use client';\n\nimport {\n memo,\n type MouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { ABOVE_MOBILE_MEDIA_QUERY } from '../../constants/breakpoint.constants';\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport {\n captureFocus,\n focusFirstMeaningful,\n isTopModal,\n preventAutoKeyboard,\n pushModal,\n} from '../../helpers/focus.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport useScrollLock from '../../hooks/useScrollLock';\nimport useSheetViewport from '../../hooks/useSheetViewport';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n /** Kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n onClose: () => void;\n children: ReactNode;\n /**\n * Başlığın altında duran, gövde kaydırılırken yerinde kalan şerit —\n * `Combobox`ın arama kutusu gibi.\n */\n toolbar?: ReactNode;\n /** Dipte duran eylem şeridi. */\n footer?: ReactNode;\n /**\n * Panelin <strong>kendiliğinden kapandığı</strong> medya sorgusu.\n *\n * <p>Varsayılan mobil eşiği (`>640`), çünkü seçim kutuları o eşiğin üstünde\n * listeyi yapışkan panelde açıyor. Kendi eşiği daha geniş olan çağıranlar\n * kendi sorgusunu verir; aksi hâlde 800 px'te açılan panel pencere 641 px'i\n * geçtiğinde kapanıyor ya da hiç kapanmıyordu.\n */\n closeAbove?: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Alt sayfa (bottom sheet) — ekranın dibinden yükselen kipsel panel.\n *\n * <h3>Ne zaman</h3>\n * Dar ekranda bir <strong>seçim listesi</strong> açan her kutu bunu kullanır\n * ({@link Select}, {@link Combobox}). Masaüstünde aynı liste tetikleyiciye\n * yapışan bir panelde açılır; telefonda o panel klavye açılınca sıkışıyor ve\n * listenin alt ucu ekranın dışında kalıyordu. Alt sayfa baş parmağın\n * erişebildiği yerde durur, satırları büyüktür ve ekranı tek işe ayırır.\n *\n * <h3>Neden yerel `<dialog>` + portal</h3>\n * `showModal()` odak tuzağını, Escape'i ve arka planın etkileşime kapanmasını\n * tarayıcıdan getirir. Panel <strong>gövdeye taşınır</strong>: seçim kutuları\n * `<label>` içinde durabiliyor ve etiketin içindeki tıklama etiketlenen öğeye\n * yönleniyor — seçeneklere basmak aynı anda tetikleyiciyi de tetikliyordu.\n *\n * <h3>Yalnızca açıkken çizilir</h3>\n * Bileşen `isOpen` almaz: çağıran taraf açıkken <em>render eder</em>, kapatmak\n * için kaldırır. Kapalı bir `<dialog>`u CSS ile gizlemeye çalışmak, sınıf\n * seçicisinin tarayıcı kuralını yenmesi yüzünden paneli ekranın dibinde asılı\n * bırakıyordu.\n *\n * <h3>Kırılma noktası aşılırsa kapanır</h3>\n * `showModal()` sayfanın geri kalanını panel çizilsin ya da çizilmesin inert\n * bırakır; pencere büyütülüp panel gizlenseydi sayfa tıklanamaz kalırdı.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Escape`</td><td>kapatır (`cancel` olayı çağırana bildirilir)</td></tr>\n * <tr><td>`Tab`</td><td>odak panelin içinde döner</td></tr>\n * </table>\n * Açılışta odak metin alanına DÜŞMEZ: `showModal()` odağı ilk odaklanabilir\n * öğeye taşıyor ve o öğe bir metin alanı olduğunda telefonda ekran klavyesi\n * kullanıcı istemeden açılıyordu (bkz. `helpers/focus.helper`). Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst BottomSheet = ({\n title,\n closeLabel,\n onClose,\n children,\n toolbar,\n footer,\n closeAbove = ABOVE_MOBILE_MEDIA_QUERY,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const titleId = useId();\n /* Yigindaki yerimiz: Escape yalnizca EN USTTEKI panelde islenir. */\n const tokenRef = useRef<symbol | null>(null);\n\n /* Panel GORUNEN alana yaslanir: klavye ve adres cubugu altinda kalmaz. */\n useSheetViewport();\n\n /* Arka plan kaydirmasi kilitlenir: `showModal()` arka plani etkilesime\n kapatir ama kaydirmayi her tarayicida engellemiyor — kullanici alt sayfayi\n kaydirdigini sanirken arkadaki listeyi kaydiriyordu. Kilit SAYACLI: bu\n panel neredeyse her zaman baska bir kipsel yuzeyin (secim kutusu, filtre\n paneli) ICINDE aciliyor ve ilki kapaninca kilit erken acilmamali. */\n useScrollLock();\n\n /*\n * ODAK GERI DONUSU ve KIPSEL YIGIN.\n *\n * Panel `isOpen` almiyor — cagiran acikken cizip kapatmak icin kaldiriyor\n * (bkz. yukaridaki not). Yani \"acilis\" MONTAJ, \"kapanis\" SOKUM: ikisi de\n * bos bagimlilikli tek bir etkiye sigiyor.\n */\n useEffect(() => {\n const restoreFocus = captureFocus();\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, []);\n\n useEffect(() => {\n const query = window.matchMedia(closeAbove);\n query.addEventListener('change', onClose);\n return () => query.removeEventListener('change', onClose);\n }, [closeAbove, onClose]);\n\n const setDialogRef = useCallback((node: HTMLDialogElement | null) => {\n if (!node || node.open) return;\n\n node.showModal();\n\n /* Odak KAPATMA DUGMESINE degil ilk anlamli ogeye: ekran okuyucu paneli\n \"Kapat, dugme\" diye aciyordu — kullanicinin duydugu ilk sey, panelin ne\n oldugu degil ondan nasil kacilacagi. */\n focusFirstMeaningful(node, `.${styles.sheet__header} button`);\n\n /* `showModal()` odagi panelin ILK odaklanabilir ogesine tasiyor; o oge bir\n metin alani oldugunda telefonda klavye kendiliginden aciliyordu\n (bkz. `helpers/focus.helper`). */\n preventAutoKeyboard(node);\n }, []);\n\n const handleBackdropClick = useCallback(\n (event: MouseEvent<HTMLDialogElement>) => {\n // Hedef dialog'un KENDISI ise perdeye tiklanmistir; icerik degil.\n if (event.target === event.currentTarget) onClose();\n },\n [onClose],\n );\n\n /* Portal `document.body`ye baglaniyor; sunucuda `document` yok. */\n if (!isClient()) return null;\n\n return createPortal(\n <dialog\n ref={setDialogRef}\n className={cx(styles.sheet, className)}\n aria-labelledby={titleId}\n data-testid={testId}\n /* Escape'i tarayici isler ama React durumu haberdar olmuyor:\n yakalanmazsa panel kapanip durum acik kaliyor ve kutu bir daha\n acilmiyordu. */\n onCancel={event => {\n event.preventDefault();\n /* Yalnizca EN USTTEKI panel kapanir: ust uste iki kipsel yuzeyde tek\n bir Escape ikisini birden kapatiyordu. */\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n onClose();\n }}\n onClick={handleBackdropClick}\n >\n <header className={styles.sheet__header}>\n <h2 id={titleId} className={styles.sheet__title}>\n {title}\n </h2>\n <IconButton\n icon={<XLg aria-hidden />}\n label={resolveLabel('BottomSheet.closeLabel', closeLabel, labels?.close)}\n variant=\"ghost\"\n size=\"sm\"\n onClick={onClose}\n />\n </header>\n\n {toolbar && <div className={styles.sheet__toolbar}>{toolbar}</div>}\n\n <div className={styles.sheet__body}>{children}</div>\n\n {footer && <div className={styles.sheet__footer}>{footer}</div>}\n </dialog>,\n document.body,\n );\n};\n\nexport default /*#__PURE__*/ memo(BottomSheet);\n","'use client';\n\nimport {\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { CaretDownFill, CheckLg, Search, XLg } from 'react-bootstrap-icons';\n\nimport { ABOVE_MOBILE_MEDIA_QUERY } from '../../constants/breakpoint.constants';\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { matchesSearch } from '../../helpers/text.helper';\nimport useListboxNavigation from '../../hooks/useListboxNavigation';\nimport { useHanui } from '../../theme/context';\nimport BottomSheet from '../BottomSheet';\nimport Spinner from '../Spinner';\n\nimport styles from './index.module.scss';\n\nexport type ComboboxOption<T extends string = string> = {\n value: T;\n label: string;\n /** İkincil satır: kod, numara, ayırt edici bilgi. */\n description?: string;\n isDisabled?: boolean;\n};\n\n/**\n * Bileşenin çizdiği metinler.\n *\n * <p>`placeholder` dışındaki her şey `HanuiProvider labels.combobox`ten de\n * gelebilir; buradaki değer kazanır. `placeholder` ALANI adlandırır\n * (\"Şehir seçin\", \"Marka seçin\") ve her çağrı yerinde farklıdır — o yüzden\n * zorunlu kaldı.\n */\nexport type ComboboxLabels = {\n /** Seçim yokken tetikleyicide ve alt sayfa başlığında görünen metin. */\n placeholder: string;\n /** Arama kutusunun yer tutucusu ve erişilebilir adı. */\n searchPlaceholder?: string;\n /** Liste boşken gösterilen metin. */\n emptyMessage?: string;\n /** Arama sürerken liste yerine gösterilen metin. */\n loadingMessage?: string;\n /** Seçimi kaldıran çarpının erişilebilir adı. */\n clearLabel?: string;\n /** Alt sayfanın kapatma düğmesinin erişilebilir adı. */\n closeLabel?: string;\n};\n\ntype Props<T extends string> = {\n options: ComboboxOption<T>[];\n value: T | null;\n onChange: (value: T | null) => void;\n labels: ComboboxLabels;\n /**\n * Verilirse arama <strong>sunucuda</strong> yapılır: bileşen listeyi kendisi\n * filtrelemez, yazılanı 300 ms bekleyip buraya bildirir. Verilmezse\n * filtreleme yerelde ve aksan duyarsız yapılır.\n */\n onSearch?: (query: string) => void;\n isLoading?: boolean;\n isDisabled?: boolean;\n /** Seçimi kaldıran çarpı düğmesi gösterilir. */\n isClearable?: boolean;\n /**\n * Arama kutusu GİZLENİR.\n *\n * <p>Az sayıda, sabit seçenekli listelerde arama bir işe yaramıyor: altı\n * satırı taramak yazmaktan hızlı ve kutu açılışta odağı çalıp mobilde\n * klavyeyi açıyordu. Ok tuşlarıyla gezinme ve `Escape` yine çalışır.\n */\n isSearchHidden?: boolean;\n /** Tetikleyicinin solundaki ikon. */\n icon?: ReactNode;\n id?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Aranabilir seçim kutusu.\n *\n * <h3>Neden yerel `<select>` değil</h3>\n * Yerel açılır liste 20 seçeneğe kadar iyidir. Binlerce seçenekli bir listede\n * kullanıcı harf harf yazarak (ve yalnızca baştan eşleşerek) arıyor, mobilde\n * ise metrelerce süren bir tekerlek çeviriyor. Aranabilir liste, seçeneği\n * <em>yazarak</em> bulmayı mümkün kılar.\n *\n * <h3>Arama kutusu listenin İÇİNDE</h3>\n * Arama alanını listenin dışına koymak kullanıcıya iki ayrı alan gösteriyor\n * ve hangisinin seçimi belirlediği anlaşılmıyordu. Tek tetikleyici, tek\n * panel: masaüstünde panel açılınca odak doğrudan arama kutusuna gider,\n * yazılır, Enter'a basılır. Dar ekranda odak VERİLMEZ — bkz. aşağıdaki not.\n *\n * <h3>Yerel mi sunucu araması mı</h3>\n * `onSearch` verilmezse bileşen elindeki listeyi aksan duyarsız filtreler.\n * Verilirse filtrelemeyi <em>yapmaz</em> — sunucudan gelen liste zaten\n * filtrelenmiştir; ikinci kez filtrelemek sunucunun daha akıllı eşleşmesini\n * (eş anlamlı, kod eşleşmesi) bozardı.\n *\n * <h3>Seçilenin etiketi listeden düşse de korunur</h3>\n * Sunucu aramasında kullanıcı yeni bir arama yaptığında seçili kayıt gelen\n * listede olmayabilir. Etiket son bilinen değerden hatırlanır; aksi hâlde\n * tetikleyici seçim varken yer tutucuya dönüyordu.\n *\n * <h3>Dar ekranda arama kutusu ODAKLANMAZ</h3>\n * Alt sayfa açılırken kutuya odaklanmak ekran klavyesini kullanıcı istemeden\n * açıyordu: panel yarı yüksekliğe sıkışıyor, liste birkaç satıra iniyor ve\n * seçim yapmak için önce klavyeyi kapatmak gerekiyordu. Telefonda liste\n * taranarak kullanılır; yazmak isteyen kutuya kendisi dokunur.\n *\n * <h3>ARIA</h3>\n * Tetikleyici `aria-haspopup=\"listbox\"`, panel içindeki arama alanı\n * `role=\"combobox\"` + `aria-activedescendant`. Masaüstünde odak arama\n * kutusundan ayrılmaz; ok tuşları yalnızca <em>etkin</em> seçeneği değiştirir.\n * Odağı seçeneklere taşımak, yazmaya devam etmeyi imkânsız kılıyordu.\n *\n * <h3>Klavye (APG: combobox with listbox popup)</h3>\n * <table>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin seçenek bir alt/üst; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son seçenek</td></tr>\n * <tr><td>`Enter`</td><td>etkin seçeneği seçer, paneli kapatır</td></tr>\n * <tr><td>`Escape`</td><td>kapatır, odak tetikleyiciye döner</td></tr>\n * <tr><td>`Tab`</td><td>kapatır, gezinme sürer</td></tr>\n * <tr><td>yazmak</td><td>filtreler ve etkin seçeneği başa çeker</td></tr>\n * </table>\n * Nöbetçi: `components/__tests__/keyboard.test.tsx`.\n */\nconst Combobox = <T extends string>({\n options,\n value,\n onChange,\n labels,\n isSearchHidden,\n onSearch,\n isLoading,\n isDisabled,\n isClearable,\n icon,\n id,\n className,\n testId,\n 'aria-describedby': describedBy,\n 'aria-invalid': isInvalid,\n}: Props<T>) => {\n const { labels: config } = useHanui();\n\n /*\n * Metinler TEMBEL cozulur: cizilmeyen bir ogenin metnini istemek yanlis\n * alarm uretiyordu — `isSearchHidden` iken arama kutusu hic yok ama toplu\n * cozumleme yine de \"eksik metin\" diye uyariyordu.\n */\n const text = {\n get search() {\n return resolveLabel(\n 'Combobox.searchPlaceholder',\n labels.searchPlaceholder,\n config?.combobox?.searchPlaceholder,\n );\n },\n get empty() {\n return resolveLabel(\n 'Combobox.emptyMessage',\n labels.emptyMessage,\n config?.combobox?.emptyMessage,\n );\n },\n get loading() {\n return resolveLabel(\n 'Combobox.loadingMessage',\n labels.loadingMessage,\n config?.combobox?.loadingMessage,\n );\n },\n get clear() {\n return resolveLabel('Combobox.clearLabel', labels.clearLabel, config?.combobox?.clearLabel);\n },\n };\n\n const generatedId = useId();\n const baseId = id ?? generatedId;\n const listboxId = `${baseId}-listbox`;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n /*\n * Panel NEREDE acilir: masaustunde tetikleyicinin altinda, dar ekranda\n * ekranin dibinde bir alt sayfada. Karar ACILIRKEN verilir — sunucuda ekran\n * genisligi bilinmiyor, ilk boyamada verilecek karar yanlis olurdu.\n */\n const [openMode, setOpenMode] = useState<'popover' | 'sheet' | null>(null);\n const isOpen = openMode !== null;\n const [query, setQuery] = useState('');\n\n // Sunucu araması sırasında seçili kayıt listeden düşebilir; etiketi\n // hatırlarız ki tetikleyici yer tutucuya dönmesin.\n const [cachedLabel, setCachedLabel] = useState<string | null>(null);\n\n const visibleOptions = useMemo(() => {\n // Sunucu araması: gelen liste zaten filtrelidir, tekrar filtrelenmez.\n if (onSearch || query.trim() === '') return options;\n\n const needle = query.trim();\n return options.filter(\n option =>\n matchesSearch(option.label, needle) ||\n (option.description ? matchesSearch(option.description, needle) : false),\n );\n }, [options, query, onSearch]);\n\n const selectedOption = options.find(option => option.value === value) ?? null;\n\n useEffect(() => {\n if (selectedOption) setCachedLabel(selectedOption.label);\n else if (value === null) setCachedLabel(null);\n }, [selectedOption, value]);\n\n const displayLabel = selectedOption?.label ?? cachedLabel;\n\n /*\n * `onSearch` her render'da yeni bir kapanis olabilir; bagimliliga koymak\n * sonsuz dongu uretir. Referansta tutulup etkiden cikarilir.\n */\n const searchRef = useRef(onSearch);\n searchRef.current = onSearch;\n\n useEffect(() => {\n if (!isOpen || !searchRef.current) return;\n\n // Her tuşta istek atmamak için 300 ms beklenir.\n const timer = window.setTimeout(() => searchRef.current?.(query.trim()), 300);\n return () => window.clearTimeout(timer);\n }, [query, isOpen]);\n\n const close = useCallback(() => {\n setOpenMode(null);\n setQuery('');\n }, []);\n\n const open = useCallback(() => {\n if (isDisabled) return;\n setOpenMode(window.matchMedia(ABOVE_MOBILE_MEDIA_QUERY).matches ? 'popover' : 'sheet');\n /* Panel acilinca etkin secenek SECILI olan olur (kancanin `initialIndex`i);\n kullanici listeyi bastan taramak zorunda kalmaz. */\n setQuery('');\n }, [isDisabled]);\n\n /*\n * Disari tiklamada kapanir. `mousedown` kullanilir: `click` beklerken\n * kullanici surukleyerek secim yaparsa panel kapanmiyordu.\n *\n * YALNIZCA masaustu panelinde. Alt sayfa govdeye tasindigi icin `rootRef`\n * onu ICERMIYOR: dinleyici acik kalsaydi panelin icindeki her dokunus\n * \"disari tiklama\" sayilip sayfayi kapatirdi. Orada bu isi perde yapiyor.\n */\n useEffect(() => {\n if (openMode !== 'popover') return;\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) close();\n };\n\n document.addEventListener('mousedown', handlePointerDown);\n return () => document.removeEventListener('mousedown', handlePointerDown);\n }, [openMode, close]);\n\n /*\n * Odak arama kutusuna YALNIZCA masaustu panelinde verilir.\n *\n * Alt sayfada (dar ekran) odaklamak, kullanici yazmak istemedigi halde\n * ekran klavyesini aciyordu: panel yari yuksekluge sikisiyor, uzun listeden\n * ucu besi goruntude kaliyor ve secim yapmak icin once klavyeyi kapatmak\n * gerekiyordu. Masaustunde ekran klavyesi YOK; oradaki odak yazarak\n * aramanin ve ok tuslariyla gezinmenin tek dayanagi.\n *\n * `preventScroll` duruyor: iOS odaklanan kutuyu gorunur kilmak icin SAYFAYI\n * kaydiriyor ve arkadaki liste baska bir yere atliyordu.\n */\n useEffect(() => {\n if (openMode === 'popover') inputRef.current?.focus({ preventScroll: true });\n }, [openMode]);\n\n const selectOption = (option: ComboboxOption<T>) => {\n if (option.isDisabled) return;\n setCachedLabel(option.label);\n onChange(option.value);\n close();\n };\n\n /*\n * Kapaninca odak TETIKLEYICIYE doner.\n *\n * Odagi `close()`in hemen ardindan vermek alt sayfada ise yaramiyordu:\n * panel o an hala kipsel ve `showModal()` disaridaki her ogeyi inert\n * birakiyor — `focus()` sessizce hicbir sey yapmiyor, panel kalkinca da\n * odak `<body>`ye dusuyordu. Kullanici secim yaptiktan sonra sayfanin en\n * basina donuyordu.\n */\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (wasOpenRef.current && !isOpen) triggerRef.current?.focus();\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n /*\n * KLAVYE MODELI `useListboxNavigation`da — `Select`le AYNI kanca.\n *\n * Alti davranis (uclarda donme, `Home`/`End`, secme, `Escape`, `Tab` ile\n * kapatip gezinmeyi surdurme, etkin secenegi gorunur tutma) iki bilesende\n * KOPYA koddu ve ayrisma SESSIZDI: her bilesenin kendi testi vardi ve her\n * biri kendi davranisini dogruluyordu.\n *\n * `Space` BURADA secmez (`hasSpaceSelect` verilmiyor): arama kutusunda\n * bosluk bir KARAKTER ve secime cevrilmesi \"fren balatasi\" yazmayi imkansiz\n * kilardi. `Select`te oyle bir kutu yok ve orada da tetiklenmiyor.\n */\n const { activeIndex, setActiveIndex, listRef, handleKeyDown } =\n useListboxNavigation<HTMLUListElement>({\n count: visibleOptions.length,\n isOpen,\n initialIndex: Math.max(\n options.findIndex(option => option.value === value),\n 0,\n ),\n onSelect: index => {\n const option = visibleOptions[index];\n if (option) selectOption(option);\n },\n /* Odagi geri vermek kapanisi izleyen etkinin isi (bkz. `wasOpenRef`). */\n onClose: close,\n });\n\n const handleInputKeyDown = handleKeyDown;\n\n const clearSelection = () => {\n onChange(null);\n setCachedLabel(null);\n };\n\n /*\n * Arama ve liste IKI YERDE ayni: masaustu panelinde ve alt sayfada. Ayri\n * ayri yazilsalardi biri guncellenip digeri unutulurdu.\n */\n const search = isSearchHidden ? null : (\n <div className={styles.combobox__search}>\n <Search aria-hidden className={styles.combobox__searchIcon} />\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n className={styles.combobox__searchInput}\n value={query}\n placeholder={text.search}\n autoComplete=\"off\"\n aria-autocomplete=\"list\"\n aria-expanded\n aria-controls={listboxId}\n aria-activedescendant={\n visibleOptions[activeIndex] ? `${baseId}-option-${activeIndex}` : undefined\n }\n aria-label={text.search}\n onChange={event => {\n setQuery(event.target.value);\n setActiveIndex(0);\n }}\n onKeyDown={handleInputKeyDown}\n />\n {isLoading && <Spinner size=\"sm\" label=\"\" />}\n </div>\n );\n\n const renderList = (isSheet: boolean) => (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n className={cx(styles.combobox__list, isSheet && styles['combobox__list--sheet'])}\n >\n {visibleOptions.map((option, index) => {\n const isActive = index === activeIndex;\n const isChosen = option.value === value;\n\n return (\n <li key={option.value}>\n <div\n id={`${baseId}-option-${index}`}\n role=\"option\"\n data-index={index}\n aria-selected={isChosen}\n aria-disabled={option.isDisabled}\n className={cx(\n styles.combobox__option,\n isActive && styles['combobox__option--active'],\n isChosen && styles['combobox__option--selected'],\n option.isDisabled && styles['combobox__option--disabled'],\n )}\n // Fare imleci seçeneğin üstündeyken etkin seçenek de oraya\n // taşınır; iki ayrı vurgu kullanıcıyı şaşırtıyordu.\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectOption(option)}\n >\n <span className={styles.combobox__optionText}>\n <span className={styles.combobox__optionLabel}>{option.label}</span>\n {option.description && (\n <span className={styles.combobox__optionDescription}>{option.description}</span>\n )}\n </span>\n\n {isChosen && <CheckLg aria-hidden className={styles.combobox__check} />}\n </div>\n </li>\n );\n })}\n\n {visibleOptions.length === 0 && (\n <li className={styles.combobox__empty}>{isLoading ? text.loading : text.empty}</li>\n )}\n </ul>\n );\n\n return (\n <div ref={rootRef} className={cx(styles.combobox, className)} data-testid={testId}>\n <button\n ref={triggerRef}\n id={baseId}\n type=\"button\"\n className={cx(\n styles.combobox__trigger,\n !displayLabel && styles['combobox__trigger--empty'],\n isOpen && styles['combobox__trigger--open'],\n isInvalid && styles['combobox__trigger--invalid'],\n isClearable && displayLabel && !isDisabled && styles['combobox__trigger--clearable'],\n )}\n disabled={isDisabled}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-label={labels.placeholder}\n /*\n Hata `aria-invalid` ile DEGIL `aria-describedby` ile duyurulur:\n `aria-invalid`, `role=\"button\"` uzerinde tanimsizdir ve ekran\n okuyucular onu yok sayar. `Field` hata metnini zaten `role=\"alert\"`\n ile bagliyor; buradaki gorev yalnizca gorsel.\n */\n aria-describedby={describedBy}\n onClick={() => (isOpen ? close() : open())}\n >\n {icon && (\n <span className={styles.combobox__leadingIcon} aria-hidden>\n {icon}\n </span>\n )}\n\n <span className={styles.combobox__value}>{displayLabel ?? labels.placeholder}</span>\n\n {/* Dolu caret — gerekcesi `Select` ile ayni. */}\n <CaretDownFill\n aria-hidden\n className={cx(styles.combobox__chevron, isOpen && styles['combobox__chevron--open'])}\n />\n </button>\n\n {/*\n TEMİZLEME DÜĞMESİ TETİKLEYİCİNİN İÇİNDE DEĞİL, KARDEŞİ.\n\n Önce `<button>`ın içinde `role=\"button\" tabIndex={0}` taşıyan bir\n `<span>` olarak duruyordu; dosyadaki yorum \"DOM'da kardeş\" diyordu ama\n kod öyle değildi. Eksen taraması bunu `nested-interactive` olarak\n bildirdi ve sonucu somut: iç içe etkileşimli öğede ekran okuyucular\n yalnızca dıştaki düğmeyi duyurur, içteki çarpıya klavyeyle ulaşılsa bile\n adı okunmaz — yani \"seçimi temizle\" eylemi destek teknolojisi\n kullanıcısı için YOK. Kardeş olarak çizilip tetikleyicinin üzerine\n konumlandırılıyor; görsel yer aynı, ağaçtaki yeri doğru.\n */}\n {isClearable && displayLabel && !isDisabled && (\n <button\n type=\"button\"\n className={styles.combobox__clear}\n aria-label={text.clear}\n onClick={clearSelection}\n >\n <XLg aria-hidden />\n </button>\n )}\n\n {/* Masaüstü: tetikleyiciye yapışan panel. */}\n {openMode === 'popover' && (\n <div className={styles.combobox__panel}>\n {search}\n {renderList(false)}\n </div>\n )}\n\n {/*\n Dar ekran: alt sayfa. Yapışkan panel telefonda klavye açılınca sıkışıyor\n ve uzun listenin alt ucu ekranın dışında kalıyordu; arama kutusu da\n tetikleyiciyle klavyenin arasına hapsoluyordu. Arama `toolbar`\n yuvasında: başlığın altında sabit kalır, liste altında kayar.\n */}\n {openMode === 'sheet' && (\n <BottomSheet\n title={labels.placeholder}\n closeLabel={labels.closeLabel ?? config?.close}\n onClose={close}\n toolbar={search ?? undefined}\n >\n {renderList(true)}\n </BottomSheet>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(Combobox) as typeof Combobox;\n","'use client';\n\nimport { type KeyboardEvent, memo, type ReactNode, useRef } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\nexport type SegmentOption<T extends string = string> = {\n value: T;\n label: string;\n /** Yalnızca ikon gösterilecekse `label` erişilebilir ad olarak kalır. */\n icon?: ReactNode;\n isDisabled?: boolean;\n};\n\ntype Props<T extends string> = {\n options: SegmentOption<T>[];\n value: T;\n onChange: (value: T) => void;\n /** Grubun erişilebilir adı (\"Görünüm\"). ZORUNLU. */\n label: string;\n /** Etiketler gizlenir, yalnızca ikon çizilir. `label` yine okunur. */\n isIconOnly?: boolean;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Bölmeli denetim — <strong>görünüm</strong> değiştirme.\n *\n * <h3>{@link ChipGroup} ile farkı: filtre mi görünüm mü</h3>\n * İkisi de `radiogroup` ve ikisi de tek seçim; ayrım seçilen şeyin ne\n * olduğunda:\n *\n * <ul>\n * <li>`ChipGroup` bir FİLTRE. Seçim listeyi daraltıyor, seçenek sayısı\n * değişken ve \"hiçbiri\" geçerli bir durum — çipe ikinci kez basmak\n * seçimi kaldırıyor.</li>\n * <li><b>`SegmentedControl` bir GÖRÜNÜM anahtarı.</b> Liste/ızgara,\n * aylık/yıllık, gelen/giden. Seçenek sayısı 2-4 ve SABİT; <strong>seçili\n * durum her zaman tektir</strong> — \"hiçbiri\" diye bir hâl yok, çünkü\n * ekranda bir şey çizilmek zorunda.</li>\n * </ul>\n *\n * <p>Bu yüzden seçili öğeye ikinci kez basmak hiçbir şey yapmaz; `ChipGroup`ta\n * aynı hareket seçimi kaldırıyor. Aynı bileşeni iki iş için kullanmak, bu\n * davranış farkını kaybetmek olurdu.\n *\n * <h3>Neden `Tabs` değil</h3>\n * `Tabs` bir PANEL değiştirir ve `aria-controls` ile ona bağlanır; bölmeli\n * denetim aynı içeriğin başka bir SUNUMUNU seçiyor — gösterilen veri aynı.\n * Sekme olarak sunmak ekran okuyucuya var olmayan bir panel vaat ediyordu.\n *\n * <h3>Klavye (APG: radio group)</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowDown`</td><td>sonraki seçenek; uçlarda DÖNER</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowUp`</td><td>önceki seçenek</td></tr>\n * <tr><td>`Tab`</td><td>grubu TEK durak olarak geçer (dönen `tabindex`)</td></tr>\n * </table>\n */\nconst SegmentedControl = <T extends string>({\n options,\n value,\n onChange,\n label,\n isIconOnly,\n size = 'md',\n className,\n testId,\n}: Props<T>) => {\n const listRef = useRef<HTMLDivElement>(null);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const offset =\n event.key === 'ArrowRight' || event.key === 'ArrowDown'\n ? 1\n : event.key === 'ArrowLeft' || event.key === 'ArrowUp'\n ? -1\n : 0;\n\n if (offset === 0) return;\n event.preventDefault();\n\n const enabled = options.filter(option => !option.isDisabled);\n if (enabled.length === 0) return;\n\n const current = enabled.findIndex(option => option.value === value);\n const next = enabled[(current + offset + enabled.length) % enabled.length];\n\n onChange(next.value);\n listRef.current\n ?.querySelector<HTMLButtonElement>(`[data-value=\"${next.value}\"]`)\n ?.focus({ preventScroll: true });\n };\n\n return (\n <div\n ref={listRef}\n role=\"radiogroup\"\n aria-label={label}\n className={cx(styles.segmented, styles[`segmented--${size}`], className)}\n data-testid={testId}\n onKeyDown={handleKeyDown}\n >\n {options.map(option => {\n const isSelected = option.value === value;\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n aria-label={isIconOnly ? option.label : undefined}\n data-value={option.value}\n disabled={option.isDisabled}\n /* Donen `tabindex`: grup Tab sirasinda TEK durak. Dort segmentin\n her biri durak olsaydi klavye kullanicisi icerige ulasmak icin\n dort kez Tab'liyordu. */\n tabIndex={isSelected ? 0 : -1}\n className={cx(\n styles.segmented__item,\n isSelected && styles['segmented__item--selected'],\n )}\n /*\n * Secili ogeye ikinci kez basmak HICBIR SEY yapmaz: gorunum\n * anahtarinda \"hicbiri\" diye bir hal yok. `ChipGroup`ta ayni\n * hareket secimi kaldiriyor ve iki bileseni ayiran sey tam olarak\n * bu.\n */\n onClick={() => !isSelected && onChange(option.value)}\n >\n {option.icon && (\n <span className={styles.segmented__icon} aria-hidden>\n {option.icon}\n </span>\n )}\n {!isIconOnly && <span className={styles.segmented__label}>{option.label}</span>}\n </button>\n );\n })}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(SegmentedControl, 'SegmentedControl'),\n) as typeof SegmentedControl;\n","'use client';\n\nimport {\n type KeyboardEvent,\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { CaretDownFill, CheckLg } from 'react-bootstrap-icons';\n\nimport useListboxNavigation from '../../hooks/useListboxNavigation';\n\nimport { ABOVE_MOBILE_MEDIA_QUERY } from '../../constants/breakpoint.constants';\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport BottomSheet from '../BottomSheet';\n\nimport styles from './index.module.scss';\n\nexport type SelectOption<T extends string = string> = {\n value: T;\n label: string;\n isDisabled?: boolean;\n};\n\n/**\n * Seçenek listesinin nerede açıldığı.\n *\n * <p>`popover` tetikleyicinin altında, `sheet` ekranın dibinde. Karar\n * <strong>açılırken</strong> verilir; sunucuda ekran genişliği bilinmediği\n * için ilk boyamada verilecek her karar yanlış olurdu.\n */\ntype OpenMode = 'popover' | 'sheet';\n\ntype Props<T extends string> = {\n options: SelectOption<T>[];\n value: T;\n onChange: (value: T) => void;\n /**\n * Alanın adı. İki işi birden yapar: alt sayfanın başlığı olur ve\n * tetikleyicinin <strong>erişilebilir adı</strong>dır.\n *\n * <p>Tetikleyici bir `<button>` ve düğmenin adı HTML-AAM'e göre\n * `<label>`den GELMEZ — görünür bir etiket olsa bile ekran okuyucu yalnızca\n * seçili değeri okur (\"En yeni, düğme\") ve neyi seçtiğini söylemez.\n */\n label: string;\n /** Seçim yokken tetikleyicide görünen metin. Verilmezse `labels.selectPlaceholder`. */\n placeholder?: string;\n /** Alt sayfanın kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n /** Tetikleyicinin solundaki ikon. */\n icon?: ReactNode;\n /** `sm` yoğun şeritler içindir (araç çubuğu); varsayılan form ölçüsü `md`. */\n size?: 'sm' | 'md';\n /**\n * Panelin hangi kenardan hizalanacağı.\n *\n * <p>Şeridin sağ ucundaki bir tetikleyicide `start` hizalama paneli sağa\n * doğru taşırıyordu; `end` panelin sağ kenarını tetikleyiciye yaslar.\n */\n align?: 'start' | 'end';\n isDisabled?: boolean;\n id?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Seçim kutusu.\n *\n * <h3>Yerel `<select>` KULLANILMAZ</h3>\n * Yerel açılır liste her tarayıcıda başka türlü çiziliyor, seçeneklerine tek\n * bir stil verilemiyor (seçili değeri işaretlemek, ikon koymak, satırı\n * yükseltmek yok) ve mobilde ekranın ortasında beliren tekerlek uygulamanın\n * geri kalanına hiç benzemiyordu. Kutu baştan sona bizim: masaüstünde\n * tetikleyicinin altında bir panel, mobilde ekranın dibinden yükselen bir\n * <strong>alt sayfa</strong> açar.\n *\n * <p>Bu, \"yerel öğe taklit öğeden iyidir\" kuralının BİLİNÇLİ tek istisnası:\n * bedeli (odak yönetimi, ok tuşları, `aria-activedescendant`) bir kez ödenip\n * tek bileşene kapatıldı.\n *\n * <h3>Klavye — odak TEK yerde</h3>\n * Panel açıkken odak tetikleyicide kalır, alt sayfada ise listenin kendisine\n * geçer; iki durumda da etkin seçenek `aria-activedescendant` ile bildirilir.\n * Seçenekleri tek tek odaklanabilir yapmak, aynı bileşende iki ayrı klavye\n * modeli demekti (APG: listbox + activedescendant).\n *\n * <table>\n * <tr><td>`ArrowDown`/`ArrowUp`/`Enter`/`Space` (kapalıyken)</td><td>paneli açar</td></tr>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin seçenek bir alt/üst; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son seçenek</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>etkin seçeneği seçer</td></tr>\n * <tr><td>`Escape`</td><td>seçim yapmadan kapatır, odak tetikleyicide</td></tr>\n * <tr><td>`Tab`</td><td>kapatır, gezinme sürer</td></tr>\n * </table>\n * Etkin seçenek açılışta SEÇİLİ olandan başlar. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n *\n * <h3>20+ seçenek varsa bu bileşen DEĞİL</h3>\n * Aramasız bir liste 20 satırdan sonra taranamaz hâle gelir; orada\n * {@link Combobox} kullanılır.\n */\nconst Select = <T extends string>({\n options,\n value,\n onChange,\n label,\n placeholder,\n closeLabel,\n icon,\n size = 'md',\n align = 'start',\n isDisabled,\n id,\n className,\n testId,\n 'aria-describedby': describedBy,\n 'aria-invalid': isInvalid,\n}: Props<T>) => {\n const { labels } = useHanui();\n const emptyText = resolveLabel('Select.placeholder', placeholder, labels?.selectPlaceholder);\n const generatedId = useId();\n const baseId = id ?? generatedId;\n const listboxId = `${baseId}-listbox`;\n const optionId = (index: number) => `${baseId}-option-${index}`;\n\n const rootRef = useRef<HTMLSpanElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const [openMode, setOpenMode] = useState<OpenMode | null>(null);\n\n const isOpen = openMode !== null;\n const selectedIndex = options.findIndex(option => option.value === value);\n const selectedOption = selectedIndex >= 0 ? options[selectedIndex] : null;\n\n const close = useCallback(() => setOpenMode(null), []);\n\n const open = useCallback(() => {\n if (isDisabled || options.length === 0) return;\n\n /* Etkin secenek SECILI olandan baslar (kancanin `initialIndex`i);\n kullanici listeyi bastan taramaz. */\n setOpenMode(window.matchMedia(ABOVE_MOBILE_MEDIA_QUERY).matches ? 'popover' : 'sheet');\n }, [isDisabled, options.length]);\n\n const selectOption = (option: SelectOption<T>) => {\n if (option.isDisabled) return;\n onChange(option.value);\n close();\n };\n\n /*\n * Kapaninca odak TETIKLEYICIYE doner.\n *\n * Odagi `selectOption` icinde geri vermek ise yaramiyor: alt sayfa ayni\n * commit'te DOM'dan kalkiyor ve odaklanan dugme sokulunce odak `<body>`ye\n * dusuyordu — klavye kullanicisi secim yaptiktan sonra sayfanin en basina\n * donuyordu.\n */\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (wasOpenRef.current && !isOpen) triggerRef.current?.focus();\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n /* Disari tiklamada panel kapanir. Alt sayfada bu is perdenin. */\n useEffect(() => {\n if (openMode !== 'popover') return;\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) close();\n };\n\n document.addEventListener('mousedown', handlePointerDown);\n return () => document.removeEventListener('mousedown', handlePointerDown);\n }, [openMode, close]);\n\n\n /*\n * KLAVYE MODELI `useListboxNavigation`da — `Combobox`la AYNI kanca.\n *\n * Alti davranis (uclarda donme, `Home`/`End`, secme, `Escape`, `Tab` ile\n * kapatip gezinmeyi surdurme, etkin secenegi gorunur tutma) iki bilesende\n * KOPYA koddu ve ayrisma sessizdi: her bilesenin kendi testi vardi ve her\n * biri kendi davranisini dogruluyordu.\n */\n const { activeIndex, setActiveIndex, listRef, handleKeyDown } =\n useListboxNavigation<HTMLUListElement>({\n count: options.length,\n isOpen,\n initialIndex: selectedIndex >= 0 ? selectedIndex : 0,\n onSelect: index => {\n const option = options[index];\n if (option) selectOption(option);\n },\n onClose: close,\n });\n\n /*\n * Alt sayfada odak listenin kendisine gecer: ok tuslari orada isler.\n *\n * `preventScroll` ZORUNLU: odaklanan oge ust katmanda duran sabit bir\n * panelin icinde ve iOS onu \"gorunur kilmak\" icin sayfayi kaydiriyor —\n * panel oldugu yerde durdugu icin kaydirmanin tek etkisi, arkadaki sayfanin\n * kullanicinin bakmadigi bir yere atlamasiydi.\n */\n useEffect(() => {\n if (openMode === 'sheet') listRef.current?.focus({ preventScroll: true });\n /* `listRef` kancadan geliyor ve `useRef` kimligi SABIT; bagimlilikta\n olmasi etkiyi yeniden calistirmaz, denetci ise kancadan gelen bir\n degerin referans oldugunu kanitlayamiyor. */\n }, [openMode, listRef]);\n\n /*\n * KAPALIYKEN ok/Enter/Space paneli ACAR. Bu adim kancada DEGIL: acilma\n * karari bilesenin (panel mi alt sayfa mi) ve kanca yalnizca gezinmeyi\n * tasiyor.\n */\n const onKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n if (!isOpen) {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) {\n event.preventDefault();\n open();\n }\n return;\n }\n\n handleKeyDown(event);\n };\n\n const renderList = (isSheet: boolean) => (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n /* Alt sayfada baslik `BottomSheet`in icinde ve kimligi bize kapali;\n listenin adi dogrudan yazilir. */\n aria-label={label}\n /* Odak alt sayfada listede, panelde tetikleyicide: etkin seçeneği\n bildiren öznitelik odağın olduğu öğede durmak zorunda. */\n aria-activedescendant={isSheet && options[activeIndex] ? optionId(activeIndex) : undefined}\n tabIndex={isSheet ? 0 : -1}\n className={cx(styles.list, isSheet && styles['list--sheet'])}\n onKeyDown={isSheet ? onKeyDown : undefined}\n >\n {options.map((option, index) => {\n const isChosen = option.value === value;\n\n return (\n <li\n key={option.value}\n id={optionId(index)}\n role=\"option\"\n data-index={index}\n aria-selected={isChosen}\n aria-disabled={option.isDisabled}\n className={cx(\n styles.option,\n index === activeIndex && styles['option--active'],\n isChosen && styles['option--selected'],\n option.isDisabled && styles['option--disabled'],\n )}\n // Fare imleci seçeneğin üstündeyken etkin seçenek de oraya taşınır;\n // iki ayrı vurgu kullanıcıyı şaşırtıyordu.\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectOption(option)}\n >\n <span className={styles.option__label}>{option.label}</span>\n {isChosen && <CheckLg aria-hidden className={styles.option__check} />}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <span ref={rootRef} className={cx(styles.select, className)} data-testid={testId}>\n <button\n ref={triggerRef}\n id={baseId}\n type=\"button\"\n role=\"combobox\"\n className={cx(\n styles.trigger,\n styles[`trigger--${size}`],\n !selectedOption && styles['trigger--empty'],\n isOpen && styles['trigger--open'],\n )}\n disabled={isDisabled}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={\n openMode === 'popover' && options[activeIndex] ? optionId(activeIndex) : undefined\n }\n aria-label={label}\n aria-describedby={describedBy}\n aria-invalid={isInvalid}\n onClick={() => (isOpen ? close() : open())}\n onKeyDown={onKeyDown}\n >\n {icon && (\n <span className={styles.trigger__icon} aria-hidden>\n {icon}\n </span>\n )}\n\n <span className={styles.trigger__value}>{selectedOption?.label ?? emptyText}</span>\n\n {/*\n * Ok DOLU CARET: ince chevron, kutunun sag ucunda `$text-2` tonunda\n * iki hairline cizgiye iniyor ve kutunun acilir oldugu uzaktan\n * okunmuyordu. Acikken 180° donuyor — yon hâlâ durumu bildiriyor.\n */}\n <CaretDownFill\n aria-hidden\n className={cx(styles.trigger__chevron, isOpen && styles['trigger__chevron--open'])}\n />\n </button>\n\n {openMode === 'popover' && (\n <div className={cx(styles.panel, styles[`panel--${align}`])}>{renderList(false)}</div>\n )}\n\n {/* Dar ekranda liste alt sayfada acilir; panel klavye acilinca sikisiyor\n ve alt ucu ekranin disinda kaliyordu (bkz. `BottomSheet`). */}\n {openMode === 'sheet' && (\n <BottomSheet title={label} closeLabel={closeLabel ?? labels?.close} onClose={close}>\n {renderList(true)}\n </BottomSheet>\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Select) as typeof Select;\n","import { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & {\n label: ReactNode;\n hint?: string;\n testId?: string;\n};\n\n/**\n * Onay kutusu.\n *\n * <p>Yerel `<input type=\"checkbox\">` korunur ve `accent-color` ile\n * renklendirilir. Özel bir kutu çizmek (gizli input + sahte kare) klavye\n * odağını ve ekran okuyucu davranışını elle yeniden kurmayı gerektirir;\n * kazanç görsel, maliyet erişilebilirlik.\n *\n * <p>Tüm satır tıklanabilir (`<label>` sarmalar): 18 px'lik kareyi\n * hedeflemek özellikle dokunmatik ekranda yorucu.\n */\nconst Checkbox = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ label, hint, className, testId, ...rest }, ref) => (\n <label className={cx(styles.checkbox, className)} data-testid={testId}>\n <input ref={ref} type=\"checkbox\" className={styles.checkbox__input} {...rest} />\n <span className={styles.checkbox__body}>\n <span className={styles.checkbox__label}>{label}</span>\n {hint && <span className={styles.checkbox__hint}>{hint}</span>}\n </span>\n </label>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Checkbox, 'Checkbox')) as typeof Checkbox;\n","'use client';\n\nimport { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'role'> & {\n /** Anahtarın görünür etiketi. */\n label: ReactNode;\n /** Etiketin altındaki açıklama; `aria-describedby` ile bağlanır. */\n hint?: string;\n /** Etiket anahtarın SOLUNDA durur — ayar listelerinin yaygın düzeni. */\n isLabelFirst?: boolean;\n testId?: string;\n};\n\n/**\n * Anahtar (switch) — <strong>anında</strong> uygulanan aç/kapa.\n *\n * <h3>`Checkbox` ile farkı: NE ZAMAN etkili olduğu</h3>\n * İkisi de iki durumlu ve ikisi de yerel `<input type=\"checkbox\">` üzerine\n * kurulu; ayrım görünüşte değil ZAMANLAMADA:\n *\n * <ul>\n * <li>{@link Checkbox} bir formda <strong>gönderilecek</strong> seçimdir.\n * \"Sözleşmeyi okudum\" işaretlendiğinde hiçbir şey olmaz; karar\n * \"Kaydet\"e basıldığında geçerli olur. Geri almak için işareti kaldırıp\n * yeniden göndermek gerekir.</li>\n * <li><b>`Switch` ANINDA uygulanır.</b> \"Kampanya bildirimleri\" açıldığı\n * anda sunucuya gider. Kaydet düğmesi yoktur, olmamalıdır da —\n * kullanıcı anahtarı çevirdikten sonra bir düğme aramak zorunda\n * kalıyordu.</li>\n * </ul>\n *\n * <p>Ayrım keyfi değil ekran okuyucuda DUYULUYOR: `role=\"switch\"` \"açık/kapalı\"\n * diye okunur, onay kutusu \"işaretli/işaretsiz\" diye. İkisi kullanıcıya farklı\n * bir söz veriyor.\n *\n * <h3>Yerel öğe korunur</h3>\n * `<input type=\"checkbox\" role=\"switch\">` — `Space` ile değiştirme, `Tab`\n * sırası, form gönderimine katılma ve `:disabled` semantiği tarayıcıdan gelir.\n * `<div role=\"switch\" tabindex=\"0\">` yazmak bunların hepsini elle yeniden\n * kurmak demekti.\n *\n * <h3>Durum RENKLE ANLATILMAZ</h3>\n * Açık ve kapalı hâl arasındaki fark yalnızca zemin rengi olsaydı renk körü\n * bir kullanıcı için iki durum aynı görünürdü (WCAG 1.4.1). Kulp KONUM\n * değiştiriyor — bu bir biçim farkı — ve zorlanmış renk kipinde çerçeve +\n * konum tek başına yeterli kalıyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Space`</td><td>durumu değiştirir</td></tr>\n * </table>\n *\n * @example\n * <Switch\n * label=\"Kampanya bildirimleri\"\n * hint=\"E-posta ile ayda en fazla iki ileti\"\n * checked={isSubscribed}\n * onChange={event => subscribe(event.target.checked)}\n * />\n */\nconst Switch = forwardRef<HTMLInputElement, Props>(\n ({ label, hint, isLabelFirst, className, id, testId, ...rest }, ref) => (\n <label\n className={cx(styles.switch, isLabelFirst && styles['switch--labelFirst'], className)}\n data-testid={testId}\n >\n <input\n ref={ref}\n type=\"checkbox\"\n /*\n * `role=\"switch\"` YEREL onay kutusunun UZERINE yazilir: davranis\n * checkbox'tan gelir, DUYURU switch olur. Ekran okuyucu \"acik/kapali\"\n * der; \"isaretli\" demek kullaniciya yanlis bir soz veriyordu.\n */\n role=\"switch\"\n id={id}\n className={styles.switch__input}\n {...rest}\n />\n\n {/* Kulbun tasiyicisi; gorsel durum tamamen CSS'te. */}\n <span className={styles.switch__track} aria-hidden>\n <span className={styles.switch__thumb} />\n </span>\n\n <span className={styles.switch__text}>\n <span className={styles.switch__label}>{label}</span>\n {hint && <span className={styles.switch__hint}>{hint}</span>}\n </span>\n </label>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Switch, 'Switch')) as typeof Switch;\n","import { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & {\n label: ReactNode;\n hint?: string;\n /** Sağda gösterilen sonuç adedi (filtre listelerinde). */\n count?: number;\n testId?: string;\n};\n\n/**\n * Radyo düğmesi.\n *\n * <p>{@link Checkbox} ile aynı gerekçe: yerel `<input type=\"radio\">` korunur\n * ve `accent-color` ile renklendirilir. Sahte bir daire çizmek ok tuşlarıyla\n * gezinmeyi ve grup duyurusunu elle yeniden kurmayı gerektirirdi.\n *\n * <p>Tüm satır tıklanabilir (`<label>` sarmalar): 18 px'lik daireyi\n * hedeflemek özellikle dokunmatik ekranda yorucu.\n */\nconst Radio = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ label, hint, count, className, testId, ...rest }, ref) => (\n <label className={cx(styles.radio, className)} data-testid={testId}>\n <input ref={ref} type=\"radio\" className={styles.radio__input} {...rest} />\n <span className={styles.radio__body}>\n <span className={styles.radio__label}>{label}</span>\n {hint && <span className={styles.radio__hint}>{hint}</span>}\n </span>\n {isDefined(count) && <span className={styles.radio__count}>{count}</span>}\n </label>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Radio, 'Radio')) as typeof Radio;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport type { CommonElementProps } from '../../types/common-element-props.type';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Radyo grubu adı — aynı gruptaki kartlar ok tuşlarıyla gezilir. */\n name: string;\n value: string;\n isSelected: boolean;\n isDisabled?: boolean;\n onChange: (value: string) => void;\n /** Zengin gövde: kartın içeriği çağırana aittir. */\n children: ReactNode;\n} & CommonElementProps;\n\n/**\n * Seçilebilir kart — zengin gövdeli radyo.\n *\n * <h3>Neden ayrı bir öğe</h3>\n * Varyant seçici ve hesap seçici aynı deseni elle kuruyordu: `<label>` + gizli\n * radyo + gövde + seçili/pasif durum matrisi. İki kopya çoktan ayrışmıştı —\n * biri odak halkasını metnin üstüne, diğeri hiç çizmiyordu; biri seçili zemini\n * boyuyor, diğeri boyamıyordu.\n *\n * <h3>Radyo GERÇEK, daire çizim</h3>\n * `<input type=\"radio\">` görsel olarak gizlenir ama DOM'da kalır: ok\n * tuşlarıyla grup içinde gezinme, `Space` ile seçim ve ekran okuyucu duyurusu\n * tarayıcıdan gelir. Yerel daire bu boyutta bir kartta görsel olarak\n * kaybolduğu için işaret ayrıca çizilir (`__indicator`).\n *\n * <h3>Seçim üç sinyalle</h3>\n * Kenarlık + zemin tinti + dolan işaret aynı anda değişir. İşaretin dolu / boş\n * hâli bir BİÇİM farkıdır — renk tek başına anlam taşımaz (WCAG 1.4.1).\n *\n * <p>Odak halkası kartın kendisinde (`:has(:focus-visible)`): gizli girdiye\n * çizilen halka görünmüyor, yalnızca metne çizilen halka da kartın nerede\n * bittiğini söylemiyordu.\n *\n * <p>{@link Radio} yalın satır içindir, gövde taşıyamaz — ikisi karışmaz.\n */\nconst RadioCard: FC<Props> = ({\n name,\n value,\n isSelected,\n isDisabled,\n onChange,\n children,\n className,\n id,\n testId,\n}) => (\n <label\n className={cx(\n styles.radioCard,\n isSelected && styles['radioCard--selected'],\n isDisabled && styles['radioCard--disabled'],\n className,\n )}\n data-testid={testId}\n >\n <input\n type=\"radio\"\n id={id}\n name={name}\n value={value}\n checked={isSelected}\n disabled={isDisabled}\n onChange={() => onChange(value)}\n className={styles.radioCard__input}\n />\n <span className={styles.radioCard__indicator} aria-hidden />\n <span className={styles.radioCard__body}>{children}</span>\n </label>\n);\n\nexport default /*#__PURE__*/ memo(RadioCard) as typeof RadioCard;\n","'use client';\n\nimport { memo, useCallback } from 'react';\n\nimport { normalize } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\nexport type RangeValue = [number, number];\n\ntype Props = {\n min: number;\n max: number;\n step?: number;\n value: RangeValue;\n /** Sürükleme sürerken her adımda çağrılır — ekrandaki değeri günceller. */\n onChange: (value: RangeValue) => void;\n /**\n * Sürükleme <em>bittiğinde</em> çağrılır. Adres çubuğuna yazmak veya\n * sunucuya istek atmak gibi pahalı işler buraya bağlanır.\n */\n onCommit?: (value: RangeValue) => void;\n /** Ham sayıyı okunur metne çevirir (\"125000\" → \"1.250 TL\"). */\n formatValue?: (value: number) => string;\n /** Grubun erişilebilir adı (\"Fiyat aralığı\"). */\n label: string;\n /** Alt kulbun erişilebilir ad eki. Verilmezse `labels.range.min`. */\n minLabel?: string;\n /** Üst kulbun erişilebilir ad eki. Verilmezse `labels.range.max`. */\n maxLabel?: string;\n isDisabled?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Çift kulplu aralık kaydırıcı.\n *\n * <h3>Neden iki gerçek `<input type=\"range\">`</h3>\n * Kulplar `<div>` ile çizilip sürükleme JavaScript'le yazıldığında klavye\n * desteği, ekran okuyucu duyurusu ve dokunma davranışı elle yeniden kurulmak\n * zorunda kalır — ve pratikte biri hep eksik kalır. Üst üste bindirilmiş iki\n * yerel aralık girdisi bunların hepsini ücretsiz getirir: ok tuşları, Home/End,\n * PageUp/PageDown ve aralık duyurusu kendiliğinden çalışır.\n *\n * <h3>Kulplar birbirini geçemez</h3>\n * Alt kulp üst değeri, üst kulp alt değeri aşamaz. Geçmelerine izin vermek\n * \"en az 8.000, en çok 1.200\" gibi anlamsız bir aralık üretiyordu.\n *\n * <h3>Sayı değil METİN duyurulur</h3>\n * `aria-valuetext` biçimlenmiş değeri taşır. Aksi hâlde ekran okuyucu ham\n * sayıyı (\"bir milyon iki yüz elli bin\") okuyordu.\n *\n * <h3>`onChange` ile `onCommit` ayrıdır</h3>\n * Kaydırırken her adımda adres çubuğuna yazmak, tek bir sürüklemede onlarca\n * gezinme kaydı bırakıp geri tuşunu kullanılamaz hâle getiriyordu. Ekran anında\n * güncellenir (`onChange`), sorgu yalnızca kulp bırakılınca yazılır.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowUp`</td><td>bir adım artırır</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowDown`</td><td>bir adım azaltır</td></tr>\n * <tr><td>`Home` / `End`</td><td>ölçeğin ucuna gider</td></tr>\n * <tr><td>`PageUp` / `PageDown`</td><td>büyük adım</td></tr>\n * </table>\n * Tamamı YEREL öğeden gelir — kütüphane hiçbir tuşu kendisi işlemez. Buraya\n * ait olan iki şey ayrıca ölçülüyor: kulpların birbirini geçmemesi ve\n * `onCommit`in tuş bırakıldığında (`keyup`) çalışması. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst RangeSlider = ({\n min,\n max,\n step = 1,\n value,\n onChange,\n onCommit,\n formatValue = String,\n label,\n minLabel,\n maxLabel,\n isDisabled,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const lowName = resolveLabel('RangeSlider.minLabel', minLabel, labels?.range?.min);\n const highName = resolveLabel('RangeSlider.maxLabel', maxLabel, labels?.range?.max);\n const [low, high] = value;\n\n const handleLowChange = useCallback(\n (raw: number) => onChange([Math.min(raw, high), high]),\n [high, onChange],\n );\n\n const handleHighChange = useCallback(\n (raw: number) => onChange([low, Math.max(raw, low)]),\n [low, onChange],\n );\n\n const commit = useCallback(() => onCommit?.([low, high]), [low, high, onCommit]);\n\n /* `normalize` yuzdeyi verir ve 100'de kirpar; olcek sifir genislikte\n oldugunda (min === max) 0 doner. */\n const span = max - min;\n const lowPercent = span === 0 ? 0 : normalize(low - min, span);\n const highPercent = span === 0 ? 0 : normalize(high - min, span);\n\n /*\n * Iki kulp ust uste geldiginde hangisinin tutulacagi belirsizlesir. Alt kulp\n * olcegin ikinci yarisindaysa one alinir; aksi halde ust kulp onu kapatip\n * alt kulbu yakalanamaz kiliyordu.\n */\n const isLowOnTop = lowPercent > 50;\n\n return (\n <div\n className={cx(styles.range, isDisabled && styles['range--disabled'], className)}\n role=\"group\"\n aria-label={label}\n data-testid={testId}\n >\n <div className={styles.range__readout}>\n <span className={styles.range__value}>{formatValue(low)}</span>\n <span className={styles.range__separator} aria-hidden>\n —\n </span>\n <span className={styles.range__value}>{formatValue(high)}</span>\n </div>\n\n <div className={styles.range__track}>\n {/* Secili aralik: kullanicinin nerede durdugunu tek bakista gosterir. */}\n <span\n className={styles.range__fill}\n style={{ left: `${lowPercent}%`, right: `${100 - highPercent}%` }}\n aria-hidden\n />\n\n <input\n type=\"range\"\n className={styles.range__input}\n style={{ zIndex: isLowOnTop ? 4 : 3 }}\n min={min}\n max={max}\n step={step}\n value={low}\n disabled={isDisabled}\n aria-label={`${label} — ${lowName}`}\n aria-valuetext={formatValue(low)}\n onChange={event => handleLowChange(Number(event.target.value))}\n onPointerUp={commit}\n onKeyUp={commit}\n />\n\n <input\n type=\"range\"\n className={styles.range__input}\n style={{ zIndex: isLowOnTop ? 3 : 4 }}\n min={min}\n max={max}\n step={step}\n value={high}\n disabled={isDisabled}\n aria-label={`${label} — ${highName}`}\n aria-valuetext={formatValue(high)}\n onChange={event => handleHighChange(Number(event.target.value))}\n onPointerUp={commit}\n onKeyUp={commit}\n />\n </div>\n\n {/* Olcegin uclari: kullanici kendi araligini baglama oturtabilmeli. */}\n <div className={styles.range__bounds} aria-hidden>\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(RangeSlider) as typeof RangeSlider;\n","'use client';\n\nimport { memo, useId, useState } from 'react';\n\nimport { StarFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveFormatter } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\n/** Beş puanın her birinin ne anlama geldiği. */\nexport type RatingLabels = Record<1 | 2 | 3 | 4 | 5, string>;\n\ntype Props = {\n value: number | null;\n onChange: (value: number) => void;\n /** Grubun erişilebilir adı (\"Ürün puanı\"). */\n label: string;\n /**\n * Puan açıklamaları. Hem ekran okuyucuya okunur hem de seçildiğinde\n * yıldızların altında yazar. Verilmezse `labels.rating.scale`.\n *\n * <p>Dolu yıldız sayısı tek başına bir renk/şekil sinyali. Yanına açıklama\n * yazmak hem anlamı netleştirir hem de renk körü kullanıcıya ikinci bir ipucu\n * verir (WCAG 1.4.1).\n */\n ratingLabels?: RatingLabels;\n /**\n * Ekran okuyucuda yıldız sayısını okuyan biçimlendirici (\"4 yıldız\").\n * Verilmezse `labels.rating.starCount`.\n */\n formatStarCount?: (star: number) => string;\n isDisabled?: boolean;\n className?: string;\n testId?: string;\n};\n\nconst STARS = [1, 2, 3, 4, 5] as const;\n\n/**\n * Yıldızla puan girişi.\n *\n * <h3>Beş gerçek radyo düğmesi</h3>\n * Yıldızlar `<span>` ile çizilip tıklama JavaScript'e bağlanabilirdi. Bunun\n * yerine `<fieldset>` içinde beş yerel `<input type=\"radio\">` kullanılır ve\n * yıldız görünümü etiketlerine verilir. Böylece ok tuşlarıyla gezinme, Tab\n * davranışı, ekran okuyucuda \"5 seçenekten 4'ü seçili\" duyurusu ve form\n * gönderimine katılma <em>bedava</em> gelir.\n *\n * <p>{@link Rating} genişletilemez: o `<span>` üretiyor ve açıkça\n * salt-gösterim. İkisini tek bileşende toplamak, gösterim tarafına hiç\n * kullanılmayan etkileşim kodu taşımak olurdu.\n *\n * <h3>Klavye (APG: radio group — tamamı YEREL)</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowDown`</td><td>bir sonraki yıldız</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowUp`</td><td>bir önceki yıldız</td></tr>\n * <tr><td>`Tab`</td><td>grubu TEK durak olarak geçer</td></tr>\n * </table>\n * Kütüphane hiçbir tuşu işlemiyor; nöbetçi bu yüzden tuşları değil DEVRİ\n * ölçüyor — beş gerçek radyo, tek grup adı, okunabilir adlar\n * (`components/__tests__/keyboard.test.tsx`). Yıldızlar `<span>`e dönerse\n * test kırılır.\n */\nconst RatingInput = ({\n value,\n onChange,\n label,\n ratingLabels,\n formatStarCount,\n isDisabled,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const scale = ratingLabels ?? labels?.rating?.scale;\n const name = useId();\n const [hovered, setHovered] = useState<number | null>(null);\n\n // Fare yildizlarin uzerindeyken onizleme gosterilir; ayrilinca gercek\n // secime doner.\n const shown = hovered ?? value;\n\n return (\n <fieldset\n className={cx(styles.rating, isDisabled && styles['rating--disabled'], className)}\n disabled={isDisabled}\n data-testid={testId}\n >\n <legend className={styles.rating__legend}>{label}</legend>\n\n <div className={styles.rating__stars} onMouseLeave={() => setHovered(null)}>\n {STARS.map(star => (\n <label\n key={star}\n className={cx(\n styles.rating__star,\n shown !== null && star <= shown && styles['rating__star--filled'],\n )}\n onMouseEnter={() => setHovered(star)}\n >\n <input\n type=\"radio\"\n name={name}\n value={star}\n checked={value === star}\n onChange={() => onChange(star)}\n className={styles.rating__input}\n />\n <StarFill aria-hidden />\n <span className={styles.rating__srOnly}>\n {resolveFormatter(\n 'RatingInput.formatStarCount',\n formatStarCount ?? labels?.rating?.starCount,\n star,\n )}{' '}\n — {scale?.[star] ?? ''}\n </span>\n </label>\n ))}\n </div>\n\n {/* Secim metni: `aria-hidden` cunku ayni bilgi radyonun etiketinde var. */}\n {shown !== null && (\n <span className={styles.rating__caption} aria-hidden>\n {scale?.[shown as 1 | 2 | 3 | 4 | 5] ?? ''}\n </span>\n )}\n </fieldset>\n );\n};\n\nexport default /*#__PURE__*/ memo(RatingInput) as typeof RatingInput;\n","'use client';\n\nimport { type FC, memo, useState } from 'react';\n\nimport { DashLg, PlusLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n value: number;\n onChange: (value: number) => void;\n /** Grubun ve girdinin erişilebilir adı. Verilmezse `labels.quantity.label`. */\n label?: string;\n /** Verilmezse `labels.quantity.decrease`. */\n decreaseLabel?: string;\n /** Verilmezse `labels.quantity.increase`. */\n increaseLabel?: string;\n min?: number;\n max?: number;\n isDisabled?: boolean;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Adet seçici.\n *\n * <p>Doğrudan yazma da desteklenir: 12 adet isteyen kullanıcının artı düğmesine\n * on iki kez basması kabul edilemez.\n *\n * <p>Yazılan değer <strong>odak kaybında</strong> sınırlara çekilir, her tuş\n * vuruşunda değil: \"12\" yazarken \"1\"i anında 1'e sabitlemek kullanıcının\n * yazmasını engellerdi.\n */\nconst QuantityStepper: FC<Props> = ({\n value,\n onChange,\n label,\n decreaseLabel,\n increaseLabel,\n min = 1,\n max = 99,\n isDisabled,\n size = 'md',\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const groupLabel = resolveLabel('QuantityStepper.label', label, labels?.quantity?.label);\n const [draft, setDraft] = useState<string | null>(null);\n\n const commit = (raw: string) => {\n setDraft(null);\n const parsed = Number(raw.replace(/\\D/g, ''));\n if (!parsed) return;\n onChange(Math.min(Math.max(parsed, min), max));\n };\n\n return (\n <div\n className={cx(styles.stepper, styles[`stepper--${size}`], className)}\n role=\"group\"\n aria-label={groupLabel}\n data-testid={testId}\n >\n <button\n type=\"button\"\n className={styles.stepper__button}\n onClick={() => onChange(Math.max(value - 1, min))}\n disabled={isDisabled || value <= min}\n aria-label={resolveLabel(\n 'QuantityStepper.decreaseLabel',\n decreaseLabel,\n labels?.quantity?.decrease,\n )}\n >\n <DashLg aria-hidden />\n </button>\n\n <input\n className={styles.stepper__input}\n value={draft ?? String(value)}\n onChange={event => setDraft(event.target.value.replace(/\\D/g, '').slice(0, 2))}\n onBlur={event => commit(event.target.value)}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n event.preventDefault();\n commit((event.target as HTMLInputElement).value);\n }\n }}\n inputMode=\"numeric\"\n disabled={isDisabled}\n aria-label={`${groupLabel} (${min}-${max})`}\n />\n\n <button\n type=\"button\"\n className={styles.stepper__button}\n onClick={() => onChange(Math.min(value + 1, max))}\n disabled={isDisabled || value >= max}\n aria-label={resolveLabel(\n 'QuantityStepper.increaseLabel',\n increaseLabel,\n labels?.quantity?.increase,\n )}\n >\n <PlusLg aria-hidden />\n </button>\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(QuantityStepper) as typeof QuantityStepper;\n","import { forwardRef, type InputHTMLAttributes, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'aria-label'> & {\n /**\n * Erişilebilir ad — ZORUNLU. Hücrede görünür etiket yok (etiket sütun\n * başlığında); adsız kutu ekran okuyucuda yalnızca \"onay kutusu\" diye\n * okunur. Satır kutusunda kaydın kimliğini söyleyin (\"SP-2026-000123 seç\").\n */\n label: string;\n testId?: string;\n};\n\n/**\n * Tablo hücresindeki toplu seçim kutusu.\n *\n * <h3>Neden `Checkbox` değil</h3>\n * Seçim sütununda etiket sütun başlığıdır ve `Checkbox` bileşeninin ürettiği\n * `<label>` sarmalayıcısı (yan yana kutu + metin yerleşimi) hücreyi bozar.\n * Doğru olan yalın `<input type=\"checkbox\">` + `aria-label` — bu bileşen o\n * deseni resmileştirir ki ekranlar çıplak `<input>` yazmak zorunda kalmasın.\n *\n * <p>Renk `Checkbox` ile aynı kaynaktan: `accent-color` mavi — onay kutusu bir\n * seçimdir, bir dönüşüm değil.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Space`</td><td>seçimi değiştirir</td></tr>\n * </table>\n * Yerel öğe: `Space`, `indeterminate` durumu ve form gönderimine katılma\n * platformdan gelir. Nöbetçi: `components/__tests__/keyboard.test.tsx`.\n */\nconst TableCheckbox = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ label, className, testId, ...rest }, ref) => (\n <input\n ref={ref}\n type=\"checkbox\"\n aria-label={label}\n className={cx(styles.checkbox, className)}\n data-testid={testId}\n {...rest}\n />\n ),\n);\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(TableCheckbox, 'TableCheckbox'),\n) as typeof TableCheckbox;\n","import { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/*\n * `prefix` HTML'in RDFa nitelikleri arasinda yer alir ve React onu `string`\n * olarak tanimlar. Kaldirilmazsa kendi `ReactNode` tanimimizla kesisip\n * `string & ReactNode` uretiyor ve ikon vermeyi imkansiz kiliyordu.\n */\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'prefix'> & {\n /** Solda gösterilen ikon veya ön ek (arama simgesi, para birimi). */\n prefix?: ReactNode;\n /** Sağda gösterilen ikon veya birim (göz simgesi, \"kg\"). */\n suffix?: ReactNode;\n /** Teknik veri: SKU, kod, seri numarası — monospace ve harf aralıklı. */\n isTechnical?: boolean;\n testId?: string;\n};\n\n/**\n * Metin girdisi.\n *\n * <p>Ön ek / son ek girdinin <em>içinde</em> konumlanır; girdinin yanına ayrı\n * bir kutu koymak hizalamayı bozar ve odak halkasını ikiye böler.\n *\n * <p>Odak halkası sarmalayıcıda değil girdinin kendisinde: sarmalayıcıya\n * verildiğinde `:focus-visible` klavye/fare ayrımını kaybediyordu.\n */\nconst Input = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ prefix, suffix, isTechnical, className, testId, ...rest }, ref) => (\n <span className={cx(styles.wrapper, className)}>\n {prefix && (\n <span className={styles.wrapper__prefix} aria-hidden>\n {prefix}\n </span>\n )}\n <input\n ref={ref}\n className={cx(\n styles.input,\n /* `Boolean(...)`: `prefix` bir `ReactNode` ve `0` da gecerli bir\n deger — `prefix &&` ifadesi o durumda dize degil sayi donuyordu. */\n Boolean(prefix) && styles['input--hasPrefix'],\n Boolean(suffix) && styles['input--hasSuffix'],\n isTechnical && styles['input--technical'],\n )}\n data-testid={testId}\n {...rest}\n />\n {suffix && (\n <span className={styles.wrapper__suffix} aria-hidden>\n {suffix}\n </span>\n )}\n </span>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Input, 'Input')) as typeof Input;\n","'use client';\n\nimport { type KeyboardEvent, memo, useId, useRef, useState } from 'react';\n\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport useAnnounce from '../../hooks/useAnnounce';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n values: string[];\n onChange: (values: string[]) => void;\n /** Alanın erişilebilir adı. ZORUNLU. */\n label: string;\n placeholder?: string;\n /** Her etiketin kaldırma düğmesinin ad öneki (\"Kaldır\"). ZORUNLU. */\n removeLabel: string;\n /** Etiketi bitiren tuşlar. Varsayılan `Enter` ve virgül. */\n separators?: string[];\n /** En fazla kaç etiket. Dolduğunda girdi PASİF olur, gizlenmez. */\n maxTags?: number;\n isDisabled?: boolean;\n id?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Etiket girdisi — yazılan metni kaldırılabilir çiplere çevirir.\n *\n * <h3>Yerel `<input>` KORUNUR</h3>\n * Yazma, panodan yapıştırma, mobil klavye ve `Tab` sırası tarayıcıdan geliyor.\n * Çipler girdinin İÇİNDE görünüyor ama DOM'da kardeşi: `<input>` çocuk\n * alamıyor ve çipleri içine koymanın tek yolu girdiyi taklit etmekti.\n *\n * <h3>Neden {@link Combobox} değil</h3>\n * `Combobox` BİLİNEN bir listeden seçtiriyor; burada değer serbest — kullanıcı\n * listede olmayan bir şey yazıyor (arama terimi, OEM kodu, e-posta). Seçilecek\n * bir liste varsa `Combobox` doğrusu.\n *\n * <h3>Yinelenen değer sessizce YUTULMAZ</h3>\n * Aynı etiket ikinci kez yazıldığında eklenmiyor ama girdi de temizleniyor;\n * kullanıcı \"yazdım, kayboldu\" diyordu. Artık var olan çip bir kare\n * vurgulanıyor ve ekran okuyucuya \"zaten ekli\" duyuruluyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Enter` / `,`</td><td>yazılanı etikete çevirir</td></tr>\n * <tr><td>`Backspace` (girdi BOŞken)</td><td>SON etiketi kaldırır</td></tr>\n * <tr><td>`Tab`</td><td>girdiden çıkar — yazılan metin de etikete DÖNER</td></tr>\n * <tr><td>çipin çarpısı</td><td>o etiketi kaldırır</td></tr>\n * </table>\n * `Tab`ta yazılanın etikete dönmesi bilinçli: yarım kalmış bir metin alanı\n * terk edildiğinde kayboluyordu ve kullanıcı bunu ancak gönderdikten sonra\n * fark ediyordu.\n */\nconst TagInput = ({\n values,\n onChange,\n label,\n placeholder,\n removeLabel,\n separators = ['Enter', ','],\n maxTags,\n isDisabled,\n id,\n className,\n testId,\n 'aria-describedby': describedBy,\n 'aria-invalid': isInvalid,\n}: Props) => {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const inputRef = useRef<HTMLInputElement>(null);\n const announce = useAnnounce();\n\n const [draft, setDraft] = useState('');\n /* Yinelenen deger: var olan cip bir kare vurgulanir. */\n const [duplicate, setDuplicate] = useState<string | null>(null);\n\n const isFull = maxTags !== undefined && values.length >= maxTags;\n\n const commit = (raw: string) => {\n const value = raw.trim();\n if (value === '') return;\n\n if (values.includes(value)) {\n /* Sessizce yutmak yerine GOSTER: kullanici \"yazdim, kayboldu\" diyordu. */\n setDuplicate(value);\n window.setTimeout(() => setDuplicate(null), 1_000);\n announce(`${value} zaten ekli`, 'assertive');\n setDraft('');\n return;\n }\n\n if (isFull) return;\n\n onChange([...values, value]);\n setDraft('');\n announce(`${value} eklendi`);\n };\n\n const remove = (value: string) => {\n onChange(values.filter(item => item !== value));\n announce(`${value} kaldırıldı`);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (separators.includes(event.key)) {\n event.preventDefault();\n commit(draft);\n return;\n }\n\n /*\n * BOS girdide Backspace SON etiketi kaldirir — metin varken kaldirmaz.\n * Kosulsuz yazildiginda kullanici bir harf silmek isterken etiketi\n * siliyordu.\n */\n if (event.key === 'Backspace' && draft === '' && values.length > 0) {\n remove(values[values.length - 1]);\n }\n };\n\n return (\n <div\n className={cx(\n styles.tagInput,\n isDisabled && styles['tagInput--disabled'],\n isInvalid && styles['tagInput--invalid'],\n className,\n )}\n data-testid={testId}\n /* Kutunun herhangi bir yerine tiklamak girdiyi odaklar: cipler arasindaki\n bosluga tiklayan kullanici hicbir sey olmadigini saniyordu. */\n onClick={() => inputRef.current?.focus()}\n >\n {values.map(value => (\n <span\n key={value}\n className={cx(\n styles.tagInput__tag,\n duplicate === value && styles['tagInput__tag--duplicate'],\n )}\n >\n {value}\n\n <button\n type=\"button\"\n className={styles.tagInput__remove}\n /* Ad degeri ICERIR: on bes cipin hepsi \"Kaldir\" diye okundugunda\n hangisi oldugu belli olmuyordu. */\n aria-label={`${value} — ${removeLabel}`}\n disabled={isDisabled}\n onClick={event => {\n event.stopPropagation();\n remove(value);\n }}\n >\n <XLg aria-hidden />\n </button>\n </span>\n ))}\n\n <input\n ref={inputRef}\n id={inputId}\n type=\"text\"\n className={styles.tagInput__field}\n value={draft}\n placeholder={values.length === 0 ? placeholder : undefined}\n aria-label={label}\n aria-describedby={describedBy}\n aria-invalid={isInvalid}\n disabled={isDisabled || isFull}\n onChange={event => setDraft(event.target.value)}\n onKeyDown={handleKeyDown}\n /* Alan terk edildiginde yazilan metin ETIKETE DONER: yarim kalmis bir\n metin kayboluyor ve kullanici bunu ancak gonderdikten sonra fark\n ediyordu. */\n onBlur={() => commit(draft)}\n />\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(TagInput, 'TagInput')) as typeof TagInput;\n","'use client';\n\nimport {\n forwardRef,\n memo,\n type TextareaHTMLAttributes,\n useCallback,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = TextareaHTMLAttributes<HTMLTextAreaElement> & {\n /**\n * Alan içeriğiyle birlikte BÜYÜR — kaydırma çubuğu yerine yükseklik.\n *\n * <p>Sabit yükseklikli bir alanda kullanıcı yazdığının tamamını göremiyor:\n * dört satırlık bir kutuya on satır yazan kişi, gönderdiğinde ne yazdığını\n * kontrol etmek için kutunun içinde kaydırmak zorunda kalıyordu. `maxRows`\n * ile tavan konur; ötesinde kaydırma geri döner (sayfa boyunca uzayan bir\n * alan, altındaki gönder düğmesini ekrandan çıkarıyordu).\n */\n isAutoSize?: boolean;\n /** Otomatik büyümenin tavanı (satır). */\n maxRows?: number;\n /**\n * Kalan karakter sayacını gösterir. `maxLength` ile birlikte anlamlı.\n *\n * <p>Sayaç `aria-hidden`: aynı bilgi her tuşta duyurulsaydı yazma\n * kesintiye uğrardı. Sınıra YAKLAŞILDIĞINDA (son %10) sayaç uyarı tonuna\n * geçiyor — sınıra çarpıp yazamamak, yaklaştığını görmemekten kötü.\n */\n hasCounter?: boolean;\n testId?: string;\n};\n\n/**\n * Çok satırlı metin girdisi.\n *\n * <p>Görünüm {@link Input} ile aynı gövdeden gelir: bir formda tek satırlı ve\n * çok satırlı alanlar yan yana durur, kenarlık ve odak davranışları ayrışırsa\n * form derlenmemiş görünür.\n *\n * <p>Yeniden boyutlandırma yalnızca <strong>dikey</strong>: yatayda büyütmek\n * alanı kapsayıcısının dışına taşırıp yerleşimi bozuyordu.\n *\n * <h3>Otomatik yükseklik neden CSS ile değil</h3>\n * `field-sizing: content` bu işi tek satırda yapıyor ama bugün yalnızca\n * Chromium'da var. Ölçüm yolu her yerde çalışıyor ve tarayıcı desteği\n * geldiğinde tek dosyada değiştirilecek.\n */\nconst Textarea = /*#__PURE__*/ forwardRef<HTMLTextAreaElement, Props>(\n (\n {\n className,\n rows = 4,\n isAutoSize,\n maxRows = 12,\n hasCounter,\n maxLength,\n value,\n defaultValue,\n onChange,\n testId,\n ...rest\n },\n ref,\n ) => {\n const innerRef = useRef<HTMLTextAreaElement | null>(null);\n /*\n * KONTROLLU kipte uzunluk `value`dan OKUNUR, ic durumdan degil.\n *\n * Sayac yalnizca `onChange` ile guncelleniyordu: disaridan gelen her deger\n * degisimi (profilden on doldurma, form sifirlama, tasklaktan gelen taslak)\n * sayaci ESKI sayida birakiyordu. Kullanici 400 karakterlik bir metni\n * yukleyip \"12 / 500\" okuyordu.\n */\n const [innerLength, setLength] = useState(String(defaultValue ?? '').length);\n const length = value === undefined ? innerLength : String(value).length;\n\n /* Cagiranin `ref`i ile ic olcum referansini birlikte tut: `useImperativeHandle`\n yalnizca bir nesne dondurur ve DOM dugumunun kendisini gizlerdi. */\n const setRefs = useCallback(\n (node: HTMLTextAreaElement | null) => {\n innerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref],\n );\n\n /*\n * OLCUM BOYAMADAN ONCE: `useEffect` ile alan bir kare boyunca eski\n * yuksekligiyle cizilip sonra ziplyordu.\n *\n * `height: auto` ONCE yazilir — yoksa `scrollHeight` bir onceki (buyuk)\n * yuksekligi raporluyor ve alan bir daha hic kucumuyordu.\n */\n useLayoutEffect(() => {\n const node = innerRef.current;\n if (!isAutoSize || !node) return;\n\n node.style.height = 'auto';\n\n const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 20;\n const max = lineHeight * maxRows;\n\n node.style.height = `${Math.min(node.scrollHeight, max)}px`;\n node.style.overflowY = node.scrollHeight > max ? 'auto' : 'hidden';\n }, [isAutoSize, maxRows, value, length]);\n\n const isNearLimit = maxLength !== undefined && length >= maxLength * 0.9;\n\n return (\n <div className={cx(styles.wrapper, className)} data-testid={testId}>\n <textarea\n ref={setRefs}\n rows={rows}\n className={cx(styles.textarea, isAutoSize && styles['textarea--autoSize'])}\n maxLength={maxLength}\n value={value}\n defaultValue={defaultValue}\n onChange={event => {\n setLength(event.target.value.length);\n onChange?.(event);\n }}\n {...rest}\n />\n\n {hasCounter && maxLength !== undefined && (\n /* `aria-hidden`: ayni bilgi her tusta duyurulsaydi yazma kesintiye\n ugrardi. Sinir zaten `maxLength` ile taniniyor. */\n <span\n className={cx(styles.counter, isNearLimit && styles['counter--near'])}\n aria-hidden\n >\n {length} / {maxLength}\n </span>\n )}\n </div>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Textarea, 'Textarea')) as typeof Textarea;\n","'use client';\n\nimport { forwardRef, type InputHTMLAttributes, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & {\n /** `date` (varsayılan) · `datetime-local` · `month` · `time`. */\n type?: 'date' | 'datetime-local' | 'month' | 'time';\n testId?: string;\n};\n\n/**\n * Tarih alanı — <strong>yerel</strong> `<input type=\"date\">`.\n *\n * <h3>Neden taklit bir takvim YOK</h3>\n * Bu kütüphanenin kuralı: yerel öğe korunur, taklit yazmanın tek gerekçesi\n * ölçülmüş bir kusurdur ({@link Select} bunun tek istisnası ve gerekçesi\n * orada yazılı). Tarih alanında böyle bir kusur YOK — tersine, yerel öğenin\n * taklidin veremeyeceği dört şeyi var:\n *\n * <ul>\n * <li><b>Mobilde işletim sisteminin seçicisi.</b> iOS'ta tekerlek, Android'de\n * takvim — kullanıcının her gün kullandığı, alışkın olduğu arayüz. Hiçbir\n * web takvimi 360 px'lik bir ekranda ona yaklaşamıyor.</li>\n * <li><b>Klavyeyle YAZARAK giriş.</b> Doğum tarihini bilen biri \"01.01.1980\"i\n * üç saniyede yazıyor; taklit takvimde aynı iş kırk yıl geriye tıklamak\n * demek.</li>\n * <li><b>Yerel biçim.</b> Tarayıcı kullanıcının işletim sistemi ayarına göre\n * gg.aa.yyyy ya da mm/dd/yyyy gösteriyor; değer her zaman ISO\n * (`YYYY-MM-DD`) kalıyor. İki biçimi elle yönetmek, kütüphanenin\n * kullanıcının yerel ayarını TAHMİN etmesi demekti.</li>\n * <li><b>Ekran okuyucu.</b> Alan üç ayrı bölüm (gün/ay/yıl) olarak okunuyor\n * ve ok tuşlarıyla artırılıyor. APG'ye uygun bir takvim ızgarası bunu\n * ancak taklit edebilir.</li>\n * </ul>\n *\n * <p>Bedeli: takvim açılışının görünüşü tarayıcıya ait ve tema token'larını\n * izlemiyor. Kabul edildi — açılan panelin rengi, yukarıdaki dördünün\n * yanında küçük bir bedel.\n *\n * <h3>`min` / `max` KULLANIN</h3>\n * İkisi de yerel öğede var ve tarayıcı doğrulamayı kendisi yapıyor. Geçersiz\n * bir tarihi yalnızca gönderimde yakalamak, kullanıcıyı formu doldurduktan\n * sonra geri gönderiyordu.\n */\nconst DateField = forwardRef<HTMLInputElement, Props>(\n ({ type = 'date', className, testId, ...rest }, ref) => (\n <input\n ref={ref}\n type={type}\n className={cx(styles.dateField, className)}\n data-testid={testId}\n {...rest}\n />\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(DateField, 'DateField')) as typeof DateField;\n\nexport type DateRangeValue = {\n /** ISO tarih (`YYYY-MM-DD`) ya da boş dize. */\n start: string;\n end: string;\n};\n\ntype RangeProps = {\n value: DateRangeValue;\n onChange: (value: DateRangeValue) => void;\n /** Başlangıç alanının erişilebilir adı (\"Başlangıç\"). ZORUNLU. */\n startLabel: string;\n /** Bitiş alanının erişilebilir adı (\"Bitiş\"). ZORUNLU. */\n endLabel: string;\n /** İki alanın arasındaki ayraç. Varsayılan yarım tire. */\n separator?: string;\n /** Ölçeğin uçları; ikisi de yerel öğeye geçer. */\n min?: string;\n max?: string;\n /** Seçilen aralığın okunur özetini gösterir. */\n isSummaryVisible?: boolean;\n isDisabled?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Tarih aralığı — <strong>iki yerel alan</strong>, taklit takvim değil.\n *\n * <h3>Neden taklit bir aralık takvimi yazılmadı</h3>\n * Taklit bir ay ızgarasının tek gerçek üstünlüğü var: iki ucu AYNI ANDA\n * görmek. Bedeli ise {@link DateField} JSDoc'unda sayılan dört şeyin\n * tamamını kaybetmek — işletim sisteminin seçicisi, yazarak giriş, yerel\n * biçim ve ekran okuyucunun bölümlü okuması — artı APG'ye uygun bir ızgara\n * klavye modelini (`ArrowUp/Down` hafta, `PageUp/Down` ay, `Home/End` hafta\n * sınırı) sıfırdan yazmak.\n *\n * <p>Takas ölçüldüğünde iki uç arasında kalıyor ve karar <strong>henüz\n * verilmedi</strong>: bu bileşen bugün iki yerel alanı doğru şekilde\n * eşleştiriyor. Aynı ekranda ay ızgarası gerçekten gerekiyorsa (bir otel\n * rezervasyonu gibi, \"boş günleri gör\" ihtiyacı olan bir akış) o zaman\n * yazılır ve gerekçesi <em>o ihtiyaç</em> olur — \"aralık seçimi\" tek başına\n * yeterli bir gerekçe değil.\n *\n * <h3>İki uç birbirini KISITLAR</h3>\n * Başlangıç seçildiğinde bitiş alanının `min`i, bitiş seçildiğinde\n * başlangıcın `max`ı güncelleniyor: tarayıcı geçersiz aralığı en baştan\n * seçtirmiyor. Sonradan doğrulayıp hata göstermek, kullanıcıyı yaptığı bir\n * seçimden geri döndürüyordu.\n */\nconst DateRangeBase = ({\n value,\n onChange,\n startLabel,\n endLabel,\n separator = '–',\n min,\n max,\n isSummaryVisible,\n isDisabled,\n className,\n testId,\n}: RangeProps) => {\n const { labels } = useHanui();\n\n /*\n * OZET `Intl` ile ve `labels.locale`den.\n *\n * Iki ISO tarih kullanici icin bir aralik degil iki sayi. Yerel ayar\n * KUTUPHANE tarafindan TAHMIN EDILMEZ; verilmediginde ozet hic cizilmez —\n * yanlis bicimde bir tarih, hic tarih olmamasindan kotu.\n */\n const summary = (() => {\n if (!isSummaryVisible || !labels?.locale || value.start === '' || value.end === '') return null;\n\n try {\n const format = new Intl.DateTimeFormat(labels.locale, { dateStyle: 'medium' });\n return `${format.format(new Date(value.start))} ${separator} ${format.format(new Date(value.end))}`;\n } catch {\n /* Gecersiz yerel ayar ya da tarih: ozet cizilmez, alanlar calismaya\n devam eder. Bir bicimlendirme hatasi girisi engellememeli. */\n return null;\n }\n })();\n\n return (\n <div className={cx(styles.range, className)} data-testid={testId}>\n <div className={styles.range__row}>\n <DateField\n className={styles.range__field}\n aria-label={startLabel}\n value={value.start}\n min={min}\n /* Baslangic bitisi GECEMEZ: tarayici gecersiz araligi en bastan\n sectirmiyor. */\n max={value.end || max}\n disabled={isDisabled}\n onChange={event => onChange({ ...value, start: event.target.value })}\n />\n\n <span className={styles.range__separator} aria-hidden>\n {separator}\n </span>\n\n <DateField\n className={styles.range__field}\n aria-label={endLabel}\n value={value.end}\n min={value.start || min}\n max={max}\n disabled={isDisabled}\n onChange={event => onChange({ ...value, end: event.target.value })}\n />\n </div>\n\n {summary && <span className={styles.range__summary}>{summary}</span>}\n </div>\n );\n};\n\nexport const DateRange = /*#__PURE__*/ named(/*#__PURE__*/ memo(DateRangeBase), 'DateRange');\n","import { type FC, memo, type ReactNode, useId } from 'react';\n\nimport { ExclamationCircleFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\n/** Girdiye yayılacak erişilebilirlik bağları. */\nexport type FieldChildProps = {\n id: string;\n 'aria-invalid'?: boolean;\n 'aria-describedby'?: string;\n required?: boolean;\n};\n\ntype BaseProps = {\n label: string;\n /** Girdi bileşenini alan `id` ve `aria-*` bağlarıyla üretir. */\n children: (props: FieldChildProps) => ReactNode;\n hint?: string;\n error?: string;\n /** Etiketi gizler ama ekran okuyucuya bırakır (arama kutusu gibi). */\n isLabelHidden?: boolean;\n className?: string;\n};\n\ntype Props = BaseProps & {\n isRequired?: boolean;\n /**\n * Zorunluluk yıldızının ekran okuyucu karşılığı (\"(zorunlu)\").\n *\n * <p>Yıldız yalnızca GÖRSEL bir kısayol; renk ve şekil tek başına anlam\n * taşıyamaz (WCAG 1.4.1), o yüzden yanında okunabilir bir metin olmak\n * zorunda. Verilmezse `labels.required` okunur.\n */\n requiredLabel?: string;\n};\n\n/**\n * Form alanı sarmalayıcısı.\n *\n * <h3>Neden render-prop</h3>\n * Etiket, hata mesajı ve yardım metni girdiye `id` / `aria-describedby` /\n * `aria-invalid` ile <strong>bağlanmak zorunda</strong> — yoksa ekran okuyucu\n * hatayı okumaz. Bu bağları her form alanında elle yazmak kaçınılmaz olarak\n * bir yerde atlanıyor.\n *\n * <p>Render-prop kalıbı bağları bileşene ürettirir: çağıran taraf yalnızca\n * aldığı props'ları girdiye yayar ve erişilebilirlik kendiliğinden doğru olur.\n *\n * <p>Hata varken yardım metni gösterilmez: ikisi birlikte gürültü yapar ve\n * kullanıcının okuması gereken mesaj kaybolur.\n *\n * @example\n * <Field label=\"E-posta\" isRequired requiredLabel=\"(zorunlu)\" error={emailError}>\n * {props => <Input {...props} type=\"email\" value={email} onChange={onChange} />}\n * </Field>\n *\n * @example\n * // `{...props}` yaymayan bileşenlerde (Combobox, Select) yalnızca `id`:\n * <Field label=\"Şehir\">{props => <Combobox id={props.id} … />}</Field>\n */\nconst Field: FC<Props> = ({\n label,\n children,\n hint,\n error,\n isRequired,\n requiredLabel,\n isLabelHidden,\n className,\n}) => {\n const { labels } = useHanui();\n const id = useId();\n const errorId = `${id}-error`;\n const hintId = `${id}-hint`;\n\n return (\n <div className={cx(styles.field, className)}>\n <label\n htmlFor={id}\n className={cx(styles.field__label, isLabelHidden && styles['field__label--hidden'])}\n >\n {label}\n {isRequired && (\n <>\n <span className={styles.field__required} aria-hidden>\n *\n </span>\n <span className={styles.field__srOnly}>\n {resolveLabel('Field.requiredLabel', requiredLabel, labels?.required)}\n </span>\n </>\n )}\n </label>\n\n {children({\n id,\n required: isRequired || undefined,\n 'aria-invalid': error ? true : undefined,\n /*\n * HATA VE YARDIM BIRLIKTE baglanir, biri digerini EZMEZ.\n *\n * Once hata varken yalnizca hata baglaniyordu ve yardim metni ekran\n * okuyucudan DUSUYORDU: \"telefon gecersiz\" duyan kullanici, bir satir\n * yukarida duran \"05XX XXX XX XX\" bicim ipucunu hic duymuyor ve neyi\n * yanlis yazdigini bilmiyordu. Goren kullanici ikisini de aliyor;\n * ayrim sebepsizdi.\n *\n * Sira ONEMLI: once hata, sonra yardim. Ekran okuyucu bagli metinleri\n * yazildiklari sirayla okuyor ve once \"ne yanlis\" duyulmali.\n */\n 'aria-describedby': [error && errorId, hint && hintId].filter(Boolean).join(' ') || undefined,\n })}\n\n {/*\n HATA VE IPUCU BIRLIKTE cizilir.\n\n Ipucu eskiden hatanin ALTERNATIFIYDI: hata belirir belirmez kural\n ekrandan siliniyordu. Yani kullanici tam olarak kurali okumasi gereken\n anda onu kaybediyordu — \"Cok kisa\" diyor ama neye gore kisa oldugunu\n artik hicbir yer yazmiyor. `aria-describedby` de ikisini birden\n gosteriyor; biri cizilmediginde bag BOS bir dugume isaret ediyordu.\n */}\n {error && (\n <p id={errorId} className={styles.field__error} role=\"alert\">\n <ExclamationCircleFill aria-hidden className={styles.field__errorIcon} />\n {error}\n </p>\n )}\n\n {hint && (\n <p id={hintId} className={styles.field__hint}>\n {hint}\n </p>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(Field) as typeof Field;\n","'use client';\n\nimport { memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/** Yüzdeyi 0-100 aralığına kırpar; ölçek sıfır genişlikteyse 0 döner. */\nconst toPercent = (value: number, max: number): number => {\n if (!Number.isFinite(value) || !Number.isFinite(max) || max <= 0) return 0;\n return Math.min(100, Math.max(0, (value / max) * 100));\n};\n\ntype Props = {\n /**\n * Tamamlanan miktar. `undefined` → BELİRSİZ ilerleme (sonu bilinmiyor);\n * çubuk kendi kendine akar.\n */\n value?: number;\n /** Ölçeğin üst ucu. */\n max?: number;\n /** Çubuğun erişilebilir adı (\"Yükleme\", \"Ödeme adımı\"). ZORUNLU. */\n label: string;\n /**\n * Ekran okuyucuya okunan METİN karşılığı (\"3 / 5 dosya\").\n *\n * <p>Verilmezse ekran okuyucu ham yüzdeyi okur. Bir dosya yüklemesinde\n * \"yüzde altmış\" ile \"5 dosyadan 3'ü\" arasındaki fark, kullanıcının\n * bekleyip beklememeye karar verebilmesi.\n */\n valueText?: string;\n /** Yüzdeyi çubuğun yanında GÖRÜNÜR olarak yazar. */\n isValueVisible?: boolean;\n tone?: 'brand' | 'success' | 'warning' | 'danger';\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * İlerleme çubuğu — <strong>ölçülebilir</strong> bekleme.\n *\n * <h3>{@link Spinner} ile farkı: sonu bilinip bilinmediği</h3>\n * `Spinner` \"bir şey oluyor\" der ve başka bir şey söyleyemez. Ölçülebilir bir\n * işte (dosya yükleme, içe aktarma, çok adımlı ödeme) bu yetmiyor: kullanıcı\n * beklemeye değip değmeyeceğine karar veremiyor ve iki saniyeyle iki dakika\n * arasındaki farkı ancak bekleyerek öğreniyordu.\n *\n * <p>`value` verilmediğinde çubuk BELİRSİZ kipe düşer: yine bir çubuk çizer\n * ama `aria-valuenow` yazmaz. Bu kasıtlı — bilinmeyen bir değeri \"0\" diye\n * bildirmek, ekran okuyucuya işin hiç ilerlemediğini söylüyordu.\n *\n * <h3>Yüzde tek başına yeterli DEĞİL</h3>\n * `valueText` verildiğinde ekran okuyucu onu okur (\"5 dosyadan 3'ü\"), yüzdeyi\n * değil. Aynı bilgi görsel tarafta `isValueVisible` ile yazılabiliyor; ikisi\n * de aynı gerçeği söylemek zorunda.\n *\n * <h3>Renk tek başına anlam taşımaz</h3>\n * `tone` yalnızca bir vurgu: \"tamamlandı\" ya da \"başarısız\" durumu çubuğun\n * rengiyle DEĞİL, yanındaki metinle ve çağıran tarafın çizdiği ikonla\n * anlatılır (WCAG 1.4.1).\n */\nconst Progress = ({\n value,\n max = 100,\n label,\n valueText,\n isValueVisible,\n tone = 'brand',\n size = 'md',\n className,\n testId,\n}: Props) => {\n const isIndeterminate = value === undefined;\n const percent = isIndeterminate ? 0 : toPercent(value, max);\n\n return (\n <div className={cx(styles.progress, className)} data-testid={testId}>\n <div\n role=\"progressbar\"\n aria-label={label}\n /*\n * BELIRSIZ kipte `aria-valuenow` YAZILMAZ. Ozniteligin yoklugu, ARIA'da\n * \"deger bilinmiyor\" demek; `0` yazmak ekran okuyucuya isin hic\n * ilerlemedigini soyluyordu.\n */\n aria-valuenow={isIndeterminate ? undefined : Math.round(percent)}\n aria-valuemin={isIndeterminate ? undefined : 0}\n aria-valuemax={isIndeterminate ? undefined : 100}\n aria-valuetext={isIndeterminate ? undefined : valueText}\n className={cx(\n styles.progress__track,\n styles[`progress__track--${size}`],\n isIndeterminate && styles['progress__track--indeterminate'],\n )}\n >\n <span\n className={cx(styles.progress__fill, styles[`progress__fill--${tone}`])}\n style={isIndeterminate ? undefined : { inlineSize: `${percent}%` }}\n />\n </div>\n\n {isValueVisible && !isIndeterminate && (\n /* Gorsel yuzde `aria-hidden`: ayni bilgi zaten `progressbar`in\n degerinde ve iki kez duyurulmasi gurultu. */\n <span className={styles.progress__value} aria-hidden>\n {valueText ?? `%${Math.round(percent)}`}\n </span>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Progress, 'Progress')) as typeof Progress;\n\ntype CircleProps = {\n /** Tamamlanan miktar. `undefined` → BELİRSİZ; çember döner. */\n value?: number;\n max?: number;\n /** Erişilebilir ad. ZORUNLU. */\n label: string;\n valueText?: string;\n /** Yüzdeyi çemberin ortasına yazar. */\n isValueVisible?: boolean;\n tone?: 'brand' | 'success' | 'warning' | 'danger';\n /** Dış çap (px). */\n size?: number;\n className?: string;\n testId?: string;\n};\n\n/**\n * Dairesel ilerleme.\n *\n * <h3>Ne zaman çubuk, ne zaman çember</h3>\n * Çubuk bir SATIRA aittir ve yanındaki metinle okunur; çember bir KUTUYA\n * aittir (kart köşesi, avatar yerine geçen madalyon, dip şeritteki adım\n * göstergesi). Kararı yer belirler, tercih değil: dar bir kutuda çubuk 30\n * piksele düşüp okunamaz hâle geliyordu.\n *\n * <h3>Ölçü prop, token DEĞİL</h3>\n * Çemberin çapı `stroke-dasharray` hesabına giriyor ve o hesap JavaScript'te\n * yapılıyor: CSS değişkeninden okunamaz. Bu yüzden `size` bir sayı — ölçü\n * ölçeğinin dışında kalan tek yer ve nedeni bu.\n */\nconst ProgressCircleBase = ({\n value,\n max = 100,\n label,\n valueText,\n isValueVisible,\n tone = 'brand',\n size = 44,\n className,\n testId,\n}: CircleProps) => {\n const isIndeterminate = value === undefined;\n const percent = isIndeterminate ? 25 : toPercent(value, max);\n\n /* Cizgi kalinligi capin ~%10'u: sabit bir kalinlik kucuk cemberde kutuyu\n dolduruyor, buyugunde sac teline donuyordu. */\n const stroke = Math.max(3, Math.round(size * 0.1));\n const radius = (size - stroke) / 2;\n const circumference = 2 * Math.PI * radius;\n\n return (\n <div\n className={cx(styles.circle, isIndeterminate && styles['circle--indeterminate'], className)}\n style={{ width: size, height: size }}\n data-testid={testId}\n >\n <svg\n className={styles.circle__svg}\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n role=\"progressbar\"\n aria-label={label}\n aria-valuenow={isIndeterminate ? undefined : Math.round(percent)}\n aria-valuemin={isIndeterminate ? undefined : 0}\n aria-valuemax={isIndeterminate ? undefined : 100}\n aria-valuetext={isIndeterminate ? undefined : valueText}\n >\n <circle\n className={styles.circle__track}\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n />\n <circle\n className={cx(styles.circle__fill, styles[`circle__fill--${tone}`])}\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n strokeDasharray={circumference}\n strokeDashoffset={circumference * (1 - percent / 100)}\n />\n </svg>\n\n {isValueVisible && !isIndeterminate && (\n <span className={styles.circle__label} aria-hidden>\n {valueText ?? `%${Math.round(percent)}`}\n </span>\n )}\n </div>\n );\n};\n\nexport const ProgressCircle = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(ProgressCircleBase),\n 'ProgressCircle',\n);\n","'use client';\n\nimport { type DragEvent, memo, type ReactNode, useId, useRef, useState } from 'react';\n\nimport { CloudArrowUpFill, ExclamationCircleFill, XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport useAnnounce from '../../hooks/useAnnounce';\nimport IconButton from '../IconButton';\nimport Progress from '../Progress';\n\nimport styles from './index.module.scss';\n\nexport type UploadFile = {\n id: string;\n name: string;\n /** Bayt. Ekranda okunur biçime çevrilir. */\n size: number;\n /** 0-100. `undefined` → yükleme başlamadı ya da bitti. */\n progress?: number;\n /** Bu dosyaya ait hata. Satır kırmızı çizilir ve metin okunur. */\n error?: string;\n};\n\ntype Props = {\n files: UploadFile[];\n /** Kullanıcı dosya seçtiğinde/bıraktığında çağrılır — DOĞRULANMIŞ liste. */\n onSelect: (files: File[]) => void;\n onRemove: (id: string) => void;\n /** Alanın görünür etiketi ve erişilebilir adı. ZORUNLU. */\n label: string;\n /** Etiketin altındaki kural cümlesi (\"PDF veya JPG, en fazla 5 MB\"). */\n hint?: string;\n /** `<input accept>` — tarayıcının dosya seçicisini süzer. */\n accept?: string;\n isMultiple?: boolean;\n /** Bayt. Aşan dosya `onSelect`e HİÇ ulaşmaz; hata metni burada üretilir. */\n maxSize?: number;\n /** Kaldırma düğmelerinin erişilebilir ad öneki (\"Kaldır\"). */\n removeLabel: string;\n /** Sürükle-bırak alanının içine yazılan çağrı (\"Dosyaları buraya bırakın\"). */\n dropLabel: string;\n /** Boyut aşıldığında yazılan hata; `{name}` ve `{max}` yerine konur. */\n sizeErrorText?: string;\n isDisabled?: boolean;\n /** Alanın tamamına ait hata (sunucu reddi). */\n error?: string;\n children?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/** Baytı okunur biçime çevirir. */\nconst formatSize = (bytes: number): string => {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n};\n\n/**\n * Dosya yükleme — sürükle-bırak <strong>ve</strong> düğme.\n *\n * <h3>Yerel `<input type=\"file\">` KORUNUR</h3>\n * Görsel olarak gizlenir ama DOM'da kalır ve `<label>` ile alana bağlanır:\n * klavyeyle `Tab` + `Enter`, ekran okuyucuda \"dosya seç, düğme\" duyurusu,\n * işletim sisteminin dosya seçicisi ve mobilde kamera/galeri seçenekleri\n * <em>bedava</em> gelir. `<div>` üzerine `onDrop` yazıp düğmeyi taklit etmek\n * bunların hiçbirini getirmiyor — ve sürükle-bırak zaten <strong>tek başına\n * erişilebilir değil</strong>: fare gerektiriyor (WCAG 2.5.7).\n *\n * <h3>Doğrulama BİLEŞENDE, ama yalnızca ÖLÇÜLEBİLİR olan</h3>\n * Boyut sınırı burada uygulanıyor çünkü cevabı kesin ve anında verilebiliyor:\n * aşan dosya `onSelect`e hiç ulaşmıyor, kullanıcı yüklemenin bitmesini\n * beklemeden hatayı görüyor. Tür/içerik doğrulaması burada YAPILMIYOR —\n * `accept` bir öneri, gerçek karar sunucunun ve istemcide \"geçerli\" demek\n * yanlış bir söz olurdu.\n *\n * <h3>Sonuç DUYURULUYOR</h3>\n * Dosya eklendiğinde ve reddedildiğinde `useAnnounce` ile ekran okuyucuya\n * bildiriliyor. Listeye sessizce eklenen bir satır, görmeyen kullanıcı için\n * hiç olmamış demekti.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>alana, sonra her dosyanın kaldırma düğmesine</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>alanda: dosya seçiciyi açar</td></tr>\n * </table>\n */\nconst FileUpload = ({\n files,\n onSelect,\n onRemove,\n label,\n hint,\n accept,\n isMultiple,\n maxSize,\n removeLabel,\n dropLabel,\n sizeErrorText = '{name} çok büyük (en fazla {max}).',\n isDisabled,\n error,\n children,\n className,\n testId,\n}: Props) => {\n const inputId = useId();\n const hintId = useId();\n const inputRef = useRef<HTMLInputElement>(null);\n const announce = useAnnounce();\n\n const [isDragging, setIsDragging] = useState(false);\n const [rejected, setRejected] = useState<string[]>([]);\n\n const handleFiles = (list: FileList | null) => {\n if (!list || list.length === 0) return;\n\n const incoming = [...list];\n const tooLarge = maxSize === undefined ? [] : incoming.filter(file => file.size > maxSize);\n const accepted = incoming.filter(file => !tooLarge.includes(file));\n\n const messages = tooLarge.map(file =>\n sizeErrorText.replace('{name}', file.name).replace('{max}', formatSize(maxSize ?? 0)),\n );\n setRejected(messages);\n\n if (accepted.length > 0) {\n onSelect(accepted);\n announce(`${accepted.length} dosya eklendi`);\n }\n\n /* Reddedilen dosya ekranda YAZIYOR ama duyurulmali da: gormeyen kullanici\n icin sessizce dusen bir dosya hic secilmemis demekti. */\n if (messages.length > 0) announce(messages.join(' '), 'assertive');\n };\n\n const handleDrop = (event: DragEvent<HTMLLabelElement>) => {\n event.preventDefault();\n setIsDragging(false);\n if (isDisabled) return;\n handleFiles(event.dataTransfer.files);\n };\n\n return (\n <div className={cx(styles.upload, className)} data-testid={testId}>\n {/*\n Sürükle-bırak alanı bir `<label>`: tıklama ve klavye YEREL girdiye\n yönleniyor. `onClick` ile `input.click()` çağırmak da çalışırdı ama\n ekran okuyucu alanı bir düğme olarak duyurmuyordu.\n */}\n <label\n htmlFor={inputId}\n className={cx(\n styles.upload__drop,\n isDragging && styles['upload__drop--dragging'],\n isDisabled && styles['upload__drop--disabled'],\n error && styles['upload__drop--invalid'],\n )}\n onDragOver={event => {\n event.preventDefault();\n if (!isDisabled) setIsDragging(true);\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={handleDrop}\n >\n <CloudArrowUpFill aria-hidden className={styles.upload__icon} />\n\n <span className={styles.upload__label}>{label}</span>\n <span className={styles.upload__drag}>{dropLabel}</span>\n {hint && (\n <span id={hintId} className={styles.upload__hint}>\n {hint}\n </span>\n )}\n\n <input\n ref={inputRef}\n id={inputId}\n type=\"file\"\n className={styles.upload__input}\n accept={accept}\n multiple={isMultiple}\n disabled={isDisabled}\n aria-describedby={hint ? hintId : undefined}\n aria-invalid={error ? true : undefined}\n onChange={event => {\n handleFiles(event.target.files);\n /* Deger SIFIRLANIR: ayni dosya ikinci kez secildiginde `change`\n olayi hic dusmuyor ve kullanici \"hicbir sey olmadi\" saniyordu. */\n event.target.value = '';\n }}\n />\n </label>\n\n {error && (\n <p className={styles.upload__error} role=\"alert\">\n <ExclamationCircleFill aria-hidden />\n {error}\n </p>\n )}\n\n {rejected.map(message => (\n <p key={message} className={styles.upload__error} role=\"alert\">\n <ExclamationCircleFill aria-hidden />\n {message}\n </p>\n ))}\n\n {files.length > 0 && (\n <ul className={styles.upload__list}>\n {files.map(file => (\n <li\n key={file.id}\n className={cx(styles.upload__file, file.error && styles['upload__file--error'])}\n >\n <span className={styles.upload__fileText}>\n <span className={styles.upload__fileName}>{file.name}</span>\n <span className={styles.upload__fileMeta}>\n {file.error ?? formatSize(file.size)}\n </span>\n </span>\n\n {file.progress !== undefined && (\n <Progress\n value={file.progress}\n label={`${file.name} yükleniyor`}\n size=\"sm\"\n className={styles.upload__progress}\n />\n )}\n\n <IconButton\n icon={<XLg aria-hidden />}\n /* Ad dosya adini ICERIR: bir listede on bes dugme \"Kaldir\" diye\n okunuyor ve hangisi oldugu belli olmuyordu. */\n label={`${file.name} — ${removeLabel}`}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onRemove(file.id)}\n />\n </li>\n ))}\n </ul>\n )}\n\n {children}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(FileUpload, 'FileUpload'),\n) as typeof FileUpload;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport {\n CheckCircleFill,\n ExclamationTriangleFill,\n InfoCircleFill,\n XCircleFill,\n} from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\nexport type AlertTone = 'info' | 'success' | 'warning' | 'danger';\n\ntype Props = {\n children: ReactNode;\n tone?: AlertTone;\n title?: string;\n /** Sağda gösterilen eylem (bağlantı veya düğme). */\n action?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Her tona kendi ikonu; renk tek başına anlam taşımaz (WCAG 1.4.1).\n *\n * <p>Dördü de DOLU (`*Fill`) sürüm: ton zeminin üzerinde ince çizgili bir\n * simge, madalyonun içinde soluk kalıp uzaktan seçilemiyordu.\n *\n * <p>`aria-hidden`: ikonun taşıdığı bilgi yanındaki metinde zaten var; ikisini\n * birden okumak ekran okuyucuda tekrar üretiyordu.\n */\nconst ICONS: Record<AlertTone, ReactNode> = {\n info: <InfoCircleFill aria-hidden />,\n success: <CheckCircleFill aria-hidden />,\n warning: <ExclamationTriangleFill aria-hidden />,\n danger: <XCircleFill aria-hidden />,\n};\n\n/**\n * Bilgi / uyarı kutusu.\n *\n * <p>`danger` ve `warning` tonları `role=\"alert\"` taşır: ekran okuyucu bunları\n * anında duyurur. `info` ve `success` duyurulmaz — sayfa yüklenirken her bilgi\n * kutusunun okunması gürültü olurdu.\n */\nconst Alert: FC<Props> = ({ children, tone = 'info', title, action, className, testId }) => (\n <div\n className={cx(styles.alert, styles[`alert--${tone}`], className)}\n role={tone === 'danger' || tone === 'warning' ? 'alert' : undefined}\n data-testid={testId}\n >\n <span className={styles.alert__icon}>{ICONS[tone]}</span>\n\n <div className={styles.alert__body}>\n {title && <strong className={styles.alert__title}>{title}</strong>}\n <div className={styles.alert__content}>{children}</div>\n </div>\n\n {action && <div className={styles.alert__action}>{action}</div>}\n </div>\n);\n\nexport default /*#__PURE__*/ memo(Alert) as typeof Alert;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Tam ad; baş harfler buradan üretilir ve görsel yoksa `alt` metnidir. */\n name: string;\n /**\n * Profil görseli. Verilmezse baş harf madalyonuna düşer — çağıran tarafın\n * koşul yazması gerekmez.\n */\n imageUrl?: string;\n /**\n * Baş harfleri büyütürken kullanılacak dil etiketi (\"tr\", \"az\").\n *\n * <p>Türkçede ZORUNLU: `toUpperCase()` \"i\" harfini \"I\" yapıyor ve \"İlhan\"ın\n * baş harfi \"I\" çıkıyor. `toLocaleUpperCase('tr')` doğru \"İ\" verir.\n * Verilmezse `labels.locale`, o da yoksa çalışma ortamının varsayılan dili.\n */\n locale?: string;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n testId?: string;\n};\n\n/**\n * Baş harfleri üretir: \"Ahmet İlhan\" → \"Aİ\".\n *\n * <p>Tek kelimelik adda ilk iki harf alınır; tek harflik bir madalyon boş\n * görünüyordu.\n */\nconst resolveInitials = (name: string, locale?: string): string => {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return '?';\n\n const letters =\n words.length === 1 ? words[0].slice(0, 2) : `${words[0][0]}${words[words.length - 1][0]}`;\n\n return locale ? letters.toLocaleUpperCase(locale) : letters.toLocaleUpperCase();\n};\n\n/**\n * Adı SABİT bir renk kovasına eşler.\n *\n * <h3>Neden rastgele değil, neden hash</h3>\n * Aynı kişi her ekranda AYNI tonda görünmeli: bir listede yan yana duran on\n * kullanıcı, hepsi aynı gri madalyonken birbirinden ayırt edilemiyordu ve\n * renk her render'da değişseydi (rastgele) madalyon kimliği taşımak yerine\n * gürültü üretiyordu.\n *\n * <p>Karma basit ve KASITLI olarak basit: kriptografik bir dağılım gerekmiyor,\n * gereken tek şey aynı girdinin aynı çıktıyı vermesi. `charCodeAt` toplamı\n * kısa adlarda kümeleniyordu (djb2'nin `* 33` çarpanı bunu dağıtıyor).\n *\n * <h3>Renk tek başına KİMLİK taşımaz</h3>\n * Madalyonun içinde zaten baş harfler var ve yanında adın kendisi yazıyor.\n * Ton yalnızca bir tarama yardımı — renk körü bir kullanıcı için hiçbir bilgi\n * kaybı yok (WCAG 1.4.1).\n */\nconst resolveTone = (name: string, total: number): number => {\n let hash = 5381;\n for (let index = 0; index < name.length; index += 1) hash = (hash * 33) ^ name.charCodeAt(index);\n\n return Math.abs(hash) % total;\n};\n\n/** Madalyon tonlarının sayısı — `_module.scss` içindeki kova sayısıyla AYNI. */\nconst TONE_COUNT = 6;\n\n/**\n * Avatar — kullanıcı madalyonu.\n *\n * <h3>Görsel yoksa baş harf</h3>\n * Profil görseli olmayan bir sistemde baş harf madalyonu kimliği\n * <em>yeterince</em> taşır: kullanıcı hesap menüsünün en üstünde doğru hesapta\n * olduğunu görmek ister, fotoğrafını değil. `imageUrl` verildiğinde görsel\n * çizilir ve baş harf yedeğe düşer; çağıran tarafların değişmesi gerekmez.\n *\n * <h3>Ekran okuyucuya okunmaz</h3>\n * Madalyon `aria-hidden`: yanında zaten adın kendisi yazıyor. İkisini de\n * okumak \"A İ Ahmet İlhan\" gibi bir gürültü üretiyordu. Adın yanında\n * durmadığı bir yerde kullanılıyorsa çağıran taraf metni kendisi yazar.\n */\nconst Avatar: FC<Props> = ({ name, imageUrl, locale, size = 'md', className, testId }) => {\n const { labels } = useHanui();\n\n return (\n <span\n className={cx(\n styles.avatar,\n styles[`avatar--${size}`],\n /* Ton yalnizca BAS HARF madalyonunda: gorselin uzerine renk basmak\n fotografi bozuyordu. */\n !imageUrl && styles[`avatar--tone-${resolveTone(name, TONE_COUNT)}`],\n className,\n )}\n aria-hidden\n data-testid={testId}\n >\n {imageUrl ? (\n <img className={styles.avatar__image} src={imageUrl} alt=\"\" />\n ) : (\n resolveInitials(name, locale ?? labels?.locale)\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Avatar) as typeof Avatar;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\nexport type BadgeTone =\n | 'neutral'\n | 'success'\n | 'danger'\n | 'warning'\n | 'info'\n /** Birincil sınıflandırma tinti (mavi-lacivert aile). */\n | 'oem'\n /** İkincil sınıflandırma tinti (mor aile). */\n | 'alt'\n /** İndirim / olumlu değişim yüzdesi. Tutarın kendisi nötr kalır. */\n | 'sale'\n /** Miktar sayacı (sepet adedi, filtre sayısı) — dolu zemine izin verilir. */\n | 'action'\n /** Gezinme etiketi. */\n | 'link';\n\nexport type BadgeVariant = 'soft' | 'solid' | 'outline';\n\ntype Props = {\n children: ReactNode;\n tone?: BadgeTone;\n variant?: BadgeVariant;\n /** Küçük ikon; metnin solunda gösterilir. */\n icon?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Rozet — durum ve sınıflandırma etiketi.\n *\n * <p><strong>Renk tek başına anlam taşımaz</strong> (WCAG 1.4.1): her rozet\n * okunabilir bir metin içerir. `tone` yalnızca metni pekiştirir; renk körü bir\n * kullanıcı da aynı bilgiyi alır.\n *\n * <h3>Durum tonlarında `solid` ile `soft` aynı şeyi verir</h3>\n * Bu bilinçli. <strong>Doygun dolgu = tıklanabilir</strong> kuralı gereği dolu\n * zeminli bir durum etiketi düğmeye benziyor ve kullanıcılar \"Son 2 adet\" gibi\n * bir etikete tıklamayı deniyordu. Prop çağıran tarafları kırmamak için\n * korundu, görünüm tint'e sabitlendi.\n *\n * <p>Doygun dolgu yalnızca <strong>miktar</strong> tonlarında (`action`,\n * `link`) anlamlı: onlar bir durumu değil bir sayıyı bildirir ve tıklanabilir\n * bir öğenin parçasıdır.\n */\nconst Badge: FC<Props> = ({\n children,\n tone = 'neutral',\n variant = 'soft',\n icon,\n className,\n testId,\n}) => (\n <span\n className={cx(styles.badge, styles[`badge--${tone}`], styles[`badge--${variant}`], className)}\n data-testid={testId}\n >\n {icon && <span className={styles.badge__icon}>{icon}</span>}\n {children}\n </span>\n);\n\nexport default /*#__PURE__*/ memo(Badge) as typeof Badge;\n","import { type FC, memo } from 'react';\n\nimport { CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\nexport type Crumb = {\n label: string;\n /** Son öğede verilmez: bulunduğumuz sayfa bağlantı olmaz. */\n href?: string;\n};\n\ntype Props = {\n items: Crumb[];\n /** Gezinme bölgesinin erişilebilir adı. Verilmezse `labels.breadcrumb`. */\n label?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kırıntı yolu.\n *\n * <p>Son öğe bağlantı DEĞİL ve `aria-current=\"page\"` taşır: bulunduğu sayfaya\n * bağlantı veren bir kırıntı yolu, ekran okuyucu kullanıcısını yanıltır.\n *\n * <p>Ayırıcı ikon `aria-hidden`; ekran okuyucu liste yapısından hiyerarşiyi\n * zaten anlar.\n */\nconst Breadcrumb: FC<Props> = ({ items, label, linkProps, className, testId }) => {\n const { labels } = useHanui();\n\n return (\n <nav\n className={className}\n aria-label={resolveLabel('Breadcrumb.label', label, labels?.breadcrumb)}\n data-testid={testId}\n >\n <ol className={cx(styles.breadcrumb)}>\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n\n return (\n <li key={`${item.label}-${index}`} className={styles.breadcrumb__item}>\n {item.href && !isLast ? (\n <HanuiLink href={item.href} className={styles.breadcrumb__link} {...linkProps}>\n {item.label}\n </HanuiLink>\n ) : (\n <span className={styles.breadcrumb__current} aria-current=\"page\">\n {item.label}\n </span>\n )}\n\n {!isLast && <CaretRightFill aria-hidden className={styles.breadcrumb__separator} />}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default /*#__PURE__*/ memo(Breadcrumb) as typeof Breadcrumb;\n","import { type ElementType, type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype CardProps = {\n children: ReactNode;\n /** Kartın tamamı bir hedefe götürüyorsa hover geri bildirimi açılır. */\n isInteractive?: boolean;\n /** Semantik etiket: liste öğesi kartları `article` olmalı. */\n as?: ElementType;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kart — medya + gövde + eylem şeridi.\n *\n * <h3>Neden bileşik (compound) bir bileşen</h3>\n * Bir uygulamadaki her kart (ürün, kampanya, sipariş) aynı üç bölümden oluşur\n * ama içerikleri tamamen farklıdır. Tek bir \"her şeyi yapan\" kart bileşeni on\n * beş isteğe bağlı prop'a şişiyordu. Bunun yerine <em>yerleşim</em>\n * paylaşılır, içerik çağırana bırakılır: kenarlık, yarıçap, gölge, medya oranı\n * ve eylem şeridinin dipte durması tek yerde tanımlıdır.\n *\n * <h3>Eylem şeridi hep dipte</h3>\n * {@link CardFooter} `margin-top: auto` alır. Izgarada yan yana duran kartların\n * başlıkları farklı uzunlukta olsa da alt şerit aynı hizada kalır; aksi hâlde\n * satır dalgalı görünüyordu.\n *\n * @example\n * <Card as=\"article\" isInteractive>\n * <CardMedia href=\"/urun/x\" ratio={1}>\n * <CardOverlay position=\"top-left\"><Badge>Yeni</Badge></CardOverlay>\n * <img src={…} alt=\"\" />\n * </CardMedia>\n * <CardBody>…</CardBody>\n * <CardFooter>…</CardFooter>\n * </Card>\n */\nconst Card: FC<CardProps> = ({ children, isInteractive, as: Tag = 'div', className, testId }) => (\n <Tag\n className={cx(styles.card, isInteractive && styles['card--interactive'], className)}\n data-testid={testId}\n >\n {children}\n </Tag>\n);\n\ntype CardMediaProps = {\n children: ReactNode;\n /** Genişlik / yükseklik oranı. Sabit oran yükleme sırasında kaymayı önler. */\n ratio?: number;\n /** Medya alanı tıklanabilirse: görsel bağlantının içine alınır. */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n /** İçeriği kırpmak yerine sığdırır (şeffaf zeminli ürün fotoğrafları gibi). */\n isContained?: boolean;\n className?: string;\n};\n\n/**\n * Kartın görsel alanı.\n *\n * <p>Oran <strong>sabittir</strong>: görsel yüklenene kadar yer tutar ve\n * yerleşim kaymasını (CLS) önler. Oransız bırakıldığında kartlar görseller\n * yüklendikçe zıplıyordu.\n */\nexport const CardMedia: FC<CardMediaProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, ratio = 1, href, linkProps, isContained = true, className }) => {\n const content = (\n <span\n className={cx(styles.media__frame, isContained && styles['media__frame--contained'])}\n style={{ aspectRatio: ratio }}\n >\n {children}\n </span>\n );\n\n return (\n <div className={cx(styles.media, className)}>\n {href ? (\n // `tabIndex={-1}` + `aria-hidden`: aynı hedefe giden başlık bağlantısı\n // zaten sekme sırasında. Görseli ikinci bir durak yapmak klavye\n // gezinmesini iki katına çıkarıyor, ekran okuyucuda da aynı kayıt\n // arka arkaya iki kez duyuruluyordu.\n <HanuiLink\n href={href}\n className={styles.media__link}\n tabIndex={-1}\n aria-hidden\n {...linkProps}\n >\n {content}\n </HanuiLink>\n ) : (\n content\n )}\n </div>\n );\n }),\n 'CardMedia',\n);\n\ntype CardOverlayProps = {\n children: ReactNode;\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n className?: string;\n};\n\n/**\n * Görselin üzerine binen katman: rozetler ve hızlı eylemler.\n *\n * <p>Varsayılan olarak `pointer-events: none` — rozet yığını, altındaki görsel\n * bağlantısının tıklanmasını engellememeli. İçindeki gerçek düğmeler kendi\n * olaylarını geri açar.\n */\nexport const CardOverlay: FC<CardOverlayProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, position = 'top-left', className }) => (\n <div className={cx(styles.overlay, styles[`overlay--${position}`], className)}>{children}</div>\n )),\n 'CardOverlay',\n);\n\ntype CardSectionProps = {\n children: ReactNode;\n className?: string;\n};\n\n/** Kartın metin gövdesi: başlık, açıklama, üstyazı. */\nexport const CardBody: FC<CardSectionProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, className }) => (\n <div className={cx(styles.body, className)}>{children}</div>\n )),\n 'CardBody',\n);\n\n/** Eylem şeridi — tutar, düğmeler. Kartın dibine yapışır. */\nexport const CardFooter: FC<CardSectionProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, className }) => (\n <div className={cx(styles.footer, className)}>{children}</div>\n )),\n 'CardFooter',\n);\n\nexport default /*#__PURE__*/ memo(Card) as typeof Card;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { CaretLeftFill, CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n children: ReactNode;\n /** Şeridin erişilebilir adı (\"Öne çıkan ürünler\"). ZORUNLU. */\n label: string;\n /** Önceki/sonraki düğmelerinin erişilebilir adları. ZORUNLU. */\n previousLabel: string;\n nextLabel: string;\n /**\n * Sayfa göstergesinin ad üreticisi (`index` 1 tabanlı).\n *\n * <p>Verilmediğinde nokta göstergesi ÇİZİLMEZ: adsız bir nokta ekran\n * okuyucuda \"düğme\" diye okunuyor ve kullanıcı nereye gittiğini\n * bilmiyordu.\n */\n formatDotLabel?: (index: number, total: number) => string;\n /** Bir kartın asgari genişliği. Şerit buna göre kaç kart göstereceğine karar verir. */\n itemMinWidth?: number;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kaydırılabilir şerit (carousel).\n *\n * <h3>OTOMATİK OYNATMA YOK — ve olmayacak</h3>\n * Kendiliğinden ilerleyen bir şerit WCAG 2.2.2'yi ihlal ediyor (beş saniyeden\n * uzun süren hareket duraklatılabilmeli) ama asıl sorun daha basit: kullanıcı\n * okumaya başladığı kartı kaybediyor. Bir prop olarak bile eklenmedi —\n * eklenseydi kullanılırdı.\n *\n * <h3>Kaydırma YEREL, JavaScript değil</h3>\n * Şerit `overflow-x: auto` + `scroll-snap`: dokunmatikte parmakla kaydırma,\n * masaüstünde shift+tekerlek ve <strong>klavyeyle ok tuşları</strong>\n * tarayıcıdan geliyor. JavaScript ile `transform` kaydıran bir uygulama\n * bunların hiçbirini getirmiyor ve kaydırma çubuğunu da götürüyor — kullanıcı\n * şeridin devam ettiğini göremiyordu.\n *\n * <p>Düğmeler `scrollBy` çağırıyor: yerel kaydırmayı DEĞİŞTİRMİYOR,\n * tetikliyor. İkisi aynı durumu paylaşıyor ve ayrışmaları imkânsız.\n *\n * <h3>Şerit klavyeyle ULAŞILABİLİR</h3>\n * Kaydırılabilir bir kutu, içinde odaklanabilir öğe yoksa `tabindex`\n * verilmediğinde klavye kullanıcısı için ulaşılamaz (WCAG 2.1.1). Şerit\n * genellikle bağlantı taşıyan kartlardan oluşuyor ve o durumda ek bir durak\n * gereksiz — bu yüzden `tabindex` yalnızca <strong>odaklanabilir çocuk\n * yoksa</strong> yazılıyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>önceki/sonraki düğmelerine ve kartların içine</td></tr>\n * <tr><td>ok tuşları</td><td>şeridi kaydırır (yerel)</td></tr>\n * </table>\n */\nconst Carousel: FC<Props> = ({\n children,\n label,\n previousLabel,\n nextLabel,\n formatDotLabel,\n itemMinWidth = 240,\n className,\n testId,\n}) => {\n const trackRef = useRef<HTMLDivElement>(null);\n\n const [canScrollBack, setCanScrollBack] = useState(false);\n const [canScrollForward, setCanScrollForward] = useState(false);\n const [page, setPage] = useState(0);\n /* Sayfa SAYISI da olculur: cocuk sayisindan hesaplamak, kac kartin yan yana\n sigdigini bilmeyi gerektiriyor ve o sey yalnizca yerlesimden okunur. */\n const [pageCount, setPageCount] = useState(1);\n const [needsTabStop, setNeedsTabStop] = useState(false);\n\n /*\n * DURUM SERIDIN KENDISINDEN OKUNUR, sayilmaz.\n *\n * Once \"kacinci karttayiz\" bir sayacla tutuluyordu ve parmakla kaydirma o\n * sayaci hic guncellemiyordu: kullanici elle kaydirdiktan sonra ok\n * dugmesine bastiginda serit basa ziplyordu.\n */\n const measure = useCallback(() => {\n const track = trackRef.current;\n if (!track) return;\n\n const { scrollLeft, scrollWidth, clientWidth } = track;\n /* 1 px tolerans: alt piksel yuvarlama yuzunden uctaki dugme hicbir zaman\n pasiflesmiyordu. */\n setCanScrollBack(scrollLeft > 1);\n setCanScrollForward(scrollLeft + clientWidth < scrollWidth - 1);\n setPage(clientWidth > 0 ? Math.round(scrollLeft / clientWidth) : 0);\n setPageCount(clientWidth > 0 ? Math.max(1, Math.ceil(scrollWidth / clientWidth)) : 1);\n\n /* Odaklanabilir cocugu olan bir seride ek bir Tab duragi gereksiz. */\n setNeedsTabStop(\n scrollWidth > clientWidth &&\n track.querySelector('a, button, input, select, textarea, [tabindex]') === null,\n );\n }, []);\n\n useEffect(() => {\n const track = trackRef.current;\n if (!track) return;\n\n measure();\n track.addEventListener('scroll', measure, { passive: true });\n\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure);\n observer?.observe(track);\n\n return () => {\n track.removeEventListener('scroll', measure);\n observer?.disconnect();\n };\n }, [measure, children]);\n\n /* Bir GORUNUM genisligi kaydirir: sabit bir kart sayisi, farkli genislikteki\n kartlarda serit ortasinda duruyordu. */\n const scrollByPage = (direction: 1 | -1) =>\n trackRef.current?.scrollBy({\n left: direction * trackRef.current.clientWidth,\n behavior: 'smooth',\n });\n\n return (\n <section className={cx(styles.carousel, className)} aria-label={label} data-testid={testId}>\n <div className={styles.carousel__controls}>\n <IconButton\n icon={<CaretLeftFill aria-hidden className={styles.carousel__arrowIcon} />}\n label={previousLabel}\n variant=\"outline\"\n size=\"sm\"\n disabled={!canScrollBack}\n onClick={() => scrollByPage(-1)}\n />\n <IconButton\n icon={<CaretRightFill aria-hidden className={styles.carousel__arrowIcon} />}\n label={nextLabel}\n variant=\"outline\"\n size=\"sm\"\n disabled={!canScrollForward}\n onClick={() => scrollByPage(1)}\n />\n </div>\n\n <div\n ref={trackRef}\n className={styles.carousel__track}\n style={{ '--hanui-carousel-item': `${itemMinWidth}px` } as React.CSSProperties}\n /* Yalnizca odaklanabilir cocugu OLMAYAN bir seride durak: aksi halde\n klavye kullanicisi hicbir sey yapmayan bir durak geciyordu. */\n tabIndex={needsTabStop ? 0 : undefined}\n role={needsTabStop ? 'group' : undefined}\n aria-label={needsTabStop ? label : undefined}\n >\n {children}\n </div>\n\n {formatDotLabel && pageCount > 1 && (\n <div className={styles.carousel__dots}>\n {Array.from({ length: pageCount }, (_, index) => (\n <button\n key={index}\n type=\"button\"\n className={cx(\n styles.carousel__dot,\n index === page && styles['carousel__dot--active'],\n )}\n /* Nokta ADSIZ birakilamaz: ekran okuyucuda \"dugme\" diye\n okunuyor ve kullanici nereye gittigini bilmiyordu. */\n aria-label={formatDotLabel(index + 1, pageCount)}\n aria-current={index === page ? 'true' : undefined}\n onClick={() =>\n trackRef.current?.scrollTo({\n left: index * trackRef.current.clientWidth,\n behavior: 'smooth',\n })\n }\n />\n ))}\n </div>\n )}\n </section>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Carousel, 'Carousel')) as typeof Carousel;\n","'use client';\n\nimport { type FC, memo, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { ClipboardCheckFill, ClipboardFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveFormatter, resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Gösterilecek ve panoya kopyalanacak değer. */\n value: string;\n /**\n * Kopyalama düğmesinin erişilebilir adı ve `title`ı.\n *\n * <p>Verilmezse `labels.copyField.copy(value)` çağrılır. Config bir DİZE\n * değil biçimlendirici tutar: ad değeri İÇERMELİ — bir listede on beş\n * kopyalama düğmesi var ve hepsi \"Kopyala\" diye okunduğunda ekran okuyucu\n * kullanıcısı hangisinin hangi kayıt olduğunu bilmiyordu.\n */\n copyLabel?: string;\n /** Kopyalandıktan sonraki ad. Verilmezse `labels.copyField.copied(value)`. */\n copiedLabel?: string;\n /** `aria-live` ile duyurulan onay cümlesi. Verilmezse `labels.copyField.announcement`. */\n copiedAnnouncement?: string;\n size?: 'sm' | 'md';\n /**\n * Kopyalama düğmesini gizler.\n *\n * <p>Yalnızca değerin <em>zaten tıklanabilir bir şeyin içinde</em> olduğu\n * yerlerde (bir bağlantının gövdesi) verilir: iç içe etkileşim öğesi geçersiz\n * HTML üretir.\n */\n isReadOnly?: boolean;\n className?: string;\n testId?: string;\n};\n\n/** \"Kopyalandı\" geri bildiriminin ekranda kalma suresi (ms). */\nconst COPIED_FEEDBACK_MS = 1600;\n\n/**\n * Kopyalanabilir teknik değer — <strong>tek dokunuşla panoya</strong>.\n *\n * <h3>Neden ayrı bir öğe</h3>\n * Bir kod (SKU, parça numarası, sipariş numarası, IBAN) dekoratif bir metin\n * değil, kullanıcının <em>taşıdığı</em> veri. Düz bir `<span>` olduğunda\n * kullanıcı onu fareyle seçmeye çalışırken kartın tamamını seçiyor ya da\n * yanlışlıkla altındaki bağlantıyı tetikliyordu.\n *\n * <h3>Neden monospace</h3>\n * \"0986479644\" gibi diziler orantılı yazı tipinde okunmuyor: `0`/`O` ve `1`/`l`\n * ayırt edilemiyor ve bir hane atlandığında tamamen başka bir kayıt oluyor.\n * `technical-text` sabit genişlik + `tabular-nums` verir; iki değer alt alta\n * geldiğinde farklı hane gözle bulunur.\n *\n * <h3>Geri bildirim neden düğmenin üstünde</h3>\n * Bir bildirim (toast) da olurdu ama listelerde on beş satır var; ekranın\n * dibinde \"kopyalandı\" yazması <em>hangisinin</em> kopyalandığını\n * söylemiyordu. İkon yerinde tike dönünce cevap tıklanan yerde.\n *\n * <h3>Pano erişimi reddedilirse</h3>\n * `navigator.clipboard` güvenli olmayan bağlamda (HTTP) ve izin verilmediğinde\n * reddeder. O durumda değer sessizce <em>seçilir</em>: kullanıcı Ctrl+C ile\n * kendisi kopyalayabilir. Sessizce hiçbir şey yapmamak, düğmeyi bozuk\n * gösteriyordu.\n */\nconst CopyField: FC<Props> = ({\n value,\n copyLabel,\n copiedLabel,\n copiedAnnouncement,\n size = 'sm',\n isReadOnly,\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const [isCopied, setIsCopied] = useState(false);\n const codeRef = useRef<HTMLSpanElement>(null);\n const timerRef = useRef<number | undefined>(undefined);\n\n // Bilesen sokulurse zamanlayici da gitmeli; aksi halde React \"unmounted\n // component\" uyarisi veriyor.\n useEffect(() => () => window.clearTimeout(timerRef.current), []);\n\n const selectValue = useCallback(() => {\n const node = codeRef.current;\n if (!node) return;\n\n const range = document.createRange();\n range.selectNodeContents(node);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n }, []);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(value);\n setIsCopied(true);\n timerRef.current = window.setTimeout(() => setIsCopied(false), COPIED_FEEDBACK_MS);\n } catch {\n // Pano yoksa/izin verilmediyse en azindan secili birakilir.\n selectValue();\n }\n }, [value, selectValue]);\n\n return (\n <span className={cx(styles.copy, styles[`copy--${size}`], className)} data-testid={testId}>\n {/*\n `user-select: all` (CSS): tek tiklama degerin TAMAMINI secer.\n Kullanicilar fareyle surukleyip yarim deger kopyaliyordu.\n */}\n <span className={styles.copy__code} ref={codeRef}>\n {value}\n </span>\n\n {!isReadOnly && (\n <button\n type=\"button\"\n className={cx(styles.copy__button, isCopied && styles['copy__button--done'])}\n onClick={handleCopy}\n aria-label={\n isCopied\n ? (copiedLabel ??\n resolveFormatter('CopyField.copiedLabel', labels?.copyField?.copied, value))\n : (copyLabel ??\n resolveFormatter('CopyField.copyLabel', labels?.copyField?.copy, value))\n }\n title={\n isCopied\n ? (copiedLabel ??\n resolveFormatter('CopyField.copiedLabel', labels?.copyField?.copied, value))\n : (copyLabel ??\n resolveFormatter('CopyField.copyLabel', labels?.copyField?.copy, value))\n }\n >\n {/*\n Kopyalandi ISARETLI PANO, yalin tik degil: yalin tik \"dogru\n deger\" diye de okunabiliyordu. Ayni gövde + tik, degisimin\n kopyalama eylemine ait oldugunu birakiyor.\n */}\n {isCopied ? <ClipboardCheckFill aria-hidden /> : <ClipboardFill aria-hidden />}\n </button>\n )}\n\n {/*\n Ekran okuyucu icin: ikon degisimi gorsel bir sinyal, duyulmuyor.\n `aria-live` yalnizca DEGISTIGINDE konusur.\n */}\n <span aria-live=\"polite\" className={styles.copy__srOnly}>\n {isCopied\n ? resolveLabel(\n 'CopyField.copiedAnnouncement',\n copiedAnnouncement,\n labels?.copyField?.announcement,\n )\n : ''}\n </span>\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(CopyField) as typeof CopyField;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Ortada gösterilen metin (\"veya\"). */\n label?: string;\n className?: string;\n};\n\n/**\n * Ayırıcı çizgi.\n *\n * <p>Etiketli hâli `role=\"separator\"` taşımaz: metin içerdiğinde ekran okuyucu\n * onu ayırıcı değil içerik olarak okumalı (\"veya\").\n */\nconst Divider: FC<Props> = ({ label, className }) =>\n label ? (\n <div className={cx(styles.divider, styles['divider--labelled'], className)}>\n <span className={styles.divider__label}>{label}</span>\n </div>\n ) : (\n <hr className={cx(styles.divider, className)} />\n );\n\nexport default /*#__PURE__*/ memo(Divider) as typeof Divider;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype DirectoryProps = {\n children: ReactNode;\n className?: string;\n};\n\n/**\n * Dizin — harf veya konu başlıklı, gruplanmış bağlantı listesi.\n *\n * <h3>Neden ortak bir bileşen</h3>\n * Bir marka dizini ile bir kategori dizini aynı işi yapıyor: yüzlerce\n * bağlantıyı gruplayıp taranabilir kılmak. Ama iki container bunu ayrı ayrı\n * kurmuştu ve sonuç iki farklı sayfa oldu — birinde grup başlığı alt çizgili\n * 19 px, diğerinde çizgisiz; birinde satırlar ızgarada, diğerinde tek kolonda.\n *\n * <p>Ortak olan <em>görsel dilbilgisi</em>: grup başlığı + ızgara + satır\n * öğesi. O buraya taşındı; ne listelendiği çağırana kaldı.\n *\n * @example\n * <Directory>\n * <DirectoryGroup label=\"A\">\n * <DirectoryRow href=\"/marka/ate\" name=\"ATE\" media={<img … />} />\n * </DirectoryGroup>\n * </Directory>\n */\nconst Directory: FC<DirectoryProps> = ({ children, className }) => (\n <div className={cx(styles.directory, className)}>{children}</div>\n);\n\ntype DirectoryGroupProps = {\n /** Grup başlığı: harf (\"A\", \"0-9\") veya konu (\"Fren sistemi\"). */\n label: string;\n /**\n * Başlık kendisi bir hedefe götürüyorsa. Harf gruplarında verilmez — \"A\"\n * diye bir sayfa yok.\n */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n /** Başlığın sağında duran sayaç (\"14 alt kategori\"). */\n meta?: ReactNode;\n children: ReactNode;\n /** Çıpa hedefi: alfabe şeridinden atlamak için. */\n id?: string;\n};\n\n/**\n * Dizin grubu.\n *\n * <p>Başlık <strong>yapışkan</strong>: uzun bir listede kaydırırken hangi\n * harfte olduğunu görmek, listeyi yukarı sarıp kontrol etmekten iyi.\n */\nexport const DirectoryGroup: FC<DirectoryGroupProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ label, href, linkProps, meta, children, id }) => (\n <section className={styles.group} id={id}>\n <header className={styles.group__header}>\n <h2 className={styles.group__label}>\n {href ? (\n <HanuiLink href={href} className={styles.group__link} {...linkProps}>\n {label}\n </HanuiLink>\n ) : (\n label\n )}\n </h2>\n {meta && <span className={styles.group__meta}>{meta}</span>}\n </header>\n\n <ul className={styles.group__list}>{children}</ul>\n </section>\n )),\n 'DirectoryGroup',\n);\n\ntype DirectoryRowProps = {\n href: string;\n name: string;\n /** Logo, ikon veya baş harf madalyonu. Satırın solunda. */\n media?: ReactNode;\n /** Sağ uçta duran işaret: rozet, kayıt sayısı. */\n marker?: ReactNode;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n className?: string;\n};\n\n/**\n * Dizin satırı — tek bir bağlantı.\n *\n * <p>Tüm satır tıklanabilir ve en az 44 px yüksekliğinde (WCAG 2.5.8):\n * yalnızca metnin tıklanabilir olduğu bir listede dokunmatik kullanıcılar\n * satırın boşluğuna basıp hiçbir şey olmadığını görüyordu.\n */\nexport const DirectoryRow: FC<DirectoryRowProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ href, name, media, marker, linkProps, className }) => (\n <li>\n <HanuiLink href={href} className={cx(styles.row, className)} {...linkProps}>\n {media && <span className={styles.row__media}>{media}</span>}\n <span className={styles.row__name}>{name}</span>\n {marker && <span className={styles.row__marker}>{marker}</span>}\n </HanuiLink>\n </li>\n )),\n 'DirectoryRow',\n);\n\ntype DirectoryJumpProps = {\n /** Grup etiketleri; her biri kendi çıpasına bağlanır. */\n labels: string[];\n /** Çıpa kimliğini üretir; `DirectoryGroup id` ile aynı olmalı. */\n toId: (label: string) => string;\n /** Şeridin erişilebilir adı. Verilmezse `labels.directoryJump`. */\n label?: string;\n};\n\n/**\n * Alfabe atlama şeridi.\n *\n * <p>Uzun bir listede \"V\" harfine ulaşmak için kaydırmak dakikalar alıyordu.\n * Şerit yatay kayar ve `#çıpa` bağlantıları taşır — JavaScript gerekmez,\n * tarayıcı kaydırmayı kendisi yapar ve bağlantı paylaşılabilir.\n *\n * <p>Bağlantılar HAM `<a>`: bunlar sayfa içi çıpa, gezinme değil. Bir\n * yönlendiriciden geçirmek aynı sayfayı yeniden çözümleyip kaydırmayı\n * kaçırıyordu.\n */\nexport const DirectoryJump: FC<DirectoryJumpProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ labels, toId, label }) => {\n /* Prop adi `labels` (grup etiketleri) config'in adiyla cakisiyor; config\n `config` olarak alinir. */\n const { labels: config } = useHanui();\n\n return (\n <nav\n className={styles.jump}\n aria-label={resolveLabel('DirectoryJump.label', label, config?.directoryJump)}\n >\n {labels.map(item => (\n <a key={item} href={`#${toId(item)}`} className={styles.jump__link}>\n {item}\n </a>\n ))}\n </nav>\n );\n }),\n 'DirectoryJump',\n);\n\nexport default /*#__PURE__*/ memo(Directory) as typeof Directory;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n description?: string;\n icon?: ReactNode;\n /** Kullanıcının buradan çıkabileceği eylem. */\n action?: ReactNode;\n /** İkincil eylem veya ipucu. */\n secondaryAction?: ReactNode;\n /**\n * `error` — liste BOŞ değil, ÇEKİLEMEDİ.\n *\n * <p>İkisi ayrı durumlar ve ayrı görünmek zorundalar: ağ hatasını \"kayıt\n * kalmamış\" diye okuyan kullanıcı yanlış karar veriyor (ürün aramayı\n * bırakıyor, siparişinin silindiğini sanıyor). Varyant `role=\"alert\"`\n * taşıyor ve tonu farklı — layout aynı kalıyor ki iki durum arasındaki\n * geçiş sıçramasın.\n *\n * <p>Ayrım ÖNCE bu bileşenin dışındaydı (\"ağ hatasında bu bileşen\n * çizilmez\") ve sonucu şuydu: her çağıran kendi hata kutusunu yazıyor,\n * kutular birbirinden farklı görünüyordu. Ayrım korunuyor — ama artık\n * BİLEŞENDE kodlu, çağıranın disiplinine bırakılmış değil.\n */\n tone?: 'empty' | 'error';\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Boş durum.\n *\n * <h3>Neden her boş durum bir eylem taşır</h3>\n * \"Sonuç bulunamadı\" tek başına çıkmaz sokaktır. Kullanıcı o ekranda ne\n * yapacağını bilmeli: aramayı temizle, filtreyi kaldır, listeye dön. `action`\n * isteğe bağlı ama çağıran taraf onu vermezse kullanıcı tıkanır.\n *\n * <h3>BOŞ ile YÜKLENEMEDİ ayrı durumlardır</h3>\n * Ağ hatasını \"kayıt kalmamış\" diye okuyan kullanıcı yanlış karar veriyor.\n * İkisi `tone` ile ayrılıyor: `error` farklı bir ton taşıyor ve\n * `role=\"alert\"` ile duyuruluyor, ama YERLEŞİM aynı — iki durum arasındaki\n * geçiş sıçramıyor.\n *\n * <p>Ayrım önce bu bileşenin DIŞINDAYDI (\"ağ hatasında çizilmez\") ve sonucu\n * şuydu: her çağıran kendi hata kutusunu yazıyor, kutular birbirinden farklı\n * görünüyordu. Ayrım korunuyor, kararın yeri değişti.\n */\nconst EmptyState: FC<Props> = ({\n title,\n description,\n icon,\n action,\n secondaryAction,\n tone = 'empty',\n size = 'md',\n className,\n testId,\n}) => (\n <div\n className={cx(styles.empty, styles[`empty--${size}`], styles[`empty--${tone}`], className)}\n /* Hata DUYURULUR: gormeyen kullanici icin sessizce degisen bir liste, hic\n degismemis demekti. Bos durum duyurulmaz — o beklenen bir sonuc. */\n role={tone === 'error' ? 'alert' : undefined}\n data-testid={testId}\n >\n {icon && <span className={styles.empty__icon}>{icon}</span>}\n <h3 className={styles.empty__title}>{title}</h3>\n {description && <p className={styles.empty__description}>{description}</p>}\n {(action || secondaryAction) && (\n <div className={styles.empty__actions}>\n {action}\n {secondaryAction}\n </div>\n )}\n </div>\n);\n\nexport default /*#__PURE__*/ memo(EmptyState) as typeof EmptyState;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n /** Başlığın üstündeki küçük bağlam etiketi (\"HESABIM\", \"KATEGORİ\"). */\n eyebrow?: string;\n /** Bir cümlelik açıklama. 68ch ile sınırlı tutulur. */\n description?: ReactNode;\n /** Sağ tarafta duran eylemler. Dar ekranda başlığın altına düşer. */\n actions?: ReactNode;\n /** Başlık satırının üstündeki kırıntı yolu. */\n breadcrumb?: ReactNode;\n /**\n * Başlığın yanındaki sayaç (\"1.248 kayıt\"). Açıklamanın değil BAŞLIĞIN\n * hizasında durur; kullanıcı sayıyı başlıkla birlikte okur.\n */\n meta?: ReactNode;\n /** Başlık bloğunun altında duran ek içerik (filtre şeridi, sekmeler). */\n children?: ReactNode;\n /** `h1` sayfada bir kez bulunur; iç bölümler `h2` alır. */\n as?: 'h1' | 'h2';\n className?: string;\n testId?: string;\n};\n\n/**\n * Sayfa başlığı — her ekranın aynı giriş bloğu.\n *\n * <h3>Neden ortak bir bileşen</h3>\n * Önceden her container kendi başlığını kuruyordu: bir sayfada punto 29 px,\n * diğerinde 23 px; birinde açıklama başlığın altında, birinde yanında;\n * boşluklar 8 px ile 24 px arasında dolaşıyordu. Sayfalar arası geçiş \"başka\n * bir siteye geçtim\" hissi veriyordu. Bu bileşen o kararları tek yerde verir.\n *\n * <h3>Açıklama genişliği sınırlı</h3>\n * Başlık tam genişlikte akabilir ama açıklama 68ch'de durur: 1360 px\n * genişlikte akan bir açıklama satırında göz satır sonunda yerini kaybediyor.\n *\n * <h3>Eylemler `flex-end`</h3>\n * Düğmeler başlık bloğunun ALT kenarına hizalanır. `baseline` verildiğinde iki\n * satırlık başlıklarda düğme ilk satıra çekiliyordu.\n */\nconst PageHeader: FC<Props> = ({\n title,\n eyebrow,\n description,\n actions,\n breadcrumb,\n meta,\n children,\n as: Heading = 'h1',\n className,\n testId,\n}) => (\n <header className={cx(styles.header, className)} data-testid={testId}>\n {breadcrumb}\n\n <div className={styles.header__top}>\n <div className={styles.header__text}>\n {eyebrow && <span className={styles.header__eyebrow}>{eyebrow}</span>}\n\n <div className={styles.header__titleRow}>\n <Heading className={styles.header__title}>{title}</Heading>\n {meta && <span className={styles.header__meta}>{meta}</span>}\n </div>\n\n {description && <p className={styles.header__description}>{description}</p>}\n </div>\n\n {actions && <div className={styles.header__actions}>{actions}</div>}\n </div>\n\n {children}\n </header>\n);\n\nexport default /*#__PURE__*/ memo(PageHeader) as typeof PageHeader;\n","import { type ElementType, type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n children: ReactNode;\n /** Panel başlığı. Verilmezse başlık şeridi hiç çizilmez. */\n title?: string;\n /** Başlık altındaki tek satırlık açıklama. */\n description?: ReactNode;\n /** Başlık şeridinin sağında duran eylemler. */\n actions?: ReactNode;\n /** Başlık şeridindeki ikon; başlığın solunda. */\n icon?: ReactNode;\n /** Gövde dolgusunu kaldırır: tablo ve tam genişlikte listeler için. */\n isFlush?: boolean;\n /** Gövde içindeki dikey aralık. */\n gap?: 'sm' | 'md' | 'lg';\n /** Dipte duran eylem şeridi (form kaydet, toplam). */\n footer?: ReactNode;\n as?: ElementType;\n className?: string;\n bodyClassName?: string;\n testId?: string;\n};\n\n/**\n * Panel — başlığı olan içerik kutusu.\n *\n * <h3>Neden bu bileşen var</h3>\n * Bir uygulamanın on bir ayarlar sayfası, on bir farklı kart kuruyordu:\n * birinde dolgu 16 px diğerinde 24 px, birinde başlık kartın içinde diğerinde\n * dışında, birinde `max-width: 560px` diğerinde tam genişlik. Aynı disiplinde\n * görünmeleri için kararların tek yerde verilmesi gerekiyordu.\n *\n * <h3>Genişlik paneli DEĞİL içeriği sınırlar</h3>\n * Panel her zaman kapsayıcısını doldurur. Form alanlarının okunabilir satır\n * uzunluğunu aşmaması gerekiyorsa {@link PanelForm} kullanılır — o iç ızgarayı\n * sınırlar, panelin kendisini daraltmaz. Önceden bir \"profil düzenle\" paneli\n * sayfanın üçte biri kadar kalıp yanındaki boşluğa bakıyordu; sorun formun\n * değil PANELİN daraltılmasıydı.\n *\n * @example\n * <Panel title=\"Profil bilgileri\" description=\"Fatura bu bilgilerle kesilir\">\n * <PanelForm>…alanlar…</PanelForm>\n * </Panel>\n */\nconst Panel: FC<Props> = ({\n children,\n title,\n description,\n actions,\n icon,\n isFlush,\n gap = 'md',\n footer,\n as: Tag = 'section',\n className,\n bodyClassName,\n testId,\n}) => (\n <Tag className={cx(styles.panel, className)} data-testid={testId}>\n {(title || actions) && (\n <div className={styles.panel__header}>\n <div className={styles.panel__heading}>\n {icon && <span className={styles.panel__icon}>{icon}</span>}\n\n <div className={styles.panel__headingText}>\n {title && <h2 className={styles.panel__title}>{title}</h2>}\n {description && <p className={styles.panel__description}>{description}</p>}\n </div>\n </div>\n\n {actions && <div className={styles.panel__actions}>{actions}</div>}\n </div>\n )}\n\n <div\n className={cx(\n styles.panel__body,\n styles[`panel__body--${gap}`],\n isFlush && styles['panel__body--flush'],\n bodyClassName,\n )}\n >\n {children}\n </div>\n\n {footer && <div className={styles.panel__footer}>{footer}</div>}\n </Tag>\n);\n\ntype PanelFormProps = {\n children: ReactNode;\n /** Sütun sayısı. `2` dar ekranda kendiliğinden tek sütuna düşer. */\n columns?: 1 | 2;\n className?: string;\n};\n\n/**\n * Panel içindeki form ızgarası.\n *\n * <p>Genişliği SINIRLI (`$measure-narrow`): girdi alanları okunabilir satır\n * uzunluğunun ötesine uzamamalı — 900 px genişliğinde bir metin kutusu\n * doldurulması zor görünür. Ama bu sınır PANELE değil ızgaraya uygulanır;\n * panel tam genişlikte kalır ve sayfa düzeni bozulmaz.\n */\nexport const PanelForm: FC<PanelFormProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, columns = 1, className }) => (\n <div className={cx(styles.form, styles[`form--${columns}`], className)}>{children}</div>\n )),\n 'PanelForm',\n);\n\ntype PanelRowProps = {\n children: ReactNode;\n className?: string;\n};\n\n/**\n * İki alanı yan yana koyan satır. Dar ekranda alt alta düşer.\n *\n * <p>`PanelForm columns={2}` tüm ızgarayı ikiye böler; bu yalnızca TEK bir\n * satırı böler (ad + soyad gibi).\n */\nexport const PanelRow: FC<PanelRowProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, className }) => (\n <div className={cx(styles.row, className)}>{children}</div>\n )),\n 'PanelRow',\n);\n\nexport default /*#__PURE__*/ memo(Panel) as typeof Panel;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** BİÇİMLENMİŞ tutar: \"1.299,90\". Bileşen hesap yapmaz. */\n value: string;\n /** Para birimi simgesi ya da kodu. Verilmezse `labels.currency`. */\n currency?: string;\n /**\n * Değeri `Intl.NumberFormat` ile biçimlendirir.\n *\n * <p>`value` bu kipte de bir DİZE olarak kalıyor ve sayıya çevriliyor —\n * bileşen hâlâ HESAP YAPMIYOR, yalnızca ayırıcıları ve para birimi\n * konumunu yerel ayardan alıyor. Yerel ayar `labels.locale`den; verilmezse\n * biçimlendirme YAPILMAZ ve değer olduğu gibi yazılır. Yanlış yerel ayarda\n * biçimlendirilmiş bir tutar, biçimlendirilmemiş olandan kötü: \"1,250\" bir\n * yerde bin iki yüz elli, başka bir yerde bir tam iki yüz elli.\n *\n * <p>Para birimi simgesinin ÖN/ARKA konumu da yerel ayara bağlı ve şu anda\n * her zaman arkada — `Intl` açıldığında doğru konumu o veriyor.\n */\n isFormatted?: boolean;\n /** Üstü çizili liste fiyatı; indirim varsa verilir (biçimlenmiş). */\n listValue?: string;\n /** İndirim oranı (tam sayı yüzde). */\n discountPercent?: number;\n /** İndirim rozetinin metnini üretir (\"%20\", \"-20%\"). */\n formatDiscount?: (percent: number) => string;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n className?: string;\n testId?: string;\n};\n\n/**\n * Tutar gösterimi.\n *\n * <h3>Bileşen HESAP YAPMAZ</h3>\n * Tutar biçimlenmiş gelir. Kuruşu istemcide çevirmek kayan nokta hatası riski\n * taşır ve biçimlendirme iki yerde ayrışır: aynı ürün listede \"1.299,90\",\n * detayda \"1299.9\" çıkıyordu. İndirim oranı da dışarıdan gelir — burada\n * `(1 - fiyat/liste)` hesaplamak için biçimlenmiş metni sayıya çevirmek\n * gerekirdi ve o kırılgan bir iş.\n *\n * <h3>Tutar NÖTR kalır</h3>\n * Güncel tutar `$text`; üstü çizili eski tutar `$text-3`; indirim yüzdesi\n * küçük bir yeşil rozet. Kırmızı fiyat ucuz durur ve kırmızıyı \"olumsuz\"\n * anlamından koparır.\n */\nconst Price: FC<Props> = ({\n value,\n currency,\n listValue,\n discountPercent,\n formatDiscount = percent => `%${percent}`,\n isFormatted,\n size = 'md',\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const symbol = resolveLabel('Price.currency', currency, labels?.currency);\n\n /*\n * BICIMLENDIRME OPSIYONEL ve yerel ayara BAGLI.\n *\n * Yerel ayar verilmediginde deger olduğu gibi yaziliyor: yanlis yerel ayarda\n * bicimlendirilmis bir tutar, bicimlendirilmemis olandan kotu — \"1,250\" bir\n * yerde bin iki yuz elli, baska bir yerde bir tam iki yuz elli.\n *\n * Cevrilemeyen bir deger de oldugu gibi kalir. Bir bicimlendirme hatasi\n * FIYATI gizleyemez; ekranda bir sey olmamasindan iyisi ham degerdir.\n */\n const format = (raw: string): string => {\n if (!isFormatted || !labels?.locale) return raw;\n\n /*\n * RAKAM ICERMEYEN deger biciMLENDIRILMEZ. Soyma adimi \"Fiyat sorunuz\"u\n * bos dizeye indiriyor, `Number('')` ise 0: ekranda tutar yerine \"0\"\n * yaziyordu — yani fiyat alani dolu gorunup icerigi YANLIS oluyordu.\n * Bicimlendirilemeyen deger oldugu gibi yazilir.\n */\n if (!/\\d/.test(raw)) return raw;\n\n const numeric = Number(\n raw\n .replace(/[^\\d.,-]/g, '')\n .replace(/\\.(?=\\d{3}\\b)/g, '')\n .replace(',', '.'),\n );\n if (!Number.isFinite(numeric)) return raw;\n\n try {\n return new Intl.NumberFormat(labels.locale).format(numeric);\n } catch {\n return raw;\n }\n };\n\n return (\n <span className={cx(styles.price, styles[`price--${size}`], className)} data-testid={testId}>\n <span className={styles.price__current}>\n {format(value)}\n <span className={styles.price__currency}>{symbol}</span>\n </span>\n\n {listValue && (\n <s className={styles.price__list}>\n {format(listValue)}\n <span className={styles.price__currency}>{symbol}</span>\n </s>\n )}\n\n {/* `isDefined` DEGIL acik karsilastirma: handy-utils'in koruyucusu\n `Exclude<any, …>` donuyor ve TypeScript'te daraltma uretmiyor. */}\n {discountPercent !== undefined && discountPercent > 0 && (\n <span className={styles.price__discount}>{formatDiscount(discountPercent)}</span>\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Price) as typeof Price;\n","import { type FC, memo } from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { StarFill, StarHalf } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveFormatter } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** 0–5 arası puan. Yarım yıldız desteklenir. */\n value: number;\n /** Değerlendirme sayısı; verilirse yıldızların yanında gösterilir. */\n count?: number;\n /**\n * Ekran okuyucuya okunan metin.\n *\n * <p>Yıldızlar `aria-hidden`: beş ayrı ikonu tek tek duyurmak anlamsız.\n * Yerine bir cümle okunur (\"5 üzerinden 4,5 — 12 değerlendirme\") ve o cümle\n * hem dile hem sayı biçimine bağlı; kütüphane onu uyduramaz.\n *\n * <p>Verilmezse `labels.rating.srLabel(value, count)` çağrılır — cümle\n * değere bağlı olduğu için config bir DİZE değil bir biçimlendirici tutar.\n */\n srLabel?: string;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Yıldız puanı — salt gösterim.\n *\n * <p>Ortalama sunucuda hesaplanır; burada yalnızca gösterilir. Puanı\n * istemcide hesaplamak, sayfalama yüzünden eksik veriyle yanlış ortalama\n * üretirdi.\n *\n * <p>Etkileşimli kardeşi {@link RatingInput}.\n */\nconst Rating: FC<Props> = ({ value, count, srLabel, size = 'sm', className, testId }) => {\n const { labels } = useHanui();\n const rounded = Math.round(value * 2) / 2;\n\n return (\n <span className={cx(styles.rating, styles[`rating--${size}`], className)} data-testid={testId}>\n {/*\n * BOS YILDIZ DA DOLU — farkı renk taşır (`rating__empty`), çizgi değil.\n *\n * <p>İçi boş yıldız yalnızca bir konturdur: dolu komşusunun yanında\n * \"eksik çizilmiş\" gibi durur ve küçük boyda kontur tek piksele inip\n * kayboluyordu. Aynı gövde + soluk ton, beş yıldızın silüetini bozmadan\n * doluluğu okutur.\n */}\n <span className={styles.rating__stars} aria-hidden>\n {Array.from({ length: 5 }, (_, index) => {\n const position = index + 1;\n if (rounded >= position) return <StarFill key={index} />;\n if (rounded >= position - 0.5) return <StarHalf key={index} />;\n return <StarFill key={index} className={styles.rating__empty} />;\n })}\n </span>\n\n <span className={styles.rating__srOnly}>\n {srLabel ?? resolveFormatter('Rating.srLabel', labels?.rating?.srLabel, value, count)}\n </span>\n\n {isDefined(count) && (\n <span className={styles.rating__count} aria-hidden>\n ({count})\n </span>\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Rating) as typeof Rating;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n description?: string;\n /** Üstte gösterilen küçük büyük-harf etiket. */\n overline?: string;\n /** Sağda gösterilen eylem (\"Tümünü gör\"). */\n action?: ReactNode;\n as?: 'h1' | 'h2' | 'h3';\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n testId?: string;\n};\n\n/**\n * Bölüm başlığı.\n *\n * <p>Başlık düzeyi (`as`) görsel boyuttan (`size`) <strong>ayrı</strong>:\n * sayfa hiyerarşisi anlamsal olmak zorunda ama görsel boyut bağlamla değişir.\n * İkisini birbirine bağlamak, doğru görünüm için yanlış başlık düzeyi seçmeye\n * zorlardı.\n */\nconst SectionHeader: FC<Props> = ({\n title,\n description,\n overline,\n action,\n as: Heading = 'h2',\n size = 'md',\n className,\n testId,\n}) => (\n <header className={cx(styles.header, styles[`header--${size}`], className)} data-testid={testId}>\n <div className={styles.header__text}>\n {overline && <span className={styles.header__overline}>{overline}</span>}\n <Heading className={styles.header__title}>{title}</Heading>\n {description && <p className={styles.header__description}>{description}</p>}\n </div>\n\n {action && <div className={styles.header__action}>{action}</div>}\n </header>\n);\n\nexport default /*#__PURE__*/ memo(SectionHeader) as typeof SectionHeader;\n","'use client';\n\nimport { type FC, type ReactNode, memo, useEffect, useRef, useState } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n children: ReactNode;\n /**\n * Kaydırılabilir bölgenin erişilebilir adı. ZORUNLU.\n *\n * <p>Bölge klavyeyle odaklanabilir olduğunda ekran okuyucu onu duyuruyor;\n * adsız bir bölge \"bölge\" diye okunuyor ve kullanıcı neyin içinde olduğunu\n * bilmiyordu.\n */\n label: string;\n /** Kaydırma yönü. `both` iki eksende de kaydırır. */\n axis?: 'vertical' | 'horizontal' | 'both';\n /** En fazla yükseklik — dikey kaydırmada zorunlu, yoksa kutu uzar gider. */\n maxHeight?: number | string;\n /** Kenarlarda içeriğin devam ettiğini gösteren solma. */\n hasFade?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kaydırma kutusu — <strong>klavyeyle erişilebilir</strong> kaydırma bölgesi.\n *\n * <h3>Neden bir bileşen: `overflow: auto` TEK BAŞINA yetmiyor</h3>\n * Kaydırılabilir bir bölge klavyeyle ulaşılabilir olmak zorunda (WCAG 2.1.1).\n * İçinde odaklanabilir öğe olmayan bir kutu — uzun bir metin, bir tablo, bir\n * kod bloğu — `tabindex` verilmediğinde klavye kullanıcısı için\n * <strong>ulaşılamaz</strong>: `Tab` onu atlıyor ve ok tuşları sayfayı\n * kaydırıyor, kutuyu değil. Firefox bunu kendiliğinden yapıyor, Chrome ve\n * Safari yapmıyor.\n *\n * <p>Ama `tabindex=\"0\"` KOŞULSUZ verilemez: içerik sığdığında kutu\n * kaydırılamaz olur ve gereksiz bir `Tab` durağına dönüşür. Bileşen taşmayı\n * ÖLÇÜYOR ve `tabindex`i yalnızca gerçekten kaydırılabilirken yazıyor.\n *\n * <h3>Kaydırma çubuğu temalı</h3>\n * İşletim sisteminin açık çubuğu koyu temada kutunun kenarında parlak bir\n * şerit bırakıyordu.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>kaydırılabilir bölgeye odaklanır (yalnızca taşma varsa)</td></tr>\n * <tr><td>ok tuşları · `PageUp`/`PageDown` · `Home`/`End`</td><td>kaydırır</td></tr>\n * </table>\n * Tuşların hepsi TARAYICIDAN geliyor; bileşenin işi yalnızca bölgeyi\n * odaklanabilir kılmak.\n */\nconst ScrollArea: FC<Props> = ({\n children,\n label,\n axis = 'vertical',\n maxHeight,\n hasFade,\n className,\n testId,\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n const [isScrollable, setIsScrollable] = useState(false);\n\n /*\n * TASMA OLCULUR, varsayilmaz.\n *\n * `tabindex=\"0\"` kosulsuz verilseydi icerigi sigan her kutu gereksiz bir\n * Tab duragina donusuyordu: sekiz kutulu bir sayfada klavye kullanicisi\n * hicbir sey yapmayan sekiz durak geciyordu.\n */\n useEffect(() => {\n const node = ref.current;\n if (!node || typeof ResizeObserver === 'undefined') return;\n\n const measure = () => {\n const vertical = node.scrollHeight > node.clientHeight;\n const horizontal = node.scrollWidth > node.clientWidth;\n setIsScrollable(\n axis === 'horizontal'\n ? horizontal\n : axis === 'vertical'\n ? vertical\n : vertical || horizontal,\n );\n };\n\n measure();\n\n /* Icerik DE kutu DA degisebiliyor: ikisi de izleniyor. */\n const observer = new ResizeObserver(measure);\n observer.observe(node);\n for (const child of node.children) observer.observe(child);\n\n return () => observer.disconnect();\n }, [axis, children]);\n\n return (\n <div\n ref={ref}\n className={cx(\n styles.scrollArea,\n styles[`scrollArea--${axis}`],\n hasFade && styles['scrollArea--fade'],\n className,\n )}\n style={maxHeight === undefined ? undefined : { maxBlockSize: maxHeight }}\n /*\n * Bolge YALNIZCA kaydirilabilirken odaklanabilir ve yalnizca o zaman bir\n * ROL tasiyor: sigmayan bir kutu bir \"bolge\" degil, siradan bir\n * sarmalayici.\n */\n tabIndex={isScrollable ? 0 : undefined}\n role={isScrollable ? 'region' : undefined}\n aria-label={isScrollable ? label : undefined}\n data-testid={testId}\n >\n {children}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(ScrollArea, 'ScrollArea'),\n) as typeof ScrollArea;\n","import { type CSSProperties, type FC, memo } from 'react';\n\nimport { isNumber } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Genişlik: sayı px, dize doğrudan CSS değeri. */\n width?: number | string;\n height?: number | string;\n /** Metin satırı görünümü: yuvarlatılmış, satır yüksekliğinde. */\n variant?: 'block' | 'text' | 'circle';\n /** Kaç satır çizilecek (`text` için). */\n lines?: number;\n className?: string;\n};\n\n/**\n * Yükleme iskeleti.\n *\n * <h3>Neden dönen çark yerine iskelet</h3>\n * İskelet gelecek içeriğin <em>şeklini</em> gösterir; kullanıcı ne beklediğini\n * bilir ve içerik geldiğinde yerleşim kaymaz (CLS). Dönen bir çark hem konumu\n * hem boyutu belirsiz bırakır.\n *\n * <p>`aria-hidden`: ekran okuyucuya \"yükleniyor\" bilgisini veren, iskeletin\n * kendisi değil onu saran bölgenin `aria-busy` özelliğidir.\n */\nconst Skeleton: FC<Props> = ({ width, height, variant = 'block', lines = 1, className }) => {\n const style: CSSProperties = {\n width: isNumber(width) ? `${width}px` : width,\n height: isNumber(height) ? `${height}px` : height,\n };\n\n if (variant === 'text' && lines > 1)\n return (\n <span className={cx(styles.group, className)} aria-hidden>\n {Array.from({ length: lines }, (_, index) => (\n <span\n key={index}\n className={cx(styles.skeleton, styles['skeleton--text'])}\n // Son satır kısa: gerçek paragraflar tam genişlikte bitmez.\n style={index === lines - 1 ? { width: '60%' } : undefined}\n />\n ))}\n </span>\n );\n\n return (\n <span\n className={cx(styles.skeleton, styles[`skeleton--${variant}`], className)}\n style={style}\n aria-hidden\n />\n );\n};\n\nexport default /*#__PURE__*/ memo(Skeleton) as typeof Skeleton;\n\ntype ShapeProps = {\n /** Kaç kopya çizilecek — bir listenin bilinen satır sayısı. */\n count?: number;\n className?: string;\n};\n\n/**\n * KART iskeleti — `Card` + `CardMedia` + iki satır metnin ölçüsü.\n *\n * <h3>Neden hazır biçimler</h3>\n * \"İskelet yerleşimi kaydırmaz\" sözü ancak iskelet gelecek içeriğin ÖLÇÜSÜNÜ\n * taşıyorsa doğru. Pratikte her çağıran ölçüyü gözle tahmin ediyordu ve\n * tahminler tutmuyordu: 180 px'lik bir görsel alanına 120 px'lik iskelet\n * konulunca içerik geldiğinde sayfa 60 px sıçrıyordu (CLS). Bu biçimler\n * ölçüyü gerçek bileşenlerden alıyor — `CardMedia`nın varsayılan oranı,\n * `$font-size-sm` satır yüksekliği, `Panel` dolgusu.\n */\nconst CardShape: FC<ShapeProps> = ({ count = 1, className }) => (\n <>\n {Array.from({ length: count }, (_, index) => (\n <div key={index} className={cx(styles.card, className)} aria-hidden>\n <Skeleton className={styles.card__media} />\n <div className={styles.card__body}>\n <Skeleton variant=\"text\" width=\"70%\" />\n <Skeleton variant=\"text\" width=\"40%\" />\n </div>\n </div>\n ))}\n </>\n);\n\n/** SATIR iskeleti — avatar + iki metin satırı; liste satırlarının ölçüsü. */\nconst RowShape: FC<ShapeProps> = ({ count = 3, className }) => (\n <div className={cx(styles.rows, className)} aria-hidden>\n {Array.from({ length: count }, (_, index) => (\n <div key={index} className={styles.row}>\n <Skeleton variant=\"circle\" width={36} height={36} />\n <div className={styles.row__text}>\n <Skeleton variant=\"text\" width=\"45%\" />\n <Skeleton variant=\"text\" width=\"25%\" />\n </div>\n </div>\n ))}\n </div>\n);\n\n/**\n * TABLO iskeleti — `DataTable`ın satır yüksekliğinde.\n *\n * <p>Sütun genişlikleri EŞİT: gerçek genişlikler içeriğe göre değişiyor ve\n * onları taklit etmeye çalışmak, veri geldiğinde daha büyük bir sıçrama\n * üretiyordu. Eşit sütunlar \"burada bir tablo olacak\" der ve fazlasını vaat\n * etmez.\n */\nconst TableShape: FC<ShapeProps & { columns?: number }> = ({\n count = 5,\n columns = 4,\n className,\n}) => (\n <div className={cx(styles.table, className)} aria-hidden>\n {Array.from({ length: count }, (_, rowIndex) => (\n <div key={rowIndex} className={styles.table__row}>\n {Array.from({ length: columns }, (_, columnIndex) => (\n <Skeleton key={columnIndex} variant=\"text\" />\n ))}\n </div>\n ))}\n </div>\n);\n\nexport const SkeletonCard = /*#__PURE__*/ named(/*#__PURE__*/ memo(CardShape), 'SkeletonCard');\nexport const SkeletonRows = /*#__PURE__*/ named(/*#__PURE__*/ memo(RowShape), 'SkeletonRows');\nexport const SkeletonTable = /*#__PURE__*/ named(/*#__PURE__*/ memo(TableShape), 'SkeletonTable');\n","'use client';\n\nimport { type FC, memo, type ReactNode } from 'react';\n\nimport { ArrowDownShort, ArrowUpShort, DashLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/** Değişimin yönü. `flat` \"değişmedi\" — yokluk DEĞİL. */\nexport type StatTrend = 'up' | 'down' | 'flat';\n\ntype Props = {\n /** Ölçülen şeyin adı (\"Bugünkü sipariş\"). */\n label: string;\n /** Değerin KENDİSİ — biçimlendirilmiş dize. Bileşen hesap yapmaz. */\n value: ReactNode;\n /** Değerin yanındaki birim (\"₺\", \"adet\"). */\n unit?: string;\n /** Değişim metni (\"%12\", \"+3\"). `trend` ile birlikte anlamlı. */\n delta?: string;\n /**\n * Değişimin yönü.\n *\n * <p>Yön TEK BAŞINA iyi/kötü demek değildir: \"iade oranı %12 arttı\" kötü,\n * \"ciro %12 arttı\" iyi. Renk kararı {@link isUpPositive} ile ayrı veriliyor.\n */\n trend?: StatTrend;\n /**\n * Artış İYİ mi. Varsayılan `true`.\n *\n * <p>`false` verildiğinde yukarı ok kırmızı, aşağı ok yeşil çizilir — iade\n * oranı, hata sayısı, terk edilen sepet gibi ölçüler için. Yönü her zaman\n * yeşil çizmek, kötüleşen bir ölçüyü iyi haber gibi gösteriyordu.\n */\n isUpPositive?: boolean;\n /** Değerin altındaki bir cümlelik bağlam (\"geçen haftaya göre\"). */\n description?: ReactNode;\n /** Sol üstte duran ikon madalyonu. */\n icon?: ReactNode;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\nconst TREND_ICON: Record<StatTrend, ReactNode> = {\n up: <ArrowUpShort aria-hidden />,\n down: <ArrowDownShort aria-hidden />,\n flat: <DashLg aria-hidden />,\n};\n\n/** Yönün ekran okuyucuya okunan karşılığı. */\nconst TREND_TEXT: Record<StatTrend, string> = {\n up: 'artış',\n down: 'azalış',\n flat: 'değişim yok',\n};\n\n/**\n * Ölçüm kutusu (KPI).\n *\n * <h3>Bileşen HESAP YAPMAZ</h3>\n * `value` ve `delta` biçimlendirilmiş dizeler. Yüzde hesabı, para birimi ve\n * yuvarlama çağıranın: bir gösterge panelinde \"%12,5\" ile \"%13\" arasındaki\n * farkı belirleyen şey ürün kararı, bileşenin varsayılanı değil. Aynı sebeple\n * `Price` de hesap yapmıyor.\n *\n * <h3>Yön TEK BAŞINA iyi/kötü demek DEĞİL</h3>\n * \"İade oranı %12 arttı\" kötü haber, \"ciro %12 arttı\" iyi. Yükselen her oku\n * yeşile boyamak, kötüleşen bir ölçüyü iyi gibi gösteriyordu — `isUpPositive`\n * bu kararı çağırana bırakıyor.\n *\n * <h3>Renk tek sinyal değil</h3>\n * Değişim üç şeyle birden anlatılıyor: <strong>ok yönü</strong> (biçim),\n * <strong>renk</strong> ve ekran okuyucuya okunan <strong>metin</strong>\n * (\"artış\" / \"azalış\" / \"değişim yok\"). Yalnızca renk kullanılsaydı renk körü\n * bir kullanıcı için artışla azalış aynı görünüyordu (WCAG 1.4.1).\n *\n * <h3>Rakamlar TABULAR</h3>\n * Alt alta duran ölçüm kutularında orantılı rakamlar sütunu tırtıklı\n * gösteriyor; `tabular-nums` her basamağı aynı genişlikte çiziyor.\n */\nconst Stat: FC<Props> = ({\n label,\n value,\n unit,\n delta,\n trend,\n isUpPositive = true,\n description,\n icon,\n size = 'md',\n className,\n testId,\n}) => {\n /* Yonun IYI mi KOTU mu oldugu ayri bir karar: \"artis\" her zaman iyi degil. */\n const isPositive = trend === 'flat' ? undefined : (trend === 'up') === isUpPositive;\n\n return (\n <div className={cx(styles.stat, styles[`stat--${size}`], className)} data-testid={testId}>\n {icon && (\n <span className={styles.stat__icon} aria-hidden>\n {icon}\n </span>\n )}\n\n <span className={styles.stat__label}>{label}</span>\n\n <span className={styles.stat__value}>\n {value}\n {unit && <span className={styles.stat__unit}>{unit}</span>}\n </span>\n\n {delta && trend && (\n <span\n className={cx(\n styles.stat__delta,\n isPositive === true && styles['stat__delta--positive'],\n isPositive === false && styles['stat__delta--negative'],\n )}\n >\n {TREND_ICON[trend]}\n {delta}\n {/* Yon METIN olarak da okunur: ok ve renk ekran okuyucuya gecmiyor. */}\n <span className={styles.stat__srOnly}>{TREND_TEXT[trend]}</span>\n </span>\n )}\n\n {description && <span className={styles.stat__description}>{description}</span>}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Stat, 'Stat')) as typeof Stat;\n","'use client';\n\nimport { memo, type ReactNode, useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\nimport {\n CheckCircleFill,\n ExclamationTriangleFill,\n InfoCircleFill,\n XCircleFill,\n XLg,\n} from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\nexport type ToastTone = 'info' | 'success' | 'warning' | 'danger';\n\nexport type ToastOptions = {\n tone?: ToastTone;\n /** Görüntülenme süresi (ms). `0` → kendiliğinden kapanmaz. */\n duration?: number;\n /** Başlığın altındaki bir cümlelik ayrıntı. */\n description?: ReactNode;\n /** Bildirimin içindeki tek eylem (\"Geri al\"). */\n action?: { label: string; onClick: () => void };\n};\n\ntype ToastRecord = ToastOptions & { id: number; message: string };\n\n/** Ton başına ikon: renk TEK BAŞINA anlam taşımaz (WCAG 1.4.1). */\nconst ICONS: Record<ToastTone, ReactNode> = {\n info: <InfoCircleFill aria-hidden />,\n success: <CheckCircleFill aria-hidden />,\n warning: <ExclamationTriangleFill aria-hidden />,\n danger: <XCircleFill aria-hidden />,\n};\n\n/**\n * Ton başına varsayılan süre.\n *\n * <p>Hata daha UZUN durur: kullanıcı bir şeyin yanlış gittiğini okumak,\n * başarıyı okumaktan daha uzun sürüyor ve genellikle bir karar gerektiriyor.\n * Dört saniyede kaybolan bir hata mesajı, kullanıcıya ne olduğunu\n * söylememekle aynı kapıya çıkıyordu.\n */\nconst DEFAULT_DURATION: Record<ToastTone, number> = {\n info: 4_000,\n success: 4_000,\n warning: 6_000,\n danger: 8_000,\n};\n\n/** Aynı anda ekranda duran en fazla bildirim. */\nconst MAX_VISIBLE = 3;\n\n/*\n * YAYIN MERKEZI — modul duzeyinde, saglayicidan BAGIMSIZ.\n *\n * `HanuiProvider` zorunlu degil (bkz. `theme/context.ts`) ve bildirim\n * cagrilari React agacinin disindan da geliyor: bir axios interceptor'unun\n * icinden, bir servis fonksiyonundan. Yayin merkezi bir context'e baglansaydi\n * o cagrilarin hicbiri calismazdi.\n */\nlet counter = 0;\n/* `new Set()` modul duzeyinde bir CAGRI ve acilama olmadan bundler onu yan\n etkili sayabilir — Faz 0'da `memo()` cagrilarinda tam olarak bu olmustu.\n Burada olculebilir bir fark yaratmadi; acilama yine de duruyor cunku kural\n modul duzeyindeki HER cagri icin gecerli ve istisnasi olmamali. */\nconst listeners = /*#__PURE__*/ new Set<(toasts: ToastRecord[]) => void>();\nlet queue: ToastRecord[] = [];\n\nconst emit = () => listeners.forEach(listener => listener(queue));\n\nconst dismiss = (id: number) => {\n queue = queue.filter(item => item.id !== id);\n emit();\n};\n\nconst push = (message: string, options: ToastOptions = {}): number => {\n counter += 1;\n const id = counter;\n\n /*\n * SIRAYA ALMA: ekranda en fazla `MAX_VISIBLE` bildirim durur, fazlasi EN\n * ESKIsini duserek yerini alir. Sinirsiz birakildiginda hizli art arda\n * gelen istekler (toplu kaydetme) ekrani bastan asagi bildirimle\n * dolduruyor ve altindaki arayuze ulasilamiyordu.\n */\n queue = [...queue, { ...options, id, message }].slice(-MAX_VISIBLE);\n emit();\n\n return id;\n};\n\n/**\n * BİLDİRİM SÖZLEŞMESİ — süre, ikon ve renk kararları TEK YERDE.\n *\n * <h3>Neden harici bir kütüphaneye sarmalayıcı DEĞİL</h3>\n * Tüketici `react-hot-toast` taşıyordu ve gövdeyi kendi yazmak zorunda\n * kalmıştı: kütüphanenin goober sınıfı bizim modül sınıfımızla AYNI\n * özgüllükteydi ve kazananı kaynak sırası belirliyordu — aynı bildirim\n * geliştirmede ve üretimde İKİ FARKLI RENKTE çıkıyordu. Bir sarmalayıcı bu\n * sorunu çözmez, erteler.\n *\n * @example\n * toast.success('Adres kaydedildi');\n * toast.error('Kart reddedildi', { action: { label: 'Yeniden dene', onClick: retry } });\n */\nexport const toast = {\n show: push,\n info: (message: string, options?: ToastOptions) => push(message, { ...options, tone: 'info' }),\n success: (message: string, options?: ToastOptions) =>\n push(message, { ...options, tone: 'success' }),\n warning: (message: string, options?: ToastOptions) =>\n push(message, { ...options, tone: 'warning' }),\n error: (message: string, options?: ToastOptions) => push(message, { ...options, tone: 'danger' }),\n dismiss,\n /** Tümünü kapatır — sayfa geçişinde bayat bildirim taşınmasın. */\n clear: () => {\n queue = [];\n emit();\n },\n};\n\ntype ItemProps = {\n toast: ToastRecord;\n closeLabel: string;\n onDismiss: (id: number) => void;\n};\n\n/** Tek bir bildirim satırı; kendi zamanlayıcısını kendisi taşır. */\nconst ToastItem = ({ toast: record, closeLabel, onDismiss }: ItemProps) => {\n const tone = record.tone ?? 'info';\n const duration = record.duration ?? DEFAULT_DURATION[tone];\n\n const [isPaused, setIsPaused] = useState(false);\n const remainingRef = useRef(duration);\n const startedRef = useRef(0);\n\n useEffect(() => {\n if (duration === 0 || isPaused) return;\n\n startedRef.current = Date.now();\n const timer = window.setTimeout(() => onDismiss(record.id), remainingRef.current);\n\n return () => {\n window.clearTimeout(timer);\n /* Kalan sure KORUNUR: imlec ayrilinca sayac bastan baslasaydi, uzerine\n bir kez gelinen bildirim ekranda cok daha uzun kaliyordu. */\n remainingRef.current = Math.max(0, remainingRef.current - (Date.now() - startedRef.current));\n };\n }, [duration, isPaused, onDismiss, record.id]);\n\n return (\n <div\n className={cx(styles.toast, styles[`toast--${tone}`])}\n /*\n * `role=\"alert\"` YALNIZCA hatada: o rol `aria-live=\"assertive\"` demek ve\n * kullanicinin okudugu seyi BOLER. Basarili bir kaydetmeyi duyurmak icin\n * kullaniciyi bolmek gurultu; `status` sirasini bekler.\n */\n role={tone === 'danger' ? 'alert' : 'status'}\n /* Fare uzerindeyken sayac DURUR: kullanici bildirimi okuyor ya da\n icindeki eylemi tiklamaya gidiyor. */\n onPointerEnter={() => setIsPaused(true)}\n onPointerLeave={() => setIsPaused(false)}\n /* Klavye odagi da duraklatir: Tab ile \"Geri al\"a ulasmaya calisan\n kullanicinin altindan bildirim kayboluyordu. */\n onFocus={() => setIsPaused(true)}\n onBlur={() => setIsPaused(false)}\n >\n <span className={styles.toast__icon} aria-hidden>\n {ICONS[tone]}\n </span>\n\n <div className={styles.toast__text}>\n <span className={styles.toast__message}>{record.message}</span>\n {record.description && (\n <span className={styles.toast__description}>{record.description}</span>\n )}\n </div>\n\n {record.action && (\n <button\n type=\"button\"\n className={styles.toast__action}\n onClick={() => {\n record.action?.onClick();\n onDismiss(record.id);\n }}\n >\n {record.action.label}\n </button>\n )}\n\n <IconButton\n icon={<XLg aria-hidden />}\n label={closeLabel}\n variant=\"ghost\"\n size=\"sm\"\n className={styles.toast__close}\n onClick={() => onDismiss(record.id)}\n />\n </div>\n );\n};\n\ntype HubProps = {\n /** Kapatma düğmelerinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n className?: string;\n};\n\n/**\n * Bildirim yığını — uygulamada <strong>BİR KEZ</strong> çizilir.\n *\n * <h3>Neden tek yığın</h3>\n * Birden fazla canlı bölge, ekran okuyucuların duyuruları birleştirip sırayla\n * okumasına ya da tamamen atlamasına yol açıyor. Yığın kök yerleşimde bir kez\n * durur; `toast.*` çağrıları React ağacının dışından da çalışır.\n *\n * <h3>Duyuru bölgesi HER ZAMAN DOM'da</h3>\n * Kapsayıcı bildirim yokken de çiziliyor. Sonradan DOM'a eklenen bir canlı\n * bölgenin ilk duyurusu güvenilmez — ekran okuyucu bölgeyi izlemeye\n * başlamadan içerik gelmiş oluyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>bildirimin eylemine ve kapatma düğmesine ulaşır</td></tr>\n * <tr><td>odak/hover</td><td>kapanma sayacını DURDURUR</td></tr>\n * </table>\n */\nconst ToastHub = ({ closeLabel, className }: HubProps) => {\n const { labels } = useHanui();\n const [toasts, setToasts] = useState<ToastRecord[]>([]);\n\n useEffect(() => {\n listeners.add(setToasts);\n setToasts(queue);\n return () => {\n listeners.delete(setToasts);\n };\n }, []);\n\n const handleDismiss = useCallback((id: number) => dismiss(id), []);\n\n /* Escape en YENI bildirimi kapatir: yigilmis bildirimleri tek tek\n kapatmanin klavyeyle tek yolu buydu. */\n useEffect(() => {\n if (toasts.length === 0) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n dismiss(toasts[toasts.length - 1].id);\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [toasts]);\n\n if (!isClient()) return null;\n\n return createPortal(\n <div className={cx(styles.hub, className)}>\n {toasts.map(record => (\n <ToastItem\n key={record.id}\n toast={record}\n closeLabel={resolveLabel('ToastHub.closeLabel', closeLabel, labels?.close)}\n onDismiss={handleDismiss}\n />\n ))}\n </div>,\n document.body,\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(ToastHub, 'ToastHub')) as typeof ToastHub;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useCallback, useId, useState } from 'react';\n\nimport { CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\nexport type AccordionItem = {\n id: string;\n /** Başlık satırı — tıklanabilir olan bu. */\n title: ReactNode;\n /** Başlığın sağında duran ikincil bilgi (sayaç, rozet). */\n meta?: ReactNode;\n content: ReactNode;\n isDisabled?: boolean;\n};\n\ntype Props = {\n items: AccordionItem[];\n /**\n * Aynı anda YALNIZCA BİR bölüm açık kalır.\n *\n * <p>Varsayılan çoklu: bir SSS listesinde iki soruyu yan yana okumak\n * yaygın bir ihtiyaç ve tek-açık kip, kullanıcının az önce açtığı bölümü\n * habersizce kapatıyordu. Tek-açık yalnızca bölümler UZUN olduğunda\n * (mobil filtre paneli) doğru.\n */\n isSingle?: boolean;\n /** Kontrolsüz kullanımda açılışta açık olan bölümler. */\n defaultOpenIds?: string[];\n /** Kontrollü kullanım; `onChange` ile birlikte verilir. */\n openIds?: string[];\n onChange?: (openIds: string[]) => void;\n className?: string;\n testId?: string;\n};\n\n/**\n * Akordeon — katlanabilir bölümler.\n *\n * <h3>Yerel `<details>` / `<summary>` üzerine</h3>\n * Açık/kapalı durumu, klavye desteği (`Enter` ve `Space`), ekran okuyucu\n * duyurusu (\"genişletildi/daraltıldı\") ve <strong>sayfa içi bulma</strong>\n * tarayıcıdan gelir. Sonuncusu taklit bir uygulamada imkânsız: Ctrl+F ile\n * aranan bir metin kapalı bir `<details>`in içindeyse tarayıcı bölümü kendisi\n * açıyor; `display: none` ile gizlenmiş bir `<div>`de o metin hiç yok.\n *\n * <p>Bedeli, tek-açık kipin elle kurulması: `<details name=\"…\">` bunu yerel\n * olarak veriyor ama Safari 17.2 öncesinde yok ve orada TÜM bölümler\n * birbirinden bağımsız açılıyordu — sessiz bir davranış farkı. Karar burada\n * veriliyor, tarayıcıya bırakılmıyor.\n *\n * <h3>Yükseklik geçişi</h3>\n * `interpolate-size: allow-keywords` + `height` geçişi ile `auto`ya\n * canlandırılıyor. Desteklemeyen tarayıcıda geçiş düşer ve bölüm ANINDA\n * açılır — eski davranış. Sabit bir piksel yüksekliği vermek ya da\n * `max-height` numarası kullanmak yanlış: ilki içeriği kırpıyor, ikincisi\n * kısa bölümlerde gözle görülür bir gecikme bırakıyordu.\n *\n * <h3>Klavye (yerel)</h3>\n * <table>\n * <tr><td>`Enter` / `Space`</td><td>bölümü açar/kapatır</td></tr>\n * <tr><td>`Tab`</td><td>başlıklar arasında gezinir</td></tr>\n * </table>\n * Ok tuşu YOKTUR ve olmamalı: akordeon bir liste değil, her başlık bağımsız\n * bir düğme (WAI-ARIA APG accordion deseni ok tuşlarını isteğe bağlı bırakıyor\n * ve yerel öğe onları getirmiyor).\n */\nconst Accordion: FC<Props> = ({\n items,\n isSingle,\n defaultOpenIds,\n openIds: controlledIds,\n onChange,\n className,\n testId,\n}) => {\n const baseId = useId();\n const [uncontrolledIds, setUncontrolledIds] = useState<string[]>(defaultOpenIds ?? []);\n\n const isControlled = controlledIds !== undefined;\n const openIds = isControlled ? controlledIds : uncontrolledIds;\n\n const toggle = useCallback(\n (id: string, willOpen: boolean) => {\n const next = willOpen\n ? isSingle\n ? [id]\n : [...openIds.filter(current => current !== id), id]\n : openIds.filter(current => current !== id);\n\n if (!isControlled) setUncontrolledIds(next);\n onChange?.(next);\n },\n [isControlled, isSingle, onChange, openIds],\n );\n\n return (\n <div className={cx(styles.accordion, className)} data-testid={testId}>\n {items.map(item => {\n const isOpen = openIds.includes(item.id);\n\n return (\n <details\n key={item.id}\n className={cx(\n styles.accordion__item,\n item.isDisabled && styles['accordion__item--disabled'],\n )}\n open={isOpen}\n /*\n * `onToggle` YEREL olaydir ve tarayici durumu DEGISTIRDIKTEN sonra\n * dusuyor. `onClick` ile yakalamak yetmiyordu: klavyeyle acilan\n * bolum (Enter/Space) tiklama uretmiyor ve durum React tarafinda\n * guncellenmiyordu.\n */\n onToggle={event => {\n const next = (event.currentTarget as HTMLDetailsElement).open;\n if (next !== isOpen) toggle(item.id, next);\n }}\n >\n <summary\n id={`${baseId}-${item.id}`}\n className={styles.accordion__summary}\n /*\n * Pasif bolum: `<summary>`nin `disabled` hali YOK. Isaretci\n * olaylari kesilir ve `tabindex=\"-1\"` ile sekme sirasindan\n * cikarilir; `aria-disabled` durumu duyurur.\n */\n aria-disabled={item.isDisabled}\n tabIndex={item.isDisabled ? -1 : undefined}\n onClick={event => item.isDisabled && event.preventDefault()}\n >\n <CaretRightFill aria-hidden className={styles.accordion__marker} />\n\n <span className={styles.accordion__title}>{item.title}</span>\n {item.meta && <span className={styles.accordion__meta}>{item.meta}</span>}\n </summary>\n\n {/*\n Ic sarmalayici ZORUNLU: yukseklik gecisi `<details>`in KENDISINE\n verilemez (isaretcinin yuksekligi de gecise girip basligi\n titretiyordu). Gecis bu kutuda.\n */}\n <div className={styles.accordion__panel}>\n <div className={styles.accordion__content}>{item.content}</div>\n </div>\n </details>\n );\n })}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Accordion, 'Accordion')) as typeof Accordion;\n","'use client';\n\nimport { type FC, memo, type ReactNode } from 'react';\n\nimport { CheckLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\nexport type StepItem = {\n id: string;\n label: string;\n /** Etiketin altındaki bir cümlelik açıklama. */\n description?: ReactNode;\n};\n\ntype Props = {\n steps: StepItem[];\n /** Bulunulan adımın DİZİNİ (0 tabanlı). Öncesi tamamlanmış sayılır. */\n currentIndex: number;\n /**\n * Bir adıma dönülebiliyorsa verilir. Verilmediğinde adımlar düğme DEĞİL\n * düz metin olur — tıklanabilir görünüp hiçbir şey yapmayan bir adım,\n * kullanıcıya var olmayan bir yol vaat ediyordu.\n */\n onStepClick?: (index: number) => void;\n /** Akışın erişilebilir adı (\"Ödeme adımları\"). ZORUNLU. */\n label: string;\n orientation?: 'horizontal' | 'vertical';\n className?: string;\n testId?: string;\n};\n\n/** Bir adımın durumu — üçü de görsel olarak AYRI çizilir. */\nconst statusOf = (index: number, currentIndex: number): 'done' | 'current' | 'upcoming' => {\n if (index < currentIndex) return 'done';\n if (index === currentIndex) return 'current';\n return 'upcoming';\n};\n\n/** Durumun ekran okuyucuya okunan karşılığı. */\nconst STATUS_TEXT: Record<'done' | 'current' | 'upcoming', string> = {\n done: 'tamamlandı',\n current: 'şu anki adım',\n upcoming: 'sıradaki',\n};\n\n/**\n * Adım göstergesi (stepper) — çok adımlı akışta NEREDE olunduğu.\n *\n * <h3>Üç durum, ÜÇ AYRI işaret</h3>\n * Tamamlanan adım <strong>tik</strong>, bulunulan adım <strong>dolu\n * madalyon + sıra numarası</strong>, sıradaki adım <strong>boş\n * madalyon</strong> taşıyor. Renk bunlara EŞLİK ediyor, tek başına\n * anlatmıyor (WCAG 1.4.1): üçünü yalnızca renkle ayırmak, renk körü bir\n * kullanıcı için \"üç aynı daire\" demekti.\n *\n * <p>Durum ayrıca METİN olarak okunuyor — her adımın erişilebilir adına\n * \"tamamlandı\" / \"şu anki adım\" / \"sıradaki\" ekleniyor. Görsel işaret ekran\n * okuyucuya geçmiyor; `aria-current` tek başına yalnızca BULUNULAN adımı\n * söylüyor, tamamlananları değil.\n *\n * <h3>Geri dönülebilirlik AÇIKÇA bildirilir</h3>\n * `onStepClick` verilmediğinde adımlar `<button>` bile değil: tıklanabilir\n * görünüp hiçbir şey yapmayan bir adım, kullanıcıya var olmayan bir yol vaat\n * ediyordu. Verildiğinde yalnızca TAMAMLANMIŞ adımlar tıklanabilir — ileri\n * atlamak, atlanan adımın verisini toplamadan devam etmek demek.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>tıklanabilir adımlar arasında gezinir</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>adıma döner</td></tr>\n * </table>\n * Ok tuşu YOK: adımlar bir seçim listesi değil, her biri bağımsız bir\n * gezinme bağlantısı.\n */\nconst Steps: FC<Props> = ({\n steps,\n currentIndex,\n onStepClick,\n label,\n orientation = 'horizontal',\n className,\n testId,\n}) => (\n <ol\n className={cx(styles.steps, styles[`steps--${orientation}`], className)}\n aria-label={label}\n data-testid={testId}\n >\n {steps.map((step, index) => {\n const status = statusOf(index, currentIndex);\n /* Ileri atlamak YOK: atlanan adimin verisi toplanmadan devam edilemez. */\n const isClickable = Boolean(onStepClick) && status === 'done';\n\n const body = (\n <>\n <span className={styles.steps__marker} aria-hidden>\n {status === 'done' ? <CheckLg /> : index + 1}\n </span>\n\n <span className={styles.steps__text}>\n <span className={styles.steps__label}>{step.label}</span>\n {step.description && (\n <span className={styles.steps__description}>{step.description}</span>\n )}\n </span>\n\n {/* Durum METIN olarak da okunur: gorsel isaret ekran okuyucuya\n gecmiyor ve `aria-current` yalnizca bulunulan adimi soyluyor. */}\n <span className={styles.steps__status}>{STATUS_TEXT[status]}</span>\n </>\n );\n\n return (\n <li\n key={step.id}\n className={cx(styles.steps__item, styles[`steps__item--${status}`])}\n aria-current={status === 'current' ? 'step' : undefined}\n >\n {isClickable ? (\n <button\n type=\"button\"\n className={styles.steps__button}\n onClick={() => onStepClick?.(index)}\n >\n {body}\n </button>\n ) : (\n <span className={styles.steps__button}>{body}</span>\n )}\n </li>\n );\n })}\n </ol>\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Steps, 'Steps')) as typeof Steps;\n","'use client';\n\nimport {\n type FC,\n type KeyboardEvent,\n memo,\n type ReactNode,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { scrollIntoViewIfPossible } from '../../helpers/scroll.helper';\n\nimport styles from './index.module.scss';\n\nexport type TabItem = {\n id: string;\n label: string;\n /** Etiketin yanında gösterilen sayı. */\n count?: number;\n /**\n * Sekmenin paneli.\n *\n * <p>Verilmezse bileşen yalnızca <strong>sekme çubuğu</strong> çizer ve\n * içeriği çağıran taraf yönetir. Bir formun üç kipi tek bir panelin içinde\n * yaşıyorsa üç ayrı panel yazmak aynı alanları üç kez tanımlamak olurdu.\n */\n content?: ReactNode;\n};\n\ntype Props = {\n items: TabItem[];\n /** Kontrolsüz kullanımda açılışta seçili sekme. */\n defaultTabId?: string;\n /**\n * Kontrollü kullanım: seçili sekme çağıranın durumunda.\n *\n * <p>`onChange` ile birlikte verilir. Kontrolsüz sürüm (yalnızca\n * `defaultTabId`) korunur — kendi durumunu tutması yeterli olan sekmelerin\n * dışarıdan yönetilmesi gereksiz.\n */\n activeId?: string;\n onChange?: (id: string) => void;\n /** Sekme çubuğunun erişilebilir adı. */\n ariaLabel?: string;\n /**\n * Ok tuşu yalnızca ODAĞI taşır; seçim `Enter`/`Space` ile yapılır.\n *\n * <p>Varsayılan OTOMATİK etkinleştirme (ok tuşu odakla birlikte seçimi de\n * taşır) ve APG panel içeriği hazır olduğu sürece onu öneriyor. Ama panel\n * PAHALIYSA — her sekme bir istek atıyorsa — otomatik etkinleştirme,\n * kullanıcı beşinci sekmeye giderken dört istek atıyor. Manuel kipte\n * kullanıcı hedefine varıp `Enter`a basıyor: tek istek.\n */\n isManualActivation?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Sekmeler.\n *\n * <p>ARIA sekme kalıbı tam uygulanır: `role=\"tablist\"`, `aria-selected`,\n * `aria-controls` ve ok tuşlarıyla gezinme. Yalnızca görsel olarak sekme gibi\n * duran düğmeler, klavye kullanıcısı için gezinilemez bir yapı olurdu.\n *\n * <p>Seçili olmayan panel DOM'dan çıkarılır: gizli panellerdeki bağlantılar ve\n * girdiler sekme sırasına girmemeli.\n *\n * <h3>İki kullanım</h3>\n * <ul>\n * <li><b>Kontrolsüz + panelli</b> — `items[].content` verilir, bileşen\n * seçimi kendisi tutar.</li>\n * <li><b>Kontrollü + panelsiz</b> — `activeId` + `onChange` verilir,\n * `content` verilmez; bileşen yalnızca çubuğu çizer.</li>\n * </ul>\n *\n * <h3>Klavye (APG: tabs, OTOMATİK etkinleştirme)</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowLeft`</td><td>sonraki / önceki sekme; uçlarda DÖNER</td></tr>\n * <tr><td>`Tab`</td><td>çubuktan panele çıkar — çubuk TEK durak</td></tr>\n * </table>\n * Ok tuşu odakla birlikte seçimi de taşır (otomatik etkinleştirme). Panel\n * içeriği hazır ve ucuz olduğu sürece APG'nin önerdiği budur; her sekmesi bir\n * istek atan pahalı bir panelde `isManualActivation` verilir — orada otomatik\n * etkinleştirme, kullanıcı beşinci sekmeye giderken dört istek atıyordu.\n * Nöbetçi: `components/__tests__/keyboard.test.tsx`.\n */\nconst Tabs: FC<Props> = ({\n items,\n defaultTabId,\n activeId: controlledId,\n onChange,\n ariaLabel,\n isManualActivation,\n className,\n testId,\n}) => {\n const baseId = useId();\n const [uncontrolledId, setUncontrolledId] = useState(defaultTabId ?? items[0]?.id);\n\n const isControlled = isDefined(controlledId);\n const activeId = isControlled ? controlledId : uncontrolledId;\n\n const activeIndex = items.findIndex(item => item.id === activeId);\n /* Manuel kipte ODAKLANAN sekme ile SECILI sekme ayrisir. */\n const [focusIndex, setFocusIndex] = useState(activeIndex < 0 ? 0 : activeIndex);\n const listRef = useRef<HTMLDivElement>(null);\n const active = items[activeIndex] ?? items[0];\n\n /*\n * SECILI SEKME GORUNURE KAYDIRILIR.\n *\n * Cubuk tasabiliyor (`scroll-row`) ve secim adres cubugundan ya da baska bir\n * denetimden de gelebiliyor: on sekmeli bir cubukta yedinci sekme secili\n * gelen bir sayfa, kullaniciya hicbir sekme secili degilmis gibi\n * gorunuyordu.\n *\n * `block: 'nearest'` — dikey kaydirma YOK: cubuk sayfanin ortasindayken\n * `scrollIntoView` bütün sayfayi zipliyordu.\n */\n useEffect(() => {\n scrollIntoViewIfPossible(listRef.current?.querySelector(`[aria-selected=\"true\"]`), {\n block: 'nearest',\n inline: 'nearest',\n });\n }, [activeId]);\n\n const select = (id: string) => {\n if (!isControlled) setUncontrolledId(id);\n onChange?.(id);\n };\n\n /**\n * Ok tuşlarıyla gezinme; başta/sonda döner.\n *\n * <p>Otomatik kipte ok tuşu odakla birlikte SEÇİMİ de taşır; manuel kipte\n * yalnızca odağı taşır ve seçim `Enter`/`Space` ile yapılır. İkisi de APG\n * içinde geçerli — ayrım panelin pahalı olup olmadığında.\n */\n const handleKeyDown = (event: KeyboardEvent) => {\n if (isManualActivation && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n select(items[focusIndex].id);\n return;\n }\n\n const offset = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;\n if (offset === 0) return;\n\n event.preventDefault();\n const next = ((isManualActivation ? focusIndex : activeIndex) + offset + items.length) % items.length;\n\n setFocusIndex(next);\n if (!isManualActivation) select(items[next].id);\n\n /* Odak HER IKI kipte de tasinir: manuel kipte seciliyle odaklanan sekme\n ayrisiyor ve `tabindex` odaklanani izlemek zorunda. */\n document.getElementById(`${baseId}-tab-${items[next].id}`)?.focus();\n };\n\n if (items.length === 0) return null;\n\n /*\n * Panelsiz kullanimda `aria-controls` VERILMEZ: var olmayan bir kimligi\n * isaret etmek ekran okuyucuda kirik bir bag uretir.\n *\n * Kontrol VARLIK uzerinden: `content` bir dize ya da sayi da olabilir ve\n * `undefined`/`null` disindaki her sey bir panel demek.\n */\n const hasPanel = isDefined(active?.content);\n\n return (\n <div className={cx(styles.tabs, className)} data-testid={testId}>\n <div\n ref={listRef}\n className={styles.tabs__list}\n role=\"tablist\"\n aria-label={ariaLabel}\n onKeyDown={handleKeyDown}\n >\n {items.map(item => {\n const isActive = item.id === active.id;\n\n return (\n <button\n key={item.id}\n id={`${baseId}-tab-${item.id}`}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={hasPanel ? `${baseId}-panel-${item.id}` : undefined}\n // Yalnızca seçili sekme sekme sırasında; gezinme ok tuşlarıyla.\n /* Donen `tabindex` ODAKLANANI izler: manuel kipte secili sekme\n ile odaklanan sekme ayri ve Tab'in geri donecegi yer\n odaklanan olmali. */\n tabIndex={(isManualActivation ? items[focusIndex]?.id === item.id : isActive) ? 0 : -1}\n className={cx(styles.tabs__tab, isActive && styles['tabs__tab--active'])}\n onClick={() => select(item.id)}\n >\n {item.label}\n {isDefined(item.count) && <span className={styles.tabs__count}>{item.count}</span>}\n </button>\n );\n })}\n </div>\n\n {hasPanel && (\n <div\n id={`${baseId}-panel-${active.id}`}\n role=\"tabpanel\"\n aria-labelledby={`${baseId}-tab-${active.id}`}\n className={styles.tabs__panel}\n tabIndex={0}\n >\n {active.content}\n </div>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(Tabs) as typeof Tabs;\n","import { memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n label: string;\n /** İkon DIŞARIDAN gelir: hangi ikonun hangi konuya ait olduğu uygulamanın bilgisi. */\n icon: ReactNode;\n href: string;\n /** Etiketin altında gösterilen ikincil satır (\"1.248 kayıt\"). */\n meta?: ReactNode;\n isActive?: boolean;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n className?: string;\n testId?: string;\n};\n\n/**\n * Karo — ikon madalyonu + etiket.\n *\n * <h3>Neden ikon, neden yuvarlak madalyon</h3>\n * Ana giriş noktaları metin listesi olarak verildiğinde kullanıcı satır satır\n * okuyor. İkon, aranan öğeyi <em>okumadan</em> bulmayı sağlar; madalyon ise\n * ikona sabit bir kutu verir — farklı ikonların doğal genişlikleri karoları\n * düzensiz hizalıyordu.\n *\n * <h3>Karonun tamamı tıklanabilir</h3>\n * Bağlantı yalnızca etiketi değil karonun tümünü kaplar. Küçük bir metin\n * bağlantısını hedeflemek, özellikle dokunmatik ekranda gereksiz bir hassasiyet\n * talebiydi.\n *\n * <h3>`meta` neden sayı değil `ReactNode`</h3>\n * \"1.248 ürün\" cümlesi hem sayı biçimine hem dile bağlı. Bileşen içinde\n * `toLocaleString` çağırmak, o kararı kütüphanenin varsayımına bağlıyordu.\n */\nconst Tile = ({ label, icon, href, meta, isActive, linkProps, className, testId }: Props) => (\n <HanuiLink\n href={href}\n className={cx(styles.tile, isActive && styles['tile--active'], className)}\n aria-current={isActive ? 'page' : undefined}\n data-testid={testId}\n {...linkProps}\n >\n <span className={styles.tile__medallion} aria-hidden>\n {icon}\n </span>\n\n <span className={styles.tile__label}>{label}</span>\n\n {meta && <span className={styles.tile__meta}>{meta}</span>}\n </HanuiLink>\n);\n\nexport default /*#__PURE__*/ memo(Tile) as typeof Tile;\n","'use client';\n\nimport { type FC, memo, type ReactNode } from 'react';\n\nimport { CheckLg, XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/** Bir olayın durumu. `pending` HENÜZ olmadı — başarısız değil. */\nexport type TimelineStatus = 'done' | 'current' | 'pending' | 'failed';\n\nexport type TimelineEvent = {\n id: string;\n title: string;\n /** Zaman damgası — BİÇİMLENDİRİLMİŞ dize. Bileşen tarih biçimlendirmez. */\n time?: string;\n description?: ReactNode;\n status?: TimelineStatus;\n /** Varsayılan işaretin yerine geçen ikon. */\n icon?: ReactNode;\n};\n\ntype Props = {\n events: TimelineEvent[];\n /** Akışın erişilebilir adı (\"Sipariş geçmişi\"). ZORUNLU. */\n label: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Durumun GÖRSEL işareti — renkten bağımsız.\n *\n * <p>`done` tik, `failed` çarpı taşıyor; ikisi de dolu daire ve YALNIZCA\n * renkle ayrılsalardı renk körü bir kullanıcı için aynı görünüyorlardı\n * (WCAG 1.4.1). `current` ve `pending` kendi biçimlerini kenarlıktan alıyor\n * (dolu halka / kesikli daire) ve glif taşımıyor.\n */\nconst STATUS_ICON: Record<TimelineStatus, ReactNode> = {\n done: <CheckLg />,\n failed: <XLg />,\n current: null,\n pending: null,\n};\n\n/** Durumun ekran okuyucuya okunan karşılığı. */\nconst STATUS_TEXT: Record<TimelineStatus, string> = {\n done: 'tamamlandı',\n current: 'şu an',\n pending: 'bekliyor',\n failed: 'başarısız',\n};\n\n/**\n * Zaman çizelgesi — sipariş durumu, işlem geçmişi.\n *\n * <h3>{@link Steps} ile farkı: ileri mi geri mi bakıyor</h3>\n * İkisi de sıralı ve durumlu; ayrım yönlerinde:\n *\n * <ul>\n * <li>`Steps` İLERİ bakar: kullanıcı bir akışın içinde ve kalan adımları\n * görüyor. Adım sayısı sabit, adımlara dönülebilir.</li>\n * <li><b>`Timeline` GERİ bakar:</b> olmuş şeylerin kaydı. Olay sayısı\n * değişken, hiçbiri tıklanabilir değil ve <strong>başarısız</strong>\n * diye bir durum var — bir adım \"başarısız\" olamaz, akış orada durur;\n * bir olay olabilir ve kayıtta kalır.</li>\n * </ul>\n *\n * <h3>Zaman biçimlendirmesi ÇAĞIRANIN</h3>\n * `time` biçimlendirilmiş bir dize. Kütüphane `Intl` çağırsaydı yerel ayarı\n * ve \"3 saat önce\" mi \"14:32\" mi yazılacağını kendisi seçmiş olurdu — ikisi\n * de bağlama bağlı kararlar.\n *\n * <h3>Durum renkle DEĞİL, üç şeyle birden</h3>\n * İşaretin <strong>biçimi</strong> (dolu / halka / tik / çarpı), rengi ve\n * ekran okuyucuya okunan <strong>metni</strong>. Yalnızca renk kullanılsaydı\n * \"tamamlandı\" ile \"başarısız\" renk körü bir kullanıcı için aynı daireydi.\n */\nconst Timeline: FC<Props> = ({ events, label, className, testId }) => (\n <ol className={cx(styles.timeline, className)} aria-label={label} data-testid={testId}>\n {events.map(event => {\n const status = event.status ?? 'done';\n\n return (\n <li\n key={event.id}\n className={cx(styles.timeline__item, styles[`timeline__item--${status}`])}\n aria-current={status === 'current' ? 'step' : undefined}\n >\n <span className={styles.timeline__marker} aria-hidden>\n {event.icon ?? STATUS_ICON[status]}\n </span>\n\n <div className={styles.timeline__body}>\n <span className={styles.timeline__title}>\n {event.title}\n {/* Durum METIN olarak da okunur: isaret ve renk ekran okuyucuya\n gecmiyor. */}\n <span className={styles.timeline__srOnly}>{STATUS_TEXT[status]}</span>\n </span>\n\n {event.time && (\n /* `<time>` DEGIL `<span>`: `datetime` icin makine okunur bir\n deger gerekiyor ve elimizde yalnizca bicimlendirilmis dize\n var. Yanlis bir `datetime`, hicbir `datetime`den kotu. */\n <span className={styles.timeline__time}>{event.time}</span>\n )}\n\n {event.description && (\n <span className={styles.timeline__description}>{event.description}</span>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Timeline, 'Timeline')) as typeof Timeline;\n","'use client';\n\nimport {\n memo,\n type MouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport {\n captureFocus,\n focusFirstMeaningful,\n isTopModal,\n preventAutoKeyboard,\n pushModal,\n} from '../../helpers/focus.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport useScrollLock from '../../hooks/useScrollLock';\nimport { useHanui } from '../../theme/context';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\nexport type ModalTone = 'neutral' | 'danger' | 'warning' | 'success' | 'info';\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n /**\n * Kapatma düğmesinin erişilebilir adı.\n *\n * <p>Verilmezse `HanuiProvider labels.close` okunur. Bağlama göre farklı\n * olması gereken pencerelerde (\"Daha sonra\") prop kazanır.\n */\n closeLabel?: string;\n children?: ReactNode;\n /**\n * Başlığın altındaki bir cümlelik açıklama.\n *\n * <p>`aria-describedby` ile pencereye bağlanır: ekran okuyucu pencere\n * açıldığında başlıkla birlikte bunu da okur. Gövdeye paragraf olarak\n * yazıldığında duyurulmuyordu.\n */\n description?: ReactNode;\n /** Altta duran eylemler. Sağa yaslanır; dar ekranda tam genişliğe yayılır. */\n footer?: ReactNode;\n /** Başlığın solunda duran ikon madalyonu; `tone` rengini alır. */\n icon?: ReactNode;\n /** İkon madalyonunun tonu. */\n tone?: ModalTone;\n size?: 'sm' | 'md' | 'lg';\n /**\n * `false` iken arka plana tıklama, Escape ve kapatma düğmesi kapatmaz.\n *\n * <p>Yalnızca <strong>sürmekte olan</strong> bir işlem için: silme isteği\n * gönderilmişken pencerenin kapanması, kullanıcıya işlem iptal edilmiş gibi\n * görünüyordu.\n */\n isDismissable?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kip pencere (modal).\n *\n * <h3>Yerel `<dialog>` + `showModal()`</h3>\n * Odak tuzağı, Escape ile kapanma, arka planın etkileşime kapanması ve\n * `aria-modal` semantiği tarayıcıdan gelir. Bunları `<div>` üzerine elle\n * kurmak yüzlerce satır ve kaçınılmaz olarak eksik bir odak yönetimi demek.\n *\n * <h3>Neden `open` özniteliği değil `showModal()`</h3>\n * `<dialog open>` pencereyi <em>kipsiz</em> açar: arka plan tıklanabilir kalır\n * ve odak tuzağı çalışmaz. Kipli davranışın tek yolu yöntemi çağırmak.\n *\n * <h3>Arka planın kaydırılması ayrıca engellenir</h3>\n * `showModal()` arka planı <em>etkileşime</em> kapatır ama tarayıcıların bir\n * kısmında sayfa hâlâ kaydırılabiliyor: kullanıcı pencereyi kaydırdığını\n * sanırken arkadaki listeyi kaydırıyordu. `<body>` kilitlenir.\n *\n * <h3>Mobilde alt sayfaya düşer</h3>\n * Dar ekranda ortalanmış bir pencere, klavye açıldığında yukarı sıkışıyor ve\n * dip düğmeleri klavyenin altında kalıyordu. Alt sayfa baş parmağın\n * erişebildiği yerde durur.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Escape`</td><td>kapatır — `isDismissable={false}` iken KAPATMAZ</td></tr>\n * <tr><td>`Tab`</td><td>odak panelin içinde döner (tarayıcı: `showModal()`)</td></tr>\n * </table>\n * Odak tuzağı tarayıcıdan gelir; kütüphanenin işi `cancel` olayını React\n * durumuna bağlamak. Yakalanmadığında pencere kapanıyor ama `isOpen` `true`\n * kalıyor ve bir daha açılamıyordu. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst Modal = ({\n isOpen,\n onClose,\n title,\n closeLabel,\n children,\n description,\n footer,\n icon,\n tone = 'neutral',\n size = 'md',\n isDismissable = true,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const dialogRef = useRef<HTMLDialogElement>(null);\n /* Yigindaki yerimiz: Escape yalnizca EN USTTEKI panelde islenir. */\n const tokenRef = useRef<symbol | null>(null);\n const titleId = useId();\n const descriptionId = useId();\n\n /*\n * ACILIS: `showModal()` + odak + yigina katilma.\n *\n * Uc is TEK etkide toplandi cunku SIRALARI onemli: pencere once acilmali\n * (yoksa icindeki hicbir sey odaklanabilir degil), sonra odak verilmeli,\n * en son yigina katilmali — yigina once katilsaydi, acilis sirasinda kisa\n * bir an icin \"en ust panel\" olup ustundeki gercek panelin Escape'ini\n * yutuyordu.\n */\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (!isOpen) {\n if (dialog.open) dialog.close();\n return;\n }\n\n const restoreFocus = captureFocus();\n if (!dialog.open) dialog.showModal();\n\n /* Odak KAPATMA DUGMESINE degil ilk anlamli ogeye. `showModal()` DOM\n sirasindaki ilk odaklanabilir ogeye gidiyor ve o neredeyse her zaman\n basliktaki carpi: ekran okuyucu pencereyi \"Kapat, dugme\" diye aciyor —\n kullanicinin duydugu ilk sey, pencerenin ne oldugu degil ondan nasil\n kacilacagi. */\n focusFirstMeaningful(dialog, `.${styles.modal__close}`);\n /* Odak bir metin alanina dustuyse geri alinir: telefonda ekran klavyesi\n kullanici istemeden aciliyordu (bkz. `helpers/focus.helper`). */\n preventAutoKeyboard(dialog);\n\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, [isOpen]);\n\n /*\n * Arka plan kaydirmasi kilitlenir. `showModal()` arka plani etkilesime\n * kapatir ama kaydirmayi her tarayicida engellemiyor: kullanici pencereyi\n * kaydirdigini sanirken arkadaki listeyi kaydiriyordu. Kilit SAYACLI —\n * ic ice iki panelde ilki kapaninca erken acilmamali (bkz. `useScrollLock`).\n */\n useScrollLock(isOpen);\n\n /*\n * Escape'i tarayici isliyor ama React durumu bundan haberdar olmuyor;\n * `cancel` olayi yakalanmazsa pencere kapanip `isOpen` true kaliyor ve bir\n * daha acilamiyordu.\n */\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const handleCancel = (event: Event) => {\n /* Varsayilan HER ZAMAN engellenir: kapanis karari React'te veriliyor ve\n tarayicinin pencereyi kendi basina kapatmasi durumu `isOpen: true`\n birakiyordu. */\n event.preventDefault();\n if (!isDismissable) return;\n\n /* Yalnizca EN USTTEKI panel kapanir. Ust uste iki pencerede tek bir\n Escape ikisini birden kapatiyordu: `cancel` her ikisine de ulasiyor\n ve ikisi de kendi `onClose`unu cagiriyordu. */\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n\n onClose();\n };\n\n dialog.addEventListener('cancel', handleCancel);\n return () => dialog.removeEventListener('cancel', handleCancel);\n }, [onClose, isDismissable]);\n\n const handleBackdropClick = useCallback(\n (event: MouseEvent<HTMLDialogElement>) => {\n if (!isDismissable) return;\n // Hedef dialog'un KENDISI ise arka plana tiklanmistir; panel degil.\n if (event.target === dialogRef.current) onClose();\n },\n [isDismissable, onClose],\n );\n\n return (\n <dialog\n ref={dialogRef}\n className={cx(styles.modal, styles[`modal--${size}`], className)}\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n data-testid={testId}\n onClick={handleBackdropClick}\n >\n <div className={styles.modal__panel}>\n <header className={styles.modal__header}>\n {icon && (\n <span className={cx(styles.modal__icon, styles[`modal__icon--${tone}`])}>{icon}</span>\n )}\n\n <div className={styles.modal__heading}>\n <h2 id={titleId} className={styles.modal__title}>\n {title}\n </h2>\n {description && (\n <p id={descriptionId} className={styles.modal__description}>\n {description}\n </p>\n )}\n </div>\n\n {isDismissable && (\n <IconButton\n icon={<XLg aria-hidden />}\n label={resolveLabel('Modal.closeLabel', closeLabel, labels?.close)}\n variant=\"ghost\"\n size=\"sm\"\n className={styles.modal__close}\n onClick={onClose}\n />\n )}\n </header>\n\n {/*\n Gövde yalnızca içerik VARSA çizilir: onay pencerelerinin çoğunda soru\n başlıkta ve açıklamada duruyor, gövde boş kalıyor ve boş bir kutu\n 40 px'lik bir boşluk bırakıyordu.\n */}\n {children && <div className={styles.modal__body}>{children}</div>}\n\n {footer && <footer className={styles.modal__footer}>{footer}</footer>}\n </div>\n </dialog>\n );\n};\n\nexport default /*#__PURE__*/ memo(Modal) as typeof Modal;\n","'use client';\n\nimport {\n type KeyboardEvent,\n memo,\n type ReactNode,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { Search } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { scrollIntoViewIfPossible } from '../../helpers/scroll.helper';\nimport { named } from '../../helpers/component.helper';\nimport { captureFocus, isTopModal, pushModal } from '../../helpers/focus.helper';\nimport { matchesSearch } from '../../helpers/text.helper';\nimport useScrollLock from '../../hooks/useScrollLock';\n\nimport styles from './index.module.scss';\n\nexport type CommandItem = {\n id: string;\n label: string;\n /** Ayırt edici ikincil satır — bir komutun nereye götürdüğü. */\n description?: string;\n /** Gruplama başlığı (\"Gezinme\", \"Eylemler\"). Aynı grup ardışık çizilir. */\n group?: string;\n icon?: ReactNode;\n /** Kısayol ipucu (\"⌘K\"). Yalnızca GÖSTERİLİR; tuşu çağıran bağlar. */\n shortcut?: string;\n onSelect: () => void;\n};\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n items: CommandItem[];\n /** Pencerenin erişilebilir adı (\"Komut paleti\"). ZORUNLU. */\n label: string;\n /** Arama kutusunun yer tutucusu ve erişilebilir adı. ZORUNLU. */\n searchPlaceholder: string;\n /** Sonuç yokken yazılan metin. ZORUNLU. */\n emptyMessage: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Komut paleti — klavyeyle her şeye ulaşma.\n *\n * <h3>Neden `Combobox` + `Modal` bileşimi DEĞİL de ayrı bir bileşen</h3>\n * Denendi ve iki yerde kırıldı. `Combobox` bir DEĞER seçtiriyor: seçim\n * tetikleyicide kalıcı olarak görünüyor, `value`/`onChange` sözleşmesi var ve\n * kapanınca seçili öğe hatırlanıyor. Palet ise bir EYLEM çalıştırıyor —\n * hatırlanacak bir değer yok. İkincisi, `Combobox`ın tetikleyicisi var;\n * palette tetikleyici KLAVYE KISAYOLU ve o kısayolu bağlamak çağıranın işi\n * (hangi tuş, hangi sayfada — kütüphane bilemez).\n *\n * <h3>Kısayolu KÜTÜPHANE bağlamaz</h3>\n * `⌘K` yaygın ama evrensel değil ve belge düzeyinde bir tuş dinleyicisi\n * kurmak, tüketicinin kendi kısayollarıyla sessizce çakışmak demek. `shortcut`\n * alanı yalnızca GÖSTERİLİYOR; `isOpen` çağıranın.\n *\n * <h3>Arama `matchesSearch` ile — aksan duyarsız</h3>\n * \"siparis\" yazan kullanıcı \"Sipariş\"i bulmalı. Aynı normalizasyon\n * `Combobox`ın yerel filtresinde de kullanılıyor; iki yerde iki farklı arama\n * kuralı, aynı terimin iki farklı sonuç vermesi demekti.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin komut; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son komut</td></tr>\n * <tr><td>`Enter`</td><td>etkin komutu çalıştırır ve kapatır</td></tr>\n * <tr><td>`Escape`</td><td>kapatır, odak AÇAN öğeye döner</td></tr>\n * </table>\n * Odak arama kutusundan AYRILMAZ; etkin komut `aria-activedescendant` ile\n * bildiriliyor. Odağı listeye taşımak yazmaya devam etmeyi imkânsız\n * kılıyordu.\n */\nconst CommandPalette = ({\n isOpen,\n onClose,\n items,\n label,\n searchPlaceholder,\n emptyMessage,\n className,\n testId,\n}: Props) => {\n const baseId = useId();\n const listboxId = `${baseId}-listbox`;\n const dialogRef = useRef<HTMLDialogElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const tokenRef = useRef<symbol | null>(null);\n\n const [query, setQuery] = useState('');\n const [activeIndex, setActiveIndex] = useState(0);\n\n const visible = useMemo(() => {\n if (query.trim() === '') return items;\n\n const needle = query.trim();\n return items.filter(\n item =>\n matchesSearch(item.label, needle) ||\n (item.description ? matchesSearch(item.description, needle) : false),\n );\n }, [items, query]);\n\n useScrollLock(isOpen);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (!isOpen) {\n if (dialog.open) dialog.close();\n return;\n }\n\n const restoreFocus = captureFocus();\n if (!dialog.open) dialog.showModal();\n\n /* Arama kutusu ACILIR ACILMAZ odaklanir: paletin tek amaci yazmak.\n `preventScroll` — odaklanan kutu ust katmanda ve iOS sayfayi\n kaydirmaya calisiyordu. */\n inputRef.current?.focus({ preventScroll: true });\n setQuery('');\n setActiveIndex(0);\n\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, [isOpen]);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const handleCancel = (event: Event) => {\n event.preventDefault();\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n onClose();\n };\n\n dialog.addEventListener('cancel', handleCancel);\n return () => dialog.removeEventListener('cancel', handleCancel);\n }, [onClose]);\n\n /* Etkin komut gorunur alanin disina cikmamali. */\n useEffect(() => {\n scrollIntoViewIfPossible(dialogRef.current?.querySelector(`[data-index=\"${activeIndex}\"]`), {\n block: 'nearest',\n });\n }, [activeIndex]);\n\n const run = (item: CommandItem) => {\n item.onSelect();\n onClose();\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n const lastIndex = visible.length - 1;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActiveIndex(current => (current >= lastIndex ? 0 : current + 1));\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n setActiveIndex(current => (current <= 0 ? lastIndex : current - 1));\n break;\n\n case 'Home':\n event.preventDefault();\n setActiveIndex(0);\n break;\n\n case 'End':\n event.preventDefault();\n setActiveIndex(lastIndex);\n break;\n\n case 'Enter': {\n event.preventDefault();\n const item = visible[activeIndex];\n if (item) run(item);\n break;\n }\n\n default:\n break;\n }\n };\n\n return (\n <dialog\n ref={dialogRef}\n className={cx(styles.palette, className)}\n aria-label={label}\n data-testid={testId}\n onClick={event => event.target === dialogRef.current && onClose()}\n >\n <div className={styles.palette__search}>\n <Search aria-hidden className={styles.palette__searchIcon} />\n\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n className={styles.palette__input}\n value={query}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n autoComplete=\"off\"\n aria-autocomplete=\"list\"\n aria-expanded\n aria-controls={listboxId}\n aria-activedescendant={\n visible[activeIndex] ? `${baseId}-option-${activeIndex}` : undefined\n }\n onChange={event => {\n setQuery(event.target.value);\n /* Yazmak etkin komutu BASA ceker: eski satir suzulmus listede\n kalmiyordu. */\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n </div>\n\n <ul id={listboxId} role=\"listbox\" aria-label={label} className={styles.palette__list}>\n {visible.map((item, index) => {\n /* Grup basligi yalnizca DEGISTIGINDE cizilir: her satirin ustune\n baslik koymak listeyi iki katina cikariyordu. */\n const isNewGroup = item.group !== undefined && item.group !== visible[index - 1]?.group;\n\n return (\n <li key={item.id}>\n {isNewGroup && (\n /* `aria-hidden`: baslik bir SECENEK degil; listbox'in cocugu\n olarak okunsaydi ekran okuyucu sayimi bozuluyordu. */\n <span className={styles.palette__group} aria-hidden>\n {item.group}\n </span>\n )}\n\n <div\n id={`${baseId}-option-${index}`}\n role=\"option\"\n data-index={index}\n aria-selected={index === activeIndex}\n className={cx(\n styles.palette__item,\n index === activeIndex && styles['palette__item--active'],\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => run(item)}\n >\n {item.icon && (\n <span className={styles.palette__icon} aria-hidden>\n {item.icon}\n </span>\n )}\n\n <span className={styles.palette__text}>\n <span className={styles.palette__label}>{item.label}</span>\n {item.description && (\n <span className={styles.palette__description}>{item.description}</span>\n )}\n </span>\n\n {item.shortcut && (\n <kbd className={styles.palette__shortcut} aria-hidden>\n {item.shortcut}\n </kbd>\n )}\n </div>\n </li>\n );\n })}\n\n {visible.length === 0 && <li className={styles.palette__empty}>{emptyMessage}</li>}\n </ul>\n </dialog>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(CommandPalette, 'CommandPalette'),\n) as typeof CommandPalette;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useState } from 'react';\n\nimport { ExclamationTriangleFill, QuestionCircleFill, TrashFill } from 'react-bootstrap-icons';\n\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport Button from '../Button';\nimport Modal, { type ModalTone } from '../Modal';\n\nexport type ConfirmKind = 'destructive' | 'warning' | 'neutral';\n\n/** Üçü de DOLU sürüm: madalyonun tint zemininde kontur kaybolur. */\nconst KIND_ICON: Record<ConfirmKind, ReactNode> = {\n destructive: <TrashFill aria-hidden />,\n warning: <ExclamationTriangleFill aria-hidden />,\n neutral: <QuestionCircleFill aria-hidden />,\n};\n\nconst KIND_TONE: Record<ConfirmKind, ModalTone> = {\n destructive: 'danger',\n warning: 'warning',\n neutral: 'info',\n};\n\nconst KIND_VARIANT: Record<ConfirmKind, UIVariant> = {\n destructive: UIVariant.DANGER,\n warning: UIVariant.PRIMARY,\n neutral: UIVariant.PRIMARY,\n};\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n /**\n * Onaylandığında çalışır. `Promise` dönerse düğme beklerken yükleme\n * durumuna geçer ve pencere <strong>kapanmaz</strong>.\n *\n * <p>İşlem başarılıysa pencereyi kapatmak çağıranın işi: hata durumunda\n * pencerenin açık kalması gerekiyor ki kullanıcı tekrar deneyebilsin.\n */\n onConfirm: () => void | Promise<void>;\n /** Soru cümlesi. Eylem odaklı yazılır: \"…silinsin mi?\". */\n title: string;\n /** Sonucu açıklar: neyin geri alınamaz olduğu burada yazılır. */\n description?: ReactNode;\n /**\n * Onay düğmesinin etiketi — ZORUNLU, config'ten okunmaz.\n *\n * <p>Eylemi TEKRARLAR: \"Sil\", \"İptal et\". Her pencerede farklı olduğu için\n * uygulama düzeyinde bir varsayılanı olamaz; \"Tamam\" gibi bir varsayılan\n * kullanıcıya neyi onayladığını söylemez ve `window.confirm()`ten kaçmamızın\n * sebeplerinden biri tam olarak buydu.\n */\n confirmLabel: string;\n /** Verilmezse `labels.cancel`. */\n cancelLabel?: string;\n /** Verilmezse `labels.close`. */\n closeLabel?: string;\n /**\n * Onayın türü — ikon, ton ve onay düğmesinin varyantını birlikte belirler.\n *\n * <p>Ad `kind`ten `variant`a taşındı: aynı işi yapan üçüncü bir ad\n * kütüphanede zaten `variant` olarak duruyordu (`Button`, `Badge`) ve\n * tüketici her bileşende hangisinin geçerli olduğunu hatırlamak zorunda\n * kalıyordu. Nöbetçi: `src/__tests__/api-consistency.test.ts`.\n */\n variant?: ConfirmKind;\n /** @deprecated `variant` kullanın. Bir sonraki büyük sürümde kalkacak. */\n kind?: ConfirmKind;\n /** Ek bağlam: silinecek kaydın özeti, uyarı kutusu. */\n children?: ReactNode;\n};\n\n/**\n * Onay penceresi.\n *\n * <h3>Neden `window.confirm()` yerine bu</h3>\n * Yerel `confirm()`in dört sorunu var:\n * <ul>\n * <li>Görünümü işletim sisteminin — sitenin diliyle hiç ilgisi yok, üstünde\n * tarayıcının alan adı yazıyor.</li>\n * <li><strong>Ana iş parçacığını kilitler.</strong></li>\n * <li>Yıkıcı eylemi vurgulayamaz: \"Tamam\" ile \"İptal\" aynı ağırlıkta ve\n * hangisinin sildiğini yalnızca metinden anlıyorsun.</li>\n * <li>İstek sürerken geri bildirim veremez; kullanıcı silme düğmesine ikinci\n * kez basıyordu.</li>\n * </ul>\n *\n * <h3>Yükleme durumu pencerede kalır</h3>\n * Onaya basıldığında pencere hemen kapanmaz: düğme yükleniyor durumuna geçer\n * ve pencere kapanmaz hâle gelir (`isDismissable={false}`). İstek bittiğinde\n * kapatma kararı çağırana ait — hata varsa pencere açık kalmalı ki kullanıcı\n * tekrar deneyebilsin.\n *\n * @example\n * const [target, setTarget] = useState<Address | null>(null);\n *\n * <ConfirmDialog\n * isOpen={target !== null}\n * onClose={() => setTarget(null)}\n * kind=\"destructive\"\n * title=\"Adres silinsin mi?\"\n * description=\"Bu işlem geri alınamaz.\"\n * confirmLabel=\"Sil\"\n * cancelLabel=\"Vazgeç\"\n * closeLabel=\"Kapat\"\n * onConfirm={async () => {\n * await remove(target!.id);\n * setTarget(null);\n * }}\n * />\n */\nconst ConfirmDialog: FC<Props> = ({\n isOpen,\n onClose,\n onConfirm,\n title,\n description,\n confirmLabel,\n cancelLabel,\n closeLabel,\n variant,\n kind,\n children,\n}) => {\n const { labels } = useHanui();\n const [isRunning, setIsRunning] = useState(false);\n\n /* Eski prop bir surum boyunca calisir; `variant` verilmisse o kazanir. */\n const resolvedVariant: ConfirmKind = variant ?? kind ?? 'neutral';\n\n const handleConfirm = async () => {\n setIsRunning(true);\n try {\n await onConfirm();\n } finally {\n /*\n * `finally`: istek hata verse de yukleme durumu birakilir. Aksi halde\n * dugme sonsuza kadar donuyor ve kullanici tekrar deneyemiyordu.\n * Pencereyi KAPATMAK cagirana ait — hata varsa acik kalmali.\n */\n setIsRunning(false);\n }\n };\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n closeLabel={closeLabel ?? labels?.close}\n description={description}\n icon={KIND_ICON[resolvedVariant]}\n tone={KIND_TONE[resolvedVariant]}\n size=\"sm\"\n // Islem surerken kapanmaz: kapanma, islem iptal edilmis gibi gorunuyordu.\n isDismissable={!isRunning}\n footer={\n <>\n {/*\n \"Vazgec\" JSX'te ONCE: klavyeyle sekme sirasi soldan saga mantikli\n olmali. Ekranda mobilde `column-reverse` ile alta duser.\n */}\n <Button\n variant={UIVariant.SECONDARY}\n size={UISize.MEDIUM}\n onClick={onClose}\n disabled={isRunning}\n >\n {resolveLabel('ConfirmDialog.cancelLabel', cancelLabel, labels?.cancel)}\n </Button>\n <Button\n variant={KIND_VARIANT[resolvedVariant]}\n size={UISize.MEDIUM}\n onClick={handleConfirm}\n isLoading={isRunning}\n >\n {confirmLabel}\n </Button>\n </>\n }\n >\n {children}\n </Modal>\n );\n};\n\nexport default /*#__PURE__*/ memo(ConfirmDialog) as typeof ConfirmDialog;\n","'use client';\n\nimport {\n memo,\n type MouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport {\n captureFocus,\n focusFirstMeaningful,\n isTopModal,\n preventAutoKeyboard,\n pushModal,\n} from '../../helpers/focus.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport useScrollLock from '../../hooks/useScrollLock';\nimport { useHanui } from '../../theme/context';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n /** Kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n children: ReactNode;\n /**\n * Panelin hangi kenardan geldiği. Mantıksal: `end` RTL'de sola açılır.\n *\n * <p>Varsayılan `end` — filtre ve ayrıntı panelleri okuma yönünün SONUNDAN\n * gelir; `start` gezinme panelleri içindir.\n */\n side?: 'start' | 'end';\n size?: 'sm' | 'md' | 'lg';\n /** Dipte duran eylem şeridi; gövde kaydırılırken yerinde kalır. */\n footer?: ReactNode;\n /** Başlığın altında duran, gövdeyle birlikte kaymayan şerit. */\n toolbar?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Çekmece (drawer) — kenardan açılan kipsel panel.\n *\n * <h3>{@link BottomSheet} ile farkı: EKRAN, tercih değil</h3>\n * İkisi de kipsel bir yan panel; ayrım hangi ekranda doğru olduklarında:\n *\n * <ul>\n * <li>`BottomSheet` DAR ekran içindir. Baş parmağın erişebildiği yer\n * ekranın dibi; kenardan gelen bir panel telefonda ekranın tamamını\n * kaplıyor ve \"panel\" olmaktan çıkıyor.</li>\n * <li><b>`Drawer` GENİŞ ekran içindir.</b> Filtre paneli ve ayrıntı\n * incelemesi sayfanın yanında durur; kullanıcı listeyi görmeye devam\n * eder. Aynı panel dipten gelseydi 1440 px'lik bir ekranda içeriğin\n * tamamını örtüyordu.</li>\n * </ul>\n *\n * <h3>`isOpen` alır — ve bu {@link BottomSheet}ten bilinçli bir AYRILIK</h3>\n * `BottomSheet` \"açıkken çizilir, kapatmak için kaldırılır\" sözleşmesini\n * kullanıyor ve bunun bir bedeli var: React sökülen bir ağacı bekletmediği\n * için <strong>çıkış animasyonu çizilemiyor</strong>, panel bir karede yok\n * oluyor. Çekmece açık/kapalı durumu kendisi taşıyor; `<dialog>` kapanırken\n * `@starting-style` + `allow-discrete` ile geri kayıyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Escape`</td><td>kapatır — üst üste açık panellerde YALNIZCA en üstteki</td></tr>\n * <tr><td>`Tab`</td><td>odak panelin içinde döner (tarayıcı: `showModal()`)</td></tr>\n * </table>\n * Açılışta odak kapatma düğmesine DEĞİL ilk anlamlı öğeye gider.\n */\nconst Drawer = ({\n isOpen,\n onClose,\n title,\n closeLabel,\n children,\n side = 'end',\n size = 'md',\n footer,\n toolbar,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const dialogRef = useRef<HTMLDialogElement>(null);\n /* Yigindaki yerimiz: Escape yalnizca EN USTTEKI panelde islenir. */\n const tokenRef = useRef<symbol | null>(null);\n const titleId = useId();\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (!isOpen) {\n if (dialog.open) dialog.close();\n return;\n }\n\n const restoreFocus = captureFocus();\n if (!dialog.open) dialog.showModal();\n\n focusFirstMeaningful(dialog, `.${styles.drawer__close}`);\n preventAutoKeyboard(dialog);\n\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, [isOpen]);\n\n useScrollLock(isOpen);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const handleCancel = (event: Event) => {\n event.preventDefault();\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n onClose();\n };\n\n dialog.addEventListener('cancel', handleCancel);\n return () => dialog.removeEventListener('cancel', handleCancel);\n }, [onClose]);\n\n const handleBackdropClick = useCallback(\n (event: MouseEvent<HTMLDialogElement>) => {\n // Hedef dialog'un KENDISI ise perdeye tiklanmistir; panel degil.\n if (event.target === dialogRef.current) onClose();\n },\n [onClose],\n );\n\n return (\n <dialog\n ref={dialogRef}\n className={cx(styles.drawer, styles[`drawer--${side}`], styles[`drawer--${size}`], className)}\n aria-labelledby={titleId}\n data-testid={testId}\n onClick={handleBackdropClick}\n >\n <header className={styles.drawer__header}>\n <h2 id={titleId} className={styles.drawer__title}>\n {title}\n </h2>\n\n <IconButton\n icon={<XLg aria-hidden />}\n label={resolveLabel('Drawer.closeLabel', closeLabel, labels?.close)}\n variant=\"ghost\"\n size=\"sm\"\n className={styles.drawer__close}\n onClick={onClose}\n />\n </header>\n\n {toolbar && <div className={styles.drawer__toolbar}>{toolbar}</div>}\n\n <div className={styles.drawer__body}>{children}</div>\n\n {footer && <div className={styles.drawer__footer}>{footer}</div>}\n </dialog>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Drawer, 'Drawer')) as typeof Drawer;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useEffect, useId, useRef, useState } from 'react';\n\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport Button from '../Button';\nimport Field, { type FieldChildProps } from '../Field';\nimport Input from '../Input';\nimport Modal from '../Modal';\nimport Textarea from '../Textarea';\n\nimport styles from './index.module.scss';\n\ntype BaseProps = {\n isOpen: boolean;\n /** Vazgeçme ve perde/Escape kapanışı. Başarı kapanışını bileşen kendisi yapar. */\n onClose: () => void;\n /**\n * Girilen değerle çalışır (değer kırpılmış gönderilir). Reddederse pencere\n * AÇIK kalır ve metin korunur; hata bildirimi çağıranın işi — bildirimi\n * gösterip hatayı yeniden fırlatın ya da hiç yakalamayın.\n */\n onSubmit: (value: string) => void | Promise<void>;\n title: string;\n /** Girdi alanının etiketi. */\n label: string;\n /** Verilmezse `labels.submit`. */\n submitLabel?: string;\n /** Verilmezse `labels.cancel`. */\n cancelLabel?: string;\n /** Kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n /** Başlığın altındaki bir cümlelik bağlam. */\n description?: ReactNode;\n hint?: string;\n placeholder?: string;\n defaultValue?: string;\n /**\n * `text` tek satır, `multiline` gerekçe gibi uzun metin, `number` adet/fark\n * gibi sayılar. Değer her durumda dize döner; ayrıştırmak çağıranın işi\n * (bir stok farkı `-5` gibi işaretli olabiliyor).\n */\n inputMode?: 'text' | 'multiline' | 'number';\n maxLength?: number;\n rows?: number;\n};\n\ntype Props = BaseProps & {\n /** Boş (yalnızca boşluk dahil) değer gönderilemez. */\n isRequired?: boolean;\n /**\n * Zorunluluk yıldızının ekran okuyucu karşılığı (\"(zorunlu)\").\n *\n * <p>Yıldız yalnızca GÖRSEL bir kısayol; renk ve şekil tek başına anlam\n * taşıyamaz (WCAG 1.4.1), o yüzden yanında okunabilir bir metin olmak\n * zorunda. Verilmezse `labels.required` okunur.\n */\n requiredLabel?: string;\n};\n\n/**\n * Metin isteyen pencere — `window.prompt()` yerine.\n *\n * <h3>Neden</h3>\n * Tarayıcı istemi tek satırlık, biçimlenemiyor, ana iş parçacığını\n * kilitliyor ve bazı tarayıcılarda sayfayı engelliyor. Bu bileşen aynı işi\n * `Modal` + `Field` + girdi ile yapar ve pencere kapanma kuralını\n * (aşağıda) getirir.\n *\n * <h3>Pencere yalnızca BAŞARIDA kapanır</h3>\n * `onSubmit` reddederse pencere açık kalır ve yazılan metin korunur — istek\n * patlarsa kullanıcının yazdığı gerekçe geri dönüşsüz silinmemeli. Değer\n * yalnızca pencere <em>yeniden açılırken</em> `defaultValue`dan tazelenir.\n *\n * <h3>Enter gönderir</h3>\n * Girdi bir `<form>` içinde; dip düğmesi `form` özniteliğiyle ona bağlanır\n * (`Modal` dip şeridi formun dışında çizer). `multiline` kipinde Enter satır\n * başı yapar, gönderme düğmeden.\n */\nconst PromptDialog: FC<Props> = ({\n isOpen,\n onClose,\n onSubmit,\n title,\n label,\n submitLabel,\n cancelLabel,\n closeLabel,\n description,\n hint,\n placeholder,\n defaultValue = '',\n isRequired,\n requiredLabel,\n inputMode = 'text',\n maxLength,\n rows = 4,\n}) => {\n const { labels } = useHanui();\n const formId = useId();\n const [value, setValue] = useState(defaultValue);\n const [isBusy, setIsBusy] = useState(false);\n\n /*\n * Deger yalnizca ACILIS kenarinda tazelenir. `isOpen`'a bagli duz bir etki,\n * pencere acikken gelen her ust render'da yazilani ezebilirdi; hatada acik\n * kalan penceredeki metin de korunmali.\n */\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (isOpen && !wasOpenRef.current) setValue(defaultValue);\n wasOpenRef.current = isOpen;\n }, [isOpen, defaultValue]);\n\n const trimmed = value.trim();\n const isSubmitDisabled = Boolean(isRequired) && trimmed === '';\n\n /** Girdi, `Field`in urettigi erisilebilirlik baglariyla cizilir. */\n const renderControl = (props: FieldChildProps) =>\n inputMode === 'multiline' ? (\n <Textarea\n {...props}\n value={value}\n onChange={event => setValue(event.target.value)}\n placeholder={placeholder}\n maxLength={maxLength}\n rows={rows}\n />\n ) : (\n <Input\n {...props}\n type={inputMode === 'number' ? 'number' : 'text'}\n value={value}\n onChange={event => setValue(event.target.value)}\n placeholder={placeholder}\n maxLength={maxLength}\n />\n );\n\n const handleSubmit = async () => {\n if (isSubmitDisabled || isBusy) return;\n\n setIsBusy(true);\n try {\n await onSubmit(trimmed);\n // Yalnizca basarida: hata durumunda pencere acik, metin yerinde kalir.\n onClose();\n } catch {\n // Bildirim cagiranin isi; burada yalnizca pencere acik tutulur.\n } finally {\n setIsBusy(false);\n }\n };\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n closeLabel={closeLabel ?? labels?.close}\n description={description}\n size=\"sm\"\n // Istek surerken kapanmaz: kapanis \"islem iptal oldu\" gibi gorunuyordu.\n isDismissable={!isBusy}\n footer={\n <>\n <Button\n variant={UIVariant.SECONDARY}\n size={UISize.MEDIUM}\n onClick={onClose}\n disabled={isBusy}\n >\n {resolveLabel('PromptDialog.cancelLabel', cancelLabel, labels?.cancel)}\n </Button>\n <Button\n type=\"submit\"\n form={formId}\n variant={UIVariant.PRIMARY}\n size={UISize.MEDIUM}\n disabled={isSubmitDisabled}\n isLoading={isBusy}\n >\n {resolveLabel('PromptDialog.submitLabel', submitLabel, labels?.submit)}\n </Button>\n </>\n }\n >\n <form\n id={formId}\n className={styles.form}\n onSubmit={event => {\n event.preventDefault();\n handleSubmit();\n }}\n >\n <Field label={label} hint={hint} isRequired={isRequired} requiredLabel={requiredLabel}>\n {renderControl}\n </Field>\n </form>\n </Modal>\n );\n};\n\nexport default /*#__PURE__*/ memo(PromptDialog) as typeof PromptDialog;\n","import { type FC, type HTMLAttributes, memo, type TableHTMLAttributes } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype ScrollerProps = HTMLAttributes<HTMLDivElement> & {\n /**\n * Çerçeve (hairline + yarıçap + yüzey). Gömülü tablolarda kapatılır: orada\n * tablo zaten bir kartın içinde ve ikinci bir çerçeve kutu içinde kutu\n * görünüyordu.\n */\n hasFrame?: boolean;\n};\n\n/**\n * Tablo kaydırma kutusu — \"tablo kendi kutusunda kayar, sayfa asla yatay\n * kaymaz\" kuralının tek uygulaması.\n *\n * <p>Yatay kaydırma yalnızca BİLEREK kurulur: geniş tablo bu kutunun içinde\n * kayar; `min-width: 0` + `align-self: stretch` kutunun esnek bir kapsayıcıda\n * kendisinin taşmasını engeller. Üç tablonun üç ayrı elle kurulmuş (ya da hiç\n * kurulmamış) kaydırma stratejisi vardı; stratejisi olmayan tabloda monospace\n * değerler 360 px'te sayfanın kendisini yatay kaydırıyordu.\n *\n * <p>Kaydırma çubuğu TEMALI (`custom-scrollbar`): işletim sisteminin açık\n * çubuğu koyu temada tablonun altında parlak bir şerit bırakıyordu.\n */\nexport const TableScroller: FC<ScrollerProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ hasFrame = true, className, children, ...rest }) => (\n <div\n className={cx(styles.scroller, hasFrame && styles['scroller--frame'], className)}\n {...rest}\n >\n {children}\n </div>\n )),\n 'TableScroller',\n);\n\ntype Props = TableHTMLAttributes<HTMLTableElement> &\n Partial<{\n /**\n * Hücre dolgusu. Tablolar aynı iskeleti paylaşır ama yoğunlukları içeriğe\n * göre değişir: yüzlerce satırlık bir liste sıkı, karşılaştırma matrisi\n * ferah durur.\n */\n density: 'compact' | 'regular' | 'spacious';\n /**\n * Başlık satırı `$surface-2` zeminle kutunun içinde YAPIŞKAN kalır.\n * Zemin zorunlu: saydam başlığın arkasından kayan satırlar geçiyordu.\n * `top: 0` doğru olan — referans üst bant değil, tablonun kendi kaydırma\n * kutusu.\n */\n hasStickyHead: boolean;\n /** Satır hover zemini: çok sütunlu tabloda göz satırını kaybediyor. */\n hasRowHover: boolean;\n }>;\n\n/**\n * Temel tablo — hairline satır ayrımı, `$surface-2` başlık, yoğunluk ölçeği.\n *\n * <p>Görsel kararlar (hangi hücre monospace, hangi sütun sabit) çağıranın\n * modülünde kalır; teknik değer hücresi `@include technical-text` ile\n * yazılır. Bileşen yalnızca üç tabloda üçe ayrışmış iskelet kurallarını tek\n * yerde toplar.\n *\n * <p>Operasyon ekranlarının durum satırlı (yükleniyor/hata/boş) sürümü için\n * {@link DataTable}.\n */\nconst Table: FC<Props> = ({\n density = 'regular',\n hasStickyHead,\n hasRowHover,\n className,\n children,\n ...rest\n}) => (\n <table\n className={cx(\n styles.table,\n styles[`table--${density}`],\n hasStickyHead && styles['table--sticky-head'],\n hasRowHover && styles['table--row-hover'],\n className,\n )}\n {...rest}\n >\n {children}\n </table>\n);\n\nexport default /*#__PURE__*/ memo(Table) as typeof Table;\n","import { Children, type FC, type HTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { ExclamationCircleFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\nexport type DataTableColumn = {\n /** Sütun kimliği (React key). */\n key: string;\n /** Başlık hücresinin içeriği. Toplu seçim kutusu gibi öğeler de girebilir. */\n label?: ReactNode;\n /**\n * Görsel başlığı olmayan sütunun erişilebilir adı (eylem sütunu gibi).\n * Boş bir `<th>` ekran okuyucuda adsız bir sütun bırakıyordu.\n *\n * <p>Metin `aria-label` OLARAK DEĞİL, görsel olarak gizlenmiş gerçek bir\n * metin düğümü olarak yazılır — gerekçe {@link DataTable} JSDoc'unda.\n */\n srLabel?: string;\n /**\n * Sıralanabilir sütunun yönü (`aria-sort`).\n *\n * <p>`onSort` ile birlikte verildiğinde başlık TIKLANABİLİR olur ve yön\n * oku çizilir. Tek başına verildiğinde yalnızca durumu bildirir —\n * sıralamayı başka bir denetim (bir `Select`) yapıyorsa doğrusu budur.\n */\n ariaSort?: 'ascending' | 'descending';\n /**\n * Sütun sıralanabilir. `DataTable.onSort` ile birlikte anlamlı; ikisinden\n * biri eksikse başlık düz metin kalır — tıklanabilir görünüp hiçbir şey\n * yapmayan bir başlık, kullanıcıya var olmayan bir yetenek vaat ediyordu.\n */\n isSortable?: boolean;\n /**\n * Sütun yatay kaydırmada YERİNDE kalır.\n *\n * <p>Yalnızca İLK sütunda anlamlı: geniş bir tabloda sağa kaydıran\n * kullanıcı hangi satıra baktığını kaybediyordu. İkinci bir yapışkan sütun\n * `left` ofsetinin elle hesaplanmasını gerektirir ve o hesap sütun\n * genişliğine bağlı — desteklenmiyor.\n */\n isSticky?: boolean;\n className?: string;\n};\n\ntype Props = {\n columns: DataTableColumn[];\n /**\n * Gövde satırları (`<tr>`). Ekranların özel hücreleri, bağlantıları ve satır\n * tintleri burada yaşar; tablo yalnızca kabuğu ve durum satırlarını\n * üstlenir. Uyarı tinti için {@link DataTableRow}.\n */\n children?: ReactNode;\n /** Satır yokken gösterilen metin. Verilmezse `labels.dataTable.empty`. */\n emptyMessage?: string;\n /** Yükleme sürerken gösterilen metin. Verilmezse `labels.dataTable.loading`. */\n loadingMessage?: string;\n isLoading?: boolean;\n /**\n * Liste ÇEKİLEMEDİ. <strong>\"Yüklenemedi\" ile \"boş\" ayrı durumlardır</strong>:\n * hata verilmişken boş mesajı asla çizilmez — ağ hatasını \"kayıt kalmamış\"\n * diye okutmak kullanıcıya yanlış karar verdirir. Hatayı tablonun dışında\n * (`Alert`) gösteren ekran bu prop'u geçmez.\n */\n error?: string | null;\n /**\n * Gövde `100dvh - <bant>` ile sınırlanır ve başlık satırı kendi kaydırma\n * alanına yapışır. Sınırsız yükseklikte `position: sticky` HİÇ çalışmıyordu:\n * `overflow` alanı ekrandan uzun olunca başlık sayfayla birlikte yukarı çıkıp\n * gidiyordu.\n */\n hasViewportCap?: boolean;\n /**\n * Sıralanabilir bir başlığa basıldığında çağrılır.\n *\n * <p>Sıralamanın KENDİSİ burada yapılmaz: veri çağıranın ve sıralama\n * neredeyse her zaman sunucuda (sayfalanmış bir listede istemcide sıralamak\n * yalnızca görünen sayfayı sıralar — kullanıcı \"en ucuz\" dediğinde en ucuz\n * 24 ürünü değil, o sayfadaki en ucuzu görüyordu).\n */\n onSort?: (key: string, direction: 'ascending' | 'descending') => void;\n /**\n * Satır seçildiğinde beliren TOPLU EYLEM şeridi.\n *\n * <p>Tablonun ÜSTÜNDE ve yapışkan: kullanıcı yüzlerce satır arasında\n * seçim yapıp aşağı kaydırdığında eylem şeridi ekranın dışında kalıyor ve\n * seçimin ne işe yaradığı görünmüyordu.\n */\n bulkBar?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Operasyon veri tablosu — durum satırlı tablo sözleşmesi.\n *\n * <h3>Neden bir bileşen</h3>\n * On iki ekranda on bir ham tablo ve altı kaydırma sarmalayıcısı kopyası\n * vardı; üçü farklı davranıyordu (kimi dikey kaymıyor, kiminin başlığı\n * yapışmıyor). Kabuk (yüzey + hairline + `overflow: auto`), tablo görünümü ve\n * üç durum satırı (yükleniyor / hata / boş) artık tek yerde; `colSpan` sütun\n * sayısından kendiliğinden hesaplanır — elle yazılan `colSpan={8}` bir sütun\n * eklenince sessizce yanlış kalıyordu.\n *\n * <h3>Durum öncelik sırası</h3>\n * `error` &gt; `isLoading` &gt; boş &gt; satırlar. Hata varken yükleme veya boş\n * mesajı gösterilmez; yüklenirken bayat satır çizilmez.\n *\n * <h3>Görünmez başlık `aria-label` DEĞİL, gizlenmiş METİN</h3>\n * Eylem sütununun adı önce `<th aria-label=\"Eylemler\">` olarak yazılıyordu.\n * Eksen taraması bunu ihlal olarak bildirdi (`empty-table-header`) ve haklı:\n * `aria-label`ın hücre başlığı olarak kullanılması destek teknolojilerinde\n * tutarsız — bazı ekran okuyucular tablo gezinme kipinde sütun adını\n * hücrenin İÇERİĞİNDEN okur ve boş bir `<th>` orada adsız kalır. Görsel olarak\n * gizlenmiş gerçek bir metin düğümü hem okunur hem de sayfa çevirisine,\n * bulma-değiştirmeye ve seçime dahil olur.\n */\nconst DataTable: FC<Props> = ({\n columns,\n children,\n isLoading,\n error,\n emptyMessage,\n loadingMessage,\n hasViewportCap,\n onSort,\n bulkBar,\n className,\n testId,\n}) => {\n /*\n * Bosluk karari satir SAYISINDAN verilir; cagiranin ayrica `isEmpty` gecmesi\n * gerekmez. Satirlar tek bir Fragment icinde verilirse sayi 1 gorunur —\n * satirlari dogrudan (ya da dizi olarak) verin.\n */\n const { labels } = useHanui();\n const rowCount = Children.count(children);\n\n const renderStateRow = (content: ReactNode, modifier?: 'error') => (\n <tr>\n <td\n colSpan={columns.length}\n className={cx(styles.state, modifier && styles[`state--${modifier}`])}\n >\n {content}\n </td>\n </tr>\n );\n\n return (\n <div\n className={cx(styles.wrapper, hasViewportCap && styles['wrapper--capped'], className)}\n data-testid={testId}\n >\n {bulkBar && <div className={styles.bulkBar}>{bulkBar}</div>}\n\n <table className={styles.table}>\n <thead>\n <tr>\n {columns.map(column => {\n const isSortable = Boolean(column.isSortable && onSort);\n /* Ilk tikta ARTAN; ikinci tik yonu cevirir. Sifirdan azalan\n baslamak, \"en pahali\" listeyi varsayilan yapiyordu. */\n const nextDirection = column.ariaSort === 'ascending' ? 'descending' : 'ascending';\n\n return (\n <th\n key={column.key}\n scope=\"col\"\n aria-sort={column.ariaSort}\n className={cx(column.className, column.isSticky && styles.sticky)}\n >\n {isSortable ? (\n /*\n * Siralama bir DUGME, `<th>`ye yazilan `onClick` degil.\n * Baslik hucresi odaklanabilir degil ve klavye kullanicisi\n * siralamaya HIC ulasamiyordu; ustelik ekran okuyucu\n * tiklanabilir oldugunu da soylemiyordu.\n */\n <button\n type=\"button\"\n className={styles.sort}\n onClick={() => onSort?.(column.key, nextDirection)}\n >\n {column.label}\n {column.srLabel && <span className={styles.srOnly}>{column.srLabel}</span>}\n\n {/*\n Yon oku: `aria-hidden` cunku ayni bilgi `aria-sort`ta.\n Siralanabilir ama siralanmamis sutunda SOLUK bir cift\n ok duruyor — sutunun siralanabildigi ancak uzerine\n gelince anlasiliyordu.\n */}\n <span\n aria-hidden\n className={cx(\n styles.sort__arrow,\n column.ariaSort && styles[`sort__arrow--${column.ariaSort}`],\n )}\n >\n {column.ariaSort === 'descending' ? '▾' : '▴'}\n </span>\n </button>\n ) : (\n <>\n {column.label}\n {column.srLabel && <span className={styles.srOnly}>{column.srLabel}</span>}\n </>\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {error\n ? renderStateRow(\n <span role=\"alert\" className={styles.state__message}>\n <ExclamationCircleFill aria-hidden />\n {error}\n </span>,\n 'error',\n )\n : isLoading\n ? renderStateRow(\n resolveLabel(\n 'DataTable.loadingMessage',\n loadingMessage,\n labels?.dataTable?.loading,\n ),\n )\n : rowCount === 0\n ? renderStateRow(\n resolveLabel('DataTable.emptyMessage', emptyMessage, labels?.dataTable?.empty),\n )\n : children}\n </tbody>\n </table>\n </div>\n );\n};\n\ntype RowProps = HTMLAttributes<HTMLTableRowElement> & {\n children: ReactNode;\n /**\n * Satır dikkat bekleyen iş taşıyor (kritik stok, karar bekleyen talep).\n *\n * <p>TEK desen: tint zemin + ilk hücrede sol kenar işareti. Önceden iki\n * uygulama vardı — yalnız düz uyarı zemini ve zemin + sol iç gölge. Zemin\n * tek başına yetmiyordu: hover vurgusu tinti ezince satırın \"iş bekliyor\"\n * bilgisi kayboluyordu ve renk tek başına zaten anlam taşıyamaz (WCAG\n * 1.4.1) — sol işaret hover'da da yerinde kalır.\n */\n isWarning?: boolean;\n};\n\nexport const DataTableRow: FC<RowProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ isWarning, className, children, ...rest }) => (\n <tr className={cx(isWarning && styles['row--warning'], className)} {...rest}>\n {children}\n </tr>\n )),\n 'DataTableRow',\n);\n\nexport default /*#__PURE__*/ memo(DataTable) as typeof DataTable;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /**\n * Filtreler uygulanır. `preventDefault` bileşenin işi; çağıran yalnızca\n * durumunu günceller (sayfayı 1'e almak + aramayı uygulamak gibi).\n */\n onSubmit: () => void;\n /** Alanlar — her biri {@link FilterBarField} içinde. */\n children: ReactNode;\n /** Şeridin sağ ucundaki eylemler (\"Uygula\" düğmesi gibi). */\n actions?: ReactNode;\n /** Şeridin erişilebilir adı. Verilmezse `labels.filters`. */\n label?: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Filtre şeridi.\n *\n * <h3>Her zaman `<form onSubmit>`</h3>\n * Beş ekran şeridi elle kuruyordu ve yalnızca üçü `<form>` kullanıyordu: arama\n * kutusunda Enter üç ekranda filtreyi uyguluyor, ikisinde hiçbir şey\n * yapmıyordu. Şerit artık her zaman bir formdur ve görünür bir gönderme düğmesi\n * olmasa bile Enter çalışsın diye gizli bir yedek gönderme düğmesi taşır\n * (birden çok alanı olan formda tarayıcının örtük gönderimi ancak bir gönderme\n * düğmesi varsa çalışır).\n *\n * <h3>320px'te taşma yok</h3>\n * Alanlar `min-width: 240–280px` taşıyordu ve en dar ekranda şerit sayfayı yana\n * kaydırıyordu. Genişlik artık `flex-basis` ile istenir, `min-width: 0` ile\n * daraltılabilir kalır: alan tercihen 220px'tir ama sığmadığı yerde küçülür,\n * taşmaz.\n */\nconst FilterBar: FC<Props> = ({ onSubmit, children, actions, label, className, testId }) => {\n const { labels } = useHanui();\n\n return (\n <form\n className={cx(styles.bar, className)}\n aria-label={resolveLabel('FilterBar.label', label, labels?.filters)}\n data-testid={testId}\n onSubmit={event => {\n event.preventDefault();\n onSubmit();\n }}\n >\n {children}\n\n {/*\n Enter'ın yedeği. Görünmez ama tarayıcı için formun varsayılan gönderme\n düğmesi: `display: none` örtük gönderimi bozmaz. Görünür \"Uygula\" düğmesi\n `actions` ile ayrıca verilebilir; ikisi aynı submit olayına düşer.\n */}\n <button type=\"submit\" className={styles.bar__hiddenSubmit} tabIndex={-1} aria-hidden />\n\n {actions && <div className={styles.bar__actions}>{actions}</div>}\n </form>\n );\n};\n\ntype FieldProps = {\n children: ReactNode;\n /**\n * Alan kalan genişliği doldurur (arama kutusu). Diğer alanlar tercih\n * ettikleri genişlikte kalır ve şerit sağa doğru boşluk bırakır.\n */\n isWide?: boolean;\n className?: string;\n};\n\n/**\n * Şerit içindeki tek alanın genişlik sözleşmesi. İçine `Field` + girdi ya da\n * yalın `Input` konur; genişlik kararı alanın kendisine yazılmaz.\n */\nexport const FilterBarField: FC<FieldProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, isWide, className }) => (\n <div className={cx(styles.field, isWide && styles['field--wide'], className)}>{children}</div>\n )),\n 'FilterBarField',\n);\n\nexport default /*#__PURE__*/ memo(FilterBar) as typeof FilterBar;\n","'use client';\n\nimport { type FC, memo, useEffect, useMemo, useRef } from 'react';\n\nimport { CaretLeftFill, CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport useAnnounce from '../../hooks/useAnnounce';\nimport { useHanui } from '../../theme/context';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport Button from '../Button';\nimport IconButton from '../IconButton';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype BaseProps = {\n page: number;\n totalPages: number;\n /** Gezinme bölgesinin erişilebilir adı. Verilmezse `labels.pagination.label`. */\n label?: string;\n /** Verilmezse `labels.pagination.previous`. */\n previousLabel?: string;\n /** Verilmezse `labels.pagination.next`. */\n nextLabel?: string;\n /**\n * Sayfa değiştiğinde ekran okuyucuya duyurulacak metin\n * (\"3. sayfa · 1.248 sonuç\").\n *\n * <p>Verilmediğinde duyuru YAPILMAZ. Görsel tarafta sayfa numarası\n * `aria-current` ile zaten işaretli ama o yalnızca ODAK oraya geldiğinde\n * okunuyor: bağlantıya basıp listenin başına dönen kullanıcı, kaçıncı\n * sayfada olduğunu ve kaç sonuç kaldığını hiç duymuyordu.\n */\n formatAnnouncement?: (page: number, totalPages: number) => string;\n className?: string;\n testId?: string;\n};\n\ntype LinkProps = BaseProps & {\n /**\n * Sayfa numarasının adresini üretir.\n *\n * <p>Verildiğinde numaralar `<a>` olur — ve olması gerekir. Düğmenin `href`i\n * yok: arama motoru bir tıklama olayını çalıştırmaz ve ikinci sayfaya HİÇ\n * geçemez; kullanıcı da orta tuşla yeni sekmede açamaz, adresi kopyalayamaz,\n * durum çubuğunda hedefi göremez.\n */\n buildHref: (page: number) => string;\n onPageChange?: never;\n /** Yönlendiriciye geçirilecek ek props (`{ scroll: false }` gibi). */\n linkProps?: HanuiLinkExtraProps;\n};\n\ntype ButtonProps = BaseProps & {\n /**\n * Sayfa değişimi adres çubuğu YERİNE buraya bildirilir.\n *\n * <p>Yalnızca sayfalamanın adrese yazılmadığı listeler için: kişiye özel,\n * `noindex` ekranlarda kimse \"ikinci sayfa\" bağlantısını paylaşmıyor ve orada\n * adresi kirletmek geri tuşunu kullanılamaz hâle getiriyordu. Bağlantı\n * verilebilecek bir hedef olmadığı için numaralar düğme kalır.\n */\n onPageChange: (page: number) => void;\n buildHref?: never;\n linkProps?: never;\n};\n\ntype Props = LinkProps | ButtonProps;\n\n/** Kenarlarda 1 ve son sayfa her zaman gorunur; arasi kisaltilir. */\nconst buildPageList = (page: number, totalPages: number): (number | 'gap')[] => {\n if (totalPages <= 7) return Array.from({ length: totalPages }, (_, index) => index + 1);\n\n const pages = new Set<number>([1, totalPages, page]);\n if (page - 1 > 1) pages.add(page - 1);\n if (page + 1 < totalPages) pages.add(page + 1);\n\n const sorted = [...pages].sort((left, right) => left - right);\n const result: (number | 'gap')[] = [];\n\n sorted.forEach((value, index) => {\n if (index > 0 && value - sorted[index - 1] > 1) result.push('gap');\n result.push(value);\n });\n\n return result;\n};\n\n/**\n * Sayfalama.\n *\n * <h3>Sayfa numaraları BAĞLANTI, düğme değil</h3>\n * `buildHref` verildiğinde numaralar `<a>` olur. Düğme olarak bırakıldığında\n * iki bedeli vardı:\n * <ul>\n * <li><strong>Tarayıcı (crawler) ikinci sayfaya geçemiyordu.</strong> Düğmenin\n * `href`i yok; arama motoru bir tıklama olayını çalıştırmaz. Derin\n * sayfalardaki kayıtlar yalnızca sitemap'te göründükleri kadar\n * keşfedilebiliyordu.</li>\n * <li><strong>Kullanıcı yeni sekmede açamıyordu.</strong> Orta tık, Cmd+tık ve\n * \"bağlantıyı kopyala\" çalışmıyor, durum çubuğunda hedef görünmüyordu.</li>\n * </ul>\n *\n * <p>Oklar her iki kipte de `IconButton`: devre dışı kalabildikleri için düğme\n * kalırlar — `<a>` etiketinin \"devre dışı\" hâli yok, `aria-disabled` ise\n * tıklamayı engellemez. Sayfa numaraları tarayıcıya zaten tam listeyi veriyor.\n */\nconst Pagination: FC<Props> = ({\n page,\n totalPages,\n label,\n previousLabel,\n nextLabel,\n buildHref,\n onPageChange,\n linkProps,\n formatAnnouncement,\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const announce = useAnnounce();\n\n /*\n * Sayfa DEGISTIGINDE duyurulur, ilk cizimde degil: acilista \"1. sayfa\"\n * demek, kullanicinin sormadigi bir soruyu cevaplamak ve ekran okuyucunun\n * sayfa basligini okumasini kesmek olurdu.\n */\n const previousPage = useRef(page);\n\n useEffect(() => {\n if (previousPage.current === page) return;\n previousPage.current = page;\n\n if (formatAnnouncement) announce(formatAnnouncement(page, totalPages));\n }, [page, totalPages, formatAnnouncement, announce]);\n const pages = useMemo(() => buildPageList(page, totalPages), [page, totalPages]);\n\n if (totalPages <= 1) return null;\n\n const goTo = (target: number) => {\n if (onPageChange) onPageChange(target);\n };\n\n return (\n <nav\n className={cx(styles.pagination, className)}\n aria-label={resolveLabel('Pagination.label', label, labels?.pagination?.label)}\n data-testid={testId}\n >\n <IconButton\n className={styles.pagination__arrow}\n icon={<CaretLeftFill aria-hidden />}\n label={resolveLabel(\n 'Pagination.previousLabel',\n previousLabel,\n labels?.pagination?.previous,\n )}\n variant=\"outline\"\n disabled={page <= 1}\n onClick={() => goTo(page - 1)}\n />\n\n <ul className={styles.pagination__list}>\n {pages.map((value, index) =>\n value === 'gap' ? (\n <li key={`gap-${index}`} className={styles.pagination__gap} aria-hidden>\n …\n </li>\n ) : (\n <li key={value}>\n {buildHref ? (\n <HanuiLink\n href={buildHref(value)}\n className={cx(\n styles.pagination__page,\n value === page && styles['pagination__page--active'],\n )}\n aria-current={value === page ? 'page' : undefined}\n {...linkProps}\n >\n {value}\n </HanuiLink>\n ) : (\n <Button\n variant={UIVariant.SECONDARY}\n size={UISize.SMALL}\n className={cx(\n styles.pagination__page,\n value === page && styles['pagination__page--active'],\n )}\n aria-current={value === page ? 'page' : undefined}\n onClick={() => goTo(value)}\n >\n {value}\n </Button>\n )}\n </li>\n ),\n )}\n </ul>\n\n <IconButton\n className={styles.pagination__arrow}\n icon={<CaretRightFill aria-hidden />}\n label={resolveLabel('Pagination.nextLabel', nextLabel, labels?.pagination?.next)}\n variant=\"outline\"\n disabled={page >= totalPages}\n onClick={() => goTo(page + 1)}\n />\n </nav>\n );\n};\n\nexport default /*#__PURE__*/ memo(Pagination) as typeof Pagination;\n"],"names":["NEUTRAL","GRAPHITE","AMBER","BLUE","STATUS","DANGER_SOLID","ACCENT","SALE","STAR","alpha","hex","value","normalized","full","character","red","green","blue","BLACK","LIGHT_THEME","DARK_THEME","METRIC_TOKENS","COMPACT_DENSITY","DEFAULT_FONTS","TOKEN_PREFIX","THEME_STYLE_ID","THEME_ATTRIBUTE","DENSITY_ATTRIBUTE","THEME_SWITCHING_CLASS","resolveTokens","scheme","config","base","overrides","buildThemeCss","blocks","declarations","tokens","indent","name","fonts","fontEntries","role","stack","metrics","body","applyThemeConfig","isClient","css","existing","element","HanuiContext","createContext","useHanui","useContext","HanuiProvider","children","theme","linkComponent","labels","themeKey","useMemo","useEffect","themeRef","useRef","jsx","initHanui","options","REGION_ID","getRegion","politeness","id","region","write","message","useAnnounce","useCallback","trimmed","readSystemScheme","_a","readPreference","attribute","useHanuiTheme","preference","setPreferenceState","useState","systemScheme","setSystemScheme","isReady","setIsReady","query","handleChange","setScheme","next","root","toggle","scrollIntoViewIfPossible","useListboxNavigation","count","isOpen","initialIndex","onSelect","onClose","hasSpaceSelect","activeIndex","setActiveIndex","listRef","current","handleKeyDown","event","lastIndex","OPPOSITE","clamp","min","max","place","anchor","surface","side","align","offset","isVertical","main","crossStart","crossSize","surfaceSize","cross","fits","position","padding","viewport","usePositioning","anchorRef","surfaceRef","state","setState","frameRef","measure","anchorRect","surfaceRect","preferred","resolvedSide","placed","schedule","useLayoutEffect","observer","useVirtualList","rowHeight","overscan","isEnabled","scrollRef","range","setRange","node","visibleCount","first","start","end","scrollToIndex","index","top","bottom","lockCount","previous","isIOS","lock","rootStyle","scrollY","scrollbarWidth","unlock","useScrollLock","isLocked","HEIGHT_VAR","INSET_VAR","openCount","frame","MIN_VIEWPORT_HEIGHT","covered","cancelScheduled","useSheetViewport","isActive","UIVariant","UISize","MOBILE_BREAKPOINT","TABLET_PORTRAIT_BREAKPOINT","TABLET_BREAKPOINT","ABOVE_TABLET_MEDIA_QUERY","ABOVE_MOBILE_MEDIA_QUERY","normalizeSearchTerm","matchesSearch","haystack","needle","NON_TEXT_INPUT_TYPES","isKeyboardOpeningElement","editable","tagName","preventAutoKeyboard","dialog","active","captureFocus","FOCUSABLE_SELECTOR","selector","focusFirstMeaningful","container","skipSelector","explicit","candidates","target","modalStack","pushModal","token","isTopModal","cx","values","result","named","component","displayName","HanuiLink","rest","LinkComponent","warned","resolveLabel","key","resolveFormatter","formatter","args","Spinner","size","label","className","styles","Button","forwardRef","variant","isLoading","isFullWidth","startIcon","endIcon","disabled","href","isExternal","linkProps","testId","ref","classNames","content","jsxs","Fragment","memo","IconButton","icon","type","TextLink","hasArrow","tone","ArrowRight","index$O","CLOSE_DELAY","LONG_PRESS_DELAY","Tooltip","openDelay","setIsOpen","useId","bubbleRef","timerRef","longPressRef","positioning","clearTimer","open","delay","close","handlePointerDown","cancelLongPress","createPortal","index$N","enabledIndexes","items","item","Menu","trigger","restoreRef","typedRef","enabled","_b","step","jumpToLetter","now","buffer","match","handleMenuKeyDown","handleTriggerKeyDown","isValidElement","triggerProps","cloneElement","index$M","Popover","controlledOpen","onOpenChange","uncontrolledOpen","setUncontrolledOpen","isControlled","setOpen","index$L","Chip","isSelected","isDefined","ChipGroup","isScrollable","selection","handleSelect","option","currentIndex","tabbableValue","index$K","BottomSheet","title","closeLabel","toolbar","footer","closeAbove","titleId","tokenRef","restoreFocus","pop","setDialogRef","handleBackdropClick","XLg","Combobox","onChange","isSearchHidden","onSearch","isDisabled","isClearable","describedBy","isInvalid","text","generatedId","baseId","listboxId","rootRef","triggerRef","inputRef","openMode","setOpenMode","setQuery","cachedLabel","setCachedLabel","visibleOptions","selectedOption","displayLabel","searchRef","timer","selectOption","wasOpenRef","handleInputKeyDown","clearSelection","search","Search","renderList","isSheet","isChosen","CheckLg","CaretDownFill","index$J","SegmentedControl","isIconOnly","index$I","Select","placeholder","emptyText","optionId","selectedIndex","onKeyDown","index$H","Checkbox","hint","index$G","Switch","isLabelFirst","index$F","Radio","index$E","RadioCard","index$D","RangeSlider","onCommit","formatValue","minLabel","maxLabel","lowName","highName","low","high","handleLowChange","raw","handleHighChange","commit","span","lowPercent","normalize","highPercent","isLowOnTop","index$C","STARS","RatingInput","ratingLabels","formatStarCount","scale","hovered","setHovered","shown","star","StarFill","index$B","QuantityStepper","decreaseLabel","increaseLabel","groupLabel","draft","setDraft","parsed","DashLg","_c","PlusLg","index$A","TableCheckbox","index$z","Input","prefix","suffix","isTechnical","TagInput","removeLabel","separators","maxTags","inputId","announce","duplicate","setDuplicate","isFull","remove","index$y","Textarea","rows","isAutoSize","maxRows","hasCounter","maxLength","defaultValue","innerRef","innerLength","setLength","length","setRefs","isNearLimit","DateField","index$x","DateRangeBase","startLabel","endLabel","separator","isSummaryVisible","summary","format","DateRange","Field","error","isRequired","requiredLabel","isLabelHidden","errorId","hintId","ExclamationCircleFill","toPercent","Progress","valueText","isValueVisible","isIndeterminate","percent","ProgressCircleBase","stroke","radius","circumference","ProgressCircle","formatSize","bytes","FileUpload","files","onRemove","accept","isMultiple","maxSize","dropLabel","sizeErrorText","isDragging","setIsDragging","rejected","setRejected","handleFiles","list","incoming","tooLarge","file","accepted","messages","handleDrop","CloudArrowUpFill","index$w","ICONS","InfoCircleFill","CheckCircleFill","ExclamationTriangleFill","XCircleFill","Alert","action","index$v","resolveInitials","locale","words","letters","resolveTone","total","hash","TONE_COUNT","Avatar","imageUrl","index$u","Badge","index$t","Breadcrumb","isLast","CaretRightFill","index$s","Card","isInteractive","Tag","CardMedia","ratio","isContained","CardOverlay","CardBody","CardFooter","index$r","Carousel","previousLabel","nextLabel","formatDotLabel","itemMinWidth","trackRef","canScrollBack","setCanScrollBack","canScrollForward","setCanScrollForward","page","setPage","pageCount","setPageCount","needsTabStop","setNeedsTabStop","track","scrollLeft","scrollWidth","clientWidth","scrollByPage","direction","CaretLeftFill","_","index$q","COPIED_FEEDBACK_MS","CopyField","copyLabel","copiedLabel","copiedAnnouncement","isReadOnly","isCopied","setIsCopied","codeRef","selectValue","handleCopy","_d","ClipboardCheckFill","ClipboardFill","_e","index$p","Divider","index$o","Directory","DirectoryGroup","meta","DirectoryRow","media","marker","DirectoryJump","toId","index$n","EmptyState","description","secondaryAction","index$m","PageHeader","eyebrow","actions","breadcrumb","Heading","index$l","Panel","isFlush","gap","bodyClassName","PanelForm","columns","PanelRow","index$k","Price","currency","listValue","discountPercent","formatDiscount","isFormatted","symbol","numeric","index$j","Rating","srLabel","rounded","StarHalf","index$i","SectionHeader","overline","index$h","ScrollArea","axis","maxHeight","hasFade","setIsScrollable","vertical","horizontal","child","index$g","Skeleton","width","height","lines","style","isNumber","index$f","CardShape","RowShape","TableShape","rowIndex","columnIndex","SkeletonCard","SkeletonRows","SkeletonTable","TREND_ICON","ArrowUpShort","ArrowDownShort","TREND_TEXT","Stat","unit","delta","trend","isUpPositive","isPositive","index$e","DEFAULT_DURATION","counter","listeners","queue","emit","listener","dismiss","push","toast","ToastItem","record","onDismiss","duration","isPaused","setIsPaused","remainingRef","startedRef","ToastHub","toasts","setToasts","handleDismiss","index$d","Accordion","isSingle","defaultOpenIds","controlledIds","uncontrolledIds","setUncontrolledIds","openIds","willOpen","index$c","statusOf","STATUS_TEXT","Steps","steps","onStepClick","orientation","status","isClickable","index$b","Tabs","defaultTabId","controlledId","ariaLabel","isManualActivation","uncontrolledId","setUncontrolledId","activeId","focusIndex","setFocusIndex","select","hasPanel","index$a","Tile","index$9","STATUS_ICON","Timeline","events","index$8","Modal","isDismissable","dialogRef","descriptionId","handleCancel","CommandPalette","searchPlaceholder","emptyMessage","visible","run","isNewGroup","index$7","KIND_ICON","TrashFill","QuestionCircleFill","KIND_TONE","KIND_VARIANT","ConfirmDialog","onConfirm","confirmLabel","cancelLabel","kind","isRunning","setIsRunning","resolvedVariant","handleConfirm","index$6","Drawer","index$5","PromptDialog","onSubmit","submitLabel","inputMode","formId","setValue","isBusy","setIsBusy","isSubmitDisabled","renderControl","props","handleSubmit","index$4","TableScroller","hasFrame","Table","density","hasStickyHead","hasRowHover","index$3","DataTable","loadingMessage","hasViewportCap","onSort","bulkBar","rowCount","Children","renderStateRow","modifier","column","isSortable","nextDirection","DataTableRow","isWarning","index$2","FilterBar","FilterBarField","isWide","index$1","buildPageList","totalPages","pages","sorted","left","right","Pagination","buildHref","onPageChange","formatAnnouncement","previousPage","goTo"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/theme/palette.ts","../src/theme/tokens.ts","../src/helpers/theme.helper.ts","../src/theme/context.ts","../src/theme/HanuiProvider.tsx","../src/theme/initHanui.ts","../src/hooks/useAnnounce.ts","../src/hooks/useHanuiTheme.ts","../src/helpers/scroll.helper.ts","../src/hooks/useListboxNavigation.ts","../src/hooks/usePositioning.ts","../src/hooks/useVirtualList.ts","../src/hooks/useScrollLock.ts","../src/hooks/useSheetViewport.ts","../src/enums/ui-variant.enum.ts","../src/enums/ui-size.enum.ts","../src/constants/breakpoint.constants.ts","../src/helpers/text.helper.ts","../src/helpers/focus.helper.ts","../src/helpers/class-name.helper.ts","../src/helpers/component.helper.ts","../src/components/Link/index.tsx","../src/helpers/label.helper.ts","../src/components/Spinner/index.tsx","../src/components/Button/index.tsx","../src/components/IconButton/index.tsx","../src/components/TextLink/index.tsx","../src/components/Tooltip/index.tsx","../src/components/Menu/index.tsx","../src/components/Popover/index.tsx","../src/components/Chip/index.tsx","../src/components/ChipGroup/index.tsx","../src/components/BottomSheet/index.tsx","../src/components/Combobox/index.tsx","../src/components/SegmentedControl/index.tsx","../src/components/Select/index.tsx","../src/components/Checkbox/index.tsx","../src/components/Switch/index.tsx","../src/components/Radio/index.tsx","../src/components/RadioCard/index.tsx","../src/components/RangeSlider/index.tsx","../src/components/RatingInput/index.tsx","../src/components/QuantityStepper/index.tsx","../src/components/TableCheckbox/index.tsx","../src/components/Input/index.tsx","../src/components/TagInput/index.tsx","../src/components/Textarea/index.tsx","../src/components/DateField/index.tsx","../src/components/Field/index.tsx","../src/components/Progress/index.tsx","../src/components/FileUpload/index.tsx","../src/components/Alert/index.tsx","../src/components/Avatar/index.tsx","../src/components/Badge/index.tsx","../src/components/Breadcrumb/index.tsx","../src/components/Card/index.tsx","../src/components/Carousel/index.tsx","../src/components/CopyField/index.tsx","../src/components/Divider/index.tsx","../src/components/Directory/index.tsx","../src/components/EmptyState/index.tsx","../src/components/PageHeader/index.tsx","../src/components/Panel/index.tsx","../src/components/Price/index.tsx","../src/components/Rating/index.tsx","../src/components/SectionHeader/index.tsx","../src/components/ScrollArea/index.tsx","../src/components/Skeleton/index.tsx","../src/components/Stat/index.tsx","../src/components/Toast/index.tsx","../src/components/Accordion/index.tsx","../src/components/Steps/index.tsx","../src/components/Tabs/index.tsx","../src/components/Tile/index.tsx","../src/components/Timeline/index.tsx","../src/components/Modal/index.tsx","../src/components/CommandPalette/index.tsx","../src/components/ConfirmDialog/index.tsx","../src/components/Drawer/index.tsx","../src/components/PromptDialog/index.tsx","../src/components/Table/index.tsx","../src/components/DataTable/index.tsx","../src/components/FilterBar/index.tsx","../src/components/Pagination/index.tsx"],"sourcesContent":["/**\n * HAM PALET — kütüphanenin TEK hex kaynağı.\n *\n * <p>Başka hiçbir dosyada birebir renk değeri yazılmaz. Zincir:\n *\n * <pre>\n * theme/palette.ts → ham hex (yalnızca burada)\n * theme/tokens.ts → anlamsal token adı → hex eşlemesi (açık + koyu)\n * styles/_tokens.generated.scss → `:root` ve `[data-hanui-theme]` yayını\n * styles/_colors.generated.scss → bileşenlerin gördüğü SCSS sözleşmesi\n * </pre>\n *\n * <p>Son iki dosya `scripts/build-tokens.mjs` tarafından ÜRETİLİR. Elle\n * yazıldıklarında TypeScript tarafındaki token listesiyle ayrışıyorlar ve\n * ayrışma sessiz: bir bileşen var olmayan bir değişkeni okuyup rengi\n * kaybediyor, derleme yine yeşil dönüyordu.\n */\n\n// --- Nötr eksen -------------------------------------------------------\n// Serin gri-mavi. Sıcak kum tonundan ayrıldık: ürün fotoğrafları ağırlıkla\n// metal ve siyah plastik; sıcak zemin onları sarartıp kirli gösteriyordu.\nexport const NEUTRAL = {\n n0: '#ffffff',\n n25: '#fafbfc',\n n50: '#f6f7f9',\n n100: '#eef0f4',\n n150: '#e7eaef',\n n200: '#e2e6ec',\n /** Kart/girdi kenarı — `n200` sayfadan ayrılmıyordu. */\n n250: '#d6dce4',\n n300: '#c9d0da',\n n400: '#aab3c0',\n n500: '#8a94a3',\n /**\n * İkincil metnin okunur tabanı.\n *\n * ÖLÇÜLDÜ (birinci düzeltme): `text-3` `n500`'dü ve beyaz üzerinde 3,2:1\n * veriyor; üstü çizili fiyat, yer tutucu ve yardım metni gövde metni\n * sayıldığı için WCAG 1.4.3'ün 4,5:1 eşiğini GEÇMİYORDU. Aynı ton açısında\n * aydınlık düşürüldü: `#6b7583`, beyaz üzerinde 4,67:1.\n *\n * ÖLÇÜLDÜ (ikinci düzeltme, `scripts/check-contrast.mjs`): o değer yalnızca\n * BEYAZ üzerinde ölçülmüştü. Gerçekte aynı metin dört yüzeyin üzerine\n * düşüyor ve beyaz onların en açığı: `page` üzerinde 4,36:1, `surface-2`\n * üzerinde (cip sayacı, pasif girdi) 3,94:1 — yani ölçüm yapılan yer\n * dışındaki her yerde ihlal. Yüzeylerin en KOYUSU (`surface-2`) eşiği\n * belirler: `#626c7a` orada 4,67:1.\n *\n * <p>Bedeli açık: `n600` ile arasındaki fark daraldı (sayfa üzerinde 5,60'a\n * karşı 4,97). Üç kademeli soluk metin merdiveni bu paletin taşıyabileceğinin\n * sınırında; kademe sayısı bir tasarım kararıdır ve görsel dil fazında\n * yeniden görülür. Ama \"görünür ama okunmayan\" bir ton, kademesi bol bir\n * merdivenden kötüdür.\n */\n n550: '#626c7a',\n n600: '#5a6472',\n n700: '#3a424f',\n n800: '#232a35',\n n900: '#11151b',\n} as const;\n\n// --- Grafit -----------------------------------------------------------\n// Üst bant, alt bilgi, tablo başlıkları, teknik bloklar ve BİRİNCİL EYLEM.\nexport const GRAPHITE = {\n base: '#1f2937',\n two: '#2b3646',\n three: '#3a4658',\n /** Koyu temada üst bant; sayfadan koyu kalmalı. */\n ink: '#12161d',\n inkTwo: '#1c222b',\n} as const;\n\n// --- Amber ------------------------------------------------------------\n// EKRANDAKİ TEK DOYGUN TURUNCU: dönüşüm eylemi (\"sepete ekle\"). Başka\n// hiçbir yerde dolgu olarak kullanılmaz.\nexport const AMBER = {\n base: '#f59e0b',\n hover: '#d98706',\n active: '#b87205',\n /** Pasif dönüşüm düğmesi; saydamlık değil KENDİ dolgusu. */\n soft: '#f8cd80',\n dark: '#fbbf24',\n darkHover: '#f0af12',\n /** Amber üzerinde metin — beyaz 2,3:1'de kalıyor, okunmuyor. */\n on: '#291500',\n} as const;\n\n// --- Mavi -------------------------------------------------------------\n// Gezinme ve keşif: bağlantı, etkin filtre, odak halkası. Amber ile\n// çarpışmaz çünkü işleri farklı.\nexport const BLUE = {\n base: '#2f6fed',\n hover: '#1d54c4',\n active: '#17439c',\n /** Gövde metni içi bağlantı — `base` 16px'te 4,55:1. */\n text: '#1d54c4',\n tint: '#eaf1fe',\n line: '#bcd2fb',\n dark: '#5b93ff',\n darkHover: '#7aa8ff',\n darkTint: '#16243c',\n darkLine: '#2a3f63',\n} as const;\n\n/**\n * MARKA ANKORLARI: kırmızı ve yeşil.\n *\n * <p>Aşağıdaki iki hex, kendi ailelerinin TEK KAYNAĞIDIR. Ailedeki her ton\n * (tint zemini, kenarlık, metin, koyu tema karşılığı) HSL uzayında bu iki\n * değerden türetildi: ton açısı ve doygunluk korunur, yalnızca aydınlık\n * kaydırılır. Yeni bir kırmızı/yeşil ton gerektiğinde gözle seçilmez —\n * buradan türetilir, yoksa aile zamanla dağılır.\n *\n * <p>⚠ ANKORLAR METİN RENGİ DEĞİLDİR. `green` beyaz üzerinde 2,22:1 —\n * gövde metni olarak WCAG'i geçmez. Bu yüzden aile iki katmanlı: ankor\n * İKON ve DOLGU için, ondan türetilen koyu ton METİN için.\n */\nexport const ANCHOR = {\n red: '#dc2626',\n green: '#34c759',\n} as const;\n\n/**\n * DURUM RENKLERİ.\n *\n * <p>Kural: TINT ZEMİN + KOYU METİN + eşleşen hairline. Asla doygun dolgu —\n * doygun dolgu \"tıklanabilir\" demektir ve durum etiketi tıklanabilir değildir.\n *\n * <p>Kenarlık tonları bir kademe koyulaştırıldı: rozetler \"kutu\" olarak\n * okunmalı; daha açık çizgiler tint zeminin üzerinde kaybolup yan yana duran\n * iki rozeti tek bir lekeye çeviriyordu.\n */\nexport const STATUS = {\n /* Yeşil ailesi `ANCHOR.green`den türetildi (L +44 / S −24, L +33 / S −14). */\n okBg: '#e8f4eb',\n /** 5,58:1 tint üzerinde — metin katmanı. */\n okFg: '#1d6e31',\n okLine: '#a8dcb7',\n okBgDark: '#122817',\n /** Koyu zeminde ankorun kendisi okunuyor (7,05:1). */\n okFgDark: '#34c759',\n okLineDark: '#22542f',\n\n warnBg: '#fdf0dd',\n warnFg: '#7a3e02',\n warnLine: '#ebc687',\n warnBgDark: '#2c2008',\n warnFgDark: '#f5c86b',\n warnLineDark: '#55401a',\n\n offBg: '#f1f2f5',\n offFg: '#3a424f',\n offLine: '#ccd2db',\n offBgDark: '#212630',\n offFgDark: '#a3adbb',\n offLineDark: '#333b47',\n\n /*\n * Kırmızı ailesi `ANCHOR.red`den türetildi. Önceki `badFg` (#7f1d1d) bir\n * bordoydu: favori kalbi ve olumsuz rozet ekranda kirli/kahverengi\n * okunuyordu. Aynı ton açısında kalıp aydınlığı açmak rengi hem canlı hem\n * okunur yapıyor.\n */\n badBg: '#f8ebeb',\n /** 5,45:1 tint üzerinde. */\n badFg: '#bb1e1e',\n badLine: '#e6a6a6',\n badBgDark: '#310f0f',\n /** 6,03:1 koyu tint üzerinde. */\n badFgDark: '#e97575',\n badLineDark: '#621b1b',\n\n /** Birincil / orijinal sınıflandırma tonu. */\n oemBg: '#eaf1fe',\n oemFg: '#16305c',\n oemLine: '#a9c6f9',\n oemBgDark: '#152139',\n oemFgDark: '#9dc0ff',\n oemLineDark: '#27395c',\n\n /** İkincil / muadil sınıflandırma tonu. */\n altBg: '#eeebfa',\n altFg: '#2e2661',\n altLine: '#c0b6ea',\n altBgDark: '#1d1a33',\n altFgDark: '#bfb3f5',\n altLineDark: '#332d56',\n} as const;\n\n/**\n * YIKICI EYLEM DOLGUSU (silme onayı).\n *\n * <p>Durum tinti DEĞİL, gerçek bir düğme. Ankorun kendisi: beyaz metinle\n * 4,83:1. Aynı kırmızıyı taşımaları kullanıcının uyarı etiketine tıklamayı\n * denemesine yol açıyordu.\n */\nexport const DANGER_SOLID = {\n base: '#dc2626',\n hover: '#bb1e1e',\n dark: '#e45b5b',\n darkHover: '#ef7a72',\n onDark: '#1a0b0a',\n} as const;\n\n/**\n * İKON DOLGULARI — favori kalbi, kopyalandı tiki gibi METİN OLMAYAN,\n * doygun kalması gereken yerler. Eşik WCAG 1.4.11: grafik öğesi 3:1.\n *\n * <p>⚠ BU DOSYA BİR ZAMANLAR \"hepsi geçiyor\" DİYORDU VE GEÇMİYORLARDI.\n * `scripts/check-contrast.mjs` yazıldığında ölçüldü: ankorun kendisi\n * (`#34c759`) beyaz üzerinde 2,21:1, `surface-2` üzerinde 1,94:1 — grafik\n * eşiğinin yarısı. `CopyField`in \"kopyalandı\" tiki tam olarak bu tonda\n * çiziliyor ve tik, kopyalamanın başarılı olduğunu söyleyen TEK görsel\n * sinyaldi (metin `visually-hidden`). Yeşil ailesinin ikon katmanı bu yüzden\n * ankordan ayrıldı: ton açısı ve doygunluk korunarak aydınlık düşürüldü.\n *\n * <h3>Açık temada bu aile ESNEK DEĞİL</h3>\n * `green` iki eşiğin arasına sıkışır: bir ikon olarak açık yüzeyden ayrılmak\n * için KOYU olmalı (3:1), üzerine metin binecekse o metne yer bırakacak kadar\n * AÇIK kalmalı (4,5:1). Bant dar ve `#299d46` içinde duruyor: `surface-2`\n * üzerinde 3,06:1, `onGreen` ile 4,56:1.\n *\n * <p>Bunun bir sonucu var: <strong>metin taşıyan bir yeşil dolgunun hover'ı\n * dolguyu koyulaştıramaz.</strong> Bir kademe koyulaşan her ton `onGreen`i\n * 4,5'in altına düşürüyor (en koyu mürekkeple bile 4,47:1). `greenHover` bu\n * yüzden yalnızca İKON hover'ıdır; metin taşıyan bir yüzeyin hover'ı\n * kenarlıkta ya da gölgede anlatılır. Kütüphane bugün yeşil dolgu üzerine\n * metin çizmiyor; `onGreen` tüketici için duruyor ve sözleşmesi `green` ile.\n *\n * <p>Koyu tema sıkışık değil: orada zemin koyu, ikon açık ve iki eşik aynı\n * yöne çekiyor.\n */\nexport const ACCENT = {\n red: '#dc2626',\n redDark: '#e35252',\n /** 3,06:1 `surface-2` üzerinde — ailenin ikon katmanı, ankor değil. */\n green: '#299d46',\n greenDark: '#4cd76c',\n /** İKON hover'ı; metin taşıyan dolgunun hover'ı değil (yukarıdaki not). */\n greenHover: '#23883c',\n greenHoverDark: '#63e084',\n /** Yeşil dolgu üzerindeki metin. BEYAZ DEĞİL: `green` üzerinde 3,50:1. */\n onGreen: '#06280f',\n} as const;\n\n/**\n * İNDİRİM / OLUMLU DEĞİŞİM ETİKETİ.\n *\n * <p>Fiyat SİYAH kalır; rozet YEŞİL — kazancı kırmızı ile işaretlemek\n * \"uyarı\" gibi okunuyordu, oysa indirim iyi haber.\n */\nexport const SALE = {\n bg: '#e8f4eb',\n fg: '#1d6e31',\n bgDark: '#122817',\n fgDark: '#34c759',\n} as const;\n\n/**\n * YILDIZ ALTINI.\n *\n * <p>Amber ailesinden AYRI kalır (amber yalnızca dönüşüm eylemi), ama eski\n * uyarı tonu (#7a3e02) bir kahverengiydi ve puan yıldızları kirli\n * görünüyordu. Bu ton sıcaklığı korur, doygun turuncuyla yarışmaz ve tek\n * başına bir dolgu olarak okunmaz.\n */\nexport const STAR = {\n /** 5,23:1 beyaz üzerinde. */\n light: '#9a5f04',\n /** 9,82:1 koyu zemin üzerinde. */\n dark: '#f0b429',\n} as const;\n","import {\n ACCENT,\n AMBER,\n BLUE,\n DANGER_SOLID,\n GRAPHITE,\n NEUTRAL,\n SALE,\n STAR,\n STATUS,\n} from './palette';\n\n/**\n * TEMA TOKEN'LARI.\n *\n * <p>Her anahtar bir CSS özel özelliğine karşılık gelir: `page` →\n * `--hanui-page`. Bileşenler SCSS tarafında yalnızca bu adları görür ve hepsi\n * bir `var(--hanui-…)` işaret eder.\n *\n * <h3>Neden CSS değişkeni, neden SCSS değişkeni değil</h3>\n * Açık/koyu tema ÇALIŞMA ZAMANINDA değişir; SCSS değişkeni derleme anında\n * sabitlenir ve tek derlemeden iki tema çıkmaz. Bunun iki sonucu var:\n *\n * <ol>\n * <li>Renk üzerinde SCSS renk fonksiyonu ÇALIŞMAZ (`rgba($surface, .9)`\n * derlenmez). Gereken her saydam değer hazır token olarak durur:\n * `scrim`, `glass`, `ring`, `track`, `glow-1`…</li>\n * <li>`prefers-color-scheme` ile renk SEÇİLMEZ. Tema `data-hanui-theme`\n * üzerinden gelir; medya sorgusu kullanıcının açık seçimini görmez —\n * yalnızca hiç seçim yapılmadığında yedek olarak devreye girer.</li>\n * </ol>\n */\n\n/** Hex rengi `rgba(...)` dizesine çevirir. Renk fonksiyonu üretim ANINDA çalışır. */\nconst alpha = (hex: string, value: number): string => {\n const normalized = hex.replace('#', '');\n const full =\n normalized.length === 3\n ? normalized\n .split('')\n .map(character => character + character)\n .join('')\n : normalized;\n\n const red = parseInt(full.slice(0, 2), 16);\n const green = parseInt(full.slice(2, 4), 16);\n const blue = parseInt(full.slice(4, 6), 16);\n\n return `rgba(${red}, ${green}, ${blue}, ${value})`;\n};\n\nconst BLACK = '#000000';\n\n/**\n * AÇIK TEMA — varsayılan.\n *\n * <p>Bilgi yoğunluğu yüksek ekranlarda açık zeminde okunurluk daha yüksek.\n */\nexport const LIGHT_THEME = {\n // --- Yüzey ---\n page: NEUTRAL.n50,\n surface: NEUTRAL.n0,\n 'surface-2': NEUTRAL.n100,\n 'surface-3': NEUTRAL.n150,\n 'surface-inset': NEUTRAL.n25,\n\n // --- Kenarlık ---\n border: NEUTRAL.n250,\n 'border-strong': NEUTRAL.n300,\n\n // --- Metin ---\n text: NEUTRAL.n900,\n 'text-2': NEUTRAL.n600,\n 'text-3': NEUTRAL.n550,\n\n // --- Grafit: bant, alt bilgi, tablo başlığı, teknik blok ---\n graphite: GRAPHITE.base,\n 'graphite-2': GRAPHITE.two,\n 'graphite-3': GRAPHITE.three,\n\n /*\n * BİRİNCİL EYLEM (dolgulu, nötr).\n *\n * `action` grafittir, amber DEĞİL. Amber tek bir dönüşüm noktasına\n * ayrılmıştır; her dolu düğmeyi amber yapmak o tekilliği yok eder ve\n * kullanıcı hangi turuncunun dönüşüm olduğunu bilemez.\n */\n action: GRAPHITE.base,\n 'action-hover': GRAPHITE.two,\n 'action-active': GRAPHITE.three,\n 'on-action': NEUTRAL.n0,\n /** Pasif dolgu; saydamlık DEĞİL kendi rengi (bkz. Button `:disabled`). */\n 'action-soft': NEUTRAL.n300,\n\n // --- Dönüşüm eylemi: ekrandaki tek doygun turuncu ---\n amber: AMBER.base,\n 'amber-hover': AMBER.hover,\n 'amber-active': AMBER.active,\n 'amber-soft': AMBER.soft,\n 'on-amber': AMBER.on,\n\n // --- Mavi: gezinme ve keşif ---\n blue: BLUE.base,\n 'blue-hover': BLUE.hover,\n 'blue-active': BLUE.active,\n 'blue-text': BLUE.text,\n 'blue-tint': BLUE.tint,\n 'blue-line': BLUE.line,\n\n // --- Durum: tint zemin + koyu metin + eşleşen hairline ---\n 'ok-bg': STATUS.okBg,\n 'ok-fg': STATUS.okFg,\n 'ok-line': STATUS.okLine,\n\n 'warn-bg': STATUS.warnBg,\n 'warn-fg': STATUS.warnFg,\n 'warn-line': STATUS.warnLine,\n\n 'off-bg': STATUS.offBg,\n 'off-fg': STATUS.offFg,\n 'off-line': STATUS.offLine,\n\n 'bad-bg': STATUS.badBg,\n 'bad-fg': STATUS.badFg,\n 'bad-line': STATUS.badLine,\n\n 'oem-bg': STATUS.oemBg,\n 'oem-fg': STATUS.oemFg,\n 'oem-line': STATUS.oemLine,\n\n 'alt-bg': STATUS.altBg,\n 'alt-fg': STATUS.altFg,\n 'alt-line': STATUS.altLine,\n\n 'sale-bg': SALE.bg,\n 'sale-fg': SALE.fg,\n\n // --- İkon vurguları: METİN DEĞİL (WCAG grafik eşiği 3:1) ---\n 'red-accent': ACCENT.red,\n 'green-accent': ACCENT.green,\n 'green-accent-hover': ACCENT.greenHover,\n 'on-green': ACCENT.onGreen,\n star: STAR.light,\n\n // --- Yıkıcı eylem: durum tinti DEĞİL, gerçek bir dolgu ---\n 'danger-solid': DANGER_SOLID.base,\n 'danger-solid-hover': DANGER_SOLID.hover,\n 'on-danger': NEUTRAL.n0,\n\n /*\n * ÜST BANT / ALT BİLGİ / KAHRAMAN BÖLÜMÜ.\n *\n * BU TOKEN'LAR TEMAYI İZLER: açık temada her yer açık, koyu temada her yer\n * koyu. Ayrı bir ad kümesi olarak kalıyorlar çünkü bantların KENDİ yüzey\n * merdiveni var: üst bant sayfadan bir kademe yükselir (beyaz zemin, gri\n * sayfa üzerinde), alt bilgi bir kademe çöker. Bunu `surface` ile yazmak\n * iki bandı sayfayla aynı tonda bırakıyordu.\n */\n 'nav-bg': NEUTRAL.n0,\n 'nav-bg-2': NEUTRAL.n100,\n 'nav-fg': NEUTRAL.n900,\n 'nav-fg-2': NEUTRAL.n600,\n /*\n * `n500` DEĞİL. Ölçüldü: `n500` üst bandın beyaz zemininde 3,06:1, alt\n * bilginin `n100` zemininde 2,68:1 veriyordu — yani bandın en soluk metni\n * (telif satırı, yardımcı bağlantılar) hiçbir yerde gövde metni eşiğini\n * geçmiyordu. Sayfa tarafındaki karşılığıyla (`text-3`) aynı tona bağlandı:\n * ikisi aynı işi yapıyor ve ayrı tutulmalarının tek sebebi bandın kendi\n * yüzey merdiveniydi, kendi okunurluk kuralı değil.\n */\n 'nav-fg-3': NEUTRAL.n550,\n 'nav-line': NEUTRAL.n200,\n 'nav-line-strong': NEUTRAL.n300,\n 'nav-hover': NEUTRAL.n100,\n 'footer-bg': NEUTRAL.n100,\n\n // --- Gölge: nötr-serin (sıcak gölge serin gri zeminde kirli durur) ---\n 'shadow-xs': `0 1px 2px ${alpha(NEUTRAL.n900, 0.05)}`,\n 'shadow-sm': `0 1px 2px ${alpha(NEUTRAL.n900, 0.05)}, 0 1px 3px ${alpha(NEUTRAL.n900, 0.04)}`,\n 'shadow-md': `0 2px 4px ${alpha(NEUTRAL.n900, 0.04)}, 0 6px 16px ${alpha(NEUTRAL.n900, 0.07)}`,\n 'shadow-lg': `0 4px 8px ${alpha(NEUTRAL.n900, 0.05)}, 0 16px 32px ${alpha(NEUTRAL.n900, 0.1)}`,\n 'shadow-xl': `0 8px 16px ${alpha(NEUTRAL.n900, 0.06)}, 0 28px 56px ${alpha(NEUTRAL.n900, 0.13)}`,\n /** Yapışkan alt bar; gölge YUKARI düşer. */\n 'shadow-up': `0 -2px 4px ${alpha(NEUTRAL.n900, 0.03)}, 0 -8px 24px ${alpha(NEUTRAL.n900, 0.08)}`,\n\n /** Odak halkası MAVİ: odak bir gezinme olayıdır, bir dönüşüm değil. */\n ring: `0 0 0 3px ${alpha(BLUE.base, 0.28)}`,\n 'ring-color': BLUE.base,\n 'ring-danger': `0 0 0 3px ${alpha(DANGER_SOLID.base, 0.24)}`,\n 'ring-ok': `0 0 0 4px ${alpha(STATUS.okFg, 0.16)}`,\n\n // --- Örtü ve cam: görsel üzerine binen yüzeyler ---\n /*\n * %55 DEĞİL. Örtü yalnızca kip pencerenin arkasını karartmıyor; `on-scrim`\n * onun üzerine yazılan metnin rengi ve o metin AÇIK temada bir sayfanın\n * üstüne düşüyor. Ölçüldü: %55 örtü `page` üzerine düzlendiğinde beyaz metin\n * 4,27:1 — gövde metni eşiğinin altında. %60'ta 5,01:1.\n *\n * <p>Koyu temada sorun yok (20:1); ölçüyü belirleyen açık tema.\n */\n scrim: alpha(NEUTRAL.n900, 0.6),\n 'scrim-soft': alpha(NEUTRAL.n900, 0.32),\n glass: alpha(NEUTRAL.n0, 0.92),\n 'glass-solid': NEUTRAL.n0,\n 'on-scrim': NEUTRAL.n0,\n\n // --- İskelet ve dönen gösterge ---\n 'skeleton-a': NEUTRAL.n100,\n 'skeleton-b': NEUTRAL.n25,\n track: alpha(NEUTRAL.n900, 0.12),\n\n /** Görsel yer tutucu (medya yoksa). */\n 'media-bg': NEUTRAL.n100,\n\n /*\n * Vurgu bloğundaki ışık lekeleri. Açık temada ZEMİN DE AÇIK olduğu için\n * lekeler çok daha hafif: koyu bant için ayarlanmış %22 opaklık açık\n * zeminde lekeyi kirli bir dasa çeviriyordu.\n */\n 'glow-1': alpha(BLUE.base, 0.1),\n 'glow-2': alpha(BLUE.base, 0.06),\n 'glow-amber': alpha(AMBER.base, 0.09),\n} as const;\n\n/**\n * KOYU TEMA.\n *\n * <p>Yüzey merdiveni açık temanın AYNISI DEĞİL, tersi: koyu temada yükselen\n * yüzey AÇILIR (`surface` > `page`), çünkü ışık yukarıdan gelir. Aynı sırayı\n * korumak kartları sayfaya gömüyordu.\n */\nexport const DARK_THEME: Record<keyof typeof LIGHT_THEME, string> = {\n page: '#0e1116',\n surface: '#171b22',\n 'surface-2': '#1f242d',\n 'surface-3': '#262c36',\n 'surface-inset': '#13171d',\n\n border: '#262c36',\n 'border-strong': '#363e4a',\n\n text: '#e7eaee',\n 'text-2': '#9aa4b2',\n /*\n * Açık temanın `text-3`ü ile AYNI HEX DEĞİL, olamaz da: koyu temada aynı ton\n * zeminden uzaklaşmaz, yaklaşır. Ölçüldü: `#6b7583` `surface` üzerinde\n * 3,69:1 ve `surface-2` üzerinde 3,25:1 — yer tutucu ve üstü çizili fiyat\n * koyu temada okunmuyordu. `#818b99` yüzeylerin en açığında (`surface-2`)\n * 4,51:1.\n */\n 'text-3': '#818b99',\n\n graphite: GRAPHITE.ink,\n 'graphite-2': GRAPHITE.inkTwo,\n 'graphite-3': GRAPHITE.two,\n\n /*\n * Koyu temada grafit dolgu sayfadan ayırt edilemez. Birincil eylem AÇIK bir\n * nötr yüzeye döner — koyu zeminde en yüksek vurgu budur.\n */\n action: NEUTRAL.n150,\n 'action-hover': NEUTRAL.n0,\n 'action-active': NEUTRAL.n300,\n 'on-action': NEUTRAL.n900,\n 'action-soft': '#414a58',\n\n amber: AMBER.dark,\n 'amber-hover': AMBER.darkHover,\n 'amber-active': AMBER.base,\n 'amber-soft': '#6d5316',\n 'on-amber': AMBER.on,\n\n blue: BLUE.dark,\n 'blue-hover': BLUE.darkHover,\n 'blue-active': BLUE.base,\n 'blue-text': BLUE.dark,\n 'blue-tint': BLUE.darkTint,\n 'blue-line': BLUE.darkLine,\n\n 'ok-bg': STATUS.okBgDark,\n 'ok-fg': STATUS.okFgDark,\n 'ok-line': STATUS.okLineDark,\n\n 'warn-bg': STATUS.warnBgDark,\n 'warn-fg': STATUS.warnFgDark,\n 'warn-line': STATUS.warnLineDark,\n\n 'off-bg': STATUS.offBgDark,\n 'off-fg': STATUS.offFgDark,\n 'off-line': STATUS.offLineDark,\n\n 'bad-bg': STATUS.badBgDark,\n 'bad-fg': STATUS.badFgDark,\n 'bad-line': STATUS.badLineDark,\n\n 'oem-bg': STATUS.oemBgDark,\n 'oem-fg': STATUS.oemFgDark,\n 'oem-line': STATUS.oemLineDark,\n\n 'alt-bg': STATUS.altBgDark,\n 'alt-fg': STATUS.altFgDark,\n 'alt-line': STATUS.altLineDark,\n\n 'sale-bg': SALE.bgDark,\n 'sale-fg': SALE.fgDark,\n\n 'red-accent': ACCENT.redDark,\n 'green-accent': ACCENT.greenDark,\n 'green-accent-hover': ACCENT.greenHoverDark,\n 'on-green': ACCENT.onGreen,\n star: STAR.dark,\n\n 'danger-solid': DANGER_SOLID.dark,\n 'danger-solid-hover': DANGER_SOLID.darkHover,\n 'on-danger': DANGER_SOLID.onDark,\n\n /* Koyu temada bant sayfadan daha KOYU: aynı tonda olsa yüzüyor görünüyor. */\n 'nav-bg': GRAPHITE.ink,\n 'nav-bg-2': GRAPHITE.inkTwo,\n 'nav-fg': '#e7eaee',\n 'nav-fg-2': '#9aa4b2',\n /* Açık temadaki kardeşiyle aynı gerekçe: bandın en soluk metni de metindir. */\n 'nav-fg-3': '#818b99',\n 'nav-line': '#262c36',\n 'nav-line-strong': '#363e4a',\n 'nav-hover': alpha(NEUTRAL.n0, 0.07),\n 'footer-bg': GRAPHITE.ink,\n\n /*\n * Koyu zeminde gölge okunmaz; derinlik daha çok kenarlıkla kurulur.\n * Gölgeler yine de KORUNUR ama daha derin: modal ve açılır liste yüzeyin\n * üzerinde durmalı.\n */\n 'shadow-xs': `0 1px 2px ${alpha(BLACK, 0.4)}`,\n 'shadow-sm': `0 1px 2px ${alpha(BLACK, 0.4)}, 0 1px 3px ${alpha(BLACK, 0.3)}`,\n 'shadow-md': `0 2px 4px ${alpha(BLACK, 0.35)}, 0 6px 16px ${alpha(BLACK, 0.45)}`,\n 'shadow-lg': `0 4px 8px ${alpha(BLACK, 0.4)}, 0 16px 32px ${alpha(BLACK, 0.55)}`,\n 'shadow-xl': `0 8px 16px ${alpha(BLACK, 0.45)}, 0 28px 56px ${alpha(BLACK, 0.6)}`,\n 'shadow-up': `0 -2px 4px ${alpha(BLACK, 0.3)}, 0 -8px 24px ${alpha(BLACK, 0.45)}`,\n\n ring: `0 0 0 3px ${alpha(BLUE.dark, 0.36)}`,\n 'ring-color': BLUE.dark,\n 'ring-danger': `0 0 0 3px ${alpha(DANGER_SOLID.dark, 0.32)}`,\n 'ring-ok': `0 0 0 4px ${alpha(STATUS.okFgDark, 0.2)}`,\n\n scrim: alpha(BLACK, 0.68),\n 'scrim-soft': alpha(BLACK, 0.45),\n glass: alpha('#1f242d', 0.92),\n 'glass-solid': '#1f242d',\n 'on-scrim': NEUTRAL.n0,\n\n 'skeleton-a': '#1f242d',\n 'skeleton-b': '#262c36',\n track: alpha(NEUTRAL.n0, 0.14),\n\n 'media-bg': '#1f242d',\n\n 'glow-1': alpha(BLUE.base, 0.2),\n 'glow-2': alpha(BLUE.dark, 0.1),\n 'glow-amber': alpha(AMBER.dark, 0.12),\n};\n\n/**\n * ÖLÇÜ TOKEN'LARI — temadan bağımsız, çalışma zamanında EZİLEBİLİR.\n *\n * <h3>Neden bunlar da CSS değişkeni</h3>\n * Bir zamanlar yalnızca renkler ve font aileleri çalışma zamanında\n * eziliyordu; yarıçap, boşluk, süre ve tipografi ölçeği `_variables.scss`\n * içinde SCSS sabitiydi. Sonucu şuydu: bir tüketici markasının RENGİNİ\n * verebiliyor ama YUVARLAKLIĞINI veremiyordu. Oysa bir markayı tanınır kılan\n * şeylerin listesinde yarıçap renkten sonra gelir — keskin köşeli bir\n * kurumsal panelle yumuşak köşeli bir vitrin aynı pakete aynı derecede\n * ihtiyaç duyuyor. Aynısı bilgi yoğunluğu (boşluk ölçeği) ve hareket süresi\n * için de geçerli.\n *\n * <h3>SCSS sabiti olarak KALANLAR ve nedenleri</h3>\n * <ul>\n * <li><b>Kırılma noktaları</b> — `@media (max-width: var(--x))` GEÇERSİZ\n * CSS. Medya sorgusu özel özellik okuyamaz; taşınsalardı bütün duyarlı\n * yerleşim sessizce çökerdi.</li>\n * <li><b>Katman (`z-*`)</b> — bir yığılma bağlamı sayısı, marka kararı\n * değil. Tüketicinin ezmesi gereken bir şey değil; ezerse kip pencere\n * perdenin altında kalır.</li>\n * <li><b>Ağırlık, harf aralığı, kapsayıcı genişlikleri, sayfa dolgusu</b> —\n * ölçek değil tekil değer; ezme ihtiyacı ölçülmedi. Gerektiğinde\n * buraya taşınabilir, ters yön (geri alma) kırıcıdır.</li>\n * </ul>\n *\n * <h3>Değerler DİZE, sayı değil</h3>\n * `'4px'` yazılıyor çünkü çıktı doğrudan bir CSS bildirimi. Sayı tutulup\n * birim sonradan eklenseydi, `radius-pill` (999px) ile `leading-normal`\n * (birimsiz 1.62) aynı listede duramazdı.\n */\nexport const METRIC_TOKENS = {\n // --- Yarıçap ---\n // Küçük öğeler ile büyük yüzeyler aynı yarıçapı PAYLAŞMAZ: küçük bir öğede\n // 12px onu şişman gösterir, büyük bir kartta 6px keskin ve ucuz görünür.\n 'radius-xs': '4px',\n 'radius-sm': '6px',\n 'radius-md': '8px',\n 'radius-lg': '12px',\n 'radius-xl': '16px',\n 'radius-pill': '999px',\n\n // --- Boşluk ---\n 'space-0': '0',\n 'space-1': '4px',\n 'space-2': '8px',\n 'space-3': '12px',\n 'space-4': '16px',\n 'space-5': '24px',\n 'space-6': '32px',\n 'space-7': '48px',\n 'space-8': '64px',\n 'space-9': '96px',\n\n /*\n * --- Tipografi ölçeği ---\n *\n * ÖLÇÜLDÜ: kaynak tasarım sisteminde `font-size` bildirimlerinin %67'si\n * 14 px ve altındaydı; arayüz varsayılanı, uzun süre ekrana bakan bir\n * kullanıcıda \"okunabilir ama yorucu\" eşiğinde duruyordu. Düzeltme TOKEN\n * düzeyinde yapıldı: yüzlerce dosyaya tek tek girmek yerine ölçek\n * kaydırıldı, böylece oranlar ve ritim korundu. Üst basamaklar (19/23/29…)\n * DEĞİŞMEDİ — onlar zaten yeterince büyüktü.\n */\n 'font-size-2xs': '12px',\n 'font-size-xs': '13px',\n 'font-size-sm': '15px',\n 'font-size-base': '16px',\n 'font-size-body': '17px',\n 'font-size-lg': '19px',\n 'font-size-xl': '23px',\n 'font-size-2xl': '29px',\n 'font-size-3xl': '37px',\n 'font-size-4xl': '47px',\n\n // Satır yüksekliği: başlıkta sıkı, metinde rahat. `leading-normal` 1.55'ten\n // 1.62'ye çıktı — 16 px gövde metninde en belirgin okunurluk kazanımı burada.\n 'leading-none': '1',\n 'leading-tight': '1.16',\n 'leading-snug': '1.35',\n 'leading-normal': '1.62',\n 'leading-relaxed': '1.75',\n\n /*\n * --- İkon ölçüsü ---\n *\n * İkonlar ölçülerini `1em` ile kapsayıcının `font-size` değerinden alır ve\n * o değer METİN için seçilmiştir: 15 px'lik bir arayüz puntosunda simge,\n * 16'lık viewBox'ın ~14 px'lik çizim alanına düşüyor ve 40 px'lik bir\n * `IconButton`ın ortasında bir nokta gibi duruyordu. Ölçek Bootstrap\n * Icons'ın 16 px'lik ızgarasının katlarına yakın durur; ara değerler\n * (17, 19) simgeyi yarım piksele oturtup bulanıklaştırıyordu.\n */\n 'icon-xs': '14px',\n 'icon-sm': '16px',\n 'icon-md': '18px',\n 'icon-lg': '20px',\n 'icon-xl': '24px',\n\n // --- Hareket ---\n // 200 ms üzerindeki geçişler tıklama ile sonuç arasında görünür bir gecikme\n // yaratır ve arayüz yavaş hissedilir.\n 'duration-instant': '80ms',\n 'duration-fast': '140ms',\n 'duration-normal': '200ms',\n 'duration-slow': '320ms',\n\n 'ease-out': 'cubic-bezier(0.22, 1, 0.36, 1)',\n 'ease-in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',\n 'ease-spring': 'cubic-bezier(0.34, 1.4, 0.64, 1)',\n\n /*\n * DÖNGÜ SÜRELERİ — geçiş ölçeğinden AYRI.\n *\n * `duration-*` ölçeği bir A→B geçişini ölçüyor ve tavanı 320 ms: onun\n * üstünde tıklama ile sonuç arasında görünür bir gecikme oluşuyor. Sürekli\n * dönen bir gösterge ise bir geçiş değil; 320 ms'lik bir dönüş baş\n * döndürücü, 140 ms'lik bir parıltı da titreşim gibi okunuyor.\n *\n * <p>Ayrı isim vermenin sebebi ölçekten kaçmak değil, ölçeği KORUMAK:\n * `Spinner` `0.7s`, iskelet parıltısı `1.4s` yazıyordu ve ikisi de hiçbir\n * yerde açıklanmamış ham değerlerdi. Ham süre artık lint hatası\n * (`stylelint.config.mjs`); bu iki değerin de bir adı var.\n */\n 'duration-spin': '700ms',\n 'duration-shimmer': '1400ms',\n} as const;\n\n/**\n * YOĞUN (compact) KİP — `<html data-hanui-density=\"compact\">`.\n *\n * <h3>Gerekçe ölçülü</h3>\n * Aynı bileşenleri iki uygulama kullanıyor: vitrin bir ekranda 8 satır,\n * operasyon paneli 80 satır gösteriyor. Vitrin için doğru olan ferahlık,\n * panelde kullanıcıyı kaydırmaya mahkûm ediyor; panel için doğru olan\n * sıkılık vitrinde ucuz duruyor. İkisini tek ölçekle karşılamanın yolu yok.\n *\n * <h3>Yalnızca boşluk ve punto iner — ÖLÇEĞİN TAMAMI DEĞİL</h3>\n * `space-0` ve `space-1` sabit kalır: 4 px'in altına inen bir boşluk kademesi\n * bir boşluk değil bir çizim hatası. Yarıçap da sabit kalır — yuvarlaklık\n * yoğunluğun değil markanın işi.\n *\n * <h3>DOKUNMA HEDEFİ KÜÇÜLMEZ</h3>\n * `tap-target` görünmez bir örtü çiziyor ve ölçüsü (44 px) buraya girmiyor:\n * yoğun kip bilgi yoğunluğunu artırmak içindir, dokunulabilirliği düşürmek\n * için değil (WCAG 2.5.8). Görsel kutu küçülür, hedef küçülmez.\n */\nexport const COMPACT_DENSITY = {\n 'space-2': '6px',\n 'space-3': '8px',\n 'space-4': '12px',\n 'space-5': '16px',\n 'space-6': '24px',\n 'space-7': '32px',\n\n 'font-size-2xs': '11px',\n 'font-size-xs': '12px',\n 'font-size-sm': '13px',\n 'font-size-base': '15px',\n 'font-size-body': '16px',\n\n 'leading-normal': '1.5',\n 'leading-relaxed': '1.6',\n} as const satisfies Partial<Record<keyof typeof METRIC_TOKENS, string>>;\n\n/** Token adları — `LIGHT_THEME`den türetilir, elle listelenmez. */\nexport type HanuiToken = keyof typeof LIGHT_THEME;\n\n/** Ölçü token adları — `METRIC_TOKENS`ten türetilir. */\nexport type HanuiMetricToken = keyof typeof METRIC_TOKENS;\n\n/** Ölçü ezmeleri. Kısmî verilebilir; verilmeyen her ölçü varsayılanında kalır. */\nexport type HanuiMetrics = Partial<Record<HanuiMetricToken, string>>;\n\n/**\n * Bilgi yoğunluğu. `default` vitrin, `compact` operasyon paneli.\n *\n * <p>Seçim `<html data-hanui-density>` ile taşınır — tıpkı tema gibi, ve aynı\n * sebeple: bir ölçek kararı tek bir React ağacının değil BELGENİN kararıdır;\n * portal ile gövdeye taşınan kip pencere de aynı yoğunlukta olmalı.\n */\nexport type HanuiDensity = 'default' | 'compact';\n\n/** Bir temanın token → değer eşlemesi. Kısmî verilebilir; eksikler varsayılandan gelir. */\nexport type HanuiThemeTokens = Partial<Record<HanuiToken, string>>;\n\n/** Bir temanın TAM eşlemesi. */\nexport type HanuiResolvedTokens = Record<HanuiToken, string>;\n\n/**\n * ÇÖZÜLMÜŞ tema — ekranda gerçekten hangisi çizili.\n *\n * <p>Burada `system` YOKTUR ve olamaz: `system` bir tercih, bir tema değil.\n * Çözüldüğünde ya açık ya koyu olur ve bileşenlerin gördüğü şey o. İkisini tek\n * tipte toplamak, `scheme === 'system'` yazan bir tüketiciye hangi renklerin\n * çizildiğini hâlâ söylemiyordu.\n */\nexport type HanuiColorScheme = 'light' | 'dark';\n\n/**\n * Kullanıcının SEÇİMİ. `system` = açık bir seçim yok, işletim sistemi tercihi\n * izlenir (`prefers-color-scheme`).\n *\n * <h3>Bu tip neden sonradan eklendi</h3>\n * `HanuiColorScheme`in JSDoc'u \"`system` işletim sistemi tercihini izler\"\n * diyordu ama tipte `system` YOKTU — belge bir yeteneği anlatıyor, tip onu\n * yasaklıyordu. İki çözüm vardı: cümleyi silmek ya da yeteneği gerçekten\n * eklemek. İkincisi seçildi çünkü eksik olan gerçek bir davranıştı: üç\n * durumlu tema anahtarı (Açık / Koyu / Sistem) yaygın bir kalıp ve kütüphane\n * onu kuramıyordu — `system`e dönmenin yolu özniteliği ELLE silmekti ve bunu\n * tüketicinin bilmesi gerekiyordu.\n *\n * <p>Ekleme KIRICI DEĞİL: `scheme` hâlâ çözülmüş değeri döndürüyor, yalnızca\n * `preference` alanı ve `setScheme('system')` girişi eklendi.\n */\nexport type HanuiColorPreference = HanuiColorScheme | 'system';\n\n/**\n * Yazı tipi ailesi sözleşmesi.\n *\n * <p>Üç rol ayrı: başlık (≥19 px), arayüz metni (11–16 px) ve teknik veri\n * (kod, seri numarası, tutar). KÜÇÜK ARAYÜZ METNİ BAŞLIK FONTUNU KULLANMAZ —\n * grotesk başlık yüzleri 12–14 px yarı-kalında sıkışıp okunurluğu düşürüyor\n * ve düğme etiketleri bir arayüzün en çok okunan kısa metinleri.\n *\n * <p>Kütüphane font YÜKLEMEZ: değerler `font-family` dizesi olarak geçer ve\n * yüklemeyi (next/font, @font-face, CDN) tüketici yapar. Bir UI paketinin\n * ağdan font çekmesi, tüketicinin ölçemediği bir istek demek.\n */\nexport type HanuiFonts = Partial<{\n heading: string;\n body: string;\n mono: string;\n}>;\n\n/** Kütüphanenin varsayılan font yığınları — hepsi sistem fontlarına iner. */\nexport const DEFAULT_FONTS: Required<HanuiFonts> = {\n heading: \"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\",\n body: \"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\",\n mono: \"ui-monospace, 'SF Mono', Menlo, Consolas, monospace\",\n};\n\n/**\n * Dışarıdan verilebilecek tema yapılandırması.\n *\n * @example\n * initHanui({\n * theme: {\n * light: { blue: '#0d6efd', 'blue-text': '#0a58ca' },\n * dark: { blue: '#6ea8fe' },\n * fonts: { heading: 'Archivo, sans-serif' },\n * },\n * });\n */\nexport type HanuiThemeConfig = Partial<{\n light: HanuiThemeTokens;\n dark: HanuiThemeTokens;\n fonts: HanuiFonts;\n /**\n * Ölçü ezmeleri — yarıçap, boşluk, punto, süre.\n *\n * <p>Renk gibi tema başına DEĞİL tek blokta: bir markanın yuvarlaklığı açık\n * temada 12 px, koyu temada 8 px olmaz. Ayrı verilebilseydi iki değerin\n * ayrışması kaçınılmazdı ve fark yalnızca tema değiştirildiğinde\n * görünürdü — yani neredeyse hiç.\n *\n * @example\n * initHanui({ theme: { metrics: { 'radius-md': '2px', 'radius-lg': '4px' } } });\n */\n metrics: HanuiMetrics;\n}>;\n","import { isClient } from '@ahmetilhn/handy-utils';\n\nimport {\n DARK_THEME,\n DEFAULT_FONTS,\n LIGHT_THEME,\n type HanuiColorScheme,\n type HanuiResolvedTokens,\n type HanuiThemeConfig,\n} from '../theme/tokens';\n\n/** CSS özel özelliği öneki — `_tokens.generated.scss` ile aynı olmak zorunda. */\nexport const TOKEN_PREFIX = '--hanui-';\n\n/** Ezme kurallarını taşıyan `<style>` etiketinin kimliği. */\nexport const THEME_STYLE_ID = 'hanui-theme-overrides';\n\n/** Temanın taşındığı öznitelik. `<html data-hanui-theme=\"dark\">`. */\nexport const THEME_ATTRIBUTE = 'data-hanui-theme';\n\n/**\n * Bilgi yoğunluğunun taşındığı öznitelik.\n * `<html data-hanui-density=\"compact\">`.\n *\n * <p>Tema gibi BELGE düzeyinde: portal ile gövdeye taşınan kip pencere de aynı\n * yoğunlukta olmalı ve bir React ağacına bağlanan değer onu kapsamıyor.\n */\nexport const DENSITY_ATTRIBUTE = 'data-hanui-density';\n\n/** Geçiş animasyonlarını tek kare boyunca kapatan sınıf (bkz. `base.scss`). */\nexport const THEME_SWITCHING_CLASS = 'hanui-theme-switching';\n\n/** Verilen şemanın tam token eşlemesi — ezmeler uygulanmış hâliyle. */\nexport const resolveTokens = (\n scheme: HanuiColorScheme,\n config?: HanuiThemeConfig,\n): HanuiResolvedTokens => {\n const base = scheme === 'dark' ? DARK_THEME : LIGHT_THEME;\n const overrides = (scheme === 'dark' ? config?.dark : config?.light) ?? {};\n\n return { ...base, ...overrides };\n};\n\n/**\n * Yapılandırmayı CSS metnine çevirir.\n *\n * <h3>Neden yalnızca EZİLEN token'lar yazılıyor</h3>\n * Tam eşlemeyi yazmak da çalışırdı ama iki bedeli var: çıktı 90 satır yerine\n * 4 satır olurdu ve daha önemlisi, kütüphane bir sonraki sürümde bir token'ın\n * varsayılanını değiştirdiğinde tüketicinin sayfası ESKİ değeri yazmaya devam\n * ederdi — üstelik ezmediği bir token için. Ezmeler ne ise o yazılır.\n *\n * <h3>Neden `<style>`, neden satır içi stil değil</h3>\n * Satır içi stil yalnızca `<html>` üzerinde durur ve `[data-hanui-theme]`\n * seçicisinden daha yüksek özgüllüktedir: kullanıcı temayı değiştirdiğinde\n * ezmeler HER İKİ temada da aynı kalıyordu. Ayrı bir kural bloğu, açık ve\n * koyu ezmeleri kendi seçicilerine bağlar.\n */\nexport const buildThemeCss = (config: HanuiThemeConfig): string => {\n const blocks: string[] = [];\n\n const declarations = (tokens: Record<string, string>, indent = ' ') =>\n Object.entries(tokens)\n .map(([name, value]) => `${indent}${TOKEN_PREFIX}${name}: ${value};`)\n .join('\\n');\n\n const fonts = config.fonts ?? {};\n const fontEntries = Object.entries(fonts).filter(([, value]) => Boolean(value)) as [\n keyof typeof DEFAULT_FONTS,\n string,\n ][];\n\n if (fontEntries.length > 0)\n blocks.push(\n `:root {\\n${fontEntries\n .map(([role, stack]) => ` ${TOKEN_PREFIX}font-${role}: ${stack};`)\n .join('\\n')}\\n}`,\n );\n\n /*\n * OLCU EZMELERI TEMA BASINA DEGIL, TEK BLOKTA.\n *\n * Bir markanin yuvarlakligi acik temada 12 px, koyu temada 8 px olmaz. Ayri\n * verilebilseydi iki degerin ayrismasi kacinilmazdi ve fark yalnizca tema\n * degistirildiginde gorunurdu — yani neredeyse hic.\n *\n * `:root` YETERLI: renk ezmelerinde iki secici gerekiyordu cunku uretilmis\n * koyu blok `[data-hanui-theme='dark']` ile ozgullukte yarisiyor. Olcuye\n * karsilik gelen uretilmis blok ise `:root` (base-tokens) — esit ozgulluk,\n * kaynak sirasi kazandiriyor ve bu etiket `<head>`in SONUNA ekleniyor.\n *\n * TEK ISTISNA yogun kip: `[data-hanui-density='compact']` daha yuksek\n * ozgullukte ve ezmeyi yener. Ezme orada da gecerli olsun diye ayni govde\n * ikinci kez, o secici altinda yaziliyor — aksi halde tuketicinin verdigi\n * `space-4`, compact acilir acilmaz kutuphanenin varsayilanina donuyordu.\n */\n const metrics = config.metrics ?? {};\n\n if (Object.keys(metrics).length > 0) {\n const body = declarations(metrics as Record<string, string>);\n blocks.push(`:root {\\n${body}\\n}`);\n blocks.push(`:root[${DENSITY_ATTRIBUTE}='compact'] {\\n${body}\\n}`);\n }\n\n /*\n * Acik tema iki secicide birden yazilir: `:root` (varsayilan) ve\n * `:root[data-hanui-theme='light']` (kullanicinin acik secimi). Yalnizca\n * `:root` yazilsaydi, sistem tercihi koyu olan bir cihazda acik temayi ELLE\n * secen kullanicida ezmeler dusuyordu — cunku uretilmis koyu blok\n * `:root:not([data-hanui-theme])` degil `[data-hanui-theme='light']` ile\n * yarisiyor ve ozgullukte kazaniyor.\n */\n if (config.light && Object.keys(config.light).length > 0) {\n const body = declarations(config.light);\n blocks.push(`:root {\\n${body}\\n}`);\n blocks.push(`:root[${THEME_ATTRIBUTE}='light'] {\\n${body}\\n}`);\n }\n\n if (config.dark && Object.keys(config.dark).length > 0) {\n const body = declarations(config.dark);\n blocks.push(`:root[${THEME_ATTRIBUTE}='dark'] {\\n${body}\\n}`);\n blocks.push(\n `@media (prefers-color-scheme: dark) {\\n :root:not([${THEME_ATTRIBUTE}]) {\\n${declarations(\n config.dark,\n ' ',\n )}\\n }\\n}`,\n );\n }\n\n return blocks.join('\\n\\n');\n};\n\n/**\n * Ezmeleri belgeye yazar. Aynı `<style>` etiketi tekrar kullanılır: her\n * çağrıda yeni bir etiket eklemek, birbirini ezen onlarca blok bırakıyordu.\n *\n * <p>Etiket `<head>`in SONUNA eklenir — paket CSS'i ondan önce yüklenmiş\n * olmalı ki eşit özgüllükte ezme kazansın.\n */\nexport const applyThemeConfig = (config: HanuiThemeConfig | undefined): void => {\n if (!isClient()) return;\n\n const css = config ? buildThemeCss(config) : '';\n const existing = document.getElementById(THEME_STYLE_ID);\n\n if (css === '') {\n existing?.remove();\n return;\n }\n\n const element = existing ?? document.createElement('style');\n element.id = THEME_STYLE_ID;\n element.textContent = css;\n\n if (!existing) document.head.appendChild(element);\n};\n","'use client';\n\nimport { createContext, useContext } from 'react';\n\nimport type { HanuiLinkComponent } from '../types/link.type';\nimport type { HanuiLabels } from './labels';\nimport type { HanuiThemeConfig } from './tokens';\n\nexport type HanuiContextValue = {\n /**\n * Tüketicinin yönlendiricisi (`next/link`, `react-router`ın `Link`i…).\n *\n * <p>Verilmezse ham `<a>` çizilir ve gezinme tam sayfa yenilemesi olur.\n * Bir bileşen kütüphanesi kendi yönlendiricisini SEÇEMEZ: `next/link`\n * import etmek paketi Next'e bağlar, `react-router` import etmek başka bir\n * uygulamayı kırar. Karar tüketicinin.\n */\n linkComponent?: HanuiLinkComponent;\n /** Uygulanan tema ezmeleri. Salt okunur; değiştirmek için `HanuiProvider`. */\n theme?: HanuiThemeConfig;\n /**\n * Arayüz metinleri. Bir bileşen metnini prop olarak almadıysa buradan okur\n * (bkz. `theme/labels.ts`).\n */\n labels?: HanuiLabels;\n};\n\nconst HanuiContext = createContext<HanuiContextValue>({});\n\n/**\n * Sağlayıcı ZORUNLU DEĞİL.\n *\n * <p>Sağlayıcısız kullanımda bağlantılar ham `<a>` olur ve tema\n * varsayılanlarda kalır — yani paket `import` edilip hiçbir kurulum\n * yapılmadan çalışır. Sağlayıcıyı zorunlu kılmak, tek bir `Badge` kullanmak\n * isteyen bir tüketiciyi de kök yerleşimi değiştirmeye zorluyordu.\n */\nexport const useHanui = (): HanuiContextValue => useContext(HanuiContext);\n\nexport default HanuiContext;\n","'use client';\n\nimport { type FC, type ReactNode, useEffect, useMemo, useRef } from 'react';\n\nimport { applyThemeConfig } from '../helpers/theme.helper';\nimport type { HanuiLinkComponent } from '../types/link.type';\nimport HanuiContext from './context';\nimport type { HanuiLabels } from './labels';\nimport type { HanuiThemeConfig } from './tokens';\n\ntype Props = {\n children: ReactNode;\n /**\n * Tema ezmeleri. Yalnızca DEĞİŞTİRİLEN token'lar verilir; verilmeyen her\n * token varsayılanında kalır.\n *\n * <p>Nesne referansı her render'da yeniden üretilirse (satır içi nesne\n * literali) `<style>` etiketi de her render'da yeniden yazılır. Bileşen\n * bunu içerik karşılaştırmasıyla engeller ama yine de sabit bir referans\n * (modül düzeyinde tanımlı bir nesne) tercih edilmeli.\n */\n theme?: HanuiThemeConfig;\n /**\n * Tüketicinin bağlantı bileşeni. Verilmezse ham `<a>` çizilir.\n *\n * @example\n * import NextLink from 'next/link';\n * <HanuiProvider linkComponent={NextLink}>…</HanuiProvider>\n */\n linkComponent?: HanuiLinkComponent;\n /**\n * Arayüz metinleri — bir kez, burada.\n *\n * <p>Kütüphane hiçbir dilde metin uydurmaz ama aynı \"Kapat\" dizesini yüz\n * çağrı yerine dağıtmak da doğru değildi: biri değiştiğinde doksan dokuzu\n * eski kalıyordu. Çözümleme sırası prop → buradaki config; ikisi de yoksa\n * geliştirme kipinde konsola uyarı düşer.\n *\n * <p>Öğeye ÖZGÜ metinler buraya girmez (`Modal.title`,\n * `ConfirmDialog.confirmLabel`, `IconButton.label`); onlar prop olarak\n * zorunlu kalır çünkü her çağrı yerinde farklıdır.\n */\n labels?: HanuiLabels;\n};\n\n/**\n * Kütüphane sağlayıcısı.\n *\n * <h3>İki iş yapar, üçüncüsünü YAPMAZ</h3>\n * <ol>\n * <li>Tema ezmelerini belgeye yazar (`<style id=\"hanui-theme-overrides\">`).</li>\n * <li>Yönlendirici bileşenini bileşen ağacına dağıtır.</li>\n * <li><strong>Açık/koyu seçimini YÖNETMEZ.</strong></li>\n * </ol>\n *\n * <h3>Neden tema seçimi burada değil</h3>\n * Seçim `<html data-hanui-theme>` üzerinde taşınır ve o özniteliğin\n * <em>boyamadan önce</em> yazılması gerekir: React ağacı monte olduktan sonra\n * yazıldığında koyu tema seçmiş kullanıcı bir kare beyaz ekran görüyor. Doğru\n * yer, sunucudan gelen HTML'in `<head>`ine konan satır içi bir betik — ve\n * oraya yazmak tüketicinin çatısının işi (Next'te `app/layout.tsx`, Vite'ta\n * `index.html`). Sağlayıcı ondan sonra monte oluyor; oraya koymak sorunu\n * çözmüyor, gizliyor.\n *\n * <p>`useHanuiTheme` kancası seçimi <em>değiştirmek</em> için var; ilk değeri\n * yazmak için değil. README \"Tema\" bölümünde hazır betik duruyor.\n *\n * @example\n * <HanuiProvider linkComponent={NextLink} theme={{ light: { blue: '#0d6efd' } }}>\n * <App />\n * </HanuiProvider>\n */\nconst HanuiProvider: FC<Props> = ({ children, theme, linkComponent, labels }) => {\n /*\n * `JSON.stringify` bagimlilik anahtari olarak kullaniliyor: cagiran taraf\n * neredeyse her zaman satir ici bir nesne literali veriyor ve referans her\n * render'da degisiyor. Referansa baglansaydi `<style>` etiketi saniyede\n * onlarca kez yeniden yazilirdi.\n */\n const themeKey = useMemo(() => (theme ? JSON.stringify(theme) : ''), [theme]);\n\n useEffect(() => {\n applyThemeConfig(theme);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [themeKey]);\n\n /*\n * `theme` bir REFERANSTAN okunur, bagimliliktan degil.\n *\n * Cagiran taraf neredeyse her zaman satir ici bir nesne literali veriyor ve\n * referans her render'da degisiyor; `theme`i bagimliliga koymak memo'yu ise\n * yaramaz hale getirip tuketicideki her bileseni bos yere yeniden cizerdi.\n * Kimlik yerine ICERIK izleniyor (`themeKey`) — ve memo'nun icinde `theme`e\n * dogrudan dokunulmadigi icin denetci de dogru: eksik bir bagimlilik yok.\n */\n const themeRef = useRef(theme);\n themeRef.current = theme;\n\n const value = useMemo(\n () => ({ theme: themeRef.current, linkComponent, labels }),\n /* `themeKey` denetciye GEREKSIZ gorunuyor cunku memo'nun govdesinde\n gecmiyor — ama tam da isi bu: temanin ICERIGI degistiginde yeni bir\n nesne uretilmesini saglayan tetik o. Cikarilirsa tema ezmesi degisse\n de tuketiciler eski degeri gorurdu. */\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [themeKey, linkComponent, labels],\n );\n\n return <HanuiContext.Provider value={value}>{children}</HanuiContext.Provider>;\n};\n\nexport default HanuiProvider;\n","import { isClient } from '@ahmetilhn/handy-utils';\n\nimport { applyThemeConfig, DENSITY_ATTRIBUTE, THEME_ATTRIBUTE } from '../helpers/theme.helper';\nimport type { HanuiColorScheme, HanuiDensity, HanuiThemeConfig } from './tokens';\n\nexport type InitHanuiOptions = Partial<{\n /** Tema ve ölçü ezmeleri. Yalnızca değiştirilen token'lar verilir. */\n theme: HanuiThemeConfig;\n /**\n * Başlangıç şeması. Verilmezse `<html data-hanui-theme>` neyse o kalır;\n * o da yoksa sistem tercihi (`prefers-color-scheme`) devreye girer.\n */\n colorScheme: HanuiColorScheme;\n /**\n * Bilgi yoğunluğu. Verilmezse `<html data-hanui-density>` neyse o kalır;\n * o da yoksa `default`.\n *\n * <p>Uygulama başına SABİT bir karar olduğunda (operasyon paneli her zaman\n * `compact`) buradan verilir; kullanıcıya seçtiren bir uygulama özniteliği\n * kendisi yazar.\n */\n density: HanuiDensity;\n}>;\n\n/**\n * Kütüphaneyi <strong>React ağacının dışından</strong> yapılandırır.\n *\n * <h3>Ne zaman bu, ne zaman `HanuiProvider`</h3>\n * `HanuiProvider` React'in içinde yaşıyor ve yönlendirici bileşenini de\n * taşıyor — normal yol o. Bu fonksiyon iki durum için:\n *\n * <ul>\n * <li><strong>Boyamadan önce çalışması gereken tema.</strong> Sağlayıcı\n * ağaç monte olduktan sonra yazıyor; koyu tema seçmiş bir kullanıcı o\n * ana kadar beyaz ekran görüyor. `<head>` içindeki satır içi bir\n * betikten çağrıldığında ezmeler ilk boyamadan önce yerinde olur.</li>\n * <li><strong>React kullanmayan bir kabuk.</strong> Tasarım token'ları\n * yalnızca CSS; bir e-posta önizlemesi ya da Storybook temasında\n * bileşen ağacı olmadan da gerekiyor.</li>\n * </ul>\n *\n * <p>İkisi birlikte kullanılabilir: aynı `<style>` etiketini paylaşırlar ve\n * son çağrı kazanır.\n *\n * @example\n * // app/layout.tsx — <head> içine, boyamadan önce.\n * <script dangerouslySetInnerHTML={{ __html: `\n * document.documentElement.dataset.hanuiTheme =\n * localStorage.getItem('theme') ?? 'light';\n * ` }} />\n */\nexport const initHanui = (options: InitHanuiOptions = {}): void => {\n applyThemeConfig(options.theme);\n\n if (!isClient()) return;\n\n if (options.colorScheme)\n document.documentElement.setAttribute(THEME_ATTRIBUTE, options.colorScheme);\n\n if (options.density) document.documentElement.setAttribute(DENSITY_ATTRIBUTE, options.density);\n};\n\nexport default initHanui;\n","'use client';\n\nimport { useCallback } from 'react';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\n/** Duyurunun aciliyeti. */\nexport type AnnouncePoliteness = 'polite' | 'assertive';\n\n/**\n * EKRAN OKUYUCU DUYURU MERKEZİ.\n *\n * <h3>Sorun: görsel geri bildirimin sesli karşılığı yoktu</h3>\n * Asenkron bir sonuç ekranda görünüyor ama ekran okuyucuya HİÇ ulaşmıyordu:\n * filtre uygulanıp liste 48 ürüne düştüğünde, sepete ekleme başarılı\n * olduğunda, form gönderimi hata verdiğinde. Gören kullanıcı sonucu bir\n * bakışta alıyor; ekran okuyucu kullanıcısı odağı olmayan bir yerde değişen\n * içeriği fark etmiyor — imleci oraya götürmedikçe.\n *\n * <p>Kütüphanede yalnızca `CopyField` kendi başına duyuruyordu ve o da kendi\n * `aria-live` bölgesini kendisi çiziyordu. Aynı deseni her bileşene kopyalamak\n * sayfada onlarca canlı bölge demek — ve birden fazla canlı bölge, ekran\n * okuyucuların duyuruları BİRLEŞTİRİP sırayla okumasına ya da tamamen\n * atlamasına yol açıyor.\n *\n * <h3>Bölge sağlayıcıda DEĞİL, belgede</h3>\n * `HanuiProvider` zorunlu değil (bkz. `theme/context.ts`): tek bir `Badge`\n * kullanmak isteyen tüketici kök yerleşimini değiştirmek zorunda kalmasın.\n * Duyuru bölgesi sağlayıcıya bağlansaydı, sağlayıcısız kullanımda hiçbir şey\n * duyurulmazdı — üstelik sessizce. Bölge ilk çağrıda belgeye eklenir ve\n * uygulamanın ömrü boyunca orada kalır; DOM'a eklenen bir canlı bölgenin\n * duyurusu güvenilmez, önceden var olması gerekir.\n *\n * <h3>Neden iki ayrı bölge</h3>\n * `polite` sıradaki cümleyi bekler, `assertive` kullanıcının okuduğu şeyi\n * BÖLER. Tek bir bölgede `aria-live` değerini değiştirmek işe yaramıyor:\n * değişiklik bir sonraki duyuruda değil, o anda okunmakta olanda etkili\n * olmuyor. Hata için `assertive` (kullanıcı yanlış bir işe devam ediyor\n * olabilir), geri kalan her şey için `polite`.\n *\n * @example\n * const announce = useAnnounce();\n * announce(`${count} ürün bulundu`);\n * announce('Kart reddedildi', 'assertive');\n */\n\nconst REGION_ID = 'hanui-live-region';\n\n/** Bölgeyi bulur; yoksa oluşturur. */\nconst getRegion = (politeness: AnnouncePoliteness): HTMLElement | null => {\n if (!isClient()) return null;\n\n const id = `${REGION_ID}-${politeness}`;\n const existing = document.getElementById(id);\n if (existing) return existing;\n\n const region = document.createElement('div');\n region.id = id;\n region.setAttribute('aria-live', politeness);\n /* `aria-atomic` — bolge her degistiginde TAMAMI okunur. Kapali\n birakildiginda ekran okuyucular yalnizca DEGISEN kelimeleri okuyor ve\n \"48 urun bulundu\" ile \"12 urun bulundu\" arasinda yalnizca sayi\n duyuruluyordu. */\n region.setAttribute('aria-atomic', 'true');\n /* Gorsel olarak gizli ama DOM'da: `display: none` ya da `hidden` bolgeyi\n erisilebilirlik agacindan da cikarir ve hicbir sey duyurulmaz. */\n region.className = 'hanui-visually-hidden';\n\n document.body.appendChild(region);\n return region;\n};\n\n/**\n * AYNI metni arka arkaya duyurmak.\n *\n * <p>Bölgenin metni değişmediğinde ekran okuyucu hiçbir şey okumaz: \"Kopyalandı\"\n * ikinci kez basıldığında sessiz kalıyordu. Metin önce boşaltılıp bir kare\n * sonra yazılıyor — değişiklik böylece gerçekten bir değişiklik oluyor.\n */\nconst write = (region: HTMLElement, message: string): void => {\n region.textContent = '';\n\n window.requestAnimationFrame(() => {\n region.textContent = message;\n });\n};\n\n/**\n * Duyuru fonksiyonu döndürür. Referans SABİT: bağımlılık dizisine güvenle\n * konur, her render'da yeni bir kapanış üretip etkileri tetiklemez.\n */\nconst useAnnounce = (): ((message: string, politeness?: AnnouncePoliteness) => void) =>\n useCallback((message: string, politeness: AnnouncePoliteness = 'polite') => {\n const trimmed = message.trim();\n /* Bos duyuru bolgeyi temizler ve bir sonraki gercek duyuruyu bastirir. */\n if (trimmed === '') return;\n\n const region = getRegion(politeness);\n if (region) write(region, trimmed);\n }, []);\n\nexport default useAnnounce;\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { THEME_ATTRIBUTE, THEME_SWITCHING_CLASS } from '../helpers/theme.helper';\nimport type { HanuiColorPreference, HanuiColorScheme } from '../theme/tokens';\n\n/** Sistem tercihini okur. Betik hiç çalışmamışsa ilk değer buradan gelir. */\nconst readSystemScheme = (): HanuiColorScheme =>\n isClient() && window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n\n/**\n * `<html>` üzerindeki AÇIK seçim; öznitelik yoksa `system`.\n *\n * <p>Özniteliğin yokluğu bir eksiklik değil bir DEĞER: \"sistemi izle\".\n */\nconst readPreference = (): HanuiColorPreference => {\n if (!isClient()) return 'system';\n\n const attribute = document.documentElement.getAttribute(THEME_ATTRIBUTE);\n return attribute === 'dark' || attribute === 'light' ? attribute : 'system';\n};\n\ntype ThemeState = {\n /**\n * ÇÖZÜLMÜŞ tema — ekranda çizili olan. `preference` `system` iken bu alan\n * işletim sisteminin o anki tercihini taşır.\n */\n scheme: HanuiColorScheme;\n /**\n * Kullanıcının SEÇİMİ. Üç durumlu bir tema anahtarı (Açık / Koyu / Sistem)\n * bunu okur; `scheme` okunsaydı \"Sistem\" seçiliyken düğme \"Koyu\"yu işaretli\n * gösterirdi.\n */\n preference: HanuiColorPreference;\n /** `'system'` verildiğinde AÇIK seçim silinir ve sistem tercihi izlenir. */\n setScheme: (preference: HanuiColorPreference) => void;\n /** Açık ↔ koyu. `system` iken ÇÖZÜLMÜŞ değerin tersine geçer. */\n toggle: () => void;\n /**\n * Sunucu çıktısında ve hidrasyondan önceki ilk karede `false`.\n *\n * <p>Tema anahtarı bunu bekler: sunucu hangi temanın seçili olduğunu\n * bilmiyor ve bir tahminle çizilen anahtar, doğru tahmin edilse bile\n * hidrasyonda uyuşmazlık üretiyordu. Anahtar hazır olana kadar\n * `aria-hidden` bir yer tutucu çizilir.\n */\n isReady: boolean;\n};\n\n/**\n * Açık/koyu seçimini okur ve değiştirir.\n *\n * <h3>KALICILIK BU KANCANIN İŞİ DEĞİL</h3>\n * Seçimi nereye yazacağı tüketicinin kararı: `localStorage`, bir çerez (SSR'da\n * okunabilmesi için), kullanıcı profili. Kütüphane `localStorage`a yazsaydı\n * sunucu tarafı onu okuyamayacağı için ilk boyama yine yanlış temada\n * olurdu — ve tüketici kendi çerezini kullanmak istediğinde iki kaynak\n * çatışırdı.\n *\n * <h3>Geçiş tek karede kapatılır</h3>\n * Şema değişirken `<html>` bir kare boyunca `hanui-theme-switching` sınıfını\n * taşır. Sınıfsız hâlde her yüzey aynı anda ama FARKLI sürelerde animasyon\n * yapıyordu (kart gölgesi 140 ms, sayfa zemini 200 ms) ve geçiş dalgalı\n * görünüyordu. Ani geçiş, dalgalı geçişten iyi.\n *\n * @example\n * const { scheme, toggle, isReady } = useHanuiTheme();\n *\n * useEffect(() => {\n * if (isReady) localStorage.setItem('theme', scheme);\n * }, [scheme, isReady]);\n */\nconst useHanuiTheme = (): ThemeState => {\n /*\n * Ilk deger SABIT 'light': sunucuda `document` yok ve istemcideki gercek\n * degeri ilk render'da okumak hidrasyon uyusmazligi uretiyordu (sunucu\n * \"light\" cizdi, istemci \"dark\" okudu). Gercek deger monte olduktan sonra\n * yaziliyor ve `isReady` o ana kadar false kaliyor.\n */\n const [preference, setPreferenceState] = useState<HanuiColorPreference>('light');\n const [systemScheme, setSystemScheme] = useState<HanuiColorScheme>('light');\n const [isReady, setIsReady] = useState(false);\n\n useEffect(() => {\n setPreferenceState(readPreference());\n setSystemScheme(readSystemScheme());\n setIsReady(true);\n }, []);\n\n /*\n * Sistem tercihi HER ZAMAN izlenir, `preference` ne olursa olsun.\n *\n * Once dinleyici `preference === 'system'` iken yaziyordu ve kullanici\n * \"Koyu\"dan \"Sistem\"e dondugunde elde guncel bir sistem degeri yoktu: kanca\n * ilk montajdaki degeri hatirliyor, aradaki degisimi kacirmis oluyordu.\n * Olcum ucuz (tek bir medya sorgusu dinleyicisi); karar ise cozumleme\n * sirasinda veriliyor.\n */\n useEffect(() => {\n if (!isClient() || !window.matchMedia) return;\n\n const query = window.matchMedia('(prefers-color-scheme: dark)');\n const handleChange = () => setSystemScheme(readSystemScheme());\n\n query.addEventListener('change', handleChange);\n return () => query.removeEventListener('change', handleChange);\n }, []);\n\n const scheme: HanuiColorScheme = preference === 'system' ? systemScheme : preference;\n\n const setScheme = useCallback((next: HanuiColorPreference) => {\n if (!isClient()) return;\n\n const root = document.documentElement;\n\n root.classList.add(THEME_SWITCHING_CLASS);\n\n /* `system` bir DEGER degil, degerin YOKLUGU: oznitelik silinir ve\n `_tokens.generated.scss` icindeki `:not([data-hanui-theme])` sorgusu\n devreye girer. `data-hanui-theme=\"system\"` yazilsaydi o sorgu eslesmez\n ve sayfa acik temada kalirdi. */\n if (next === 'system') root.removeAttribute(THEME_ATTRIBUTE);\n else root.setAttribute(THEME_ATTRIBUTE, next);\n\n setPreferenceState(next);\n\n /*\n * Sinif BIR SONRAKI karede kaldirilir. Ayni karede kaldirilsaydi tarayici\n * hicbir zaman gecissiz bir boyama yapmayacak ve sinifin varligi hicbir\n * ise yaramayacakti.\n */\n window.requestAnimationFrame(() => {\n window.requestAnimationFrame(() => root.classList.remove(THEME_SWITCHING_CLASS));\n });\n }, []);\n\n const toggle = useCallback(\n () => setScheme(scheme === 'dark' ? 'light' : 'dark'),\n [scheme, setScheme],\n );\n\n return { scheme, preference, setScheme, toggle, isReady };\n};\n\nexport default useHanuiTheme;\n","/**\n * Kaydırma yardımcıları.\n *\n * <h3>Neden `scrollIntoView` doğrudan çağrılmıyor</h3>\n * jsdom `Element.prototype.scrollIntoView`u UYGULAMIYOR ve çağrı bir\n * `TypeError` atıyor. Bedeli kütüphanenin kendi testleri değil, TÜKETİCİNİN\n * testleri: `Tabs` çizen bir bileşen ölçüldüğünde `E.scrollIntoView is not a\n * function` ile düşüyordu — kırılan yer kullanıcının kodu, sebebi ise\n * kütüphanenin ekranı kaydırma girişimi. Test ortamı için tüketiciye\n * `Element.prototype.scrollIntoView = jest.fn()` yazdırmak, kütüphanenin\n * eksiğini her tüketicinin kurulum dosyasına dağıtmak olurdu.\n *\n * <p>Aynı koruma gerçek tarayıcılarda da işe yarıyor: `scrollIntoView` eski\n * WebView'larda seçenek nesnesini yok sayıyor ama VAR; burada ölçülen şey\n * fonksiyonun varlığı, davranışı değil.\n */\n\n/** Öğeyi görünür alana kaydırır; ortam desteklemiyorsa sessizce geçer. */\nexport const scrollIntoViewIfPossible = (\n element: Element | null | undefined,\n options?: ScrollIntoViewOptions,\n): void => {\n if (typeof element?.scrollIntoView === 'function') element.scrollIntoView(options);\n};\n","'use client';\n\nimport { type KeyboardEvent, type RefObject, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { scrollIntoViewIfPossible } from '../helpers/scroll.helper';\n\nexport type ListboxNavigationOptions = {\n /** Seçenek sayısı. Liste süzüldüğünde değişir. */\n count: number;\n isOpen: boolean;\n /** Açılışta etkin olacak dizin — genellikle seçili olan. */\n initialIndex?: number;\n /** `Enter` / `Space` ile seçildiğinde. */\n onSelect: (index: number) => void;\n onClose: () => void;\n};\n\nexport type ListboxNavigation<T extends HTMLElement = HTMLElement> = {\n activeIndex: number;\n setActiveIndex: (index: number) => void;\n /**\n * Etkin seçeneği görünür alanda tutmak için LİSTEYE bağlanır.\n *\n * <p>Tip parametresi çağıran taraf için: `Select` bu referansı `<ul>`e\n * veriyor ve panel açıldığında `focus()` çağırıyor. `HTMLElement`e sabitlense\n * çağıran ikinci bir referans tutmak ve ikisini elle eşlemek zorunda kalırdı.\n */\n listRef: RefObject<T | null>;\n handleKeyDown: (event: KeyboardEvent<HTMLElement>) => void;\n};\n\n/**\n * LISTBOX KLAVYE GEZİNMESİ — `Select` ve `Combobox`ın ortak modeli.\n *\n * <h3>Neden bir kanca</h3>\n * İki bileşen aynı klavye modelini <strong>kopya kod</strong> olarak\n * taşıyordu: `ArrowDown`/`ArrowUp` uçlarda dönme, `Home`/`End`, `Enter` ile\n * seçme, `Escape` ile kapatma, `Tab` ile kapatıp gezinmeye devam etme ve\n * etkin seçeneği görünür alanda tutma. Altı davranış, iki yerde. Kopya kod\n * ayrışmaya açık ve ayrışma sessiz: bir bileşende `Home` çalışıp diğerinde\n * çalışmadığında hiçbir test kırılmıyordu — ikisinin de kendi testi vardı ve\n * ikisi de kendi davranışını doğruluyordu.\n *\n * <p>Kanca yalnızca <strong>gezinmeyi</strong> taşıyor. Açılma kararı (panel\n * mi alt sayfa mı), filtreleme ve seçim sözleşmesi (`value`/`onChange`) hâlâ\n * bileşenlerin: ikisi orada gerçekten farklı ve tek bir kancaya toplamak\n * `Select`e hiç kullanmayacağı arama koduna taşıtırdı.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin seçenek; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>etkin seçeneği seçer</td></tr>\n * <tr><td>`Escape`</td><td>kapatır</td></tr>\n * <tr><td>`Tab`</td><td>kapatır, gezinme SÜRER (`preventDefault` yok)</td></tr>\n * </table>\n *\n * <p>`Space` yalnızca `hasSpaceSelect` ile: `Combobox`ın arama kutusunda boşluk\n * bir KARAKTER ve onu seçime çevirmek \"fren balatası\" yazmayı imkânsız\n * kılıyordu.\n */\nconst useListboxNavigation = <T extends HTMLElement = HTMLElement>(\n { count, isOpen, initialIndex = 0, onSelect, onClose }: ListboxNavigationOptions,\n { hasSpaceSelect = false } = {},\n): ListboxNavigation<T> => {\n const [activeIndex, setActiveIndex] = useState(initialIndex);\n const listRef = useRef<T | null>(null);\n\n /* Panel her acildiginda etkin secenek SECILI olandan baslar; kullanici\n listeyi bastan taramak zorunda kalmaz. */\n useEffect(() => {\n if (isOpen) setActiveIndex(initialIndex);\n }, [isOpen, initialIndex]);\n\n /*\n * Liste SUZULDUGUNDE etkin dizin listenin disinda kalabiliyor: uc secenek\n * gorunurken `activeIndex` 7'de kaldiginda `Enter` hicbir sey secmiyordu.\n */\n useEffect(() => {\n setActiveIndex(current => (current >= count ? Math.max(0, count - 1) : current));\n }, [count]);\n\n /* Etkin secenek gorunur alanin disina cikmamali. */\n useEffect(() => {\n if (!isOpen) return;\n scrollIntoViewIfPossible(listRef.current?.querySelector(`[data-index=\"${activeIndex}\"]`), {\n block: 'nearest',\n });\n }, [activeIndex, isOpen, count]);\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLElement>) => {\n const lastIndex = count - 1;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActiveIndex(current => (current >= lastIndex ? 0 : current + 1));\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n setActiveIndex(current => (current <= 0 ? lastIndex : current - 1));\n break;\n\n case 'Home':\n event.preventDefault();\n setActiveIndex(0);\n break;\n\n case 'End':\n event.preventDefault();\n setActiveIndex(lastIndex);\n break;\n\n case ' ':\n case 'Enter': {\n /* Arama kutusunda BOSLUK bir KARAKTER: onu secime cevirmek \"fren\n balatasi\" yazmayi imkansiz kiliyordu. `Enter` her iki kipte de\n secer. */\n if (event.key === ' ' && !hasSpaceSelect) break;\n\n event.preventDefault();\n if (count > 0) onSelect(activeIndex);\n break;\n }\n\n case 'Escape':\n event.preventDefault();\n onClose();\n break;\n\n case 'Tab':\n /* Kapatir ama varsayilan gezinme SURER. */\n onClose();\n break;\n\n default:\n break;\n }\n },\n [activeIndex, count, hasSpaceSelect, onClose, onSelect],\n );\n\n return { activeIndex, setActiveIndex, listRef, handleKeyDown };\n};\n\nexport default useListboxNavigation;\n","'use client';\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\n/** Yüzeyin tercih ettiği kenar. Yer yoksa karşıtına düşer. */\nexport type PositionSide = 'top' | 'bottom' | 'left' | 'right';\n\n/** Tercih edilen kenar boyunca hizalama. */\nexport type PositionAlign = 'start' | 'center' | 'end';\n\nexport type PositioningOptions = {\n side?: PositionSide;\n align?: PositionAlign;\n /** Tetikleyici ile yüzey arasındaki boşluk (px). */\n offset?: number;\n /** Görünüm alanının kenarından bırakılacak asgari pay (px). */\n padding?: number;\n /** Kapalıyken ölçüm yapılmaz ve dinleyici kurulmaz. */\n isOpen: boolean;\n};\n\nexport type PositioningState = {\n /** Yüzeye uygulanacak stil — `position: fixed` + hesaplanmış koordinat. */\n style: { position: 'fixed'; top: number; left: number };\n /** ÇÖZÜLMÜŞ kenar: çarpışma yüzünden tercih edilenin karşıtı olabilir. */\n side: PositionSide;\n /** İlk ölçüm yapıldı mı. Yapılmadan çizilen yüzey sol üst köşede parlıyor. */\n isPositioned: boolean;\n};\n\nconst OPPOSITE: Record<PositionSide, PositionSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\n/** Bir sayıyı [min, max] aralığına kırpar. */\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\ntype Rect = { top: number; left: number; width: number; height: number };\n\n/** Verilen kenarda yüzeyin sol-üst köşesi nereye düşer. */\nconst place = (\n anchor: Rect,\n surface: { width: number; height: number },\n side: PositionSide,\n align: PositionAlign,\n offset: number,\n): { top: number; left: number } => {\n const isVertical = side === 'top' || side === 'bottom';\n\n /* Ana eksen: tetikleyicinin disinda, `offset` kadar uzakta. */\n const main = {\n top: anchor.top - surface.height - offset,\n bottom: anchor.top + anchor.height + offset,\n left: anchor.left - surface.width - offset,\n right: anchor.left + anchor.width + offset,\n }[side];\n\n /* Capraz eksen: hizalama. */\n const crossStart = isVertical ? anchor.left : anchor.top;\n const crossSize = isVertical ? anchor.width : anchor.height;\n const surfaceSize = isVertical ? surface.width : surface.height;\n\n const cross = {\n start: crossStart,\n center: crossStart + crossSize / 2 - surfaceSize / 2,\n end: crossStart + crossSize - surfaceSize,\n }[align];\n\n return isVertical ? { top: main, left: cross } : { top: cross, left: main };\n};\n\n/** Yüzey görünüm alanına sığıyor mu (yalnızca ana eksende). */\nconst fits = (\n position: { top: number; left: number },\n surface: { width: number; height: number },\n side: PositionSide,\n padding: number,\n viewport: { width: number; height: number },\n): boolean =>\n ({\n top: position.top >= padding,\n bottom: position.top + surface.height <= viewport.height - padding,\n left: position.left >= padding,\n right: position.left + surface.width <= viewport.width - padding,\n })[side];\n\n/**\n * ÇARPIŞMAYA DUYARLI KONUMLANDIRMA — `Tooltip`, `Popover`, `Menu` ve açılır\n * listelerin ortak temeli.\n *\n * <h3>Neden var: `position: absolute` yetmiyordu</h3>\n * `Tooltip` balonu tetikleyicinin içinde, `position: absolute` ile duruyordu.\n * Üç somut sonucu vardı:\n *\n * <ul>\n * <li><b>Kırpılma.</b> `overflow: hidden` taşıyan her kapsayıcı (kart,\n * tablo kaydırma kutusu, `Panel`) balonu kesiyordu. Bir tablo hücresinde\n * ipucu görünmüyordu — hiç.</li>\n * <li><b>Taşma.</b> Ekranın sağ kenarındaki bir tetikleyicinin balonu\n * görünüm alanının dışına çıkıyor, yatay kaydırma açıyordu.</li>\n * <li><b>Yığılma bağlamı.</b> `transform` taşıyan bir ata (`Card` hover\n * animasyonu) yeni bir yığılma bağlamı açıyor ve `z-index` orada\n * hapsoluyordu; balon kendi kartının altında kalıyordu.</li>\n * </ul>\n *\n * <p>Çözüm portal + `position: fixed`: yüzey gövdeye taşınır, koordinat\n * görünüm alanına göre hesaplanır. Kırpılacak bir kapsayıcı ve yarışılacak bir\n * yığılma bağlamı kalmaz.\n *\n * <h3>Neden yeni bir bağımlılık YOK</h3>\n * `floating-ui` bu işi yapıyor ve iyi yapıyor; ama paketin tek çalışma zamanı\n * bağımlılığının ikon seti olması bilinçli bir karar (bkz. README). Burada\n * ihtiyaç duyulan şey o kütüphanenin küçük bir alt kümesi: bir kenar, bir\n * hizalama ve karşıt kenara düşme. Ok konumlandırma, otomatik yerleşim\n * (`autoPlacement`), sanal öğe ve middleware zinciri gerekmiyor — ve\n * gerektiğinde eklenecek yer burası.\n *\n * <h3>CSS Anchor Positioning neden kullanılmıyor</h3>\n * Denendi ve BUGÜN kullanılamıyor: `anchor-name` / `position-anchor` yalnızca\n * Chromium'da var (Safari ve Firefox'ta bayrak arkasında bile değil). İki\n * kod yolu tutmak — biri modern tarayıcıda, biri yedekte — konumlandırmayı iki\n * kez yazmak ve ikisinin ayrışmasını beklemek demek. Ölçüm tabanlı yol her\n * yerde çalışıyor; tarayıcı desteği geldiğinde geçiş TEK dosyada.\n *\n * <h3>Ölçüm ne zaman yenileniyor</h3>\n * Açılışta, pencere yeniden boyutlandığında ve <em>herhangi bir atanın</em>\n * kaydırılmasında. Sonuncusu için `capture: true` ile belge düzeyinde tek bir\n * dinleyici: kaydırma olayı baloncuklanmıyor ve her ata için ayrı dinleyici\n * kurmak, derin bir ağaçta onlarca dinleyici demekti.\n */\nconst usePositioning = (\n anchorRef: { current: HTMLElement | null },\n surfaceRef: { current: HTMLElement | null },\n { side = 'top', align = 'center', offset = 8, padding = 8, isOpen }: PositioningOptions,\n): PositioningState => {\n const [state, setState] = useState<PositioningState>({\n style: { position: 'fixed', top: 0, left: 0 },\n side,\n isPositioned: false,\n });\n\n /* Olcum her karede yeniden planlanmasin: kaydirma sirasinda saniyede\n onlarca olay dusuyor ve her biri bir yerlesim okumasi. */\n const frameRef = useRef(0);\n\n const measure = useCallback(() => {\n const anchor = anchorRef.current;\n const surface = surfaceRef.current;\n if (!anchor || !surface) return;\n\n const anchorRect = anchor.getBoundingClientRect();\n const surfaceRect = surface.getBoundingClientRect();\n const viewport = { width: window.innerWidth, height: window.innerHeight };\n\n /*\n * KENAR SECIMI: tercih edilen kenar sigmiyorsa KARSITI denenir; o da\n * sigmiyorsa tercih edilene donulur ve kirpma devreye girer. Ucuncu bir\n * kenara (dikeyden yataya) atlamak YOK — bir ipucu bir anda saga zipladiginda\n * kullanici onu tetikleyiciyle iliskilendiremiyor.\n */\n const preferred = place(anchorRect, surfaceRect, side, align, offset);\n const resolvedSide = fits(preferred, surfaceRect, side, padding, viewport)\n ? side\n : fits(\n place(anchorRect, surfaceRect, OPPOSITE[side], align, offset),\n surfaceRect,\n OPPOSITE[side],\n padding,\n viewport,\n )\n ? OPPOSITE[side]\n : side;\n\n const placed = place(anchorRect, surfaceRect, resolvedSide, align, offset);\n\n /* Capraz eksende KIRPMA: ekranin sag ucundaki bir tetikleyicinin balonu\n disari tasmak yerine kenara yaslanir. */\n setState({\n style: {\n position: 'fixed',\n top: Math.round(clamp(placed.top, padding, viewport.height - surfaceRect.height - padding)),\n left: Math.round(clamp(placed.left, padding, viewport.width - surfaceRect.width - padding)),\n },\n side: resolvedSide,\n isPositioned: true,\n });\n }, [anchorRef, surfaceRef, side, align, offset, padding]);\n\n const schedule = useCallback(() => {\n if (frameRef.current) return;\n frameRef.current = window.requestAnimationFrame(() => {\n frameRef.current = 0;\n measure();\n });\n }, [measure]);\n\n /*\n * `useLayoutEffect`: olcum BOYAMADAN once yapilmali. `useEffect` ile\n * yuzey bir kare boyunca (0, 0) noktasinda — ekranin sol ust kosesinde —\n * cizilip sonra yerine ziplyordu.\n */\n const useIsomorphicLayoutEffect = isClient() ? useLayoutEffect : useEffect;\n\n useIsomorphicLayoutEffect(() => {\n if (!isOpen) {\n setState(current => (current.isPositioned ? { ...current, isPositioned: false } : current));\n return;\n }\n\n measure();\n\n window.addEventListener('resize', schedule);\n /* `capture: true` — kaydirma olayi BALONCUKLANMAZ; yakalama evresinde\n dinlemek, tetikleyicinin kaydirilan HER atasini tek dinleyiciyle\n kapsar. */\n document.addEventListener('scroll', schedule, true);\n\n /* Yuzeyin kendi olcusu degisebiliyor (icerik geldi, liste suzuldu) ve\n degistiginde konum yanlis kalir. */\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);\n if (observer && surfaceRef.current) observer.observe(surfaceRef.current);\n if (observer && anchorRef.current) observer.observe(anchorRef.current);\n\n return () => {\n window.removeEventListener('resize', schedule);\n document.removeEventListener('scroll', schedule, true);\n observer?.disconnect();\n\n if (frameRef.current) {\n window.cancelAnimationFrame(frameRef.current);\n frameRef.current = 0;\n }\n };\n }, [isOpen, measure, schedule, anchorRef, surfaceRef]);\n\n return state;\n};\n\nexport default usePositioning;\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type VirtualRange = {\n /** Çizilecek ilk öğenin dizini. */\n start: number;\n /** Çizilecek son öğenin dizini (dahil DEĞİL). */\n end: number;\n /** Listenin gerçek toplam yüksekliği — kaydırma çubuğu doğru boyda olmalı. */\n totalHeight: number;\n /** Görünen ilk öğenin üstünde bırakılacak boşluk. */\n offset: number;\n};\n\n/**\n * SANALLAŞTIRMA — yalnızca görünen satırları çiz.\n *\n * <h3>Ölçülen sorun</h3>\n * 1121 markalı bir `Combobox` listesinde DOM 1121 satır taşıyordu. Panel\n * açılışı mobilde gözle görülür şekilde donuyor, her tuş vuruşunda liste\n * yeniden çiziliyordu. Ekran okuyucu tarafında da bedeli var: 1121 öğelik bir\n * `listbox`ta gezinmek pratikte imkânsız.\n *\n * <h3>Neden kütüphane içinde</h3>\n * `react-window` / `@tanstack/virtual` bu işi yapıyor ve iyi yapıyor; ama\n * paketin tek çalışma zamanı bağımlılığının ikon seti olması bilinçli bir\n * karar. Burada gereken şey o kütüphanelerin küçük bir alt kümesi: SABİT\n * yükseklikli satırlar, tek eksen, yatay yok, değişken yükseklik yok.\n *\n * <h3>SABİT satır yüksekliği — ve bu bir kısıt</h3>\n * Değişken yükseklikli sanallaştırma her satırın ölçülmesini ve bir konum\n * haritası tutulmasını gerektiriyor. Açılır liste satırları zaten sabit\n * yükseklikte (`min-height` + tek satır metin); ikincil satır taşıyan\n * seçeneklerde ölçü `rowHeight` ile verilir.\n *\n * <h3>`overscan` neden var</h3>\n * Yalnızca görünen satırlar çizilseydi hızlı kaydırmada alt kenarda bir kare\n * boyunca boşluk görünüyordu — tarayıcı kaydırma olayını boyamadan sonra\n * veriyor. Görünür alanın üstüne ve altına birkaç satır fazladan çizilir.\n *\n * <h3>Klavye gezinmesiyle ilişkisi</h3>\n * Etkin seçeneği görünür tutan `scrollIntoView`, o seçenek ÇİZİLMEMİŞSE\n * çalışmaz. `scrollToIndex` bu yüzden var: klavyeyle listenin dibine giden\n * kullanıcı için konum önce hesaplanır, satır sonra çizilir.\n */\nconst useVirtualList = (\n count: number,\n { rowHeight = 40, overscan = 6, isEnabled = true } = {},\n) => {\n const scrollRef = useRef<HTMLElement | null>(null);\n const [range, setRange] = useState<VirtualRange>({\n start: 0,\n end: count,\n totalHeight: count * rowHeight,\n offset: 0,\n });\n\n const measure = useCallback(() => {\n const node = scrollRef.current;\n\n /*\n * KAPALIYKEN VE OLCUM YOKKEN TAM LISTE.\n *\n * Kutu daha olculmemisken (ilk kare, `display: none`) `clientHeight` 0\n * doner ve sifir satir cizilirdi: liste bir kare boyunca BOS gorunuyor,\n * ekran okuyucu da o karede \"0 secenek\" diyordu.\n */\n if (!isEnabled || !node || node.clientHeight === 0) {\n setRange({ start: 0, end: count, totalHeight: count * rowHeight, offset: 0 });\n return;\n }\n\n const visibleCount = Math.ceil(node.clientHeight / rowHeight);\n const first = Math.floor(node.scrollTop / rowHeight);\n\n const start = Math.max(0, first - overscan);\n const end = Math.min(count, first + visibleCount + overscan);\n\n setRange({ start, end, totalHeight: count * rowHeight, offset: start * rowHeight });\n }, [count, isEnabled, overscan, rowHeight]);\n\n useEffect(() => {\n const node = scrollRef.current;\n if (!node) return;\n\n measure();\n node.addEventListener('scroll', measure, { passive: true });\n\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure);\n observer?.observe(node);\n\n return () => {\n node.removeEventListener('scroll', measure);\n observer?.disconnect();\n };\n }, [measure]);\n\n /**\n * Verilen dizini görünür alana getirir.\n *\n * <p>`scrollIntoView` çizilmemiş bir satırda çalışmıyor; klavyeyle listenin\n * dibine giden kullanıcı için konum önce hesaplanmak zorunda.\n */\n const scrollToIndex = useCallback(\n (index: number) => {\n const node = scrollRef.current;\n if (!node || !isEnabled) return;\n\n const top = index * rowHeight;\n const bottom = top + rowHeight;\n\n if (top < node.scrollTop) node.scrollTop = top;\n else if (bottom > node.scrollTop + node.clientHeight)\n node.scrollTop = bottom - node.clientHeight;\n },\n [isEnabled, rowHeight],\n );\n\n return { scrollRef, range, scrollToIndex, measure };\n};\n\nexport default useVirtualList;\n","'use client';\n\nimport { useEffect } from 'react';\n\n/**\n * SAYFA KAYDIRMA KİLİDİ — sayaçlı, tek yerde.\n *\n * <h3>Neden bir kanca, neden bileşenin içinde iki satır değil</h3>\n * `Modal` ve `BottomSheet` kilidi kendi başlarına yazıyordu:\n *\n * <pre>\n * const previous = document.body.style.overflow;\n * document.body.style.overflow = 'hidden';\n * return () => { document.body.style.overflow = previous; };\n * </pre>\n *\n * <p>Tek pencerede doğru; İÇ İÇE iki pencerede değil. `Select` bir kip\n * pencerenin içinde açıldığında (`Modal` → `BottomSheet`) sıra şu:\n * dış pencere `''` kaydeder ve `hidden` yazar; iç panel `'hidden'` kaydeder ve\n * `hidden` yazar; iç panel kapanınca kaydettiği `'hidden'`i geri yazar — buraya\n * kadar tesadüfen doğru. Ama React sökme sırası her zaman bu değil: iki panel\n * aynı commit'te kapandığında DIŞ pencerenin temizliği önce koşabiliyor ve\n * `''` yazıyor; iç panel hâlâ açıkken kilit AÇILIYOR ve kullanıcı panelin\n * arkasındaki listeyi kaydırıyordu.\n *\n * <p>Sayaç bunu yapısal olarak imkânsız kılıyor: kilit ilk açılışta yazılır,\n * SON kapanışta kaldırılır, arada kim ne yaparsa yapsın.\n *\n * <h3>Kaydırma çubuğu ve yatay sıçrama</h3>\n * `overflow: hidden` kaydırma çubuğunu da götürüyor ve sayfa o çubuğun\n * genişliği kadar (macOS dışında ~15 px) YATAY OLARAK SIÇRIYOR: pencere\n * açılınca arkadaki bütün içerik sağa kayıyor, kapanınca geri geliyordu.\n * `scrollbar-gutter: stable` çubuğun yerini kalıcı olarak ayırıyor —\n * desteklemeyen tarayıcıda ölçülen genişlik dolgu olarak yazılıyor.\n *\n * <h3>iOS</h3>\n * Safari'de `overflow: hidden` gövdeyi durdurmaya YETMİYOR: dokunmatik\n * kaydırma arkadaki belgeye sızıyor (\"scroll chaining\"). Gövde\n * `position: fixed` ile sabitlenir ve kaydırma konumu `top` ile korunur;\n * kilit kalkarken tam olarak aynı yere geri dönülür — korunmasaydı pencere\n * kapandığında kullanıcı sayfanın başına düşerdi.\n *\n * @param isLocked Kilit bu örnek için etkin mi.\n */\n\n/* Kac tane acik panel var. Modul duzeyinde: kilit BELGENIN durumu, bir React\n agacinin degil. */\nlet lockCount = 0;\n\n/** Kilit yazılmadan önceki hâl — SON kapanışta buradan geri yüklenir. */\nlet previous: {\n overflow: string;\n position: string;\n top: string;\n width: string;\n paddingRight: string;\n scrollY: number;\n} | null = null;\n\n/** iOS Safari mi? Gövdeyi sabitleme bedeli yalnızca orada ödenir. */\nconst isIOS = (): boolean =>\n /iP(hone|ad|od)/.test(navigator.platform) ||\n (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);\n\nconst lock = (): void => {\n lockCount += 1;\n if (lockCount > 1) return;\n\n const { body, style: rootStyle } = { body: document.body, style: document.documentElement.style };\n const scrollY = window.scrollY;\n\n previous = {\n overflow: body.style.overflow,\n position: body.style.position,\n top: body.style.top,\n width: body.style.width,\n paddingRight: body.style.paddingRight,\n scrollY,\n };\n\n /*\n * Cubugun genisligi: `scrollbar-gutter` desteklenmiyorsa dolgu olarak\n * yazilir. Destekleniyorsa olcum 0 cikar ve dolgu yazilmaz.\n */\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n if (scrollbarWidth > 0) body.style.paddingRight = `${scrollbarWidth}px`;\n\n rootStyle.setProperty('scrollbar-gutter', 'stable');\n body.style.overflow = 'hidden';\n\n if (isIOS()) {\n body.style.position = 'fixed';\n body.style.top = `${-scrollY}px`;\n body.style.width = '100%';\n }\n};\n\nconst unlock = (): void => {\n lockCount = Math.max(0, lockCount - 1);\n if (lockCount > 0 || !previous) return;\n\n const { body } = document;\n const { scrollY } = previous;\n\n body.style.overflow = previous.overflow;\n body.style.position = previous.position;\n body.style.top = previous.top;\n body.style.width = previous.width;\n body.style.paddingRight = previous.paddingRight;\n document.documentElement.style.removeProperty('scrollbar-gutter');\n\n previous = null;\n\n /* Govde sabitlenmisken kaydirma konumu sifirlaniyor; geri yazilmazsa\n kullanici pencereyi kapattiginda sayfanin en basina duser. */\n window.scrollTo(0, scrollY);\n};\n\nconst useScrollLock = (isLocked = true): void => {\n useEffect(() => {\n if (!isLocked) return;\n\n lock();\n return unlock;\n }, [isLocked]);\n};\n\nexport default useScrollLock;\n","'use client';\n\nimport { useEffect } from 'react';\n\n/** Panelin kaplayabilecegi en fazla yukseklik — GORUNEN alanin yuksekligi. */\nconst HEIGHT_VAR = '--hanui-sheet-height';\n\n/** Panelin dibinin, yerlesim gorunum alaninin dibinden ne kadar yukarida duracagi. */\nconst INSET_VAR = '--hanui-sheet-inset-bottom';\n\n/*\n * Tek olcum, tek dinleyici.\n *\n * Ayni anda birden fazla alt sayfa acilabiliyor (filtre panelinin icindeki bir\n * secim kutusu gibi). Her biri kendi dinleyicisini kursaydi ayni karede ayni\n * degeri birkac kez yazacak, ustelik ustteki panel kapandiginda alttaki hala\n * acikken degiskenler silinecekti. Sayac sifirlanmadan hicbir sey kaldirilmaz.\n */\nlet openCount = 0;\nlet frame = 0;\n\n/**\n * Gorsel gorunum alanini olcup CSS degiskenlerine yazar.\n *\n * `window.innerHeight` YERLESIM gorunum alanidir: iOS'ta adres cubugu\n * daralmis kabul edilerek hesaplanir ve klavye onu hic kucultmez.\n * `visualViewport` ise gercekten GORUNEN alandir. Ikisinin farki, ekranin\n * dibinde kullanicinin goremedigi seridin yuksekligi: klavye, tarayicinin alt\n * cubugu ya da adres cubugu genisken asagi tasan bolum.\n *\n * `position: fixed; bottom: 0` yerlesim gorunum alanina gore hizalanir — yani\n * o seridin ALTINA. Panel bu yuzden dibinden kirpik goruluyordu; kisa bir\n * panel (alti secenekli bir liste) neredeyse yarisini kaybederken ekranin\n * cogunu kaplayan bir panel ayni kaymayi gorunur kilmiyordu.\n */\n/**\n * MAKUL EN KÜÇÜK GÖRÜNÜM ALANI.\n *\n * <p>Bunun altındaki bir ölçüm bir görünüm alanı değil, GEÇİCİ BİR HÂL:\n * klavye açılırken/kapanırken, sayfa arka plana alınıp geri gelirken ve\n * `<dialog>` üst katmana girerken `visualViewport.height` bir kare boyunca\n * absürt küçük değerler raporluyor.\n *\n * <p>ÖLÇÜLDÜ (`e2e` sondası): değişkene 120 px yazıldığında panelin tamamı\n * 96 px'e iniyor — 57 px başlık + <strong>39 px gövde</strong>, yani listenin\n * yarım satırı görünen bir kaydırma yarığı. Bu, gerçek cihazda bildirilen\n * hatanın birebir görüntüsü.\n */\nconst MIN_VIEWPORT_HEIGHT = 240;\n\nconst measure = () => {\n const viewport = window.visualViewport;\n if (!viewport) return;\n\n /*\n * ABSURT OLCUM YAZILMAZ.\n *\n * Once her deger kosulsuz yaziliyordu ve tek bir gecici kare paneli\n * kullanilamaz hale getirmeye yetiyordu. Daha kotusu KALICIYDI: yanlis\n * deger ancak bir sonraki `resize` ile duzeliyor, o olay gelmezse panel\n * kapanana kadar oyle kaliyordu.\n *\n * Olcum atlandiginda ONCEKI dogru deger yerinde kalir; hicbir olcum\n * yapilmadiysa CSS yedegi (`100dvh`) devrede.\n */\n if (viewport.height < MIN_VIEWPORT_HEIGHT) return;\n\n const covered = window.innerHeight - viewport.height - viewport.offsetTop;\n const root = document.documentElement;\n\n root.style.setProperty(INSET_VAR, `${Math.max(0, Math.round(covered))}px`);\n root.style.setProperty(HEIGHT_VAR, `${Math.round(viewport.height)}px`);\n};\n\n/**\n * Kare başına bir ölçüm: klavye açılırken `resize` ve `scroll` ard arda\n * düşüyor ve her ölçüm bir yerleşim okuması.\n *\n * <h3>Kare bayrağı NEDEN sıfırlanabilir olmak zorunda</h3>\n * Bayrak yalnızca `requestAnimationFrame` geri çağrısında sıfırlanıyordu.\n * O geri çağrı ÇALIŞMAYABİLİR: tarayıcı sekme arka plandayken kareleri\n * durduruyor, iOS bunu üst katman geçişlerinde de yapıyor. Kare hiç\n * gelmediğinde bayrak sonsuza kadar dolu kalıyor ve <strong>sonraki her\n * ölçüm sessizce atlanıyordu</strong> — panel, o an ne ölçüldüyse orada\n * donuyordu. Panel açılırken bayrak elle sıfırlanıyor (bkz. kancanın\n * gövdesi).\n */\nconst schedule = () => {\n if (frame) return;\n frame = window.requestAnimationFrame(() => {\n frame = 0;\n measure();\n });\n};\n\n/** Bekleyen kareyi iptal eder ve bayrağı serbest bırakır. */\nconst cancelScheduled = () => {\n if (!frame) return;\n window.cancelAnimationFrame(frame);\n frame = 0;\n};\n\n/**\n * Alt sayfayi <strong>gorunen</strong> alana yaslar.\n *\n * <h3>Neden `dvh` ve `env()` yetmiyor</h3>\n * `dvh` tarayici cubuklarini hesaba katar ama <em>klavyeyi katmaz</em>;\n * `env(safe-area-inset-bottom)` ise cihazin centik/ana ekran cubugu payidir, o\n * da klavyeden habersiz. iOS'ta klavye acildiginda yerlesim gorunum alani hic\n * degismez: panel oldugu yerde durur, klavye uzerine biner ve alt yarisi —\n * arama kutusuyla birlikte — erisilemez hale gelir.\n *\n * <h3>Android'de ne oluyor</h3>\n * Tuketici `interactiveWidget: 'resizes-content'` verdiginde orada klavye\n * yerlesim alanini da kuculttugu icin fark sifir cikar ve bu kanca hicbir sey\n * degistirmez. Duzeltme iOS icindir, ama olcum platformdan bagimsiz dogru.\n *\n * <h3>Degiskenler `<html>` uzerinde</h3>\n * Panelin kendisine yazilamaz: `::backdrop` ve `<dialog>` ust katmandadir,\n * ayrica ayni degeri iki farkli panel paylasiyor. Kok ogeye yazmak tek kaynak\n * birakir.\n *\n * @param isActive Panel acik mi. Yalnizca acikken olculur: kendisi yalnizca\n * acikken cizilen bir panel varsayilani kullanir, ama sayfa boyunca DOM'da\n * duran bir panel bayraksiz cagirdiginda her kullanicida iki gorunum alani\n * dinleyicisi bos yere acik kaliyordu.\n */\nconst useSheetViewport = (isActive = true) => {\n useEffect(() => {\n if (!isActive) return;\n\n const viewport = window.visualViewport;\n if (!viewport) return;\n\n openCount += 1;\n\n if (openCount === 1) {\n viewport.addEventListener('resize', schedule);\n viewport.addEventListener('scroll', schedule);\n window.addEventListener('orientationchange', schedule);\n }\n\n /*\n * Bekleyen kare IPTAL edilir ve olcum SENKRON yapilir.\n *\n * Onceki panelden kalmis, hicbir zaman calismamis bir kare bayragi\n * sonraki her olcumu susturuyordu (bkz. `schedule`). Panel her acildiginda\n * bayrak serbest birakiliyor ve deger o anda yeniden okunuyor: acilan\n * panel HER ZAMAN taze bir olcumle basliyor.\n */\n cancelScheduled();\n measure();\n\n return () => {\n openCount -= 1;\n if (openCount > 0) return;\n\n viewport.removeEventListener('resize', schedule);\n viewport.removeEventListener('scroll', schedule);\n window.removeEventListener('orientationchange', schedule);\n\n cancelScheduled();\n\n /* Degiskenler SILINIR, sifirlanmaz: yedek deger CSS'te\n (`var(…, 0px)` / `var(…, 100dvh)`) ve panel kapaliyken dogru olan o. */\n document.documentElement.style.removeProperty(INSET_VAR);\n document.documentElement.style.removeProperty(HEIGHT_VAR);\n };\n }, [isActive]);\n};\n\nexport default useSheetViewport;\n","/**\n * Düğme ve eylem varyantları.\n *\n * <p>Sıra bir <strong>vurgu hiyerarşisi</strong>dir: bir ekranda tek bir\n * `PRIMARY` bulunur. İki dolu düğme yan yana durduğunda hiçbiri öne çıkmaz ve\n * kullanıcı hangisinin beklenen eylem olduğunu bilemez.\n *\n * <h3>Doygun dolgu = tıklanabilir</h3>\n * Bu kuralın karşılığı: durum etiketleri (rozet, uyarı) her zaman tint\n * zeminlidir, eylemler her zaman dolgulu veya çerçevelidir. İkisi karışırsa\n * kullanıcı bir durum etiketine tıklamayı dener.\n */\nenum UIVariant {\n /**\n * Ekranın tek beklenen eylemi: <strong>nötr grafit</strong> dolgu.\n *\n * <p>`CART` DEĞİL. Doygun turuncu tek bir dönüşüm noktasına ayrıldı; her\n * dolu düğmeyi o renge boyamak tekilliği yok eder ve kullanıcı hangi\n * turuncunun dönüşüm olduğunu bilemez.\n */\n PRIMARY = 'PRIMARY',\n /**\n * <strong>Dönüşüm eylemi — ve yalnızca o.</strong>\n *\n * <p>Ekranda görünen tek doygun turuncu. Favori, karşılaştır, paylaş,\n * filtrele hepsi nötr veya mavidir. Bir kampanya bandında bu ton\n * kullanılırsa o ekranda dönüşüm düğmesi `PRIMARY`'ye çevrilir — ikisi aynı\n * anda olmaz.\n *\n * <p>Adı domain'den geliyor (kaynak sistemde \"sepete ekle\") ve\n * kasıtlı korundu: bir ekranda kaç tane olabileceğini adın kendisi\n * söylüyor. `ACCENT` deseydi hiyerarşi bilgisi kaybolurdu.\n */\n CART = 'CART',\n /** Nötr ikincil eylem: gri kenarlık, koyu metin (\"Vazgeç\"). */\n SECONDARY = 'SECONDARY',\n /**\n * Mavi çerçeveli eylem — teşvik edilen ama birincil olmayan gezinme\n * (\"Tümünü gör\").\n *\n * <p>Çerçeveli, dolgulu değil: mavi gezinme ve keşif rengidir; dolu mavi\n * düğme onu bir dönüşüm noktası gibi gösterip `CART` ile yarışıyordu.\n */\n OUTLINE = 'OUTLINE',\n /** Vurgu bandı içindeki eylem: bandın kendi yüzey merdivenini kullanır. */\n DARK = 'DARK',\n /** Nötr yüzey dolgusu; kart içi ikincil eylem. */\n LIGHT = 'LIGHT',\n /** Zeminsiz eylem: araç çubuğu ve satır içi ikincil işler. */\n GHOST = 'GHOST',\n /** Yıkıcı eylem: silme onayı. Durum tinti değil, gerçek bir dolgu. */\n DANGER = 'DANGER',\n}\n\nexport default UIVariant;\n","/**\n * Ölçü basamakları.\n *\n * <p>`MEDIUM` ve `LARGE` dokunma hedefi kuralına uyar (WCAG 2.5.8, ≥44 px).\n * `SMALL` yoğun şeritler içindir ve orada görsel kutu küçülür ama tıklanabilir\n * alan `tap-target` ile korunur.\n */\nenum UISize {\n SMALL = 'SMALL',\n MEDIUM = 'MEDIUM',\n LARGE = 'LARGE',\n}\n\nexport default UISize;\n","/**\n * Kırılma noktaları — `styles/_variables.scss` içindeki `$breakpoint-*` ile\n * <strong>aynı</strong> değerler.\n *\n * <p>Kararı normalde CSS verir; bu sabitler yalnızca <em>JavaScript'in de\n * bilmek zorunda olduğu</em> tek durum için var: kipsel bir panel\n * (`<dialog>`) açıkken pencere büyütüldüğünde. `showModal()` sayfanın geri\n * kalanını inert bırakır ve bu, panelin çizilip çizilmediğine değil kipsel\n * olmasına bağlıdır — CSS onu gizlese bile sayfa tıklanamaz kalır. Panel bu\n * yüzden kırılma noktası aşıldığında JavaScript ile kapatılır.\n *\n * <p>Değerler iki yerde durduğu için ayrışabilir. Ayrışırlarsa panel yanlış\n * genişlikte kapanır; CSS tarafı her zaman kazanır, buradaki değer ona\n * uydurulur.\n */\nexport const MOBILE_BREAKPOINT = 640;\n\nexport const TABLET_PORTRAIT_BREAKPOINT = 768;\n\nexport const TABLET_BREAKPOINT = 1024;\n\n/** Kenar çubuğu ekranda olduğu için filtre paneli bu ölçünün üstünde gizlenir. */\nexport const ABOVE_TABLET_MEDIA_QUERY = `(min-width: ${TABLET_BREAKPOINT + 1}px)`;\n\n/** Seçim kutusunun alt sayfası yalnızca bu ölçünün altında kullanılır. */\nexport const ABOVE_MOBILE_MEDIA_QUERY = `(min-width: ${MOBILE_BREAKPOINT + 1}px)`;\n","/**\n * Metin normalizasyonu — aksan ve büyük/küçük harf duyarsız arama.\n *\n * <p>{@link matchesSearch} `Combobox`ın yerel filtresidir. Sunucu araması\n * (`onSearch`) verildiğinde bileşen hiç filtrelemez; bu yol yalnızca elde\n * duran bir listeyi taramak için.\n */\n\n/**\n * Serbest metin arama anahtarı: ASCII, küçük harf, tek boşlukla ayrılmış.\n *\n * <h3>Neden aksan sökülüyor</h3>\n * Kullanıcı \"sisli\" yazdığında \"Şişli\" bulunmalı. Doğru aksanı yakalamak\n * zorunda kalmak — özellikle mobil klavyede — aramayı bitiren bir sürtünme.\n *\n * <h3>Türkçe `İ` özel durumu</h3>\n * `toLowerCase()`ten <em>önce</em> `İ → i` eşlenir: varsayılan küçültme\n * \"İSTANBUL\"u \"i̇stanbul\" (birleşik nokta ile) yapıyor ve eşleşmeyi\n * kaçırıyordu. Aynı sorun `ı` için ters yönde yok — o zaten tek kod noktası.\n *\n * <p>Latin-1 aksanları (`é`, `ñ`, `ü`…) `NFD` ayrıştırması + birleştirici\n * işaret temizliğiyle sökülür; Türkçe harfler bu yolla çözülmediği için\n * (`ı` ve `İ` ayrı kod noktaları) önce elle eşlenir.\n */\nexport const normalizeSearchTerm = (value: string): string =>\n value\n .replace(/İ/g, 'i')\n .replace(/I/g, 'i')\n .replace(/ı/g, 'i')\n .toLowerCase()\n .normalize('NFD')\n /* Birlestirici aksan isaretleri (U+0300–U+036F). */\n .replace(/[\\u0300-\\u036f]/g, '')\n /* NFD'nin ayristirmadigi harfler: her biri tek kod noktasi. */\n .replace(/ş/g, 's')\n .replace(/ğ/g, 'g')\n .replace(/ç/g, 'c')\n .replace(/ø/g, 'o')\n .replace(/æ/g, 'ae')\n .replace(/ß/g, 'ss')\n .replace(/đ/g, 'd')\n .replace(/ł/g, 'l')\n .replace(/\\s+/g, ' ')\n .trim();\n\n/**\n * Aranan metin, hedefin içinde geçiyor mu?\n *\n * <p>Aramanın tek kapısı burasıdır: her liste kendi `includes` çağrısını\n * yazdığında biri normalizasyonu atlıyor ve o listede aksanlı arama\n * çalışmıyordu.\n */\nexport const matchesSearch = (haystack: string, needle: string): boolean =>\n normalizeSearchTerm(haystack).includes(normalizeSearchTerm(needle));\n","/**\n * Kipsel panel açılırken ekran klavyesinin kendiliğinden açılmasını engeller.\n *\n * <h3>Sorun</h3>\n * `showModal()` odağı panelin <strong>ilk odaklanabilir öğesine</strong> taşır\n * (HTML \"dialog focusing steps\"). O öğe bir metin alanıysa telefonda klavye\n * kendiliğinden açılır: alt sayfa yarı yüksekliğe sıkışır, liste kısalır ve\n * kullanıcı yazmak istemediği hâlde önce klavyeyi kapatmak zorunda kalır.\n *\n * <h3>Neden odak tümüyle bırakılmıyor</h3>\n * Odağı panelin dışında bırakmak kip semantiğini bozar: odak tuzağı çalışmaz,\n * Escape panele ulaşmaz ve ekran okuyucu paneli hiç duyurmaz. Odak panelin\n * KENDİSİNE alınır — kip davranışı durur, klavye açılmaz.\n */\n\n/** Odaklanınca ekran klavyesi AÇMAYAN giriş türleri. */\nconst NON_TEXT_INPUT_TYPES = new Set([\n 'button',\n 'checkbox',\n 'color',\n 'file',\n 'hidden',\n 'image',\n 'radio',\n 'range',\n 'reset',\n 'submit',\n]);\n\n/** Odaklanınca mobilde ekran klavyesini açacak bir öğe mi? */\nexport const isKeyboardOpeningElement = (element: Element | null): boolean => {\n if (!(element instanceof HTMLElement)) return false;\n\n /* `isContentEditable` mirasi da kapsar (duzenlenebilir bolgenin ICINDEKI\n oge), ama jsdom onu uygulamiyor ve her zaman false donuyor; oznitelik\n kontrolu testte de gecerli olan yedek. */\n if (element.isContentEditable) return true;\n const editable = element.getAttribute('contenteditable');\n if (editable === '' || editable === 'true' || editable === 'plaintext-only') return true;\n\n const tagName = element.tagName;\n if (tagName === 'TEXTAREA') return true;\n if (tagName !== 'INPUT') return false;\n\n return !NON_TEXT_INPUT_TYPES.has((element as HTMLInputElement).type);\n};\n\n/**\n * `showModal()` ÇAĞRILDIKTAN SONRA çağrılır. Odak bir metin alanına düştüyse\n * panelin kendisine geri alınır; düşmediyse hiçbir şey yapılmaz.\n */\nexport const preventAutoKeyboard = (dialog: HTMLDialogElement): void => {\n const active = dialog.ownerDocument.activeElement;\n if (!dialog.contains(active) || !isKeyboardOpeningElement(active)) return;\n\n (active as HTMLElement).blur();\n // `<dialog>` varsayılan olarak odaklanabilir değil; odağı alabilmesi için\n // sıra dışı bırakılır (Tab ile gezinmede görünmez, `focus()` ile alınır).\n dialog.tabIndex = -1;\n dialog.focus({ preventScroll: true });\n};\n\n/**\n * ODAK GERİ DÖNÜŞÜ.\n *\n * <p>Kipsel bir yüzey kapandığında odak, onu AÇAN öğeye dönmeli. Dönmezse\n * odak `<body>`ye düşer ve klavye kullanıcısı sayfanın en başına gider —\n * yirmi kez Tab'ladığı bir listede seçim yapan kullanıcı, seçimden sonra\n * yeniden yirmi kez Tab'lamak zorunda kalıyordu.\n *\n * <p>Açan öğeyi çağıranın hatırlaması gerekiyor: kapanış anında\n * `document.activeElement` çoktan panelin içindeki bir şey. {@link captureFocus}\n * açılışta çağrılır, döndürdüğü fonksiyon kapanışta.\n *\n * @returns Odağı geri veren fonksiyon.\n */\nexport const captureFocus = (): (() => void) => {\n const previous = typeof document === 'undefined' ? null : document.activeElement;\n\n return () => {\n if (!(previous instanceof HTMLElement)) return;\n\n /*\n * Oge hala BELGEDE mi: acan dugme, panel kapanirken DOM'dan kalkmis\n * olabilir (bir satiri silen onay penceresi, satirla birlikte dugmeyi de\n * goturuyor). Kalkmis bir ogeye `focus()` sessizce hicbir sey yapmiyor ve\n * odak yine `<body>`ye dusuyordu; cagiran taraf bunu bilip alternatif bir\n * hedef verebilmeli.\n */\n if (!previous.isConnected) return;\n\n /* `preventScroll` — odaklanan oge gorunum alaninin disindaysa tarayici\n sayfayi oraya kaydiriyor ve kullanici kapattigi pencerenin yerine bambaska\n bir yere bakiyordu. */\n previous.focus({ preventScroll: true });\n };\n};\n\n/** Odaklanabilir öğelerin seçicisi — `inert` ve `disabled` olanlar hariç. */\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not(:disabled)',\n 'input:not(:disabled)',\n 'select:not(:disabled)',\n 'textarea:not(:disabled)',\n '[tabindex]:not([tabindex=\"-1\"])',\n]\n .map(selector => `${selector}:not([inert]):not([aria-hidden=\"true\"])`)\n .join(', ');\n\n/**\n * Panelin İLK ANLAMLI öğesine odaklanır.\n *\n * <h3>\"Anlamlı\" ne demek: kapatma düğmesi DEĞİL</h3>\n * `showModal()` odağı DOM sırasındaki ilk odaklanabilir öğeye taşıyor ve o\n * öğe neredeyse her zaman başlıktaki kapatma düğmesi oluyor. Ekran okuyucu\n * pencereyi \"Kapat, düğme\" diye açıyor — kullanıcının duyduğu ilk şey,\n * pencerenin ne olduğu değil ondan nasıl kaçılacağı.\n *\n * <p>Bu fonksiyon `[data-hanui-autofocus]` işaretli öğeyi arar, yoksa\n * kapatma düğmesi DIŞINDAKİ ilk odaklanabilir öğeyi, o da yoksa panelin\n * kendisini odaklar. Panelin kendisi son çare: odağı panelin dışında bırakmak\n * kip semantiğini bozar (odak tuzağı çalışmaz, `Escape` panele ulaşmaz).\n *\n * @param container Odak aranacak kök.\n * @param skipSelector Atlanacak öğe (varsayılan: kapatma düğmesi).\n */\nexport const focusFirstMeaningful = (\n container: HTMLElement,\n skipSelector = '[data-hanui-close]',\n): void => {\n const explicit = container.querySelector<HTMLElement>('[data-hanui-autofocus]');\n if (explicit) {\n explicit.focus({ preventScroll: true });\n return;\n }\n\n const candidates = [...container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)];\n const target = candidates.find(element => !element.matches(skipSelector)) ?? candidates[0];\n\n if (target) {\n target.focus({ preventScroll: true });\n return;\n }\n\n container.tabIndex = -1;\n container.focus({ preventScroll: true });\n};\n\n/**\n * KİPSEL YIĞIN — üst üste binen paneller.\n *\n * <p>Aynı anda iki kipsel yüzey açılabiliyor: bir onay penceresinin içindeki\n * seçim kutusu, filtre panelinin içindeki alt sayfa. `<dialog>` üst katmanda\n * (top layer) yaşadığı için görsel sıra tarayıcıdan geliyor — ama `Escape`\n * ve odak geri dönüşü İKİSİNE de ulaşıyordu: bir `Escape` her iki paneli\n * birden kapatıyordu.\n *\n * <p>Yığın, \"en üstteki kim\" sorusuna tek bir cevap veriyor. Kapanış olayını\n * yalnızca en üstteki işler.\n */\nconst modalStack: symbol[] = [];\n\n/** Yığına katılır; dönen fonksiyon çıkarır. */\nexport const pushModal = (): { token: symbol; pop: () => void } => {\n const token = Symbol('hanui-modal');\n modalStack.push(token);\n\n return {\n token,\n pop: () => {\n const index = modalStack.indexOf(token);\n if (index >= 0) modalStack.splice(index, 1);\n },\n };\n};\n\n/** Verilen panel yığının EN ÜSTÜNDE mi. */\nexport const isTopModal = (token: symbol): boolean => modalStack[modalStack.length - 1] === token;\n\n/** Yalnızca test içindir: modül düzeyindeki yığın testler arasında sızmamalı. */\nexport const resetModalStack = (): void => {\n modalStack.length = 0;\n};\n","/** Sınıf birleştiricinin kabul ettiği değerler. */\nexport type ClassValue = string | false | null | undefined;\n\n/**\n * Sınıf adı birleştirici.\n *\n * <h3>Neden `clsx` değil</h3>\n * Kaynak tasarım sistemi `clsx` kullanıyordu ve orada doğruydu — bir\n * uygulamada 500 baytlık bir bağımlılık bedava. Bir <em>kütüphanede</em> aynı\n * bağımlılık tüketicinin ağacına ineriyor ve `clsx`ın desteklediği yedi\n * girdi biçiminden (nesne, iç içe dizi, sayı…) burada yalnızca ikisi\n * kullanılıyor: dize ve koşullu dize.\n *\n * <p>Bilerek DAR: nesne biçimi (`{ active: true }`) desteklenmez. Desteklemek\n * çağrı yerlerinde iki ayrı yazım stiline yol açıyor ve hangisinin kullanıldığı\n * dosyadan dosyaya değişiyordu.\n */\nexport const cx = (...values: ClassValue[]): string => {\n let result = '';\n\n for (const value of values) {\n if (!value) continue;\n result = result === '' ? value : `${result} ${value}`;\n }\n\n return result;\n};\n","/**\n * DevTools adı — modül düzeyinde YAN ETKİ bırakmadan.\n *\n * <h3>Neden `X.displayName = 'X'` değil</h3>\n * Bileşenler `memo(forwardRef(…))` ile dışa veriliyor ve bu sarmalayıcıların\n * kendi adı yok: React DevTools onları \"Memo(ForwardRef)\" diye gösterir. Ad bu\n * yüzden ayrıca yazılıyordu — ama modül düzeyindeki bir ÖZELLİK ATAMASI\n * bundler için yan etkili bir ifade ve silinemez.\n *\n * <p>ÖLÇÜLDÜ (`npm run size`): yalnızca `Badge` import eden bir uygulama\n * <strong>20,7 kB</strong> indiriyordu — paketin tamamı 21,8 kB. Yirmi tane\n * `displayName` ataması, zincirleriyle birlikte neredeyse her bileşeni ayakta\n * tutuyordu: `Button.displayName = 'Button'` satırı `Button`ı, o da\n * `Spinner`ı, `HanuiLink`i ve sınıf yardımcısını çağırıyor. Ağaç sallama\n * \"çalışmıyor\" değildi; sallanacak dal bırakılmamıştı.\n *\n * <p>Atama bir ÇAĞRIYA dönüştüğünde `/*#__PURE__*` işaretlenebiliyor ve\n * kullanılmayan bileşenle birlikte adı da düşüyor. Aynı ölçüm sonrasında:\n * `Badge` 2,71 kB, `Button` 3,34 kB.\n *\n * <p>Alternatif — iç fonksiyonu adlandırmak\n * (`forwardRef(function Button(…) {…})`) — de doğru olurdu ve yan etkisi yok;\n * yirmi bileşende ok fonksiyonunu gövdeli fonksiyona çevirmek, ölçülen kazancı\n * değiştirmeyen ama her dosyayı elleyen bir değişiklik olurdu. Tek satırlık bu\n * yardımcı aynı sonucu veriyor.\n *\n * @example\n * export default memo(named(Button, 'Button')) as typeof Button;\n */\nexport const named = <TComponent extends object>(\n component: TComponent,\n displayName: string,\n): TComponent => Object.assign(component, { displayName });\n","'use client';\n\nimport type { AnchorHTMLAttributes, FC } from 'react';\n\nimport { useHanui } from '../../theme/context';\nimport type { HanuiLinkProps } from '../../types/link.type';\n\n/**\n * Kütüphanenin İÇ bağlantı öğesi.\n *\n * <p>Sağlayıcıya bir `linkComponent` verilmişse ona, verilmemişse ham `<a>`ya\n * çizilir. Böylece bir bağlantı taşıyan her bileşen (`Button href`, `Chip`,\n * `Breadcrumb`, `Pagination`, `TextLink`, `Directory`, `Tile`) yönlendirici\n * kararını TEK yerden alır.\n *\n * <p>Bileşenler bunu doğrudan dışa vermez: tüketici zaten kendi Link'ini\n * kullanır. Dışa vermek \"hanui'nin Link'i\" diye üçüncü bir kavram üretirdi.\n *\n * <h3>Neden `forwardRef` değil</h3>\n * `HanuiLinkProps` yönlendiriciye özgü ek props için bir indeks imzası\n * taşıyor ve `forwardRef`in `PropsWithoutRef` eşlemesi o imzayı açıkça\n * bildirilmiş `children`ın üstüne geçirip tipini `unknown`a düşürüyordu. Ref'e\n * ihtiyaç da yok: hiçbir çağrı yeri bu öğeye ref vermiyor, verecek olan\n * tüketicinin kendi Link'i.\n */\nconst HanuiLink: FC<HanuiLinkProps> = ({ children, ...rest }) => {\n const { linkComponent: LinkComponent } = useHanui();\n\n if (LinkComponent) return <LinkComponent {...(rest as HanuiLinkProps)}>{children}</LinkComponent>;\n\n /*\n * Yonlendirici yoksa ham `<a>`. `rest` indeks imzasi tasiyor (yonlendiriciye\n * ozgu props icin); DOM'a giderken anchor sozlesmesine daraltilir —\n * tanimadigi bir ozniteligi React zaten oldugu gibi geciriyor.\n */\n return <a {...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}>{children}</a>;\n};\n\nexport default HanuiLink;\n","/**\n * Metin çözümlemesi: prop → sağlayıcı config'i → geliştirme uyarısı.\n *\n * <p>Sözleşme `theme/labels.ts` içinde anlatıldı. Buradaki tek iş, eksik bir\n * metni SESSİZ bırakmamak: `aria-label`ı olmayan bir kapatma düğmesi ekran\n * okuyucuda \"düğme\" diye okunur ve bu, ekranda hiçbir iz bırakmayan bir\n * erişilebilirlik hatası. Derleyici bunu göremiyor (sağlayıcı çalışma\n * zamanında), o yüzden geliştirme kipinde konsola iniyor.\n */\n\n/*\n * Uyari ANAHTAR BASINA bir kez verilir.\n *\n * Uyari her render'da yazilsaydi, listedeki yirmi satirin her biri icin ayni\n * satir konsola dusuyor ve gercek hatalar o gurultunun icinde kayboluyordu.\n */\nconst warned = new Set<string>();\n\n/** Uyarı durumu testler arasında sızmamalı; her test kendi durumundan başlar. */\nexport const resetLabelWarnings = (): void => warned.clear();\n\n/**\n * Verilen metni çözer.\n *\n * @param key Uyarıda gösterilecek yol (`Modal.closeLabel`).\n * @param values Öncelik sırasına göre adaylar: prop önce, config sonra.\n */\nexport const resolveLabel = (key: string, ...values: (string | undefined)[]): string => {\n for (const value of values) if (value !== undefined) return value;\n\n if (process.env.NODE_ENV !== 'production' && !warned.has(key)) {\n warned.add(key);\n console.error(\n `[hanui] Eksik metin: ${key}. Prop olarak geçin ya da ` +\n '<HanuiProvider labels={…}> içinde bir kez tanımlayın. ' +\n 'Metinsiz bırakılan öğe ekran okuyucuda adsız kalır.',\n );\n }\n\n return '';\n};\n\n/**\n * Biçimlendirici çözümü — değere bağlı metinler için.\n *\n * <p>`CopyField`in \"SP-123 kopyala\"sı ve `Rating`in \"5 üzerinden 4,5\"i bir\n * dize olamaz: içine değer giriyor. Config bir fonksiyon taşır.\n */\nexport const resolveFormatter = <TArgs extends unknown[]>(\n key: string,\n formatter: Formatter<TArgs> | undefined,\n ...args: TArgs\n): string => {\n if (formatter) return formatter(...args);\n\n return resolveLabel(key);\n};\n\ntype Formatter<TArgs extends unknown[]> = (...args: TArgs) => string;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n size?: 'sm' | 'md' | 'lg';\n /**\n * Ekran okuyucuya okunacak metin; görsel olarak gizli.\n *\n * <p>Verilmezse `labels.loading` okunur. Boş dizeye BİLİNÇLİ olarak izin\n * verilir: göstergenin <em>zaten adı olan</em> bir öğenin içinde durduğu\n * yerlerde (yükleniyor durumundaki bir düğme) duyurmak tekrar üretiyor.\n * `label=\"\"` orada doğru olan ve config'i de bastırır.\n */\n label?: string;\n className?: string;\n};\n\n/**\n * Yükleme göstergesi.\n *\n * <p>İskelet (`Skeleton`) tercih edilir; bu bileşen yalnızca <em>şekli\n * bilinmeyen</em> bir bekleme için — düğme içi işlem veya belirsiz süreli bir\n * sorgu gibi.\n */\nconst Spinner: FC<Props> = ({ size = 'md', label, className }) => {\n const { labels } = useHanui();\n\n return (\n <span className={cx(styles.spinner, styles[`spinner--${size}`], className)} role=\"status\">\n <span className={styles.spinner__label}>\n {label ?? resolveLabel('Spinner.label', labels?.loading)}\n </span>\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Spinner) as typeof Spinner;\n","'use client';\n\nimport { type ButtonHTMLAttributes, forwardRef, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport type { CommonElementProps } from '../../types/common-element-props.type';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\nimport Spinner from '../Spinner';\n\nimport styles from './index.module.scss';\n\ntype BaseProps = Partial<{\n variant: UIVariant;\n size: UISize;\n isLoading: boolean;\n isFullWidth: boolean;\n startIcon: ReactNode;\n endIcon: ReactNode;\n}> &\n CommonElementProps;\n\ntype Props = BaseProps &\n ButtonHTMLAttributes<HTMLButtonElement> & {\n /** Verilirse düğme bir bağlantı olarak çizilir. */\n href?: string;\n /**\n * Uygulama dışına çıkan bağlantı: yeni sekmede açılır ve yönlendirici\n * devreye girmez.\n */\n isExternal?: boolean;\n /** Yönlendiriciye geçirilecek ek props (`{ scroll: false }`, `{ replace: true }`). */\n linkProps?: HanuiLinkExtraProps;\n };\n\n/**\n * Düğme.\n *\n * <h3>Yüklenirken içerik korunur</h3>\n * Metin dönen çarkla DEĞİŞTİRİLMEZ, yanına eklenir ve düğme genişliği\n * sabitlenir. Metni değiştirmek düğmeyi daraltıp yerleşimi kaydırıyordu ve\n * kullanıcı neye tıkladığını kaybediyordu.\n *\n * <h3>Bağlantı mı düğme mi</h3>\n * `href` verilirse `<a>` çizilir. Görsel olarak düğme gibi duran bir\n * bağlantının gerçekten `<a>` olması gerekir: orta tuşla yeni sekmede\n * açılması ve tarayıcı geçmişine girmesi beklenen davranıştır.\n *\n * <p>`isExternal` ile birlikte yönlendirici DEĞİL ham `<a>` çizilir ve\n * `target=\"_blank\"` + `rel=\"noopener noreferrer\"` eklenir. Uygulama dışı bir\n * adres için yönlendiriciyi araya sokmak anlamsız; `rel` ise zorunlu —\n * `noopener` olmadan açılan sekme `window.opener` üzerinden bu sayfaya\n * erişebiliyor. Düğme benzeri dış bağlantı elle `<a>` olarak yazılmasın diye\n * burada: elle yazılan her bağlantı odak halkasını ve durum matrisini yeniden\n * kurmak zorunda kalıyordu.\n *\n * @example\n * <Button variant={UIVariant.PRIMARY} isLoading={isSaving} onClick={save}>\n * Kaydet\n * </Button>\n */\nconst Button = /*#__PURE__*/ forwardRef<HTMLButtonElement, Props>(\n (\n {\n variant = UIVariant.PRIMARY,\n size = UISize.MEDIUM,\n isLoading,\n isFullWidth,\n startIcon,\n endIcon,\n className,\n children,\n disabled,\n href,\n isExternal,\n linkProps,\n testId,\n ...rest\n },\n ref,\n ) => {\n const classNames = cx(\n styles.button,\n styles[`button--${variant.toLowerCase()}`],\n styles[`button--${size.toLowerCase()}`],\n isFullWidth && styles['button--full'],\n isLoading && styles['button--loading'],\n className,\n );\n\n const content = (\n <>\n {isLoading && <Spinner size=\"sm\" className={styles.button__spinner} label=\"\" />}\n {!isLoading && startIcon && <span className={styles.button__icon}>{startIcon}</span>}\n <span className={styles.button__label}>{children}</span>\n {endIcon && <span className={styles.button__icon}>{endIcon}</span>}\n </>\n );\n\n if (href && isExternal)\n return (\n <a\n href={href}\n className={classNames}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={rest['aria-label']}\n data-testid={testId}\n >\n {content}\n </a>\n );\n\n if (href)\n return (\n <HanuiLink href={href} className={classNames} data-testid={testId} {...linkProps}>\n {content}\n </HanuiLink>\n );\n\n return (\n <button\n ref={ref}\n className={classNames}\n disabled={disabled || isLoading}\n aria-busy={isLoading}\n data-testid={testId}\n {...rest}\n >\n {content}\n </button>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Button, 'Button')) as typeof Button;\n","'use client';\n\nimport { type ButtonHTMLAttributes, forwardRef, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\nexport type IconButtonVariant = 'ghost' | 'outline' | 'solid' | 'cart' | 'danger';\n\ntype Props = ButtonHTMLAttributes<HTMLButtonElement> & {\n icon: ReactNode;\n /** Görsel etiketi olmayan düğmenin erişilebilir adı — ZORUNLU. */\n label: string;\n /**\n * `cart` <strong>yalnızca dönüşüm eyleminde</strong> kullanılır — ekranda\n * görünen tek doygun turuncu odur. Nötr dolgu için `solid`.\n */\n variant?: IconButtonVariant;\n size?: 'sm' | 'md';\n /** Verilirse öğe bir bağlantı olarak çizilir. */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n testId?: string;\n};\n\n/**\n * Yalnızca ikon taşıyan düğme.\n *\n * <p>`label` <strong>zorunlu</strong>: görsel etiketi olmayan bir düğme\n * `aria-label` olmadan ekran okuyucuda \"düğme\" diye okunur. Zorunlu tutmak,\n * unutulmasını derleme zamanında engeller.\n *\n * <p>Dokunma hedefi 44×44 px'ten küçük olamaz (WCAG 2.5.8) — görsel kutu daha\n * küçük olsa bile tıklanabilir alan korunur.\n *\n * <h3>`href` verilince `<a>` çizilir</h3>\n * Bir tablo satırının \"düzenle\" simgesi görsel olarak düğme ama davranışı\n * bağlantı: orta tuşla yeni sekmede açılması, adresinin kopyalanabilmesi ve\n * tarayıcı geçmişine girmesi beklenen davranış. `onClick` + `router.push` ile\n * yazıldığında bunların hiçbiri çalışmıyordu.\n *\n * <p>Bağlantı kipinde `disabled` YOKTUR — `<a>` etiketinin devre dışı hâli\n * yok ve `aria-disabled` tıklamayı engellemez. Erişilemez olması gereken bir\n * eylem hiç çizilmez.\n */\nconst IconButton = /*#__PURE__*/ forwardRef<HTMLButtonElement, Props>(\n (\n {\n icon,\n label,\n variant = 'ghost',\n size = 'md',\n className,\n type = 'button',\n href,\n linkProps,\n testId,\n ...rest\n },\n ref,\n ) => {\n const classNames = cx(\n styles.iconButton,\n styles[`iconButton--${variant}`],\n styles[`iconButton--${size}`],\n className,\n );\n\n if (href)\n return (\n <HanuiLink\n href={href}\n className={classNames}\n aria-label={label}\n title={rest.title ?? label}\n data-testid={testId}\n {...linkProps}\n >\n {icon}\n </HanuiLink>\n );\n\n return (\n <button\n ref={ref}\n type={type}\n className={classNames}\n aria-label={label}\n title={label}\n data-testid={testId}\n {...rest}\n >\n {icon}\n </button>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(IconButton, 'IconButton'),\n) as typeof IconButton;\n","import { type AnchorHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { ArrowRight } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {\n href: string;\n children: ReactNode;\n /** Sonda ok gösterilir — \"devam et\" anlamı taşıyan bağlantılarda. */\n hasArrow?: boolean;\n tone?: 'brand' | 'muted';\n size?: 'sm' | 'md';\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n};\n\n/**\n * Metin bağlantısı.\n *\n * <h3>Ok bir süs değil</h3>\n * Sondaki ok yalnızca <em>gezinme</em> bağlantılarında kullanılır (\"Tümünü gör\n * →\"). Bir eylemi tetikleyen bağlantıya ok koymak, kullanıcıya başka bir\n * sayfaya gideceğini söyler ve beklentiyi yanıltır.\n *\n * <p>Ok, üzerine gelindiğinde <strong>ilerler</strong>: hareket, bağlantının\n * götürdüğü yönü fiziksel olarak sezdirir.\n *\n * <h3>Alt çizgi hover'da eklenir, kaldırılmaz</h3>\n * Sürekli altı çizili bağlantılar yoğun bir liste sayfasında görsel gürültü\n * yaratıyordu. Ama alt çizginin <em>hiç</em> olmaması bağlantıyı düz metinden\n * ayırt edilemez kılar; renk tek başına yeterli değil (WCAG 1.4.1). Çözüm:\n * renk her zaman, alt çizgi etkileşimde.\n */\nconst TextLink = ({\n href,\n children,\n hasArrow,\n tone = 'brand',\n size = 'md',\n className,\n linkProps,\n ...rest\n}: Props) => (\n <HanuiLink\n href={href}\n className={cx(styles.link, styles[`link--${tone}`], styles[`link--${size}`], className)}\n {...linkProps}\n {...rest}\n >\n <span className={styles.link__label}>{children}</span>\n {/*\n * Ok DOLU DEĞİL: Bootstrap Icons'ta uzun okun dolu bir eşi yok ve dolu\n * caret bir \"devam\" oku değil, bir açılır menü işareti okunuyor.\n */}\n {hasArrow && <ArrowRight aria-hidden className={styles.link__arrow} />}\n </HanuiLink>\n);\n\nexport default /*#__PURE__*/ memo(TextLink) as typeof TextLink;\n","'use client';\n\nimport {\n memo,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport usePositioning, { type PositionSide } from '../../hooks/usePositioning';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Balonda gösterilecek açıklama. */\n content: ReactNode;\n /** Açıklamanın bağlandığı öğe — düğme, ikon, etiket. */\n children: ReactNode;\n /**\n * Tercih edilen kenar. Yer yoksa KARŞITINA düşer; üçüncü bir kenara\n * atlamaz (bkz. `usePositioning`).\n */\n side?: PositionSide;\n /**\n * Açılma gecikmesi (ms). Fare bir araç çubuğunun üzerinden geçerken sıfır\n * gecikme, art arda beş balon açıp kapatıyordu.\n */\n openDelay?: number;\n /**\n * @deprecated `side` kullanın. Bu prop bir sonraki büyük sürümde kalkacak.\n *\n * <p>Ad değişti çünkü davranış değişti: `position` SABİT bir kenar\n * yazıyordu ve balon oraya sığmadığında görünüm alanının dışına taşıyordu.\n * `side` yalnızca TERCİH — yer yoksa karşıt kenara düşülüyor. Aynı adı\n * korumak, artık doğru olmayan bir sözü sürdürmek olurdu.\n */\n position?: 'top' | 'bottom';\n className?: string;\n};\n\n/** Balonun kapanmadan önce beklediği süre — imlecin balona ulaşması için. */\nconst CLOSE_DELAY = 120;\n\n/** Dokunmatikte balonu açan basma süresi. Daha kısası kaydırma jestini yakalıyordu. */\nconst LONG_PRESS_DELAY = 500;\n\n/**\n * İpucu balonu.\n *\n * <h3>Neden native `title` yetmiyor</h3>\n * Tarayıcının `title` özniteliği <strong>dokunmatikte hiç görünmez</strong>,\n * gecikmesi ayarlanamaz ve biçimlendirilemez. Trafiğin ağırlığı mobil olan\n * bir arayüzde \"üzerine gelince açıklama çıkar\" demek, kullanıcıların çoğu\n * için açıklamanın hiç olmaması demek.\n *\n * <h3>Balon PORTAL ile gövdede</h3>\n * Önce tetikleyicinin içinde `position: absolute` ile duruyordu ve üç yerde\n * birden bozuluyordu: `overflow: hidden` taşıyan bir kapsayıcının içinde\n * (kart, tablo hücresi, `Panel`) KIRPILIYOR, ekranın kenarında görünüm\n * alanının dışına TAŞIYOR, `transform` taşıyan bir atanın altında yığılma\n * bağlamına HAPSOLUYORDU. Konum artık `usePositioning` ile ölçülüyor;\n * gerekçenin tamamı orada.\n *\n * <h3>Neden yalnızca AÇIKLAMA taşır</h3>\n * Balonda <em>yalnızca</em> yardımcı metin durur — bağlantı, düğme veya\n * okunması zorunlu bir bilgi değil. İçine bir eylem konsaydı ona erişmenin\n * yolu olmazdı: balon `pointer-events: none` ve klavyeyle içine girilemiyor.\n * Eylem taşıyan yüzey `Popover`ın işi; kalıcı olması gereken metin `Field`ın\n * `hint`i.\n *\n * <h3>Dokunmatik: uzun basma</h3>\n * Dokunmatikte `hover` yok — ipucu orada hiç açılmıyordu. Uzun basma balonu\n * açar; ekranın herhangi bir yerine dokunmak kapatır. Bağlam menüsü\n * bastırılır: uzun basmada iOS'ta seçim büyüteci, Android'de kopyala menüsü\n * çıkıyor ve ikisi de balonun üstüne biniyordu.\n *\n * <h3>Kapanma toleransı</h3>\n * İmleç tetikleyiciden çıkar çıkmaz kapatmak, balonun kendisine ulaşmayı\n * imkânsız kılıyordu (metin seçilemiyor). Kapanış {@link CLOSE_DELAY} kadar\n * bekletilir ve bu sürede balona giren imleç onu açık tutar.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>tetikleyiciye gelince GECİKMESİZ açılır</td></tr>\n * <tr><td>`Escape`</td><td>kapatır; odak tetikleyicide kalır</td></tr>\n * </table>\n * Gecikme fare için var; Tab ile gelen kullanıcı zaten bilinçli olarak orada\n * duruyor.\n */\nconst Tooltip = ({ content, children, side, position, openDelay = 300, className }: Props) => {\n const [isOpen, setIsOpen] = useState(false);\n const id = useId();\n\n /* Eski prop bir surum boyunca calisir; `side` verilmisse o kazanir. */\n const resolvedSide: PositionSide = side ?? position ?? 'top';\n\n const anchorRef = useRef<HTMLSpanElement>(null);\n const bubbleRef = useRef<HTMLSpanElement>(null);\n const timerRef = useRef(0);\n const longPressRef = useRef(0);\n\n const positioning = usePositioning(anchorRef, bubbleRef, {\n side: resolvedSide,\n align: 'center',\n isOpen,\n });\n\n const clearTimer = useCallback(() => {\n if (timerRef.current) window.clearTimeout(timerRef.current);\n timerRef.current = 0;\n }, []);\n\n const open = useCallback(\n (delay: number) => {\n clearTimer();\n timerRef.current = window.setTimeout(() => setIsOpen(true), delay);\n },\n [clearTimer],\n );\n\n const close = useCallback(\n (delay: number = CLOSE_DELAY) => {\n clearTimer();\n timerRef.current = window.setTimeout(() => setIsOpen(false), delay);\n },\n [clearTimer],\n );\n\n useEffect(() => clearTimer, [clearTimer]);\n\n /*\n * Escape BELGE duzeyinde dinleniyor.\n *\n * Sarmalayicida dinlemek yetmiyordu: balon acikken odak tetikleyicide\n * OLMAYABILIR (fareyle acilmis bir ipucu) ve o durumda tus olayi hic\n * sarmalayiciya ulasmiyor, ipucu ekranda asili kaliyordu.\n */\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') close(0);\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, close]);\n\n /* Dokunmatikte ekranin herhangi bir yerine dokunmak kapatir: balonun kendi\n kapatma yolu yok ve `pointer-events: none` oldugu icin ona da\n dokunulamiyor. */\n useEffect(() => {\n if (!isOpen) return;\n\n const handlePointerDown = (event: globalThis.PointerEvent) => {\n if (event.pointerType === 'mouse') return;\n if (anchorRef.current?.contains(event.target as Node)) return;\n close(0);\n };\n\n document.addEventListener('pointerdown', handlePointerDown);\n return () => document.removeEventListener('pointerdown', handlePointerDown);\n }, [isOpen, close]);\n\n const cancelLongPress = () => {\n if (longPressRef.current) window.clearTimeout(longPressRef.current);\n longPressRef.current = 0;\n };\n\n const handlePointerDown = (event: ReactPointerEvent) => {\n if (event.pointerType === 'mouse') return;\n longPressRef.current = window.setTimeout(() => setIsOpen(true), LONG_PRESS_DELAY);\n };\n\n return (\n <>\n <span\n ref={anchorRef}\n className={cx(styles.tooltip, className)}\n onPointerEnter={event => event.pointerType === 'mouse' && open(openDelay)}\n onPointerLeave={event => {\n cancelLongPress();\n if (event.pointerType === 'mouse') close();\n }}\n onPointerDown={handlePointerDown}\n onPointerUp={cancelLongPress}\n onPointerCancel={cancelLongPress}\n onFocus={() => open(0)}\n onBlur={() => close(0)}\n onContextMenu={event => {\n if (isOpen || longPressRef.current) event.preventDefault();\n }}\n >\n <span aria-describedby={isOpen ? id : undefined} className={styles.tooltip__trigger}>\n {children}\n </span>\n </span>\n\n {/*\n Balon DOM'da yalnizca ACIKKEN: kapaliyken de birakip gizlemek, ekran\n okuyucunun onu `aria-describedby` olmadan da bulup okumasina yol\n aciyordu.\n */}\n {isOpen &&\n isClient() &&\n createPortal(\n <span\n ref={bubbleRef}\n id={id}\n role=\"tooltip\"\n className={cx(styles.bubble, styles[`bubble--${positioning.side}`])}\n style={{\n ...positioning.style,\n /* Olculmeden cizilen balon bir kare boyunca sol ust kosede\n parliyordu. */\n visibility: positioning.isPositioned ? 'visible' : 'hidden',\n }}\n /* Imlec balona giderken tetikleyiciden cikiyor; balon uzerindeyken\n kapanis iptal edilir ve metin secilebilir kalir. */\n onPointerEnter={clearTimer}\n onPointerLeave={() => close()}\n >\n {content}\n </span>,\n document.body,\n )}\n </>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Tooltip, 'Tooltip')) as typeof Tooltip;\n","'use client';\n\nimport {\n cloneElement,\n isValidElement,\n type KeyboardEvent,\n memo,\n type MouseEvent,\n type ReactElement,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { captureFocus } from '../../helpers/focus.helper';\nimport usePositioning, { type PositionAlign, type PositionSide } from '../../hooks/usePositioning';\n\nimport styles from './index.module.scss';\n\nexport type MenuItem = {\n id: string;\n label: string;\n icon?: ReactNode;\n onSelect: () => void;\n isDisabled?: boolean;\n /** Geri alınamaz eylem: yıkıcı tonda çizilir. */\n isDanger?: boolean;\n};\n\ntype Props = {\n /** Tetikleyici. TEK öğe; bileşen ona `ref` ve ARIA ekliyor. */\n trigger: ReactElement;\n items: MenuItem[];\n /** Menünün erişilebilir adı (\"Satır eylemleri\"). ZORUNLU. */\n label: string;\n side?: PositionSide;\n align?: PositionAlign;\n className?: string;\n testId?: string;\n};\n\n/** Pasif olmayan seçeneklerin dizinleri. */\nconst enabledIndexes = (items: MenuItem[]): number[] =>\n items.map((item, index) => (item.isDisabled ? -1 : index)).filter(index => index >= 0);\n\n/**\n * Menü — bir listeden EYLEM seçme.\n *\n * <h3>{@link Select} ile farkı: seçim mi eylem mi</h3>\n * Görsel olarak benzerler; ayrım seçilen şeyin ne olduğunda:\n *\n * <ul>\n * <li>`Select` bir DEĞER seçer. Seçim kalıcıdır, tetikleyicide görünür ve\n * geri alınabilir. ARIA rolü `listbox`.</li>\n * <li><b>`Menu` bir EYLEM çalıştırır.</b> \"Sil\", \"Kopyala\", \"Dışa aktar\".\n * Seçilen şey hatırlanmaz; menü kapanır ve iş yapılır. ARIA rolü\n * `menu`.</li>\n * </ul>\n *\n * <p>Ayrım ekran okuyucuda duyuluyor: `listbox` \"3 seçenekten 2.'si seçili\"\n * der, `menu` \"menü, 3 öğe\" der. Eylem listesini `listbox` olarak sunmak,\n * kullanıcıya kalıcı bir seçim yaptığını söylüyordu.\n *\n * <h3>Odak GERÇEKTEN taşınır</h3>\n * `Select` odağı tetikleyicide tutup etkin seçeneği `aria-activedescendant`\n * ile bildiriyor; menüde bu YANLIŞ olurdu. APG menü deseni gerçek odak\n * istiyor çünkü menü öğeleri düğme gibi davranıyor — ve harfe atlama\n * (type-ahead) yalnızca odaklanmış bir öğe üzerinde anlamlı.\n *\n * <h3>Klavye (APG: menu button)</h3>\n * <table>\n * <tr><td>`Enter` / `Space` / `ArrowDown`</td><td>tetikleyicide: açar, İLK öğeye odaklanır</td></tr>\n * <tr><td>`ArrowUp`</td><td>tetikleyicide: açar, SON öğeye odaklanır</td></tr>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>öğeler arasında; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son öğe</td></tr>\n * <tr><td>harf</td><td>o harfle başlayan ilk öğeye atlar</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>öğeyi çalıştırır ve menüyü kapatır</td></tr>\n * <tr><td>`Escape` / `Tab`</td><td>kapatır, odak TETİKLEYİCİYE döner</td></tr>\n * </table>\n */\nconst Menu = ({\n trigger,\n items,\n label,\n side = 'bottom',\n align = 'start',\n className,\n testId,\n}: Props) => {\n const id = useId();\n const anchorRef = useRef<HTMLElement>(null);\n const surfaceRef = useRef<HTMLDivElement>(null);\n const restoreRef = useRef<(() => void) | null>(null);\n /* Harfe atlama tamponu: art arda basilan harfler tek bir arama olur. */\n const typedRef = useRef({ text: '', at: 0 });\n\n const [isOpen, setIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(0);\n\n const positioning = usePositioning(anchorRef, surfaceRef, { side, align, isOpen });\n const enabled = enabledIndexes(items);\n\n const open = useCallback(\n (target: 'first' | 'last') => {\n if (enabled.length === 0) return;\n restoreRef.current = captureFocus();\n setActiveIndex(target === 'first' ? enabled[0] : enabled[enabled.length - 1]);\n setIsOpen(true);\n },\n [enabled],\n );\n\n const close = useCallback(() => {\n setIsOpen(false);\n /* Odak TETIKLEYICIYE doner: donmezse `<body>`ye duser ve klavye\n kullanicisi sayfanin en basina giderdi. */\n restoreRef.current?.();\n restoreRef.current = null;\n }, []);\n\n /* Etkin oge GERCEKTEN odaklanir (APG menu deseni). */\n useEffect(() => {\n if (!isOpen) return;\n surfaceRef.current\n ?.querySelector<HTMLElement>(`[data-index=\"${activeIndex}\"]`)\n ?.focus({ preventScroll: true });\n }, [isOpen, activeIndex]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n const target = event.target as Node;\n if (surfaceRef.current?.contains(target) || anchorRef.current?.contains(target)) return;\n close();\n };\n\n document.addEventListener('mousedown', handlePointerDown);\n return () => document.removeEventListener('mousedown', handlePointerDown);\n }, [isOpen, close]);\n\n const step = (offset: number) => {\n const position = enabled.indexOf(activeIndex);\n const next = (position + offset + enabled.length) % enabled.length;\n setActiveIndex(enabled[next]);\n };\n\n /** Harfe atlama: 500 ms içinde basılan harfler tek bir arama. */\n const jumpToLetter = (key: string) => {\n const now = Date.now();\n const buffer = now - typedRef.current.at > 500 ? key : typedRef.current.text + key;\n typedRef.current = { text: buffer, at: now };\n\n const match = enabled.find(index =>\n items[index].label.toLocaleLowerCase('tr').startsWith(buffer.toLocaleLowerCase('tr')),\n );\n\n if (match !== undefined) setActiveIndex(match);\n };\n\n const handleMenuKeyDown = (event: KeyboardEvent) => {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n step(1);\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n step(-1);\n break;\n\n case 'Home':\n event.preventDefault();\n setActiveIndex(enabled[0]);\n break;\n\n case 'End':\n event.preventDefault();\n setActiveIndex(enabled[enabled.length - 1]);\n break;\n\n case 'Escape':\n event.preventDefault();\n close();\n break;\n\n case 'Tab':\n /* Menu KAPANIR ama gezinme SURER: kullanici menuden cikip sayfaya\n devam ediyor. `preventDefault` yok. */\n close();\n break;\n\n default:\n if (event.key.length === 1 && !event.metaKey && !event.ctrlKey) jumpToLetter(event.key);\n }\n };\n\n const handleTriggerKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n open('last');\n return;\n }\n\n if (['ArrowDown', 'Enter', ' '].includes(event.key)) {\n event.preventDefault();\n open('first');\n }\n };\n\n if (!isValidElement(trigger)) return null;\n\n const triggerProps = trigger.props as Record<string, unknown>;\n\n const anchor = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: anchorRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n 'aria-controls': isOpen ? id : undefined,\n onClick: (event: MouseEvent) => {\n (triggerProps.onClick as ((event: MouseEvent) => void) | undefined)?.(event);\n if (isOpen) close();\n else open('first');\n },\n onKeyDown: (event: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((event: KeyboardEvent) => void) | undefined)?.(event);\n if (!isOpen) handleTriggerKeyDown(event);\n },\n });\n\n return (\n <>\n {anchor}\n\n {isOpen &&\n isClient() &&\n createPortal(\n <div\n ref={surfaceRef}\n id={id}\n role=\"menu\"\n aria-label={label}\n className={cx(styles.menu, styles[`menu--${positioning.side}`], className)}\n style={{\n ...positioning.style,\n visibility: positioning.isPositioned ? 'visible' : 'hidden',\n }}\n data-testid={testId}\n onKeyDown={handleMenuKeyDown}\n >\n {items.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"menuitem\"\n data-index={index}\n /*\n * DONEN `tabindex`: menu Tab sirasinda TEK durak. Her oge\n * odaklanabilir olsaydi sekiz ogeli bir menude klavye\n * kullanicisi sayfaya donmek icin sekiz kez Tab'liyordu.\n */\n tabIndex={index === activeIndex ? 0 : -1}\n disabled={item.isDisabled}\n className={cx(styles.menu__item, item.isDanger && styles['menu__item--danger'])}\n onClick={() => {\n item.onSelect();\n close();\n }}\n /* Fare imleci ogenin uzerindeyken etkin oge de oraya tasinir;\n iki ayri vurgu kullaniciyi sasirtiyordu. */\n onMouseEnter={() => !item.isDisabled && setActiveIndex(index)}\n >\n {item.icon && (\n <span className={styles.menu__icon} aria-hidden>\n {item.icon}\n </span>\n )}\n {item.label}\n </button>\n ))}\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Menu, 'Menu')) as typeof Menu;\n","'use client';\n\nimport {\n cloneElement,\n isValidElement,\n memo,\n type ReactElement,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { captureFocus, focusFirstMeaningful } from '../../helpers/focus.helper';\nimport usePositioning, { type PositionAlign, type PositionSide } from '../../hooks/usePositioning';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /**\n * Tetikleyici. TEK bir öğe olmak zorunda: bileşen ona `ref`, `onClick` ve\n * `aria-expanded` ekliyor.\n */\n trigger: ReactElement;\n children: ReactNode;\n /** Yüzeyin erişilebilir adı. ZORUNLU — adsız bir bölge \"grup\" diye okunur. */\n label: string;\n side?: PositionSide;\n align?: PositionAlign;\n /** Kontrollü kullanım. Verilmezse bileşen durumu kendisi tutar. */\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n className?: string;\n testId?: string;\n};\n\n/**\n * Popover — <strong>eylem taşıyabilen</strong>, odaklanabilir yüzey.\n *\n * <h3>{@link Tooltip} ile farkı: içine ne konabildiği</h3>\n * İkisi de tetikleyiciye yapışan bir yüzey açıyor; ayrım içeriğin\n * ERİŞİLEBİLİR olup olmamasında:\n *\n * <ul>\n * <li>`Tooltip` yalnızca AÇIKLAMA taşır. `pointer-events: none` ve klavyeyle\n * içine girilemez — içine bir bağlantı konsa ona ulaşmanın yolu olmazdı\n * (fare balona giderken tetikleyiciden çıkıyor).</li>\n * <li><b>`Popover` odak alır.</b> Açıldığında odak içeri girer, `Escape`\n * kapatır ve odak tetikleyiciye döner. Bağlantı, düğme, kısa bir form\n * konabilir.</li>\n * </ul>\n *\n * <h3>Kipsel DEĞİL</h3>\n * Arka plan tıklanabilir kalır ve sayfa kaydırılabilir. Kararı bekleyen,\n * kaçınılmaz bir seçim `Modal`ın işi; popover yardımcı bir yüzey ve\n * kullanıcıyı hapsetmemeli. Bu yüzden `<dialog>` DEĞİL portal + `usePositioning`:\n * `showModal()` arka planı inert bırakıyor, `<dialog open>` (kipsiz) ise üst\n * katmana hiç girmiyor ve `z-index` yarışına dönüyordu.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Enter` / `Space`</td><td>tetikleyicide: açar</td></tr>\n * <tr><td>`Escape`</td><td>kapatır, odak TETİKLEYİCİYE döner</td></tr>\n * <tr><td>`Tab`</td><td>yüzeyin içinde gezinir; dışına çıkınca KAPANIR</td></tr>\n * </table>\n * Odak tuzağı YOK — kipsel olmayan bir yüzeyde odağı hapsetmek, kullanıcıyı\n * sayfadan koparır. Odak dışarı çıktığında yüzey kapanır.\n */\nconst Popover = ({\n trigger,\n children,\n label,\n side = 'bottom',\n align = 'start',\n isOpen: controlledOpen,\n onOpenChange,\n className,\n testId,\n}: Props) => {\n const id = useId();\n const anchorRef = useRef<HTMLElement>(null);\n const surfaceRef = useRef<HTMLDivElement>(null);\n const restoreRef = useRef<(() => void) | null>(null);\n\n const [uncontrolledOpen, setUncontrolledOpen] = useState(false);\n const isControlled = controlledOpen !== undefined;\n const isOpen = isControlled ? controlledOpen : uncontrolledOpen;\n\n const positioning = usePositioning(anchorRef, surfaceRef, { side, align, isOpen });\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setUncontrolledOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n /* Acilista odak ICERI girer, kapanista TETIKLEYICIYE doner. */\n useEffect(() => {\n if (!isOpen) return;\n\n restoreRef.current = captureFocus();\n const surface = surfaceRef.current;\n if (surface) focusFirstMeaningful(surface);\n\n return () => {\n restoreRef.current?.();\n restoreRef.current = null;\n };\n }, [isOpen]);\n\n /* Escape ve DISARI tiklama. Ikisi de belge duzeyinde: odak yuzeyin icinde\n olmayabilir (fareyle acilmis bir popover). */\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false);\n };\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n const target = event.target as Node;\n if (surfaceRef.current?.contains(target)) return;\n if (anchorRef.current?.contains(target)) return;\n setOpen(false);\n };\n\n document.addEventListener('keydown', handleKeyDown);\n /* `mousedown`: `click` beklerken kullanici surukleyerek secim yaparsa\n yuzey kapanmiyordu. */\n document.addEventListener('mousedown', handlePointerDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('mousedown', handlePointerDown);\n };\n }, [isOpen, setOpen]);\n\n if (!isValidElement(trigger)) return null;\n\n const triggerProps = trigger.props as Record<string, unknown>;\n\n const anchor = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: anchorRef,\n 'aria-expanded': isOpen,\n 'aria-haspopup': 'dialog',\n 'aria-controls': isOpen ? id : undefined,\n onClick: (event: React.MouseEvent) => {\n (triggerProps.onClick as ((event: React.MouseEvent) => void) | undefined)?.(event);\n setOpen(!isOpen);\n },\n });\n\n return (\n <>\n {anchor}\n\n {isOpen &&\n isClient() &&\n createPortal(\n <div\n ref={surfaceRef}\n id={id}\n /*\n * `role=\"dialog\"` ama `aria-modal` YOK: yuzey kipsel degil ve\n * `aria-modal=\"true\"` yazmak ekran okuyucuya sayfanin geri\n * kalaninin erisilemez oldugunu soyluyordu — oysa erisilebilir.\n */\n role=\"dialog\"\n aria-label={label}\n className={cx(styles.popover, styles[`popover--${positioning.side}`], className)}\n style={{\n ...positioning.style,\n visibility: positioning.isPositioned ? 'visible' : 'hidden',\n }}\n data-testid={testId}\n /* Odak yuzeyin DISINA ciktiginda kapanir: kipsel olmayan bir\n yuzeyde odagi hapsetmek kullaniciyi sayfadan koparirdi. */\n onBlur={event => {\n if (event.currentTarget.contains(event.relatedTarget as Node)) return;\n if (anchorRef.current?.contains(event.relatedTarget as Node)) return;\n setOpen(false);\n }}\n >\n {children}\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Popover, 'Popover')) as typeof Popover;\n","'use client';\n\nimport { type ButtonHTMLAttributes, forwardRef, memo, type ReactNode } from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\nexport type ChipSize = 'sm' | 'md';\n\ntype Props = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> & {\n /** Görünen metin. Yalnız ikon taşıyan çipte verilmez; `label` zorunlu olur. */\n children?: ReactNode;\n /** Metnin solundaki ikon. */\n icon?: ReactNode;\n /** Metnin sağındaki ikon (ok, çarpı). */\n endIcon?: ReactNode;\n /** Sağda gösterilen sonuç adedi. */\n count?: number;\n isSelected?: boolean;\n size?: ChipSize;\n /**\n * Erişilebilir ad. Görünür metin yoksa <strong>zorunlu</strong>: yalnız ikon\n * taşıyan bir çip ekran okuyucuda \"düğme\" diye okunur.\n */\n label?: string;\n /** Verilirse çip bir bağlantı olarak çizilir. */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n /**\n * Grup içindeki ARIA rolü. Tek seçimli gruplarda `radio`, çok seçimlide\n * verilmez — {@link ChipGroup} bunu kendisi ayarlar; elle kullanımda\n * `aria-pressed` üretilir.\n */\n role?: 'radio';\n testId?: string;\n};\n\n/**\n * Çip — seçilebilir etiket.\n *\n * <h3>Tasarım sisteminin en çok tekrarlanan öğesi</h3>\n * Kategori seçimi, hızlı filtre, sıralama tercihi, görünüm anahtarı: hepsi\n * aynı öğe. Ayrı ayrı düğme stilleri yazmak yerine tek çip kullanılır;\n * böylece seçili durumun nasıl göründüğü uygulamanın her yerinde aynıdır.\n *\n * <h3>Seçili durum üç sinyalle birden bildirilir</h3>\n * Kenarlık + metin rengi + ikon rengi <em>birlikte</em> değişir. Yalnızca\n * zemini doldurmak (renk tek başına, WCAG 1.4.1) renk körü kullanıcı için\n * ayırt edilemez olurdu; ayrıca dolu zemin çipi düğmeye benzetip \"buraya\n * tıkla\" gibi okutuyordu — oysa çip bir <em>durum</em> gösterir.\n *\n * <h3>Neden `aria-pressed`, `disabled` değil</h3>\n * Seçili çip pasifleştirilmez: kullanıcı seçimini geri alabilmeli. Basılı\n * düğme semantiği (`aria-pressed`) ekran okuyucuya \"seçili, kapatılabilir\"\n * bilgisini verir.\n */\nconst Chip = /*#__PURE__*/ forwardRef<HTMLButtonElement, Props>(\n (\n {\n children,\n icon,\n endIcon,\n count,\n isSelected,\n size = 'md',\n label,\n href,\n linkProps,\n className,\n type = 'button',\n role,\n testId,\n ...rest\n },\n ref,\n ) => {\n const classNames = cx(\n styles.chip,\n styles[`chip--${size}`],\n isSelected && styles['chip--selected'],\n !children && styles['chip--iconOnly'],\n className,\n );\n\n const content = (\n <>\n {icon && (\n <span className={styles.chip__icon} aria-hidden>\n {icon}\n </span>\n )}\n {children && <span className={styles.chip__label}>{children}</span>}\n {isDefined(count) && <span className={styles.chip__count}>{count}</span>}\n {endIcon && (\n <span className={styles.chip__icon} aria-hidden>\n {endIcon}\n </span>\n )}\n </>\n );\n\n if (href)\n return (\n <HanuiLink\n href={href}\n className={classNames}\n aria-label={children ? undefined : label}\n aria-current={isSelected ? 'page' : undefined}\n title={children ? undefined : label}\n data-testid={testId}\n {...linkProps}\n >\n {content}\n </HanuiLink>\n );\n\n return (\n <button\n ref={ref}\n type={type}\n role={role}\n className={classNames}\n aria-label={children ? undefined : label}\n title={children ? undefined : label}\n data-testid={testId}\n // Tek seçimli grupta radyo semantiği, aksi halde basılı düğme.\n {...(role === 'radio'\n ? { 'aria-checked': Boolean(isSelected) }\n : { 'aria-pressed': Boolean(isSelected) })}\n {...rest}\n >\n {content}\n </button>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Chip, 'Chip')) as typeof Chip;\n","'use client';\n\nimport { type KeyboardEvent, memo, type ReactNode, useRef } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport Chip, { type ChipSize } from '../Chip';\n\nimport styles from './index.module.scss';\n\nexport type ChipOption<T extends string = string> = {\n value: T;\n label: string;\n icon?: ReactNode;\n count?: number;\n isDisabled?: boolean;\n};\n\ntype BaseProps<T extends string> = {\n options: ChipOption<T>[];\n /** Grubun erişilebilir adı (\"Sıralama\", \"Kalite\"). */\n label: string;\n size?: ChipSize;\n /** Taşan çipleri alta sarmak yerine yatay kaydırır (mobil filtre şeridi). */\n isScrollable?: boolean;\n className?: string;\n};\n\ntype SingleProps<T extends string> = BaseProps<T> & {\n isMultiple?: false;\n value: T | null;\n /** Seçili çipe tekrar basılırsa `null` gelir — seçim geri alınabilir. */\n onChange: (value: T | null) => void;\n};\n\ntype MultipleProps<T extends string> = BaseProps<T> & {\n isMultiple: true;\n value: T[];\n onChange: (value: T[]) => void;\n};\n\ntype Props<T extends string> = SingleProps<T> | MultipleProps<T>;\n\n/**\n * Çip grubu — açılır liste yerine tek dokunuşla seçim.\n *\n * <h3>Ne zaman çip grubu, ne zaman açılır liste</h3>\n * Seçenek sayısı azsa (kabaca 7'ye kadar) ve seçenekler ekranda durabiliyorsa\n * çip grubu kullanılır: kullanıcı listeyi <em>açmadan</em> hem seçenekleri hem\n * de hangisinin seçili olduğunu görür — açılır listede bu bilgi iki tıklama\n * arkasındadır. 5–20 seçenek için {@link Select}, 20+ için {@link Combobox}.\n *\n * <h3>Tek seçim radyo grubudur</h3>\n * Tek seçimli grup `role=\"radiogroup\"` alır ve çipler `role=\"radio\"` olur.\n * Görsel olarak radyo düğmesi gibi durmasalar da davranış aynıdır; ekran\n * okuyucu \"3 seçenekten 2.'si\" diye okur. Yalnız `aria-pressed` kullanmak,\n * seçeneklerin birbirini dışladığı bilgisini kaybettiriyordu.\n *\n * <h3>Gezinme tabindex'i dolaşır (roving tabindex)</h3>\n * Radyo grubunda Tab tuşu <strong>gruba</strong> girer, seçenekler arasında ok\n * tuşlarıyla gezilir. Her çipin ayrı ayrı Tab durağı olması, 7 seçenekli bir\n * filtrede klavye kullanıcısını 7 kez Tab'lamaya zorluyordu.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowDown`</td><td>sonraki seçenek; uçlarda DÖNER</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowUp`</td><td>önceki seçenek</td></tr>\n * </table>\n * ÇOKLU seçimde ok tuşu YOKTUR: orada her çip bağımsız bir onay kutusu ve\n * `Tab` ile gezilir — ok tuşuyla gezinmek seçimi de değiştirirdi, oysa\n * radyo grubunun aksine burada gezinmek seçmek demek değil. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst ChipGroup = <T extends string>({\n options,\n label,\n size = 'md',\n isScrollable,\n className,\n ...selection\n}: Props<T>) => {\n const listRef = useRef<HTMLDivElement>(null);\n\n const isSelected = (value: T) =>\n selection.isMultiple ? selection.value.includes(value) : selection.value === value;\n\n const handleSelect = (value: T) => {\n if (selection.isMultiple) {\n const next = selection.value.includes(value)\n ? selection.value.filter(item => item !== value)\n : [...selection.value, value];\n selection.onChange(next);\n return;\n }\n\n // Seçili çipe tekrar basmak seçimi kaldırır: \"hepsi\" seçeneği olmayan\n // filtrelerde kullanıcının geri dönebileceği tek yol bu.\n selection.onChange(selection.value === value ? null : value);\n };\n\n /** Ok tuşlarıyla gezinme; başta/sonda döner (yalnızca tek seçimde). */\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (selection.isMultiple) return;\n\n const offset =\n event.key === 'ArrowRight' || event.key === 'ArrowDown'\n ? 1\n : event.key === 'ArrowLeft' || event.key === 'ArrowUp'\n ? -1\n : 0;\n if (offset === 0) return;\n\n event.preventDefault();\n\n const enabled = options.filter(option => !option.isDisabled);\n if (enabled.length === 0) return;\n\n const currentIndex = enabled.findIndex(option => option.value === selection.value);\n const next = enabled[(currentIndex + offset + enabled.length) % enabled.length];\n\n selection.onChange(next.value);\n listRef.current?.querySelector<HTMLButtonElement>(`[data-chip-value=\"${next.value}\"]`)?.focus();\n };\n\n // Roving tabindex: seçili çip tabbable; hiçbiri seçili değilse ilki.\n const tabbableValue = selection.isMultiple\n ? null\n : (selection.value ?? options.find(option => !option.isDisabled)?.value ?? null);\n\n return (\n <div\n ref={listRef}\n className={cx(styles.group, isScrollable && styles['group--scrollable'], className)}\n role={selection.isMultiple ? 'group' : 'radiogroup'}\n aria-label={label}\n onKeyDown={handleKeyDown}\n >\n {options.map(option => (\n <Chip\n key={option.value}\n size={size}\n icon={option.icon}\n count={option.count}\n isSelected={isSelected(option.value)}\n disabled={option.isDisabled}\n role={selection.isMultiple ? undefined : 'radio'}\n tabIndex={selection.isMultiple || option.value === tabbableValue ? 0 : -1}\n data-chip-value={option.value}\n onClick={() => handleSelect(option.value)}\n >\n {option.label}\n </Chip>\n ))}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(ChipGroup) as typeof ChipGroup;\n","'use client';\n\nimport {\n memo,\n type MouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { isClient } from '@ahmetilhn/handy-utils';\n\nimport { ABOVE_MOBILE_MEDIA_QUERY } from '../../constants/breakpoint.constants';\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport {\n captureFocus,\n focusFirstMeaningful,\n isTopModal,\n preventAutoKeyboard,\n pushModal,\n} from '../../helpers/focus.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport useScrollLock from '../../hooks/useScrollLock';\nimport useSheetViewport from '../../hooks/useSheetViewport';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n /** Kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n onClose: () => void;\n children: ReactNode;\n /**\n * Başlığın altında duran, gövde kaydırılırken yerinde kalan şerit —\n * `Combobox`ın arama kutusu gibi.\n */\n toolbar?: ReactNode;\n /** Dipte duran eylem şeridi. */\n footer?: ReactNode;\n /**\n * Panelin <strong>kendiliğinden kapandığı</strong> medya sorgusu.\n *\n * <p>Varsayılan mobil eşiği (`>640`), çünkü seçim kutuları o eşiğin üstünde\n * listeyi yapışkan panelde açıyor. Kendi eşiği daha geniş olan çağıranlar\n * kendi sorgusunu verir; aksi hâlde 800 px'te açılan panel pencere 641 px'i\n * geçtiğinde kapanıyor ya da hiç kapanmıyordu.\n */\n closeAbove?: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Alt sayfa (bottom sheet) — ekranın dibinden yükselen kipsel panel.\n *\n * <h3>Ne zaman</h3>\n * Dar ekranda bir <strong>seçim listesi</strong> açan her kutu bunu kullanır\n * ({@link Select}, {@link Combobox}). Masaüstünde aynı liste tetikleyiciye\n * yapışan bir panelde açılır; telefonda o panel klavye açılınca sıkışıyor ve\n * listenin alt ucu ekranın dışında kalıyordu. Alt sayfa baş parmağın\n * erişebildiği yerde durur, satırları büyüktür ve ekranı tek işe ayırır.\n *\n * <h3>Neden yerel `<dialog>` + portal</h3>\n * `showModal()` odak tuzağını, Escape'i ve arka planın etkileşime kapanmasını\n * tarayıcıdan getirir. Panel <strong>gövdeye taşınır</strong>: seçim kutuları\n * `<label>` içinde durabiliyor ve etiketin içindeki tıklama etiketlenen öğeye\n * yönleniyor — seçeneklere basmak aynı anda tetikleyiciyi de tetikliyordu.\n *\n * <h3>Yalnızca açıkken çizilir</h3>\n * Bileşen `isOpen` almaz: çağıran taraf açıkken <em>render eder</em>, kapatmak\n * için kaldırır. Kapalı bir `<dialog>`u CSS ile gizlemeye çalışmak, sınıf\n * seçicisinin tarayıcı kuralını yenmesi yüzünden paneli ekranın dibinde asılı\n * bırakıyordu.\n *\n * <h3>Kırılma noktası aşılırsa kapanır</h3>\n * `showModal()` sayfanın geri kalanını panel çizilsin ya da çizilmesin inert\n * bırakır; pencere büyütülüp panel gizlenseydi sayfa tıklanamaz kalırdı.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Escape`</td><td>kapatır (`cancel` olayı çağırana bildirilir)</td></tr>\n * <tr><td>`Tab`</td><td>odak panelin içinde döner</td></tr>\n * </table>\n * Açılışta odak metin alanına DÜŞMEZ: `showModal()` odağı ilk odaklanabilir\n * öğeye taşıyor ve o öğe bir metin alanı olduğunda telefonda ekran klavyesi\n * kullanıcı istemeden açılıyordu (bkz. `helpers/focus.helper`). Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst BottomSheet = ({\n title,\n closeLabel,\n onClose,\n children,\n toolbar,\n footer,\n closeAbove = ABOVE_MOBILE_MEDIA_QUERY,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const titleId = useId();\n /* Yigindaki yerimiz: Escape yalnizca EN USTTEKI panelde islenir. */\n const tokenRef = useRef<symbol | null>(null);\n\n /* Panel GORUNEN alana yaslanir: klavye ve adres cubugu altinda kalmaz. */\n useSheetViewport();\n\n /* Arka plan kaydirmasi kilitlenir: `showModal()` arka plani etkilesime\n kapatir ama kaydirmayi her tarayicida engellemiyor — kullanici alt sayfayi\n kaydirdigini sanirken arkadaki listeyi kaydiriyordu. Kilit SAYACLI: bu\n panel neredeyse her zaman baska bir kipsel yuzeyin (secim kutusu, filtre\n paneli) ICINDE aciliyor ve ilki kapaninca kilit erken acilmamali. */\n useScrollLock();\n\n /*\n * ODAK GERI DONUSU ve KIPSEL YIGIN.\n *\n * Panel `isOpen` almiyor — cagiran acikken cizip kapatmak icin kaldiriyor\n * (bkz. yukaridaki not). Yani \"acilis\" MONTAJ, \"kapanis\" SOKUM: ikisi de\n * bos bagimlilikli tek bir etkiye sigiyor.\n */\n useEffect(() => {\n const restoreFocus = captureFocus();\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, []);\n\n useEffect(() => {\n const query = window.matchMedia(closeAbove);\n query.addEventListener('change', onClose);\n return () => query.removeEventListener('change', onClose);\n }, [closeAbove, onClose]);\n\n const setDialogRef = useCallback((node: HTMLDialogElement | null) => {\n if (!node || node.open) return;\n\n node.showModal();\n\n /* Odak KAPATMA DUGMESINE degil ilk anlamli ogeye: ekran okuyucu paneli\n \"Kapat, dugme\" diye aciyordu — kullanicinin duydugu ilk sey, panelin ne\n oldugu degil ondan nasil kacilacagi. */\n focusFirstMeaningful(node, `.${styles.sheet__header} button`);\n\n /* `showModal()` odagi panelin ILK odaklanabilir ogesine tasiyor; o oge bir\n metin alani oldugunda telefonda klavye kendiliginden aciliyordu\n (bkz. `helpers/focus.helper`). */\n preventAutoKeyboard(node);\n }, []);\n\n const handleBackdropClick = useCallback(\n (event: MouseEvent<HTMLDialogElement>) => {\n // Hedef dialog'un KENDISI ise perdeye tiklanmistir; icerik degil.\n if (event.target === event.currentTarget) onClose();\n },\n [onClose],\n );\n\n /* Portal `document.body`ye baglaniyor; sunucuda `document` yok. */\n if (!isClient()) return null;\n\n return createPortal(\n <dialog\n ref={setDialogRef}\n className={cx(styles.sheet, className)}\n aria-labelledby={titleId}\n data-testid={testId}\n /* Escape'i tarayici isler ama React durumu haberdar olmuyor:\n yakalanmazsa panel kapanip durum acik kaliyor ve kutu bir daha\n acilmiyordu. */\n onCancel={event => {\n event.preventDefault();\n /* Yalnizca EN USTTEKI panel kapanir: ust uste iki kipsel yuzeyde tek\n bir Escape ikisini birden kapatiyordu. */\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n onClose();\n }}\n onClick={handleBackdropClick}\n >\n <header className={styles.sheet__header}>\n <h2 id={titleId} className={styles.sheet__title}>\n {title}\n </h2>\n <IconButton\n icon={<XLg aria-hidden />}\n label={resolveLabel('BottomSheet.closeLabel', closeLabel, labels?.close)}\n variant=\"ghost\"\n size=\"sm\"\n onClick={onClose}\n />\n </header>\n\n {toolbar && <div className={styles.sheet__toolbar}>{toolbar}</div>}\n\n <div className={styles.sheet__body}>{children}</div>\n\n {footer && <div className={styles.sheet__footer}>{footer}</div>}\n </dialog>,\n document.body,\n );\n};\n\nexport default /*#__PURE__*/ memo(BottomSheet);\n","'use client';\n\nimport {\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { CaretDownFill, CheckLg, Search, XLg } from 'react-bootstrap-icons';\n\nimport { ABOVE_MOBILE_MEDIA_QUERY } from '../../constants/breakpoint.constants';\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { matchesSearch } from '../../helpers/text.helper';\nimport useListboxNavigation from '../../hooks/useListboxNavigation';\nimport usePositioning from '../../hooks/usePositioning';\nimport useVirtualList from '../../hooks/useVirtualList';\nimport { useHanui } from '../../theme/context';\nimport BottomSheet from '../BottomSheet';\nimport Spinner from '../Spinner';\n\nimport styles from './index.module.scss';\n\n/**\n * Sanallaştırmanın devreye girdiği eşik.\n *\n * <p>Altında kazanç yok: kırk satırlık bir listede DOM maliyeti zaten ihmal\n * edilebilir ve ölçüm katmanı yalnızca karmaşıklık ekler.\n */\nconst VIRTUAL_THRESHOLD = 80;\n\n/**\n * Seçenek satırının yüksekliği (`--sheet` dışında).\n *\n * <p>SCSS'teki `min-height` ile birlikte değişir; ayrıştıklarında satırlar\n * yanlış konumlanır. Ölçüyü çalışma zamanında okumak (`getComputedStyle`) bir\n * seçenek değil: liste henüz çizilmemişken okunacak bir satır yok.\n */\nconst OPTION_HEIGHT = 40;\n\nexport type ComboboxOption<T extends string = string> = {\n value: T;\n label: string;\n /** İkincil satır: kod, numara, ayırt edici bilgi. */\n description?: string;\n isDisabled?: boolean;\n};\n\n/**\n * Bileşenin çizdiği metinler.\n *\n * <p>`placeholder` dışındaki her şey `HanuiProvider labels.combobox`ten de\n * gelebilir; buradaki değer kazanır. `placeholder` ALANI adlandırır\n * (\"Şehir seçin\", \"Marka seçin\") ve her çağrı yerinde farklıdır — o yüzden\n * zorunlu kaldı.\n */\nexport type ComboboxLabels = {\n /** Seçim yokken tetikleyicide ve alt sayfa başlığında görünen metin. */\n placeholder: string;\n /** Arama kutusunun yer tutucusu ve erişilebilir adı. */\n searchPlaceholder?: string;\n /** Liste boşken gösterilen metin. */\n emptyMessage?: string;\n /** Arama sürerken liste yerine gösterilen metin. */\n loadingMessage?: string;\n /** Seçimi kaldıran çarpının erişilebilir adı. */\n clearLabel?: string;\n /** Alt sayfanın kapatma düğmesinin erişilebilir adı. */\n closeLabel?: string;\n};\n\ntype Props<T extends string> = {\n options: ComboboxOption<T>[];\n value: T | null;\n onChange: (value: T | null) => void;\n labels: ComboboxLabels;\n /**\n * Verilirse arama <strong>sunucuda</strong> yapılır: bileşen listeyi kendisi\n * filtrelemez, yazılanı 300 ms bekleyip buraya bildirir. Verilmezse\n * filtreleme yerelde ve aksan duyarsız yapılır.\n */\n onSearch?: (query: string) => void;\n isLoading?: boolean;\n isDisabled?: boolean;\n /** Seçimi kaldıran çarpı düğmesi gösterilir. */\n isClearable?: boolean;\n /**\n * Arama kutusu GİZLENİR.\n *\n * <p>Az sayıda, sabit seçenekli listelerde arama bir işe yaramıyor: altı\n * satırı taramak yazmaktan hızlı ve kutu açılışta odağı çalıp mobilde\n * klavyeyi açıyordu. Ok tuşlarıyla gezinme ve `Escape` yine çalışır.\n */\n isSearchHidden?: boolean;\n /** Tetikleyicinin solundaki ikon. */\n icon?: ReactNode;\n id?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Aranabilir seçim kutusu.\n *\n * <h3>Neden yerel `<select>` değil</h3>\n * Yerel açılır liste 20 seçeneğe kadar iyidir. Binlerce seçenekli bir listede\n * kullanıcı harf harf yazarak (ve yalnızca baştan eşleşerek) arıyor, mobilde\n * ise metrelerce süren bir tekerlek çeviriyor. Aranabilir liste, seçeneği\n * <em>yazarak</em> bulmayı mümkün kılar.\n *\n * <h3>Arama kutusu listenin İÇİNDE</h3>\n * Arama alanını listenin dışına koymak kullanıcıya iki ayrı alan gösteriyor\n * ve hangisinin seçimi belirlediği anlaşılmıyordu. Tek tetikleyici, tek\n * panel: masaüstünde panel açılınca odak doğrudan arama kutusuna gider,\n * yazılır, Enter'a basılır. Dar ekranda odak VERİLMEZ — bkz. aşağıdaki not.\n *\n * <h3>Yerel mi sunucu araması mı</h3>\n * `onSearch` verilmezse bileşen elindeki listeyi aksan duyarsız filtreler.\n * Verilirse filtrelemeyi <em>yapmaz</em> — sunucudan gelen liste zaten\n * filtrelenmiştir; ikinci kez filtrelemek sunucunun daha akıllı eşleşmesini\n * (eş anlamlı, kod eşleşmesi) bozardı.\n *\n * <h3>Seçilenin etiketi listeden düşse de korunur</h3>\n * Sunucu aramasında kullanıcı yeni bir arama yaptığında seçili kayıt gelen\n * listede olmayabilir. Etiket son bilinen değerden hatırlanır; aksi hâlde\n * tetikleyici seçim varken yer tutucuya dönüyordu.\n *\n * <h3>Dar ekranda arama kutusu ODAKLANMAZ</h3>\n * Alt sayfa açılırken kutuya odaklanmak ekran klavyesini kullanıcı istemeden\n * açıyordu: panel yarı yüksekliğe sıkışıyor, liste birkaç satıra iniyor ve\n * seçim yapmak için önce klavyeyi kapatmak gerekiyordu. Telefonda liste\n * taranarak kullanılır; yazmak isteyen kutuya kendisi dokunur.\n *\n * <h3>ARIA</h3>\n * Tetikleyici `aria-haspopup=\"listbox\"`, panel içindeki arama alanı\n * `role=\"combobox\"` + `aria-activedescendant`. Masaüstünde odak arama\n * kutusundan ayrılmaz; ok tuşları yalnızca <em>etkin</em> seçeneği değiştirir.\n * Odağı seçeneklere taşımak, yazmaya devam etmeyi imkânsız kılıyordu.\n *\n * <h3>Klavye (APG: combobox with listbox popup)</h3>\n * <table>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin seçenek bir alt/üst; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son seçenek</td></tr>\n * <tr><td>`Enter`</td><td>etkin seçeneği seçer, paneli kapatır</td></tr>\n * <tr><td>`Escape`</td><td>kapatır, odak tetikleyiciye döner</td></tr>\n * <tr><td>`Tab`</td><td>kapatır, gezinme sürer</td></tr>\n * <tr><td>yazmak</td><td>filtreler ve etkin seçeneği başa çeker</td></tr>\n * </table>\n * Nöbetçi: `components/__tests__/keyboard.test.tsx`.\n */\nconst Combobox = <T extends string>({\n options,\n value,\n onChange,\n labels,\n isSearchHidden,\n onSearch,\n isLoading,\n isDisabled,\n isClearable,\n icon,\n id,\n className,\n testId,\n 'aria-describedby': describedBy,\n 'aria-invalid': isInvalid,\n}: Props<T>) => {\n const { labels: config } = useHanui();\n\n /*\n * Metinler TEMBEL cozulur: cizilmeyen bir ogenin metnini istemek yanlis\n * alarm uretiyordu — `isSearchHidden` iken arama kutusu hic yok ama toplu\n * cozumleme yine de \"eksik metin\" diye uyariyordu.\n */\n const text = {\n get search() {\n return resolveLabel(\n 'Combobox.searchPlaceholder',\n labels.searchPlaceholder,\n config?.combobox?.searchPlaceholder,\n );\n },\n get empty() {\n return resolveLabel(\n 'Combobox.emptyMessage',\n labels.emptyMessage,\n config?.combobox?.emptyMessage,\n );\n },\n get loading() {\n return resolveLabel(\n 'Combobox.loadingMessage',\n labels.loadingMessage,\n config?.combobox?.loadingMessage,\n );\n },\n get clear() {\n return resolveLabel('Combobox.clearLabel', labels.clearLabel, config?.combobox?.clearLabel);\n },\n };\n\n const generatedId = useId();\n const baseId = id ?? generatedId;\n const listboxId = `${baseId}-listbox`;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n /*\n * Panel NEREDE acilir: masaustunde tetikleyicinin altinda, dar ekranda\n * ekranin dibinde bir alt sayfada. Karar ACILIRKEN verilir — sunucuda ekran\n * genisligi bilinmiyor, ilk boyamada verilecek karar yanlis olurdu.\n */\n const [openMode, setOpenMode] = useState<'popover' | 'sheet' | null>(null);\n const isOpen = openMode !== null;\n const [query, setQuery] = useState('');\n\n // Sunucu araması sırasında seçili kayıt listeden düşebilir; etiketi\n // hatırlarız ki tetikleyici yer tutucuya dönmesin.\n const [cachedLabel, setCachedLabel] = useState<string | null>(null);\n\n const visibleOptions = useMemo(() => {\n // Sunucu araması: gelen liste zaten filtrelidir, tekrar filtrelenmez.\n if (onSearch || query.trim() === '') return options;\n\n const needle = query.trim();\n return options.filter(\n option =>\n matchesSearch(option.label, needle) ||\n (option.description ? matchesSearch(option.description, needle) : false),\n );\n }, [options, query, onSearch]);\n\n const selectedOption = options.find(option => option.value === value) ?? null;\n\n useEffect(() => {\n if (selectedOption) setCachedLabel(selectedOption.label);\n else if (value === null) setCachedLabel(null);\n }, [selectedOption, value]);\n\n const displayLabel = selectedOption?.label ?? cachedLabel;\n\n /*\n * `onSearch` her render'da yeni bir kapanis olabilir; bagimliliga koymak\n * sonsuz dongu uretir. Referansta tutulup etkiden cikarilir.\n */\n const searchRef = useRef(onSearch);\n searchRef.current = onSearch;\n\n useEffect(() => {\n if (!isOpen || !searchRef.current) return;\n\n // Her tuşta istek atmamak için 300 ms beklenir.\n const timer = window.setTimeout(() => searchRef.current?.(query.trim()), 300);\n return () => window.clearTimeout(timer);\n }, [query, isOpen]);\n\n const close = useCallback(() => {\n setOpenMode(null);\n setQuery('');\n }, []);\n\n const open = useCallback(() => {\n if (isDisabled) return;\n setOpenMode(window.matchMedia(ABOVE_MOBILE_MEDIA_QUERY).matches ? 'popover' : 'sheet');\n /* Panel acilinca etkin secenek SECILI olan olur (kancanin `initialIndex`i);\n kullanici listeyi bastan taramak zorunda kalmaz. */\n setQuery('');\n }, [isDisabled]);\n\n /*\n * Disari tiklamada kapanir. `mousedown` kullanilir: `click` beklerken\n * kullanici surukleyerek secim yaparsa panel kapanmiyordu.\n *\n * YALNIZCA masaustu panelinde. Alt sayfa govdeye tasindigi icin `rootRef`\n * onu ICERMIYOR: dinleyici acik kalsaydi panelin icindeki her dokunus\n * \"disari tiklama\" sayilip sayfayi kapatirdi. Orada bu isi perde yapiyor.\n */\n useEffect(() => {\n if (openMode !== 'popover') return;\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) close();\n };\n\n document.addEventListener('mousedown', handlePointerDown);\n return () => document.removeEventListener('mousedown', handlePointerDown);\n }, [openMode, close]);\n\n /*\n * Odak arama kutusuna YALNIZCA masaustu panelinde verilir.\n *\n * Alt sayfada (dar ekran) odaklamak, kullanici yazmak istemedigi halde\n * ekran klavyesini aciyordu: panel yari yuksekluge sikisiyor, uzun listeden\n * ucu besi goruntude kaliyor ve secim yapmak icin once klavyeyi kapatmak\n * gerekiyordu. Masaustunde ekran klavyesi YOK; oradaki odak yazarak\n * aramanin ve ok tuslariyla gezinmenin tek dayanagi.\n *\n * `preventScroll` duruyor: iOS odaklanan kutuyu gorunur kilmak icin SAYFAYI\n * kaydiriyor ve arkadaki liste baska bir yere atliyordu.\n */\n useEffect(() => {\n if (openMode === 'popover') inputRef.current?.focus({ preventScroll: true });\n }, [openMode]);\n\n const selectOption = (option: ComboboxOption<T>) => {\n if (option.isDisabled) return;\n setCachedLabel(option.label);\n onChange(option.value);\n close();\n };\n\n /*\n * Kapaninca odak TETIKLEYICIYE doner.\n *\n * Odagi `close()`in hemen ardindan vermek alt sayfada ise yaramiyordu:\n * panel o an hala kipsel ve `showModal()` disaridaki her ogeyi inert\n * birakiyor — `focus()` sessizce hicbir sey yapmiyor, panel kalkinca da\n * odak `<body>`ye dusuyordu. Kullanici secim yaptiktan sonra sayfanin en\n * basina donuyordu.\n */\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (wasOpenRef.current && !isOpen) triggerRef.current?.focus();\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n /*\n * KLAVYE MODELI `useListboxNavigation`da — `Select`le AYNI kanca.\n *\n * Alti davranis (uclarda donme, `Home`/`End`, secme, `Escape`, `Tab` ile\n * kapatip gezinmeyi surdurme, etkin secenegi gorunur tutma) iki bilesende\n * KOPYA koddu ve ayrisma SESSIZDI: her bilesenin kendi testi vardi ve her\n * biri kendi davranisini dogruluyordu.\n *\n * `Space` BURADA secmez (`hasSpaceSelect` verilmiyor): arama kutusunda\n * bosluk bir KARAKTER ve secime cevrilmesi \"fren balatasi\" yazmayi imkansiz\n * kilardi. `Select`te oyle bir kutu yok ve orada da tetiklenmiyor.\n */\n /*\n * ═══ PANEL SABIT KONUMLU, MUTLAK DEGIL ═══\n *\n * Panel `position: absolute` idi ve tetikleyicinin kapsayicisina gore\n * konumlaniyordu. Kip pencerenin govdesi `overflow: hidden` tasidigi icin\n * (uzun formda basligin sabit kalmasi gerekiyor) panel oraya girdiginde\n * KIRPILIYORDU: \"Aracınızı tanımlayın\" penceresinde marka listesinin\n * yalnizca ilk satiri gorunuyor, gerisi pencerenin alt kenarinda kesiliyordu.\n *\n * `usePositioning` iki sorunu birden cozer: sabit konum kirpan atayi\n * atlar ve asagida yer yoksa paneli YUKARI cevirir. Ayni kanca `Popover`\n * ve `Tooltip` icinde de kullaniliyor — konumlandirma tek yerden.\n */\n const positioning = usePositioning(triggerRef, panelRef, {\n side: 'bottom',\n align: 'start',\n isOpen: isOpen && openMode === 'popover',\n });\n\n const { activeIndex, setActiveIndex, listRef, handleKeyDown } =\n useListboxNavigation<HTMLUListElement>({\n count: visibleOptions.length,\n isOpen,\n initialIndex: Math.max(\n options.findIndex(option => option.value === value),\n 0,\n ),\n onSelect: index => {\n const option = visibleOptions[index];\n if (option) selectOption(option);\n },\n /* Odagi geri vermek kapanisi izleyen etkinin isi (bkz. `wasOpenRef`). */\n onClose: close,\n });\n\n /*\n * SANALLASTIRMA — ve UC kosulu birden.\n *\n * Olculen sorun: 1121 markali bir listede DOM 1121 satir tasiyordu, panel\n * acilisi donuyor ve her tus vurusunda liste yeniden ciziliyordu. Ama kanca\n * SABIT satir yuksekligi istiyor ve burada uc sinir var:\n *\n * 1. `popover` KIPINDE. Alt sayfada kaydiran oge liste degil sayfanin\n * govdesi (`--sheet`: `overflow: visible`); kancanin olctugu kutu hic\n * kaydirilmiyor ve aralik hep basta kalirdi.\n * 2. ACIKLAMASIZ listede. Ikincil satir tasiyan secenek daha uzun; karisik\n * bir listede tek bir `rowHeight` her satiri yanlis konumlandirir.\n * 3. Liste UZUNSA. Kirk satirlik bir listede sanallastirma hicbir sey\n * kazandirmaz, yalnizca bir olcum katmani ekler.\n *\n * Ucu birden saglanmiyorsa liste TAM cizilir — eski davranis.\n */\n const hasDescriptions = visibleOptions.some(option => Boolean(option.description));\n const isVirtual =\n openMode === 'popover' && !hasDescriptions && visibleOptions.length > VIRTUAL_THRESHOLD;\n\n const { scrollRef, range, scrollToIndex } = useVirtualList(visibleOptions.length, {\n rowHeight: OPTION_HEIGHT,\n isEnabled: isVirtual,\n });\n\n /*\n * Etkin secenek CIZILMEMIS olabilir: `scrollIntoView` o satirda calismaz.\n * Konum once hesaplanir, satir sonra cizilir.\n */\n useEffect(() => {\n if (isVirtual) scrollToIndex(activeIndex);\n }, [activeIndex, isVirtual, scrollToIndex]);\n\n /* Iki kanca da AYNI `<ul>`e baglanir: biri etkin secenegi gorunur tutuyor,\n digeri kaydirmayi olcuyor. */\n const attachList = (node: HTMLUListElement | null) => {\n listRef.current = node;\n scrollRef.current = node;\n };\n\n const handleInputKeyDown = handleKeyDown;\n\n const clearSelection = () => {\n onChange(null);\n setCachedLabel(null);\n };\n\n /*\n * Arama ve liste IKI YERDE ayni: masaustu panelinde ve alt sayfada. Ayri\n * ayri yazilsalardi biri guncellenip digeri unutulurdu.\n */\n const search = isSearchHidden ? null : (\n <div className={styles.combobox__search}>\n <Search aria-hidden className={styles.combobox__searchIcon} />\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n className={styles.combobox__searchInput}\n value={query}\n placeholder={text.search}\n autoComplete=\"off\"\n aria-autocomplete=\"list\"\n aria-expanded\n aria-controls={listboxId}\n aria-activedescendant={\n visibleOptions[activeIndex] ? `${baseId}-option-${activeIndex}` : undefined\n }\n aria-label={text.search}\n onChange={event => {\n setQuery(event.target.value);\n setActiveIndex(0);\n }}\n onKeyDown={handleInputKeyDown}\n />\n {isLoading && <Spinner size=\"sm\" label=\"\" />}\n </div>\n );\n\n const renderList = (isSheet: boolean) => {\n /*\n * Cizilen dilim. Sanallastirma kapaliyken aralik tum listeyi kapsiyor\n * (`useVirtualList` olcum yoksa tam listeye duser), yani burada ayri bir\n * kosula gerek yok.\n */\n const slice = visibleOptions.slice(range.start, range.end);\n\n return (\n <ul\n ref={attachList}\n id={listboxId}\n role=\"listbox\"\n className={cx(styles.combobox__list, isSheet && styles['combobox__list--sheet'])}\n >\n {/*\n Kaydirma cubugu GERCEK boyda olmali: cizilmeyen satirlarin yeri\n korunmazsa 1121 ogelik bir liste 16 satirlik bir cubuk gosterir ve\n kullanici listenin bittigini sanardi. Yukseklik ust ve alt bosluklara\n boluniyor — tek bir mutlak konumlu kutu kullanmak `<ul>`in cocuk\n sozlesmesini bozardi (`role=\"listbox\"` yalnizca `option` bekler).\n */}\n {isVirtual && range.offset > 0 && <li aria-hidden style={{ height: range.offset }} />}\n\n {slice.map((option, sliceIndex) => {\n const index = range.start + sliceIndex;\n const isActive = index === activeIndex;\n const isChosen = option.value === value;\n\n return (\n <li key={option.value}>\n <div\n id={`${baseId}-option-${index}`}\n role=\"option\"\n data-index={index}\n /*\n EKRAN OKUYUCU GERCEK SAYIYI DUYMALI. Cizilmeyen satirlar\n yuzunden \"16 secenekten 3.\" deniyordu; dogrusu \"1121\n secenekten 3.\". Ikisi de yalnizca sanallastirma acikken\n yazilir — tam cizilen listede tarayici zaten dogru sayiyor ve\n elle yazmak iki kaynak demek olurdu.\n */\n aria-setsize={isVirtual ? visibleOptions.length : undefined}\n aria-posinset={isVirtual ? index + 1 : undefined}\n aria-selected={isChosen}\n aria-disabled={option.isDisabled}\n className={cx(\n styles.combobox__option,\n isActive && styles['combobox__option--active'],\n isChosen && styles['combobox__option--selected'],\n option.isDisabled && styles['combobox__option--disabled'],\n )}\n // Fare imleci seçeneğin üstündeyken etkin seçenek de oraya\n // taşınır; iki ayrı vurgu kullanıcıyı şaşırtıyordu.\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectOption(option)}\n >\n <span className={styles.combobox__optionText}>\n <span className={styles.combobox__optionLabel}>{option.label}</span>\n {option.description && (\n <span className={styles.combobox__optionDescription}>{option.description}</span>\n )}\n </span>\n\n {isChosen && <CheckLg aria-hidden className={styles.combobox__check} />}\n </div>\n </li>\n );\n })}\n\n {isVirtual && range.end < visibleOptions.length && (\n <li aria-hidden style={{ height: (visibleOptions.length - range.end) * OPTION_HEIGHT }} />\n )}\n\n {visibleOptions.length === 0 && (\n <li className={styles.combobox__empty}>{isLoading ? text.loading : text.empty}</li>\n )}\n </ul>\n );\n };\n\n return (\n <div ref={rootRef} className={cx(styles.combobox, className)} data-testid={testId}>\n <button\n ref={triggerRef}\n id={baseId}\n type=\"button\"\n className={cx(\n styles.combobox__trigger,\n !displayLabel && styles['combobox__trigger--empty'],\n isOpen && styles['combobox__trigger--open'],\n isInvalid && styles['combobox__trigger--invalid'],\n isClearable && displayLabel && !isDisabled && styles['combobox__trigger--clearable'],\n )}\n disabled={isDisabled}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-label={labels.placeholder}\n /*\n Hata `aria-invalid` ile DEGIL `aria-describedby` ile duyurulur:\n `aria-invalid`, `role=\"button\"` uzerinde tanimsizdir ve ekran\n okuyucular onu yok sayar. `Field` hata metnini zaten `role=\"alert\"`\n ile bagliyor; buradaki gorev yalnizca gorsel.\n */\n aria-describedby={describedBy}\n onClick={() => (isOpen ? close() : open())}\n >\n {icon && (\n <span className={styles.combobox__leadingIcon} aria-hidden>\n {icon}\n </span>\n )}\n\n <span className={styles.combobox__value}>{displayLabel ?? labels.placeholder}</span>\n\n {/* Dolu caret — gerekcesi `Select` ile ayni. */}\n <CaretDownFill\n aria-hidden\n className={cx(styles.combobox__chevron, isOpen && styles['combobox__chevron--open'])}\n />\n </button>\n\n {/*\n TEMİZLEME DÜĞMESİ TETİKLEYİCİNİN İÇİNDE DEĞİL, KARDEŞİ.\n\n Önce `<button>`ın içinde `role=\"button\" tabIndex={0}` taşıyan bir\n `<span>` olarak duruyordu; dosyadaki yorum \"DOM'da kardeş\" diyordu ama\n kod öyle değildi. Eksen taraması bunu `nested-interactive` olarak\n bildirdi ve sonucu somut: iç içe etkileşimli öğede ekran okuyucular\n yalnızca dıştaki düğmeyi duyurur, içteki çarpıya klavyeyle ulaşılsa bile\n adı okunmaz — yani \"seçimi temizle\" eylemi destek teknolojisi\n kullanıcısı için YOK. Kardeş olarak çizilip tetikleyicinin üzerine\n konumlandırılıyor; görsel yer aynı, ağaçtaki yeri doğru.\n */}\n {isClearable && displayLabel && !isDisabled && (\n <button\n type=\"button\"\n className={styles.combobox__clear}\n aria-label={text.clear}\n onClick={clearSelection}\n >\n <XLg aria-hidden />\n </button>\n )}\n\n {/* Masaüstü: tetikleyiciye yapışan panel. */}\n {openMode === 'popover' && (\n <div\n ref={panelRef}\n className={styles.combobox__panel}\n style={{\n ...positioning.style,\n /* Panel tetikleyiciyle AYNI genislikte: sabit konum onu\n kapsayicidan kopardigi icin genislik artik miras alinmiyor. */\n width: triggerRef.current?.offsetWidth,\n /* Ilk karede olcu yok; yanlis yerde bir kare parlamasin. */\n visibility: positioning.isPositioned ? undefined : 'hidden',\n }}\n >\n {search}\n {renderList(false)}\n </div>\n )}\n\n {/*\n Dar ekran: alt sayfa. Yapışkan panel telefonda klavye açılınca sıkışıyor\n ve uzun listenin alt ucu ekranın dışında kalıyordu; arama kutusu da\n tetikleyiciyle klavyenin arasına hapsoluyordu. Arama `toolbar`\n yuvasında: başlığın altında sabit kalır, liste altında kayar.\n */}\n {openMode === 'sheet' && (\n <BottomSheet\n title={labels.placeholder}\n closeLabel={labels.closeLabel ?? config?.close}\n onClose={close}\n toolbar={search ?? undefined}\n >\n {renderList(true)}\n </BottomSheet>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(Combobox) as typeof Combobox;\n","'use client';\n\nimport { type KeyboardEvent, memo, type ReactNode, useRef } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\nexport type SegmentOption<T extends string = string> = {\n value: T;\n label: string;\n /** Yalnızca ikon gösterilecekse `label` erişilebilir ad olarak kalır. */\n icon?: ReactNode;\n isDisabled?: boolean;\n};\n\ntype Props<T extends string> = {\n options: SegmentOption<T>[];\n value: T;\n onChange: (value: T) => void;\n /** Grubun erişilebilir adı (\"Görünüm\"). ZORUNLU. */\n label: string;\n /** Etiketler gizlenir, yalnızca ikon çizilir. `label` yine okunur. */\n isIconOnly?: boolean;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Bölmeli denetim — <strong>görünüm</strong> değiştirme.\n *\n * <h3>{@link ChipGroup} ile farkı: filtre mi görünüm mü</h3>\n * İkisi de `radiogroup` ve ikisi de tek seçim; ayrım seçilen şeyin ne\n * olduğunda:\n *\n * <ul>\n * <li>`ChipGroup` bir FİLTRE. Seçim listeyi daraltıyor, seçenek sayısı\n * değişken ve \"hiçbiri\" geçerli bir durum — çipe ikinci kez basmak\n * seçimi kaldırıyor.</li>\n * <li><b>`SegmentedControl` bir GÖRÜNÜM anahtarı.</b> Liste/ızgara,\n * aylık/yıllık, gelen/giden. Seçenek sayısı 2-4 ve SABİT; <strong>seçili\n * durum her zaman tektir</strong> — \"hiçbiri\" diye bir hâl yok, çünkü\n * ekranda bir şey çizilmek zorunda.</li>\n * </ul>\n *\n * <p>Bu yüzden seçili öğeye ikinci kez basmak hiçbir şey yapmaz; `ChipGroup`ta\n * aynı hareket seçimi kaldırıyor. Aynı bileşeni iki iş için kullanmak, bu\n * davranış farkını kaybetmek olurdu.\n *\n * <h3>Neden `Tabs` değil</h3>\n * `Tabs` bir PANEL değiştirir ve `aria-controls` ile ona bağlanır; bölmeli\n * denetim aynı içeriğin başka bir SUNUMUNU seçiyor — gösterilen veri aynı.\n * Sekme olarak sunmak ekran okuyucuya var olmayan bir panel vaat ediyordu.\n *\n * <h3>Klavye (APG: radio group)</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowDown`</td><td>sonraki seçenek; uçlarda DÖNER</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowUp`</td><td>önceki seçenek</td></tr>\n * <tr><td>`Tab`</td><td>grubu TEK durak olarak geçer (dönen `tabindex`)</td></tr>\n * </table>\n */\nconst SegmentedControl = <T extends string>({\n options,\n value,\n onChange,\n label,\n isIconOnly,\n size = 'md',\n className,\n testId,\n}: Props<T>) => {\n const listRef = useRef<HTMLDivElement>(null);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const offset =\n event.key === 'ArrowRight' || event.key === 'ArrowDown'\n ? 1\n : event.key === 'ArrowLeft' || event.key === 'ArrowUp'\n ? -1\n : 0;\n\n if (offset === 0) return;\n event.preventDefault();\n\n const enabled = options.filter(option => !option.isDisabled);\n if (enabled.length === 0) return;\n\n const current = enabled.findIndex(option => option.value === value);\n const next = enabled[(current + offset + enabled.length) % enabled.length];\n\n onChange(next.value);\n listRef.current\n ?.querySelector<HTMLButtonElement>(`[data-value=\"${next.value}\"]`)\n ?.focus({ preventScroll: true });\n };\n\n return (\n <div\n ref={listRef}\n role=\"radiogroup\"\n aria-label={label}\n className={cx(styles.segmented, styles[`segmented--${size}`], className)}\n data-testid={testId}\n onKeyDown={handleKeyDown}\n >\n {options.map(option => {\n const isSelected = option.value === value;\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n aria-label={isIconOnly ? option.label : undefined}\n data-value={option.value}\n disabled={option.isDisabled}\n /* Donen `tabindex`: grup Tab sirasinda TEK durak. Dort segmentin\n her biri durak olsaydi klavye kullanicisi icerige ulasmak icin\n dort kez Tab'liyordu. */\n tabIndex={isSelected ? 0 : -1}\n className={cx(\n styles.segmented__item,\n isSelected && styles['segmented__item--selected'],\n )}\n /*\n * Secili ogeye ikinci kez basmak HICBIR SEY yapmaz: gorunum\n * anahtarinda \"hicbiri\" diye bir hal yok. `ChipGroup`ta ayni\n * hareket secimi kaldiriyor ve iki bileseni ayiran sey tam olarak\n * bu.\n */\n onClick={() => !isSelected && onChange(option.value)}\n >\n {option.icon && (\n <span className={styles.segmented__icon} aria-hidden>\n {option.icon}\n </span>\n )}\n {!isIconOnly && <span className={styles.segmented__label}>{option.label}</span>}\n </button>\n );\n })}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(SegmentedControl, 'SegmentedControl'),\n) as typeof SegmentedControl;\n","'use client';\n\nimport {\n type KeyboardEvent,\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { CaretDownFill, CheckLg } from 'react-bootstrap-icons';\n\nimport useListboxNavigation from '../../hooks/useListboxNavigation';\n\nimport { ABOVE_MOBILE_MEDIA_QUERY } from '../../constants/breakpoint.constants';\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport BottomSheet from '../BottomSheet';\n\nimport styles from './index.module.scss';\n\nexport type SelectOption<T extends string = string> = {\n value: T;\n label: string;\n isDisabled?: boolean;\n};\n\n/**\n * Seçenek listesinin nerede açıldığı.\n *\n * <p>`popover` tetikleyicinin altında, `sheet` ekranın dibinde. Karar\n * <strong>açılırken</strong> verilir; sunucuda ekran genişliği bilinmediği\n * için ilk boyamada verilecek her karar yanlış olurdu.\n */\ntype OpenMode = 'popover' | 'sheet';\n\ntype Props<T extends string> = {\n options: SelectOption<T>[];\n value: T;\n onChange: (value: T) => void;\n /**\n * Alanın adı. İki işi birden yapar: alt sayfanın başlığı olur ve\n * tetikleyicinin <strong>erişilebilir adı</strong>dır.\n *\n * <p>Tetikleyici bir `<button>` ve düğmenin adı HTML-AAM'e göre\n * `<label>`den GELMEZ — görünür bir etiket olsa bile ekran okuyucu yalnızca\n * seçili değeri okur (\"En yeni, düğme\") ve neyi seçtiğini söylemez.\n */\n label: string;\n /** Seçim yokken tetikleyicide görünen metin. Verilmezse `labels.selectPlaceholder`. */\n placeholder?: string;\n /** Alt sayfanın kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n /** Tetikleyicinin solundaki ikon. */\n icon?: ReactNode;\n /** `sm` yoğun şeritler içindir (araç çubuğu); varsayılan form ölçüsü `md`. */\n size?: 'sm' | 'md';\n /**\n * Panelin hangi kenardan hizalanacağı.\n *\n * <p>Şeridin sağ ucundaki bir tetikleyicide `start` hizalama paneli sağa\n * doğru taşırıyordu; `end` panelin sağ kenarını tetikleyiciye yaslar.\n */\n align?: 'start' | 'end';\n isDisabled?: boolean;\n id?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Seçim kutusu.\n *\n * <h3>Yerel `<select>` KULLANILMAZ</h3>\n * Yerel açılır liste her tarayıcıda başka türlü çiziliyor, seçeneklerine tek\n * bir stil verilemiyor (seçili değeri işaretlemek, ikon koymak, satırı\n * yükseltmek yok) ve mobilde ekranın ortasında beliren tekerlek uygulamanın\n * geri kalanına hiç benzemiyordu. Kutu baştan sona bizim: masaüstünde\n * tetikleyicinin altında bir panel, mobilde ekranın dibinden yükselen bir\n * <strong>alt sayfa</strong> açar.\n *\n * <p>Bu, \"yerel öğe taklit öğeden iyidir\" kuralının BİLİNÇLİ tek istisnası:\n * bedeli (odak yönetimi, ok tuşları, `aria-activedescendant`) bir kez ödenip\n * tek bileşene kapatıldı.\n *\n * <h3>Klavye — odak TEK yerde</h3>\n * Panel açıkken odak tetikleyicide kalır, alt sayfada ise listenin kendisine\n * geçer; iki durumda da etkin seçenek `aria-activedescendant` ile bildirilir.\n * Seçenekleri tek tek odaklanabilir yapmak, aynı bileşende iki ayrı klavye\n * modeli demekti (APG: listbox + activedescendant).\n *\n * <table>\n * <tr><td>`ArrowDown`/`ArrowUp`/`Enter`/`Space` (kapalıyken)</td><td>paneli açar</td></tr>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin seçenek bir alt/üst; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son seçenek</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>etkin seçeneği seçer</td></tr>\n * <tr><td>`Escape`</td><td>seçim yapmadan kapatır, odak tetikleyicide</td></tr>\n * <tr><td>`Tab`</td><td>kapatır, gezinme sürer</td></tr>\n * </table>\n * Etkin seçenek açılışta SEÇİLİ olandan başlar. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n *\n * <h3>20+ seçenek varsa bu bileşen DEĞİL</h3>\n * Aramasız bir liste 20 satırdan sonra taranamaz hâle gelir; orada\n * {@link Combobox} kullanılır.\n */\nconst Select = <T extends string>({\n options,\n value,\n onChange,\n label,\n placeholder,\n closeLabel,\n icon,\n size = 'md',\n align = 'start',\n isDisabled,\n id,\n className,\n testId,\n 'aria-describedby': describedBy,\n 'aria-invalid': isInvalid,\n}: Props<T>) => {\n const { labels } = useHanui();\n const emptyText = resolveLabel('Select.placeholder', placeholder, labels?.selectPlaceholder);\n const generatedId = useId();\n const baseId = id ?? generatedId;\n const listboxId = `${baseId}-listbox`;\n const optionId = (index: number) => `${baseId}-option-${index}`;\n\n const rootRef = useRef<HTMLSpanElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const [openMode, setOpenMode] = useState<OpenMode | null>(null);\n\n const isOpen = openMode !== null;\n const selectedIndex = options.findIndex(option => option.value === value);\n const selectedOption = selectedIndex >= 0 ? options[selectedIndex] : null;\n\n const close = useCallback(() => setOpenMode(null), []);\n\n const open = useCallback(() => {\n if (isDisabled || options.length === 0) return;\n\n /* Etkin secenek SECILI olandan baslar (kancanin `initialIndex`i);\n kullanici listeyi bastan taramaz. */\n setOpenMode(window.matchMedia(ABOVE_MOBILE_MEDIA_QUERY).matches ? 'popover' : 'sheet');\n }, [isDisabled, options.length]);\n\n const selectOption = (option: SelectOption<T>) => {\n if (option.isDisabled) return;\n onChange(option.value);\n close();\n };\n\n /*\n * Kapaninca odak TETIKLEYICIYE doner.\n *\n * Odagi `selectOption` icinde geri vermek ise yaramiyor: alt sayfa ayni\n * commit'te DOM'dan kalkiyor ve odaklanan dugme sokulunce odak `<body>`ye\n * dusuyordu — klavye kullanicisi secim yaptiktan sonra sayfanin en basina\n * donuyordu.\n */\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (wasOpenRef.current && !isOpen) triggerRef.current?.focus();\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n /* Disari tiklamada panel kapanir. Alt sayfada bu is perdenin. */\n useEffect(() => {\n if (openMode !== 'popover') return;\n\n const handlePointerDown = (event: globalThis.MouseEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) close();\n };\n\n document.addEventListener('mousedown', handlePointerDown);\n return () => document.removeEventListener('mousedown', handlePointerDown);\n }, [openMode, close]);\n\n\n /*\n * KLAVYE MODELI `useListboxNavigation`da — `Combobox`la AYNI kanca.\n *\n * Alti davranis (uclarda donme, `Home`/`End`, secme, `Escape`, `Tab` ile\n * kapatip gezinmeyi surdurme, etkin secenegi gorunur tutma) iki bilesende\n * KOPYA koddu ve ayrisma sessizdi: her bilesenin kendi testi vardi ve her\n * biri kendi davranisini dogruluyordu.\n */\n const { activeIndex, setActiveIndex, listRef, handleKeyDown } =\n useListboxNavigation<HTMLUListElement>({\n count: options.length,\n isOpen,\n initialIndex: selectedIndex >= 0 ? selectedIndex : 0,\n onSelect: index => {\n const option = options[index];\n if (option) selectOption(option);\n },\n onClose: close,\n });\n\n /*\n * Alt sayfada odak listenin kendisine gecer: ok tuslari orada isler.\n *\n * `preventScroll` ZORUNLU: odaklanan oge ust katmanda duran sabit bir\n * panelin icinde ve iOS onu \"gorunur kilmak\" icin sayfayi kaydiriyor —\n * panel oldugu yerde durdugu icin kaydirmanin tek etkisi, arkadaki sayfanin\n * kullanicinin bakmadigi bir yere atlamasiydi.\n */\n useEffect(() => {\n if (openMode === 'sheet') listRef.current?.focus({ preventScroll: true });\n /* `listRef` kancadan geliyor ve `useRef` kimligi SABIT; bagimlilikta\n olmasi etkiyi yeniden calistirmaz, denetci ise kancadan gelen bir\n degerin referans oldugunu kanitlayamiyor. */\n }, [openMode, listRef]);\n\n /*\n * KAPALIYKEN ok/Enter/Space paneli ACAR. Bu adim kancada DEGIL: acilma\n * karari bilesenin (panel mi alt sayfa mi) ve kanca yalnizca gezinmeyi\n * tasiyor.\n */\n const onKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n if (!isOpen) {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) {\n event.preventDefault();\n open();\n }\n return;\n }\n\n handleKeyDown(event);\n };\n\n const renderList = (isSheet: boolean) => (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n /* Alt sayfada baslik `BottomSheet`in icinde ve kimligi bize kapali;\n listenin adi dogrudan yazilir. */\n aria-label={label}\n /* Odak alt sayfada listede, panelde tetikleyicide: etkin seçeneği\n bildiren öznitelik odağın olduğu öğede durmak zorunda. */\n aria-activedescendant={isSheet && options[activeIndex] ? optionId(activeIndex) : undefined}\n tabIndex={isSheet ? 0 : -1}\n className={cx(styles.list, isSheet && styles['list--sheet'])}\n onKeyDown={isSheet ? onKeyDown : undefined}\n >\n {options.map((option, index) => {\n const isChosen = option.value === value;\n\n return (\n <li\n key={option.value}\n id={optionId(index)}\n role=\"option\"\n data-index={index}\n aria-selected={isChosen}\n aria-disabled={option.isDisabled}\n className={cx(\n styles.option,\n index === activeIndex && styles['option--active'],\n isChosen && styles['option--selected'],\n option.isDisabled && styles['option--disabled'],\n )}\n // Fare imleci seçeneğin üstündeyken etkin seçenek de oraya taşınır;\n // iki ayrı vurgu kullanıcıyı şaşırtıyordu.\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectOption(option)}\n >\n <span className={styles.option__label}>{option.label}</span>\n {isChosen && <CheckLg aria-hidden className={styles.option__check} />}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <span ref={rootRef} className={cx(styles.select, className)} data-testid={testId}>\n <button\n ref={triggerRef}\n id={baseId}\n type=\"button\"\n role=\"combobox\"\n className={cx(\n styles.trigger,\n styles[`trigger--${size}`],\n !selectedOption && styles['trigger--empty'],\n isOpen && styles['trigger--open'],\n )}\n disabled={isDisabled}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={\n openMode === 'popover' && options[activeIndex] ? optionId(activeIndex) : undefined\n }\n aria-label={label}\n aria-describedby={describedBy}\n aria-invalid={isInvalid}\n onClick={() => (isOpen ? close() : open())}\n onKeyDown={onKeyDown}\n >\n {icon && (\n <span className={styles.trigger__icon} aria-hidden>\n {icon}\n </span>\n )}\n\n <span className={styles.trigger__value}>{selectedOption?.label ?? emptyText}</span>\n\n {/*\n * Ok DOLU CARET: ince chevron, kutunun sag ucunda `$text-2` tonunda\n * iki hairline cizgiye iniyor ve kutunun acilir oldugu uzaktan\n * okunmuyordu. Acikken 180° donuyor — yon hâlâ durumu bildiriyor.\n */}\n <CaretDownFill\n aria-hidden\n className={cx(styles.trigger__chevron, isOpen && styles['trigger__chevron--open'])}\n />\n </button>\n\n {openMode === 'popover' && (\n <div className={cx(styles.panel, styles[`panel--${align}`])}>{renderList(false)}</div>\n )}\n\n {/* Dar ekranda liste alt sayfada acilir; panel klavye acilinca sikisiyor\n ve alt ucu ekranin disinda kaliyordu (bkz. `BottomSheet`). */}\n {openMode === 'sheet' && (\n <BottomSheet title={label} closeLabel={closeLabel ?? labels?.close} onClose={close}>\n {renderList(true)}\n </BottomSheet>\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Select) as typeof Select;\n","import { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & {\n label: ReactNode;\n hint?: string;\n testId?: string;\n};\n\n/**\n * Onay kutusu.\n *\n * <p>Yerel `<input type=\"checkbox\">` korunur ve `accent-color` ile\n * renklendirilir. Özel bir kutu çizmek (gizli input + sahte kare) klavye\n * odağını ve ekran okuyucu davranışını elle yeniden kurmayı gerektirir;\n * kazanç görsel, maliyet erişilebilirlik.\n *\n * <p>Tüm satır tıklanabilir (`<label>` sarmalar): 18 px'lik kareyi\n * hedeflemek özellikle dokunmatik ekranda yorucu.\n */\nconst Checkbox = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ label, hint, className, testId, ...rest }, ref) => (\n <label className={cx(styles.checkbox, className)} data-testid={testId}>\n <input ref={ref} type=\"checkbox\" className={styles.checkbox__input} {...rest} />\n <span className={styles.checkbox__body}>\n <span className={styles.checkbox__label}>{label}</span>\n {hint && <span className={styles.checkbox__hint}>{hint}</span>}\n </span>\n </label>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Checkbox, 'Checkbox')) as typeof Checkbox;\n","'use client';\n\nimport { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'role'> & {\n /** Anahtarın görünür etiketi. */\n label: ReactNode;\n /** Etiketin altındaki açıklama; `aria-describedby` ile bağlanır. */\n hint?: string;\n /** Etiket anahtarın SOLUNDA durur — ayar listelerinin yaygın düzeni. */\n isLabelFirst?: boolean;\n testId?: string;\n};\n\n/**\n * Anahtar (switch) — <strong>anında</strong> uygulanan aç/kapa.\n *\n * <h3>`Checkbox` ile farkı: NE ZAMAN etkili olduğu</h3>\n * İkisi de iki durumlu ve ikisi de yerel `<input type=\"checkbox\">` üzerine\n * kurulu; ayrım görünüşte değil ZAMANLAMADA:\n *\n * <ul>\n * <li>{@link Checkbox} bir formda <strong>gönderilecek</strong> seçimdir.\n * \"Sözleşmeyi okudum\" işaretlendiğinde hiçbir şey olmaz; karar\n * \"Kaydet\"e basıldığında geçerli olur. Geri almak için işareti kaldırıp\n * yeniden göndermek gerekir.</li>\n * <li><b>`Switch` ANINDA uygulanır.</b> \"Kampanya bildirimleri\" açıldığı\n * anda sunucuya gider. Kaydet düğmesi yoktur, olmamalıdır da —\n * kullanıcı anahtarı çevirdikten sonra bir düğme aramak zorunda\n * kalıyordu.</li>\n * </ul>\n *\n * <p>Ayrım keyfi değil ekran okuyucuda DUYULUYOR: `role=\"switch\"` \"açık/kapalı\"\n * diye okunur, onay kutusu \"işaretli/işaretsiz\" diye. İkisi kullanıcıya farklı\n * bir söz veriyor.\n *\n * <h3>Yerel öğe korunur</h3>\n * `<input type=\"checkbox\" role=\"switch\">` — `Space` ile değiştirme, `Tab`\n * sırası, form gönderimine katılma ve `:disabled` semantiği tarayıcıdan gelir.\n * `<div role=\"switch\" tabindex=\"0\">` yazmak bunların hepsini elle yeniden\n * kurmak demekti.\n *\n * <h3>Durum RENKLE ANLATILMAZ</h3>\n * Açık ve kapalı hâl arasındaki fark yalnızca zemin rengi olsaydı renk körü\n * bir kullanıcı için iki durum aynı görünürdü (WCAG 1.4.1). Kulp KONUM\n * değiştiriyor — bu bir biçim farkı — ve zorlanmış renk kipinde çerçeve +\n * konum tek başına yeterli kalıyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Space`</td><td>durumu değiştirir</td></tr>\n * </table>\n *\n * @example\n * <Switch\n * label=\"Kampanya bildirimleri\"\n * hint=\"E-posta ile ayda en fazla iki ileti\"\n * checked={isSubscribed}\n * onChange={event => subscribe(event.target.checked)}\n * />\n */\nconst Switch = forwardRef<HTMLInputElement, Props>(\n ({ label, hint, isLabelFirst, className, id, testId, ...rest }, ref) => (\n <label\n className={cx(styles.switch, isLabelFirst && styles['switch--labelFirst'], className)}\n data-testid={testId}\n >\n <input\n ref={ref}\n type=\"checkbox\"\n /*\n * `role=\"switch\"` YEREL onay kutusunun UZERINE yazilir: davranis\n * checkbox'tan gelir, DUYURU switch olur. Ekran okuyucu \"acik/kapali\"\n * der; \"isaretli\" demek kullaniciya yanlis bir soz veriyordu.\n */\n role=\"switch\"\n id={id}\n className={styles.switch__input}\n {...rest}\n />\n\n {/* Kulbun tasiyicisi; gorsel durum tamamen CSS'te. */}\n <span className={styles.switch__track} aria-hidden>\n <span className={styles.switch__thumb} />\n </span>\n\n <span className={styles.switch__text}>\n <span className={styles.switch__label}>{label}</span>\n {hint && <span className={styles.switch__hint}>{hint}</span>}\n </span>\n </label>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Switch, 'Switch')) as typeof Switch;\n","import { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & {\n label: ReactNode;\n hint?: string;\n /** Sağda gösterilen sonuç adedi (filtre listelerinde). */\n count?: number;\n testId?: string;\n};\n\n/**\n * Radyo düğmesi.\n *\n * <p>{@link Checkbox} ile aynı gerekçe: yerel `<input type=\"radio\">` korunur\n * ve `accent-color` ile renklendirilir. Sahte bir daire çizmek ok tuşlarıyla\n * gezinmeyi ve grup duyurusunu elle yeniden kurmayı gerektirirdi.\n *\n * <p>Tüm satır tıklanabilir (`<label>` sarmalar): 18 px'lik daireyi\n * hedeflemek özellikle dokunmatik ekranda yorucu.\n */\nconst Radio = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ label, hint, count, className, testId, ...rest }, ref) => (\n <label className={cx(styles.radio, className)} data-testid={testId}>\n <input ref={ref} type=\"radio\" className={styles.radio__input} {...rest} />\n <span className={styles.radio__body}>\n <span className={styles.radio__label}>{label}</span>\n {hint && <span className={styles.radio__hint}>{hint}</span>}\n </span>\n {isDefined(count) && <span className={styles.radio__count}>{count}</span>}\n </label>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Radio, 'Radio')) as typeof Radio;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport type { CommonElementProps } from '../../types/common-element-props.type';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Radyo grubu adı — aynı gruptaki kartlar ok tuşlarıyla gezilir. */\n name: string;\n value: string;\n isSelected: boolean;\n isDisabled?: boolean;\n onChange: (value: string) => void;\n /** Zengin gövde: kartın içeriği çağırana aittir. */\n children: ReactNode;\n} & CommonElementProps;\n\n/**\n * Seçilebilir kart — zengin gövdeli radyo.\n *\n * <h3>Neden ayrı bir öğe</h3>\n * Varyant seçici ve hesap seçici aynı deseni elle kuruyordu: `<label>` + gizli\n * radyo + gövde + seçili/pasif durum matrisi. İki kopya çoktan ayrışmıştı —\n * biri odak halkasını metnin üstüne, diğeri hiç çizmiyordu; biri seçili zemini\n * boyuyor, diğeri boyamıyordu.\n *\n * <h3>Radyo GERÇEK, daire çizim</h3>\n * `<input type=\"radio\">` görsel olarak gizlenir ama DOM'da kalır: ok\n * tuşlarıyla grup içinde gezinme, `Space` ile seçim ve ekran okuyucu duyurusu\n * tarayıcıdan gelir. Yerel daire bu boyutta bir kartta görsel olarak\n * kaybolduğu için işaret ayrıca çizilir (`__indicator`).\n *\n * <h3>Seçim üç sinyalle</h3>\n * Kenarlık + zemin tinti + dolan işaret aynı anda değişir. İşaretin dolu / boş\n * hâli bir BİÇİM farkıdır — renk tek başına anlam taşımaz (WCAG 1.4.1).\n *\n * <p>Odak halkası kartın kendisinde (`:has(:focus-visible)`): gizli girdiye\n * çizilen halka görünmüyor, yalnızca metne çizilen halka da kartın nerede\n * bittiğini söylemiyordu.\n *\n * <p>{@link Radio} yalın satır içindir, gövde taşıyamaz — ikisi karışmaz.\n */\nconst RadioCard: FC<Props> = ({\n name,\n value,\n isSelected,\n isDisabled,\n onChange,\n children,\n className,\n id,\n testId,\n}) => (\n <label\n className={cx(\n styles.radioCard,\n isSelected && styles['radioCard--selected'],\n isDisabled && styles['radioCard--disabled'],\n className,\n )}\n data-testid={testId}\n >\n <input\n type=\"radio\"\n id={id}\n name={name}\n value={value}\n checked={isSelected}\n disabled={isDisabled}\n onChange={() => onChange(value)}\n className={styles.radioCard__input}\n />\n <span className={styles.radioCard__indicator} aria-hidden />\n <span className={styles.radioCard__body}>{children}</span>\n </label>\n);\n\nexport default /*#__PURE__*/ memo(RadioCard) as typeof RadioCard;\n","'use client';\n\nimport { memo, useCallback } from 'react';\n\nimport { normalize } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\nexport type RangeValue = [number, number];\n\ntype Props = {\n min: number;\n max: number;\n step?: number;\n value: RangeValue;\n /** Sürükleme sürerken her adımda çağrılır — ekrandaki değeri günceller. */\n onChange: (value: RangeValue) => void;\n /**\n * Sürükleme <em>bittiğinde</em> çağrılır. Adres çubuğuna yazmak veya\n * sunucuya istek atmak gibi pahalı işler buraya bağlanır.\n */\n onCommit?: (value: RangeValue) => void;\n /** Ham sayıyı okunur metne çevirir (\"125000\" → \"1.250 TL\"). */\n formatValue?: (value: number) => string;\n /** Grubun erişilebilir adı (\"Fiyat aralığı\"). */\n label: string;\n /** Alt kulbun erişilebilir ad eki. Verilmezse `labels.range.min`. */\n minLabel?: string;\n /** Üst kulbun erişilebilir ad eki. Verilmezse `labels.range.max`. */\n maxLabel?: string;\n isDisabled?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Çift kulplu aralık kaydırıcı.\n *\n * <h3>Neden iki gerçek `<input type=\"range\">`</h3>\n * Kulplar `<div>` ile çizilip sürükleme JavaScript'le yazıldığında klavye\n * desteği, ekran okuyucu duyurusu ve dokunma davranışı elle yeniden kurulmak\n * zorunda kalır — ve pratikte biri hep eksik kalır. Üst üste bindirilmiş iki\n * yerel aralık girdisi bunların hepsini ücretsiz getirir: ok tuşları, Home/End,\n * PageUp/PageDown ve aralık duyurusu kendiliğinden çalışır.\n *\n * <h3>Kulplar birbirini geçemez</h3>\n * Alt kulp üst değeri, üst kulp alt değeri aşamaz. Geçmelerine izin vermek\n * \"en az 8.000, en çok 1.200\" gibi anlamsız bir aralık üretiyordu.\n *\n * <h3>Sayı değil METİN duyurulur</h3>\n * `aria-valuetext` biçimlenmiş değeri taşır. Aksi hâlde ekran okuyucu ham\n * sayıyı (\"bir milyon iki yüz elli bin\") okuyordu.\n *\n * <h3>`onChange` ile `onCommit` ayrıdır</h3>\n * Kaydırırken her adımda adres çubuğuna yazmak, tek bir sürüklemede onlarca\n * gezinme kaydı bırakıp geri tuşunu kullanılamaz hâle getiriyordu. Ekran anında\n * güncellenir (`onChange`), sorgu yalnızca kulp bırakılınca yazılır.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowUp`</td><td>bir adım artırır</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowDown`</td><td>bir adım azaltır</td></tr>\n * <tr><td>`Home` / `End`</td><td>ölçeğin ucuna gider</td></tr>\n * <tr><td>`PageUp` / `PageDown`</td><td>büyük adım</td></tr>\n * </table>\n * Tamamı YEREL öğeden gelir — kütüphane hiçbir tuşu kendisi işlemez. Buraya\n * ait olan iki şey ayrıca ölçülüyor: kulpların birbirini geçmemesi ve\n * `onCommit`in tuş bırakıldığında (`keyup`) çalışması. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst RangeSlider = ({\n min,\n max,\n step = 1,\n value,\n onChange,\n onCommit,\n formatValue = String,\n label,\n minLabel,\n maxLabel,\n isDisabled,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const lowName = resolveLabel('RangeSlider.minLabel', minLabel, labels?.range?.min);\n const highName = resolveLabel('RangeSlider.maxLabel', maxLabel, labels?.range?.max);\n const [low, high] = value;\n\n const handleLowChange = useCallback(\n (raw: number) => onChange([Math.min(raw, high), high]),\n [high, onChange],\n );\n\n const handleHighChange = useCallback(\n (raw: number) => onChange([low, Math.max(raw, low)]),\n [low, onChange],\n );\n\n const commit = useCallback(() => onCommit?.([low, high]), [low, high, onCommit]);\n\n /* `normalize` yuzdeyi verir ve 100'de kirpar; olcek sifir genislikte\n oldugunda (min === max) 0 doner. */\n const span = max - min;\n const lowPercent = span === 0 ? 0 : normalize(low - min, span);\n const highPercent = span === 0 ? 0 : normalize(high - min, span);\n\n /*\n * Iki kulp ust uste geldiginde hangisinin tutulacagi belirsizlesir. Alt kulp\n * olcegin ikinci yarisindaysa one alinir; aksi halde ust kulp onu kapatip\n * alt kulbu yakalanamaz kiliyordu.\n */\n const isLowOnTop = lowPercent > 50;\n\n return (\n <div\n className={cx(styles.range, isDisabled && styles['range--disabled'], className)}\n role=\"group\"\n aria-label={label}\n data-testid={testId}\n >\n <div className={styles.range__readout}>\n <span className={styles.range__value}>{formatValue(low)}</span>\n <span className={styles.range__separator} aria-hidden>\n —\n </span>\n <span className={styles.range__value}>{formatValue(high)}</span>\n </div>\n\n <div className={styles.range__track}>\n {/* Secili aralik: kullanicinin nerede durdugunu tek bakista gosterir. */}\n <span\n className={styles.range__fill}\n style={{ left: `${lowPercent}%`, right: `${100 - highPercent}%` }}\n aria-hidden\n />\n\n <input\n type=\"range\"\n className={styles.range__input}\n style={{ zIndex: isLowOnTop ? 4 : 3 }}\n min={min}\n max={max}\n step={step}\n value={low}\n disabled={isDisabled}\n aria-label={`${label} — ${lowName}`}\n aria-valuetext={formatValue(low)}\n onChange={event => handleLowChange(Number(event.target.value))}\n onPointerUp={commit}\n onKeyUp={commit}\n />\n\n <input\n type=\"range\"\n className={styles.range__input}\n style={{ zIndex: isLowOnTop ? 3 : 4 }}\n min={min}\n max={max}\n step={step}\n value={high}\n disabled={isDisabled}\n aria-label={`${label} — ${highName}`}\n aria-valuetext={formatValue(high)}\n onChange={event => handleHighChange(Number(event.target.value))}\n onPointerUp={commit}\n onKeyUp={commit}\n />\n </div>\n\n {/* Olcegin uclari: kullanici kendi araligini baglama oturtabilmeli. */}\n <div className={styles.range__bounds} aria-hidden>\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(RangeSlider) as typeof RangeSlider;\n","'use client';\n\nimport { memo, useId, useState } from 'react';\n\nimport { StarFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveFormatter } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\n/** Beş puanın her birinin ne anlama geldiği. */\nexport type RatingLabels = Record<1 | 2 | 3 | 4 | 5, string>;\n\ntype Props = {\n value: number | null;\n onChange: (value: number) => void;\n /** Grubun erişilebilir adı (\"Ürün puanı\"). */\n label: string;\n /**\n * Puan açıklamaları. Hem ekran okuyucuya okunur hem de seçildiğinde\n * yıldızların altında yazar. Verilmezse `labels.rating.scale`.\n *\n * <p>Dolu yıldız sayısı tek başına bir renk/şekil sinyali. Yanına açıklama\n * yazmak hem anlamı netleştirir hem de renk körü kullanıcıya ikinci bir ipucu\n * verir (WCAG 1.4.1).\n */\n ratingLabels?: RatingLabels;\n /**\n * Ekran okuyucuda yıldız sayısını okuyan biçimlendirici (\"4 yıldız\").\n * Verilmezse `labels.rating.starCount`.\n */\n formatStarCount?: (star: number) => string;\n isDisabled?: boolean;\n className?: string;\n testId?: string;\n};\n\nconst STARS = [1, 2, 3, 4, 5] as const;\n\n/**\n * Yıldızla puan girişi.\n *\n * <h3>Beş gerçek radyo düğmesi</h3>\n * Yıldızlar `<span>` ile çizilip tıklama JavaScript'e bağlanabilirdi. Bunun\n * yerine `<fieldset>` içinde beş yerel `<input type=\"radio\">` kullanılır ve\n * yıldız görünümü etiketlerine verilir. Böylece ok tuşlarıyla gezinme, Tab\n * davranışı, ekran okuyucuda \"5 seçenekten 4'ü seçili\" duyurusu ve form\n * gönderimine katılma <em>bedava</em> gelir.\n *\n * <p>{@link Rating} genişletilemez: o `<span>` üretiyor ve açıkça\n * salt-gösterim. İkisini tek bileşende toplamak, gösterim tarafına hiç\n * kullanılmayan etkileşim kodu taşımak olurdu.\n *\n * <h3>Klavye (APG: radio group — tamamı YEREL)</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowDown`</td><td>bir sonraki yıldız</td></tr>\n * <tr><td>`ArrowLeft` / `ArrowUp`</td><td>bir önceki yıldız</td></tr>\n * <tr><td>`Tab`</td><td>grubu TEK durak olarak geçer</td></tr>\n * </table>\n * Kütüphane hiçbir tuşu işlemiyor; nöbetçi bu yüzden tuşları değil DEVRİ\n * ölçüyor — beş gerçek radyo, tek grup adı, okunabilir adlar\n * (`components/__tests__/keyboard.test.tsx`). Yıldızlar `<span>`e dönerse\n * test kırılır.\n */\nconst RatingInput = ({\n value,\n onChange,\n label,\n ratingLabels,\n formatStarCount,\n isDisabled,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const scale = ratingLabels ?? labels?.rating?.scale;\n const name = useId();\n const [hovered, setHovered] = useState<number | null>(null);\n\n // Fare yildizlarin uzerindeyken onizleme gosterilir; ayrilinca gercek\n // secime doner.\n const shown = hovered ?? value;\n\n return (\n <fieldset\n className={cx(styles.rating, isDisabled && styles['rating--disabled'], className)}\n disabled={isDisabled}\n data-testid={testId}\n >\n <legend className={styles.rating__legend}>{label}</legend>\n\n <div className={styles.rating__stars} onMouseLeave={() => setHovered(null)}>\n {STARS.map(star => (\n <label\n key={star}\n className={cx(\n styles.rating__star,\n shown !== null && star <= shown && styles['rating__star--filled'],\n )}\n onMouseEnter={() => setHovered(star)}\n >\n <input\n type=\"radio\"\n name={name}\n value={star}\n checked={value === star}\n onChange={() => onChange(star)}\n className={styles.rating__input}\n />\n <StarFill aria-hidden />\n <span className={styles.rating__srOnly}>\n {resolveFormatter(\n 'RatingInput.formatStarCount',\n formatStarCount ?? labels?.rating?.starCount,\n star,\n )}{' '}\n — {scale?.[star] ?? ''}\n </span>\n </label>\n ))}\n </div>\n\n {/* Secim metni: `aria-hidden` cunku ayni bilgi radyonun etiketinde var. */}\n {shown !== null && (\n <span className={styles.rating__caption} aria-hidden>\n {scale?.[shown as 1 | 2 | 3 | 4 | 5] ?? ''}\n </span>\n )}\n </fieldset>\n );\n};\n\nexport default /*#__PURE__*/ memo(RatingInput) as typeof RatingInput;\n","'use client';\n\nimport { type FC, memo, useState } from 'react';\n\nimport { DashLg, PlusLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n value: number;\n onChange: (value: number) => void;\n /** Grubun ve girdinin erişilebilir adı. Verilmezse `labels.quantity.label`. */\n label?: string;\n /** Verilmezse `labels.quantity.decrease`. */\n decreaseLabel?: string;\n /** Verilmezse `labels.quantity.increase`. */\n increaseLabel?: string;\n min?: number;\n max?: number;\n isDisabled?: boolean;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Adet seçici.\n *\n * <p>Doğrudan yazma da desteklenir: 12 adet isteyen kullanıcının artı düğmesine\n * on iki kez basması kabul edilemez.\n *\n * <p>Yazılan değer <strong>odak kaybında</strong> sınırlara çekilir, her tuş\n * vuruşunda değil: \"12\" yazarken \"1\"i anında 1'e sabitlemek kullanıcının\n * yazmasını engellerdi.\n */\nconst QuantityStepper: FC<Props> = ({\n value,\n onChange,\n label,\n decreaseLabel,\n increaseLabel,\n min = 1,\n max = 99,\n isDisabled,\n size = 'md',\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const groupLabel = resolveLabel('QuantityStepper.label', label, labels?.quantity?.label);\n const [draft, setDraft] = useState<string | null>(null);\n\n const commit = (raw: string) => {\n setDraft(null);\n const parsed = Number(raw.replace(/\\D/g, ''));\n if (!parsed) return;\n onChange(Math.min(Math.max(parsed, min), max));\n };\n\n return (\n <div\n className={cx(styles.stepper, styles[`stepper--${size}`], className)}\n role=\"group\"\n aria-label={groupLabel}\n data-testid={testId}\n >\n <button\n type=\"button\"\n className={styles.stepper__button}\n onClick={() => onChange(Math.max(value - 1, min))}\n disabled={isDisabled || value <= min}\n aria-label={resolveLabel(\n 'QuantityStepper.decreaseLabel',\n decreaseLabel,\n labels?.quantity?.decrease,\n )}\n >\n <DashLg aria-hidden />\n </button>\n\n <input\n className={styles.stepper__input}\n value={draft ?? String(value)}\n onChange={event => setDraft(event.target.value.replace(/\\D/g, '').slice(0, 2))}\n onBlur={event => commit(event.target.value)}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n event.preventDefault();\n commit((event.target as HTMLInputElement).value);\n }\n }}\n inputMode=\"numeric\"\n disabled={isDisabled}\n aria-label={`${groupLabel} (${min}-${max})`}\n />\n\n <button\n type=\"button\"\n className={styles.stepper__button}\n onClick={() => onChange(Math.min(value + 1, max))}\n disabled={isDisabled || value >= max}\n aria-label={resolveLabel(\n 'QuantityStepper.increaseLabel',\n increaseLabel,\n labels?.quantity?.increase,\n )}\n >\n <PlusLg aria-hidden />\n </button>\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(QuantityStepper) as typeof QuantityStepper;\n","import { forwardRef, type InputHTMLAttributes, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'aria-label'> & {\n /**\n * Erişilebilir ad — ZORUNLU. Hücrede görünür etiket yok (etiket sütun\n * başlığında); adsız kutu ekran okuyucuda yalnızca \"onay kutusu\" diye\n * okunur. Satır kutusunda kaydın kimliğini söyleyin (\"SP-2026-000123 seç\").\n */\n label: string;\n testId?: string;\n};\n\n/**\n * Tablo hücresindeki toplu seçim kutusu.\n *\n * <h3>Neden `Checkbox` değil</h3>\n * Seçim sütununda etiket sütun başlığıdır ve `Checkbox` bileşeninin ürettiği\n * `<label>` sarmalayıcısı (yan yana kutu + metin yerleşimi) hücreyi bozar.\n * Doğru olan yalın `<input type=\"checkbox\">` + `aria-label` — bu bileşen o\n * deseni resmileştirir ki ekranlar çıplak `<input>` yazmak zorunda kalmasın.\n *\n * <p>Renk `Checkbox` ile aynı kaynaktan: `accent-color` mavi — onay kutusu bir\n * seçimdir, bir dönüşüm değil.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Space`</td><td>seçimi değiştirir</td></tr>\n * </table>\n * Yerel öğe: `Space`, `indeterminate` durumu ve form gönderimine katılma\n * platformdan gelir. Nöbetçi: `components/__tests__/keyboard.test.tsx`.\n */\nconst TableCheckbox = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ label, className, testId, ...rest }, ref) => (\n <input\n ref={ref}\n type=\"checkbox\"\n aria-label={label}\n className={cx(styles.checkbox, className)}\n data-testid={testId}\n {...rest}\n />\n ),\n);\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(TableCheckbox, 'TableCheckbox'),\n) as typeof TableCheckbox;\n","import { forwardRef, type InputHTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/*\n * `prefix` HTML'in RDFa nitelikleri arasinda yer alir ve React onu `string`\n * olarak tanimlar. Kaldirilmazsa kendi `ReactNode` tanimimizla kesisip\n * `string & ReactNode` uretiyor ve ikon vermeyi imkansiz kiliyordu.\n */\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'prefix'> & {\n /** Solda gösterilen ikon veya ön ek (arama simgesi, para birimi). */\n prefix?: ReactNode;\n /** Sağda gösterilen ikon veya birim (göz simgesi, \"kg\"). */\n suffix?: ReactNode;\n /** Teknik veri: SKU, kod, seri numarası — monospace ve harf aralıklı. */\n isTechnical?: boolean;\n testId?: string;\n};\n\n/**\n * Metin girdisi.\n *\n * <p>Ön ek / son ek girdinin <em>içinde</em> konumlanır; girdinin yanına ayrı\n * bir kutu koymak hizalamayı bozar ve odak halkasını ikiye böler.\n *\n * <p>Odak halkası sarmalayıcıda değil girdinin kendisinde: sarmalayıcıya\n * verildiğinde `:focus-visible` klavye/fare ayrımını kaybediyordu.\n */\nconst Input = /*#__PURE__*/ forwardRef<HTMLInputElement, Props>(\n ({ prefix, suffix, isTechnical, className, testId, ...rest }, ref) => (\n <span className={cx(styles.wrapper, className)}>\n {prefix && (\n <span className={styles.wrapper__prefix} aria-hidden>\n {prefix}\n </span>\n )}\n <input\n ref={ref}\n className={cx(\n styles.input,\n /* `Boolean(...)`: `prefix` bir `ReactNode` ve `0` da gecerli bir\n deger — `prefix &&` ifadesi o durumda dize degil sayi donuyordu. */\n Boolean(prefix) && styles['input--hasPrefix'],\n Boolean(suffix) && styles['input--hasSuffix'],\n isTechnical && styles['input--technical'],\n )}\n data-testid={testId}\n {...rest}\n />\n {suffix && (\n <span className={styles.wrapper__suffix} aria-hidden>\n {suffix}\n </span>\n )}\n </span>\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Input, 'Input')) as typeof Input;\n","'use client';\n\nimport { type KeyboardEvent, memo, useId, useRef, useState } from 'react';\n\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport useAnnounce from '../../hooks/useAnnounce';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n values: string[];\n onChange: (values: string[]) => void;\n /** Alanın erişilebilir adı. ZORUNLU. */\n label: string;\n placeholder?: string;\n /** Her etiketin kaldırma düğmesinin ad öneki (\"Kaldır\"). ZORUNLU. */\n removeLabel: string;\n /** Etiketi bitiren tuşlar. Varsayılan `Enter` ve virgül. */\n separators?: string[];\n /** En fazla kaç etiket. Dolduğunda girdi PASİF olur, gizlenmez. */\n maxTags?: number;\n isDisabled?: boolean;\n id?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Etiket girdisi — yazılan metni kaldırılabilir çiplere çevirir.\n *\n * <h3>Yerel `<input>` KORUNUR</h3>\n * Yazma, panodan yapıştırma, mobil klavye ve `Tab` sırası tarayıcıdan geliyor.\n * Çipler girdinin İÇİNDE görünüyor ama DOM'da kardeşi: `<input>` çocuk\n * alamıyor ve çipleri içine koymanın tek yolu girdiyi taklit etmekti.\n *\n * <h3>Neden {@link Combobox} değil</h3>\n * `Combobox` BİLİNEN bir listeden seçtiriyor; burada değer serbest — kullanıcı\n * listede olmayan bir şey yazıyor (arama terimi, OEM kodu, e-posta). Seçilecek\n * bir liste varsa `Combobox` doğrusu.\n *\n * <h3>Yinelenen değer sessizce YUTULMAZ</h3>\n * Aynı etiket ikinci kez yazıldığında eklenmiyor ama girdi de temizleniyor;\n * kullanıcı \"yazdım, kayboldu\" diyordu. Artık var olan çip bir kare\n * vurgulanıyor ve ekran okuyucuya \"zaten ekli\" duyuruluyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Enter` / `,`</td><td>yazılanı etikete çevirir</td></tr>\n * <tr><td>`Backspace` (girdi BOŞken)</td><td>SON etiketi kaldırır</td></tr>\n * <tr><td>`Tab`</td><td>girdiden çıkar — yazılan metin de etikete DÖNER</td></tr>\n * <tr><td>çipin çarpısı</td><td>o etiketi kaldırır</td></tr>\n * </table>\n * `Tab`ta yazılanın etikete dönmesi bilinçli: yarım kalmış bir metin alanı\n * terk edildiğinde kayboluyordu ve kullanıcı bunu ancak gönderdikten sonra\n * fark ediyordu.\n */\nconst TagInput = ({\n values,\n onChange,\n label,\n placeholder,\n removeLabel,\n separators = ['Enter', ','],\n maxTags,\n isDisabled,\n id,\n className,\n testId,\n 'aria-describedby': describedBy,\n 'aria-invalid': isInvalid,\n}: Props) => {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const inputRef = useRef<HTMLInputElement>(null);\n const announce = useAnnounce();\n\n const [draft, setDraft] = useState('');\n /* Yinelenen deger: var olan cip bir kare vurgulanir. */\n const [duplicate, setDuplicate] = useState<string | null>(null);\n\n const isFull = maxTags !== undefined && values.length >= maxTags;\n\n const commit = (raw: string) => {\n const value = raw.trim();\n if (value === '') return;\n\n if (values.includes(value)) {\n /* Sessizce yutmak yerine GOSTER: kullanici \"yazdim, kayboldu\" diyordu. */\n setDuplicate(value);\n window.setTimeout(() => setDuplicate(null), 1_000);\n announce(`${value} zaten ekli`, 'assertive');\n setDraft('');\n return;\n }\n\n if (isFull) return;\n\n onChange([...values, value]);\n setDraft('');\n announce(`${value} eklendi`);\n };\n\n const remove = (value: string) => {\n onChange(values.filter(item => item !== value));\n announce(`${value} kaldırıldı`);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (separators.includes(event.key)) {\n event.preventDefault();\n commit(draft);\n return;\n }\n\n /*\n * BOS girdide Backspace SON etiketi kaldirir — metin varken kaldirmaz.\n * Kosulsuz yazildiginda kullanici bir harf silmek isterken etiketi\n * siliyordu.\n */\n if (event.key === 'Backspace' && draft === '' && values.length > 0) {\n remove(values[values.length - 1]);\n }\n };\n\n return (\n <div\n className={cx(\n styles.tagInput,\n isDisabled && styles['tagInput--disabled'],\n isInvalid && styles['tagInput--invalid'],\n className,\n )}\n data-testid={testId}\n /* Kutunun herhangi bir yerine tiklamak girdiyi odaklar: cipler arasindaki\n bosluga tiklayan kullanici hicbir sey olmadigini saniyordu. */\n onClick={() => inputRef.current?.focus()}\n >\n {values.map(value => (\n <span\n key={value}\n className={cx(\n styles.tagInput__tag,\n duplicate === value && styles['tagInput__tag--duplicate'],\n )}\n >\n {value}\n\n <button\n type=\"button\"\n className={styles.tagInput__remove}\n /* Ad degeri ICERIR: on bes cipin hepsi \"Kaldir\" diye okundugunda\n hangisi oldugu belli olmuyordu. */\n aria-label={`${value} — ${removeLabel}`}\n disabled={isDisabled}\n onClick={event => {\n event.stopPropagation();\n remove(value);\n }}\n >\n <XLg aria-hidden />\n </button>\n </span>\n ))}\n\n <input\n ref={inputRef}\n id={inputId}\n type=\"text\"\n className={styles.tagInput__field}\n value={draft}\n placeholder={values.length === 0 ? placeholder : undefined}\n aria-label={label}\n aria-describedby={describedBy}\n aria-invalid={isInvalid}\n disabled={isDisabled || isFull}\n onChange={event => setDraft(event.target.value)}\n onKeyDown={handleKeyDown}\n /* Alan terk edildiginde yazilan metin ETIKETE DONER: yarim kalmis bir\n metin kayboluyor ve kullanici bunu ancak gonderdikten sonra fark\n ediyordu. */\n onBlur={() => commit(draft)}\n />\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(TagInput, 'TagInput')) as typeof TagInput;\n","'use client';\n\nimport {\n forwardRef,\n memo,\n type TextareaHTMLAttributes,\n useCallback,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = TextareaHTMLAttributes<HTMLTextAreaElement> & {\n /**\n * Alan içeriğiyle birlikte BÜYÜR — kaydırma çubuğu yerine yükseklik.\n *\n * <p>Sabit yükseklikli bir alanda kullanıcı yazdığının tamamını göremiyor:\n * dört satırlık bir kutuya on satır yazan kişi, gönderdiğinde ne yazdığını\n * kontrol etmek için kutunun içinde kaydırmak zorunda kalıyordu. `maxRows`\n * ile tavan konur; ötesinde kaydırma geri döner (sayfa boyunca uzayan bir\n * alan, altındaki gönder düğmesini ekrandan çıkarıyordu).\n */\n isAutoSize?: boolean;\n /** Otomatik büyümenin tavanı (satır). */\n maxRows?: number;\n /**\n * Kalan karakter sayacını gösterir. `maxLength` ile birlikte anlamlı.\n *\n * <p>Sayaç `aria-hidden`: aynı bilgi her tuşta duyurulsaydı yazma\n * kesintiye uğrardı. Sınıra YAKLAŞILDIĞINDA (son %10) sayaç uyarı tonuna\n * geçiyor — sınıra çarpıp yazamamak, yaklaştığını görmemekten kötü.\n */\n hasCounter?: boolean;\n testId?: string;\n};\n\n/**\n * Çok satırlı metin girdisi.\n *\n * <p>Görünüm {@link Input} ile aynı gövdeden gelir: bir formda tek satırlı ve\n * çok satırlı alanlar yan yana durur, kenarlık ve odak davranışları ayrışırsa\n * form derlenmemiş görünür.\n *\n * <p>Yeniden boyutlandırma yalnızca <strong>dikey</strong>: yatayda büyütmek\n * alanı kapsayıcısının dışına taşırıp yerleşimi bozuyordu.\n *\n * <h3>Otomatik yükseklik neden CSS ile değil</h3>\n * `field-sizing: content` bu işi tek satırda yapıyor ama bugün yalnızca\n * Chromium'da var. Ölçüm yolu her yerde çalışıyor ve tarayıcı desteği\n * geldiğinde tek dosyada değiştirilecek.\n */\nconst Textarea = /*#__PURE__*/ forwardRef<HTMLTextAreaElement, Props>(\n (\n {\n className,\n rows = 4,\n isAutoSize,\n maxRows = 12,\n hasCounter,\n maxLength,\n value,\n defaultValue,\n onChange,\n testId,\n ...rest\n },\n ref,\n ) => {\n const innerRef = useRef<HTMLTextAreaElement | null>(null);\n /*\n * KONTROLLU kipte uzunluk `value`dan OKUNUR, ic durumdan degil.\n *\n * Sayac yalnizca `onChange` ile guncelleniyordu: disaridan gelen her deger\n * degisimi (profilden on doldurma, form sifirlama, tasklaktan gelen taslak)\n * sayaci ESKI sayida birakiyordu. Kullanici 400 karakterlik bir metni\n * yukleyip \"12 / 500\" okuyordu.\n */\n const [innerLength, setLength] = useState(String(defaultValue ?? '').length);\n const length = value === undefined ? innerLength : String(value).length;\n\n /* Cagiranin `ref`i ile ic olcum referansini birlikte tut: `useImperativeHandle`\n yalnizca bir nesne dondurur ve DOM dugumunun kendisini gizlerdi. */\n const setRefs = useCallback(\n (node: HTMLTextAreaElement | null) => {\n innerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref],\n );\n\n /*\n * OLCUM BOYAMADAN ONCE: `useEffect` ile alan bir kare boyunca eski\n * yuksekligiyle cizilip sonra ziplyordu.\n *\n * `height: auto` ONCE yazilir — yoksa `scrollHeight` bir onceki (buyuk)\n * yuksekligi raporluyor ve alan bir daha hic kucumuyordu.\n */\n useLayoutEffect(() => {\n const node = innerRef.current;\n if (!isAutoSize || !node) return;\n\n node.style.height = 'auto';\n\n const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 20;\n const max = lineHeight * maxRows;\n\n node.style.height = `${Math.min(node.scrollHeight, max)}px`;\n node.style.overflowY = node.scrollHeight > max ? 'auto' : 'hidden';\n }, [isAutoSize, maxRows, value, length]);\n\n const isNearLimit = maxLength !== undefined && length >= maxLength * 0.9;\n\n return (\n <div className={cx(styles.wrapper, className)} data-testid={testId}>\n <textarea\n ref={setRefs}\n rows={rows}\n className={cx(styles.textarea, isAutoSize && styles['textarea--autoSize'])}\n maxLength={maxLength}\n value={value}\n defaultValue={defaultValue}\n onChange={event => {\n setLength(event.target.value.length);\n onChange?.(event);\n }}\n {...rest}\n />\n\n {hasCounter && maxLength !== undefined && (\n /* `aria-hidden`: ayni bilgi her tusta duyurulsaydi yazma kesintiye\n ugrardi. Sinir zaten `maxLength` ile taniniyor. */\n <span\n className={cx(styles.counter, isNearLimit && styles['counter--near'])}\n aria-hidden\n >\n {length} / {maxLength}\n </span>\n )}\n </div>\n );\n },\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Textarea, 'Textarea')) as typeof Textarea;\n","'use client';\n\nimport { forwardRef, type InputHTMLAttributes, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & {\n /** `date` (varsayılan) · `datetime-local` · `month` · `time`. */\n type?: 'date' | 'datetime-local' | 'month' | 'time';\n testId?: string;\n};\n\n/**\n * Tarih alanı — <strong>yerel</strong> `<input type=\"date\">`.\n *\n * <h3>Neden taklit bir takvim YOK</h3>\n * Bu kütüphanenin kuralı: yerel öğe korunur, taklit yazmanın tek gerekçesi\n * ölçülmüş bir kusurdur ({@link Select} bunun tek istisnası ve gerekçesi\n * orada yazılı). Tarih alanında böyle bir kusur YOK — tersine, yerel öğenin\n * taklidin veremeyeceği dört şeyi var:\n *\n * <ul>\n * <li><b>Mobilde işletim sisteminin seçicisi.</b> iOS'ta tekerlek, Android'de\n * takvim — kullanıcının her gün kullandığı, alışkın olduğu arayüz. Hiçbir\n * web takvimi 360 px'lik bir ekranda ona yaklaşamıyor.</li>\n * <li><b>Klavyeyle YAZARAK giriş.</b> Doğum tarihini bilen biri \"01.01.1980\"i\n * üç saniyede yazıyor; taklit takvimde aynı iş kırk yıl geriye tıklamak\n * demek.</li>\n * <li><b>Yerel biçim.</b> Tarayıcı kullanıcının işletim sistemi ayarına göre\n * gg.aa.yyyy ya da mm/dd/yyyy gösteriyor; değer her zaman ISO\n * (`YYYY-MM-DD`) kalıyor. İki biçimi elle yönetmek, kütüphanenin\n * kullanıcının yerel ayarını TAHMİN etmesi demekti.</li>\n * <li><b>Ekran okuyucu.</b> Alan üç ayrı bölüm (gün/ay/yıl) olarak okunuyor\n * ve ok tuşlarıyla artırılıyor. APG'ye uygun bir takvim ızgarası bunu\n * ancak taklit edebilir.</li>\n * </ul>\n *\n * <p>Bedeli: takvim açılışının görünüşü tarayıcıya ait ve tema token'larını\n * izlemiyor. Kabul edildi — açılan panelin rengi, yukarıdaki dördünün\n * yanında küçük bir bedel.\n *\n * <h3>`min` / `max` KULLANIN</h3>\n * İkisi de yerel öğede var ve tarayıcı doğrulamayı kendisi yapıyor. Geçersiz\n * bir tarihi yalnızca gönderimde yakalamak, kullanıcıyı formu doldurduktan\n * sonra geri gönderiyordu.\n */\nconst DateField = forwardRef<HTMLInputElement, Props>(\n ({ type = 'date', className, testId, ...rest }, ref) => (\n <input\n ref={ref}\n type={type}\n className={cx(styles.dateField, className)}\n data-testid={testId}\n {...rest}\n />\n ),\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(DateField, 'DateField')) as typeof DateField;\n\nexport type DateRangeValue = {\n /** ISO tarih (`YYYY-MM-DD`) ya da boş dize. */\n start: string;\n end: string;\n};\n\ntype RangeProps = {\n value: DateRangeValue;\n onChange: (value: DateRangeValue) => void;\n /** Başlangıç alanının erişilebilir adı (\"Başlangıç\"). ZORUNLU. */\n startLabel: string;\n /** Bitiş alanının erişilebilir adı (\"Bitiş\"). ZORUNLU. */\n endLabel: string;\n /** İki alanın arasındaki ayraç. Varsayılan yarım tire. */\n separator?: string;\n /** Ölçeğin uçları; ikisi de yerel öğeye geçer. */\n min?: string;\n max?: string;\n /** Seçilen aralığın okunur özetini gösterir. */\n isSummaryVisible?: boolean;\n isDisabled?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Tarih aralığı — <strong>iki yerel alan</strong>, taklit takvim değil.\n *\n * <h3>Neden taklit bir aralık takvimi yazılmadı</h3>\n * Taklit bir ay ızgarasının tek gerçek üstünlüğü var: iki ucu AYNI ANDA\n * görmek. Bedeli ise {@link DateField} JSDoc'unda sayılan dört şeyin\n * tamamını kaybetmek — işletim sisteminin seçicisi, yazarak giriş, yerel\n * biçim ve ekran okuyucunun bölümlü okuması — artı APG'ye uygun bir ızgara\n * klavye modelini (`ArrowUp/Down` hafta, `PageUp/Down` ay, `Home/End` hafta\n * sınırı) sıfırdan yazmak.\n *\n * <p>Takas ölçüldüğünde iki uç arasında kalıyor ve karar <strong>henüz\n * verilmedi</strong>: bu bileşen bugün iki yerel alanı doğru şekilde\n * eşleştiriyor. Aynı ekranda ay ızgarası gerçekten gerekiyorsa (bir otel\n * rezervasyonu gibi, \"boş günleri gör\" ihtiyacı olan bir akış) o zaman\n * yazılır ve gerekçesi <em>o ihtiyaç</em> olur — \"aralık seçimi\" tek başına\n * yeterli bir gerekçe değil.\n *\n * <h3>İki uç birbirini KISITLAR</h3>\n * Başlangıç seçildiğinde bitiş alanının `min`i, bitiş seçildiğinde\n * başlangıcın `max`ı güncelleniyor: tarayıcı geçersiz aralığı en baştan\n * seçtirmiyor. Sonradan doğrulayıp hata göstermek, kullanıcıyı yaptığı bir\n * seçimden geri döndürüyordu.\n */\nconst DateRangeBase = ({\n value,\n onChange,\n startLabel,\n endLabel,\n separator = '–',\n min,\n max,\n isSummaryVisible,\n isDisabled,\n className,\n testId,\n}: RangeProps) => {\n const { labels } = useHanui();\n\n /*\n * OZET `Intl` ile ve `labels.locale`den.\n *\n * Iki ISO tarih kullanici icin bir aralik degil iki sayi. Yerel ayar\n * KUTUPHANE tarafindan TAHMIN EDILMEZ; verilmediginde ozet hic cizilmez —\n * yanlis bicimde bir tarih, hic tarih olmamasindan kotu.\n */\n const summary = (() => {\n if (!isSummaryVisible || !labels?.locale || value.start === '' || value.end === '') return null;\n\n try {\n const format = new Intl.DateTimeFormat(labels.locale, { dateStyle: 'medium' });\n return `${format.format(new Date(value.start))} ${separator} ${format.format(new Date(value.end))}`;\n } catch {\n /* Gecersiz yerel ayar ya da tarih: ozet cizilmez, alanlar calismaya\n devam eder. Bir bicimlendirme hatasi girisi engellememeli. */\n return null;\n }\n })();\n\n return (\n <div className={cx(styles.range, className)} data-testid={testId}>\n <div className={styles.range__row}>\n <DateField\n className={styles.range__field}\n aria-label={startLabel}\n value={value.start}\n min={min}\n /* Baslangic bitisi GECEMEZ: tarayici gecersiz araligi en bastan\n sectirmiyor. */\n max={value.end || max}\n disabled={isDisabled}\n onChange={event => onChange({ ...value, start: event.target.value })}\n />\n\n <span className={styles.range__separator} aria-hidden>\n {separator}\n </span>\n\n <DateField\n className={styles.range__field}\n aria-label={endLabel}\n value={value.end}\n min={value.start || min}\n max={max}\n disabled={isDisabled}\n onChange={event => onChange({ ...value, end: event.target.value })}\n />\n </div>\n\n {summary && <span className={styles.range__summary}>{summary}</span>}\n </div>\n );\n};\n\nexport const DateRange = /*#__PURE__*/ named(/*#__PURE__*/ memo(DateRangeBase), 'DateRange');\n","import { type FC, memo, type ReactNode, useId } from 'react';\n\nimport { ExclamationCircleFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\n/** Girdiye yayılacak erişilebilirlik bağları. */\nexport type FieldChildProps = {\n id: string;\n 'aria-invalid'?: boolean;\n 'aria-describedby'?: string;\n required?: boolean;\n};\n\ntype BaseProps = {\n label: string;\n /** Girdi bileşenini alan `id` ve `aria-*` bağlarıyla üretir. */\n children: (props: FieldChildProps) => ReactNode;\n hint?: string;\n error?: string;\n /** Etiketi gizler ama ekran okuyucuya bırakır (arama kutusu gibi). */\n isLabelHidden?: boolean;\n className?: string;\n};\n\ntype Props = BaseProps & {\n isRequired?: boolean;\n /**\n * Zorunluluk yıldızının ekran okuyucu karşılığı (\"(zorunlu)\").\n *\n * <p>Yıldız yalnızca GÖRSEL bir kısayol; renk ve şekil tek başına anlam\n * taşıyamaz (WCAG 1.4.1), o yüzden yanında okunabilir bir metin olmak\n * zorunda. Verilmezse `labels.required` okunur.\n */\n requiredLabel?: string;\n};\n\n/**\n * Form alanı sarmalayıcısı.\n *\n * <h3>Neden render-prop</h3>\n * Etiket, hata mesajı ve yardım metni girdiye `id` / `aria-describedby` /\n * `aria-invalid` ile <strong>bağlanmak zorunda</strong> — yoksa ekran okuyucu\n * hatayı okumaz. Bu bağları her form alanında elle yazmak kaçınılmaz olarak\n * bir yerde atlanıyor.\n *\n * <p>Render-prop kalıbı bağları bileşene ürettirir: çağıran taraf yalnızca\n * aldığı props'ları girdiye yayar ve erişilebilirlik kendiliğinden doğru olur.\n *\n * <p>Hata varken yardım metni gösterilmez: ikisi birlikte gürültü yapar ve\n * kullanıcının okuması gereken mesaj kaybolur.\n *\n * @example\n * <Field label=\"E-posta\" isRequired requiredLabel=\"(zorunlu)\" error={emailError}>\n * {props => <Input {...props} type=\"email\" value={email} onChange={onChange} />}\n * </Field>\n *\n * @example\n * // `{...props}` yaymayan bileşenlerde (Combobox, Select) yalnızca `id`:\n * <Field label=\"Şehir\">{props => <Combobox id={props.id} … />}</Field>\n */\nconst Field: FC<Props> = ({\n label,\n children,\n hint,\n error,\n isRequired,\n requiredLabel,\n isLabelHidden,\n className,\n}) => {\n const { labels } = useHanui();\n const id = useId();\n const errorId = `${id}-error`;\n const hintId = `${id}-hint`;\n\n return (\n <div className={cx(styles.field, className)}>\n <label\n htmlFor={id}\n className={cx(styles.field__label, isLabelHidden && styles['field__label--hidden'])}\n >\n {label}\n {isRequired && (\n <>\n <span className={styles.field__required} aria-hidden>\n *\n </span>\n <span className={styles.field__srOnly}>\n {resolveLabel('Field.requiredLabel', requiredLabel, labels?.required)}\n </span>\n </>\n )}\n </label>\n\n {children({\n id,\n required: isRequired || undefined,\n 'aria-invalid': error ? true : undefined,\n /*\n * HATA VE YARDIM BIRLIKTE baglanir, biri digerini EZMEZ.\n *\n * Once hata varken yalnizca hata baglaniyordu ve yardim metni ekran\n * okuyucudan DUSUYORDU: \"telefon gecersiz\" duyan kullanici, bir satir\n * yukarida duran \"05XX XXX XX XX\" bicim ipucunu hic duymuyor ve neyi\n * yanlis yazdigini bilmiyordu. Goren kullanici ikisini de aliyor;\n * ayrim sebepsizdi.\n *\n * Sira ONEMLI: once hata, sonra yardim. Ekran okuyucu bagli metinleri\n * yazildiklari sirayla okuyor ve once \"ne yanlis\" duyulmali.\n */\n 'aria-describedby': [error && errorId, hint && hintId].filter(Boolean).join(' ') || undefined,\n })}\n\n {/*\n HATA VE IPUCU BIRLIKTE cizilir.\n\n Ipucu eskiden hatanin ALTERNATIFIYDI: hata belirir belirmez kural\n ekrandan siliniyordu. Yani kullanici tam olarak kurali okumasi gereken\n anda onu kaybediyordu — \"Cok kisa\" diyor ama neye gore kisa oldugunu\n artik hicbir yer yazmiyor. `aria-describedby` de ikisini birden\n gosteriyor; biri cizilmediginde bag BOS bir dugume isaret ediyordu.\n */}\n {error && (\n <p id={errorId} className={styles.field__error} role=\"alert\">\n <ExclamationCircleFill aria-hidden className={styles.field__errorIcon} />\n {error}\n </p>\n )}\n\n {hint && (\n <p id={hintId} className={styles.field__hint}>\n {hint}\n </p>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(Field) as typeof Field;\n","'use client';\n\nimport { memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/** Yüzdeyi 0-100 aralığına kırpar; ölçek sıfır genişlikteyse 0 döner. */\nconst toPercent = (value: number, max: number): number => {\n if (!Number.isFinite(value) || !Number.isFinite(max) || max <= 0) return 0;\n return Math.min(100, Math.max(0, (value / max) * 100));\n};\n\ntype Props = {\n /**\n * Tamamlanan miktar. `undefined` → BELİRSİZ ilerleme (sonu bilinmiyor);\n * çubuk kendi kendine akar.\n */\n value?: number;\n /** Ölçeğin üst ucu. */\n max?: number;\n /** Çubuğun erişilebilir adı (\"Yükleme\", \"Ödeme adımı\"). ZORUNLU. */\n label: string;\n /**\n * Ekran okuyucuya okunan METİN karşılığı (\"3 / 5 dosya\").\n *\n * <p>Verilmezse ekran okuyucu ham yüzdeyi okur. Bir dosya yüklemesinde\n * \"yüzde altmış\" ile \"5 dosyadan 3'ü\" arasındaki fark, kullanıcının\n * bekleyip beklememeye karar verebilmesi.\n */\n valueText?: string;\n /** Yüzdeyi çubuğun yanında GÖRÜNÜR olarak yazar. */\n isValueVisible?: boolean;\n tone?: 'brand' | 'success' | 'warning' | 'danger';\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * İlerleme çubuğu — <strong>ölçülebilir</strong> bekleme.\n *\n * <h3>{@link Spinner} ile farkı: sonu bilinip bilinmediği</h3>\n * `Spinner` \"bir şey oluyor\" der ve başka bir şey söyleyemez. Ölçülebilir bir\n * işte (dosya yükleme, içe aktarma, çok adımlı ödeme) bu yetmiyor: kullanıcı\n * beklemeye değip değmeyeceğine karar veremiyor ve iki saniyeyle iki dakika\n * arasındaki farkı ancak bekleyerek öğreniyordu.\n *\n * <p>`value` verilmediğinde çubuk BELİRSİZ kipe düşer: yine bir çubuk çizer\n * ama `aria-valuenow` yazmaz. Bu kasıtlı — bilinmeyen bir değeri \"0\" diye\n * bildirmek, ekran okuyucuya işin hiç ilerlemediğini söylüyordu.\n *\n * <h3>Yüzde tek başına yeterli DEĞİL</h3>\n * `valueText` verildiğinde ekran okuyucu onu okur (\"5 dosyadan 3'ü\"), yüzdeyi\n * değil. Aynı bilgi görsel tarafta `isValueVisible` ile yazılabiliyor; ikisi\n * de aynı gerçeği söylemek zorunda.\n *\n * <h3>Renk tek başına anlam taşımaz</h3>\n * `tone` yalnızca bir vurgu: \"tamamlandı\" ya da \"başarısız\" durumu çubuğun\n * rengiyle DEĞİL, yanındaki metinle ve çağıran tarafın çizdiği ikonla\n * anlatılır (WCAG 1.4.1).\n */\nconst Progress = ({\n value,\n max = 100,\n label,\n valueText,\n isValueVisible,\n tone = 'brand',\n size = 'md',\n className,\n testId,\n}: Props) => {\n const isIndeterminate = value === undefined;\n const percent = isIndeterminate ? 0 : toPercent(value, max);\n\n return (\n <div className={cx(styles.progress, className)} data-testid={testId}>\n <div\n role=\"progressbar\"\n aria-label={label}\n /*\n * BELIRSIZ kipte `aria-valuenow` YAZILMAZ. Ozniteligin yoklugu, ARIA'da\n * \"deger bilinmiyor\" demek; `0` yazmak ekran okuyucuya isin hic\n * ilerlemedigini soyluyordu.\n */\n aria-valuenow={isIndeterminate ? undefined : Math.round(percent)}\n aria-valuemin={isIndeterminate ? undefined : 0}\n aria-valuemax={isIndeterminate ? undefined : 100}\n aria-valuetext={isIndeterminate ? undefined : valueText}\n className={cx(\n styles.progress__track,\n styles[`progress__track--${size}`],\n isIndeterminate && styles['progress__track--indeterminate'],\n )}\n >\n <span\n className={cx(styles.progress__fill, styles[`progress__fill--${tone}`])}\n style={isIndeterminate ? undefined : { inlineSize: `${percent}%` }}\n />\n </div>\n\n {isValueVisible && !isIndeterminate && (\n /* Gorsel yuzde `aria-hidden`: ayni bilgi zaten `progressbar`in\n degerinde ve iki kez duyurulmasi gurultu. */\n <span className={styles.progress__value} aria-hidden>\n {valueText ?? `%${Math.round(percent)}`}\n </span>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Progress, 'Progress')) as typeof Progress;\n\ntype CircleProps = {\n /** Tamamlanan miktar. `undefined` → BELİRSİZ; çember döner. */\n value?: number;\n max?: number;\n /** Erişilebilir ad. ZORUNLU. */\n label: string;\n valueText?: string;\n /** Yüzdeyi çemberin ortasına yazar. */\n isValueVisible?: boolean;\n tone?: 'brand' | 'success' | 'warning' | 'danger';\n /** Dış çap (px). */\n size?: number;\n className?: string;\n testId?: string;\n};\n\n/**\n * Dairesel ilerleme.\n *\n * <h3>Ne zaman çubuk, ne zaman çember</h3>\n * Çubuk bir SATIRA aittir ve yanındaki metinle okunur; çember bir KUTUYA\n * aittir (kart köşesi, avatar yerine geçen madalyon, dip şeritteki adım\n * göstergesi). Kararı yer belirler, tercih değil: dar bir kutuda çubuk 30\n * piksele düşüp okunamaz hâle geliyordu.\n *\n * <h3>Ölçü prop, token DEĞİL</h3>\n * Çemberin çapı `stroke-dasharray` hesabına giriyor ve o hesap JavaScript'te\n * yapılıyor: CSS değişkeninden okunamaz. Bu yüzden `size` bir sayı — ölçü\n * ölçeğinin dışında kalan tek yer ve nedeni bu.\n */\nconst ProgressCircleBase = ({\n value,\n max = 100,\n label,\n valueText,\n isValueVisible,\n tone = 'brand',\n size = 44,\n className,\n testId,\n}: CircleProps) => {\n const isIndeterminate = value === undefined;\n const percent = isIndeterminate ? 25 : toPercent(value, max);\n\n /* Cizgi kalinligi capin ~%10'u: sabit bir kalinlik kucuk cemberde kutuyu\n dolduruyor, buyugunde sac teline donuyordu. */\n const stroke = Math.max(3, Math.round(size * 0.1));\n const radius = (size - stroke) / 2;\n const circumference = 2 * Math.PI * radius;\n\n return (\n <div\n className={cx(styles.circle, isIndeterminate && styles['circle--indeterminate'], className)}\n style={{ width: size, height: size }}\n data-testid={testId}\n >\n <svg\n className={styles.circle__svg}\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n role=\"progressbar\"\n aria-label={label}\n aria-valuenow={isIndeterminate ? undefined : Math.round(percent)}\n aria-valuemin={isIndeterminate ? undefined : 0}\n aria-valuemax={isIndeterminate ? undefined : 100}\n aria-valuetext={isIndeterminate ? undefined : valueText}\n >\n <circle\n className={styles.circle__track}\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n />\n <circle\n className={cx(styles.circle__fill, styles[`circle__fill--${tone}`])}\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n strokeDasharray={circumference}\n strokeDashoffset={circumference * (1 - percent / 100)}\n />\n </svg>\n\n {isValueVisible && !isIndeterminate && (\n <span className={styles.circle__label} aria-hidden>\n {valueText ?? `%${Math.round(percent)}`}\n </span>\n )}\n </div>\n );\n};\n\nexport const ProgressCircle = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(ProgressCircleBase),\n 'ProgressCircle',\n);\n","'use client';\n\nimport { type DragEvent, memo, type ReactNode, useId, useRef, useState } from 'react';\n\nimport { CloudArrowUpFill, ExclamationCircleFill, XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport useAnnounce from '../../hooks/useAnnounce';\nimport IconButton from '../IconButton';\nimport Progress from '../Progress';\n\nimport styles from './index.module.scss';\n\nexport type UploadFile = {\n id: string;\n name: string;\n /** Bayt. Ekranda okunur biçime çevrilir. */\n size: number;\n /** 0-100. `undefined` → yükleme başlamadı ya da bitti. */\n progress?: number;\n /** Bu dosyaya ait hata. Satır kırmızı çizilir ve metin okunur. */\n error?: string;\n};\n\ntype Props = {\n files: UploadFile[];\n /** Kullanıcı dosya seçtiğinde/bıraktığında çağrılır — DOĞRULANMIŞ liste. */\n onSelect: (files: File[]) => void;\n onRemove: (id: string) => void;\n /** Alanın görünür etiketi ve erişilebilir adı. ZORUNLU. */\n label: string;\n /** Etiketin altındaki kural cümlesi (\"PDF veya JPG, en fazla 5 MB\"). */\n hint?: string;\n /** `<input accept>` — tarayıcının dosya seçicisini süzer. */\n accept?: string;\n isMultiple?: boolean;\n /** Bayt. Aşan dosya `onSelect`e HİÇ ulaşmaz; hata metni burada üretilir. */\n maxSize?: number;\n /** Kaldırma düğmelerinin erişilebilir ad öneki (\"Kaldır\"). */\n removeLabel: string;\n /** Sürükle-bırak alanının içine yazılan çağrı (\"Dosyaları buraya bırakın\"). */\n dropLabel: string;\n /** Boyut aşıldığında yazılan hata; `{name}` ve `{max}` yerine konur. */\n sizeErrorText?: string;\n isDisabled?: boolean;\n /** Alanın tamamına ait hata (sunucu reddi). */\n error?: string;\n children?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/** Baytı okunur biçime çevirir. */\nconst formatSize = (bytes: number): string => {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n};\n\n/**\n * Dosya yükleme — sürükle-bırak <strong>ve</strong> düğme.\n *\n * <h3>Yerel `<input type=\"file\">` KORUNUR</h3>\n * Görsel olarak gizlenir ama DOM'da kalır ve `<label>` ile alana bağlanır:\n * klavyeyle `Tab` + `Enter`, ekran okuyucuda \"dosya seç, düğme\" duyurusu,\n * işletim sisteminin dosya seçicisi ve mobilde kamera/galeri seçenekleri\n * <em>bedava</em> gelir. `<div>` üzerine `onDrop` yazıp düğmeyi taklit etmek\n * bunların hiçbirini getirmiyor — ve sürükle-bırak zaten <strong>tek başına\n * erişilebilir değil</strong>: fare gerektiriyor (WCAG 2.5.7).\n *\n * <h3>Doğrulama BİLEŞENDE, ama yalnızca ÖLÇÜLEBİLİR olan</h3>\n * Boyut sınırı burada uygulanıyor çünkü cevabı kesin ve anında verilebiliyor:\n * aşan dosya `onSelect`e hiç ulaşmıyor, kullanıcı yüklemenin bitmesini\n * beklemeden hatayı görüyor. Tür/içerik doğrulaması burada YAPILMIYOR —\n * `accept` bir öneri, gerçek karar sunucunun ve istemcide \"geçerli\" demek\n * yanlış bir söz olurdu.\n *\n * <h3>Sonuç DUYURULUYOR</h3>\n * Dosya eklendiğinde ve reddedildiğinde `useAnnounce` ile ekran okuyucuya\n * bildiriliyor. Listeye sessizce eklenen bir satır, görmeyen kullanıcı için\n * hiç olmamış demekti.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>alana, sonra her dosyanın kaldırma düğmesine</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>alanda: dosya seçiciyi açar</td></tr>\n * </table>\n */\nconst FileUpload = ({\n files,\n onSelect,\n onRemove,\n label,\n hint,\n accept,\n isMultiple,\n maxSize,\n removeLabel,\n dropLabel,\n sizeErrorText = '{name} çok büyük (en fazla {max}).',\n isDisabled,\n error,\n children,\n className,\n testId,\n}: Props) => {\n const inputId = useId();\n const hintId = useId();\n const inputRef = useRef<HTMLInputElement>(null);\n const announce = useAnnounce();\n\n const [isDragging, setIsDragging] = useState(false);\n const [rejected, setRejected] = useState<string[]>([]);\n\n const handleFiles = (list: FileList | null) => {\n if (!list || list.length === 0) return;\n\n const incoming = [...list];\n const tooLarge = maxSize === undefined ? [] : incoming.filter(file => file.size > maxSize);\n const accepted = incoming.filter(file => !tooLarge.includes(file));\n\n const messages = tooLarge.map(file =>\n sizeErrorText.replace('{name}', file.name).replace('{max}', formatSize(maxSize ?? 0)),\n );\n setRejected(messages);\n\n if (accepted.length > 0) {\n onSelect(accepted);\n announce(`${accepted.length} dosya eklendi`);\n }\n\n /* Reddedilen dosya ekranda YAZIYOR ama duyurulmali da: gormeyen kullanici\n icin sessizce dusen bir dosya hic secilmemis demekti. */\n if (messages.length > 0) announce(messages.join(' '), 'assertive');\n };\n\n const handleDrop = (event: DragEvent<HTMLLabelElement>) => {\n event.preventDefault();\n setIsDragging(false);\n if (isDisabled) return;\n handleFiles(event.dataTransfer.files);\n };\n\n return (\n <div className={cx(styles.upload, className)} data-testid={testId}>\n {/*\n Sürükle-bırak alanı bir `<label>`: tıklama ve klavye YEREL girdiye\n yönleniyor. `onClick` ile `input.click()` çağırmak da çalışırdı ama\n ekran okuyucu alanı bir düğme olarak duyurmuyordu.\n */}\n <label\n htmlFor={inputId}\n className={cx(\n styles.upload__drop,\n isDragging && styles['upload__drop--dragging'],\n isDisabled && styles['upload__drop--disabled'],\n error && styles['upload__drop--invalid'],\n )}\n onDragOver={event => {\n event.preventDefault();\n if (!isDisabled) setIsDragging(true);\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={handleDrop}\n >\n <CloudArrowUpFill aria-hidden className={styles.upload__icon} />\n\n <span className={styles.upload__label}>{label}</span>\n <span className={styles.upload__drag}>{dropLabel}</span>\n {hint && (\n <span id={hintId} className={styles.upload__hint}>\n {hint}\n </span>\n )}\n\n <input\n ref={inputRef}\n id={inputId}\n type=\"file\"\n className={styles.upload__input}\n accept={accept}\n multiple={isMultiple}\n disabled={isDisabled}\n aria-describedby={hint ? hintId : undefined}\n aria-invalid={error ? true : undefined}\n onChange={event => {\n handleFiles(event.target.files);\n /* Deger SIFIRLANIR: ayni dosya ikinci kez secildiginde `change`\n olayi hic dusmuyor ve kullanici \"hicbir sey olmadi\" saniyordu. */\n event.target.value = '';\n }}\n />\n </label>\n\n {error && (\n <p className={styles.upload__error} role=\"alert\">\n <ExclamationCircleFill aria-hidden />\n {error}\n </p>\n )}\n\n {rejected.map(message => (\n <p key={message} className={styles.upload__error} role=\"alert\">\n <ExclamationCircleFill aria-hidden />\n {message}\n </p>\n ))}\n\n {files.length > 0 && (\n <ul className={styles.upload__list}>\n {files.map(file => (\n <li\n key={file.id}\n className={cx(styles.upload__file, file.error && styles['upload__file--error'])}\n >\n <span className={styles.upload__fileText}>\n <span className={styles.upload__fileName}>{file.name}</span>\n <span className={styles.upload__fileMeta}>\n {file.error ?? formatSize(file.size)}\n </span>\n </span>\n\n {file.progress !== undefined && (\n <Progress\n value={file.progress}\n label={`${file.name} yükleniyor`}\n size=\"sm\"\n className={styles.upload__progress}\n />\n )}\n\n <IconButton\n icon={<XLg aria-hidden />}\n /* Ad dosya adini ICERIR: bir listede on bes dugme \"Kaldir\" diye\n okunuyor ve hangisi oldugu belli olmuyordu. */\n label={`${file.name} — ${removeLabel}`}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onRemove(file.id)}\n />\n </li>\n ))}\n </ul>\n )}\n\n {children}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(FileUpload, 'FileUpload'),\n) as typeof FileUpload;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport {\n CheckCircleFill,\n ExclamationTriangleFill,\n InfoCircleFill,\n XCircleFill,\n} from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\nexport type AlertTone = 'info' | 'success' | 'warning' | 'danger';\n\ntype Props = {\n children: ReactNode;\n tone?: AlertTone;\n title?: string;\n /** Sağda gösterilen eylem (bağlantı veya düğme). */\n action?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Her tona kendi ikonu; renk tek başına anlam taşımaz (WCAG 1.4.1).\n *\n * <p>Dördü de DOLU (`*Fill`) sürüm: ton zeminin üzerinde ince çizgili bir\n * simge, madalyonun içinde soluk kalıp uzaktan seçilemiyordu.\n *\n * <p>`aria-hidden`: ikonun taşıdığı bilgi yanındaki metinde zaten var; ikisini\n * birden okumak ekran okuyucuda tekrar üretiyordu.\n */\nconst ICONS: Record<AlertTone, ReactNode> = {\n info: <InfoCircleFill aria-hidden />,\n success: <CheckCircleFill aria-hidden />,\n warning: <ExclamationTriangleFill aria-hidden />,\n danger: <XCircleFill aria-hidden />,\n};\n\n/**\n * Bilgi / uyarı kutusu.\n *\n * <p>`danger` ve `warning` tonları `role=\"alert\"` taşır: ekran okuyucu bunları\n * anında duyurur. `info` ve `success` duyurulmaz — sayfa yüklenirken her bilgi\n * kutusunun okunması gürültü olurdu.\n */\nconst Alert: FC<Props> = ({ children, tone = 'info', title, action, className, testId }) => (\n <div\n className={cx(styles.alert, styles[`alert--${tone}`], className)}\n role={tone === 'danger' || tone === 'warning' ? 'alert' : undefined}\n data-testid={testId}\n >\n <span className={styles.alert__icon}>{ICONS[tone]}</span>\n\n <div className={styles.alert__body}>\n {title && <strong className={styles.alert__title}>{title}</strong>}\n <div className={styles.alert__content}>{children}</div>\n </div>\n\n {action && <div className={styles.alert__action}>{action}</div>}\n </div>\n);\n\nexport default /*#__PURE__*/ memo(Alert) as typeof Alert;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Tam ad; baş harfler buradan üretilir ve görsel yoksa `alt` metnidir. */\n name: string;\n /**\n * Profil görseli. Verilmezse baş harf madalyonuna düşer — çağıran tarafın\n * koşul yazması gerekmez.\n */\n imageUrl?: string;\n /**\n * Baş harfleri büyütürken kullanılacak dil etiketi (\"tr\", \"az\").\n *\n * <p>Türkçede ZORUNLU: `toUpperCase()` \"i\" harfini \"I\" yapıyor ve \"İlhan\"ın\n * baş harfi \"I\" çıkıyor. `toLocaleUpperCase('tr')` doğru \"İ\" verir.\n * Verilmezse `labels.locale`, o da yoksa çalışma ortamının varsayılan dili.\n */\n locale?: string;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n testId?: string;\n};\n\n/**\n * Baş harfleri üretir: \"Ahmet İlhan\" → \"Aİ\".\n *\n * <p>Tek kelimelik adda ilk iki harf alınır; tek harflik bir madalyon boş\n * görünüyordu.\n */\nconst resolveInitials = (name: string, locale?: string): string => {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return '?';\n\n const letters =\n words.length === 1 ? words[0].slice(0, 2) : `${words[0][0]}${words[words.length - 1][0]}`;\n\n return locale ? letters.toLocaleUpperCase(locale) : letters.toLocaleUpperCase();\n};\n\n/**\n * Adı SABİT bir renk kovasına eşler.\n *\n * <h3>Neden rastgele değil, neden hash</h3>\n * Aynı kişi her ekranda AYNI tonda görünmeli: bir listede yan yana duran on\n * kullanıcı, hepsi aynı gri madalyonken birbirinden ayırt edilemiyordu ve\n * renk her render'da değişseydi (rastgele) madalyon kimliği taşımak yerine\n * gürültü üretiyordu.\n *\n * <p>Karma basit ve KASITLI olarak basit: kriptografik bir dağılım gerekmiyor,\n * gereken tek şey aynı girdinin aynı çıktıyı vermesi. `charCodeAt` toplamı\n * kısa adlarda kümeleniyordu (djb2'nin `* 33` çarpanı bunu dağıtıyor).\n *\n * <h3>Renk tek başına KİMLİK taşımaz</h3>\n * Madalyonun içinde zaten baş harfler var ve yanında adın kendisi yazıyor.\n * Ton yalnızca bir tarama yardımı — renk körü bir kullanıcı için hiçbir bilgi\n * kaybı yok (WCAG 1.4.1).\n */\nconst resolveTone = (name: string, total: number): number => {\n let hash = 5381;\n for (let index = 0; index < name.length; index += 1) hash = (hash * 33) ^ name.charCodeAt(index);\n\n return Math.abs(hash) % total;\n};\n\n/** Madalyon tonlarının sayısı — `_module.scss` içindeki kova sayısıyla AYNI. */\nconst TONE_COUNT = 6;\n\n/**\n * Avatar — kullanıcı madalyonu.\n *\n * <h3>Görsel yoksa baş harf</h3>\n * Profil görseli olmayan bir sistemde baş harf madalyonu kimliği\n * <em>yeterince</em> taşır: kullanıcı hesap menüsünün en üstünde doğru hesapta\n * olduğunu görmek ister, fotoğrafını değil. `imageUrl` verildiğinde görsel\n * çizilir ve baş harf yedeğe düşer; çağıran tarafların değişmesi gerekmez.\n *\n * <h3>Ekran okuyucuya okunmaz</h3>\n * Madalyon `aria-hidden`: yanında zaten adın kendisi yazıyor. İkisini de\n * okumak \"A İ Ahmet İlhan\" gibi bir gürültü üretiyordu. Adın yanında\n * durmadığı bir yerde kullanılıyorsa çağıran taraf metni kendisi yazar.\n */\nconst Avatar: FC<Props> = ({ name, imageUrl, locale, size = 'md', className, testId }) => {\n const { labels } = useHanui();\n\n return (\n <span\n className={cx(\n styles.avatar,\n styles[`avatar--${size}`],\n /* Ton yalnizca BAS HARF madalyonunda: gorselin uzerine renk basmak\n fotografi bozuyordu. */\n !imageUrl && styles[`avatar--tone-${resolveTone(name, TONE_COUNT)}`],\n className,\n )}\n aria-hidden\n data-testid={testId}\n >\n {imageUrl ? (\n <img className={styles.avatar__image} src={imageUrl} alt=\"\" />\n ) : (\n resolveInitials(name, locale ?? labels?.locale)\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Avatar) as typeof Avatar;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\nexport type BadgeTone =\n | 'neutral'\n | 'success'\n | 'danger'\n | 'warning'\n | 'info'\n /** Birincil sınıflandırma tinti (mavi-lacivert aile). */\n | 'oem'\n /** İkincil sınıflandırma tinti (mor aile). */\n | 'alt'\n /** İndirim / olumlu değişim yüzdesi. Tutarın kendisi nötr kalır. */\n | 'sale'\n /** Miktar sayacı (sepet adedi, filtre sayısı) — dolu zemine izin verilir. */\n | 'action'\n /** Gezinme etiketi. */\n | 'link';\n\nexport type BadgeVariant = 'soft' | 'solid' | 'outline';\n\ntype Props = {\n children: ReactNode;\n tone?: BadgeTone;\n variant?: BadgeVariant;\n /** Küçük ikon; metnin solunda gösterilir. */\n icon?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Rozet — durum ve sınıflandırma etiketi.\n *\n * <p><strong>Renk tek başına anlam taşımaz</strong> (WCAG 1.4.1): her rozet\n * okunabilir bir metin içerir. `tone` yalnızca metni pekiştirir; renk körü bir\n * kullanıcı da aynı bilgiyi alır.\n *\n * <h3>Durum tonlarında `solid` ile `soft` aynı şeyi verir</h3>\n * Bu bilinçli. <strong>Doygun dolgu = tıklanabilir</strong> kuralı gereği dolu\n * zeminli bir durum etiketi düğmeye benziyor ve kullanıcılar \"Son 2 adet\" gibi\n * bir etikete tıklamayı deniyordu. Prop çağıran tarafları kırmamak için\n * korundu, görünüm tint'e sabitlendi.\n *\n * <p>Doygun dolgu yalnızca <strong>miktar</strong> tonlarında (`action`,\n * `link`) anlamlı: onlar bir durumu değil bir sayıyı bildirir ve tıklanabilir\n * bir öğenin parçasıdır.\n */\nconst Badge: FC<Props> = ({\n children,\n tone = 'neutral',\n variant = 'soft',\n icon,\n className,\n testId,\n}) => (\n <span\n className={cx(styles.badge, styles[`badge--${tone}`], styles[`badge--${variant}`], className)}\n data-testid={testId}\n >\n {icon && <span className={styles.badge__icon}>{icon}</span>}\n {children}\n </span>\n);\n\nexport default /*#__PURE__*/ memo(Badge) as typeof Badge;\n","import { type FC, memo } from 'react';\n\nimport { CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\nexport type Crumb = {\n label: string;\n /** Son öğede verilmez: bulunduğumuz sayfa bağlantı olmaz. */\n href?: string;\n};\n\ntype Props = {\n items: Crumb[];\n /** Gezinme bölgesinin erişilebilir adı. Verilmezse `labels.breadcrumb`. */\n label?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kırıntı yolu.\n *\n * <p>Son öğe bağlantı DEĞİL ve `aria-current=\"page\"` taşır: bulunduğu sayfaya\n * bağlantı veren bir kırıntı yolu, ekran okuyucu kullanıcısını yanıltır.\n *\n * <p>Ayırıcı ikon `aria-hidden`; ekran okuyucu liste yapısından hiyerarşiyi\n * zaten anlar.\n */\nconst Breadcrumb: FC<Props> = ({ items, label, linkProps, className, testId }) => {\n const { labels } = useHanui();\n\n return (\n <nav\n className={className}\n aria-label={resolveLabel('Breadcrumb.label', label, labels?.breadcrumb)}\n data-testid={testId}\n >\n <ol className={cx(styles.breadcrumb)}>\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n\n return (\n <li key={`${item.label}-${index}`} className={styles.breadcrumb__item}>\n {item.href && !isLast ? (\n <HanuiLink href={item.href} className={styles.breadcrumb__link} {...linkProps}>\n {item.label}\n </HanuiLink>\n ) : (\n <span className={styles.breadcrumb__current} aria-current=\"page\">\n {item.label}\n </span>\n )}\n\n {!isLast && <CaretRightFill aria-hidden className={styles.breadcrumb__separator} />}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default /*#__PURE__*/ memo(Breadcrumb) as typeof Breadcrumb;\n","import { type ElementType, type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype CardProps = {\n children: ReactNode;\n /** Kartın tamamı bir hedefe götürüyorsa hover geri bildirimi açılır. */\n isInteractive?: boolean;\n /** Semantik etiket: liste öğesi kartları `article` olmalı. */\n as?: ElementType;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kart — medya + gövde + eylem şeridi.\n *\n * <h3>Neden bileşik (compound) bir bileşen</h3>\n * Bir uygulamadaki her kart (ürün, kampanya, sipariş) aynı üç bölümden oluşur\n * ama içerikleri tamamen farklıdır. Tek bir \"her şeyi yapan\" kart bileşeni on\n * beş isteğe bağlı prop'a şişiyordu. Bunun yerine <em>yerleşim</em>\n * paylaşılır, içerik çağırana bırakılır: kenarlık, yarıçap, gölge, medya oranı\n * ve eylem şeridinin dipte durması tek yerde tanımlıdır.\n *\n * <h3>Eylem şeridi hep dipte</h3>\n * {@link CardFooter} `margin-top: auto` alır. Izgarada yan yana duran kartların\n * başlıkları farklı uzunlukta olsa da alt şerit aynı hizada kalır; aksi hâlde\n * satır dalgalı görünüyordu.\n *\n * @example\n * <Card as=\"article\" isInteractive>\n * <CardMedia href=\"/urun/x\" ratio={1}>\n * <CardOverlay position=\"top-left\"><Badge>Yeni</Badge></CardOverlay>\n * <img src={…} alt=\"\" />\n * </CardMedia>\n * <CardBody>…</CardBody>\n * <CardFooter>…</CardFooter>\n * </Card>\n */\nconst Card: FC<CardProps> = ({ children, isInteractive, as: Tag = 'div', className, testId }) => (\n <Tag\n className={cx(styles.card, isInteractive && styles['card--interactive'], className)}\n data-testid={testId}\n >\n {children}\n </Tag>\n);\n\ntype CardMediaProps = {\n children: ReactNode;\n /** Genişlik / yükseklik oranı. Sabit oran yükleme sırasında kaymayı önler. */\n ratio?: number;\n /** Medya alanı tıklanabilirse: görsel bağlantının içine alınır. */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n /** İçeriği kırpmak yerine sığdırır (şeffaf zeminli ürün fotoğrafları gibi). */\n isContained?: boolean;\n className?: string;\n};\n\n/**\n * Kartın görsel alanı.\n *\n * <p>Oran <strong>sabittir</strong>: görsel yüklenene kadar yer tutar ve\n * yerleşim kaymasını (CLS) önler. Oransız bırakıldığında kartlar görseller\n * yüklendikçe zıplıyordu.\n */\nexport const CardMedia: FC<CardMediaProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, ratio = 1, href, linkProps, isContained = true, className }) => {\n const content = (\n <span\n className={cx(styles.media__frame, isContained && styles['media__frame--contained'])}\n style={{ aspectRatio: ratio }}\n >\n {children}\n </span>\n );\n\n return (\n <div className={cx(styles.media, className)}>\n {href ? (\n // `tabIndex={-1}` + `aria-hidden`: aynı hedefe giden başlık bağlantısı\n // zaten sekme sırasında. Görseli ikinci bir durak yapmak klavye\n // gezinmesini iki katına çıkarıyor, ekran okuyucuda da aynı kayıt\n // arka arkaya iki kez duyuruluyordu.\n <HanuiLink\n href={href}\n className={styles.media__link}\n tabIndex={-1}\n aria-hidden\n {...linkProps}\n >\n {content}\n </HanuiLink>\n ) : (\n content\n )}\n </div>\n );\n }),\n 'CardMedia',\n);\n\ntype CardOverlayProps = {\n children: ReactNode;\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n className?: string;\n};\n\n/**\n * Görselin üzerine binen katman: rozetler ve hızlı eylemler.\n *\n * <p>Varsayılan olarak `pointer-events: none` — rozet yığını, altındaki görsel\n * bağlantısının tıklanmasını engellememeli. İçindeki gerçek düğmeler kendi\n * olaylarını geri açar.\n */\nexport const CardOverlay: FC<CardOverlayProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, position = 'top-left', className }) => (\n <div className={cx(styles.overlay, styles[`overlay--${position}`], className)}>{children}</div>\n )),\n 'CardOverlay',\n);\n\ntype CardSectionProps = {\n children: ReactNode;\n className?: string;\n};\n\n/** Kartın metin gövdesi: başlık, açıklama, üstyazı. */\nexport const CardBody: FC<CardSectionProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, className }) => (\n <div className={cx(styles.body, className)}>{children}</div>\n )),\n 'CardBody',\n);\n\n/** Eylem şeridi — tutar, düğmeler. Kartın dibine yapışır. */\nexport const CardFooter: FC<CardSectionProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, className }) => (\n <div className={cx(styles.footer, className)}>{children}</div>\n )),\n 'CardFooter',\n);\n\nexport default /*#__PURE__*/ memo(Card) as typeof Card;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { CaretLeftFill, CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n children: ReactNode;\n /** Şeridin erişilebilir adı (\"Öne çıkan ürünler\"). ZORUNLU. */\n label: string;\n /** Önceki/sonraki düğmelerinin erişilebilir adları. ZORUNLU. */\n previousLabel: string;\n nextLabel: string;\n /**\n * Sayfa göstergesinin ad üreticisi (`index` 1 tabanlı).\n *\n * <p>Verilmediğinde nokta göstergesi ÇİZİLMEZ: adsız bir nokta ekran\n * okuyucuda \"düğme\" diye okunuyor ve kullanıcı nereye gittiğini\n * bilmiyordu.\n */\n formatDotLabel?: (index: number, total: number) => string;\n /** Bir kartın asgari genişliği. Şerit buna göre kaç kart göstereceğine karar verir. */\n itemMinWidth?: number;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kaydırılabilir şerit (carousel).\n *\n * <h3>OTOMATİK OYNATMA YOK — ve olmayacak</h3>\n * Kendiliğinden ilerleyen bir şerit WCAG 2.2.2'yi ihlal ediyor (beş saniyeden\n * uzun süren hareket duraklatılabilmeli) ama asıl sorun daha basit: kullanıcı\n * okumaya başladığı kartı kaybediyor. Bir prop olarak bile eklenmedi —\n * eklenseydi kullanılırdı.\n *\n * <h3>Kaydırma YEREL, JavaScript değil</h3>\n * Şerit `overflow-x: auto` + `scroll-snap`: dokunmatikte parmakla kaydırma,\n * masaüstünde shift+tekerlek ve <strong>klavyeyle ok tuşları</strong>\n * tarayıcıdan geliyor. JavaScript ile `transform` kaydıran bir uygulama\n * bunların hiçbirini getirmiyor ve kaydırma çubuğunu da götürüyor — kullanıcı\n * şeridin devam ettiğini göremiyordu.\n *\n * <p>Düğmeler `scrollBy` çağırıyor: yerel kaydırmayı DEĞİŞTİRMİYOR,\n * tetikliyor. İkisi aynı durumu paylaşıyor ve ayrışmaları imkânsız.\n *\n * <h3>Şerit klavyeyle ULAŞILABİLİR</h3>\n * Kaydırılabilir bir kutu, içinde odaklanabilir öğe yoksa `tabindex`\n * verilmediğinde klavye kullanıcısı için ulaşılamaz (WCAG 2.1.1). Şerit\n * genellikle bağlantı taşıyan kartlardan oluşuyor ve o durumda ek bir durak\n * gereksiz — bu yüzden `tabindex` yalnızca <strong>odaklanabilir çocuk\n * yoksa</strong> yazılıyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>önceki/sonraki düğmelerine ve kartların içine</td></tr>\n * <tr><td>ok tuşları</td><td>şeridi kaydırır (yerel)</td></tr>\n * </table>\n */\nconst Carousel: FC<Props> = ({\n children,\n label,\n previousLabel,\n nextLabel,\n formatDotLabel,\n itemMinWidth = 240,\n className,\n testId,\n}) => {\n const trackRef = useRef<HTMLDivElement>(null);\n\n const [canScrollBack, setCanScrollBack] = useState(false);\n const [canScrollForward, setCanScrollForward] = useState(false);\n const [page, setPage] = useState(0);\n /* Sayfa SAYISI da olculur: cocuk sayisindan hesaplamak, kac kartin yan yana\n sigdigini bilmeyi gerektiriyor ve o sey yalnizca yerlesimden okunur. */\n const [pageCount, setPageCount] = useState(1);\n const [needsTabStop, setNeedsTabStop] = useState(false);\n\n /*\n * DURUM SERIDIN KENDISINDEN OKUNUR, sayilmaz.\n *\n * Once \"kacinci karttayiz\" bir sayacla tutuluyordu ve parmakla kaydirma o\n * sayaci hic guncellemiyordu: kullanici elle kaydirdiktan sonra ok\n * dugmesine bastiginda serit basa ziplyordu.\n */\n const measure = useCallback(() => {\n const track = trackRef.current;\n if (!track) return;\n\n const { scrollLeft, scrollWidth, clientWidth } = track;\n /* 1 px tolerans: alt piksel yuvarlama yuzunden uctaki dugme hicbir zaman\n pasiflesmiyordu. */\n setCanScrollBack(scrollLeft > 1);\n setCanScrollForward(scrollLeft + clientWidth < scrollWidth - 1);\n setPage(clientWidth > 0 ? Math.round(scrollLeft / clientWidth) : 0);\n setPageCount(clientWidth > 0 ? Math.max(1, Math.ceil(scrollWidth / clientWidth)) : 1);\n\n /* Odaklanabilir cocugu olan bir seride ek bir Tab duragi gereksiz. */\n setNeedsTabStop(\n scrollWidth > clientWidth &&\n track.querySelector('a, button, input, select, textarea, [tabindex]') === null,\n );\n }, []);\n\n useEffect(() => {\n const track = trackRef.current;\n if (!track) return;\n\n measure();\n track.addEventListener('scroll', measure, { passive: true });\n\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure);\n observer?.observe(track);\n\n return () => {\n track.removeEventListener('scroll', measure);\n observer?.disconnect();\n };\n }, [measure, children]);\n\n /* Bir GORUNUM genisligi kaydirir: sabit bir kart sayisi, farkli genislikteki\n kartlarda serit ortasinda duruyordu. */\n const scrollByPage = (direction: 1 | -1) =>\n trackRef.current?.scrollBy({\n left: direction * trackRef.current.clientWidth,\n behavior: 'smooth',\n });\n\n return (\n <section className={cx(styles.carousel, className)} aria-label={label} data-testid={testId}>\n <div className={styles.carousel__controls}>\n <IconButton\n icon={<CaretLeftFill aria-hidden className={styles.carousel__arrowIcon} />}\n label={previousLabel}\n variant=\"outline\"\n size=\"sm\"\n disabled={!canScrollBack}\n onClick={() => scrollByPage(-1)}\n />\n <IconButton\n icon={<CaretRightFill aria-hidden className={styles.carousel__arrowIcon} />}\n label={nextLabel}\n variant=\"outline\"\n size=\"sm\"\n disabled={!canScrollForward}\n onClick={() => scrollByPage(1)}\n />\n </div>\n\n <div\n ref={trackRef}\n className={styles.carousel__track}\n style={{ '--hanui-carousel-item': `${itemMinWidth}px` } as React.CSSProperties}\n /* Yalnizca odaklanabilir cocugu OLMAYAN bir seride durak: aksi halde\n klavye kullanicisi hicbir sey yapmayan bir durak geciyordu. */\n tabIndex={needsTabStop ? 0 : undefined}\n role={needsTabStop ? 'group' : undefined}\n aria-label={needsTabStop ? label : undefined}\n >\n {children}\n </div>\n\n {formatDotLabel && pageCount > 1 && (\n <div className={styles.carousel__dots}>\n {Array.from({ length: pageCount }, (_, index) => (\n <button\n key={index}\n type=\"button\"\n className={cx(\n styles.carousel__dot,\n index === page && styles['carousel__dot--active'],\n )}\n /* Nokta ADSIZ birakilamaz: ekran okuyucuda \"dugme\" diye\n okunuyor ve kullanici nereye gittigini bilmiyordu. */\n aria-label={formatDotLabel(index + 1, pageCount)}\n aria-current={index === page ? 'true' : undefined}\n onClick={() =>\n trackRef.current?.scrollTo({\n left: index * trackRef.current.clientWidth,\n behavior: 'smooth',\n })\n }\n />\n ))}\n </div>\n )}\n </section>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Carousel, 'Carousel')) as typeof Carousel;\n","'use client';\n\nimport { type FC, memo, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { ClipboardCheckFill, ClipboardFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveFormatter, resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Gösterilecek ve panoya kopyalanacak değer. */\n value: string;\n /**\n * Kopyalama düğmesinin erişilebilir adı ve `title`ı.\n *\n * <p>Verilmezse `labels.copyField.copy(value)` çağrılır. Config bir DİZE\n * değil biçimlendirici tutar: ad değeri İÇERMELİ — bir listede on beş\n * kopyalama düğmesi var ve hepsi \"Kopyala\" diye okunduğunda ekran okuyucu\n * kullanıcısı hangisinin hangi kayıt olduğunu bilmiyordu.\n */\n copyLabel?: string;\n /** Kopyalandıktan sonraki ad. Verilmezse `labels.copyField.copied(value)`. */\n copiedLabel?: string;\n /** `aria-live` ile duyurulan onay cümlesi. Verilmezse `labels.copyField.announcement`. */\n copiedAnnouncement?: string;\n size?: 'sm' | 'md';\n /**\n * Kopyalama düğmesini gizler.\n *\n * <p>Yalnızca değerin <em>zaten tıklanabilir bir şeyin içinde</em> olduğu\n * yerlerde (bir bağlantının gövdesi) verilir: iç içe etkileşim öğesi geçersiz\n * HTML üretir.\n */\n isReadOnly?: boolean;\n className?: string;\n testId?: string;\n};\n\n/** \"Kopyalandı\" geri bildiriminin ekranda kalma suresi (ms). */\nconst COPIED_FEEDBACK_MS = 1600;\n\n/**\n * Kopyalanabilir teknik değer — <strong>tek dokunuşla panoya</strong>.\n *\n * <h3>Neden ayrı bir öğe</h3>\n * Bir kod (SKU, parça numarası, sipariş numarası, IBAN) dekoratif bir metin\n * değil, kullanıcının <em>taşıdığı</em> veri. Düz bir `<span>` olduğunda\n * kullanıcı onu fareyle seçmeye çalışırken kartın tamamını seçiyor ya da\n * yanlışlıkla altındaki bağlantıyı tetikliyordu.\n *\n * <h3>Neden monospace</h3>\n * \"0986479644\" gibi diziler orantılı yazı tipinde okunmuyor: `0`/`O` ve `1`/`l`\n * ayırt edilemiyor ve bir hane atlandığında tamamen başka bir kayıt oluyor.\n * `technical-text` sabit genişlik + `tabular-nums` verir; iki değer alt alta\n * geldiğinde farklı hane gözle bulunur.\n *\n * <h3>Geri bildirim neden düğmenin üstünde</h3>\n * Bir bildirim (toast) da olurdu ama listelerde on beş satır var; ekranın\n * dibinde \"kopyalandı\" yazması <em>hangisinin</em> kopyalandığını\n * söylemiyordu. İkon yerinde tike dönünce cevap tıklanan yerde.\n *\n * <h3>Pano erişimi reddedilirse</h3>\n * `navigator.clipboard` güvenli olmayan bağlamda (HTTP) ve izin verilmediğinde\n * reddeder. O durumda değer sessizce <em>seçilir</em>: kullanıcı Ctrl+C ile\n * kendisi kopyalayabilir. Sessizce hiçbir şey yapmamak, düğmeyi bozuk\n * gösteriyordu.\n */\nconst CopyField: FC<Props> = ({\n value,\n copyLabel,\n copiedLabel,\n copiedAnnouncement,\n size = 'sm',\n isReadOnly,\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const [isCopied, setIsCopied] = useState(false);\n const codeRef = useRef<HTMLSpanElement>(null);\n const timerRef = useRef<number | undefined>(undefined);\n\n // Bilesen sokulurse zamanlayici da gitmeli; aksi halde React \"unmounted\n // component\" uyarisi veriyor.\n useEffect(() => () => window.clearTimeout(timerRef.current), []);\n\n const selectValue = useCallback(() => {\n const node = codeRef.current;\n if (!node) return;\n\n const range = document.createRange();\n range.selectNodeContents(node);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n }, []);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(value);\n setIsCopied(true);\n timerRef.current = window.setTimeout(() => setIsCopied(false), COPIED_FEEDBACK_MS);\n } catch {\n // Pano yoksa/izin verilmediyse en azindan secili birakilir.\n selectValue();\n }\n }, [value, selectValue]);\n\n return (\n <span className={cx(styles.copy, styles[`copy--${size}`], className)} data-testid={testId}>\n {/*\n `user-select: all` (CSS): tek tiklama degerin TAMAMINI secer.\n Kullanicilar fareyle surukleyip yarim deger kopyaliyordu.\n */}\n <span className={styles.copy__code} ref={codeRef}>\n {value}\n </span>\n\n {!isReadOnly && (\n <button\n type=\"button\"\n className={cx(styles.copy__button, isCopied && styles['copy__button--done'])}\n onClick={handleCopy}\n aria-label={\n isCopied\n ? (copiedLabel ??\n resolveFormatter('CopyField.copiedLabel', labels?.copyField?.copied, value))\n : (copyLabel ??\n resolveFormatter('CopyField.copyLabel', labels?.copyField?.copy, value))\n }\n title={\n isCopied\n ? (copiedLabel ??\n resolveFormatter('CopyField.copiedLabel', labels?.copyField?.copied, value))\n : (copyLabel ??\n resolveFormatter('CopyField.copyLabel', labels?.copyField?.copy, value))\n }\n >\n {/*\n Kopyalandi ISARETLI PANO, yalin tik degil: yalin tik \"dogru\n deger\" diye de okunabiliyordu. Ayni gövde + tik, degisimin\n kopyalama eylemine ait oldugunu birakiyor.\n */}\n {isCopied ? <ClipboardCheckFill aria-hidden /> : <ClipboardFill aria-hidden />}\n </button>\n )}\n\n {/*\n Ekran okuyucu icin: ikon degisimi gorsel bir sinyal, duyulmuyor.\n `aria-live` yalnizca DEGISTIGINDE konusur.\n */}\n <span aria-live=\"polite\" className={styles.copy__srOnly}>\n {isCopied\n ? resolveLabel(\n 'CopyField.copiedAnnouncement',\n copiedAnnouncement,\n labels?.copyField?.announcement,\n )\n : ''}\n </span>\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(CopyField) as typeof CopyField;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Ortada gösterilen metin (\"veya\"). */\n label?: string;\n className?: string;\n};\n\n/**\n * Ayırıcı çizgi.\n *\n * <p>Etiketli hâli `role=\"separator\"` taşımaz: metin içerdiğinde ekran okuyucu\n * onu ayırıcı değil içerik olarak okumalı (\"veya\").\n */\nconst Divider: FC<Props> = ({ label, className }) =>\n label ? (\n <div className={cx(styles.divider, styles['divider--labelled'], className)}>\n <span className={styles.divider__label}>{label}</span>\n </div>\n ) : (\n <hr className={cx(styles.divider, className)} />\n );\n\nexport default /*#__PURE__*/ memo(Divider) as typeof Divider;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype DirectoryProps = {\n children: ReactNode;\n className?: string;\n};\n\n/**\n * Dizin — harf veya konu başlıklı, gruplanmış bağlantı listesi.\n *\n * <h3>Neden ortak bir bileşen</h3>\n * Bir marka dizini ile bir kategori dizini aynı işi yapıyor: yüzlerce\n * bağlantıyı gruplayıp taranabilir kılmak. Ama iki container bunu ayrı ayrı\n * kurmuştu ve sonuç iki farklı sayfa oldu — birinde grup başlığı alt çizgili\n * 19 px, diğerinde çizgisiz; birinde satırlar ızgarada, diğerinde tek kolonda.\n *\n * <p>Ortak olan <em>görsel dilbilgisi</em>: grup başlığı + ızgara + satır\n * öğesi. O buraya taşındı; ne listelendiği çağırana kaldı.\n *\n * @example\n * <Directory>\n * <DirectoryGroup label=\"A\">\n * <DirectoryRow href=\"/marka/ate\" name=\"ATE\" media={<img … />} />\n * </DirectoryGroup>\n * </Directory>\n */\nconst Directory: FC<DirectoryProps> = ({ children, className }) => (\n <div className={cx(styles.directory, className)}>{children}</div>\n);\n\ntype DirectoryGroupProps = {\n /** Grup başlığı: harf (\"A\", \"0-9\") veya konu (\"Fren sistemi\"). */\n label: string;\n /**\n * Başlık kendisi bir hedefe götürüyorsa. Harf gruplarında verilmez — \"A\"\n * diye bir sayfa yok.\n */\n href?: string;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n /** Başlığın sağında duran sayaç (\"14 alt kategori\"). */\n meta?: ReactNode;\n children: ReactNode;\n /** Çıpa hedefi: alfabe şeridinden atlamak için. */\n id?: string;\n};\n\n/**\n * Dizin grubu.\n *\n * <p>Başlık <strong>yapışkan</strong>: uzun bir listede kaydırırken hangi\n * harfte olduğunu görmek, listeyi yukarı sarıp kontrol etmekten iyi.\n */\nexport const DirectoryGroup: FC<DirectoryGroupProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ label, href, linkProps, meta, children, id }) => (\n <section className={styles.group} id={id}>\n <header className={styles.group__header}>\n <h2 className={styles.group__label}>\n {href ? (\n <HanuiLink href={href} className={styles.group__link} {...linkProps}>\n {label}\n </HanuiLink>\n ) : (\n label\n )}\n </h2>\n {meta && <span className={styles.group__meta}>{meta}</span>}\n </header>\n\n <ul className={styles.group__list}>{children}</ul>\n </section>\n )),\n 'DirectoryGroup',\n);\n\ntype DirectoryRowProps = {\n href: string;\n name: string;\n /** Logo, ikon veya baş harf madalyonu. Satırın solunda. */\n media?: ReactNode;\n /** Sağ uçta duran işaret: rozet, kayıt sayısı. */\n marker?: ReactNode;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n className?: string;\n};\n\n/**\n * Dizin satırı — tek bir bağlantı.\n *\n * <p>Tüm satır tıklanabilir ve en az 44 px yüksekliğinde (WCAG 2.5.8):\n * yalnızca metnin tıklanabilir olduğu bir listede dokunmatik kullanıcılar\n * satırın boşluğuna basıp hiçbir şey olmadığını görüyordu.\n */\nexport const DirectoryRow: FC<DirectoryRowProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ href, name, media, marker, linkProps, className }) => (\n <li>\n <HanuiLink href={href} className={cx(styles.row, className)} {...linkProps}>\n {media && <span className={styles.row__media}>{media}</span>}\n <span className={styles.row__name}>{name}</span>\n {marker && <span className={styles.row__marker}>{marker}</span>}\n </HanuiLink>\n </li>\n )),\n 'DirectoryRow',\n);\n\ntype DirectoryJumpProps = {\n /** Grup etiketleri; her biri kendi çıpasına bağlanır. */\n labels: string[];\n /** Çıpa kimliğini üretir; `DirectoryGroup id` ile aynı olmalı. */\n toId: (label: string) => string;\n /** Şeridin erişilebilir adı. Verilmezse `labels.directoryJump`. */\n label?: string;\n};\n\n/**\n * Alfabe atlama şeridi.\n *\n * <p>Uzun bir listede \"V\" harfine ulaşmak için kaydırmak dakikalar alıyordu.\n * Şerit yatay kayar ve `#çıpa` bağlantıları taşır — JavaScript gerekmez,\n * tarayıcı kaydırmayı kendisi yapar ve bağlantı paylaşılabilir.\n *\n * <p>Bağlantılar HAM `<a>`: bunlar sayfa içi çıpa, gezinme değil. Bir\n * yönlendiriciden geçirmek aynı sayfayı yeniden çözümleyip kaydırmayı\n * kaçırıyordu.\n */\nexport const DirectoryJump: FC<DirectoryJumpProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ labels, toId, label }) => {\n /* Prop adi `labels` (grup etiketleri) config'in adiyla cakisiyor; config\n `config` olarak alinir. */\n const { labels: config } = useHanui();\n\n return (\n <nav\n className={styles.jump}\n aria-label={resolveLabel('DirectoryJump.label', label, config?.directoryJump)}\n >\n {labels.map(item => (\n <a key={item} href={`#${toId(item)}`} className={styles.jump__link}>\n {item}\n </a>\n ))}\n </nav>\n );\n }),\n 'DirectoryJump',\n);\n\nexport default /*#__PURE__*/ memo(Directory) as typeof Directory;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n description?: string;\n icon?: ReactNode;\n /** Kullanıcının buradan çıkabileceği eylem. */\n action?: ReactNode;\n /** İkincil eylem veya ipucu. */\n secondaryAction?: ReactNode;\n /**\n * `error` — liste BOŞ değil, ÇEKİLEMEDİ.\n *\n * <p>İkisi ayrı durumlar ve ayrı görünmek zorundalar: ağ hatasını \"kayıt\n * kalmamış\" diye okuyan kullanıcı yanlış karar veriyor (ürün aramayı\n * bırakıyor, siparişinin silindiğini sanıyor). Varyant `role=\"alert\"`\n * taşıyor ve tonu farklı — layout aynı kalıyor ki iki durum arasındaki\n * geçiş sıçramasın.\n *\n * <p>Ayrım ÖNCE bu bileşenin dışındaydı (\"ağ hatasında bu bileşen\n * çizilmez\") ve sonucu şuydu: her çağıran kendi hata kutusunu yazıyor,\n * kutular birbirinden farklı görünüyordu. Ayrım korunuyor — ama artık\n * BİLEŞENDE kodlu, çağıranın disiplinine bırakılmış değil.\n */\n tone?: 'empty' | 'error';\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Boş durum.\n *\n * <h3>Neden her boş durum bir eylem taşır</h3>\n * \"Sonuç bulunamadı\" tek başına çıkmaz sokaktır. Kullanıcı o ekranda ne\n * yapacağını bilmeli: aramayı temizle, filtreyi kaldır, listeye dön. `action`\n * isteğe bağlı ama çağıran taraf onu vermezse kullanıcı tıkanır.\n *\n * <h3>BOŞ ile YÜKLENEMEDİ ayrı durumlardır</h3>\n * Ağ hatasını \"kayıt kalmamış\" diye okuyan kullanıcı yanlış karar veriyor.\n * İkisi `tone` ile ayrılıyor: `error` farklı bir ton taşıyor ve\n * `role=\"alert\"` ile duyuruluyor, ama YERLEŞİM aynı — iki durum arasındaki\n * geçiş sıçramıyor.\n *\n * <p>Ayrım önce bu bileşenin DIŞINDAYDI (\"ağ hatasında çizilmez\") ve sonucu\n * şuydu: her çağıran kendi hata kutusunu yazıyor, kutular birbirinden farklı\n * görünüyordu. Ayrım korunuyor, kararın yeri değişti.\n */\nconst EmptyState: FC<Props> = ({\n title,\n description,\n icon,\n action,\n secondaryAction,\n tone = 'empty',\n size = 'md',\n className,\n testId,\n}) => (\n <div\n className={cx(styles.empty, styles[`empty--${size}`], styles[`empty--${tone}`], className)}\n /* Hata DUYURULUR: gormeyen kullanici icin sessizce degisen bir liste, hic\n degismemis demekti. Bos durum duyurulmaz — o beklenen bir sonuc. */\n role={tone === 'error' ? 'alert' : undefined}\n data-testid={testId}\n >\n {icon && <span className={styles.empty__icon}>{icon}</span>}\n <h3 className={styles.empty__title}>{title}</h3>\n {description && <p className={styles.empty__description}>{description}</p>}\n {(action || secondaryAction) && (\n <div className={styles.empty__actions}>\n {action}\n {secondaryAction}\n </div>\n )}\n </div>\n);\n\nexport default /*#__PURE__*/ memo(EmptyState) as typeof EmptyState;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n /** Başlığın üstündeki küçük bağlam etiketi (\"HESABIM\", \"KATEGORİ\"). */\n eyebrow?: string;\n /** Bir cümlelik açıklama. 68ch ile sınırlı tutulur. */\n description?: ReactNode;\n /** Sağ tarafta duran eylemler. Dar ekranda başlığın altına düşer. */\n actions?: ReactNode;\n /** Başlık satırının üstündeki kırıntı yolu. */\n breadcrumb?: ReactNode;\n /**\n * Başlığın yanındaki sayaç (\"1.248 kayıt\"). Açıklamanın değil BAŞLIĞIN\n * hizasında durur; kullanıcı sayıyı başlıkla birlikte okur.\n */\n meta?: ReactNode;\n /** Başlık bloğunun altında duran ek içerik (filtre şeridi, sekmeler). */\n children?: ReactNode;\n /** `h1` sayfada bir kez bulunur; iç bölümler `h2` alır. */\n as?: 'h1' | 'h2';\n className?: string;\n testId?: string;\n};\n\n/**\n * Sayfa başlığı — her ekranın aynı giriş bloğu.\n *\n * <h3>Neden ortak bir bileşen</h3>\n * Önceden her container kendi başlığını kuruyordu: bir sayfada punto 29 px,\n * diğerinde 23 px; birinde açıklama başlığın altında, birinde yanında;\n * boşluklar 8 px ile 24 px arasında dolaşıyordu. Sayfalar arası geçiş \"başka\n * bir siteye geçtim\" hissi veriyordu. Bu bileşen o kararları tek yerde verir.\n *\n * <h3>Açıklama genişliği sınırlı</h3>\n * Başlık tam genişlikte akabilir ama açıklama 68ch'de durur: 1360 px\n * genişlikte akan bir açıklama satırında göz satır sonunda yerini kaybediyor.\n *\n * <h3>Eylemler `flex-end`</h3>\n * Düğmeler başlık bloğunun ALT kenarına hizalanır. `baseline` verildiğinde iki\n * satırlık başlıklarda düğme ilk satıra çekiliyordu.\n */\nconst PageHeader: FC<Props> = ({\n title,\n eyebrow,\n description,\n actions,\n breadcrumb,\n meta,\n children,\n as: Heading = 'h1',\n className,\n testId,\n}) => (\n <header className={cx(styles.header, className)} data-testid={testId}>\n {breadcrumb}\n\n <div className={styles.header__top}>\n <div className={styles.header__text}>\n {eyebrow && <span className={styles.header__eyebrow}>{eyebrow}</span>}\n\n <div className={styles.header__titleRow}>\n <Heading className={styles.header__title}>{title}</Heading>\n {meta && <span className={styles.header__meta}>{meta}</span>}\n </div>\n\n {description && <p className={styles.header__description}>{description}</p>}\n </div>\n\n {actions && <div className={styles.header__actions}>{actions}</div>}\n </div>\n\n {children}\n </header>\n);\n\nexport default /*#__PURE__*/ memo(PageHeader) as typeof PageHeader;\n","import { type ElementType, type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n children: ReactNode;\n /** Panel başlığı. Verilmezse başlık şeridi hiç çizilmez. */\n title?: string;\n /** Başlık altındaki tek satırlık açıklama. */\n description?: ReactNode;\n /** Başlık şeridinin sağında duran eylemler. */\n actions?: ReactNode;\n /** Başlık şeridindeki ikon; başlığın solunda. */\n icon?: ReactNode;\n /** Gövde dolgusunu kaldırır: tablo ve tam genişlikte listeler için. */\n isFlush?: boolean;\n /** Gövde içindeki dikey aralık. */\n gap?: 'sm' | 'md' | 'lg';\n /** Dipte duran eylem şeridi (form kaydet, toplam). */\n footer?: ReactNode;\n as?: ElementType;\n className?: string;\n bodyClassName?: string;\n testId?: string;\n};\n\n/**\n * Panel — başlığı olan içerik kutusu.\n *\n * <h3>Neden bu bileşen var</h3>\n * Bir uygulamanın on bir ayarlar sayfası, on bir farklı kart kuruyordu:\n * birinde dolgu 16 px diğerinde 24 px, birinde başlık kartın içinde diğerinde\n * dışında, birinde `max-width: 560px` diğerinde tam genişlik. Aynı disiplinde\n * görünmeleri için kararların tek yerde verilmesi gerekiyordu.\n *\n * <h3>Genişlik paneli DEĞİL içeriği sınırlar</h3>\n * Panel her zaman kapsayıcısını doldurur. Form alanlarının okunabilir satır\n * uzunluğunu aşmaması gerekiyorsa {@link PanelForm} kullanılır — o iç ızgarayı\n * sınırlar, panelin kendisini daraltmaz. Önceden bir \"profil düzenle\" paneli\n * sayfanın üçte biri kadar kalıp yanındaki boşluğa bakıyordu; sorun formun\n * değil PANELİN daraltılmasıydı.\n *\n * @example\n * <Panel title=\"Profil bilgileri\" description=\"Fatura bu bilgilerle kesilir\">\n * <PanelForm>…alanlar…</PanelForm>\n * </Panel>\n */\nconst Panel: FC<Props> = ({\n children,\n title,\n description,\n actions,\n icon,\n isFlush,\n gap = 'md',\n footer,\n as: Tag = 'section',\n className,\n bodyClassName,\n testId,\n}) => (\n <Tag className={cx(styles.panel, className)} data-testid={testId}>\n {(title || actions) && (\n <div className={styles.panel__header}>\n <div className={styles.panel__heading}>\n {icon && <span className={styles.panel__icon}>{icon}</span>}\n\n <div className={styles.panel__headingText}>\n {title && <h2 className={styles.panel__title}>{title}</h2>}\n {description && <p className={styles.panel__description}>{description}</p>}\n </div>\n </div>\n\n {actions && <div className={styles.panel__actions}>{actions}</div>}\n </div>\n )}\n\n <div\n className={cx(\n styles.panel__body,\n styles[`panel__body--${gap}`],\n isFlush && styles['panel__body--flush'],\n bodyClassName,\n )}\n >\n {children}\n </div>\n\n {footer && <div className={styles.panel__footer}>{footer}</div>}\n </Tag>\n);\n\ntype PanelFormProps = {\n children: ReactNode;\n /** Sütun sayısı. `2` dar ekranda kendiliğinden tek sütuna düşer. */\n columns?: 1 | 2;\n className?: string;\n};\n\n/**\n * Panel içindeki form ızgarası.\n *\n * <p>Genişliği SINIRLI (`$measure-narrow`): girdi alanları okunabilir satır\n * uzunluğunun ötesine uzamamalı — 900 px genişliğinde bir metin kutusu\n * doldurulması zor görünür. Ama bu sınır PANELE değil ızgaraya uygulanır;\n * panel tam genişlikte kalır ve sayfa düzeni bozulmaz.\n */\nexport const PanelForm: FC<PanelFormProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, columns = 1, className }) => (\n <div className={cx(styles.form, styles[`form--${columns}`], className)}>{children}</div>\n )),\n 'PanelForm',\n);\n\ntype PanelRowProps = {\n children: ReactNode;\n className?: string;\n};\n\n/**\n * İki alanı yan yana koyan satır. Dar ekranda alt alta düşer.\n *\n * <p>`PanelForm columns={2}` tüm ızgarayı ikiye böler; bu yalnızca TEK bir\n * satırı böler (ad + soyad gibi).\n */\nexport const PanelRow: FC<PanelRowProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, className }) => (\n <div className={cx(styles.row, className)}>{children}</div>\n )),\n 'PanelRow',\n);\n\nexport default /*#__PURE__*/ memo(Panel) as typeof Panel;\n","import { type FC, memo } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** BİÇİMLENMİŞ tutar: \"1.299,90\". Bileşen hesap yapmaz. */\n value: string;\n /** Para birimi simgesi ya da kodu. Verilmezse `labels.currency`. */\n currency?: string;\n /**\n * Değeri `Intl.NumberFormat` ile biçimlendirir.\n *\n * <p>`value` bu kipte de bir DİZE olarak kalıyor ve sayıya çevriliyor —\n * bileşen hâlâ HESAP YAPMIYOR, yalnızca ayırıcıları ve para birimi\n * konumunu yerel ayardan alıyor. Yerel ayar `labels.locale`den; verilmezse\n * biçimlendirme YAPILMAZ ve değer olduğu gibi yazılır. Yanlış yerel ayarda\n * biçimlendirilmiş bir tutar, biçimlendirilmemiş olandan kötü: \"1,250\" bir\n * yerde bin iki yüz elli, başka bir yerde bir tam iki yüz elli.\n *\n * <p>Para birimi simgesinin ÖN/ARKA konumu da yerel ayara bağlı ve şu anda\n * her zaman arkada — `Intl` açıldığında doğru konumu o veriyor.\n */\n isFormatted?: boolean;\n /** Üstü çizili liste fiyatı; indirim varsa verilir (biçimlenmiş). */\n listValue?: string;\n /** İndirim oranı (tam sayı yüzde). */\n discountPercent?: number;\n /** İndirim rozetinin metnini üretir (\"%20\", \"-20%\"). */\n formatDiscount?: (percent: number) => string;\n size?: 'sm' | 'md' | 'lg' | 'xl';\n className?: string;\n testId?: string;\n};\n\n/**\n * Tutar gösterimi.\n *\n * <h3>Bileşen HESAP YAPMAZ</h3>\n * Tutar biçimlenmiş gelir. Kuruşu istemcide çevirmek kayan nokta hatası riski\n * taşır ve biçimlendirme iki yerde ayrışır: aynı ürün listede \"1.299,90\",\n * detayda \"1299.9\" çıkıyordu. İndirim oranı da dışarıdan gelir — burada\n * `(1 - fiyat/liste)` hesaplamak için biçimlenmiş metni sayıya çevirmek\n * gerekirdi ve o kırılgan bir iş.\n *\n * <h3>Tutar NÖTR kalır</h3>\n * Güncel tutar `$text`; üstü çizili eski tutar `$text-3`; indirim yüzdesi\n * küçük bir yeşil rozet. Kırmızı fiyat ucuz durur ve kırmızıyı \"olumsuz\"\n * anlamından koparır.\n */\nconst Price: FC<Props> = ({\n value,\n currency,\n listValue,\n discountPercent,\n formatDiscount = percent => `%${percent}`,\n isFormatted,\n size = 'md',\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const symbol = resolveLabel('Price.currency', currency, labels?.currency);\n\n /*\n * BICIMLENDIRME OPSIYONEL ve yerel ayara BAGLI.\n *\n * Yerel ayar verilmediginde deger olduğu gibi yaziliyor: yanlis yerel ayarda\n * bicimlendirilmis bir tutar, bicimlendirilmemis olandan kotu — \"1,250\" bir\n * yerde bin iki yuz elli, baska bir yerde bir tam iki yuz elli.\n *\n * Cevrilemeyen bir deger de oldugu gibi kalir. Bir bicimlendirme hatasi\n * FIYATI gizleyemez; ekranda bir sey olmamasindan iyisi ham degerdir.\n */\n const format = (raw: string): string => {\n if (!isFormatted || !labels?.locale) return raw;\n\n /*\n * RAKAM ICERMEYEN deger biciMLENDIRILMEZ. Soyma adimi \"Fiyat sorunuz\"u\n * bos dizeye indiriyor, `Number('')` ise 0: ekranda tutar yerine \"0\"\n * yaziyordu — yani fiyat alani dolu gorunup icerigi YANLIS oluyordu.\n * Bicimlendirilemeyen deger oldugu gibi yazilir.\n */\n if (!/\\d/.test(raw)) return raw;\n\n const numeric = Number(\n raw\n .replace(/[^\\d.,-]/g, '')\n .replace(/\\.(?=\\d{3}\\b)/g, '')\n .replace(',', '.'),\n );\n if (!Number.isFinite(numeric)) return raw;\n\n try {\n return new Intl.NumberFormat(labels.locale).format(numeric);\n } catch {\n return raw;\n }\n };\n\n return (\n <span className={cx(styles.price, styles[`price--${size}`], className)} data-testid={testId}>\n <span className={styles.price__current}>\n {format(value)}\n <span className={styles.price__currency}>{symbol}</span>\n </span>\n\n {listValue && (\n <s className={styles.price__list}>\n {format(listValue)}\n <span className={styles.price__currency}>{symbol}</span>\n </s>\n )}\n\n {/* `isDefined` DEGIL acik karsilastirma: handy-utils'in koruyucusu\n `Exclude<any, …>` donuyor ve TypeScript'te daraltma uretmiyor. */}\n {discountPercent !== undefined && discountPercent > 0 && (\n <span className={styles.price__discount}>{formatDiscount(discountPercent)}</span>\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Price) as typeof Price;\n","import { type FC, memo } from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { StarFill, StarHalf } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveFormatter } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** 0–5 arası puan. Yarım yıldız desteklenir. */\n value: number;\n /** Değerlendirme sayısı; verilirse yıldızların yanında gösterilir. */\n count?: number;\n /**\n * Ekran okuyucuya okunan metin.\n *\n * <p>Yıldızlar `aria-hidden`: beş ayrı ikonu tek tek duyurmak anlamsız.\n * Yerine bir cümle okunur (\"5 üzerinden 4,5 — 12 değerlendirme\") ve o cümle\n * hem dile hem sayı biçimine bağlı; kütüphane onu uyduramaz.\n *\n * <p>Verilmezse `labels.rating.srLabel(value, count)` çağrılır — cümle\n * değere bağlı olduğu için config bir DİZE değil bir biçimlendirici tutar.\n */\n srLabel?: string;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\n/**\n * Yıldız puanı — salt gösterim.\n *\n * <p>Ortalama sunucuda hesaplanır; burada yalnızca gösterilir. Puanı\n * istemcide hesaplamak, sayfalama yüzünden eksik veriyle yanlış ortalama\n * üretirdi.\n *\n * <p>Etkileşimli kardeşi {@link RatingInput}.\n */\nconst Rating: FC<Props> = ({ value, count, srLabel, size = 'sm', className, testId }) => {\n const { labels } = useHanui();\n const rounded = Math.round(value * 2) / 2;\n\n return (\n <span className={cx(styles.rating, styles[`rating--${size}`], className)} data-testid={testId}>\n {/*\n * BOS YILDIZ DA DOLU — farkı renk taşır (`rating__empty`), çizgi değil.\n *\n * <p>İçi boş yıldız yalnızca bir konturdur: dolu komşusunun yanında\n * \"eksik çizilmiş\" gibi durur ve küçük boyda kontur tek piksele inip\n * kayboluyordu. Aynı gövde + soluk ton, beş yıldızın silüetini bozmadan\n * doluluğu okutur.\n */}\n <span className={styles.rating__stars} aria-hidden>\n {Array.from({ length: 5 }, (_, index) => {\n const position = index + 1;\n if (rounded >= position) return <StarFill key={index} />;\n if (rounded >= position - 0.5) return <StarHalf key={index} />;\n return <StarFill key={index} className={styles.rating__empty} />;\n })}\n </span>\n\n <span className={styles.rating__srOnly}>\n {srLabel ?? resolveFormatter('Rating.srLabel', labels?.rating?.srLabel, value, count)}\n </span>\n\n {isDefined(count) && (\n <span className={styles.rating__count} aria-hidden>\n ({count})\n </span>\n )}\n </span>\n );\n};\n\nexport default /*#__PURE__*/ memo(Rating) as typeof Rating;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n title: string;\n description?: string;\n /** Üstte gösterilen küçük büyük-harf etiket. */\n overline?: string;\n /** Sağda gösterilen eylem (\"Tümünü gör\"). */\n action?: ReactNode;\n as?: 'h1' | 'h2' | 'h3';\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n testId?: string;\n};\n\n/**\n * Bölüm başlığı.\n *\n * <p>Başlık düzeyi (`as`) görsel boyuttan (`size`) <strong>ayrı</strong>:\n * sayfa hiyerarşisi anlamsal olmak zorunda ama görsel boyut bağlamla değişir.\n * İkisini birbirine bağlamak, doğru görünüm için yanlış başlık düzeyi seçmeye\n * zorlardı.\n */\nconst SectionHeader: FC<Props> = ({\n title,\n description,\n overline,\n action,\n as: Heading = 'h2',\n size = 'md',\n className,\n testId,\n}) => (\n <header className={cx(styles.header, styles[`header--${size}`], className)} data-testid={testId}>\n <div className={styles.header__text}>\n {overline && <span className={styles.header__overline}>{overline}</span>}\n <Heading className={styles.header__title}>{title}</Heading>\n {description && <p className={styles.header__description}>{description}</p>}\n </div>\n\n {action && <div className={styles.header__action}>{action}</div>}\n </header>\n);\n\nexport default /*#__PURE__*/ memo(SectionHeader) as typeof SectionHeader;\n","'use client';\n\nimport { type FC, type ReactNode, memo, useEffect, useRef, useState } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n children: ReactNode;\n /**\n * Kaydırılabilir bölgenin erişilebilir adı. ZORUNLU.\n *\n * <p>Bölge klavyeyle odaklanabilir olduğunda ekran okuyucu onu duyuruyor;\n * adsız bir bölge \"bölge\" diye okunuyor ve kullanıcı neyin içinde olduğunu\n * bilmiyordu.\n */\n label: string;\n /** Kaydırma yönü. `both` iki eksende de kaydırır. */\n axis?: 'vertical' | 'horizontal' | 'both';\n /** En fazla yükseklik — dikey kaydırmada zorunlu, yoksa kutu uzar gider. */\n maxHeight?: number | string;\n /** Kenarlarda içeriğin devam ettiğini gösteren solma. */\n hasFade?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kaydırma kutusu — <strong>klavyeyle erişilebilir</strong> kaydırma bölgesi.\n *\n * <h3>Neden bir bileşen: `overflow: auto` TEK BAŞINA yetmiyor</h3>\n * Kaydırılabilir bir bölge klavyeyle ulaşılabilir olmak zorunda (WCAG 2.1.1).\n * İçinde odaklanabilir öğe olmayan bir kutu — uzun bir metin, bir tablo, bir\n * kod bloğu — `tabindex` verilmediğinde klavye kullanıcısı için\n * <strong>ulaşılamaz</strong>: `Tab` onu atlıyor ve ok tuşları sayfayı\n * kaydırıyor, kutuyu değil. Firefox bunu kendiliğinden yapıyor, Chrome ve\n * Safari yapmıyor.\n *\n * <p>Ama `tabindex=\"0\"` KOŞULSUZ verilemez: içerik sığdığında kutu\n * kaydırılamaz olur ve gereksiz bir `Tab` durağına dönüşür. Bileşen taşmayı\n * ÖLÇÜYOR ve `tabindex`i yalnızca gerçekten kaydırılabilirken yazıyor.\n *\n * <h3>Kaydırma çubuğu temalı</h3>\n * İşletim sisteminin açık çubuğu koyu temada kutunun kenarında parlak bir\n * şerit bırakıyordu.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>kaydırılabilir bölgeye odaklanır (yalnızca taşma varsa)</td></tr>\n * <tr><td>ok tuşları · `PageUp`/`PageDown` · `Home`/`End`</td><td>kaydırır</td></tr>\n * </table>\n * Tuşların hepsi TARAYICIDAN geliyor; bileşenin işi yalnızca bölgeyi\n * odaklanabilir kılmak.\n */\nconst ScrollArea: FC<Props> = ({\n children,\n label,\n axis = 'vertical',\n maxHeight,\n hasFade,\n className,\n testId,\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n const [isScrollable, setIsScrollable] = useState(false);\n\n /*\n * TASMA OLCULUR, varsayilmaz.\n *\n * `tabindex=\"0\"` kosulsuz verilseydi icerigi sigan her kutu gereksiz bir\n * Tab duragina donusuyordu: sekiz kutulu bir sayfada klavye kullanicisi\n * hicbir sey yapmayan sekiz durak geciyordu.\n */\n useEffect(() => {\n const node = ref.current;\n if (!node || typeof ResizeObserver === 'undefined') return;\n\n const measure = () => {\n const vertical = node.scrollHeight > node.clientHeight;\n const horizontal = node.scrollWidth > node.clientWidth;\n setIsScrollable(\n axis === 'horizontal'\n ? horizontal\n : axis === 'vertical'\n ? vertical\n : vertical || horizontal,\n );\n };\n\n measure();\n\n /* Icerik DE kutu DA degisebiliyor: ikisi de izleniyor. */\n const observer = new ResizeObserver(measure);\n observer.observe(node);\n for (const child of node.children) observer.observe(child);\n\n return () => observer.disconnect();\n }, [axis, children]);\n\n return (\n <div\n ref={ref}\n className={cx(\n styles.scrollArea,\n styles[`scrollArea--${axis}`],\n hasFade && styles['scrollArea--fade'],\n className,\n )}\n style={maxHeight === undefined ? undefined : { maxBlockSize: maxHeight }}\n /*\n * Bolge YALNIZCA kaydirilabilirken odaklanabilir ve yalnizca o zaman bir\n * ROL tasiyor: sigmayan bir kutu bir \"bolge\" degil, siradan bir\n * sarmalayici.\n */\n tabIndex={isScrollable ? 0 : undefined}\n role={isScrollable ? 'region' : undefined}\n aria-label={isScrollable ? label : undefined}\n data-testid={testId}\n >\n {children}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(ScrollArea, 'ScrollArea'),\n) as typeof ScrollArea;\n","import { type CSSProperties, type FC, memo } from 'react';\n\nimport { isNumber } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /** Genişlik: sayı px, dize doğrudan CSS değeri. */\n width?: number | string;\n height?: number | string;\n /** Metin satırı görünümü: yuvarlatılmış, satır yüksekliğinde. */\n variant?: 'block' | 'text' | 'circle';\n /** Kaç satır çizilecek (`text` için). */\n lines?: number;\n className?: string;\n};\n\n/**\n * Yükleme iskeleti.\n *\n * <h3>Neden dönen çark yerine iskelet</h3>\n * İskelet gelecek içeriğin <em>şeklini</em> gösterir; kullanıcı ne beklediğini\n * bilir ve içerik geldiğinde yerleşim kaymaz (CLS). Dönen bir çark hem konumu\n * hem boyutu belirsiz bırakır.\n *\n * <p>`aria-hidden`: ekran okuyucuya \"yükleniyor\" bilgisini veren, iskeletin\n * kendisi değil onu saran bölgenin `aria-busy` özelliğidir.\n */\nconst Skeleton: FC<Props> = ({ width, height, variant = 'block', lines = 1, className }) => {\n const style: CSSProperties = {\n width: isNumber(width) ? `${width}px` : width,\n height: isNumber(height) ? `${height}px` : height,\n };\n\n if (variant === 'text' && lines > 1)\n return (\n <span className={cx(styles.group, className)} aria-hidden>\n {Array.from({ length: lines }, (_, index) => (\n <span\n key={index}\n className={cx(styles.skeleton, styles['skeleton--text'])}\n // Son satır kısa: gerçek paragraflar tam genişlikte bitmez.\n style={index === lines - 1 ? { width: '60%' } : undefined}\n />\n ))}\n </span>\n );\n\n return (\n <span\n className={cx(styles.skeleton, styles[`skeleton--${variant}`], className)}\n style={style}\n aria-hidden\n />\n );\n};\n\nexport default /*#__PURE__*/ memo(Skeleton) as typeof Skeleton;\n\ntype ShapeProps = {\n /** Kaç kopya çizilecek — bir listenin bilinen satır sayısı. */\n count?: number;\n className?: string;\n};\n\n/**\n * KART iskeleti — `Card` + `CardMedia` + iki satır metnin ölçüsü.\n *\n * <h3>Neden hazır biçimler</h3>\n * \"İskelet yerleşimi kaydırmaz\" sözü ancak iskelet gelecek içeriğin ÖLÇÜSÜNÜ\n * taşıyorsa doğru. Pratikte her çağıran ölçüyü gözle tahmin ediyordu ve\n * tahminler tutmuyordu: 180 px'lik bir görsel alanına 120 px'lik iskelet\n * konulunca içerik geldiğinde sayfa 60 px sıçrıyordu (CLS). Bu biçimler\n * ölçüyü gerçek bileşenlerden alıyor — `CardMedia`nın varsayılan oranı,\n * `$font-size-sm` satır yüksekliği, `Panel` dolgusu.\n */\nconst CardShape: FC<ShapeProps> = ({ count = 1, className }) => (\n <>\n {Array.from({ length: count }, (_, index) => (\n <div key={index} className={cx(styles.card, className)} aria-hidden>\n <Skeleton className={styles.card__media} />\n <div className={styles.card__body}>\n <Skeleton variant=\"text\" width=\"70%\" />\n <Skeleton variant=\"text\" width=\"40%\" />\n </div>\n </div>\n ))}\n </>\n);\n\n/** SATIR iskeleti — avatar + iki metin satırı; liste satırlarının ölçüsü. */\nconst RowShape: FC<ShapeProps> = ({ count = 3, className }) => (\n <div className={cx(styles.rows, className)} aria-hidden>\n {Array.from({ length: count }, (_, index) => (\n <div key={index} className={styles.row}>\n <Skeleton variant=\"circle\" width={36} height={36} />\n <div className={styles.row__text}>\n <Skeleton variant=\"text\" width=\"45%\" />\n <Skeleton variant=\"text\" width=\"25%\" />\n </div>\n </div>\n ))}\n </div>\n);\n\n/**\n * TABLO iskeleti — `DataTable`ın satır yüksekliğinde.\n *\n * <p>Sütun genişlikleri EŞİT: gerçek genişlikler içeriğe göre değişiyor ve\n * onları taklit etmeye çalışmak, veri geldiğinde daha büyük bir sıçrama\n * üretiyordu. Eşit sütunlar \"burada bir tablo olacak\" der ve fazlasını vaat\n * etmez.\n */\nconst TableShape: FC<ShapeProps & { columns?: number }> = ({\n count = 5,\n columns = 4,\n className,\n}) => (\n <div className={cx(styles.table, className)} aria-hidden>\n {Array.from({ length: count }, (_, rowIndex) => (\n <div key={rowIndex} className={styles.table__row}>\n {Array.from({ length: columns }, (_, columnIndex) => (\n <Skeleton key={columnIndex} variant=\"text\" />\n ))}\n </div>\n ))}\n </div>\n);\n\nexport const SkeletonCard = /*#__PURE__*/ named(/*#__PURE__*/ memo(CardShape), 'SkeletonCard');\nexport const SkeletonRows = /*#__PURE__*/ named(/*#__PURE__*/ memo(RowShape), 'SkeletonRows');\nexport const SkeletonTable = /*#__PURE__*/ named(/*#__PURE__*/ memo(TableShape), 'SkeletonTable');\n","'use client';\n\nimport { type FC, memo, type ReactNode } from 'react';\n\nimport { ArrowDownShort, ArrowUpShort, DashLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/** Değişimin yönü. `flat` \"değişmedi\" — yokluk DEĞİL. */\nexport type StatTrend = 'up' | 'down' | 'flat';\n\ntype Props = {\n /** Ölçülen şeyin adı (\"Bugünkü sipariş\"). */\n label: string;\n /** Değerin KENDİSİ — biçimlendirilmiş dize. Bileşen hesap yapmaz. */\n value: ReactNode;\n /** Değerin yanındaki birim (\"₺\", \"adet\"). */\n unit?: string;\n /** Değişim metni (\"%12\", \"+3\"). `trend` ile birlikte anlamlı. */\n delta?: string;\n /**\n * Değişimin yönü.\n *\n * <p>Yön TEK BAŞINA iyi/kötü demek değildir: \"iade oranı %12 arttı\" kötü,\n * \"ciro %12 arttı\" iyi. Renk kararı {@link isUpPositive} ile ayrı veriliyor.\n */\n trend?: StatTrend;\n /**\n * Artış İYİ mi. Varsayılan `true`.\n *\n * <p>`false` verildiğinde yukarı ok kırmızı, aşağı ok yeşil çizilir — iade\n * oranı, hata sayısı, terk edilen sepet gibi ölçüler için. Yönü her zaman\n * yeşil çizmek, kötüleşen bir ölçüyü iyi haber gibi gösteriyordu.\n */\n isUpPositive?: boolean;\n /** Değerin altındaki bir cümlelik bağlam (\"geçen haftaya göre\"). */\n description?: ReactNode;\n /** Sol üstte duran ikon madalyonu. */\n icon?: ReactNode;\n size?: 'sm' | 'md';\n className?: string;\n testId?: string;\n};\n\nconst TREND_ICON: Record<StatTrend, ReactNode> = {\n up: <ArrowUpShort aria-hidden />,\n down: <ArrowDownShort aria-hidden />,\n flat: <DashLg aria-hidden />,\n};\n\n/** Yönün ekran okuyucuya okunan karşılığı. */\nconst TREND_TEXT: Record<StatTrend, string> = {\n up: 'artış',\n down: 'azalış',\n flat: 'değişim yok',\n};\n\n/**\n * Ölçüm kutusu (KPI).\n *\n * <h3>Bileşen HESAP YAPMAZ</h3>\n * `value` ve `delta` biçimlendirilmiş dizeler. Yüzde hesabı, para birimi ve\n * yuvarlama çağıranın: bir gösterge panelinde \"%12,5\" ile \"%13\" arasındaki\n * farkı belirleyen şey ürün kararı, bileşenin varsayılanı değil. Aynı sebeple\n * `Price` de hesap yapmıyor.\n *\n * <h3>Yön TEK BAŞINA iyi/kötü demek DEĞİL</h3>\n * \"İade oranı %12 arttı\" kötü haber, \"ciro %12 arttı\" iyi. Yükselen her oku\n * yeşile boyamak, kötüleşen bir ölçüyü iyi gibi gösteriyordu — `isUpPositive`\n * bu kararı çağırana bırakıyor.\n *\n * <h3>Renk tek sinyal değil</h3>\n * Değişim üç şeyle birden anlatılıyor: <strong>ok yönü</strong> (biçim),\n * <strong>renk</strong> ve ekran okuyucuya okunan <strong>metin</strong>\n * (\"artış\" / \"azalış\" / \"değişim yok\"). Yalnızca renk kullanılsaydı renk körü\n * bir kullanıcı için artışla azalış aynı görünüyordu (WCAG 1.4.1).\n *\n * <h3>Rakamlar TABULAR</h3>\n * Alt alta duran ölçüm kutularında orantılı rakamlar sütunu tırtıklı\n * gösteriyor; `tabular-nums` her basamağı aynı genişlikte çiziyor.\n */\nconst Stat: FC<Props> = ({\n label,\n value,\n unit,\n delta,\n trend,\n isUpPositive = true,\n description,\n icon,\n size = 'md',\n className,\n testId,\n}) => {\n /* Yonun IYI mi KOTU mu oldugu ayri bir karar: \"artis\" her zaman iyi degil. */\n const isPositive = trend === 'flat' ? undefined : (trend === 'up') === isUpPositive;\n\n return (\n <div className={cx(styles.stat, styles[`stat--${size}`], className)} data-testid={testId}>\n {icon && (\n <span className={styles.stat__icon} aria-hidden>\n {icon}\n </span>\n )}\n\n <span className={styles.stat__label}>{label}</span>\n\n <span className={styles.stat__value}>\n {value}\n {unit && <span className={styles.stat__unit}>{unit}</span>}\n </span>\n\n {delta && trend && (\n <span\n className={cx(\n styles.stat__delta,\n isPositive === true && styles['stat__delta--positive'],\n isPositive === false && styles['stat__delta--negative'],\n )}\n >\n {TREND_ICON[trend]}\n {delta}\n {/* Yon METIN olarak da okunur: ok ve renk ekran okuyucuya gecmiyor. */}\n <span className={styles.stat__srOnly}>{TREND_TEXT[trend]}</span>\n </span>\n )}\n\n {description && <span className={styles.stat__description}>{description}</span>}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Stat, 'Stat')) as typeof Stat;\n","'use client';\n\nimport { memo, type ReactNode, useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n CheckCircleFill,\n ExclamationTriangleFill,\n InfoCircleFill,\n XCircleFill,\n XLg,\n} from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\nexport type ToastTone = 'info' | 'success' | 'warning' | 'danger';\n\nexport type ToastOptions = {\n tone?: ToastTone;\n /** Görüntülenme süresi (ms). `0` → kendiliğinden kapanmaz. */\n duration?: number;\n /** Başlığın altındaki bir cümlelik ayrıntı. */\n description?: ReactNode;\n /** Bildirimin içindeki tek eylem (\"Geri al\"). */\n action?: { label: string; onClick: () => void };\n};\n\ntype ToastRecord = ToastOptions & { id: number; message: string };\n\n/** Ton başına ikon: renk TEK BAŞINA anlam taşımaz (WCAG 1.4.1). */\nconst ICONS: Record<ToastTone, ReactNode> = {\n info: <InfoCircleFill aria-hidden />,\n success: <CheckCircleFill aria-hidden />,\n warning: <ExclamationTriangleFill aria-hidden />,\n danger: <XCircleFill aria-hidden />,\n};\n\n/**\n * Ton başına varsayılan süre.\n *\n * <p>Hata daha UZUN durur: kullanıcı bir şeyin yanlış gittiğini okumak,\n * başarıyı okumaktan daha uzun sürüyor ve genellikle bir karar gerektiriyor.\n * Dört saniyede kaybolan bir hata mesajı, kullanıcıya ne olduğunu\n * söylememekle aynı kapıya çıkıyordu.\n */\nconst DEFAULT_DURATION: Record<ToastTone, number> = {\n info: 4_000,\n success: 4_000,\n warning: 6_000,\n danger: 8_000,\n};\n\n/** Aynı anda ekranda duran en fazla bildirim. */\nconst MAX_VISIBLE = 3;\n\n/*\n * YAYIN MERKEZI — modul duzeyinde, saglayicidan BAGIMSIZ.\n *\n * `HanuiProvider` zorunlu degil (bkz. `theme/context.ts`) ve bildirim\n * cagrilari React agacinin disindan da geliyor: bir axios interceptor'unun\n * icinden, bir servis fonksiyonundan. Yayin merkezi bir context'e baglansaydi\n * o cagrilarin hicbiri calismazdi.\n */\nlet counter = 0;\n/* `new Set()` modul duzeyinde bir CAGRI ve acilama olmadan bundler onu yan\n etkili sayabilir — Faz 0'da `memo()` cagrilarinda tam olarak bu olmustu.\n Burada olculebilir bir fark yaratmadi; acilama yine de duruyor cunku kural\n modul duzeyindeki HER cagri icin gecerli ve istisnasi olmamali. */\nconst listeners = /*#__PURE__*/ new Set<(toasts: ToastRecord[]) => void>();\nlet queue: ToastRecord[] = [];\n\nconst emit = () => listeners.forEach(listener => listener(queue));\n\nconst dismiss = (id: number) => {\n queue = queue.filter(item => item.id !== id);\n emit();\n};\n\nconst push = (message: string, options: ToastOptions = {}): number => {\n counter += 1;\n const id = counter;\n\n /*\n * SIRAYA ALMA: ekranda en fazla `MAX_VISIBLE` bildirim durur, fazlasi EN\n * ESKIsini duserek yerini alir. Sinirsiz birakildiginda hizli art arda\n * gelen istekler (toplu kaydetme) ekrani bastan asagi bildirimle\n * dolduruyor ve altindaki arayuze ulasilamiyordu.\n */\n queue = [...queue, { ...options, id, message }].slice(-MAX_VISIBLE);\n emit();\n\n return id;\n};\n\n/**\n * BİLDİRİM SÖZLEŞMESİ — süre, ikon ve renk kararları TEK YERDE.\n *\n * <h3>Neden harici bir kütüphaneye sarmalayıcı DEĞİL</h3>\n * Tüketici `react-hot-toast` taşıyordu ve gövdeyi kendi yazmak zorunda\n * kalmıştı: kütüphanenin goober sınıfı bizim modül sınıfımızla AYNI\n * özgüllükteydi ve kazananı kaynak sırası belirliyordu — aynı bildirim\n * geliştirmede ve üretimde İKİ FARKLI RENKTE çıkıyordu. Bir sarmalayıcı bu\n * sorunu çözmez, erteler.\n *\n * @example\n * toast.success('Adres kaydedildi');\n * toast.error('Kart reddedildi', { action: { label: 'Yeniden dene', onClick: retry } });\n */\nexport const toast = {\n show: push,\n info: (message: string, options?: ToastOptions) => push(message, { ...options, tone: 'info' }),\n success: (message: string, options?: ToastOptions) =>\n push(message, { ...options, tone: 'success' }),\n warning: (message: string, options?: ToastOptions) =>\n push(message, { ...options, tone: 'warning' }),\n error: (message: string, options?: ToastOptions) => push(message, { ...options, tone: 'danger' }),\n dismiss,\n /** Tümünü kapatır — sayfa geçişinde bayat bildirim taşınmasın. */\n clear: () => {\n queue = [];\n emit();\n },\n};\n\ntype ItemProps = {\n toast: ToastRecord;\n closeLabel: string;\n onDismiss: (id: number) => void;\n};\n\n/** Tek bir bildirim satırı; kendi zamanlayıcısını kendisi taşır. */\nconst ToastItem = ({ toast: record, closeLabel, onDismiss }: ItemProps) => {\n const tone = record.tone ?? 'info';\n const duration = record.duration ?? DEFAULT_DURATION[tone];\n\n const [isPaused, setIsPaused] = useState(false);\n const remainingRef = useRef(duration);\n const startedRef = useRef(0);\n\n useEffect(() => {\n if (duration === 0 || isPaused) return;\n\n startedRef.current = Date.now();\n const timer = window.setTimeout(() => onDismiss(record.id), remainingRef.current);\n\n return () => {\n window.clearTimeout(timer);\n /* Kalan sure KORUNUR: imlec ayrilinca sayac bastan baslasaydi, uzerine\n bir kez gelinen bildirim ekranda cok daha uzun kaliyordu. */\n remainingRef.current = Math.max(0, remainingRef.current - (Date.now() - startedRef.current));\n };\n }, [duration, isPaused, onDismiss, record.id]);\n\n return (\n <div\n className={cx(styles.toast, styles[`toast--${tone}`])}\n /*\n * `role=\"alert\"` YALNIZCA hatada: o rol `aria-live=\"assertive\"` demek ve\n * kullanicinin okudugu seyi BOLER. Basarili bir kaydetmeyi duyurmak icin\n * kullaniciyi bolmek gurultu; `status` sirasini bekler.\n */\n role={tone === 'danger' ? 'alert' : 'status'}\n /* Fare uzerindeyken sayac DURUR: kullanici bildirimi okuyor ya da\n icindeki eylemi tiklamaya gidiyor. */\n onPointerEnter={() => setIsPaused(true)}\n onPointerLeave={() => setIsPaused(false)}\n /* Klavye odagi da duraklatir: Tab ile \"Geri al\"a ulasmaya calisan\n kullanicinin altindan bildirim kayboluyordu. */\n onFocus={() => setIsPaused(true)}\n onBlur={() => setIsPaused(false)}\n >\n <span className={styles.toast__icon} aria-hidden>\n {ICONS[tone]}\n </span>\n\n <div className={styles.toast__text}>\n <span className={styles.toast__message}>{record.message}</span>\n {record.description && (\n <span className={styles.toast__description}>{record.description}</span>\n )}\n </div>\n\n {record.action && (\n <button\n type=\"button\"\n className={styles.toast__action}\n onClick={() => {\n record.action?.onClick();\n onDismiss(record.id);\n }}\n >\n {record.action.label}\n </button>\n )}\n\n <IconButton\n icon={<XLg aria-hidden />}\n label={closeLabel}\n variant=\"ghost\"\n size=\"sm\"\n className={styles.toast__close}\n onClick={() => onDismiss(record.id)}\n />\n </div>\n );\n};\n\ntype HubProps = {\n /** Kapatma düğmelerinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n className?: string;\n};\n\n/**\n * Bildirim yığını — uygulamada <strong>BİR KEZ</strong> çizilir.\n *\n * <h3>Neden tek yığın</h3>\n * Birden fazla canlı bölge, ekran okuyucuların duyuruları birleştirip sırayla\n * okumasına ya da tamamen atlamasına yol açıyor. Yığın kök yerleşimde bir kez\n * durur; `toast.*` çağrıları React ağacının dışından da çalışır.\n *\n * <h3>Duyuru bölgesi HER ZAMAN DOM'da</h3>\n * Kapsayıcı bildirim yokken de çiziliyor. Sonradan DOM'a eklenen bir canlı\n * bölgenin ilk duyurusu güvenilmez — ekran okuyucu bölgeyi izlemeye\n * başlamadan içerik gelmiş oluyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>bildirimin eylemine ve kapatma düğmesine ulaşır</td></tr>\n * <tr><td>odak/hover</td><td>kapanma sayacını DURDURUR</td></tr>\n * </table>\n */\nconst ToastHub = ({ closeLabel, className }: HubProps) => {\n const { labels } = useHanui();\n const [toasts, setToasts] = useState<ToastRecord[]>([]);\n\n useEffect(() => {\n listeners.add(setToasts);\n setToasts(queue);\n return () => {\n listeners.delete(setToasts);\n };\n }, []);\n\n const handleDismiss = useCallback((id: number) => dismiss(id), []);\n\n /* Escape en YENI bildirimi kapatir: yigilmis bildirimleri tek tek\n kapatmanin klavyeyle tek yolu buydu. */\n useEffect(() => {\n if (toasts.length === 0) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n dismiss(toasts[toasts.length - 1].id);\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [toasts]);\n\n /*\n * ═══ HIDRASYON: `isClient()` RENDER İÇİNDE OKUNAMAZ ═══\n *\n * Burada `if (!isClient()) return null` yazıyordu ve bu, React'in\n * hidrasyon uyuşmazlığı için listelediği ilk maddenin ta kendisiydi:\n * sunucu/istemci dallanması. Sunucu `null` üretiyor, istemcinin İLK\n * render'ı ise portalı üretiyordu; ağaç o noktada ayrıştığı için React\n * \"server rendered HTML didn't match\" diyor ve alt ağacın tamamını\n * yeniden çiziyordu.\n *\n * Etkisi büyüktü: `ToastHub` kök yerleşimde duruyor, yani uyuşmazlık\n * uygulamanın HER sayfasında oluşuyordu (ölçüldü: tüketici uygulamada\n * `<ToastHub />` kaldırılınca hata tümüyle kayboluyor).\n *\n * Doğru kalıp bir DURUM bayrağı: sunucu ve istemcinin ilk render'ı aynı\n * şeyi (`null`) üretir, portal ancak montajdan SONRA açılır. Bildirimler\n * zaten yalnızca kullanıcı etkileşimiyle çıkıyor; bir kare gecikmenin\n * görünür bir bedeli yok.\n */\n const [isMounted, setIsMounted] = useState(false);\n\n useEffect(() => setIsMounted(true), []);\n\n if (!isMounted) return null;\n\n return createPortal(\n <div className={cx(styles.hub, className)}>\n {toasts.map(record => (\n <ToastItem\n key={record.id}\n toast={record}\n closeLabel={resolveLabel('ToastHub.closeLabel', closeLabel, labels?.close)}\n onDismiss={handleDismiss}\n />\n ))}\n </div>,\n document.body,\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(ToastHub, 'ToastHub')) as typeof ToastHub;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useCallback, useId, useState } from 'react';\n\nimport { CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\nexport type AccordionItem = {\n id: string;\n /** Başlık satırı — tıklanabilir olan bu. */\n title: ReactNode;\n /** Başlığın sağında duran ikincil bilgi (sayaç, rozet). */\n meta?: ReactNode;\n content: ReactNode;\n isDisabled?: boolean;\n};\n\ntype Props = {\n items: AccordionItem[];\n /**\n * Aynı anda YALNIZCA BİR bölüm açık kalır.\n *\n * <p>Varsayılan çoklu: bir SSS listesinde iki soruyu yan yana okumak\n * yaygın bir ihtiyaç ve tek-açık kip, kullanıcının az önce açtığı bölümü\n * habersizce kapatıyordu. Tek-açık yalnızca bölümler UZUN olduğunda\n * (mobil filtre paneli) doğru.\n */\n isSingle?: boolean;\n /** Kontrolsüz kullanımda açılışta açık olan bölümler. */\n defaultOpenIds?: string[];\n /** Kontrollü kullanım; `onChange` ile birlikte verilir. */\n openIds?: string[];\n onChange?: (openIds: string[]) => void;\n className?: string;\n testId?: string;\n};\n\n/**\n * Akordeon — katlanabilir bölümler.\n *\n * <h3>Yerel `<details>` / `<summary>` üzerine</h3>\n * Açık/kapalı durumu, klavye desteği (`Enter` ve `Space`), ekran okuyucu\n * duyurusu (\"genişletildi/daraltıldı\") ve <strong>sayfa içi bulma</strong>\n * tarayıcıdan gelir. Sonuncusu taklit bir uygulamada imkânsız: Ctrl+F ile\n * aranan bir metin kapalı bir `<details>`in içindeyse tarayıcı bölümü kendisi\n * açıyor; `display: none` ile gizlenmiş bir `<div>`de o metin hiç yok.\n *\n * <p>Bedeli, tek-açık kipin elle kurulması: `<details name=\"…\">` bunu yerel\n * olarak veriyor ama Safari 17.2 öncesinde yok ve orada TÜM bölümler\n * birbirinden bağımsız açılıyordu — sessiz bir davranış farkı. Karar burada\n * veriliyor, tarayıcıya bırakılmıyor.\n *\n * <h3>Yükseklik geçişi</h3>\n * `interpolate-size: allow-keywords` + `height` geçişi ile `auto`ya\n * canlandırılıyor. Desteklemeyen tarayıcıda geçiş düşer ve bölüm ANINDA\n * açılır — eski davranış. Sabit bir piksel yüksekliği vermek ya da\n * `max-height` numarası kullanmak yanlış: ilki içeriği kırpıyor, ikincisi\n * kısa bölümlerde gözle görülür bir gecikme bırakıyordu.\n *\n * <h3>Klavye (yerel)</h3>\n * <table>\n * <tr><td>`Enter` / `Space`</td><td>bölümü açar/kapatır</td></tr>\n * <tr><td>`Tab`</td><td>başlıklar arasında gezinir</td></tr>\n * </table>\n * Ok tuşu YOKTUR ve olmamalı: akordeon bir liste değil, her başlık bağımsız\n * bir düğme (WAI-ARIA APG accordion deseni ok tuşlarını isteğe bağlı bırakıyor\n * ve yerel öğe onları getirmiyor).\n */\nconst Accordion: FC<Props> = ({\n items,\n isSingle,\n defaultOpenIds,\n openIds: controlledIds,\n onChange,\n className,\n testId,\n}) => {\n const baseId = useId();\n const [uncontrolledIds, setUncontrolledIds] = useState<string[]>(defaultOpenIds ?? []);\n\n const isControlled = controlledIds !== undefined;\n const openIds = isControlled ? controlledIds : uncontrolledIds;\n\n const toggle = useCallback(\n (id: string, willOpen: boolean) => {\n const next = willOpen\n ? isSingle\n ? [id]\n : [...openIds.filter(current => current !== id), id]\n : openIds.filter(current => current !== id);\n\n if (!isControlled) setUncontrolledIds(next);\n onChange?.(next);\n },\n [isControlled, isSingle, onChange, openIds],\n );\n\n return (\n <div className={cx(styles.accordion, className)} data-testid={testId}>\n {items.map(item => {\n const isOpen = openIds.includes(item.id);\n\n return (\n <details\n key={item.id}\n className={cx(\n styles.accordion__item,\n item.isDisabled && styles['accordion__item--disabled'],\n )}\n open={isOpen}\n /*\n * `onToggle` YEREL olaydir ve tarayici durumu DEGISTIRDIKTEN sonra\n * dusuyor. `onClick` ile yakalamak yetmiyordu: klavyeyle acilan\n * bolum (Enter/Space) tiklama uretmiyor ve durum React tarafinda\n * guncellenmiyordu.\n */\n onToggle={event => {\n const next = (event.currentTarget as HTMLDetailsElement).open;\n if (next !== isOpen) toggle(item.id, next);\n }}\n >\n <summary\n id={`${baseId}-${item.id}`}\n className={styles.accordion__summary}\n /*\n * Pasif bolum: `<summary>`nin `disabled` hali YOK. Isaretci\n * olaylari kesilir ve `tabindex=\"-1\"` ile sekme sirasindan\n * cikarilir; `aria-disabled` durumu duyurur.\n */\n aria-disabled={item.isDisabled}\n tabIndex={item.isDisabled ? -1 : undefined}\n onClick={event => item.isDisabled && event.preventDefault()}\n >\n <CaretRightFill aria-hidden className={styles.accordion__marker} />\n\n <span className={styles.accordion__title}>{item.title}</span>\n {item.meta && <span className={styles.accordion__meta}>{item.meta}</span>}\n </summary>\n\n {/*\n Ic sarmalayici ZORUNLU: yukseklik gecisi `<details>`in KENDISINE\n verilemez (isaretcinin yuksekligi de gecise girip basligi\n titretiyordu). Gecis bu kutuda.\n */}\n <div className={styles.accordion__panel}>\n <div className={styles.accordion__content}>{item.content}</div>\n </div>\n </details>\n );\n })}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Accordion, 'Accordion')) as typeof Accordion;\n","'use client';\n\nimport { type FC, memo, type ReactNode } from 'react';\n\nimport { CheckLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\nexport type StepItem = {\n id: string;\n label: string;\n /** Etiketin altındaki bir cümlelik açıklama. */\n description?: ReactNode;\n};\n\ntype Props = {\n steps: StepItem[];\n /** Bulunulan adımın DİZİNİ (0 tabanlı). Öncesi tamamlanmış sayılır. */\n currentIndex: number;\n /**\n * Bir adıma dönülebiliyorsa verilir. Verilmediğinde adımlar düğme DEĞİL\n * düz metin olur — tıklanabilir görünüp hiçbir şey yapmayan bir adım,\n * kullanıcıya var olmayan bir yol vaat ediyordu.\n */\n onStepClick?: (index: number) => void;\n /** Akışın erişilebilir adı (\"Ödeme adımları\"). ZORUNLU. */\n label: string;\n orientation?: 'horizontal' | 'vertical';\n className?: string;\n testId?: string;\n};\n\n/** Bir adımın durumu — üçü de görsel olarak AYRI çizilir. */\nconst statusOf = (index: number, currentIndex: number): 'done' | 'current' | 'upcoming' => {\n if (index < currentIndex) return 'done';\n if (index === currentIndex) return 'current';\n return 'upcoming';\n};\n\n/** Durumun ekran okuyucuya okunan karşılığı. */\nconst STATUS_TEXT: Record<'done' | 'current' | 'upcoming', string> = {\n done: 'tamamlandı',\n current: 'şu anki adım',\n upcoming: 'sıradaki',\n};\n\n/**\n * Adım göstergesi (stepper) — çok adımlı akışta NEREDE olunduğu.\n *\n * <h3>Üç durum, ÜÇ AYRI işaret</h3>\n * Tamamlanan adım <strong>tik</strong>, bulunulan adım <strong>dolu\n * madalyon + sıra numarası</strong>, sıradaki adım <strong>boş\n * madalyon</strong> taşıyor. Renk bunlara EŞLİK ediyor, tek başına\n * anlatmıyor (WCAG 1.4.1): üçünü yalnızca renkle ayırmak, renk körü bir\n * kullanıcı için \"üç aynı daire\" demekti.\n *\n * <p>Durum ayrıca METİN olarak okunuyor — her adımın erişilebilir adına\n * \"tamamlandı\" / \"şu anki adım\" / \"sıradaki\" ekleniyor. Görsel işaret ekran\n * okuyucuya geçmiyor; `aria-current` tek başına yalnızca BULUNULAN adımı\n * söylüyor, tamamlananları değil.\n *\n * <h3>Geri dönülebilirlik AÇIKÇA bildirilir</h3>\n * `onStepClick` verilmediğinde adımlar `<button>` bile değil: tıklanabilir\n * görünüp hiçbir şey yapmayan bir adım, kullanıcıya var olmayan bir yol vaat\n * ediyordu. Verildiğinde yalnızca TAMAMLANMIŞ adımlar tıklanabilir — ileri\n * atlamak, atlanan adımın verisini toplamadan devam etmek demek.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Tab`</td><td>tıklanabilir adımlar arasında gezinir</td></tr>\n * <tr><td>`Enter` / `Space`</td><td>adıma döner</td></tr>\n * </table>\n * Ok tuşu YOK: adımlar bir seçim listesi değil, her biri bağımsız bir\n * gezinme bağlantısı.\n */\nconst Steps: FC<Props> = ({\n steps,\n currentIndex,\n onStepClick,\n label,\n orientation = 'horizontal',\n className,\n testId,\n}) => (\n <ol\n className={cx(styles.steps, styles[`steps--${orientation}`], className)}\n aria-label={label}\n data-testid={testId}\n >\n {steps.map((step, index) => {\n const status = statusOf(index, currentIndex);\n /* Ileri atlamak YOK: atlanan adimin verisi toplanmadan devam edilemez. */\n const isClickable = Boolean(onStepClick) && status === 'done';\n\n const body = (\n <>\n <span className={styles.steps__marker} aria-hidden>\n {status === 'done' ? <CheckLg /> : index + 1}\n </span>\n\n <span className={styles.steps__text}>\n <span className={styles.steps__label}>{step.label}</span>\n {step.description && (\n <span className={styles.steps__description}>{step.description}</span>\n )}\n </span>\n\n {/* Durum METIN olarak da okunur: gorsel isaret ekran okuyucuya\n gecmiyor ve `aria-current` yalnizca bulunulan adimi soyluyor. */}\n <span className={styles.steps__status}>{STATUS_TEXT[status]}</span>\n </>\n );\n\n return (\n <li\n key={step.id}\n className={cx(styles.steps__item, styles[`steps__item--${status}`])}\n aria-current={status === 'current' ? 'step' : undefined}\n >\n {isClickable ? (\n <button\n type=\"button\"\n className={styles.steps__button}\n onClick={() => onStepClick?.(index)}\n >\n {body}\n </button>\n ) : (\n <span className={styles.steps__button}>{body}</span>\n )}\n </li>\n );\n })}\n </ol>\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Steps, 'Steps')) as typeof Steps;\n","'use client';\n\nimport {\n type FC,\n type KeyboardEvent,\n memo,\n type ReactNode,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { isDefined } from '@ahmetilhn/handy-utils';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { scrollIntoViewIfPossible } from '../../helpers/scroll.helper';\n\nimport styles from './index.module.scss';\n\nexport type TabItem = {\n id: string;\n label: string;\n /** Etiketin yanında gösterilen sayı. */\n count?: number;\n /**\n * Sekmenin paneli.\n *\n * <p>Verilmezse bileşen yalnızca <strong>sekme çubuğu</strong> çizer ve\n * içeriği çağıran taraf yönetir. Bir formun üç kipi tek bir panelin içinde\n * yaşıyorsa üç ayrı panel yazmak aynı alanları üç kez tanımlamak olurdu.\n */\n content?: ReactNode;\n};\n\ntype Props = {\n items: TabItem[];\n /** Kontrolsüz kullanımda açılışta seçili sekme. */\n defaultTabId?: string;\n /**\n * Kontrollü kullanım: seçili sekme çağıranın durumunda.\n *\n * <p>`onChange` ile birlikte verilir. Kontrolsüz sürüm (yalnızca\n * `defaultTabId`) korunur — kendi durumunu tutması yeterli olan sekmelerin\n * dışarıdan yönetilmesi gereksiz.\n */\n activeId?: string;\n onChange?: (id: string) => void;\n /** Sekme çubuğunun erişilebilir adı. */\n ariaLabel?: string;\n /**\n * Ok tuşu yalnızca ODAĞI taşır; seçim `Enter`/`Space` ile yapılır.\n *\n * <p>Varsayılan OTOMATİK etkinleştirme (ok tuşu odakla birlikte seçimi de\n * taşır) ve APG panel içeriği hazır olduğu sürece onu öneriyor. Ama panel\n * PAHALIYSA — her sekme bir istek atıyorsa — otomatik etkinleştirme,\n * kullanıcı beşinci sekmeye giderken dört istek atıyor. Manuel kipte\n * kullanıcı hedefine varıp `Enter`a basıyor: tek istek.\n */\n isManualActivation?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Sekmeler.\n *\n * <p>ARIA sekme kalıbı tam uygulanır: `role=\"tablist\"`, `aria-selected`,\n * `aria-controls` ve ok tuşlarıyla gezinme. Yalnızca görsel olarak sekme gibi\n * duran düğmeler, klavye kullanıcısı için gezinilemez bir yapı olurdu.\n *\n * <p>Seçili olmayan panel DOM'dan çıkarılır: gizli panellerdeki bağlantılar ve\n * girdiler sekme sırasına girmemeli.\n *\n * <h3>İki kullanım</h3>\n * <ul>\n * <li><b>Kontrolsüz + panelli</b> — `items[].content` verilir, bileşen\n * seçimi kendisi tutar.</li>\n * <li><b>Kontrollü + panelsiz</b> — `activeId` + `onChange` verilir,\n * `content` verilmez; bileşen yalnızca çubuğu çizer.</li>\n * </ul>\n *\n * <h3>Klavye (APG: tabs, OTOMATİK etkinleştirme)</h3>\n * <table>\n * <tr><td>`ArrowRight` / `ArrowLeft`</td><td>sonraki / önceki sekme; uçlarda DÖNER</td></tr>\n * <tr><td>`Tab`</td><td>çubuktan panele çıkar — çubuk TEK durak</td></tr>\n * </table>\n * Ok tuşu odakla birlikte seçimi de taşır (otomatik etkinleştirme). Panel\n * içeriği hazır ve ucuz olduğu sürece APG'nin önerdiği budur; her sekmesi bir\n * istek atan pahalı bir panelde `isManualActivation` verilir — orada otomatik\n * etkinleştirme, kullanıcı beşinci sekmeye giderken dört istek atıyordu.\n * Nöbetçi: `components/__tests__/keyboard.test.tsx`.\n */\nconst Tabs: FC<Props> = ({\n items,\n defaultTabId,\n activeId: controlledId,\n onChange,\n ariaLabel,\n isManualActivation,\n className,\n testId,\n}) => {\n const baseId = useId();\n const [uncontrolledId, setUncontrolledId] = useState(defaultTabId ?? items[0]?.id);\n\n const isControlled = isDefined(controlledId);\n const activeId = isControlled ? controlledId : uncontrolledId;\n\n const activeIndex = items.findIndex(item => item.id === activeId);\n /* Manuel kipte ODAKLANAN sekme ile SECILI sekme ayrisir. */\n const [focusIndex, setFocusIndex] = useState(activeIndex < 0 ? 0 : activeIndex);\n const listRef = useRef<HTMLDivElement>(null);\n const active = items[activeIndex] ?? items[0];\n\n /*\n * SECILI SEKME GORUNURE KAYDIRILIR.\n *\n * Cubuk tasabiliyor (`scroll-row`) ve secim adres cubugundan ya da baska bir\n * denetimden de gelebiliyor: on sekmeli bir cubukta yedinci sekme secili\n * gelen bir sayfa, kullaniciya hicbir sekme secili degilmis gibi\n * gorunuyordu.\n *\n * `block: 'nearest'` — dikey kaydirma YOK: cubuk sayfanin ortasindayken\n * `scrollIntoView` bütün sayfayi zipliyordu.\n */\n useEffect(() => {\n scrollIntoViewIfPossible(listRef.current?.querySelector(`[aria-selected=\"true\"]`), {\n block: 'nearest',\n inline: 'nearest',\n });\n }, [activeId]);\n\n const select = (id: string) => {\n if (!isControlled) setUncontrolledId(id);\n onChange?.(id);\n };\n\n /**\n * Ok tuşlarıyla gezinme; başta/sonda döner.\n *\n * <p>Otomatik kipte ok tuşu odakla birlikte SEÇİMİ de taşır; manuel kipte\n * yalnızca odağı taşır ve seçim `Enter`/`Space` ile yapılır. İkisi de APG\n * içinde geçerli — ayrım panelin pahalı olup olmadığında.\n */\n const handleKeyDown = (event: KeyboardEvent) => {\n if (isManualActivation && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n select(items[focusIndex].id);\n return;\n }\n\n const offset = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;\n if (offset === 0) return;\n\n event.preventDefault();\n const next = ((isManualActivation ? focusIndex : activeIndex) + offset + items.length) % items.length;\n\n setFocusIndex(next);\n if (!isManualActivation) select(items[next].id);\n\n /* Odak HER IKI kipte de tasinir: manuel kipte seciliyle odaklanan sekme\n ayrisiyor ve `tabindex` odaklanani izlemek zorunda. */\n document.getElementById(`${baseId}-tab-${items[next].id}`)?.focus();\n };\n\n if (items.length === 0) return null;\n\n /*\n * Panelsiz kullanimda `aria-controls` VERILMEZ: var olmayan bir kimligi\n * isaret etmek ekran okuyucuda kirik bir bag uretir.\n *\n * Kontrol VARLIK uzerinden: `content` bir dize ya da sayi da olabilir ve\n * `undefined`/`null` disindaki her sey bir panel demek.\n */\n const hasPanel = isDefined(active?.content);\n\n return (\n <div className={cx(styles.tabs, className)} data-testid={testId}>\n <div\n ref={listRef}\n className={styles.tabs__list}\n role=\"tablist\"\n aria-label={ariaLabel}\n onKeyDown={handleKeyDown}\n >\n {items.map(item => {\n const isActive = item.id === active.id;\n\n return (\n <button\n key={item.id}\n id={`${baseId}-tab-${item.id}`}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={hasPanel ? `${baseId}-panel-${item.id}` : undefined}\n // Yalnızca seçili sekme sekme sırasında; gezinme ok tuşlarıyla.\n /* Donen `tabindex` ODAKLANANI izler: manuel kipte secili sekme\n ile odaklanan sekme ayri ve Tab'in geri donecegi yer\n odaklanan olmali. */\n tabIndex={(isManualActivation ? items[focusIndex]?.id === item.id : isActive) ? 0 : -1}\n className={cx(styles.tabs__tab, isActive && styles['tabs__tab--active'])}\n onClick={() => select(item.id)}\n >\n {item.label}\n {isDefined(item.count) && <span className={styles.tabs__count}>{item.count}</span>}\n </button>\n );\n })}\n </div>\n\n {hasPanel && (\n <div\n id={`${baseId}-panel-${active.id}`}\n role=\"tabpanel\"\n aria-labelledby={`${baseId}-tab-${active.id}`}\n className={styles.tabs__panel}\n tabIndex={0}\n >\n {active.content}\n </div>\n )}\n </div>\n );\n};\n\nexport default /*#__PURE__*/ memo(Tabs) as typeof Tabs;\n","import { memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n label: string;\n /** İkon DIŞARIDAN gelir: hangi ikonun hangi konuya ait olduğu uygulamanın bilgisi. */\n icon: ReactNode;\n href: string;\n /** Etiketin altında gösterilen ikincil satır (\"1.248 kayıt\"). */\n meta?: ReactNode;\n isActive?: boolean;\n /** Yönlendiriciye geçirilecek ek props. */\n linkProps?: HanuiLinkExtraProps;\n className?: string;\n testId?: string;\n};\n\n/**\n * Karo — ikon madalyonu + etiket.\n *\n * <h3>Neden ikon, neden yuvarlak madalyon</h3>\n * Ana giriş noktaları metin listesi olarak verildiğinde kullanıcı satır satır\n * okuyor. İkon, aranan öğeyi <em>okumadan</em> bulmayı sağlar; madalyon ise\n * ikona sabit bir kutu verir — farklı ikonların doğal genişlikleri karoları\n * düzensiz hizalıyordu.\n *\n * <h3>Karonun tamamı tıklanabilir</h3>\n * Bağlantı yalnızca etiketi değil karonun tümünü kaplar. Küçük bir metin\n * bağlantısını hedeflemek, özellikle dokunmatik ekranda gereksiz bir hassasiyet\n * talebiydi.\n *\n * <h3>`meta` neden sayı değil `ReactNode`</h3>\n * \"1.248 ürün\" cümlesi hem sayı biçimine hem dile bağlı. Bileşen içinde\n * `toLocaleString` çağırmak, o kararı kütüphanenin varsayımına bağlıyordu.\n */\nconst Tile = ({ label, icon, href, meta, isActive, linkProps, className, testId }: Props) => (\n <HanuiLink\n href={href}\n className={cx(styles.tile, isActive && styles['tile--active'], className)}\n aria-current={isActive ? 'page' : undefined}\n data-testid={testId}\n {...linkProps}\n >\n <span className={styles.tile__medallion} aria-hidden>\n {icon}\n </span>\n\n <span className={styles.tile__label}>{label}</span>\n\n {meta && <span className={styles.tile__meta}>{meta}</span>}\n </HanuiLink>\n);\n\nexport default /*#__PURE__*/ memo(Tile) as typeof Tile;\n","'use client';\n\nimport { type FC, memo, type ReactNode } from 'react';\n\nimport { CheckLg, XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\n/** Bir olayın durumu. `pending` HENÜZ olmadı — başarısız değil. */\nexport type TimelineStatus = 'done' | 'current' | 'pending' | 'failed';\n\nexport type TimelineEvent = {\n id: string;\n title: string;\n /** Zaman damgası — BİÇİMLENDİRİLMİŞ dize. Bileşen tarih biçimlendirmez. */\n time?: string;\n description?: ReactNode;\n status?: TimelineStatus;\n /** Varsayılan işaretin yerine geçen ikon. */\n icon?: ReactNode;\n};\n\ntype Props = {\n events: TimelineEvent[];\n /** Akışın erişilebilir adı (\"Sipariş geçmişi\"). ZORUNLU. */\n label: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Durumun GÖRSEL işareti — renkten bağımsız.\n *\n * <p>`done` tik, `failed` çarpı taşıyor; ikisi de dolu daire ve YALNIZCA\n * renkle ayrılsalardı renk körü bir kullanıcı için aynı görünüyorlardı\n * (WCAG 1.4.1). `current` ve `pending` kendi biçimlerini kenarlıktan alıyor\n * (dolu halka / kesikli daire) ve glif taşımıyor.\n */\nconst STATUS_ICON: Record<TimelineStatus, ReactNode> = {\n done: <CheckLg />,\n failed: <XLg />,\n current: null,\n pending: null,\n};\n\n/** Durumun ekran okuyucuya okunan karşılığı. */\nconst STATUS_TEXT: Record<TimelineStatus, string> = {\n done: 'tamamlandı',\n current: 'şu an',\n pending: 'bekliyor',\n failed: 'başarısız',\n};\n\n/**\n * Zaman çizelgesi — sipariş durumu, işlem geçmişi.\n *\n * <h3>{@link Steps} ile farkı: ileri mi geri mi bakıyor</h3>\n * İkisi de sıralı ve durumlu; ayrım yönlerinde:\n *\n * <ul>\n * <li>`Steps` İLERİ bakar: kullanıcı bir akışın içinde ve kalan adımları\n * görüyor. Adım sayısı sabit, adımlara dönülebilir.</li>\n * <li><b>`Timeline` GERİ bakar:</b> olmuş şeylerin kaydı. Olay sayısı\n * değişken, hiçbiri tıklanabilir değil ve <strong>başarısız</strong>\n * diye bir durum var — bir adım \"başarısız\" olamaz, akış orada durur;\n * bir olay olabilir ve kayıtta kalır.</li>\n * </ul>\n *\n * <h3>Zaman biçimlendirmesi ÇAĞIRANIN</h3>\n * `time` biçimlendirilmiş bir dize. Kütüphane `Intl` çağırsaydı yerel ayarı\n * ve \"3 saat önce\" mi \"14:32\" mi yazılacağını kendisi seçmiş olurdu — ikisi\n * de bağlama bağlı kararlar.\n *\n * <h3>Durum renkle DEĞİL, üç şeyle birden</h3>\n * İşaretin <strong>biçimi</strong> (dolu / halka / tik / çarpı), rengi ve\n * ekran okuyucuya okunan <strong>metni</strong>. Yalnızca renk kullanılsaydı\n * \"tamamlandı\" ile \"başarısız\" renk körü bir kullanıcı için aynı daireydi.\n */\nconst Timeline: FC<Props> = ({ events, label, className, testId }) => (\n <ol className={cx(styles.timeline, className)} aria-label={label} data-testid={testId}>\n {events.map(event => {\n const status = event.status ?? 'done';\n\n return (\n <li\n key={event.id}\n className={cx(styles.timeline__item, styles[`timeline__item--${status}`])}\n aria-current={status === 'current' ? 'step' : undefined}\n >\n <span className={styles.timeline__marker} aria-hidden>\n {event.icon ?? STATUS_ICON[status]}\n </span>\n\n <div className={styles.timeline__body}>\n <span className={styles.timeline__title}>\n {event.title}\n {/* Durum METIN olarak da okunur: isaret ve renk ekran okuyucuya\n gecmiyor. */}\n <span className={styles.timeline__srOnly}>{STATUS_TEXT[status]}</span>\n </span>\n\n {event.time && (\n /* `<time>` DEGIL `<span>`: `datetime` icin makine okunur bir\n deger gerekiyor ve elimizde yalnizca bicimlendirilmis dize\n var. Yanlis bir `datetime`, hicbir `datetime`den kotu. */\n <span className={styles.timeline__time}>{event.time}</span>\n )}\n\n {event.description && (\n <span className={styles.timeline__description}>{event.description}</span>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n);\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Timeline, 'Timeline')) as typeof Timeline;\n","'use client';\n\nimport {\n memo,\n type MouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport {\n captureFocus,\n focusFirstMeaningful,\n isTopModal,\n preventAutoKeyboard,\n pushModal,\n} from '../../helpers/focus.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport useScrollLock from '../../hooks/useScrollLock';\nimport { useHanui } from '../../theme/context';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\nexport type ModalTone = 'neutral' | 'danger' | 'warning' | 'success' | 'info';\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n /**\n * Kapatma düğmesinin erişilebilir adı.\n *\n * <p>Verilmezse `HanuiProvider labels.close` okunur. Bağlama göre farklı\n * olması gereken pencerelerde (\"Daha sonra\") prop kazanır.\n */\n closeLabel?: string;\n children?: ReactNode;\n /**\n * Başlığın altındaki bir cümlelik açıklama.\n *\n * <p>`aria-describedby` ile pencereye bağlanır: ekran okuyucu pencere\n * açıldığında başlıkla birlikte bunu da okur. Gövdeye paragraf olarak\n * yazıldığında duyurulmuyordu.\n */\n description?: ReactNode;\n /** Altta duran eylemler. Sağa yaslanır; dar ekranda tam genişliğe yayılır. */\n footer?: ReactNode;\n /** Başlığın solunda duran ikon madalyonu; `tone` rengini alır. */\n icon?: ReactNode;\n /** İkon madalyonunun tonu. */\n tone?: ModalTone;\n size?: 'sm' | 'md' | 'lg';\n /**\n * `false` iken arka plana tıklama, Escape ve kapatma düğmesi kapatmaz.\n *\n * <p>Yalnızca <strong>sürmekte olan</strong> bir işlem için: silme isteği\n * gönderilmişken pencerenin kapanması, kullanıcıya işlem iptal edilmiş gibi\n * görünüyordu.\n */\n isDismissable?: boolean;\n className?: string;\n testId?: string;\n};\n\n/**\n * Kip pencere (modal).\n *\n * <h3>Yerel `<dialog>` + `showModal()`</h3>\n * Odak tuzağı, Escape ile kapanma, arka planın etkileşime kapanması ve\n * `aria-modal` semantiği tarayıcıdan gelir. Bunları `<div>` üzerine elle\n * kurmak yüzlerce satır ve kaçınılmaz olarak eksik bir odak yönetimi demek.\n *\n * <h3>Neden `open` özniteliği değil `showModal()`</h3>\n * `<dialog open>` pencereyi <em>kipsiz</em> açar: arka plan tıklanabilir kalır\n * ve odak tuzağı çalışmaz. Kipli davranışın tek yolu yöntemi çağırmak.\n *\n * <h3>Arka planın kaydırılması ayrıca engellenir</h3>\n * `showModal()` arka planı <em>etkileşime</em> kapatır ama tarayıcıların bir\n * kısmında sayfa hâlâ kaydırılabiliyor: kullanıcı pencereyi kaydırdığını\n * sanırken arkadaki listeyi kaydırıyordu. `<body>` kilitlenir.\n *\n * <h3>Mobilde alt sayfaya düşer</h3>\n * Dar ekranda ortalanmış bir pencere, klavye açıldığında yukarı sıkışıyor ve\n * dip düğmeleri klavyenin altında kalıyordu. Alt sayfa baş parmağın\n * erişebildiği yerde durur.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Escape`</td><td>kapatır — `isDismissable={false}` iken KAPATMAZ</td></tr>\n * <tr><td>`Tab`</td><td>odak panelin içinde döner (tarayıcı: `showModal()`)</td></tr>\n * </table>\n * Odak tuzağı tarayıcıdan gelir; kütüphanenin işi `cancel` olayını React\n * durumuna bağlamak. Yakalanmadığında pencere kapanıyor ama `isOpen` `true`\n * kalıyor ve bir daha açılamıyordu. Nöbetçi:\n * `components/__tests__/keyboard.test.tsx`.\n */\nconst Modal = ({\n isOpen,\n onClose,\n title,\n closeLabel,\n children,\n description,\n footer,\n icon,\n tone = 'neutral',\n size = 'md',\n isDismissable = true,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const dialogRef = useRef<HTMLDialogElement>(null);\n /* Yigindaki yerimiz: Escape yalnizca EN USTTEKI panelde islenir. */\n const tokenRef = useRef<symbol | null>(null);\n const titleId = useId();\n const descriptionId = useId();\n\n /*\n * ACILIS: `showModal()` + odak + yigina katilma.\n *\n * Uc is TEK etkide toplandi cunku SIRALARI onemli: pencere once acilmali\n * (yoksa icindeki hicbir sey odaklanabilir degil), sonra odak verilmeli,\n * en son yigina katilmali — yigina once katilsaydi, acilis sirasinda kisa\n * bir an icin \"en ust panel\" olup ustundeki gercek panelin Escape'ini\n * yutuyordu.\n */\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (!isOpen) {\n if (dialog.open) dialog.close();\n return;\n }\n\n const restoreFocus = captureFocus();\n if (!dialog.open) dialog.showModal();\n\n /* Odak KAPATMA DUGMESINE degil ilk anlamli ogeye. `showModal()` DOM\n sirasindaki ilk odaklanabilir ogeye gidiyor ve o neredeyse her zaman\n basliktaki carpi: ekran okuyucu pencereyi \"Kapat, dugme\" diye aciyor —\n kullanicinin duydugu ilk sey, pencerenin ne oldugu degil ondan nasil\n kacilacagi. */\n focusFirstMeaningful(dialog, `.${styles.modal__close}`);\n /* Odak bir metin alanina dustuyse geri alinir: telefonda ekran klavyesi\n kullanici istemeden aciliyordu (bkz. `helpers/focus.helper`). */\n preventAutoKeyboard(dialog);\n\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, [isOpen]);\n\n /*\n * Arka plan kaydirmasi kilitlenir. `showModal()` arka plani etkilesime\n * kapatir ama kaydirmayi her tarayicida engellemiyor: kullanici pencereyi\n * kaydirdigini sanirken arkadaki listeyi kaydiriyordu. Kilit SAYACLI —\n * ic ice iki panelde ilki kapaninca erken acilmamali (bkz. `useScrollLock`).\n */\n useScrollLock(isOpen);\n\n /*\n * Escape'i tarayici isliyor ama React durumu bundan haberdar olmuyor;\n * `cancel` olayi yakalanmazsa pencere kapanip `isOpen` true kaliyor ve bir\n * daha acilamiyordu.\n */\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const handleCancel = (event: Event) => {\n /* Varsayilan HER ZAMAN engellenir: kapanis karari React'te veriliyor ve\n tarayicinin pencereyi kendi basina kapatmasi durumu `isOpen: true`\n birakiyordu. */\n event.preventDefault();\n if (!isDismissable) return;\n\n /* Yalnizca EN USTTEKI panel kapanir. Ust uste iki pencerede tek bir\n Escape ikisini birden kapatiyordu: `cancel` her ikisine de ulasiyor\n ve ikisi de kendi `onClose`unu cagiriyordu. */\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n\n onClose();\n };\n\n dialog.addEventListener('cancel', handleCancel);\n return () => dialog.removeEventListener('cancel', handleCancel);\n }, [onClose, isDismissable]);\n\n const handleBackdropClick = useCallback(\n (event: MouseEvent<HTMLDialogElement>) => {\n if (!isDismissable) return;\n // Hedef dialog'un KENDISI ise arka plana tiklanmistir; panel degil.\n if (event.target === dialogRef.current) onClose();\n },\n [isDismissable, onClose],\n );\n\n return (\n <dialog\n ref={dialogRef}\n className={cx(styles.modal, styles[`modal--${size}`], className)}\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n data-testid={testId}\n onClick={handleBackdropClick}\n >\n <div className={styles.modal__panel}>\n <header className={styles.modal__header}>\n {icon && (\n <span className={cx(styles.modal__icon, styles[`modal__icon--${tone}`])}>{icon}</span>\n )}\n\n <div className={styles.modal__heading}>\n <h2 id={titleId} className={styles.modal__title}>\n {title}\n </h2>\n {description && (\n <p id={descriptionId} className={styles.modal__description}>\n {description}\n </p>\n )}\n </div>\n\n {isDismissable && (\n <IconButton\n icon={<XLg aria-hidden />}\n label={resolveLabel('Modal.closeLabel', closeLabel, labels?.close)}\n variant=\"ghost\"\n size=\"sm\"\n className={styles.modal__close}\n onClick={onClose}\n />\n )}\n </header>\n\n {/*\n Gövde yalnızca içerik VARSA çizilir: onay pencerelerinin çoğunda soru\n başlıkta ve açıklamada duruyor, gövde boş kalıyor ve boş bir kutu\n 40 px'lik bir boşluk bırakıyordu.\n */}\n {children && <div className={styles.modal__body}>{children}</div>}\n\n {footer && <footer className={styles.modal__footer}>{footer}</footer>}\n </div>\n </dialog>\n );\n};\n\nexport default /*#__PURE__*/ memo(Modal) as typeof Modal;\n","'use client';\n\nimport {\n type KeyboardEvent,\n memo,\n type ReactNode,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { Search } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { scrollIntoViewIfPossible } from '../../helpers/scroll.helper';\nimport { named } from '../../helpers/component.helper';\nimport { captureFocus, isTopModal, pushModal } from '../../helpers/focus.helper';\nimport { matchesSearch } from '../../helpers/text.helper';\nimport useScrollLock from '../../hooks/useScrollLock';\n\nimport styles from './index.module.scss';\n\nexport type CommandItem = {\n id: string;\n label: string;\n /** Ayırt edici ikincil satır — bir komutun nereye götürdüğü. */\n description?: string;\n /** Gruplama başlığı (\"Gezinme\", \"Eylemler\"). Aynı grup ardışık çizilir. */\n group?: string;\n icon?: ReactNode;\n /** Kısayol ipucu (\"⌘K\"). Yalnızca GÖSTERİLİR; tuşu çağıran bağlar. */\n shortcut?: string;\n onSelect: () => void;\n};\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n items: CommandItem[];\n /** Pencerenin erişilebilir adı (\"Komut paleti\"). ZORUNLU. */\n label: string;\n /** Arama kutusunun yer tutucusu ve erişilebilir adı. ZORUNLU. */\n searchPlaceholder: string;\n /** Sonuç yokken yazılan metin. ZORUNLU. */\n emptyMessage: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Komut paleti — klavyeyle her şeye ulaşma.\n *\n * <h3>Neden `Combobox` + `Modal` bileşimi DEĞİL de ayrı bir bileşen</h3>\n * Denendi ve iki yerde kırıldı. `Combobox` bir DEĞER seçtiriyor: seçim\n * tetikleyicide kalıcı olarak görünüyor, `value`/`onChange` sözleşmesi var ve\n * kapanınca seçili öğe hatırlanıyor. Palet ise bir EYLEM çalıştırıyor —\n * hatırlanacak bir değer yok. İkincisi, `Combobox`ın tetikleyicisi var;\n * palette tetikleyici KLAVYE KISAYOLU ve o kısayolu bağlamak çağıranın işi\n * (hangi tuş, hangi sayfada — kütüphane bilemez).\n *\n * <h3>Kısayolu KÜTÜPHANE bağlamaz</h3>\n * `⌘K` yaygın ama evrensel değil ve belge düzeyinde bir tuş dinleyicisi\n * kurmak, tüketicinin kendi kısayollarıyla sessizce çakışmak demek. `shortcut`\n * alanı yalnızca GÖSTERİLİYOR; `isOpen` çağıranın.\n *\n * <h3>Arama `matchesSearch` ile — aksan duyarsız</h3>\n * \"siparis\" yazan kullanıcı \"Sipariş\"i bulmalı. Aynı normalizasyon\n * `Combobox`ın yerel filtresinde de kullanılıyor; iki yerde iki farklı arama\n * kuralı, aynı terimin iki farklı sonuç vermesi demekti.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`ArrowDown` / `ArrowUp`</td><td>etkin komut; uçlarda DÖNER</td></tr>\n * <tr><td>`Home` / `End`</td><td>ilk / son komut</td></tr>\n * <tr><td>`Enter`</td><td>etkin komutu çalıştırır ve kapatır</td></tr>\n * <tr><td>`Escape`</td><td>kapatır, odak AÇAN öğeye döner</td></tr>\n * </table>\n * Odak arama kutusundan AYRILMAZ; etkin komut `aria-activedescendant` ile\n * bildiriliyor. Odağı listeye taşımak yazmaya devam etmeyi imkânsız\n * kılıyordu.\n */\nconst CommandPalette = ({\n isOpen,\n onClose,\n items,\n label,\n searchPlaceholder,\n emptyMessage,\n className,\n testId,\n}: Props) => {\n const baseId = useId();\n const listboxId = `${baseId}-listbox`;\n const dialogRef = useRef<HTMLDialogElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const tokenRef = useRef<symbol | null>(null);\n\n const [query, setQuery] = useState('');\n const [activeIndex, setActiveIndex] = useState(0);\n\n const visible = useMemo(() => {\n if (query.trim() === '') return items;\n\n const needle = query.trim();\n return items.filter(\n item =>\n matchesSearch(item.label, needle) ||\n (item.description ? matchesSearch(item.description, needle) : false),\n );\n }, [items, query]);\n\n useScrollLock(isOpen);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (!isOpen) {\n if (dialog.open) dialog.close();\n return;\n }\n\n const restoreFocus = captureFocus();\n if (!dialog.open) dialog.showModal();\n\n /* Arama kutusu ACILIR ACILMAZ odaklanir: paletin tek amaci yazmak.\n `preventScroll` — odaklanan kutu ust katmanda ve iOS sayfayi\n kaydirmaya calisiyordu. */\n inputRef.current?.focus({ preventScroll: true });\n setQuery('');\n setActiveIndex(0);\n\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, [isOpen]);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const handleCancel = (event: Event) => {\n event.preventDefault();\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n onClose();\n };\n\n dialog.addEventListener('cancel', handleCancel);\n return () => dialog.removeEventListener('cancel', handleCancel);\n }, [onClose]);\n\n /* Etkin komut gorunur alanin disina cikmamali. */\n useEffect(() => {\n scrollIntoViewIfPossible(dialogRef.current?.querySelector(`[data-index=\"${activeIndex}\"]`), {\n block: 'nearest',\n });\n }, [activeIndex]);\n\n const run = (item: CommandItem) => {\n item.onSelect();\n onClose();\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n const lastIndex = visible.length - 1;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActiveIndex(current => (current >= lastIndex ? 0 : current + 1));\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n setActiveIndex(current => (current <= 0 ? lastIndex : current - 1));\n break;\n\n case 'Home':\n event.preventDefault();\n setActiveIndex(0);\n break;\n\n case 'End':\n event.preventDefault();\n setActiveIndex(lastIndex);\n break;\n\n case 'Enter': {\n event.preventDefault();\n const item = visible[activeIndex];\n if (item) run(item);\n break;\n }\n\n default:\n break;\n }\n };\n\n return (\n <dialog\n ref={dialogRef}\n className={cx(styles.palette, className)}\n aria-label={label}\n data-testid={testId}\n onClick={event => event.target === dialogRef.current && onClose()}\n >\n <div className={styles.palette__search}>\n <Search aria-hidden className={styles.palette__searchIcon} />\n\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n className={styles.palette__input}\n value={query}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n autoComplete=\"off\"\n aria-autocomplete=\"list\"\n aria-expanded\n aria-controls={listboxId}\n aria-activedescendant={\n visible[activeIndex] ? `${baseId}-option-${activeIndex}` : undefined\n }\n onChange={event => {\n setQuery(event.target.value);\n /* Yazmak etkin komutu BASA ceker: eski satir suzulmus listede\n kalmiyordu. */\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n </div>\n\n <ul id={listboxId} role=\"listbox\" aria-label={label} className={styles.palette__list}>\n {visible.map((item, index) => {\n /* Grup basligi yalnizca DEGISTIGINDE cizilir: her satirin ustune\n baslik koymak listeyi iki katina cikariyordu. */\n const isNewGroup = item.group !== undefined && item.group !== visible[index - 1]?.group;\n\n return (\n <li key={item.id}>\n {isNewGroup && (\n /* `aria-hidden`: baslik bir SECENEK degil; listbox'in cocugu\n olarak okunsaydi ekran okuyucu sayimi bozuluyordu. */\n <span className={styles.palette__group} aria-hidden>\n {item.group}\n </span>\n )}\n\n <div\n id={`${baseId}-option-${index}`}\n role=\"option\"\n data-index={index}\n aria-selected={index === activeIndex}\n className={cx(\n styles.palette__item,\n index === activeIndex && styles['palette__item--active'],\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => run(item)}\n >\n {item.icon && (\n <span className={styles.palette__icon} aria-hidden>\n {item.icon}\n </span>\n )}\n\n <span className={styles.palette__text}>\n <span className={styles.palette__label}>{item.label}</span>\n {item.description && (\n <span className={styles.palette__description}>{item.description}</span>\n )}\n </span>\n\n {item.shortcut && (\n <kbd className={styles.palette__shortcut} aria-hidden>\n {item.shortcut}\n </kbd>\n )}\n </div>\n </li>\n );\n })}\n\n {visible.length === 0 && <li className={styles.palette__empty}>{emptyMessage}</li>}\n </ul>\n </dialog>\n );\n};\n\nexport default /*#__PURE__*/ memo(\n /*#__PURE__*/ named(CommandPalette, 'CommandPalette'),\n) as typeof CommandPalette;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useState } from 'react';\n\nimport { ExclamationTriangleFill, QuestionCircleFill, TrashFill } from 'react-bootstrap-icons';\n\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport Button from '../Button';\nimport Modal, { type ModalTone } from '../Modal';\n\nexport type ConfirmKind = 'destructive' | 'warning' | 'neutral';\n\n/** Üçü de DOLU sürüm: madalyonun tint zemininde kontur kaybolur. */\nconst KIND_ICON: Record<ConfirmKind, ReactNode> = {\n destructive: <TrashFill aria-hidden />,\n warning: <ExclamationTriangleFill aria-hidden />,\n neutral: <QuestionCircleFill aria-hidden />,\n};\n\nconst KIND_TONE: Record<ConfirmKind, ModalTone> = {\n destructive: 'danger',\n warning: 'warning',\n neutral: 'info',\n};\n\nconst KIND_VARIANT: Record<ConfirmKind, UIVariant> = {\n destructive: UIVariant.DANGER,\n warning: UIVariant.PRIMARY,\n neutral: UIVariant.PRIMARY,\n};\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n /**\n * Onaylandığında çalışır. `Promise` dönerse düğme beklerken yükleme\n * durumuna geçer ve pencere <strong>kapanmaz</strong>.\n *\n * <p>İşlem başarılıysa pencereyi kapatmak çağıranın işi: hata durumunda\n * pencerenin açık kalması gerekiyor ki kullanıcı tekrar deneyebilsin.\n */\n onConfirm: () => void | Promise<void>;\n /** Soru cümlesi. Eylem odaklı yazılır: \"…silinsin mi?\". */\n title: string;\n /** Sonucu açıklar: neyin geri alınamaz olduğu burada yazılır. */\n description?: ReactNode;\n /**\n * Onay düğmesinin etiketi — ZORUNLU, config'ten okunmaz.\n *\n * <p>Eylemi TEKRARLAR: \"Sil\", \"İptal et\". Her pencerede farklı olduğu için\n * uygulama düzeyinde bir varsayılanı olamaz; \"Tamam\" gibi bir varsayılan\n * kullanıcıya neyi onayladığını söylemez ve `window.confirm()`ten kaçmamızın\n * sebeplerinden biri tam olarak buydu.\n */\n confirmLabel: string;\n /** Verilmezse `labels.cancel`. */\n cancelLabel?: string;\n /** Verilmezse `labels.close`. */\n closeLabel?: string;\n /**\n * Onayın türü — ikon, ton ve onay düğmesinin varyantını birlikte belirler.\n *\n * <p>Ad `kind`ten `variant`a taşındı: aynı işi yapan üçüncü bir ad\n * kütüphanede zaten `variant` olarak duruyordu (`Button`, `Badge`) ve\n * tüketici her bileşende hangisinin geçerli olduğunu hatırlamak zorunda\n * kalıyordu. Nöbetçi: `src/__tests__/api-consistency.test.ts`.\n */\n variant?: ConfirmKind;\n /** @deprecated `variant` kullanın. Bir sonraki büyük sürümde kalkacak. */\n kind?: ConfirmKind;\n /** Ek bağlam: silinecek kaydın özeti, uyarı kutusu. */\n children?: ReactNode;\n};\n\n/**\n * Onay penceresi.\n *\n * <h3>Neden `window.confirm()` yerine bu</h3>\n * Yerel `confirm()`in dört sorunu var:\n * <ul>\n * <li>Görünümü işletim sisteminin — sitenin diliyle hiç ilgisi yok, üstünde\n * tarayıcının alan adı yazıyor.</li>\n * <li><strong>Ana iş parçacığını kilitler.</strong></li>\n * <li>Yıkıcı eylemi vurgulayamaz: \"Tamam\" ile \"İptal\" aynı ağırlıkta ve\n * hangisinin sildiğini yalnızca metinden anlıyorsun.</li>\n * <li>İstek sürerken geri bildirim veremez; kullanıcı silme düğmesine ikinci\n * kez basıyordu.</li>\n * </ul>\n *\n * <h3>Yükleme durumu pencerede kalır</h3>\n * Onaya basıldığında pencere hemen kapanmaz: düğme yükleniyor durumuna geçer\n * ve pencere kapanmaz hâle gelir (`isDismissable={false}`). İstek bittiğinde\n * kapatma kararı çağırana ait — hata varsa pencere açık kalmalı ki kullanıcı\n * tekrar deneyebilsin.\n *\n * @example\n * const [target, setTarget] = useState<Address | null>(null);\n *\n * <ConfirmDialog\n * isOpen={target !== null}\n * onClose={() => setTarget(null)}\n * kind=\"destructive\"\n * title=\"Adres silinsin mi?\"\n * description=\"Bu işlem geri alınamaz.\"\n * confirmLabel=\"Sil\"\n * cancelLabel=\"Vazgeç\"\n * closeLabel=\"Kapat\"\n * onConfirm={async () => {\n * await remove(target!.id);\n * setTarget(null);\n * }}\n * />\n */\nconst ConfirmDialog: FC<Props> = ({\n isOpen,\n onClose,\n onConfirm,\n title,\n description,\n confirmLabel,\n cancelLabel,\n closeLabel,\n variant,\n kind,\n children,\n}) => {\n const { labels } = useHanui();\n const [isRunning, setIsRunning] = useState(false);\n\n /* Eski prop bir surum boyunca calisir; `variant` verilmisse o kazanir. */\n const resolvedVariant: ConfirmKind = variant ?? kind ?? 'neutral';\n\n const handleConfirm = async () => {\n setIsRunning(true);\n try {\n await onConfirm();\n } finally {\n /*\n * `finally`: istek hata verse de yukleme durumu birakilir. Aksi halde\n * dugme sonsuza kadar donuyor ve kullanici tekrar deneyemiyordu.\n * Pencereyi KAPATMAK cagirana ait — hata varsa acik kalmali.\n */\n setIsRunning(false);\n }\n };\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n closeLabel={closeLabel ?? labels?.close}\n description={description}\n icon={KIND_ICON[resolvedVariant]}\n tone={KIND_TONE[resolvedVariant]}\n size=\"sm\"\n // Islem surerken kapanmaz: kapanma, islem iptal edilmis gibi gorunuyordu.\n isDismissable={!isRunning}\n footer={\n <>\n {/*\n \"Vazgec\" JSX'te ONCE: klavyeyle sekme sirasi soldan saga mantikli\n olmali. Ekranda mobilde `column-reverse` ile alta duser.\n */}\n <Button\n variant={UIVariant.SECONDARY}\n size={UISize.MEDIUM}\n onClick={onClose}\n disabled={isRunning}\n >\n {resolveLabel('ConfirmDialog.cancelLabel', cancelLabel, labels?.cancel)}\n </Button>\n <Button\n variant={KIND_VARIANT[resolvedVariant]}\n size={UISize.MEDIUM}\n onClick={handleConfirm}\n isLoading={isRunning}\n >\n {confirmLabel}\n </Button>\n </>\n }\n >\n {children}\n </Modal>\n );\n};\n\nexport default /*#__PURE__*/ memo(ConfirmDialog) as typeof ConfirmDialog;\n","'use client';\n\nimport {\n memo,\n type MouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { XLg } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport {\n captureFocus,\n focusFirstMeaningful,\n isTopModal,\n preventAutoKeyboard,\n pushModal,\n} from '../../helpers/focus.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport useScrollLock from '../../hooks/useScrollLock';\nimport { useHanui } from '../../theme/context';\nimport IconButton from '../IconButton';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n /** Kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n children: ReactNode;\n /**\n * Panelin hangi kenardan geldiği. Mantıksal: `end` RTL'de sola açılır.\n *\n * <p>Varsayılan `end` — filtre ve ayrıntı panelleri okuma yönünün SONUNDAN\n * gelir; `start` gezinme panelleri içindir.\n */\n side?: 'start' | 'end';\n size?: 'sm' | 'md' | 'lg';\n /** Dipte duran eylem şeridi; gövde kaydırılırken yerinde kalır. */\n footer?: ReactNode;\n /** Başlığın altında duran, gövdeyle birlikte kaymayan şerit. */\n toolbar?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Çekmece (drawer) — kenardan açılan kipsel panel.\n *\n * <h3>{@link BottomSheet} ile farkı: EKRAN, tercih değil</h3>\n * İkisi de kipsel bir yan panel; ayrım hangi ekranda doğru olduklarında:\n *\n * <ul>\n * <li>`BottomSheet` DAR ekran içindir. Baş parmağın erişebildiği yer\n * ekranın dibi; kenardan gelen bir panel telefonda ekranın tamamını\n * kaplıyor ve \"panel\" olmaktan çıkıyor.</li>\n * <li><b>`Drawer` GENİŞ ekran içindir.</b> Filtre paneli ve ayrıntı\n * incelemesi sayfanın yanında durur; kullanıcı listeyi görmeye devam\n * eder. Aynı panel dipten gelseydi 1440 px'lik bir ekranda içeriğin\n * tamamını örtüyordu.</li>\n * </ul>\n *\n * <h3>`isOpen` alır — ve bu {@link BottomSheet}ten bilinçli bir AYRILIK</h3>\n * `BottomSheet` \"açıkken çizilir, kapatmak için kaldırılır\" sözleşmesini\n * kullanıyor ve bunun bir bedeli var: React sökülen bir ağacı bekletmediği\n * için <strong>çıkış animasyonu çizilemiyor</strong>, panel bir karede yok\n * oluyor. Çekmece açık/kapalı durumu kendisi taşıyor; `<dialog>` kapanırken\n * `@starting-style` + `allow-discrete` ile geri kayıyor.\n *\n * <h3>Klavye</h3>\n * <table>\n * <tr><td>`Escape`</td><td>kapatır — üst üste açık panellerde YALNIZCA en üstteki</td></tr>\n * <tr><td>`Tab`</td><td>odak panelin içinde döner (tarayıcı: `showModal()`)</td></tr>\n * </table>\n * Açılışta odak kapatma düğmesine DEĞİL ilk anlamlı öğeye gider.\n */\nconst Drawer = ({\n isOpen,\n onClose,\n title,\n closeLabel,\n children,\n side = 'end',\n size = 'md',\n footer,\n toolbar,\n className,\n testId,\n}: Props) => {\n const { labels } = useHanui();\n const dialogRef = useRef<HTMLDialogElement>(null);\n /* Yigindaki yerimiz: Escape yalnizca EN USTTEKI panelde islenir. */\n const tokenRef = useRef<symbol | null>(null);\n const titleId = useId();\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (!isOpen) {\n if (dialog.open) dialog.close();\n return;\n }\n\n const restoreFocus = captureFocus();\n if (!dialog.open) dialog.showModal();\n\n focusFirstMeaningful(dialog, `.${styles.drawer__close}`);\n preventAutoKeyboard(dialog);\n\n const { token, pop } = pushModal();\n tokenRef.current = token;\n\n return () => {\n pop();\n tokenRef.current = null;\n restoreFocus();\n };\n }, [isOpen]);\n\n useScrollLock(isOpen);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const handleCancel = (event: Event) => {\n event.preventDefault();\n if (tokenRef.current && !isTopModal(tokenRef.current)) return;\n onClose();\n };\n\n dialog.addEventListener('cancel', handleCancel);\n return () => dialog.removeEventListener('cancel', handleCancel);\n }, [onClose]);\n\n const handleBackdropClick = useCallback(\n (event: MouseEvent<HTMLDialogElement>) => {\n // Hedef dialog'un KENDISI ise perdeye tiklanmistir; panel degil.\n if (event.target === dialogRef.current) onClose();\n },\n [onClose],\n );\n\n return (\n <dialog\n ref={dialogRef}\n className={cx(styles.drawer, styles[`drawer--${side}`], styles[`drawer--${size}`], className)}\n aria-labelledby={titleId}\n data-testid={testId}\n onClick={handleBackdropClick}\n >\n <header className={styles.drawer__header}>\n <h2 id={titleId} className={styles.drawer__title}>\n {title}\n </h2>\n\n <IconButton\n icon={<XLg aria-hidden />}\n label={resolveLabel('Drawer.closeLabel', closeLabel, labels?.close)}\n variant=\"ghost\"\n size=\"sm\"\n className={styles.drawer__close}\n onClick={onClose}\n />\n </header>\n\n {toolbar && <div className={styles.drawer__toolbar}>{toolbar}</div>}\n\n <div className={styles.drawer__body}>{children}</div>\n\n {footer && <div className={styles.drawer__footer}>{footer}</div>}\n </dialog>\n );\n};\n\nexport default /*#__PURE__*/ memo(/*#__PURE__*/ named(Drawer, 'Drawer')) as typeof Drawer;\n","'use client';\n\nimport { type FC, memo, type ReactNode, useEffect, useId, useRef, useState } from 'react';\n\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport Button from '../Button';\nimport Field, { type FieldChildProps } from '../Field';\nimport Input from '../Input';\nimport Modal from '../Modal';\nimport Textarea from '../Textarea';\n\nimport styles from './index.module.scss';\n\ntype BaseProps = {\n isOpen: boolean;\n /** Vazgeçme ve perde/Escape kapanışı. Başarı kapanışını bileşen kendisi yapar. */\n onClose: () => void;\n /**\n * Girilen değerle çalışır (değer kırpılmış gönderilir). Reddederse pencere\n * AÇIK kalır ve metin korunur; hata bildirimi çağıranın işi — bildirimi\n * gösterip hatayı yeniden fırlatın ya da hiç yakalamayın.\n */\n onSubmit: (value: string) => void | Promise<void>;\n title: string;\n /** Girdi alanının etiketi. */\n label: string;\n /** Verilmezse `labels.submit`. */\n submitLabel?: string;\n /** Verilmezse `labels.cancel`. */\n cancelLabel?: string;\n /** Kapatma düğmesinin erişilebilir adı. Verilmezse `labels.close`. */\n closeLabel?: string;\n /** Başlığın altındaki bir cümlelik bağlam. */\n description?: ReactNode;\n hint?: string;\n placeholder?: string;\n defaultValue?: string;\n /**\n * `text` tek satır, `multiline` gerekçe gibi uzun metin, `number` adet/fark\n * gibi sayılar. Değer her durumda dize döner; ayrıştırmak çağıranın işi\n * (bir stok farkı `-5` gibi işaretli olabiliyor).\n */\n inputMode?: 'text' | 'multiline' | 'number';\n maxLength?: number;\n rows?: number;\n};\n\ntype Props = BaseProps & {\n /** Boş (yalnızca boşluk dahil) değer gönderilemez. */\n isRequired?: boolean;\n /**\n * Zorunluluk yıldızının ekran okuyucu karşılığı (\"(zorunlu)\").\n *\n * <p>Yıldız yalnızca GÖRSEL bir kısayol; renk ve şekil tek başına anlam\n * taşıyamaz (WCAG 1.4.1), o yüzden yanında okunabilir bir metin olmak\n * zorunda. Verilmezse `labels.required` okunur.\n */\n requiredLabel?: string;\n};\n\n/**\n * Metin isteyen pencere — `window.prompt()` yerine.\n *\n * <h3>Neden</h3>\n * Tarayıcı istemi tek satırlık, biçimlenemiyor, ana iş parçacığını\n * kilitliyor ve bazı tarayıcılarda sayfayı engelliyor. Bu bileşen aynı işi\n * `Modal` + `Field` + girdi ile yapar ve pencere kapanma kuralını\n * (aşağıda) getirir.\n *\n * <h3>Pencere yalnızca BAŞARIDA kapanır</h3>\n * `onSubmit` reddederse pencere açık kalır ve yazılan metin korunur — istek\n * patlarsa kullanıcının yazdığı gerekçe geri dönüşsüz silinmemeli. Değer\n * yalnızca pencere <em>yeniden açılırken</em> `defaultValue`dan tazelenir.\n *\n * <h3>Enter gönderir</h3>\n * Girdi bir `<form>` içinde; dip düğmesi `form` özniteliğiyle ona bağlanır\n * (`Modal` dip şeridi formun dışında çizer). `multiline` kipinde Enter satır\n * başı yapar, gönderme düğmeden.\n */\nconst PromptDialog: FC<Props> = ({\n isOpen,\n onClose,\n onSubmit,\n title,\n label,\n submitLabel,\n cancelLabel,\n closeLabel,\n description,\n hint,\n placeholder,\n defaultValue = '',\n isRequired,\n requiredLabel,\n inputMode = 'text',\n maxLength,\n rows = 4,\n}) => {\n const { labels } = useHanui();\n const formId = useId();\n const [value, setValue] = useState(defaultValue);\n const [isBusy, setIsBusy] = useState(false);\n\n /*\n * Deger yalnizca ACILIS kenarinda tazelenir. `isOpen`'a bagli duz bir etki,\n * pencere acikken gelen her ust render'da yazilani ezebilirdi; hatada acik\n * kalan penceredeki metin de korunmali.\n */\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (isOpen && !wasOpenRef.current) setValue(defaultValue);\n wasOpenRef.current = isOpen;\n }, [isOpen, defaultValue]);\n\n const trimmed = value.trim();\n const isSubmitDisabled = Boolean(isRequired) && trimmed === '';\n\n /** Girdi, `Field`in urettigi erisilebilirlik baglariyla cizilir. */\n const renderControl = (props: FieldChildProps) =>\n inputMode === 'multiline' ? (\n <Textarea\n {...props}\n value={value}\n onChange={event => setValue(event.target.value)}\n placeholder={placeholder}\n maxLength={maxLength}\n rows={rows}\n />\n ) : (\n <Input\n {...props}\n type={inputMode === 'number' ? 'number' : 'text'}\n value={value}\n onChange={event => setValue(event.target.value)}\n placeholder={placeholder}\n maxLength={maxLength}\n />\n );\n\n const handleSubmit = async () => {\n if (isSubmitDisabled || isBusy) return;\n\n setIsBusy(true);\n try {\n await onSubmit(trimmed);\n // Yalnizca basarida: hata durumunda pencere acik, metin yerinde kalir.\n onClose();\n } catch {\n // Bildirim cagiranin isi; burada yalnizca pencere acik tutulur.\n } finally {\n setIsBusy(false);\n }\n };\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n closeLabel={closeLabel ?? labels?.close}\n description={description}\n size=\"sm\"\n // Istek surerken kapanmaz: kapanis \"islem iptal oldu\" gibi gorunuyordu.\n isDismissable={!isBusy}\n footer={\n <>\n <Button\n variant={UIVariant.SECONDARY}\n size={UISize.MEDIUM}\n onClick={onClose}\n disabled={isBusy}\n >\n {resolveLabel('PromptDialog.cancelLabel', cancelLabel, labels?.cancel)}\n </Button>\n <Button\n type=\"submit\"\n form={formId}\n variant={UIVariant.PRIMARY}\n size={UISize.MEDIUM}\n disabled={isSubmitDisabled}\n isLoading={isBusy}\n >\n {resolveLabel('PromptDialog.submitLabel', submitLabel, labels?.submit)}\n </Button>\n </>\n }\n >\n <form\n id={formId}\n className={styles.form}\n onSubmit={event => {\n event.preventDefault();\n handleSubmit();\n }}\n >\n <Field label={label} hint={hint} isRequired={isRequired} requiredLabel={requiredLabel}>\n {renderControl}\n </Field>\n </form>\n </Modal>\n );\n};\n\nexport default /*#__PURE__*/ memo(PromptDialog) as typeof PromptDialog;\n","import { type FC, type HTMLAttributes, memo, type TableHTMLAttributes } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\n\nimport styles from './index.module.scss';\n\ntype ScrollerProps = HTMLAttributes<HTMLDivElement> & {\n /**\n * Çerçeve (hairline + yarıçap + yüzey). Gömülü tablolarda kapatılır: orada\n * tablo zaten bir kartın içinde ve ikinci bir çerçeve kutu içinde kutu\n * görünüyordu.\n */\n hasFrame?: boolean;\n};\n\n/**\n * Tablo kaydırma kutusu — \"tablo kendi kutusunda kayar, sayfa asla yatay\n * kaymaz\" kuralının tek uygulaması.\n *\n * <p>Yatay kaydırma yalnızca BİLEREK kurulur: geniş tablo bu kutunun içinde\n * kayar; `min-width: 0` + `align-self: stretch` kutunun esnek bir kapsayıcıda\n * kendisinin taşmasını engeller. Üç tablonun üç ayrı elle kurulmuş (ya da hiç\n * kurulmamış) kaydırma stratejisi vardı; stratejisi olmayan tabloda monospace\n * değerler 360 px'te sayfanın kendisini yatay kaydırıyordu.\n *\n * <p>Kaydırma çubuğu TEMALI (`custom-scrollbar`): işletim sisteminin açık\n * çubuğu koyu temada tablonun altında parlak bir şerit bırakıyordu.\n */\nexport const TableScroller: FC<ScrollerProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ hasFrame = true, className, children, ...rest }) => (\n <div\n className={cx(styles.scroller, hasFrame && styles['scroller--frame'], className)}\n {...rest}\n >\n {children}\n </div>\n )),\n 'TableScroller',\n);\n\ntype Props = TableHTMLAttributes<HTMLTableElement> &\n Partial<{\n /**\n * Hücre dolgusu. Tablolar aynı iskeleti paylaşır ama yoğunlukları içeriğe\n * göre değişir: yüzlerce satırlık bir liste sıkı, karşılaştırma matrisi\n * ferah durur.\n */\n density: 'compact' | 'regular' | 'spacious';\n /**\n * Başlık satırı `$surface-2` zeminle kutunun içinde YAPIŞKAN kalır.\n * Zemin zorunlu: saydam başlığın arkasından kayan satırlar geçiyordu.\n * `top: 0` doğru olan — referans üst bant değil, tablonun kendi kaydırma\n * kutusu.\n */\n hasStickyHead: boolean;\n /** Satır hover zemini: çok sütunlu tabloda göz satırını kaybediyor. */\n hasRowHover: boolean;\n }>;\n\n/**\n * Temel tablo — hairline satır ayrımı, `$surface-2` başlık, yoğunluk ölçeği.\n *\n * <p>Görsel kararlar (hangi hücre monospace, hangi sütun sabit) çağıranın\n * modülünde kalır; teknik değer hücresi `@include technical-text` ile\n * yazılır. Bileşen yalnızca üç tabloda üçe ayrışmış iskelet kurallarını tek\n * yerde toplar.\n *\n * <p>Operasyon ekranlarının durum satırlı (yükleniyor/hata/boş) sürümü için\n * {@link DataTable}.\n */\nconst Table: FC<Props> = ({\n density = 'regular',\n hasStickyHead,\n hasRowHover,\n className,\n children,\n ...rest\n}) => (\n <table\n className={cx(\n styles.table,\n styles[`table--${density}`],\n hasStickyHead && styles['table--sticky-head'],\n hasRowHover && styles['table--row-hover'],\n className,\n )}\n {...rest}\n >\n {children}\n </table>\n);\n\nexport default /*#__PURE__*/ memo(Table) as typeof Table;\n","import { Children, type FC, type HTMLAttributes, memo, type ReactNode } from 'react';\n\nimport { ExclamationCircleFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\nexport type DataTableColumn = {\n /** Sütun kimliği (React key). */\n key: string;\n /** Başlık hücresinin içeriği. Toplu seçim kutusu gibi öğeler de girebilir. */\n label?: ReactNode;\n /**\n * Görsel başlığı olmayan sütunun erişilebilir adı (eylem sütunu gibi).\n * Boş bir `<th>` ekran okuyucuda adsız bir sütun bırakıyordu.\n *\n * <p>Metin `aria-label` OLARAK DEĞİL, görsel olarak gizlenmiş gerçek bir\n * metin düğümü olarak yazılır — gerekçe {@link DataTable} JSDoc'unda.\n */\n srLabel?: string;\n /**\n * Sıralanabilir sütunun yönü (`aria-sort`).\n *\n * <p>`onSort` ile birlikte verildiğinde başlık TIKLANABİLİR olur ve yön\n * oku çizilir. Tek başına verildiğinde yalnızca durumu bildirir —\n * sıralamayı başka bir denetim (bir `Select`) yapıyorsa doğrusu budur.\n */\n ariaSort?: 'ascending' | 'descending';\n /**\n * Sütun sıralanabilir. `DataTable.onSort` ile birlikte anlamlı; ikisinden\n * biri eksikse başlık düz metin kalır — tıklanabilir görünüp hiçbir şey\n * yapmayan bir başlık, kullanıcıya var olmayan bir yetenek vaat ediyordu.\n */\n isSortable?: boolean;\n /**\n * Sütun yatay kaydırmada YERİNDE kalır.\n *\n * <p>Yalnızca İLK sütunda anlamlı: geniş bir tabloda sağa kaydıran\n * kullanıcı hangi satıra baktığını kaybediyordu. İkinci bir yapışkan sütun\n * `left` ofsetinin elle hesaplanmasını gerektirir ve o hesap sütun\n * genişliğine bağlı — desteklenmiyor.\n */\n isSticky?: boolean;\n className?: string;\n};\n\ntype Props = {\n columns: DataTableColumn[];\n /**\n * Gövde satırları (`<tr>`). Ekranların özel hücreleri, bağlantıları ve satır\n * tintleri burada yaşar; tablo yalnızca kabuğu ve durum satırlarını\n * üstlenir. Uyarı tinti için {@link DataTableRow}.\n */\n children?: ReactNode;\n /** Satır yokken gösterilen metin. Verilmezse `labels.dataTable.empty`. */\n emptyMessage?: string;\n /** Yükleme sürerken gösterilen metin. Verilmezse `labels.dataTable.loading`. */\n loadingMessage?: string;\n isLoading?: boolean;\n /**\n * Liste ÇEKİLEMEDİ. <strong>\"Yüklenemedi\" ile \"boş\" ayrı durumlardır</strong>:\n * hata verilmişken boş mesajı asla çizilmez — ağ hatasını \"kayıt kalmamış\"\n * diye okutmak kullanıcıya yanlış karar verdirir. Hatayı tablonun dışında\n * (`Alert`) gösteren ekran bu prop'u geçmez.\n */\n error?: string | null;\n /**\n * Gövde `100dvh - <bant>` ile sınırlanır ve başlık satırı kendi kaydırma\n * alanına yapışır. Sınırsız yükseklikte `position: sticky` HİÇ çalışmıyordu:\n * `overflow` alanı ekrandan uzun olunca başlık sayfayla birlikte yukarı çıkıp\n * gidiyordu.\n */\n hasViewportCap?: boolean;\n /**\n * Sıralanabilir bir başlığa basıldığında çağrılır.\n *\n * <p>Sıralamanın KENDİSİ burada yapılmaz: veri çağıranın ve sıralama\n * neredeyse her zaman sunucuda (sayfalanmış bir listede istemcide sıralamak\n * yalnızca görünen sayfayı sıralar — kullanıcı \"en ucuz\" dediğinde en ucuz\n * 24 ürünü değil, o sayfadaki en ucuzu görüyordu).\n */\n onSort?: (key: string, direction: 'ascending' | 'descending') => void;\n /**\n * Satır seçildiğinde beliren TOPLU EYLEM şeridi.\n *\n * <p>Tablonun ÜSTÜNDE ve yapışkan: kullanıcı yüzlerce satır arasında\n * seçim yapıp aşağı kaydırdığında eylem şeridi ekranın dışında kalıyor ve\n * seçimin ne işe yaradığı görünmüyordu.\n */\n bulkBar?: ReactNode;\n className?: string;\n testId?: string;\n};\n\n/**\n * Operasyon veri tablosu — durum satırlı tablo sözleşmesi.\n *\n * <h3>Neden bir bileşen</h3>\n * On iki ekranda on bir ham tablo ve altı kaydırma sarmalayıcısı kopyası\n * vardı; üçü farklı davranıyordu (kimi dikey kaymıyor, kiminin başlığı\n * yapışmıyor). Kabuk (yüzey + hairline + `overflow: auto`), tablo görünümü ve\n * üç durum satırı (yükleniyor / hata / boş) artık tek yerde; `colSpan` sütun\n * sayısından kendiliğinden hesaplanır — elle yazılan `colSpan={8}` bir sütun\n * eklenince sessizce yanlış kalıyordu.\n *\n * <h3>Durum öncelik sırası</h3>\n * `error` &gt; `isLoading` &gt; boş &gt; satırlar. Hata varken yükleme veya boş\n * mesajı gösterilmez; yüklenirken bayat satır çizilmez.\n *\n * <h3>Görünmez başlık `aria-label` DEĞİL, gizlenmiş METİN</h3>\n * Eylem sütununun adı önce `<th aria-label=\"Eylemler\">` olarak yazılıyordu.\n * Eksen taraması bunu ihlal olarak bildirdi (`empty-table-header`) ve haklı:\n * `aria-label`ın hücre başlığı olarak kullanılması destek teknolojilerinde\n * tutarsız — bazı ekran okuyucular tablo gezinme kipinde sütun adını\n * hücrenin İÇERİĞİNDEN okur ve boş bir `<th>` orada adsız kalır. Görsel olarak\n * gizlenmiş gerçek bir metin düğümü hem okunur hem de sayfa çevirisine,\n * bulma-değiştirmeye ve seçime dahil olur.\n */\nconst DataTable: FC<Props> = ({\n columns,\n children,\n isLoading,\n error,\n emptyMessage,\n loadingMessage,\n hasViewportCap,\n onSort,\n bulkBar,\n className,\n testId,\n}) => {\n /*\n * Bosluk karari satir SAYISINDAN verilir; cagiranin ayrica `isEmpty` gecmesi\n * gerekmez. Satirlar tek bir Fragment icinde verilirse sayi 1 gorunur —\n * satirlari dogrudan (ya da dizi olarak) verin.\n */\n const { labels } = useHanui();\n const rowCount = Children.count(children);\n\n const renderStateRow = (content: ReactNode, modifier?: 'error') => (\n <tr>\n <td\n colSpan={columns.length}\n className={cx(styles.state, modifier && styles[`state--${modifier}`])}\n >\n {content}\n </td>\n </tr>\n );\n\n return (\n <div\n className={cx(styles.wrapper, hasViewportCap && styles['wrapper--capped'], className)}\n data-testid={testId}\n >\n {bulkBar && <div className={styles.bulkBar}>{bulkBar}</div>}\n\n <table className={styles.table}>\n <thead>\n <tr>\n {columns.map(column => {\n const isSortable = Boolean(column.isSortable && onSort);\n /* Ilk tikta ARTAN; ikinci tik yonu cevirir. Sifirdan azalan\n baslamak, \"en pahali\" listeyi varsayilan yapiyordu. */\n const nextDirection = column.ariaSort === 'ascending' ? 'descending' : 'ascending';\n\n return (\n <th\n key={column.key}\n scope=\"col\"\n aria-sort={column.ariaSort}\n className={cx(column.className, column.isSticky && styles.sticky)}\n >\n {isSortable ? (\n /*\n * Siralama bir DUGME, `<th>`ye yazilan `onClick` degil.\n * Baslik hucresi odaklanabilir degil ve klavye kullanicisi\n * siralamaya HIC ulasamiyordu; ustelik ekran okuyucu\n * tiklanabilir oldugunu da soylemiyordu.\n */\n <button\n type=\"button\"\n className={styles.sort}\n onClick={() => onSort?.(column.key, nextDirection)}\n >\n {column.label}\n {column.srLabel && <span className={styles.srOnly}>{column.srLabel}</span>}\n\n {/*\n Yon oku: `aria-hidden` cunku ayni bilgi `aria-sort`ta.\n Siralanabilir ama siralanmamis sutunda SOLUK bir cift\n ok duruyor — sutunun siralanabildigi ancak uzerine\n gelince anlasiliyordu.\n */}\n <span\n aria-hidden\n className={cx(\n styles.sort__arrow,\n column.ariaSort && styles[`sort__arrow--${column.ariaSort}`],\n )}\n >\n {column.ariaSort === 'descending' ? '▾' : '▴'}\n </span>\n </button>\n ) : (\n <>\n {column.label}\n {column.srLabel && <span className={styles.srOnly}>{column.srLabel}</span>}\n </>\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {error\n ? renderStateRow(\n <span role=\"alert\" className={styles.state__message}>\n <ExclamationCircleFill aria-hidden />\n {error}\n </span>,\n 'error',\n )\n : isLoading\n ? renderStateRow(\n resolveLabel(\n 'DataTable.loadingMessage',\n loadingMessage,\n labels?.dataTable?.loading,\n ),\n )\n : rowCount === 0\n ? renderStateRow(\n resolveLabel('DataTable.emptyMessage', emptyMessage, labels?.dataTable?.empty),\n )\n : children}\n </tbody>\n </table>\n </div>\n );\n};\n\ntype RowProps = HTMLAttributes<HTMLTableRowElement> & {\n children: ReactNode;\n /**\n * Satır dikkat bekleyen iş taşıyor (kritik stok, karar bekleyen talep).\n *\n * <p>TEK desen: tint zemin + ilk hücrede sol kenar işareti. Önceden iki\n * uygulama vardı — yalnız düz uyarı zemini ve zemin + sol iç gölge. Zemin\n * tek başına yetmiyordu: hover vurgusu tinti ezince satırın \"iş bekliyor\"\n * bilgisi kayboluyordu ve renk tek başına zaten anlam taşıyamaz (WCAG\n * 1.4.1) — sol işaret hover'da da yerinde kalır.\n */\n isWarning?: boolean;\n};\n\nexport const DataTableRow: FC<RowProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ isWarning, className, children, ...rest }) => (\n <tr className={cx(isWarning && styles['row--warning'], className)} {...rest}>\n {children}\n </tr>\n )),\n 'DataTableRow',\n);\n\nexport default /*#__PURE__*/ memo(DataTable) as typeof DataTable;\n","import { type FC, memo, type ReactNode } from 'react';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { named } from '../../helpers/component.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport { useHanui } from '../../theme/context';\n\nimport styles from './index.module.scss';\n\ntype Props = {\n /**\n * Filtreler uygulanır. `preventDefault` bileşenin işi; çağıran yalnızca\n * durumunu günceller (sayfayı 1'e almak + aramayı uygulamak gibi).\n */\n onSubmit: () => void;\n /** Alanlar — her biri {@link FilterBarField} içinde. */\n children: ReactNode;\n /** Şeridin sağ ucundaki eylemler (\"Uygula\" düğmesi gibi). */\n actions?: ReactNode;\n /** Şeridin erişilebilir adı. Verilmezse `labels.filters`. */\n label?: string;\n className?: string;\n testId?: string;\n};\n\n/**\n * Filtre şeridi.\n *\n * <h3>Her zaman `<form onSubmit>`</h3>\n * Beş ekran şeridi elle kuruyordu ve yalnızca üçü `<form>` kullanıyordu: arama\n * kutusunda Enter üç ekranda filtreyi uyguluyor, ikisinde hiçbir şey\n * yapmıyordu. Şerit artık her zaman bir formdur ve görünür bir gönderme düğmesi\n * olmasa bile Enter çalışsın diye gizli bir yedek gönderme düğmesi taşır\n * (birden çok alanı olan formda tarayıcının örtük gönderimi ancak bir gönderme\n * düğmesi varsa çalışır).\n *\n * <h3>320px'te taşma yok</h3>\n * Alanlar `min-width: 240–280px` taşıyordu ve en dar ekranda şerit sayfayı yana\n * kaydırıyordu. Genişlik artık `flex-basis` ile istenir, `min-width: 0` ile\n * daraltılabilir kalır: alan tercihen 220px'tir ama sığmadığı yerde küçülür,\n * taşmaz.\n */\nconst FilterBar: FC<Props> = ({ onSubmit, children, actions, label, className, testId }) => {\n const { labels } = useHanui();\n\n return (\n <form\n className={cx(styles.bar, className)}\n aria-label={resolveLabel('FilterBar.label', label, labels?.filters)}\n data-testid={testId}\n onSubmit={event => {\n event.preventDefault();\n onSubmit();\n }}\n >\n {children}\n\n {/*\n Enter'ın yedeği. Görünmez ama tarayıcı için formun varsayılan gönderme\n düğmesi: `display: none` örtük gönderimi bozmaz. Görünür \"Uygula\" düğmesi\n `actions` ile ayrıca verilebilir; ikisi aynı submit olayına düşer.\n */}\n <button type=\"submit\" className={styles.bar__hiddenSubmit} tabIndex={-1} aria-hidden />\n\n {actions && <div className={styles.bar__actions}>{actions}</div>}\n </form>\n );\n};\n\ntype FieldProps = {\n children: ReactNode;\n /**\n * Alan kalan genişliği doldurur (arama kutusu). Diğer alanlar tercih\n * ettikleri genişlikte kalır ve şerit sağa doğru boşluk bırakır.\n */\n isWide?: boolean;\n className?: string;\n};\n\n/**\n * Şerit içindeki tek alanın genişlik sözleşmesi. İçine `Field` + girdi ya da\n * yalın `Input` konur; genişlik kararı alanın kendisine yazılmaz.\n */\nexport const FilterBarField: FC<FieldProps> = /*#__PURE__*/ named(\n /*#__PURE__*/ memo(({ children, isWide, className }) => (\n <div className={cx(styles.field, isWide && styles['field--wide'], className)}>{children}</div>\n )),\n 'FilterBarField',\n);\n\nexport default /*#__PURE__*/ memo(FilterBar) as typeof FilterBar;\n","'use client';\n\nimport { type FC, memo, useEffect, useMemo, useRef } from 'react';\n\nimport { CaretLeftFill, CaretRightFill } from 'react-bootstrap-icons';\n\nimport { cx } from '../../helpers/class-name.helper';\nimport { resolveLabel } from '../../helpers/label.helper';\nimport useAnnounce from '../../hooks/useAnnounce';\nimport { useHanui } from '../../theme/context';\nimport UISize from '../../enums/ui-size.enum';\nimport UIVariant from '../../enums/ui-variant.enum';\nimport type { HanuiLinkExtraProps } from '../../types/link.type';\nimport Button from '../Button';\nimport IconButton from '../IconButton';\nimport HanuiLink from '../Link';\n\nimport styles from './index.module.scss';\n\ntype BaseProps = {\n page: number;\n totalPages: number;\n /** Gezinme bölgesinin erişilebilir adı. Verilmezse `labels.pagination.label`. */\n label?: string;\n /** Verilmezse `labels.pagination.previous`. */\n previousLabel?: string;\n /** Verilmezse `labels.pagination.next`. */\n nextLabel?: string;\n /**\n * Sayfa değiştiğinde ekran okuyucuya duyurulacak metin\n * (\"3. sayfa · 1.248 sonuç\").\n *\n * <p>Verilmediğinde duyuru YAPILMAZ. Görsel tarafta sayfa numarası\n * `aria-current` ile zaten işaretli ama o yalnızca ODAK oraya geldiğinde\n * okunuyor: bağlantıya basıp listenin başına dönen kullanıcı, kaçıncı\n * sayfada olduğunu ve kaç sonuç kaldığını hiç duymuyordu.\n */\n formatAnnouncement?: (page: number, totalPages: number) => string;\n className?: string;\n testId?: string;\n};\n\ntype LinkProps = BaseProps & {\n /**\n * Sayfa numarasının adresini üretir.\n *\n * <p>Verildiğinde numaralar `<a>` olur — ve olması gerekir. Düğmenin `href`i\n * yok: arama motoru bir tıklama olayını çalıştırmaz ve ikinci sayfaya HİÇ\n * geçemez; kullanıcı da orta tuşla yeni sekmede açamaz, adresi kopyalayamaz,\n * durum çubuğunda hedefi göremez.\n */\n buildHref: (page: number) => string;\n onPageChange?: never;\n /** Yönlendiriciye geçirilecek ek props (`{ scroll: false }` gibi). */\n linkProps?: HanuiLinkExtraProps;\n};\n\ntype ButtonProps = BaseProps & {\n /**\n * Sayfa değişimi adres çubuğu YERİNE buraya bildirilir.\n *\n * <p>Yalnızca sayfalamanın adrese yazılmadığı listeler için: kişiye özel,\n * `noindex` ekranlarda kimse \"ikinci sayfa\" bağlantısını paylaşmıyor ve orada\n * adresi kirletmek geri tuşunu kullanılamaz hâle getiriyordu. Bağlantı\n * verilebilecek bir hedef olmadığı için numaralar düğme kalır.\n */\n onPageChange: (page: number) => void;\n buildHref?: never;\n linkProps?: never;\n};\n\ntype Props = LinkProps | ButtonProps;\n\n/** Kenarlarda 1 ve son sayfa her zaman gorunur; arasi kisaltilir. */\nconst buildPageList = (page: number, totalPages: number): (number | 'gap')[] => {\n if (totalPages <= 7) return Array.from({ length: totalPages }, (_, index) => index + 1);\n\n const pages = new Set<number>([1, totalPages, page]);\n if (page - 1 > 1) pages.add(page - 1);\n if (page + 1 < totalPages) pages.add(page + 1);\n\n const sorted = [...pages].sort((left, right) => left - right);\n const result: (number | 'gap')[] = [];\n\n sorted.forEach((value, index) => {\n if (index > 0 && value - sorted[index - 1] > 1) result.push('gap');\n result.push(value);\n });\n\n return result;\n};\n\n/**\n * Sayfalama.\n *\n * <h3>Sayfa numaraları BAĞLANTI, düğme değil</h3>\n * `buildHref` verildiğinde numaralar `<a>` olur. Düğme olarak bırakıldığında\n * iki bedeli vardı:\n * <ul>\n * <li><strong>Tarayıcı (crawler) ikinci sayfaya geçemiyordu.</strong> Düğmenin\n * `href`i yok; arama motoru bir tıklama olayını çalıştırmaz. Derin\n * sayfalardaki kayıtlar yalnızca sitemap'te göründükleri kadar\n * keşfedilebiliyordu.</li>\n * <li><strong>Kullanıcı yeni sekmede açamıyordu.</strong> Orta tık, Cmd+tık ve\n * \"bağlantıyı kopyala\" çalışmıyor, durum çubuğunda hedef görünmüyordu.</li>\n * </ul>\n *\n * <p>Oklar her iki kipte de `IconButton`: devre dışı kalabildikleri için düğme\n * kalırlar — `<a>` etiketinin \"devre dışı\" hâli yok, `aria-disabled` ise\n * tıklamayı engellemez. Sayfa numaraları tarayıcıya zaten tam listeyi veriyor.\n */\nconst Pagination: FC<Props> = ({\n page,\n totalPages,\n label,\n previousLabel,\n nextLabel,\n buildHref,\n onPageChange,\n linkProps,\n formatAnnouncement,\n className,\n testId,\n}) => {\n const { labels } = useHanui();\n const announce = useAnnounce();\n\n /*\n * Sayfa DEGISTIGINDE duyurulur, ilk cizimde degil: acilista \"1. sayfa\"\n * demek, kullanicinin sormadigi bir soruyu cevaplamak ve ekran okuyucunun\n * sayfa basligini okumasini kesmek olurdu.\n */\n const previousPage = useRef(page);\n\n useEffect(() => {\n if (previousPage.current === page) return;\n previousPage.current = page;\n\n if (formatAnnouncement) announce(formatAnnouncement(page, totalPages));\n }, [page, totalPages, formatAnnouncement, announce]);\n const pages = useMemo(() => buildPageList(page, totalPages), [page, totalPages]);\n\n if (totalPages <= 1) return null;\n\n const goTo = (target: number) => {\n if (onPageChange) onPageChange(target);\n };\n\n return (\n <nav\n className={cx(styles.pagination, className)}\n aria-label={resolveLabel('Pagination.label', label, labels?.pagination?.label)}\n data-testid={testId}\n >\n <IconButton\n className={styles.pagination__arrow}\n icon={<CaretLeftFill aria-hidden />}\n label={resolveLabel(\n 'Pagination.previousLabel',\n previousLabel,\n labels?.pagination?.previous,\n )}\n variant=\"outline\"\n disabled={page <= 1}\n onClick={() => goTo(page - 1)}\n />\n\n <ul className={styles.pagination__list}>\n {pages.map((value, index) =>\n value === 'gap' ? (\n <li key={`gap-${index}`} className={styles.pagination__gap} aria-hidden>\n …\n </li>\n ) : (\n <li key={value}>\n {buildHref ? (\n <HanuiLink\n href={buildHref(value)}\n className={cx(\n styles.pagination__page,\n value === page && styles['pagination__page--active'],\n )}\n aria-current={value === page ? 'page' : undefined}\n {...linkProps}\n >\n {value}\n </HanuiLink>\n ) : (\n <Button\n variant={UIVariant.SECONDARY}\n size={UISize.SMALL}\n className={cx(\n styles.pagination__page,\n value === page && styles['pagination__page--active'],\n )}\n aria-current={value === page ? 'page' : undefined}\n onClick={() => goTo(value)}\n >\n {value}\n </Button>\n )}\n </li>\n ),\n )}\n </ul>\n\n <IconButton\n className={styles.pagination__arrow}\n icon={<CaretRightFill aria-hidden />}\n label={resolveLabel('Pagination.nextLabel', nextLabel, labels?.pagination?.next)}\n variant=\"outline\"\n disabled={page >= totalPages}\n onClick={() => goTo(page + 1)}\n />\n </nav>\n );\n};\n\nexport default /*#__PURE__*/ memo(Pagination) as typeof Pagination;\n"],"names":["NEUTRAL","GRAPHITE","AMBER","BLUE","STATUS","DANGER_SOLID","ACCENT","SALE","STAR","alpha","hex","value","normalized","full","character","red","green","blue","BLACK","LIGHT_THEME","DARK_THEME","METRIC_TOKENS","COMPACT_DENSITY","DEFAULT_FONTS","TOKEN_PREFIX","THEME_STYLE_ID","THEME_ATTRIBUTE","DENSITY_ATTRIBUTE","THEME_SWITCHING_CLASS","resolveTokens","scheme","config","base","overrides","buildThemeCss","blocks","declarations","tokens","indent","name","fonts","fontEntries","role","stack","metrics","body","applyThemeConfig","isClient","css","existing","element","HanuiContext","createContext","useHanui","useContext","HanuiProvider","children","theme","linkComponent","labels","themeKey","useMemo","useEffect","themeRef","useRef","jsx","initHanui","options","REGION_ID","getRegion","politeness","id","region","write","message","useAnnounce","useCallback","trimmed","readSystemScheme","_a","readPreference","attribute","useHanuiTheme","preference","setPreferenceState","useState","systemScheme","setSystemScheme","isReady","setIsReady","query","handleChange","setScheme","next","root","toggle","scrollIntoViewIfPossible","useListboxNavigation","count","isOpen","initialIndex","onSelect","onClose","hasSpaceSelect","activeIndex","setActiveIndex","listRef","current","handleKeyDown","event","lastIndex","OPPOSITE","clamp","min","max","place","anchor","surface","side","align","offset","isVertical","main","crossStart","crossSize","surfaceSize","cross","fits","position","padding","viewport","usePositioning","anchorRef","surfaceRef","state","setState","frameRef","measure","anchorRect","surfaceRect","preferred","resolvedSide","placed","schedule","useLayoutEffect","observer","useVirtualList","rowHeight","overscan","isEnabled","scrollRef","range","setRange","node","visibleCount","first","start","end","scrollToIndex","index","top","bottom","lockCount","previous","isIOS","lock","rootStyle","scrollY","scrollbarWidth","unlock","useScrollLock","isLocked","HEIGHT_VAR","INSET_VAR","openCount","frame","MIN_VIEWPORT_HEIGHT","covered","cancelScheduled","useSheetViewport","isActive","UIVariant","UISize","MOBILE_BREAKPOINT","TABLET_PORTRAIT_BREAKPOINT","TABLET_BREAKPOINT","ABOVE_TABLET_MEDIA_QUERY","ABOVE_MOBILE_MEDIA_QUERY","normalizeSearchTerm","matchesSearch","haystack","needle","NON_TEXT_INPUT_TYPES","isKeyboardOpeningElement","editable","tagName","preventAutoKeyboard","dialog","active","captureFocus","FOCUSABLE_SELECTOR","selector","focusFirstMeaningful","container","skipSelector","explicit","candidates","target","modalStack","pushModal","token","isTopModal","cx","values","result","named","component","displayName","HanuiLink","rest","LinkComponent","warned","resolveLabel","key","resolveFormatter","formatter","args","Spinner","size","label","className","styles","Button","forwardRef","variant","isLoading","isFullWidth","startIcon","endIcon","disabled","href","isExternal","linkProps","testId","ref","classNames","content","jsxs","Fragment","memo","IconButton","icon","type","TextLink","hasArrow","tone","ArrowRight","index$O","CLOSE_DELAY","LONG_PRESS_DELAY","Tooltip","openDelay","setIsOpen","useId","bubbleRef","timerRef","longPressRef","positioning","clearTimer","open","delay","close","handlePointerDown","cancelLongPress","createPortal","index$N","enabledIndexes","items","item","Menu","trigger","restoreRef","typedRef","enabled","_b","step","jumpToLetter","now","buffer","match","handleMenuKeyDown","handleTriggerKeyDown","isValidElement","triggerProps","cloneElement","index$M","Popover","controlledOpen","onOpenChange","uncontrolledOpen","setUncontrolledOpen","isControlled","setOpen","index$L","Chip","isSelected","isDefined","ChipGroup","isScrollable","selection","handleSelect","option","currentIndex","tabbableValue","index$K","BottomSheet","title","closeLabel","toolbar","footer","closeAbove","titleId","tokenRef","restoreFocus","pop","setDialogRef","handleBackdropClick","XLg","VIRTUAL_THRESHOLD","OPTION_HEIGHT","Combobox","onChange","isSearchHidden","onSearch","isDisabled","isClearable","describedBy","isInvalid","text","generatedId","baseId","listboxId","rootRef","triggerRef","panelRef","inputRef","openMode","setOpenMode","setQuery","cachedLabel","setCachedLabel","visibleOptions","selectedOption","displayLabel","searchRef","timer","selectOption","wasOpenRef","hasDescriptions","isVirtual","attachList","handleInputKeyDown","clearSelection","search","Search","renderList","isSheet","slice","sliceIndex","isChosen","CheckLg","CaretDownFill","index$J","SegmentedControl","isIconOnly","index$I","Select","placeholder","emptyText","optionId","selectedIndex","onKeyDown","index$H","Checkbox","hint","index$G","Switch","isLabelFirst","index$F","Radio","index$E","RadioCard","index$D","RangeSlider","onCommit","formatValue","minLabel","maxLabel","lowName","highName","low","high","handleLowChange","raw","handleHighChange","commit","span","lowPercent","normalize","highPercent","isLowOnTop","index$C","STARS","RatingInput","ratingLabels","formatStarCount","scale","hovered","setHovered","shown","star","StarFill","index$B","QuantityStepper","decreaseLabel","increaseLabel","groupLabel","draft","setDraft","parsed","DashLg","_c","PlusLg","index$A","TableCheckbox","index$z","Input","prefix","suffix","isTechnical","TagInput","removeLabel","separators","maxTags","inputId","announce","duplicate","setDuplicate","isFull","remove","index$y","Textarea","rows","isAutoSize","maxRows","hasCounter","maxLength","defaultValue","innerRef","innerLength","setLength","length","setRefs","isNearLimit","DateField","index$x","DateRangeBase","startLabel","endLabel","separator","isSummaryVisible","summary","format","DateRange","Field","error","isRequired","requiredLabel","isLabelHidden","errorId","hintId","ExclamationCircleFill","toPercent","Progress","valueText","isValueVisible","isIndeterminate","percent","ProgressCircleBase","stroke","radius","circumference","ProgressCircle","formatSize","bytes","FileUpload","files","onRemove","accept","isMultiple","maxSize","dropLabel","sizeErrorText","isDragging","setIsDragging","rejected","setRejected","handleFiles","list","incoming","tooLarge","file","accepted","messages","handleDrop","CloudArrowUpFill","index$w","ICONS","InfoCircleFill","CheckCircleFill","ExclamationTriangleFill","XCircleFill","Alert","action","index$v","resolveInitials","locale","words","letters","resolveTone","total","hash","TONE_COUNT","Avatar","imageUrl","index$u","Badge","index$t","Breadcrumb","isLast","CaretRightFill","index$s","Card","isInteractive","Tag","CardMedia","ratio","isContained","CardOverlay","CardBody","CardFooter","index$r","Carousel","previousLabel","nextLabel","formatDotLabel","itemMinWidth","trackRef","canScrollBack","setCanScrollBack","canScrollForward","setCanScrollForward","page","setPage","pageCount","setPageCount","needsTabStop","setNeedsTabStop","track","scrollLeft","scrollWidth","clientWidth","scrollByPage","direction","CaretLeftFill","_","index$q","COPIED_FEEDBACK_MS","CopyField","copyLabel","copiedLabel","copiedAnnouncement","isReadOnly","isCopied","setIsCopied","codeRef","selectValue","handleCopy","_d","ClipboardCheckFill","ClipboardFill","_e","index$p","Divider","index$o","Directory","DirectoryGroup","meta","DirectoryRow","media","marker","DirectoryJump","toId","index$n","EmptyState","description","secondaryAction","index$m","PageHeader","eyebrow","actions","breadcrumb","Heading","index$l","Panel","isFlush","gap","bodyClassName","PanelForm","columns","PanelRow","index$k","Price","currency","listValue","discountPercent","formatDiscount","isFormatted","symbol","numeric","index$j","Rating","srLabel","rounded","StarHalf","index$i","SectionHeader","overline","index$h","ScrollArea","axis","maxHeight","hasFade","setIsScrollable","vertical","horizontal","child","index$g","Skeleton","width","height","lines","style","isNumber","index$f","CardShape","RowShape","TableShape","rowIndex","columnIndex","SkeletonCard","SkeletonRows","SkeletonTable","TREND_ICON","ArrowUpShort","ArrowDownShort","TREND_TEXT","Stat","unit","delta","trend","isUpPositive","isPositive","index$e","DEFAULT_DURATION","counter","listeners","queue","emit","listener","dismiss","push","toast","ToastItem","record","onDismiss","duration","isPaused","setIsPaused","remainingRef","startedRef","ToastHub","toasts","setToasts","handleDismiss","isMounted","setIsMounted","index$d","Accordion","isSingle","defaultOpenIds","controlledIds","uncontrolledIds","setUncontrolledIds","openIds","willOpen","index$c","statusOf","STATUS_TEXT","Steps","steps","onStepClick","orientation","status","isClickable","index$b","Tabs","defaultTabId","controlledId","ariaLabel","isManualActivation","uncontrolledId","setUncontrolledId","activeId","focusIndex","setFocusIndex","select","hasPanel","index$a","Tile","index$9","STATUS_ICON","Timeline","events","index$8","Modal","isDismissable","dialogRef","descriptionId","handleCancel","CommandPalette","searchPlaceholder","emptyMessage","visible","run","isNewGroup","index$7","KIND_ICON","TrashFill","QuestionCircleFill","KIND_TONE","KIND_VARIANT","ConfirmDialog","onConfirm","confirmLabel","cancelLabel","kind","isRunning","setIsRunning","resolvedVariant","handleConfirm","index$6","Drawer","index$5","PromptDialog","onSubmit","submitLabel","inputMode","formId","setValue","isBusy","setIsBusy","isSubmitDisabled","renderControl","props","handleSubmit","index$4","TableScroller","hasFrame","Table","density","hasStickyHead","hasRowHover","index$3","DataTable","loadingMessage","hasViewportCap","onSort","bulkBar","rowCount","Children","renderStateRow","modifier","column","isSortable","nextDirection","DataTableRow","isWarning","index$2","FilterBar","FilterBarField","isWide","index$1","buildPageList","totalPages","pages","sorted","left","right","Pagination","buildHref","onPageChange","formatAnnouncement","previousPage","goTo"],"mappings":"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"}