uibee 3.2.0 → 3.3.1

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.
Files changed (162) hide show
  1. package/dist/components/alert/alert.d.ts +15 -0
  2. package/dist/components/alert/alert.js +29 -0
  3. package/dist/components/badge/badge.d.ts +16 -0
  4. package/dist/components/badge/badge.js +26 -0
  5. package/dist/components/buttons/button.d.ts +25 -0
  6. package/dist/components/buttons/button.js +44 -0
  7. package/dist/components/code/code.d.ts +23 -0
  8. package/dist/components/code/code.js +39 -0
  9. package/dist/components/confirm/confirmPopup.d.ts +23 -0
  10. package/dist/components/confirm/confirmPopup.js +52 -0
  11. package/dist/components/container/accordion.d.ts +25 -0
  12. package/dist/components/container/accordion.js +41 -0
  13. package/dist/components/container/card.d.ts +13 -0
  14. package/dist/components/container/card.js +10 -0
  15. package/dist/components/container/expandableCard.d.ts +32 -0
  16. package/dist/components/container/expandableCard.js +70 -0
  17. package/dist/components/container/glassCard.d.ts +13 -0
  18. package/dist/components/container/glassCard.js +10 -0
  19. package/dist/components/container/highlight.d.ts +10 -0
  20. package/dist/components/container/highlight.js +10 -0
  21. package/dist/components/container/iconBubble.d.ts +25 -0
  22. package/dist/components/container/iconBubble.js +21 -0
  23. package/dist/components/container/leftBarPanel.d.ts +15 -0
  24. package/dist/components/container/leftBarPanel.js +10 -0
  25. package/dist/components/container/page.d.ts +15 -0
  26. package/dist/components/container/page.js +16 -0
  27. package/dist/components/container/pulseDot.d.ts +12 -0
  28. package/dist/components/container/pulseDot.js +23 -0
  29. package/dist/components/container/statCard.d.ts +18 -0
  30. package/dist/components/container/statCard.js +25 -0
  31. package/dist/components/container/tabs.d.ts +35 -0
  32. package/dist/components/container/tabs.js +36 -0
  33. package/dist/components/empty/emptyState.d.ts +19 -0
  34. package/dist/components/empty/emptyState.js +27 -0
  35. package/dist/components/footer/footer.d.ts +49 -0
  36. package/dist/components/footer/footer.js +109 -0
  37. package/dist/components/footer/loginContent.d.ts +18 -0
  38. package/dist/components/footer/loginContent.js +138 -0
  39. package/dist/components/inputs/checkbox.d.ts +20 -0
  40. package/dist/components/inputs/checkbox.js +76 -0
  41. package/dist/components/inputs/fileInput.d.ts +19 -0
  42. package/dist/components/inputs/fileInput.js +108 -0
  43. package/dist/components/inputs/input.d.ts +16 -0
  44. package/dist/components/inputs/input.js +157 -0
  45. package/dist/components/inputs/multiSelect.d.ts +37 -0
  46. package/dist/components/inputs/multiSelect.js +99 -0
  47. package/dist/components/inputs/radio.d.ts +20 -0
  48. package/dist/components/inputs/radio.js +70 -0
  49. package/dist/components/inputs/range.d.ts +14 -0
  50. package/dist/components/inputs/range.js +60 -0
  51. package/dist/components/inputs/searchInput.d.ts +11 -0
  52. package/dist/components/inputs/searchInput.js +56 -0
  53. package/dist/components/inputs/select.d.ts +42 -0
  54. package/dist/components/inputs/select.js +164 -0
  55. package/dist/components/inputs/shared/colorPickerPopup.js +293 -0
  56. package/dist/components/inputs/shared/dateTimePickerPopup.js +225 -0
  57. package/dist/components/inputs/shared/fieldWrapper.js +33 -0
  58. package/dist/components/inputs/shared/index.js +6 -0
  59. package/dist/components/inputs/shared/inputError.js +17 -0
  60. package/dist/components/inputs/shared/inputInfo.js +13 -0
  61. package/dist/components/inputs/shared/inputLabel.js +19 -0
  62. package/dist/components/inputs/switch.d.ts +14 -0
  63. package/dist/components/inputs/switch.js +37 -0
  64. package/dist/components/inputs/tagInput.d.ts +31 -0
  65. package/dist/components/inputs/tagInput.js +72 -0
  66. package/dist/components/inputs/textarea.d.ts +14 -0
  67. package/dist/components/inputs/textarea.js +76 -0
  68. package/dist/components/inputs/toggle.d.ts +21 -0
  69. package/dist/components/inputs/toggle.js +33 -0
  70. package/dist/components/login/loginPage.d.ts +15 -0
  71. package/dist/components/login/loginPage.js +80 -0
  72. package/dist/components/logo/logo.d.ts +9 -0
  73. package/dist/components/logo/logo.js +138 -0
  74. package/dist/components/logo/logoSmall.d.ts +4 -0
  75. package/dist/components/logo/logoSmall.js +56 -0
  76. package/dist/components/markdownrender/markdownRender.d.ts +16 -0
  77. package/dist/components/markdownrender/markdownRender.js +59 -0
  78. package/dist/components/modal/modal.d.ts +22 -0
  79. package/dist/components/modal/modal.js +59 -0
  80. package/dist/components/navbar/bubble.js +36 -0
  81. package/dist/components/navbar/navbar.d.ts +50 -0
  82. package/dist/components/navbar/navbar.js +99 -0
  83. package/dist/components/navbar/navbarDropdown.d.ts +15 -0
  84. package/dist/components/navbar/navbarDropdown.js +63 -0
  85. package/dist/components/navbar/navbarItem.d.ts +23 -0
  86. package/dist/components/navbar/navbarItem.js +38 -0
  87. package/dist/components/sidebar/sidebar.d.ts +34 -0
  88. package/dist/components/sidebar/sidebar.js +135 -0
  89. package/dist/components/spinner/spinner.d.ts +11 -0
  90. package/dist/components/spinner/spinner.js +16 -0
  91. package/dist/components/table/body.js +253 -0
  92. package/dist/components/table/constants.js +58 -0
  93. package/dist/components/table/empty.js +24 -0
  94. package/dist/components/table/format.js +39 -0
  95. package/dist/components/table/header.js +109 -0
  96. package/dist/components/table/menu.d.ts +18 -0
  97. package/dist/components/table/menu.js +76 -0
  98. package/dist/components/table/pagination.d.ts +14 -0
  99. package/dist/components/table/pagination.js +130 -0
  100. package/dist/components/table/skeleton.js +39 -0
  101. package/dist/components/table/table.d.ts +7 -0
  102. package/dist/components/table/table.js +213 -0
  103. package/dist/components/table/types.d.ts +52 -0
  104. package/dist/components/table/utils.js +9 -0
  105. package/dist/components/toast/toastItem.js +61 -0
  106. package/dist/components/toast/toaster.d.ts +13 -0
  107. package/dist/components/toast/toaster.js +117 -0
  108. package/dist/components/toggle/language.d.ts +10 -0
  109. package/dist/components/toggle/language.js +34 -0
  110. package/dist/components/toggle/theme.d.ts +8 -0
  111. package/dist/components/toggle/theme.js +135 -0
  112. package/dist/components/version/version.d.ts +13 -0
  113. package/dist/components/version/version.js +19 -0
  114. package/dist/components/vulnerability/constants.d.ts +4 -0
  115. package/dist/components/vulnerability/constants.js +17 -0
  116. package/dist/components/vulnerability/severityPill.d.ts +15 -0
  117. package/dist/components/vulnerability/severityPill.js +20 -0
  118. package/dist/{style.css → globals.css} +155 -226
  119. package/dist/hooks/useClickOutside.d.ts +6 -0
  120. package/dist/{useClickOutside-Cmp-RsP3.js → hooks/useClickOutside.js} +1 -1
  121. package/dist/hooks/useDarkMode.d.ts +4 -0
  122. package/dist/hooks/useDarkMode.js +19 -0
  123. package/dist/hooks/useVisibility.d.ts +7 -0
  124. package/dist/hooks/useVisibility.js +25 -0
  125. package/dist/icons/icons.d.ts +420 -0
  126. package/dist/{icons-lZYQ6Vlr.js → icons/icons.js} +1 -1
  127. package/dist/src/components/index.d.ts +51 -901
  128. package/dist/src/components/index.js +49 -4160
  129. package/dist/src/hooks/index.d.ts +3 -14
  130. package/dist/src/hooks/index.js +3 -42
  131. package/dist/src/icons/index.d.ts +1 -419
  132. package/dist/src/icons/index.js +1 -1
  133. package/dist/src/styles/index.js +1 -1
  134. package/dist/src/utils/index.d.ts +5 -37
  135. package/dist/src/utils/index.js +5 -124
  136. package/dist/utils/auth/callback.d.ts +14 -0
  137. package/dist/utils/auth/callback.js +53 -0
  138. package/dist/utils/auth/getDomain.js +6 -0
  139. package/dist/utils/auth/login.d.ts +12 -0
  140. package/dist/utils/auth/login.js +17 -0
  141. package/dist/utils/auth/logout.d.ts +10 -0
  142. package/dist/utils/auth/logout.js +20 -0
  143. package/dist/utils/auth/token.d.ts +10 -0
  144. package/dist/utils/auth/token.js +30 -0
  145. package/dist/utils/logoConsoleOutput/logoConsoleOutput.d.ts +4 -0
  146. package/dist/utils/logoConsoleOutput/logoConsoleOutput.js +11 -0
  147. package/package.json +1 -1
  148. package/src/components/buttons/button.tsx +2 -0
  149. package/src/components/footer/footer.tsx +65 -28
  150. package/src/components/index.ts +0 -1
  151. package/src/components/inputs/checkbox.tsx +2 -0
  152. package/src/components/inputs/input.tsx +2 -0
  153. package/src/components/inputs/radio.tsx +2 -0
  154. package/src/components/inputs/range.tsx +2 -0
  155. package/src/components/inputs/shared/colorPickerPopup.tsx +2 -0
  156. package/src/components/inputs/shared/dateTimePickerPopup.tsx +2 -0
  157. package/src/components/inputs/textarea.tsx +2 -0
  158. package/src/components/inputs/toggle.tsx +2 -0
  159. package/src/components/sidebar/sidebar.tsx +37 -10
  160. package/src/components/toast/toastItem.tsx +2 -0
  161. package/src/globals.css +6 -1
  162. package/tsdown.config.ts +1 -0
