@moontra/moonui 6.19.0 → 6.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +185 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/ui/__tests__/progress-warning-error-contrast.test.ts +331 -0
- package/src/components/ui/__tests__/progress.test.tsx +9 -2
- package/src/components/ui/__tests__/slider-accent-contrast.test.ts +553 -0
- package/src/components/ui/__tests__/slider-warning-error-contrast.test.ts +478 -0
- package/src/components/ui/__tests__/slider.test.tsx +12 -4
- package/src/components/ui/__tests__/switch-variant-contrast.test.tsx +460 -0
- package/src/components/ui/__tests__/switch.test.tsx +11 -2
- package/src/components/ui/__tests__/table.test.tsx +222 -8
- package/src/components/ui/progress.tsx +25 -2
- package/src/components/ui/slider.tsx +92 -6
- package/src/components/ui/switch.tsx +44 -5
- package/src/components/ui/table.tsx +88 -43
package/package.json
CHANGED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #424 — Progress `warning` / `error` varyantlarında dolgu↔track kontrast değişmezi.
|
|
3
|
+
*
|
|
4
|
+
* BULGU (#372'nin birebir kardeşi): dolgu `bg-warning` / `bg-error`, track ise
|
|
5
|
+
* `bg-warning/20` / `bg-error/20` — dolgu ile track AYNI token'ın iki alfa değeri.
|
|
6
|
+
* LIGHT temada ayrım kayboluyordu: warning 1.83 · error 2.89 (eşik 3:1, WCAG
|
|
7
|
+
* 1.4.11 metin-dışı). DARK tema zaten temizdi (warning 6.97 · error 4.46), yani
|
|
8
|
+
* bu bulgu YALNIZ light temaya ait — düzeltmenin de dark render'ı değiştirmemesi
|
|
9
|
+
* gerekir. axe bunu yakalamaz: `color-contrast` yalnız METİN öğelerini ölçer.
|
|
10
|
+
*
|
|
11
|
+
* KÖK NEDEN — token seviyesinde eksik tema-uyarlaması:
|
|
12
|
+
* `--warning` ve `--error` tokens.css'te `.dark` bloğunda EZİLMİYOR; iki temada
|
|
13
|
+
* da aynı renk. Kardeşleri tema-uyarlanabilir olduğu için eşiği geçiyor
|
|
14
|
+
* (`--success` light %29 → dark %36). Bu iki aile o uyarlamadan yoksun.
|
|
15
|
+
*
|
|
16
|
+
* ÇÖZÜM: eksik uyarlamayı component düzeyinde ver — light'ta skalanın -700
|
|
17
|
+
* kademesine in, dark'ta semantik token'a dokunma:
|
|
18
|
+
* warning: "bg-[rgb(var(--warning-700))] dark:bg-warning"
|
|
19
|
+
* error: "bg-[rgb(var(--error-700))] dark:bg-error"
|
|
20
|
+
*
|
|
21
|
+
* Tema-KÖR bir -700 ataması (issue gövdesinin uyardığı refleks) dark'ı KIRARDI —
|
|
22
|
+
* aşağıda testle kanıtlanıyor. `#372`'nin tek-orta-ton çözümü (`--secondary-500`)
|
|
23
|
+
* burada UYGULANAMAZ: orada `--secondary` temaya göre değişiyordu, burada
|
|
24
|
+
* değişmiyor; track `/20` iken skalada iki temayı birden geçen kademe YOK
|
|
25
|
+
* (o da aşağıda kanıtlanıyor). Track alfaları bu yüzden `/20` KALDI.
|
|
26
|
+
*
|
|
27
|
+
* Hesap yöntemi progress-secondary-contrast.test.ts ile birebir aynıdır (WCAG 2.x
|
|
28
|
+
* bağıl parlaklık); oradaki "hesaplayıcı doğru mu?" çapası burada da var.
|
|
29
|
+
* NOT: #372'nin dosyasıyla BİLEREK ayrı dosya — o dosya `--secondary` eksenini
|
|
30
|
+
* kilitler, bu dosya `--warning`/`--error` eksenini; çakışma yok.
|
|
31
|
+
*/
|
|
32
|
+
import * as React from 'react'
|
|
33
|
+
import { render, screen } from '@testing-library/react'
|
|
34
|
+
import '@testing-library/jest-dom'
|
|
35
|
+
import * as fs from 'fs'
|
|
36
|
+
import * as path from 'path'
|
|
37
|
+
import { Progress } from '../progress'
|
|
38
|
+
|
|
39
|
+
const KOK = path.resolve(__dirname, '../../..')
|
|
40
|
+
const tokens = fs.readFileSync(path.join(KOK, 'styles/tokens.css'), 'utf8')
|
|
41
|
+
|
|
42
|
+
/** "H S% L%" biçimindeki token değerini oku (light = :root, dark = .dark bloğu) */
|
|
43
|
+
function tokenOku(ad: string, blok: 'light' | 'dark'): string | null {
|
|
44
|
+
const kaynak =
|
|
45
|
+
blok === 'dark'
|
|
46
|
+
? tokens.slice(tokens.indexOf('.dark'))
|
|
47
|
+
: tokens.slice(0, tokens.indexOf('.dark'))
|
|
48
|
+
return kaynak.match(new RegExp(`--${ad}:\\s*([^;]+);`))?.[1].trim() ?? null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hslToRgb(h: number, s: number, l: number): [number, number, number] {
|
|
52
|
+
h /= 360
|
|
53
|
+
s /= 100
|
|
54
|
+
l /= 100
|
|
55
|
+
const f = (n: number) => {
|
|
56
|
+
const k = (n + h * 12) % 12
|
|
57
|
+
const a = s * Math.min(l, 1 - l)
|
|
58
|
+
return l - a * Math.max(-1, Math.min(k - 3, Math.min(9 - k, 1)))
|
|
59
|
+
}
|
|
60
|
+
return [Math.round(255 * f(0)), Math.round(255 * f(8)), Math.round(255 * f(4))]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const hslTokenRgb = (v: string): [number, number, number] => {
|
|
64
|
+
const [h, s, l] = v.split(/\s+/).map((x) => parseFloat(x))
|
|
65
|
+
return hslToRgb(h, s, l)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Skala token'ları ("--warning-700: 161 98 7") HSL DEĞİL, RGB üçlüsüdür
|
|
70
|
+
* (semantik token'ların HSL formatından farklı) — component'te bu yüzden
|
|
71
|
+
* `bg-[rgb(var(--warning-700))]` kompozisyonu kullanılır, hsl() değil.
|
|
72
|
+
*/
|
|
73
|
+
const rgbTokenRgb = (v: string): [number, number, number] => {
|
|
74
|
+
const p = v.split(/\s+/).map((x) => parseFloat(x))
|
|
75
|
+
return [p[0], p[1], p[2]]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function bagilParlaklik([r, g, b]: [number, number, number]): number {
|
|
79
|
+
const c = (v: number) => {
|
|
80
|
+
const x = v / 255
|
|
81
|
+
return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4)
|
|
82
|
+
}
|
|
83
|
+
return 0.2126 * c(r) + 0.7152 * c(g) + 0.0722 * c(b)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function rgbKontrast(a: [number, number, number], b: [number, number, number]): number {
|
|
87
|
+
const la = bagilParlaklik(a)
|
|
88
|
+
const lb = bagilParlaklik(b)
|
|
89
|
+
const [hi, lo] = la > lb ? [la, lb] : [lb, la]
|
|
90
|
+
return (hi + 0.05) / (lo + 0.05)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** `bg-warning/20` gibi alfa katmanının zemin üstündeki bileşke rengi */
|
|
94
|
+
function alfaBileske(
|
|
95
|
+
ust: [number, number, number],
|
|
96
|
+
alfa: number,
|
|
97
|
+
zemin: [number, number, number]
|
|
98
|
+
): [number, number, number] {
|
|
99
|
+
return [
|
|
100
|
+
Math.round(alfa * ust[0] + (1 - alfa) * zemin[0]),
|
|
101
|
+
Math.round(alfa * ust[1] + (1 - alfa) * zemin[1]),
|
|
102
|
+
Math.round(alfa * ust[2] + (1 - alfa) * zemin[2]),
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Docs kabuğunda ölçülen GERÇEK koyu kart zemini (#111827 = rgb(17,24,39)) —
|
|
108
|
+
* #284/#368 konvansiyonu: kontrast, --background'ın yanında bu gerçek yüzeye
|
|
109
|
+
* göre de ölçülür. Bu zemin bu bulguda DARBOĞAZ: en düşük oranları o veriyor.
|
|
110
|
+
*/
|
|
111
|
+
const KART_GERCEK_DARK: [number, number, number] = [17, 24, 39]
|
|
112
|
+
|
|
113
|
+
const AILELER = ['warning', 'error'] as const
|
|
114
|
+
type Aile = (typeof AILELER)[number]
|
|
115
|
+
|
|
116
|
+
/** Semantik token'ın ilgili temadaki değeri — `.dark` ezmesi YOKSA light'a düşer */
|
|
117
|
+
function semantikRgb(aile: Aile, blok: 'light' | 'dark'): [number, number, number] {
|
|
118
|
+
return hslTokenRgb(tokenOku(aile, blok) ?? tokenOku(aile, 'light')!)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** O temada track'in oluşabileceği tüm zeminler */
|
|
122
|
+
function zeminler(blok: 'light' | 'dark'): Array<[string, [number, number, number]]> {
|
|
123
|
+
const z: Array<[string, [number, number, number]]> = [
|
|
124
|
+
['--background', hslTokenRgb(tokenOku('background', blok)!)],
|
|
125
|
+
['--card', hslTokenRgb(tokenOku('card', blok)!)],
|
|
126
|
+
]
|
|
127
|
+
if (blok === 'dark') z.push(['gerçek kart #111827', KART_GERCEK_DARK])
|
|
128
|
+
return z
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ——— Renkler KAYNAKTAN türetilir ———————————————————————————————————————
|
|
132
|
+
// Ölçümü `bg-...-700` varsayımına göre değil, progress.tsx'in O ANKİ sınıf
|
|
133
|
+
// dizgelerine göre yapıyoruz. Böylece aşağıdaki ≥3:1 testleri component'e
|
|
134
|
+
// GERÇEKTEN bağlanır: biri dolguyu eski hâline döndürürse (ya da track alfasını
|
|
135
|
+
// oynatırsa) kriter testi kırmızı olur — yalnız sözleşme testleri değil.
|
|
136
|
+
const kaynak = fs.readFileSync(path.join(KOK, 'components/ui/progress.tsx'), 'utf8')
|
|
137
|
+
const AYRAC = kaynak.indexOf('progressIndicatorVariants')
|
|
138
|
+
const TRACK_BLOK = kaynak.slice(0, AYRAC)
|
|
139
|
+
const DOLGU_BLOK = kaynak.slice(AYRAC)
|
|
140
|
+
|
|
141
|
+
/** CVA bloğundan `<aile>: "<sınıflar>"` değerini oku */
|
|
142
|
+
function varyantSinifi(blok: string, aile: Aile): string {
|
|
143
|
+
const m = blok.match(new RegExp(`\\n\\s*${aile}:\\s*"([^"]+)"`))
|
|
144
|
+
if (!m) throw new Error(`${aile} varyantı bulunamadı`)
|
|
145
|
+
return m[1]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Tek bir Tailwind bg sınıfını renge çevir (arbitrary skala VEYA semantik token) */
|
|
149
|
+
function sinifRengi(sinif: string, blok: 'light' | 'dark'): [number, number, number] {
|
|
150
|
+
const skala = sinif.match(/^bg-\[rgb\(var\(--([a-z0-9-]+)\)\)\]$/)
|
|
151
|
+
if (skala) return rgbTokenRgb(tokenOku(skala[1], 'light')!) // skala yalnız :root'ta
|
|
152
|
+
const semantik = sinif.match(/^bg-([a-z-]+)$/)
|
|
153
|
+
if (semantik) return hslTokenRgb(tokenOku(semantik[1], blok) ?? tokenOku(semantik[1], 'light')!)
|
|
154
|
+
throw new Error(`çözülemeyen sınıf: ${sinif}`)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Dolgunun o temada GERÇEKTEN uygulanan rengi — `dark:` öneki dark'ta kazanır */
|
|
158
|
+
function dolguRengi(aile: Aile, blok: 'light' | 'dark'): [number, number, number] {
|
|
159
|
+
const siniflar = varyantSinifi(DOLGU_BLOK, aile).split(/\s+/)
|
|
160
|
+
const darkSinif = siniflar.find((s) => s.startsWith('dark:'))?.slice('dark:'.length)
|
|
161
|
+
const lightSinif = siniflar.find((s) => !s.startsWith('dark:'))
|
|
162
|
+
if (!lightSinif) throw new Error(`${aile}: temel (light) sınıf yok`)
|
|
163
|
+
return sinifRengi(blok === 'dark' ? darkSinif ?? lightSinif : lightSinif, blok)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Track'in o zemin üstündeki bileşke rengi — alfa da kaynaktan okunur */
|
|
167
|
+
function trackler(aile: Aile, blok: 'light' | 'dark') {
|
|
168
|
+
const sinif = varyantSinifi(TRACK_BLOK, aile)
|
|
169
|
+
const m = sinif.match(/^bg-([a-z-]+)\/(\d+)$/)
|
|
170
|
+
if (!m) throw new Error(`track sınıfı çözülemedi: ${sinif}`)
|
|
171
|
+
const taban = hslTokenRgb(tokenOku(m[1], blok) ?? tokenOku(m[1], 'light')!)
|
|
172
|
+
const alfa = Number(m[2]) / 100
|
|
173
|
+
return zeminler(blok).map(([ad, z]) => [ad, alfaBileske(taban, alfa, z)] as const)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const KADEMELER = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]
|
|
177
|
+
|
|
178
|
+
describe('#424 progress warning/error dolgu↔track kontrastı', () => {
|
|
179
|
+
it('hesaplayıcı DOĞRU — bilinen bir çift belgelenen oranı veriyor', () => {
|
|
180
|
+
// Sessiz-yeşil koruması: `--info-subtle` çifti tokens.css'te 9.52:1 diye
|
|
181
|
+
// belgelenmiş; hesaplayıcı bozulursa bu çapa kırmızı olur.
|
|
182
|
+
const oran = rgbKontrast(
|
|
183
|
+
hslTokenRgb(tokenOku('info-subtle', 'light')!),
|
|
184
|
+
hslTokenRgb(tokenOku('info-subtle-foreground', 'light')!)
|
|
185
|
+
)
|
|
186
|
+
expect(oran).toBeGreaterThan(9.3)
|
|
187
|
+
expect(oran).toBeLessThan(9.7)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('hesaplayıcı, denetimin TARAYICIDA ölçtüğü renkleri birebir üretiyor', () => {
|
|
191
|
+
// Çapraz doğrulama: issue #424 gövdesindeki gerçek tarayıcı ölçümleri
|
|
192
|
+
// warning dolgu rgb(245,159,10) / track rgb(253,236,206), error dolgu
|
|
193
|
+
// rgb(239,67,67) / track rgb(252,217,217). Model bunları tutturamıyorsa
|
|
194
|
+
// aşağıdaki tüm oranlar anlamsızdır.
|
|
195
|
+
expect(semantikRgb('warning', 'light')).toEqual([245, 159, 10])
|
|
196
|
+
expect(semantikRgb('error', 'light')).toEqual([239, 67, 67])
|
|
197
|
+
expect(trackler('warning', 'light')[0][1]).toEqual([253, 236, 206])
|
|
198
|
+
expect(trackler('error', 'light')[0][1]).toEqual([252, 217, 217])
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
describe('kök neden: --warning ve --error `.dark` bloğunda EZİLMİYOR', () => {
|
|
202
|
+
it.each(AILELER)('--%s dark ezmesi yok → iki temada aynı renk', (aile) => {
|
|
203
|
+
// Bu, bulgunun yapısal kök nedeni. Biri ileride `.dark` bloğuna
|
|
204
|
+
// `--warning`/`--error` eklerse bu test kırmızı olur ve component
|
|
205
|
+
// düzeyindeki `dark:` telafisinin yeniden ölçülmesi gerektiğini söyler.
|
|
206
|
+
expect(tokenOku(aile, 'dark')).toBeNull()
|
|
207
|
+
expect(semantikRgb(aile, 'light')).toEqual(semantikRgb(aile, 'dark'))
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('karşıtlık: --success tema-uyarlanabilir olduğu İÇİN eşiği geçiyor', () => {
|
|
211
|
+
// Neden success'e dokunulmadığının kanıtı: onun dark ezmesi VAR.
|
|
212
|
+
expect(tokenOku('success', 'dark')).not.toBeNull()
|
|
213
|
+
expect(tokenOku('success', 'light')).not.toBe(tokenOku('success', 'dark'))
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it.each(AILELER)('--%s-700 tanımlı ve RGB üçlüsü olarak ayrıştırılabiliyor', (aile) => {
|
|
217
|
+
const ham = tokenOku(`${aile}-700`, 'light')
|
|
218
|
+
expect(ham).toBeTruthy()
|
|
219
|
+
rgbTokenRgb(ham!).forEach((kanal) => {
|
|
220
|
+
expect(Number.isFinite(kanal)).toBe(true)
|
|
221
|
+
expect(kanal).toBeGreaterThanOrEqual(0)
|
|
222
|
+
expect(kanal).toBeLessThanOrEqual(255)
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
describe('kaynak sözleşmesi: dolgu ile track FARKLI renklere basıyor', () => {
|
|
228
|
+
it.each(AILELER)('track %s sınıfı `/20` alfasını KORUYOR (altı varyantın ortak deseni)', (aile) => {
|
|
229
|
+
expect(kaynak).toMatch(new RegExp(`${aile}:\\s*"bg-${aile}\\/20"`))
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it.each(AILELER)('dolgu %s sınıfı light\'ta -700, dark\'ta semantik token', (aile) => {
|
|
233
|
+
expect(kaynak).toMatch(
|
|
234
|
+
new RegExp(`${aile}:\\s*"bg-\\[rgb\\(var\\(--${aile}-700\\)\\)\\] dark:bg-${aile}"`)
|
|
235
|
+
)
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
describe('render sözleşmesi', () => {
|
|
240
|
+
it.each(AILELER)('<Progress variant="%s" /> — track ve dolgu DOM\'a ayrışmış iniyor', (aile) => {
|
|
241
|
+
render(React.createElement(Progress, { variant: aile, value: 50 }))
|
|
242
|
+
const track = screen.getByRole('progressbar')
|
|
243
|
+
expect(track).toHaveClass(`bg-${aile}/20`)
|
|
244
|
+
const dolgu = track.firstElementChild as HTMLElement
|
|
245
|
+
expect(dolgu).not.toBeNull()
|
|
246
|
+
expect(dolgu.className).toContain(`bg-[rgb(var(--${aile}-700))]`)
|
|
247
|
+
expect(dolgu.className).toContain(`dark:bg-${aile}`)
|
|
248
|
+
// Light'ta semantik token dolguya UYGULANMAMALI (track'in aynısıydı):
|
|
249
|
+
// yalnız `dark:` önekli hâli kalmalı.
|
|
250
|
+
expect(dolgu.className).not.toMatch(new RegExp(`(?:^|\\s)bg-${aile}(?:\\s|$)`))
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it.each(AILELER)('#318 düşüş mantığı KORUNUYOR — indicatorVariant hâlâ %s varyantını ezer', (aile) => {
|
|
254
|
+
render(
|
|
255
|
+
React.createElement(Progress, { variant: aile, indicatorVariant: 'success', value: 50 })
|
|
256
|
+
)
|
|
257
|
+
const dolgu = screen.getByRole('progressbar').firstElementChild as HTMLElement
|
|
258
|
+
expect(dolgu.className).toContain('bg-success')
|
|
259
|
+
expect(dolgu.className).not.toContain(`--${aile}-700`)
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
describe.each(AILELER)('%s — kabul kriteri ≥3:1 (WCAG 1.4.11)', (aile) => {
|
|
264
|
+
it.each(['light', 'dark'] as const)('%s temada TÜM zeminlerde eşiği geçiyor', (blok) => {
|
|
265
|
+
// Ölçülen: warning light 4.24 · dark 6.97 (docs kartı 5.77)
|
|
266
|
+
// error light 4.95 · dark 4.46 (docs kartı 3.82)
|
|
267
|
+
const dolgu = dolguRengi(aile, blok)
|
|
268
|
+
for (const [ad, track] of trackler(aile, blok)) {
|
|
269
|
+
const oran = rgbKontrast(dolgu, track)
|
|
270
|
+
expect({ zemin: ad, gecti: oran >= 3.0 }).toEqual({ zemin: ad, gecti: true })
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('ESKİ dolgu (semantik token) LIGHT temada başarısızdı — bug\'ın belgesi', () => {
|
|
275
|
+
// warning 1.83 · error 2.89. Bu test düzeltmenin GEREKLİLİĞİNİ sabitler:
|
|
276
|
+
// biri dolguyu `bg-warning`/`bg-error`e geri döndürürse üstteki kriter
|
|
277
|
+
// testi kırmızı olur, burası da nedenini belgeler.
|
|
278
|
+
const eski = semantikRgb(aile, 'light')
|
|
279
|
+
for (const [, track] of trackler(aile, 'light')) {
|
|
280
|
+
expect(rgbKontrast(eski, track)).toBeLessThan(3.0)
|
|
281
|
+
}
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('DARK render değişmedi — eski dolgu dark\'ta zaten geçiyordu ve hâlâ o renk', () => {
|
|
285
|
+
// Bulgu light'a özgüydü; düzeltmenin dark'ta hiçbir şeyi oynatmaması
|
|
286
|
+
// bilinçli bir kısıt (regresyon yüzeyini sıfıra indirir).
|
|
287
|
+
expect(dolguRengi(aile, 'dark')).toEqual(semantikRgb(aile, 'dark'))
|
|
288
|
+
for (const [, track] of trackler(aile, 'dark')) {
|
|
289
|
+
expect(rgbKontrast(semantikRgb(aile, 'dark'), track)).toBeGreaterThanOrEqual(3.0)
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
describe('seçim gerekçesi — reddedilen alternatifler', () => {
|
|
295
|
+
it.each(AILELER)('TEMA-KÖR `-700` ataması %s varyantını DARK\'ta kırardı', (aile) => {
|
|
296
|
+
// Issue gövdesinin uyardığı refleks. -700 kademesi dark track'e karşı
|
|
297
|
+
// (gerçek docs kartı zemininde) eşiğin ALTINDA: warning 2.50 · error 2.23.
|
|
298
|
+
// `dark:` ayrımı tam olarak bunu önlüyor.
|
|
299
|
+
const k700 = rgbTokenRgb(tokenOku(`${aile}-700`, 'light')!)
|
|
300
|
+
const docsTrack = trackler(aile, 'dark').find(([ad]) => ad === 'gerçek kart #111827')![1]
|
|
301
|
+
expect(rgbKontrast(k700, docsTrack)).toBeLessThan(3.0)
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it.each(AILELER)('#372\'nin tek-orta-ton çözümü %s için UYGULANAMAZ — geçen kademe YOK', (aile) => {
|
|
305
|
+
// #372 dolguyu tek bir skala kademesine (`--secondary-500`) sabitleyip iki
|
|
306
|
+
// temayı birden geçebilmişti, çünkü `--secondary` temaya göre DEĞİŞİYOR.
|
|
307
|
+
// Burada semantik token sabit olduğundan track'ler birbirinden çok uzak:
|
|
308
|
+
// skalanın 11 kademesinin HİÇBİRİ tema-kör olarak iki temayı birden
|
|
309
|
+
// geçemiyor. Bu, `dark:` ayrımını zorunlu kılan kanıttır.
|
|
310
|
+
const tumTrackler = [...trackler(aile, 'light'), ...trackler(aile, 'dark')]
|
|
311
|
+
const gecen = KADEMELER.filter((k) => {
|
|
312
|
+
const ham = tokenOku(`${aile}-${k}`, 'light')
|
|
313
|
+
if (!ham) return false
|
|
314
|
+
const d = rgbTokenRgb(ham)
|
|
315
|
+
return tumTrackler.every(([, t]) => rgbKontrast(d, t) >= 3.0)
|
|
316
|
+
})
|
|
317
|
+
expect(gecen).toEqual([])
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
it.each(AILELER)('%s track alfası düşürülmedi — /20 ayrımı /10\'dan güçlü', (aile) => {
|
|
321
|
+
// Alternatif öneri track'i `/10`'a çekmekti; kabul edilmedi çünkü track
|
|
322
|
+
// zemine yaklaşır ve barın TOPLAM uzunluğu görünmez olur. Altı varyantın
|
|
323
|
+
// ortak `/20` deseni de bozulurdu.
|
|
324
|
+
const zemin = zeminler('light')[0][1]
|
|
325
|
+
const sem = semantikRgb(aile, 'light')
|
|
326
|
+
const yirmi = rgbKontrast(alfaBileske(sem, 0.2, zemin), zemin)
|
|
327
|
+
const on = rgbKontrast(alfaBileske(sem, 0.1, zemin), zemin)
|
|
328
|
+
expect(yirmi).toBeGreaterThan(on)
|
|
329
|
+
})
|
|
330
|
+
})
|
|
331
|
+
})
|
|
@@ -235,14 +235,21 @@ describe('Progress Component', () => {
|
|
|
235
235
|
render(<Progress indicatorVariant="warning" />)
|
|
236
236
|
const progress = screen.getByRole('progressbar')
|
|
237
237
|
const indicator = progress.querySelector('div')
|
|
238
|
-
|
|
238
|
+
// #424: dolgu light'ta artık `bg-warning` DEĞİL — o token track'in
|
|
239
|
+
// (`bg-warning/20`) aynısıydı, light'ta ayrım 1.83'e düşüyordu. Dark
|
|
240
|
+
// render'ı korumak için semantik token `dark:` altına taşındı.
|
|
241
|
+
// Gerekçe + kontrast hesabı: progress-warning-error-contrast.test.ts
|
|
242
|
+
expect(indicator).toHaveClass('bg-[rgb(var(--warning-700))]')
|
|
243
|
+
expect(indicator).toHaveClass('dark:bg-warning')
|
|
239
244
|
})
|
|
240
245
|
|
|
241
246
|
it('renders error indicator variant correctly', () => {
|
|
242
247
|
render(<Progress indicatorVariant="error" />)
|
|
243
248
|
const progress = screen.getByRole('progressbar')
|
|
244
249
|
const indicator = progress.querySelector('div')
|
|
245
|
-
|
|
250
|
+
// #424: aynı düzeltme — light 2.89 → 4.95, dark render'ı değişmedi.
|
|
251
|
+
expect(indicator).toHaveClass('bg-[rgb(var(--error-700))]')
|
|
252
|
+
expect(indicator).toHaveClass('dark:bg-error')
|
|
246
253
|
})
|
|
247
254
|
})
|
|
248
255
|
|