@cdx-ui/components 0.0.1-beta.115 → 0.0.1-beta.117
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/README.md +1 -1
- package/lib/commonjs/components/Slider/getSliderPopupPosition.js +43 -0
- package/lib/commonjs/components/Slider/getSliderPopupPosition.js.map +1 -0
- package/lib/commonjs/components/Slider/index.js +363 -0
- package/lib/commonjs/components/Slider/index.js.map +1 -0
- package/lib/commonjs/components/Slider/styles.js +112 -0
- package/lib/commonjs/components/Slider/styles.js.map +1 -0
- package/lib/commonjs/components/index.js +12 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/module/components/Slider/getSliderPopupPosition.js +38 -0
- package/lib/module/components/Slider/getSliderPopupPosition.js.map +1 -0
- package/lib/module/components/Slider/index.js +359 -0
- package/lib/module/components/Slider/index.js.map +1 -0
- package/lib/module/components/Slider/styles.js +108 -0
- package/lib/module/components/Slider/styles.js.map +1 -0
- package/lib/module/components/index.js +1 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/typescript/components/Slider/getSliderPopupPosition.d.ts +10 -0
- package/lib/typescript/components/Slider/getSliderPopupPosition.d.ts.map +1 -0
- package/lib/typescript/components/Slider/index.d.ts +61 -0
- package/lib/typescript/components/Slider/index.d.ts.map +1 -0
- package/lib/typescript/components/Slider/styles.d.ts +30 -0
- package/lib/typescript/components/Slider/styles.d.ts.map +1 -0
- package/lib/typescript/components/index.d.ts +1 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/components/Slider/getSliderPopupPosition.ts +37 -0
- package/src/components/Slider/index.tsx +456 -0
- package/src/components/Slider/styles.ts +147 -0
- package/src/components/index.ts +1 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
export declare const sliderColorOptions: readonly ["action", "danger", "warning", "success", "info"];
|
|
3
|
+
export type SliderColor = (typeof sliderColorOptions)[number];
|
|
4
|
+
export declare const sliderRootVariants: (props?: ({
|
|
5
|
+
orientation?: "vertical" | "horizontal" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
export declare const sliderRailVariants: (props?: ({
|
|
8
|
+
orientation?: "vertical" | "horizontal" | null | undefined;
|
|
9
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
|
+
export declare const sliderRailColorVariants: (props?: ({
|
|
11
|
+
color?: "danger" | "warning" | "success" | "info" | "action" | null | undefined;
|
|
12
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
13
|
+
export declare const sliderTrackVariants: (props?: ({
|
|
14
|
+
orientation?: "vertical" | "horizontal" | null | undefined;
|
|
15
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
16
|
+
export declare const sliderTrackColorVariants: (props?: ({
|
|
17
|
+
color?: "danger" | "warning" | "success" | "info" | "action" | null | undefined;
|
|
18
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
19
|
+
export declare const sliderThumbVariants: (props?: ({
|
|
20
|
+
color?: "danger" | "warning" | "success" | "info" | "action" | null | undefined;
|
|
21
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
22
|
+
export declare const sliderThumbHaloVariants: (props?: ({
|
|
23
|
+
visible?: boolean | null | undefined;
|
|
24
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
25
|
+
export declare const sliderPopupBaseVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
26
|
+
export declare const sliderMarkerVariants: (props?: ({
|
|
27
|
+
filled?: boolean | null | undefined;
|
|
28
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
29
|
+
export type SliderVariantProps = VariantProps<typeof sliderRootVariants> & VariantProps<typeof sliderRailVariants> & VariantProps<typeof sliderRailColorVariants> & VariantProps<typeof sliderTrackVariants> & VariantProps<typeof sliderTrackColorVariants> & VariantProps<typeof sliderThumbVariants>;
|
|
30
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/Slider/styles.ts"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,eAAO,MAAM,kBAAkB,6DAA8D,CAAC;AAC9F,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D,eAAO,MAAM,kBAAkB;;8EAkB9B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;8EAa9B,CAAC;AAEF,eAAO,MAAM,uBAAuB;;8EAalC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;8EAU9B,CAAC;AAEH,eAAO,MAAM,wBAAwB;;8EAanC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;8EAyB/B,CAAC;AAEF,eAAO,MAAM,uBAAuB;;8EAQlC,CAAC;AAEH,eAAO,MAAM,uBAAuB,oFAGlC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;8EAahC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,kBAAkB,CAAC,GACtE,YAAY,CAAC,OAAO,kBAAkB,CAAC,GACvC,YAAY,CAAC,OAAO,uBAAuB,CAAC,GAC5C,YAAY,CAAC,OAAO,mBAAmB,CAAC,GACxC,YAAY,CAAC,OAAO,wBAAwB,CAAC,GAC7C,YAAY,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdx-ui/components",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.117",
|
|
4
4
|
"main": "lib/commonjs/index.js",
|
|
5
5
|
"module": "lib/module/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"class-variance-authority": "^0.7.1",
|
|
77
77
|
"react-native-reanimated-carousel": "5.0.0-beta.5",
|
|
78
78
|
"uniwind": "1.10.0",
|
|
79
|
-
"@cdx-ui/primitives": "0.0.1-beta.
|
|
80
|
-
"@cdx-ui/utils": "0.0.1-beta.
|
|
81
|
-
"@cdx-ui/icons": "0.0.1-beta.
|
|
79
|
+
"@cdx-ui/primitives": "0.0.1-beta.117",
|
|
80
|
+
"@cdx-ui/utils": "0.0.1-beta.117",
|
|
81
|
+
"@cdx-ui/icons": "0.0.1-beta.117"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@react-navigation/bottom-tabs": "*",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Platform, type ViewStyle } from 'react-native';
|
|
2
|
+
import type { AnchorLayout, SliderOrientation } from '@cdx-ui/primitives';
|
|
3
|
+
|
|
4
|
+
export const SLIDER_POPUP_OFFSET = 8;
|
|
5
|
+
export const SLIDER_POPUP_Z_INDEX = 9999;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Popover-style placement for the slider value tooltip, modeled after anchored
|
|
9
|
+
* popover content positioning (placement + offset relative to a measured trigger).
|
|
10
|
+
*/
|
|
11
|
+
export function getSliderPopupAnchorStyle(
|
|
12
|
+
anchor: AnchorLayout,
|
|
13
|
+
orientation: SliderOrientation,
|
|
14
|
+
offset = SLIDER_POPUP_OFFSET,
|
|
15
|
+
): ViewStyle {
|
|
16
|
+
const position = (Platform.OS === 'web' ? 'fixed' : 'absolute') as ViewStyle['position'];
|
|
17
|
+
|
|
18
|
+
if (orientation === 'vertical') {
|
|
19
|
+
const centerY = anchor.y + anchor.height / 2;
|
|
20
|
+
return {
|
|
21
|
+
position,
|
|
22
|
+
left: anchor.x + anchor.width + offset,
|
|
23
|
+
top: centerY,
|
|
24
|
+
zIndex: SLIDER_POPUP_Z_INDEX,
|
|
25
|
+
transform: [{ translateY: '-50%' }] as ViewStyle['transform'],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const centerX = anchor.x + anchor.width / 2;
|
|
30
|
+
return {
|
|
31
|
+
position,
|
|
32
|
+
left: centerX,
|
|
33
|
+
top: anchor.y - offset,
|
|
34
|
+
zIndex: SLIDER_POPUP_Z_INDEX,
|
|
35
|
+
transform: [{ translateX: '-50%' }, { translateY: '-100%' }] as ViewStyle['transform'],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
forwardRef,
|
|
5
|
+
isValidElement,
|
|
6
|
+
useId,
|
|
7
|
+
useMemo,
|
|
8
|
+
type ReactElement,
|
|
9
|
+
type ReactNode,
|
|
10
|
+
} from 'react';
|
|
11
|
+
import { Platform, StyleSheet, Text, View, type ViewProps, type ViewStyle } from 'react-native';
|
|
12
|
+
import {
|
|
13
|
+
SliderRoot as SliderRootPrimitive,
|
|
14
|
+
SliderRail as SliderRailPrimitive,
|
|
15
|
+
SliderThumb as SliderThumbPrimitive,
|
|
16
|
+
Slot,
|
|
17
|
+
Portal,
|
|
18
|
+
createPortalFn,
|
|
19
|
+
useAnchorPosition,
|
|
20
|
+
dataAttributes,
|
|
21
|
+
getMarkerPositionStyle,
|
|
22
|
+
getMarkerStepValues,
|
|
23
|
+
mergeDataAttributes,
|
|
24
|
+
percentToFillExtent,
|
|
25
|
+
useSliderContext,
|
|
26
|
+
valueToPercent,
|
|
27
|
+
type ISliderProps,
|
|
28
|
+
type ISliderRailProps,
|
|
29
|
+
type ISliderThumbProps,
|
|
30
|
+
type SliderOrientation,
|
|
31
|
+
} from '@cdx-ui/primitives';
|
|
32
|
+
import { cn, ParentContext, useParentContext, useStyleContext } from '@cdx-ui/utils';
|
|
33
|
+
import {
|
|
34
|
+
sliderMarkerVariants,
|
|
35
|
+
sliderPopupBaseVariants,
|
|
36
|
+
sliderRootVariants,
|
|
37
|
+
sliderRailVariants,
|
|
38
|
+
sliderRailColorVariants,
|
|
39
|
+
sliderTrackColorVariants,
|
|
40
|
+
sliderTrackVariants,
|
|
41
|
+
sliderThumbVariants,
|
|
42
|
+
type SliderColor,
|
|
43
|
+
type SliderVariantProps,
|
|
44
|
+
} from './styles';
|
|
45
|
+
import { getSliderPopupAnchorStyle, SLIDER_POPUP_Z_INDEX } from './getSliderPopupPosition';
|
|
46
|
+
|
|
47
|
+
const SCOPE = 'SLIDER';
|
|
48
|
+
|
|
49
|
+
const useSliderStyleContext = () => {
|
|
50
|
+
const { color, orientation } = useStyleContext(SCOPE) as Pick<
|
|
51
|
+
SliderVariantProps,
|
|
52
|
+
'color' | 'orientation'
|
|
53
|
+
>;
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
color,
|
|
57
|
+
orientation: orientation ?? 'horizontal',
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export interface SliderProps extends Omit<ISliderProps, 'orientation'> {
|
|
62
|
+
className?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Semantic color token for the track fill and thumb border.
|
|
65
|
+
* @default `action`
|
|
66
|
+
*/
|
|
67
|
+
color?: SliderColor;
|
|
68
|
+
orientation?: SliderOrientation;
|
|
69
|
+
children?: ReactNode;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const SliderRoot = forwardRef<View, SliderProps>(
|
|
73
|
+
(
|
|
74
|
+
{
|
|
75
|
+
className,
|
|
76
|
+
style,
|
|
77
|
+
color = 'action',
|
|
78
|
+
orientation = 'horizontal',
|
|
79
|
+
children,
|
|
80
|
+
isDisabled,
|
|
81
|
+
...props
|
|
82
|
+
},
|
|
83
|
+
ref,
|
|
84
|
+
) => {
|
|
85
|
+
const parent = useParentContext();
|
|
86
|
+
const ctx = useMemo(
|
|
87
|
+
() => ({
|
|
88
|
+
...parent,
|
|
89
|
+
[SCOPE]: { color, orientation },
|
|
90
|
+
}),
|
|
91
|
+
[color, orientation, parent],
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const computedClassName = cn(sliderRootVariants({ orientation }), className);
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<ParentContext.Provider value={ctx}>
|
|
98
|
+
<SliderRootPrimitive
|
|
99
|
+
ref={ref}
|
|
100
|
+
className={computedClassName}
|
|
101
|
+
style={style}
|
|
102
|
+
orientation={orientation}
|
|
103
|
+
isDisabled={isDisabled}
|
|
104
|
+
{...props}
|
|
105
|
+
>
|
|
106
|
+
{children}
|
|
107
|
+
</SliderRootPrimitive>
|
|
108
|
+
</ParentContext.Provider>
|
|
109
|
+
);
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
SliderRoot.displayName = 'Slider';
|
|
114
|
+
|
|
115
|
+
export interface SliderRailProps extends ISliderRailProps {
|
|
116
|
+
className?: string;
|
|
117
|
+
children?: ReactNode;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const SliderRail = forwardRef<View, SliderRailProps>(
|
|
121
|
+
({ className, style, children, ...props }, ref) => {
|
|
122
|
+
const { orientation, color } = useSliderStyleContext();
|
|
123
|
+
|
|
124
|
+
const computedClassName = cn(
|
|
125
|
+
sliderRailVariants({ orientation }),
|
|
126
|
+
sliderRailColorVariants({ color }),
|
|
127
|
+
className,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<SliderRailPrimitive ref={ref} className={computedClassName} style={style} {...props}>
|
|
132
|
+
{children}
|
|
133
|
+
</SliderRailPrimitive>
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
SliderRail.displayName = 'Slider.Rail';
|
|
139
|
+
|
|
140
|
+
export interface SliderTrackProps extends ViewProps {
|
|
141
|
+
asChild?: boolean;
|
|
142
|
+
className?: string;
|
|
143
|
+
children?: ReactNode;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const SliderTrack = forwardRef<View, SliderTrackProps>(
|
|
147
|
+
({ asChild, className, style, children, testID, ...props }, ref) => {
|
|
148
|
+
const { color, orientation } = useSliderStyleContext();
|
|
149
|
+
const { percent, isDragging, trackLayout, thumbSize } = useSliderContext();
|
|
150
|
+
|
|
151
|
+
const fillStyle = useMemo((): ViewStyle => {
|
|
152
|
+
const trackSize =
|
|
153
|
+
trackLayout == null
|
|
154
|
+
? 0
|
|
155
|
+
: orientation === 'horizontal'
|
|
156
|
+
? trackLayout.width
|
|
157
|
+
: trackLayout.height;
|
|
158
|
+
|
|
159
|
+
if (trackSize <= 0) {
|
|
160
|
+
return orientation === 'vertical'
|
|
161
|
+
? { position: 'absolute', left: 0, right: 0, bottom: 0, height: 0 }
|
|
162
|
+
: { position: 'absolute', top: 0, bottom: 0, left: 0, width: 0 };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const extent = percentToFillExtent(percent, trackSize, thumbSize);
|
|
166
|
+
|
|
167
|
+
if (orientation === 'vertical') {
|
|
168
|
+
return {
|
|
169
|
+
position: 'absolute',
|
|
170
|
+
left: 0,
|
|
171
|
+
right: 0,
|
|
172
|
+
bottom: 0,
|
|
173
|
+
height: extent,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
position: 'absolute',
|
|
179
|
+
top: 0,
|
|
180
|
+
bottom: 0,
|
|
181
|
+
left: 0,
|
|
182
|
+
width: extent,
|
|
183
|
+
};
|
|
184
|
+
}, [orientation, percent, thumbSize, trackLayout]);
|
|
185
|
+
|
|
186
|
+
const computedClassName = cn(
|
|
187
|
+
sliderTrackVariants({ orientation }),
|
|
188
|
+
sliderTrackColorVariants({ color }),
|
|
189
|
+
className,
|
|
190
|
+
);
|
|
191
|
+
const Comp = asChild ? Slot : View;
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<Comp
|
|
195
|
+
ref={ref}
|
|
196
|
+
testID={testID}
|
|
197
|
+
className={computedClassName}
|
|
198
|
+
pointerEvents="none"
|
|
199
|
+
style={[fillStyle, style]}
|
|
200
|
+
accessibilityElementsHidden
|
|
201
|
+
importantForAccessibility="no-hide-descendants"
|
|
202
|
+
{...mergeDataAttributes(
|
|
203
|
+
props,
|
|
204
|
+
dataAttributes({ slot: 'slider-track', dragging: isDragging }),
|
|
205
|
+
)}
|
|
206
|
+
>
|
|
207
|
+
{children}
|
|
208
|
+
</Comp>
|
|
209
|
+
);
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
SliderTrack.displayName = 'Slider.Track';
|
|
214
|
+
|
|
215
|
+
export interface SliderThumbProps extends ISliderThumbProps {
|
|
216
|
+
className?: string;
|
|
217
|
+
children?: ReactNode;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const SliderThumb = forwardRef<View, SliderThumbProps>(
|
|
221
|
+
({ className, style, children, ...props }, ref) => {
|
|
222
|
+
const { color } = useSliderStyleContext();
|
|
223
|
+
|
|
224
|
+
const computedClassName = cn(sliderThumbVariants({ color }), className);
|
|
225
|
+
|
|
226
|
+
return (
|
|
227
|
+
<SliderThumbPrimitive ref={ref} className={computedClassName} style={style} {...props}>
|
|
228
|
+
{children}
|
|
229
|
+
</SliderThumbPrimitive>
|
|
230
|
+
);
|
|
231
|
+
},
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
SliderThumb.displayName = 'Slider.Thumb';
|
|
235
|
+
|
|
236
|
+
function dataOrientation(orientation: 'horizontal' | 'vertical' | null | undefined) {
|
|
237
|
+
return { 'data-orientation': orientation ?? 'horizontal' } as const;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function renderPopupLabel(children: ReactNode, getValueLabel: () => string) {
|
|
241
|
+
if (children == null || typeof children === 'string' || typeof children === 'number') {
|
|
242
|
+
return (
|
|
243
|
+
<Text className="text-content-primary text-xs font-medium select-none" selectable={false}>
|
|
244
|
+
{children ?? getValueLabel()}
|
|
245
|
+
</Text>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return children;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface SliderPopupProps extends ViewProps {
|
|
253
|
+
asChild?: boolean;
|
|
254
|
+
className?: string;
|
|
255
|
+
children?: ReactNode;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const SliderPopup = forwardRef<View, SliderPopupProps>(
|
|
259
|
+
({ asChild, className, style, children, ...props }, ref) => {
|
|
260
|
+
const { orientation } = useSliderStyleContext();
|
|
261
|
+
const { isDragging, isHovered, isFocused, getValueLabel, thumbRef, percent } =
|
|
262
|
+
useSliderContext();
|
|
263
|
+
const portalName = useId();
|
|
264
|
+
|
|
265
|
+
const visible = isDragging || isHovered || isFocused;
|
|
266
|
+
const anchorLayout = useAnchorPosition(thumbRef, visible, {
|
|
267
|
+
remeasureKey: percent,
|
|
268
|
+
trackWhileOpen: true,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
if (!visible || anchorLayout == null) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const label = renderPopupLabel(children, getValueLabel);
|
|
276
|
+
const computedClassName = cn(sliderPopupBaseVariants(), className);
|
|
277
|
+
const Comp = asChild ? Slot : View;
|
|
278
|
+
const anchorStyle = getSliderPopupAnchorStyle(anchorLayout, orientation);
|
|
279
|
+
|
|
280
|
+
const popup = (
|
|
281
|
+
<View pointerEvents="none" style={anchorStyle}>
|
|
282
|
+
<Comp
|
|
283
|
+
ref={ref}
|
|
284
|
+
className={computedClassName}
|
|
285
|
+
style={style}
|
|
286
|
+
accessibilityElementsHidden
|
|
287
|
+
importantForAccessibility="no-hide-descendants"
|
|
288
|
+
{...mergeDataAttributes(
|
|
289
|
+
props,
|
|
290
|
+
dataAttributes({ slot: 'slider-popup', visible: true }),
|
|
291
|
+
dataOrientation(orientation),
|
|
292
|
+
)}
|
|
293
|
+
>
|
|
294
|
+
{label}
|
|
295
|
+
</Comp>
|
|
296
|
+
</View>
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
if (Platform.OS === 'web' && createPortalFn && typeof document !== 'undefined') {
|
|
300
|
+
return createPortalFn(popup, document.body);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return (
|
|
304
|
+
<Portal name={portalName}>
|
|
305
|
+
<View
|
|
306
|
+
pointerEvents="box-none"
|
|
307
|
+
style={[StyleSheet.absoluteFill, { zIndex: SLIDER_POPUP_Z_INDEX }]}
|
|
308
|
+
>
|
|
309
|
+
{popup}
|
|
310
|
+
</View>
|
|
311
|
+
</Portal>
|
|
312
|
+
);
|
|
313
|
+
},
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
SliderPopup.displayName = 'Slider.Popup';
|
|
317
|
+
|
|
318
|
+
export interface SliderMarkerProps extends ViewProps {
|
|
319
|
+
asChild?: boolean;
|
|
320
|
+
className?: string;
|
|
321
|
+
value?: number;
|
|
322
|
+
children?: ReactNode;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const SliderMarker = forwardRef<View, SliderMarkerProps>(
|
|
326
|
+
({ asChild, className, style, value, testID, ...props }, ref) => {
|
|
327
|
+
const {
|
|
328
|
+
value: currentValue,
|
|
329
|
+
min,
|
|
330
|
+
max,
|
|
331
|
+
orientation,
|
|
332
|
+
trackLayout,
|
|
333
|
+
thumbSize,
|
|
334
|
+
} = useSliderContext();
|
|
335
|
+
|
|
336
|
+
const markerStyle = useMemo(() => {
|
|
337
|
+
if (value == null) {
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
const percent = valueToPercent(value, min, max);
|
|
341
|
+
return getMarkerPositionStyle(percent, orientation, trackLayout, thumbSize);
|
|
342
|
+
}, [max, min, orientation, thumbSize, trackLayout, value]);
|
|
343
|
+
|
|
344
|
+
const isFilled = value != null && value <= currentValue;
|
|
345
|
+
const computedClassName = cn(sliderMarkerVariants({ filled: isFilled }), className);
|
|
346
|
+
const Comp = asChild ? Slot : View;
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<Comp
|
|
350
|
+
ref={ref}
|
|
351
|
+
testID={testID}
|
|
352
|
+
className={computedClassName}
|
|
353
|
+
style={[markerStyle, style]}
|
|
354
|
+
accessibilityElementsHidden
|
|
355
|
+
importantForAccessibility="no-hide-descendants"
|
|
356
|
+
{...mergeDataAttributes(
|
|
357
|
+
props,
|
|
358
|
+
dataAttributes({
|
|
359
|
+
slot: 'slider-marker',
|
|
360
|
+
value: value == null ? undefined : String(value),
|
|
361
|
+
filled: isFilled,
|
|
362
|
+
}),
|
|
363
|
+
)}
|
|
364
|
+
/>
|
|
365
|
+
);
|
|
366
|
+
},
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
SliderMarker.displayName = 'Slider.Marker';
|
|
370
|
+
|
|
371
|
+
function isSliderMarkerElement(child: unknown): child is ReactElement<SliderMarkerProps> {
|
|
372
|
+
if (!isValidElement(child)) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
const type = child.type as { displayName?: string };
|
|
376
|
+
return type.displayName === 'Slider.Marker';
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export interface SliderMarkerGroupProps extends ViewProps {
|
|
380
|
+
asChild?: boolean;
|
|
381
|
+
className?: string;
|
|
382
|
+
children?: ReactNode;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const SliderMarkerGroup = forwardRef<View, SliderMarkerGroupProps>(
|
|
386
|
+
({ asChild, className, style, children, testID, ...props }, ref) => {
|
|
387
|
+
const { min, max, step } = useSliderContext();
|
|
388
|
+
|
|
389
|
+
const markers = useMemo(() => {
|
|
390
|
+
if (step <= 0 || max <= min) {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const childList = Children.toArray(children);
|
|
395
|
+
if (childList.length === 0) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const templateMarker = childList.find(
|
|
400
|
+
(child): child is ReactElement<SliderMarkerProps> =>
|
|
401
|
+
isSliderMarkerElement(child) && child.props.value == null,
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
if (templateMarker) {
|
|
405
|
+
return getMarkerStepValues(min, max, step).map((markerValue) =>
|
|
406
|
+
cloneElement(templateMarker, { key: markerValue, value: markerValue }),
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return childList;
|
|
411
|
+
}, [children, max, min, step]);
|
|
412
|
+
|
|
413
|
+
if (!markers) {
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const Comp = asChild ? Slot : View;
|
|
418
|
+
|
|
419
|
+
return (
|
|
420
|
+
<Comp
|
|
421
|
+
ref={ref}
|
|
422
|
+
testID={testID}
|
|
423
|
+
className={cn('absolute inset-0 z-[1]', className)}
|
|
424
|
+
style={style}
|
|
425
|
+
pointerEvents="none"
|
|
426
|
+
accessibilityElementsHidden
|
|
427
|
+
importantForAccessibility="no-hide-descendants"
|
|
428
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'slider-marker-group' }))}
|
|
429
|
+
>
|
|
430
|
+
{markers}
|
|
431
|
+
</Comp>
|
|
432
|
+
);
|
|
433
|
+
},
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
SliderMarkerGroup.displayName = 'Slider.MarkerGroup';
|
|
437
|
+
|
|
438
|
+
type SliderCompoundComponent = typeof SliderRoot & {
|
|
439
|
+
Rail: typeof SliderRail;
|
|
440
|
+
Track: typeof SliderTrack;
|
|
441
|
+
Thumb: typeof SliderThumb;
|
|
442
|
+
Popup: typeof SliderPopup;
|
|
443
|
+
MarkerGroup: typeof SliderMarkerGroup;
|
|
444
|
+
Marker: typeof SliderMarker;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
export const Slider = Object.assign(SliderRoot, {
|
|
448
|
+
Rail: SliderRail,
|
|
449
|
+
Track: SliderTrack,
|
|
450
|
+
Thumb: SliderThumb,
|
|
451
|
+
Popup: SliderPopup,
|
|
452
|
+
MarkerGroup: SliderMarkerGroup,
|
|
453
|
+
Marker: SliderMarker,
|
|
454
|
+
}) as SliderCompoundComponent;
|
|
455
|
+
|
|
456
|
+
export type { SliderColor, SliderVariantProps };
|