@@ -0,0 +1,42 @@
1
+ //#region src/components/inputs/select.d.ts
2
+ type Option = {
3
+ value: string | number;
4
+ label: string;
5
+ image?: string;
6
+ };
7
+ type SelectProps = {
8
+ label?: string;
9
+ name: string;
10
+ value?: string | number | null;
11
+ onChange?: (value: string | number | null) => void;
12
+ options: Option[];
13
+ error?: string;
14
+ className?: string;
15
+ disabled?: boolean;
16
+ required?: boolean;
17
+ placeholder?: string;
18
+ info?: string;
19
+ description?: string;
20
+ clearable?: boolean;
21
+ searchable?: boolean;
22
+ textSize?: 'sm' | 'md';
23
+ };
24
+ declare function Select({
25
+ label,
26
+ name,
27
+ value,
28
+ onChange,
29
+ options,
30
+ error,
31
+ className,
32
+ disabled,
33
+ required,
34
+ placeholder,
35
+ info,
36
+ description,
37
+ clearable,
38
+ searchable,
39
+ textSize
40
+ }: SelectProps): import("react").JSX.Element;
41
+ //#endregion
42
+ export { Option, SelectProps, Select as default };
@@ -0,0 +1,164 @@
1
+ "use client";
2
+ import FieldWrapper from "./shared/fieldWrapper.js";
3
+ import "./shared/index.js";
4
+ import useClickOutside from "../../hooks/useClickOutside.js";
5
+ import { useEffect, useRef, useState } from "react";
6
+ import { ChevronDown, Search, X } from "lucide-react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import Image from "next/image.js";
9
+ //#region src/components/inputs/select.tsx
10
+ function Select({ label, name, value, onChange, options, error, className, disabled, required, placeholder = "Select an option", info, description, clearable = true, searchable = true, textSize = "sm" }) {
11
+ const [isOpen, setIsOpen] = useState(false);
12
+ const [searchTerm, setSearchTerm] = useState("");
13
+ const [selectedOption, setSelectedOption] = useState(options.find((opt) => opt.value === value));
14
+ useEffect(() => {
15
+ if (!isOpen) setSearchTerm("");
16
+ }, [isOpen]);
17
+ useEffect(() => {
18
+ setSelectedOption(options.find((opt) => opt.value === value));
19
+ }, [value, options]);
20
+ const containerRef = useRef(null);
21
+ useClickOutside(containerRef, () => setIsOpen(false));
22
+ function handleSelect(option) {
23
+ if (disabled) return;
24
+ setSelectedOption(option);
25
+ setIsOpen(false);
26
+ if (onChange) onChange(option.value);
27
+ }
28
+ function handleClear(e) {
29
+ e.stopPropagation();
30
+ if (disabled) return;
31
+ setSelectedOption(void 0);
32
+ if (onChange) onChange(null);
33
+ }
34
+ const filteredOptions = options.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()));
35
+ return /* @__PURE__ */ jsxs(FieldWrapper, {
36
+ label,
37
+ name,
38
+ required,
39
+ info,
40
+ description,
41
+ error,
42
+ textSize,
43
+ className,
44
+ children: [/* @__PURE__ */ jsxs("div", {
45
+ className: "relative",
46
+ ref: containerRef,
47
+ children: [/* @__PURE__ */ jsxs("button", {
48
+ type: "button",
49
+ onClick: () => !disabled && setIsOpen(!isOpen),
50
+ disabled,
51
+ "aria-haspopup": "listbox",
52
+ "aria-expanded": isOpen,
53
+ "aria-labelledby": label ? void 0 : name,
54
+ className: `
55
+ w-full rounded-md bg-login-500/50 border border-login-500
56
+ text-login-text text-left text-sm
57
+ focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
58
+ disabled:opacity-40 disabled:cursor-not-allowed
59
+ h-10 py-2 pl-3 pr-10
60
+ transition-all duration-150
61
+ flex items-center justify-between
62
+ ${error ? "border-red-500/70 focus:border-red-500/70 focus:ring-red-500/30" : ""}
63
+ ${!selectedOption ? "text-login-200" : ""}
64
+ `,
65
+ title: label,
66
+ children: [/* @__PURE__ */ jsxs("div", {
67
+ className: "flex items-center gap-2 truncate",
68
+ children: [selectedOption?.image && /* @__PURE__ */ jsx(Image, {
69
+ src: selectedOption.image,
70
+ alt: "",
71
+ width: 30,
72
+ height: 20,
73
+ className: "rounded-xs object-cover shrink-0"
74
+ }), /* @__PURE__ */ jsx("span", {
75
+ className: "truncate",
76
+ children: selectedOption ? selectedOption.label : placeholder
77
+ })]
78
+ }), /* @__PURE__ */ jsxs("div", {
79
+ className: "absolute inset-y-0 right-0 flex items-center px-2 gap-1",
80
+ children: [clearable && selectedOption && !disabled && /* @__PURE__ */ jsx("div", {
81
+ role: "button",
82
+ onClick: handleClear,
83
+ className: `
84
+ p-1 hover:bg-login-500 rounded-full text-login-200
85
+ hover:text-red-400 transition-colors cursor-pointer
86
+ `,
87
+ title: "Clear selection",
88
+ children: /* @__PURE__ */ jsx(X, { className: "w-3 h-3" })
89
+ }), /* @__PURE__ */ jsx("div", {
90
+ className: `
91
+ text-login-200 pointer-events-none
92
+ transition-transform duration-200
93
+ ${isOpen ? "rotate-180" : ""}
94
+ `,
95
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "w-4 h-4" })
96
+ })]
97
+ })]
98
+ }), isOpen && /* @__PURE__ */ jsxs("div", {
99
+ className: `
100
+ absolute z-50 w-full mt-1 bg-login-700 border border-login-500/50
101
+ rounded-md shadow-xl max-h-60 overflow-hidden flex flex-col
102
+ `,
103
+ children: [searchable && /* @__PURE__ */ jsx("div", {
104
+ className: "p-2 sticky top-0 bg-login-700 border-b border-login-500/20 z-10",
105
+ children: /* @__PURE__ */ jsxs("div", {
106
+ className: "relative",
107
+ children: [/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-login-200" }), /* @__PURE__ */ jsx("input", {
108
+ type: "text",
109
+ value: searchTerm,
110
+ onChange: (e) => setSearchTerm(e.target.value),
111
+ placeholder: "Search...",
112
+ autoFocus: true,
113
+ className: `
114
+ w-full bg-login-600 border border-login-500/50 rounded-md
115
+ py-1.5 pl-9 pr-3 text-sm text-login-text
116
+ focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
117
+ `
118
+ })]
119
+ })
120
+ }), /* @__PURE__ */ jsx("div", {
121
+ className: "overflow-auto noscroll",
122
+ children: filteredOptions.length > 0 ? /* @__PURE__ */ jsx("ul", {
123
+ className: "py-1",
124
+ role: "listbox",
125
+ children: filteredOptions.map((option) => /* @__PURE__ */ jsx("li", {
126
+ role: "option",
127
+ "aria-selected": selectedOption?.value === option.value,
128
+ children: /* @__PURE__ */ jsxs("button", {
129
+ type: "button",
130
+ onClick: () => handleSelect(option),
131
+ className: `
132
+ w-full text-left px-3 py-2 text-sm
133
+ hover:bg-login-600 transition-colors duration-150
134
+ flex items-center gap-2
135
+ ${selectedOption?.value === option.value ? "bg-login/15 text-login" : "text-login-text"}
136
+ `,
137
+ children: [option.image && /* @__PURE__ */ jsx(Image, {
138
+ src: option.image,
139
+ alt: "",
140
+ width: 75,
141
+ height: 25,
142
+ className: "rounded-md object-cover shrink-0"
143
+ }), /* @__PURE__ */ jsx("span", {
144
+ className: "truncate",
145
+ children: option.label
146
+ })]
147
+ })
148
+ }, option.value))
149
+ }) : /* @__PURE__ */ jsx("div", {
150
+ className: "px-3 py-2 text-sm text-login-200",
151
+ children: searchTerm ? "No results found" : "No options available"
152
+ })
153
+ })]
154
+ })]
155
+ }), /* @__PURE__ */ jsx("input", {
156
+ type: "hidden",
157
+ name,
158
+ value: selectedOption?.value || "",
159
+ required
160
+ })]
161
+ });
162
+ }
163
+ //#endregion
164
+ export { Select as default };
@@ -0,0 +1,293 @@
1
+ "use client";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/components/inputs/shared/colorPickerPopup.tsx
5
+ function hexToHsv(hex) {
6
+ hex = hex.replace("#", "");
7
+ let r = 0, g = 0, b = 0;
8
+ if (hex.length === 3) {
9
+ r = parseInt(hex[0] + hex[0], 16);
10
+ g = parseInt(hex[1] + hex[1], 16);
11
+ b = parseInt(hex[2] + hex[2], 16);
12
+ } else if (hex.length === 6) {
13
+ r = parseInt(hex.substring(0, 2), 16);
14
+ g = parseInt(hex.substring(2, 4), 16);
15
+ b = parseInt(hex.substring(4, 6), 16);
16
+ }
17
+ r /= 255;
18
+ g /= 255;
19
+ b /= 255;
20
+ const max = Math.max(r, g, b);
21
+ const min = Math.min(r, g, b);
22
+ const d = max - min;
23
+ let h = 0;
24
+ const s = max === 0 ? 0 : d / max;
25
+ const v = max;
26
+ if (max !== min) {
27
+ switch (max) {
28
+ case r:
29
+ h = (g - b) / d + (g < b ? 6 : 0);
30
+ break;
31
+ case g:
32
+ h = (b - r) / d + 2;
33
+ break;
34
+ case b:
35
+ h = (r - g) / d + 4;
36
+ break;
37
+ }
38
+ h /= 6;
39
+ }
40
+ return {
41
+ h: h * 360,
42
+ s: s * 100,
43
+ v: v * 100
44
+ };
45
+ }
46
+ function hsvToRgb(h, s, v) {
47
+ let r = 0, g = 0, b = 0;
48
+ const i = Math.floor(h * 6);
49
+ const f = h * 6 - i;
50
+ const p = v * (1 - s);
51
+ const q = v * (1 - f * s);
52
+ const t = v * (1 - (1 - f) * s);
53
+ switch (i % 6) {
54
+ case 0:
55
+ r = v;
56
+ g = t;
57
+ b = p;
58
+ break;
59
+ case 1:
60
+ r = q;
61
+ g = v;
62
+ b = p;
63
+ break;
64
+ case 2:
65
+ r = p;
66
+ g = v;
67
+ b = t;
68
+ break;
69
+ case 3:
70
+ r = p;
71
+ g = q;
72
+ b = v;
73
+ break;
74
+ case 4:
75
+ r = t;
76
+ g = p;
77
+ b = v;
78
+ break;
79
+ case 5:
80
+ r = v;
81
+ g = p;
82
+ b = q;
83
+ break;
84
+ }
85
+ return {
86
+ r: Math.round(r * 255),
87
+ g: Math.round(g * 255),
88
+ b: Math.round(b * 255)
89
+ };
90
+ }
91
+ function hsvToHex(h, s, v) {
92
+ const { r, g, b } = hsvToRgb(h / 360, s / 100, v / 100);
93
+ function toHex(x) {
94
+ const hex = x.toString(16);
95
+ return hex.length === 1 ? "0" + hex : hex;
96
+ }
97
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
98
+ }
99
+ const PRESET_COLORS = [
100
+ "#f87171",
101
+ "#fd8738",
102
+ "#fbbf24",
103
+ "#facc15",
104
+ "#a3e635",
105
+ "#4ade80",
106
+ "#34d399",
107
+ "#2dd4bf",
108
+ "#38bdf8",
109
+ "#60a5fa",
110
+ "#818cf8",
111
+ "#a78bfa",
112
+ "#c084fc",
113
+ "#e879f9",
114
+ "#f472b6",
115
+ "#fb7185"
116
+ ];
117
+ function SaturationPicker({ hsv, onChange }) {
118
+ const containerRef = useRef(null);
119
+ function handleMove(e) {
120
+ if (!containerRef.current) return;
121
+ const { left, top, width, height } = containerRef.current.getBoundingClientRect();
122
+ const x = Math.min(Math.max((e.clientX - left) / width, 0), 1);
123
+ const y = Math.min(Math.max((e.clientY - top) / height, 0), 1);
124
+ onChange(x * 100, (1 - y) * 100);
125
+ }
126
+ function handleMouseDown(e) {
127
+ handleMove(e);
128
+ function moveHandler(e) {
129
+ handleMove(e);
130
+ }
131
+ function upHandler() {
132
+ window.removeEventListener("mousemove", moveHandler);
133
+ window.removeEventListener("mouseup", upHandler);
134
+ }
135
+ window.addEventListener("mousemove", moveHandler);
136
+ window.addEventListener("mouseup", upHandler);
137
+ }
138
+ return /* @__PURE__ */ jsxs("div", {
139
+ ref: containerRef,
140
+ className: "w-full h-32 relative rounded-md overflow-hidden cursor-crosshair mb-3 select-none",
141
+ style: { backgroundColor: hsvToHex(hsv.h, 100, 100) },
142
+ onMouseDown: handleMouseDown,
143
+ children: [
144
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-linear-to-r from-white to-transparent" }),
145
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-linear-to-t from-black to-transparent" }),
146
+ /* @__PURE__ */ jsx("div", {
147
+ className: `
148
+ absolute w-3 h-3 border-2 border-white rounded-full
149
+ shadow-md -translate-x-1/2 -translate-y-1/2 pointer-events-none
150
+ `,
151
+ style: {
152
+ left: `${hsv.s}%`,
153
+ top: `${100 - hsv.v}%`
154
+ }
155
+ })
156
+ ]
157
+ });
158
+ }
159
+ function HuePicker({ hue, onChange }) {
160
+ const containerRef = useRef(null);
161
+ function handleMove(e) {
162
+ if (!containerRef.current) return;
163
+ const { left, width } = containerRef.current.getBoundingClientRect();
164
+ onChange(Math.min(Math.max((e.clientX - left) / width, 0), 1) * 360);
165
+ }
166
+ function handleMouseDown(e) {
167
+ handleMove(e);
168
+ function moveHandler(e) {
169
+ handleMove(e);
170
+ }
171
+ function upHandler() {
172
+ window.removeEventListener("mousemove", moveHandler);
173
+ window.removeEventListener("mouseup", upHandler);
174
+ }
175
+ window.addEventListener("mousemove", moveHandler);
176
+ window.addEventListener("mouseup", upHandler);
177
+ }
178
+ return /* @__PURE__ */ jsx("div", {
179
+ ref: containerRef,
180
+ className: "w-full h-3 relative rounded-full cursor-pointer mb-4 select-none",
181
+ style: { background: "linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%)" },
182
+ onMouseDown: handleMouseDown,
183
+ children: /* @__PURE__ */ jsx("div", {
184
+ className: `
185
+ absolute w-4 h-4 bg-white border border-gray-200
186
+ rounded-full shadow-sm -translate-x-1/2 -translate-y-1/2
187
+ top-1/2 pointer-events-none
188
+ `,
189
+ style: { left: `${hue / 360 * 100}%` }
190
+ })
191
+ });
192
+ }
193
+ function ColorPickerPopup({ value, onChange, onClose, anchorName }) {
194
+ const [hsv, setHsv] = useState(() => hexToHsv(value || "#000000"));
195
+ const [hexInput, setHexInput] = useState(value || "#000000");
196
+ useEffect(() => {
197
+ if (value && value !== hexInput) {
198
+ setHsv(hexToHsv(value));
199
+ setHexInput(value);
200
+ }
201
+ }, [value]);
202
+ function handleColorChange(newHsv) {
203
+ setHsv(newHsv);
204
+ const hex = hsvToHex(newHsv.h, newHsv.s, newHsv.v);
205
+ setHexInput(hex);
206
+ onChange(hex);
207
+ }
208
+ function handleSaturationChange(s, v) {
209
+ handleColorChange({
210
+ ...hsv,
211
+ s,
212
+ v
213
+ });
214
+ }
215
+ function handleHueChange(h) {
216
+ handleColorChange({
217
+ ...hsv,
218
+ h
219
+ });
220
+ }
221
+ function manualHexChange(e) {
222
+ const val = e.target.value;
223
+ setHexInput(val);
224
+ if (/^#[0-9A-F]{6}$/i.test(val)) {
225
+ setHsv(hexToHsv(val));
226
+ onChange(val);
227
+ }
228
+ }
229
+ return /* @__PURE__ */ jsxs("div", {
230
+ className: "fixed z-50 bg-login-700 border border-login-500/50 rounded-md shadow-xl p-3 w-64 select-none anchor-popup",
231
+ style: {
232
+ positionAnchor: anchorName,
233
+ positionArea: "bottom span-right",
234
+ insetArea: "bottom span-right",
235
+ positionTryFallbacks: "flip-block",
236
+ margin: "0.25rem 0"
237
+ },
238
+ children: [
239
+ /* @__PURE__ */ jsx(SaturationPicker, {
240
+ hsv,
241
+ onChange: handleSaturationChange
242
+ }),
243
+ /* @__PURE__ */ jsx(HuePicker, {
244
+ hue: hsv.h,
245
+ onChange: handleHueChange
246
+ }),
247
+ /* @__PURE__ */ jsxs("div", {
248
+ className: "flex items-center gap-2 mb-3",
249
+ children: [
250
+ /* @__PURE__ */ jsx("div", {
251
+ className: "text-xs text-login-200 font-mono",
252
+ children: "HEX"
253
+ }),
254
+ /* @__PURE__ */ jsx("input", {
255
+ type: "text",
256
+ value: hexInput,
257
+ onChange: manualHexChange,
258
+ className: `
259
+ flex-1 min-w-0 bg-login-600 border border-login-500/50 rounded
260
+ px-2 py-1 text-sm text-login-text focus:outline-none
261
+ focus:border-login/60 focus:ring-1 focus:ring-login/30
262
+ `,
263
+ spellCheck: false
264
+ }),
265
+ /* @__PURE__ */ jsx("div", {
266
+ className: "w-8 h-8 rounded border border-login-500/50 shrink-0",
267
+ style: { backgroundColor: hexInput }
268
+ })
269
+ ]
270
+ }),
271
+ /* @__PURE__ */ jsx("div", {
272
+ className: "grid grid-cols-8 gap-1.5 pt-3 border-t border-login-500/25",
273
+ children: PRESET_COLORS.map((color) => /* @__PURE__ */ jsx("button", {
274
+ type: "button",
275
+ className: `
276
+ w-6 h-6 rounded-sm cursor-pointer hover:scale-110
277
+ hover:zIndex-10 transition-transform ring-1 ring-inset ring-black/10
278
+ `,
279
+ style: { backgroundColor: color },
280
+ onClick: () => {
281
+ setHsv(hexToHsv(color));
282
+ setHexInput(color);
283
+ onChange(color);
284
+ onClose();
285
+ },
286
+ title: color
287
+ }, color))
288
+ })
289
+ ]
290
+ });
291
+ }
292
+ //#endregion
293
+ export { ColorPickerPopup as default };