@wetransform/core 1.0.1 → 1.1.0

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/README.md CHANGED
@@ -31,6 +31,8 @@ sdk.on('successSubmit', (payload) => console.log('File successfully submitted',
31
31
 
32
32
  // Opening WeTransform
33
33
  await sdk.open()
34
+ // Dynamically switch locale without remounting
35
+ await sdk.setLocale('fr')
34
36
  // Close WeTransform
35
37
  await sdk.close()
36
38
  // Destroy WeTransform session
@@ -46,6 +48,7 @@ Returns a `WeTransformInstance` with:
46
48
  - `open(): Promise<void>` - initializes auth and mounts WeTransform
47
49
  - `close(): Promise<void>` - closes SDK UI and unmounts WeTransform
48
50
  - `destroy(): Promise<void>` - closes and tears down SDK resources
51
+ - `setLocale(locale): Promise<void>` - updates locale/auth context and syncs iframe locale when active
49
52
  - `on(event, handler): () => void` - subscribes to SDK events, returns unsubscribe function
50
53
 
51
54
  ### `WeTransformConfig`
@@ -57,6 +60,17 @@ Returns a `WeTransformInstance` with:
57
60
  - `displayAsModal?: boolean` (default: `true`)
58
61
  - `mountElement?: string | HTMLElement` (default id: `weTransform_iframeContainer`, used when `displayAsModal` is `false`)
59
62
 
63
+ `locale` defaults to `'en'` when not provided.
64
+
65
+ ### Runtime locale switching
66
+
67
+ - `setLocale('en' | 'fr')` is additive and does not require destroy/recreate.
68
+ - If the locale is unchanged, `setLocale` is a no-op.
69
+ - If SDK status is `open`, locale is sent to iframe immediately via bridge messaging.
70
+ - If SDK status is `opening`, locale is sent after iframe readiness is reached.
71
+ - `setLocale` updates auth API URL context to `{VITE_SENDER_API_URL}/{locale}/send/{organizationHandle}` for subsequent auth calls.
72
+ - Calling `setLocale` after `destroy()` throws `Cannot set locale after destroy.`
73
+
60
74
  #### Inline mounting behavior (`displayAsModal: false`)
61
75
 
62
76
  When `displayAsModal` is `false`, wetTransform SDK mounts the iframe into:
package/dist/index.d.mts CHANGED
@@ -54,6 +54,7 @@ type WeTransformInstance = {
54
54
  open: () => Promise<void>;
55
55
  close: () => Promise<void>;
56
56
  destroy: () => Promise<void>;
57
+ setLocale: (locale: SupportedLocales) => Promise<void>;
57
58
  on: <K extends keyof WeTransformEventMap>(event: K, handler: WeTransformEventMap[K]) => () => void;
58
59
  };
59
60
  type SupportedLocales = 'en' | 'fr';
package/dist/index.mjs CHANGED
@@ -84,6 +84,9 @@ var AuthBridge = class {
84
84
  });
85
85
  return this.refreshPromise;
86
86
  }
