Skip to content

Commit 5565152

Browse files
authored
feat: adding formatValue to allow customizing the value format (#2268)
* feat: adding formatValue to allow customizing the value format * docs: update props table for SliderField * docs: update docs * Create red-pigs-rhyme.md * chore: address feedback * test: add unit tests * chore: address comments
1 parent 44ed118 commit 5565152

File tree

8 files changed

+118
-15
lines changed

8 files changed

+118
-15
lines changed

.changeset/red-pigs-rhyme.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
"@aws-amplify/ui-react": minor
3+
---
4+
5+
feat: adding `formatValue` prop on SliderField to allow formatting the value
6+
7+
***Example***
8+
9+
```jsx
10+
export const SliderFieldFormatValueExample = () => {
11+
const formatValue = (value: number) => {
12+
return `${value}%`;
13+
};
14+
return (
15+
<SliderField
16+
label="SliderField with formatted value"
17+
defaultValue={50}
18+
formatValue={formatValue}
19+
/>
20+
);
21+
};
22+
23+
```
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { SliderField } from '@aws-amplify/ui-react';
2+
3+
export const SliderFieldFormatValueExample = () => {
4+
const formatValue = (value: number) => {
5+
return `${value}%`;
6+
};
7+
return (
8+
<SliderField
9+
label="SliderField with formatted value"
10+
defaultValue={50}
11+
formatValue={formatValue}
12+
/>
13+
);
14+
};

docs/src/pages/[platform]/components/sliderfield/examples/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export { DefaultSliderFieldExample } from './DefaultSliderFieldExample';
22
export { ControlledSliderFieldExample } from './ControlledSliderFieldExample';
33
export { SliderFieldBasicsExample } from './SliderFieldBasicsExample';
4+
export { SliderFieldFormatValueExample } from './SliderFieldFormatValueExample';
45
export { SliderFieldOrientationExample } from './SliderFieldOrientationExample';
56
export { SliderFieldAriaExample } from './SliderFieldAriaExample';
67
export { SliderFieldIconsExample } from './SliderFieldIconsExample';

docs/src/pages/[platform]/components/sliderfield/props-table.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@ StyleToken<Property.Color>
139139
<TableCell className="props-table__tr-description">Applies to the filled-in part of the SliderField track</TableCell>
140140
</TableRow>
141141

142+
<TableRow>
143+
<TableCell className="props-table__tr-name">formatValue</TableCell>
144+
<TableCell>
145+
```jsx
146+
(value: number) => React.ReactNode
147+
```
148+
</TableCell>
149+
<TableCell className="props-table__tr-description">Use to format how the value gets rendered</TableCell>
150+
</TableRow>
151+
142152
<TableRow>
143153
<TableCell className="props-table__tr-name">hasError</TableCell>
144154
<TableCell>

docs/src/pages/[platform]/components/sliderfield/react.mdx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
DefaultSliderFieldExample,
66
ControlledSliderFieldExample,
77
SliderFieldBasicsExample,
8+
SliderFieldFormatValueExample,
89
SliderFieldOrientationExample,
910
SliderFieldAriaExample,
1011
SliderFieldIconsExample,
@@ -135,6 +136,19 @@ To add icons on either side of the SliderField, you may use the `outerStartCompo
135136
</ExampleCode>
136137
</Example>
137138
139+
### Format value
140+
To format how the `value` is displayed, you can pass in a render function to `formatValue` prop.
141+
142+
<Example>
143+
<SliderFieldFormatValueExample />
144+
<ExampleCode>
145+
```jsx file=./examples/SliderFieldFormatValueExample.tsx
146+
147+
```
148+
149+
</ExampleCode>
150+
</Example>
151+
138152
### Validation error
139153

140154
To validate the SliderField input, use the `hasError` and `errorMessage` props.
@@ -190,15 +204,6 @@ To override styling on all SliderField components, you can set the Amplify CSS v
190204
}
191205
```
192206

193-
To replace SliderField styling, unset it:
194-
195-
```css
196-
.amplify-sliderfield {
197-
all: unset;
198-
/* Add your styling here*/
199-
}
200-
```
201-
202207
### Local styling
203208

204209
To override styling on a specific SliderField, you can use class selectors or style props.

packages/react/src/primitives/SliderField/SliderField.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const SliderFieldPrimitive: Primitive<SliderFieldProps, typeof Root> = (
2929
emptyTrackColor,
3030
errorMessage,
3131
filledTrackColor,
32+
formatValue,
3233
hasError = false,
3334
id,
3435
isDisabled,
@@ -77,6 +78,17 @@ const SliderFieldPrimitive: Primitive<SliderFieldProps, typeof Root> = (
7778
[onChange]
7879
);
7980

81+
const renderedValue = React.useMemo(() => {
82+
const formattedValue = isFunction(formatValue)
83+
? formatValue(currentValue)
84+
: currentValue;
85+
return typeof formatValue === 'string' ? (
86+
<View as="span">{formattedValue}</View>
87+
) : (
88+
formattedValue
89+
);
90+
}, [currentValue, formatValue]);
91+
8092
const isVertical = orientation === 'vertical';
8193
const componentClasses = classNames(
8294
ComponentClassNames.SliderFieldTrack,
@@ -109,7 +121,7 @@ const SliderFieldPrimitive: Primitive<SliderFieldProps, typeof Root> = (
109121
visuallyHidden={labelHidden}
110122
>
111123
<View as="span">{label}</View>
112-
{!isValueHidden ? <View as="span">{currentValue}</View> : null}
124+
{!isValueHidden ? renderedValue : null}
113125
</Label>
114126
<FieldDescription
115127
id={descriptionId}

packages/react/src/primitives/SliderField/__tests__/SliderField.test.tsx

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
SLIDER_ROOT_TEST_ID,
99
SLIDER_TRACK_TEST_ID,
1010
} from '../SliderField';
11+
import { Heading } from '../../Heading';
1112
import {
1213
testFlexProps,
1314
expectFlexContainerStyleProps,
@@ -85,13 +86,43 @@ describe('SliderField: ', () => {
8586

8687
it('should display value if isValueHidden is false', async () => {
8788
render(<SliderField defaultValue={10} label="slider" />);
88-
const value = await screen.queryByText('10');
89+
const value = screen.queryByText('10');
8990
expect(value).toBeInTheDocument();
9091
});
9192

93+
it('should display string formatted value if formatValue is provided', async () => {
94+
render(
95+
<SliderField
96+
defaultValue={10}
97+
label="slider"
98+
formatValue={(value) => {
99+
return `${value}%`;
100+
}}
101+
/>
102+
);
103+
104+
const value = await screen.findByText('10%');
105+
expect(value).toBeInTheDocument();
106+
});
107+
108+
it('should display component-based formatted value if formatValue is provided', async () => {
109+
render(
110+
<SliderField
111+
defaultValue={10}
112+
label="slider"
113+
formatValue={(value) => {
114+
return <Heading>{value}</Heading>;
115+
}}
116+
/>
117+
);
118+
119+
const heading = await screen.findByText('10');
120+
expect(heading).toHaveClass(ComponentClassNames.Heading);
121+
});
122+
92123
it('should not display value if isValueHidden is true', async () => {
93124
render(<SliderField defaultValue={10} label="slider" isValueHidden />);
94-
const value = await screen.queryByText('10');
125+
const value = screen.queryByText('10');
95126
expect(value).not.toBeInTheDocument();
96127
});
97128
});
@@ -290,7 +321,7 @@ describe('SliderField: ', () => {
290321
/>
291322
);
292323

293-
const errorText = await screen.queryByText(errorMessage);
324+
const errorText = screen.queryByText(errorMessage);
294325
expect(errorText).not.toBeInTheDocument();
295326
});
296327

@@ -303,7 +334,7 @@ describe('SliderField: ', () => {
303334
hasError
304335
/>
305336
);
306-
const errorText = await screen.queryByText(errorMessage);
337+
const errorText = screen.queryByText(errorMessage);
307338
expect(errorText.innerHTML).toContain(errorMessage);
308339
});
309340
});
@@ -318,7 +349,7 @@ describe('SliderField: ', () => {
318349
/>
319350
);
320351

321-
const descriptiveText = await screen.queryByText('Description');
352+
const descriptiveText = screen.queryByText('Description');
322353
expect(descriptiveText.innerHTML).toContain('Description');
323354
});
324355

packages/react/src/primitives/types/sliderField.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Property } from 'csstype';
2+
import React from 'react';
23

34
import { StyleToken } from './style';
45
import { TextInputFieldProps } from './textField';
@@ -74,6 +75,12 @@ export interface SliderFieldProps extends TextInputFieldProps, ViewProps {
7475
*/
7576
defaultValue?: number;
7677

78+
/**
79+
* @description
80+
* Use to format how the value gets rendered
81+
*/
82+
formatValue?: (value: number) => React.ReactNode;
83+
7784
/**
7885
* @description
7986
* Handles changes to the current value when using the SliderField as a controlled component

0 commit comments

Comments
 (0)