@khanacademy/wonder-blocks-icon 2.2.1 → 4.0.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,17 @@
1
1
  # @khanacademy/wonder-blocks-icon
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 171e3b01: Delete Icon component in favor of PhosphorIcon
8
+
9
+ ## 3.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - 96f675d2: Remove size/weight restriction from PhosphorIcon and remove some exported types from the package.
14
+
3
15
  ## 2.2.1
4
16
 
5
17
  ### Patch Changes
@@ -1,68 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { AriaProps, StyleType } from "@khanacademy/wonder-blocks-core";
3
- import { PhosphorIconAsset, PhosphorIconMedium, PhosphorIconSmall } from "../types";
4
- type CommonProps = Pick<AriaProps, "aria-hidden" | "aria-label"> & {
5
- /**
6
- * The color of the icon. Will default to `currentColor`, which means that
7
- * it will take on the CSS `color` value from the parent element.
8
- */
9
- color?: string;
10
- /**
11
- * Additional styles to apply to the icon.
12
- */
13
- style?: StyleType;
14
- /**
15
- * Adds CSS classes to the Icon.
16
- */
17
- className?: string;
18
- /**
19
- * Test ID used for e2e testing.
20
- */
21
- testId?: string;
22
- };
23
- type PropsForSmallIcon = CommonProps & {
24
- /**
25
- * The icon size (16px).
26
- *
27
- * __NOTE:__ small icons only support `bold` and `fill` weights. **Make sure
28
- * you are not using a `regular` icon.**
29
- */
30
- size?: "small";
31
- /**
32
- * The icon to display. This is a reference to the icon asset
33
- * (imported as a static SVG file).
34
- * __NOTE:__ small icons only support `bold` and `fill` weights.
35
- */
36
- icon: PhosphorIconSmall;
37
- };
38
- type PropsForMediumIcon = CommonProps & {
39
- /**
40
- * The icon size (24px). Defaults to `medium`.
41
- *
42
- * __NOTE:__ medium icons only support `regular` and `fill` weights. **Make
43
- * sure you are not using a `bold` icon.**
44
- */
45
- size?: "medium";
46
- /**
47
- * The icon to display. This is a reference to the icon asset
48
- * (imported as a static SVG file).
49
- * __NOTE:__ medium icons only support `regular` and `fill` weights.
50
- */
51
- icon: PhosphorIconMedium;
52
- };
53
- type PropsForOtherSizes = CommonProps & {
54
- /**
55
- * large: The icon size (48px).
56
- * xlarge: The icon size (96px).
57
- */
58
- size?: "large" | "xlarge";
59
- /**
60
- * The icon to display. This is a reference to the icon asset
61
- * (imported as a static SVG file).
62
- */
63
- icon: PhosphorIconAsset;
64
- };
65
- type Props = PropsForSmallIcon | PropsForMediumIcon | PropsForOtherSizes;
3
+ import { IconSize, PhosphorIconAsset } from "../types";
66
4
  /**
67
5
  * A `PhosphorIcon` displays a small informational or decorative image as an
68
6
  * HTML element that renders a Phosphor Icon SVG available from the
@@ -88,5 +26,36 @@ type Props = PropsForSmallIcon | PropsForMediumIcon | PropsForOtherSizes;
88
26
  * These icons should fit into a viewport of `16`, `24`, `48`, and `96` pixels,
89
27
  * respectively.
90
28
  */
91
- export declare const PhosphorIcon: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLSpanElement>>;
92
- export {};
29
+ export declare const PhosphorIcon: React.ForwardRefExoticComponent<Pick<AriaProps, "role" | "aria-hidden" | "aria-label"> & {
30
+ /**
31
+ * The color of the icon. Will default to `currentColor`, which means that
32
+ * it will take on the CSS `color` value from the parent element.
33
+ */
34
+ color?: string | undefined;
35
+ /**
36
+ * Additional styles to apply to the icon.
37
+ */
38
+ style?: StyleType;
39
+ /**
40
+ * Adds CSS classes to the Icon.
41
+ */
42
+ className?: string | undefined;
43
+ /**
44
+ * Test ID used for e2e testing.
45
+ */
46
+ testId?: string | undefined;
47
+ /**
48
+ * Size of the icon. One of `small` (16), `medium` (24), `large` (48), or
49
+ * `xlarge` (96). Defaults to `small`.
50
+ */
51
+ size?: IconSize | undefined;
52
+ /**
53
+ * The icon to display. This is a reference to the icon asset (imported as a
54
+ * static SVG file).
55
+ *
56
+ * It supports the following types:
57
+ * - `PhosphorIconAsset`: a reference to a Phosphor SVG asset.
58
+ * - `string`: an import referencing an arbitrary SVG file.
59
+ */
60
+ icon: PhosphorIconAsset | string;
61
+ } & React.RefAttributes<HTMLSpanElement>>;
package/dist/es/index.js CHANGED
@@ -36,164 +36,6 @@ const viewportPixelsForSize = size => ({
36
36
  large: 48,
37
37
  xlarge: 96
38
38
  })[size];
