@ikatec/nebula-react 1.0.26 → 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 +1140 -76
- package/dist/index.mjs +1136 -78
- 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, UserIcon, 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
|
);
|
|
@@ -2332,16 +2357,17 @@ var DialogOverlay = React8.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
2332
2357
|
}
|
|
2333
2358
|
));
|
|
2334
2359
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
2335
|
-
var DialogContent = React8.forwardRef(
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
/* @__PURE__ */
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
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
|
|
2345
2371
|
fixed
|
|
2346
2372
|
left-[50%]
|
|
2347
2373
|
top-[50%]
|
|
@@ -2366,29 +2392,30 @@ var DialogContent = React8.forwardRef(({ className, children, portal = false, ..
|
|
|
2366
2392
|
data-[state=closed]:slide-out-to-top-[48%]
|
|
2367
2393
|
data-[state=open]:slide-in-from-left-1/2
|
|
2368
2394
|
data-[state=open]:slide-in-from-top-[48%]`,
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
}
|
|
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
|
+
);
|
|
2392
2419
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
2393
2420
|
var DialogHeader = ({
|
|
2394
2421
|
className,
|
|
@@ -3204,13 +3231,13 @@ function custom(message, options) {
|
|
|
3204
3231
|
}
|
|
3205
3232
|
);
|
|
3206
3233
|
}
|
|
3207
|
-
async function promise(promise2,
|
|
3234
|
+
async function promise(promise2, messages20, options) {
|
|
3208
3235
|
const loadingToast = toast$1.custom(
|
|
3209
3236
|
(t) => /* @__PURE__ */ jsx(
|
|
3210
3237
|
ToastComponent,
|
|
3211
3238
|
{
|
|
3212
3239
|
type: "info",
|
|
3213
|
-
message:
|
|
3240
|
+
message: messages20.loading,
|
|
3214
3241
|
options,
|
|
3215
3242
|
t
|
|
3216
3243
|
}
|
|
@@ -3224,7 +3251,7 @@ async function promise(promise2, messages17, options) {
|
|
|
3224
3251
|
ToastComponent,
|
|
3225
3252
|
{
|
|
3226
3253
|
type: "success",
|
|
3227
|
-
message:
|
|
3254
|
+
message: messages20.success,
|
|
3228
3255
|
options,
|
|
3229
3256
|
t
|
|
3230
3257
|
}
|
|
@@ -3239,7 +3266,7 @@ async function promise(promise2, messages17, options) {
|
|
|
3239
3266
|
ToastComponent,
|
|
3240
3267
|
{
|
|
3241
3268
|
type: "error",
|
|
3242
|
-
message:
|
|
3269
|
+
message: messages20.error,
|
|
3243
3270
|
options,
|
|
3244
3271
|
t
|
|
3245
3272
|
}
|
|
@@ -3409,8 +3436,8 @@ var CountrySelect = ({
|
|
|
3409
3436
|
const handleSelect = (event) => {
|
|
3410
3437
|
onChange(event.target.value);
|
|
3411
3438
|
};
|
|
3412
|
-
const { messages:
|
|
3413
|
-
const { countries } =
|
|
3439
|
+
const { messages: messages20 } = useNebulaI18n();
|
|
3440
|
+
const { countries } = messages20.inputPhone;
|
|
3414
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: [
|
|
3415
3442
|
/* @__PURE__ */ jsxs("div", { className: "nebula-ds inline-flex items-center gap-1", "aria-hidden": "true", children: [
|
|
3416
3443
|
/* @__PURE__ */ jsx(FlagComponent, { country: value, countryName: value, "aria-hidden": "true" }),
|
|
@@ -4230,7 +4257,7 @@ var InputDateTimePickerSingle = ({
|
|
|
4230
4257
|
formattedDateByLanguage ? new Date(formattedDateByLanguage) : void 0
|
|
4231
4258
|
);
|
|
4232
4259
|
const [popoverIsOpen, setPopoverIsOpen] = useState(false);
|
|
4233
|
-
const { locale, messages:
|
|
4260
|
+
const { locale, messages: messages20 } = useNebulaI18n();
|
|
4234
4261
|
const [month, setMonth] = useState(/* @__PURE__ */ new Date());
|
|
4235
4262
|
const inputTimeRef = useRef(null);
|
|
4236
4263
|
const handleClearValue = () => {
|
|
@@ -4402,7 +4429,7 @@ var InputDateTimePickerSingle = ({
|
|
|
4402
4429
|
disabled: disabledDates,
|
|
4403
4430
|
footer: /* @__PURE__ */ jsxs(Space, { className: "nebula-ds items-center", children: [
|
|
4404
4431
|
/* @__PURE__ */ jsxs(Label, { children: [
|
|
4405
|
-
|
|
4432
|
+
messages20.timePicker.label,
|
|
4406
4433
|
":"
|
|
4407
4434
|
] }),
|
|
4408
4435
|
/* @__PURE__ */ jsx(
|
|
@@ -4944,9 +4971,11 @@ var ProfileImage = ({
|
|
|
4944
4971
|
onError,
|
|
4945
4972
|
maxFiles = Infinity,
|
|
4946
4973
|
onRemove,
|
|
4974
|
+
image,
|
|
4947
4975
|
...rest
|
|
4948
4976
|
}) => {
|
|
4949
4977
|
const maxSize = maxSizeMB * 1024 * 1024;
|
|
4978
|
+
const id = useId();
|
|
4950
4979
|
const [
|
|
4951
4980
|
{ files, isDragging, errors },
|
|
4952
4981
|
{
|
|
@@ -4959,6 +4988,15 @@ var ProfileImage = ({
|
|
|
4959
4988
|
getInputProps
|
|
4960
4989
|
}
|
|
4961
4990
|
] = useFileUpload({
|
|
4991
|
+
initialFiles: image ? [
|
|
4992
|
+
{
|
|
4993
|
+
id,
|
|
4994
|
+
url: image,
|
|
4995
|
+
name: image,
|
|
4996
|
+
size: 0,
|
|
4997
|
+
type: "image"
|
|
4998
|
+
}
|
|
4999
|
+
] : [],
|
|
4962
5000
|
multiple: false,
|
|
4963
5001
|
maxSize: maxSize > 0 ? maxSize : void 0,
|
|
4964
5002
|
accept: "image/*",
|
|
@@ -5034,6 +5072,1026 @@ var ProfileImage = ({
|
|
|
5034
5072
|
] });
|
|
5035
5073
|
};
|
|
5036
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
|
+
}
|
|
5037
6095
|
|
|
5038
6096
|
// src/tailwind.ts
|
|
5039
6097
|
function content({ base = "./" } = {}) {
|
|
@@ -5045,4 +6103,4 @@ var tailwind = {
|
|
|
5045
6103
|
// plugin: () => require("tailwindcss")("node_modules/@nebulareact/dist/tailwind.config.js"),
|
|
5046
6104
|
};
|
|
5047
6105
|
|
|
5048
|
-
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, ProfileImage, 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 };
|