tamga-ui 0.1.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/LICENSE +21 -0
- package/README.md +172 -0
- package/dist/blocks/count-row.d.ts +29 -0
- package/dist/blocks/count-row.d.ts.map +1 -0
- package/dist/blocks/count-row.js +19 -0
- package/dist/blocks/filter-bar.d.ts +123 -0
- package/dist/blocks/filter-bar.d.ts.map +1 -0
- package/dist/blocks/filter-bar.js +74 -0
- package/dist/blocks/index.d.ts +24 -0
- package/dist/blocks/index.d.ts.map +1 -0
- package/dist/blocks/index.js +23 -0
- package/dist/blocks/save-bar.d.ts +31 -0
- package/dist/blocks/save-bar.d.ts.map +1 -0
- package/dist/blocks/save-bar.js +21 -0
- package/dist/components/a11y.d.ts +21 -0
- package/dist/components/a11y.d.ts.map +1 -0
- package/dist/components/a11y.js +159 -0
- package/dist/components/advanced-input.d.ts +115 -0
- package/dist/components/advanced-input.d.ts.map +1 -0
- package/dist/components/advanced-input.js +189 -0
- package/dist/components/avatar.d.ts +63 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/avatar.js +54 -0
- package/dist/components/badge.d.ts +37 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +29 -0
- package/dist/components/bar.d.ts +32 -0
- package/dist/components/bar.d.ts.map +1 -0
- package/dist/components/bar.js +33 -0
- package/dist/components/button.d.ts +45 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +56 -0
- package/dist/components/chart.d.ts +43 -0
- package/dist/components/chart.d.ts.map +1 -0
- package/dist/components/chart.js +41 -0
- package/dist/components/checkbox.d.ts +13 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox.js +16 -0
- package/dist/components/chrome.d.ts +87 -0
- package/dist/components/chrome.d.ts.map +1 -0
- package/dist/components/chrome.js +107 -0
- package/dist/components/combobox.d.ts +31 -0
- package/dist/components/combobox.d.ts.map +1 -0
- package/dist/components/combobox.js +62 -0
- package/dist/components/control-base.d.ts +7 -0
- package/dist/components/control-base.d.ts.map +1 -0
- package/dist/components/control-base.js +6 -0
- package/dist/components/data-table.d.ts +68 -0
- package/dist/components/data-table.d.ts.map +1 -0
- package/dist/components/data-table.js +50 -0
- package/dist/components/date-picker.d.ts +52 -0
- package/dist/components/date-picker.d.ts.map +1 -0
- package/dist/components/date-picker.js +73 -0
- package/dist/components/disclosure.d.ts +31 -0
- package/dist/components/disclosure.d.ts.map +1 -0
- package/dist/components/disclosure.js +32 -0
- package/dist/components/display.d.ts +188 -0
- package/dist/components/display.d.ts.map +1 -0
- package/dist/components/display.js +190 -0
- package/dist/components/empty-state.d.ts +150 -0
- package/dist/components/empty-state.d.ts.map +1 -0
- package/dist/components/empty-state.js +113 -0
- package/dist/components/error-state.d.ts +38 -0
- package/dist/components/error-state.d.ts.map +1 -0
- package/dist/components/error-state.js +16 -0
- package/dist/components/file-upload.d.ts +34 -0
- package/dist/components/file-upload.d.ts.map +1 -0
- package/dist/components/file-upload.js +34 -0
- package/dist/components/gauge.d.ts +47 -0
- package/dist/components/gauge.d.ts.map +1 -0
- package/dist/components/gauge.js +65 -0
- package/dist/components/icon.d.ts +32 -0
- package/dist/components/icon.d.ts.map +1 -0
- package/dist/components/icon.js +20 -0
- package/dist/components/icons.d.ts +19 -0
- package/dist/components/icons.d.ts.map +1 -0
- package/dist/components/icons.js +39 -0
- package/dist/components/input.d.ts +35 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +41 -0
- package/dist/components/layout.d.ts +133 -0
- package/dist/components/layout.d.ts.map +1 -0
- package/dist/components/layout.js +132 -0
- package/dist/components/link.d.ts +22 -0
- package/dist/components/link.d.ts.map +1 -0
- package/dist/components/link.js +2 -0
- package/dist/components/live-scope.d.ts +15 -0
- package/dist/components/live-scope.d.ts.map +1 -0
- package/dist/components/live-scope.js +67 -0
- package/dist/components/log-view.d.ts +34 -0
- package/dist/components/log-view.d.ts.map +1 -0
- package/dist/components/log-view.js +30 -0
- package/dist/components/number-input.d.ts +26 -0
- package/dist/components/number-input.d.ts.map +1 -0
- package/dist/components/number-input.js +57 -0
- package/dist/components/overlay.d.ts +257 -0
- package/dist/components/overlay.d.ts.map +1 -0
- package/dist/components/overlay.js +276 -0
- package/dist/components/pagination.d.ts +38 -0
- package/dist/components/pagination.d.ts.map +1 -0
- package/dist/components/pagination.js +46 -0
- package/dist/components/pie.d.ts +40 -0
- package/dist/components/pie.d.ts.map +1 -0
- package/dist/components/pie.js +74 -0
- package/dist/components/primitives.d.ts +96 -0
- package/dist/components/primitives.d.ts.map +1 -0
- package/dist/components/primitives.js +81 -0
- package/dist/components/progress.d.ts +29 -0
- package/dist/components/progress.d.ts.map +1 -0
- package/dist/components/progress.js +16 -0
- package/dist/components/radio-group.d.ts +17 -0
- package/dist/components/radio-group.d.ts.map +1 -0
- package/dist/components/radio-group.js +23 -0
- package/dist/components/rail-link.d.ts +24 -0
- package/dist/components/rail-link.d.ts.map +1 -0
- package/dist/components/rail-link.js +24 -0
- package/dist/components/rich-text.d.ts +51 -0
- package/dist/components/rich-text.d.ts.map +1 -0
- package/dist/components/rich-text.js +147 -0
- package/dist/components/section.d.ts +15 -0
- package/dist/components/section.d.ts.map +1 -0
- package/dist/components/section.js +8 -0
- package/dist/components/segmented.d.ts +13 -0
- package/dist/components/segmented.d.ts.map +1 -0
- package/dist/components/segmented.js +12 -0
- package/dist/components/skeleton.d.ts +69 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton.js +67 -0
- package/dist/components/slider.d.ts +18 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/slider.js +15 -0
- package/dist/components/sparkline.d.ts +17 -0
- package/dist/components/sparkline.d.ts.map +1 -0
- package/dist/components/sparkline.js +19 -0
- package/dist/components/spinner.d.ts +15 -0
- package/dist/components/spinner.d.ts.map +1 -0
- package/dist/components/spinner.js +22 -0
- package/dist/components/stacked-bar.d.ts +21 -0
- package/dist/components/stacked-bar.d.ts.map +1 -0
- package/dist/components/stacked-bar.js +41 -0
- package/dist/components/surface.d.ts +76 -0
- package/dist/components/surface.d.ts.map +1 -0
- package/dist/components/surface.js +49 -0
- package/dist/components/switch.d.ts +12 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/switch.js +13 -0
- package/dist/components/tabs.d.ts +47 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +12 -0
- package/dist/components/timeline-strip.d.ts +19 -0
- package/dist/components/timeline-strip.d.ts.map +1 -0
- package/dist/components/timeline-strip.js +14 -0
- package/dist/components/tone.d.ts +58 -0
- package/dist/components/tone.d.ts.map +1 -0
- package/dist/components/tone.js +70 -0
- package/dist/components/tree-select.d.ts +26 -0
- package/dist/components/tree-select.d.ts.map +1 -0
- package/dist/components/tree-select.js +59 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/kit.css +2248 -0
- package/dist/lib/cn.d.ts +10 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +12 -0
- package/dist/lib/color.d.ts +68 -0
- package/dist/lib/color.d.ts.map +1 -0
- package/dist/lib/color.js +134 -0
- package/dist/lib/palette.d.ts +84 -0
- package/dist/lib/palette.d.ts.map +1 -0
- package/dist/lib/palette.js +193 -0
- package/dist/lib/scroll-lock.d.ts +19 -0
- package/dist/lib/scroll-lock.d.ts.map +1 -0
- package/dist/lib/scroll-lock.js +33 -0
- package/dist/patterns/app-shell.d.ts +36 -0
- package/dist/patterns/app-shell.d.ts.map +1 -0
- package/dist/patterns/app-shell.js +14 -0
- package/dist/patterns/auth-template.d.ts +36 -0
- package/dist/patterns/auth-template.d.ts.map +1 -0
- package/dist/patterns/auth-template.js +40 -0
- package/dist/patterns/detail-template.d.ts +52 -0
- package/dist/patterns/detail-template.d.ts.map +1 -0
- package/dist/patterns/detail-template.js +11 -0
- package/dist/patterns/index.d.ts +18 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +17 -0
- package/dist/patterns/list-template.d.ts +32 -0
- package/dist/patterns/list-template.d.ts.map +1 -0
- package/dist/patterns/list-template.js +8 -0
- package/dist/patterns/overview-template.d.ts +26 -0
- package/dist/patterns/overview-template.d.ts.map +1 -0
- package/dist/patterns/overview-template.js +8 -0
- package/dist/patterns/public-template.d.ts +28 -0
- package/dist/patterns/public-template.d.ts.map +1 -0
- package/dist/patterns/public-template.js +7 -0
- package/dist/patterns/settings-template.d.ts +50 -0
- package/dist/patterns/settings-template.d.ts.map +1 -0
- package/dist/patterns/settings-template.js +33 -0
- package/dist/patterns/shared.d.ts +40 -0
- package/dist/patterns/shared.d.ts.map +1 -0
- package/dist/patterns/shared.js +29 -0
- package/dist/patterns/wizard-template.d.ts +28 -0
- package/dist/patterns/wizard-template.d.ts.map +1 -0
- package/dist/patterns/wizard-template.js +15 -0
- package/dist/styles.css +5 -0
- package/dist/theme.css +812 -0
- package/package.json +87 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mantıksal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# tamga-ui
|
|
2
|
+
|
|
3
|
+
Mantıksal'ın ortak arayüz kütüphanesi: token'lar, fizik ve bileşenler.
|
|
4
|
+
|
|
5
|
+
Framework değil **kütüphane** — ekranları sen kurarsın, kit parçaları verir. Kit hiçbir ürünün
|
|
6
|
+
adını, sözlüğünü ya da kimliğini bilmez.
|
|
7
|
+
|
|
8
|
+
- **Bileşenler** `tamga-ui`
|
|
9
|
+
- **İkonlar** `tamga-ui/icons`
|
|
10
|
+
- **Bloklar** `tamga-ui/blocks` — bir bileşenden büyük, bir ekrandan küçük
|
|
11
|
+
- **Şablonlar** `tamga-ui/patterns` — ekranların şekli (liste, detay, ayar, oturum, kabuk)
|
|
12
|
+
|
|
13
|
+
Doküman sitesi: depoyu klonlayıp `pnpm install && pnpm --filter tamga-docs dev` (port **6070**).
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Kurulum
|
|
18
|
+
|
|
19
|
+
### Henüz npm'de değil
|
|
20
|
+
|
|
21
|
+
Paket yayınlanmadı. Bugün üç yol var, üçü de çalışıyor:
|
|
22
|
+
|
|
23
|
+
**1 · Tarball (en temiz).** Kit deposunda:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm install
|
|
27
|
+
pnpm --filter tamga-ui pack # tamga-ui-0.1.0.tgz üretir
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Kendi projende:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install ../tamga/packages/ui/tamga-ui-0.1.0.tgz
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**2 · Yerel yol.** Aynı makinede duruyorsa:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install file:../tamga/packages/ui
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> **Dikkat:** `file:` bir SEMBOLİK BAĞ kuruyor, ve Tailwind v4 `@source` taramasını sembolik
|
|
43
|
+
> bağın ardına götürmüyor. Sonuç sinsi: tipler çözülür, importlar çalışır, ama utility sınıfları
|
|
44
|
+
> üretilmediği için bileşenler yarı çıplak çıkar. Geliştirirken hızlı, teslim ederken tarball.
|
|
45
|
+
|
|
46
|
+
**3 · Git.** npm bir monorepo'nun alt klasörünü doğrudan kuramıyor, o yüzden depoyu klonlayıp
|
|
47
|
+
1 ya da 2'yi kullan.
|
|
48
|
+
|
|
49
|
+
Üçünde de `prepare` betiği `dist/`i kurulum anında üretiyor; ayrıca bir build adımı gerekmiyor.
|
|
50
|
+
|
|
51
|
+
### Gerekenler
|
|
52
|
+
|
|
53
|
+
| | |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| React | **19** (peer dependency) |
|
|
56
|
+
| Tailwind | **v4** |
|
|
57
|
+
| Node | 20+ |
|
|
58
|
+
|
|
59
|
+
Tailwind v4 bir tercih değil şart: bileşenler utility sınıfı kullanıyor ve o sınıfları **senin**
|
|
60
|
+
build'in üretiyor.
|
|
61
|
+
|
|
62
|
+
### CSS
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
@import "tailwindcss";
|
|
66
|
+
@import "tamga-ui/styles.css";
|
|
67
|
+
|
|
68
|
+
@source "../../node_modules/tamga-ui/dist";
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**`@source` satırını atlama.** Onsuz Tailwind kitin `dist/`i içindeki sınıfları taramaz, üretmez,
|
|
72
|
+
ve bileşenler **stilsiz** çıkar. Yol senin CSS dosyandan `node_modules`a göre; derinliğe göre
|
|
73
|
+
`../` sayısı değişir.
|
|
74
|
+
|
|
75
|
+
### Kullanım
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { Button, StatusChip } from "tamga-ui";
|
|
79
|
+
import { Plus } from "tamga-ui/icons";
|
|
80
|
+
|
|
81
|
+
<Button variant="primary">
|
|
82
|
+
<Icon icon={Plus} size="xs" />
|
|
83
|
+
Yeni kayıt
|
|
84
|
+
</Button>;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Kurulum anketi
|
|
90
|
+
|
|
91
|
+
**Bu bölüm kiti kuran kişi ya da ajan içindir.** Kit kurulduğunda proje çalışır ama KİMSESİZDİR:
|
|
92
|
+
mavi bir vurgu, baş harften bir karo, adsız bir kullanıcı. Aşağıdaki yedi sorunun cevabı
|
|
93
|
+
alınmadan kurulum bitmiş sayılmaz.
|
|
94
|
+
|
|
95
|
+
Her satırın son sütunu önemli: **cevap bir kere sorulup koda gömülmez, bir ayar ekranına da
|
|
96
|
+
konur.** Kurulumda sorulan her şey projenin üçüncü ayında da değiştirilebilir olmalı; yoksa
|
|
97
|
+
müşteri rengini değiştirmek istediğinde tek yol bir geliştiricinin CSS yazıp yeniden yayın
|
|
98
|
+
alması olur.
|
|
99
|
+
|
|
100
|
+
| # | Sorulacak | Nereye gider | Ayar ekranında |
|
|
101
|
+
| --- | --- | --- | --- |
|
|
102
|
+
| 1 | Ürünün adı | Kabuk, sekme başlığı, oturum ekranı | hayır, ürünün kimliği |
|
|
103
|
+
| 2 | **Marka rengi (tek hex)** | `paletUret()` → token'lar (aşağıda) | **evet** |
|
|
104
|
+
| 3 | Logo (geniş, yatay) | Oturum ekranı, geniş kenar çubuğu | **evet** |
|
|
105
|
+
| 4 | Amblem (kare) | Dar kenar çubuğu, sekme ikonu | **evet** |
|
|
106
|
+
| 5 | Varsayılan tema | `açık` · `koyu` · `sistem` | **evet** |
|
|
107
|
+
| 6 | Kenar çubuğu davranışı | `hep dar` · `hep geniş` · `kullanıcı seçsin` | **evet** |
|
|
108
|
+
| 7 | Arayüz dili / dilleri | Bütün `labels` prop'ları | duruma göre |
|
|
109
|
+
|
|
110
|
+
**2, 3 ve 4 birbirinden bağımsız sorulur.** Yüklenen bir logodan amblem OTOMATİK çıkarılamaz:
|
|
111
|
+
bir görsel dosyasında "amblem" diye işaretli bir şey yoktur, konumu sabit değildir (solda, üstte,
|
|
112
|
+
yazının içinde ya da hiç yok), ve yanlış kesim sessizdir. Yarım bir harf panelin her sayfasının
|
|
113
|
+
sol üstünde durur ve kimse bunun otomatik kesildiğini bilmez. Amblemi ya ayrı bir dosya olarak
|
|
114
|
+
iste, ya kullanıcıya logo üzerinde kare bir alan seçtir, ya da hiç isteme: amblem yoksa
|
|
115
|
+
`LogoTile` baş harften bir karo üretir ve bu çalışan bir cevaptır.
|
|
116
|
+
|
|
117
|
+
Sorulacakların ekranı `SettingsTemplate` ile kuruluyor; adım adım anlatımı doküman sitesinde
|
|
118
|
+
`/docs/yeni-panel` sayfasında.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Renkleri değiştirmek
|
|
123
|
+
|
|
124
|
+
Bir bileşen hiçbir yerde sabit renk taşımıyor; hepsi token okuyor.
|
|
125
|
+
|
|
126
|
+
### Tek hex'ten bütün palet
|
|
127
|
+
|
|
128
|
+
`tamga-ui/palette` bir marka renginden iki temanın tamamını üretiyor. Elle üç token yazmaktan
|
|
129
|
+
daha güvenli, çünkü üreteç kontrastı ARAYARAK buluyor: yüzün açıklığını, üstündeki mürekkebin
|
|
130
|
+
AA eşiğini geçene kadar adım adım kaydırıyor. Kırk ton ve iki tema, bir kapının sürekli ölçtüğü
|
|
131
|
+
880 ölçüm.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { paletUret, paletCss } from "tamga-ui/palette";
|
|
135
|
+
|
|
136
|
+
const cift = paletUret("#e02938"); // { light, dark }
|
|
137
|
+
document.documentElement.setAttribute("style", paletCss(cift));
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Renk çalışma zamanında değişebiliyorsa (ayar ekranı) yol budur: token'lar kök elemana yazılıyor
|
|
141
|
+
ve kitin 87 sınıfı onları okuduğu için bütün panel tek satırda dönüyor, hiçbir CSS yeniden
|
|
142
|
+
derlenmeden.
|
|
143
|
+
|
|
144
|
+
### Ya da elle
|
|
145
|
+
|
|
146
|
+
Rengin sabit olduğu ve derleme zamanında bilindiği projelerde token'ları doğrudan geçersiz
|
|
147
|
+
kılabilirsin:
|
|
148
|
+
|
|
149
|
+
```css
|
|
150
|
+
@import "tamga-ui/styles.css";
|
|
151
|
+
|
|
152
|
+
:root {
|
|
153
|
+
--color-accent: #2069c9; /* birincil yüz */
|
|
154
|
+
--color-accent-shadow: #12245c; /* yüzün altındaki taban */
|
|
155
|
+
--color-accent-ink: #fdfcfa; /* yüzün üstündeki mürekkep */
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Bu yolda kontrastı kendin doğrulamak zorundasın: üreteç yok, kapı yok.
|
|
160
|
+
|
|
161
|
+
Bu yüzden **kendi bileşenlerinde de sabit renk yazma**: `text-ink`, `bg-shell`,
|
|
162
|
+
`var(--color-critical)` yaz. Palet değiştiğinde ekranların onunla birlikte döner; sabit yazılmış
|
|
163
|
+
her renk elle bulunup düzeltilir.
|
|
164
|
+
|
|
165
|
+
Token'ların tamamı doküman sitesinde (`/docs/tokens`), temayı değiştirmenin adımları
|
|
166
|
+
`/docs/tema` sayfasında.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Lisans
|
|
171
|
+
|
|
172
|
+
MIT — [LICENSE](./LICENSE)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* SAYAÇ SATIRI: tablonun tepesindeki tek satırlık okuma.
|
|
4
|
+
*
|
|
5
|
+
* KAÇ KAYIT OLDUĞU HER ZAMAN YAZIYOR. Filtre uygulandıktan sonra kaç kayda
|
|
6
|
+
* bakıldığını söylemeyen bir liste, kullanıcıya saydırıyor.
|
|
7
|
+
*
|
|
8
|
+
* SAĞ TARAF İKİ ŞEY TAŞIYABİLİR ve ikisi de isteğe bağlı: ekrana özel ikinci
|
|
9
|
+
* bir okuma (`aside` — "12 tanesi eşiği geçti" gibi) ve sayfa boyu seçimi.
|
|
10
|
+
* İkincisi verilmezse hiç çizilmiyor: sayfalanmayan bir listeye sayfa boyu
|
|
11
|
+
* sormak, olmayan bir kontrolü öğretmek.
|
|
12
|
+
*/
|
|
13
|
+
export declare function CountRow({ count, unit, aside, pageSize, pageSizeOptions, onPageSize, labels, }: {
|
|
14
|
+
count: number;
|
|
15
|
+
/** "sipariş", "müşteri": sayının yanında ne yazacağı. */
|
|
16
|
+
unit: string;
|
|
17
|
+
/** Ekrana özel ikinci okuma. */
|
|
18
|
+
aside?: ReactNode;
|
|
19
|
+
pageSize?: number;
|
|
20
|
+
pageSizeOptions?: number[];
|
|
21
|
+
onPageSize?: (n: number) => void;
|
|
22
|
+
/** Sayının biçimi çağıranın: binlik ayıracı dile bağlı. */
|
|
23
|
+
labels?: {
|
|
24
|
+
format?: (n: number) => string;
|
|
25
|
+
perPage?: string;
|
|
26
|
+
records?: string;
|
|
27
|
+
};
|
|
28
|
+
}): import("react").JSX.Element;
|
|
29
|
+
//# sourceMappingURL=count-row.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"count-row.d.ts","sourceRoot":"","sources":["../../src/blocks/count-row.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,eAAe,EACf,UAAU,EACV,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,2DAA2D;IAC3D,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjF,+BA0BA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Label } from "../components/surface.js";
|
|
4
|
+
import { Select } from "../components/primitives.js";
|
|
5
|
+
/**
|
|
6
|
+
* SAYAÇ SATIRI: tablonun tepesindeki tek satırlık okuma.
|
|
7
|
+
*
|
|
8
|
+
* KAÇ KAYIT OLDUĞU HER ZAMAN YAZIYOR. Filtre uygulandıktan sonra kaç kayda
|
|
9
|
+
* bakıldığını söylemeyen bir liste, kullanıcıya saydırıyor.
|
|
10
|
+
*
|
|
11
|
+
* SAĞ TARAF İKİ ŞEY TAŞIYABİLİR ve ikisi de isteğe bağlı: ekrana özel ikinci
|
|
12
|
+
* bir okuma (`aside` — "12 tanesi eşiği geçti" gibi) ve sayfa boyu seçimi.
|
|
13
|
+
* İkincisi verilmezse hiç çizilmiyor: sayfalanmayan bir listeye sayfa boyu
|
|
14
|
+
* sormak, olmayan bir kontrolü öğretmek.
|
|
15
|
+
*/
|
|
16
|
+
export function CountRow({ count, unit, aside, pageSize, pageSizeOptions, onPageSize, labels, }) {
|
|
17
|
+
const format = labels?.format ?? ((n) => String(n));
|
|
18
|
+
return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b border-[var(--color-line)] px-4 py-3", children: [_jsxs(Label, { children: [_jsx("strong", { className: "tabular-nums text-ink", children: format(count) }), " ", unit] }), aside, pageSizeOptions && onPageSize && pageSize !== undefined && (_jsxs("label", { className: "flex items-center gap-2 text-small text-ink-soft", children: [labels?.perPage, _jsx(Select, { className: "w-24", options: pageSizeOptions.map(String), value: String(pageSize), onChange: (v) => onPageSize(Number(v)), placeholder: String(pageSizeOptions[0]) }), labels?.records] }))] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* FİLTRE ÇUBUĞU.
|
|
4
|
+
*
|
|
5
|
+
* ─── NEDEN KİTTE ────────────────────────────────────────────────────────
|
|
6
|
+
* Bir süre üründe durdu ve orada "kite taşınmadı, bilinçli" diye bir not
|
|
7
|
+
* vardı: gerekçesi "Excel ile ara" ve "Tüm filtreler" gibi şeylerin bir
|
|
8
|
+
* e-ticaret paneli kalıbı olması. Not yanlış çıktı ve iki sebeple:
|
|
9
|
+
*
|
|
10
|
+
* ① ADR-0003'ün katman şeması `tamga-ui` kutusunun içine zaten
|
|
11
|
+
* "filtre paneli · toplu eylem çubuğu" yazıyor. Bir satır içi yorum,
|
|
12
|
+
* kilitli bir ADR'yi geçersiz kılmaz.
|
|
13
|
+
* ② Notun işaret ettiği sözlük SÖZCÜKLERDİ, mekanizma değil. Metinler
|
|
14
|
+
* `labels`a çıkınca geriye kalan şey saf mekanizma: bir arama kutusu, en
|
|
15
|
+
* çok dört alan, bir çekmece, ve uygulanan filtrelerin çipleri. Dosyayla
|
|
16
|
+
* arama da bir alan adı değil bir yöntem; her yönetim listesi yapabilir.
|
|
17
|
+
*
|
|
18
|
+
* ─── ÜÇ MADDE, VE ÜÇÜNCÜSÜ EN ÖNEMLİSİ ──────────────────────────────────
|
|
19
|
+
* Bir yönetim panelinin filtresi otuz alanı aynı anda açık tutmaya meyleder,
|
|
20
|
+
* hepsi aynı görsel ağırlıkta. Buradaki fikir tek cümle: birkaçı üstte,
|
|
21
|
+
* gerisi çekmecede, VE çekmecede bir şey açıksa bunu görüyorsun.
|
|
22
|
+
*
|
|
23
|
+
* Gizli bir filtre açıkken kullanıcı listeyi eksik görür ve sebebini bulamaz;
|
|
24
|
+
* bu, filtreyi gizlemenin tek gerçek riski. O yüzden uygulanan her filtre
|
|
25
|
+
* tablonun üstünde bir çip olarak duruyor, tek tıkla kalkıyor, ve çekmece
|
|
26
|
+
* düğmesinde aktif sayıyı gösteren bir rozet var.
|
|
27
|
+
*
|
|
28
|
+
* ─── ENTER UYGULAR ──────────────────────────────────────────────────────
|
|
29
|
+
* Çekmecedeki alanlar bir `<form>` içinde ve "Uygula" o formun `submit`
|
|
30
|
+
* düğmesi, yani Enter tarayıcının kendi davranışıyla çalışıyor: dinlenen bir
|
|
31
|
+
* tuş değil, formun anlamı.
|
|
32
|
+
*/
|
|
33
|
+
/** Filtre durumunun tamamı: anahtar → dizgi. Boş dizgi "filtre yok" demek. */
|
|
34
|
+
export type FilterValues = Record<string, string>;
|
|
35
|
+
export type FilterFieldKind = "text" | "select"
|
|
36
|
+
/** Aranabilir seçim: seçenek sayısı göz gezdirmenin ötesine geçtiğinde. */
|
|
37
|
+
| "searchable"
|
|
38
|
+
/**
|
|
39
|
+
* ÇOKLU seçim, çip olarak. Tek seçimden farkı bir kolaylık değil bir ANLAM:
|
|
40
|
+
* "Nike VEYA Adidas" ile "Nike" aynı soru değil.
|
|
41
|
+
*/
|
|
42
|
+
| "multi"
|
|
43
|
+
/** İKİ TARİH: başlangıç ve bitiş. Tek bir kutu bir aralık soramaz. */
|
|
44
|
+
| "dateRange";
|
|
45
|
+
export type FilterField = {
|
|
46
|
+
key: string;
|
|
47
|
+
label: string;
|
|
48
|
+
kind: FilterFieldKind;
|
|
49
|
+
/** Verilmezse `optionSource[key]` kullanılır; ikisi de yoksa liste boş. */
|
|
50
|
+
options?: string[];
|
|
51
|
+
};
|
|
52
|
+
export type FilterGroup = {
|
|
53
|
+
title: string;
|
|
54
|
+
fields: FilterField[];
|
|
55
|
+
};
|
|
56
|
+
export declare const rangeStart: (key: string) => string;
|
|
57
|
+
export declare const rangeEnd: (key: string) => string;
|
|
58
|
+
export type FilterBarLabels = {
|
|
59
|
+
/** Arama kutusunun yer tutucusu. */
|
|
60
|
+
search: string;
|
|
61
|
+
/**
|
|
62
|
+
* "Hepsi" seçeneğinin adı, ve LİSTENİN İÇİNDE bir seçenek olarak duruyor.
|
|
63
|
+
*
|
|
64
|
+
* Kullanıcı bir değer seçtikten sonra tekrar hepsini görmek istediğinde,
|
|
65
|
+
* geri dönüş yolunun GİDİŞ YOLUYLA AYNI YERDE olması gerekiyor. Kontrolün
|
|
66
|
+
* yanına bir çarpı koymak her filtreye ikinci bir düğme ekler ve ancak seçim
|
|
67
|
+
* varken görünür, yani kullanıcı onu aramayı öğrenemez.
|
|
68
|
+
*/
|
|
69
|
+
all: string;
|
|
70
|
+
allFilters: string;
|
|
71
|
+
clearAll: string;
|
|
72
|
+
clear: string;
|
|
73
|
+
apply: string;
|
|
74
|
+
noMatch: string;
|
|
75
|
+
/** "<alan> seç" gibi; kontrolü açan düğmenin erişilebilir adı. */
|
|
76
|
+
open: (label: string) => string;
|
|
77
|
+
/** "<filtre> filtresini kaldır". */
|
|
78
|
+
remove: (label: string) => string;
|
|
79
|
+
rangeStart: string;
|
|
80
|
+
rangeEnd: string;
|
|
81
|
+
calendar: {
|
|
82
|
+
previousMonth: string;
|
|
83
|
+
nextMonth: string;
|
|
84
|
+
open: string;
|
|
85
|
+
clear: string;
|
|
86
|
+
};
|
|
87
|
+
/** Dosyayla arama bölümü; `fileSearchKey` verilmezse hiç çizilmiyor. */
|
|
88
|
+
fileSearch?: {
|
|
89
|
+
title: string;
|
|
90
|
+
help: ReactNode;
|
|
91
|
+
choose: string;
|
|
92
|
+
remove: string;
|
|
93
|
+
label: string;
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
export type FilterBarProps = {
|
|
97
|
+
values: FilterValues;
|
|
98
|
+
onChange: (next: FilterValues) => void;
|
|
99
|
+
/** Üstte duran alanlar. En çok dört tane; gerisi çekmeceye. */
|
|
100
|
+
top: readonly FilterField[];
|
|
101
|
+
/** Çekmecedeki gruplar. Düz bir yığın değil, gruplu. */
|
|
102
|
+
drawer: readonly FilterGroup[];
|
|
103
|
+
/** Seçim listelerinin kaynağı; sunucudan gelecek. */
|
|
104
|
+
optionSource?: Record<string, string[]>;
|
|
105
|
+
/**
|
|
106
|
+
* ARAMA KUTUSUNUN YAZDIĞI ANAHTAR.
|
|
107
|
+
*
|
|
108
|
+
* Prop, çünkü sunucunun beklediği ad ürünün kararı: kimi `q` diyor, kimi
|
|
109
|
+
* `ara`, kimi `search`. Blok bir süre `q`yu sabitledi ve ilk tüketicide
|
|
110
|
+
* sessizce kırdı: kutuya yazılan şey `q`ya gidiyor, ekran `ara`yı okuyor,
|
|
111
|
+
* ve arama hiçbir şey yapmıyordu. Hata vermeyen bir kırılma en pahalısı.
|
|
112
|
+
*/
|
|
113
|
+
searchKey?: string;
|
|
114
|
+
/** Dosyayla arama bu ekranda varsa anahtarı; yoksa bölüm hiç çizilmiyor. */
|
|
115
|
+
fileSearchKey?: string;
|
|
116
|
+
/** Filtre satırına, "Tüm filtreler"in yanına giren ekrana özel düğme. */
|
|
117
|
+
extra?: ReactNode;
|
|
118
|
+
/** `DatePicker`ın takvimi için: "tr-TR", "en-GB". */
|
|
119
|
+
locale?: string;
|
|
120
|
+
labels: FilterBarLabels;
|
|
121
|
+
};
|
|
122
|
+
export declare function FilterBar({ values, onChange, top, drawer, optionSource, searchKey, fileSearchKey, extra, locale, labels, }: FilterBarProps): import("react").JSX.Element;
|
|
123
|
+
//# sourceMappingURL=filter-bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-bar.d.ts","sourceRoot":"","sources":["../../src/blocks/filter-bar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAWxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,QAAQ;AACV,2EAA2E;GACzE,YAAY;AACd;;;GAGG;GACD,OAAO;AACT,sEAAsE;GACpE,WAAW,CAAC;AAEhB,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;IACtB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE,CAAC;AAInE,eAAO,MAAM,UAAU,QAAS,MAAM,WAAkB,CAAC;AACzD,eAAO,MAAM,QAAQ,QAAS,MAAM,WAAgB,CAAC;AAErD,MAAM,MAAM,eAAe,GAAG;IAC5B,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,oCAAoC;IACpC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACpF,wEAAwE;IACxE,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAChG,CAAC;AA+FF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,+DAA+D;IAC/D,GAAG,EAAE,SAAS,WAAW,EAAE,CAAC;IAC5B,wDAAwD;IACxD,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,MAAM,EACN,QAAQ,EACR,GAAG,EACH,MAAM,EACN,YAAiB,EACjB,SAAe,EACf,aAAa,EACb,KAAK,EACL,MAAgB,EAChB,MAAM,GACP,EAAE,cAAc,+BA8MhB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId, useState } from "react";
|
|
4
|
+
import { Button, buttonVariants } from "../components/button.js";
|
|
5
|
+
import { MiniButton } from "../components/button.js";
|
|
6
|
+
import { Combobox } from "../components/combobox.js";
|
|
7
|
+
import { MultiSelect } from "../components/advanced-input.js";
|
|
8
|
+
import { DatePicker } from "../components/date-picker.js";
|
|
9
|
+
import { Icon } from "../components/icon.js";
|
|
10
|
+
import { Close, Customize, Search, Upload } from "../components/icons.js";
|
|
11
|
+
import { Input } from "../components/input.js";
|
|
12
|
+
import { Select, Sheet } from "../components/primitives.js";
|
|
13
|
+
/* Tarih aralığı İKİ ANAHTAR tutuyor. Tek bir dizgeye sıkıştırmak, sunucuya iki
|
|
14
|
+
ayrı parametre giderken burada tekrar ayrıştırmak demekti. */
|
|
15
|
+
export const rangeStart = (key) => `${key}Start`;
|
|
16
|
+
export const rangeEnd = (key) => `${key}End`;
|
|
17
|
+
function FieldControl({ field, values, write, optionSource, locale, labels, }) {
|
|
18
|
+
const options = field.options?.length ? field.options : (optionSource[field.key] ?? []);
|
|
19
|
+
if (field.kind === "dateRange") {
|
|
20
|
+
return (_jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [_jsx(DatePicker, { locale: locale, value: values[rangeStart(field.key)] || undefined, onChange: (v) => write(rangeStart(field.key), v ?? ""), placeholder: labels.rangeStart, labels: labels.calendar }), _jsx(DatePicker, { locale: locale, value: values[rangeEnd(field.key)] || undefined, onChange: (v) => write(rangeEnd(field.key), v ?? ""), placeholder: labels.rangeEnd, labels: labels.calendar })] }));
|
|
21
|
+
}
|
|
22
|
+
if (field.kind === "multi") {
|
|
23
|
+
/* Değerler virgülle tek bir dizgede: filtre durumunun tamamı
|
|
24
|
+
`Record<string,string>` ve bir alanın tipi yüzünden o sözleşmeyi
|
|
25
|
+
değiştirmek, her ekranı ilgilendirirdi. */
|
|
26
|
+
const selected = (values[field.key] ?? "").split(",").filter(Boolean);
|
|
27
|
+
return (_jsx(MultiSelect, { className: "w-full", options: options.map((o) => ({ value: o, label: o })), value: selected, onChange: (next) => write(field.key, next.join(",")), placeholder: labels.all, labels: {
|
|
28
|
+
empty: labels.noMatch,
|
|
29
|
+
remove: labels.remove,
|
|
30
|
+
open: labels.open(field.label),
|
|
31
|
+
} }));
|
|
32
|
+
}
|
|
33
|
+
if (field.kind === "searchable") {
|
|
34
|
+
return (_jsx(Combobox, { className: "w-full", options: options.map((o) => ({ value: o, label: o })), value: values[field.key] || undefined, onChange: (v) => write(field.key, v ?? ""), placeholder: labels.all, labels: { empty: labels.noMatch, clear: labels.clear, open: labels.open(field.label) } }));
|
|
35
|
+
}
|
|
36
|
+
if (field.kind === "select") {
|
|
37
|
+
return (_jsx(Select, { className: "w-full", options: [labels.all, ...options], value: values[field.key], onChange: (v) => write(field.key, v === labels.all ? "" : v), placeholder: labels.all }));
|
|
38
|
+
}
|
|
39
|
+
return (_jsx(Input, { full: true, value: values[field.key] ?? "", onChange: (e) => write(field.key, e.target.value) }));
|
|
40
|
+
}
|
|
41
|
+
export function FilterBar({ values, onChange, top, drawer, optionSource = {}, searchKey = "q", fileSearchKey, extra, locale = "en-GB", labels, }) {
|
|
42
|
+
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
43
|
+
const formId = useId();
|
|
44
|
+
const active = Object.entries(values).filter(([, v]) => v);
|
|
45
|
+
const drawerKeys = new Set(drawer.flatMap((g) => g.fields.map((f) => f.key)));
|
|
46
|
+
const hiddenActive = active.filter(([k]) => drawerKeys.has(k)).length;
|
|
47
|
+
function write(key, value) {
|
|
48
|
+
const next = { ...values };
|
|
49
|
+
if (value)
|
|
50
|
+
next[key] = value;
|
|
51
|
+
else
|
|
52
|
+
delete next[key];
|
|
53
|
+
onChange(next);
|
|
54
|
+
}
|
|
55
|
+
const allFields = [...top, ...drawer.flatMap((g) => g.fields)];
|
|
56
|
+
/* Aralık anahtarları (`dateStart`) alan listesinde YOK: adı, ait olduğu
|
|
57
|
+
alandan türetiliyor. Yoksa çipte ham anahtar görünüyordu. */
|
|
58
|
+
const labelFor = (key) => {
|
|
59
|
+
const direct = allFields.find((f) => f.key === key)?.label;
|
|
60
|
+
if (direct)
|
|
61
|
+
return direct;
|
|
62
|
+
const range = allFields.find((f) => f.kind === "dateRange" && (rangeStart(f.key) === key || rangeEnd(f.key) === key));
|
|
63
|
+
if (range) {
|
|
64
|
+
return `${range.label} ${rangeStart(range.key) === key ? labels.rangeStart : labels.rangeEnd}`;
|
|
65
|
+
}
|
|
66
|
+
if (key === searchKey)
|
|
67
|
+
return labels.search;
|
|
68
|
+
return key === fileSearchKey ? (labels.fileSearch?.label ?? key) : key;
|
|
69
|
+
};
|
|
70
|
+
return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "grid items-end gap-3 grid-cols-1 md:grid-cols-2 xl:grid-cols-[minmax(10rem,1fr)_repeat(4,minmax(0,1.25fr))_auto]", children: [_jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [_jsx("span", { className: "text-small font-medium text-ink", children: labels.search }), _jsxs("span", { className: "relative flex items-center", children: [_jsx(Icon, { icon: Search, size: "xs", "aria-hidden": true, className: "pointer-events-none absolute left-2.5 text-ink-faint" }), _jsx(Input, { type: "search", full: true, leading: true, placeholder: labels.search, value: values[searchKey] ?? "", onChange: (e) => write(searchKey, e.target.value) })] })] }), top.map((field) => (_jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [_jsx("span", { className: "text-small font-medium text-ink", children: field.label }), _jsx(FieldControl, { field: field, values: values, write: write, optionSource: optionSource, locale: locale, labels: labels })] }, field.key))), _jsxs(Button, { onClick: () => setDrawerOpen(true), children: [_jsx(Icon, { icon: Customize, size: "xs" }), labels.allFilters, hiddenActive > 0 && (_jsx("span", { className: "ml-1 rounded-full bg-[var(--color-accent)] px-1.5 text-micro font-semibold text-[var(--color-accent-ink)] tabular-nums", children: hiddenActive }))] }), extra] }), active.length > 0 && (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [active.map(([key, value]) => (_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-(--radius-ctl) border border-[var(--color-edge)] bg-shell py-1 pl-2.5 pr-1 text-small text-ink", children: [_jsxs("span", { className: "text-ink-faint", children: [labelFor(key), ":"] }), value, _jsx(MiniButton, { "aria-label": labels.remove(labelFor(key)), onClick: () => write(key, ""), children: _jsx(Icon, { icon: Close, size: "xs" }) })] }, key))), _jsx(Button, { variant: "link", size: "sm", onClick: () => onChange({}), children: labels.clearAll })] })), _jsx(Sheet, { open: drawerOpen, onClose: () => setDrawerOpen(false), title: labels.allFilters, closeLabel: labels.calendar.clear, footer: _jsxs(_Fragment, { children: [_jsx(Button, { type: "button", onClick: () => onChange({}), children: labels.clear }), _jsx(Button, { type: "submit", form: formId, variant: "primary", children: labels.apply })] }), children: _jsxs("form", { id: formId, onSubmit: (e) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
setDrawerOpen(false);
|
|
73
|
+
}, className: "flex flex-col gap-7", children: [drawer.map((group) => (_jsxs("div", { children: [_jsx("p", { className: "mb-3 text-micro font-semibold uppercase tracking-wide text-ink-faint", children: group.title }), _jsx("div", { className: "grid gap-3 sm:grid-cols-[repeat(2,minmax(0,1fr))]", children: group.fields.map((field) => (_jsxs("div", { className: `flex flex-col gap-1.5 ${field.kind === "dateRange" ? "sm:col-span-2" : ""}`, children: [_jsx("span", { className: "text-small text-ink-soft", children: field.label }), _jsx(FieldControl, { field: field, values: values, write: write, optionSource: optionSource, locale: locale, labels: labels })] }, field.key))) })] }, group.title))), fileSearchKey && labels.fileSearch && (_jsxs("div", { children: [_jsx("p", { className: "mb-3 text-micro font-semibold uppercase tracking-wide text-ink-faint", children: labels.fileSearch.title }), _jsx("p", { className: "mb-3 text-small leading-relaxed text-ink-soft", children: labels.fileSearch.help }), values[fileSearchKey] ? (_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "truncate text-small text-ink", children: values[fileSearchKey] }), _jsx(Button, { type: "button", size: "sm", onClick: () => write(fileSearchKey, ""), children: labels.fileSearch.remove })] })) : (_jsxs("label", { className: `${buttonVariants({})} cursor-pointer`, children: [_jsx(Icon, { icon: Upload, size: "xs" }), labels.fileSearch.choose, _jsx("input", { type: "file", accept: ".xlsx,.xls,.csv", className: "sr-only", onChange: (e) => write(fileSearchKey, e.target.files?.[0]?.name ?? "") })] }))] }))] }) })] }));
|
|
74
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLOK KATMANI — `tamga-ui/blocks`.
|
|
3
|
+
*
|
|
4
|
+
* BİR BLOK NEDİR. Bir bileşenden büyük, bir şablondan küçük: birkaç bileşenin
|
|
5
|
+
* bir araya gelip TEK BİR İŞ yaptığı bölüm. Filtre çubuğu bir düğme değil ama
|
|
6
|
+
* bir ekran da değil; bir ekranın içindeki bir bölge.
|
|
7
|
+
*
|
|
8
|
+
* ADR-0003'ün katman şeması "filtre paneli · toplu eylem çubuğu" diye ikisini
|
|
9
|
+
* de `tamga-ui` kutusunun içine yazıyor. Toplu eylem çubuğu ZATEN VARDI:
|
|
10
|
+
* `SelectionBar`, bir bileşen olarak, kendi doküman sayfasıyla. Buraya bir
|
|
11
|
+
* `BulkBar` yazıldı ve aynı propları alan ikinci bir kopyaydı; silindi.
|
|
12
|
+
*
|
|
13
|
+
* DERS BU DOSYANIN BAŞINDA DURSUN: yeni bir blok yazmadan önce kitin o işi
|
|
14
|
+
* yapan bir bileşeni var mı diye bakılır. Bir tasarım sisteminin en sinsi
|
|
15
|
+
* hatası, aynı şeyin iki adla iki yerde durmasıdır.
|
|
16
|
+
*
|
|
17
|
+
* BURAYA NE GİRMEZ. Bir ürünün sözlüğünü taşıyan hiçbir şey. Bir sipariş
|
|
18
|
+
* kartı, bir iade satırı, bir mülk özeti: bunlar e-ticaret ya da izleme
|
|
19
|
+
* katmanının işi. Blok, alanı bilmeyen bölümdür.
|
|
20
|
+
*/
|
|
21
|
+
export { FilterBar, rangeStart, rangeEnd, type FilterBarLabels, type FilterBarProps, type FilterField, type FilterFieldKind, type FilterGroup, type FilterValues, } from "./filter-bar.js";
|
|
22
|
+
export { SaveBar } from "./save-bar.js";
|
|
23
|
+
export { CountRow } from "./count-row.js";
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blocks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLOK KATMANI — `tamga-ui/blocks`.
|
|
3
|
+
*
|
|
4
|
+
* BİR BLOK NEDİR. Bir bileşenden büyük, bir şablondan küçük: birkaç bileşenin
|
|
5
|
+
* bir araya gelip TEK BİR İŞ yaptığı bölüm. Filtre çubuğu bir düğme değil ama
|
|
6
|
+
* bir ekran da değil; bir ekranın içindeki bir bölge.
|
|
7
|
+
*
|
|
8
|
+
* ADR-0003'ün katman şeması "filtre paneli · toplu eylem çubuğu" diye ikisini
|
|
9
|
+
* de `tamga-ui` kutusunun içine yazıyor. Toplu eylem çubuğu ZATEN VARDI:
|
|
10
|
+
* `SelectionBar`, bir bileşen olarak, kendi doküman sayfasıyla. Buraya bir
|
|
11
|
+
* `BulkBar` yazıldı ve aynı propları alan ikinci bir kopyaydı; silindi.
|
|
12
|
+
*
|
|
13
|
+
* DERS BU DOSYANIN BAŞINDA DURSUN: yeni bir blok yazmadan önce kitin o işi
|
|
14
|
+
* yapan bir bileşeni var mı diye bakılır. Bir tasarım sisteminin en sinsi
|
|
15
|
+
* hatası, aynı şeyin iki adla iki yerde durmasıdır.
|
|
16
|
+
*
|
|
17
|
+
* BURAYA NE GİRMEZ. Bir ürünün sözlüğünü taşıyan hiçbir şey. Bir sipariş
|
|
18
|
+
* kartı, bir iade satırı, bir mülk özeti: bunlar e-ticaret ya da izleme
|
|
19
|
+
* katmanının işi. Blok, alanı bilmeyen bölümdür.
|
|
20
|
+
*/
|
|
21
|
+
export { FilterBar, rangeStart, rangeEnd, } from "./filter-bar.js";
|
|
22
|
+
export { SaveBar } from "./save-bar.js";
|
|
23
|
+
export { CountRow } from "./count-row.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* KAYDET ŞERİDİ: kayan yüzeyin dibine yapışık.
|
|
4
|
+
*
|
|
5
|
+
* NEDEN FORMUN SONUNDA DEĞİL. Eski panellerin alışkanlığı kaydet düğmesini
|
|
6
|
+
* formun en altına koymak; yirmi alanlık bir formda üstteki bir alanı
|
|
7
|
+
* düzeltip kaydetmek için sonuna kadar kaydırmak gerekiyor. Şerit her zaman
|
|
8
|
+
* görünür, ve kaydedilecek bir şey olup olmadığını da söylüyor.
|
|
9
|
+
*
|
|
10
|
+
* FİZİĞİ BİR SINIFTA (`.tamga-save-bar`), ve orada ölçülmüş bir tuzak yazılı:
|
|
11
|
+
* `sticky bottom-0` şeridin alt kenarını yüzeyin İÇERİK kutusuna hizalıyor,
|
|
12
|
+
* ama yüzeyin kendi alt dolgusu var ve içerik o boşluktan akıp geçiyordu.
|
|
13
|
+
*
|
|
14
|
+
* DEĞİŞİKLİK YOKSA KAYDEDİLECEK BİR ŞEY DE YOK: düğme kapalı. Tıklanıp
|
|
15
|
+
* hiçbir şey olmayan bir düğme, olmayan bir düğmeden kötüdür.
|
|
16
|
+
*/
|
|
17
|
+
export declare function SaveBar({ changed, busy, onCancel, extra, labels, }: {
|
|
18
|
+
/** Değişiklik yoksa kaydet kapalı. */
|
|
19
|
+
changed?: boolean;
|
|
20
|
+
/** Kaydetme sürüyor: iki düğme de kilitli, kaydet spinner gösteriyor. */
|
|
21
|
+
busy?: boolean;
|
|
22
|
+
onCancel?: () => void;
|
|
23
|
+
/** Şeridin sağında duran ekrana özel şey: bir sayaç, bir uyarı satırı. */
|
|
24
|
+
extra?: ReactNode;
|
|
25
|
+
labels: {
|
|
26
|
+
save: string;
|
|
27
|
+
cancel: string;
|
|
28
|
+
saving?: string;
|
|
29
|
+
};
|
|
30
|
+
}): import("react").JSX.Element;
|
|
31
|
+
//# sourceMappingURL=save-bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save-bar.d.ts","sourceRoot":"","sources":["../../src/blocks/save-bar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,EACtB,OAAc,EACd,IAAY,EACZ,QAAQ,EACR,KAAK,EACL,MAAM,GACP,EAAE;IACD,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3D,+BAkBA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from "../components/button.js";
|
|
4
|
+
/**
|
|
5
|
+
* KAYDET ŞERİDİ: kayan yüzeyin dibine yapışık.
|
|
6
|
+
*
|
|
7
|
+
* NEDEN FORMUN SONUNDA DEĞİL. Eski panellerin alışkanlığı kaydet düğmesini
|
|
8
|
+
* formun en altına koymak; yirmi alanlık bir formda üstteki bir alanı
|
|
9
|
+
* düzeltip kaydetmek için sonuna kadar kaydırmak gerekiyor. Şerit her zaman
|
|
10
|
+
* görünür, ve kaydedilecek bir şey olup olmadığını da söylüyor.
|
|
11
|
+
*
|
|
12
|
+
* FİZİĞİ BİR SINIFTA (`.tamga-save-bar`), ve orada ölçülmüş bir tuzak yazılı:
|
|
13
|
+
* `sticky bottom-0` şeridin alt kenarını yüzeyin İÇERİK kutusuna hizalıyor,
|
|
14
|
+
* ama yüzeyin kendi alt dolgusu var ve içerik o boşluktan akıp geçiyordu.
|
|
15
|
+
*
|
|
16
|
+
* DEĞİŞİKLİK YOKSA KAYDEDİLECEK BİR ŞEY DE YOK: düğme kapalı. Tıklanıp
|
|
17
|
+
* hiçbir şey olmayan bir düğme, olmayan bir düğmeden kötüdür.
|
|
18
|
+
*/
|
|
19
|
+
export function SaveBar({ changed = true, busy = false, onCancel, extra, labels, }) {
|
|
20
|
+
return (_jsxs("div", { className: "tamga-save-bar", "data-changed": changed, children: [_jsx(Button, { variant: "primary", type: "submit", disabled: !changed, busy: busy, busyLabel: labels.saving, children: labels.save }), _jsx(Button, { type: "button", onClick: onCancel, disabled: busy, children: labels.cancel }), extra && _jsx("span", { className: "ml-auto", children: extra })] }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Traps Tab inside a modal surface and gives it back on close.
|
|
3
|
+
*
|
|
4
|
+
* Without this a dialog looks modal and is not: Tab walks straight out into
|
|
5
|
+
* the page behind the scrim, where a keyboard user is stuck operating a page
|
|
6
|
+
* they cannot see. The scrim only stops the mouse.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useFocusTrap<T extends HTMLElement>(open: boolean): import("react").RefObject<T | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Roving focus for a list of options — menus and selects.
|
|
11
|
+
*
|
|
12
|
+
* Arrow keys move, Home/End jump, Enter and Space choose, Escape closes.
|
|
13
|
+
* `data-tamga-option` marks the items so separators and labels are skipped
|
|
14
|
+
* without the hook needing to know what a separator is.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useListKeys({ open, containerRef, onClose, }: {
|
|
17
|
+
open: boolean;
|
|
18
|
+
containerRef: React.RefObject<HTMLElement | null>;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
}): void;
|
|
21
|
+
//# sourceMappingURL=a11y.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a11y.d.ts","sourceRoot":"","sources":["../../src/components/a11y.ts"],"names":[],"mappings":"AAkCA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,OAAO,uCAqEhE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,YAAY,EACZ,OAAO,GACR,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAClD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,QAmDA"}
|