@cdx-ui/primitives 0.0.1-beta.170 → 0.0.1-beta.172
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/accordion/Accordion.js +59 -0
- package/lib/commonjs/accordion/Accordion.js.map +1 -0
- package/lib/commonjs/accordion/AccordionItem.js +68 -0
- package/lib/commonjs/accordion/AccordionItem.js.map +1 -0
- package/lib/commonjs/accordion/AccordionPanel.js +71 -0
- package/lib/commonjs/accordion/AccordionPanel.js.map +1 -0
- package/lib/commonjs/accordion/AccordionTrigger.js +122 -0
- package/lib/commonjs/accordion/AccordionTrigger.js.map +1 -0
- package/lib/commonjs/accordion/context.js +26 -0
- package/lib/commonjs/accordion/context.js.map +1 -0
- package/lib/commonjs/accordion/index.js +59 -0
- package/lib/commonjs/accordion/index.js.map +1 -0
- package/lib/commonjs/accordion/types.js +6 -0
- package/lib/commonjs/accordion/types.js.map +1 -0
- package/lib/commonjs/accordion/utils.js +24 -0
- package/lib/commonjs/accordion/utils.js.map +1 -0
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/slider/SliderRail.js +35 -9
- package/lib/commonjs/slider/SliderRail.js.map +1 -1
- package/lib/commonjs/slider/SliderRoot.js +155 -97
- package/lib/commonjs/slider/SliderRoot.js.map +1 -1
- package/lib/commonjs/slider/SliderThumb.js +182 -68
- package/lib/commonjs/slider/SliderThumb.js.map +1 -1
- package/lib/commonjs/slider/context.js +4 -1
- package/lib/commonjs/slider/context.js.map +1 -1
- package/lib/commonjs/slider/index.js +36 -0
- package/lib/commonjs/slider/index.js.map +1 -1
- package/lib/commonjs/slider/useSliderPointer.js +1 -1
- package/lib/commonjs/slider/useSliderPointer.js.map +1 -1
- package/lib/commonjs/slider/utils.js +68 -0
- package/lib/commonjs/slider/utils.js.map +1 -1
- package/lib/module/accordion/Accordion.js +55 -0
- package/lib/module/accordion/Accordion.js.map +1 -0
- package/lib/module/accordion/AccordionItem.js +64 -0
- package/lib/module/accordion/AccordionItem.js.map +1 -0
- package/lib/module/accordion/AccordionPanel.js +67 -0
- package/lib/module/accordion/AccordionPanel.js.map +1 -0
- package/lib/module/accordion/AccordionTrigger.js +118 -0
- package/lib/module/accordion/AccordionTrigger.js.map +1 -0
- package/lib/module/accordion/context.js +20 -0
- package/lib/module/accordion/context.js.map +1 -0
- package/lib/module/accordion/index.js +8 -0
- package/lib/module/accordion/index.js.map +1 -0
- package/lib/module/accordion/types.js +4 -0
- package/lib/module/accordion/types.js.map +1 -0
- package/lib/module/accordion/utils.js +19 -0
- package/lib/module/accordion/utils.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/slider/SliderRail.js +35 -9
- package/lib/module/slider/SliderRail.js.map +1 -1
- package/lib/module/slider/SliderRoot.js +157 -99
- package/lib/module/slider/SliderRoot.js.map +1 -1
- package/lib/module/slider/SliderThumb.js +185 -71
- package/lib/module/slider/SliderThumb.js.map +1 -1
- package/lib/module/slider/context.js +1 -0
- package/lib/module/slider/context.js.map +1 -1
- package/lib/module/slider/index.js +2 -2
- package/lib/module/slider/index.js.map +1 -1
- package/lib/module/slider/useSliderPointer.js +1 -1
- package/lib/module/slider/useSliderPointer.js.map +1 -1
- package/lib/module/slider/utils.js +63 -0
- package/lib/module/slider/utils.js.map +1 -1
- package/lib/typescript/accordion/Accordion.d.ts +8 -0
- package/lib/typescript/accordion/Accordion.d.ts.map +1 -0
- package/lib/typescript/accordion/AccordionItem.d.ts +8 -0
- package/lib/typescript/accordion/AccordionItem.d.ts.map +1 -0
- package/lib/typescript/accordion/AccordionPanel.d.ts +7 -0
- package/lib/typescript/accordion/AccordionPanel.d.ts.map +1 -0
- package/lib/typescript/accordion/AccordionTrigger.d.ts +6 -0
- package/lib/typescript/accordion/AccordionTrigger.d.ts.map +1 -0
- package/lib/typescript/accordion/context.d.ts +6 -0
- package/lib/typescript/accordion/context.d.ts.map +1 -0
- package/lib/typescript/accordion/index.d.ts +7 -0
- package/lib/typescript/accordion/index.d.ts.map +1 -0
- package/lib/typescript/accordion/types.d.ts +50 -0
- package/lib/typescript/accordion/types.d.ts.map +1 -0
- package/lib/typescript/accordion/utils.d.ts +4 -0
- package/lib/typescript/accordion/utils.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/slider/SliderRail.d.ts.map +1 -1
- package/lib/typescript/slider/SliderRoot.d.ts +2 -2
- package/lib/typescript/slider/SliderRoot.d.ts.map +1 -1
- package/lib/typescript/slider/SliderThumb.d.ts.map +1 -1
- package/lib/typescript/slider/context.d.ts +53 -9
- package/lib/typescript/slider/context.d.ts.map +1 -1
- package/lib/typescript/slider/index.d.ts +4 -4
- package/lib/typescript/slider/index.d.ts.map +1 -1
- package/lib/typescript/slider/types.d.ts +44 -8
- package/lib/typescript/slider/types.d.ts.map +1 -1
- package/lib/typescript/slider/utils.d.ts +8 -0
- package/lib/typescript/slider/utils.d.ts.map +1 -1
- package/package.json +5 -3
- package/src/accordion/Accordion.tsx +72 -0
- package/src/accordion/AccordionItem.tsx +70 -0
- package/src/accordion/AccordionPanel.tsx +72 -0
- package/src/accordion/AccordionTrigger.tsx +120 -0
- package/src/accordion/context.tsx +22 -0
- package/src/accordion/index.ts +21 -0
- package/src/accordion/types.ts +56 -0
- package/src/accordion/utils.ts +22 -0
- package/src/index.ts +1 -0
- package/src/slider/SliderRail.tsx +56 -8
- package/src/slider/SliderRoot.tsx +255 -136
- package/src/slider/SliderThumb.tsx +240 -88
- package/src/slider/context.tsx +53 -9
- package/src/slider/index.ts +9 -2
- package/src/slider/types.ts +49 -8
- package/src/slider/useSliderPointer.ts +1 -1
- package/src/slider/utils.ts +76 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import { Platform, View } from 'react-native';
|
|
3
|
+
import { useDisclosure } from '@react-native-aria/disclosure';
|
|
4
|
+
import { Slot } from '../slot';
|
|
5
|
+
import { dataAttributes, mergeDataAttributes } from '../utils/dataAttributes';
|
|
6
|
+
import { useAccordionItemContext } from './context';
|
|
7
|
+
import type { IAccordionPanelProps } from './types';
|
|
8
|
+
|
|
9
|
+
export interface AccordionPanelRootProps extends IAccordionPanelProps {
|
|
10
|
+
asChild?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const AccordionPanelRoot = forwardRef<View, AccordionPanelRootProps>(
|
|
14
|
+
({ asChild, children, className, style, ...props }, ref) => {
|
|
15
|
+
const { isExpanded, isDisabled, triggerId, panelId, toggle } = useAccordionItemContext();
|
|
16
|
+
|
|
17
|
+
const toggleState = {
|
|
18
|
+
isSelected: isExpanded,
|
|
19
|
+
defaultSelected: false,
|
|
20
|
+
setSelected: (selected: boolean) => {
|
|
21
|
+
if (selected !== isExpanded) {
|
|
22
|
+
toggle();
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
toggle,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const { disclosureProps } = useDisclosure({}, toggleState);
|
|
29
|
+
const Comp = asChild ? Slot : View;
|
|
30
|
+
|
|
31
|
+
if (!isExpanded) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const platformA11yProps =
|
|
36
|
+
Platform.OS === 'web'
|
|
37
|
+
? {
|
|
38
|
+
id: panelId,
|
|
39
|
+
nativeID: panelId,
|
|
40
|
+
role: 'region' as const,
|
|
41
|
+
'aria-labelledby': triggerId,
|
|
42
|
+
}
|
|
43
|
+
: {
|
|
44
|
+
nativeID: panelId,
|
|
45
|
+
accessibilityLabelledBy: triggerId,
|
|
46
|
+
accessibilityRole: 'none' as const,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Comp
|
|
51
|
+
ref={ref}
|
|
52
|
+
className={className}
|
|
53
|
+
style={style}
|
|
54
|
+
{...disclosureProps}
|
|
55
|
+
{...props}
|
|
56
|
+
{...mergeDataAttributes(
|
|
57
|
+
props,
|
|
58
|
+
dataAttributes({
|
|
59
|
+
slot: 'accordion-panel',
|
|
60
|
+
state: 'open',
|
|
61
|
+
disabled: isDisabled,
|
|
62
|
+
}),
|
|
63
|
+
)}
|
|
64
|
+
{...platformA11yProps}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</Comp>
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
AccordionPanelRoot.displayName = 'AccordionPanelRoot';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { forwardRef, useMemo } from 'react';
|
|
2
|
+
import { Platform, Pressable } from 'react-native';
|
|
3
|
+
import { composeEventHandlers } from '@cdx-ui/utils';
|
|
4
|
+
import { useFocus, useFocusRing } from '@react-native-aria/focus';
|
|
5
|
+
import { usePress, useHover } from '@react-native-aria/interactions';
|
|
6
|
+
import { useDisclosureButton } from '@react-native-aria/disclosure';
|
|
7
|
+
import { Slot } from '../slot';
|
|
8
|
+
import { dataAttributes, mergeDataAttributes } from '../utils/dataAttributes';
|
|
9
|
+
import { useAccordionItemContext } from './context';
|
|
10
|
+
import type { IAccordionTriggerProps } from './types';
|
|
11
|
+
|
|
12
|
+
export interface AccordionTriggerRootProps extends IAccordionTriggerProps {
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const AccordionTriggerRoot = forwardRef<
|
|
17
|
+
React.ComponentRef<typeof Pressable>,
|
|
18
|
+
AccordionTriggerRootProps
|
|
19
|
+
>(
|
|
20
|
+
(
|
|
21
|
+
{
|
|
22
|
+
asChild,
|
|
23
|
+
children,
|
|
24
|
+
className,
|
|
25
|
+
style,
|
|
26
|
+
onPress,
|
|
27
|
+
onPressIn,
|
|
28
|
+
onPressOut,
|
|
29
|
+
onHoverIn,
|
|
30
|
+
onHoverOut,
|
|
31
|
+
onFocus,
|
|
32
|
+
onBlur,
|
|
33
|
+
accessibilityLabel,
|
|
34
|
+
...props
|
|
35
|
+
},
|
|
36
|
+
ref,
|
|
37
|
+
) => {
|
|
38
|
+
const { isExpanded, isDisabled, triggerId, panelId, toggle } = useAccordionItemContext();
|
|
39
|
+
|
|
40
|
+
const toggleState = useMemo(
|
|
41
|
+
() => ({
|
|
42
|
+
isSelected: isExpanded,
|
|
43
|
+
defaultSelected: false,
|
|
44
|
+
setSelected: (selected: boolean) => {
|
|
45
|
+
if (selected !== isExpanded) {
|
|
46
|
+
toggle();
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
toggle,
|
|
50
|
+
}),
|
|
51
|
+
[isExpanded, toggle],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const { buttonProps } = useDisclosureButton({}, toggleState);
|
|
55
|
+
const { focusProps, isFocused } = useFocus();
|
|
56
|
+
const { focusProps: focusRingProps, isFocusVisible } = useFocusRing() as {
|
|
57
|
+
focusProps: { onFocus?: () => void; onBlur?: () => void };
|
|
58
|
+
isFocusVisible: boolean;
|
|
59
|
+
};
|
|
60
|
+
const { pressProps, isPressed } = usePress({ isDisabled });
|
|
61
|
+
const { hoverProps, isHovered } = useHover({ isDisabled });
|
|
62
|
+
|
|
63
|
+
const Comp = asChild ? Slot : Pressable;
|
|
64
|
+
|
|
65
|
+
const platformA11yProps =
|
|
66
|
+
Platform.OS === 'web'
|
|
67
|
+
? {
|
|
68
|
+
id: triggerId,
|
|
69
|
+
role: 'button' as const,
|
|
70
|
+
'aria-expanded': isExpanded,
|
|
71
|
+
'aria-disabled': isDisabled || undefined,
|
|
72
|
+
'aria-controls': isExpanded ? panelId : undefined,
|
|
73
|
+
}
|
|
74
|
+
: {
|
|
75
|
+
nativeID: triggerId,
|
|
76
|
+
accessibilityRole: 'button' as const,
|
|
77
|
+
accessibilityState: { expanded: isExpanded, disabled: isDisabled },
|
|
78
|
+
accessibilityControls: isExpanded ? panelId : undefined,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const { onPress: disclosureOnPress, ...disclosureRestProps } = buttonProps;
|
|
82
|
+
const disclosureProps = Platform.OS === 'web' ? {} : disclosureRestProps;
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<Comp
|
|
86
|
+
ref={ref}
|
|
87
|
+
disabled={isDisabled}
|
|
88
|
+
accessibilityLabel={accessibilityLabel}
|
|
89
|
+
className={className}
|
|
90
|
+
style={style}
|
|
91
|
+
{...props}
|
|
92
|
+
{...disclosureProps}
|
|
93
|
+
{...platformA11yProps}
|
|
94
|
+
{...mergeDataAttributes(
|
|
95
|
+
props,
|
|
96
|
+
dataAttributes({
|
|
97
|
+
slot: 'accordion-trigger',
|
|
98
|
+
state: isExpanded ? 'open' : 'closed',
|
|
99
|
+
disabled: isDisabled,
|
|
100
|
+
hover: isHovered,
|
|
101
|
+
active: isPressed,
|
|
102
|
+
focus: isFocused,
|
|
103
|
+
focusVisible: isFocusVisible,
|
|
104
|
+
}),
|
|
105
|
+
)}
|
|
106
|
+
onPressIn={composeEventHandlers(onPressIn, pressProps.onPressIn)}
|
|
107
|
+
onPressOut={composeEventHandlers(onPressOut, pressProps.onPressOut)}
|
|
108
|
+
onHoverIn={composeEventHandlers(onHoverIn, hoverProps.onHoverIn)}
|
|
109
|
+
onHoverOut={composeEventHandlers(onHoverOut, hoverProps.onHoverOut)}
|
|
110
|
+
onPress={composeEventHandlers(onPress, disclosureOnPress)}
|
|
111
|
+
onFocus={composeEventHandlers(onFocus, focusProps.onFocus, focusRingProps.onFocus)}
|
|
112
|
+
onBlur={composeEventHandlers(onBlur, focusProps.onBlur, focusRingProps.onBlur)}
|
|
113
|
+
>
|
|
114
|
+
{children}
|
|
115
|
+
</Comp>
|
|
116
|
+
);
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
AccordionTriggerRoot.displayName = 'AccordionTriggerRoot';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type { IAccordionContextValue, IAccordionItemContextValue } from './types';
|
|
3
|
+
|
|
4
|
+
export const AccordionContext = createContext<IAccordionContextValue | null>(null);
|
|
5
|
+
|
|
6
|
+
export const AccordionItemContext = createContext<IAccordionItemContextValue | null>(null);
|
|
7
|
+
|
|
8
|
+
export function useAccordionContext(): IAccordionContextValue {
|
|
9
|
+
const context = useContext(AccordionContext);
|
|
10
|
+
if (!context) {
|
|
11
|
+
throw new Error('Accordion compound components must be used within Accordion');
|
|
12
|
+
}
|
|
13
|
+
return context;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function useAccordionItemContext(): IAccordionItemContextValue {
|
|
17
|
+
const context = useContext(AccordionItemContext);
|
|
18
|
+
if (!context) {
|
|
19
|
+
throw new Error('Accordion.Item sub-components must be used within Accordion.Item');
|
|
20
|
+
}
|
|
21
|
+
return context;
|
|
22
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
IAccordionProps,
|
|
3
|
+
IAccordionItemProps,
|
|
4
|
+
IAccordionTriggerProps,
|
|
5
|
+
IAccordionPanelProps,
|
|
6
|
+
IAccordionContextValue,
|
|
7
|
+
IAccordionItemContextValue,
|
|
8
|
+
AccordionType,
|
|
9
|
+
} from './types';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
AccordionContext,
|
|
13
|
+
AccordionItemContext,
|
|
14
|
+
useAccordionContext,
|
|
15
|
+
useAccordionItemContext,
|
|
16
|
+
} from './context';
|
|
17
|
+
|
|
18
|
+
export { AccordionRoot, type AccordionRootProps } from './Accordion';
|
|
19
|
+
export { AccordionItemRoot, type AccordionItemRootProps } from './AccordionItem';
|
|
20
|
+
export { AccordionTriggerRoot, type AccordionTriggerRootProps } from './AccordionTrigger';
|
|
21
|
+
export { AccordionPanelRoot, type AccordionPanelRootProps } from './AccordionPanel';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { PressableProps, ViewProps } from 'react-native';
|
|
3
|
+
import type { DisclosureGroupState } from '@react-stately/disclosure';
|
|
4
|
+
|
|
5
|
+
export type AccordionType = 'single' | 'multiple';
|
|
6
|
+
|
|
7
|
+
export interface IAccordionProps extends ViewProps {
|
|
8
|
+
/** Controlled expanded item value(s). */
|
|
9
|
+
value?: string | string[];
|
|
10
|
+
/** Default expanded value(s) for uncontrolled usage. */
|
|
11
|
+
defaultValue?: string | string[];
|
|
12
|
+
/** Called when expanded items change. */
|
|
13
|
+
onValueChange?: (value: string | string[]) => void;
|
|
14
|
+
/** Single-select (accordion) vs multi-select (disclosure group). @default 'single' */
|
|
15
|
+
type?: AccordionType;
|
|
16
|
+
/** When `type="single"`, allow closing the open item. @default true */
|
|
17
|
+
collapsible?: boolean;
|
|
18
|
+
/** Disables expansion for all items. */
|
|
19
|
+
isDisabled?: boolean;
|
|
20
|
+
'aria-label'?: string;
|
|
21
|
+
'aria-labelledby'?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface IAccordionItemProps extends ViewProps {
|
|
25
|
+
/** Required stable id within the Accordion. */
|
|
26
|
+
value: string;
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface IAccordionTriggerProps extends PressableProps {
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
asChild?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface IAccordionPanelProps extends ViewProps {
|
|
36
|
+
children?: ReactNode;
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface IAccordionContextValue {
|
|
41
|
+
groupState: DisclosureGroupState;
|
|
42
|
+
type: AccordionType;
|
|
43
|
+
collapsible: boolean;
|
|
44
|
+
isDisabled: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface IAccordionItemContextValue {
|
|
48
|
+
value: string;
|
|
49
|
+
isExpanded: boolean;
|
|
50
|
+
isDisabled: boolean;
|
|
51
|
+
triggerId: string;
|
|
52
|
+
panelId: string;
|
|
53
|
+
toggle: () => void;
|
|
54
|
+
disableGutters?: boolean;
|
|
55
|
+
showSeparator?: boolean;
|
|
56
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AccordionType } from './types';
|
|
2
|
+
|
|
3
|
+
export function toExpandedKeys(value: string | string[] | undefined): Set<string> | undefined {
|
|
4
|
+
if (value === undefined) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
if (Array.isArray(value)) {
|
|
8
|
+
return new Set(value);
|
|
9
|
+
}
|
|
10
|
+
if (value === '') {
|
|
11
|
+
return new Set<string>();
|
|
12
|
+
}
|
|
13
|
+
return new Set<string>([value]);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function fromExpandedKeys(
|
|
17
|
+
keys: Iterable<string | number>,
|
|
18
|
+
type: AccordionType,
|
|
19
|
+
): string | string[] {
|
|
20
|
+
const values = Array.from(keys).map(String);
|
|
21
|
+
return type === 'single' ? (values[0] ?? '') : values;
|
|
22
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -65,6 +65,7 @@ export * from './tooltip';
|
|
|
65
65
|
export * from './portal';
|
|
66
66
|
export * from './progress-bar';
|
|
67
67
|
export * from './radio';
|
|
68
|
+
export * from './accordion';
|
|
68
69
|
export * from './slider';
|
|
69
70
|
export type { InteractionState } from './types';
|
|
70
71
|
export { FormControlContext, useFormControlContext } from '@cdx-ui/utils';
|
|
@@ -14,23 +14,30 @@ import { dataAttributes } from '../utils/dataAttributes';
|
|
|
14
14
|
import { useSliderContext } from './context';
|
|
15
15
|
import type { InterfaceSliderRailProps } from './types';
|
|
16
16
|
import { getPointerCoords, getRatioFromPagePoint, useWebSliderDrag } from './useSliderPointer';
|
|
17
|
+
import { clamp, getClosestValueIndex } from './utils';
|
|
17
18
|
|
|
18
19
|
export interface SliderRailProps extends InterfaceSliderRailProps {}
|
|
19
20
|
|
|
20
21
|
export const SliderRail = forwardRef<View, SliderRailProps>(
|
|
21
22
|
({ asChild, style, onLayout, children, ...props }, ref) => {
|
|
22
23
|
const {
|
|
24
|
+
values,
|
|
25
|
+
min,
|
|
26
|
+
max,
|
|
27
|
+
step,
|
|
23
28
|
orientation,
|
|
24
29
|
isDisabled,
|
|
25
30
|
isDragging,
|
|
26
31
|
trackLayout,
|
|
27
32
|
thumbSize,
|
|
28
|
-
|
|
33
|
+
setNearestThumbValueFromRatio,
|
|
34
|
+
setThumbValueFromRatio,
|
|
35
|
+
setDraggingIndex,
|
|
29
36
|
setTrackLayout,
|
|
30
|
-
setIsDragging,
|
|
31
37
|
} = useSliderContext();
|
|
32
38
|
|
|
33
39
|
const railRef = useRef<View>(null);
|
|
40
|
+
const draggingThumbIndexRef = useRef<number | null>(null);
|
|
34
41
|
|
|
35
42
|
const measureRail = useCallback(() => {
|
|
36
43
|
const node = railRef.current;
|
|
@@ -50,10 +57,32 @@ export const SliderRail = forwardRef<View, SliderRailProps>(
|
|
|
50
57
|
[measureRail, onLayout],
|
|
51
58
|
);
|
|
52
59
|
|
|
60
|
+
const setRatioForRailDrag = useCallback(
|
|
61
|
+
(ratio: number, complete?: boolean) => {
|
|
62
|
+
const thumbIndex = draggingThumbIndexRef.current;
|
|
63
|
+
if (thumbIndex == null) {
|
|
64
|
+
setNearestThumbValueFromRatio(ratio, complete);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
setThumbValueFromRatio(thumbIndex, ratio, complete);
|
|
68
|
+
if (complete) {
|
|
69
|
+
draggingThumbIndexRef.current = null;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
[setNearestThumbValueFromRatio, setThumbValueFromRatio],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const setDraggingForRail = useCallback(
|
|
76
|
+
(dragging: boolean) => {
|
|
77
|
+
setDraggingIndex(dragging ? draggingThumbIndexRef.current : null);
|
|
78
|
+
},
|
|
79
|
+
[setDraggingIndex],
|
|
80
|
+
);
|
|
81
|
+
|
|
53
82
|
const { startDrag } = useWebSliderDrag({
|
|
54
83
|
isDisabled,
|
|
55
|
-
setIsDragging,
|
|
56
|
-
setValueFromRatio,
|
|
84
|
+
setIsDragging: setDraggingForRail,
|
|
85
|
+
setValueFromRatio: setRatioForRailDrag,
|
|
57
86
|
trackLayout,
|
|
58
87
|
orientation,
|
|
59
88
|
thumbSize,
|
|
@@ -65,9 +94,12 @@ export const SliderRail = forwardRef<View, SliderRailProps>(
|
|
|
65
94
|
return;
|
|
66
95
|
}
|
|
67
96
|
const { x, y } = getPointerCoords(event.nativeEvent);
|
|
68
|
-
|
|
97
|
+
setNearestThumbValueFromRatio(
|
|
98
|
+
getRatioFromPagePoint(x, y, trackLayout, orientation, thumbSize),
|
|
99
|
+
true,
|
|
100
|
+
);
|
|
69
101
|
},
|
|
70
|
-
[isDisabled, orientation,
|
|
102
|
+
[isDisabled, orientation, setNearestThumbValueFromRatio, thumbSize, trackLayout],
|
|
71
103
|
);
|
|
72
104
|
|
|
73
105
|
const handlePress = useCallback(
|
|
@@ -91,9 +123,25 @@ export const SliderRail = forwardRef<View, SliderRailProps>(
|
|
|
91
123
|
setTrackLayout(freshLayout);
|
|
92
124
|
|
|
93
125
|
const { x, y } = getPointerCoords(event.nativeEvent);
|
|
94
|
-
|
|
126
|
+
const ratio = getRatioFromPagePoint(x, y, freshLayout, orientation, thumbSize);
|
|
127
|
+
const target = min + clamp(ratio, 0, 1) * (max - min);
|
|
128
|
+
const nearestIndex = getClosestValueIndex(values, target);
|
|
129
|
+
draggingThumbIndexRef.current = nearestIndex;
|
|
130
|
+
setDraggingIndex(nearestIndex);
|
|
131
|
+
startDrag(x, y, ratio, freshLayout);
|
|
95
132
|
},
|
|
96
|
-
[
|
|
133
|
+
[
|
|
134
|
+
isDisabled,
|
|
135
|
+
max,
|
|
136
|
+
min,
|
|
137
|
+
orientation,
|
|
138
|
+
setDraggingIndex,
|
|
139
|
+
setTrackLayout,
|
|
140
|
+
startDrag,
|
|
141
|
+
step,
|
|
142
|
+
thumbSize,
|
|
143
|
+
values,
|
|
144
|
+
],
|
|
97
145
|
);
|
|
98
146
|
|
|
99
147
|
const Comp = asChild ? Slot : View;
|