react-proportion-slider 0.9.0 → 0.9.2
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/package.json +27 -5
- package/dev/App.css +0 -13
- package/dev/App.tsx +0 -49
- package/dev/index.html +0 -17
- package/dev/main.tsx +0 -9
- package/eslint.config.js +0 -28
- package/src/components/DynamicChildPositioner.tsx +0 -143
- package/src/components/Proportion.tsx +0 -55
- package/src/components/ProportionSlider.tsx +0 -112
- package/src/components/SliderKnob.tsx +0 -68
- package/src/index.ts +0 -1
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.app.json +0 -26
- package/tsconfig.json +0 -7
- package/tsconfig.node.json +0 -24
- package/vite.config.ts +0 -26
package/package.json
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-proportion-slider",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.2",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"main": "./dist/react-proportion-slider.umd.js",
|
|
10
|
+
"module": "./dist/react-proportion-slider.es.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/react-proportion-slider.es.js",
|
|
15
|
+
"require": "./dist/react-proportion-slider.umd.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
6
19
|
"scripts": {
|
|
7
20
|
"dev": "vite",
|
|
8
21
|
"build": "tsc -b && vite build",
|
|
9
22
|
"lint": "eslint .",
|
|
10
|
-
"preview": "vite preview"
|
|
23
|
+
"preview": "vite preview",
|
|
24
|
+
"test": "vitest"
|
|
11
25
|
},
|
|
12
26
|
"dependencies": {
|
|
13
|
-
"react": "
|
|
14
|
-
"react-dom": "
|
|
27
|
+
"react": ">=16.8.0",
|
|
28
|
+
"react-dom": ">=16.8.0"
|
|
15
29
|
},
|
|
16
30
|
"devDependencies": {
|
|
17
31
|
"@eslint/js": "^9.21.0",
|
|
32
|
+
"@testing-library/react": "^14.2.1",
|
|
18
33
|
"@types/react": "^19.0.10",
|
|
19
34
|
"@types/react-dom": "^19.0.4",
|
|
20
35
|
"@vitejs/plugin-react": "^4.3.4",
|
|
@@ -22,8 +37,15 @@
|
|
|
22
37
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
23
38
|
"eslint-plugin-react-refresh": "^0.4.19",
|
|
24
39
|
"globals": "^15.15.0",
|
|
40
|
+
"jsdom": "^24.0.0",
|
|
25
41
|
"typescript": "~5.7.2",
|
|
26
42
|
"typescript-eslint": "^8.24.1",
|
|
27
|
-
"vite": "^6.2.0"
|
|
43
|
+
"vite": "^6.2.0",
|
|
44
|
+
"vite-plugin-dts": "^4.5.3",
|
|
45
|
+
"vitest": "^3.0.8"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"react": ">=16.8.0",
|
|
49
|
+
"react-dom": ">=16.8.0"
|
|
28
50
|
}
|
|
29
51
|
}
|
package/dev/App.css
DELETED
package/dev/App.tsx
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import "./App.css";
|
|
3
|
-
import { ProportionSlider } from "../src/components/ProportionSlider";
|
|
4
|
-
|
|
5
|
-
function App() {
|
|
6
|
-
const [proportions, setProportions] = React.useState<[number, number]>([
|
|
7
|
-
50, 50,
|
|
8
|
-
]);
|
|
9
|
-
return (
|
|
10
|
-
<div
|
|
11
|
-
style={{
|
|
12
|
-
height: "100%",
|
|
13
|
-
flex: 1,
|
|
14
|
-
padding: "20px 200px",
|
|
15
|
-
display: "flex",
|
|
16
|
-
flexDirection: "column",
|
|
17
|
-
justifyContent: "center",
|
|
18
|
-
}}
|
|
19
|
-
>
|
|
20
|
-
<ProportionSlider
|
|
21
|
-
value={proportions}
|
|
22
|
-
proportions={[
|
|
23
|
-
{
|
|
24
|
-
name: "Skill",
|
|
25
|
-
backgroundColor: "#31332E",
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: "3.7 Sonnet",
|
|
29
|
-
backgroundColor: "#5f625C",
|
|
30
|
-
},
|
|
31
|
-
]}
|
|
32
|
-
onChange={(change) => {
|
|
33
|
-
setProportions(change);
|
|
34
|
-
}}
|
|
35
|
-
sliderOptions={{
|
|
36
|
-
width: 5,
|
|
37
|
-
gap: 5,
|
|
38
|
-
backgroundColor: "#EC1308",
|
|
39
|
-
}}
|
|
40
|
-
options={{
|
|
41
|
-
height: 50,
|
|
42
|
-
displayValueType: "percentage",
|
|
43
|
-
}}
|
|
44
|
-
/>
|
|
45
|
-
</div>
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export default App;
|
package/dev/index.html
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8" />
|
|
6
|
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
7
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
-
<title>Dev Environment</title>
|
|
9
|
-
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@200;400;700&display=swap" rel="stylesheet">
|
|
10
|
-
</head>
|
|
11
|
-
|
|
12
|
-
<body>
|
|
13
|
-
<div id="root"></div>
|
|
14
|
-
<script type="module" src="/dev/main.tsx"></script>
|
|
15
|
-
</body>
|
|
16
|
-
|
|
17
|
-
</html>
|
package/dev/main.tsx
DELETED
package/eslint.config.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import js from '@eslint/js'
|
|
2
|
-
import globals from 'globals'
|
|
3
|
-
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
-
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
-
import tseslint from 'typescript-eslint'
|
|
6
|
-
|
|
7
|
-
export default tseslint.config(
|
|
8
|
-
{ ignores: ['dist'] },
|
|
9
|
-
{
|
|
10
|
-
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
-
files: ['**/*.{ts,tsx}'],
|
|
12
|
-
languageOptions: {
|
|
13
|
-
ecmaVersion: 2020,
|
|
14
|
-
globals: globals.browser,
|
|
15
|
-
},
|
|
16
|
-
plugins: {
|
|
17
|
-
'react-hooks': reactHooks,
|
|
18
|
-
'react-refresh': reactRefresh,
|
|
19
|
-
},
|
|
20
|
-
rules: {
|
|
21
|
-
...reactHooks.configs.recommended.rules,
|
|
22
|
-
'react-refresh/only-export-components': [
|
|
23
|
-
'warn',
|
|
24
|
-
{ allowConstantExport: true },
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
)
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import React, { useRef, useState, useMemo, useEffect } from "react";
|
|
2
|
-
|
|
3
|
-
type DynamicChildPositionerProps = {
|
|
4
|
-
rightNode: React.ReactNode;
|
|
5
|
-
leftNode: React.ReactNode;
|
|
6
|
-
options: {
|
|
7
|
-
primary: "left" | "right";
|
|
8
|
-
};
|
|
9
|
-
backgroundColor?: string;
|
|
10
|
-
width: number | string;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const DynamicChildPositioner = ({
|
|
14
|
-
rightNode,
|
|
15
|
-
leftNode,
|
|
16
|
-
options: { primary },
|
|
17
|
-
width,
|
|
18
|
-
backgroundColor = "gray",
|
|
19
|
-
}: DynamicChildPositionerProps) => {
|
|
20
|
-
const ref = useRef<HTMLDivElement | null>(null);
|
|
21
|
-
const refRight = useRef<HTMLDivElement | null>(null);
|
|
22
|
-
const refLeft = useRef<HTMLDivElement | null>(null);
|
|
23
|
-
const [fitStatus, setFitStatus] = useState<"both" | "primary" | "none">(
|
|
24
|
-
"both"
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const rightStyle = useMemo(() => {
|
|
28
|
-
const rightNoSpace =
|
|
29
|
-
fitStatus === "none" || (fitStatus === "primary" && primary === "left");
|
|
30
|
-
if (primary === "right") {
|
|
31
|
-
return rightNoSpace ? STYLES["BOTTOM_RIGHT"] : STYLES["RIGHT"];
|
|
32
|
-
} else {
|
|
33
|
-
return rightNoSpace ? STYLES["TOP_LEFT"] : STYLES["RIGHT"];
|
|
34
|
-
}
|
|
35
|
-
}, [fitStatus, primary]);
|
|
36
|
-
|
|
37
|
-
const leftStyle = useMemo(() => {
|
|
38
|
-
const leftNoSpace =
|
|
39
|
-
fitStatus === "none" || (fitStatus === "primary" && primary === "right");
|
|
40
|
-
if (primary === "left") {
|
|
41
|
-
return leftNoSpace ? STYLES["BOTTOM_LEFT"] : STYLES["LEFT"];
|
|
42
|
-
} else {
|
|
43
|
-
return leftNoSpace ? STYLES["TOP_RIGHT"] : STYLES["LEFT"];
|
|
44
|
-
}
|
|
45
|
-
}, [fitStatus, primary]);
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
const interval = setInterval(() => {
|
|
49
|
-
const textRight = refRight.current;
|
|
50
|
-
const textLeft = refLeft.current;
|
|
51
|
-
const container = ref.current;
|
|
52
|
-
if (!container || !textRight || !textLeft) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const containerRectWidth = container.getBoundingClientRect().width;
|
|
56
|
-
const rightWidth = textRight.getBoundingClientRect().width;
|
|
57
|
-
const leftWidth = textLeft.getBoundingClientRect().width;
|
|
58
|
-
|
|
59
|
-
const { primaryWidth, secondaryWidth } =
|
|
60
|
-
primary === "left"
|
|
61
|
-
? { primaryWidth: leftWidth, secondaryWidth: rightWidth }
|
|
62
|
-
: { primaryWidth: rightWidth, secondaryWidth: leftWidth };
|
|
63
|
-
|
|
64
|
-
const primaryCanFit = primaryWidth + 2 * GAP <= containerRectWidth;
|
|
65
|
-
const secondaryCanFit =
|
|
66
|
-
secondaryWidth + primaryWidth + 3 * GAP <= containerRectWidth;
|
|
67
|
-
|
|
68
|
-
const fitStatus = primaryCanFit
|
|
69
|
-
? secondaryCanFit
|
|
70
|
-
? "both"
|
|
71
|
-
: "primary"
|
|
72
|
-
: "none";
|
|
73
|
-
|
|
74
|
-
setFitStatus(fitStatus);
|
|
75
|
-
}, 1000 / 30);
|
|
76
|
-
return () => clearInterval(interval);
|
|
77
|
-
}, [ref, refRight, refLeft, primary]);
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<div
|
|
81
|
-
ref={ref}
|
|
82
|
-
style={{
|
|
83
|
-
position: "relative",
|
|
84
|
-
width,
|
|
85
|
-
backgroundColor,
|
|
86
|
-
borderRadius: "5px",
|
|
87
|
-
color: "white",
|
|
88
|
-
}}
|
|
89
|
-
>
|
|
90
|
-
<div ref={refLeft} style={leftStyle}>
|
|
91
|
-
{leftNode}
|
|
92
|
-
</div>
|
|
93
|
-
<div ref={refRight} style={rightStyle}>
|
|
94
|
-
{rightNode}
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const GAP = 5;
|
|
101
|
-
const COMMON_STYLES: React.CSSProperties = {
|
|
102
|
-
position: "absolute",
|
|
103
|
-
transition: "all 200ms cubic-bezier(.47,1.64,.41,.8)",
|
|
104
|
-
transitionProperty: "transform, top, left, bottom, right",
|
|
105
|
-
};
|
|
106
|
-
const STYLES: Record<string, React.CSSProperties> = {
|
|
107
|
-
TOP_LEFT: {
|
|
108
|
-
...COMMON_STYLES,
|
|
109
|
-
left: GAP,
|
|
110
|
-
top: -GAP,
|
|
111
|
-
transform: "translateY(-100%)",
|
|
112
|
-
},
|
|
113
|
-
LEFT: {
|
|
114
|
-
...COMMON_STYLES,
|
|
115
|
-
left: GAP,
|
|
116
|
-
top: "50%",
|
|
117
|
-
transform: "translateY(-50%)",
|
|
118
|
-
},
|
|
119
|
-
BOTTOM_LEFT: {
|
|
120
|
-
...COMMON_STYLES,
|
|
121
|
-
left: GAP,
|
|
122
|
-
bottom: -GAP,
|
|
123
|
-
transform: "translateY(100%)",
|
|
124
|
-
},
|
|
125
|
-
TOP_RIGHT: {
|
|
126
|
-
...COMMON_STYLES,
|
|
127
|
-
right: GAP,
|
|
128
|
-
top: -GAP,
|
|
129
|
-
transform: "translateY(-100%)",
|
|
130
|
-
},
|
|
131
|
-
RIGHT: {
|
|
132
|
-
...COMMON_STYLES,
|
|
133
|
-
right: GAP,
|
|
134
|
-
top: "50%",
|
|
135
|
-
transform: "translateY(-50%)",
|
|
136
|
-
},
|
|
137
|
-
BOTTOM_RIGHT: {
|
|
138
|
-
...COMMON_STYLES,
|
|
139
|
-
right: GAP,
|
|
140
|
-
bottom: -GAP,
|
|
141
|
-
transform: "translateY(100%)",
|
|
142
|
-
},
|
|
143
|
-
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { DynamicChildPositioner } from "./DynamicChildPositioner";
|
|
2
|
-
import { ProportionDetail, DisplayValueTypes } from "./ProportionSlider";
|
|
3
|
-
|
|
4
|
-
export type ProportionProp = {
|
|
5
|
-
value: number;
|
|
6
|
-
total: number;
|
|
7
|
-
detail: ProportionDetail;
|
|
8
|
-
width: number | string;
|
|
9
|
-
anchorName: "left" | "right";
|
|
10
|
-
displayValueType: DisplayValueTypes;
|
|
11
|
-
backgroundColor?: string;
|
|
12
|
-
};
|
|
13
|
-
export const Proportion = ({
|
|
14
|
-
value,
|
|
15
|
-
total,
|
|
16
|
-
detail,
|
|
17
|
-
width,
|
|
18
|
-
anchorName,
|
|
19
|
-
displayValueType,
|
|
20
|
-
backgroundColor = "gray",
|
|
21
|
-
}: ProportionProp) => {
|
|
22
|
-
const nameNode = (
|
|
23
|
-
<div
|
|
24
|
-
style={{
|
|
25
|
-
userSelect: "none",
|
|
26
|
-
whiteSpace: "nowrap",
|
|
27
|
-
}}
|
|
28
|
-
>
|
|
29
|
-
{detail.name}
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
const percentNode =
|
|
33
|
-
displayValueType === "percentage" ? (
|
|
34
|
-
<div
|
|
35
|
-
style={{
|
|
36
|
-
userSelect: "none",
|
|
37
|
-
whiteSpace: "nowrap",
|
|
38
|
-
}}
|
|
39
|
-
>
|
|
40
|
-
{`${Math.round((value * 100) / total)}%`}
|
|
41
|
-
</div>
|
|
42
|
-
) : null;
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<DynamicChildPositioner
|
|
46
|
-
width={width}
|
|
47
|
-
rightNode={anchorName === "right" ? nameNode : percentNode}
|
|
48
|
-
leftNode={anchorName === "left" ? nameNode : percentNode}
|
|
49
|
-
options={{
|
|
50
|
-
primary: anchorName,
|
|
51
|
-
}}
|
|
52
|
-
backgroundColor={backgroundColor}
|
|
53
|
-
></DynamicChildPositioner>
|
|
54
|
-
);
|
|
55
|
-
};
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { useCallback, useRef } from "react";
|
|
2
|
-
import { SliderKnob } from "./SliderKnob";
|
|
3
|
-
import { Proportion } from "./Proportion";
|
|
4
|
-
|
|
5
|
-
export type ProportionDetail = {
|
|
6
|
-
name: string;
|
|
7
|
-
backgroundColor?: string;
|
|
8
|
-
};
|
|
9
|
-
export type DisplayValueTypes = "percentage" | "none";
|
|
10
|
-
|
|
11
|
-
export type ProportionSliderProps = {
|
|
12
|
-
value: [number, number];
|
|
13
|
-
proportions: [ProportionDetail, ProportionDetail];
|
|
14
|
-
onChange: (change: [number, number]) => void;
|
|
15
|
-
sliderOptions?: {
|
|
16
|
-
width: number;
|
|
17
|
-
gap: number;
|
|
18
|
-
backgroundColor?: string;
|
|
19
|
-
};
|
|
20
|
-
options?: {
|
|
21
|
-
height: number;
|
|
22
|
-
displayValueType: DisplayValueTypes;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
export const ProportionSlider = ({
|
|
26
|
-
value,
|
|
27
|
-
proportions,
|
|
28
|
-
onChange,
|
|
29
|
-
sliderOptions = {
|
|
30
|
-
width: 5,
|
|
31
|
-
gap: 2,
|
|
32
|
-
},
|
|
33
|
-
options = {
|
|
34
|
-
height: 20,
|
|
35
|
-
displayValueType: "percentage",
|
|
36
|
-
},
|
|
37
|
-
}: ProportionSliderProps) => {
|
|
38
|
-
const refWidth = useRef<number | null>(null);
|
|
39
|
-
|
|
40
|
-
const total = value[0] + value[1];
|
|
41
|
-
|
|
42
|
-
const refStartX = useRef<number | null>(null);
|
|
43
|
-
const refValue1Start = useRef<number | null>(null);
|
|
44
|
-
const refValue2Start = useRef<number | null>(null);
|
|
45
|
-
const sliderWidth = sliderOptions.width + sliderOptions.gap * 2;
|
|
46
|
-
const onDragStart = useCallback(
|
|
47
|
-
(px: number): void => {
|
|
48
|
-
refStartX.current = px;
|
|
49
|
-
refValue1Start.current = value[0];
|
|
50
|
-
refValue2Start.current = value[1];
|
|
51
|
-
},
|
|
52
|
-
[value]
|
|
53
|
-
);
|
|
54
|
-
const onDragEnd = useCallback(() => {
|
|
55
|
-
refStartX.current = null;
|
|
56
|
-
refValue1Start.current = null;
|
|
57
|
-
refValue2Start.current = null;
|
|
58
|
-
}, []);
|
|
59
|
-
const onDrag = useCallback(
|
|
60
|
-
(px: number): void => {
|
|
61
|
-
if (refStartX.current === null) return;
|
|
62
|
-
const diffPx = px - refStartX.current;
|
|
63
|
-
const totalWidthPx = refWidth.current! - sliderWidth;
|
|
64
|
-
const total = refValue1Start.current! + refValue2Start.current!;
|
|
65
|
-
let newValue1 = refValue1Start.current! + (diffPx / totalWidthPx) * total;
|
|
66
|
-
newValue1 = Math.max(0, Math.min(total, newValue1));
|
|
67
|
-
onChange([newValue1, total - newValue1]);
|
|
68
|
-
},
|
|
69
|
-
[onChange, sliderWidth]
|
|
70
|
-
);
|
|
71
|
-
return (
|
|
72
|
-
<div
|
|
73
|
-
ref={(el) => {
|
|
74
|
-
if (el) {
|
|
75
|
-
refWidth.current = el.getBoundingClientRect().width;
|
|
76
|
-
}
|
|
77
|
-
}}
|
|
78
|
-
style={{
|
|
79
|
-
display: "flex",
|
|
80
|
-
flexDirection: "row",
|
|
81
|
-
height: options.height,
|
|
82
|
-
}}
|
|
83
|
-
>
|
|
84
|
-
<Proportion
|
|
85
|
-
value={value[0]}
|
|
86
|
-
backgroundColor={proportions[0].backgroundColor}
|
|
87
|
-
total={total}
|
|
88
|
-
width={`calc(${(value[0] * 100) / total}% - ${sliderWidth / 2}px)`}
|
|
89
|
-
detail={proportions[0]}
|
|
90
|
-
anchorName="left"
|
|
91
|
-
displayValueType={options.displayValueType}
|
|
92
|
-
/>
|
|
93
|
-
<SliderKnob
|
|
94
|
-
backgroundColor={sliderOptions.backgroundColor}
|
|
95
|
-
width={sliderOptions.width}
|
|
96
|
-
gap={sliderOptions.gap}
|
|
97
|
-
onDragStart={onDragStart}
|
|
98
|
-
onDrag={onDrag}
|
|
99
|
-
onDragEnd={onDragEnd}
|
|
100
|
-
/>
|
|
101
|
-
<Proportion
|
|
102
|
-
value={value[1]}
|
|
103
|
-
total={total}
|
|
104
|
-
backgroundColor={proportions[1].backgroundColor}
|
|
105
|
-
width={`calc(${(value[1] * 100) / total}% - ${sliderWidth / 2}px)`}
|
|
106
|
-
detail={proportions[1]}
|
|
107
|
-
anchorName="right"
|
|
108
|
-
displayValueType={options.displayValueType}
|
|
109
|
-
/>
|
|
110
|
-
</div>
|
|
111
|
-
);
|
|
112
|
-
};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { useRef, useEffect } from "react";
|
|
2
|
-
|
|
3
|
-
export type SliderKnobProps = {
|
|
4
|
-
width: number;
|
|
5
|
-
gap: number;
|
|
6
|
-
backgroundColor?: string;
|
|
7
|
-
onDragStart: (px: number) => void;
|
|
8
|
-
onDrag: (px: number) => void;
|
|
9
|
-
onDragEnd: () => void;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const SliderKnob = ({
|
|
13
|
-
width,
|
|
14
|
-
gap,
|
|
15
|
-
backgroundColor = "red",
|
|
16
|
-
onDrag,
|
|
17
|
-
onDragStart,
|
|
18
|
-
onDragEnd,
|
|
19
|
-
}: SliderKnobProps) => {
|
|
20
|
-
const ref = useRef<HTMLDivElement | null>(null);
|
|
21
|
-
const refIsDragging = useRef<boolean>(false);
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
const onMouseDown = (e: MouseEvent) => {
|
|
24
|
-
if (e.target !== ref.current) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
refIsDragging.current = true;
|
|
28
|
-
onDragStart(e.clientX);
|
|
29
|
-
return true;
|
|
30
|
-
};
|
|
31
|
-
const onMouseMove = (e: MouseEvent) => {
|
|
32
|
-
if (!refIsDragging.current) {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
onDrag(e.clientX);
|
|
36
|
-
return true;
|
|
37
|
-
};
|
|
38
|
-
const onMouseUp = () => {
|
|
39
|
-
if (!refIsDragging.current) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
refIsDragging.current = false;
|
|
43
|
-
onDragEnd();
|
|
44
|
-
return true;
|
|
45
|
-
};
|
|
46
|
-
window.addEventListener("mousedown", onMouseDown);
|
|
47
|
-
window.addEventListener("mousemove", onMouseMove);
|
|
48
|
-
window.addEventListener("mouseup", onMouseUp);
|
|
49
|
-
return () => {
|
|
50
|
-
window.removeEventListener("mousedown", onMouseDown);
|
|
51
|
-
window.removeEventListener("mousemove", onMouseMove);
|
|
52
|
-
window.removeEventListener("mouseup", onMouseUp);
|
|
53
|
-
};
|
|
54
|
-
}, [onDragStart, onDrag, onDragEnd]);
|
|
55
|
-
return (
|
|
56
|
-
<div
|
|
57
|
-
ref={ref}
|
|
58
|
-
style={{
|
|
59
|
-
width: `${width}px`,
|
|
60
|
-
margin: `${gap}px ${gap}px`,
|
|
61
|
-
alignSelf: "stretch",
|
|
62
|
-
background: backgroundColor,
|
|
63
|
-
borderRadius: "2px",
|
|
64
|
-
cursor: "ew-resize",
|
|
65
|
-
}}
|
|
66
|
-
></div>
|
|
67
|
-
);
|
|
68
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./components/ProportionSlider";
|
package/src/vite-env.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="vite/client" />
|
package/tsconfig.app.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
-
"target": "ES2020",
|
|
5
|
-
"useDefineForClassFields": true,
|
|
6
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
-
"module": "ESNext",
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"moduleDetection": "force",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
"jsx": "react-jsx",
|
|
17
|
-
|
|
18
|
-
/* Linting */
|
|
19
|
-
"strict": true,
|
|
20
|
-
"noUnusedLocals": true,
|
|
21
|
-
"noUnusedParameters": true,
|
|
22
|
-
"noFallthroughCasesInSwitch": true,
|
|
23
|
-
"noUncheckedSideEffectImports": true
|
|
24
|
-
},
|
|
25
|
-
"include": ["src"]
|
|
26
|
-
}
|
package/tsconfig.json
DELETED
package/tsconfig.node.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
-
"target": "ES2022",
|
|
5
|
-
"lib": ["ES2023"],
|
|
6
|
-
"module": "ESNext",
|
|
7
|
-
"skipLibCheck": true,
|
|
8
|
-
|
|
9
|
-
/* Bundler mode */
|
|
10
|
-
"moduleResolution": "bundler",
|
|
11
|
-
"allowImportingTsExtensions": true,
|
|
12
|
-
"isolatedModules": true,
|
|
13
|
-
"moduleDetection": "force",
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
|
|
16
|
-
/* Linting */
|
|
17
|
-
"strict": true,
|
|
18
|
-
"noUnusedLocals": true,
|
|
19
|
-
"noUnusedParameters": true,
|
|
20
|
-
"noFallthroughCasesInSwitch": true,
|
|
21
|
-
"noUncheckedSideEffectImports": true
|
|
22
|
-
},
|
|
23
|
-
"include": ["vite.config.ts"]
|
|
24
|
-
}
|
package/vite.config.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import react from "@vitejs/plugin-react";
|
|
3
|
-
|
|
4
|
-
// https://vite.dev/config/
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
plugins: [react()],
|
|
7
|
-
build: {
|
|
8
|
-
rollupOptions: {
|
|
9
|
-
external: ["react", "react-dom"],
|
|
10
|
-
output: {
|
|
11
|
-
globals: {
|
|
12
|
-
react: "React",
|
|
13
|
-
"react-dom": "ReactDOM",
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
lib: {
|
|
18
|
-
entry: "src/index.ts",
|
|
19
|
-
name: "react-proportion-slider",
|
|
20
|
-
fileName: (format) => `my-react-library.${format}.js`,
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
server: {
|
|
24
|
-
open: "/dev/index.html", // Open the dev environment on `npm run dev`
|
|
25
|
-
},
|
|
26
|
-
});
|