87
+ setApiUrl(apiUrl) {
88
+ this.apiUrl = apiUrl;
89
+ }
87
90
  clear() {
88
91
  this.accessToken = null;
89
92
  this.refreshToken = null;
@@ -224,6 +227,14 @@ var IframeManager = class {
224
227
  async requestLogout(signal) {
225
228
  await this.notifyLogout(signal ?? this.activeSignal ?? void 0);
226
229
  }
230
+ async setLocale(locale, signal) {
231
+ const updateLocale = (this.childApi ? await this.withAbort(this.childApi, signal) : null)?.setLocale;
232
+ if (!updateLocale) return;
233
+ await this.withAbort(updateLocale({ locale }), signal);
234
+ }
235
+ updateLocale(locale) {
236
+ this.locationInfo.locale = locale;
237
+ }
227
238
  clearPersistedRoute() {
228
239
  sessionStorage.removeItem(EMBED_ROUTE_STORAGE_KEY);
229
240
  sessionStorage.removeItem(EMBED_ROUTE_PENDING_STORAGE_KEY);
@@ -338,6 +349,7 @@ var IframeManager = class {
338
349
  const url = new URL(path, this.baseUrl);
339
350
  url.searchParams.set("sdk", "true");
340
351
  if (bootstrapToken) url.searchParams.set("token", bootstrapToken);
352
+ if (this.locationInfo.locale) url.searchParams.set("locale", this.locationInfo.locale);
341
353
  return url.toString();
342
354
  }
343
355
  resolveInitialPath() {
@@ -532,8 +544,8 @@ function ensureDefaultInlineContainerStyles() {
532
544
  const style = document.createElement("style");
533
545
  style.id = DEFAULT_IFRAME_CONTAINER_STYLE_ID;
534
546
  style.textContent = `
535
- :where(#weTransform_iframeContainer) {
536
- width: 1080px;
547
+ :where(.weTransform_iframeContainer) {
548
+ width: min(1080px, 100%);
537
549
  height: 720px;
538
550
  border: 0;
539
551
  position: relative;
@@ -676,16 +688,19 @@ var UiHost = class {
676
688
  if (this.config.mountElement instanceof HTMLElement) {
677
689
  this.inlineContainer = this.config.mountElement;
678
690
  this.ownsInlineContainer = false;
691
+ this.config.mountElement.classList.add("weTransform_iframeContainer");
679
692
  return this.config.mountElement;
680
693
  }
681
694
  const existingMountElement = document.getElementById(this.config.mountElement);
682
695
  if (existingMountElement) {
683
696
  this.inlineContainer = existingMountElement;
684
697
  this.ownsInlineContainer = false;
698
+ existingMountElement.classList.add("weTransform_iframeContainer");
685
699
  return existingMountElement;
686
700
  }
687
701
  const container = document.createElement("div");
688
702
  container.id = this.config.mountElement;
703
+ container.classList.add("weTransform_iframeContainer");
689
704
  document.body.appendChild(container);
690
705
  this.inlineContainer = container;
691
706
  this.ownsInlineContainer = true;
@@ -709,19 +724,23 @@ function createWeTransform(config) {
709
724
  if (typeof window === "undefined") throw new Error("WeTransform SDK must run in a browser context.");
710
725
  ensureDefaultInlineContainerStyles();
711
726
  const baseUrl = resolveBaseUrl(config.organizationHandle);
712
- const apiUrl = resolveApiUrl(config.organizationHandle, config.locale);
727
+ let currentLocale = config.locale ?? "en";
728
+ const resolveCurrentApiUrl = () => {
729
+ return resolveApiUrl(config.organizationHandle, currentLocale);
730
+ };
713
731
  const events = new EventEmitter();
714
732
  const uiHost = new UiHost({
715
733
  displayAsModal: config.displayAsModal ?? true,
716
734
  mountElement: config.mountElement ?? "weTransform_iframeContainer"
717
735
  });
718
- const authBridge = new AuthBridge(apiUrl, config.authentication, (payload) => {
736
+ const authBridge = new AuthBridge(resolveCurrentApiUrl(), config.authentication, (payload) => {
719
737
  events.emit("error", payload);
720
738
  });
721
739
  const iframeManager = new IframeManager(baseUrl, events, authBridge, {
722
740
  initialLocation: config.initialLocation,
723
741
  templateHandle: config.authentication.templateHandle,
724
- sourceId: config.authentication.sourceId
742
+ sourceId: config.authentication.sourceId,
743
+ locale: currentLocale
725
744
  });
726
745
  const revokeOnPageUnload = () => {
727
746
  authBridge.revokeSession({ bestEffort: true });
@@ -736,6 +755,12 @@ function createWeTransform(config) {
736
755
  let openingPromise = null;
737
756
  let currentOpenAbortController = null;
738
757
  let stopWaitingForReady = null;
758
+ let localeTransitionQueue = Promise.resolve();
759
+ const requestLogoutBestEffort = async () => {
760
+ try {
761
+ await iframeManager.requestLogout();
762
+ } catch {}
763
+ };
739
764
  const open = async () => {
740
765
  if (status !== "idle") return;
741
766
  status = "opening";
@@ -801,7 +826,7 @@ function createWeTransform(config) {
801
826
  currentOpenAbortController?.abort();
802
827
  if (wasOpening) {
803
828
  stopWaitingForReady?.();
804
- await iframeManager.requestLogout();
829
+ await requestLogoutBestEffort();
805
830
  iframeManager.unmount();
806
831
  iframeManager.clearPersistedRoute();
807
832
  uiHost.cancelOpening();
@@ -810,7 +835,7 @@ function createWeTransform(config) {
810
835
  return;
811
836
  }
812
837
  if (wasOpen) {
813
- await iframeManager.requestLogout();
838
+ await requestLogoutBestEffort();
814
839
  iframeManager.unmount();
815
840
  uiHost.close();
816
841
  iframeManager.clearPersistedRoute();
@@ -818,6 +843,31 @@ function createWeTransform(config) {
818
843
  events.emit("close");
819
844
  }
820
845
  };
846
+ const runSetLocale = async (nextLocale) => {
847
+ if (status === "destroyed") return;
848
+ if (nextLocale === currentLocale) return;
849
+ const wasOpening = status === "opening";
850
+ const wasOpen = status === "open";
851
+ currentLocale = nextLocale;
852
+ authBridge.setApiUrl(resolveCurrentApiUrl());
853
+ iframeManager.updateLocale(currentLocale);
854
+ if (wasOpen) {
855
+ await iframeManager.setLocale(currentLocale, currentOpenAbortController?.signal ?? void 0);
856
+ return;
857
+ }
858
+ if (wasOpening) {
859
+ const openingInFlight = openingPromise;
860
+ if (!openingInFlight) return;
861
+ await openingInFlight;
862
+ if (status === "open") await iframeManager.setLocale(currentLocale);
863
+ }
864
+ };
865
+ const setLocale = async (nextLocale) => {
866
+ if (status === "destroyed") throw new Error("Cannot set locale after destroy.");
867
+ const transition = localeTransitionQueue.then(() => runSetLocale(nextLocale));
868
+ localeTransitionQueue = transition.catch(() => void 0);
869
+ await transition;
870
+ };
821
871
  const destroy = async () => {
822
872
  if (status === "destroyed") return;
823
873
  currentOpenAbortController?.abort();
@@ -839,6 +889,7 @@ function createWeTransform(config) {
839
889
  open,
840
890
  close,
841
891
  destroy,
892
+ setLocale,
842
893
  on
843
894
  };
844
895
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wetransform/core",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "license": "ISC",
5
5
  "files": [
6
6
  "dist/**"
@@ -12,24 +12,23 @@
12
12
  "publishConfig": {
13
13
  "access": "public"
14
14
  },
15
- "scripts": {
16
- "build": "VITE_MODE=production vp pack",
17
- "dev": "vp pack --watch",
18
- "lint": "vp lint --type-aware --type-check .",
19
- "test": "vp test run",
20
- "publish": "npm publish"
21
- },
22
15
  "dependencies": {
23
16
  "focus-trap": "^8.0.1",
24
17
  "penpal": "^7.0.6"
25
18
  },
26
19
  "devDependencies": {
27
- "@types/node": "catalog:",
20
+ "@types/node": "^24.12.0",
28
21
  "jsdom": "^29.0.1",
29
- "typescript": "catalog:",
30
- "vite": "catalog:",
22
+ "typescript": "^6.0.2",
23
+ "vite": "npm:@voidzero-dev/vite-plus-core@latest",
31
24
  "vite-plugin-css-injected-by-js": "^4.0.1",
32
- "vite-plus": "catalog:",
33
- "vitest": "catalog:"
25
+ "vite-plus": "^0.1.14",
26
+ "vitest": "npm:@voidzero-dev/vite-plus-test@latest"
27
+ },
28
+ "scripts": {
29
+ "build": "VITE_MODE=production vp pack",
30
+ "dev": "vp pack --watch",
31
+ "lint": "vp lint --type-aware --type-check .",
32
+ "test": "vp test run"
34
33
  }
35
- }
34
+ }