react-proportion-slider 0.9.0

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 ADDED
@@ -0,0 +1,124 @@
1
+ # React Proportion Slider
2
+
3
+ > **Note:** This package is currently in beta
4
+
5
+ A React component that allows users to adjust the proportion of two elements using a slider.
6
+
7
+ ## Installation
8
+
9
+ (Not yet published to npm)
10
+
11
+ ```bash
12
+ npm install react-proportion-slider
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```tsx
18
+ import React from "react";
19
+ import { ProportionSlider } from "react-proportion-slider";
20
+
21
+ function App() {
22
+ const [proportions, setProportions] = React.useState<[number, number]>([
23
+ 50, 50,
24
+ ]);
25
+ return (
26
+ <div
27
+ style={{
28
+ height: "100%",
29
+ flex: 1,
30
+ padding: "20px 200px",
31
+ display: "flex",
32
+ flexDirection: "column",
33
+ justifyContent: "center",
34
+ }}
35
+ >
36
+ <ProportionSlider
37
+ value={proportions}
38
+ proportions={[
39
+ {
40
+ name: "Skill",
41
+ backgroundColor: "#31332E",
42
+ },
43
+ {
44
+ name: "3.7 Sonnet",
45
+ backgroundColor: "#5f625C",
46
+ },
47
+ ]}
48
+ onChange={(change) => {
49
+ setProportions(change);
50
+ }}
51
+ sliderOptions={{
52
+ width: 5,
53
+ gap: 5,
54
+ backgroundColor: "#EC1308",
55
+ }}
56
+ options={{
57
+ height: 50,
58
+ displayValueType: "percentage",
59
+ }}
60
+ />
61
+ </div>
62
+ );
63
+ }
64
+ ```
65
+
66
+ ## Future Features
67
+
68
+ 1. Make it possible to adjust the proportion of more than two elements
69
+ 2. Add more customization options
70
+
71
+ ## React + TypeScript + Vite
72
+
73
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
74
+
75
+ Currently, two official plugins are available:
76
+
77
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
78
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
79
+
80
+ ### Expanding the ESLint configuration
81
+
82
+ If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
83
+
84
+ ```js
85
+ export default tseslint.config({
86
+ extends: [
87
+ // Remove ...tseslint.configs.recommended and replace with this
88
+ ...tseslint.configs.recommendedTypeChecked,
89
+ // Alternatively, use this for stricter rules
90
+ ...tseslint.configs.strictTypeChecked,
91
+ // Optionally, add this for stylistic rules
92
+ ...tseslint.configs.stylisticTypeChecked,
93
+ ],
94
+ languageOptions: {
95
+ // other options...
96
+ parserOptions: {
97
+ project: ["./tsconfig.node.json", "./tsconfig.app.json"],
98
+ tsconfigRootDir: import.meta.dirname,
99
+ },
100
+ },
101
+ });
102
+ ```
103
+
104
+ You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
105
+
106
+ ```js
107
+ // eslint.config.js
108
+ import reactX from "eslint-plugin-react-x";
109
+ import reactDom from "eslint-plugin-react-dom";
110
+
111
+ export default tseslint.config({
112
+ plugins: {
113
+ // Add the react-x and react-dom plugins
114
+ "react-x": reactX,
115
+ "react-dom": reactDom,
116
+ },
117
+ rules: {
118
+ // other rules...
119
+ // Enable its recommended typescript rules
120
+ ...reactX.configs["recommended-typescript"].rules,
121
+ ...reactDom.configs.recommended.rules,
122
+ },
123
+ });
124
+ ```
package/dev/App.css ADDED
@@ -0,0 +1,13 @@
1
+ html,body {
2
+ height: 100%;
3
+ }
4
+
5
+ #root{
6
+ height: 100%;
7
+ background-color: #11110D;
8
+ }
9
+
10
+ * {
11
+ font-family: Roboto, sans-serif;
12
+ font-weight: 200;
13
+ }
package/dev/App.tsx ADDED
@@ -0,0 +1,49 @@
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 ADDED
@@ -0,0 +1,17 @@
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 ADDED
@@ -0,0 +1,9 @@
1
+ import React, { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import App from "./App.tsx";
4
+
5
+ createRoot(document.getElementById("root")!).render(
6
+ <StrictMode>
7
+ <App />
8
+ </StrictMode>
9
+ );
@@ -0,0 +1,28 @@
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
+ )
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "react-proportion-slider",
3
+ "private": false,
4
+ "version": "0.9.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "react": "^19.0.0",
14
+ "react-dom": "^19.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@eslint/js": "^9.21.0",
18
+ "@types/react": "^19.0.10",
19
+ "@types/react-dom": "^19.0.4",
20
+ "@vitejs/plugin-react": "^4.3.4",
21
+ "eslint": "^9.21.0",
22
+ "eslint-plugin-react-hooks": "^5.1.0",
23
+ "eslint-plugin-react-refresh": "^0.4.19",
24
+ "globals": "^15.15.0",
25
+ "typescript": "~5.7.2",
26
+ "typescript-eslint": "^8.24.1",
27
+ "vite": "^6.2.0"
28
+ }
29
+ }
@@ -0,0 +1,143 @@
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
+ };
@@ -0,0 +1,55 @@
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
+ };
@@ -0,0 +1,112 @@
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
+ };
@@ -0,0 +1,68 @@
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 ADDED
@@ -0,0 +1 @@
1
+ export * from "./components/ProportionSlider";
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,26 @@
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 ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,24 @@
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 ADDED
@@ -0,0 +1,26 @@
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
+ });