-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathProgressBar.tsx
More file actions
120 lines (108 loc) · 3.92 KB
/
Copy pathProgressBar.tsx
File metadata and controls
120 lines (108 loc) · 3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
* Copyright 2022 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {AriaProgressBarProps, useProgressBar} from 'react-aria/useProgressBar';
import {useNumberFormatter} from 'react-aria/useNumberFormatter';
import {clamp} from 'react-stately/private/utils/number';
import {
ClassNameOrFunction,
ContextValue,
dom,
RenderProps,
SlotProps,
useContextProps,
useRenderProps,
useSlot
} from './utils';
import {filterDOMProps} from 'react-aria/filterDOMProps';
import {GlobalDOMAttributes} from '@react-types/shared';
import {LabelContext} from './Label';
import {mergeProps} from 'react-aria/mergeProps';
import React, {createContext, ForwardedRef, forwardRef} from 'react';
export interface ProgressBarProps
extends
Omit<AriaProgressBarProps, 'label'>,
RenderProps<ProgressBarRenderProps>,
SlotProps,
GlobalDOMAttributes<HTMLDivElement> {
/**
* The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
* element. A function may be provided to compute the class based on component state.
*
* @default 'react-aria-ProgressBar'
*/
className?: ClassNameOrFunction<ProgressBarRenderProps>;
}
export interface ProgressBarRenderProps {
/**
* The value as a percentage between the minimum and maximum.
*/
percentage: number | undefined;
/**
* A formatted version of the value.
*
* @selector [aria-valuetext]
*/
valueText: string | undefined;
/**
* Whether the progress bar is indeterminate.
*
* @selector :not([aria-valuenow])
*/
isIndeterminate: boolean;
}
export const ProgressBarContext =
createContext<ContextValue<ProgressBarProps, HTMLDivElement>>(null);
const DEFAULT_FORMAT_OPTIONS: Intl.NumberFormatOptions = {style: 'percent'};
/**
* Progress bars show either determinate or indeterminate progress of an operation
* over time.
*/
export const ProgressBar = forwardRef(function ProgressBar(
props: ProgressBarProps,
ref: ForwardedRef<HTMLDivElement>
) {
[props, ref] = useContextProps(props, ref, ProgressBarContext);
let {value = 0, minValue = 0, maxValue = 100, isIndeterminate = false} = props;
value = clamp(value, minValue, maxValue);
let range = maxValue - minValue;
let formatOptions = props.formatOptions ?? DEFAULT_FORMAT_OPTIONS;
let formatter = useNumberFormatter(formatOptions);
let [labelRef, label] = useSlot(!props['aria-label'] && !props['aria-labelledby']);
let valueLabel =
!isIndeterminate && range === 0 && !props.valueLabel && formatOptions.style === 'percent'
? formatter.format(0)
: props.valueLabel;
let {progressBarProps, labelProps} = useProgressBar({...props, label, valueLabel});
// Calculate the width of the progress bar as a percentage
let percentage =
isIndeterminate ? undefined : range === 0 ? 0 : ((value - minValue) / range) * 100;
let renderProps = useRenderProps({
...props,
defaultClassName: 'react-aria-ProgressBar',
values: {
percentage,
valueText: progressBarProps['aria-valuetext'],
isIndeterminate
}
});
let DOMProps = filterDOMProps(props, {global: true});
return (
<dom.div
{...mergeProps(DOMProps, renderProps, progressBarProps)}
ref={ref}
slot={props.slot || undefined}>
<LabelContext.Provider value={{...labelProps, ref: labelRef, elementType: 'span'}}>
{renderProps.children}
</LabelContext.Provider>
</dom.div>
);
});