diff --git a/packages/ui-number-input/src/NumberInput/__examples__/NumberInput.examples.ts b/packages/ui-number-input/src/NumberInput/__examples__/NumberInput.examples.tsx similarity index 87% rename from packages/ui-number-input/src/NumberInput/__examples__/NumberInput.examples.ts rename to packages/ui-number-input/src/NumberInput/__examples__/NumberInput.examples.tsx index 27a197af75..9f0ae7916a 100644 --- a/packages/ui-number-input/src/NumberInput/__examples__/NumberInput.examples.ts +++ b/packages/ui-number-input/src/NumberInput/__examples__/NumberInput.examples.tsx @@ -22,7 +22,9 @@ * SOFTWARE. */ +import React from 'react' import type { StoryConfig } from '@instructure/ui-test-utils' +import { IconZoomInLine, IconZoomOutLine } from '@instructure/ui-icons' import type { NumberInputProps } from '../props' export default { @@ -30,7 +32,14 @@ export default { maxExamplesPerPage: 50, propValues: { placeholder: [null, 'type something'], - layout: [null, 'inline'] + layout: [null, 'inline'], + renderIcons: [ + null, + { + increase: , + decrease: + } + ] }, getComponentProps: () => { return { diff --git a/packages/ui-number-input/src/NumberInput/__new-tests__/NumberInput.test.tsx b/packages/ui-number-input/src/NumberInput/__new-tests__/NumberInput.test.tsx index 16540b1205..a76c5ba862 100644 --- a/packages/ui-number-input/src/NumberInput/__new-tests__/NumberInput.test.tsx +++ b/packages/ui-number-input/src/NumberInput/__new-tests__/NumberInput.test.tsx @@ -33,6 +33,7 @@ import { NumberInput } from '../index' import NumberInputExamples from '../__examples__/NumberInput.examples' // eslint-disable-next-line no-restricted-imports import { generateA11yTests } from '@instructure/ui-scripts/lib/test/generateA11yTests' +import { IconZoomInLine, IconZoomOutLine } from '@instructure/ui-icons' describe('', () => { let consoleWarningMock: ReturnType @@ -282,4 +283,39 @@ describe('', () => { }) } }) + + it('renders custom interactive icons', async () => { + const onDecrement = vi.fn() + const onIncrement = vi.fn() + const { container } = render( + , + decrease: + }} + /> + ) + + const zoomInIcon = container.querySelector('svg[name="IconZoomIn"]') + const zoomOutIcon = container.querySelector('svg[name="IconZoomOut"]') + expect(zoomInIcon).toBeInTheDocument() + expect(zoomOutIcon).toBeInTheDocument() + + const buttons = container.querySelectorAll( + 'button[class$="-numberInput_arrow' + ) + + userEvent.click(buttons[0]) + await waitFor(() => { + expect(onIncrement).toHaveBeenCalledTimes(1) + }) + + userEvent.click(buttons[1]) + await waitFor(() => { + expect(onDecrement).toHaveBeenCalledTimes(1) + }) + }) }) diff --git a/packages/ui-number-input/src/NumberInput/index.tsx b/packages/ui-number-input/src/NumberInput/index.tsx index 4c40a1e2f6..703cecd52d 100644 --- a/packages/ui-number-input/src/NumberInput/index.tsx +++ b/packages/ui-number-input/src/NumberInput/index.tsx @@ -52,6 +52,7 @@ import type { NumberInputState, NumberInputStyleProps } from './props' +import { Renderable } from '@instructure/shared-types' /** --- @@ -203,7 +204,7 @@ class NumberInput extends Component { } } - renderArrows() { + renderArrows(customIcons?: { increase: Renderable; decrease: Renderable }) { return ( ) @@ -238,7 +247,8 @@ class NumberInput extends Component { value, width, styles, - allowStringValue + allowStringValue, + renderIcons } = this.props const { interaction } = this @@ -295,7 +305,7 @@ class NumberInput extends Component { onChange={this.handleChange} onKeyDown={this.handleKeyDown} /> - {showArrows ? this.renderArrows() : null} + {showArrows ? this.renderArrows(renderIcons) : null} diff --git a/packages/ui-number-input/src/NumberInput/props.ts b/packages/ui-number-input/src/NumberInput/props.ts index d41f03fa75..38b190d2eb 100644 --- a/packages/ui-number-input/src/NumberInput/props.ts +++ b/packages/ui-number-input/src/NumberInput/props.ts @@ -166,6 +166,14 @@ type NumberInputOwnProps = { * sets the input type to string and allows string as value */ allowStringValue?: boolean + + /** + * Sets the icons to be rendered for increase and decrease buttons + */ + renderIcons?: { + increase: Renderable + decrease: Renderable + } } type NumberInputState = { @@ -226,7 +234,11 @@ const propTypes: PropValidators = { onKeyDown: PropTypes.func, inputMode: PropTypes.oneOf(['numeric', 'decimal', 'tel']), textAlign: PropTypes.oneOf(['start', 'center']), - allowStringValue: PropTypes.bool + allowStringValue: PropTypes.bool, + renderIcons: PropTypes.shape({ + increase: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired, + decrease: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired + }) } const allowedProps: AllowedPropKeys = [ @@ -250,7 +262,8 @@ const allowedProps: AllowedPropKeys = [ 'onKeyDown', 'inputMode', 'textAlign', - 'allowStringValue' + 'allowStringValue', + 'renderIcons' ] export type {