virtual-ui-lib 1.0.70 → 1.0.72

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.js CHANGED
@@ -32,6 +32,7 @@ __export(index_exports, {
32
32
  AvatarCard: () => AvatarCard,
33
33
  BackgoundImageSlider: () => BackgoundImageSlider,
34
34
  Charts: () => Charts,
35
+ ColorPicker: () => ColorPicker,
35
36
  FileUpload: () => FileUpload,
36
37
  Footer: () => Footer,
37
38
  ImageCard: () => ImageCard,
@@ -43,6 +44,7 @@ __export(index_exports, {
43
44
  OTPInput: () => OTPInput,
44
45
  PageLoader: () => PageLoader,
45
46
  PricingCard: () => PricingCard,
47
+ RatingStars: () => RatingStars,
46
48
  Sidebar: () => Sidebar
47
49
  });
48
50
  module.exports = __toCommonJS(index_exports);
@@ -2758,11 +2760,362 @@ var FileUpload = ({
2758
2760
  } })));
2759
2761
  })));
2760
2762
  };
2763
+
2764
+ // src/components/ColorPicker/ColorPicker.jsx
2765
+ var import_react16 = __toESM(require("react"));
2766
+ var ColorPicker = ({
2767
+ defaultColor = "#6366f1",
2768
+ showOpacity = true,
2769
+ showEyedropper = true,
2770
+ showInput = true,
2771
+ accent = "#6366f1",
2772
+ bg = "#0f172a",
2773
+ radius = "16px",
2774
+ onChange = () => {
2775
+ },
2776
+ swatches = [
2777
+ "#6366f1",
2778
+ "#8b5cf6",
2779
+ "#a855f7",
2780
+ "#ec4899",
2781
+ "#f43f5e",
2782
+ "#ef4444",
2783
+ "#f97316",
2784
+ "#f59e0b",
2785
+ "#eab308",
2786
+ "#84cc16",
2787
+ "#22c55e",
2788
+ "#10b981",
2789
+ "#14b8a6",
2790
+ "#06b6d4",
2791
+ "#3b82f6",
2792
+ "#0ea5e9",
2793
+ "#64748b",
2794
+ "#94a3b8",
2795
+ "#ffffff",
2796
+ "#000000"
2797
+ ]
2798
+ }) => {
2799
+ const [color, setColor] = (0, import_react16.useState)(defaultColor);
2800
+ const [hex, setHex] = (0, import_react16.useState)(defaultColor);
2801
+ const [opacity, setOpacity] = (0, import_react16.useState)(100);
2802
+ const [inputErr, setInputErr] = (0, import_react16.useState)(false);
2803
+ const [copied, setCopied] = (0, import_react16.useState)(false);
2804
+ const alpha = (hexVal, op) => {
2805
+ const r = parseInt(hexVal.slice(1, 3), 16);
2806
+ const g = parseInt(hexVal.slice(3, 5), 16);
2807
+ const b = parseInt(hexVal.slice(5, 7), 16);
2808
+ return `rgba(${r},${g},${b},${op})`;
2809
+ };
2810
+ const isValidHex = (v) => /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(v);
2811
+ const applyColor = (val) => {
2812
+ if (!isValidHex(val)) {
2813
+ setInputErr(true);
2814
+ return;
2815
+ }
2816
+ setInputErr(false);
2817
+ setColor(val);
2818
+ setHex(val);
2819
+ onChange({ hex: val, opacity, rgba: alpha(val, opacity / 100) });
2820
+ };
2821
+ const pickSwatch = (val) => {
2822
+ setColor(val);
2823
+ setHex(val);
2824
+ setInputErr(false);
2825
+ onChange({ hex: val, opacity, rgba: alpha(val, opacity / 100) });
2826
+ };
2827
+ const handleOpacity = (v) => {
2828
+ setOpacity(v);
2829
+ onChange({ hex: color, opacity: v, rgba: alpha(color, v / 100) });
2830
+ };
2831
+ const copyHex = () => {
2832
+ var _a;
2833
+ (_a = navigator.clipboard) == null ? void 0 : _a.writeText(hex).catch(() => {
2834
+ });
2835
+ setCopied(true);
2836
+ setTimeout(() => setCopied(false), 1500);
2837
+ };
2838
+ const hueGradient = "linear-gradient(90deg,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)";
2839
+ return /* @__PURE__ */ import_react16.default.createElement("div", { style: {
2840
+ background: bg,
2841
+ borderRadius: radius,
2842
+ padding: "20px",
2843
+ width: "260px",
2844
+ fontFamily: "system-ui, sans-serif",
2845
+ border: "1px solid rgba(255,255,255,0.07)",
2846
+ boxShadow: "0 10px 40px rgba(0,0,0,0.4)"
2847
+ } }, /* @__PURE__ */ import_react16.default.createElement("div", { style: {
2848
+ height: "52px",
2849
+ borderRadius: "12px",
2850
+ marginBottom: "16px",
2851
+ background: alpha(color, opacity / 100),
2852
+ border: "1px solid rgba(255,255,255,0.08)",
2853
+ position: "relative",
2854
+ overflow: "hidden"
2855
+ } }, /* @__PURE__ */ import_react16.default.createElement("div", { style: {
2856
+ position: "absolute",
2857
+ inset: 0,
2858
+ zIndex: 0,
2859
+ backgroundImage: "linear-gradient(45deg,#555 25%,transparent 25%),linear-gradient(-45deg,#555 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#555 75%),linear-gradient(-45deg,transparent 75%,#555 75%)",
2860
+ backgroundSize: "10px 10px",
2861
+ backgroundPosition: "0 0,0 5px,5px -5px,-5px 0",
2862
+ opacity: 0.3
2863
+ } }), /* @__PURE__ */ import_react16.default.createElement("div", { style: { position: "absolute", inset: 0, background: alpha(color, opacity / 100) } })), /* @__PURE__ */ import_react16.default.createElement("div", { style: { position: "relative", marginBottom: "12px" } }, /* @__PURE__ */ import_react16.default.createElement(
2864
+ "input",
2865
+ {
2866
+ type: "range",
2867
+ min: "0",
2868
+ max: "360",
2869
+ defaultValue: "240",
2870
+ onChange: (e) => {
2871
+ const h = e.target.value;
2872
+ const c = `hsl(${h},80%,60%)`;
2873
+ const el = document.createElement("div");
2874
+ el.style.color = c;
2875
+ document.body.appendChild(el);
2876
+ const rgb = getComputedStyle(el).color;
2877
+ document.body.removeChild(el);
2878
+ const [r, g, b] = rgb.match(/\d+/g).map(Number);
2879
+ const hex6 = "#" + [r, g, b].map((n) => n.toString(16).padStart(2, "0")).join("");
2880
+ pickSwatch(hex6);
2881
+ },
2882
+ style: {
2883
+ width: "100%",
2884
+ height: "10px",
2885
+ borderRadius: "5px",
2886
+ appearance: "none",
2887
+ WebkitAppearance: "none",
2888
+ background: hueGradient,
2889
+ cursor: "pointer",
2890
+ outline: "none",
2891
+ border: "none"
2892
+ }
2893
+ }
2894
+ )), showOpacity && /* @__PURE__ */ import_react16.default.createElement("div", { style: { marginBottom: "16px" } }, /* @__PURE__ */ import_react16.default.createElement(
2895
+ "input",
2896
+ {
2897
+ type: "range",
2898
+ min: "0",
2899
+ max: "100",
2900
+ value: opacity,
2901
+ onChange: (e) => handleOpacity(Number(e.target.value)),
2902
+ style: {
2903
+ width: "100%",
2904
+ height: "10px",
2905
+ borderRadius: "5px",
2906
+ appearance: "none",
2907
+ WebkitAppearance: "none",
2908
+ background: `linear-gradient(90deg, transparent, ${color})`,
2909
+ cursor: "pointer",
2910
+ outline: "none",
2911
+ border: "none"
2912
+ }
2913
+ }
2914
+ ), /* @__PURE__ */ import_react16.default.createElement("div", { style: { display: "flex", justifyContent: "space-between", marginTop: "4px" } }, /* @__PURE__ */ import_react16.default.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.25)" } }, "Opacity"), /* @__PURE__ */ import_react16.default.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.45)", fontWeight: "600" } }, opacity, "%"))), showInput && /* @__PURE__ */ import_react16.default.createElement("div", { style: { display: "flex", gap: "8px", marginBottom: "16px", alignItems: "center" } }, /* @__PURE__ */ import_react16.default.createElement("div", { style: {
2915
+ width: "32px",
2916
+ height: "32px",
2917
+ borderRadius: "8px",
2918
+ flexShrink: 0,
2919
+ background: color,
2920
+ border: "1px solid rgba(255,255,255,0.1)"
2921
+ } }), /* @__PURE__ */ import_react16.default.createElement(
2922
+ "input",
2923
+ {
2924
+ value: hex,
2925
+ onChange: (e) => {
2926
+ setHex(e.target.value);
2927
+ setInputErr(false);
2928
+ },
2929
+ onBlur: (e) => applyColor(e.target.value),
2930
+ onKeyDown: (e) => e.key === "Enter" && applyColor(hex),
2931
+ placeholder: "#000000",
2932
+ style: {
2933
+ flex: 1,
2934
+ background: "rgba(255,255,255,0.05)",
2935
+ border: `1px solid ${inputErr ? "rgba(239,68,68,0.6)" : "rgba(255,255,255,0.1)"}`,
2936
+ borderRadius: "8px",
2937
+ padding: "7px 10px",
2938
+ fontSize: "12px",
2939
+ fontFamily: "monospace",
2940
+ color: inputErr ? "#f87171" : "#fff",
2941
+ outline: "none"
2942
+ }
2943
+ }
2944
+ ), /* @__PURE__ */ import_react16.default.createElement(
2945
+ "button",
2946
+ {
2947
+ onClick: copyHex,
2948
+ title: "Copy hex",
2949
+ style: {
2950
+ width: "32px",
2951
+ height: "32px",
2952
+ borderRadius: "8px",
2953
+ flexShrink: 0,
2954
+ background: copied ? "rgba(16,185,129,0.15)" : "rgba(255,255,255,0.05)",
2955
+ border: `1px solid ${copied ? "rgba(16,185,129,0.3)" : "rgba(255,255,255,0.1)"}`,
2956
+ cursor: "pointer",
2957
+ display: "flex",
2958
+ alignItems: "center",
2959
+ justifyContent: "center",
2960
+ color: copied ? "#34d399" : "rgba(255,255,255,0.4)",
2961
+ transition: "all 0.2s"
2962
+ }
2963
+ },
2964
+ copied ? /* @__PURE__ */ import_react16.default.createElement("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }, /* @__PURE__ */ import_react16.default.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ import_react16.default.createElement("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ import_react16.default.createElement("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }), /* @__PURE__ */ import_react16.default.createElement("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" }))
2965
+ )), /* @__PURE__ */ import_react16.default.createElement("div", { style: { height: "1px", background: "rgba(255,255,255,0.06)", marginBottom: "14px" } }), /* @__PURE__ */ import_react16.default.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: "7px" } }, swatches.map((s) => /* @__PURE__ */ import_react16.default.createElement(
2966
+ "button",
2967
+ {
2968
+ key: s,
2969
+ onClick: () => pickSwatch(s),
2970
+ title: s,
2971
+ style: {
2972
+ width: "22px",
2973
+ height: "22px",
2974
+ borderRadius: "6px",
2975
+ background: s,
2976
+ border: `2px solid ${color === s ? "#fff" : "transparent"}`,
2977
+ cursor: "pointer",
2978
+ padding: 0,
2979
+ transition: "transform 0.15s, border-color 0.15s",
2980
+ outline: "none",
2981
+ boxShadow: s === "#ffffff" ? "inset 0 0 0 1px rgba(0,0,0,0.15)" : "none"
2982
+ },
2983
+ onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.2)",
2984
+ onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)"
2985
+ }
2986
+ ))), /* @__PURE__ */ import_react16.default.createElement("div", { style: {
2987
+ marginTop: "14px",
2988
+ padding: "8px 10px",
2989
+ borderRadius: "8px",
2990
+ background: "rgba(255,255,255,0.03)",
2991
+ border: "1px solid rgba(255,255,255,0.06)",
2992
+ display: "flex",
2993
+ justifyContent: "space-between",
2994
+ alignItems: "center"
2995
+ } }, /* @__PURE__ */ import_react16.default.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.25)", fontWeight: "600", textTransform: "uppercase", letterSpacing: "0.5px" } }, "RGBA"), /* @__PURE__ */ import_react16.default.createElement("span", { style: { fontSize: "10px", fontFamily: "monospace", color: "rgba(255,255,255,0.5)" } }, alpha(color, opacity / 100))));
2996
+ };
2997
+
2998
+ // src/components/RatingStars/RatingStars.jsx
2999
+ var import_react17 = __toESM(require("react"));
3000
+ var RatingStars = ({
3001
+ defaultRating = 0,
3002
+ total = 5,
3003
+ size = 32,
3004
+ allowHalf = true,
3005
+ showLabel = true,
3006
+ showCount = true,
3007
+ reviewCount = 0,
3008
+ readOnly = false,
3009
+ accent = "#f59e0b",
3010
+ bg = "#0f172a",
3011
+ radius = "14px",
3012
+ onChange = () => {
3013
+ }
3014
+ }) => {
3015
+ const [rating, setRating] = (0, import_react17.useState)(defaultRating);
3016
+ const [hovered, setHovered] = (0, import_react17.useState)(0);
3017
+ const labels = ["", "Terrible", "Bad", "Okay", "Good", "Excellent"];
3018
+ const halfLabels = { 0.5: "Awful", 1: "Terrible", 1.5: "Very Bad", 2: "Bad", 2.5: "Below Average", 3: "Okay", 3.5: "Above Average", 4: "Good", 4.5: "Great", 5: "Excellent" };
3019
+ const alpha = (hex, op) => {
3020
+ const r = parseInt(hex.slice(1, 3), 16);
3021
+ const g = parseInt(hex.slice(3, 5), 16);
3022
+ const b = parseInt(hex.slice(5, 7), 16);
3023
+ return `rgba(${r},${g},${b},${op})`;
3024
+ };
3025
+ const active = hovered || rating;
3026
+ const handleMouseMove = (e, i) => {
3027
+ if (readOnly) return;
3028
+ if (allowHalf) {
3029
+ const rect = e.currentTarget.getBoundingClientRect();
3030
+ const half = e.clientX - rect.left < rect.width / 2;
3031
+ setHovered(half ? i - 0.5 : i);
3032
+ } else {
3033
+ setHovered(i);
3034
+ }
3035
+ };
3036
+ const handleClick = (e, i) => {
3037
+ if (readOnly) return;
3038
+ let val;
3039
+ if (allowHalf) {
3040
+ const rect = e.currentTarget.getBoundingClientRect();
3041
+ val = e.clientX - rect.left < rect.width / 2 ? i - 0.5 : i;
3042
+ } else {
3043
+ val = i;
3044
+ }
3045
+ setRating(val);
3046
+ onChange(val);
3047
+ };
3048
+ const StarIcon = ({ index }) => {
3049
+ const fill = active >= index ? "full" : active >= index - 0.5 ? "half" : "empty";
3050
+ const id = `half-${index}`;
3051
+ return /* @__PURE__ */ import_react17.default.createElement(
3052
+ "svg",
3053
+ {
3054
+ width: size,
3055
+ height: size,
3056
+ viewBox: "0 0 24 24",
3057
+ style: { cursor: readOnly ? "default" : "pointer", transition: "transform 0.1s", flexShrink: 0 },
3058
+ onMouseMove: (e) => handleMouseMove(e, index),
3059
+ onMouseLeave: () => !readOnly && setHovered(0),
3060
+ onClick: (e) => handleClick(e, index),
3061
+ onMouseEnter: (e) => {
3062
+ if (!readOnly) e.currentTarget.style.transform = "scale(1.15)";
3063
+ }
3064
+ },
3065
+ /* @__PURE__ */ import_react17.default.createElement("defs", null, /* @__PURE__ */ import_react17.default.createElement("linearGradient", { id }, /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: "transparent" }))),
3066
+ /* @__PURE__ */ import_react17.default.createElement(
3067
+ "polygon",
3068
+ {
3069
+ points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
3070
+ fill: fill === "full" ? accent : fill === "half" ? `url(#${id})` : "transparent",
3071
+ stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
3072
+ strokeWidth: "1.5"
3073
+ }
3074
+ )
3075
+ );
3076
+ };
3077
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: {
3078
+ background: bg,
3079
+ borderRadius: radius,
3080
+ padding: "20px 22px",
3081
+ display: "inline-flex",
3082
+ flexDirection: "column",
3083
+ alignItems: "center",
3084
+ gap: "12px",
3085
+ fontFamily: "system-ui, sans-serif",
3086
+ border: "1px solid rgba(255,255,255,0.07)",
3087
+ boxShadow: "0 10px 40px rgba(0,0,0,0.4)"
3088
+ } }, /* @__PURE__ */ import_react17.default.createElement("div", { style: { display: "flex", gap: "4px", alignItems: "center" } }, Array.from({ length: total }, (_, i) => /* @__PURE__ */ import_react17.default.createElement(StarIcon, { key: i + 1, index: i + 1 }))), showLabel && /* @__PURE__ */ import_react17.default.createElement("div", { style: {
3089
+ fontSize: "14px",
3090
+ fontWeight: "700",
3091
+ minHeight: "20px",
3092
+ color: active > 0 ? accent : "rgba(255,255,255,0.2)",
3093
+ transition: "color 0.2s"
3094
+ } }, active > 0 ? allowHalf ? halfLabels[active] : labels[Math.round(active)] : readOnly ? "Not rated" : "Rate this"), (rating > 0 || readOnly) && showCount && /* @__PURE__ */ import_react17.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3095
+ fontSize: "28px",
3096
+ fontWeight: "800",
3097
+ color: "#fff",
3098
+ lineHeight: 1
3099
+ } }, rating.toFixed(1)), /* @__PURE__ */ import_react17.default.createElement("div", null, /* @__PURE__ */ import_react17.default.createElement("div", { style: { display: "flex", gap: "1px", marginBottom: "3px" } }, Array.from({ length: total }, (_, i) => {
3100
+ const fill = rating >= i + 1 ? "full" : rating >= i + 0.5 ? "half" : "empty";
3101
+ const gid = `sm-${i}`;
3102
+ return /* @__PURE__ */ import_react17.default.createElement("svg", { key: i, width: "12", height: "12", viewBox: "0 0 24 24" }, /* @__PURE__ */ import_react17.default.createElement("defs", null, /* @__PURE__ */ import_react17.default.createElement("linearGradient", { id: gid }, /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ import_react17.default.createElement("stop", { offset: "50%", stopColor: "transparent" }))), /* @__PURE__ */ import_react17.default.createElement(
3103
+ "polygon",
3104
+ {
3105
+ points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
3106
+ fill: fill === "full" ? accent : fill === "half" ? `url(#${gid})` : "transparent",
3107
+ stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
3108
+ strokeWidth: "1.5"
3109
+ }
3110
+ ));
3111
+ })), reviewCount > 0 && /* @__PURE__ */ import_react17.default.createElement("span", { style: { fontSize: "11px", color: "rgba(255,255,255,0.3)" } }, reviewCount.toLocaleString(), " reviews"))), !readOnly && rating === 0 && /* @__PURE__ */ import_react17.default.createElement("p", { style: { fontSize: "11px", color: "rgba(255,255,255,0.2)", margin: 0 } }, allowHalf ? "Hover to rate \u2022 Half stars supported" : "Click to rate"));
3112
+ };
2761
3113
  // Annotate the CommonJS export names for ESM import in node:
