@seamly/web-ui 25.4.1-beta → 25.5.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamly/web-ui",
3
- "version": "25.4.1-beta",
3
+ "version": "25.5.1",
4
4
  "main": "build/dist/lib/index.js",
5
5
  "types": "build/src/javascripts/index.d.ts",
6
6
  "exports": {
@@ -21,22 +21,22 @@
21
21
  "webpack/*"
22
22
  ],
23
23
  "dependencies": {
24
- "@reduxjs/toolkit": "^2.11.2",
24
+ "@reduxjs/toolkit": "^2.12.0",
25
25
  "@ultraq/icu-message-formatter": "^0.15.2",
26
26
  "core-js": "^3.49.0",
27
- "focus-trap": "^7.8.0",
27
+ "focus-trap": "^8.2.2",
28
28
  "include-media": "^2.0.0",
29
- "js-cookie": "^3.0.5",
29
+ "js-cookie": "^3.0.8",
30
30
  "minivents": "^2.2.1",
31
- "react-redux": "^9.2.0",
31
+ "react-redux": "^9.3.0",
32
32
  "reconnecting-websocket": "^4.4.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@babel/core": "^7.28.5",
36
- "@babel/preset-env": "^7.28.5",
37
- "@babel/preset-react": "^7.28.5",
38
- "@babel/preset-typescript": "^7.28.5",
39
- "@playwright/test": "^1.58.2",
35
+ "@babel/core": "^7.29.7",
36
+ "@babel/preset-env": "^7.29.7",
37
+ "@babel/preset-react": "^7.29.7",
38
+ "@babel/preset-typescript": "^7.29.7",
39
+ "@playwright/test": "^1.61.1",
40
40
  "@seamly/doc-site": "^4.1.1",
41
41
  "@seamly/eslint-config": "^4.0.0",
42
42
  "@seamly/prettier-config": "^3.2.0",
@@ -45,30 +45,30 @@
45
45
  "@testing-library/preact": "^3.2.4",
46
46
  "@types/core-js": "^2.5.8",
47
47
  "@types/jest": "^30.0.0",
48
- "@types/node": "^25.5.0",
49
- "babel-jest": "30.3.0",
48
+ "@types/node": "^25.9.4",
49
+ "babel-jest": "30.4.1",
50
50
  "babel-loader": "^10.1.1",
51
51
  "copy-webpack-plugin": "^14.0.0",
52
52
  "eslint": "^9.39.4",
53
53
  "file-loader": "^6.2.0",
54
54
  "fork-ts-checker-webpack-plugin": "^9.1.0",
55
55
  "husky": "^9.1.7",
56
- "jest": "^30.3.0",
57
- "jest-environment-jsdom": "^30.3.0",
56
+ "jest": "^30.4.2",
57
+ "jest-environment-jsdom": "^30.4.1",
58
58
  "jest-watch-typeahead": "^3.0.1",
59
59
  "nyc": "^18.0.0",
60
60
  "openapi-typescript": "6.7.6",
61
61
  "playwright-test-coverage": "^1.2.12",
62
- "postcss": "^8.5.8",
63
- "preact": "^10.29.0",
64
- "prettier": "^3.8.1",
62
+ "postcss": "^8.5.16",
63
+ "preact": "^10.29.3",
64
+ "prettier": "^3.9.3",
65
65
  "rimraf": "^6.1.3",
66
66
  "style-loader": "^4.0.0",
67
- "stylelint": "^17.6.0",
68
- "typescript": "^6.0.2",
69
- "webpack": "^5.105.4",
70
- "webpack-cli": "^7.0.2",
71
- "webpack-dev-server": "^5.2.3",
67
+ "stylelint": "^17.14.0",
68
+ "typescript": "^6.0.3",
69
+ "webpack": "^5.108.2",
70
+ "webpack-cli": "^7.1.0",
71
+ "webpack-dev-server": "^5.2.5",
72
72
  "webpack-merge": "^6.0.1"
73
73
  },
74
74
  "resolutions": {
@@ -77,7 +77,7 @@
77
77
  "undici": "^7.22.0"
78
78
  },
79
79
  "peerDependencies": {
80
- "preact": "^10.29.0"
80
+ "preact": "^10.29.1"
81
81
  },
82
82
  "scripts": {
83
83
  "build:clean": "rimraf build; mkdir -p build",
@@ -108,5 +108,5 @@
108
108
  "test:e2e:coverage": "yarn nyc report --reporter cobertura --reporter html",
109
109
  "prepare": "husky"
110
110
  },
