react-spin-prize 2.0.0 → 2.1.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 CHANGED
@@ -78,6 +78,7 @@ function App() {
78
78
  | `disabled` | `boolean` | false | Disable the spin button |
79
79
  | `winningIndex` | `number` | - | Force a specific winner (for testing) |
80
80
  | `autoSpinTrigger` | `string \| number \| boolean \| null` | - | Change this value to trigger a programmatic spin |
81
+ | `textLayout` | `'radial' \| 'horizontal'` | 'horizontal' | Text layout style: 'radial' for rotating text, 'horizontal' for edge-to-center text |
81
82
 
82
83
  ## SpinnerWheelItem
83
84
 
@@ -125,6 +126,15 @@ interface SpinnerWheelItem {
125
126
  console.log('Winner:', item);
126
127
  }}
127
128
  />
129
+
130
+ // Horizontal text layout (edge-to-center)
131
+ <SpinnerWheel
132
+ items={items}
133
+ textLayout="horizontal"
134
+ onSpinComplete={(item) => {
135
+ console.log('Winner:', item);
136
+ }}
137
+ />
128
138
  ```
129
139
 
130
140
  ## License
@@ -1 +1 @@
1
- {"version":3,"file":"SpinnerWheel.d.ts","sourceRoot":"","sources":["../src/SpinnerWheel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAQjD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAwSpD,CAAC"}
1
+ {"version":3,"file":"SpinnerWheel.d.ts","sourceRoot":"","sources":["../src/SpinnerWheel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAQjD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAoWpD,CAAC"}
@@ -1,11 +1,11 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useRef, useEffect, useCallback } from "react";
3
3
  const DEFAULT_COLORS = [
4
4
  "#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A",
5
5
  "#98D8C8", "#F7DC6F", "#BB8FCE", "#85C1E2",
6
6
  "#F8B739", "#52B788", "#E76F51", "#2A9D8F",
7
7
  ];
8
- export const SpinnerWheel = ({ items, onSpinComplete, onButtonClick, spinning: externalSpinning, duration = 5000, size = 500, fontSize = 16, borderWidth = 8, borderColor = "#333", buttonText = "SPIN", buttonColor = "#333", buttonTextColor = "#fff", buttonIcon, buttonSize, buttonBorderColor = "#333", buttonBorderWidth = 4, disabled = false, winningIndex, autoSpinTrigger, }) => {
8
+ export const SpinnerWheel = ({ items, onSpinComplete, onButtonClick, spinning: externalSpinning, duration = 5000, size = 500, fontSize = 16, borderWidth = 8, borderColor = "#333", buttonText = "SPIN", buttonColor = "#333", buttonTextColor = "#fff", buttonIcon, buttonSize, buttonBorderColor = "#333", buttonBorderWidth = 4, disabled = false, winningIndex, autoSpinTrigger, textLayout = "horizontal", }) => {
9
9
  const [rotation, setRotation] = useState(0);
10
10
  const [spinning, setSpinning] = useState(false);
11
11
  const animationRef = useRef();
@@ -122,25 +122,55 @@ export const SpinnerWheel = ({ items, onSpinComplete, onButtonClick, spinning: e
122
122
  `A ${wheelRadius} ${wheelRadius} 0 0 1 ${x2} ${y2}`,
123
123
  "Z",
124
124
  ].join(" ");
125
- // Text position
126
- const textRadius = items.length > 30 ? wheelRadius * 0.65
127
- : items.length > 20 ? wheelRadius * 0.68
128
- : wheelRadius * 0.7;
129
- const textX = centerX + textRadius * Math.cos(midAngle);
130
- const textY = centerY + textRadius * Math.sin(midAngle);
131
- const textAngle = (midAngle * 180) / Math.PI + 90;
132
- // Truncate long labels
133
- let displayLabel = item.label;
134
- if (items.length > 30 && displayLabel.length > 8) {
135
- displayLabel = displayLabel.substring(0, 7) + "...";
136
- }
137
- else if (items.length > 20 && displayLabel.length > 12) {
138
- displayLabel = displayLabel.substring(0, 11) + "...";
125
+ // Text position and rendering based on layout
126
+ let textElement;
127
+ if (textLayout === "horizontal") {
128
+ // Horizontal layout: text starts from edge towards center
129
+ const outerTextRadius = wheelRadius * 0.85;
130
+ const innerTextRadius = wheelRadius * 0.35;
131
+ // Calculate start position (at the edge)
132
+ const startX = centerX + outerTextRadius * Math.cos(midAngle);
133
+ const startY = centerY + outerTextRadius * Math.sin(midAngle);
134
+ // Calculate end position (towards center)
135
+ const endX = centerX + innerTextRadius * Math.cos(midAngle);
136
+ const endY = centerY + innerTextRadius * Math.sin(midAngle);
137
+ // Text path for horizontal text
138
+ const textPathId = `textPath-${item.id}`;
139
+ // Truncate long labels
140
+ let displayLabel = item.label;
141
+ if (items.length > 30 && displayLabel.length > 8) {
142
+ displayLabel = displayLabel.substring(0, 7) + "...";
143
+ }
144
+ else if (items.length > 20 && displayLabel.length > 12) {
145
+ displayLabel = displayLabel.substring(0, 11) + "...";
146
+ }
147
+ else if (items.length > 12 && displayLabel.length > 15) {
148
+ displayLabel = displayLabel.substring(0, 14) + "...";
149
+ }
150
+ textElement = (_jsxs(_Fragment, { children: [_jsx("defs", { children: _jsx("path", { id: textPathId, d: `M ${startX} ${startY} L ${endX} ${endY}` }) }), _jsx("text", { fill: getTextColor(index), fontSize: dynamicFontSize, fontWeight: "bold", style: { userSelect: "none", pointerEvents: "none" }, children: _jsx("textPath", { href: `#${textPathId}`, startOffset: "50%", textAnchor: "middle", children: displayLabel }) })] }));
139
151
  }
