@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.js
CHANGED
|
@@ -28,6 +28,7 @@ var dateFns = require('date-fns');
|
|
|
28
28
|
var reactDayPicker = require('react-day-picker');
|
|
29
29
|
var locale = require('react-day-picker/locale');
|
|
30
30
|
var mask = require('@react-input/mask');
|
|
31
|
+
var SliderPrimitive = require('@radix-ui/react-slider');
|
|
31
32
|
|
|
32
33
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
33
34
|
|
|
@@ -67,6 +68,7 @@ var AccordionPrimitive__namespace = /*#__PURE__*/_interopNamespace(AccordionPrim
|
|
|
67
68
|
var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
|
|
68
69
|
var RPNInput__namespace = /*#__PURE__*/_interopNamespace(RPNInput);
|
|
69
70
|
var flags__default = /*#__PURE__*/_interopDefault(flags);
|
|
71
|
+
var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
|
|
70
72
|
|
|
71
73
|
// src/button.tsx
|
|
72
74
|
|
|
@@ -1157,8 +1159,16 @@ var messages5 = {
|
|
|
1157
1159
|
};
|
|
1158
1160
|
var file_upload_default = messages5;
|
|
1159
1161
|
|
|
1162
|
+
// src/i18n/messages/en/cropper.ts
|
|
1163
|
+
var messages6 = {
|
|
1164
|
+
applyButtonLabel: "Apply",
|
|
1165
|
+
dialogTitle: "Adjust image"
|
|
1166
|
+
};
|
|
1167
|
+
var cropper_default = messages6;
|
|
1168
|
+
|
|
1160
1169
|
// src/i18n/messages/en/index.ts
|
|
1161
1170
|
var enMessages = {
|
|
1171
|
+
cropper: cropper_default,
|
|
1162
1172
|
pagination: pagination_default,
|
|
1163
1173
|
inputSelect: input_select_default,
|
|
1164
1174
|
inputPhone: input_phone_default,
|
|
@@ -1167,7 +1177,7 @@ var enMessages = {
|
|
|
1167
1177
|
};
|
|
1168
1178
|
|
|
1169
1179
|
// src/i18n/messages/es/pagination.ts
|
|
1170
|
-
var
|
|
1180
|
+
var messages7 = {
|
|
1171
1181
|
totalResultsLabel(pagesSize, totalResults) {
|
|
1172
1182
|
if (totalResults < pagesSize) {
|
|
1173
1183
|
pagesSize = totalResults;
|
|
@@ -1178,16 +1188,16 @@ var messages6 = {
|
|
|
1178
1188
|
return `P\xE1gina ${currentPage} de ${totalPages}`;
|
|
1179
1189
|
}
|
|
1180
1190
|
};
|
|
1181
|
-
var pagination_default2 =
|
|
1191
|
+
var pagination_default2 = messages7;
|
|
1182
1192
|
|
|
1183
1193
|
// src/i18n/messages/es/input-select.ts
|
|
1184
|
-
var
|
|
1194
|
+
var messages8 = {
|
|
1185
1195
|
noOptions: "No hay opciones disponibles"
|
|
1186
1196
|
};
|
|
1187
|
-
var input_select_default2 =
|
|
1197
|
+
var input_select_default2 = messages8;
|
|
1188
1198
|
|
|
1189
1199
|
// src/i18n/messages/es/input-phone.ts
|
|
1190
|
-
var
|
|
1200
|
+
var messages9 = {
|
|
1191
1201
|
countries: {
|
|
1192
1202
|
empty: "Seleccionar",
|
|
1193
1203
|
AF: "Afganist\xE1n",
|
|
@@ -1437,22 +1447,30 @@ var messages8 = {
|
|
|
1437
1447
|
ZW: "Zimbabue"
|
|
1438
1448
|
}
|
|
1439
1449
|
};
|
|
1440
|
-
var input_phone_default2 =
|
|
1450
|
+
var input_phone_default2 = messages9;
|
|
1441
1451
|
|
|
1442
1452
|
// src/i18n/messages/es/time-picker.ts
|
|
1443
|
-
var
|
|
1453
|
+
var messages10 = {
|
|
1444
1454
|
label: "Tiempo"
|
|
1445
1455
|
};
|
|
1446
|
-
var time_picker_default2 =
|
|
1456
|
+
var time_picker_default2 = messages10;
|
|
1447
1457
|
|
|
1448
1458
|
// src/i18n/messages/es/file-upload.ts
|
|
1449
|
-
var
|
|
1459
|
+
var messages11 = {
|
|
1450
1460
|
deleteAll: "Remover todos"
|
|
1451
1461
|
};
|
|
1452
|
-
var file_upload_default2 =
|
|
1462
|
+
var file_upload_default2 = messages11;
|
|
1463
|
+
|
|
1464
|
+
// src/i18n/messages/es/cropper.ts
|
|
1465
|
+
var messages12 = {
|
|
1466
|
+
applyButtonLabel: "Aplicar",
|
|
1467
|
+
dialogTitle: "Ajustar la imagen"
|
|
1468
|
+
};
|
|
1469
|
+
var cropper_default2 = messages12;
|
|
1453
1470
|
|
|
1454
1471
|
// src/i18n/messages/es/index.ts
|
|
1455
1472
|
var esMessages = {
|
|
1473
|
+
cropper: cropper_default2,
|
|
1456
1474
|
pagination: pagination_default2,
|
|
1457
1475
|
inputSelect: input_select_default2,
|
|
1458
1476
|
inputPhone: input_phone_default2,
|
|
@@ -1461,7 +1479,7 @@ var esMessages = {
|
|
|
1461
1479
|
};
|
|
1462
1480
|
|
|
1463
1481
|
// src/i18n/messages/pt-br/pagination.ts
|
|
1464
|
-
var
|
|
1482
|
+
var messages13 = {
|
|
1465
1483
|
totalResultsLabel(pagesSize, totalResults) {
|
|
1466
1484
|
if (totalResults < pagesSize) {
|
|
1467
1485
|
pagesSize = totalResults;
|
|
@@ -1472,16 +1490,16 @@ var messages11 = {
|
|
|
1472
1490
|
return `P\xE1gina ${currentPage} de ${totalPages}`;
|
|
1473
1491
|
}
|
|
1474
1492
|
};
|
|
1475
|
-
var pagination_default3 =
|
|
1493
|
+
var pagination_default3 = messages13;
|
|
1476
1494
|
|
|
1477
1495
|
// src/i18n/messages/pt-br/input-select.ts
|
|
1478
|
-
var
|
|
1496
|
+
var messages14 = {
|
|
1479
1497
|
noOptions: "Nenhuma op\xE7\xE3o dispon\xEDvel"
|
|
1480
1498
|
};
|
|
1481
|
-
var input_select_default3 =
|
|
1499
|
+
var input_select_default3 = messages14;
|
|
1482
1500
|
|
|
1483
1501
|
// src/i18n/messages/pt-br/input-phone.ts
|
|
1484
|
-
var
|
|
1502
|
+
var messages15 = {
|
|
1485
1503
|
countries: {
|
|
1486
1504
|
empty: "Selecione",
|
|
1487
1505
|
AF: "Afeganist\xE3o",
|
|
@@ -1731,19 +1749,26 @@ var messages13 = {
|
|
|
1731
1749
|
ZW: "Zimb\xE1bue"
|
|
1732
1750
|
}
|
|
1733
1751
|
};
|
|
1734
|
-
var input_phone_default3 =
|
|
1752
|
+
var input_phone_default3 = messages15;
|
|
1735
1753
|
|
|
1736
1754
|
// src/i18n/messages/pt-br/time-picker.ts
|
|
1737
|
-
var
|
|
1755
|
+
var messages16 = {
|
|
1738
1756
|
label: "Hor\xE1rio"
|
|
1739
1757
|
};
|
|
1740
|
-
var time_picker_default3 =
|
|
1758
|
+
var time_picker_default3 = messages16;
|
|
1741
1759
|
|
|
1742
1760
|
// src/i18n/messages/pt-br/file-upload.ts
|
|
1743
|
-
var
|
|
1761
|
+
var messages17 = {
|
|
1744
1762
|
deleteAll: "Remover todos"
|
|
1745
1763
|
};
|
|
1746
|
-
var file_upload_default3 =
|
|
1764
|
+
var file_upload_default3 = messages17;
|
|
1765
|
+
|
|
1766
|
+
// src/i18n/messages/pt-br/cropper.ts
|
|
1767
|
+
var messages18 = {
|
|
1768
|
+
applyButtonLabel: "Aplicar",
|
|
1769
|
+
dialogTitle: "Ajustar imagem"
|
|
1770
|
+
};
|
|
1771
|
+
var cropper_default3 = messages18;
|
|
1747
1772
|
|
|
1748
1773
|
// src/i18n/messages/pt-br/index.ts
|
|
1749
1774
|
var ptBrMessages = {
|
|
@@ -1751,7 +1776,8 @@ var ptBrMessages = {
|
|
|
1751
1776
|
inputSelect: input_select_default3,
|
|
1752
1777
|
inputPhone: input_phone_default3,
|
|
1753
1778
|
timePicker: time_picker_default3,
|
|
1754
|
-
fileUpload: file_upload_default3
|
|
1779
|
+
fileUpload: file_upload_default3,
|
|
1780
|
+
cropper: cropper_default3
|
|
1755
1781
|
};
|
|
1756
1782
|
|
|
1757
1783
|
// src/i18n/message-storage-handler.ts
|
|
@@ -1776,7 +1802,7 @@ var setNebulaLanguage = (language) => {
|
|
|
1776
1802
|
}
|
|
1777
1803
|
localStorage.setItem(getNebulaI18nStorageKey(), language);
|
|
1778
1804
|
};
|
|
1779
|
-
var
|
|
1805
|
+
var messages19 = /* @__PURE__ */ new Map([
|
|
1780
1806
|
[null, enMessages],
|
|
1781
1807
|
[void 0, enMessages],
|
|
1782
1808
|
["en-US", enMessages],
|
|
@@ -1794,14 +1820,14 @@ var NebulaI18nProvider = ({
|
|
|
1794
1820
|
() => customI18nStorageKey ?? localStorageKey,
|
|
1795
1821
|
[customI18nStorageKey]
|
|
1796
1822
|
);
|
|
1797
|
-
const [
|
|
1798
|
-
|
|
1823
|
+
const [messages20, setMessages] = React8.useState(
|
|
1824
|
+
messages19.get(getNebulaLanguage()) ?? messages19.get("en-US")
|
|
1799
1825
|
);
|
|
1800
1826
|
const handleStorageChange = React8.useCallback(
|
|
1801
1827
|
({ detail }) => {
|
|
1802
1828
|
if (detail.key === storageKey) {
|
|
1803
1829
|
setMessages(
|
|
1804
|
-
|
|
1830
|
+
messages19.get(detail.value) ?? messages19.get("en-US")
|
|
1805
1831
|
);
|
|
1806
1832
|
}
|
|
1807
1833
|
},
|
|
@@ -1845,7 +1871,7 @@ var NebulaI18nProvider = ({
|
|
|
1845
1871
|
NebulaI18nContext.Provider,
|
|
1846
1872
|
{
|
|
1847
1873
|
value: {
|
|
1848
|
-
messages:
|
|
1874
|
+
messages: messages20,
|
|
1849
1875
|
locale: getNebulaLanguage()
|
|
1850
1876
|
},
|
|
1851
1877
|
children
|
|
@@ -1867,7 +1893,7 @@ var Pagination = ({
|
|
|
1867
1893
|
onChangePage,
|
|
1868
1894
|
...props
|
|
1869
1895
|
}) => {
|
|
1870
|
-
const { messages:
|
|
1896
|
+
const { messages: messages20 } = useNebulaI18n();
|
|
1871
1897
|
const totalPages = React8.useMemo(() => {
|
|
1872
1898
|
return Math.ceil(total / (pageSize || 1));
|
|
1873
1899
|
}, [total, pageSize]);
|
|
@@ -1900,13 +1926,13 @@ var Pagination = ({
|
|
|
1900
1926
|
}, [totalPages, pageSize, total]);
|
|
1901
1927
|
const totalResultsLabel = React8.useMemo(() => {
|
|
1902
1928
|
if (page === totalPages) {
|
|
1903
|
-
return
|
|
1929
|
+
return messages20.pagination.totalResultsLabel(lastPageSize, total);
|
|
1904
1930
|
}
|
|
1905
|
-
return
|
|
1906
|
-
}, [
|
|
1931
|
+
return messages20.pagination.totalResultsLabel(pageSize, total);
|
|
1932
|
+
}, [messages20.pagination, pageSize, total, page, totalPages, lastPageSize]);
|
|
1907
1933
|
const currentPageLabel = React8.useMemo(
|
|
1908
|
-
() =>
|
|
1909
|
-
[
|
|
1934
|
+
() => messages20.pagination.currentPageLabel(normalizedPage, totalPages),
|
|
1935
|
+
[messages20.pagination, normalizedPage, totalPages]
|
|
1910
1936
|
);
|
|
1911
1937
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1912
1938
|
"nav",
|
|
@@ -2179,7 +2205,7 @@ var createStyledSelect = (BaseSelect, displayName) => {
|
|
|
2179
2205
|
isError = false,
|
|
2180
2206
|
...props
|
|
2181
2207
|
}) => {
|
|
2182
|
-
const { messages:
|
|
2208
|
+
const { messages: messages20 } = useNebulaI18n();
|
|
2183
2209
|
const customClassNames = React8.useMemo(() => {
|
|
2184
2210
|
return {
|
|
2185
2211
|
control: (props2) => controlStyles(props2, isError),
|
|
@@ -2226,7 +2252,7 @@ var createStyledSelect = (BaseSelect, displayName) => {
|
|
|
2226
2252
|
isDisabled: disabled,
|
|
2227
2253
|
components: customComponents,
|
|
2228
2254
|
classNames: customClassNames,
|
|
2229
|
-
noOptionsMessage: () => /* @__PURE__ */ jsxRuntime.jsx("p", { children:
|
|
2255
|
+
noOptionsMessage: () => /* @__PURE__ */ jsxRuntime.jsx("p", { children: messages20.inputSelect.noOptions }),
|
|
2230
2256
|
...props
|
|
2231
2257
|
}
|
|
2232
2258
|
);
|
|
@@ -2242,15 +2268,9 @@ var StyledAsyncCreatable = createStyledSelect(
|
|
|
2242
2268
|
"AsyncCreatable"
|
|
2243
2269
|
);
|
|
2244
2270
|
var InputText = React8__namespace.forwardRef(
|
|
2245
|
-
({
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
isError = false,
|
|
2249
|
-
onClean,
|
|
2250
|
-
iconPlacement = "start",
|
|
2251
|
-
disabled,
|
|
2252
|
-
...props
|
|
2253
|
-
}, ref) => {
|
|
2271
|
+
({ className, isError = false, onClean, disabled, suffix, ...props }, ref) => {
|
|
2272
|
+
const icon = "icon" in props ? props.icon : null;
|
|
2273
|
+
const iconPlacement = "iconPlacement" in props || props.type !== "password" ? props.iconPlacement || "start" : null;
|
|
2254
2274
|
const initialInputType = props.type || "text";
|
|
2255
2275
|
const [type, setType] = React8__namespace.useState(initialInputType);
|
|
2256
2276
|
const iconClass = {
|
|
@@ -2261,71 +2281,92 @@ var InputText = React8__namespace.forwardRef(
|
|
|
2261
2281
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2262
2282
|
"div",
|
|
2263
2283
|
{
|
|
2264
|
-
className: cn(
|
|
2265
|
-
"
|
|
2266
|
-
|
|
2284
|
+
className: cn(
|
|
2285
|
+
"w-full flex outline-none",
|
|
2286
|
+
"rounded-input",
|
|
2287
|
+
"border border-inputText-border-default focus-within:ring-[3px] focus-within:ring-inputText-border-focus focus-within:border-inputText-border-focus",
|
|
2288
|
+
"focus-within:text-inputText-text-focus placeholder:text-inputText-text-default disabled:text-inputText-text-disabled",
|
|
2289
|
+
isError && "border-inputText-border-danger focus-within:border-inputText-border-danger focus-within:ring-button-danger-border-focus",
|
|
2290
|
+
disabled && "pointer-events-none"
|
|
2291
|
+
),
|
|
2267
2292
|
children: [
|
|
2268
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2269
|
-
|
|
2293
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nebula-ds relative w-full", children: [
|
|
2294
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2295
|
+
"input",
|
|
2296
|
+
{
|
|
2297
|
+
ref,
|
|
2298
|
+
className: cn(
|
|
2299
|
+
"w-full h-10 outline-none text-sm leading-none font-medium",
|
|
2300
|
+
"bg-inputText-background-default disabled:bg-inputText-background-disabled",
|
|
2301
|
+
"text-inputText-text-filled",
|
|
2302
|
+
"disabled:cursor-not-allowed",
|
|
2303
|
+
"rounded-input",
|
|
2304
|
+
"pl-4",
|
|
2305
|
+
!!suffix && "rounded-r-none",
|
|
2306
|
+
{
|
|
2307
|
+
"pl-10 pr-4": !!icon && iconPlacement === "start",
|
|
2308
|
+
"pr-10": initialInputType === "password",
|
|
2309
|
+
"pr-10 pl-4": !!icon && iconPlacement === "end" && initialInputType !== "password"
|
|
2310
|
+
},
|
|
2311
|
+
className
|
|
2312
|
+
),
|
|
2313
|
+
...{ ...props, icon: void 0, iconPlacement: void 0 },
|
|
2314
|
+
disabled,
|
|
2315
|
+
type
|
|
2316
|
+
}
|
|
2317
|
+
),
|
|
2318
|
+
onClean && props.value && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2319
|
+
"button",
|
|
2320
|
+
{
|
|
2321
|
+
type: "button",
|
|
2322
|
+
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2323
|
+
"right-10": initialInputType === "password" || iconPlacement === "end",
|
|
2324
|
+
"right-4": initialInputType === "text" && iconPlacement === "start"
|
|
2325
|
+
}),
|
|
2326
|
+
onClick: onClean,
|
|
2327
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleX, { className: cn("w-4 h-4", iconClass) })
|
|
2328
|
+
}
|
|
2329
|
+
),
|
|
2330
|
+
initialInputType === "password" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2331
|
+
"button",
|
|
2332
|
+
{
|
|
2333
|
+
type: "button",
|
|
2334
|
+
className: "nebula-ds absolute right-4 top-1/2 transform -translate-y-1/2",
|
|
2335
|
+
onClick: () => setType((prev) => prev === "text" ? "password" : "text"),
|
|
2336
|
+
children: type === "text" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: cn("w-4 h-4", iconClass) }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: cn("w-4 h-4", iconClass) })
|
|
2337
|
+
}
|
|
2338
|
+
),
|
|
2339
|
+
icon && initialInputType !== "password" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2340
|
+
"span",
|
|
2341
|
+
{
|
|
2342
|
+
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2343
|
+
"left-4": iconPlacement === "start",
|
|
2344
|
+
"right-4": iconPlacement === "end"
|
|
2345
|
+
}),
|
|
2346
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2347
|
+
"span",
|
|
2348
|
+
{
|
|
2349
|
+
className: cn(
|
|
2350
|
+
"w-4 h-4 flex items-center justify-center disabled:text-inputText-icon-disabled",
|
|
2351
|
+
iconClass
|
|
2352
|
+
),
|
|
2353
|
+
children: icon
|
|
2354
|
+
}
|
|
2355
|
+
)
|
|
2356
|
+
}
|
|
2357
|
+
)
|
|
2358
|
+
] }),
|
|
2359
|
+
!!suffix && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2360
|
+
"div",
|
|
2270
2361
|
{
|
|
2271
|
-
ref,
|
|
2272
2362
|
className: cn(
|
|
2273
|
-
"w-
|
|
2274
|
-
"bg-inputText-
|
|
2275
|
-
"
|
|
2276
|
-
"
|
|
2277
|
-
"
|
|
2278
|
-
{
|
|
2279
|
-
"pl-10 pr-4": !!icon && iconPlacement === "start",
|
|
2280
|
-
"pr-10 pl-4": !!icon && iconPlacement === "end" && initialInputType !== "password",
|
|
2281
|
-
"px-4": !icon,
|
|
2282
|
-
"border-inputText-border-danger focus:border-inputText-border-danger focus:ring-button-danger-border-focus": isError
|
|
2283
|
-
},
|
|
2284
|
-
className
|
|
2363
|
+
"w-fit h-10 outline-none rounded-input text-sm leading-none font-medium rounded-l-none flex items-center px-4",
|
|
2364
|
+
"bg-inputText-suffixBackground disabled:bg-inputText-background-disabled",
|
|
2365
|
+
"text-inputText-text-filled",
|
|
2366
|
+
"border-l border-inputText-border-default",
|
|
2367
|
+
"rounded-input rounded-l-none"
|
|
2285
2368
|
),
|
|
2286
|
-
|
|
2287
|
-
disabled,
|
|
2288
|
-
type
|
|
2289
|
-
}
|
|
2290
|
-
),
|
|
2291
|
-
onClean && props.value && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2292
|
-
"button",
|
|
2293
|
-
{
|
|
2294
|
-
type: "button",
|
|
2295
|
-
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2296
|
-
"right-10": initialInputType === "password" || iconPlacement === "end",
|
|
2297
|
-
"right-4": initialInputType === "text" && iconPlacement === "start"
|
|
2298
|
-
}),
|
|
2299
|
-
onClick: onClean,
|
|
2300
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleX, { className: cn("w-4 h-4", iconClass) })
|
|
2301
|
-
}
|
|
2302
|
-
),
|
|
2303
|
-
initialInputType === "password" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2304
|
-
"button",
|
|
2305
|
-
{
|
|
2306
|
-
type: "button",
|
|
2307
|
-
className: "nebula-ds absolute right-4 top-1/2 transform -translate-y-1/2",
|
|
2308
|
-
onClick: () => setType((prev) => prev === "text" ? "password" : "text"),
|
|
2309
|
-
children: type === "text" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: cn("w-4 h-4", iconClass) }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: cn("w-4 h-4", iconClass) })
|
|
2310
|
-
}
|
|
2311
|
-
),
|
|
2312
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2313
|
-
"span",
|
|
2314
|
-
{
|
|
2315
|
-
className: cn("absolute top-1/2 transform -translate-y-1/2", {
|
|
2316
|
-
"left-4": iconPlacement === "start",
|
|
2317
|
-
"right-4": iconPlacement === "end" && initialInputType !== "password"
|
|
2318
|
-
}),
|
|
2319
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2320
|
-
"span",
|
|
2321
|
-
{
|
|
2322
|
-
className: cn(
|
|
2323
|
-
"w-4 h-4 flex items-center justify-center disabled:text-inputText-icon-disabled",
|
|
2324
|
-
iconClass
|
|
2325
|
-
),
|
|
2326
|
-
children: icon
|
|
2327
|
-
}
|
|
2328
|
-
)
|
|
2369
|
+
children: suffix
|
|
2329
2370
|
}
|
|
2330
2371
|
)
|
|
2331
2372
|
]
|
|
@@ -2357,16 +2398,17 @@ var DialogOverlay = React8__namespace.forwardRef(({ className, ...props }, ref)
|
|
|
2357
2398
|
}
|
|
2358
2399
|
));
|
|
2359
2400
|
DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
|
|
2360
|
-
var DialogContent = React8__namespace.forwardRef(
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2401
|
+
var DialogContent = React8__namespace.forwardRef(
|
|
2402
|
+
({ className, children, portal = false, showClose = true, ...props }, ref) => {
|
|
2403
|
+
const Comp = portal ? DialogPortal : React8__namespace.Fragment;
|
|
2404
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Comp, { children: [
|
|
2405
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
2406
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2407
|
+
DialogPrimitive__namespace.Content,
|
|
2408
|
+
{
|
|
2409
|
+
ref,
|
|
2410
|
+
className: cn(
|
|
2411
|
+
`rounded-2xl
|
|
2370
2412
|
fixed
|
|
2371
2413
|
left-[50%]
|
|
2372
2414
|
top-[50%]
|
|
@@ -2391,29 +2433,30 @@ var DialogContent = React8__namespace.forwardRef(({ className, children, portal
|
|
|
2391
2433
|
data-[state=closed]:slide-out-to-top-[48%]
|
|
2392
2434
|
data-[state=open]:slide-in-from-left-1/2
|
|
2393
2435
|
data-[state=open]:slide-in-from-top-[48%]`,
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
}
|
|
2436
|
+
className
|
|
2437
|
+
),
|
|
2438
|
+
...props,
|
|
2439
|
+
children: [
|
|
2440
|
+
children,
|
|
2441
|
+
showClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2442
|
+
DialogPrimitive__namespace.Close,
|
|
2443
|
+
{
|
|
2444
|
+
asChild: true,
|
|
2445
|
+
className: `absolute
|
|
2446
|
+
right-4
|
|
2447
|
+
top-4`,
|
|
2448
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", icon: true, children: [
|
|
2449
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "nebula-ds !h-4 !w-4 !text-dialog-icon" }),
|
|
2450
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "nebula-ds sr-only", children: "Close" })
|
|
2451
|
+
] })
|
|
2452
|
+
}
|
|
2453
|
+
)
|
|
2454
|
+
]
|
|
2455
|
+
}
|
|
2456
|
+
)
|
|
2457
|
+
] });
|
|
2458
|
+
}
|
|
2459
|
+
);
|
|
2417
2460
|
DialogContent.displayName = DialogPrimitive__namespace.Content.displayName;
|
|
2418
2461
|
var DialogHeader = ({
|
|
2419
2462
|
className,
|
|
@@ -3229,13 +3272,13 @@ function custom(message, options) {
|
|
|
3229
3272
|
}
|
|
3230
3273
|
);
|
|
3231
3274
|
}
|
|
3232
|
-
async function promise(promise2,
|
|
3275
|
+
async function promise(promise2, messages20, options) {
|
|
3233
3276
|
const loadingToast = sonner.toast.custom(
|
|
3234
3277
|
(t) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3235
3278
|
ToastComponent,
|
|
3236
3279
|
{
|
|
3237
3280
|
type: "info",
|
|
3238
|
-
message:
|
|
3281
|
+
message: messages20.loading,
|
|
3239
3282
|
options,
|
|
3240
3283
|
t
|
|
3241
3284
|
}
|
|
@@ -3249,7 +3292,7 @@ async function promise(promise2, messages17, options) {
|
|
|
3249
3292
|
ToastComponent,
|
|
3250
3293
|
{
|
|
3251
3294
|
type: "success",
|
|
3252
|
-
message:
|
|
3295
|
+
message: messages20.success,
|
|
3253
3296
|
options,
|
|
3254
3297
|
t
|
|
3255
3298
|
}
|
|
@@ -3264,7 +3307,7 @@ async function promise(promise2, messages17, options) {
|
|
|
3264
3307
|
ToastComponent,
|
|
3265
3308
|
{
|
|
3266
3309
|
type: "error",
|
|
3267
|
-
message:
|
|
3310
|
+
message: messages20.error,
|
|
3268
3311
|
options,
|
|
3269
3312
|
t
|
|
3270
3313
|
}
|
|
@@ -3434,8 +3477,8 @@ var CountrySelect = ({
|
|
|
3434
3477
|
const handleSelect = (event) => {
|
|
3435
3478
|
onChange(event.target.value);
|
|
3436
3479
|
};
|
|
3437
|
-
const { messages:
|
|
3438
|
-
const { countries } =
|
|
3480
|
+
const { messages: messages20 } = useNebulaI18n();
|
|
3481
|
+
const { countries } = messages20.inputPhone;
|
|
3439
3482
|
return /* @__PURE__ */ jsxRuntime.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: [
|
|
3440
3483
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nebula-ds inline-flex items-center gap-1", "aria-hidden": "true", children: [
|
|
3441
3484
|
/* @__PURE__ */ jsxRuntime.jsx(FlagComponent, { country: value, countryName: value, "aria-hidden": "true" }),
|
|
@@ -4243,7 +4286,10 @@ var InputDateTimePickerSingle = ({
|
|
|
4243
4286
|
...rest
|
|
4244
4287
|
}) => {
|
|
4245
4288
|
const [innerTimeValue, setInnerTimeValue] = React8.useState(
|
|
4246
|
-
|
|
4289
|
+
() => {
|
|
4290
|
+
const [, time] = (value || "")?.split?.(DATA_TIME_SEPARATOR);
|
|
4291
|
+
return time ?? "";
|
|
4292
|
+
}
|
|
4247
4293
|
);
|
|
4248
4294
|
const formattedDateByLanguage = formatDateToSubmit(
|
|
4249
4295
|
value?.split(DATA_TIME_SEPARATOR)?.at(0) ?? ""
|
|
@@ -4252,7 +4298,7 @@ var InputDateTimePickerSingle = ({
|
|
|
4252
4298
|
formattedDateByLanguage ? new Date(formattedDateByLanguage) : void 0
|
|
4253
4299
|
);
|
|
4254
4300
|
const [popoverIsOpen, setPopoverIsOpen] = React8.useState(false);
|
|
4255
|
-
const { locale, messages:
|
|
4301
|
+
const { locale, messages: messages20 } = useNebulaI18n();
|
|
4256
4302
|
const [month, setMonth] = React8.useState(/* @__PURE__ */ new Date());
|
|
4257
4303
|
const inputTimeRef = React8.useRef(null);
|
|
4258
4304
|
const handleClearValue = () => {
|
|
@@ -4310,8 +4356,9 @@ var InputDateTimePickerSingle = ({
|
|
|
4310
4356
|
if (date && !dateFormatIsValid(date, locale)) {
|
|
4311
4357
|
handleClearValue();
|
|
4312
4358
|
}
|
|
4359
|
+
const hasInputtedDate = date.length === "__/__/____".length;
|
|
4313
4360
|
onChange?.(
|
|
4314
|
-
date + (newTime ? DATA_TIME_SEPARATOR + newTime : ""),
|
|
4361
|
+
date + (newTime && hasInputtedDate ? DATA_TIME_SEPARATOR + newTime : ""),
|
|
4315
4362
|
innerDate,
|
|
4316
4363
|
newTime
|
|
4317
4364
|
);
|
|
@@ -4423,7 +4470,7 @@ var InputDateTimePickerSingle = ({
|
|
|
4423
4470
|
disabled: disabledDates,
|
|
4424
4471
|
footer: /* @__PURE__ */ jsxRuntime.jsxs(Space, { className: "nebula-ds items-center", children: [
|
|
4425
4472
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
4426
|
-
|
|
4473
|
+
messages20.timePicker.label,
|
|
4427
4474
|
":"
|
|
4428
4475
|
] }),
|
|
4429
4476
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4443,11 +4490,11 @@ var InputDateTimePickerSingle = ({
|
|
|
4443
4490
|
) })
|
|
4444
4491
|
] });
|
|
4445
4492
|
};
|
|
4446
|
-
var FileUploadError = /* @__PURE__ */ ((
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
return
|
|
4493
|
+
var FileUploadError = /* @__PURE__ */ ((FileUploadError4) => {
|
|
4494
|
+
FileUploadError4["MAX_FILES_EXCEEDED"] = "MAX_FILES_EXCEEDED";
|
|
4495
|
+
FileUploadError4["MAXIMUM_FILE_SIZE_EXCEEDED"] = "MAXIMUM_FILE_SIZE_EXCEEDED";
|
|
4496
|
+
FileUploadError4["INVALID_FORMAT"] = "INVALID_FORMAT";
|
|
4497
|
+
return FileUploadError4;
|
|
4451
4498
|
})(FileUploadError || {});
|
|
4452
4499
|
var useFileUpload = (options = {}) => {
|
|
4453
4500
|
const {
|
|
@@ -4548,9 +4595,6 @@ var useFileUpload = (options = {}) => {
|
|
|
4548
4595
|
const newFilesArray = Array.from(newFiles);
|
|
4549
4596
|
const errors = [];
|
|
4550
4597
|
setState((prev) => ({ ...prev, errors: [] }));
|
|
4551
|
-
if (!multiple) {
|
|
4552
|
-
clearFiles();
|
|
4553
|
-
}
|
|
4554
4598
|
if (multiple && maxFiles !== Infinity && state.files.length + newFilesArray.length > maxFiles) {
|
|
4555
4599
|
errors.push({ error: "MAX_FILES_EXCEEDED" /* MAX_FILES_EXCEEDED */ });
|
|
4556
4600
|
setState((prev) => ({ ...prev, errors }));
|
|
@@ -4585,6 +4629,9 @@ var useFileUpload = (options = {}) => {
|
|
|
4585
4629
|
}
|
|
4586
4630
|
});
|
|
4587
4631
|
if (validFiles.length > 0) {
|
|
4632
|
+
if (!multiple) {
|
|
4633
|
+
clearFiles();
|
|
4634
|
+
}
|
|
4588
4635
|
onFilesAdded?.(validFiles);
|
|
4589
4636
|
setState((prev) => {
|
|
4590
4637
|
const newFiles2 = !multiple ? validFiles : [...prev.files, ...validFiles];
|
|
@@ -4881,6 +4928,7 @@ function FileUpload({
|
|
|
4881
4928
|
) })
|
|
4882
4929
|
] });
|
|
4883
4930
|
}
|
|
4931
|
+
FileUpload.displayName = "FileUpload";
|
|
4884
4932
|
var TextArea = React8__namespace.forwardRef(
|
|
4885
4933
|
({
|
|
4886
4934
|
className,
|
|
@@ -4958,6 +5006,1133 @@ var TextArea = React8__namespace.forwardRef(
|
|
|
4958
5006
|
}
|
|
4959
5007
|
);
|
|
4960
5008
|
TextArea.displayName = "TextArea";
|
|
5009
|
+
var ProfileImage = ({
|
|
5010
|
+
maxSizeMB = 2,
|
|
5011
|
+
subtitle,
|
|
5012
|
+
onError,
|
|
5013
|
+
maxFiles = Infinity,
|
|
5014
|
+
onRemove,
|
|
5015
|
+
image,
|
|
5016
|
+
...rest
|
|
5017
|
+
}) => {
|
|
5018
|
+
const maxSize = maxSizeMB * 1024 * 1024;
|
|
5019
|
+
const id = React8.useId();
|
|
5020
|
+
const [
|
|
5021
|
+
{ files, isDragging, errors },
|
|
5022
|
+
{
|
|
5023
|
+
handleDragEnter,
|
|
5024
|
+
handleDragLeave,
|
|
5025
|
+
handleDragOver,
|
|
5026
|
+
handleDrop,
|
|
5027
|
+
openFileDialog,
|
|
5028
|
+
removeFile,
|
|
5029
|
+
getInputProps
|
|
5030
|
+
}
|
|
5031
|
+
] = useFileUpload({
|
|
5032
|
+
initialFiles: image ? [
|
|
5033
|
+
{
|
|
5034
|
+
id,
|
|
5035
|
+
url: image,
|
|
5036
|
+
name: image,
|
|
5037
|
+
size: 0,
|
|
5038
|
+
type: "image"
|
|
5039
|
+
}
|
|
5040
|
+
] : [],
|
|
5041
|
+
multiple: false,
|
|
5042
|
+
maxSize: maxSize > 0 ? maxSize : void 0,
|
|
5043
|
+
accept: "image/*",
|
|
5044
|
+
...rest,
|
|
5045
|
+
maxFiles
|
|
5046
|
+
});
|
|
5047
|
+
React8.useEffect(() => {
|
|
5048
|
+
onError?.(errors);
|
|
5049
|
+
}, [errors, onError]);
|
|
5050
|
+
const [file] = files;
|
|
5051
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nebula-ds flex flex-col gap-3", children: [
|
|
5052
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "nebula-ds flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5053
|
+
"div",
|
|
5054
|
+
{
|
|
5055
|
+
role: "button",
|
|
5056
|
+
onClick: openFileDialog,
|
|
5057
|
+
onDragEnter: handleDragEnter,
|
|
5058
|
+
onDragLeave: handleDragLeave,
|
|
5059
|
+
onDragOver: handleDragOver,
|
|
5060
|
+
onDrop: handleDrop,
|
|
5061
|
+
"data-dragging": isDragging || void 0,
|
|
5062
|
+
className: cn(
|
|
5063
|
+
"relative border border-transparent rounded-full size-fit",
|
|
5064
|
+
"bg-fileUpload-background hover:bg-fileUpload-backgroundHover transition-colors",
|
|
5065
|
+
!file && "border-dashed border-fileUpload-border"
|
|
5066
|
+
),
|
|
5067
|
+
"data-testid": "select-image-profile",
|
|
5068
|
+
children: [
|
|
5069
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5070
|
+
"input",
|
|
5071
|
+
{
|
|
5072
|
+
...getInputProps(),
|
|
5073
|
+
className: "nebula-ds sr-only",
|
|
5074
|
+
"aria-label": "Upload file"
|
|
5075
|
+
}
|
|
5076
|
+
),
|
|
5077
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5078
|
+
"div",
|
|
5079
|
+
{
|
|
5080
|
+
className: "nebula-ds flex size-12 shrink-0 items-center justify-center rounded-full",
|
|
5081
|
+
"aria-hidden": "true",
|
|
5082
|
+
children: [
|
|
5083
|
+
file && file.preview && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5084
|
+
"img",
|
|
5085
|
+
{
|
|
5086
|
+
src: file.preview,
|
|
5087
|
+
alt: file.file.name,
|
|
5088
|
+
className: "nebula-ds rounded-[inherit] object-cover h-full w-full"
|
|
5089
|
+
}
|
|
5090
|
+
),
|
|
5091
|
+
!file && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserIcon, { className: "nebula-ds size-4 opacity-60 text-fileUpload-icon" })
|
|
5092
|
+
]
|
|
5093
|
+
}
|
|
5094
|
+
),
|
|
5095
|
+
file && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5096
|
+
"button",
|
|
5097
|
+
{
|
|
5098
|
+
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",
|
|
5099
|
+
"data-testid": "remove-profile-image",
|
|
5100
|
+
onClick: (e) => {
|
|
5101
|
+
e.stopPropagation();
|
|
5102
|
+
removeFile(file.id);
|
|
5103
|
+
onRemove?.();
|
|
5104
|
+
},
|
|
5105
|
+
type: "button",
|
|
5106
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "nebula-ds size-2" })
|
|
5107
|
+
}
|
|
5108
|
+
)
|
|
5109
|
+
]
|
|
5110
|
+
}
|
|
5111
|
+
) }),
|
|
5112
|
+
!!subtitle && /* @__PURE__ */ jsxRuntime.jsx(Paragraph, { className: "nebula-ds text-center", size: "sm", children: subtitle })
|
|
5113
|
+
] });
|
|
5114
|
+
};
|
|
5115
|
+
ProfileImage.displayName = "ProfileImage";
|
|
5116
|
+
function clamp(value, min, max) {
|
|
5117
|
+
return Math.min(Math.max(value, min), max);
|
|
5118
|
+
}
|
|
5119
|
+
var CropperContext = React8.createContext(null);
|
|
5120
|
+
var useCropperContext = () => {
|
|
5121
|
+
const context = React8.useContext(CropperContext);
|
|
5122
|
+
if (!context) {
|
|
5123
|
+
throw new Error("useCropperContext must be used within a Cropper.Root");
|
|
5124
|
+
}
|
|
5125
|
+
return context;
|
|
5126
|
+
};
|
|
5127
|
+
var CropperRoot = ({
|
|
5128
|
+
image,
|
|
5129
|
+
cropPadding = 25,
|
|
5130
|
+
aspectRatio = 1,
|
|
5131
|
+
minZoom = 1,
|
|
5132
|
+
maxZoom = 3,
|
|
5133
|
+
zoomSensitivity = 5e-3,
|
|
5134
|
+
keyboardStep = 10,
|
|
5135
|
+
className,
|
|
5136
|
+
style,
|
|
5137
|
+
zoom: zoomProp,
|
|
5138
|
+
onCropChange,
|
|
5139
|
+
onZoomChange,
|
|
5140
|
+
children,
|
|
5141
|
+
...restProps
|
|
5142
|
+
}) => {
|
|
5143
|
+
const descriptionId = React8.useId();
|
|
5144
|
+
const [imgWidth, setImgWidth] = React8.useState(null);
|
|
5145
|
+
const [imgHeight, setImgHeight] = React8.useState(null);
|
|
5146
|
+
const containerRef = React8.useRef(null);
|
|
5147
|
+
const [cropAreaWidth, setCropAreaWidth] = React8.useState(0);
|
|
5148
|
+
const [cropAreaHeight, setCropAreaHeight] = React8.useState(0);
|
|
5149
|
+
const [imageWrapperWidth, setImageWrapperWidth] = React8.useState(0);
|
|
5150
|
+
const [imageWrapperHeight, setImageWrapperHeight] = React8.useState(0);
|
|
5151
|
+
const [offsetX, setOffsetX] = React8.useState(0);
|
|
5152
|
+
const [offsetY, setOffsetY] = React8.useState(0);
|
|
5153
|
+
const [internalZoom, setInternalZoom] = React8.useState(minZoom);
|
|
5154
|
+
const [isDragging, setIsDragging] = React8.useState(false);
|
|
5155
|
+
const dragStartPointRef = React8.useRef({ x: 0, y: 0 });
|
|
5156
|
+
const dragStartOffsetRef = React8.useRef({ x: 0, y: 0 });
|
|
5157
|
+
const latestRestrictedOffsetRef = React8.useRef({
|
|
5158
|
+
x: offsetX,
|
|
5159
|
+
y: offsetY
|
|
5160
|
+
});
|
|
5161
|
+
const latestZoomRef = React8.useRef(internalZoom);
|
|
5162
|
+
const isInitialSetupDoneRef = React8.useRef(false);
|
|
5163
|
+
const initialPinchDistanceRef = React8.useRef(0);
|
|
5164
|
+
const initialPinchZoomRef = React8.useRef(1);
|
|
5165
|
+
const isPinchingRef = React8.useRef(false);
|
|
5166
|
+
const hasWarnedRef = React8.useRef(false);
|
|
5167
|
+
const isZoomControlled = zoomProp !== void 0;
|
|
5168
|
+
const effectiveZoom = isZoomControlled ? zoomProp : internalZoom;
|
|
5169
|
+
const updateZoom = React8.useCallback(
|
|
5170
|
+
(newZoomValue) => {
|
|
5171
|
+
const clampedZoom = clamp(newZoomValue, minZoom, maxZoom);
|
|
5172
|
+
if (onZoomChange) {
|
|
5173
|
+
onZoomChange(clampedZoom);
|
|
5174
|
+
} else if (!isZoomControlled) {
|
|
5175
|
+
setInternalZoom(clampedZoom);
|
|
5176
|
+
}
|
|
5177
|
+
return clampedZoom;
|
|
5178
|
+
},
|
|
5179
|
+
[minZoom, maxZoom, onZoomChange, isZoomControlled]
|
|
5180
|
+
);
|
|
5181
|
+
React8.useEffect(() => {
|
|
5182
|
+
latestZoomRef.current = effectiveZoom;
|
|
5183
|
+
}, [effectiveZoom]);
|
|
5184
|
+
React8.useEffect(() => {
|
|
5185
|
+
setOffsetX(0);
|
|
5186
|
+
setOffsetY(0);
|
|
5187
|
+
if (!isZoomControlled) {
|
|
5188
|
+
setInternalZoom(minZoom);
|
|
5189
|
+
}
|
|
5190
|
+
isInitialSetupDoneRef.current = false;
|
|
5191
|
+
if (!image) {
|
|
5192
|
+
setImgWidth(null);
|
|
5193
|
+
setImgHeight(null);
|
|
5194
|
+
return;
|
|
5195
|
+
}
|
|
5196
|
+
let isMounted = true;
|
|
5197
|
+
const img = new Image();
|
|
5198
|
+
img.onload = () => {
|
|
5199
|
+
if (isMounted) {
|
|
5200
|
+
setImgWidth(img.naturalWidth);
|
|
5201
|
+
setImgHeight(img.naturalHeight);
|
|
5202
|
+
}
|
|
5203
|
+
};
|
|
5204
|
+
img.onerror = () => {
|
|
5205
|
+
if (isMounted) {
|
|
5206
|
+
setImgWidth(null);
|
|
5207
|
+
setImgHeight(null);
|
|
5208
|
+
}
|
|
5209
|
+
};
|
|
5210
|
+
img.src = image;
|
|
5211
|
+
return () => {
|
|
5212
|
+
isMounted = false;
|
|
5213
|
+
};
|
|
5214
|
+
}, [image, minZoom, isZoomControlled]);
|
|
5215
|
+
const updateCropAreaDimensions = React8.useCallback(
|
|
5216
|
+
(containerWidth, containerHeight) => {
|
|
5217
|
+
if (containerWidth <= 0 || containerHeight <= 0) {
|
|
5218
|
+
setCropAreaWidth(0);
|
|
5219
|
+
setCropAreaHeight(0);
|
|
5220
|
+
return;
|
|
5221
|
+
}
|
|
5222
|
+
const maxPossibleWidth = Math.max(0, containerWidth - cropPadding * 2);
|
|
5223
|
+
const maxPossibleHeight = Math.max(0, containerHeight - cropPadding * 2);
|
|
5224
|
+
let targetCropW = 0;
|
|
5225
|
+
let targetCropH = 0;
|
|
5226
|
+
if (maxPossibleWidth / aspectRatio >= maxPossibleHeight) {
|
|
5227
|
+
targetCropH = maxPossibleHeight;
|
|
5228
|
+
targetCropW = targetCropH * aspectRatio;
|
|
5229
|
+
} else {
|
|
5230
|
+
targetCropW = maxPossibleWidth;
|
|
5231
|
+
targetCropH = targetCropW / aspectRatio;
|
|
5232
|
+
}
|
|
5233
|
+
setCropAreaWidth(targetCropW);
|
|
5234
|
+
setCropAreaHeight(targetCropH);
|
|
5235
|
+
},
|
|
5236
|
+
[aspectRatio, cropPadding]
|
|
5237
|
+
);
|
|
5238
|
+
React8.useEffect(() => {
|
|
5239
|
+
const element = containerRef.current;
|
|
5240
|
+
if (!element) return;
|
|
5241
|
+
const observer = new ResizeObserver((entries) => {
|
|
5242
|
+
for (const entry of entries) {
|
|
5243
|
+
const { width, height } = entry.contentRect;
|
|
5244
|
+
if (width > 0 && height > 0) updateCropAreaDimensions(width, height);
|
|
5245
|
+
}
|
|
5246
|
+
});
|
|
5247
|
+
observer.observe(element);
|
|
5248
|
+
const initialWidth = element.clientWidth;
|
|
5249
|
+
const initialHeight = element.clientHeight;
|
|
5250
|
+
if (initialWidth > 0 && initialHeight > 0)
|
|
5251
|
+
updateCropAreaDimensions(initialWidth, initialHeight);
|
|
5252
|
+
return () => observer.disconnect();
|
|
5253
|
+
}, [updateCropAreaDimensions]);
|
|
5254
|
+
React8.useEffect(() => {
|
|
5255
|
+
if (cropAreaWidth <= 0 || cropAreaHeight <= 0 || !imgWidth || !imgHeight) {
|
|
5256
|
+
setImageWrapperWidth(0);
|
|
5257
|
+
setImageWrapperHeight(0);
|
|
5258
|
+
return;
|
|
5259
|
+
}
|
|
5260
|
+
const naturalAspect = imgWidth / imgHeight;
|
|
5261
|
+
const cropAspect = cropAreaWidth / cropAreaHeight;
|
|
5262
|
+
let targetWrapperWidth = 0;
|
|
5263
|
+
let targetWrapperHeight = 0;
|
|
5264
|
+
if (naturalAspect >= cropAspect) {
|
|
5265
|
+
targetWrapperHeight = cropAreaHeight;
|
|
5266
|
+
targetWrapperWidth = targetWrapperHeight * naturalAspect;
|
|
5267
|
+
} else {
|
|
5268
|
+
targetWrapperWidth = cropAreaWidth;
|
|
5269
|
+
targetWrapperHeight = targetWrapperWidth / naturalAspect;
|
|
5270
|
+
}
|
|
5271
|
+
setImageWrapperWidth(targetWrapperWidth);
|
|
5272
|
+
setImageWrapperHeight(targetWrapperHeight);
|
|
5273
|
+
}, [cropAreaWidth, cropAreaHeight, imgWidth, imgHeight]);
|
|
5274
|
+
const restrictOffset = React8.useCallback(
|
|
5275
|
+
(dragOffsetX, dragOffsetY, currentZoom) => {
|
|
5276
|
+
if (imageWrapperWidth <= 0 || imageWrapperHeight <= 0 || cropAreaWidth <= 0 || cropAreaHeight <= 0)
|
|
5277
|
+
return { x: 0, y: 0 };
|
|
5278
|
+
const effectiveWrapperWidth = imageWrapperWidth * currentZoom;
|
|
5279
|
+
const effectiveWrapperHeight = imageWrapperHeight * currentZoom;
|
|
5280
|
+
const maxDragX = Math.max(0, (effectiveWrapperWidth - cropAreaWidth) / 2);
|
|
5281
|
+
const maxDragY = Math.max(
|
|
5282
|
+
0,
|
|
5283
|
+
(effectiveWrapperHeight - cropAreaHeight) / 2
|
|
5284
|
+
);
|
|
5285
|
+
return {
|
|
5286
|
+
x: clamp(dragOffsetX, -maxDragX, maxDragX),
|
|
5287
|
+
y: clamp(dragOffsetY, -maxDragY, maxDragY)
|
|
5288
|
+
};
|
|
5289
|
+
},
|
|
5290
|
+
[imageWrapperWidth, imageWrapperHeight, cropAreaWidth, cropAreaHeight]
|
|
5291
|
+
);
|
|
5292
|
+
const calculateCropData = React8.useCallback(
|
|
5293
|
+
(finalOffsetX, finalOffsetY, finalZoom) => {
|
|
5294
|
+
const currentOffsetX = finalOffsetX !== void 0 ? finalOffsetX : latestRestrictedOffsetRef.current.x;
|
|
5295
|
+
const currentOffsetY = finalOffsetY !== void 0 ? finalOffsetY : latestRestrictedOffsetRef.current.y;
|
|
5296
|
+
const currentZoom = finalZoom !== void 0 ? finalZoom : effectiveZoom;
|
|
5297
|
+
if (!imgWidth || !imgHeight || imageWrapperWidth <= 0 || imageWrapperHeight <= 0 || cropAreaWidth <= 0 || cropAreaHeight <= 0)
|
|
5298
|
+
return null;
|
|
5299
|
+
const scaledWrapperWidth = imageWrapperWidth * currentZoom;
|
|
5300
|
+
const scaledWrapperHeight = imageWrapperHeight * currentZoom;
|
|
5301
|
+
const topLeftOffsetX = currentOffsetX + (cropAreaWidth - scaledWrapperWidth) / 2;
|
|
5302
|
+
const topLeftOffsetY = currentOffsetY + (cropAreaHeight - scaledWrapperHeight) / 2;
|
|
5303
|
+
const baseScale = imgWidth / imageWrapperWidth;
|
|
5304
|
+
if (isNaN(baseScale) || baseScale === 0) return null;
|
|
5305
|
+
const sx = -topLeftOffsetX * baseScale / currentZoom;
|
|
5306
|
+
const sy = -topLeftOffsetY * baseScale / currentZoom;
|
|
5307
|
+
const sWidth = cropAreaWidth * baseScale / currentZoom;
|
|
5308
|
+
const sHeight = cropAreaHeight * baseScale / currentZoom;
|
|
5309
|
+
const finalX = clamp(Math.round(sx), 0, imgWidth);
|
|
5310
|
+
const finalY = clamp(Math.round(sy), 0, imgHeight);
|
|
5311
|
+
const finalWidth = clamp(Math.round(sWidth), 0, imgWidth - finalX);
|
|
5312
|
+
const finalHeight = clamp(Math.round(sHeight), 0, imgHeight - finalY);
|
|
5313
|
+
if (finalWidth <= 0 || finalHeight <= 0) return null;
|
|
5314
|
+
return { x: finalX, y: finalY, width: finalWidth, height: finalHeight };
|
|
5315
|
+
},
|
|
5316
|
+
[
|
|
5317
|
+
imgWidth,
|
|
5318
|
+
imgHeight,
|
|
5319
|
+
imageWrapperWidth,
|
|
5320
|
+
imageWrapperHeight,
|
|
5321
|
+
cropAreaWidth,
|
|
5322
|
+
cropAreaHeight,
|
|
5323
|
+
effectiveZoom
|
|
5324
|
+
]
|
|
5325
|
+
);
|
|
5326
|
+
React8.useEffect(() => {
|
|
5327
|
+
if (imageWrapperWidth > 0 && imageWrapperHeight > 0 && cropAreaWidth > 0 && cropAreaHeight > 0) {
|
|
5328
|
+
const currentZoomForSetup = effectiveZoom;
|
|
5329
|
+
if (!isInitialSetupDoneRef.current) {
|
|
5330
|
+
const initialX = 0;
|
|
5331
|
+
const initialY = 0;
|
|
5332
|
+
const restrictedInitial = restrictOffset(
|
|
5333
|
+
initialX,
|
|
5334
|
+
initialY,
|
|
5335
|
+
currentZoomForSetup
|
|
5336
|
+
);
|
|
5337
|
+
setOffsetX(restrictedInitial.x);
|
|
5338
|
+
setOffsetY(restrictedInitial.y);
|
|
5339
|
+
if (!isZoomControlled) setInternalZoom(currentZoomForSetup);
|
|
5340
|
+
dragStartOffsetRef.current = restrictedInitial;
|
|
5341
|
+
latestRestrictedOffsetRef.current = restrictedInitial;
|
|
5342
|
+
latestZoomRef.current = currentZoomForSetup;
|
|
5343
|
+
if (onCropChange)
|
|
5344
|
+
onCropChange(
|
|
5345
|
+
calculateCropData(
|
|
5346
|
+
restrictedInitial.x,
|
|
5347
|
+
restrictedInitial.y,
|
|
5348
|
+
currentZoomForSetup
|
|
5349
|
+
)
|
|
5350
|
+
);
|
|
5351
|
+
isInitialSetupDoneRef.current = true;
|
|
5352
|
+
} else {
|
|
5353
|
+
const restrictedCurrent = restrictOffset(
|
|
5354
|
+
latestRestrictedOffsetRef.current.x,
|
|
5355
|
+
latestRestrictedOffsetRef.current.y,
|
|
5356
|
+
currentZoomForSetup
|
|
5357
|
+
);
|
|
5358
|
+
if (restrictedCurrent.x !== latestRestrictedOffsetRef.current.x || restrictedCurrent.y !== latestRestrictedOffsetRef.current.y) {
|
|
5359
|
+
setOffsetX(restrictedCurrent.x);
|
|
5360
|
+
setOffsetY(restrictedCurrent.y);
|
|
5361
|
+
latestRestrictedOffsetRef.current = restrictedCurrent;
|
|
5362
|
+
dragStartOffsetRef.current = restrictedCurrent;
|
|
5363
|
+
}
|
|
5364
|
+
if (onCropChange)
|
|
5365
|
+
onCropChange(
|
|
5366
|
+
calculateCropData(
|
|
5367
|
+
restrictedCurrent.x,
|
|
5368
|
+
restrictedCurrent.y,
|
|
5369
|
+
currentZoomForSetup
|
|
5370
|
+
)
|
|
5371
|
+
);
|
|
5372
|
+
}
|
|
5373
|
+
} else {
|
|
5374
|
+
isInitialSetupDoneRef.current = false;
|
|
5375
|
+
setOffsetX(0);
|
|
5376
|
+
setOffsetY(0);
|
|
5377
|
+
if (!isZoomControlled) setInternalZoom(minZoom);
|
|
5378
|
+
dragStartOffsetRef.current = { x: 0, y: 0 };
|
|
5379
|
+
latestRestrictedOffsetRef.current = { x: 0, y: 0 };
|
|
5380
|
+
latestZoomRef.current = effectiveZoom;
|
|
5381
|
+
if (onCropChange) onCropChange(null);
|
|
5382
|
+
}
|
|
5383
|
+
}, [
|
|
5384
|
+
imageWrapperWidth,
|
|
5385
|
+
imgHeight,
|
|
5386
|
+
cropAreaWidth,
|
|
5387
|
+
cropAreaHeight,
|
|
5388
|
+
restrictOffset,
|
|
5389
|
+
onCropChange,
|
|
5390
|
+
calculateCropData,
|
|
5391
|
+
minZoom,
|
|
5392
|
+
effectiveZoom,
|
|
5393
|
+
isZoomControlled,
|
|
5394
|
+
updateZoom,
|
|
5395
|
+
imageWrapperHeight
|
|
5396
|
+
]);
|
|
5397
|
+
React8.useEffect(() => {
|
|
5398
|
+
const checkTimeout = setTimeout(() => {
|
|
5399
|
+
if (containerRef.current && !hasWarnedRef.current) {
|
|
5400
|
+
const hasDescription = document.getElementById(descriptionId);
|
|
5401
|
+
if (!hasDescription) {
|
|
5402
|
+
hasWarnedRef.current = true;
|
|
5403
|
+
}
|
|
5404
|
+
}
|
|
5405
|
+
}, 100);
|
|
5406
|
+
return () => clearTimeout(checkTimeout);
|
|
5407
|
+
}, [descriptionId]);
|
|
5408
|
+
const handleInteractionEnd = React8.useCallback(() => {
|
|
5409
|
+
if (onCropChange) {
|
|
5410
|
+
const finalData = calculateCropData(
|
|
5411
|
+
latestRestrictedOffsetRef.current.x,
|
|
5412
|
+
latestRestrictedOffsetRef.current.y,
|
|
5413
|
+
effectiveZoom
|
|
5414
|
+
);
|
|
5415
|
+
onCropChange(finalData);
|
|
5416
|
+
}
|
|
5417
|
+
}, [onCropChange, calculateCropData, effectiveZoom]);
|
|
5418
|
+
const handleMouseDown = React8.useCallback(
|
|
5419
|
+
(e) => {
|
|
5420
|
+
if (e.button !== 0 || !containerRef.current) return;
|
|
5421
|
+
e.preventDefault();
|
|
5422
|
+
setIsDragging(true);
|
|
5423
|
+
isPinchingRef.current = false;
|
|
5424
|
+
dragStartPointRef.current = { x: e.clientX, y: e.clientY };
|
|
5425
|
+
dragStartOffsetRef.current = {
|
|
5426
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5427
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5428
|
+
};
|
|
5429
|
+
const handleMouseMove = (ev) => {
|
|
5430
|
+
const deltaX = ev.clientX - dragStartPointRef.current.x;
|
|
5431
|
+
const deltaY = ev.clientY - dragStartPointRef.current.y;
|
|
5432
|
+
const targetOffsetX = dragStartOffsetRef.current.x + deltaX;
|
|
5433
|
+
const targetOffsetY = dragStartOffsetRef.current.y + deltaY;
|
|
5434
|
+
const restricted = restrictOffset(
|
|
5435
|
+
targetOffsetX,
|
|
5436
|
+
targetOffsetY,
|
|
5437
|
+
effectiveZoom
|
|
5438
|
+
);
|
|
5439
|
+
latestRestrictedOffsetRef.current = restricted;
|
|
5440
|
+
setOffsetX(restricted.x);
|
|
5441
|
+
setOffsetY(restricted.y);
|
|
5442
|
+
};
|
|
5443
|
+
const handleMouseUp = () => {
|
|
5444
|
+
setIsDragging(false);
|
|
5445
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
5446
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
5447
|
+
handleInteractionEnd();
|
|
5448
|
+
};
|
|
5449
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
5450
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
5451
|
+
},
|
|
5452
|
+
[restrictOffset, effectiveZoom, handleInteractionEnd]
|
|
5453
|
+
);
|
|
5454
|
+
const handleWheel = React8.useCallback(
|
|
5455
|
+
(e) => {
|
|
5456
|
+
e.preventDefault();
|
|
5457
|
+
e.stopPropagation();
|
|
5458
|
+
if (!containerRef.current || imageWrapperWidth <= 0 || imageWrapperHeight <= 0)
|
|
5459
|
+
return;
|
|
5460
|
+
const currentZoom = latestZoomRef.current;
|
|
5461
|
+
const currentOffsetX = latestRestrictedOffsetRef.current.x;
|
|
5462
|
+
const currentOffsetY = latestRestrictedOffsetRef.current.y;
|
|
5463
|
+
const delta = e.deltaY * -zoomSensitivity;
|
|
5464
|
+
const targetZoom = currentZoom + delta;
|
|
5465
|
+
if (clamp(targetZoom, minZoom, maxZoom) === currentZoom) return;
|
|
5466
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
5467
|
+
const pointerX = e.clientX - rect.left - rect.width / 2;
|
|
5468
|
+
const pointerY = e.clientY - rect.top - rect.height / 2;
|
|
5469
|
+
const imagePointX = (pointerX - currentOffsetX) / currentZoom;
|
|
5470
|
+
const imagePointY = (pointerY - currentOffsetY) / currentZoom;
|
|
5471
|
+
const finalNewZoom = updateZoom(targetZoom);
|
|
5472
|
+
const newOffsetX = pointerX - imagePointX * finalNewZoom;
|
|
5473
|
+
const newOffsetY = pointerY - imagePointY * finalNewZoom;
|
|
5474
|
+
const restrictedNewOffset = restrictOffset(
|
|
5475
|
+
newOffsetX,
|
|
5476
|
+
newOffsetY,
|
|
5477
|
+
finalNewZoom
|
|
5478
|
+
);
|
|
5479
|
+
setOffsetX(restrictedNewOffset.x);
|
|
5480
|
+
setOffsetY(restrictedNewOffset.y);
|
|
5481
|
+
latestRestrictedOffsetRef.current = restrictedNewOffset;
|
|
5482
|
+
if (onCropChange) {
|
|
5483
|
+
const finalData = calculateCropData(
|
|
5484
|
+
restrictedNewOffset.x,
|
|
5485
|
+
restrictedNewOffset.y,
|
|
5486
|
+
finalNewZoom
|
|
5487
|
+
);
|
|
5488
|
+
onCropChange(finalData);
|
|
5489
|
+
}
|
|
5490
|
+
},
|
|
5491
|
+
[
|
|
5492
|
+
restrictOffset,
|
|
5493
|
+
calculateCropData,
|
|
5494
|
+
imageWrapperWidth,
|
|
5495
|
+
imageWrapperHeight,
|
|
5496
|
+
onCropChange,
|
|
5497
|
+
minZoom,
|
|
5498
|
+
maxZoom,
|
|
5499
|
+
zoomSensitivity,
|
|
5500
|
+
updateZoom
|
|
5501
|
+
]
|
|
5502
|
+
);
|
|
5503
|
+
const getPinchDistance = (touches) => Math.sqrt(
|
|
5504
|
+
Math.pow(touches[1].clientX - touches[0].clientX, 2) + Math.pow(touches[1].clientY - touches[0].clientY, 2)
|
|
5505
|
+
);
|
|
5506
|
+
const getPinchCenter = (touches) => ({
|
|
5507
|
+
x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
5508
|
+
y: (touches[0].clientY + touches[1].clientY) / 2
|
|
5509
|
+
});
|
|
5510
|
+
const handleTouchStart = React8.useCallback(
|
|
5511
|
+
(e) => {
|
|
5512
|
+
if (!containerRef.current || imageWrapperWidth <= 0 || imageWrapperHeight <= 0)
|
|
5513
|
+
return;
|
|
5514
|
+
e.preventDefault();
|
|
5515
|
+
const touches = e.touches;
|
|
5516
|
+
if (touches.length === 1) {
|
|
5517
|
+
setIsDragging(true);
|
|
5518
|
+
isPinchingRef.current = false;
|
|
5519
|
+
dragStartPointRef.current = {
|
|
5520
|
+
x: touches[0].clientX,
|
|
5521
|
+
y: touches[0].clientY
|
|
5522
|
+
};
|
|
5523
|
+
dragStartOffsetRef.current = {
|
|
5524
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5525
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5526
|
+
};
|
|
5527
|
+
} else if (touches.length === 2) {
|
|
5528
|
+
setIsDragging(false);
|
|
5529
|
+
isPinchingRef.current = true;
|
|
5530
|
+
initialPinchDistanceRef.current = getPinchDistance(touches);
|
|
5531
|
+
initialPinchZoomRef.current = latestZoomRef.current;
|
|
5532
|
+
dragStartOffsetRef.current = {
|
|
5533
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5534
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5535
|
+
};
|
|
5536
|
+
}
|
|
5537
|
+
},
|
|
5538
|
+
[imageWrapperWidth, imageWrapperHeight]
|
|
5539
|
+
);
|
|
5540
|
+
const handleTouchMove = React8.useCallback(
|
|
5541
|
+
(e) => {
|
|
5542
|
+
if (!containerRef.current || imageWrapperWidth <= 0 || imageWrapperHeight <= 0)
|
|
5543
|
+
return;
|
|
5544
|
+
e.preventDefault();
|
|
5545
|
+
const touches = e.touches;
|
|
5546
|
+
if (touches.length === 1 && isDragging && !isPinchingRef.current) {
|
|
5547
|
+
const deltaX = touches[0].clientX - dragStartPointRef.current.x;
|
|
5548
|
+
const deltaY = touches[0].clientY - dragStartPointRef.current.y;
|
|
5549
|
+
const targetOffsetX = dragStartOffsetRef.current.x + deltaX;
|
|
5550
|
+
const targetOffsetY = dragStartOffsetRef.current.y + deltaY;
|
|
5551
|
+
const restricted = restrictOffset(
|
|
5552
|
+
targetOffsetX,
|
|
5553
|
+
targetOffsetY,
|
|
5554
|
+
effectiveZoom
|
|
5555
|
+
);
|
|
5556
|
+
latestRestrictedOffsetRef.current = restricted;
|
|
5557
|
+
setOffsetX(restricted.x);
|
|
5558
|
+
setOffsetY(restricted.y);
|
|
5559
|
+
} else if (touches.length === 2 && isPinchingRef.current) {
|
|
5560
|
+
const currentPinchDistance = getPinchDistance(touches);
|
|
5561
|
+
const scale = currentPinchDistance / initialPinchDistanceRef.current;
|
|
5562
|
+
const currentZoom = initialPinchZoomRef.current;
|
|
5563
|
+
const targetZoom = currentZoom * scale;
|
|
5564
|
+
if (clamp(targetZoom, minZoom, maxZoom) === latestZoomRef.current)
|
|
5565
|
+
return;
|
|
5566
|
+
const pinchCenter = getPinchCenter(touches);
|
|
5567
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
5568
|
+
const pinchCenterX = pinchCenter.x - rect.left - rect.width / 2;
|
|
5569
|
+
const pinchCenterY = pinchCenter.y - rect.top - rect.height / 2;
|
|
5570
|
+
const currentOffsetX = dragStartOffsetRef.current.x;
|
|
5571
|
+
const currentOffsetY = dragStartOffsetRef.current.y;
|
|
5572
|
+
const imagePointX = (pinchCenterX - currentOffsetX) / currentZoom;
|
|
5573
|
+
const imagePointY = (pinchCenterY - currentOffsetY) / currentZoom;
|
|
5574
|
+
const finalNewZoom = updateZoom(targetZoom);
|
|
5575
|
+
const newOffsetX = pinchCenterX - imagePointX * finalNewZoom;
|
|
5576
|
+
const newOffsetY = pinchCenterY - imagePointY * finalNewZoom;
|
|
5577
|
+
const restrictedNewOffset = restrictOffset(
|
|
5578
|
+
newOffsetX,
|
|
5579
|
+
newOffsetY,
|
|
5580
|
+
finalNewZoom
|
|
5581
|
+
);
|
|
5582
|
+
setOffsetX(restrictedNewOffset.x);
|
|
5583
|
+
setOffsetY(restrictedNewOffset.y);
|
|
5584
|
+
latestRestrictedOffsetRef.current = restrictedNewOffset;
|
|
5585
|
+
if (onCropChange) {
|
|
5586
|
+
const finalData = calculateCropData(
|
|
5587
|
+
restrictedNewOffset.x,
|
|
5588
|
+
restrictedNewOffset.y,
|
|
5589
|
+
finalNewZoom
|
|
5590
|
+
);
|
|
5591
|
+
onCropChange(finalData);
|
|
5592
|
+
}
|
|
5593
|
+
}
|
|
5594
|
+
},
|
|
5595
|
+
[
|
|
5596
|
+
isDragging,
|
|
5597
|
+
restrictOffset,
|
|
5598
|
+
minZoom,
|
|
5599
|
+
maxZoom,
|
|
5600
|
+
imageWrapperWidth,
|
|
5601
|
+
imageWrapperHeight,
|
|
5602
|
+
effectiveZoom,
|
|
5603
|
+
updateZoom,
|
|
5604
|
+
onCropChange,
|
|
5605
|
+
calculateCropData
|
|
5606
|
+
]
|
|
5607
|
+
);
|
|
5608
|
+
const handleTouchEnd = React8.useCallback(
|
|
5609
|
+
(e) => {
|
|
5610
|
+
e.preventDefault();
|
|
5611
|
+
const touches = e.touches;
|
|
5612
|
+
if (isPinchingRef.current && touches.length < 2) {
|
|
5613
|
+
isPinchingRef.current = false;
|
|
5614
|
+
if (touches.length === 1) {
|
|
5615
|
+
setIsDragging(true);
|
|
5616
|
+
dragStartPointRef.current = {
|
|
5617
|
+
x: touches[0].clientX,
|
|
5618
|
+
y: touches[0].clientY
|
|
5619
|
+
};
|
|
5620
|
+
dragStartOffsetRef.current = {
|
|
5621
|
+
x: latestRestrictedOffsetRef.current.x,
|
|
5622
|
+
y: latestRestrictedOffsetRef.current.y
|
|
5623
|
+
};
|
|
5624
|
+
} else {
|
|
5625
|
+
setIsDragging(false);
|
|
5626
|
+
handleInteractionEnd();
|
|
5627
|
+
}
|
|
5628
|
+
} else if (isDragging && touches.length === 0) {
|
|
5629
|
+
setIsDragging(false);
|
|
5630
|
+
handleInteractionEnd();
|
|
5631
|
+
}
|
|
5632
|
+
},
|
|
5633
|
+
[isDragging, handleInteractionEnd]
|
|
5634
|
+
);
|
|
5635
|
+
const handleKeyDown = React8.useCallback(
|
|
5636
|
+
(e) => {
|
|
5637
|
+
if (imageWrapperWidth <= 0) return;
|
|
5638
|
+
let targetOffsetX = latestRestrictedOffsetRef.current.x;
|
|
5639
|
+
let targetOffsetY = latestRestrictedOffsetRef.current.y;
|
|
5640
|
+
let moved = false;
|
|
5641
|
+
switch (e.key) {
|
|
5642
|
+
case "ArrowUp":
|
|
5643
|
+
targetOffsetY += keyboardStep;
|
|
5644
|
+
moved = true;
|
|
5645
|
+
break;
|
|
5646
|
+
case "ArrowDown":
|
|
5647
|
+
targetOffsetY -= keyboardStep;
|
|
5648
|
+
moved = true;
|
|
5649
|
+
break;
|
|
5650
|
+
case "ArrowLeft":
|
|
5651
|
+
targetOffsetX += keyboardStep;
|
|
5652
|
+
moved = true;
|
|
5653
|
+
break;
|
|
5654
|
+
case "ArrowRight":
|
|
5655
|
+
targetOffsetX -= keyboardStep;
|
|
5656
|
+
moved = true;
|
|
5657
|
+
break;
|
|
5658
|
+
default:
|
|
5659
|
+
return;
|
|
5660
|
+
}
|
|
5661
|
+
if (moved) {
|
|
5662
|
+
e.preventDefault();
|
|
5663
|
+
const restricted = restrictOffset(
|
|
5664
|
+
targetOffsetX,
|
|
5665
|
+
targetOffsetY,
|
|
5666
|
+
effectiveZoom
|
|
5667
|
+
);
|
|
5668
|
+
if (restricted.x !== latestRestrictedOffsetRef.current.x || restricted.y !== latestRestrictedOffsetRef.current.y) {
|
|
5669
|
+
latestRestrictedOffsetRef.current = restricted;
|
|
5670
|
+
setOffsetX(restricted.x);
|
|
5671
|
+
setOffsetY(restricted.y);
|
|
5672
|
+
}
|
|
5673
|
+
}
|
|
5674
|
+
},
|
|
5675
|
+
[keyboardStep, imageWrapperWidth, restrictOffset, effectiveZoom]
|
|
5676
|
+
);
|
|
5677
|
+
const handleKeyUp = React8.useCallback(
|
|
5678
|
+
(e) => {
|
|
5679
|
+
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
5680
|
+
handleInteractionEnd();
|
|
5681
|
+
}
|
|
5682
|
+
},
|
|
5683
|
+
[handleInteractionEnd]
|
|
5684
|
+
);
|
|
5685
|
+
React8.useEffect(() => {
|
|
5686
|
+
const node = containerRef.current;
|
|
5687
|
+
if (!node) return;
|
|
5688
|
+
const options = { passive: false };
|
|
5689
|
+
node.addEventListener("wheel", handleWheel, options);
|
|
5690
|
+
node.addEventListener("touchstart", handleTouchStart, options);
|
|
5691
|
+
node.addEventListener("touchmove", handleTouchMove, options);
|
|
5692
|
+
node.addEventListener("touchend", handleTouchEnd, options);
|
|
5693
|
+
node.addEventListener("touchcancel", handleTouchEnd, options);
|
|
5694
|
+
return () => {
|
|
5695
|
+
node.removeEventListener("wheel", handleWheel, options);
|
|
5696
|
+
node.removeEventListener("touchstart", handleTouchStart, options);
|
|
5697
|
+
node.removeEventListener("touchmove", handleTouchMove, options);
|
|
5698
|
+
node.removeEventListener("touchend", handleTouchEnd, options);
|
|
5699
|
+
node.removeEventListener("touchcancel", handleTouchEnd, options);
|
|
5700
|
+
};
|
|
5701
|
+
}, [handleWheel, handleTouchStart, handleTouchMove, handleTouchEnd]);
|
|
5702
|
+
const getRootProps = React8.useCallback(
|
|
5703
|
+
() => ({
|
|
5704
|
+
className,
|
|
5705
|
+
style,
|
|
5706
|
+
onMouseDown: handleMouseDown,
|
|
5707
|
+
onKeyDown: handleKeyDown,
|
|
5708
|
+
onKeyUp: handleKeyUp,
|
|
5709
|
+
tabIndex: 0,
|
|
5710
|
+
role: "application",
|
|
5711
|
+
"aria-label": "Interactive image cropper",
|
|
5712
|
+
"aria-describedby": descriptionId,
|
|
5713
|
+
"aria-valuemin": minZoom,
|
|
5714
|
+
"aria-valuemax": maxZoom,
|
|
5715
|
+
"aria-valuenow": effectiveZoom,
|
|
5716
|
+
"aria-valuetext": `Zoom: ${Math.round(effectiveZoom * 100)}%`
|
|
5717
|
+
}),
|
|
5718
|
+
[
|
|
5719
|
+
className,
|
|
5720
|
+
style,
|
|
5721
|
+
handleMouseDown,
|
|
5722
|
+
handleKeyDown,
|
|
5723
|
+
handleKeyUp,
|
|
5724
|
+
descriptionId,
|
|
5725
|
+
minZoom,
|
|
5726
|
+
maxZoom,
|
|
5727
|
+
effectiveZoom
|
|
5728
|
+
]
|
|
5729
|
+
);
|
|
5730
|
+
const getImageWrapperStyle = React8.useCallback(
|
|
5731
|
+
() => ({
|
|
5732
|
+
width: imageWrapperWidth,
|
|
5733
|
+
height: imageWrapperHeight,
|
|
5734
|
+
transform: `translate3d(${offsetX}px, ${offsetY}px, 0px) scale(${effectiveZoom})`,
|
|
5735
|
+
position: "absolute",
|
|
5736
|
+
left: `calc(50% - ${imageWrapperWidth / 2}px)`,
|
|
5737
|
+
top: `calc(50% - ${imageWrapperHeight / 2}px)`,
|
|
5738
|
+
willChange: "transform"
|
|
5739
|
+
}),
|
|
5740
|
+
[imageWrapperWidth, imageWrapperHeight, offsetX, offsetY, effectiveZoom]
|
|
5741
|
+
);
|
|
5742
|
+
const getImageProps = React8.useCallback(
|
|
5743
|
+
() => ({
|
|
5744
|
+
src: image,
|
|
5745
|
+
alt: "Image being cropped",
|
|
5746
|
+
draggable: false,
|
|
5747
|
+
"aria-hidden": true
|
|
5748
|
+
}),
|
|
5749
|
+
[image]
|
|
5750
|
+
);
|
|
5751
|
+
const getCropAreaStyle = React8.useCallback(
|
|
5752
|
+
() => ({
|
|
5753
|
+
width: cropAreaWidth,
|
|
5754
|
+
height: cropAreaHeight
|
|
5755
|
+
}),
|
|
5756
|
+
[cropAreaWidth, cropAreaHeight]
|
|
5757
|
+
);
|
|
5758
|
+
const getCropAreaProps = React8.useCallback(
|
|
5759
|
+
() => ({
|
|
5760
|
+
style: getCropAreaStyle(),
|
|
5761
|
+
"aria-hidden": true
|
|
5762
|
+
}),
|
|
5763
|
+
[getCropAreaStyle]
|
|
5764
|
+
);
|
|
5765
|
+
const contextValue = {
|
|
5766
|
+
containerRef,
|
|
5767
|
+
image,
|
|
5768
|
+
imgWidth,
|
|
5769
|
+
imgHeight,
|
|
5770
|
+
cropAreaWidth,
|
|
5771
|
+
cropAreaHeight,
|
|
5772
|
+
imageWrapperWidth,
|
|
5773
|
+
imageWrapperHeight,
|
|
5774
|
+
offsetX,
|
|
5775
|
+
offsetY,
|
|
5776
|
+
effectiveZoom,
|
|
5777
|
+
minZoom,
|
|
5778
|
+
maxZoom,
|
|
5779
|
+
getRootProps,
|
|
5780
|
+
getImageProps,
|
|
5781
|
+
getImageWrapperStyle,
|
|
5782
|
+
getCropAreaProps,
|
|
5783
|
+
getCropAreaStyle,
|
|
5784
|
+
descriptionId
|
|
5785
|
+
};
|
|
5786
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CropperContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, ...getRootProps(), ...restProps, children }) });
|
|
5787
|
+
};
|
|
5788
|
+
var CropperImage = ({ className, ...restProps }) => {
|
|
5789
|
+
const { image, getImageProps, getImageWrapperStyle } = useCropperContext();
|
|
5790
|
+
if (!image) return null;
|
|
5791
|
+
const imageProps = getImageProps();
|
|
5792
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: getImageWrapperStyle(), children: /* @__PURE__ */ jsxRuntime.jsx("img", { ...imageProps, className, ...restProps }) });
|
|
5793
|
+
};
|
|
5794
|
+
var CropperCropArea = ({
|
|
5795
|
+
className,
|
|
5796
|
+
style,
|
|
5797
|
+
...restProps
|
|
5798
|
+
}) => {
|
|
5799
|
+
const { cropAreaWidth, cropAreaHeight, getCropAreaProps, getCropAreaStyle } = useCropperContext();
|
|
5800
|
+
if (cropAreaWidth <= 0 || cropAreaHeight <= 0) return null;
|
|
5801
|
+
const areaProps = getCropAreaProps();
|
|
5802
|
+
const areaStyle = getCropAreaStyle();
|
|
5803
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5804
|
+
"div",
|
|
5805
|
+
{
|
|
5806
|
+
...areaProps,
|
|
5807
|
+
style: { ...areaProps.style, ...style, ...areaStyle },
|
|
5808
|
+
className,
|
|
5809
|
+
...restProps
|
|
5810
|
+
}
|
|
5811
|
+
);
|
|
5812
|
+
};
|
|
5813
|
+
var CropperDescription = ({
|
|
5814
|
+
children,
|
|
5815
|
+
className,
|
|
5816
|
+
...restProps
|
|
5817
|
+
}) => {
|
|
5818
|
+
const { descriptionId } = useCropperContext();
|
|
5819
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { id: descriptionId, className, ...restProps, children: children ?? // Default description if none provided by user
|
|
5820
|
+
"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." });
|
|
5821
|
+
};
|
|
5822
|
+
var Cropper = {
|
|
5823
|
+
Root: CropperRoot,
|
|
5824
|
+
Image: CropperImage,
|
|
5825
|
+
CropArea: CropperCropArea,
|
|
5826
|
+
Description: CropperDescription
|
|
5827
|
+
};
|
|
5828
|
+
function Slider({
|
|
5829
|
+
className,
|
|
5830
|
+
defaultValue,
|
|
5831
|
+
value,
|
|
5832
|
+
min = 0,
|
|
5833
|
+
max = 100,
|
|
5834
|
+
...props
|
|
5835
|
+
}) {
|
|
5836
|
+
const [internalValues, setInternalValues] = React8__namespace.useState(
|
|
5837
|
+
Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]
|
|
5838
|
+
);
|
|
5839
|
+
React8__namespace.useEffect(() => {
|
|
5840
|
+
if (value !== void 0) {
|
|
5841
|
+
setInternalValues(Array.isArray(value) ? value : [value]);
|
|
5842
|
+
}
|
|
5843
|
+
}, [value]);
|
|
5844
|
+
const handleValueChange = (newValue) => {
|
|
5845
|
+
setInternalValues(newValue);
|
|
5846
|
+
props.onValueChange?.(newValue);
|
|
5847
|
+
};
|
|
5848
|
+
const renderThumb = () => {
|
|
5849
|
+
const thumb = /* @__PURE__ */ jsxRuntime.jsx(
|
|
5850
|
+
SliderPrimitive__namespace.Thumb,
|
|
5851
|
+
{
|
|
5852
|
+
"data-testid": "slider-thumb",
|
|
5853
|
+
"data-slot": "slider-thumb",
|
|
5854
|
+
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"
|
|
5855
|
+
}
|
|
5856
|
+
);
|
|
5857
|
+
return thumb;
|
|
5858
|
+
};
|
|
5859
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5860
|
+
SliderPrimitive__namespace.Root,
|
|
5861
|
+
{
|
|
5862
|
+
"data-slot": "slider",
|
|
5863
|
+
defaultValue,
|
|
5864
|
+
value,
|
|
5865
|
+
min,
|
|
5866
|
+
max,
|
|
5867
|
+
className: cn(
|
|
5868
|
+
"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",
|
|
5869
|
+
className
|
|
5870
|
+
),
|
|
5871
|
+
onValueChange: handleValueChange,
|
|
5872
|
+
...props,
|
|
5873
|
+
children: [
|
|
5874
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5875
|
+
SliderPrimitive__namespace.Track,
|
|
5876
|
+
{
|
|
5877
|
+
"data-slot": "slider-track",
|
|
5878
|
+
className: cn(
|
|
5879
|
+
"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"
|
|
5880
|
+
),
|
|
5881
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5882
|
+
SliderPrimitive__namespace.Range,
|
|
5883
|
+
{
|
|
5884
|
+
"data-slot": "slider-range",
|
|
5885
|
+
className: cn(
|
|
5886
|
+
"bg-slider-rangeColor absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
|
|
5887
|
+
)
|
|
5888
|
+
}
|
|
5889
|
+
)
|
|
5890
|
+
}
|
|
5891
|
+
),
|
|
5892
|
+
Array.from({ length: internalValues.length }, (_, index) => /* @__PURE__ */ jsxRuntime.jsx(React8__namespace.Fragment, { children: renderThumb() }, index))
|
|
5893
|
+
]
|
|
5894
|
+
}
|
|
5895
|
+
);
|
|
5896
|
+
}
|
|
5897
|
+
function CropperRoot2({
|
|
5898
|
+
className,
|
|
5899
|
+
...props
|
|
5900
|
+
}) {
|
|
5901
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5902
|
+
Cropper.Root,
|
|
5903
|
+
{
|
|
5904
|
+
"data-slot": "cropper",
|
|
5905
|
+
className: cn(
|
|
5906
|
+
"relative flex w-full cursor-move touch-none items-center justify-center overflow-hidden focus:outline-none",
|
|
5907
|
+
className
|
|
5908
|
+
),
|
|
5909
|
+
...props
|
|
5910
|
+
}
|
|
5911
|
+
);
|
|
5912
|
+
}
|
|
5913
|
+
function CropperDescription2({
|
|
5914
|
+
className,
|
|
5915
|
+
...props
|
|
5916
|
+
}) {
|
|
5917
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5918
|
+
Cropper.Description,
|
|
5919
|
+
{
|
|
5920
|
+
"data-slot": "cropper-description",
|
|
5921
|
+
className: cn("sr-only", className),
|
|
5922
|
+
...props
|
|
5923
|
+
}
|
|
5924
|
+
);
|
|
5925
|
+
}
|
|
5926
|
+
function CropperImage2({
|
|
5927
|
+
className,
|
|
5928
|
+
...props
|
|
5929
|
+
}) {
|
|
5930
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5931
|
+
Cropper.Image,
|
|
5932
|
+
{
|
|
5933
|
+
"data-slot": "cropper-image",
|
|
5934
|
+
className: cn(
|
|
5935
|
+
"pointer-events-none h-full w-full object-cover",
|
|
5936
|
+
className
|
|
5937
|
+
),
|
|
5938
|
+
...props
|
|
5939
|
+
}
|
|
5940
|
+
);
|
|
5941
|
+
}
|
|
5942
|
+
function CropperCropArea2({
|
|
5943
|
+
className,
|
|
5944
|
+
rounded,
|
|
5945
|
+
...props
|
|
5946
|
+
}) {
|
|
5947
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5948
|
+
Cropper.CropArea,
|
|
5949
|
+
{
|
|
5950
|
+
"data-slot": "cropper-crop-area",
|
|
5951
|
+
className: cn(
|
|
5952
|
+
"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",
|
|
5953
|
+
rounded && "rounded-full",
|
|
5954
|
+
className,
|
|
5955
|
+
"border-2 border-cropper-cropAreaBorderColor"
|
|
5956
|
+
),
|
|
5957
|
+
...props
|
|
5958
|
+
}
|
|
5959
|
+
);
|
|
5960
|
+
}
|
|
5961
|
+
var createImage = (url) => new Promise((resolve, reject) => {
|
|
5962
|
+
const image = new Image();
|
|
5963
|
+
image.addEventListener("load", () => resolve(image));
|
|
5964
|
+
image.addEventListener("error", (error2) => reject(error2));
|
|
5965
|
+
image.setAttribute("crossOrigin", "anonymous");
|
|
5966
|
+
image.src = url;
|
|
5967
|
+
});
|
|
5968
|
+
async function getCroppedImg(imageSrc, pixelCrop, outputWidth = pixelCrop.width, outputHeight = pixelCrop.height) {
|
|
5969
|
+
try {
|
|
5970
|
+
const image = await createImage(imageSrc);
|
|
5971
|
+
const canvas = document.createElement("canvas");
|
|
5972
|
+
const ctx = canvas.getContext("2d");
|
|
5973
|
+
if (!ctx) {
|
|
5974
|
+
return null;
|
|
5975
|
+
}
|
|
5976
|
+
canvas.width = outputWidth;
|
|
5977
|
+
canvas.height = outputHeight;
|
|
5978
|
+
ctx.drawImage(
|
|
5979
|
+
image,
|
|
5980
|
+
pixelCrop.x,
|
|
5981
|
+
pixelCrop.y,
|
|
5982
|
+
pixelCrop.width,
|
|
5983
|
+
pixelCrop.height,
|
|
5984
|
+
0,
|
|
5985
|
+
0,
|
|
5986
|
+
outputWidth,
|
|
5987
|
+
// Draw onto the output size
|
|
5988
|
+
outputHeight
|
|
5989
|
+
);
|
|
5990
|
+
return new Promise((resolve) => {
|
|
5991
|
+
canvas.toBlob((blob) => {
|
|
5992
|
+
resolve(blob);
|
|
5993
|
+
}, "image/jpeg");
|
|
5994
|
+
});
|
|
5995
|
+
} catch (error2) {
|
|
5996
|
+
return null;
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
function Cropper2({
|
|
6000
|
+
onOpenChange,
|
|
6001
|
+
open,
|
|
6002
|
+
previewUrl,
|
|
6003
|
+
onRemove: removeFile,
|
|
6004
|
+
onApply,
|
|
6005
|
+
rounded = false,
|
|
6006
|
+
portal = false
|
|
6007
|
+
}) {
|
|
6008
|
+
const [finalImageUrl, setFinalImageUrl] = React8.useState(null);
|
|
6009
|
+
const [croppedAreaPixels, setCroppedAreaPixels] = React8.useState(null);
|
|
6010
|
+
const [zoom, setZoom] = React8.useState(1);
|
|
6011
|
+
const handleCropChange = React8.useCallback((pixels) => {
|
|
6012
|
+
setCroppedAreaPixels(pixels);
|
|
6013
|
+
}, []);
|
|
6014
|
+
const handleApply = async () => {
|
|
6015
|
+
if (!previewUrl || !croppedAreaPixels) {
|
|
6016
|
+
if (previewUrl) {
|
|
6017
|
+
removeFile();
|
|
6018
|
+
setCroppedAreaPixels(null);
|
|
6019
|
+
}
|
|
6020
|
+
return;
|
|
6021
|
+
}
|
|
6022
|
+
try {
|
|
6023
|
+
const croppedBlob = await getCroppedImg(previewUrl, croppedAreaPixels);
|
|
6024
|
+
if (!croppedBlob) {
|
|
6025
|
+
throw new Error("Failed to generate cropped image blob.");
|
|
6026
|
+
}
|
|
6027
|
+
const newFinalUrl = URL.createObjectURL(croppedBlob);
|
|
6028
|
+
if (finalImageUrl) {
|
|
6029
|
+
URL.revokeObjectURL(finalImageUrl);
|
|
6030
|
+
}
|
|
6031
|
+
setFinalImageUrl(newFinalUrl);
|
|
6032
|
+
onOpenChange(false);
|
|
6033
|
+
onApply(newFinalUrl, croppedBlob);
|
|
6034
|
+
} catch (error2) {
|
|
6035
|
+
onOpenChange(false);
|
|
6036
|
+
}
|
|
6037
|
+
};
|
|
6038
|
+
React8.useEffect(() => {
|
|
6039
|
+
const currentFinalUrl = finalImageUrl;
|
|
6040
|
+
return () => {
|
|
6041
|
+
if (currentFinalUrl && currentFinalUrl.startsWith("blob:")) {
|
|
6042
|
+
URL.revokeObjectURL(currentFinalUrl);
|
|
6043
|
+
}
|
|
6044
|
+
};
|
|
6045
|
+
}, [finalImageUrl]);
|
|
6046
|
+
const { cropper } = useNebulaI18n().messages;
|
|
6047
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6048
|
+
DialogContent,
|
|
6049
|
+
{
|
|
6050
|
+
className: "nebula-ds gap-0 p-0 sm:max-w-140 *:[button]:hidden border border-cropper-dialogBorderColor",
|
|
6051
|
+
portal,
|
|
6052
|
+
showClose: false,
|
|
6053
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
6054
|
+
children: [
|
|
6055
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { className: "nebula-ds contents space-y-0 text-left", children: /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "nebula-ds flex items-center justify-between p-4 text-base", children: [
|
|
6056
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nebula-ds flex items-center gap-2", children: [
|
|
6057
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6058
|
+
Button,
|
|
6059
|
+
{
|
|
6060
|
+
icon: true,
|
|
6061
|
+
type: "button",
|
|
6062
|
+
variant: "ghost",
|
|
6063
|
+
onClick: () => onOpenChange(false),
|
|
6064
|
+
"aria-label": "close-cropper-dialog",
|
|
6065
|
+
"data-testid": "close-cropper-dialog",
|
|
6066
|
+
size: "sm",
|
|
6067
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { "aria-hidden": "true" })
|
|
6068
|
+
}
|
|
6069
|
+
),
|
|
6070
|
+
cropper.dialogTitle
|
|
6071
|
+
] }),
|
|
6072
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6073
|
+
Button,
|
|
6074
|
+
{
|
|
6075
|
+
autoFocus: false,
|
|
6076
|
+
onClick: handleApply,
|
|
6077
|
+
disabled: !previewUrl,
|
|
6078
|
+
variant: "primary",
|
|
6079
|
+
size: "sm",
|
|
6080
|
+
type: "button",
|
|
6081
|
+
"aria-label": "apply-cropper-image",
|
|
6082
|
+
"data-testid": "apply-cropper-image",
|
|
6083
|
+
children: cropper.applyButtonLabel
|
|
6084
|
+
}
|
|
6085
|
+
)
|
|
6086
|
+
] }) }),
|
|
6087
|
+
previewUrl && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6088
|
+
CropperRoot2,
|
|
6089
|
+
{
|
|
6090
|
+
className: "nebula-ds h-96 sm:h-120",
|
|
6091
|
+
image: previewUrl,
|
|
6092
|
+
zoom,
|
|
6093
|
+
onCropChange: handleCropChange,
|
|
6094
|
+
onZoomChange: setZoom,
|
|
6095
|
+
children: [
|
|
6096
|
+
/* @__PURE__ */ jsxRuntime.jsx(CropperDescription2, {}),
|
|
6097
|
+
/* @__PURE__ */ jsxRuntime.jsx(CropperImage2, {}),
|
|
6098
|
+
/* @__PURE__ */ jsxRuntime.jsx(CropperCropArea2, { rounded })
|
|
6099
|
+
]
|
|
6100
|
+
}
|
|
6101
|
+
),
|
|
6102
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogFooter, { className: "nebula-ds border-t border-t-cropper-dialogBorderColor px-4 py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nebula-ds mx-auto flex w-full max-w-80 items-center gap-4", children: [
|
|
6103
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6104
|
+
lucideReact.MinusIcon,
|
|
6105
|
+
{
|
|
6106
|
+
className: "nebula-ds shrink-0 size-5 text-cropper-sliderIconColor",
|
|
6107
|
+
size: 16,
|
|
6108
|
+
"aria-hidden": "true"
|
|
6109
|
+
}
|
|
6110
|
+
),
|
|
6111
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6112
|
+
Slider,
|
|
6113
|
+
{
|
|
6114
|
+
defaultValue: [1],
|
|
6115
|
+
value: [zoom],
|
|
6116
|
+
min: 1,
|
|
6117
|
+
max: 3,
|
|
6118
|
+
step: 0.1,
|
|
6119
|
+
onValueChange: (value) => setZoom(value[0]),
|
|
6120
|
+
"aria-label": "Zoom slider"
|
|
6121
|
+
}
|
|
6122
|
+
),
|
|
6123
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6124
|
+
lucideReact.PlusIcon,
|
|
6125
|
+
{
|
|
6126
|
+
className: "nebula-ds shrink-0 size-5 text-cropper-sliderIconColor",
|
|
6127
|
+
size: 16,
|
|
6128
|
+
"aria-hidden": "true"
|
|
6129
|
+
}
|
|
6130
|
+
)
|
|
6131
|
+
] }) })
|
|
6132
|
+
]
|
|
6133
|
+
}
|
|
6134
|
+
) });
|
|
6135
|
+
}
|
|
4961
6136
|
|
|
4962
6137
|
// src/tailwind.ts
|
|
4963
6138
|
function content({ base = "./" } = {}) {
|
|
@@ -5011,6 +6186,10 @@ exports.Calendar = Calendar;
|
|
|
5011
6186
|
exports.Caption = Caption;
|
|
5012
6187
|
exports.Checkbox = Checkbox;
|
|
5013
6188
|
exports.Creatable = StyledCreatable;
|
|
6189
|
+
exports.Cropper = Cropper2;
|
|
6190
|
+
exports.CropperCropArea = CropperCropArea2;
|
|
6191
|
+
exports.CropperDescription = CropperDescription2;
|
|
6192
|
+
exports.CropperImage = CropperImage2;
|
|
5014
6193
|
exports.Dialog = Dialog;
|
|
5015
6194
|
exports.DialogBody = DialogBody;
|
|
5016
6195
|
exports.DialogClose = DialogClose;
|
|
@@ -5061,9 +6240,11 @@ exports.Paragraph = Paragraph;
|
|
|
5061
6240
|
exports.Popover = Popover;
|
|
5062
6241
|
exports.PopoverContent = PopoverContent;
|
|
5063
6242
|
exports.PopoverTrigger = PopoverTrigger;
|
|
6243
|
+
exports.ProfileImage = ProfileImage;
|
|
5064
6244
|
exports.Select = StyledSelect;
|
|
5065
6245
|
exports.Separator = Separator2;
|
|
5066
6246
|
exports.Skeleton = Skeleton;
|
|
6247
|
+
exports.Slider = Slider;
|
|
5067
6248
|
exports.Space = Space;
|
|
5068
6249
|
exports.SpaceDirectionEnum = SpaceDirectionEnum;
|
|
5069
6250
|
exports.SpaceSizeEnum = SpaceSizeEnum;
|
|
@@ -5094,7 +6275,7 @@ exports.dateIsAvailable = dateIsAvailable;
|
|
|
5094
6275
|
exports.formatBytes = formatBytes;
|
|
5095
6276
|
exports.getNebulaLanguage = getNebulaLanguage;
|
|
5096
6277
|
exports.localeByi18nKey = localeByi18nKey;
|
|
5097
|
-
exports.messages =
|
|
6278
|
+
exports.messages = messages19;
|
|
5098
6279
|
exports.separatorVariants = separatorVariants;
|
|
5099
6280
|
exports.setNebulaLanguage = setNebulaLanguage;
|
|
5100
6281
|
exports.tagVariantsEnum = tagVariantsEnum;
|