@khanacademy/wonder-blocks-card 1.1.0 → 1.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @khanacademy/wonder-blocks-card
2
2
 
3
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 607595f: Adds support for image backgrounds via the background prop
8
+
9
+ ### Patch Changes
10
+
11
+ - @khanacademy/wonder-blocks-icon-button@10.5.3
12
+
3
13
  ## 1.1.0
4
14
 
5
15
  ### Minor Changes
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 getComponentStyles=({background,borderRadius,paddingSize,elevation})=>{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}};return StyleSheet.create({root:{backgroundColor:background&&styleMap.backgroundColor[background],borderColor:semanticColor.core.border.neutral.subtle,borderStyle:"solid",borderRadius:borderRadius&&styleMap.borderRadius[borderRadius],borderWidth:border.width.thin,boxShadow:elevation&&styleMap.elevation[elevation],padding:paddingSize&&styleMap.padding[paddingSize],minInlineSize:sizing.size_280,position:"relative"}})};
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 isBackgroundToken=background==="base-default"||background==="base-subtle";const componentStyles=getComponentStyles({background:isBackgroundToken?background:null,borderRadius,paddingSize,elevation});return jsxs(View,{"aria-label":labels?.cardAriaLabel,style:[componentStyles.root,!isBackgroundToken&&{background:`url(${background})`,backgroundSize:"cover"},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 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
@@ -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 getComponentStyles=({background,borderRadius,paddingSize,elevation})=>{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}};return aphrodite.StyleSheet.create({root:{backgroundColor:background&&styleMap.backgroundColor[background],borderColor:wonderBlocksTokens.semanticColor.core.border.neutral.subtle,borderStyle:"solid",borderRadius:borderRadius&&styleMap.borderRadius[borderRadius],borderWidth:wonderBlocksTokens.border.width.thin,boxShadow:elevation&&styleMap.elevation[elevation],padding:paddingSize&&styleMap.padding[paddingSize],minInlineSize:wonderBlocksTokens.sizing.size_280,position:"relative"}})};
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 isBackgroundToken=background==="base-default"||background==="base-subtle";const componentStyles=getComponentStyles({background:isBackgroundToken?background:null,borderRadius,paddingSize,elevation});return jsxRuntime.jsxs(wonderBlocksCore.View,{"aria-label":labels?.cardAriaLabel,style:[componentStyles.root,!isBackgroundToken&&{background:`url(${background})`,backgroundSize:"cover"},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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-card",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "design": "v1",
5
5
  "description": "Card component for Wonder Blocks.",
6
6
  "main": "dist/index.js",
@@ -14,8 +14,8 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@khanacademy/wonder-blocks-core": "12.4.0",
17
- "@khanacademy/wonder-blocks-tokens": "14.0.0",
18
- "@khanacademy/wonder-blocks-icon-button": "10.5.2"
17
+ "@khanacademy/wonder-blocks-icon-button": "10.5.3",
18
+ "@khanacademy/wonder-blocks-tokens": "14.0.0"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "aphrodite": "^1.2.5",
@@ -64,6 +64,9 @@ import Card from "../../components/card";
64
64
  Content
65
65
  </Card>;
66
66
 
67
+ // @ts-expect-error - onClick is not allowed on Card wrapper
68
+ <Card onClick={() => {}}>Content</Card>;
69
+
67
70
  /**
68
71
  * Card with different HTML tags
69
72
  */
@@ -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";
@@ -79,10 +80,13 @@ type StyleProps = {
79
80
  * This can be one of:
80
81
  * - `"base-subtle"` (color), `semanticColor.core.background.base.subtle`: a light gray background.
81
82
  * - `"base-default"` (color), `semanticColor.core.background.base.default`: a white background.
83
+ * - `Image` (image), a URL string for a background image. Can be an imported image file or a URL string.
84
+ *
85
+ * For additional background styling such as repeat or size, use the `styles.root` prop to pass in custom styles.
82
86
  *
83
87
  * Default: `"base-default"`
84
88
  */
85
- background?: "base-subtle" | "base-default";
89
+ background?: "base-subtle" | "base-default" | typeof Image | null;
86
90
  /**
87
91
  * The border radius of the card, as a string identifier that matches a border.radius token.
88
92
  * This can be one of:
@@ -141,7 +145,7 @@ type Props = BaseCardProps & TagProps & DismissProps;
141
145
  *
142
146
  * When the `onDismiss` prop is provided, a dismiss button will be rendered. In this case, the `labels.dismissButtonAriaLabel` prop is required to provide an accessible label for the dismiss button.
143
147
  *
144
- * See additional [Accessibility docs](./?path=/docs/packages-card-card-accessibility--docs).
148
+ * See additional Accessibility docs.
145
149
  */
146
150
 
147
151
  const Card = React.forwardRef(function Card(
@@ -162,16 +166,26 @@ const Card = React.forwardRef(function Card(
162
166
  inert,
163
167
  } = props;
164
168
 
169
+ const isBackgroundToken =
170
+ background === "base-default" || background === "base-subtle";
165
171
  const componentStyles = getComponentStyles({
166
- background,
172
+ background: isBackgroundToken ? background : null,
167
173
  borderRadius,
168
174
  paddingSize,
169
175
  elevation,
170
176
  });
177
+
171
178
  return (
172
179
  <View
173
180
  aria-label={labels?.cardAriaLabel}
174
- style={[componentStyles.root, styles?.root]}
181
+ style={[
182
+ componentStyles.root,
183
+ !isBackgroundToken && {
184
+ background: `url(${background})`,
185
+ backgroundSize: "cover",
186
+ },
187
+ styles?.root,
188
+ ]}
175
189
  ref={ref}
176
190
  tag={tag}
177
191
  testId={testId}
@@ -188,44 +202,52 @@ const Card = React.forwardRef(function Card(
188
202
  );
189
203
  });
190
204
 
205
+ // Map prop values to tokens
206
+ const styleMap = {
207
+ backgroundColor: {
208
+ "base-subtle": semanticColor.core.background.base.subtle,
209
+ "base-default": semanticColor.core.background.base.default,
210
+ },
211
+ borderRadius: {
212
+ small: border.radius.radius_080,
213
+ medium: border.radius.radius_120,
214
+ },
215
+ padding: {
216
+ none: sizing.size_0,
217
+ small: sizing.size_160,
218
+ medium: sizing.size_240,
219
+ },
220
+ elevation: {
221
+ none: "none",
222
+ low: boxShadow.low,
223
+ },
224
+ } as const;
225
+
226
+ /**
227
+ * Gets the styles for the card based on its props
228
+ */
191
229
  const getComponentStyles = ({
192
- background,
193
- borderRadius,
194
- paddingSize,
195
- elevation,
230
+ background = "base-default",
231
+ borderRadius = "small",
232
+ paddingSize = "small",
233
+ elevation = "none",
196
234
  }: StyleProps) => {
197
- // Map prop values to tokens
198
- const styleMap = {
199
- backgroundColor: {
200
- "base-subtle": semanticColor.core.background.base.subtle,
201
- "base-default": semanticColor.core.background.base.default,
202
- },
203
- borderRadius: {
204
- small: border.radius.radius_080,
205
- medium: border.radius.radius_120,
206
- },
207
- padding: {
208
- none: sizing.size_0,
209
- small: sizing.size_160,
210
- medium: sizing.size_240,
211
- },
212
- elevation: {
213
- none: "none",
214
- low: boxShadow.low,
215
- },
216
- } as const;
217
-
235
+ const bgColor = background as keyof typeof styleMap.backgroundColor;
218
236
  return StyleSheet.create({
219
237
  root: {
220
- backgroundColor: background && styleMap.backgroundColor[background],
238
+ backgroundColor: bgColor && styleMap.backgroundColor[bgColor],
239
+ // Common styles
221
240
  borderColor: semanticColor.core.border.neutral.subtle,
222
241
  borderStyle: "solid",
223
- borderRadius: borderRadius && styleMap.borderRadius[borderRadius],
224
242
  borderWidth: border.width.thin,
225
- boxShadow: elevation && styleMap.elevation[elevation],
226
- padding: paddingSize && styleMap.padding[paddingSize],
243
+ // Apply the system font to cards by default
244
+ fontFamily: font.family.sans,
227
245
  minInlineSize: sizing.size_280,
228
246
  position: "relative",
247
+ // Optional styles based on props
248
+ borderRadius: styleMap.borderRadius[borderRadius],
249
+ boxShadow: styleMap.elevation[elevation],
250
+ padding: styleMap.padding[paddingSize],
229
251
  },
230
252
  });
231
253
  };