@moontra/moonui 6.15.0 → 6.16.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui",
3
- "version": "6.15.0",
3
+ "version": "6.16.0",
4
4
  "description": "Premium React component library with modern design and customization",
5
5
  "author": "MoonUI",
6
6
  "license": "MIT",
@@ -0,0 +1,65 @@
1
+ /**
2
+ * #340 — `SelectTrigger` erişilebilir ad taşır.
3
+ *
4
+ * BULGUNUN İNCELİĞİ: docs'ta hiçbir tetikleyici etiketsiz değildi — hepsinde
5
+ * `<SelectValue placeholder="Select a theme" />` vardı ve metin ekranda GÖRÜNÜYORDU.
6
+ * Yine de axe 10 `button-name` ihlali sayıyordu. Sebebi axe'ın açıklaması verdi:
7
+ *
8
+ * "Element does not have inner text that is visible to screen readers"
9
+ *
10
+ * `SelectPrimitive.Trigger` `role="combobox"` render eder ve ARIA'da bu rol
11
+ * **"name from author"**dur — erişilebilir ad İÇERİKTEN GELMEZ. Yani görünür metin
12
+ * gözle okunur ama ekran okuyucuya hiç ad taşımaz.
13
+ *
14
+ * Sonuç: `aria-label` verilmeyen HER MoonUI Select adsızdı. Bu bir docs örneği
15
+ * kusuru değil, component yüzeyiydi.
16
+ */
17
+ import * as React from 'react'
18
+ import { render, screen } from '@testing-library/react'
19
+ import '@testing-library/jest-dom'
20
+
21
+ import { Select, SelectTrigger, SelectValue } from '../select'
22
+
23
+ const kur = (props: React.ComponentProps<typeof SelectTrigger> = {}) =>
24
+ render(
25
+ <Select>
26
+ <SelectTrigger {...props}>
27
+ <SelectValue placeholder="Select a theme" />
28
+ </SelectTrigger>
29
+ </Select>
30
+ )
31
+
32
+ describe('#340 SelectTrigger erişilebilir ad', () => {
33
+ it('ad verilmezse GÖRÜNÜR içerik ada bağlanır', () => {
34
+ kur()
35
+ // `role="combobox"` içerikten ad almadığı için component `aria-labelledby`
36
+ // ile açıkça bağlamak zorunda.
37
+ expect(screen.getByRole('combobox')).toHaveAccessibleName('Select a theme')
38
+ })
39
+
40
+ it('tüketicinin `aria-label`i KAZANIR', () => {
41
+ kur({ 'aria-label': 'Theme selector' })
42
+ expect(screen.getByRole('combobox')).toHaveAccessibleName('Theme selector')
43
+ })
44
+
45
+ it('tüketicinin `aria-labelledby`si KORUNUR (ezilmez)', () => {
46
+ render(
47
+ <>
48
+ <span id="dis-etiket">Appearance</span>
49
+ <Select>
50
+ <SelectTrigger aria-labelledby="dis-etiket">
51
+ <SelectValue placeholder="Select a theme" />
52
+ </SelectTrigger>
53
+ </Select>
54
+ </>
55
+ )
56
+ expect(screen.getByRole('combobox')).toHaveAccessibleName('Appearance')
57
+ })
58
+
59
+ it('rol gerçekten `combobox` — bu testin varsayımı ayakta', () => {
60
+ // Radix rolü değiştirirse (ör. `button`) ad-içerikten-gelir kuralı geçerli olur
61
+ // ve bu bekçinin gerekçesi düşer. O zaman bilinçli gözden geçirilmeli.
62
+ kur()
63
+ expect(screen.getByRole('combobox')).toBeInTheDocument()
64
+ })
65
+ })
@@ -100,7 +100,24 @@ export interface SelectTriggerProps extends React.ComponentPropsWithoutRef<typeo
100
100
  const SelectTrigger = React.forwardRef<
101
101
  React.ElementRef<typeof SelectPrimitive.Trigger>,
102
102
  SelectTriggerProps
103
- >(({ className, children, variant, size, error, success, loading, leftIcon, rightIcon, ...props }, ref) => (
103
+ >(({ className, children, variant, size, error, success, loading, leftIcon, rightIcon, ...props }, ref) => {
104
+ /**
105
+ * #340: `SelectPrimitive.Trigger` `role="combobox"` render eder. ARIA'da bu rol
106
+ * **"name from author"**dur — yani erişilebilir ad İÇERİKTEN GELMEZ. Tetikleyicinin
107
+ * içindeki görünür metin ("Select a theme") gözle okunur ama ekran okuyucuya HİÇ
108
+ * ad taşımaz; axe bunu `button-name` (critical) sayar.
109
+ *
110
+ * Sonuç: `aria-label` verilmeyen HER MoonUI Select adsızdı — docs örneği değil,
111
+ * component yüzeyi. Bu yüzden tetikleyicinin görünür içeriğine bir id verilip
112
+ * `aria-labelledby` ile ona bağlanıyor: ad, kullanıcının GÖRDÜĞÜ metin olur.
113
+ *
114
+ * Tüketici kendi `aria-label`/`aria-labelledby`sini verdiyse ona dokunulmaz.
115
+ */
116
+ const icerikId = React.useId()
117
+ const adVerilmis =
118
+ props["aria-label"] != null || props["aria-labelledby"] != null
119
+
120
+ return (
104
121
  <SelectPrimitive.Trigger
105
122
  ref={ref}
106
123
  className={cn(
@@ -119,8 +136,9 @@ const SelectTrigger = React.forwardRef<
119
136
  data-error={error ? true : undefined}
120
137
  data-success={success ? true : undefined}
121
138
  data-loading={loading ? true : undefined}
139
+ aria-labelledby={adVerilmis ? props["aria-labelledby"] : icerikId}
122
140
  >
123
- <div className="flex items-center flex-1 gap-2">
141
+ <div id={icerikId} className="flex items-center flex-1 gap-2">
124
142
  {leftIcon && (
125
143
  <span className="flex items-center justify-center text-muted-foreground">
126
144
  {leftIcon}
@@ -143,7 +161,8 @@ const SelectTrigger = React.forwardRef<
143
161
  </SelectPrimitive.Icon>
144
162
  )}
145
163
  </SelectPrimitive.Trigger>
146
- ))
164
+ )
165
+ })
147
166
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
148
167
 
149
168
  /**