From f8cdf9ae6b567c3758d8714039cecc2a39ead387 Mon Sep 17 00:00:00 2001 From: hshoff Date: Sat, 1 Aug 2020 21:49:55 -0400 Subject: [PATCH 1/3] feat(vx-shape): add BarRounded shape. fixes #529 --- packages/vx-shape/src/index.ts | 1 + packages/vx-shape/src/shapes/BarRounded.tsx | 82 ++++++++++++++++++++ packages/vx-shape/test/BarRounded.test.tsx | 84 +++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 packages/vx-shape/src/shapes/BarRounded.tsx create mode 100644 packages/vx-shape/test/BarRounded.test.tsx diff --git a/packages/vx-shape/src/index.ts b/packages/vx-shape/src/index.ts index 3a09c38cc..54ce2ee06 100644 --- a/packages/vx-shape/src/index.ts +++ b/packages/vx-shape/src/index.ts @@ -7,6 +7,7 @@ export { default as Area } from './shapes/Area'; export { default as AreaClosed } from './shapes/AreaClosed'; export { default as AreaStack } from './shapes/AreaStack'; export { default as Bar } from './shapes/Bar'; +export { default as BarRounded } from './shapes/BarRounded'; export { default as BarGroup } from './shapes/BarGroup'; export { default as BarGroupHorizontal } from './shapes/BarGroupHorizontal'; export { default as BarStack } from './shapes/BarStack'; diff --git a/packages/vx-shape/src/shapes/BarRounded.tsx b/packages/vx-shape/src/shapes/BarRounded.tsx new file mode 100644 index 000000000..bcc01fc8f --- /dev/null +++ b/packages/vx-shape/src/shapes/BarRounded.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import cx from 'classnames'; + +export type BarRoundedProps = { + /** className to apply to rect element. */ + className?: string; + /** reference to rect element. */ + innerRef?: React.Ref; + /** left position of the bar */ + x: number; + /** top position of the bar */ + y: number; + /** width of the bar starting from x */ + width: number; + /** height of the bar starting from y */ + height: number; + /** corner radius of the bar. clamped to center of the shorter side of the bar (Math.min(width,height) / 2) */ + radius: number; + /** apply corner radius to top left corner, top right corner, bottom right corner, and bottom left corner */ + all?: boolean; + /** apply corner radius to top left corner, and top right corner */ + top?: boolean; + /** apply corner radius to bottom right corner, and bottom left corner */ + bottom?: boolean; + /** apply corner radius to top left corner, and bottom left corner */ + left?: boolean; + /** apply corner radius to top right corner, and bottom right corner */ + right?: boolean; + /** apply corner radius to top left corner */ + topLeft?: boolean; + /** apply corner radius to top right corner */ + topRight?: boolean; + /** apply corner radius to bottom left corner */ + bottomLeft?: boolean; + /** apply corner radius to bottom right */ + bottomRight?: boolean; +}; + +export default function BarRounded({ + className, + innerRef, + x, + y, + width, + height, + radius, + all = false, + top = false, + bottom = false, + left = false, + right = false, + topLeft = false, + topRight = false, + bottomLeft = false, + bottomRight = false, + ...restProps +}: BarRoundedProps & Omit, keyof BarRoundedProps>) { + topRight = all || top || topRight; + bottomRight = all || bottom || bottomRight; + bottomLeft = all || bottom || bottomLeft; + topLeft = all || top || topLeft; + + // clamp radius to center of shortest side of the rect + radius = Math.min(radius, Math.min(width, height) / 2); + + const diameter = 2 * radius; + const path = `M${x + radius},${y} h${width - diameter} + ${topRight ? `a${radius},${radius} 0 0 1 ${radius},${radius}` : `h${radius}v${radius}`} + v${height - diameter} + ${bottomRight ? `a${radius},${radius} 0 0 1 ${-radius},${radius}` : `v${radius}h${-radius}`} + h${diameter - width} + ${bottomLeft ? `a${radius},${radius} 0 0 1 ${-radius},${-radius}` : `h${-radius}v${-radius}`} + v${diameter - height} + ${topLeft ? `a${radius},${radius} 0 0 1 ${radius},${-radius}` : `v${-radius}h${radius}`} +z` + .split('\n') + .join(''); + + return ( + + ); +} diff --git a/packages/vx-shape/test/BarRounded.test.tsx b/packages/vx-shape/test/BarRounded.test.tsx new file mode 100644 index 000000000..6a6e015cd --- /dev/null +++ b/packages/vx-shape/test/BarRounded.test.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { shallow, mount } from 'enzyme'; + +import { BarRounded } from '../src'; + +const testProps = { x: 0, y: 0, width: 10, height: 20, radius: 2 }; +const BarRoundedWrapper = (restProps = {}) => shallow(); + +describe('', () => { + test('it should be defined', () => { + expect(BarRounded).toBeDefined(); + }); + + test('it should have the .vx-bar class', () => { + expect( + BarRoundedWrapper({ + className: 'test', + }).prop('className'), + ).toBe('vx-bar-rounded test'); + }); + + test('it should expose its ref via an innerRef prop', () => { + return new Promise(done => { + const refCallback = (ref: SVGPathElement) => { + expect(ref.tagName).toMatch('path'); + done(); + }; + mount( + + + , + ); + }); + }); + + test('it should set top left corner radius', () => { + const wrapper = BarRoundedWrapper({ topLeft: true }); + expect(wrapper.prop('d')).toBe('M2,0 h6 h2v2 v16 v2h-2 h-6 h-2v-2 v-16 a2,2 0 0 1 2,-2z'); + }); + + test('it should set top right corner radius', () => { + const wrapper = BarRoundedWrapper({ topRight: true }); + expect(wrapper.prop('d')).toBe('M2,0 h6 a2,2 0 0 1 2,2 v16 v2h-2 h-6 h-2v-2 v-16 v-2h2z'); + }); + + test('it should set bottom left corner radius', () => { + const wrapper = BarRoundedWrapper({ bottomLeft: true }); + expect(wrapper.prop('d')).toBe('M2,0 h6 h2v2 v16 v2h-2 h-6 a2,2 0 0 1 -2,-2 v-16 v-2h2z'); + }); + + test('it should set bottom right corner radius', () => { + const wrapper = BarRoundedWrapper({ bottomRight: true }); + expect(wrapper.prop('d')).toBe('M2,0 h6 h2v2 v16 a2,2 0 0 1 -2,2 h-6 h-2v-2 v-16 v-2h2z'); + }); + + test('it should set top left & top right corner radius', () => { + const wrapper = BarRoundedWrapper({ top: true }); + expect(wrapper.prop('d')).toBe( + 'M2,0 h6 a2,2 0 0 1 2,2 v16 v2h-2 h-6 h-2v-2 v-16 a2,2 0 0 1 2,-2z', + ); + }); + + test('it should set bottom left & bottom right corner radius', () => { + const wrapper = BarRoundedWrapper({ bottom: true }); + expect(wrapper.prop('d')).toBe( + 'M2,0 h6 h2v2 v16 a2,2 0 0 1 -2,2 h-6 a2,2 0 0 1 -2,-2 v-16 v-2h2z', + ); + }); + + test('it should set all corner radius', () => { + const wrapper = BarRoundedWrapper({ all: true }); + expect(wrapper.prop('d')).toBe( + 'M2,0 h6 a2,2 0 0 1 2,2 v16 a2,2 0 0 1 -2,2 h-6 a2,2 0 0 1 -2,-2 v-16 a2,2 0 0 1 2,-2z', + ); + }); + + test('it should clamp radius to the center of the shortest side of the rect', () => { + const wrapper = BarRoundedWrapper({ topLeft: true, width: 4, radius: 400 }); + const r = Math.min(4, testProps.height) / 2; + expect(wrapper.prop('d')).toBe( + `M2,0 h0 h2v2 v16 v2h-2 h0 h-2v-2 v-16 a${r},${r} 0 0 1 ${r},-${r}z`, + ); + }); +}); From 66f56380619f7b6ba31f9aea818a2013e15949f9 Mon Sep 17 00:00:00 2001 From: hshoff Date: Sat, 1 Aug 2020 22:03:02 -0400 Subject: [PATCH 2/3] feat(vx-shape): add left/right BarRounded shortcut --- packages/vx-shape/src/shapes/BarRounded.tsx | 8 ++++---- packages/vx-shape/test/BarRounded.test.tsx | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/vx-shape/src/shapes/BarRounded.tsx b/packages/vx-shape/src/shapes/BarRounded.tsx index bcc01fc8f..f4ed5ac17 100644 --- a/packages/vx-shape/src/shapes/BarRounded.tsx +++ b/packages/vx-shape/src/shapes/BarRounded.tsx @@ -55,10 +55,10 @@ export default function BarRounded({ bottomRight = false, ...restProps }: BarRoundedProps & Omit, keyof BarRoundedProps>) { - topRight = all || top || topRight; - bottomRight = all || bottom || bottomRight; - bottomLeft = all || bottom || bottomLeft; - topLeft = all || top || topLeft; + topRight = all || top || right || topRight; + bottomRight = all || bottom || right || bottomRight; + bottomLeft = all || bottom || left || bottomLeft; + topLeft = all || top || left || topLeft; // clamp radius to center of shortest side of the rect radius = Math.min(radius, Math.min(width, height) / 2); diff --git a/packages/vx-shape/test/BarRounded.test.tsx b/packages/vx-shape/test/BarRounded.test.tsx index 6a6e015cd..0e1f216cc 100644 --- a/packages/vx-shape/test/BarRounded.test.tsx +++ b/packages/vx-shape/test/BarRounded.test.tsx @@ -67,6 +67,20 @@ describe('', () => { ); }); + test('it should set top left & bottom left corner radius', () => { + const wrapper = BarRoundedWrapper({ left: true }); + expect(wrapper.prop('d')).toBe( + 'M2,0 h6 h2v2 v16 v2h-2 h-6 a2,2 0 0 1 -2,-2 v-16 a2,2 0 0 1 2,-2z', + ); + }); + + test('it should set top right & bottom right corner radius', () => { + const wrapper = BarRoundedWrapper({ right: true }); + expect(wrapper.prop('d')).toBe( + 'M2,0 h6 a2,2 0 0 1 2,2 v16 a2,2 0 0 1 -2,2 h-6 h-2v-2 v-16 v-2h2z', + ); + }); + test('it should set all corner radius', () => { const wrapper = BarRoundedWrapper({ all: true }); expect(wrapper.prop('d')).toBe( From f05b2da1fc9c600c5140fbdbd4f6ee51e7d1a178 Mon Sep 17 00:00:00 2001 From: hshoff Date: Sun, 2 Aug 2020 11:15:30 -0400 Subject: [PATCH 3/3] chore(vx-shape): update doc comment to path --- packages/vx-shape/src/shapes/BarRounded.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vx-shape/src/shapes/BarRounded.tsx b/packages/vx-shape/src/shapes/BarRounded.tsx index f4ed5ac17..49c2c415f 100644 --- a/packages/vx-shape/src/shapes/BarRounded.tsx +++ b/packages/vx-shape/src/shapes/BarRounded.tsx @@ -2,9 +2,9 @@ import React from 'react'; import cx from 'classnames'; export type BarRoundedProps = { - /** className to apply to rect element. */ + /** className to apply to path element. */ className?: string; - /** reference to rect element. */ + /** reference to path element. */ innerRef?: React.Ref; /** left position of the bar */ x: number;