@chao-component/bag-animation-ui 1.0.11 → 1.0.12

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/dist/index.d.mts CHANGED
@@ -5,13 +5,15 @@ interface BagAnimationProps {
5
5
  frames?: string[];
6
6
  defaultImage?: string;
7
7
  defaultImageAlt?: string;
8
+ hasChances?: boolean;
8
9
  swipeHintText?: string;
9
10
  boxOpeningText?: string;
11
+ clickHintText?: string;
10
12
  showMask?: boolean;
11
13
  maskOpacity?: number;
12
14
  maskBlur?: number;
13
15
  }
14
- declare function BagAnimation({ doneFunction, frames, defaultImage, defaultImageAlt, swipeHintText, boxOpeningText, showMask, maskOpacity, maskBlur }: BagAnimationProps): react_jsx_runtime.JSX.Element;
16
+ declare function BagAnimation({ doneFunction, frames, defaultImage, defaultImageAlt, swipeHintText, boxOpeningText, clickHintText, hasChances, showMask, maskOpacity, maskBlur }: BagAnimationProps): react_jsx_runtime.JSX.Element;
15
17
 
16
18
  /**
17
19
  * 获取打包后的资源路径
package/dist/index.d.ts CHANGED
@@ -5,13 +5,15 @@ interface BagAnimationProps {
5
5
  frames?: string[];
6
6
  defaultImage?: string;
7
7
  defaultImageAlt?: string;
8
+ hasChances?: boolean;
8
9
  swipeHintText?: string;
9
10
  boxOpeningText?: string;
11
+ clickHintText?: string;
10
12
  showMask?: boolean;
11
13
  maskOpacity?: number;
12
14
  maskBlur?: number;
13
15
  }
14
- declare function BagAnimation({ doneFunction, frames, defaultImage, defaultImageAlt, swipeHintText, boxOpeningText, showMask, maskOpacity, maskBlur }: BagAnimationProps): react_jsx_runtime.JSX.Element;
16
+ declare function BagAnimation({ doneFunction, frames, defaultImage, defaultImageAlt, swipeHintText, boxOpeningText, clickHintText, hasChances, showMask, maskOpacity, maskBlur }: BagAnimationProps): react_jsx_runtime.JSX.Element;
15
17
 
16
18
  /**
17
19
  * 获取打包后的资源路径
package/dist/index.js CHANGED
@@ -785,6 +785,7 @@ module.exports = __toCommonJS(index_exports);
785
785
  // src/BagAnimation.tsx
786
786
  var import_react = require("react");
787
787
  var import_apng_js = __toESM(require_lib());
788
+ var import_lucide_react = require("lucide-react");
788
789
 
789
790
  // src/assets.ts
790
791
  function getAssetPath(relativePath) {
@@ -808,6 +809,8 @@ function BagAnimation({
808
809
  defaultImageAlt = "Weedza Mystery Box",
809
810
  swipeHintText = "Swipe to open",
810
811
  boxOpeningText = "Box Opening...",
812
+ clickHintText = "Click to open",
813
+ hasChances = true,
811
814
  showMask = true,
812
815
  maskOpacity = 0.7,
813
816
  maskBlur = 8
@@ -1030,127 +1033,145 @@ function BagAnimation({
1030
1033
  setShowSwipeHint(true);
1031
1034
  }
1032
1035
  };
1033
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex w-full relative justify-center items-center", children: [
1034
- isAnimating && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1035
- showMask && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1036
- "div",
1036
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1037
+ !isAnimating && hasChances && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute top-8 left-[calc(50%-0px)] transform -translate-x-1/2 z-50 pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center animate-bounce", children: [
1038
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1039
+ "p",
1037
1040
  {
1038
- className: "fixed inset-0 z-[99]",
1039
- style: {
1040
- backgroundColor: `rgba(0, 0, 0, ${maskOpacity})`,
1041
- backdropFilter: `blur(${maskBlur}px)`,
1042
- WebkitBackdropFilter: `blur(${maskBlur}px)`
1043
- // Safari 支持
1044
- },
1045
- onClick: (e) => {
1046
- e.stopPropagation();
1047
- }
1041
+ className: "font-bold text-lg md:text-xl mb-1 drop-shadow-lg text-theme_gold",
1042
+ children: clickHintText
1048
1043
  }
1049
1044
  ),
1050
1045
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1051
- "div",
1046
+ import_lucide_react.ChevronDown,
1052
1047
  {
1053
- className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none",
1054
- style: { pointerEvents: "none" },
1055
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1056
- "div",
1057
- {
1058
- className: "relative w-full max-w-[90vw] max-h-[90vh] flex items-center justify-center pointer-events-auto",
1059
- style: { pointerEvents: "auto" },
1060
- children: [
1061
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1062
- "canvas",
1063
- {
1064
- ref: canvasRef,
1065
- onMouseDown,
1066
- onMouseMove,
1067
- onMouseUp,
1068
- onMouseLeave: onMouseUp,
1069
- onTouchStart: (e) => {
1070
- if (isPausedAtThird && canvasRef.current) {
1071
- const touch = e.touches[0];
1072
- const rect = canvasRef.current.getBoundingClientRect();
1073
- const touchGap = touch.clientX - rect.left;
1074
- const initialProgress = Math.max(0, Math.min(100, touchGap / rect.width * 100));
1075
- setThirdFrameProgress(initialProgress);
1076
- setShowSwipeHint(false);
1077
- }
1078
- },
1079
- onTouchMove: (e) => {
1080
- if (!isPausedAtThird || !canvasRef.current || hasTriggeredFourthFrame.current) return;
1081
- const touch = e.touches[0];
1082
- const rect = canvasRef.current.getBoundingClientRect();
1083
- const relativeX = touch.clientX - rect.left;
1084
- const canvasWidth = rect.width;
1085
- const progress = Math.max(0, Math.min(100, relativeX / canvasWidth * 100));
1086
- setThirdFrameProgress(progress);
1087
- if (progress >= 95 && !hasTriggeredFourthFrame.current) {
1088
- hasTriggeredFourthFrame.current = true;
1089
- setIsPausedAtThird(false);
1090
- setThirdFrameProgress(0);
1091
- setFrame(3);
1092
- }
1093
- },
1094
- onTouchEnd: (e) => {
1095
- if (isPausedAtThird) {
1096
- e.preventDefault();
1097
- setThirdFrameProgress(0);
1098
- setShowSwipeHint(true);
1099
- }
1100
- },
1101
- className: "select-none cursor-pointer w-full h-full object-contain",
1102
- style: {
1103
- imageRendering: "pixelated",
1104
- cursor: isPausedAtThird ? "grab" : "pointer",
1105
- touchAction: "none",
1106
- // 防止默認觸摸行為
1107
- userSelect: "none",
1108
- // 防止選中
1109
- maxWidth: "100%",
1110
- maxHeight: "100%"
1111
- }
1112
- }
1113
- ),
1114
- isPausedAtThird && showSwipeHint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute bottom-8 left-1/2 transform -translate-x-1/2 bg-black/70 text-white px-6 py-3 rounded-full text-sm md:text-base font-medium animate-pulse pointer-events-none z-20", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
1048
+ className: "h-8 w-8 md:h-10 md:w-10 text-lime-500 drop-shadow-lg text-theme_gold",
1049
+ strokeWidth: 4
1050
+ }
1051
+ )
1052
+ ] }) }),
1053
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex w-full relative justify-center items-center", children: [
1054
+ isAnimating && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1055
+ showMask && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1056
+ "div",
1057
+ {
1058
+ className: "fixed inset-0 z-[99]",
1059
+ style: {
1060
+ backgroundColor: `rgba(0, 0, 0, ${maskOpacity})`,
1061
+ backdropFilter: `blur(${maskBlur}px)`,
1062
+ WebkitBackdropFilter: `blur(${maskBlur}px)`
1063
+ // Safari 支持
1064
+ },
1065
+ onClick: (e) => {
1066
+ e.stopPropagation();
1067
+ }
1068
+ }
1069
+ ),
1070
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1071
+ "div",
1072
+ {
1073
+ className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none",
1074
+ style: { pointerEvents: "none" },
1075
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1076
+ "div",
1077
+ {
1078
+ className: "relative w-full max-w-[90vw] max-h-[90vh] flex items-center justify-center pointer-events-auto",
1079
+ style: { pointerEvents: "auto" },
1080
+ children: [
1115
1081
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1116
- "svg",
1082
+ "canvas",
1117
1083
  {
1118
- className: "w-5 h-5 md:w-6 md:h-6",
1119
- fill: "none",
1120
- stroke: "currentColor",
1121
- viewBox: "0 0 24 24",
1122
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1123
- "path",
1124
- {
1125
- strokeLinecap: "round",
1126
- strokeLinejoin: "round",
1127
- strokeWidth: 2,
1128
- d: "M13 7l5 5m0 0l-5 5m5-5H6"
1084
+ ref: canvasRef,
1085
+ onMouseDown,
1086
+ onMouseMove,
1087
+ onMouseUp,
1088
+ onMouseLeave: onMouseUp,
1089
+ onTouchStart: (e) => {
1090
+ if (isPausedAtThird && canvasRef.current) {
1091
+ const touch = e.touches[0];
1092
+ const rect = canvasRef.current.getBoundingClientRect();
1093
+ const touchGap = touch.clientX - rect.left;
1094
+ const initialProgress = Math.max(0, Math.min(100, touchGap / rect.width * 100));
1095
+ setThirdFrameProgress(initialProgress);
1096
+ setShowSwipeHint(false);
1129
1097
  }
1130
- )
1098
+ },
1099
+ onTouchMove: (e) => {
1100
+ if (!isPausedAtThird || !canvasRef.current || hasTriggeredFourthFrame.current) return;
1101
+ const touch = e.touches[0];
1102
+ const rect = canvasRef.current.getBoundingClientRect();
1103
+ const relativeX = touch.clientX - rect.left;
1104
+ const canvasWidth = rect.width;
1105
+ const progress = Math.max(0, Math.min(100, relativeX / canvasWidth * 100));
1106
+ setThirdFrameProgress(progress);
1107
+ if (progress >= 95 && !hasTriggeredFourthFrame.current) {
1108
+ hasTriggeredFourthFrame.current = true;
1109
+ setIsPausedAtThird(false);
1110
+ setThirdFrameProgress(0);
1111
+ setFrame(3);
1112
+ }
1113
+ },
1114
+ onTouchEnd: (e) => {
1115
+ if (isPausedAtThird) {
1116
+ e.preventDefault();
1117
+ setThirdFrameProgress(0);
1118
+ setShowSwipeHint(true);
1119
+ }
1120
+ },
1121
+ className: "select-none cursor-pointer w-full h-full object-contain",
1122
+ style: {
1123
+ imageRendering: "pixelated",
1124
+ cursor: isPausedAtThird ? "grab" : "pointer",
1125
+ touchAction: "none",
1126
+ // 防止默認觸摸行為
1127
+ userSelect: "none",
1128
+ // 防止選中
1129
+ maxWidth: "100%",
1130
+ maxHeight: "100%"
1131
+ }
1131
1132
  }
1132
1133
  ),
1133
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: swipeHintText })
1134
- ] }) })
1135
- ]
1136
- }
1137
- )
1134
+ isPausedAtThird && showSwipeHint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute bottom-8 left-1/2 transform -translate-x-1/2 bg-black/70 text-white px-6 py-3 rounded-full text-sm md:text-base font-medium animate-pulse pointer-events-none z-20", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
1135
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1136
+ "svg",
1137
+ {
1138
+ className: "w-5 h-5 md:w-6 md:h-6",
1139
+ fill: "none",
1140
+ stroke: "currentColor",
1141
+ viewBox: "0 0 24 24",
1142
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1143
+ "path",
1144
+ {
1145
+ strokeLinecap: "round",
1146
+ strokeLinejoin: "round",
1147
+ strokeWidth: 2,
1148
+ d: "M13 7l5 5m0 0l-5 5m5-5H6"
1149
+ }
1150
+ )
1151
+ }
1152
+ ),
1153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: swipeHintText })
1154
+ ] }) })
1155
+ ]
1156
+ }
1157
+ )
1158
+ }
1159
+ ),
1160
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "fixed z-[101] top-0 left-0 w-full h-[10%] flex justify-center items-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-theme_gold animate-pulse text-sm md:text-base text-center z-[101]", children: boxOpeningText }) })
1161
+ ] }),
1162
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1163
+ "img",
1164
+ {
1165
+ src: mysteryBoxImage,
1166
+ alt: mysteryBoxAlt,
1167
+ onClick: () => {
1168
+ setIsAnimating(true);
1169
+ },
1170
+ className: "w-36 h-36 md:w-96 md:h-96 object-contain relative z-10"
1138
1171
  }
1139
- ),
1140
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "fixed z-[101] top-0 left-0 w-full h-[10%] flex justify-center items-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-theme_gold animate-pulse text-sm md:text-base text-center z-[101]", children: boxOpeningText }) })
1141
- ] }),
1142
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1143
- "img",
1144
- {
1145
- src: mysteryBoxImage,
1146
- alt: mysteryBoxAlt,
1147
- onClick: () => {
1148
- setIsAnimating(true);
1149
- },
1150
- className: "w-36 h-36 md:w-96 md:h-96 object-contain relative z-10"
1151
- }
1152
- )
1153
- ] }) });
1172
+ )
1173
+ ] })
1174
+ ] });
1154
1175
  }
1155
1176
  // Annotate the CommonJS export names for ESM import in node:
1156
1177
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -769,6 +769,7 @@ var require_lib = __commonJS({
769
769
  // src/BagAnimation.tsx
770
770
  var import_apng_js = __toESM(require_lib());
771
771
  import { useEffect, useRef, useState } from "react";
772
+ import { ChevronDown } from "lucide-react";
772
773
 
773
774
  // src/assets.ts
774
775
  function getAssetPath(relativePath) {
@@ -792,6 +793,8 @@ function BagAnimation({
792
793
  defaultImageAlt = "Weedza Mystery Box",
793
794
  swipeHintText = "Swipe to open",
794
795
  boxOpeningText = "Box Opening...",
796
+ clickHintText = "Click to open",
797
+ hasChances = true,
795
798
  showMask = true,
796
799
  maskOpacity = 0.7,
797
800
  maskBlur = 8
@@ -1014,127 +1017,145 @@ function BagAnimation({
1014
1017
  setShowSwipeHint(true);
1015
1018
  }
1016
1019
  };
1017
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "flex w-full relative justify-center items-center", children: [
1018
- isAnimating && /* @__PURE__ */ jsxs(Fragment, { children: [
1019
- showMask && /* @__PURE__ */ jsx(
1020
- "div",
1020
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1021
+ !isAnimating && hasChances && /* @__PURE__ */ jsx("div", { className: "absolute top-8 left-[calc(50%-0px)] transform -translate-x-1/2 z-50 pointer-events-none", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center animate-bounce", children: [
1022
+ /* @__PURE__ */ jsx(
1023
+ "p",
1021
1024
  {
1022
- className: "fixed inset-0 z-[99]",
1023
- style: {
1024
- backgroundColor: `rgba(0, 0, 0, ${maskOpacity})`,
1025
- backdropFilter: `blur(${maskBlur}px)`,
1026
- WebkitBackdropFilter: `blur(${maskBlur}px)`
1027
- // Safari 支持
1028
- },
1029
- onClick: (e) => {
1030
- e.stopPropagation();
1031
- }
1025
+ className: "font-bold text-lg md:text-xl mb-1 drop-shadow-lg text-theme_gold",
1026
+ children: clickHintText
1032
1027
  }
1033
1028
  ),
1034
1029
  /* @__PURE__ */ jsx(
1035
- "div",
1030
+ ChevronDown,
1036
1031
  {
1037
- className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none",
1038
- style: { pointerEvents: "none" },
1039
- children: /* @__PURE__ */ jsxs(
1040
- "div",
1041
- {
1042
- className: "relative w-full max-w-[90vw] max-h-[90vh] flex items-center justify-center pointer-events-auto",
1043
- style: { pointerEvents: "auto" },
1044
- children: [
1045
- /* @__PURE__ */ jsx(
1046
- "canvas",
1047
- {
1048
- ref: canvasRef,
1049
- onMouseDown,
1050
- onMouseMove,
1051
- onMouseUp,
1052
- onMouseLeave: onMouseUp,
1053
- onTouchStart: (e) => {
1054
- if (isPausedAtThird && canvasRef.current) {
1055
- const touch = e.touches[0];
1056
- const rect = canvasRef.current.getBoundingClientRect();
1057
- const touchGap = touch.clientX - rect.left;
1058
- const initialProgress = Math.max(0, Math.min(100, touchGap / rect.width * 100));
1059
- setThirdFrameProgress(initialProgress);
1060
- setShowSwipeHint(false);
1061
- }
1062
- },
1063
- onTouchMove: (e) => {
1064
- if (!isPausedAtThird || !canvasRef.current || hasTriggeredFourthFrame.current) return;
1065
- const touch = e.touches[0];
1066
- const rect = canvasRef.current.getBoundingClientRect();
1067
- const relativeX = touch.clientX - rect.left;
1068
- const canvasWidth = rect.width;
1069
- const progress = Math.max(0, Math.min(100, relativeX / canvasWidth * 100));
1070
- setThirdFrameProgress(progress);
1071
- if (progress >= 95 && !hasTriggeredFourthFrame.current) {
1072
- hasTriggeredFourthFrame.current = true;
1073
- setIsPausedAtThird(false);
1074
- setThirdFrameProgress(0);
1075
- setFrame(3);
1076
- }
1077
- },
1078
- onTouchEnd: (e) => {
1079
- if (isPausedAtThird) {
1080
- e.preventDefault();
1081
- setThirdFrameProgress(0);
1082
- setShowSwipeHint(true);
1083
- }
1084
- },
1085
- className: "select-none cursor-pointer w-full h-full object-contain",
1086
- style: {
1087
- imageRendering: "pixelated",
1088
- cursor: isPausedAtThird ? "grab" : "pointer",
1089
- touchAction: "none",
1090
- // 防止默認觸摸行為
1091
- userSelect: "none",
1092
- // 防止選中
1093
- maxWidth: "100%",
1094
- maxHeight: "100%"
1095
- }
1096
- }
1097
- ),
1098
- isPausedAtThird && showSwipeHint && /* @__PURE__ */ jsx("div", { className: "absolute bottom-8 left-1/2 transform -translate-x-1/2 bg-black/70 text-white px-6 py-3 rounded-full text-sm md:text-base font-medium animate-pulse pointer-events-none z-20", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1032
+ className: "h-8 w-8 md:h-10 md:w-10 text-lime-500 drop-shadow-lg text-theme_gold",
1033
+ strokeWidth: 4
1034
+ }
1035
+ )
1036
+ ] }) }),
1037
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full relative justify-center items-center", children: [
1038
+ isAnimating && /* @__PURE__ */ jsxs(Fragment, { children: [
1039
+ showMask && /* @__PURE__ */ jsx(
1040
+ "div",
1041
+ {
1042
+ className: "fixed inset-0 z-[99]",
1043
+ style: {
1044
+ backgroundColor: `rgba(0, 0, 0, ${maskOpacity})`,
1045
+ backdropFilter: `blur(${maskBlur}px)`,
1046
+ WebkitBackdropFilter: `blur(${maskBlur}px)`
1047
+ // Safari 支持
1048
+ },
1049
+ onClick: (e) => {
1050
+ e.stopPropagation();
1051
+ }
1052
+ }
1053
+ ),
1054
+ /* @__PURE__ */ jsx(
1055
+ "div",
1056
+ {
1057
+ className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none",
1058
+ style: { pointerEvents: "none" },
1059
+ children: /* @__PURE__ */ jsxs(
1060
+ "div",
1061
+ {
1062
+ className: "relative w-full max-w-[90vw] max-h-[90vh] flex items-center justify-center pointer-events-auto",
1063
+ style: { pointerEvents: "auto" },
1064
+ children: [
1099
1065
  /* @__PURE__ */ jsx(
1100
- "svg",
1066
+ "canvas",
1101
1067
  {
1102
- className: "w-5 h-5 md:w-6 md:h-6",
1103
- fill: "none",
1104
- stroke: "currentColor",
1105
- viewBox: "0 0 24 24",
1106
- children: /* @__PURE__ */ jsx(
1107
- "path",
1108
- {
1109
- strokeLinecap: "round",
1110
- strokeLinejoin: "round",
1111
- strokeWidth: 2,
1112
- d: "M13 7l5 5m0 0l-5 5m5-5H6"
1068
+ ref: canvasRef,
1069
+ onMouseDown,
1070
+ onMouseMove,
1071
+ onMouseUp,
1072
+ onMouseLeave: onMouseUp,
1073
+ onTouchStart: (e) => {
1074
+ if (isPausedAtThird && canvasRef.current) {
1075
+ const touch = e.touches[0];
1076
+ const rect = canvasRef.current.getBoundingClientRect();
1077
+ const touchGap = touch.clientX - rect.left;
1078
+ const initialProgress = Math.max(0, Math.min(100, touchGap / rect.width * 100));
1079
+ setThirdFrameProgress(initialProgress);
1080
+ setShowSwipeHint(false);
1113
1081
  }
1114
- )
1082
+ },
1083
+ onTouchMove: (e) => {
1084
+ if (!isPausedAtThird || !canvasRef.current || hasTriggeredFourthFrame.current) return;
1085
+ const touch = e.touches[0];
1086
+ const rect = canvasRef.current.getBoundingClientRect();
1087
+ const relativeX = touch.clientX - rect.left;
1088
+ const canvasWidth = rect.width;
1089
+ const progress = Math.max(0, Math.min(100, relativeX / canvasWidth * 100));
1090
+ setThirdFrameProgress(progress);
1091
+ if (progress >= 95 && !hasTriggeredFourthFrame.current) {
1092
+ hasTriggeredFourthFrame.current = true;
1093
+ setIsPausedAtThird(false);
1094
+ setThirdFrameProgress(0);
1095
+ setFrame(3);
1096
+ }
1097
+ },
1098
+ onTouchEnd: (e) => {
1099
+ if (isPausedAtThird) {
1100
+ e.preventDefault();
1101
+ setThirdFrameProgress(0);
1102
+ setShowSwipeHint(true);
1103
+ }
1104
+ },
1105
+ className: "select-none cursor-pointer w-full h-full object-contain",
1106
+ style: {
1107
+ imageRendering: "pixelated",
1108
+ cursor: isPausedAtThird ? "grab" : "pointer",
1109
+ touchAction: "none",
1110
+ // 防止默認觸摸行為
1111
+ userSelect: "none",
1112
+ // 防止選中
1113
+ maxWidth: "100%",
1114
+ maxHeight: "100%"
1115
+ }
1115
1116
  }
1116
1117
  ),
1117
- /* @__PURE__ */ jsx("span", { children: swipeHintText })
1118
- ] }) })
1119
- ]
1120
- }
1121
- )
1118
+ isPausedAtThird && showSwipeHint && /* @__PURE__ */ jsx("div", { className: "absolute bottom-8 left-1/2 transform -translate-x-1/2 bg-black/70 text-white px-6 py-3 rounded-full text-sm md:text-base font-medium animate-pulse pointer-events-none z-20", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1119
+ /* @__PURE__ */ jsx(
1120
+ "svg",
1121
+ {
1122
+ className: "w-5 h-5 md:w-6 md:h-6",
1123
+ fill: "none",
1124
+ stroke: "currentColor",
1125
+ viewBox: "0 0 24 24",
1126
+ children: /* @__PURE__ */ jsx(
1127
+ "path",
1128
+ {
1129
+ strokeLinecap: "round",
1130
+ strokeLinejoin: "round",
1131
+ strokeWidth: 2,
1132
+ d: "M13 7l5 5m0 0l-5 5m5-5H6"
1133
+ }
1134
+ )
1135
+ }
1136
+ ),
1137
+ /* @__PURE__ */ jsx("span", { children: swipeHintText })
1138
+ ] }) })
1139
+ ]
1140
+ }
1141
+ )
1142
+ }
1143
+ ),
1144
+ /* @__PURE__ */ jsx("div", { className: "fixed z-[101] top-0 left-0 w-full h-[10%] flex justify-center items-center", children: /* @__PURE__ */ jsx("p", { className: "text-theme_gold animate-pulse text-sm md:text-base text-center z-[101]", children: boxOpeningText }) })
1145
+ ] }),
1146
+ /* @__PURE__ */ jsx(
1147
+ "img",
1148
+ {
1149
+ src: mysteryBoxImage,
1150
+ alt: mysteryBoxAlt,
1151
+ onClick: () => {
1152
+ setIsAnimating(true);
1153
+ },
1154
+ className: "w-36 h-36 md:w-96 md:h-96 object-contain relative z-10"
1122
1155
  }
1123
- ),
1124
- /* @__PURE__ */ jsx("div", { className: "fixed z-[101] top-0 left-0 w-full h-[10%] flex justify-center items-center", children: /* @__PURE__ */ jsx("p", { className: "text-theme_gold animate-pulse text-sm md:text-base text-center z-[101]", children: boxOpeningText }) })
1125
- ] }),
1126
- /* @__PURE__ */ jsx(
1127
- "img",
1128
- {
1129
- src: mysteryBoxImage,
1130
- alt: mysteryBoxAlt,
1131
- onClick: () => {
1132
- setIsAnimating(true);
1133
- },
1134
- className: "w-36 h-36 md:w-96 md:h-96 object-contain relative z-10"
1135
- }
1136
- )
1137
- ] }) });
1156
+ )
1157
+ ] })
1158
+ ] });
1138
1159
  }
1139
1160
  export {
1140
1161
  BagAnimation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chao-component/bag-animation-ui",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -37,17 +37,20 @@
37
37
  "react-dom": "^19.2.3"
38
38
  },
39
39
  "devDependencies": {
40
- "apng-js": "^1.1.5",
41
40
  "@types/react": "^19.2.7",
42
41
  "@types/react-dom": "^19.2.3",
43
- "tsup": "^8.5.1",
44
- "typescript": "^5.9.3",
45
- "vite": "^5.0.0",
46
42
  "@vitejs/plugin-react": "^4.2.0",
43
+ "apng-js": "^1.1.5",
44
+ "autoprefixer": "^10.4.0",
45
+ "postcss": "^8.4.0",
47
46
  "react": "^19.2.3",
48
47
  "react-dom": "^19.2.3",
49
48
  "tailwindcss": "^3.4.0",
50
- "postcss": "^8.4.0",
51
- "autoprefixer": "^10.4.0"
49
+ "tsup": "^8.5.1",
50
+ "typescript": "^5.9.3",
51
+ "vite": "^5.0.0"
52
+ },
53
+ "dependencies": {
54
+ "lucide-react": "^0.562.0"
52
55
  }
53
56
  }