2762
3114
  0 && (module.exports = {
2763
3115
  AvatarCard,
2764
3116
  BackgoundImageSlider,
2765
3117
  Charts,
3118
+ ColorPicker,
2766
3119
  FileUpload,
2767
3120
  Footer,
2768
3121
  ImageCard,
@@ -2774,5 +3127,6 @@ var FileUpload = ({
2774
3127
  OTPInput,
2775
3128
  PageLoader,
2776
3129
  PricingCard,
3130
+ RatingStars,
2777
3131
  Sidebar
2778
3132
  });
package/dist/index.mjs CHANGED
@@ -2709,10 +2709,361 @@ var FileUpload = ({
2709
2709
  } })));
2710
2710
  })));
2711
2711
  };
2712
+
2713
+ // src/components/ColorPicker/ColorPicker.jsx
2714
+ import React16, { useState as useState14 } from "react";
2715
+ var ColorPicker = ({
2716
+ defaultColor = "#6366f1",
2717
+ showOpacity = true,
2718
+ showEyedropper = true,
2719
+ showInput = true,
2720
+ accent = "#6366f1",
2721
+ bg = "#0f172a",
2722
+ radius = "16px",
2723
+ onChange = () => {
2724
+ },
2725
+ swatches = [
2726
+ "#6366f1",
2727
+ "#8b5cf6",
2728
+ "#a855f7",
2729
+ "#ec4899",
2730
+ "#f43f5e",
2731
+ "#ef4444",
2732
+ "#f97316",
2733
+ "#f59e0b",
2734
+ "#eab308",
2735
+ "#84cc16",
2736
+ "#22c55e",
2737
+ "#10b981",
2738
+ "#14b8a6",
2739
+ "#06b6d4",
2740
+ "#3b82f6",
2741
+ "#0ea5e9",
2742
+ "#64748b",
2743
+ "#94a3b8",
2744
+ "#ffffff",
2745
+ "#000000"
2746
+ ]
2747
+ }) => {
2748
+ const [color, setColor] = useState14(defaultColor);
2749
+ const [hex, setHex] = useState14(defaultColor);
2750
+ const [opacity, setOpacity] = useState14(100);
2751
+ const [inputErr, setInputErr] = useState14(false);
2752
+ const [copied, setCopied] = useState14(false);
2753
+ const alpha = (hexVal, op) => {
2754
+ const r = parseInt(hexVal.slice(1, 3), 16);
2755
+ const g = parseInt(hexVal.slice(3, 5), 16);
2756
+ const b = parseInt(hexVal.slice(5, 7), 16);
2757
+ return `rgba(${r},${g},${b},${op})`;
2758
+ };
2759
+ const isValidHex = (v) => /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(v);
2760
+ const applyColor = (val) => {
2761
+ if (!isValidHex(val)) {
2762
+ setInputErr(true);
2763
+ return;
2764
+ }
2765
+ setInputErr(false);
2766
+ setColor(val);
2767
+ setHex(val);
2768
+ onChange({ hex: val, opacity, rgba: alpha(val, opacity / 100) });
2769
+ };
2770
+ const pickSwatch = (val) => {
2771
+ setColor(val);
2772
+ setHex(val);
2773
+ setInputErr(false);
2774
+ onChange({ hex: val, opacity, rgba: alpha(val, opacity / 100) });
2775
+ };
2776
+ const handleOpacity = (v) => {
2777
+ setOpacity(v);
2778
+ onChange({ hex: color, opacity: v, rgba: alpha(color, v / 100) });
2779
+ };
2780
+ const copyHex = () => {
2781
+ var _a;
2782
+ (_a = navigator.clipboard) == null ? void 0 : _a.writeText(hex).catch(() => {
2783
+ });
2784
+ setCopied(true);
2785
+ setTimeout(() => setCopied(false), 1500);
2786
+ };
2787
+ const hueGradient = "linear-gradient(90deg,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)";
2788
+ return /* @__PURE__ */ React16.createElement("div", { style: {
2789
+ background: bg,
2790
+ borderRadius: radius,
2791
+ padding: "20px",
2792
+ width: "260px",
2793
+ fontFamily: "system-ui, sans-serif",
2794
+ border: "1px solid rgba(255,255,255,0.07)",
2795
+ boxShadow: "0 10px 40px rgba(0,0,0,0.4)"
2796
+ } }, /* @__PURE__ */ React16.createElement("div", { style: {
2797
+ height: "52px",
2798
+ borderRadius: "12px",
2799
+ marginBottom: "16px",
2800
+ background: alpha(color, opacity / 100),
2801
+ border: "1px solid rgba(255,255,255,0.08)",
2802
+ position: "relative",
2803
+ overflow: "hidden"
2804
+ } }, /* @__PURE__ */ React16.createElement("div", { style: {
2805
+ position: "absolute",
2806
+ inset: 0,
2807
+ zIndex: 0,
2808
+ backgroundImage: "linear-gradient(45deg,#555 25%,transparent 25%),linear-gradient(-45deg,#555 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#555 75%),linear-gradient(-45deg,transparent 75%,#555 75%)",
2809
+ backgroundSize: "10px 10px",
2810
+ backgroundPosition: "0 0,0 5px,5px -5px,-5px 0",
2811
+ opacity: 0.3
2812
+ } }), /* @__PURE__ */ React16.createElement("div", { style: { position: "absolute", inset: 0, background: alpha(color, opacity / 100) } })), /* @__PURE__ */ React16.createElement("div", { style: { position: "relative", marginBottom: "12px" } }, /* @__PURE__ */ React16.createElement(
2813
+ "input",
2814
+ {
2815
+ type: "range",
2816
+ min: "0",
2817
+ max: "360",
2818
+ defaultValue: "240",
2819
+ onChange: (e) => {
2820
+ const h = e.target.value;
2821
+ const c = `hsl(${h},80%,60%)`;
2822
+ const el = document.createElement("div");
2823
+ el.style.color = c;
2824
+ document.body.appendChild(el);
2825
+ const rgb = getComputedStyle(el).color;
2826
+ document.body.removeChild(el);
2827
+ const [r, g, b] = rgb.match(/\d+/g).map(Number);
2828
+ const hex6 = "#" + [r, g, b].map((n) => n.toString(16).padStart(2, "0")).join("");
2829
+ pickSwatch(hex6);
2830
+ },
2831
+ style: {
2832
+ width: "100%",
2833
+ height: "10px",
2834
+ borderRadius: "5px",
2835
+ appearance: "none",
2836
+ WebkitAppearance: "none",
2837
+ background: hueGradient,
2838
+ cursor: "pointer",
2839
+ outline: "none",
2840
+ border: "none"
2841
+ }
2842
+ }
2843
+ )), showOpacity && /* @__PURE__ */ React16.createElement("div", { style: { marginBottom: "16px" } }, /* @__PURE__ */ React16.createElement(
2844
+ "input",
2845
+ {
2846
+ type: "range",
2847
+ min: "0",
2848
+ max: "100",
2849
+ value: opacity,
2850
+ onChange: (e) => handleOpacity(Number(e.target.value)),
2851
+ style: {
2852
+ width: "100%",
2853
+ height: "10px",
2854
+ borderRadius: "5px",
2855
+ appearance: "none",
2856
+ WebkitAppearance: "none",
2857
+ background: `linear-gradient(90deg, transparent, ${color})`,
2858
+ cursor: "pointer",
2859
+ outline: "none",
2860
+ border: "none"
2861
+ }
2862
+ }
2863
+ ), /* @__PURE__ */ React16.createElement("div", { style: { display: "flex", justifyContent: "space-between", marginTop: "4px" } }, /* @__PURE__ */ React16.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.25)" } }, "Opacity"), /* @__PURE__ */ React16.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.45)", fontWeight: "600" } }, opacity, "%"))), showInput && /* @__PURE__ */ React16.createElement("div", { style: { display: "flex", gap: "8px", marginBottom: "16px", alignItems: "center" } }, /* @__PURE__ */ React16.createElement("div", { style: {
2864
+ width: "32px",
2865
+ height: "32px",
2866
+ borderRadius: "8px",
2867
+ flexShrink: 0,
2868
+ background: color,
2869
+ border: "1px solid rgba(255,255,255,0.1)"
2870
+ } }), /* @__PURE__ */ React16.createElement(
2871
+ "input",
2872
+ {
2873
+ value: hex,
2874
+ onChange: (e) => {
2875
+ setHex(e.target.value);
2876
+ setInputErr(false);
2877
+ },
2878
+ onBlur: (e) => applyColor(e.target.value),
2879
+ onKeyDown: (e) => e.key === "Enter" && applyColor(hex),
2880
+ placeholder: "#000000",
2881
+ style: {
2882
+ flex: 1,
2883
+ background: "rgba(255,255,255,0.05)",
2884
+ border: `1px solid ${inputErr ? "rgba(239,68,68,0.6)" : "rgba(255,255,255,0.1)"}`,
2885
+ borderRadius: "8px",
2886
+ padding: "7px 10px",
2887
+ fontSize: "12px",
2888
+ fontFamily: "monospace",
2889
+ color: inputErr ? "#f87171" : "#fff",
2890
+ outline: "none"
2891
+ }
2892
+ }
2893
+ ), /* @__PURE__ */ React16.createElement(
2894
+ "button",
2895
+ {
2896
+ onClick: copyHex,
2897
+ title: "Copy hex",
2898
+ style: {
2899
+ width: "32px",
2900
+ height: "32px",
2901
+ borderRadius: "8px",
2902
+ flexShrink: 0,
2903
+ background: copied ? "rgba(16,185,129,0.15)" : "rgba(255,255,255,0.05)",
2904
+ border: `1px solid ${copied ? "rgba(16,185,129,0.3)" : "rgba(255,255,255,0.1)"}`,
2905
+ cursor: "pointer",
2906
+ display: "flex",
2907
+ alignItems: "center",
2908
+ justifyContent: "center",
2909
+ color: copied ? "#34d399" : "rgba(255,255,255,0.4)",
2910
+ transition: "all 0.2s"
2911
+ }
2912
+ },
2913
+ copied ? /* @__PURE__ */ React16.createElement("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }, /* @__PURE__ */ React16.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ React16.createElement("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ React16.createElement("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }), /* @__PURE__ */ React16.createElement("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" }))
2914
+ )), /* @__PURE__ */ React16.createElement("div", { style: { height: "1px", background: "rgba(255,255,255,0.06)", marginBottom: "14px" } }), /* @__PURE__ */ React16.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: "7px" } }, swatches.map((s) => /* @__PURE__ */ React16.createElement(
2915
+ "button",
2916
+ {
2917
+ key: s,
2918
+ onClick: () => pickSwatch(s),
2919
+ title: s,
2920
+ style: {
2921
+ width: "22px",
2922
+ height: "22px",
2923
+ borderRadius: "6px",
2924
+ background: s,
2925
+ border: `2px solid ${color === s ? "#fff" : "transparent"}`,
2926
+ cursor: "pointer",
2927
+ padding: 0,
2928
+ transition: "transform 0.15s, border-color 0.15s",
2929
+ outline: "none",
2930
+ boxShadow: s === "#ffffff" ? "inset 0 0 0 1px rgba(0,0,0,0.15)" : "none"
2931
+ },
2932
+ onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.2)",
2933
+ onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)"
2934
+ }
2935
+ ))), /* @__PURE__ */ React16.createElement("div", { style: {
2936
+ marginTop: "14px",
2937
+ padding: "8px 10px",
2938
+ borderRadius: "8px",
2939
+ background: "rgba(255,255,255,0.03)",
2940
+ border: "1px solid rgba(255,255,255,0.06)",
2941
+ display: "flex",
2942
+ justifyContent: "space-between",
2943
+ alignItems: "center"
2944
+ } }, /* @__PURE__ */ React16.createElement("span", { style: { fontSize: "10px", color: "rgba(255,255,255,0.25)", fontWeight: "600", textTransform: "uppercase", letterSpacing: "0.5px" } }, "RGBA"), /* @__PURE__ */ React16.createElement("span", { style: { fontSize: "10px", fontFamily: "monospace", color: "rgba(255,255,255,0.5)" } }, alpha(color, opacity / 100))));
2945
+ };
2946
+
2947
+ // src/components/RatingStars/RatingStars.jsx
2948
+ import React17, { useState as useState15 } from "react";
2949
+ var RatingStars = ({
2950
+ defaultRating = 0,
2951
+ total = 5,
2952
+ size = 32,
2953
+ allowHalf = true,
2954
+ showLabel = true,
2955
+ showCount = true,
2956
+ reviewCount = 0,
2957
+ readOnly = false,
2958
+ accent = "#f59e0b",
2959
+ bg = "#0f172a",
2960
+ radius = "14px",
2961
+ onChange = () => {
2962
+ }
2963
+ }) => {
2964
+ const [rating, setRating] = useState15(defaultRating);
2965
+ const [hovered, setHovered] = useState15(0);
2966
+ const labels = ["", "Terrible", "Bad", "Okay", "Good", "Excellent"];
2967
+ const halfLabels = { 0.5: "Awful", 1: "Terrible", 1.5: "Very Bad", 2: "Bad", 2.5: "Below Average", 3: "Okay", 3.5: "Above Average", 4: "Good", 4.5: "Great", 5: "Excellent" };
2968
+ const alpha = (hex, op) => {
2969
+ const r = parseInt(hex.slice(1, 3), 16);
2970
+ const g = parseInt(hex.slice(3, 5), 16);
2971
+ const b = parseInt(hex.slice(5, 7), 16);
2972
+ return `rgba(${r},${g},${b},${op})`;
2973
+ };
2974
+ const active = hovered || rating;
2975
+ const handleMouseMove = (e, i) => {
2976
+ if (readOnly) return;
2977
+ if (allowHalf) {
2978
+ const rect = e.currentTarget.getBoundingClientRect();
2979
+ const half = e.clientX - rect.left < rect.width / 2;
2980
+ setHovered(half ? i - 0.5 : i);
2981
+ } else {
2982
+ setHovered(i);
2983
+ }
2984
+ };
2985
+ const handleClick = (e, i) => {
2986
+ if (readOnly) return;
2987
+ let val;
2988
+ if (allowHalf) {
2989
+ const rect = e.currentTarget.getBoundingClientRect();
2990
+ val = e.clientX - rect.left < rect.width / 2 ? i - 0.5 : i;
2991
+ } else {
2992
+ val = i;
2993
+ }
2994
+ setRating(val);
2995
+ onChange(val);
2996
+ };
2997
+ const StarIcon = ({ index }) => {
2998
+ const fill = active >= index ? "full" : active >= index - 0.5 ? "half" : "empty";
2999
+ const id = `half-${index}`;
3000
+ return /* @__PURE__ */ React17.createElement(
3001
+ "svg",
3002
+ {
3003
+ width: size,
3004
+ height: size,
3005
+ viewBox: "0 0 24 24",
3006
+ style: { cursor: readOnly ? "default" : "pointer", transition: "transform 0.1s", flexShrink: 0 },
3007
+ onMouseMove: (e) => handleMouseMove(e, index),
3008
+ onMouseLeave: () => !readOnly && setHovered(0),
3009
+ onClick: (e) => handleClick(e, index),
3010
+ onMouseEnter: (e) => {
3011
+ if (!readOnly) e.currentTarget.style.transform = "scale(1.15)";
3012
+ }
3013
+ },
3014
+ /* @__PURE__ */ React17.createElement("defs", null, /* @__PURE__ */ React17.createElement("linearGradient", { id }, /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: "transparent" }))),
3015
+ /* @__PURE__ */ React17.createElement(
3016
+ "polygon",
3017
+ {
3018
+ points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
3019
+ fill: fill === "full" ? accent : fill === "half" ? `url(#${id})` : "transparent",
3020
+ stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
3021
+ strokeWidth: "1.5"
3022
+ }
3023
+ )
3024
+ );
3025
+ };
3026
+ return /* @__PURE__ */ React17.createElement("div", { style: {
3027
+ background: bg,
3028
+ borderRadius: radius,
3029
+ padding: "20px 22px",
3030
+ display: "inline-flex",
3031
+ flexDirection: "column",
3032
+ alignItems: "center",
3033
+ gap: "12px",
3034
+ fontFamily: "system-ui, sans-serif",
3035
+ border: "1px solid rgba(255,255,255,0.07)",
3036
+ boxShadow: "0 10px 40px rgba(0,0,0,0.4)"
3037
+ } }, /* @__PURE__ */ React17.createElement("div", { style: { display: "flex", gap: "4px", alignItems: "center" } }, Array.from({ length: total }, (_, i) => /* @__PURE__ */ React17.createElement(StarIcon, { key: i + 1, index: i + 1 }))), showLabel && /* @__PURE__ */ React17.createElement("div", { style: {
3038
+ fontSize: "14px",
3039
+ fontWeight: "700",
3040
+ minHeight: "20px",
3041
+ color: active > 0 ? accent : "rgba(255,255,255,0.2)",
3042
+ transition: "color 0.2s"
3043
+ } }, active > 0 ? allowHalf ? halfLabels[active] : labels[Math.round(active)] : readOnly ? "Not rated" : "Rate this"), (rating > 0 || readOnly) && showCount && /* @__PURE__ */ React17.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ React17.createElement("span", { style: {
3044
+ fontSize: "28px",
3045
+ fontWeight: "800",
3046
+ color: "#fff",
3047
+ lineHeight: 1
3048
+ } }, rating.toFixed(1)), /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { style: { display: "flex", gap: "1px", marginBottom: "3px" } }, Array.from({ length: total }, (_, i) => {
3049
+ const fill = rating >= i + 1 ? "full" : rating >= i + 0.5 ? "half" : "empty";
3050
+ const gid = `sm-${i}`;
3051
+ return /* @__PURE__ */ React17.createElement("svg", { key: i, width: "12", height: "12", viewBox: "0 0 24 24" }, /* @__PURE__ */ React17.createElement("defs", null, /* @__PURE__ */ React17.createElement("linearGradient", { id: gid }, /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: accent }), /* @__PURE__ */ React17.createElement("stop", { offset: "50%", stopColor: "transparent" }))), /* @__PURE__ */ React17.createElement(
3052
+ "polygon",
3053
+ {
3054
+ points: "12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26",
3055
+ fill: fill === "full" ? accent : fill === "half" ? `url(#${gid})` : "transparent",
3056
+ stroke: fill === "empty" ? "rgba(255,255,255,0.15)" : accent,
3057
+ strokeWidth: "1.5"
3058
+ }
3059
+ ));
3060
+ })), reviewCount > 0 && /* @__PURE__ */ React17.createElement("span", { style: { fontSize: "11px", color: "rgba(255,255,255,0.3)" } }, reviewCount.toLocaleString(), " reviews"))), !readOnly && rating === 0 && /* @__PURE__ */ React17.createElement("p", { style: { fontSize: "11px", color: "rgba(255,255,255,0.2)", margin: 0 } }, allowHalf ? "Hover to rate \u2022 Half stars supported" : "Click to rate"));
3061
+ };
2712
3062
  export {
2713
3063
  AvatarCard,
2714
3064
  BackgoundImageSlider,
2715
3065
  Charts,
3066
+ ColorPicker,
2716
3067
  FileUpload,
2717
3068
  Footer,
2718
3069
  ImageCard,
@@ -2724,5 +3075,6 @@ export {
2724
3075
  OTPInput,
2725
3076
  PageLoader,
2726
3077
  PricingCard,
3078
+ RatingStars,
2727
3079
  Sidebar
2728
3080
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtual-ui-lib",
3
- "version": "1.0.70",
3
+ "version": "1.0.72",
4
4
  "description": "Virtual UI React Component Library",
5
5
  "author": "Ankush",
6
6
  "license": "ISC",