Skip to content

Commit

Permalink
Merge branch 'master' into add-border-radius-to-radio-button-group
Browse files Browse the repository at this point in the history
  • Loading branch information
LeandroTorresSicilia authored Oct 25, 2022
2 parents 177af01 + d72f26a commit 19a5dd0
Show file tree
Hide file tree
Showing 16 changed files with 607 additions and 17 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"dependencies": {
"@rainbow-modules/hooks": "^0.12.0",
"@rainbow-modules/validation": "^0.53.0",
"autosize": "^4.0.2",
"chart.js": "2.9.4",
"clipboard-copy": "^2.0.0",
Expand Down Expand Up @@ -134,7 +135,10 @@
"@rainbow-modules/icons": "^0.24.1-canary.2",
"@rainbow-modules/search": "^0.51.1",
"@stripe/stripe-js": "^1.3.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^3.2.1",
"@testing-library/user-event": "^14.4.3",
"@wdio/allure-reporter": "^7",
"@wdio/cli": "^7",
"@wdio/jasmine-framework": "^7",
Expand Down
1 change: 1 addition & 0 deletions setupTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { configure } from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
import { toHaveNoViolations } from 'jest-axe';
import toBeFocusable from './jestMatchers/toBeFocusable';
import '@testing-library/jest-dom';

configure({ adapter: new Adapter() });

Expand Down
6 changes: 3 additions & 3 deletions src/components/Button/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ import React from 'react';
import { Button } from 'react-rainbow-components';

<div className="rainbow-p-vertical_large rainbow-align-content_center rainbow-flex_wrap">
<Button label="Button Square" variant="brand" className="rainbow-m-around_medium" borderRadius='square'/>
<Button label="Button Semi Rounded" variant="brand" className="rainbow-m-around_medium" borderRadius='semi-rounded'/>
<Button label="Button Rounded" variant="brand" className="rainbow-m-around_medium" borderRadius='rounded'/>
<Button label="Button Square" variant="brand" className="rainbow-m-around_medium" borderRadius="square"/>
<Button label="Button Semi Rounded" variant="brand" className="rainbow-m-around_medium" borderRadius="semi-rounded"/>
<Button label="Button Rounded" variant="brand" className="rainbow-m-around_medium" borderRadius="rounded"/>
</div>
```
1 change: 1 addition & 0 deletions src/components/ButtonIcon/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface ButtonIconProps extends BaseProps {
ariaPressed?: boolean;
form?: string;
id?: string;
borderRadius?: 'square' | 'semi-rounded' | 'rounded';
}

declare const ButtonIcon: ComponentType<ButtonIconProps>;
Expand Down
5 changes: 5 additions & 0 deletions src/components/ButtonIcon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const ButtonIcon = React.forwardRef((props, ref) => {
variant,
size,
tooltip,
borderRadius,
} = props;
const {
onMouseEnter,
Expand Down Expand Up @@ -119,6 +120,7 @@ const ButtonIcon = React.forwardRef((props, ref) => {
onMouseLeave={handleMouseLeave}
form={form}
ref={buttonRef}
borderRadius={borderRadius}
>
{icon}
<AssistiveText text={assistiveText} />
Expand Down Expand Up @@ -209,6 +211,8 @@ ButtonIcon.propTypes = {
style: PropTypes.object,
/** The id of the outer element. */
id: PropTypes.string,
/** The border radius of the button. Valid values are square, semi-rounded and rounded. This value defaults to rounded. */
borderRadius: PropTypes.oneOf(['square', 'semi-rounded', 'rounded']),
};

ButtonIcon.defaultProps = {
Expand Down Expand Up @@ -237,6 +241,7 @@ ButtonIcon.defaultProps = {
ariaControls: undefined,
ariaExpanded: undefined,
form: undefined,
borderRadius: 'rounded',
};

export default ButtonIcon;
22 changes: 22 additions & 0 deletions src/components/ButtonIcon/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ import { faStar } from '@fortawesome/free-regular-svg-icons';
</div>
```

# ButtonIcons with Border Radius
##### ButtonIcons with different border radius.

```js
import React from 'react';
import { ButtonIcon } from 'react-rainbow-components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faStar } from '@fortawesome/free-regular-svg-icons';

<div className="rainbow-p-vertical_large rainbow-p-left_x-large rainbow-flex rainbow-align_center">
<div className="rainbow-p-right_large">
<ButtonIcon variant="neutral" borderRadius="square" icon={<FontAwesomeIcon icon={faStar} />} />
</div>
<div className="rainbow-p-right_large">
<ButtonIcon variant="neutral" borderRadius="semi-rounded" icon={<FontAwesomeIcon icon={faStar} />} />
</div>
<div className="rainbow-p-right_large">
<ButtonIcon variant="neutral" borderRadius="rounded" icon={<FontAwesomeIcon icon={faStar} />} />
</div>
</div>
```

# ButtonIcons with shaded variant
##### The appearance of a ButtonIcon can be changed by implementing the shaded variant, so the whole section will appear with a shadow around it.

Expand Down
18 changes: 17 additions & 1 deletion src/components/ButtonIcon/styled/button.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import styled from 'styled-components';
import { BORDER_RADIUS_2 } from '../../../styles/borderRadius';
import {
BORDER_RADIUS_2,
BORDER_RADIUS_SQUARE,
BORDER_RADIUS_SEMI_ROUNDED,
} from '../../../styles/borderRadius';
import { COLOR_WHITE, COLOR_GRAY_3, COLOR_DARK_1 } from '../../../styles/colors';
import { lighten, colorToRgba, replaceAlpha } from '../../../styles/helpers/color';
import attachThemeAttrs from '../../../styles/helpers/attachThemeAttrs';
Expand Down Expand Up @@ -397,6 +401,18 @@ const StyledButton = attachThemeAttrs(styled.button).attrs(props => {
font-size: 1rem !important;
}
`};
${props =>
props.borderRadius === 'square' &&
`
border-radius: ${BORDER_RADIUS_SQUARE};
`};
${props =>
props.borderRadius === 'semi-rounded' &&
`
border-radius: ${BORDER_RADIUS_SEMI_ROUNDED};
`};
`;

export default StyledButton;
145 changes: 145 additions & 0 deletions src/components/CurrencyInput/__test__/currencyInput.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import React, { useState } from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import CurrencyInput from '..';

const TestCurrencyInput = props => {
// eslint-disable-next-line react/prop-types
const { initialValue } = props;
const [value, setValue] = useState(initialValue);
return <CurrencyInput onChange={setValue} value={value} />;
};

describe('<CurrencyInput />', () => {
it('should mount a input with a value of $5.00', () => {
[5, '5', '5.', '5.00', '5.00003'].forEach(value => {
render(<CurrencyInput value={value} />);
});
screen.getAllByRole('textbox').forEach(input => {
expect(input).toHaveValue('$5.00');
});
});

it('should mount a input with a value of $0.00', () => {
[0, '.0', '0.00003'].forEach(value => {
render(<CurrencyInput value={value} />);
});
screen.getAllByRole('textbox').forEach(input => {
expect(input).toHaveValue('$0.00');
});
});

it('should mount a input with a empty value', () => {
['', ' ', 'foo', null, undefined, true, false, Infinity, {}, []].forEach(value => {
render(<CurrencyInput value={value} />);
});
screen.getAllByRole('textbox').forEach(input => {
expect(input).toHaveValue('');
});
});

it('should mount a input with a value of "-"', () => {
const { getByRole } = render(<CurrencyInput value="-" />);
expect(getByRole('textbox')).toHaveValue('-');
});

it('should be change value to 5 when is fucused', () => {
const { getByRole } = render(<CurrencyInput value={5} />);
const input = getByRole('textbox');
expect(input).toHaveValue('$5.00');
fireEvent.focus(input);
expect(input).toHaveValue('5');
});

it('should be change value to $5.00 when is not focused', () => {
const { getByRole } = render(<CurrencyInput value={5} />);
const input = getByRole('textbox');
fireEvent.focus(input);
expect(input).toHaveValue('5');
fireEvent.blur(input);
expect(input).toHaveValue('$5.00');
});

it('should fire onChange with the value when it is a valid value', () => {
const onChangeMockFn = jest.fn();
const { getByRole } = render(<CurrencyInput onChange={onChangeMockFn} />);
const input = getByRole('textbox');
['5', '5.', '05', '5.00', '-', '.0', '-5'].forEach(value => {
fireEvent.change(input, { target: { value } });
expect(onChangeMockFn).toHaveBeenCalledWith(value);
});
});

it('should not fire onChange with the value when it is an invalid value', () => {
const onChangeMockFn = jest.fn();
const { getByRole } = render(<CurrencyInput onChange={onChangeMockFn} />);
const input = getByRole('textbox');
['5..', '5..0', '.', 'foo', ' ', ''].forEach(value => {
fireEvent.change(input, { target: { value } });
});
expect(onChangeMockFn).toHaveBeenCalledTimes(0);
});

it('should calculate the selectionStart when writing to the input', async () => {
const { getByRole } = render(<TestCurrencyInput />);
const input = getByRole('textbox');

fireEvent.focus(input);
input.focus();
input.setSelectionRange(0, 0);
expect(input.selectionStart).toBe(0);
expect(input.selectionEnd).toBe(0);

await userEvent.type(input, '123');
expect(input).toHaveValue('123');
expect(input.selectionStart).toBe(3);

await userEvent.type(input, '4');
expect(input).toHaveValue('1,234');
expect(input.selectionStart).toBe(5);
});

it('should calculate the selectionStart when a valid number is pasted into the input', async () => {
const { getByRole } = render(<TestCurrencyInput initialValue={1234} />);
const input = getByRole('textbox');

fireEvent.focus(input);
input.focus();
input.setSelectionRange(2, 2);
expect(input.selectionStart).toBe(2);
expect(input).toHaveValue('1,234');

await userEvent.paste('567');
expect(input).toHaveValue('1,567,234');
expect(input.selectionStart).toBe(6);
});

it('should calculate the selectionStart when an input slice is cut', async () => {
const { getByRole } = render(<TestCurrencyInput initialValue={1234567} />);
const input = getByRole('textbox');

fireEvent.focus(input);
input.focus();
input.setSelectionRange(2, 6);
expect(input).toHaveValue('1,234,567');

expect(input.selectionStart).toBe(2);
await userEvent.cut();
expect(input).toHaveValue('1,567');
expect(input.selectionStart).toBe(1);
});

it('should calculate the selectionStart when an input slice is cut', async () => {
const { getByRole } = render(<TestCurrencyInput initialValue="0.0" />);
const input = getByRole('textbox');

fireEvent.focus(input);
expect(input).toHaveValue('0.0');

expect(input.selectionStart).toBe(0);
fireEvent.change(input, { target: { value: '01.0', selectionStart: 2 } });
expect(input).toHaveValue('1.0');
expect(input.selectionStart).toBe(1);
});
});
9 changes: 5 additions & 4 deletions src/components/CurrencyInput/helpers/formatCurrency.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import isValidNumberValue from './isValidNumberValue';

export default function formatCurrency({ value, locale, options }) {
if (value === '-' || value === '' || value === null) {
if (value === '-') {
return value;
}
const number = Number(value);

if (!Number.isNaN(number)) {
return new Intl.NumberFormat(locale, options).format(number);
if (isValidNumberValue(value)) {
return new Intl.NumberFormat(locale, options).format(Number(value));
}

return '';
Expand Down
1 change: 1 addition & 0 deletions src/components/CurrencyInput/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as countCharacters } from './countCharacters';
export { default as isValidStringNumber } from './isValidStringNumber';
export { default as normalizeValue } from './normalizeValue';
export { default as formatInteger } from './formatInteger';
export { default as isValidNumberValue } from './isValidNumberValue';
6 changes: 6 additions & 0 deletions src/components/CurrencyInput/helpers/isValidNumberValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { isBoolean, isEmpty, isNumber } from '@rainbow-modules/validation';

export default function isValidNumberValue(value) {
const number = Number(value);
return !isBoolean(value) && !isEmpty(value) && isNumber(number) && Number.isFinite(number);
}
5 changes: 3 additions & 2 deletions src/components/CurrencyInput/helpers/normalizeValue.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import formatInteger from './formatInteger';
import isValidNumberValue from './isValidNumberValue';

export default function normalizeValue({ value, locale, decimalSeparator, options }) {
const stringValue = String(value);
if (value === '-' || value === '' || value === null) {
if (value === '-') {
return value;
}

if (!Number.isNaN(Number(value))) {
if (isValidNumberValue(value)) {
const [integer, fraction] = stringValue.split('.');
const formattedInteger = formatInteger({ integer, locale, options });

Expand Down
Loading

0 comments on commit 19a5dd0

Please sign in to comment.