@moontra/moonui 6.24.0 → 6.26.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/dist/cdn/moonui.css +2 -2
- package/dist/cdn/moonui.esm.js +12 -12
- package/dist/cdn/moonui.global.js +12 -12
- package/dist/index.d.mts +24 -6
- package/dist/index.d.ts +24 -6
- package/dist/index.js +436 -93
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +437 -95
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/issue-544-kontrast.test.tsx +153 -145
- package/src/__tests__/issue-645-overlay-tab-focus.test.tsx +262 -0
- package/src/__tests__/issue-646-dark-scope-override.test.tsx +297 -0
- package/src/__tests__/issue-661-a11y.test.tsx +113 -0
- package/src/__tests__/issue-661-token-kontrast.test.tsx +82 -0
- package/src/components/ui/__tests__/accent-foreground-contrast.test.ts +197 -0
- package/src/components/ui/__tests__/accordion.test.tsx +6 -4
- package/src/components/ui/__tests__/alert.test.tsx +4 -1
- package/src/components/ui/__tests__/button.test.tsx +6 -1
- package/src/components/ui/__tests__/dark-token-contrast.test.ts +18 -18
- package/src/components/ui/__tests__/heading-level-policy.test.tsx +4 -4
- package/src/components/ui/__tests__/issue-643-card-token-parite.test.tsx +113 -0
- package/src/components/ui/__tests__/issue-649-button-aschild.test.tsx +199 -0
- package/src/components/ui/__tests__/issue-664-separator-dekoratif-rol.test.tsx +41 -0
- package/src/components/ui/__tests__/preset-color-shadowing.test.ts +10 -10
- package/src/components/ui/__tests__/primary-subtle-token.test.ts +7 -7
- package/src/components/ui/__tests__/progress-secondary-contrast.test.ts +38 -38
- package/src/components/ui/__tests__/progress-warning-error-contrast.test.ts +64 -64
- package/src/components/ui/__tests__/quality-group-de.test.tsx +2 -2
- package/src/components/ui/__tests__/responsive-color-invariance.test.ts +20 -20
- package/src/components/ui/__tests__/select.test.tsx +6 -1
- package/src/components/ui/__tests__/semantic-token-usage.test.ts +23 -23
- package/src/components/ui/__tests__/size-scale-convention.test.ts +10 -10
- package/src/components/ui/__tests__/slider-accent-contrast.test.ts +142 -136
- package/src/components/ui/__tests__/slider-secondary-contrast.test.ts +60 -60
- package/src/components/ui/__tests__/slider-warning-error-contrast.test.ts +100 -100
- package/src/components/ui/__tests__/switch-variant-contrast.test.tsx +103 -103
- package/src/components/ui/__tests__/tooltip.test.tsx +122 -0
- package/src/components/ui/accordion.tsx +16 -3
- package/src/components/ui/alert.tsx +1 -1
- package/src/components/ui/badge.tsx +12 -1
- package/src/components/ui/button.tsx +95 -24
- package/src/components/ui/card.tsx +59 -5
- package/src/components/ui/dropdown-menu.tsx +99 -5
- package/src/components/ui/file-upload.tsx +4 -0
- package/src/components/ui/index.ts +4 -1
- package/src/components/ui/popover-pro.tsx +41 -0
- package/src/components/ui/popover.tsx +162 -7
- package/src/components/ui/rating.tsx +24 -2
- package/src/components/ui/select.tsx +4 -4
- package/src/components/ui/simple-editor.tsx +3 -18
- package/src/components/ui/tabs.tsx +16 -1
- package/src/components/ui/textarea.tsx +6 -1
- package/src/components/ui/toast.tsx +17 -2
- package/src/components/ui/tooltip.tsx +154 -2
- package/src/styles/tokens.css +34 -2
|
@@ -44,12 +44,12 @@ const KOK = path.resolve(__dirname, '../../..')
|
|
|
44
44
|
const tokens = fs.readFileSync(path.join(KOK, 'styles/tokens.css'), 'utf8')
|
|
45
45
|
|
|
46
46
|
/** "H S% L%" biçimindeki token değerini oku (light = :root, dark = .dark bloğu) */
|
|
47
|
-
function tokenOku(
|
|
48
|
-
const
|
|
47
|
+
function tokenOku(name: string, blok: 'light' | 'dark'): string | null {
|
|
48
|
+
const source =
|
|
49
49
|
blok === 'dark'
|
|
50
50
|
? tokens.slice(tokens.indexOf('.dark'))
|
|
51
51
|
: tokens.slice(0, tokens.indexOf('.dark'))
|
|
52
|
-
return
|
|
52
|
+
return source.match(new RegExp(`--${name}:\\s*([^;]+);`))?.[1].trim() ?? null
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function hslToRgb(h: number, s: number, l: number): [number, number, number] {
|
|
@@ -79,7 +79,7 @@ const rgbTokenRgb = (v: string): [number, number, number] => {
|
|
|
79
79
|
return [p[0], p[1], p[2]]
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
function
|
|
82
|
+
function relativeLuminance([r, g, b]: [number, number, number]): number {
|
|
83
83
|
const c = (v: number) => {
|
|
84
84
|
const x = v / 255
|
|
85
85
|
return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4)
|
|
@@ -88,8 +88,8 @@ function bagilParlaklik([r, g, b]: [number, number, number]): number {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
function rgbKontrast(a: [number, number, number], b: [number, number, number]): number {
|
|
91
|
-
const la =
|
|
92
|
-
const lb =
|
|
91
|
+
const la = relativeLuminance(a)
|
|
92
|
+
const lb = relativeLuminance(b)
|
|
93
93
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la]
|
|
94
94
|
return (hi + 0.05) / (lo + 0.05)
|
|
95
95
|
}
|
|
@@ -98,12 +98,12 @@ function rgbKontrast(a: [number, number, number], b: [number, number, number]):
|
|
|
98
98
|
function alfaBileske(
|
|
99
99
|
ust: [number, number, number],
|
|
100
100
|
alfa: number,
|
|
101
|
-
|
|
101
|
+
background: [number, number, number]
|
|
102
102
|
): [number, number, number] {
|
|
103
103
|
return [
|
|
104
|
-
Math.round(alfa * ust[0] + (1 - alfa) *
|
|
105
|
-
Math.round(alfa * ust[1] + (1 - alfa) *
|
|
106
|
-
Math.round(alfa * ust[2] + (1 - alfa) *
|
|
104
|
+
Math.round(alfa * ust[0] + (1 - alfa) * background[0]),
|
|
105
|
+
Math.round(alfa * ust[1] + (1 - alfa) * background[1]),
|
|
106
|
+
Math.round(alfa * ust[2] + (1 - alfa) * background[2]),
|
|
107
107
|
]
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -112,23 +112,23 @@ function alfaBileske(
|
|
|
112
112
|
* #284/#368 konvansiyonu: kontrast, --background'ın yanında bu gerçek yüzeye göre
|
|
113
113
|
* de ölçülür. Bu bulguda DARBOĞAZ: en düşük dark oranlarını o veriyor.
|
|
114
114
|
*/
|
|
115
|
-
const
|
|
115
|
+
const CARD_ACTUAL_DARK: [number, number, number] = [17, 24, 39]
|
|
116
116
|
|
|
117
117
|
const AILELER = ['warning', 'error'] as const
|
|
118
118
|
type Aile = (typeof AILELER)[number]
|
|
119
119
|
|
|
120
120
|
/** Semantik token'ın ilgili temadaki değeri — `.dark` ezmesi YOKSA light'a düşer */
|
|
121
|
-
function
|
|
121
|
+
function semanticRgb(aile: Aile, blok: 'light' | 'dark'): [number, number, number] {
|
|
122
122
|
return hslTokenRgb(tokenOku(aile, blok) ?? tokenOku(aile, 'light')!)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/** O temada slider'ın oturabileceği tüm zeminler */
|
|
126
|
-
function
|
|
126
|
+
function backgrounds(blok: 'light' | 'dark'): Array<[string, [number, number, number]]> {
|
|
127
127
|
const z: Array<[string, [number, number, number]]> = [
|
|
128
128
|
['--background', hslTokenRgb(tokenOku('background', blok)!)],
|
|
129
129
|
['--card', hslTokenRgb(tokenOku('card', blok)!)],
|
|
130
130
|
]
|
|
131
|
-
if (blok === 'dark') z.push(['gerçek kart #111827',
|
|
131
|
+
if (blok === 'dark') z.push(['gerçek kart #111827', CARD_ACTUAL_DARK])
|
|
132
132
|
return z
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -136,30 +136,30 @@ function zeminler(blok: 'light' | 'dark'): Array<[string, [number, number, numbe
|
|
|
136
136
|
// PR #440'ın dersi: ölçümü `-700` VARSAYIMINA göre yaparsan, biri değeri eskiye
|
|
137
137
|
// döndürdüğünde kriter testleri yeşil kalır (boş-yeşil). Bu yüzden renkler
|
|
138
138
|
// slider.tsx'in O ANKİ CVA sınıf dizgelerinden çözülür.
|
|
139
|
-
const
|
|
140
|
-
const iTrack =
|
|
141
|
-
const iRange =
|
|
142
|
-
const iThumb =
|
|
143
|
-
const iSon =
|
|
144
|
-
const TRACK_BLOK =
|
|
145
|
-
const RANGE_BLOK =
|
|
146
|
-
const THUMB_BLOK =
|
|
139
|
+
const source = fs.readFileSync(path.join(KOK, 'components/ui/slider.tsx'), 'utf8')
|
|
140
|
+
const iTrack = source.indexOf('sliderTrackVariants')
|
|
141
|
+
const iRange = source.indexOf('sliderRangeVariants')
|
|
142
|
+
const iThumb = source.indexOf('sliderThumbVariants')
|
|
143
|
+
const iSon = source.indexOf('SliderBaseProps')
|
|
144
|
+
const TRACK_BLOK = source.slice(iTrack, iRange)
|
|
145
|
+
const RANGE_BLOK = source.slice(iRange, iThumb)
|
|
146
|
+
const THUMB_BLOK = source.slice(iThumb, iSon)
|
|
147
147
|
|
|
148
148
|
/** CVA bloğundan `<aile>: "<sınıflar>"` değerini oku */
|
|
149
|
-
function
|
|
149
|
+
function variantClass(blok: string, aile: string): string {
|
|
150
150
|
const m = blok.match(new RegExp(`\\n\\s*${aile}:\\s*"([^"]+)"`))
|
|
151
151
|
if (!m) throw new Error(`${aile} varyantı bulunamadı`)
|
|
152
152
|
return m[1]
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
/** Tek bir Tailwind sınıfını renge çevir (arbitrary skala VEYA semantik token) */
|
|
156
|
-
function
|
|
157
|
-
const
|
|
158
|
-
if (
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
161
|
-
return hslTokenRgb(tokenOku(
|
|
162
|
-
throw new Error(`çözülemeyen sınıf: ${
|
|
156
|
+
function classColor(cls: string, blok: 'light' | 'dark'): [number, number, number] {
|
|
157
|
+
const scale = cls.match(/^(?:bg|border)-\[rgb\(var\(--([a-z0-9-]+)\)\)\]$/)
|
|
158
|
+
if (scale) return rgbTokenRgb(tokenOku(scale[1], 'light')!) // skala yalnız :root'ta
|
|
159
|
+
const semantic = cls.match(/^(?:bg|border)-([a-z-]+)$/)
|
|
160
|
+
if (semantic)
|
|
161
|
+
return hslTokenRgb(tokenOku(semantic[1], blok) ?? tokenOku(semantic[1], 'light')!)
|
|
162
|
+
throw new Error(`çözülemeyen sınıf: ${cls}`)
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
/**
|
|
@@ -167,40 +167,40 @@ function sinifRengi(sinif: string, blok: 'light' | 'dark'): [number, number, num
|
|
|
167
167
|
* `dark:` önekli sınıf dark temada kazanır; `onek` ile eksen seçilir
|
|
168
168
|
* (thumb dizgesi `border-*` yanında `bg-background` da taşır).
|
|
169
169
|
*/
|
|
170
|
-
function
|
|
170
|
+
function appliedColor(
|
|
171
171
|
cvaBlok: string,
|
|
172
172
|
aile: Aile,
|
|
173
173
|
onek: 'bg' | 'border',
|
|
174
174
|
blok: 'light' | 'dark'
|
|
175
175
|
): [number, number, number] {
|
|
176
|
-
const
|
|
176
|
+
const classNames = variantClass(cvaBlok, aile)
|
|
177
177
|
.split(/\s+/)
|
|
178
178
|
.filter((s) => s.replace(/^dark:/, '').startsWith(`${onek}-`))
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
182
|
-
return
|
|
179
|
+
const darkClass = classNames.find((s) => s.startsWith('dark:'))?.slice('dark:'.length)
|
|
180
|
+
const lightClass = classNames.find((s) => !s.startsWith('dark:'))
|
|
181
|
+
if (!lightClass) throw new Error(`${aile}/${onek}: temel (light) sınıf yok`)
|
|
182
|
+
return classColor(blok === 'dark' ? darkClass ?? lightClass : lightClass, blok)
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
const rangeRengi = (aile: Aile, blok: 'light' | 'dark') =>
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
186
|
+
appliedColor(RANGE_BLOK, aile, 'bg', blok)
|
|
187
|
+
const thumbBorderColor = (aile: Aile, blok: 'light' | 'dark') =>
|
|
188
|
+
appliedColor(THUMB_BLOK, aile, 'border', blok)
|
|
189
189
|
|
|
190
190
|
/** Track'in her zemin üstündeki bileşkesi — alfa da KAYNAKTAN okunur */
|
|
191
191
|
function trackler(aile: Aile, blok: 'light' | 'dark') {
|
|
192
|
-
const
|
|
193
|
-
const m =
|
|
194
|
-
if (!m) throw new Error(`track sınıfı çözülemedi: ${
|
|
195
|
-
const
|
|
192
|
+
const cls = variantClass(TRACK_BLOK, aile)
|
|
193
|
+
const m = cls.match(/^bg-([a-z-]+)\/(\d+)$/)
|
|
194
|
+
if (!m) throw new Error(`track sınıfı çözülemedi: ${cls}`)
|
|
195
|
+
const base = hslTokenRgb(tokenOku(m[1], blok) ?? tokenOku(m[1], 'light')!)
|
|
196
196
|
const alfa = Number(m[2]) / 100
|
|
197
|
-
return
|
|
197
|
+
return backgrounds(blok).map(([name, z]) => [name, alfaBileske(base, alfa, z)] as const)
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
const KADEMELER = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]
|
|
201
201
|
|
|
202
202
|
/** Slider DOM'u: kök > .moonui-theme > track > range; thumb'lar track'in KARDEŞİ */
|
|
203
|
-
function
|
|
203
|
+
function parts(container: HTMLElement) {
|
|
204
204
|
const kabuk = container.querySelector('.moonui-theme') as HTMLElement
|
|
205
205
|
expect(kabuk).not.toBeNull()
|
|
206
206
|
const track = kabuk.firstElementChild as HTMLElement
|
|
@@ -226,8 +226,8 @@ describe('#442 slider warning/error — hesaplayıcı çapası', () => {
|
|
|
226
226
|
it('hesaplayıcı, denetimin TARAYICIDA ölçtüğü renkleri birebir üretiyor', () => {
|
|
227
227
|
// Çapraz doğrulama (#424/#442 gövdesindeki gerçek tarayıcı ölçümleri): model
|
|
228
228
|
// bunları tutturamıyorsa aşağıdaki tüm oranlar anlamsızdır.
|
|
229
|
-
expect(
|
|
230
|
-
expect(
|
|
229
|
+
expect(semanticRgb('warning', 'light')).toEqual([245, 159, 10])
|
|
230
|
+
expect(semanticRgb('error', 'light')).toEqual([239, 67, 67])
|
|
231
231
|
expect(trackler('warning', 'light')[0][1]).toEqual([253, 236, 206])
|
|
232
232
|
expect(trackler('error', 'light')[0][1]).toEqual([252, 217, 217])
|
|
233
233
|
})
|
|
@@ -239,7 +239,7 @@ describe('#442 kök neden: --warning ve --error `.dark` bloğunda EZİLMİYOR',
|
|
|
239
239
|
// `--error` eklerse burası kırmızı olur ve component düzeyindeki `dark:`
|
|
240
240
|
// telafisinin yeniden ölçülmesi gerektiğini söyler.
|
|
241
241
|
expect(tokenOku(aile, 'dark')).toBeNull()
|
|
242
|
-
expect(
|
|
242
|
+
expect(semanticRgb(aile, 'light')).toEqual(semanticRgb(aile, 'dark'))
|
|
243
243
|
})
|
|
244
244
|
|
|
245
245
|
it('karşıtlık: --success tema-uyarlanabilir olduğu İÇİN eşiği geçiyor', () => {
|
|
@@ -262,13 +262,13 @@ describe('#442 kök neden: --warning ve --error `.dark` bloğunda EZİLMİYOR',
|
|
|
262
262
|
// Hesap, track'in/tutamacın altındaki yüzeyin --background/--card olduğunu
|
|
263
263
|
// VARSAYAR. Biri `.moonui-theme`i token kapsamına çevirirse o varsayım
|
|
264
264
|
// sessizce yanlışlanır — o an burası kırmızı olur (#389 deseni).
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
.readdirSync(
|
|
265
|
+
const styleDir = path.join(KOK, 'styles')
|
|
266
|
+
const styles = fs
|
|
267
|
+
.readdirSync(styleDir)
|
|
268
268
|
.filter((f) => f.endsWith('.css'))
|
|
269
|
-
.map((f) => fs.readFileSync(path.join(
|
|
269
|
+
.map((f) => fs.readFileSync(path.join(styleDir, f), 'utf8'))
|
|
270
270
|
.join('\n')
|
|
271
|
-
expect(
|
|
271
|
+
expect(styles).not.toMatch(/\.moonui-theme[^{]*\{[^}]*--(warning|error|background|card)/)
|
|
272
272
|
})
|
|
273
273
|
})
|
|
274
274
|
|
|
@@ -276,17 +276,17 @@ describe('#442 kaynak sözleşmesi — slider.tsx', () => {
|
|
|
276
276
|
it.each(AILELER)('track %s sınıfı `/20` alfasını KORUYOR (yedi varyantın ortak deseni)', (aile) => {
|
|
277
277
|
// Alternatif öneri track'i `/10`'a çekmekti; kabul edilmedi (track↔zemin
|
|
278
278
|
// ayrımını zayıflatır, ortak konvansiyonu bozar). Burası o kararı kilitler.
|
|
279
|
-
expect(
|
|
279
|
+
expect(variantClass(TRACK_BLOK, aile)).toBe(`bg-${aile}/20`)
|
|
280
280
|
})
|
|
281
281
|
|
|
282
282
|
it.each(AILELER)('EKSEN A: range %s light\'ta -700, dark\'ta semantik token', (aile) => {
|
|
283
|
-
expect(
|
|
283
|
+
expect(variantClass(RANGE_BLOK, aile)).toBe(
|
|
284
284
|
`bg-[rgb(var(--${aile}-700))] dark:bg-${aile}`
|
|
285
285
|
)
|
|
286
286
|
})
|
|
287
287
|
|
|
288
288
|
it.each(AILELER)('EKSEN B: thumb %s kenarlığı light\'ta -700, dark\'ta semantik token', (aile) => {
|
|
289
|
-
expect(
|
|
289
|
+
expect(variantClass(THUMB_BLOK, aile)).toBe(
|
|
290
290
|
`border-[rgb(var(--${aile}-700))] dark:border-${aile} bg-background`
|
|
291
291
|
)
|
|
292
292
|
})
|
|
@@ -295,8 +295,8 @@ describe('#442 kaynak sözleşmesi — slider.tsx', () => {
|
|
|
295
295
|
// Gereksiz değişiklik yeni regresyon riski. Ölçüm: success A light 3.73 /
|
|
296
296
|
// dark 4.83 · primary A light 3.71 / dark 11.24 — ikisi de ≥3.
|
|
297
297
|
for (const aile of ['primary', 'success'] as const) {
|
|
298
|
-
expect(
|
|
299
|
-
expect(
|
|
298
|
+
expect(variantClass(RANGE_BLOK, aile)).toBe(`bg-${aile}`)
|
|
299
|
+
expect(variantClass(THUMB_BLOK, aile)).toBe(`border-${aile} bg-background`)
|
|
300
300
|
}
|
|
301
301
|
})
|
|
302
302
|
})
|
|
@@ -306,7 +306,7 @@ describe('#442 render sözleşmesi — <Slider />', () => {
|
|
|
306
306
|
const { container } = render(
|
|
307
307
|
React.createElement(Slider, { trackVariant: aile, rangeVariant: aile })
|
|
308
308
|
)
|
|
309
|
-
const { track, range } =
|
|
309
|
+
const { track, range } = parts(container)
|
|
310
310
|
expect(track).toHaveClass(`bg-${aile}/20`)
|
|
311
311
|
expect(range.className).toContain(`bg-[rgb(var(--${aile}-700))]`)
|
|
312
312
|
expect(range.className).toContain(`dark:bg-${aile}`)
|
|
@@ -316,7 +316,7 @@ describe('#442 render sözleşmesi — <Slider />', () => {
|
|
|
316
316
|
|
|
317
317
|
it.each(AILELER)('%s: thumb kenarlığı yeni ifadeyle iniyor, dolgusu bg-background kalıyor', (aile) => {
|
|
318
318
|
const { container } = render(React.createElement(Slider, { thumbVariant: aile }))
|
|
319
|
-
const { thumb } =
|
|
319
|
+
const { thumb } = parts(container)
|
|
320
320
|
expect(thumb.className).toContain(`border-[rgb(var(--${aile}-700))]`)
|
|
321
321
|
expect(thumb.className).toContain(`dark:border-${aile}`)
|
|
322
322
|
expect(thumb.className).toContain('bg-background')
|
|
@@ -327,7 +327,7 @@ describe('#442 render sözleşmesi — <Slider />', () => {
|
|
|
327
327
|
// `trackVariant || thumbVariant || "default"` ve `rangeVariant || thumbVariant ||
|
|
328
328
|
// "primary"` düşüşleri değişmedi; en yaygın kullanım bu yoldan geçer.
|
|
329
329
|
const { container } = render(React.createElement(Slider, { thumbVariant: aile }))
|
|
330
|
-
const { track, range, thumb } =
|
|
330
|
+
const { track, range, thumb } = parts(container)
|
|
331
331
|
expect(track).toHaveClass(`bg-${aile}/20`)
|
|
332
332
|
expect(range.className).toContain(`bg-[rgb(var(--${aile}-700))]`)
|
|
333
333
|
expect(thumb.className).toContain(`border-[rgb(var(--${aile}-700))]`)
|
|
@@ -337,7 +337,7 @@ describe('#442 render sözleşmesi — <Slider />', () => {
|
|
|
337
337
|
const { container } = render(
|
|
338
338
|
React.createElement(Slider, { thumbVariant: 'warning', rangeVariant: 'success' })
|
|
339
339
|
)
|
|
340
|
-
const { range, thumb } =
|
|
340
|
+
const { range, thumb } = parts(container)
|
|
341
341
|
expect(range.className).toContain('bg-success')
|
|
342
342
|
expect(range.className).not.toContain('--warning-700')
|
|
343
343
|
// Eksenler bağımsız: tutamaç kendi varyantını korur.
|
|
@@ -348,7 +348,7 @@ describe('#442 render sözleşmesi — <Slider />', () => {
|
|
|
348
348
|
const { container } = render(
|
|
349
349
|
React.createElement(Slider, { rangeVariant: 'primary', thumbVariant: 'primary' })
|
|
350
350
|
)
|
|
351
|
-
const { range, thumb } =
|
|
351
|
+
const { range, thumb } = parts(container)
|
|
352
352
|
expect(range.className).toContain('bg-primary')
|
|
353
353
|
expect(thumb.className).toContain('border-primary')
|
|
354
354
|
expect(range.className).not.toContain('700')
|
|
@@ -362,13 +362,13 @@ describe.each(AILELER)('#442 %s — kabul kriteri ≥3:1 (WCAG 1.4.11)', (aile)
|
|
|
362
362
|
(blok) => {
|
|
363
363
|
// Ölçülen: warning light 4.235 · dark 6.97 (docs kartı 5.77)
|
|
364
364
|
// error light 4.950 · dark 4.46 (docs kartı 3.82)
|
|
365
|
-
const
|
|
366
|
-
for (const [
|
|
367
|
-
const oran = rgbKontrast(
|
|
368
|
-
expect({
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
365
|
+
const fill = rangeRengi(aile, blok)
|
|
366
|
+
for (const [name, track] of trackler(aile, blok)) {
|
|
367
|
+
const oran = rgbKontrast(fill, track)
|
|
368
|
+
expect({ axis: 'A', background: name, didPass: oran >= 3.0 }).toEqual({
|
|
369
|
+
axis: 'A',
|
|
370
|
+
background: name,
|
|
371
|
+
didPass: true,
|
|
372
372
|
})
|
|
373
373
|
}
|
|
374
374
|
}
|
|
@@ -379,13 +379,13 @@ describe.each(AILELER)('#442 %s — kabul kriteri ≥3:1 (WCAG 1.4.11)', (aile)
|
|
|
379
379
|
(blok) => {
|
|
380
380
|
// Ölçülen: warning light 4.923 · dark 9.45 (docs kartı 8.32)
|
|
381
381
|
// error light 6.470 · dark 5.33 (docs kartı 4.69)
|
|
382
|
-
const
|
|
383
|
-
for (const [
|
|
384
|
-
const oran = rgbKontrast(
|
|
385
|
-
expect({
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
382
|
+
const border = thumbBorderColor(aile, blok)
|
|
383
|
+
for (const [name, background] of backgrounds(blok)) {
|
|
384
|
+
const oran = rgbKontrast(border, background)
|
|
385
|
+
expect({ axis: 'B', background: name, didPass: oran >= 3.0 }).toEqual({
|
|
386
|
+
axis: 'B',
|
|
387
|
+
background: name,
|
|
388
|
+
didPass: true,
|
|
389
389
|
})
|
|
390
390
|
}
|
|
391
391
|
}
|
|
@@ -393,19 +393,19 @@ describe.each(AILELER)('#442 %s — kabul kriteri ≥3:1 (WCAG 1.4.11)', (aile)
|
|
|
393
393
|
|
|
394
394
|
it('ESKİ range (semantik token) LIGHT temada başarısızdı — bug’ın belgesi', () => {
|
|
395
395
|
// warning 1.835 · error 2.893. Düzeltmenin GEREKLİLİĞİNİ sabitler.
|
|
396
|
-
const
|
|
396
|
+
const old = semanticRgb(aile, 'light')
|
|
397
397
|
for (const [, track] of trackler(aile, 'light')) {
|
|
398
|
-
expect(rgbKontrast(
|
|
398
|
+
expect(rgbKontrast(old, track)).toBeLessThan(3.0)
|
|
399
399
|
}
|
|
400
400
|
})
|
|
401
401
|
|
|
402
402
|
it('DARK render DEĞİŞMEDİ — iki eksende de eski semantik token uygulanıyor', () => {
|
|
403
403
|
// Bulgu light'a özgüydü; düzeltmenin dark'ta hiçbir şeyi oynatmaması bilinçli
|
|
404
404
|
// bir kısıt (regresyon yüzeyini sıfıra indirir).
|
|
405
|
-
expect(rangeRengi(aile, 'dark')).toEqual(
|
|
406
|
-
expect(
|
|
405
|
+
expect(rangeRengi(aile, 'dark')).toEqual(semanticRgb(aile, 'dark'))
|
|
406
|
+
expect(thumbBorderColor(aile, 'dark')).toEqual(semanticRgb(aile, 'dark'))
|
|
407
407
|
for (const [, track] of trackler(aile, 'dark')) {
|
|
408
|
-
expect(rgbKontrast(
|
|
408
|
+
expect(rgbKontrast(semanticRgb(aile, 'dark'), track)).toBeGreaterThanOrEqual(3.0)
|
|
409
409
|
}
|
|
410
410
|
})
|
|
411
411
|
|
|
@@ -414,29 +414,29 @@ describe.each(AILELER)('#442 %s — kabul kriteri ≥3:1 (WCAG 1.4.11)', (aile)
|
|
|
414
414
|
// ve `error` tutamacının NEDEN değiştirildiğinin kilidi: kontrastı zaten
|
|
415
415
|
// geçiyordu (3.781), ama range light'ta -700'e inince kenarlığı `border-error`
|
|
416
416
|
// bırakmak iki-tonlu bir görünüm üretirdi.
|
|
417
|
-
expect(
|
|
418
|
-
expect(
|
|
417
|
+
expect(thumbBorderColor(aile, 'light')).toEqual(rangeRengi(aile, 'light'))
|
|
418
|
+
expect(thumbBorderColor(aile, 'dark')).toEqual(rangeRengi(aile, 'dark'))
|
|
419
419
|
})
|
|
420
420
|
})
|
|
421
421
|
|
|
422
422
|
describe('#442 eksen B — ailelerin başlangıç durumu FARKLIYDI (kapsam kararının belgesi)', () => {
|
|
423
423
|
it('ESKİ thumb kenarlığı: warning LIGHT\'ta eşiğin ALTINDAYDI (2.133)', () => {
|
|
424
|
-
const
|
|
425
|
-
for (const [,
|
|
426
|
-
expect(rgbKontrast(
|
|
424
|
+
const old = semanticRgb('warning', 'light')
|
|
425
|
+
for (const [, background] of backgrounds('light')) {
|
|
426
|
+
expect(rgbKontrast(old, background)).toBeLessThan(3.0)
|
|
427
427
|
}
|
|
428
428
|
})
|
|
429
429
|
|
|
430
430
|
it('ESKİ thumb kenarlığı: error LIGHT\'ta zaten geçiyordu (3.781) — değişim gerekçesi tutarlılık', () => {
|
|
431
431
|
// Dürüst kayıt: `error` tutamacı bir kontrast BUG'ı değildi. Aynı ifadeye
|
|
432
432
|
// çekilmesinin sebebi tek-renk tutarlılığı; ölçüm de düşmedi, yükseldi.
|
|
433
|
-
const
|
|
434
|
-
for (const [,
|
|
435
|
-
expect(rgbKontrast(
|
|
433
|
+
const old = semanticRgb('error', 'light')
|
|
434
|
+
for (const [, background] of backgrounds('light')) {
|
|
435
|
+
expect(rgbKontrast(old, background)).toBeGreaterThanOrEqual(3.0)
|
|
436
436
|
}
|
|
437
|
-
const yeni =
|
|
438
|
-
expect(rgbKontrast(yeni,
|
|
439
|
-
rgbKontrast(
|
|
437
|
+
const yeni = thumbBorderColor('error', 'light')
|
|
438
|
+
expect(rgbKontrast(yeni, backgrounds('light')[0][1])).toBeGreaterThan(
|
|
439
|
+
rgbKontrast(old, backgrounds('light')[0][1])
|
|
440
440
|
)
|
|
441
441
|
})
|
|
442
442
|
})
|
|
@@ -446,7 +446,7 @@ describe('#442 seçim gerekçesi — reddedilen alternatifler', () => {
|
|
|
446
446
|
// Issue gövdesinin uyardığı refleks. -700 kademesi dark track'e karşı gerçek
|
|
447
447
|
// docs kartı zemininde eşiğin ALTINDA: warning 2.499 · error 2.232.
|
|
448
448
|
const k700 = rgbTokenRgb(tokenOku(`${aile}-700`, 'light')!)
|
|
449
|
-
const docsTrack = trackler(aile, 'dark').find(([
|
|
449
|
+
const docsTrack = trackler(aile, 'dark').find(([name]) => name === 'gerçek kart #111827')![1]
|
|
450
450
|
expect(rgbKontrast(k700, docsTrack)).toBeLessThan(3.0)
|
|
451
451
|
})
|
|
452
452
|
|
|
@@ -457,22 +457,22 @@ describe('#442 seçim gerekçesi — reddedilen alternatifler', () => {
|
|
|
457
457
|
// skalanın 11 kademesinin HİÇBİRİ tema-kör olarak iki temayı birden geçemiyor.
|
|
458
458
|
// Bu, `dark:` ayrımını zorunlu kılan kanıttır.
|
|
459
459
|
const tumTrackler = [...trackler(aile, 'light'), ...trackler(aile, 'dark')]
|
|
460
|
-
const
|
|
460
|
+
const passedCount = KADEMELER.filter((k) => {
|
|
461
461
|
const ham = tokenOku(`${aile}-${k}`, 'light')
|
|
462
462
|
if (!ham) return false
|
|
463
463
|
const d = rgbTokenRgb(ham)
|
|
464
464
|
return tumTrackler.every(([, t]) => rgbKontrast(d, t) >= 3.0)
|
|
465
465
|
})
|
|
466
|
-
expect(
|
|
466
|
+
expect(passedCount).toEqual([])
|
|
467
467
|
})
|
|
468
468
|
|
|
469
469
|
it.each(AILELER)('%s track alfası düşürülmedi — /20 ayrımı /10\'dan güçlü', (aile) => {
|
|
470
470
|
// Track'i `/10`'a çekmek dolgu↔track'i kazanırken track↔zemin'i harcardı:
|
|
471
471
|
// barın TOPLAM uzunluğu görünmezleşir.
|
|
472
|
-
const
|
|
473
|
-
const sem =
|
|
474
|
-
expect(rgbKontrast(alfaBileske(sem, 0.2,
|
|
475
|
-
rgbKontrast(alfaBileske(sem, 0.1,
|
|
472
|
+
const background = backgrounds('light')[0][1]
|
|
473
|
+
const sem = semanticRgb(aile, 'light')
|
|
474
|
+
expect(rgbKontrast(alfaBileske(sem, 0.2, background), background)).toBeGreaterThan(
|
|
475
|
+
rgbKontrast(alfaBileske(sem, 0.1, background), background)
|
|
476
476
|
)
|
|
477
477
|
})
|
|
478
478
|
})
|