@subiz/widget-v4 4.1.215 → 4.1.216

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.
Files changed (38) hide show
  1. package/README.md +6 -0
  2. package/api.md +9 -5
  3. package/assets/img/bubble_default.svg +1 -0
  4. package/assets/less/widget.less +12 -0
  5. package/compiled_src/chatbox/ChatButton.js +19 -17
  6. package/compiled_src/store/store.js +4 -1
  7. package/dist/{1a12a5ed6a9.278.js → 1a12ecfb6db.278.js} +1 -1
  8. package/dist/1a12ecfb6db.app.js +1 -0
  9. package/dist/{1a12a5ed6a9.chat.html → 1a12ecfb6db.chat.html} +1 -1
  10. package/dist/1a12ecfb6db.chat.js +1 -0
  11. package/dist/{1a12a5ed6a9.form.html → 1a12ecfb6db.form.html} +1 -1
  12. package/dist/{1a12a5ed6a9.form.js → 1a12ecfb6db.form.js} +1 -1
  13. package/dist/{1a12a5ed6a9.index.html → 1a12ecfb6db.index.html} +1 -1
  14. package/dist/{1a12a5ed6a9.library.html → 1a12ecfb6db.library.html} +1 -1
  15. package/dist/1a12ecfb6db.library.js +1 -0
  16. package/dist/{1a12a5ed6a9.preview.html → 1a12ecfb6db.preview.html} +1 -1
  17. package/dist/1a12ecfb6db.preview.js +1 -0
  18. package/dist/1a12ecfb6db.webview.js +1 -0
  19. package/dist/HASH +1 -0
  20. package/dist/assets/img/{bubble_default.7d5e4ab.svg → bubble_default.6f6eec8.svg} +1 -0
  21. package/dist/screenshoot.js +25 -20
  22. package/package.json +1 -1
  23. package/src/chatbox/ChatButton.js +22 -20
  24. package/src/store/store.js +3 -2
  25. package/up +18 -0
  26. package/dist/.HASH +0 -1
  27. package/dist/1a12a5ed6a9.app.js +0 -1
  28. package/dist/1a12a5ed6a9.chat.js +0 -1
  29. package/dist/1a12a5ed6a9.library.js +0 -1
  30. package/dist/1a12a5ed6a9.preview.js +0 -1
  31. package/dist/1a12a5ed6a9.webview.js +0 -1
  32. /package/dist/{1a12a5ed6a9.127.js → 1a12ecfb6db.127.js} +0 -0
  33. /package/dist/{1a12a5ed6a9.132.js → 1a12ecfb6db.132.js} +0 -0
  34. /package/dist/{1a12a5ed6a9.185.js → 1a12ecfb6db.185.js} +0 -0
  35. /package/dist/{1a12a5ed6a9.27.js → 1a12ecfb6db.27.js} +0 -0
  36. /package/dist/{1a12a5ed6a9.339.js → 1a12ecfb6db.339.js} +0 -0
  37. /package/dist/{1a12a5ed6a9.459.js → 1a12ecfb6db.459.js} +0 -0
  38. /package/dist/{1a12a5ed6a9.490.js → 1a12ecfb6db.490.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subiz/widget-v4",
3
- "version": "4.1.215",
3
+ "version": "4.1.216",
4
4
  "main": "./compiled_src/lib.js",
5
5
  "scripts": {
6
6
  "dev": "npx webpack serve --config webpack.dev.js",
@@ -391,6 +391,7 @@ export default class ChatButton extends Com {
391
391
 
392
392
  let imgurl = sb.get(accountSetting, 'desktop_button.background_image_url')
393
393
  let maskurl = sb.get(accountSetting, 'desktop_button.background_mask_url')
394
+ // Keep configured dimensions even when the image fails; default only missing dimensions to 70px.
394
395
  let imgwidth = sb.get(accountSetting, 'desktop_button.width') || 70
395
396
  let imgheight = sb.get(accountSetting, 'desktop_button.height') || 70
396
397
 
@@ -450,18 +451,10 @@ export default class ChatButton extends Com {
450
451
  appearance.maskAsset ? prepareButtonMask(appearance.maskAsset) : Promise.resolve(null),
451
452
  ])
452
453
  const stale = () => !this._isMounted || this._buttonImageVersion !== version
453
- if (stale()) {
454
- if (mask) URL.revokeObjectURL(mask)
455
- return
456
- }
454
+ if (stale()) return
457
455
  const fallback = loaded.some((success) => !success) || (!!appearance.maskAsset && !mask)
458
456
  const ready = !fallback || (await preloadButtonImage(defaultBubble))
459
- if (stale()) {
460
- if (mask) URL.revokeObjectURL(mask)
461
- return
462
- }
463
- if (this._buttonMaskUrl) URL.revokeObjectURL(this._buttonMaskUrl)
464
- this._buttonMaskUrl = mask
457
+ if (stale()) return
465
458
  // Commit the hidden style before revealing even when images are cached.
466
459
  // Otherwise older browsers can paint only the final state and skip the transition.
467
460
  if (this._buttonElement) window.getComputedStyle(this._buttonElement).transform
@@ -470,7 +463,6 @@ export default class ChatButton extends Com {
470
463
  }
471
464
 
472
465
  componentWillUnmount() {
473
- if (this._buttonMaskUrl) URL.revokeObjectURL(this._buttonMaskUrl)
474
466
  if (this._animateTimeout) clearTimeout(this._animateTimeout)
475
467
  }
476
468
 
@@ -478,12 +470,13 @@ export default class ChatButton extends Com {
478
470
  if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_button = sb.Date.now()
479
471
  const appearance = this.getButtonAppearance()
480
472
  let {imgsrc, imgurl, maskurl, background, position, imgwidth, imgheight} = appearance
473
+ const fallback = this.state.readyImageKey === appearance.key && this.state.fallbackButtonImage
481
474
  // Never attach a remote CSS mask while the local copy is being prepared.
482
475
  if (appearance.maskAsset) {
483
476
  maskurl = this.state.readyImageKey === appearance.key ? this.state.buttonMaskUrl : ''
484
477
  if (imgsrc === appearance.maskAsset) imgsrc = maskurl || ''
485
478
  }
486
- if (this.state.readyImageKey === appearance.key && this.state.fallbackButtonImage) {
479
+ if (fallback) {
487
480
  imgsrc = imgurl = defaultBubble
488
481
  maskurl = ''
489
482
  }
@@ -548,7 +541,12 @@ export default class ChatButton extends Com {
548
541
  `
549
542
  }
550
543
 
544
+ if (fallback) {
545
+ imgcontainerstyle += `width: ${imgwidth}px !important; height: ${imgheight}px !important;`
546
+ }
547
+
551
548
  let cls = 'chat-button chat-button--' + position
549
+ if (fallback) cls += ' chat-button--fallback'
552
550
  // dont render till all image is loaded
553
551
 
554
552
  let whiteBgStyle = `
@@ -679,18 +677,22 @@ function preloadButtonImage(src, {crossOrigin = false} = {}) {
679
677
  })
680
678
  }
681
679
 
682
- // CSS masks use a separate CORS image request. Pin the loaded bytes locally so
683
- // revealing the white backing never races another network request by CSS.
680
+ // Pin the mask bytes with a data URL: some sites allow data: images but block blob:.
681
+ // If inline images or fetch are blocked, preload the original URL with CORS for CSS masks.
684
682
  async function prepareButtonMask(src) {
685
- let url
686
683
  try {
687
684
  const response = await fetch(src)
688
685
  if (!response.ok) return null
689
- url = URL.createObjectURL(await response.blob())
690
- if (await preloadButtonImage(url)) return url
686
+ const blob = await response.blob()
687
+ const url = await new Promise((resolve) => {
688
+ const reader = new FileReader()
689
+ reader.onload = () => resolve(reader.result)
690
+ reader.onerror = reader.onabort = () => resolve('')
691
+ reader.readAsDataURL(blob)
692
+ })
693
+ if (url && await preloadButtonImage(url)) return url
691
694
  } catch (_) {
692
- // Use the bundled fallback if the custom mask cannot be loaded.
695
+ // A blocked fetch or failed conversion does not mean the original image is unavailable.
693
696
  }
694
- if (url) URL.revokeObjectURL(url)
695
- return null
697
+ return await preloadButtonImage(src, {crossOrigin: true}) ? src : null
696
698
  }
@@ -959,9 +959,10 @@ export default class Store {
959
959
  await this.readyGate.entry()
960
960
  const key = websiteFormStorageKey(this.api, formid)
961
961
  const kv = this.kv
962
+ const values = sb.cloneDeep(payload.values)
962
963
  const result = formResult(await this.api.submitWebsiteForm(formid, payload))
963
964
  try {
964
- kv.put(key, {conversation_id: result.conversation_id, expires_at: sb.Date.now() + 7 * 24 * 60 * 60 * 1000})
965
+ kv.put(key, {conversation_id: result.conversation_id, values, expires_at: sb.Date.now() + 7 * 24 * 60 * 60 * 1000})
965
966
  } catch (_) { /* Storage failure must not make callers retry a successful submission. */ }
966
967
  return result
967
968
  }
@@ -979,7 +980,7 @@ export default class Store {
979
980
  this.kv.del(key)
980
981
  return {submitted: false, status: 'expired'}
981
982
  }
982
- return {submitted: true, status: 'found', conversation_id: receipt.conversation_id}
983
+ return {submitted: true, status: 'found', conversation_id: receipt.conversation_id, values: Array.isArray(receipt.values) ? sb.cloneDeep(receipt.values) : []}
983
984
  } catch (_) {
984
985
  return {submitted: false, status: 'storage_unavailable'}
985
986
  }
package/up CHANGED
@@ -1,6 +1,22 @@
1
1
  #!/bin/sh
2
2
  set -e # exit when any command fails
3
3
 
4
+ # The storage client still references ssl.PROTOCOL_TLSv1; the local Python 3.14
5
+ # uses OpenSSL 4, which removed the underlying legacy API.
6
+ # Respect an explicit interpreter; otherwise prefer a compatible installed Python.
7
+ if [ -z "${CLOUDSDK_PYTHON:-}" ]; then
8
+ for python in python3.13 python3.12 python3.11 python3.10; do
9
+ if command -v "$python" >/dev/null 2>&1; then
10
+ CLOUDSDK_PYTHON=$(command -v "$python")
11
+ export CLOUDSDK_PYTHON
12
+ break
13
+ fi
14
+ done
15
+ fi
16
+
17
+ # Fail before rebuilding if gcloud cannot load the upload command.
18
+ gcloud storage cp --help >/dev/null
19
+
4
20
  # safety first
5
21
  echo "Clean"
6
22
  #rm -rf node_modules && rm -rf package-lock.json && npm i --no-optional
@@ -17,8 +33,10 @@ echo "Build OK. New version hash: $(cat dist/HASH)"
17
33
  # DEPLOY TO WIDGET SERVER
18
34
  # (do not deploy dist/HASH)
19
35
  mv dist/HASH dist/.HASH
36
+ trap 'if [ -f dist/.HASH ]; then mv dist/.HASH dist/HASH; fi' 0
20
37
  gcloud storage cp -r --cache-control="public, max-age=31536000" --gzip-local="html,js,css,svg,jpg,png" dist/* gs://public-gcs.subiz-cdn.com/widget-v4/public/
21
38
  mv dist/.HASH dist/HASH
39
+ trap - 0
22
40
 
23
41
  if [ "$1" = 'prod' ]; then
24
42
  gcloud storage cp --cache-control="public, max-age=10" --content-type="text/plain" dist/HASH gs://public-gcs.subiz-cdn.com/widget-v4/public/
package/dist/.HASH DELETED
@@ -1 +0,0 @@
1
- 1a12a5ed6a9