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