|
1 | 1 | // `V extends any` is the "force-distribution" idiom: it keeps `V` naked in the outer |
2 | 2 | // conditional so the check distributes across union variants. That matters for slot |
3 | 3 | // types shaped as `T | (T & DataAttributes)` (the `WithDataAttributes` widening) — the |
4 | | -// assertion passes as soon as one branch exposes both keys, while a non-widened branch |
5 | | -// failing on its own is fine. |
| 4 | +// assertion passes as soon as one branch exposes the marker key, while a non-widened |
| 5 | +// branch failing on its own is fine. |
6 | 6 | // |
7 | | -// `'data-x'` and `'aria-label'` are used as marker keys. `'data-x'` matches the |
| 7 | +// `'data-x'` is used as the marker key: it matches the |
8 | 8 | // ` [k: `data-${string}`]: ... ` template-literal index signature exposed by |
9 | | -// `DataAttributes`, and `'aria-label'` stands in for the `React.AriaAttributes` shape |
10 | | -// (whose keys are otherwise all optional, which would make a direct structural check |
11 | | -// trivially satisfied). Both markers are present only when the variant has been widened via |
12 | | -// `DataAttributes`. |
13 | | -type AcceptsDataAndAria<V> = V extends any |
14 | | - ? 'data-x' extends keyof V |
15 | | - ? 'aria-label' extends keyof V |
16 | | - ? true |
17 | | - : false |
18 | | - : false |
19 | | - : never; |
| 9 | +// `DataAttributes`, and is present only when the variant has been widened via |
| 10 | +// `DataAttributes`. `aria-*` is not checked here — every real slot inner type in |
| 11 | +// MUI X inherits `React.AriaAttributes` through its element or component base type, |
| 12 | +// so aria coverage is a structural property of the inner type, not something this |
| 13 | +// widener needs to re-verify. |
| 14 | +type AcceptsDataAttributes<V> = V extends any ? ('data-x' extends keyof V ? true : false) : never; |
20 | 15 |
|
21 | 16 | type CheckVariant<V> = V extends (...args: any[]) => infer R |
22 | | - ? AcceptsDataAndAria<R> |
23 | | - : AcceptsDataAndAria<V>; |
| 17 | + ? AcceptsDataAttributes<R> |
| 18 | + : AcceptsDataAttributes<V>; |
24 | 19 |
|
25 | 20 | type SlotAcceptsDataAttributes<T> = true extends CheckVariant<NonNullable<T>> ? true : false; |
26 | 21 |
|
27 | 22 | /** |
28 | 23 | * Maps each slot of a `*SlotProps` type to either `true` or a failure message |
29 | | - * identifying the slot that does not accept `data-*` / `aria-*` attributes. |
| 24 | + * identifying the slot that does not accept `data-*` attributes. |
30 | 25 | * |
31 | | - * The check probes each slot's value type for both the |
| 26 | + * The check probes each slot's value type for the |
32 | 27 | * `` [key: `data-${string}`]: ... `` index signature (covering arbitrary |
33 | | - * `data-*` keys) and `'aria-label'` as the marker aria attribute (standing in |
34 | | - * for the full `React.AriaAttributes` surface). The check distributes across |
35 | | - * union variants and unwraps function variants to their return type; any |
36 | | - * variant providing both signatures — typically via an intersection with |
37 | | - * `DataAttributes` — passes. |
| 28 | + * `data-*` keys). The check distributes across union variants and unwraps |
| 29 | + * function variants to their return type; any variant providing the signature |
| 30 | + * — typically via an intersection with `DataAttributes` — passes. |
38 | 31 | */ |
39 | 32 | export type AssertAllSlotsAcceptDataAttributes<T, Name extends string = 'Component'> = { |
40 | 33 | [K in keyof T]-?: SlotAcceptsDataAttributes<T[K]> extends true |
41 | 34 | ? true |
42 | | - : `FAIL [${Name}.${Extract<K, string>}]: slot must accept data-* and aria-* attributes. Use SlotComponentPropsFromProps.`; |
| 35 | + : `FAIL [${Name}.${Extract<K, string>}]: slot must accept data-* attributes. Use SlotComponentPropsFromProps.`; |
43 | 36 | }; |
44 | 37 |
|
45 | 38 | /** |
|
0 commit comments