39
- const getPathForIcon = (icon, size) => {
40
- if (typeof icon[size] === "number") {
41
- return {
42
- assetSize: size,
43
- path: icon[size]
44
- };
45
- } else {
46
- const desiredPixelSize = viewportPixelsForSize(size);
47
- const availableSizes = Object.keys(icon);
48
- const sortFn = availableSize => {
49
- const availablePixelSize = viewportPixelsForSize(availableSize);
50
- const tooLargeByPixels = availablePixelSize - desiredPixelSize;
51
- return tooLargeByPixels > 0 ? Number.POSITIVE_INFINITY : Math.abs(tooLargeByPixels);
52
- };
53
- const assetSizes = availableSizes.sort((a, b) => sortFn(a) - sortFn(b));
54
- const bestAssetSize = assetSizes[0];
55
- if (bestAssetSize && icon[bestAssetSize]) {
56
- return {
57
- assetSize: bestAssetSize,
58
- path: icon[bestAssetSize]
59
- };
60
- } else {
61
- throw new Error("Icon does not contain any valid asset sizes!");
62
- }
63
- }
64
- };
65
-
66
- const _excluded$1 = ["color", "icon", "size", "style", "testId"];
67
- const StyledSVG = addStyle("svg");
68
- const Icon = React.forwardRef(function Icon(props, ref) {
69
- const {
70
- color = "currentColor",
71
- icon,
72
- size = "small",
73
- style,
74
- testId
75
- } = props,
76
- sharedProps = _objectWithoutPropertiesLoose(props, _excluded$1);
77
- const {
78
- assetSize,
79
- path
80
- } = getPathForIcon(icon, size);
81
- const pixelSize = viewportPixelsForSize(size);
82
- const viewboxPixelSize = viewportPixelsForSize(assetSize);
83
- return React.createElement(StyledSVG, _extends({}, sharedProps, {
84
- style: [styles$1.svg, style],
85
- width: pixelSize,
86
- height: pixelSize,
87
- viewBox: `0 0 ${viewboxPixelSize} ${viewboxPixelSize}`,
88
- "data-test-id": testId,
89
- ref: ref
90
- }), React.createElement("path", {
91
- fill: color,
92
- d: path
93
- }));
94
- });
95
- const styles$1 = StyleSheet.create({
96
- svg: {
97
- display: "inline-block",
98
- verticalAlign: "text-bottom",
99
- flexShrink: 0,
100
- flexGrow: 0
101
- }
102
- });
103
-
104
- const add = {
105
- medium: "M11 11V7a1 1 0 0 1 2 0v4h4a1 1 0 0 1 0 2h-4v4a1 1 0 0 1-2 0v-4H7a1 1 0 0 1 0-2h4zm1 13C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"
106
- };
107
- const caretDown = {
108
- small: "M8 8.586l3.293-3.293a1 1 0 0 1 1.414 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 1.414-1.414L8 8.586z",
109
- medium: "M17.293 8.293a1 1 0 0 1 1.414 1.414l-6 6a1 1 0 0 1-1.414 0l-6-6a1 1 0 0 1 1.414-1.414L12 13.586l5.293-5.293z"
110
- };
111
- const caretLeft = {
112
- small: "M7.414 8l3.293 3.293a1 1 0 0 1-1.414 1.414l-4-4a1 1 0 0 1 0-1.414l4-4a1 1 0 0 1 1.414 1.414L7.414 8z",
113
- medium: "M15.707 17.293a1 1 0 0 1-1.414 1.414l-6-6a1 1 0 0 1 0-1.414l6-6a1 1 0 0 1 1.414 1.414L10.414 12l5.293 5.293z"
114
- };
115
- const caretRight = {
116
- small: "M8.586 8L5.293 4.707a1 1 0 0 1 1.414-1.414l4 4a1 1 0 0 1 0 1.414l-4 4a1 1 0 0 1-1.414-1.414L8.586 8z",
117
- medium: "M8.293 17.293a1 1 0 0 0 1.414 1.414l6-6a1 1 0 0 0 0-1.414l-6-6a1 1 0 0 0-1.414 1.414L13.586 12l-5.293 5.293z"
118
- };
119
- const caretUp = {
120
- small: "M8 7.414l-3.293 3.293a1 1 0 0 1-1.414-1.414l4-4a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1-1.414 1.414L8 7.414z",
121
- medium: "M17.293 15.707a1 1 0 0 0 1.414-1.414l-6-6a1 1 0 0 0-1.414 0l-6 6a1 1 0 0 0 1.414 1.414L12 10.414l5.293 5.293z"
122
- };
123
- const check = {
124
- small: "M6.072 10.4l6.175-7.058a1 1 0 1 1 1.506 1.317L6.769 12.64a1 1 0 0 1-1.55-.054L2.203 8.604a1 1 0 1 1 1.594-1.208L6.072 10.4z"
125
- };
126
- const contentArticle = {
127
- small: "M11 12V8h2v5a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h3v2H5v8h6zM9.5 6a.5.5 0 0 1-.5-.5V2l4 4H9.5z",
128
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm3-6v-4h2v5a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h3v2H9v8h6zm-1.5-6a.5.5 0 0 1-.5-.5V6l4 4h-3.5z"
129
- };
130
- const contentExercise = {
131
- small: "M7.5 6.914L5 9.414V11h1.586l2.5-2.5L7.5 6.914zM8.914 5.5L10.5 7.086 11.586 6 10 4.414 8.914 5.5zM3 9a1 1 0 0 1 .293-.707l6-6a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1 0 1.414l-6 6A1 1 0 0 1 7 13H4a1 1 0 0 1-1-1V9z",
132
- medium: "M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm-.5-11.086l1.586 1.586-2.5 2.5H9v-1.586l2.5-2.5zM12.914 9.5L14 8.414 15.586 10 14.5 11.086 12.914 9.5zM12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zM7 13v3a1 1 0 0 0 1 1h3a1 1 0 0 0 .707-.293l6-6a1 1 0 0 0 0-1.414l-3-3a1 1 0 0 0-1.414 0l-6 6A1 1 0 0 0 7 13z"
133
- };
134
- const contentVideo = {
135
- small: "M6 5.87v4.263l3.197-2.131L6 5.87zm-.445-2.7l6 4a1 1 0 0 1 0 1.664l-6 4A1 1 0 0 1 4 12.002v-8a1 1 0 0 1 1.555-.832z",
136
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM10.555 7.17l6 4a1 1 0 0 1 0 1.664l-6 4A1 1 0 0 1 9 16.002v-8a1 1 0 0 1 1.555-.832zM11 14.133l3.197-2.131L11 9.87v4.263z"
137
- };
138
- const correct = {
139
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm-1.928-7.6l6.175-7.058a1 1 0 1 1 1.506 1.317l-6.984 7.981a1 1 0 0 1-1.55-.054l-3.016-3.982a1 1 0 0 1 1.594-1.208l2.275 3.003z"
140
- };
141
- const _delete = {
142
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm-5-9a1 1 0 0 1 0-2h10a1 1 0 0 1 0 2H7z"
143
- };
144
- const dismiss = {
145
- small: "M8 6.586l3.293-3.293a1 1 0 0 1 1.414 1.414L9.414 8l3.293 3.293a1 1 0 0 1-1.414 1.414L8 9.414l-3.293 3.293a1 1 0 1 1-1.414-1.414L6.586 8 3.293 4.707a1 1 0 0 1 1.414-1.414L8 6.586z",
146
- medium: "M12 10.586L7.706 6.293a1 1 0 1 0-1.413 1.413L10.586 12l-4.293 4.294a1 1 0 0 0 1.413 1.413L12 13.414l4.294 4.293a1 1 0 0 0 1.413-1.413L13.414 12l4.293-4.294a1 1 0 1 0-1.413-1.413L12 10.586z"
147
- };
148
- const hint = {
149
- medium: "M10.835 15.993a1 1 0 0 1 1.008-.247 5.5 5.5 0 1 0-3.59-3.59 1 1 0 0 1-.246 1.009L6.172 15 9 17.828l1.835-1.835zm-.78 3.61a1.496 1.496 0 0 1-2.11 0l-3.548-3.549a1.496 1.496 0 0 1 0-2.108l1.787-1.787a7.5 7.5 0 1 1 5.657 5.657l-1.787 1.787zm-6.762.104a1 1 0 0 1 1.414-1.414l1 1a1 1 0 0 1-1.414 1.414l-1-1z"
150
- };
151
- const incorrect = {
152
- medium: "M12 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414L13.414 12l3.293 3.293a1 1 0 0 1-1.414 1.414L12 13.414l-3.293 3.293a1 1 0 1 1-1.414-1.414L10.586 12 7.293 8.707a1 1 0 0 1 1.414-1.414L12 10.586zM12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"
153
- };
154
- const info = {
155
- small: "M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM7 8a1 1 0 1 1 2 0v3a1 1 0 0 1-2 0V8zm1-2a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"
156
- };
157
- const search = {
158
- small: "M11.172 9.757l2.535 2.536a1 1 0 0 1-1.414 1.414l-2.536-2.535a5 5 0 1 1 1.414-1.414zM7 10a3 3 0 1 0 0-6 3 3 0 0 0 0 6z",
159
- medium: "M11 17a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm6.32-1.094l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387a8 8 0 1 1 1.414-1.414z"
160
- };
161
- const sortableArrowDown = {
162
- small: "M7 9.586V4a1 1 0 1 1 2 0v5.586l2.293-2.293a1 1 0 0 1 1.414 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 1.414-1.414L7 9.586z"
163
- };
164
- const sortableArrowUp = {
165
- small: "M9 6.414l2.293 2.293a1 1 0 0 0 1.414-1.414l-4-4a1 1 0 0 0-1.414 0l-4 4a1 1 0 0 0 1.414 1.414L7 6.414V12a1 1 0 1 0 2 0V6.414z"
166
- };
167
- const zoomIn = {
168
- medium: "M17.32 15.906l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387a8 8 0 1 1 1.414-1.414zM12 10h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H8a1 1 0 0 1 0-2h2V8a1 1 0 0 1 2 0v2zm-1 7a6 6 0 1 0 0-12 6 6 0 0 0 0 12z"
169
- };
170
- const zoomOut = {
171
- medium: "M17.32 15.906l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387a8 8 0 1 1 1.414-1.414zM11 17a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm-3-5a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8z"
172
- };
173
-
174
- var iconAssets = /*#__PURE__*/Object.freeze({
175
- __proto__: null,
176
- add: add,
177
- caretDown: caretDown,
178
- caretLeft: caretLeft,
179
- caretRight: caretRight,
180
- caretUp: caretUp,
181
- check: check,
182
- contentArticle: contentArticle,
183
- contentExercise: contentExercise,
184
- contentVideo: contentVideo,
185
- correct: correct,
186
- 'delete': _delete,
187
- dismiss: dismiss,
188
- hint: hint,
189
- incorrect: incorrect,
190
- info: info,
191
- search: search,
192
- sortableArrowDown: sortableArrowDown,
193
- sortableArrowUp: sortableArrowUp,
194
- zoomIn: zoomIn,
195
- zoomOut: zoomOut
196
- });
197
39
 
