@khanacademy/wonder-blocks-card 0.0.0-PR2816-20251007224034 → 0.0.0-PR2816-20251008182823
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 +1 -1
- package/dist/es/index.js +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/__tests__/components/card.test.tsx +0 -182
- package/src/components/card.tsx +13 -35
package/CHANGELOG.md
CHANGED
package/dist/es/index.js
CHANGED
|
@@ -2,13 +2,13 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { StyleSheet } from 'aphrodite';
|
|
4
4
|
import { View } from '@khanacademy/wonder-blocks-core';
|
|
5
|
-
import { sizing, semanticColor, border, boxShadow } from '@khanacademy/wonder-blocks-tokens';
|
|
5
|
+
import { sizing, semanticColor, border, boxShadow, font } from '@khanacademy/wonder-blocks-tokens';
|
|
6
6
|
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
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}=props;const componentStyles=getComponentStyles({background,borderRadius,paddingSize,elevation});return jsxs(View,{"aria-label":labels?.cardAriaLabel,style:[componentStyles.root,styles?.root],ref:ref,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",onClick:e=>onDismiss?.(e)}):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
|
|
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}=props;const componentStyles=getComponentStyles({background,borderRadius,paddingSize,elevation});return jsxs(View,{"aria-label":labels?.cardAriaLabel,style:[componentStyles.root,styles?.root],ref:ref,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",onClick:e=>onDismiss?.(e)}):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 isBackgroundColorStyle=background==="base-subtle"||background==="base-default";return StyleSheet.create({root:{...isBackgroundColorStyle&&{backgroundColor:styleMap.backgroundColor[background]},...!isBackgroundColorStyle&&background&&{background:`url(${background})`,backgroundSize:"cover"},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
|
@@ -37,6 +37,6 @@ var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
|
|
|
37
37
|
|
|
38
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}=props;const componentStyles=getComponentStyles({background,borderRadius,paddingSize,elevation});return jsxRuntime.jsxs(wonderBlocksCore.View,{"aria-label":labels?.cardAriaLabel,style:[componentStyles.root,styles?.root],ref:ref,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsxRuntime.jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",onClick:e=>onDismiss?.(e)}):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
|
|
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}=props;const componentStyles=getComponentStyles({background,borderRadius,paddingSize,elevation});return jsxRuntime.jsxs(wonderBlocksCore.View,{"aria-label":labels?.cardAriaLabel,style:[componentStyles.root,styles?.root],ref:ref,tag:tag,testId:testId,inert:inert?"":undefined,children:[onDismiss?jsxRuntime.jsx(DismissButton,{"aria-label":labels?.dismissButtonAriaLabel||"Close",onClick:e=>onDismiss?.(e)}):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 isBackgroundColorStyle=background==="base-subtle"||background==="base-default";return aphrodite.StyleSheet.create({root:{...isBackgroundColorStyle&&{backgroundColor:styleMap.backgroundColor[background]},...!isBackgroundColorStyle&&background&&{background:`url(${background})`,backgroundSize:"cover"},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
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import {render, screen} from "@testing-library/react";
|
|
3
3
|
import {userEvent} from "@testing-library/user-event";
|
|
4
|
-
import {
|
|
5
|
-
boxShadow,
|
|
6
|
-
border,
|
|
7
|
-
semanticColor,
|
|
8
|
-
sizing,
|
|
9
|
-
} from "@khanacademy/wonder-blocks-tokens";
|
|
10
4
|
|
|
11
5
|
import Card from "../../components/card";
|
|
12
6
|
|
|
@@ -197,180 +191,4 @@ describe("Card", () => {
|
|
|
197
191
|
expect(secondChild).toBeInTheDocument();
|
|
198
192
|
});
|
|
199
193
|
});
|
|
200
|
-
|
|
201
|
-
describe("Style application", () => {
|
|
202
|
-
it("should apply default styles", () => {
|
|
203
|
-
// Arrange
|
|
204
|
-
const testId = "test-card";
|
|
205
|
-
|
|
206
|
-
// Act
|
|
207
|
-
render(<Card testId={testId}>Content</Card>);
|
|
208
|
-
const card = screen.getByTestId(testId);
|
|
209
|
-
|
|
210
|
-
// Assert
|
|
211
|
-
expect(card).toHaveStyle({
|
|
212
|
-
position: "relative",
|
|
213
|
-
borderStyle: "solid",
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it("should apply base-subtle background", () => {
|
|
218
|
-
// Arrange
|
|
219
|
-
const testId = "test-card";
|
|
220
|
-
|
|
221
|
-
// Act
|
|
222
|
-
render(
|
|
223
|
-
<Card testId={testId} background="base-subtle">
|
|
224
|
-
Content
|
|
225
|
-
</Card>,
|
|
226
|
-
);
|
|
227
|
-
const card = screen.getByTestId(testId);
|
|
228
|
-
|
|
229
|
-
// Assert
|
|
230
|
-
expect(card).toHaveStyle({
|
|
231
|
-
backgroundColor: semanticColor.core.background.base.subtle,
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it("should apply medium border radius", () => {
|
|
236
|
-
// Arrange
|
|
237
|
-
const testId = "test-card";
|
|
238
|
-
|
|
239
|
-
// Act
|
|
240
|
-
render(
|
|
241
|
-
<Card testId={testId} borderRadius="medium">
|
|
242
|
-
Content
|
|
243
|
-
</Card>,
|
|
244
|
-
);
|
|
245
|
-
const card = screen.getByTestId(testId);
|
|
246
|
-
|
|
247
|
-
// Assert
|
|
248
|
-
expect(card).toHaveStyle({
|
|
249
|
-
borderRadius: border.radius.radius_120,
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it("should apply medium padding", () => {
|
|
254
|
-
// Arrange
|
|
255
|
-
const testId = "test-card";
|
|
256
|
-
|
|
257
|
-
// Act
|
|
258
|
-
render(
|
|
259
|
-
<Card testId={testId} paddingSize="medium">
|
|
260
|
-
Content
|
|
261
|
-
</Card>,
|
|
262
|
-
);
|
|
263
|
-
const card = screen.getByTestId(testId);
|
|
264
|
-
|
|
265
|
-
// Assert
|
|
266
|
-
expect(card).toHaveStyle({
|
|
267
|
-
padding: sizing.size_240,
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
it("should apply low elevation", () => {
|
|
272
|
-
// Arrange
|
|
273
|
-
const testId = "test-card";
|
|
274
|
-
|
|
275
|
-
// Act
|
|
276
|
-
render(
|
|
277
|
-
<Card testId={testId} elevation="low">
|
|
278
|
-
Content
|
|
279
|
-
</Card>,
|
|
280
|
-
);
|
|
281
|
-
const card = screen.getByTestId(testId);
|
|
282
|
-
|
|
283
|
-
// Assert
|
|
284
|
-
expect(card).toHaveStyle({
|
|
285
|
-
boxShadow: boxShadow.low,
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it("should apply image background", () => {
|
|
290
|
-
// Arrange
|
|
291
|
-
const testId = "test-card";
|
|
292
|
-
const testImage = Image;
|
|
293
|
-
|
|
294
|
-
// Act
|
|
295
|
-
render(
|
|
296
|
-
<Card testId={testId} background={testImage}>
|
|
297
|
-
Content
|
|
298
|
-
</Card>,
|
|
299
|
-
);
|
|
300
|
-
const card = screen.getByTestId(testId);
|
|
301
|
-
|
|
302
|
-
// Assert
|
|
303
|
-
expect(card).toHaveStyle({
|
|
304
|
-
backgroundSize: "cover",
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
describe("Style application", () => {
|
|
310
|
-
it("should apply custom margin style", () => {
|
|
311
|
-
// Arrange
|
|
312
|
-
const testId = "test-card";
|
|
313
|
-
const customStyle = {marginTop: "10px"};
|
|
314
|
-
|
|
315
|
-
// Act
|
|
316
|
-
render(
|
|
317
|
-
<Card testId={testId} styles={{root: customStyle}}>
|
|
318
|
-
Content
|
|
319
|
-
</Card>,
|
|
320
|
-
);
|
|
321
|
-
|
|
322
|
-
// Assert
|
|
323
|
-
expect(screen.getByTestId(testId)).toHaveStyle(customStyle);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it("should apply custom padding style", () => {
|
|
327
|
-
// Arrange
|
|
328
|
-
const testId = "test-card";
|
|
329
|
-
const customStyle = {padding: "20px"};
|
|
330
|
-
|
|
331
|
-
// Act
|
|
332
|
-
render(
|
|
333
|
-
<Card testId={testId} styles={{root: customStyle}}>
|
|
334
|
-
Content
|
|
335
|
-
</Card>,
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
// Assert
|
|
339
|
-
expect(screen.getByTestId(testId)).toHaveStyle(customStyle);
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it("should apply custom background color", () => {
|
|
343
|
-
// Arrange
|
|
344
|
-
const testId = "test-card";
|
|
345
|
-
const customStyle = {backgroundColor: "rgb(255, 0, 0)"};
|
|
346
|
-
|
|
347
|
-
// Act
|
|
348
|
-
render(
|
|
349
|
-
<Card testId={testId} styles={{root: customStyle}}>
|
|
350
|
-
Content
|
|
351
|
-
</Card>,
|
|
352
|
-
);
|
|
353
|
-
|
|
354
|
-
// Assert
|
|
355
|
-
expect(screen.getByTestId(testId)).toHaveStyle(customStyle);
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
it("should maintain default styles with custom styles", () => {
|
|
359
|
-
// Arrange
|
|
360
|
-
const testId = "test-card";
|
|
361
|
-
const customStyle = {marginTop: "10px"};
|
|
362
|
-
|
|
363
|
-
// Act
|
|
364
|
-
render(
|
|
365
|
-
<Card testId={testId} styles={{root: customStyle}}>
|
|
366
|
-
Content
|
|
367
|
-
</Card>,
|
|
368
|
-
);
|
|
369
|
-
|
|
370
|
-
// Assert
|
|
371
|
-
const element = screen.getByTestId(testId);
|
|
372
|
-
expect(element).toHaveStyle(customStyle);
|
|
373
|
-
expect(element).toHaveStyle({position: "relative"}); // A default style
|
|
374
|
-
});
|
|
375
|
-
});
|
|
376
194
|
});
|
package/src/components/card.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
border,
|
|
9
9
|
semanticColor,
|
|
10
10
|
sizing,
|
|
11
|
+
font,
|
|
11
12
|
} from "@khanacademy/wonder-blocks-tokens";
|
|
12
13
|
|
|
13
14
|
import {DismissButton} from "./dismiss-button";
|
|
@@ -212,39 +213,19 @@ const styleMap = {
|
|
|
212
213
|
},
|
|
213
214
|
} as const;
|
|
214
215
|
|
|
215
|
-
// Cache for dynamically generated styles
|
|
216
|
-
const dynamicStyles: Record<string, any> = {};
|
|
217
|
-
|
|
218
216
|
/**
|
|
219
|
-
*
|
|
217
|
+
* Gets the styles for the card based on its props
|
|
220
218
|
*/
|
|
221
|
-
const
|
|
222
|
-
background,
|
|
223
|
-
borderRadius,
|
|
224
|
-
paddingSize,
|
|
225
|
-
elevation,
|
|
226
|
-
}: StyleProps)
|
|
227
|
-
return `${background || "default"}-${borderRadius || "small"}-${
|
|
228
|
-
paddingSize || "small"
|
|
229
|
-
}-${elevation || "none"}`;
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Generates the component styles with caching for better performance
|
|
234
|
-
*/
|
|
235
|
-
const getComponentStyles = (props: StyleProps) => {
|
|
236
|
-
const styleKey = getStyleKey(props);
|
|
237
|
-
// Return cached styles if they exist
|
|
238
|
-
if (dynamicStyles[styleKey]) {
|
|
239
|
-
return dynamicStyles[styleKey];
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const {background, borderRadius, paddingSize, elevation} = props;
|
|
219
|
+
const getComponentStyles = ({
|
|
220
|
+
background = "base-default",
|
|
221
|
+
borderRadius = "small",
|
|
222
|
+
paddingSize = "small",
|
|
223
|
+
elevation = "none",
|
|
224
|
+
}: StyleProps) => {
|
|
243
225
|
const isBackgroundColorStyle =
|
|
244
226
|
background === "base-subtle" || background === "base-default";
|
|
245
227
|
|
|
246
|
-
|
|
247
|
-
const newStyles = StyleSheet.create({
|
|
228
|
+
return StyleSheet.create({
|
|
248
229
|
root: {
|
|
249
230
|
// Background styles
|
|
250
231
|
...(isBackgroundColorStyle && {
|
|
@@ -260,18 +241,15 @@ const getComponentStyles = (props: StyleProps) => {
|
|
|
260
241
|
borderColor: semanticColor.core.border.neutral.subtle,
|
|
261
242
|
borderStyle: "solid",
|
|
262
243
|
borderWidth: border.width.thin,
|
|
244
|
+
fontFamily: font.family.sans,
|
|
263
245
|
minInlineSize: sizing.size_280,
|
|
264
246
|
position: "relative",
|
|
265
247
|
// Optional styles based on props
|
|
266
|
-
borderRadius:
|
|
267
|
-
boxShadow:
|
|
268
|
-
padding:
|
|
248
|
+
borderRadius: styleMap.borderRadius[borderRadius],
|
|
249
|
+
boxShadow: styleMap.elevation[elevation],
|
|
250
|
+
padding: styleMap.padding[paddingSize],
|
|
269
251
|
},
|
|
270
252
|
});
|
|
271
|
-
|
|
272
|
-
// Cache the styles
|
|
273
|
-
dynamicStyles[styleKey] = newStyles;
|
|
274
|
-
return newStyles;
|
|
275
253
|
};
|
|
276
254
|
|
|
277
255
|
export default Card;
|