@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.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 messages6 = {
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 = messages6;
1191
+ var pagination_default2 = messages7;
1182
1192
 
1183
1193
  // src/i18n/messages/es/input-select.ts
1184
- var messages7 = {
1194
+ var messages8 = {
1185
1195
  noOptions: "No hay opciones disponibles"
1186
1196
  };
1187
- var input_select_default2 = messages7;
1197
+ var input_select_default2 = messages8;
1188
1198
 
1189
1199
  // src/i18n/messages/es/input-phone.ts
1190
- var messages8 = {
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 = messages8;
1450
+ var input_phone_default2 = messages9;
1441
1451
 
1442
1452
  // src/i18n/messages/es/time-picker.ts
1443
- var messages9 = {
1453
+ var messages10 = {
1444
1454
  label: "Tiempo"
1445
1455
  };
1446
- var time_picker_default2 = messages9;
1456
+ var time_picker_default2 = messages10;
1447
1457
 
1448
1458
  // src/i18n/messages/es/file-upload.ts
1449
- var messages10 = {
1459
+ var messages11 = {
1450
1460
  deleteAll: "Remover todos"
1451
1461
  };
1452
- var file_upload_default2 = messages10;
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 messages11 = {
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 = messages11;
1493
+ var pagination_default3 = messages13;
1476
1494
 
1477
1495
  // src/i18n/messages/pt-br/input-select.ts
1478
- var messages12 = {
1496
+ var messages14 = {
1479
1497
  noOptions: "Nenhuma op\xE7\xE3o dispon\xEDvel"
1480
1498
  };
1481
- var input_select_default3 = messages12;
1499
+ var input_select_default3 = messages14;
1482
1500
 
1483
1501
  // src/i18n/messages/pt-br/input-phone.ts
1484
- var messages13 = {
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 = messages13;
1752
+ var input_phone_default3 = messages15;
1735
1753
 
1736
1754
  // src/i18n/messages/pt-br/time-picker.ts
1737
- var messages14 = {
1755
+ var messages16 = {
1738
1756
  label: "Hor\xE1rio"
1739
1757
  };
1740
- var time_picker_default3 = messages14;
1758
+ var time_picker_default3 = messages16;
1741
1759
 
1742
1760
  // src/i18n/messages/pt-br/file-upload.ts
1743
- var messages15 = {
1761
+ var messages17 = {
1744
1762
  deleteAll: "Remover todos"
1745
1763
  };
1746
- var file_upload_default3 = messages15;
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 messages16 = /* @__PURE__ */ new Map([
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 [messages17, setMessages] = React8.useState(
1798
- messages16.get(getNebulaLanguage()) ?? messages16.get("en-US")
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
- messages16.get(detail.value) ?? messages16.get("en-US")
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: messages17,
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: messages17 } = useNebulaI18n();
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 messages17.pagination.totalResultsLabel(lastPageSize, total);
1929
+ return messages20.pagination.totalResultsLabel(lastPageSize, total);
1904
1930
  }
1905
- return messages17.pagination.totalResultsLabel(pageSize, total);
1906
- }, [messages17.pagination, pageSize, total, page, totalPages, lastPageSize]);
1931
+ return messages20.pagination.totalResultsLabel(pageSize, total);
1932
+ }, [messages20.pagination, pageSize, total, page, totalPages, lastPageSize]);
1907
1933
  const currentPageLabel = React8.useMemo(
1908
- () => messages17.pagination.currentPageLabel(normalizedPage, totalPages),
1909
- [messages17.pagination, normalizedPage, totalPages]
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: messages17 } = useNebulaI18n();
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: messages17.inputSelect.noOptions }),
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
- className,
2247
- icon,
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("relative w-full", {
2265
- "pointer-events-none": disabled
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.jsx(
2269
- "input",
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-full h-10 outline-none rounded-input text-sm leading-none font-medium",
2274
- "bg-inputText-background-default disabled:bg-inputText-background-disabled",
2275
- "border border-inputText-border-default focus:ring-[3px] focus:ring-inputText-border-focus focus:border-inputText-border-focus",
2276
- "text-inputText-text-filled focus:text-inputText-text-focus placeholder:text-inputText-text-default disabled:text-inputText-text-disabled",
2277
- "disabled:cursor-not-allowed",
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
- ...props,
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(({ className, children, portal = false, ...props }, ref) => {
2361
- const Comp = portal ? DialogPortal : React8__namespace.Fragment;
2362
- return /* @__PURE__ */ jsxRuntime.jsxs(Comp, { children: [
2363
- /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
2364
- /* @__PURE__ */ jsxRuntime.jsxs(
2365
- DialogPrimitive__namespace.Content,
2366
- {
2367
- ref,
2368
- className: cn(
2369
- `rounded-2xl
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
- className
2395
- ),
2396
- ...props,
2397
- children: [
2398
- children,
2399
- /* @__PURE__ */ jsxRuntime.jsx(
2400
- DialogPrimitive__namespace.Close,
2401
- {
2402
- asChild: true,
2403
- className: `absolute
2404
- right-4
2405
- top-4`,
2406
- children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", icon: true, children: [
2407
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "nebula-ds !h-4 !w-4 !text-dialog-icon" }),
2408
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nebula-ds sr-only", children: "Close" })
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, messages17, options) {
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: messages17.loading,
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: messages17.success,
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: messages17.error,
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: messages17 } = useNebulaI18n();
3438
- const { countries } = messages17.inputPhone;
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
- value?.split?.(DATA_TIME_SEPARATOR)?.at?.(-1) ?? ""
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: messages17 } = useNebulaI18n();
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
- messages17.timePicker.label,
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__ */ ((FileUploadError2) => {
4447
- FileUploadError2["MAX_FILES_EXCEEDED"] = "MAX_FILES_EXCEEDED";
4448
- FileUploadError2["MAXIMUM_FILE_SIZE_EXCEEDED"] = "MAXIMUM_FILE_SIZE_EXCEEDED";
4449
- FileUploadError2["INVALID_FORMAT"] = "INVALID_FORMAT";
4450
- return FileUploadError2;
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 = messages16;
6278
+ exports.messages = messages19;
5098
6279
  exports.separatorVariants = separatorVariants;
5099
6280
  exports.setNebulaLanguage = setNebulaLanguage;
5100
6281
  exports.tagVariantsEnum = tagVariantsEnum;