@leafygreen-ui/icon 11.9.0 → 11.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leafygreen-ui/icon",
3
- "version": "11.9.0",
3
+ "version": "11.10.0",
4
4
  "description": "LeafyGreen UI Kit Icons",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -26,5 +26,13 @@
26
26
  "dependencies": {
27
27
  "@leafygreen-ui/lib": "^9.2.0"
28
28
  },
29
- "gitHead": "dd71a2d404218ccec2e657df9c0263dc1c15b9e0"
30
- }
29
+ "gitHead": "dd71a2d404218ccec2e657df9c0263dc1c15b9e0",
30
+ "homepage": "https://github.com/mongodb/leafygreen-ui/tree/main/packages/icon",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/mongodb/leafygreen-ui"
34
+ },
35
+ "bugs": {
36
+ "url": "https://jira.mongodb.org/projects/PD/summary"
37
+ }
38
+ }
package/scripts/build.ts CHANGED
@@ -8,7 +8,7 @@ const { CLIEngine } = require('eslint');
8
8
  const meow = require('meow');
9
9
  const prettier = require('prettier');
10
10
 
11
- const template = require('../src/template');
11
+ const template = require('./template');
12
12
 
13
13
  const cli = meow(
14
14
  `
File without changes
package/src/Icon.spec.tsx CHANGED
@@ -11,6 +11,7 @@ import { createIconComponent, glyphs } from '.';
11
11
  import createGlyphComponent from './createGlyphComponent';
12
12
  import EditIcon from '@leafygreen-ui/icon/dist/Edit';
13
13
  import { Size } from './glyphCommon';
14
+ import { isComponentGlyph } from './isComponentGlyph';
14
15
 
15
16
  function getBaseName(filePath: string): string {
16
17
  return path.basename(filePath, path.extname(filePath));
@@ -32,6 +33,50 @@ fs.readdirSync(generatedFilesDirectory).forEach(filePath => {
32
33
  baseNameToGeneratedFilePath[getBaseName(filePath)] = filePath;
33
34
  });
34
35
 
36
+ const MyTestSVGRGlyph: SVGR.Component = props => (
37
+ <svg data-testid="my-glyph" {...props}></svg>
38
+ );
39
+
40
+ const customTestGlyphs = {
41
+ MyTestSVGRGlyph: createGlyphComponent('MyTestSVGRGlyph', MyTestSVGRGlyph),
42
+ };
43
+
44
+ describe('packages/Icon/isComponentGlyph', () => {
45
+ test('returns `true` for a rendered component', () => {
46
+ const TestNode: React.ComponentType<any> & { isGlyph?: boolean } = () => (
47
+ <div />
48
+ );
49
+ TestNode.isGlyph = true;
50
+ const renderedTestNode = <TestNode />;
51
+ expect(isComponentGlyph(renderedTestNode)).toBeTruthy();
52
+ });
53
+
54
+ test('returns `true` for a component function', () => {
55
+ const TestNode: React.ComponentType<any> & { isGlyph?: boolean } = () => (
56
+ <div />
57
+ );
58
+ TestNode.isGlyph = true;
59
+ expect(isComponentGlyph(TestNode)).toBeTruthy();
60
+ });
61
+
62
+ test('returns `false` if isGlyph is false', () => {
63
+ const TestNode: React.ComponentType<any> & { isGlyph?: boolean } = () => (
64
+ <div />
65
+ );
66
+ TestNode.isGlyph = false;
67
+ const renderedTestNode = <TestNode />;
68
+ expect(isComponentGlyph(TestNode)).toBeFalsy();
69
+ expect(isComponentGlyph(renderedTestNode)).toBeFalsy();
70
+ });
71
+
72
+ test('returns `false` if isGlyph is not set', () => {
73
+ const TestNode: React.ComponentType<any> = () => <div />;
74
+ const renderedTestNode = <TestNode />;
75
+ expect(isComponentGlyph(TestNode)).toBeFalsy();
76
+ expect(isComponentGlyph(renderedTestNode)).toBeFalsy();
77
+ });
78
+ });
79
+
35
80
  describe('packages/Icon/glyphs/', () => {
36
81
  describe('a11y', () => {
37
82
  test('does not have basic accessibility issues', async () => {
@@ -86,19 +131,28 @@ describe('packages/Icon/glyphs/', () => {
86
131
  });
87
132
  });
88
133
 
89
- const MyGlyph: SVGR.Component = props => (
90
- <svg data-testid="my-glyph" {...props}></svg>
91
- );
92
-
93
134
  describe('packages/Icon/createGlyphComponent', () => {
94
- const GlyphComponent = createGlyphComponent('MyGlyph', MyGlyph);
135
+ const GlyphComponent = createGlyphComponent(
136
+ 'MyTestSVGRGlyph',
137
+ MyTestSVGRGlyph,
138
+ );
95
139
 
96
- test('returns a function', () => {
140
+ test('returns a LGGlyph component', () => {
97
141
  expect(typeof GlyphComponent).toBe('function');
142
+ expect(isComponentGlyph(GlyphComponent)).toBeTruthy();
143
+ });
144
+
145
+ test('returned component has correct display name', () => {
146
+ expect(GlyphComponent.displayName).toBe('MyTestSVGRGlyph');
147
+ });
148
+
149
+ test('returned component has the property `isGlyph`', () => {
150
+ expect(GlyphComponent).toHaveProperty('isGlyph');
151
+ expect(GlyphComponent.isGlyph).toBeTruthy();
98
152
  });
99
153
 
100
- test('returned function has correct display name', () => {
101
- expect(GlyphComponent.displayName).toBe('MyGlyph');
154
+ test('returned function passes `isComponentGlyph`', () => {
155
+ expect(isComponentGlyph(GlyphComponent)).toBeTruthy();
102
156
  });
103
157
 
104
158
  test('returned function renders the glyph specified', () => {
@@ -134,12 +188,8 @@ describe('packages/Icon/createGlyphComponent', () => {
134
188
  });
135
189
  });
136
190
 
137
- const customGlyphs = {
138
- MyGlyph: createGlyphComponent('MyGlyph', MyGlyph),
139
- };
140
-
141
191
  describe('packages/Icon/createIconComponent', () => {
142
- const IconComponent = createIconComponent(customGlyphs);
192
+ const IconComponent = createIconComponent(customTestGlyphs);
143
193
 
144
194
  test('returns a function', () => {
145
195
  expect(typeof IconComponent).toBe('function');
@@ -149,8 +199,17 @@ describe('packages/Icon/createIconComponent', () => {
149
199
  expect(IconComponent.displayName).toBe('Icon');
150
200
  });
151
201
 
202
+ test('returned function has the property: `isGlyph`', () => {
203
+ expect(IconComponent).toHaveProperty('isGlyph');
204
+ expect(IconComponent.isGlyph).toBeTruthy();
205
+ });
206
+
207
+ test('returned function passes `isComponentGlyph`', () => {
208
+ expect(isComponentGlyph(IconComponent)).toBeTruthy();
209
+ });
210
+
152
211
  test('returned funciton renders the glyph specified', () => {
153
- const { getByTestId } = render(<IconComponent glyph="MyGlyph" />);
212
+ const { getByTestId } = render(<IconComponent glyph="MyTestSVGRGlyph" />);
154
213
  const glyph = getByTestId('my-glyph');
155
214
 
156
215
  if (!typeIs.element(glyph)) {
@@ -162,7 +221,7 @@ describe('packages/Icon/createIconComponent', () => {
162
221
  describe('returned funcion passes through props', () => {
163
222
  test('`size` prop as number', () => {
164
223
  const { getByTestId } = render(
165
- <IconComponent glyph="MyGlyph" size={20} />,
224
+ <IconComponent glyph="MyTestSVGRGlyph" size={20} />,
166
225
  );
167
226
  const glyph = getByTestId('my-glyph');
168
227
  expect(glyph).toHaveAttribute('height', '20');
@@ -171,7 +230,7 @@ describe('packages/Icon/createIconComponent', () => {
171
230
 
172
231
  test('`size` prop as Size', () => {
173
232
  const { getByTestId } = render(
174
- <IconComponent glyph="MyGlyph" size={Size.Large} />,
233
+ <IconComponent glyph="MyTestSVGRGlyph" size={Size.Large} />,
175
234
  );
176
235
  const glyph = getByTestId('my-glyph');
177
236
  expect(glyph).toHaveAttribute('height', '20');
@@ -180,7 +239,7 @@ describe('packages/Icon/createIconComponent', () => {
180
239
 
181
240
  test('`role`', () => {
182
241
  const { getByTestId } = render(
183
- <IconComponent glyph="MyGlyph" role="presentation" />,
242
+ <IconComponent glyph="MyTestSVGRGlyph" role="presentation" />,
184
243
  );
185
244
  const glyph = getByTestId('my-glyph');
186
245
  expect(glyph).toHaveAttribute('role', 'presentation');
@@ -1,16 +1,21 @@
1
+ // TODO: Generate Icon props with controls
1
2
  import React from 'react';
2
- import Icon, { glyphs, Size } from '.';
3
+ import Icon, { glyphs } from '.';
3
4
  import { css } from '@leafygreen-ui/emotion';
4
- import { storiesOf } from '@storybook/react';
5
- import { color, select } from '@storybook/addon-knobs';
6
- import { uiColors } from '@leafygreen-ui/palette';
5
+ import { ComponentStory, Meta } from '@storybook/react';
6
+ import { palette } from '@leafygreen-ui/palette';
7
+
8
+ export default {
9
+ title: 'Packages/Icons',
10
+ component: Icon,
11
+ } as Meta<typeof Icon>;
7
12
 
8
13
  const containerStyle = css`
9
14
  width: 150px;
10
15
  height: 70px;
11
16
  flex-shrink: 0;
12
17
  text-align: center;
13
- border: 1px solid #babdbe;
18
+ border: 1px solid ${palette.gray.light1};
14
19
  border-radius: 5px;
15
20
  display: flex;
16
21
  align-items: center;
@@ -21,22 +26,17 @@ const containerStyle = css`
21
26
 
22
27
  const textStyle = css`
23
28
  font-size: 12px;
24
- color: ${uiColors.gray.base};
29
+ color: ${palette.gray.base};
25
30
  margin-top: 0.5rem;
26
31
  `;
27
32
 
28
- storiesOf('Packages/Icons', module).add('Icon', () => {
29
- const fill = color('Fill', '#000000');
30
- const size = select('size', Object.values(Size), Size.Default);
31
-
32
- return (
33
- <>
34
- {Object.keys(glyphs).map(glyph => (
35
- <div key={glyph} className={containerStyle}>
36
- <Icon glyph={glyph} fill={fill} size={size} />
37
- <div className={textStyle}>{glyph}</div>
38
- </div>
39
- ))}
40
- </>
41
- );
42
- });
33
+ export const AllIcons: ComponentStory<typeof Icon> = args => (
34
+ <>
35
+ {Object.keys(glyphs).map(glyph => (
36
+ <div key={glyph} className={containerStyle}>
37
+ <Icon {...args} glyph={glyph} />
38
+ <div className={textStyle}>{glyph}</div>
39
+ </div>
40
+ ))}
41
+ </>
42
+ );
@@ -15,7 +15,7 @@ export default function createGlyphComponent(
15
15
  glyphName: string,
16
16
  Glyph: SVGR.Component,
17
17
  ): LGGlyph.Component {
18
- function GlyphComponent({
18
+ const GlyphComponent: LGGlyph.Component = ({
19
19
  className,
20
20
  size = Size.Default,
21
21
  fill,
@@ -24,7 +24,7 @@ export default function createGlyphComponent(
24
24
  'aria-label': ariaLabel,
25
25
  role = 'img',
26
26
  ...rest
27
- }: LGGlyph.ComponentProps) {
27
+ }: LGGlyph.ComponentProps) => {
28
28
  const fillStyle = css`
29
29
  color: ${fill};
30
30
  `;
@@ -56,7 +56,7 @@ export default function createGlyphComponent(
56
56
  {...rest}
57
57
  />
58
58
  );
59
- }
59
+ };
60
60
 
61
61
  GlyphComponent.displayName = glyphName;
62
62
 
@@ -21,12 +21,14 @@ export default function createIconComponent<
21
21
  >(glyphs: G) {
22
22
  const Icon = ({ glyph, ...rest }: IconProps) => {
23
23
  const SVGComponent = glyphs[glyph];
24
-
24
+ SVGComponent.isGlyph = true;
25
25
  return <SVGComponent {...rest} />;
26
26
  };
27
27
 
28
28
  Icon.displayName = 'Icon';
29
29
 
30
+ Icon.isGlyph = true;
31
+
30
32
  Icon.propTypes = {
31
33
  glyph: PropTypes.oneOf(Object.keys(glyphs)).isRequired,
32
34
  size: PropTypes.oneOfType([
@@ -1,13 +1,34 @@
1
+ import { ComponentType, isValidElement, ReactNode } from 'react';
1
2
  import { LGGlyph } from './types';
2
3
 
4
+ type ExtendedComponentType = ComponentType<any> & {
5
+ [key: string]: any;
6
+ };
3
7
  /** Helper type to check if element is a LeafyGreen UI Glyph */
4
- export function isComponentGlyph(
5
- child: React.ReactNode,
6
- ): child is React.ReactElement<LGGlyph.ComponentProps> {
8
+ function isComponentGlyph(node: ReactNode): node is LGGlyph.Element;
9
+ function isComponentGlyph(
10
+ component: ExtendedComponentType,
11
+ ): component is LGGlyph.Component;
12
+ function isComponentGlyph(
13
+ child: ReactNode | ExtendedComponentType,
14
+ ): child is LGGlyph.Element | LGGlyph.Component {
15
+ // If we're received a rendered component (i.e. ReactNode)
16
+ if (isValidElement(child)) {
17
+ return (
18
+ child != null &&
19
+ typeof child === 'object' &&
20
+ 'type' in child &&
21
+ (child.type as any).isGlyph === true
22
+ );
23
+ }
24
+
25
+ // If we've recieved a component function
7
26
  return (
8
27
  child != null &&
9
- typeof child === 'object' &&
10
- 'type' in child &&
11
- (child.type as any).isGlyph === true
28
+ typeof child === 'function' &&
29
+ 'isGlyph' in child &&
30
+ child.isGlyph === true
12
31
  );
13
32
  }
33
+
34
+ export { isComponentGlyph };
@@ -1,8 +1,10 @@
1
- import { ComponentType } from 'react';
1
+ import { ComponentType, ReactComponentElement } from 'react';
2
2
  import * as SVGR from './SVGR';
3
3
 
4
4
  export interface ComponentProps extends SVGR.ComponentProps {
5
5
  size?: number | 'small' | 'default' | 'large' | 'xlarge';
6
6
  }
7
7
 
8
- export type Component = ComponentType<ComponentProps>;
8
+ export type Component = ComponentType<ComponentProps> & { isGlyph?: boolean };
9
+
10
+ export type Element = ReactComponentElement<Component, ComponentProps>;