@ikatec/nebula-react 1.0.25 → 1.0.27
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 +24 -10
- package/dist/index.d.ts +24 -10
- package/dist/index.js +1337 -156
- package/dist/index.mjs +1332 -158
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React8 from 'react';
|
|
2
|
-
import React8__default, { createContext, forwardRef, useMemo, useState, useEffect, useCallback, useContext, useRef } from 'react';
|
|
2
|
+
import React8__default, { createContext, forwardRef, useMemo, useState, useEffect, useCallback, useContext, useRef, useId } from 'react';
|
|
3
3
|
import { Slot } from '@radix-ui/react-slot';
|
|
4
4
|
import { cva } from 'class-variance-authority';
|
|
5
5
|
import { extendTailwindMerge } from 'tailwind-merge';
|
|
@@ -7,7 +7,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
7
7
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
8
8
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
9
9
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
10
|
-
import { ChevronRight, Check, Circle, CircleX, Eye, EyeOff, X, Minus, ClockIcon, ChevronsLeft, ChevronLeft, ChevronsRight, MoreHorizontal, ChevronDown, ChevronLeftIcon, ChevronDownIcon, ChevronRightIcon, CalendarIcon, ImageUpIcon, XIcon, PhoneIcon, FileTextIcon, FileAudioIcon, FileVideoIcon, Info, CircleCheckBig } from 'lucide-react';
|
|
10
|
+
import { ChevronRight, Check, Circle, CircleX, Eye, EyeOff, X, Minus, ClockIcon, ChevronsLeft, ChevronLeft, ChevronsRight, MoreHorizontal, ChevronDown, ChevronLeftIcon, ChevronDownIcon, ChevronRightIcon, CalendarIcon, ImageUpIcon, XIcon, UserIcon, MinusIcon, PlusIcon, PhoneIcon, FileTextIcon, FileAudioIcon, FileVideoIcon, Info, CircleCheckBig } from 'lucide-react';
|
|
11
11
|
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
12
12
|
import Select, { components } from 'react-select';
|
|
13
13
|
import Creatable from 'react-select/creatable';
|
|
@@ -27,6 +27,7 @@ import { formatDate, isValid, addMonths, isSameDay, isBefore, isAfter } from 'da
|
|
|
27
27
|
import { DayPicker } from 'react-day-picker';
|
|
28
28
|
import { ptBR, enUS, es } from 'react-day-picker/locale';
|
|
29
29
|
import { useMask } from '@react-input/mask';
|
|
30
|
+
import * as SliderPrimitive from '@radix-ui/react-slider';
|
|
30
31
|
|
|
31
32
|
// src/button.tsx
|
|
32
33
|
|
|
@@ -1117,8 +1118,16 @@ var messages5 = {
|
|
|
1117
1118
|
};
|
|
1118
1119
|
var file_upload_default = messages5;
|
|
1119
1120
|
|
|
1121
|
+
// src/i18n/messages/en/cropper.ts
|
|
1122
|
+
var messages6 = {
|
|
1123
|
+
applyButtonLabel: "Apply",
|
|
1124
|
+
dialogTitle: "Adjust image"
|
|
1125
|
+
};
|
|
1126
|
+
var cropper_default = messages6;
|
|
1127
|
+
|
|
1120
1128
|
// src/i18n/messages/en/index.ts
|
|
1121
1129
|
var enMessages = {
|
|
1130
|
+
cropper: cropper_default,
|
|
1122
1131
|
pagination: pagination_default,
|
|
1123
1132
|
inputSelect: input_select_default,
|
|
1124
1133
|
inputPhone: input_phone_default,
|
|
@@ -1127,7 +1136,7 @@ var enMessages = {
|
|
|
1127
1136
|
};
|
|
1128
1137
|
|
|
1129
1138
|
// src/i18n/messages/es/pagination.ts
|
|
1130
|
-
var
|
|
1139
|
+
var messages7 = {
|
|
1131
1140
|
totalResultsLabel(pagesSize, totalResults) {
|
|
1132
1141
|
if (totalResults < pagesSize) {
|
|
1133
1142
|
pagesSize = totalResults;
|
|
@@ -1138,16 +1147,16 @@ var messages6 = {
|
|
|
1138
1147
|
return `P\xE1gina ${currentPage} de ${totalPages}`;
|
|
1139
1148
|
}
|
|
1140
1149
|
};
|
|
1141
|
-
var pagination_default2 =
|
|
1150
|
+
var pagination_default2 = messages7;
|
|
1142
1151
|
|
|
1143
1152
|
// src/i18n/messages/es/input-select.ts
|
|
1144
|
-
var
|
|
1153
|
+
var messages8 = {
|
|
1145
1154
|
noOptions: "No hay opciones disponibles"
|
|
1146
1155
|
};
|
|
1147
|
-
var input_select_default2 =
|
|
1156
|
+
var input_select_default2 = messages8;
|
|
1148
1157
|
|
|
1149
1158
|
// src/i18n/messages/es/input-phone.ts
|
|
1150
|
-
var
|
|
1159
|
+
var messages9 = {
|
|
1151
1160
|
countries: {
|
|
1152
1161
|
empty: "Seleccionar",
|
|
1153
1162
|
AF: "Afganist\xE1n",
|
|
@@ -1397,22 +1406,30 @@ var messages8 = {
|
|
|
1397
1406
|
ZW: "Zimbabue"
|
|
1398
1407
|
}
|
|
1399
1408
|
};
|
|
1400
|
-
var input_phone_default2 =
|
|
1409
|
+
var input_phone_default2 = messages9;
|
|
1401
1410
|
|
|
1402
1411
|
// src/i18n/messages/es/time-picker.ts
|
|
1403
|
-
var
|
|
1412
|
+
var messages10 = {
|
|
1404
1413
|
label: "Tiempo"
|
|
1405
1414
|
};
|
|
1406
|
-
var time_picker_default2 =
|
|
1415
|
+
var time_picker_default2 = messages10;
|
|
1407
1416
|
|
|
1408
1417
|
// src/i18n/messages/es/file-upload.ts
|
|
1409
|
-
var
|
|
1418
|
+
var messages11 = {
|
|
1410
1419
|
deleteAll: "Remover todos"
|
|
1411
1420
|
};
|
|
1412
|
-
var file_upload_default2 =
|
|
1421
|
+
var file_upload_default2 = messages11;
|
|
1422
|
+
|
|
1423
|
+
// src/i18n/messages/es/cropper.ts
|
|
1424
|
+
var messages12 = {
|
|
1425
|
+
applyButtonLabel: "Aplicar",
|
|
1426
|
+
dialogTitle: "Ajustar la imagen"
|
|
1427
|
+
};
|
|
1428
|
+
var cropper_default2 = messages12;
|
|
1413
1429
|
|
|
1414
1430
|
// src/i18n/messages/es/index.ts
|
|
1415
1431
|
var esMessages = {
|
|
1432
|
+
cropper: cropper_default2,
|
|
1416
1433
|
pagination: pagination_default2,
|
|
1417
1434
|
inputSelect: input_select_default2,
|
|
1418
1435
|
inputPhone: input_phone_default2,
|
|
@@ -1421,7 +1438,7 @@ var esMessages = {
|
|
|
1421
1438
|
};
|
|
1422
1439
|
|
|
1423
1440
|
// src/i18n/messages/pt-br/pagination.ts
|
|
1424
|
-
var
|
|
1441
|
+
var messages13 = {
|
|
1425
1442
|
totalResultsLabel(pagesSize, totalResults) {
|
|
1426
1443
|
if (totalResults < pagesSize) {
|
|
1427
1444
|
pagesSize = totalResults;
|
|
@@ -1432,16 +1449,16 @@ var messages11 = {
|
|
|
1432
1449
|
return `P\xE1gina ${currentPage} de ${totalPages}`;
|
|
1433
1450
|
}
|
|
1434
1451
|
};
|
|
1435
|
-
var pagination_default3 =
|
|
1452
|
+
var pagination_default3 = messages13;
|
|
1436
1453
|
|
|
1437
1454
|
// src/i18n/messages/pt-br/input-select.ts
|
|
1438
|
-
var
|
|
1455
|
+
var messages14 = {
|
|
1439
1456
|
noOptions: "Nenhuma op\xE7\xE3o dispon\xEDvel"
|
|
1440
1457
|
};
|
|
1441
|
-
var input_select_default3 =
|
|
1458
|
+
var input_select_default3 = messages14;
|
|
1442
1459
|
|
|
1443
1460
|
// src/i18n/messages/pt-br/input-phone.ts
|
|
1444
|
-
var
|
|
1461
|
+
var messages15 = {
|
|
1445
1462
|
countries: {
|
|
1446
1463
|
empty: "Selecione",
|
|
1447
1464
|
AF: "Afeganist\xE3o",
|
|
@@ -1691,19 +1708,26 @@ var messages13 = {
|
|
|
1691
1708
|
ZW: "Zimb\xE1bue"
|
|
1692
1709
|
}
|
|
1693
1710
|
};
|
|
1694
|
-
var input_phone_default3 =
|
|
1711
|
+
var input_phone_default3 = messages15;
|
|
1695
1712
|
|
|
1696
1713
|
// src/i18n/messages/pt-br/time-picker.ts
|
|
1697
|
-
var
|
|
1714
|
+
var messages16 = {
|
|
1698
1715
|
label: "Hor\xE1rio"
|
|
1699
1716
|
};
|
|
1700
|
-
var time_picker_default3 =
|
|
1717
|
+
var time_picker_default3 = messages16;
|
|
1701
1718
|
|
|
1702
1719
|
// src/i18n/messages/pt-br/file-upload.ts
|
|
1703
|
-
var
|
|
1720
|
+
var messages17 = {
|
|
1704
1721
|
deleteAll: "Remover todos"
|
|
1705
1722
|
};
|
|
1706
|
-
var file_upload_default3 =
|
|
1723
|
+
var file_upload_default3 = messages17;
|
|
1724
|
+
|
|
1725
|
+
// src/i18n/messages/pt-br/cropper.ts
|
|
1726
|
+
var messages18 = {
|
|
1727
|
+
applyButtonLabel: "Aplicar",
|
|
1728
|
+
dialogTitle: "Ajustar imagem"
|
|
1729
|
+
};
|
|
1730
|
+
var cropper_default3 = messages18;
|
|
1707
1731
|
|
|
1708
1732
|
// src/i18n/messages/pt-br/index.ts
|
|
1709
1733
|
var ptBrMessages = {
|
|
@@ -1711,7 +1735,8 @@ var ptBrMessages = {
|
|
|
1711
1735
|
inputSelect: input_select_default3,
|
|
1712
1736
|
inputPhone: input_phone_default3,
|
|
1713
1737
|
timePicker: time_picker_default3,
|
|
1714
|
-
fileUpload: file_upload_default3
|
|
1738
|
+
fileUpload: file_upload_default3,
|
|
1739
|
+
cropper: cropper_default3
|
|
1715
1740
|
};
|
|
1716
1741
|
|
|
1717
1742
|
// src/i18n/message-storage-handler.ts
|
|
@@ -1736,7 +1761,7 @@ var setNebulaLanguage = (language) => {
|
|
|
1736
1761
|
}
|
|
1737
1762
|
localStorage.setItem(getNebulaI18nStorageKey(), language);
|
|
1738
1763
|
};
|
|
1739
|
-
var
|
|
1764
|
+
var messages19 = /* @__PURE__ */ new Map([
|
|
1740
1765
|
[null, enMessages],
|
|
1741
1766
|
[void 0, enMessages],
|
|
1742
1767
|
["en-US", enMessages],
|
|
@@ -1754,14 +1779,14 @@ var NebulaI18nProvider = ({
|
|
|
1754
1779
|
() => customI18nStorageKey ?? localStorageKey,
|
|
1755
1780
|
[customI18nStorageKey]
|
|
1756
1781
|
);
|
|
1757
|
-
const [
|
|
1758
|
-
|
|
1782
|
+
const [messages20, setMessages] = useState(
|
|
1783
|
+
messages19.get(getNebulaLanguage()) ?? messages19.get("en-US")
|
|
1759
1784
|
);
|
|
1760
1785
|
const handleStorageChange = useCallback(
|
|
1761
1786
|
({ detail }) => {
|
|
1762
1787
|
if (detail.key === storageKey) {
|
|
1763
1788
|
setMessages(
|
|
1764
|
-
|
|
1789
|
+
messages19.get(detail.value) ?? messages19.get("en-US")
|
|
1765
1790
|
);
|
|
1766
1791
|
}
|
|
1767
1792
|
},
|
|
@@ -1805,7 +1830,7 @@ var NebulaI18nProvider = ({
|
|
|
1805
1830
|
NebulaI18nContext.Provider,
|
|
1806
1831
|
{
|
|
1807
1832
|
value: {
|
|
1808
|
-
messages:
|
|
1833
|
+
messages: messages20,
|
|
1809
1834
|
locale: getNebulaLanguage()
|
|
1810
1835
|
},
|
|
1811
1836
|
children
|
|
@@ -1827,7 +1852,7 @@ var Pagination = ({
|
|
|
1827
1852
|
onChangePage,
|
|
1828
1853
|
...props
|
|
1829
1854
|
}) => {
|
|
1830
|
-
const { messages:
|
|
1855
|
+
const { messages: messages20 } = useNebulaI18n();
|
|
1831
1856
|
const totalPages = useMemo(() => {
|
|
1832
1857
|
return Math.ceil(total / (pageSize || 1));
|
|
1833
1858
|
}, [total, pageSize]);
|
|
@@ -1860,13 +1885,13 @@ var Pagination = ({
|
|
|
1860
1885
|
}, [totalPages, pageSize, total]);
|
|
1861
1886
|
const totalResultsLabel = useMemo(() => {
|
|
1862
1887
|
if (page === totalPages) {
|
|
1863
|
-
return
|
|
1888
|
+
return messages20.pagination.totalResultsLabel(lastPageSize, total);
|
|
1864
1889
|
}
|
|
1865
|
-
return
|
|
1866
|
-
}, [
|
|
1890
|
+
return messages20.pagination.totalResultsLabel(pageSize, total);
|
|
1891
|
+
}, [messages20.pagination, pageSize, total, page, totalPages, lastPageSize]);
|
|
1867
1892
|
const currentPageLabel = useMemo(
|
|
1868
|
-
() =>
|
|
1869
|
-
[
|
|
1893
|
+
() => messages20.pagination.currentPageLabel(normalizedPage, totalPages),
|
|
1894
|
+
[messages20.pagination, normalizedPage, totalPages]
|
|
1870
1895
|
);
|
|
1871
1896
|
return /* @__PURE__ */ jsxs(
|
|
1872
1897
|
"nav",
|
|
@@ -2139,7 +2164,7 @@ var createStyledSelect = (BaseSelect, displayName) => {
|
|
|
2139
2164
|
isError = false,
|
|
2140
2165
|
...props
|
|
2141
2166
|
}) => {
|
|
2142
|
-
const { messages:
|
|
2167
|
+
const { messages: messages20 } = useNebulaI18n();
|
|
2143
2168
|
const customClassNames = useMemo(() => {
|
|
2144
2169
|
return {
|
|
2145
2170
|
control: (props2) => controlStyles(props2, isError),
|
|
@@ -2186,7 +2211,7 @@ var createStyledSelect = (BaseSelect, displayName) => {
|
|
|
2186
2211
|
isDisabled: disabled,
|
|
2187
2212
|
components: customComponents,
|
|
2188
2213
|
classNames: customClassNames,
|
|
2189
|
-
noOptionsMessage: () => /* @__PURE__ */ jsx("p", { children:
|
|
2214
|
+
noOptionsMessage: () => /* @__PURE__ */ jsx("p", { children: messages20.inputSelect.noOptions }),
|
|
2190
2215
|
...props
|
|
2191
2216
|
}
|
|
2192
2217
|
);
|
|
@@ -2202,15 +2227,9 @@ var StyledAsyncCreatable = createStyledSelect(
|
|
|
2202
2227
|
"AsyncCreatable"
|
|
2203
2228
|
);
|
|
2204
2229
|
var InputText = React8.forwardRef(
|
|
2205
|
-
({
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
isError = false,
|
|
2209
|
-
onClean,
|
|
2210
|
-
iconPlacement = "start",
|
|
2211
|
-
disabled,
|
|
2212
|
-
...props
|
|
2213
|
-
}, ref) => {
|
|
2230
|
+
({ className, isError = false, onClean, disabled, suffix, ...props }, ref) => {
|
|
2231
|
+
const icon = "icon" in props ? props.icon : null;
|
|
2232
|
+
const iconPlacement = "iconPlacement" in props || props.type !== "password" ? props.iconPlacement || "start" : null;
|
|
2214
2233
|
const initialInputType = props.type || "text";
|
|
2215
2234
|
const [type, setType] = React8.useState(initialInputType);
|
|
2216
2235
|
const iconClass = {
|
|
@@ -2221,71 +2240,92 @@ var InputText = React8.forwardRef(
|
|
|
2221
2240
|
return /* @__PURE__ */ jsxs(
|
|
2222
2241
|
"div",
|
|
2223
2242
|
{
|
|
2224
|
-
className: cn(
|
|
2225
|
-
"
|
|
2226
|
-
|
|
2243
|
+
className: cn(
|
|
2244
|
+
"w-full flex outline-none",
|
|
2245
|
+
"rounded-input",
|
|
2246
|
+
"border border-inputText-border-default focus-within:ring-[3px] focus-within:ring-inputText-border-focus focus-within:border-inputText-border-focus",
|
|
2247
|
+
"focus-within:text-inputText-text-focus placeholder:text-inputText-text-default disabled:text-inputText-text-disabled",
|
|
2248
|
+
isError && "border-inputText-border-danger focus-within:border-inputText-border-danger focus-within:ring-button-danger-border-focus",
|
|
2249
|
+
disabled && "pointer-events-none"
|
|
2250
|
+
),
|
|
2227
2251
|
children: [
|
|
2228
|
-
/* @__PURE__ */
|
|
2229
|
-
|
|
2252
|
+
/* @__PURE__ */ jsxs("div", { className: "nebula-ds relative w-full", children: [
|
|
2253
|
+
/* @__PURE__ */ jsx(
|
|
2254
|
+
"input",
|
|
2255
|
+
{
|
|
2256
|
+
ref,
|
|
2257
|
+
className: cn(
|
|
2258
|
+
"w-full h-10 outline-none text-sm leading-none font-medium",
|
|
2259
|
+
"bg-inputText-background-default disabled:bg-inputText-background-disabled",
|
|
2260
|
+
"text-inputText-text-filled",
|
|
2261
|
+
"disabled:cursor-not-allowed",
|
|
2262
|
+
"rounded-input",
|
|
2263
|
+
"pl-4",
|
|
2264
|
+
!!suffix && "rounded-r-none",
|
|
2265
|
+
{
|
|
2266
|
+
"pl-10 pr-4": !!icon && iconPlacement === "start",
|
|
2267
|
+
"pr-10": initialInputType === "password",
|
|
2268
|
+
"pr-10 pl-4": !!icon && iconPlacement === "end" && initialInputType !== "password"
|
|
2269
|
+
},
|
|
2270
|
+
className
|
|
2271
|
+
),
|
|
2272
|
+
...{ ...props, icon: void 0, iconPlacement: void 0 },
|
|
2273
|
+
disabled,
|
|
2274
|
+
type
|
|
2275
|
+
}
|
|
2276
|
+
),
|
|
2277
|
+
onClean && props.value && /* @__PURE__ */ jsx(
|
|
2278
|
+
"button",
|
|
2279
|
+
{
|
|
2280
|
+
type: "button",
|
|
2281
|
+
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2282
|
+
"right-10": initialInputType === "password" || iconPlacement === "end",
|
|
2283
|
+
"right-4": initialInputType === "text" && iconPlacement === "start"
|
|
2284
|
+
}),
|
|
2285
|
+
onClick: onClean,
|
|
2286
|
+
children: /* @__PURE__ */ jsx(CircleX, { className: cn("w-4 h-4", iconClass) })
|
|
2287
|
+
}
|
|
2288
|
+
),
|
|
2289
|
+
initialInputType === "password" && /* @__PURE__ */ jsx(
|
|
2290
|
+
"button",
|
|
2291
|
+
{
|
|
2292
|
+
type: "button",
|
|
2293
|
+
className: "nebula-ds absolute right-4 top-1/2 transform -translate-y-1/2",
|
|
2294
|
+
onClick: () => setType((prev) => prev === "text" ? "password" : "text"),
|
|
2295
|
+
children: type === "text" ? /* @__PURE__ */ jsx(Eye, { className: cn("w-4 h-4", iconClass) }) : /* @__PURE__ */ jsx(EyeOff, { className: cn("w-4 h-4", iconClass) })
|
|
2296
|
+
}
|
|
2297
|
+
),
|
|
2298
|
+
icon && initialInputType !== "password" && /* @__PURE__ */ jsx(
|
|
2299
|
+
"span",
|
|
2300
|
+
{
|
|
2301
|
+
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2302
|
+
"left-4": iconPlacement === "start",
|
|
2303
|
+
"right-4": iconPlacement === "end"
|
|
2304
|
+
}),
|
|
2305
|
+
children: /* @__PURE__ */ jsx(
|
|
2306
|
+
"span",
|
|
2307
|
+
{
|
|
2308
|
+
className: cn(
|
|
2309
|
+
"w-4 h-4 flex items-center justify-center disabled:text-inputText-icon-disabled",
|
|
2310
|
+
iconClass
|
|
2311
|
+
),
|
|
2312
|
+
children: icon
|
|
2313
|
+
}
|
|
2314
|
+
)
|
|
2315
|
+
}
|
|
2316
|
+
)
|
|
2317
|
+
] }),
|
|
2318
|
+
!!suffix && /* @__PURE__ */ jsx(
|
|
2319
|
+
"div",
|
|
2230
2320
|
{
|
|
2231
|
-
ref,
|
|
2232
2321
|
className: cn(
|
|
2233
|
-
"w-
|
|
2234
|
-
"bg-inputText-
|
|
2235
|
-
"
|
|
2236
|
-
"
|
|
2237
|
-
"
|
|
2238
|
-
{
|
|
2239
|
-
"pl-10 pr-4": !!icon && iconPlacement === "start",
|
|
2240
|
-
"pr-10 pl-4": !!icon && iconPlacement === "end" && initialInputType !== "password",
|
|
2241
|
-
"px-4": !icon,
|
|
2242
|
-
"border-inputText-border-danger focus:border-inputText-border-danger focus:ring-button-danger-border-focus": isError
|
|
2243
|
-
},
|
|
2244
|
-
className
|
|
2322
|
+
"w-fit h-10 outline-none rounded-input text-sm leading-none font-medium rounded-l-none flex items-center px-4",
|
|
2323
|
+
"bg-inputText-suffixBackground disabled:bg-inputText-background-disabled",
|
|
2324
|
+
"text-inputText-text-filled",
|
|
2325
|
+
"border-l border-inputText-border-default",
|
|
2326
|
+
"rounded-input rounded-l-none"
|
|
2245
2327
|
),
|
|
2246
|
-
|
|
2247
|
-
disabled,
|
|
2248
|
-
type
|
|
2249
|
-
}
|
|
2250
|
-
),
|
|
2251
|
-
onClean && props.value && /* @__PURE__ */ jsx(
|
|
2252
|
-
"button",
|
|
2253
|
-
{
|
|
2254
|
-
type: "button",
|
|
2255
|
-
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2256
|
-
"right-10": initialInputType === "password" || iconPlacement === "end",
|
|
2257
|
-
"right-4": initialInputType === "text" && iconPlacement === "start"
|
|
2258
|
-
}),
|
|
2259
|
-
onClick: onClean,
|
|
2260
|
-
children: /* @__PURE__ */ jsx(CircleX, { className: cn("w-4 h-4", iconClass) })
|
|
2261
|
-
}
|
|
2262
|
-
),
|
|
2263
|
-
initialInputType === "password" && /* @__PURE__ */ jsx(
|
|
2264
|
-
"button",
|
|
2265
|
-
{
|
|
2266
|
-
type: "button",
|
|
2267
|
-
className: "nebula-ds absolute right-4 top-1/2 transform -translate-y-1/2",
|
|
2268
|
-
onClick: () => setType((prev) => prev === "text" ? "password" : "text"),
|
|
2269
|
-
children: type === "text" ? /* @__PURE__ */ jsx(Eye, { className: cn("w-4 h-4", iconClass) }) : /* @__PURE__ */ jsx(EyeOff, { className: cn("w-4 h-4", iconClass) })
|
|
2270
|
-
}
|
|
2271
|
-
),
|
|
2272
|
-
icon && /* @__PURE__ */ jsx(
|
|
2273
|
-
"span",
|
|
2274
|
-
{
|
|
2275
|
-
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2276
|
-
"left-4": iconPlacement === "start",
|
|
2277
|
-
"right-4": iconPlacement === "end" && initialInputType !== "password"
|
|
2278
|
-
}),
|
|
2279
|
-
children: /* @__PURE__ */ jsx(
|
|
2280
|
-
"span",
|
|
2281
|
-
{
|
|
2282
|
-
className: cn(
|
|
2283
|
-
"w-4 h-4 flex items-center justify-center disabled:text-inputText-icon-disabled",
|
|
2284
|
-
iconClass
|
|
2285
|
-
),
|
|
2286
|
-
children: icon
|
|
2287
|
-
}
|
|
2288
|
-
)
|
|
2328
|
+
children: suffix
|
|
2289
2329
|
}
|
|
2290
2330
|
)
|
|
2291
2331
|
]
|
|
@@ -2317,16 +2357,17 @@ var DialogOverlay = React8.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
2317
2357
|
}
|
|
2318
2358
|
));
|
|
2319
2359
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
2320
|
-
var DialogContent = React8.forwardRef(
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
/* @__PURE__ */
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2360
|
+
var DialogContent = React8.forwardRef(
|
|
2361
|
+
({ className, children, portal = false, showClose = true, ...props }, ref) => {
|
|
2362
|
+
const Comp = portal ? DialogPortal : React8.Fragment;
|
|
2363
|
+
return /* @__PURE__ */ jsxs(Comp, { children: [
|
|
2364
|
+
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
2365
|
+
/* @__PURE__ */ jsxs(
|
|
2366
|
+
DialogPrimitive.Content,
|
|
2367
|
+
{
|
|
2368
|
+
ref,
|
|
2369
|
+
className: cn(
|
|
2370
|
+
`rounded-2xl
|
|
2330
2371
|
fixed
|
|
2331
2372
|
left-[50%]
|
|
2332
2373
|
top-[50%]
|
|
@@ -2351,29 +2392,30 @@ var DialogContent = React8.forwardRef(({ className, children, portal = false, ..
|
|
|
2351
2392
|
data-[state=closed]:slide-out-to-top-[48%]
|
|
2352
2393
|
data-[state=open]:slide-in-from-left-1/2
|
|
2353
2394
|
data-[state=open]:slide-in-from-top-[48%]`,
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
}
|
|
2395
|
+
className
|
|
2396
|
+
),
|
|
2397
|
+
...props,
|
|
2398
|
+
children: [
|
|
2399
|
+
children,
|
|
2400
|
+
showClose && /* @__PURE__ */ jsx(
|
|
2401
|
+
DialogPrimitive.Close,
|
|
2402
|
+
{
|
|
2403
|
+
asChild: true,
|
|
2404
|
+
className: `absolute
|
|
2405
|
+
right-4
|
|
2406
|
+
top-4`,
|
|
2407
|
+
children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", icon: true, children: [
|
|
2408
|
+
/* @__PURE__ */ jsx(X, { className: "nebula-ds !h-4 !w-4 !text-dialog-icon" }),
|
|
2409
|
+
/* @__PURE__ */ jsx("span", { className: "nebula-ds sr-only", children: "Close" })
|
|
2410
|
+
] })
|
|
2411
|
+
}
|
|
2412
|
+
)
|
|
2413
|
+
]
|
|
2414
|
+
}
|
|
2415
|
+
)
|
|
2416
|
+
] });
|
|
2417
|
+
}
|
|
2418
|
+
);
|
|
2377
2419
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
2378
2420
|
var DialogHeader = ({
|
|
2379
2421
|
className,
|
|
@@ -3189,13 +3231,13 @@ function custom(message, options) {
|
|
|
3189
3231
|
}
|
|
3190
3232
|
);
|
|
3191
3233
|
}
|
|
3192
|
-
async function promise(promise2,
|
|
3234
|
+
async function promise(promise2, messages20, options) {
|
|
3193
3235
|
const loadingToast = toast$1.custom(
|
|
3194
3236
|
(t) => /* @__PURE__ */ jsx(
|
|
3195
3237
|
ToastComponent,
|
|
3196
3238
|
{
|
|
3197
3239
|
type: "info",
|
|
3198
|
-
message:
|
|
3240
|
+
message: messages20.loading,
|
|
3199
3241
|
options,
|
|
3200
3242
|
t
|
|
3201
3243
|
}
|
|
@@ -3209,7 +3251,7 @@ async function promise(promise2, messages17, options) {
|
|
|
3209
3251
|
ToastComponent,
|
|
3210
3252
|
{
|
|
3211
3253
|
type: "success",
|
|
3212
|
-
message:
|
|
3254
|
+
message: messages20.success,
|
|
3213
3255
|
options,
|
|
3214
3256
|
t
|
|
3215
3257
|
}
|
|
@@ -3224,7 +3266,7 @@ async function promise(promise2, messages17, options) {
|
|
|
3224
3266
|
ToastComponent,
|
|
3225
3267
|
{
|
|
3226
3268
|
type: "error",
|
|
3227
|
-
message:
|
|
3269
|
+
message: messages20.error,
|
|
3228
3270
|
options,
|
|
3229
3271
|
t
|
|
3230
3272
|
}
|
|
@@ -3394,8 +3436,8 @@ var CountrySelect = ({
|
|
|
3394
3436
|
const handleSelect = (event) => {
|
|
3395
3437
|
onChange(event.target.value);
|
|
3396
3438
|
};
|
|
3397
|
-
const { messages:
|
|
3398
|
-
const { countries } =
|
|
3439
|
+
const { messages: messages20 } = useNebulaI18n();
|
|
3440
|
+
const { countries } = messages20.inputPhone;
|
|
3399
3441
|
return /* @__PURE__ */ jsxs("div", { className: "nebula-ds rounded-s-[20px] relative inline-flex items-center self-stretch py-2 ps-4 pe-2 transition-[color,box-shadow] outline-none has-disabled:pointer-events-none has-disabled:opacity-50", children: [
|
|
3400
3442
|
/* @__PURE__ */ jsxs("div", { className: "nebula-ds inline-flex items-center gap-1", "aria-hidden": "true", children: [
|
|
3401
3443
|
/* @__PURE__ */ jsx(FlagComponent, { country: value, countryName: value, "aria-hidden": "true" }),
|
|
@@ -4203,7 +4245,10 @@ var InputDateTimePickerSingle = ({
|
|
|
4203
4245
|
...rest
|
|
4204
4246
|
}) => {
|
|
4205
4247
|
const [innerTimeValue, setInnerTimeValue] = useState(
|
|
4206
|
-
|
|
4248
|
+
() => {
|
|
4249
|
+
const [, time] = (value || "")?.split?.(DATA_TIME_SEPARATOR);
|
|
4250
|
+
return time ?? "";
|
|
4251
|
+
}
|
|
4207
4252
|
);
|
|
4208
4253
|
const formattedDateByLanguage = formatDateToSubmit(
|
|
4209
4254
|
value?.split(DATA_TIME_SEPARATOR)?.at(0) ?? ""
|
|
@@ -4212,7 +4257,7 @@ var InputDateTimePickerSingle = ({
|
|
|
4212
4257
|
formattedDateByLanguage ? new Date(formattedDateByLanguage) : void 0
|
|
4213
4258
|
);
|
|
4214
4259
|
const [popoverIsOpen, setPopoverIsOpen] = useState(false);
|
|
4215
|
-
const { locale, messages:
|
|
4260
|
+
const { locale, messages: messages20 } = useNebulaI18n();
|
|
4216
4261
|
const [month, setMonth] = useState(/* @__PURE__ */ new Date());
|
|
4217
4262
|
const inputTimeRef = useRef(null);
|
|
4218
4263
|
const handleClearValue = () => {
|
|
@@ -4270,8 +4315,9 @@ var InputDateTimePickerSingle = ({
|
|
|
4270
4315
|
if (date && !dateFormatIsValid(date, locale)) {
|
|
4271
4316
|
handleClearValue();
|
|
4272
4317
|
}
|
|
4318
|
+
const hasInputtedDate = date.length === "__/__/____".length;
|
|
4273
4319
|
onChange?.(
|
|
4274
|
-
date + (newTime ? DATA_TIME_SEPARATOR + newTime : ""),
|
|
4320
|
+
date + (newTime && hasInputtedDate ? DATA_TIME_SEPARATOR + newTime : ""),
|
|
4275
4321
|
innerDate,
|
|
4276
4322
|
newTime
|
|
4277
4323
|
);
|
|
@@ -4383,7 +4429,7 @@ var InputDateTimePickerSingle = ({
|
|
|
4383
4429
|
disabled: disabledDates,
|
|
4384
4430
|
footer: /* @__PURE__ */ jsxs(Space, { className: "nebula-ds items-center", children: [
|
|
4385
4431
|
/* @__PURE__ */ jsxs(Label, { children: [
|
|
4386
|
-
|
|
4432
|
+
messages20.timePicker.label,
|
|
4387
4433
|
":"
|
|
4388
4434
|
] }),
|
|
4389
4435
|
/* @__PURE__ */ jsx(
|
|
@@ -4403,11 +4449,11 @@ var InputDateTimePickerSingle = ({
|
|
|
4403
4449
|
) })
|
|
4404
4450
|
] });
|
|
4405
4451
|
};
|
|
4406
|
-
var FileUploadError = /* @__PURE__ */ ((
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
return
|
|
4452
|
+
var FileUploadError = /* @__PURE__ */ ((FileUploadError4) => {
|
|
4453
|
+
FileUploadError4["MAX_FILES_EXCEEDED"] = "MAX_FILES_EXCEEDED";
|
|
4454
|
+
FileUploadError4["MAXIMUM_FILE_SIZE_EXCEEDED"] = "MAXIMUM_FILE_SIZE_EXCEEDED";
|
|
4455
|
+
FileUploadError4["INVALID_FORMAT"] = "INVALID_FORMAT";
|
|
4456
|
+
return FileUploadError4;
|
|
4411
4457
|
})(FileUploadError || {});
|
|
4412
4458
|
var useFileUpload = (options = {}) => {
|
|
4413
4459
|
const {
|
|
@@ -4508,9 +4554,6 @@ var useFileUpload = (options = {}) => {
|
|
|
4508
4554
|
const newFilesArray = Array.from(newFiles);
|
|
4509
4555
|
const errors = [];
|
|
4510
4556
|
setState((prev) => ({ ...prev, errors: [] }));
|
|
4511
|
-
if (!multiple) {
|
|
4512
|
-
clearFiles();
|
|
4513
|
-
}
|
|
4514
4557
|
if (multiple && maxFiles !== Infinity && state.files.length + newFilesArray.length > maxFiles) {
|
|
4515
4558
|
errors.push({ error: "MAX_FILES_EXCEEDED" /* MAX_FILES_EXCEEDED */ });
|
|
4516
4559
|
setState((prev) => ({ ...prev, errors }));
|
|
@@ -4545,6 +4588,9 @@ var useFileUpload = (options = {}) => {
|
|
|
4545
4588
|
}
|
|
4546
4589
|
});
|
|
4547
4590
|
if (validFiles.length > 0) {
|
|
4591
|
+
if (!multiple) {
|
|
4592
|
+
clearFiles();
|
|
4593
|
+
}
|
|
4548
4594
|
onFilesAdded?.(validFiles);
|
|
4549
4595
|
setState((prev) => {
|
|
4550
4596
|
const newFiles2 = !multiple ? validFiles : [...prev.files, ...validFiles];
|
|
@@ -4841,6 +4887,7 @@ function FileUpload({
|
|
|
4841
4887
|
) })
|
|
4842
4888
|
] });
|
|
4843
4889
|
}
|
|
4890
|
+
FileUpload.displayName = "FileUpload";
|
|
4844
4891
|
var TextArea = React8.forwardRef(
|
|
4845
4892
|
({
|
|
4846
4893
|
className,
|
|
@@ -4918,6 +4965,1133 @@ var TextArea = React8.forwardRef(
|
|
|
4918
4965
|
}
|
|
4919
4966
|
);
|
|
4920
4967
|
TextArea.displayName = "TextArea";
|
|
4968
|
+
var ProfileImage = ({
|
|
4969
|
+
maxSizeMB = 2,
|
|
4970
|
+
subtitle,
|
|
4971
|
+
onError,
|
|
4972
|
+
maxFiles = Infinity,
|
|
4973
|
+
onRemove,
|
|
4974
|
+
image,
|
|
4975
|
+
...rest
|
|
4976
|
+
}) => {
|
|
4977
|
+
const maxSize = maxSizeMB * 1024 * 1024;
|
|
4978
|
+
const id = useId();
|
|
4979
|
+
const [
|
|
4980
|
+
{ files, isDragging, errors },
|
|
4981
|
+
{
|
|
4982
|
+
handleDragEnter,
|
|
4983
|
+
handleDragLeave,
|
|
4984
|
+
handleDragOver,
|
|
4985
|
+
handleDrop,
|
|
4986
|
+
openFileDialog,
|
|
4987
|
+
removeFile,
|
|
4988
|
+
getInputProps
|
|
4989
|
+
}
|
|
4990
|
+
] = useFileUpload({
|
|
4991
|
+
initialFiles: image ? [
|
|
4992
|
+
{
|
|
4993
|
+
id,
|
|
4994
|
+
url: image,
|
|
4995
|
+
name: image,
|
|
4996
|
+
size: 0,
|
|
4997
|
+
type: "image"
|
|
4998
|
+
}
|
|
4999
|
+
] : [],
|
|
5000
|
+
multiple: false,
|
|
5001
|
+
maxSize: maxSize > 0 ? maxSize : void 0,
|
|
5002
|
+
accept: "image/*",
|
|
5003
|
+
...rest,
|
|
5004
|
+
maxFiles
|
|
5005
|
+
});
|
|
5006
|
+
useEffect(() => {
|
|
5007
|
+
onError?.(errors);
|
|
5008
|
+
}, [errors, onError]);
|
|
5009
|
+
const [file] = files;
|
|
5010
|
+
return /* @__PURE__ */ jsxs("div", { className: "nebula-ds flex flex-col gap-3", children: [
|
|
5011
|
+
/* @__PURE__ */ jsx("div", { className: "nebula-ds flex justify-center", children: /* @__PURE__ */ jsxs(
|
|
5012
|
+
"div",
|
|
5013
|
+
{
|
|
5014
|
+
role: "button",
|
|
5015
|
+
onClick: openFileDialog,
|
|
5016
|
+
onDragEnter: handleDragEnter,
|
|
5017
|
+
onDragLeave: handleDragLeave,
|
|
5018
|
+
onDragOver: handleDragOver,
|
|
5019
|
+
onDrop: handleDrop,
|
|
5020
|
+
"data-dragging": isDragging || void 0,
|
|
5021
|
+
className: cn(
|
|
5022
|
+
"relative border border-transparent rounded-full size-fit",
|
|
5023
|
+
"bg-fileUpload-background hover:bg-fileUpload-backgroundHover transition-colors",
|
|
5024
|
+
!file && "border-dashed border-fileUpload-border"
|
|
5025
|
+
),
|
|
5026
|
+
"data-testid": "select-image-profile",
|
|
5027
|
+
children: [
|
|
5028
|
+
/* @__PURE__ */ jsx(
|
|
5029
|
+
"input",
|
|
5030
|
+
{
|
|
5031
|
+
...getInputProps(),
|
|
5032
|
+
className: "nebula-ds sr-only",
|
|
5033
|
+
"aria-label": "Upload file"
|
|
5034
|
+
}
|
|
5035
|
+
),
|
|
5036
|
+
/* @__PURE__ */ jsxs(
|
|
5037
|
+
"div",
|
|
5038
|
+
{
|
|
5039
|
+
className: "nebula-ds flex size-12 shrink-0 items-center justify-center rounded-full",
|
|
5040
|
+
"aria-hidden": "true",
|
|
5041
|
+
children: [
|
|
5042
|
+
file && file.preview && /* @__PURE__ */ jsx(
|
|
5043
|
+
"img",
|
|
5044
|
+
{
|
|
5045
|
+
src: file.preview,
|
|
5046
|
+
alt: file.file.name,
|
|
5047
|
+
className: "nebula-ds rounded-[inherit] object-cover h-full w-full"
|
|
5048
|
+
}
|
|
5049
|
+
),
|
|
5050
|
+
!file && /* @__PURE__ */ jsx(UserIcon, { className: "nebula-ds size-4 opacity-60 text-fileUpload-icon" })
|
|
5051
|
+
]
|
|
5052
|
+
}
|
|
5053
|
+
),
|
|
5054
|
+
file && /* @__PURE__ */ jsx(
|
|
5055
|
+
"button",
|
|
5056
|
+
{
|
|
5057
|
+
className: "nebula-ds box-border absolute flex items-center justify-center -top-1 -right-1 rounded-full size-5 text-profileImage-removeImageButton-icon border-2 border-profileImage-removeImageButton-border bg-profileImage-removeImageButton-background hover:bg-profileImage-removeImageButton-hover",
|
|
5058
|
+
"data-testid": "remove-profile-image",
|
|
5059
|
+
onClick: (e) => {
|
|
5060
|
+
e.stopPropagation();
|
|
5061
|
+
removeFile(file.id);
|
|
5062
|
+
onRemove?.();
|
|
5063
|
+
},
|
|
5064
|
+
type: "button",
|
|
5065
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "nebula-ds size-2" })
|
|
5066
|
+
}
|
|
5067
|
+
)
|
|
5068
|
+
]
|
|
5069
|
+
}
|
|
5070
|
+
) }),
|
|
5071
|
+
!!subtitle && /* @__PURE__ */ jsx(Paragraph, { className: "nebula-ds text-center", size: "sm", children: subtitle })
|
|
5072
|
+
] });
|
|
5073
|
+
};
|
|
5074
|
+
ProfileImage.displayName = "ProfileImage";
|
|
5075
|
+
function clamp(value, min, max) {
|
|
5076
|
+
return Math.min(Math.max(value, min), max);
|
|
5077
|
+
}
|
|
5078
|
+
var CropperContext = createContext(null);
|
|
5079
|
+
var useCropperContext = () => {
|
|
5080
|
+
const context = useContext(CropperContext);
|
|
5081
|
+
if (!context) {
|
|
5082
|
+
throw new Error("useCropperContext must be used within a Cropper.Root");
|
|
5083
|
+
}
|
|
5084
|
+
return context;
|
|
5085
|
+
};
|
|
5086
|
+
var CropperRoot = ({
|
|
5087
|
+
image,
|
|
5088
|
+
cropPadding = 25,
|
|
5089
|
+
aspectRatio = 1,
|
|
5090
|
+
minZoom = 1,
|
|
5091
|
+
maxZoom = 3,
|
|
5092
|
+
zoomSensitivity = 5e-3,
|
|
5093
|
+
keyboardStep = 10,
|
|
5094
|
+
className,
|
|
5095
|
+
style,
|
|
5096
|
+
zoom: zoomProp,
|
|
5097
|
+
onCropChange,
|
|
5098
|
+
onZoomChange,
|
|
5099
|
+
children,
|
|
5100
|
+
...restProps
|
|
5101
|
+
}) => {
|
|
5102
|
+
const descriptionId = useId();
|
|
5103
|
+
const [imgWidth, setImgWidth] = useState(null);
|
|
5104
|
+
const [imgHeight, setImgHeight] = useState(null);
|
|
5105
|
+
const containerRef = useRef(null);
|
|
5106
|
+
const [cropAreaWidth, setCropAreaWidth] = useState(0);
|
|
5107
|
+
const [cropAreaHeight, setCropAreaHeight] = useState(0);
|
|
5108
|
+
const [imageWrapperWidth, setImageWrapperWidth] = useState(0);
|
|
5109
|
+
const [imageWrapperHeight, setImageWrapperHeight] = useState(0);
|
|
5110
|
+
const [offsetX, setOffsetX] = useState(0);
|
|
5111
|
+
const [offsetY, setOffsetY] = useState(0);
|
|
5112
|
+
const [internalZoom, setInternalZoom] = useState(minZoom);
|
|
5113
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
5114
|
+
const dragStartPointRef = useRef({ x: 0, y: 0 });
|
|
5115
|
+
const dragStartOffsetRef = useRef({ x: 0, y: 0 });
|
|
5116
|
+
const latestRestrictedOffsetRef = useRef({
|
|
5117
|
+
x: offsetX,
|
|
5118
|
+
y: offsetY
|
|
5119
|
+
});
|
|
5120
|
+
const latestZoomRef = useRef(internalZoom);
|
|
5121
|
+
const isInitialSetupDoneRef = useRef(false);
|
|
5122
|
+
const initialPinchDistanceRef = useRef(0);
|
|
5123
|
+
const initialPinchZoomRef = useRef(1);
|
|
5124
|
+
const isPinchingRef = useRef(false);
|
|
5125
|
+
const hasWarnedRef = useRef(false);
|
|
5126
|
+
const isZoomControlled = zoomProp !== void 0;
|
|
5127
|
+
const effectiveZoom = isZoomControlled ? zoomProp : internalZoom;
|
|
5128
|
+
const updateZoom = useCallback(
|
|
5129
|
+
(newZoomValue) => {
|
|
5130
|
+
const clampedZoom = clamp(newZoomValue, minZoom, maxZoom);
|
|
5131
|
+
if (onZoomChange) {
|
|
5132
|
+
onZoomChange(clampedZoom);
|
|
5133
|
+
} else if (!isZoomControlled) {
|
|
5134
|
+
setInternalZoom(clampedZoom);
|
|
5135
|
+
}
|
|
5136
|
+
return clampedZoom;
|
|
5137
|
+
},
|
|
5138
|
+
[minZoom, maxZoom, onZoomChange, isZoomControlled]
|
|
5139
|
+
);
|
|
5140
|
+
useEffect(() => {
|
|
5141
|
+
latestZoomRef.current = effectiveZoom;
|
|
5142
|
+
}, [effectiveZoom]);
|
|
5143
|
+
useEffect(() => {
|
|
5144
|
+
setOffsetX(0);
|
|
5145
|
+
setOffsetY(0);
|
|
5146
|
+
if (!isZoomControlled) {
|
|
5147
|
+
setInternalZoom(minZoom);
|
|
5148
|
+
}
|
|
5149
|
+
isInitialSetupDoneRef.current = false;
|
|
5150
|
+
if (!image) {
|
|
5151
|
+
setImgWidth(null);
|
|
5152
|
+
setImgHeight(null);
|
|
5153
|
+
return;
|
|
5154
|
+
}
|
|
5155
|
+
let isMounted = true;
|
|
5156
|
+
const img = new Image();
|
|
5157
|
+
img.onload = () => {
|
|
5158
|
+
if (isMounted) {
|
|
5159
|
+
setImgWidth(img.naturalWidth);
|
|
5160
|
+
setImgHeight(img.naturalHeight);
|
|
5161
|
+
}
|
|
5162
|
+
};
|
|
5163
|
+
img.onerror = () => {
|
|
5164
|
+
if (isMounted) {
|
|
5165
|
+
setImgWidth(null);
|
|
5166
|
+
setImgHeight(null);
|
|
5167
|
+
}
|
|
5168
|
+
};
|
|
5169
|
+
img.src = image;
|
|
5170
|
+
return () => {
|
|
5171
|
+
isMounted = false;
|
|
5172
|
+
};
|
|
5173
|
+
}, [image, minZoom, isZoomControlled]);
|
|
5174
|
+
const updateCropAreaDimensions = useCallback(
|
|
5175
|
+
(containerWidth, containerHeight) => {
|
|
5176
|
+
if (containerWidth <= 0 || containerHeight <= 0) {
|
|
5177
|
+
setCropAreaWidth(0);
|
|
5178
|
+
setCropAreaHeight(0);
|
|
5179
|
+
return;
|
|
5180
|
+
}
|
|
5181
|
+
const maxPossibleWidth = Math.max(0, containerWidth - cropPadding * 2);
|
|
5182
|
+
const maxPossibleHeight = Math.max(0, containerHeight - cropPadding * 2);
|
|
5183
|
+
let targetCropW = 0;
|
|
5184
|
+
let targetCropH = 0;
|
|
5185
|
+
if (maxPossibleWidth / aspectRatio >= maxPossibleHeight) {
|
|
5186
|
+
targetCropH = maxPossibleHeight;
|
|
5187
|
+
targetCropW = targetCropH * aspectRatio;
|
|
5188
|
+
} else {
|
|
5189
|
+
targetCropW = maxPossibleWidth;
|
|
5190
|
+
targetCropH = targetCropW / aspectRatio;
|
|
5191
|
+
}
|
|
5192
|
+
setCropAreaWidth(targetCropW);
|
|
5193
|
+
setCropAreaHeight(targetCropH);
|
|
5194
|
+
},
|
|
5195
|
+
[aspectRatio, cropPadding]
|
|
5196
|
+
);
|
|
5197
|
+
useEffect(() => {
|
|
5198
|
+
const element = containerRef.current;
|
|
5199
|
+
if (!element) return;
|
|
5200
|
+
const observer = new ResizeObserver((entries) => {
|
|
5201
|
+
for (const entry of entries) {
|
|
5202
|
+
const { width, height } = entry.contentRect;
|
|
5203
|
+
if (width > 0 && height > 0) updateCropAreaDimensions(width, height);
|
|
5204
|
+
}
|
|
5205
|
+
});
|
|
5206
|
+
observer.observe(element);
|
|
5207
|
+
const initialWidth = element.clientWidth;
|
|
5208
|
+
const initialHeight = element.clientHeight;
|
|
5209
|
+
if (initialWidth > 0 && initialHeight > 0)
|
|
5210
|
+
updateCropAreaDimensions(initialWidth, initialHeight);
|
|
5211
|
+
return () => observer.disconnect();
|
|
5212
|
+
}, [updateCropAreaDimensions]);
|
|
5213
|
+
useEffect(() => {
|
|
5214
|
+
if (cropAreaWidth <= 0 || cropAreaHeight <= 0 || !imgWidth || !imgHeight) {
|
|
5215
|
+
setImageWrapperWidth(0);
|
|
5216
|
+
setImageWrapperHeight(0);
|
|
5217
|
+
return;
|
|
5218
|
+
}
|
|
5219
|
+
const naturalAspect = imgWidth / imgHeight;
|
|
5220
|
+
const cropAspect = cropAreaWidth / cropAreaHeight;
|
|
5221
|
+
let targetWrapperWidth = 0;
|
|
5222
|
+
let targetWrapperHeight = 0;
|
|
5223
|
+
if (naturalAspect >= cropAspect) {
|
|
5224
|
+
targetWrapperHeight = cropAreaHeight;
|
|
5225
|
+
targetWrapperWidth = targetWrapperHeight * naturalAspect;
|
|
5226
|
+
} else {
|
|
5227
|
+
targetWrapperWidth = cropAreaWidth;
|
|
5228
|
+
targetWrapperHeight = targetWrapperWidth / naturalAspect;
|
|
5229
|
+
}
|
|
5230
|
+
setImageWrapperWidth(targetWrapperWidth);
|
|
5231
|
+
setImageWrapperHeight(targetWrapperHeight);
|
|
5232
|
+
}, [cropAreaWidth, cropAreaHeight, imgWidth, imgHeight]);
|
|
5233
|
+
const restrictOffset = useCallback(
|
|
5234
|
+
(dragOffsetX, dragOffsetY, currentZoom) => {
|
|
5235
|
+
if (imageWrapperWidth <= 0 || imageWrapperHeight <= 0 || cropAreaWidth <= 0 || cropAreaHeight <= 0)
|
|
5236
|
+
return { x: 0, y: 0 };
|
|
5237
|
+
const effectiveWrapperWidth = imageWrapperWidth * currentZoom;
|
|
5238
|
+
const effectiveWrapperHeight = imageWrapperHeight * currentZoom;
|
|
5239
|
+
const maxDragX = Math.max(0, (effectiveWrapperWidth - cropAreaWidth) / 2);
|
|
5240
|
+
const maxDragY = Math.max(
|
|
5241
|
+
0,
|
|
5242
|
+
(effectiveWrapperHeight - cropAreaHeight) / 2
|
|
5243
|
+
);
|
|
5244
|
+
return {
|
|
5245
|
+
x: clamp(dragOffsetX, -maxDragX, maxDragX),
|
|
5246
|
+
y: clamp(dragOffsetY, -maxDragY, maxDragY)
|
|
5247
|
+
};
|
|
5248
|
+
},
|
|
5249
|
+
[imageWrapperWidth, imageWrapperHeight, cropAreaWidth, cropAreaHeight]
|
|
5250
|
+
);
|
|
5251
|
+
const calculateCropData = useCallback(
|
|
5252
|
+
(finalOffsetX, finalOffsetY, finalZoom) => {
|
|
5253
|
+
const currentOffsetX = finalOffsetX !== void 0 ? finalOffsetX : latestRestrictedOffsetRef.current.x;
|
|
5254
|
+
const currentOffsetY = finalOffsetY !== void 0 ? finalOffsetY : latestRestrictedOffsetRef.current.y;
|
|
5255
|
+
const currentZoom = finalZoom !== void 0 ? finalZoom : effectiveZoom;
|
|
5256
|
+
if (!imgWidth || !imgHeight || imageWrapperWidth <= 0 || imageWrapperHeight <= 0 || cropAreaWidth <= 0 || cropAreaHeight <= 0)
|
|
5257
|
+
return null;
|
|
5258
|
+
const scaledWrapperWidth = imageWrapperWidth * currentZoom;
|
|
5259
|
+
const scaledWrapperHeight = imageWrapperHeight * currentZoom;
|
|
5260
|
+
const topLeftOffsetX = currentOffsetX + (cropAreaWidth - scaledWrapperWidth) / 2;
|
|
5261
|
+
const topLeftOffsetY = currentOffsetY + (cropAreaHeight - scaledWrapperHeight) / 2;
|
|
5262
|
+
const baseScale = imgWidth / imageWrapperWidth;
|
|
5263
|
+
if (isNaN(baseScale) || baseScale === 0) return null;
|
|
5264
|
+
const sx = -topLeftOffsetX * baseScale / currentZoom;
|
|
5265
|
+
const sy = -topLeftOffsetY * baseScale / currentZoom;
|
|
5266
|
+
const sWidth = cropAreaWidth * baseScale / currentZoom;
|
|
5267
|
+
const sHeight = cropAreaHeight * baseScale / currentZoom;
|
|
5268
|
+
const finalX = clamp(Math.round(sx), 0, imgWidth);
|
|
5269
|
+
const finalY = clamp(Math.round(sy), 0, imgHeight);
|
|
5270
|
+
const finalWidth = clamp(Math.round(sWidth), 0, imgWidth - finalX);
|
|
5271
|
+
const finalHeight = clamp(Math.round(sHeight), 0, imgHeight - finalY);
|
|
5272
|
+
if (finalWidth <= 0 || finalHeight <= 0) return null;
|
|
5273
|
+
return { x: finalX, y: finalY, width: finalWidth, height: finalHeight };
|
|
5274
|
+
},
|
|
5275
|
+
[
|
|
5276
|
+
imgWidth,
|
|
5277
|
+
imgHeight,
|
|
5278
|
+
imageWrapperWidth,
|
|
5279
|
+
imageWrapperHeight,
|
|
5280
|
+
cropAreaWidth,
|
|
5281
|
+
cropAreaHeight,
|
|
5282
|
+
effectiveZoom
|
|
5283
|
+
]
|
|
5284
|
+
);
|
|
5285
|
+
useEffect(() => {
|
|
5286
|
+
if (imageWrapperWidth > 0 && imageWrapperHeight > 0 && cropAreaWidth > 0 && cropAreaHeight > 0) {
|
|
5287
|
+
const currentZoomForSetup = effectiveZoom;
|
|
5288
|
+
if (!isInitialSetupDoneRef.current) {
|
|
5289
|
+
const initialX = 0;
|
|
5290
|
+
const initialY = 0;
|
|
5291
|
+
const restrictedInitial = restrictOffset(
|
|
5292
|
+
initialX,
|
|
5293
|
+
initialY,
|
|
5294
|
+
currentZoomForSetup
|
|
5295
|
+
);
|
|
5296
|
+
setOffsetX(restrictedInitial.x);
|
|
5297
|
+
setOffsetY(restrictedInitial.y);
|
|
5298
|
+
if (!isZoomControlled) setInternalZoom(currentZoomForSetup);
|
|
5299
|
+
dragStartOffsetRef.current = restrictedInitial;
|
|
5300
|
+
latestRestrictedOffsetRef.current = restrictedInitial;
|
|
5301
|
+
latestZoomRef.current = currentZoomForSetup;
|
|
5302
|
+
if (onCropChange)
|
|
5303
|
+
onCropChange(
|
|
5304
|
+
calculateCropData(
|
|
5305
|
+
restrictedInitial.x,
|
|
5306
|
+
restrictedInitial.y,
|
|
5307
|
+
currentZoomForSetup
|
|
5308
|
+
)
|
|
5309
|
+
);
|
|
5310
|
+
isInitialSetupDoneRef.current = true;
|
|
5311
|
+
} else {
|
|
5312
|
+
const restrictedCurrent = restrictOffset(
|
|
5313
|
+
latestRestrictedOffsetRef.current.x,
|
|
5314
|
+
latestRestrictedOffsetRef.current.y,
|
|
5315
|
+
currentZoomForSetup
|
|
5316
|
+
);
|
|
5317
|
+
if (restrictedCurrent.x !== latestRestrictedOffsetRef.current.x || restrictedCurrent.y !== latestRestrictedOffsetRef.current.y) {
|
|
5318
|
+
setOffsetX(restrictedCurrent.x);
|
|
5319
|
+
setOffsetY(restrictedCurrent.y);
|
|
5320
|
+
latestRestrictedOffsetRef.current = restrictedCurrent;
|
|
5321
|
+
dragStartOffsetRef.current = restrictedCurrent;
|
|
5322
|
+
}
|
|
5323
|
+
if (onCropChange)
|
|
5324
|
+
onCropChange(
|
|
5325
|
+
calculateCropData(
|
|
5326
|
+
restrictedCurrent.x,
|
|
5327
|
+
restrictedCurrent.y,
|
|
5328
|
+
currentZoomForSetup
|
|
5329
|
+
)
|
|
5330
|
+
);
|
|
5331
|
+
}
|
|
5332
|
+
} else {
|
|
5333
|
+
isInitialSetupDoneRef.current = false;
|
|
5334
|
+
setOffsetX(0);
|
|
5335
|
+
setOffsetY(0);
|
|
5336
|
+
if (!isZoomControlled) setInternalZoom(minZoom);
|
|
5337
|
+
dragStartOffsetRef.current = { x: 0, y: 0 };
|
|
5338
|
+
latestRestrictedOffsetRef.current = { x: 0, y: 0 };
|
|
5339
|
+
latestZoomRef.current = effectiveZoom;
|
|
5340
|
+
if (onCropChange) onCropChange(null);
|
|
5341
|
+
}
|
|
5342
|
+
}, [
|
|
5343
|
+
imageWrapperWidth,
|
|
5344
|
+
imgHeight,
|
|
5345
|
+
cropAreaWidth,
|
|
5346
|
+
cropAreaHeight,
|
|
5347
|
+
restrictOffset,
|
|
5348
|
+
onCropChange,
|
|
5349
|
+
calculateCropData,
|
|
5350
|
+
minZoom,
|
|
5351
|
+
effectiveZoom,
|
|
5352
|
+
isZoomControlled,
|
|
5353
|
+
updateZoom,
|
|
5354
|
+
imageWrapperHeight
|
|
5355
|
+
]);
|
|
5356
|
+
useEffect(() => {
|
|
5357
|
+
const checkTimeout = setTimeout(() => {
|
|
5358
|
+
if (containerRef.current && !hasWarnedRef.current) {
|
|
5359
|
+
const hasDescription = document.getElementById(descriptionId);
|
|
5360
|
+
if (!hasDescription) {
|
|
5361
|
+
hasWarnedRef.current = true;
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5364
|
+
}, 100);
|
|
5365
|
+
return () => clearTimeout(checkTimeout);
|
|
5366
|
+
}, [descriptionId]);
|
|
5367
|
+
const handleInteractionEnd = useCallback(() => {
|
|
5368
|
+
if (onCropChange) {
|
|
5369
|
+
const finalData = calculateCropData(
|
|
5370
|
+
latestRestrictedOffsetRef.current.x,
|
|
5371
|
+
latestRestrictedOffsetRef.current.y,
|
|
5372
|
+
effectiveZoom
|
|
5373
|
+
);
|
|
5374
|
+
onCropChange(finalData);
|
|
5375
|
+
}
|
|
5376
|
+
}, [onCropChange, calculateCropData, effectiveZoom]);
|
|
5377
|
+
const handleMouseDown = useCallback(
|
|
5378
|
+
(e) => {
|
|
5379
|
+
if (e.button !== 0 || !containerRef.current) return;
|
|
5380
|
+
e.preventDefault();
|
|
5381
|
+
setIsDragging(true);
|
|
5382
|
+
isPinchingRef.current = false;
|
|
5383
|
+
dragStartPointRef.current = { x: e.clientX, y: e.clientY };
|
|
5384
|
+
dragStartOffsetRef.current = {
|
|
5385
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5386
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5387
|
+
};
|
|
5388
|
+
const handleMouseMove = (ev) => {
|
|
5389
|
+
const deltaX = ev.clientX - dragStartPointRef.current.x;
|
|
5390
|
+
const deltaY = ev.clientY - dragStartPointRef.current.y;
|
|
5391
|
+
const targetOffsetX = dragStartOffsetRef.current.x + deltaX;
|
|
5392
|
+
const targetOffsetY = dragStartOffsetRef.current.y + deltaY;
|
|
5393
|
+
const restricted = restrictOffset(
|
|
5394
|
+
targetOffsetX,
|
|
5395
|
+
targetOffsetY,
|
|
5396
|
+
effectiveZoom
|
|
5397
|
+
);
|
|
5398
|
+
latestRestrictedOffsetRef.current = restricted;
|
|
5399
|
+
setOffsetX(restricted.x);
|
|
5400
|
+
setOffsetY(restricted.y);
|
|
5401
|
+
};
|
|
5402
|
+
const handleMouseUp = () => {
|
|
5403
|
+
setIsDragging(false);
|
|
5404
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
5405
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
5406
|
+
handleInteractionEnd();
|
|
5407
|
+
};
|
|
5408
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
5409
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
5410
|
+
},
|
|
5411
|
+
[restrictOffset, effectiveZoom, handleInteractionEnd]
|
|
5412
|
+
);
|
|
5413
|
+
const handleWheel = useCallback(
|
|
5414
|
+
(e) => {
|
|
5415
|
+
e.preventDefault();
|
|
5416
|
+
e.stopPropagation();
|
|
5417
|
+
if (!containerRef.current || imageWrapperWidth <= 0 || imageWrapperHeight <= 0)
|
|
5418
|
+
return;
|
|
5419
|
+
const currentZoom = latestZoomRef.current;
|
|
5420
|
+
const currentOffsetX = latestRestrictedOffsetRef.current.x;
|
|
5421
|
+
const currentOffsetY = latestRestrictedOffsetRef.current.y;
|
|
5422
|
+
const delta = e.deltaY * -zoomSensitivity;
|
|
5423
|
+
const targetZoom = currentZoom + delta;
|
|
5424
|
+
if (clamp(targetZoom, minZoom, maxZoom) === currentZoom) return;
|
|
5425
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
5426
|
+
const pointerX = e.clientX - rect.left - rect.width / 2;
|
|
5427
|
+
const pointerY = e.clientY - rect.top - rect.height / 2;
|
|
5428
|
+
const imagePointX = (pointerX - currentOffsetX) / currentZoom;
|
|
5429
|
+
const imagePointY = (pointerY - currentOffsetY) / currentZoom;
|
|
5430
|
+
const finalNewZoom = updateZoom(targetZoom);
|
|
5431
|
+
const newOffsetX = pointerX - imagePointX * finalNewZoom;
|
|
5432
|
+
const newOffsetY = pointerY - imagePointY * finalNewZoom;
|
|
5433
|
+
const restrictedNewOffset = restrictOffset(
|
|
5434
|
+
newOffsetX,
|
|
5435
|
+
newOffsetY,
|
|
5436
|
+
finalNewZoom
|
|
5437
|
+
);
|
|
5438
|
+
setOffsetX(restrictedNewOffset.x);
|
|
5439
|
+
setOffsetY(restrictedNewOffset.y);
|
|
5440
|
+
latestRestrictedOffsetRef.current = restrictedNewOffset;
|
|
5441
|
+
if (onCropChange) {
|
|
5442
|
+
const finalData = calculateCropData(
|
|
5443
|
+
restrictedNewOffset.x,
|
|
5444
|
+
restrictedNewOffset.y,
|
|
5445
|
+
finalNewZoom
|
|
5446
|
+
);
|
|
5447
|
+
onCropChange(finalData);
|
|
5448
|
+
}
|
|
5449
|
+
},
|
|
5450
|
+
[
|
|
5451
|
+
restrictOffset,
|
|
5452
|
+
calculateCropData,
|
|
5453
|
+
imageWrapperWidth,
|
|
5454
|
+
imageWrapperHeight,
|
|
5455
|
+
onCropChange,
|
|
5456
|
+
minZoom,
|
|
5457
|
+
maxZoom,
|
|
5458
|
+
zoomSensitivity,
|
|
5459
|
+
updateZoom
|
|
5460
|
+
]
|
|
5461
|
+
);
|
|
5462
|
+
const getPinchDistance = (touches) => Math.sqrt(
|
|
5463
|
+
Math.pow(touches[1].clientX - touches[0].clientX, 2) + Math.pow(touches[1].clientY - touches[0].clientY, 2)
|
|
5464
|
+
);
|
|
5465
|
+
const getPinchCenter = (touches) => ({
|
|
5466
|
+
x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
5467
|
+
y: (touches[0].clientY + touches[1].clientY) / 2
|
|
5468
|
+
});
|
|
5469
|
+
const handleTouchStart = useCallback(
|
|
5470
|
+
(e) => {
|
|
5471
|
+
if (!containerRef.current || imageWrapperWidth <= 0 || imageWrapperHeight <= 0)
|
|
5472
|
+
return;
|
|
5473
|
+
e.preventDefault();
|
|
5474
|
+
const touches = e.touches;
|
|
5475
|
+
if (touches.length === 1) {
|
|
5476
|
+
setIsDragging(true);
|
|
5477
|
+
isPinchingRef.current = false;
|
|
5478
|
+
dragStartPointRef.current = {
|
|
5479
|
+
x: touches[0].clientX,
|
|
5480
|
+
y: touches[0].clientY
|
|
5481
|
+
};
|
|
5482
|
+
dragStartOffsetRef.current = {
|
|
5483
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5484
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5485
|
+
};
|
|
5486
|
+
} else if (touches.length === 2) {
|
|
5487
|
+
setIsDragging(false);
|
|
5488
|
+
isPinchingRef.current = true;
|
|
5489
|
+
initialPinchDistanceRef.current = getPinchDistance(touches);
|
|
5490
|
+
initialPinchZoomRef.current = latestZoomRef.current;
|
|
5491
|
+
dragStartOffsetRef.current = {
|
|
5492
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5493
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5494
|
+
};
|
|
5495
|
+
}
|
|
5496
|
+
},
|
|
5497
|
+
[imageWrapperWidth, imageWrapperHeight]
|
|
5498
|
+
);
|
|
5499
|
+
const handleTouchMove = useCallback(
|
|
5500
|
+
(e) => {
|
|
5501
|
+
if (!containerRef.current || imageWrapperWidth <= 0 || imageWrapperHeight <= 0)
|
|
5502
|
+
return;
|
|
5503
|
+
e.preventDefault();
|
|
5504
|
+
const touches = e.touches;
|
|
5505
|
+
if (touches.length === 1 && isDragging && !isPinchingRef.current) {
|
|
5506
|
+
const deltaX = touches[0].clientX - dragStartPointRef.current.x;
|
|
5507
|
+
const deltaY = touches[0].clientY - dragStartPointRef.current.y;
|
|
5508
|
+
const targetOffsetX = dragStartOffsetRef.current.x + deltaX;
|
|
5509
|
+
const targetOffsetY = dragStartOffsetRef.current.y + deltaY;
|
|
5510
|
+
const restricted = restrictOffset(
|
|
5511
|
+
targetOffsetX,
|
|
5512
|
+
targetOffsetY,
|
|
5513
|
+
effectiveZoom
|
|
5514
|
+
);
|
|
5515
|
+
latestRestrictedOffsetRef.current = restricted;
|
|
5516
|
+
setOffsetX(restricted.x);
|
|
5517
|
+
setOffsetY(restricted.y);
|
|
5518
|
+
} else if (touches.length === 2 && isPinchingRef.current) {
|
|
5519
|
+
const currentPinchDistance = getPinchDistance(touches);
|
|
5520
|
+
const scale = currentPinchDistance / initialPinchDistanceRef.current;
|
|
5521
|
+
const currentZoom = initialPinchZoomRef.current;
|
|
5522
|
+
const targetZoom = currentZoom * scale;
|
|
5523
|
+
if (clamp(targetZoom, minZoom, maxZoom) === latestZoomRef.current)
|
|
5524
|
+
return;
|
|
5525
|
+
const pinchCenter = getPinchCenter(touches);
|
|
5526
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
5527
|
+
const pinchCenterX = pinchCenter.x - rect.left - rect.width / 2;
|
|
5528
|
+
const pinchCenterY = pinchCenter.y - rect.top - rect.height / 2;
|
|
5529
|
+
const currentOffsetX = dragStartOffsetRef.current.x;
|
|
5530
|
+
const currentOffsetY = dragStartOffsetRef.current.y;
|
|
5531
|
+
const imagePointX = (pinchCenterX - currentOffsetX) / currentZoom;
|
|
5532
|
+
const imagePointY = (pinchCenterY - currentOffsetY) / currentZoom;
|
|
5533
|
+
const finalNewZoom = updateZoom(targetZoom);
|
|
5534
|
+
const newOffsetX = pinchCenterX - imagePointX * finalNewZoom;
|
|
5535
|
+
const newOffsetY = pinchCenterY - imagePointY * finalNewZoom;
|
|
5536
|
+
const restrictedNewOffset = restrictOffset(
|
|
5537
|
+
newOffsetX,
|
|
5538
|
+
newOffsetY,
|
|
5539
|
+
finalNewZoom
|
|
5540
|
+
);
|
|
5541
|
+
setOffsetX(restrictedNewOffset.x);
|
|
5542
|
+
setOffsetY(restrictedNewOffset.y);
|
|
5543
|
+
latestRestrictedOffsetRef.current = restrictedNewOffset;
|
|
5544
|
+
if (onCropChange) {
|
|
5545
|
+
const finalData = calculateCropData(
|
|
5546
|
+
restrictedNewOffset.x,
|
|
5547
|
+
restrictedNewOffset.y,
|
|
5548
|
+
finalNewZoom
|
|
5549
|
+
);
|
|
5550
|
+
onCropChange(finalData);
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
},
|
|
5554
|
+
[
|
|
5555
|
+
isDragging,
|
|
5556
|
+
restrictOffset,
|
|
5557
|
+
minZoom,
|
|
5558
|
+
maxZoom,
|
|
5559
|
+
imageWrapperWidth,
|
|
5560
|
+
imageWrapperHeight,
|
|
5561
|
+
effectiveZoom,
|
|
5562
|
+
updateZoom,
|
|
5563
|
+
onCropChange,
|
|
5564
|
+
calculateCropData
|
|
5565
|
+
]
|
|
5566
|
+
);
|
|
5567
|
+
const handleTouchEnd = useCallback(
|
|
5568
|
+
(e) => {
|
|
5569
|
+
e.preventDefault();
|
|
5570
|
+
const touches = e.touches;
|
|
5571
|
+
if (isPinchingRef.current && touches.length < 2) {
|
|
5572
|
+
isPinchingRef.current = false;
|
|
5573
|
+
if (touches.length === 1) {
|
|
5574
|
+
setIsDragging(true);
|
|
5575
|
+
dragStartPointRef.current = {
|
|
5576
|
+
x: touches[0].clientX,
|
|
5577
|
+
y: touches[0].clientY
|
|
5578
|
+
};
|
|
5579
|
+
dragStartOffsetRef.current = {
|
|
5580
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5581
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5582
|
+
};
|
|
5583
|
+
} else {
|
|
5584
|
+
setIsDragging(false);
|
|
5585
|
+
handleInteractionEnd();
|
|
5586
|
+
}
|
|
5587
|
+
} else if (isDragging && touches.length === 0) {
|
|
5588
|
+
setIsDragging(false);
|
|
5589
|
+
handleInteractionEnd();
|
|
5590
|
+
}
|
|
5591
|
+
},
|
|
5592
|
+
[isDragging, handleInteractionEnd]
|
|
5593
|
+
);
|
|
5594
|
+
const handleKeyDown = useCallback(
|
|
5595
|
+
(e) => {
|
|
5596
|
+
if (imageWrapperWidth <= 0) return;
|
|
5597
|
+
let targetOffsetX = latestRestrictedOffsetRef.current.x;
|
|
5598
|
+
let targetOffsetY = latestRestrictedOffsetRef.current.y;
|
|
5599
|
+
let moved = false;
|
|
5600
|
+
switch (e.key) {
|
|
5601
|
+
case "ArrowUp":
|
|
5602
|
+
targetOffsetY += keyboardStep;
|
|
5603
|
+
moved = true;
|
|
5604
|
+
break;
|
|
5605
|
+
case "ArrowDown":
|
|
5606
|
+
targetOffsetY -= keyboardStep;
|
|
5607
|
+
moved = true;
|
|
5608
|
+
break;
|
|
5609
|
+
case "ArrowLeft":
|
|
5610
|
+
targetOffsetX += keyboardStep;
|
|
5611
|
+
moved = true;
|
|
5612
|
+
break;
|
|
5613
|
+
case "ArrowRight":
|
|
5614
|
+
targetOffsetX -= keyboardStep;
|
|
5615
|
+
moved = true;
|
|
5616
|
+
break;
|
|
5617
|
+
default:
|
|
5618
|
+
return;
|
|
5619
|
+
}
|
|
5620
|
+
if (moved) {
|
|
5621
|
+
e.preventDefault();
|
|
5622
|
+
const restricted = restrictOffset(
|
|
5623
|
+
targetOffsetX,
|
|
5624
|
+
targetOffsetY,
|
|
5625
|
+
effectiveZoom
|
|
5626
|
+
);
|
|
5627
|
+
if (restricted.x !== latestRestrictedOffsetRef.current.x || restricted.y !== latestRestrictedOffsetRef.current.y) {
|
|
5628
|
+
latestRestrictedOffsetRef.current = restricted;
|
|
5629
|
+
setOffsetX(restricted.x);
|
|
5630
|
+
setOffsetY(restricted.y);
|
|
5631
|
+
}
|
|
5632
|
+
}
|
|
5633
|
+
},
|
|
5634
|
+
[keyboardStep, imageWrapperWidth, restrictOffset, effectiveZoom]
|
|
5635
|
+
);
|
|
5636
|
+
const handleKeyUp = useCallback(
|
|
5637
|
+
(e) => {
|
|
5638
|
+
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
5639
|
+
handleInteractionEnd();
|
|
5640
|
+
}
|
|
5641
|
+
},
|
|
5642
|
+
[handleInteractionEnd]
|
|
5643
|
+
);
|
|
5644
|
+
useEffect(() => {
|
|
5645
|
+
const node = containerRef.current;
|
|
5646
|
+
if (!node) return;
|
|
5647
|
+
const options = { passive: false };
|
|
5648
|
+
node.addEventListener("wheel", handleWheel, options);
|
|
5649
|
+
node.addEventListener("touchstart", handleTouchStart, options);
|
|
5650
|
+
node.addEventListener("touchmove", handleTouchMove, options);
|
|
5651
|
+
node.addEventListener("touchend", handleTouchEnd, options);
|
|
5652
|
+
node.addEventListener("touchcancel", handleTouchEnd, options);
|
|
5653
|
+
return () => {
|
|
5654
|
+
node.removeEventListener("wheel", handleWheel, options);
|
|
5655
|
+
node.removeEventListener("touchstart", handleTouchStart, options);
|
|
5656
|
+
node.removeEventListener("touchmove", handleTouchMove, options);
|
|
5657
|
+
node.removeEventListener("touchend", handleTouchEnd, options);
|
|
5658
|
+
node.removeEventListener("touchcancel", handleTouchEnd, options);
|
|
5659
|
+
};
|
|
5660
|
+
}, [handleWheel, handleTouchStart, handleTouchMove, handleTouchEnd]);
|
|
5661
|
+
const getRootProps = useCallback(
|
|
5662
|
+
() => ({
|
|
5663
|
+
className,
|
|
5664
|
+
style,
|
|
5665
|
+
onMouseDown: handleMouseDown,
|
|
5666
|
+
onKeyDown: handleKeyDown,
|
|
5667
|
+
onKeyUp: handleKeyUp,
|
|
5668
|
+
tabIndex: 0,
|
|
5669
|
+
role: "application",
|
|
5670
|
+
"aria-label": "Interactive image cropper",
|
|
5671
|
+
"aria-describedby": descriptionId,
|
|
5672
|
+
"aria-valuemin": minZoom,
|
|
5673
|
+
"aria-valuemax": maxZoom,
|
|
5674
|
+
"aria-valuenow": effectiveZoom,
|
|
5675
|
+
"aria-valuetext": `Zoom: ${Math.round(effectiveZoom * 100)}%`
|
|
5676
|
+
}),
|
|
5677
|
+
[
|
|
5678
|
+
className,
|
|
5679
|
+
style,
|
|
5680
|
+
handleMouseDown,
|
|
5681
|
+
handleKeyDown,
|
|
5682
|
+
handleKeyUp,
|
|
5683
|
+
descriptionId,
|
|
5684
|
+
minZoom,
|
|
5685
|
+
maxZoom,
|
|
5686
|
+
effectiveZoom
|
|
5687
|
+
]
|
|
5688
|
+
);
|
|
5689
|
+
const getImageWrapperStyle = useCallback(
|
|
5690
|
+
() => ({
|
|
5691
|
+
width: imageWrapperWidth,
|
|
5692
|
+
height: imageWrapperHeight,
|
|
5693
|
+
transform: `translate3d(${offsetX}px, ${offsetY}px, 0px) scale(${effectiveZoom})`,
|
|
5694
|
+
position: "absolute",
|
|
5695
|
+
left: `calc(50% - ${imageWrapperWidth / 2}px)`,
|
|
5696
|
+
top: `calc(50% - ${imageWrapperHeight / 2}px)`,
|
|
5697
|
+
willChange: "transform"
|
|
5698
|
+
}),
|
|
5699
|
+
[imageWrapperWidth, imageWrapperHeight, offsetX, offsetY, effectiveZoom]
|
|
5700
|
+
);
|
|
5701
|
+
const getImageProps = useCallback(
|
|
5702
|
+
() => ({
|
|
5703
|
+
src: image,
|
|
5704
|
+
alt: "Image being cropped",
|
|
5705
|
+
draggable: false,
|
|
5706
|
+
"aria-hidden": true
|
|
5707
|
+
}),
|
|
5708
|
+
[image]
|
|
5709
|
+
);
|
|
5710
|
+
const getCropAreaStyle = useCallback(
|
|
5711
|
+
() => ({
|
|
5712
|
+
width: cropAreaWidth,
|
|
5713
|
+
height: cropAreaHeight
|
|
5714
|
+
}),
|
|
5715
|
+
[cropAreaWidth, cropAreaHeight]
|
|
5716
|
+
);
|
|
5717
|
+
const getCropAreaProps = useCallback(
|
|
5718
|
+
() => ({
|
|
5719
|
+
style: getCropAreaStyle(),
|
|
5720
|
+
"aria-hidden": true
|
|
5721
|
+
}),
|
|
5722
|
+
[getCropAreaStyle]
|
|
5723
|
+
);
|
|
5724
|
+
const contextValue = {
|
|
5725
|
+
containerRef,
|
|
5726
|
+
image,
|
|
5727
|
+
imgWidth,
|
|
5728
|
+
imgHeight,
|
|
5729
|
+
cropAreaWidth,
|
|
5730
|
+
cropAreaHeight,
|
|
5731
|
+
imageWrapperWidth,
|
|
5732
|
+
imageWrapperHeight,
|
|
5733
|
+
offsetX,
|
|
5734
|
+
offsetY,
|
|
5735
|
+
effectiveZoom,
|
|
5736
|
+
minZoom,
|
|
5737
|
+
maxZoom,
|
|
5738
|
+
getRootProps,
|
|
5739
|
+
getImageProps,
|
|
5740
|
+
getImageWrapperStyle,
|
|
5741
|
+
getCropAreaProps,
|
|
5742
|
+
getCropAreaStyle,
|
|
5743
|
+
descriptionId
|
|
5744
|
+
};
|
|
5745
|
+
return /* @__PURE__ */ jsx(CropperContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { ref: containerRef, ...getRootProps(), ...restProps, children }) });
|
|
5746
|
+
};
|
|
5747
|
+
var CropperImage = ({ className, ...restProps }) => {
|
|
5748
|
+
const { image, getImageProps, getImageWrapperStyle } = useCropperContext();
|
|
5749
|
+
if (!image) return null;
|
|
5750
|
+
const imageProps = getImageProps();
|
|
5751
|
+
return /* @__PURE__ */ jsx("div", { style: getImageWrapperStyle(), children: /* @__PURE__ */ jsx("img", { ...imageProps, className, ...restProps }) });
|
|
5752
|
+
};
|
|
5753
|
+
var CropperCropArea = ({
|
|
5754
|
+
className,
|
|
5755
|
+
style,
|
|
5756
|
+
...restProps
|
|
5757
|
+
}) => {
|
|
5758
|
+
const { cropAreaWidth, cropAreaHeight, getCropAreaProps, getCropAreaStyle } = useCropperContext();
|
|
5759
|
+
if (cropAreaWidth <= 0 || cropAreaHeight <= 0) return null;
|
|
5760
|
+
const areaProps = getCropAreaProps();
|
|
5761
|
+
const areaStyle = getCropAreaStyle();
|
|
5762
|
+
return /* @__PURE__ */ jsx(
|
|
5763
|
+
"div",
|
|
5764
|
+
{
|
|
5765
|
+
...areaProps,
|
|
5766
|
+
style: { ...areaProps.style, ...style, ...areaStyle },
|
|
5767
|
+
className,
|
|
5768
|
+
...restProps
|
|
5769
|
+
}
|
|
5770
|
+
);
|
|
5771
|
+
};
|
|
5772
|
+
var CropperDescription = ({
|
|
5773
|
+
children,
|
|
5774
|
+
className,
|
|
5775
|
+
...restProps
|
|
5776
|
+
}) => {
|
|
5777
|
+
const { descriptionId } = useCropperContext();
|
|
5778
|
+
return /* @__PURE__ */ jsx("div", { id: descriptionId, className, ...restProps, children: children ?? // Default description if none provided by user
|
|
5779
|
+
"Use mouse wheel or pinch gesture to zoom. Drag with mouse or touch, or use arrow keys to pan the image within the crop area." });
|
|
5780
|
+
};
|
|
5781
|
+
var Cropper = {
|
|
5782
|
+
Root: CropperRoot,
|
|
5783
|
+
Image: CropperImage,
|
|
5784
|
+
CropArea: CropperCropArea,
|
|
5785
|
+
Description: CropperDescription
|
|
5786
|
+
};
|
|
5787
|
+
function Slider({
|
|
5788
|
+
className,
|
|
5789
|
+
defaultValue,
|
|
5790
|
+
value,
|
|
5791
|
+
min = 0,
|
|
5792
|
+
max = 100,
|
|
5793
|
+
...props
|
|
5794
|
+
}) {
|
|
5795
|
+
const [internalValues, setInternalValues] = React8.useState(
|
|
5796
|
+
Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]
|
|
5797
|
+
);
|
|
5798
|
+
React8.useEffect(() => {
|
|
5799
|
+
if (value !== void 0) {
|
|
5800
|
+
setInternalValues(Array.isArray(value) ? value : [value]);
|
|
5801
|
+
}
|
|
5802
|
+
}, [value]);
|
|
5803
|
+
const handleValueChange = (newValue) => {
|
|
5804
|
+
setInternalValues(newValue);
|
|
5805
|
+
props.onValueChange?.(newValue);
|
|
5806
|
+
};
|
|
5807
|
+
const renderThumb = () => {
|
|
5808
|
+
const thumb = /* @__PURE__ */ jsx(
|
|
5809
|
+
SliderPrimitive.Thumb,
|
|
5810
|
+
{
|
|
5811
|
+
"data-testid": "slider-thumb",
|
|
5812
|
+
"data-slot": "slider-thumb",
|
|
5813
|
+
className: "nebula-ds border-2 border-slider-rangeColor bg-slider-thumbColor ring-ring/50 block size-4 shrink-0 rounded-full transition-[color,box-shadow] outline-none hover:ring-4 focus-visible:ring-4 disabled:pointer-events-none disabled:opacity-50"
|
|
5814
|
+
}
|
|
5815
|
+
);
|
|
5816
|
+
return thumb;
|
|
5817
|
+
};
|
|
5818
|
+
return /* @__PURE__ */ jsxs(
|
|
5819
|
+
SliderPrimitive.Root,
|
|
5820
|
+
{
|
|
5821
|
+
"data-slot": "slider",
|
|
5822
|
+
defaultValue,
|
|
5823
|
+
value,
|
|
5824
|
+
min,
|
|
5825
|
+
max,
|
|
5826
|
+
className: cn(
|
|
5827
|
+
"relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
|
|
5828
|
+
className
|
|
5829
|
+
),
|
|
5830
|
+
onValueChange: handleValueChange,
|
|
5831
|
+
...props,
|
|
5832
|
+
children: [
|
|
5833
|
+
/* @__PURE__ */ jsx(
|
|
5834
|
+
SliderPrimitive.Track,
|
|
5835
|
+
{
|
|
5836
|
+
"data-slot": "slider-track",
|
|
5837
|
+
className: cn(
|
|
5838
|
+
"bg-slider-trackColor relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
|
|
5839
|
+
),
|
|
5840
|
+
children: /* @__PURE__ */ jsx(
|
|
5841
|
+
SliderPrimitive.Range,
|
|
5842
|
+
{
|
|
5843
|
+
"data-slot": "slider-range",
|
|
5844
|
+
className: cn(
|
|
5845
|
+
"bg-slider-rangeColor absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
|
|
5846
|
+
)
|
|
5847
|
+
}
|
|
5848
|
+
)
|
|
5849
|
+
}
|
|
5850
|
+
),
|
|
5851
|
+
Array.from({ length: internalValues.length }, (_, index) => /* @__PURE__ */ jsx(React8.Fragment, { children: renderThumb() }, index))
|
|
5852
|
+
]
|
|
5853
|
+
}
|
|
5854
|
+
);
|
|
5855
|
+
}
|
|
5856
|
+
function CropperRoot2({
|
|
5857
|
+
className,
|
|
5858
|
+
...props
|
|
5859
|
+
}) {
|
|
5860
|
+
return /* @__PURE__ */ jsx(
|
|
5861
|
+
Cropper.Root,
|
|
5862
|
+
{
|
|
5863
|
+
"data-slot": "cropper",
|
|
5864
|
+
className: cn(
|
|
5865
|
+
"relative flex w-full cursor-move touch-none items-center justify-center overflow-hidden focus:outline-none",
|
|
5866
|
+
className
|
|
5867
|
+
),
|
|
5868
|
+
...props
|
|
5869
|
+
}
|
|
5870
|
+
);
|
|
5871
|
+
}
|
|
5872
|
+
function CropperDescription2({
|
|
5873
|
+
className,
|
|
5874
|
+
...props
|
|
5875
|
+
}) {
|
|
5876
|
+
return /* @__PURE__ */ jsx(
|
|
5877
|
+
Cropper.Description,
|
|
5878
|
+
{
|
|
5879
|
+
"data-slot": "cropper-description",
|
|
5880
|
+
className: cn("sr-only", className),
|
|
5881
|
+
...props
|
|
5882
|
+
}
|
|
5883
|
+
);
|
|
5884
|
+
}
|
|
5885
|
+
function CropperImage2({
|
|
5886
|
+
className,
|
|
5887
|
+
...props
|
|
5888
|
+
}) {
|
|
5889
|
+
return /* @__PURE__ */ jsx(
|
|
5890
|
+
Cropper.Image,
|
|
5891
|
+
{
|
|
5892
|
+
"data-slot": "cropper-image",
|
|
5893
|
+
className: cn(
|
|
5894
|
+
"pointer-events-none h-full w-full object-cover",
|
|
5895
|
+
className
|
|
5896
|
+
),
|
|
5897
|
+
...props
|
|
5898
|
+
}
|
|
5899
|
+
);
|
|
5900
|
+
}
|
|
5901
|
+
function CropperCropArea2({
|
|
5902
|
+
className,
|
|
5903
|
+
rounded,
|
|
5904
|
+
...props
|
|
5905
|
+
}) {
|
|
5906
|
+
return /* @__PURE__ */ jsx(
|
|
5907
|
+
Cropper.CropArea,
|
|
5908
|
+
{
|
|
5909
|
+
"data-slot": "cropper-crop-area",
|
|
5910
|
+
className: cn(
|
|
5911
|
+
"pointer-events-none absolute shadow-[0_0_0_9999px_rgba(0,0,0,0.5)] in-[[data-slot=cropper]:focus-visible]:ring-[2px] in-[[data-slot=cropper]:focus-visible]:ring-white",
|
|
5912
|
+
rounded && "rounded-full",
|
|
5913
|
+
className,
|
|
5914
|
+
"border-2 border-cropper-cropAreaBorderColor"
|
|
5915
|
+
),
|
|
5916
|
+
...props
|
|
5917
|
+
}
|
|
5918
|
+
);
|
|
5919
|
+
}
|
|
5920
|
+
var createImage = (url) => new Promise((resolve, reject) => {
|
|
5921
|
+
const image = new Image();
|
|
5922
|
+
image.addEventListener("load", () => resolve(image));
|
|
5923
|
+
image.addEventListener("error", (error2) => reject(error2));
|
|
5924
|
+
image.setAttribute("crossOrigin", "anonymous");
|
|
5925
|
+
image.src = url;
|
|
5926
|
+
});
|
|
5927
|
+
async function getCroppedImg(imageSrc, pixelCrop, outputWidth = pixelCrop.width, outputHeight = pixelCrop.height) {
|
|
5928
|
+
try {
|
|
5929
|
+
const image = await createImage(imageSrc);
|
|
5930
|
+
const canvas = document.createElement("canvas");
|
|
5931
|
+
const ctx = canvas.getContext("2d");
|
|
5932
|
+
if (!ctx) {
|
|
5933
|
+
return null;
|
|
5934
|
+
}
|
|
5935
|
+
canvas.width = outputWidth;
|
|
5936
|
+
canvas.height = outputHeight;
|
|
5937
|
+
ctx.drawImage(
|
|
5938
|
+
image,
|
|
5939
|
+
pixelCrop.x,
|
|
5940
|
+
pixelCrop.y,
|
|
5941
|
+
pixelCrop.width,
|
|
5942
|
+
pixelCrop.height,
|
|
5943
|
+
0,
|
|
5944
|
+
0,
|
|
5945
|
+
outputWidth,
|
|
5946
|
+
// Draw onto the output size
|
|
5947
|
+
outputHeight
|
|
5948
|
+
);
|
|
5949
|
+
return new Promise((resolve) => {
|
|
5950
|
+
canvas.toBlob((blob) => {
|
|
5951
|
+
resolve(blob);
|
|
5952
|
+
}, "image/jpeg");
|
|
5953
|
+
});
|
|
5954
|
+
} catch (error2) {
|
|
5955
|
+
return null;
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
function Cropper2({
|
|
5959
|
+
onOpenChange,
|
|
5960
|
+
open,
|
|
5961
|
+
previewUrl,
|
|
5962
|
+
onRemove: removeFile,
|
|
5963
|
+
onApply,
|
|
5964
|
+
rounded = false,
|
|
5965
|
+
portal = false
|
|
5966
|
+
}) {
|
|
5967
|
+
const [finalImageUrl, setFinalImageUrl] = useState(null);
|
|
5968
|
+
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
|
|
5969
|
+
const [zoom, setZoom] = useState(1);
|
|
5970
|
+
const handleCropChange = useCallback((pixels) => {
|
|
5971
|
+
setCroppedAreaPixels(pixels);
|
|
5972
|
+
}, []);
|
|
5973
|
+
const handleApply = async () => {
|
|
5974
|
+
if (!previewUrl || !croppedAreaPixels) {
|
|
5975
|
+
if (previewUrl) {
|
|
5976
|
+
removeFile();
|
|
5977
|
+
setCroppedAreaPixels(null);
|
|
5978
|
+
}
|
|
5979
|
+
return;
|
|
5980
|
+
}
|
|
5981
|
+
try {
|
|
5982
|
+
const croppedBlob = await getCroppedImg(previewUrl, croppedAreaPixels);
|
|
5983
|
+
if (!croppedBlob) {
|
|
5984
|
+
throw new Error("Failed to generate cropped image blob.");
|
|
5985
|
+
}
|
|
5986
|
+
const newFinalUrl = URL.createObjectURL(croppedBlob);
|
|
5987
|
+
if (finalImageUrl) {
|
|
5988
|
+
URL.revokeObjectURL(finalImageUrl);
|
|
5989
|
+
}
|
|
5990
|
+
setFinalImageUrl(newFinalUrl);
|
|
5991
|
+
onOpenChange(false);
|
|
5992
|
+
onApply(newFinalUrl, croppedBlob);
|
|
5993
|
+
} catch (error2) {
|
|
5994
|
+
onOpenChange(false);
|
|
5995
|
+
}
|
|
5996
|
+
};
|
|
5997
|
+
useEffect(() => {
|
|
5998
|
+
const currentFinalUrl = finalImageUrl;
|
|
5999
|
+
return () => {
|
|
6000
|
+
if (currentFinalUrl && currentFinalUrl.startsWith("blob:")) {
|
|
6001
|
+
URL.revokeObjectURL(currentFinalUrl);
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
6004
|
+
}, [finalImageUrl]);
|
|
6005
|
+
const { cropper } = useNebulaI18n().messages;
|
|
6006
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
|
|
6007
|
+
DialogContent,
|
|
6008
|
+
{
|
|
6009
|
+
className: "nebula-ds gap-0 p-0 sm:max-w-140 *:[button]:hidden border border-cropper-dialogBorderColor",
|
|
6010
|
+
portal,
|
|
6011
|
+
showClose: false,
|
|
6012
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
6013
|
+
children: [
|
|
6014
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "nebula-ds contents space-y-0 text-left", children: /* @__PURE__ */ jsxs(DialogTitle, { className: "nebula-ds flex items-center justify-between p-4 text-base", children: [
|
|
6015
|
+
/* @__PURE__ */ jsxs("div", { className: "nebula-ds flex items-center gap-2", children: [
|
|
6016
|
+
/* @__PURE__ */ jsx(
|
|
6017
|
+
Button,
|
|
6018
|
+
{
|
|
6019
|
+
icon: true,
|
|
6020
|
+
type: "button",
|
|
6021
|
+
variant: "ghost",
|
|
6022
|
+
onClick: () => onOpenChange(false),
|
|
6023
|
+
"aria-label": "close-cropper-dialog",
|
|
6024
|
+
"data-testid": "close-cropper-dialog",
|
|
6025
|
+
size: "sm",
|
|
6026
|
+
children: /* @__PURE__ */ jsx(XIcon, { "aria-hidden": "true" })
|
|
6027
|
+
}
|
|
6028
|
+
),
|
|
6029
|
+
cropper.dialogTitle
|
|
6030
|
+
] }),
|
|
6031
|
+
/* @__PURE__ */ jsx(
|
|
6032
|
+
Button,
|
|
6033
|
+
{
|
|
6034
|
+
autoFocus: false,
|
|
6035
|
+
onClick: handleApply,
|
|
6036
|
+
disabled: !previewUrl,
|
|
6037
|
+
variant: "primary",
|
|
6038
|
+
size: "sm",
|
|
6039
|
+
type: "button",
|
|
6040
|
+
"aria-label": "apply-cropper-image",
|
|
6041
|
+
"data-testid": "apply-cropper-image",
|
|
6042
|
+
children: cropper.applyButtonLabel
|
|
6043
|
+
}
|
|
6044
|
+
)
|
|
6045
|
+
] }) }),
|
|
6046
|
+
previewUrl && /* @__PURE__ */ jsxs(
|
|
6047
|
+
CropperRoot2,
|
|
6048
|
+
{
|
|
6049
|
+
className: "nebula-ds h-96 sm:h-120",
|
|
6050
|
+
image: previewUrl,
|
|
6051
|
+
zoom,
|
|
6052
|
+
onCropChange: handleCropChange,
|
|
6053
|
+
onZoomChange: setZoom,
|
|
6054
|
+
children: [
|
|
6055
|
+
/* @__PURE__ */ jsx(CropperDescription2, {}),
|
|
6056
|
+
/* @__PURE__ */ jsx(CropperImage2, {}),
|
|
6057
|
+
/* @__PURE__ */ jsx(CropperCropArea2, { rounded })
|
|
6058
|
+
]
|
|
6059
|
+
}
|
|
6060
|
+
),
|
|
6061
|
+
/* @__PURE__ */ jsx(DialogFooter, { className: "nebula-ds border-t border-t-cropper-dialogBorderColor px-4 py-6", children: /* @__PURE__ */ jsxs("div", { className: "nebula-ds mx-auto flex w-full max-w-80 items-center gap-4", children: [
|
|
6062
|
+
/* @__PURE__ */ jsx(
|
|
6063
|
+
MinusIcon,
|
|
6064
|
+
{
|
|
6065
|
+
className: "nebula-ds shrink-0 size-5 text-cropper-sliderIconColor",
|
|
6066
|
+
size: 16,
|
|
6067
|
+
"aria-hidden": "true"
|
|
6068
|
+
}
|
|
6069
|
+
),
|
|
6070
|
+
/* @__PURE__ */ jsx(
|
|
6071
|
+
Slider,
|
|
6072
|
+
{
|
|
6073
|
+
defaultValue: [1],
|
|
6074
|
+
value: [zoom],
|
|
6075
|
+
min: 1,
|
|
6076
|
+
max: 3,
|
|
6077
|
+
step: 0.1,
|
|
6078
|
+
onValueChange: (value) => setZoom(value[0]),
|
|
6079
|
+
"aria-label": "Zoom slider"
|
|
6080
|
+
}
|
|
6081
|
+
),
|
|
6082
|
+
/* @__PURE__ */ jsx(
|
|
6083
|
+
PlusIcon,
|
|
6084
|
+
{
|
|
6085
|
+
className: "nebula-ds shrink-0 size-5 text-cropper-sliderIconColor",
|
|
6086
|
+
size: 16,
|
|
6087
|
+
"aria-hidden": "true"
|
|
6088
|
+
}
|
|
6089
|
+
)
|
|
6090
|
+
] }) })
|
|
6091
|
+
]
|
|
6092
|
+
}
|
|
6093
|
+
) });
|
|
6094
|
+
}
|
|
4921
6095
|
|
|
4922
6096
|
// src/tailwind.ts
|
|
4923
6097
|
function content({ base = "./" } = {}) {
|
|
@@ -4929,4 +6103,4 @@ var tailwind = {
|
|
|
4929
6103
|
// plugin: () => require("tailwindcss")("node_modules/@nebulareact/dist/tailwind.config.js"),
|
|
4930
6104
|
};
|
|
4931
6105
|
|
|
4932
|
-
export { Accordion, AccordionContent, AccordionDescription, AccordionItem, AccordionTitle, AccordionTrigger, ActionBar, ActionBarButton, ActionBarClose, ActionBarContent, ActionBarDivider, ActionBarPortal, ActionBarTrigger, Alert, AlertButton, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, AlertTitle, StyledAsync as Async, StyledAsyncCreatable as AsyncCreatable, Badge, Box, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, Caption, Checkbox, StyledCreatable as Creatable, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FileUpload, FileUploadError, Heading, InputDatePickerSingle, InputDateTimePickerSingle, InputPhone, InputText, InputTime, Label, Link, NebulaI18nProvider, Pagination, Paragraph, Popover, PopoverContent, PopoverTrigger, StyledSelect as Select, Separator2 as Separator, Skeleton, Space, SpaceDirectionEnum, SpaceSizeEnum, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TextArea, Toaster, Tooltip, alertVariants, badgeSizeEnum, badgeVariantEnum, buttonSizeEnum, buttonVariantEnum, buttonVariantsConfig, dateIsAvailable, formatBytes, getNebulaLanguage, localeByi18nKey,
|
|
6106
|
+
export { Accordion, AccordionContent, AccordionDescription, AccordionItem, AccordionTitle, AccordionTrigger, ActionBar, ActionBarButton, ActionBarClose, ActionBarContent, ActionBarDivider, ActionBarPortal, ActionBarTrigger, Alert, AlertButton, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, AlertTitle, StyledAsync as Async, StyledAsyncCreatable as AsyncCreatable, Badge, Box, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, Caption, Checkbox, StyledCreatable as Creatable, Cropper2 as Cropper, CropperCropArea2 as CropperCropArea, CropperDescription2 as CropperDescription, CropperImage2 as CropperImage, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FileUpload, FileUploadError, Heading, InputDatePickerSingle, InputDateTimePickerSingle, InputPhone, InputText, InputTime, Label, Link, NebulaI18nProvider, Pagination, Paragraph, Popover, PopoverContent, PopoverTrigger, ProfileImage, StyledSelect as Select, Separator2 as Separator, Skeleton, Slider, Space, SpaceDirectionEnum, SpaceSizeEnum, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TextArea, Toaster, Tooltip, alertVariants, badgeSizeEnum, badgeVariantEnum, buttonSizeEnum, buttonVariantEnum, buttonVariantsConfig, dateIsAvailable, formatBytes, getNebulaLanguage, localeByi18nKey, messages19 as messages, separatorVariants, setNebulaLanguage, tagVariantsEnum, tailwind, toast, useClickOutside, useFileUpload, useKeyPress, useNebulaI18n };
|