limbo-component 1.8.3 → 1.8.5

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/limbo.es.js CHANGED
@@ -12635,9 +12635,11 @@ let globalConfig = {
12635
12635
  token: null,
12636
12636
  // JWT token (opcional, generado automáticamente)
12637
12637
  authMode: null,
12638
- // "session" | "manual"
12638
+ // "session" | "manual" | "jwt"
12639
12639
  tokenEndpoint: null,
12640
12640
  // Endpoint para obtener token (configurable)
12641
+ tokenProvider: null,
12642
+ // Custom function to provide JWT token
12641
12643
  prod: false
12642
12644
  };
12643
12645
  function configureApiClient(config) {
@@ -12663,7 +12665,17 @@ async function getHeaders({ isFormData = false, useJWT = true, customHeaders = {
12663
12665
  }
12664
12666
  let token = globalConfig.token;
12665
12667
  if (useJWT) {
12666
- if (globalConfig.authMode === "session" && !token) {
12668
+ if (globalConfig.authMode === "jwt" && globalConfig.tokenProvider && !token) {
12669
+ try {
12670
+ console.log("🔑 Calling tokenProvider...");
12671
+ token = await globalConfig.tokenProvider();
12672
+ console.log("✅ Token obtained from tokenProvider");
12673
+ globalConfig.token = token;
12674
+ } catch (error) {
12675
+ console.error("❌ tokenProvider failed:", error);
12676
+ throw new Error("Failed to obtain token from tokenProvider: " + error.message);
12677
+ }
12678
+ } else if (globalConfig.authMode === "session" && !token) {
12667
12679
  try {
12668
12680
  const baseUrl = getBaseUrl(globalConfig);
12669
12681
  const endpoint = globalConfig.tokenEndpoint || "/auth/token";
@@ -12691,7 +12703,8 @@ async function getHeaders({ isFormData = false, useJWT = true, customHeaders = {
12691
12703
  } else {
12692
12704
  console.warn("⚠️ No JWT token available:", {
12693
12705
  authMode: globalConfig.authMode,
12694
- hasPublicKey: !!globalConfig.publicKey
12706
+ hasPublicKey: !!globalConfig.publicKey,
12707
+ hasTokenProvider: !!globalConfig.tokenProvider
12695
12708
  });
12696
12709
  }
12697
12710
  }
@@ -19331,6 +19344,9 @@ function CropperView({
19331
19344
  const [showImageOptions, setShowImageOptions] = useState(true);
19332
19345
  const [zoomInfo, setZoomInfo] = useState({ current: 1, percentage: 100 });
19333
19346
  const [editableFilename] = useState(() => {
19347
+ if (!image || !image.filename) {
19348
+ return "image";
19349
+ }
19334
19350
  const [name] = image.filename.split(".");
19335
19351
  return name;
19336
19352
  });
@@ -19471,9 +19487,13 @@ function CropperView({
19471
19487
  const saveCurrentCropState = useCallback(() => {
19472
19488
  if (!cropper.manager || !state.isReady) return;
19473
19489
  try {
19490
+ if (!cropper.manager.transform) {
19491
+ console.warn("Transform manager not available");
19492
+ return null;
19493
+ }
19474
19494
  const currentCropData = cropData ? { ...cropData } : null;
19475
- const currentZoom = cropper.manager.transform.getZoom();
19476
- const currentRotation = cropper.manager.transform.getRotation();
19495
+ const currentZoom = typeof cropper.manager.transform.getZoom === "function" ? cropper.manager.transform.getZoom() : 1;
19496
+ const currentRotation = typeof cropper.manager.transform.getRotation === "function" ? cropper.manager.transform.getRotation() : 0;
19477
19497
  const savedState = {
19478
19498
  cropData: currentCropData,
19479
19499
  transforms: {
@@ -19915,9 +19935,9 @@ function CropperView({
19915
19935
  }
19916
19936
  }, [imageInfo, state.isReady, cropConfig.mandatoryCrops.length, crops]);
19917
19937
  useEffect(() => {
19918
- if (!cropper.manager || !cropper.manager.utils) return;
19938
+ if (!cropper.manager || !cropper.manager.utils || !cropper.manager.transform) return;
19919
19939
  try {
19920
- const currentZoom = cropper.manager.transform.getZoom();
19940
+ const currentZoom = typeof cropper.manager.transform.getZoom === "function" ? cropper.manager.transform.getZoom() : 1;
19921
19941
  const info = {
19922
19942
  current: currentZoom,
19923
19943
  isZoomedIn: currentZoom > 1,
@@ -20014,10 +20034,10 @@ function CropperView({
20014
20034
  children: "Cancelar"
20015
20035
  }
20016
20036
  ),
20017
- /* @__PURE__ */ jsx(
20037
+ onDelete && /* @__PURE__ */ jsx(
20018
20038
  "button",
20019
20039
  {
20020
- onClick: () => onDelete?.(image),
20040
+ onClick: () => onDelete(image),
20021
20041
  disabled: deleting | creatingVariant,
20022
20042
  className: "limbo-btn limbo-btn-danger px-4 sm:py-1 h-min flex-1 sm:flex-initial",
20023
20043
  "aria-label": `Eliminar imagen ${image.filename}`,
@@ -20088,7 +20108,7 @@ function CropperView({
20088
20108
  }
20089
20109
  ),
20090
20110
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
20091
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
20111
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
20092
20112
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-800 truncate", children: activeCrop.label === crop.label && crop.required === false ? /* @__PURE__ */ jsx(
20093
20113
  "input",
20094
20114
  {
@@ -21176,15 +21196,19 @@ function useDeleteImage() {
21176
21196
  }
21177
21197
  const cache = /* @__PURE__ */ new Map();
21178
21198
  const CACHE_TTL = 10 * 60 * 1e3;
21179
- function useImages(apiKey, prod = false, params = {}) {
21199
+ function useImages(apiKey, prod = false, params = {}, enabled = true) {
21180
21200
  const [images, setImages] = useState([]);
21181
- const [loading, setLoading] = useState(true);
21201
+ const [loading, setLoading] = useState(enabled);
21182
21202
  const [error, setError] = useState(null);
21183
21203
  const [pagination, setPagination] = useState(null);
21184
21204
  const [retryCount, setRetryCount] = useState(0);
21185
21205
  const MAX_RETRIES = 3;
21186
21206
  const paramsKey = useMemo(() => JSON.stringify(params), [params]);
21187
21207
  useEffect(() => {
21208
+ if (!enabled) {
21209
+ setLoading(false);
21210
+ return;
21211
+ }
21188
21212
  const cacheKey = `${paramsKey}`;
21189
21213
  const cached = cache.get(cacheKey);
21190
21214
  const now = Date.now();
@@ -21230,7 +21254,7 @@ function useImages(apiKey, prod = false, params = {}) {
21230
21254
  return () => {
21231
21255
  isMounted = false;
21232
21256
  };
21233
- }, [apiKey, prod, paramsKey, retryCount, params]);
21257
+ }, [apiKey, prod, paramsKey, retryCount, params, enabled]);
21234
21258
  const invalidateCache = () => {
21235
21259
  cache.delete(`${paramsKey}`);
21236
21260
  };
@@ -21382,6 +21406,7 @@ function App({
21382
21406
  ...galleryFilters.dateFrom && { dateFrom: galleryFilters.dateFrom },
21383
21407
  ...galleryFilters.dateTo && { dateTo: galleryFilters.dateTo }
21384
21408
  };
21409
+ const shouldFetchImages = activeFeatures.includes("gallery");
21385
21410
  const {
21386
21411
  images,
21387
21412
  loading: loadingImages,
@@ -21389,7 +21414,7 @@ function App({
21389
21414
  pagination,
21390
21415
  invalidateCache,
21391
21416
  setImages
21392
- } = useImages(apiKey, prod, apiParams);
21417
+ } = useImages(apiKey, prod, apiParams, shouldFetchImages);
21393
21418
  const { refreshVariants } = useImageVariants();
21394
21419
  const handleVariantCreated = (assetId, variantData) => {
21395
21420
  refreshVariants(assetId);
@@ -21679,7 +21704,7 @@ function App({
21679
21704
  }
21680
21705
  )
21681
21706
  ] }),
21682
- activeTab === "cropper" && /* @__PURE__ */ jsx(
21707
+ activeTab === "cropper" && selectedImage && /* @__PURE__ */ jsx(
21683
21708
  CropperView,
21684
21709
  {
21685
21710
  image: selectedImage,
@@ -21691,6 +21716,7 @@ function App({
21691
21716
  onVariantCreated: handleVariantCreated
21692
21717
  }
21693
21718
  ),
21719
+ activeTab === "cropper" && !selectedImage && /* @__PURE__ */ jsx("div", { className: "limbo-empty-state", children: /* @__PURE__ */ jsx("p", { children: "Selecciona una imagen de la galería para comenzar a recortar." }) }),
21694
21720
  /* @__PURE__ */ jsx(
21695
21721
  TokenExpiredModal,
21696
21722
  {
@@ -22009,7 +22035,9 @@ class LimboInstance {
22009
22035
  ui: this.config.ui,
22010
22036
  callbacks: this._createCallbacks(),
22011
22037
  instanceId: this.id,
22012
- authMode: this.config.authMode || this.config.publicKey ? "session" : "manual"
22038
+ authMode: this.config.authMode || this.config.publicKey ? "session" : "manual",
22039
+ _externalImage: this.config._externalImage || null
22040
+ // 🆕 Pass external image for cropper
22013
22041
  })
22014
22042
  );
22015
22043
  }
@@ -23207,8 +23235,8 @@ class Modal {
23207
23235
  const sizeClasses = {
23208
23236
  small: isMobile ? "width: 100%; height: 100%;" : "max-width: 400px;",
23209
23237
  medium: isMobile ? "width: 100%; height: 100%;" : "max-width: 600px;",
23210
- large: isMobile ? "width: 100%; height: 100%;" : "max-width: 800px;",
23211
- xlarge: isMobile ? "width: 100%; height: 100%;" : "max-width: 1200px;"
23238
+ large: isMobile ? "width: 100%; height: 100%;" : "max-width: 1300px;",
23239
+ xlarge: isMobile ? "width: 100%; height: 100%;" : "max-width: 90dvw;"
23212
23240
  };
23213
23241
  const baseStyles = isMobile ? `
23214
23242
  position: fixed;
@@ -24844,7 +24872,9 @@ class LimboCore {
24844
24872
  token: options.token,
24845
24873
  // Solo para authMode: "manual"
24846
24874
  authMode: options.authMode || "manual",
24847
- // "session" | "manual"
24875
+ // "session" | "manual" | "jwt"
24876
+ tokenProvider: options.tokenProvider,
24877
+ // Custom function to provide JWT token
24848
24878
  prod: options.prod || false,
24849
24879
  mode: options.mode || "embed",
24850
24880
  // "embed" | "modal"