140
- else if (items.length > 12 && displayLabel.length > 15) {
141
- displayLabel = displayLabel.substring(0, 14) + "...";
152
+ else {
153
+ // Radial layout (default): rotating text
154
+ const textRadius = items.length > 30 ? wheelRadius * 0.65
155
+ : items.length > 20 ? wheelRadius * 0.68
156
+ : wheelRadius * 0.7;
157
+ const textX = centerX + textRadius * Math.cos(midAngle);
158
+ const textY = centerY + textRadius * Math.sin(midAngle);
159
+ const textAngle = (midAngle * 180) / Math.PI + 90;
160
+ // Truncate long labels
161
+ let displayLabel = item.label;
162
+ if (items.length > 30 && displayLabel.length > 8) {
163
+ displayLabel = displayLabel.substring(0, 7) + "...";
164
+ }
165
+ else if (items.length > 20 && displayLabel.length > 12) {
166
+ displayLabel = displayLabel.substring(0, 11) + "...";
167
+ }
168
+ else if (items.length > 12 && displayLabel.length > 15) {
169
+ displayLabel = displayLabel.substring(0, 14) + "...";
170
+ }
171
+ textElement = (_jsx("text", { x: textX, y: textY, fill: getTextColor(index), fontSize: dynamicFontSize, fontWeight: "bold", textAnchor: "middle", dominantBaseline: "middle", transform: `rotate(${textAngle} ${textX} ${textY})`, style: { userSelect: "none", pointerEvents: "none" }, children: displayLabel }));
142
172
  }
143
- return (_jsxs("g", { children: [_jsx("path", { d: pathData, fill: getColor(index), stroke: borderColor, strokeWidth: 1 }), _jsx("text", { x: textX, y: textY, fill: getTextColor(index), fontSize: dynamicFontSize, fontWeight: "bold", textAnchor: "middle", dominantBaseline: "middle", transform: `rotate(${textAngle} ${textX} ${textY})`, style: { userSelect: "none", pointerEvents: "none" }, children: displayLabel })] }, item.id));
173
+ return (_jsxs("g", { children: [_jsx("path", { d: pathData, fill: getColor(index), stroke: borderColor, strokeWidth: 1 }), textElement] }, item.id));
144
174
  });
145
175
  };
146
176
  return (_jsxs("div", { style: { position: "relative", width: size, height: size, margin: "0 auto" }, children: [_jsxs("svg", { width: size, height: size, style: {
package/dist/types.d.ts CHANGED
@@ -24,5 +24,6 @@ export interface SpinnerWheelProps {
24
24
  disabled?: boolean;
25
25
  winningIndex?: number;
26
26
  autoSpinTrigger?: string | number | boolean | null;
27
+ textLayout?: "radial" | "horizontal";
27
28
  }
28
29
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,aAAa,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;CACpD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,aAAa,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACnD,UAAU,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;CACtC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-spin-prize",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Modern, customizable prize wheel spinner component for React with TypeScript support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",