tamga-ui 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +908 -0
- package/README.md +3 -1
- package/dist/blocks/count-row.d.ts +3 -8
- package/dist/blocks/count-row.d.ts.map +1 -1
- package/dist/blocks/count-row.js +3 -8
- package/dist/blocks/filter-bar.d.ts +42 -28
- package/dist/blocks/filter-bar.d.ts.map +1 -1
- package/dist/blocks/filter-bar.js +13 -5
- package/dist/blocks/index.d.ts +4 -17
- package/dist/blocks/index.d.ts.map +1 -1
- package/dist/blocks/index.js +4 -17
- package/dist/blocks/save-bar.d.ts +4 -12
- package/dist/blocks/save-bar.d.ts.map +1 -1
- package/dist/blocks/save-bar.js +4 -12
- package/dist/components/a11y.d.ts.map +1 -1
- package/dist/components/a11y.js +4 -15
- package/dist/components/advanced-input.d.ts +54 -48
- package/dist/components/advanced-input.d.ts.map +1 -1
- package/dist/components/advanced-input.js +64 -59
- package/dist/components/announcement.d.ts +34 -0
- package/dist/components/announcement.d.ts.map +1 -0
- package/dist/components/announcement.js +12 -0
- package/dist/components/appearance.d.ts +33 -1
- package/dist/components/appearance.d.ts.map +1 -1
- package/dist/components/appearance.js +78 -7
- package/dist/components/avatar.d.ts +28 -21
- package/dist/components/avatar.d.ts.map +1 -1
- package/dist/components/avatar.js +46 -22
- package/dist/components/badge.d.ts +54 -4
- package/dist/components/badge.d.ts.map +1 -1
- package/dist/components/badge.js +42 -9
- package/dist/components/bar.d.ts.map +1 -1
- package/dist/components/bar.js +4 -20
- package/dist/components/button.d.ts +15 -7
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +54 -8
- package/dist/components/chart.d.ts +5 -0
- package/dist/components/chart.d.ts.map +1 -1
- package/dist/components/chart.js +18 -11
- package/dist/components/checkbox.d.ts +23 -1
- package/dist/components/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox.js +3 -4
- package/dist/components/chrome.d.ts +38 -54
- package/dist/components/chrome.d.ts.map +1 -1
- package/dist/components/chrome.js +55 -63
- package/dist/components/combobox.d.ts.map +1 -1
- package/dist/components/combobox.js +19 -3
- package/dist/components/data-table.d.ts +4 -4
- package/dist/components/data-table.d.ts.map +1 -1
- package/dist/components/data-table.js +15 -16
- package/dist/components/date-picker.d.ts.map +1 -1
- package/dist/components/date-picker.js +11 -4
- package/dist/components/disclosure.d.ts +17 -2
- package/dist/components/disclosure.d.ts.map +1 -1
- package/dist/components/disclosure.js +4 -8
- package/dist/components/display.d.ts +119 -94
- package/dist/components/display.d.ts.map +1 -1
- package/dist/components/display.js +103 -106
- package/dist/components/empty-state.d.ts +70 -52
- package/dist/components/empty-state.d.ts.map +1 -1
- package/dist/components/empty-state.js +40 -52
- package/dist/components/error-state.d.ts +21 -4
- package/dist/components/error-state.d.ts.map +1 -1
- package/dist/components/error-state.js +16 -6
- package/dist/components/file-upload.d.ts +45 -2
- package/dist/components/file-upload.d.ts.map +1 -1
- package/dist/components/file-upload.js +32 -7
- package/dist/components/gauge.d.ts +72 -9
- package/dist/components/gauge.d.ts.map +1 -1
- package/dist/components/gauge.js +52 -49
- package/dist/components/icons.d.ts +1 -1
- package/dist/components/icons.d.ts.map +1 -1
- package/dist/components/icons.js +4 -0
- package/dist/components/input.d.ts +21 -0
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +15 -1
- package/dist/components/layout.d.ts +47 -70
- package/dist/components/layout.d.ts.map +1 -1
- package/dist/components/layout.js +31 -73
- package/dist/components/link.d.ts +5 -10
- package/dist/components/link.d.ts.map +1 -1
- package/dist/components/live-scope.d.ts.map +1 -1
- package/dist/components/live-scope.js +5 -8
- package/dist/components/log-view.d.ts +32 -1
- package/dist/components/log-view.d.ts.map +1 -1
- package/dist/components/log-view.js +42 -15
- package/dist/components/number-input.d.ts +20 -2
- package/dist/components/number-input.d.ts.map +1 -1
- package/dist/components/number-input.js +32 -9
- package/dist/components/overlay.d.ts +69 -61
- package/dist/components/overlay.d.ts.map +1 -1
- package/dist/components/overlay.js +134 -77
- package/dist/components/pagination.d.ts.map +1 -1
- package/dist/components/pagination.js +12 -7
- package/dist/components/pie.d.ts.map +1 -1
- package/dist/components/pie.js +8 -7
- package/dist/components/primitives.d.ts +136 -6
- package/dist/components/primitives.d.ts.map +1 -1
- package/dist/components/primitives.js +73 -20
- package/dist/components/progress.d.ts +44 -9
- package/dist/components/progress.d.ts.map +1 -1
- package/dist/components/progress.js +21 -9
- package/dist/components/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group.js +11 -12
- package/dist/components/rail-link.d.ts +17 -1
- package/dist/components/rail-link.d.ts.map +1 -1
- package/dist/components/rail-link.js +3 -3
- package/dist/components/rich-text.d.ts +8 -1
- package/dist/components/rich-text.d.ts.map +1 -1
- package/dist/components/rich-text.js +13 -19
- package/dist/components/says-bubble.d.ts +38 -0
- package/dist/components/says-bubble.d.ts.map +1 -0
- package/dist/components/says-bubble.js +6 -0
- package/dist/components/scroll-x.d.ts +23 -0
- package/dist/components/scroll-x.d.ts.map +1 -0
- package/dist/components/scroll-x.js +27 -0
- package/dist/components/section.d.ts +18 -1
- package/dist/components/section.d.ts.map +1 -1
- package/dist/components/section.js +12 -1
- package/dist/components/segmented.d.ts +17 -1
- package/dist/components/segmented.d.ts.map +1 -1
- package/dist/components/segmented.js +26 -6
- package/dist/components/skeleton.d.ts.map +1 -1
- package/dist/components/skeleton.js +1 -1
- package/dist/components/slider.d.ts +16 -2
- package/dist/components/slider.d.ts.map +1 -1
- package/dist/components/slider.js +12 -5
- package/dist/components/sparkline.d.ts +9 -2
- package/dist/components/sparkline.d.ts.map +1 -1
- package/dist/components/sparkline.js +9 -5
- package/dist/components/spinner.d.ts +16 -1
- package/dist/components/spinner.d.ts.map +1 -1
- package/dist/components/spinner.js +24 -1
- package/dist/components/square-picker.d.ts +4 -20
- package/dist/components/square-picker.d.ts.map +1 -1
- package/dist/components/square-picker.js +4 -20
- package/dist/components/stacked-bar.d.ts.map +1 -1
- package/dist/components/stacked-bar.js +5 -4
- package/dist/components/surface.d.ts +32 -3
- package/dist/components/surface.d.ts.map +1 -1
- package/dist/components/surface.js +11 -4
- package/dist/components/switch.d.ts +14 -1
- package/dist/components/switch.d.ts.map +1 -1
- package/dist/components/switch.js +2 -3
- package/dist/components/tabs.d.ts +35 -11
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +48 -5
- package/dist/components/timeline-strip.d.ts +28 -3
- package/dist/components/timeline-strip.d.ts.map +1 -1
- package/dist/components/timeline-strip.js +19 -8
- package/dist/components/tone.d.ts +51 -14
- package/dist/components/tone.d.ts.map +1 -1
- package/dist/components/tone.js +76 -14
- package/dist/components/tree-select.d.ts.map +1 -1
- package/dist/components/tree-select.js +10 -3
- package/dist/fonts/LICENSE-jetbrains-mono.txt +93 -0
- package/dist/fonts/LICENSE-onest.txt +93 -0
- package/dist/fonts/LICENSE-red-hat-display.txt +93 -0
- package/dist/fonts/jetbrains-mono-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/jetbrains-mono-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/onest-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/onest-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/red-hat-display-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/red-hat-display-latin-wght-normal.woff2 +0 -0
- package/dist/fonts.css +54 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -6
- package/dist/kit.css +3175 -645
- package/dist/lib/color.d.ts +8 -19
- package/dist/lib/color.d.ts.map +1 -1
- package/dist/lib/color.js +8 -19
- package/dist/lib/data-props.d.ts +4 -15
- package/dist/lib/data-props.d.ts.map +1 -1
- package/dist/lib/data-props.js +4 -15
- package/dist/lib/image.d.ts +4 -20
- package/dist/lib/image.d.ts.map +1 -1
- package/dist/lib/image.js +4 -20
- package/dist/lib/palette.d.ts +16 -20
- package/dist/lib/palette.d.ts.map +1 -1
- package/dist/lib/palette.js +136 -71
- package/dist/lib/scroll-lock.d.ts +4 -14
- package/dist/lib/scroll-lock.d.ts.map +1 -1
- package/dist/lib/scroll-lock.js +4 -14
- package/dist/patterns/app-shell.d.ts.map +1 -1
- package/dist/patterns/app-shell.js +4 -13
- package/dist/patterns/appearance-template.d.ts +20 -15
- package/dist/patterns/appearance-template.d.ts.map +1 -1
- package/dist/patterns/appearance-template.js +29 -8
- package/dist/patterns/list-template.d.ts.map +1 -1
- package/dist/patterns/list-template.js +1 -1
- package/dist/patterns/overview-template.d.ts.map +1 -1
- package/dist/patterns/overview-template.js +1 -1
- package/dist/patterns/settings-template.d.ts +1 -12
- package/dist/patterns/settings-template.d.ts.map +1 -1
- package/dist/patterns/settings-template.js +2 -2
- package/dist/patterns/shared.d.ts.map +1 -1
- package/dist/patterns/shared.js +8 -1
- package/dist/styles.css +2 -1
- package/dist/theme.css +96 -259
- package/package.json +4 -2
- package/dist/components/control-base.d.ts +0 -7
- package/dist/components/control-base.d.ts.map +0 -1
- package/dist/components/control-base.js +0 -6
|
@@ -17,57 +17,36 @@ export function Surface({ raised = false, className, children, ...props }) {
|
|
|
17
17
|
return (_jsx("div", { className: cn(raised ? "tamga-raised" : "tamga-surface", className), ...props, children: children }));
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
* Yatay taşma kabı
|
|
20
|
+
* Yatay taşma kabı · asıl işi erişilebilirlik. `overflow-x: auto` tek başına
|
|
21
|
+
* yalnız FARE için çalışıyor; `tabIndex={0}` + `role="region"` + zorunlu bir ad
|
|
22
|
+
* o kutuyu klavyeye açıyor.
|
|
21
23
|
*
|
|
22
|
-
*
|
|
23
|
-
* kutuya hiç giremez: kaydırılabilir bir alan odaklanabilir değilse içindeki
|
|
24
|
-
* geniş tabloyu yana kaydırmanın yolu yoktur. Tarayıcılar bunu kendiliğinden
|
|
25
|
-
* çözmüyor.
|
|
26
|
-
*
|
|
27
|
-
* `tabIndex={0}` + `role="region"` + bir ad, o kutuyu klavyeye açıyor. Ad
|
|
28
|
-
* zorunlu: adsız bir `region` ekran okuyucunun landmark listesinde
|
|
29
|
-
* "bölge, bölge, bölge" olarak birikir ve hiçbirinin ne olduğu bilinmez.
|
|
24
|
+
* Gerekçe: docs/gerekce/05-yuzey-ve-kabuk.md
|
|
30
25
|
*/
|
|
31
|
-
export function ScrollX({ label, className, children, ...props }) {
|
|
32
|
-
return (_jsx("div", { className: cn("tamga-scroll-x", className), role: "region", "aria-label": label, tabIndex: 0, ...props, children: children }));
|
|
33
|
-
}
|
|
34
26
|
/**
|
|
35
|
-
* Aşağıdan giren blok.
|
|
36
|
-
*
|
|
37
|
-
* `.tamga-rise` bir HOVER etkisi değil, bir GİRİŞ animasyonu: sekiz piksel
|
|
38
|
-
* aşağıdan, sönükten. Azaltılmış harekette CSS onu tamamen kapatıyor.
|
|
27
|
+
* Aşağıdan giren blok · GİRİŞ animasyonu, hover etkisi değil.
|
|
39
28
|
*
|
|
40
|
-
*
|
|
41
|
-
* satırlık bir listede 60ms'lik bir gecikme, sonuncuyu iki saniye sonra
|
|
42
|
-
* gösterir ve bekleme hissi yaratır.
|
|
29
|
+
* Gerekçe: docs/gerekce/05-yuzey-ve-kabuk.md
|
|
43
30
|
*/
|
|
44
|
-
export function
|
|
45
|
-
return (_jsx("div", { className: cn("tamga-
|
|
31
|
+
export function Reveal({ delay = 0, className, children, ...props }) {
|
|
32
|
+
return (_jsx("div", { className: cn("tamga-reveal", className), style: delay ? { animationDelay: `${delay}ms` } : undefined, ...props, children: children }));
|
|
46
33
|
}
|
|
47
34
|
/**
|
|
48
|
-
* İki durumun aynı yerde
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* ve yanındaki her şey kayar. Swap ikisini de aynı ızgara hücresine koyuyor:
|
|
52
|
-
* kutu her zaman UZUN olanın genişliğinde, yani hiçbir şey oynamıyor.
|
|
35
|
+
* İki durumun aynı yerde durması · kutu her zaman UZUN olanın genişliğinde,
|
|
36
|
+
* yani "Kaydet" → "Kaydediliyor…" yanındaki hiçbir şeyi kaydırmıyor. Gizlenen
|
|
37
|
+
* taraf `aria-hidden` alıyor.
|
|
53
38
|
*
|
|
54
|
-
*
|
|
55
|
-
* arka arkaya okurdu — "Kaydet Kaydediliyor" — ve hangisinin geçerli olduğu
|
|
56
|
-
* anlaşılmazdı.
|
|
39
|
+
* Gerekçe: docs/gerekce/05-yuzey-ve-kabuk.md
|
|
57
40
|
*/
|
|
58
41
|
export function Swap({ showing, a, b, className, ...rest }) {
|
|
59
42
|
return (_jsxs("span", { ...dataProps(rest), className: cn("tamga-swap", className), children: [_jsx("span", { "data-hidden": showing !== "a", "aria-hidden": showing !== "a", children: a }), _jsx("span", { "data-hidden": showing !== "b", "aria-hidden": showing !== "b", children: b })] }));
|
|
60
43
|
}
|
|
61
44
|
/**
|
|
62
|
-
* Liste satırı
|
|
45
|
+
* Liste satırı · tablo olmayan listeler için. `href` verilirse bağlantı,
|
|
46
|
+
* `onClick` verilirse düğme, ikisi de yoksa düz satır: tıklanabilir bir `<div>`
|
|
47
|
+
* klavyeyle erişilemiyor.
|
|
63
48
|
*
|
|
64
|
-
*
|
|
65
|
-
* entegrasyon satırı, üye satırı. Sabit yükseklik ve alt kural, satırların
|
|
66
|
-
* taranabilir kalmasını sağlıyor.
|
|
67
|
-
*
|
|
68
|
-
* `href` verilirse bir bağlantıya, `onClick` verilirse bir düğmeye döner —
|
|
69
|
-
* ikisi de yoksa düz bir satır kalır. Bu ayrım önemli: tıklanabilir bir
|
|
70
|
-
* `<div>` klavyeyle erişilemez ve ekran okuyucuya hiçbir şey söylemez.
|
|
49
|
+
* Gerekçe: docs/gerekce/05-yuzey-ve-kabuk.md
|
|
71
50
|
*/
|
|
72
51
|
export function ListRow({ size = "base", href, onClick, className, children, ...rest }) {
|
|
73
52
|
const cls = cn("tamga-list-row", size === "sm" && "tamga-list-row-sm", className);
|
|
@@ -80,18 +59,12 @@ export function ListRow({ size = "base", href, onClick, className, children, ...
|
|
|
80
59
|
return _jsx("div", { className: cls, children: children });
|
|
81
60
|
}
|
|
82
61
|
/**
|
|
83
|
-
* İçinde bir panel AÇILAN tablo hücresi.
|
|
62
|
+
* İçinde bir panel AÇILAN tablo hücresi. Tek işi kırpmayı kapatmak, ve
|
|
63
|
+
* unutulduğunda görünmeyen bir hata üretiyor: hücredeki menü hücre sınırında
|
|
64
|
+
* KESİLİYOR, konsol sessiz, ve ilk akla gelen z-index oluyor. Z-index bunu
|
|
65
|
+
* çözmez · hiçbir yığın sırası bir `overflow` kırpmasını aşamaz.
|
|
84
66
|
*
|
|
85
|
-
*
|
|
86
|
-
* üretiyor: hücrenin içindeki bir menü, ipucu ya da açılır panel hücre
|
|
87
|
-
* sınırında KESİLİYOR. Kontrol çalışıyor, tıklanıyor, ama yarısı yok. Hata
|
|
88
|
-
* mesajı yok, konsol sessiz, ve ilk akla gelen z-index oluyor. Z-index bunu
|
|
89
|
-
* çözmez: hiçbir yığın sırası bir `overflow` kırpmasını aşamaz.
|
|
90
|
-
*
|
|
91
|
-
* `align` VARSAYILAN OLARAK SAĞDA, çünkü en sık kullanımı satır sonundaki
|
|
92
|
-
* eylem menüsü. Ama hiza ile kırpma AYRI iki karar: sola yaslı bir hücrede
|
|
93
|
-
* ipucu barındırmak isteyen, hizasını feda etmek zorunda kalmasın diye
|
|
94
|
-
* `align="start"` var. (Uzun süre tek parçaydı ve tam bu yüzden yakalandı.)
|
|
67
|
+
* `align` varsayılan olarak sağda: en sık kullanımı satır sonundaki eylem.
|
|
95
68
|
*/
|
|
96
69
|
export function CellActions({ className, children, align = "end", ...props
|
|
97
70
|
/* `Omit`: `<td>`in kendi `align` niteliği var (HTML 4'ten kalma, artık
|
|
@@ -100,37 +73,22 @@ export function CellActions({ className, children, align = "end", ...props
|
|
|
100
73
|
return (_jsx("td", { className: cn("tamga-cell-open", align === "end" && "tamga-cell-actions", className), ...props, children: _jsx("span", { className: cn("flex items-center gap-1", align === "end" ? "justify-end" : "justify-start"), children: children }) }));
|
|
101
74
|
}
|
|
102
75
|
/**
|
|
103
|
-
* Sayfa başlığı şeridi.
|
|
104
|
-
*
|
|
105
|
-
* Ürün bunu kendi yazmıştı (23 satır) ve doğru yazmıştı — ama her ekranın
|
|
106
|
-
* tepesinde duran bir şeyin her projede yeniden yazılması, on panelde on
|
|
107
|
-
* farklı boşluk demek.
|
|
76
|
+
* Sayfa başlığı şeridi. Eylem SAĞA yaslı ve başlığın taban çizgisinde.
|
|
108
77
|
*
|
|
109
|
-
*
|
|
110
|
-
* altındaki listeden kopmuş görünüyor — bu bir tercih değil, ölçülmüş bir şey.
|
|
78
|
+
* Doküman: /docs/page-band
|
|
111
79
|
*/
|
|
112
|
-
export function PageBand({ title, subtitle, actions, className, ...rest }) {
|
|
113
|
-
return (_jsxs("div", { ...dataProps(rest), className: cn("
|
|
80
|
+
export function PageBand({ eyebrow, title, subtitle, actions, className, ...rest }) {
|
|
81
|
+
return (_jsxs("div", { ...dataProps(rest), className: cn("flex flex-wrap items-end gap-4", className), children: [_jsxs("div", { className: "min-w-0 flex-1 basis-65", children: [eyebrow ? (_jsx("p", { className: "mb-1.5 text-small font-semibold text-ink-faint", children: eyebrow })) : null, _jsx("h1", { className: "font-display text-display-lg leading-tight font-extrabold text-ink", children: title }), subtitle ? _jsx("p", { className: "mt-1.5 text-body text-ink-soft", children: subtitle }) : null] }), actions ? _jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions }) : null] }));
|
|
114
82
|
}
|
|
115
83
|
/**
|
|
116
|
-
* Gezinen bağlantı.
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* olmaması, tam olarak checkbox'ın yaşadığı boşluk.
|
|
121
|
-
*
|
|
122
|
-
* NEDEN `Button variant="link"` DEĞİL. O bir `<button>`; bir bağlantı gibi
|
|
123
|
-
* GÖRÜNÜR ama gezinmez. Orta tuşla yeni sekmede açılamaz, sağ tıkla
|
|
124
|
-
* kopyalanamaz, ve ekran okuyucuya "düğme" der. Görünüm aynı, sözleşme
|
|
125
|
-
* ters.
|
|
126
|
-
*
|
|
127
|
-
* `external` verilince `rel="noopener noreferrer"` geliyor. `noopener`
|
|
128
|
-
* olmadan açılan sayfa `window.opener` üzerinden seninkini yönlendirebilir —
|
|
129
|
-
* eski ve hâlâ geçerli bir açık.
|
|
84
|
+
* Gezinen bağlantı. `Button variant="link"` DEĞİL: o bir `<button>`, yani orta
|
|
85
|
+
* tuşla yeni sekmede açılmıyor, kopyalanmıyor, ve ekran okuyucuya "düğme"
|
|
86
|
+
* diyor. `external` verilince `rel="noopener noreferrer"` geliyor · `noopener`
|
|
87
|
+
* olmadan açılan sayfa `window.opener` ile seninkini yönlendirebilir.
|
|
130
88
|
*/
|
|
131
|
-
export function Link({ external = false, className, children, href, linkComponent: Router, ...props }) {
|
|
89
|
+
export function Link({ external = false, look = "inline", className, children, href, linkComponent: Router, ...props }) {
|
|
132
90
|
const shared = {
|
|
133
|
-
className: cn("tamga-link", className),
|
|
91
|
+
className: cn("tamga-link", look === "standalone" && "tamga-link-standalone", look === "quiet" && "tamga-link-quiet", look === "marked" && "tamga-link-marked", className),
|
|
134
92
|
target: external ? "_blank" : undefined,
|
|
135
93
|
rel: external ? "noopener noreferrer" : undefined,
|
|
136
94
|
...props,
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from "react";
|
|
2
2
|
/**
|
|
3
|
-
* Yönlendiricinin bağlantısı, dışarıdan verilir
|
|
3
|
+
* Yönlendiricinin bağlantısı, dışarıdan verilir: kit hangi yönlendiricinin
|
|
4
|
+
* kullanıldığını bilmiyor ve bilmemeli. `components/` altında, çünkü bir
|
|
5
|
+
* BİLEŞEN de (`Kpi`) bağlantı olabiliyor ve şablondan import etmesi katmanı
|
|
6
|
+
* ters çevirirdi; `patterns/shared.tsx` tipi yeniden dışa vuruyor.
|
|
4
7
|
*
|
|
5
|
-
*
|
|
6
|
-
* bilmiyor ve bilmemeli (`next/link`, `react-router`, ya da düz `a`).
|
|
7
|
-
* Bileşen bir `href` alıp `a` yazsaydı her tıklama tam sayfa yüklerdi.
|
|
8
|
-
*
|
|
9
|
-
* NEDEN `components/` ALTINDA, `patterns/` ALTINDA DEĞİL: burada doğmuştu,
|
|
10
|
-
* ama bir BİLEŞEN de (`Kpi`) bağlantı olabildiği için şablon katmanına
|
|
11
|
-
* bağımlı olması gerekiyordu. Bir bileşenin şablondan import etmesi katmanı
|
|
12
|
-
* ters çevirir; tip aşağı indi, `patterns/shared.tsx` onu yeniden dışa
|
|
13
|
-
* vuruyor ve dışarıdan bakan API hiç değişmedi.
|
|
8
|
+
* Gerekçe: docs/gerekce/05-yuzey-ve-kabuk.md
|
|
14
9
|
*/
|
|
15
10
|
export type LinkComponent = ComponentType<{
|
|
16
11
|
href: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/components/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/components/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,aAAa,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC,CAAC;AAEH,eAAO,MAAM,SAAS,EAAE,aAIvB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-scope.d.ts","sourceRoot":"","sources":["../../src/components/live-scope.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,+
|
|
1
|
+
{"version":3,"file":"live-scope.d.ts","sourceRoot":"","sources":["../../src/components/live-scope.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,+BAoCpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAe7D"}
|
|
@@ -19,14 +19,11 @@ export function LiveScope({ children }) {
|
|
|
19
19
|
const winner = useMemo(() => {
|
|
20
20
|
let best = null;
|
|
21
21
|
let bestSeverity = -Infinity;
|
|
22
|
-
/*
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
signal matters more than which row carries it, and every alternative
|
|
28
|
-
(timestamp, domain priority) buys a nicer tie-break by making call sites
|
|
29
|
-
thread data they do not otherwise need. */
|
|
22
|
+
/* Insertion order is tree order, so a strict `>` keeps the FIRST of equals, and
|
|
23
|
+
"first" means highest on the page. (SETTLED 2026-08-19, Ercüment.) Every
|
|
24
|
+
alternative buys a nicer tie-break by making call sites thread data they do
|
|
25
|
+
not otherwise need.
|
|
26
|
+
Gerekçe: docs/gerekce/06-isaret-ve-ton.md */
|
|
30
27
|
for (const [id, severity] of Object.entries(claims)) {
|
|
31
28
|
if (severity > bestSeverity) {
|
|
32
29
|
best = id;
|
|
@@ -11,16 +11,47 @@ export type LogLine = {
|
|
|
11
11
|
* bilmez.
|
|
12
12
|
*/
|
|
13
13
|
time?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The level badge's word: "INFO", "ERROR", "HATA". The kit draws the badge, the product
|
|
16
|
+
* writes it. TR: Seviye etiketinin sözcüğü: "INFO", "ERROR", "HATA". Rozeti kit çizer,
|
|
17
|
+
* sözcüğü ürün yazar.
|
|
18
|
+
*/
|
|
19
|
+
level?: string;
|
|
14
20
|
text: string;
|
|
15
21
|
tone?: Tone;
|
|
16
22
|
};
|
|
17
|
-
export declare function LogView({ lines, label, height, follow, wrap, className, ...rest }: {
|
|
23
|
+
export declare function LogView({ lines, label, labels, filters, height, follow, wrap, className, ...rest }: {
|
|
18
24
|
lines: readonly LogLine[];
|
|
19
25
|
/**
|
|
20
26
|
* The region's name; it shows in the landmark list for keyboard navigation. TR: Bölgenin adı;
|
|
21
27
|
* klavyeyle gezinende landmark listesinde görünür.
|
|
22
28
|
*/
|
|
23
29
|
label: string;
|
|
30
|
+
/**
|
|
31
|
+
* `newLines` is the button that appears when lines arrive while you are reading further up:
|
|
32
|
+
* "↓ 12 new lines". TR: `newLines`, yukarıda okurken satır geldiğinde beliren düğme: "↓ 12
|
|
33
|
+
* yeni satır".
|
|
34
|
+
*/
|
|
35
|
+
labels: {
|
|
36
|
+
newLines: (n: number) => string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The level filter bar over the stream. The kit draws the bar and marks the chosen one; WHICH
|
|
40
|
+
* levels exist and what they are called is the product's vocabulary, and the filtering itself
|
|
41
|
+
* happens on the caller's side · a log view that filters its own lines would have to know what
|
|
42
|
+
* a level means. TR: Akışın üstündeki seviye filtresi. Çubuğu kit çiziyor ve seçili olanı
|
|
43
|
+
* işaretliyor; hangi seviyelerin olduğu ve adları ürünün sözlüğü, ve süzme çağıranın tarafında
|
|
44
|
+
* kalıyor · kendi satırlarını süzen bir günlük, bir seviyenin ne demek olduğunu bilmek
|
|
45
|
+
* zorunda kalırdı.
|
|
46
|
+
*/
|
|
47
|
+
filters?: {
|
|
48
|
+
options: readonly ({
|
|
49
|
+
value: string;
|
|
50
|
+
label: string;
|
|
51
|
+
} & Record<string, unknown>)[];
|
|
52
|
+
value: string;
|
|
53
|
+
onChange: (value: string) => void;
|
|
54
|
+
};
|
|
24
55
|
height?: number;
|
|
25
56
|
/** Scroll to the bottom when a new line arrives. TR: Yeni satır geldiğinde en alta kay. */
|
|
26
57
|
follow?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-view.d.ts","sourceRoot":"","sources":["../../src/components/log-view.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAU,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAE9C;;;;GAIG;AAEH,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,CAAC;AAEF,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,KAAK,EACL,MAAY,EACZ,MAAa,EACb,IAAY,EACZ,SAAS,EACT,GAAG,IAAI,EACR,EAAE;IACD,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,CAAC,CAAC,EAAE,QAAQ,MAAM,EAAE,GAAG,OAAO,CAAC;CAChC,+
|
|
1
|
+
{"version":3,"file":"log-view.d.ts","sourceRoot":"","sources":["../../src/components/log-view.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAU,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAE9C;;;;GAIG;AAEH,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,CAAC;AAEF,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,KAAK,EACL,MAAM,EACN,OAAO,EACP,MAAY,EACZ,MAAa,EACb,IAAY,EACZ,SAAS,EACT,GAAG,IAAI,EACR,EAAE;IACD,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,MAAM,EAAE;QAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;KAAE,CAAC;IAC5C;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE;QACR,OAAO,EAAE,SAAS,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;QACjF,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACnC,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,CAAC,CAAC,EAAE,QAAQ,MAAM,EAAE,GAAG,OAAO,CAAC;CAChC,+BAmHA"}
|
|
@@ -1,31 +1,58 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { createElement as _createElement } from "react";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
5
|
import { cn } from "../lib/cn.js";
|
|
5
6
|
import { dataProps } from "../lib/data-props.js";
|
|
6
7
|
import { toneOf } from "./tone.js";
|
|
7
|
-
export function LogView({ lines, label, height = 320, follow = true, wrap = false, className, ...rest }) {
|
|
8
|
+
export function LogView({ lines, label, labels, filters, height = 320, follow = true, wrap = false, className, ...rest }) {
|
|
8
9
|
const box = useRef(null);
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
/* Okunmamış satırlar SAYILIYOR, sadece "yeni var mı" değil: sayı, aşağı
|
|
11
|
+
inmeye değer mi kararını veren şey. Son görülen uzunluk bir ref'te
|
|
12
|
+
tutuluyor çünkü render'ı tetiklemesi gereken şey sayı, uzunluk değil. */
|
|
13
|
+
const gorulen = useRef(lines.length);
|
|
14
|
+
const [yeni, setYeni] = useState(0);
|
|
15
|
+
function altta(el) {
|
|
16
|
+
/* 32px tolerans: tam altta olmayı beklemek, bir piksellik kaydırmada
|
|
17
|
+
takibi kapatıyor. */
|
|
18
|
+
return el.scrollHeight - el.scrollTop - el.clientHeight < 32;
|
|
19
|
+
}
|
|
20
|
+
function dibeGit() {
|
|
21
|
+
const el = box.current;
|
|
22
|
+
if (!el)
|
|
11
23
|
return;
|
|
24
|
+
el.scrollTop = el.scrollHeight;
|
|
25
|
+
gorulen.current = lines.length;
|
|
26
|
+
setYeni(0);
|
|
27
|
+
}
|
|
28
|
+
useEffect(() => {
|
|
12
29
|
const el = box.current;
|
|
13
30
|
if (!el)
|
|
14
31
|
return;
|
|
32
|
+
const eklenen = Math.max(0, lines.length - gorulen.current);
|
|
15
33
|
/* SADECE ZATEN ALTTAYSA kaydır. Yukarıda bir şey okuyan kişiyi aşağı
|
|
16
34
|
fırlatmak, bu bileşenin yapabileceği en can sıkıcı şey — ve "hep en
|
|
17
35
|
alta git" davranışının varsayılan olduğu her log görüntüleyicide
|
|
18
|
-
yaşanır.
|
|
19
|
-
|
|
20
|
-
if (
|
|
36
|
+
yaşanır. Fırlatmamanın bedeli, gelen satırın görünmemesi: düğme tam
|
|
37
|
+
onun için var. */
|
|
38
|
+
if (follow && altta(el)) {
|
|
21
39
|
el.scrollTop = el.scrollHeight;
|
|
40
|
+
setYeni(0);
|
|
41
|
+
}
|
|
42
|
+
else if (eklenen > 0) {
|
|
43
|
+
setYeni((n) => n + eklenen);
|
|
44
|
+
}
|
|
45
|
+
gorulen.current = lines.length;
|
|
22
46
|
}, [lines, follow]);
|
|
23
|
-
return (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
return (_jsxs("div", { ...dataProps(rest), className: cn("tamga-log", className), style: { height }, children: [filters ? (_jsx("div", { className: "tamga-log-filtre", children: filters.options.map(({ value: v, label: etiket, ...kanca }) => (_createElement("button", { ...kanca, key: v, type: "button", className: `tamga-btn tamga-btn-sm ${v === filters.value ? "tamga-btn-primary" : ""}`, "aria-pressed": v === filters.value, onClick: () => filters.onChange(v) }, etiket))) })) : null, _jsx("div", { ref: box, className: "tamga-log-akis", "data-filtreli": filters ? true : undefined,
|
|
48
|
+
/* `log` rolü: ekran okuyucu bunu bir günlük olarak tanır ve — kritik
|
|
49
|
+
olarak — `aria-live` OLMADAN sessiz kalır. Akan bir bölgeyi
|
|
50
|
+
duyurmak sesli okuyucuyu boğar; kullanıcı isterse kendisi okur. */
|
|
51
|
+
role: "log", "aria-label": label, tabIndex: 0, onScroll: (e) => {
|
|
52
|
+
if (yeni > 0 && altta(e.currentTarget))
|
|
53
|
+
setYeni(0);
|
|
54
|
+
}, children: lines.map((l) => {
|
|
55
|
+
const c = l.tone ? toneOf(l.tone) : null;
|
|
56
|
+
return (_jsxs("div", { className: "tamga-log-satir", "data-wrap": wrap || undefined, children: [l.time ? (_jsx("span", { className: "tamga-log-saat tabular-nums", children: l.time })) : null, l.level ? (_jsx("span", { className: "tamga-log-yuva", children: _jsx("span", { className: "tamga-log-seviye", style: c ? { background: c.bg, color: c.fg } : undefined, children: l.level }) })) : null, _jsx("span", { className: "tamga-log-metin", style: c && !l.level ? { color: c.mark } : undefined, children: l.text })] }, l.id));
|
|
57
|
+
}) }), yeni > 0 ? (_jsxs("button", { type: "button", className: "tamga-log-yeni", onClick: dibeGit, children: ["\u2193 ", labels.newLines(yeni)] })) : null] }));
|
|
31
58
|
}
|
|
@@ -3,13 +3,23 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Gerekçe: docs/gerekce/01-form-ve-girdi.md
|
|
5
5
|
*/
|
|
6
|
-
export declare function NumberInput({ value, onChange, min, max, step,
|
|
6
|
+
export declare function NumberInput({ value, onChange, look, min, max, step,
|
|
7
7
|
/** Değerin sonuna yapışan birim: "₺", "kg", "%" */
|
|
8
8
|
suffix, disabled, invalid, full,
|
|
9
9
|
/** Artır/azalt düğmelerinin erişilebilir adları. Kit çeviri çekmez. */
|
|
10
|
-
labels, className, ...rest }: {
|
|
10
|
+
labels, locale, className, ...rest }: {
|
|
11
11
|
value: number | null;
|
|
12
12
|
onChange?: (next: number | null) => void;
|
|
13
|
+
/**
|
|
14
|
+
* `field` a text field with the stepper on its right edge · for a threshold, a rate, a price:
|
|
15
|
+
* numbers that are TYPED and only nudged. `quantity` the joined control with the buttons
|
|
16
|
+
* flanking the value · for a count that is CLICKED into place ("3 adet"), where the number is
|
|
17
|
+
* small and the two buttons are the whole interaction. TR: `field` sağ kenarında sayaç olan
|
|
18
|
+
* metin alanı · eşik, oran, fiyat için: YAZILAN ve yalnız dürtülen sayılar. `quantity`
|
|
19
|
+
* düğmeleri değerin iki yanında duran birleşik kontrol · TIKLANARAK ayarlanan adet için
|
|
20
|
+
* ("3 adet"), sayı küçükken ve etkileşimin tamamı o iki düğmeyken.
|
|
21
|
+
*/
|
|
22
|
+
look?: "field" | "quantity";
|
|
13
23
|
min?: number;
|
|
14
24
|
max?: number;
|
|
15
25
|
step?: number;
|
|
@@ -21,6 +31,14 @@ labels, className, ...rest }: {
|
|
|
21
31
|
increase: string;
|
|
22
32
|
decrease: string;
|
|
23
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* BCP-47 tag for how the number is SHOWN: "tr-TR" prints 249,9 and "en-US" prints 249.9. Not
|
|
36
|
+
* given, the number is shown as typed. This is formatting, not translation: the kit does not
|
|
37
|
+
* pick the tag, the caller does. TR: Sayının NASIL GÖSTERİLECEĞİ: "tr-TR" 249,9 yazar,
|
|
38
|
+
* "en-US" 249.9. Verilmezse sayı yazıldığı gibi görünür. Bu çeviri değil biçimleme: etiketi
|
|
39
|
+
* kit seçmiyor, çağıran veriyor.
|
|
40
|
+
*/
|
|
41
|
+
locale?: string;
|
|
24
42
|
className?: string;
|
|
25
43
|
/** `data-*` hooks pass through. TR: `data-*` kancaları geçiyor. */
|
|
26
44
|
[k: `data-${string}`]: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-input.d.ts","sourceRoot":"","sources":["../../src/components/number-input.tsx"],"names":[],"mappings":"AAQA;;;;GAIG;AAEH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,GAAG,EACH,GAAG,EACH,IAAQ;AACR,mDAAmD;AACnD,MAAM,EACN,QAAgB,EAChB,OAAe,EACf,IAAY;AACZ,uEAAuE;AACvE,MAAM,EACN,SAAS,EACT,GAAG,IAAI,EACR,EAAE;IACD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,CAAC,CAAC,EAAE,QAAQ,MAAM,EAAE,GAAG,OAAO,CAAC;CAChC,+
|
|
1
|
+
{"version":3,"file":"number-input.d.ts","sourceRoot":"","sources":["../../src/components/number-input.tsx"],"names":[],"mappings":"AAQA;;;;GAIG;AAEH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,IAAc,EACd,GAAG,EACH,GAAG,EACH,IAAQ;AACR,mDAAmD;AACnD,MAAM,EACN,QAAgB,EAChB,OAAe,EACf,IAAY;AACZ,uEAAuE;AACvE,MAAM,EACN,MAAM,EACN,SAAS,EACT,GAAG,IAAI,EACR,EAAE;IACD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,CAAC,CAAC,EAAE,QAAQ,MAAM,EAAE,GAAG,OAAO,CAAC;CAChC,+BAuIA"}
|
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useId } from "react";
|
|
3
|
+
import { useId, useState } from "react";
|
|
4
4
|
import { cn } from "../lib/cn.js";
|
|
5
5
|
import { dataProps } from "../lib/data-props.js";
|
|
6
6
|
import { Icon } from "./icon.js";
|
|
7
|
-
import { CaretDown } from "./icons.js";
|
|
7
|
+
import { CaretDown, Minus, Plus } from "./icons.js";
|
|
8
8
|
/**
|
|
9
9
|
* NumberInput — fiyat, stok, ağırlık.
|
|
10
10
|
*
|
|
11
11
|
* Gerekçe: docs/gerekce/01-form-ve-girdi.md
|
|
12
12
|
*/
|
|
13
|
-
export function NumberInput({ value, onChange, min, max, step = 1,
|
|
13
|
+
export function NumberInput({ value, onChange, look = "field", min, max, step = 1,
|
|
14
14
|
/** Değerin sonuna yapışan birim: "₺", "kg", "%" */
|
|
15
15
|
suffix, disabled = false, invalid = false, full = false,
|
|
16
16
|
/** Artır/azalt düğmelerinin erişilebilir adları. Kit çeviri çekmez. */
|
|
17
|
-
labels, className, ...rest }) {
|
|
17
|
+
labels, locale, className, ...rest }) {
|
|
18
18
|
const id = useId();
|
|
19
|
+
/* YAZARKEN BİÇİMLENMİYOR, BIRAKINCA BİÇİMLENİYOR.
|
|
20
|
+
Her tuşta biçimlemek "249," yazan birinin virgülünü siliyor, yani ondalık
|
|
21
|
+
yazılamıyor. Taslak yalnız odaktayken yaşıyor; odak çıkınca değerin kendisi
|
|
22
|
+
yerel biçimde görünüyor. */
|
|
23
|
+
const [taslak, setTaslak] = useState(null);
|
|
24
|
+
const goster = (n) => {
|
|
25
|
+
if (n === null)
|
|
26
|
+
return "";
|
|
27
|
+
return locale ? n.toLocaleString(locale) : String(n);
|
|
28
|
+
};
|
|
19
29
|
const clamp = (n) => {
|
|
20
30
|
if (min !== undefined && n < min)
|
|
21
31
|
return min;
|
|
@@ -34,14 +44,27 @@ labels, className, ...rest }) {
|
|
|
34
44
|
};
|
|
35
45
|
const atMin = min !== undefined && value !== null && value <= min;
|
|
36
46
|
const atMax = max !== undefined && value !== null && value >= max;
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
if (look === "quantity") {
|
|
48
|
+
/* DEĞER BİR GİRDİ DEĞİL BİR METİN: adet kontrolünde sayı tıklanarak
|
|
49
|
+
ayarlanıyor, ve yazılabilir bir alan burada klavyeyle girilen geçersiz
|
|
50
|
+
değerin kapısını açıyor. Yazmak gerekiyorsa `field` var. */
|
|
51
|
+
return (_jsxs("span", { ...dataProps(rest), className: cn("tamga-qty", full && "w-full", className), "data-disabled": disabled || undefined, children: [_jsx("button", { type: "button", "aria-label": labels.decrease, disabled: disabled || atMin, onClick: () => bump(-1), children: _jsx(Icon, { icon: Minus, size: "sm", weight: "bold" }) }), _jsxs("span", { className: "tamga-qty-deger tabular-nums", "aria-live": "polite", children: [goster(value), suffix ? _jsx("span", { className: "tamga-qty-birim", children: suffix }) : null] }), _jsx("button", { type: "button", "aria-label": labels.increase, disabled: disabled || atMax, onClick: () => bump(1), children: _jsx(Icon, { icon: Plus, size: "sm", weight: "bold" }) })] }));
|
|
52
|
+
}
|
|
53
|
+
return (_jsxs("span", { ...dataProps(rest), className: cn("relative inline-flex items-center", full && "w-full", className), children: [_jsx("input", { id: id, type: "text", inputMode: "decimal", value: taslak ?? goster(value), disabled: disabled, "aria-invalid": invalid || undefined, onChange: (e) => {
|
|
54
|
+
setTaslak(e.target.value);
|
|
55
|
+
/* Binlik ayracı temizleniyor, ondalık ayracı noktaya çevriliyor:
|
|
56
|
+
kullanıcı "1.234,5" de yazabilir "1234.5" de. */
|
|
57
|
+
const raw = e.target.value.replace(/\s/g, "").replace(/\.(?=\d{3}\b)/g, "").replace(",", ".");
|
|
39
58
|
if (raw === "")
|
|
40
59
|
return onChange?.(null);
|
|
41
60
|
const n = Number(raw);
|
|
42
61
|
if (!Number.isNaN(n))
|
|
43
62
|
onChange?.(n);
|
|
44
|
-
}, onBlur: () =>
|
|
63
|
+
}, onBlur: () => {
|
|
64
|
+
setTaslak(null);
|
|
65
|
+
if (value !== null)
|
|
66
|
+
onChange?.(clamp(value));
|
|
67
|
+
}, onKeyDown: (e) => {
|
|
45
68
|
if (e.key === "ArrowUp") {
|
|
46
69
|
e.preventDefault();
|
|
47
70
|
bump(1);
|
|
@@ -51,8 +74,8 @@ labels, className, ...rest }) {
|
|
|
51
74
|
bump(-1);
|
|
52
75
|
}
|
|
53
76
|
},
|
|
54
|
-
/* Sağ boşluk spinner'ın genişliği (
|
|
77
|
+
/* Sağ boşluk spinner'ın genişliği (38px) artı kenar payı; birim varsa
|
|
55
78
|
onun yeri de eklenir. Elle sayı yazmak yerine hesaplanıyor, çünkü
|
|
56
79
|
birim "₺" da olabilir "adet" de. */
|
|
57
|
-
className: cn("tamga-input w-full
|
|
80
|
+
className: cn("tamga-input tamga-sayi w-full", invalid && "tamga-input-invalid"), style: { paddingRight: suffix ? 96 : 48 } }), suffix ? (_jsx("span", { className: "tamga-stepper-birim", children: suffix })) : null, _jsxs("span", { className: "tamga-stepper", children: [_jsx("button", { type: "button", "aria-label": labels.increase, "aria-controls": id, disabled: disabled || atMax, onClick: () => bump(1), children: _jsx(Icon, { icon: CaretDown, size: "xs", weight: "bold", className: "rotate-180" }) }), _jsx("button", { type: "button", "aria-label": labels.decrease, "aria-controls": id, disabled: disabled || atMin, onClick: () => bump(-1), children: _jsx(Icon, { icon: CaretDown, size: "xs", weight: "bold" }) })] })] }));
|
|
58
81
|
}
|