198
40
  const _excluded = ["color", "icon", "size", "style", "testId", "className"];
199
41
  const StyledIcon = addStyle("span");
@@ -209,29 +51,43 @@ const PhosphorIcon = React.forwardRef(function PhosphorIcon(props, ref) {
209
51
  sharedProps = _objectWithoutPropertiesLoose(props, _excluded);
210
52
  const pixelSize = viewportPixelsForSize(size);
211
53
  const classNames = `${className != null ? className : ""}`;
54
+ const iconStyles = _generateStyles(color, pixelSize);
212
55
  return React.createElement(StyledIcon, _extends({}, sharedProps, {
213
56
  className: classNames,
214
- style: [styles.svg, {
215
- maskImage: `url(${icon})`,
216
- maskSize: "100%",
217
- maskRepeat: "no-repeat",
218
- maskPosition: "center",
219
- backgroundColor: color,
220
- width: pixelSize,
221
- height: pixelSize
57
+ style: [styles.svg, iconStyles.icon, {
58
+ maskImage: `url(${icon})`
222
59
  }, style],
223
60
  "data-test-id": testId,
224
61
  ref: ref
225
62
  }));
226
63
  });
64
+ const dynamicStyles = {};
65
+ const _generateStyles = (color, size) => {
66
+ const iconStyle = `${color}-${size}`;
67
+ if (styles[iconStyle]) {
68
+ return styles[iconStyle];
69
+ }
70
+ const newStyles = {
71
+ icon: {
72
+ backgroundColor: color,
73
+ width: size,
74
+ height: size
75
+ }
76
+ };
77
+ dynamicStyles[iconStyle] = StyleSheet.create(newStyles);
78
+ return dynamicStyles[iconStyle];
79
+ };
227
80
  const styles = StyleSheet.create({
228
81
  svg: {
229
82
  display: "inline-block",
230
83
  verticalAlign: "text-bottom",
231
84
  flexShrink: 0,
232
- flexGrow: 0
85
+ flexGrow: 0,
86
+ maskSize: "100%",
87
+ maskRepeat: "no-repeat",
88
+ maskPosition: "center"
233
89
  }
234
90
  });
235
91
  PhosphorIcon.displayName = "PhosphorIcon";
236
92
 
237
- export { PhosphorIcon, Icon as default, iconAssets as icons };
93
+ export { PhosphorIcon };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,2 @@
1
- import Icon from "./components/icon";
2
- import type { IconAsset, IconSize } from "./util/icon-assets";
3
- export * as icons from "./util/icon-assets";
4
1
  export { PhosphorIcon } from "./components/phosphor-icon";
5
- export type { PhosphorIconAsset, PhosphorIconMedium, PhosphorIconSmall, } from "./types";
6
- export type { IconAsset, IconSize };
7
- export default Icon;
2
+ export type { IconSize, PhosphorIconAsset } from "./types";
package/dist/index.js CHANGED
@@ -60,164 +60,6 @@ const viewportPixelsForSize = size => ({
60
60
  large: 48,
61
61
  xlarge: 96
62
62
  })[size];
63
- const getPathForIcon = (icon, size) => {
64
- if (typeof icon[size] === "number") {
65
- return {
66
- assetSize: size,
67
- path: icon[size]
68
- };
69
- } else {
70
- const desiredPixelSize = viewportPixelsForSize(size);
71
- const availableSizes = Object.keys(icon);
72
- const sortFn = availableSize => {
73
- const availablePixelSize = viewportPixelsForSize(availableSize);
74
- const tooLargeByPixels = availablePixelSize - desiredPixelSize;
75
- return tooLargeByPixels > 0 ? Number.POSITIVE_INFINITY : Math.abs(tooLargeByPixels);
76
- };
77
- const assetSizes = availableSizes.sort((a, b) => sortFn(a) - sortFn(b));
78
- const bestAssetSize = assetSizes[0];
79
- if (bestAssetSize && icon[bestAssetSize]) {
80
- return {
81
- assetSize: bestAssetSize,
82
- path: icon[bestAssetSize]
83
- };
84
- } else {
85
- throw new Error("Icon does not contain any valid asset sizes!");
86
- }
87
- }
88
- };
89
-
90
- const _excluded$1 = ["color", "icon", "size", "style", "testId"];
91
- const StyledSVG = wonderBlocksCore.addStyle("svg");
92
- const Icon = React__namespace.forwardRef(function Icon(props, ref) {
93
- const {
94
- color = "currentColor",
95
- icon,
96
- size = "small",
97
- style,
98
- testId
99
- } = props,
100
- sharedProps = _objectWithoutPropertiesLoose(props, _excluded$1);
101
- const {
102
- assetSize,
103
- path
104
- } = getPathForIcon(icon, size);
105
- const pixelSize = viewportPixelsForSize(size);
106
- const viewboxPixelSize = viewportPixelsForSize(assetSize);
107
- return React__namespace.createElement(StyledSVG, _extends({}, sharedProps, {
108
- style: [styles$1.svg, style],
109
- width: pixelSize,
110
- height: pixelSize,
111
- viewBox: `0 0 ${viewboxPixelSize} ${viewboxPixelSize}`,
112
- "data-test-id": testId,
113
- ref: ref
114
- }), React__namespace.createElement("path", {
115
- fill: color,
116
- d: path
117
- }));
118
- });
119
- const styles$1 = aphrodite.StyleSheet.create({
120
- svg: {
121
- display: "inline-block",
122
- verticalAlign: "text-bottom",
123
- flexShrink: 0,
124
- flexGrow: 0
125
- }
126
- });
127
-
128
- const add = {
129
- medium: "M11 11V7a1 1 0 0 1 2 0v4h4a1 1 0 0 1 0 2h-4v4a1 1 0 0 1-2 0v-4H7a1 1 0 0 1 0-2h4zm1 13C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"
130
- };
131
- const caretDown = {
132
- small: "M8 8.586l3.293-3.293a1 1 0 0 1 1.414 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 1.414-1.414L8 8.586z",
133
- medium: "M17.293 8.293a1 1 0 0 1 1.414 1.414l-6 6a1 1 0 0 1-1.414 0l-6-6a1 1 0 0 1 1.414-1.414L12 13.586l5.293-5.293z"
134
- };
135
- const caretLeft = {
136
- small: "M7.414 8l3.293 3.293a1 1 0 0 1-1.414 1.414l-4-4a1 1 0 0 1 0-1.414l4-4a1 1 0 0 1 1.414 1.414L7.414 8z",
137
- medium: "M15.707 17.293a1 1 0 0 1-1.414 1.414l-6-6a1 1 0 0 1 0-1.414l6-6a1 1 0 0 1 1.414 1.414L10.414 12l5.293 5.293z"
138
- };
139
- const caretRight = {
140
- small: "M8.586 8L5.293 4.707a1 1 0 0 1 1.414-1.414l4 4a1 1 0 0 1 0 1.414l-4 4a1 1 0 0 1-1.414-1.414L8.586 8z",
141
- medium: "M8.293 17.293a1 1 0 0 0 1.414 1.414l6-6a1 1 0 0 0 0-1.414l-6-6a1 1 0 0 0-1.414 1.414L13.586 12l-5.293 5.293z"
142
- };
143
- const caretUp = {
144
- small: "M8 7.414l-3.293 3.293a1 1 0 0 1-1.414-1.414l4-4a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1-1.414 1.414L8 7.414z",
145
- medium: "M17.293 15.707a1 1 0 0 0 1.414-1.414l-6-6a1 1 0 0 0-1.414 0l-6 6a1 1 0 0 0 1.414 1.414L12 10.414l5.293 5.293z"
146
- };
147
- const check = {
148
- small: "M6.072 10.4l6.175-7.058a1 1 0 1 1 1.506 1.317L6.769 12.64a1 1 0 0 1-1.55-.054L2.203 8.604a1 1 0 1 1 1.594-1.208L6.072 10.4z"
149
- };
150
- const contentArticle = {
151
- small: "M11 12V8h2v5a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h3v2H5v8h6zM9.5 6a.5.5 0 0 1-.5-.5V2l4 4H9.5z",
152
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm3-6v-4h2v5a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h3v2H9v8h6zm-1.5-6a.5.5 0 0 1-.5-.5V6l4 4h-3.5z"
153
- };
154
- const contentExercise = {
155
- small: "M7.5 6.914L5 9.414V11h1.586l2.5-2.5L7.5 6.914zM8.914 5.5L10.5 7.086 11.586 6 10 4.414 8.914 5.5zM3 9a1 1 0 0 1 .293-.707l6-6a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1 0 1.414l-6 6A1 1 0 0 1 7 13H4a1 1 0 0 1-1-1V9z",
156
- medium: "M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm-.5-11.086l1.586 1.586-2.5 2.5H9v-1.586l2.5-2.5zM12.914 9.5L14 8.414 15.586 10 14.5 11.086 12.914 9.5zM12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zM7 13v3a1 1 0 0 0 1 1h3a1 1 0 0 0 .707-.293l6-6a1 1 0 0 0 0-1.414l-3-3a1 1 0 0 0-1.414 0l-6 6A1 1 0 0 0 7 13z"
157
- };
158
- const contentVideo = {
159
- small: "M6 5.87v4.263l3.197-2.131L6 5.87zm-.445-2.7l6 4a1 1 0 0 1 0 1.664l-6 4A1 1 0 0 1 4 12.002v-8a1 1 0 0 1 1.555-.832z",
160
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM10.555 7.17l6 4a1 1 0 0 1 0 1.664l-6 4A1 1 0 0 1 9 16.002v-8a1 1 0 0 1 1.555-.832zM11 14.133l3.197-2.131L11 9.87v4.263z"
161
- };
162
- const correct = {
163
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm-1.928-7.6l6.175-7.058a1 1 0 1 1 1.506 1.317l-6.984 7.981a1 1 0 0 1-1.55-.054l-3.016-3.982a1 1 0 0 1 1.594-1.208l2.275 3.003z"
164
- };
165
- const _delete = {
166
- medium: "M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zm-5-9a1 1 0 0 1 0-2h10a1 1 0 0 1 0 2H7z"
167
- };
168
- const dismiss = {
169
- small: "M8 6.586l3.293-3.293a1 1 0 0 1 1.414 1.414L9.414 8l3.293 3.293a1 1 0 0 1-1.414 1.414L8 9.414l-3.293 3.293a1 1 0 1 1-1.414-1.414L6.586 8 3.293 4.707a1 1 0 0 1 1.414-1.414L8 6.586z",
170
- medium: "M12 10.586L7.706 6.293a1 1 0 1 0-1.413 1.413L10.586 12l-4.293 4.294a1 1 0 0 0 1.413 1.413L12 13.414l4.294 4.293a1 1 0 0 0 1.413-1.413L13.414 12l4.293-4.294a1 1 0 1 0-1.413-1.413L12 10.586z"
171
- };
172
- const hint = {
173
- medium: "M10.835 15.993a1 1 0 0 1 1.008-.247 5.5 5.5 0 1 0-3.59-3.59 1 1 0 0 1-.246 1.009L6.172 15 9 17.828l1.835-1.835zm-.78 3.61a1.496 1.496 0 0 1-2.11 0l-3.548-3.549a1.496 1.496 0 0 1 0-2.108l1.787-1.787a7.5 7.5 0 1 1 5.657 5.657l-1.787 1.787zm-6.762.104a1 1 0 0 1 1.414-1.414l1 1a1 1 0 0 1-1.414 1.414l-1-1z"
174
- };
175
- const incorrect = {
176
- medium: "M12 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414L13.414 12l3.293 3.293a1 1 0 0 1-1.414 1.414L12 13.414l-3.293 3.293a1 1 0 1 1-1.414-1.414L10.586 12 7.293 8.707a1 1 0 0 1 1.414-1.414L12 10.586zM12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-2c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"
177
- };
178
- const info = {
179
- small: "M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM7 8a1 1 0 1 1 2 0v3a1 1 0 0 1-2 0V8zm1-2a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"
180
- };
181
- const search = {
182
- small: "M11.172 9.757l2.535 2.536a1 1 0 0 1-1.414 1.414l-2.536-2.535a5 5 0 1 1 1.414-1.414zM7 10a3 3 0 1 0 0-6 3 3 0 0 0 0 6z",
183
- medium: "M11 17a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm6.32-1.094l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387a8 8 0 1 1 1.414-1.414z"
184
- };
185
- const sortableArrowDown = {
186
- small: "M7 9.586V4a1 1 0 1 1 2 0v5.586l2.293-2.293a1 1 0 0 1 1.414 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 1.414-1.414L7 9.586z"
187
- };
188
- const sortableArrowUp = {
189
- small: "M9 6.414l2.293 2.293a1 1 0 0 0 1.414-1.414l-4-4a1 1 0 0 0-1.414 0l-4 4a1 1 0 0 0 1.414 1.414L7 6.414V12a1 1 0 1 0 2 0V6.414z"
190
- };
191
- const zoomIn = {
192
- medium: "M17.32 15.906l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387a8 8 0 1 1 1.414-1.414zM12 10h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H8a1 1 0 0 1 0-2h2V8a1 1 0 0 1 2 0v2zm-1 7a6 6 0 1 0 0-12 6 6 0 0 0 0 12z"
193
- };
194
- const zoomOut = {
195
- medium: "M17.32 15.906l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387a8 8 0 1 1 1.414-1.414zM11 17a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm-3-5a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8z"
196
- };
197
-
198
- var iconAssets = /*#__PURE__*/Object.freeze({
199
- __proto__: null,
200
- add: add,
201
- caretDown: caretDown,
202
- caretLeft: caretLeft,
203
- caretRight: caretRight,
204
- caretUp: caretUp,
205
- check: check,
206
- contentArticle: contentArticle,
207
- contentExercise: contentExercise,
208
- contentVideo: contentVideo,
209
- correct: correct,
210
- 'delete': _delete,
211
- dismiss: dismiss,
212
- hint: hint,
213
- incorrect: incorrect,
214
- info: info,
215
- search: search,
216
- sortableArrowDown: sortableArrowDown,
217
- sortableArrowUp: sortableArrowUp,
218
- zoomIn: zoomIn,
219
- zoomOut: zoomOut
220
- });
221
63
 
222
64
  const _excluded = ["color", "icon", "size", "style", "testId", "className"];
223
65
  const StyledIcon = wonderBlocksCore.addStyle("span");
@@ -233,31 +75,43 @@ const PhosphorIcon = React__namespace.forwardRef(function PhosphorIcon(props, re
233
75
  sharedProps = _objectWithoutPropertiesLoose(props, _excluded);
234
76
  const pixelSize = viewportPixelsForSize(size);
235
77
  const classNames = `${className != null ? className : ""}`;
78
+ const iconStyles = _generateStyles(color, pixelSize);
236
79
  return React__namespace.createElement(StyledIcon, _extends({}, sharedProps, {
237
80
  className: classNames,
238
- style: [styles.svg, {
239
- maskImage: `url(${icon})`,
240
- maskSize: "100%",
241
- maskRepeat: "no-repeat",
242
- maskPosition: "center",
243
- backgroundColor: color,
244
- width: pixelSize,
245
- height: pixelSize
81
+ style: [styles.svg, iconStyles.icon, {
82
+ maskImage: `url(${icon})`
246
83
  }, style],
247
84
  "data-test-id": testId,
248
85
  ref: ref
249
86
  }));
250
87
  });
88
+ const dynamicStyles = {};
89
+ const _generateStyles = (color, size) => {
90
+ const iconStyle = `${color}-${size}`;
91
+ if (styles[iconStyle]) {
92
+ return styles[iconStyle];
93
+ }
94
+ const newStyles = {
95
+ icon: {
96
+ backgroundColor: color,
97
+ width: size,
98
+ height: size
99
+ }
100
+ };
101
+ dynamicStyles[iconStyle] = aphrodite.StyleSheet.create(newStyles);
102
+ return dynamicStyles[iconStyle];
103
+ };
251
104
  const styles = aphrodite.StyleSheet.create({
252
105
  svg: {
253
106
  display: "inline-block",
254
107
  verticalAlign: "text-bottom",
255
108
  flexShrink: 0,
256
- flexGrow: 0
109
+ flexGrow: 0,
110
+ maskSize: "100%",
111
+ maskRepeat: "no-repeat",
112
+ maskPosition: "center"
257
113
  }
258
114
  });
259
115
  PhosphorIcon.displayName = "PhosphorIcon";
260
116
 
261
117
  exports.PhosphorIcon = PhosphorIcon;
262
- exports["default"] = Icon;
263
- exports.icons = iconAssets;
package/dist/types.d.ts CHANGED
@@ -3,10 +3,6 @@
3
3
  */
4
4
  export type PhosphorIconAsset = PhosphorRegular | PhosphorBold | PhosphorFill;
5
5
  /**
6
- * The different icon weights for small icons.
7
- */
8
- export type PhosphorIconSmall = PhosphorBold | PhosphorFill;
9
- /**
10
- * The different icon weights for medium icons.
6
+ * All the possible icon weights.
11
7
  */
12
- export type PhosphorIconMedium = PhosphorRegular | PhosphorFill;
8
+ export type IconSize = "small" | "medium" | "large" | "xlarge";
@@ -1,21 +1,6 @@
1
- import type { IconAsset, IconSize } from "./icon-assets";
1
+ import { IconSize } from "../types";
2
2
  /**
3
3
  * A simple function that tells us how many viewport pixels each icon size
4
4
  * corresponds to.
5
5
  */
6
6
  export declare const viewportPixelsForSize: (size: IconSize) => number;
7
- /**
8
- * A utility to find the right asset from an IconAsset to display in an icon
9
- * at a given IconSize. We're looking for, in the following order:
10
- * 1. The path for the IconSize (e.g. small, medium) requested
11
- * 2. A path that's _smaller_ than the size we requested
12
- * 3. Any path (what remains is one for a larger IconSize)
13
- *
14
- * The goal here is to provide a path that looks good at the given size...
15
- * obviously, if the size that we want is provided, we'll use it. Otherwise we'd
16
- * rather blow up a smaller, simpler icon than scrunch down a more complex one.
17
- */
18
- export declare const getPathForIcon: (icon: IconAsset, size: IconSize) => {
19
- assetSize: IconSize;
20
- path: string;
21
- };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-icon",
3
- "version": "2.2.1",
3
+ "version": "4.0.0",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1 @@
1
+ <svg>this is a custom svg</svg>
@@ -3,6 +3,8 @@ import {render, screen} from "@testing-library/react";
3
3
 
4
4
  import Plus from "@phosphor-icons/core/regular/plus.svg";
5
5
  import PlusBold from "@phosphor-icons/core/bold/plus-bold.svg";
6
+ // mock out the custom icon
7
+ import customIcon from "./custom-icon-mock.svg";
6
8
 
7
9
  import {PhosphorIcon} from "../phosphor-icon";
8
10
  import * as utils from "../../util/icon-util";
@@ -91,7 +93,7 @@ describe("PhosphorIcon", () => {
91
93
  it("applies style prop", async () => {
92
94
  // Arrange
93
95
  const expectedStyle = {
94
- display: "none",
96
+ width: 30,
95
97
  } as const;
96
98
 
97
99
  // Act
@@ -104,9 +106,7 @@ describe("PhosphorIcon", () => {
104
106
  );
105
107
 
106
108
  // Assert
107
- expect(screen.getByTestId("phosphor-icon")).toHaveStyle(
108
- "display: none;",
109
- );
109
+ expect(screen.getByTestId("phosphor-icon")).toHaveStyle("width: 30px");
110
110
  });
111
111
 
112
112
  it("includes SVG using the maskImage css attribute", async () => {
@@ -120,4 +120,16 @@ describe("PhosphorIcon", () => {
120
120
  `mask-image: url(${Plus});`,
121
121
  );
122
122
  });
123
+
124
+ it("allows importing an arbitrary SVG file (custom icon)", async () => {
125
+ // Arrange
126
+
127
+ // Act
128
+ render(<PhosphorIcon icon={customIcon} testId="phosphor-icon" />);
129
+
130
+ // Assert
131
+ expect(screen.getByTestId("phosphor-icon")).toHaveStyle(
132
+ `mask-image: url(${customIcon});`,
133
+ );
134
+ });
123
135
  });