@khanacademy/wonder-blocks-card 0.0.0-PR2903-20251211204408 → 0.0.0-PR2904-20251211205241
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/CHANGELOG.md +5 -6
- package/dist/components/card.d.ts +0 -2
- package/dist/components/dismiss-button.d.ts +0 -2
- package/dist/es/index.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +4 -4
- package/dist/__tests__/components/card.test.d.ts +0 -1
- package/dist/__tests__/components/card.typestest.d.ts +0 -1
- package/dist/__tests__/components/dismiss-button.test.d.ts +0 -1
- package/src/__tests__/components/card.test.tsx +0 -301
- package/src/__tests__/components/card.typestest.tsx +0 -207
- package/src/__tests__/components/dismiss-button.test.tsx +0 -158
- package/src/components/card.tsx +0 -308
- package/src/components/dismiss-button.tsx +0 -53
- package/src/index.ts +0 -3
- package/tsconfig-build.json +0 -16
- package/tsconfig-build.tsbuildinfo +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-card
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
4
|
-
|
|
5
|
-
### Minor Changes
|
|
6
|
-
|
|
7
|
-
- 0a5444d: Expose aria-describedby attribute of the Dismiss button
|
|
3
|
+
## 0.0.0-PR2904-20251211205241
|
|
8
4
|
|
|
9
5
|
### Patch Changes
|
|
10
6
|
|
|
11
|
-
-
|
|
7
|
+
- Updated dependencies [169a6bf]
|
|
8
|
+
- @khanacademy/wonder-blocks-core@0.0.0-PR2904-20251211205241
|
|
9
|
+
- @khanacademy/wonder-blocks-icon-button@0.0.0-PR2904-20251211205241
|
|
10
|
+
- @khanacademy/wonder-blocks-tokens@14.1.3
|
|
12
11
|
|
|
13
12
|
## 1.3.2
|
|
14
13
|
|
|
@@ -121,7 +121,6 @@ declare const Card: React.ForwardRefExoticComponent<(Omit<{
|
|
|
121
121
|
onDismiss: (e?: React.SyntheticEvent) => void;
|
|
122
122
|
labels: {
|
|
123
123
|
dismissButtonAriaLabel: string;
|
|
124
|
-
dismissButtonAriaDescribedBy?: string;
|
|
125
124
|
} & Record<string, any>;
|
|
126
125
|
}, "ref"> | Omit<{
|
|
127
126
|
/**
|
|
@@ -212,7 +211,6 @@ declare const Card: React.ForwardRefExoticComponent<(Omit<{
|
|
|
212
211
|
onDismiss: (e?: React.SyntheticEvent) => void;
|
|
213
212
|
labels: {
|
|
214
213
|
dismissButtonAriaLabel: string;
|
|
215
|
-
dismissButtonAriaDescribedBy?: string;
|
|
216
214
|
} & Record<string, any>;
|
|
217
215
|
}, "ref"> | Omit<{
|
|
218
216
|
/**
|
|
@@ -5,8 +5,6 @@ type Props = {
|
|
|
5
5
|
onClick?: (e?: React.SyntheticEvent) => unknown;
|
|
6
6
|
/** Screen reader label for close button */
|
|
7
7
|
"aria-label"?: string;
|
|
8
|
-
/** Optional aria-describedby attribute */
|
|
9
|
-
"aria-describedby"?: string;
|
|
10
8
|
/** Optional custom styles. */
|
|
11
9
|
style?: StyleType;
|
|
12
10
|
/** Test ID used for e2e testing, passed down from its parent card.*/
|
package/dist/es/index.js
CHANGED
|
@@ -7,8 +7,8 @@ import xIcon from '@phosphor-icons/core/bold/x-bold.svg';
|
|
|
7
7
|
import IconButton from '@khanacademy/wonder-blocks-icon-button';
|
|
8
8
|
import { focusStyles } from '@khanacademy/wonder-blocks-styles';
|
|
9
9
|
|
|
10
|
-
const DismissButton=props=>{const{onClick,style,testId
|
|
10
|
+
const DismissButton=props=>{const{onClick,style,testId}=props;return jsx(IconButton,{icon:xIcon,"aria-label":props["aria-label"]||"Close",onClick:onClick,kind:"tertiary",actionType:"neutral",style:[componentStyles.root,style],testId:testId})};const componentStyles=StyleSheet.create({root:{position:"absolute",insetInlineEnd:sizing.size_080,top:sizing.size_080,zIndex:1,":focus":focusStyles.focus[":focus-visible"]}});
|
|
11
11
|
|
|
12
|
-
const Card=React.forwardRef(function Card(props,ref){const{styles,labels,tag,testId,background="base-default",borderRadius="small",paddingSize="small",elevation="none",children,onDismiss,inert,"aria-labelledby":ariaLabelledBy,"aria-busy":ariaBusy,role}=props;const isBackgroundToken=background==="base-default"||background==="base-subtle";const componentStyles=getComponentStyles({background:isBackgroundToken?background:null,borderRadius,paddingSize,elevation});return jsxs(View,{"aria-busy":ariaBusy,"aria-label":labels?.cardAriaLabel,"aria-labelledby":ariaLabelledBy,style:[componentStyles.root,!isBackgroundToken&&{background:`url(${background})`,backgroundSize:"cover"},styles?.root],ref:ref,role:role,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",
|
|
12
|
+
const Card=React.forwardRef(function Card(props,ref){const{styles,labels,tag,testId,background="base-default",borderRadius="small",paddingSize="small",elevation="none",children,onDismiss,inert,"aria-labelledby":ariaLabelledBy,"aria-busy":ariaBusy,role}=props;const isBackgroundToken=background==="base-default"||background==="base-subtle";const componentStyles=getComponentStyles({background:isBackgroundToken?background:null,borderRadius,paddingSize,elevation});return jsxs(View,{"aria-busy":ariaBusy,"aria-label":labels?.cardAriaLabel,"aria-labelledby":ariaLabelledBy,style:[componentStyles.root,!isBackgroundToken&&{background:`url(${background})`,backgroundSize:"cover"},styles?.root],ref:ref,role:role,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",onClick:e=>onDismiss?.(e),testId:testId&&`${testId}-dismiss-button`}):null,children]})});const styleMap={backgroundColor:{"base-subtle":semanticColor.core.background.base.subtle,"base-default":semanticColor.core.background.base.default},borderRadius:{small:border.radius.radius_080,medium:border.radius.radius_120},padding:{none:sizing.size_0,small:sizing.size_160,medium:sizing.size_240},elevation:{none:"none",low:boxShadow.low}};const getComponentStyles=({background="base-default",borderRadius="small",paddingSize="small",elevation="none"})=>{const bgColor=background;return StyleSheet.create({root:{backgroundColor:bgColor&&styleMap.backgroundColor[bgColor],borderColor:semanticColor.core.border.neutral.subtle,borderStyle:"solid",borderWidth:border.width.thin,fontFamily:font.family.sans,minInlineSize:sizing.size_280,position:"relative",borderRadius:styleMap.borderRadius[borderRadius],boxShadow:styleMap.elevation[elevation],padding:styleMap.padding[paddingSize]}})};
|
|
13
13
|
|
|
14
14
|
export { Card };
|
package/dist/index.js
CHANGED
|
@@ -35,8 +35,8 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
|
35
35
|
var xIcon__default = /*#__PURE__*/_interopDefaultLegacy(xIcon);
|
|
36
36
|
var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
|
|
37
37
|
|
|
38
|
-
const DismissButton=props=>{const{onClick,style,testId
|
|
38
|
+
const DismissButton=props=>{const{onClick,style,testId}=props;return jsxRuntime.jsx(IconButton__default["default"],{icon:xIcon__default["default"],"aria-label":props["aria-label"]||"Close",onClick:onClick,kind:"tertiary",actionType:"neutral",style:[componentStyles.root,style],testId:testId})};const componentStyles=aphrodite.StyleSheet.create({root:{position:"absolute",insetInlineEnd:wonderBlocksTokens.sizing.size_080,top:wonderBlocksTokens.sizing.size_080,zIndex:1,":focus":wonderBlocksStyles.focusStyles.focus[":focus-visible"]}});
|
|
39
39
|
|
|
40
|
-
const Card=React__namespace.forwardRef(function Card(props,ref){const{styles,labels,tag,testId,background="base-default",borderRadius="small",paddingSize="small",elevation="none",children,onDismiss,inert,"aria-labelledby":ariaLabelledBy,"aria-busy":ariaBusy,role}=props;const isBackgroundToken=background==="base-default"||background==="base-subtle";const componentStyles=getComponentStyles({background:isBackgroundToken?background:null,borderRadius,paddingSize,elevation});return jsxRuntime.jsxs(wonderBlocksCore.View,{"aria-busy":ariaBusy,"aria-label":labels?.cardAriaLabel,"aria-labelledby":ariaLabelledBy,style:[componentStyles.root,!isBackgroundToken&&{background:`url(${background})`,backgroundSize:"cover"},styles?.root],ref:ref,role:role,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsxRuntime.jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",
|
|
40
|
+
const Card=React__namespace.forwardRef(function Card(props,ref){const{styles,labels,tag,testId,background="base-default",borderRadius="small",paddingSize="small",elevation="none",children,onDismiss,inert,"aria-labelledby":ariaLabelledBy,"aria-busy":ariaBusy,role}=props;const isBackgroundToken=background==="base-default"||background==="base-subtle";const componentStyles=getComponentStyles({background:isBackgroundToken?background:null,borderRadius,paddingSize,elevation});return jsxRuntime.jsxs(wonderBlocksCore.View,{"aria-busy":ariaBusy,"aria-label":labels?.cardAriaLabel,"aria-labelledby":ariaLabelledBy,style:[componentStyles.root,!isBackgroundToken&&{background:`url(${background})`,backgroundSize:"cover"},styles?.root],ref:ref,role:role,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsxRuntime.jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",onClick:e=>onDismiss?.(e),testId:testId&&`${testId}-dismiss-button`}):null,children]})});const styleMap={backgroundColor:{"base-subtle":wonderBlocksTokens.semanticColor.core.background.base.subtle,"base-default":wonderBlocksTokens.semanticColor.core.background.base.default},borderRadius:{small:wonderBlocksTokens.border.radius.radius_080,medium:wonderBlocksTokens.border.radius.radius_120},padding:{none:wonderBlocksTokens.sizing.size_0,small:wonderBlocksTokens.sizing.size_160,medium:wonderBlocksTokens.sizing.size_240},elevation:{none:"none",low:wonderBlocksTokens.boxShadow.low}};const getComponentStyles=({background="base-default",borderRadius="small",paddingSize="small",elevation="none"})=>{const bgColor=background;return aphrodite.StyleSheet.create({root:{backgroundColor:bgColor&&styleMap.backgroundColor[bgColor],borderColor:wonderBlocksTokens.semanticColor.core.border.neutral.subtle,borderStyle:"solid",borderWidth:wonderBlocksTokens.border.width.thin,fontFamily:wonderBlocksTokens.font.family.sans,minInlineSize:wonderBlocksTokens.sizing.size_280,position:"relative",borderRadius:styleMap.borderRadius[borderRadius],boxShadow:styleMap.elevation[elevation],padding:styleMap.padding[paddingSize]}})};
|
|
41
41
|
|
|
42
42
|
exports.Card = Card;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Card component for Wonder Blocks.",
|
|
4
4
|
"author": "Khan Academy",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.0.0-
|
|
6
|
+
"version": "0.0.0-PR2904-20251211205241",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"types": "dist/index.d.ts",
|
|
22
22
|
"source": "src/index.js",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@khanacademy/wonder-blocks-core": "
|
|
25
|
-
"@khanacademy/wonder-blocks-icon-button": "
|
|
24
|
+
"@khanacademy/wonder-blocks-core": "0.0.0-PR2904-20251211205241",
|
|
25
|
+
"@khanacademy/wonder-blocks-icon-button": "0.0.0-PR2904-20251211205241",
|
|
26
26
|
"@khanacademy/wonder-blocks-tokens": "14.1.3"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@phosphor-icons/core": "^2.0.2"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@khanacademy/wb-dev-build-settings": "
|
|
34
|
+
"@khanacademy/wb-dev-build-settings": "0.0.0-PR2904-20251211205241"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render, screen} from "@testing-library/react";
|
|
3
|
-
import {userEvent} from "@testing-library/user-event";
|
|
4
|
-
|
|
5
|
-
import Card from "../../components/card";
|
|
6
|
-
|
|
7
|
-
describe("Card", () => {
|
|
8
|
-
describe("Basic rendering", () => {
|
|
9
|
-
it("should render children correctly", () => {
|
|
10
|
-
// Arrange
|
|
11
|
-
render(
|
|
12
|
-
<Card>
|
|
13
|
-
<div data-testid="child-content">Card Content</div>
|
|
14
|
-
</Card>,
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
// Act
|
|
18
|
-
const childContent = screen.getByTestId("child-content");
|
|
19
|
-
|
|
20
|
-
// Assert
|
|
21
|
-
expect(childContent).toBeInTheDocument();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("should not render dismiss button by default", () => {
|
|
25
|
-
// Arrange
|
|
26
|
-
render(
|
|
27
|
-
<Card>
|
|
28
|
-
<div>Content</div>
|
|
29
|
-
</Card>,
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
// Act
|
|
33
|
-
const dismissButton = screen.queryByRole("button");
|
|
34
|
-
|
|
35
|
-
// Assert
|
|
36
|
-
expect(dismissButton).not.toBeInTheDocument();
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe("Dismiss button functionality", () => {
|
|
41
|
-
it("should render dismiss button when onDismiss is present", () => {
|
|
42
|
-
// Arrange
|
|
43
|
-
render(
|
|
44
|
-
<Card
|
|
45
|
-
onDismiss={() => {}}
|
|
46
|
-
labels={{dismissButtonAriaLabel: "Close"}}
|
|
47
|
-
>
|
|
48
|
-
<div>Content</div>
|
|
49
|
-
</Card>,
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
// Act
|
|
53
|
-
const dismissButton = screen.getByRole("button");
|
|
54
|
-
|
|
55
|
-
// Assert
|
|
56
|
-
expect(dismissButton).toBeInTheDocument();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("should not render dismiss button there is no onDismiss prop", () => {
|
|
60
|
-
// Arrange
|
|
61
|
-
render(
|
|
62
|
-
<Card>
|
|
63
|
-
<div>Content</div>
|
|
64
|
-
</Card>,
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
// Act
|
|
68
|
-
const dismissButton = screen.queryByRole("button");
|
|
69
|
-
|
|
70
|
-
// Assert
|
|
71
|
-
expect(dismissButton).not.toBeInTheDocument();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("should call onDismiss when dismiss button is clicked", async () => {
|
|
75
|
-
// Arrange
|
|
76
|
-
const mockOnDismiss = jest.fn();
|
|
77
|
-
render(
|
|
78
|
-
<Card
|
|
79
|
-
labels={{dismissButtonAriaLabel: "Close it!"}}
|
|
80
|
-
onDismiss={mockOnDismiss}
|
|
81
|
-
>
|
|
82
|
-
<div>Content</div>
|
|
83
|
-
</Card>,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
// Act
|
|
87
|
-
const dismissButton = screen.getByRole("button", {
|
|
88
|
-
name: "Close it!",
|
|
89
|
-
});
|
|
90
|
-
await userEvent.click(dismissButton);
|
|
91
|
-
|
|
92
|
-
// Assert
|
|
93
|
-
expect(mockOnDismiss).toHaveBeenCalledTimes(1);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe("Test IDs", () => {
|
|
98
|
-
it("should apply a custom testId for card", () => {
|
|
99
|
-
// Arrange
|
|
100
|
-
render(
|
|
101
|
-
<Card testId="my-card">
|
|
102
|
-
<div>Content</div>
|
|
103
|
-
</Card>,
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
// Act
|
|
107
|
-
const card = screen.getByTestId("my-card");
|
|
108
|
-
|
|
109
|
-
// Assert
|
|
110
|
-
expect(card).toBeInTheDocument();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("should append -dismiss-button to testId for dismiss button", () => {
|
|
114
|
-
// Arrange
|
|
115
|
-
render(
|
|
116
|
-
<Card
|
|
117
|
-
testId="my-card"
|
|
118
|
-
onDismiss={() => {}}
|
|
119
|
-
labels={{dismissButtonAriaLabel: "Close"}}
|
|
120
|
-
>
|
|
121
|
-
<div>Content</div>
|
|
122
|
-
</Card>,
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
// Act
|
|
126
|
-
const dismissButton = screen.getByTestId("my-card-dismiss-button");
|
|
127
|
-
|
|
128
|
-
// Assert
|
|
129
|
-
expect(dismissButton).toBeInTheDocument();
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
describe("Accessibility", () => {
|
|
134
|
-
it("should pass custom aria-label to dismiss button", () => {
|
|
135
|
-
// Arrange
|
|
136
|
-
render(
|
|
137
|
-
<Card
|
|
138
|
-
onDismiss={() => {}}
|
|
139
|
-
labels={{dismissButtonAriaLabel: "Custom Close"}}
|
|
140
|
-
>
|
|
141
|
-
<div>Content</div>
|
|
142
|
-
</Card>,
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
// Act
|
|
146
|
-
const dismissButton = screen.getByRole("button", {
|
|
147
|
-
name: "Custom Close",
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// Assert
|
|
151
|
-
expect(dismissButton).toBeInTheDocument();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it("should pass custom aria-describedby to dismiss button", () => {
|
|
155
|
-
// Arrange
|
|
156
|
-
render(
|
|
157
|
-
<Card
|
|
158
|
-
onDismiss={() => {}}
|
|
159
|
-
labels={{
|
|
160
|
-
dismissButtonAriaLabel: "Custom Close",
|
|
161
|
-
dismissButtonAriaDescribedBy:
|
|
162
|
-
"dismiss-button-describedby",
|
|
163
|
-
}}
|
|
164
|
-
>
|
|
165
|
-
<div>Content</div>
|
|
166
|
-
</Card>,
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
// Act
|
|
170
|
-
const dismissButton = screen.getByRole("button", {
|
|
171
|
-
name: "Custom Close",
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
// Assert
|
|
175
|
-
expect(dismissButton).toHaveAttribute(
|
|
176
|
-
"aria-describedby",
|
|
177
|
-
"dismiss-button-describedby",
|
|
178
|
-
);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it("should render with a custom tag", () => {
|
|
182
|
-
// Arrange
|
|
183
|
-
render(
|
|
184
|
-
<Card tag="section" labels={{cardAriaLabel: "Card Section"}}>
|
|
185
|
-
<h2>Heading</h2>
|
|
186
|
-
<p>Description</p>
|
|
187
|
-
</Card>,
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
// Act
|
|
191
|
-
const section = screen.getByRole("region");
|
|
192
|
-
|
|
193
|
-
// Assert
|
|
194
|
-
expect(section).toBeInTheDocument();
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it("should apply labels.cardAriaLabel for a custom tag (preferred)", () => {
|
|
198
|
-
// Arrange
|
|
199
|
-
render(
|
|
200
|
-
<Card
|
|
201
|
-
tag="section"
|
|
202
|
-
labels={{cardAriaLabel: "Custom section label"}}
|
|
203
|
-
>
|
|
204
|
-
<h2>Heading</h2>
|
|
205
|
-
<p>Description</p>
|
|
206
|
-
</Card>,
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Act
|
|
210
|
-
const section = screen.getByRole("region", {
|
|
211
|
-
name: "Custom section label",
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Assert
|
|
215
|
-
expect(section).toBeInTheDocument();
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it("should apply aria-labelledby for a custom tag", () => {
|
|
219
|
-
// Arrange
|
|
220
|
-
render(
|
|
221
|
-
<div>
|
|
222
|
-
<h2 id="card-heading">My Card Title</h2>
|
|
223
|
-
<Card tag="section" aria-labelledby="card-heading">
|
|
224
|
-
<p>Description</p>
|
|
225
|
-
</Card>
|
|
226
|
-
</div>,
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
// Act
|
|
230
|
-
const section = screen.getByRole("region", {
|
|
231
|
-
name: "My Card Title",
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// Assert
|
|
235
|
-
expect(section).toBeInTheDocument();
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it("should only apply aria-labelledby", () => {
|
|
239
|
-
// Arrange
|
|
240
|
-
render(
|
|
241
|
-
<div>
|
|
242
|
-
<h2 id="card-heading">My Card Title</h2>
|
|
243
|
-
<Card
|
|
244
|
-
tag="section"
|
|
245
|
-
aria-labelledby="card-heading"
|
|
246
|
-
aria-label="Fallback label"
|
|
247
|
-
>
|
|
248
|
-
<p>Description</p>
|
|
249
|
-
</Card>
|
|
250
|
-
</div>,
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
// Act
|
|
254
|
-
const section = screen.getByRole("region", {
|
|
255
|
-
name: "My Card Title",
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
// Assert
|
|
259
|
-
expect(section).toBeInTheDocument();
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it("should apply the inert attribute", () => {
|
|
263
|
-
// Arrange
|
|
264
|
-
render(
|
|
265
|
-
<Card inert testId="card">
|
|
266
|
-
<h2>Heading</h2>
|
|
267
|
-
<p>Description</p>
|
|
268
|
-
<button>Button</button>
|
|
269
|
-
</Card>,
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
// Act
|
|
273
|
-
const section = screen.getByTestId("card");
|
|
274
|
-
|
|
275
|
-
// Assert
|
|
276
|
-
expect(section).toHaveAttribute("inert");
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
describe("Complex content scenarios", () => {
|
|
281
|
-
it("should work with fragment children", () => {
|
|
282
|
-
// Arrange
|
|
283
|
-
render(
|
|
284
|
-
<Card>
|
|
285
|
-
<>
|
|
286
|
-
<span data-testid="fragment-child-1">First</span>
|
|
287
|
-
<span data-testid="fragment-child-2">Second</span>
|
|
288
|
-
</>
|
|
289
|
-
</Card>,
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
// Act
|
|
293
|
-
const firstChild = screen.getByTestId("fragment-child-1");
|
|
294
|
-
const secondChild = screen.getByTestId("fragment-child-2");
|
|
295
|
-
|
|
296
|
-
// Assert
|
|
297
|
-
expect(firstChild).toBeInTheDocument();
|
|
298
|
-
expect(secondChild).toBeInTheDocument();
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
});
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
// Import Button and Link for proper usage examples
|
|
4
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
5
|
-
import Link from "@khanacademy/wonder-blocks-link";
|
|
6
|
-
import Card from "../../components/card";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Basic Card usage
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
<Card>Hello, world!</Card>;
|
|
13
|
-
|
|
14
|
-
<Card>
|
|
15
|
-
<div>Some content</div>
|
|
16
|
-
</Card>;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Card with Button and Link components (correct usage)
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
<Card>
|
|
23
|
-
<Button onClick={() => {}}>Click me</Button>
|
|
24
|
-
</Card>;
|
|
25
|
-
|
|
26
|
-
<Card>
|
|
27
|
-
<Link href="/foo">Click me</Link>
|
|
28
|
-
</Card>;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Card with all style props
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
<Card
|
|
35
|
-
background="base-default"
|
|
36
|
-
borderRadius="small"
|
|
37
|
-
paddingSize="small"
|
|
38
|
-
elevation="none"
|
|
39
|
-
>
|
|
40
|
-
Content
|
|
41
|
-
</Card>;
|
|
42
|
-
|
|
43
|
-
<Card
|
|
44
|
-
background="base-subtle"
|
|
45
|
-
borderRadius="medium"
|
|
46
|
-
paddingSize="medium"
|
|
47
|
-
elevation="low"
|
|
48
|
-
>
|
|
49
|
-
Content
|
|
50
|
-
</Card>;
|
|
51
|
-
|
|
52
|
-
<Card paddingSize="none">Content</Card>;
|
|
53
|
-
|
|
54
|
-
// @ts-expect-error - invalid background value
|
|
55
|
-
<Card background="invalid-background">Content</Card>;
|
|
56
|
-
|
|
57
|
-
// @ts-expect-error - invalid borderRadius value
|
|
58
|
-
<Card borderRadius="invalid-radius">Content</Card>;
|
|
59
|
-
|
|
60
|
-
// @ts-expect-error - invalid paddingSize value
|
|
61
|
-
<Card paddingSize="invalid-padding">Content</Card>;
|
|
62
|
-
|
|
63
|
-
// @ts-expect-error - invalid elevation value
|
|
64
|
-
<Card elevation="invalid-elevation">Content</Card>;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Card with dismiss functionality
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
<Card onDismiss={() => {}} labels={{dismissButtonAriaLabel: "Close card"}}>
|
|
71
|
-
Content
|
|
72
|
-
</Card>;
|
|
73
|
-
|
|
74
|
-
// @ts-expect-error - onDismiss requires dismissButtonAriaLabel
|
|
75
|
-
<Card onDismiss={() => {}}>Content</Card>;
|
|
76
|
-
|
|
77
|
-
// @ts-expect-error - onDismiss requires dismissButtonAriaLabel
|
|
78
|
-
<Card onDismiss={() => {}} labels={{}}>
|
|
79
|
-
Content
|
|
80
|
-
</Card>;
|
|
81
|
-
|
|
82
|
-
// @ts-expect-error - onClick is not allowed on Card wrapper
|
|
83
|
-
<Card onClick={() => {}}>Content</Card>;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Card with different HTML tags
|
|
87
|
-
*/
|
|
88
|
-
|
|
89
|
-
<Card tag="div">Content</Card>;
|
|
90
|
-
|
|
91
|
-
// @ts-expect-error - button tag not allowed, use Wonder Blocks Button component instead
|
|
92
|
-
<Card tag="button">Content</Card>;
|
|
93
|
-
|
|
94
|
-
// @ts-expect-error - anchor tag not allowed, use Wonder Blocks Link component instead
|
|
95
|
-
<Card tag="a">Content</Card>;
|
|
96
|
-
|
|
97
|
-
<Card tag="section" labels={{cardAriaLabel: "Card section"}}>
|
|
98
|
-
Content
|
|
99
|
-
</Card>;
|
|
100
|
-
|
|
101
|
-
<Card tag="figure" labels={{cardAriaLabel: "Card figure"}}>
|
|
102
|
-
Content
|
|
103
|
-
</Card>;
|
|
104
|
-
|
|
105
|
-
<Card tag="section" aria-label="Card section">
|
|
106
|
-
Content
|
|
107
|
-
</Card>;
|
|
108
|
-
|
|
109
|
-
<Card tag="figure" aria-label="Card figure">
|
|
110
|
-
Content
|
|
111
|
-
</Card>;
|
|
112
|
-
|
|
113
|
-
<Card tag="section" aria-labelledby="someId">
|
|
114
|
-
<h2 id="someId">Card title</h2>
|
|
115
|
-
</Card>;
|
|
116
|
-
|
|
117
|
-
<Card tag="figure" aria-labelledby="someId2">
|
|
118
|
-
<h2 id="someId2">Card title</h2>
|
|
119
|
-
</Card>;
|
|
120
|
-
|
|
121
|
-
// @ts-expect-error - aria-labelledby cannot be used with labels.cardAriaLabel
|
|
122
|
-
<Card
|
|
123
|
-
tag="figure"
|
|
124
|
-
aria-labelledby="someId2"
|
|
125
|
-
labels={{cardAriaLabel: "preferred label"}}
|
|
126
|
-
>
|
|
127
|
-
<h2 id="someId2">Card title</h2>
|
|
128
|
-
</Card>;
|
|
129
|
-
|
|
130
|
-
// @ts-expect-error - aria-labelledby cannot be used with labels.cardAriaLabel
|
|
131
|
-
<Card
|
|
132
|
-
tag="section"
|
|
133
|
-
aria-labelledby="someId2"
|
|
134
|
-
labels={{cardAriaLabel: "preferred label"}}
|
|
135
|
-
>
|
|
136
|
-
<h2 id="someId2">Card title</h2>
|
|
137
|
-
</Card>;
|
|
138
|
-
|
|
139
|
-
<Card tag="figure" aria-labelledby="someId2" aria-label="fallback label">
|
|
140
|
-
<h2 id="someId2">Card title</h2>
|
|
141
|
-
</Card>;
|
|
142
|
-
|
|
143
|
-
<Card tag="section">Content</Card>;
|
|
144
|
-
|
|
145
|
-
<Card tag="figure">Content</Card>;
|
|
146
|
-
|
|
147
|
-
<Card tag="section" labels={{}}>
|
|
148
|
-
Content
|
|
149
|
-
</Card>;
|
|
150
|
-
|
|
151
|
-
<Card tag="figure" labels={{}}>
|
|
152
|
-
Content
|
|
153
|
-
</Card>;
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Card with additional props
|
|
157
|
-
*/
|
|
158
|
-
|
|
159
|
-
<Card testId="my-card">Content</Card>;
|
|
160
|
-
|
|
161
|
-
<Card inert>Content</Card>;
|
|
162
|
-
|
|
163
|
-
<Card ref={React.createRef<HTMLDivElement>()}>Content</Card>;
|
|
164
|
-
|
|
165
|
-
<Card styles={{root: {width: 200}, dismissButton: {position: "absolute"}}}>
|
|
166
|
-
Content
|
|
167
|
-
</Card>;
|
|
168
|
-
|
|
169
|
-
<Card
|
|
170
|
-
tag="section"
|
|
171
|
-
onDismiss={() => {}}
|
|
172
|
-
labels={{
|
|
173
|
-
cardAriaLabel: "Card section",
|
|
174
|
-
dismissButtonAriaLabel: "Close card",
|
|
175
|
-
}}
|
|
176
|
-
>
|
|
177
|
-
Content
|
|
178
|
-
</Card>;
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Card with all props
|
|
182
|
-
*/
|
|
183
|
-
|
|
184
|
-
<Card
|
|
185
|
-
aria-busy={true}
|
|
186
|
-
aria-roledescription="A custom card"
|
|
187
|
-
background="base-subtle"
|
|
188
|
-
borderRadius="medium"
|
|
189
|
-
paddingSize="medium"
|
|
190
|
-
elevation="low"
|
|
191
|
-
tag="figure"
|
|
192
|
-
onDismiss={() => {}}
|
|
193
|
-
labels={{
|
|
194
|
-
cardAriaLabel: "Card figure",
|
|
195
|
-
dismissButtonAriaLabel: "Close card",
|
|
196
|
-
}}
|
|
197
|
-
testId="complex-card"
|
|
198
|
-
inert
|
|
199
|
-
styles={{
|
|
200
|
-
root: {width: 300},
|
|
201
|
-
dismissButton: {top: 10, right: 10},
|
|
202
|
-
}}
|
|
203
|
-
ref={React.createRef<HTMLElement>()}
|
|
204
|
-
role="status"
|
|
205
|
-
>
|
|
206
|
-
<div>Complex content</div>
|
|
207
|
-
</Card>;
|