111
- "packageManager": "yarn@4.13.0"
111
+ "packageManager": "yarn@4.14.1"
112
112
  }
@@ -305,8 +305,7 @@ export interface components {
305
305
  service: components['schemas']['Service']
306
306
  transactionId: components['schemas']['TransactionId']
307
307
  translatedBody:
308
- | components['schemas']['ServiceDataBodySuggestion']
309
- | null
308
+ components['schemas']['ServiceDataBodySuggestion'] | null
310
309
  translation: components['schemas']['Translation']
311
310
  /**
312
311
  * @description Type of the message body
@@ -146,10 +146,7 @@ export type ServiceDataEvent = {
146
146
  }
147
147
 
148
148
  export type ChannelEvent =
149
- | MessageEvent
150
- | ParticipantEvent
151
- | ServiceDataEvent
152
- | InfoEvent
149
+ MessageEvent | ParticipantEvent | ServiceDataEvent | InfoEvent
153
150
 
154
151
  type EntryOptions = NonNullable<
155
152
  AsyncAPIComponents['schemas']['MessageIncoming']['payload']['entry']
@@ -43,7 +43,7 @@ export default function TranslationsOptionsButton({
43
43
  }
44
44
 
45
45
  const handleToggleClick = () => {
46
- setMenuIsOpen(!menuIsOpen)
46
+ setMenuIsOpen((isOpen) => !isOpen)
47
47
  }
48
48
 
49
49
  const handleToggleKeyDown = (e: KeyboardEvent) => {
@@ -63,6 +63,7 @@ export default function TranslationsOptionsButton({
63
63
  >
64
64
  <div className={className('options__dialog')} role="dialog">
65
65
  <TranslationsOptionsDialog
66
+ clickOutsideEnabled={menuIsOpen}
66
67
  onClose={handleDialogClose}
67
68
  position={position}
68
69
  />
@@ -5,11 +5,13 @@ import type { FramePosition } from 'ui/components/options/options-frame'
5
5
  import { useGeneratedId } from 'ui/hooks/seamly-hooks'
6
6
 
7
7
  type TranslationsOptionsDialogProps = {
8
+ clickOutsideEnabled: boolean
8
9
  onClose: () => void
9
10
  position: FramePosition
10
11
  }
11
12
 
12
13
  function TranslationsOptionsDialog({
14
+ clickOutsideEnabled,
13
15
  onClose,
14
16
  position,
15
17
  }: TranslationsOptionsDialogProps) {
@@ -23,6 +25,7 @@ function TranslationsOptionsDialog({
23
25
  description={t('translations.menu.description')}
24
26
  descriptionId={descriptionId}
25
27
  position={position}
28
+ clickOutsideEnabled={clickOutsideEnabled}
26
29
  disableButtonFocusing
27
30
  >
28
31
  <TranslationOptions describedById={descriptionId} onChange={onClose} />
@@ -55,7 +55,19 @@ export const setVisibility = createAsyncThunk<
55
55
  }
56
56
  }
57
57
 
58
+ const visibility = (api.store.get(StoreKey) || {}) as Record<
59
+ string,
60
+ VisibilityOptions | boolean | null | undefined
61
+ >
62
+
58
63
  if (previousVisibility === calculatedVisibility) {
64
+ api.store.set(StoreKey, {
65
+ ...visibility,
66
+ [layoutMode]: requestedVisibility,
67
+ ...(typeof showPreChat !== 'undefined' ? { showPreChat } : {}),
68
+ ...(typeof showContinueChat !== 'undefined' ? { showContinueChat } : {}),
69
+ })
70
+
59
71
  return {
60
72
  visibility: null,
61
73
  setInputFocus: args.setInputFocus,
@@ -64,12 +76,12 @@ export const setVisibility = createAsyncThunk<
64
76
  }
65
77
  }
66
78
 
67
- const visibility = api.store.get(StoreKey) as object | undefined
68
-
69
79
  // Store the user-requested visibility in order to reinitialize after refresh
70
80
  api.store.set(StoreKey, {
71
- ...(visibility || {}),
81
+ ...visibility,
72
82
  [layoutMode]: requestedVisibility,
83
+ ...(typeof showPreChat !== 'undefined' ? { showPreChat } : {}),
84
+ ...(typeof showContinueChat !== 'undefined' ? { showContinueChat } : {}),
73
85
  })
74
86
  if (requestedVisibility) {
75
87
  eventBus.emit('ui.visible', requestedVisibility, {
@@ -94,10 +106,39 @@ export const initializeVisibility = createAsyncThunk<any, void, ThunkAPI>(
94
106
  // initialize stored visibility
95
107
  const { layoutMode } = ConfigSelectors.selectConfig(getState())
96
108
 
97
- const storedVisibility =
98
- api.store.get(StoreKey)?.[layoutMode] || visibilityStates.initialize
109
+ const storedVisibilitySettings = (api.store.get(StoreKey) || {}) as Record<
110
+ string,
111
+ VisibilityOptions | boolean | null | undefined
112
+ >
113
+ const storedVisibilityValue = storedVisibilitySettings[layoutMode]
99
114
 
100
- dispatch(setVisibility({ visibility: storedVisibility }))
115
+ const storedVisibility = isPersistedVisibilityState(storedVisibilityValue)
116
+ ? storedVisibilityValue
117
+ : visibilityStates.initialize
118
+
119
+ const storedShowPreChat = storedVisibilitySettings.showPreChat
120
+ const storedShowContinueChat = storedVisibilitySettings.showContinueChat
121
+
122
+ dispatch(
123
+ setVisibility({
124
+ visibility: storedVisibility,
125
+ showPreChat:
126
+ typeof storedShowPreChat === 'boolean'
127
+ ? storedShowPreChat
128
+ : undefined,
129
+ showContinueChat:
130
+ typeof storedShowContinueChat === 'boolean'
131
+ ? storedShowContinueChat
132
+ : undefined,
133
+ }),
134
+ )
101
135
  return storedVisibility
102
136
  },
103
137
  )
138
+
139
+ const isPersistedVisibilityState = (
140
+ value: VisibilityOptions | boolean | undefined,
141
+ ): value is (typeof validVisibilityStates)[number] =>
142
+ value === visibilityStates.open ||
143
+ value === visibilityStates.minimized ||
144
+ value === visibilityStates.hidden
@@ -19,8 +19,7 @@ import Loader from './loader'
19
19
  const Events = () => {
20
20
  const events = useEvents()
21
21
  let prevParticipant:
22
- | MessageInfo['participant']
23
- | MessageMessage['participant']
22
+ MessageInfo['participant'] | MessageMessage['participant']
24
23
  return (
25
24
  <>
26
25
  {events.map((event) => {
@@ -23,6 +23,7 @@ type OptionsFrameProps = {
23
23
  descriptionId?: string
24
24
  cancelButtonText?: string
25
25
  cancelButtonRef?: MutableRef<HTMLButtonElement | null>
26
+ clickOutsideEnabled?: boolean
26
27
  disableButtonFocusing?: boolean
27
28
  position: FramePosition
28
29
  }
@@ -36,6 +37,7 @@ const OptionsFrame: FC<OptionsFrameProps> = ({
36
37
  descriptionId,
37
38
  cancelButtonText,
38
39
  cancelButtonRef,
40
+ clickOutsideEnabled = true,
39
41
  disableButtonFocusing,
40
42
  position = {
41
43
  horizontal: 'left',
@@ -62,7 +64,7 @@ const OptionsFrame: FC<OptionsFrameProps> = ({
62
64
  closePanel()
63
65
  }, [closePanel, onCancel])
64
66
 
65
- const container = useClickOutside(onCancelHandler)
67
+ const container = useClickOutside(onCancelHandler, clickOutsideEnabled)
66
68
 
67
69
  useEffect(() => {
68
70
  focusElement(container.current)
@@ -1,9 +1,13 @@
1
1
  import { useEffect, useRef } from 'preact/hooks'
2
2
 
3
- const useClickOutside = (callback: Function) => {
3
+ const useClickOutside = (callback: Function, enabled = true) => {
4
4
  const ref = useRef<HTMLElement>(null)
5
5
 
6
6
  useEffect(() => {
7
+ if (!enabled) {
8
+ return undefined
9
+ }
10
+
7
11
  const handler = (el: TouchEvent | MouseEvent): void => {
8
12
  if (
9
13
  ref.current &&
@@ -23,7 +27,7 @@ const useClickOutside = (callback: Function) => {
23
27
  document.removeEventListener('click', handler, true)
24
28
  document.removeEventListener('touchstart', handler, true)
25
29
  }
26
- }, [callback, ref])
30
+ }, [callback, enabled, ref])
27
31
 
28
32
  return ref
29
33
  }
@@ -801,7 +801,7 @@ const deletedFileDownloadAgentMessage = {
801
801
  },
802
802
  }
803
803
 
804
- const fileDownloadUserMessageImage = {
804
+ const userImageMessage = {
805
805
  type: 'message',
806
806
  payload: {
807
807
  ...messageBodyUploadImage,
@@ -812,19 +812,30 @@ const fileDownloadUserMessageImage = {
812
812
  }
813
813
 
814
814
  sessionStorage.setItem(
815
- `image-${fileDownloadUserMessageImage.payload.id}`,
816
- fileDownloadUserMessageImage.payload.body.url,
815
+ `image-${userImageMessage.payload.id}`,
816
+ userImageMessage.payload.body.url,
817
817
  )
818
818
 
819
- const emptyUrlFileDownloadUserMessage = {
820
- ...fileDownloadUserMessageImage,
819
+ const fileDownloadUserMessage = {
820
+ type: 'message',
821
821
  payload: {
822
- ...fileDownloadUserMessageImage.payload,
822
+ ...messageBodyUploadUrl,
823
+ fromClient: true,
824
+ participant: 'client',
823
825
  id: randomId(),
826
+ },
827
+ }
828
+
829
+ const deletedFileDownloadUserMessage = {
830
+ ...fileDownloadUserMessage,
831
+ payload: {
832
+ ...fileDownloadUserMessage.payload,
824
833
  body: {
825
- ...fileDownloadUserMessageImage.payload.body,
826
- url: null,
834
+ ...fileDownloadUserMessage.payload.body,
835
+ isDeleted: true,
836
+ url: undefined,
827
837
  },
838
+ id: randomId(),
828
839
  },
829
840
  }
830
841
 
@@ -1075,8 +1086,9 @@ const standardState = {
1075
1086
  textMessageWithLinks,
1076
1087
  textMessageWithLongLink,
1077
1088
  imageMessageWithLightbox,
1078
- fileDownloadUserMessageImage,
1079
- emptyUrlFileDownloadUserMessage,
1089
+ userImageMessage,
1090
+ fileDownloadUserMessage,
1091
+ deletedFileDownloadUserMessage,
1080
1092
  textMesageWithBullets,
1081
1093
  textMesageWithOrderedList,
1082
1094
  choicePromptMessage,
@@ -1091,8 +1103,9 @@ const standardState = {
1091
1103
  events: [
1092
1104
  userMessage,
1093
1105
  userMessageLong,
1094
- fileDownloadUserMessageImage,
1095
- emptyUrlFileDownloadUserMessage,
1106
+ userImageMessage,
1107
+ fileDownloadUserMessage,
1108
+ deletedFileDownloadUserMessage,
1096
1109
  userMessageWithLinks,
1097
1110
  ],
1098
1111
  },
@@ -1141,8 +1154,9 @@ const standardState = {
1141
1154
  fileDownloadAgentMessageByUrl,
1142
1155
  fileDownloadAgentMessageImage,
1143
1156
  deletedFileDownloadAgentMessage,
1144
- fileDownloadUserMessageImage,
1145
- emptyUrlFileDownloadUserMessage,
1157
+ userImageMessage,
1158
+ fileDownloadUserMessage,
1159
+ deletedFileDownloadUserMessage,
1146
1160
  ],
1147
1161
  },
1148
1162
  systemMessages: {
@@ -1922,8 +1936,8 @@ const standardState = {
1922
1936
  textMessageWithLinks,
1923
1937
  textMessageWithLongLink,
1924
1938
  imageMessageWithLightbox,
1925
- fileDownloadUserMessageImage,
1926
- emptyUrlFileDownloadUserMessage,
1939
+ userImageMessage,
1940
+ fileDownloadUserMessage,
1927
1941
  textMesageWithBullets,
1928
1942
  textMesageWithOrderedList,
1929
1943
  choicePromptMessage,
@@ -1961,8 +1975,8 @@ const standardState = {
1961
1975
  textMessageWithLinks,
1962
1976
  textMessageWithLongLink,
1963
1977
  imageMessageWithLightbox,
1964
- fileDownloadUserMessageImage,
1965
- emptyUrlFileDownloadUserMessage,
1978
+ userImageMessage,
1979
+ fileDownloadUserMessage,
1966
1980
  textMesageWithBullets,
1967
1981
  textMesageWithOrderedList,
1968
1982
  choicePromptMessage,