@fibery/ui-kit 1.38.0 → 1.38.2

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 (111) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/config/jest/testFrameworkSetup.js +1 -1
  3. package/package.json +23 -22
  4. package/src/abbreviate-name.ts +42 -0
  5. package/src/actions-menu/actions-menu-item.tsx +14 -5
  6. package/src/actions-menu/actions-menu-props.tsx +1 -0
  7. package/src/actions-menu/actions-menu.tsx +4 -1
  8. package/src/actions-menu/context-actions-menu.tsx +22 -0
  9. package/src/animated-height-container.tsx +24 -5
  10. package/src/antd/ant-upload.tsx +1 -1
  11. package/src/antd/input.tsx +4 -0
  12. package/src/avatar.tsx +1 -27
  13. package/src/button/base-button.tsx +2 -0
  14. package/src/button/button.tsx +4 -4
  15. package/src/button/icon-button.tsx +3 -3
  16. package/src/card-container.tsx +3 -2
  17. package/src/checkbox.tsx +17 -0
  18. package/src/collapsible/index.tsx +4 -2
  19. package/src/collapsible-section.tsx +3 -1
  20. package/src/date-picker/autocomplete.tsx +11 -5
  21. package/src/date-picker/date-range-input.tsx +5 -1
  22. package/src/date-picker/date-range-picker-popup-content.tsx +31 -13
  23. package/src/date-picker/single-date-input.tsx +5 -1
  24. package/src/date-picker/styles.ts +20 -0
  25. package/src/design-system.ts +26 -1
  26. package/src/dropdown-menu/index.tsx +11 -1
  27. package/src/emoji-picker/emoji-picker-preview-footer.tsx +4 -0
  28. package/src/emoji-picker/emoji.tsx +4 -3
  29. package/src/emoji-picker/primitives/emoji.tsx +49 -51
  30. package/src/emoji-picker/primitives/footer.tsx +6 -0
  31. package/src/emoji-picker/primitives/search.tsx +8 -0
  32. package/src/emoji-picker/primitives/skin-tone.tsx +12 -2
  33. package/src/fibermoji-placeholder.tsx +2 -29
  34. package/src/file-item-2.tsx +566 -0
  35. package/src/file-item.tsx +196 -162
  36. package/src/header-layout.tsx +11 -0
  37. package/src/html-styles.ts +13 -4
  38. package/src/icons/ast/Back.ts +1 -1
  39. package/src/icons/ast/ExtensionFiles.ts +1 -1
  40. package/src/icons/ast/FileArchive.ts +8 -0
  41. package/src/icons/ast/FileBroken.ts +8 -0
  42. package/src/icons/ast/FileDocument.ts +8 -0
  43. package/src/icons/ast/FileImage.ts +8 -0
  44. package/src/icons/ast/FilePresentation.ts +8 -0
  45. package/src/icons/ast/FileTable.ts +8 -0
  46. package/src/icons/ast/FileUpload.ts +1 -1
  47. package/src/icons/ast/FileVideo.ts +8 -0
  48. package/src/icons/ast/SwitchToMention.ts +8 -0
  49. package/src/icons/ast/SwitchToText.ts +8 -0
  50. package/src/icons/ast/SwitchToWidget.ts +8 -0
  51. package/src/icons/ast/ViewGallery.ts +8 -0
  52. package/src/icons/ast/index.tsx +11 -0
  53. package/src/icons/react/FileArchive.tsx +13 -0
  54. package/src/icons/react/FileBroken.tsx +13 -0
  55. package/src/icons/react/FileDocument.tsx +13 -0
  56. package/src/icons/react/FileImage.tsx +13 -0
  57. package/src/icons/react/FilePresentation.tsx +13 -0
  58. package/src/icons/react/FileTable.tsx +13 -0
  59. package/src/icons/react/FileVideo.tsx +13 -0
  60. package/src/icons/react/SwitchToMention.tsx +13 -0
  61. package/src/icons/react/SwitchToText.tsx +13 -0
  62. package/src/icons/react/SwitchToWidget.tsx +13 -0
  63. package/src/icons/react/ViewGallery.tsx +13 -0
  64. package/src/icons/react/index.tsx +11 -0
  65. package/src/icons/svg/back.svg +3 -1
  66. package/src/icons/svg/extension/files.svg +3 -1
  67. package/src/icons/svg/file-archive.svg +3 -0
  68. package/src/icons/svg/file-broken.svg +3 -0
  69. package/src/icons/svg/file-document.svg +3 -0
  70. package/src/icons/svg/file-image.svg +3 -0
  71. package/src/icons/svg/file-presentation.svg +3 -0
  72. package/src/icons/svg/file-table.svg +3 -0
  73. package/src/icons/svg/file-upload.svg +3 -6
  74. package/src/icons/svg/file-video.svg +3 -0
  75. package/src/icons/svg/switch-to-mention.svg +3 -0
  76. package/src/icons/svg/switch-to-text.svg +4 -0
  77. package/src/icons/svg/switch-to-widget.svg +4 -0
  78. package/src/icons/svg/view-gallery.svg +4 -0
  79. package/src/images-gallery/images-gallery-fall-through-provider.tsx +11 -0
  80. package/src/images-gallery/images-gallery.tsx +13 -10
  81. package/src/images-gallery/zoom.tsx +13 -2
  82. package/src/images-gallery-2/images-gallery-2.tsx +522 -0
  83. package/src/images-gallery-2/slide-buttons.tsx +271 -0
  84. package/src/images-gallery-2/zoom.tsx +35 -0
  85. package/src/kbd.tsx +46 -0
  86. package/src/loading-sausage.tsx +2 -2
  87. package/src/modal-menu/modal-menu-item.tsx +10 -2
  88. package/src/modal-menu/modal-menu-trigger.tsx +19 -2
  89. package/src/notification-dot.tsx +16 -7
  90. package/src/platform-symbols.ts +9 -0
  91. package/src/platform.ts +2 -0
  92. package/src/popover/index.tsx +31 -8
  93. package/src/popover/modifiers.tsx +26 -19
  94. package/src/reactions/reaction-button.tsx +323 -101
  95. package/src/reactions/reaction-picker.tsx +14 -1
  96. package/src/reactions/reactions.tsx +11 -1
  97. package/src/reactions/tootltip.tsx +55 -0
  98. package/src/rich-text-embed-error.tsx +2 -1
  99. package/src/select/components/group-heading.tsx +8 -0
  100. package/src/select/components/menu-list-virtualized.tsx +6 -2
  101. package/src/select/components/option.tsx +4 -0
  102. package/src/select/select-control-settings-context.tsx +11 -2
  103. package/src/select/select-in-popover.tsx +10 -7
  104. package/src/select/styles.ts +21 -1
  105. package/src/tab-nav/tab-nav.tsx +1 -1
  106. package/src/toggle.tsx +8 -0
  107. package/src/tooltip.tsx +28 -19
  108. package/src/type-badge.tsx +5 -2
  109. package/src/unit/unit-with-tooltip.tsx +1 -1
  110. package/src/use-is-phone.tsx +34 -6
  111. package/src/shortcut-badge.tsx +0 -29
@@ -0,0 +1,522 @@
1
+ /* eslint-disable max-lines */
2
+ import PhotoSwipeLightbox, {type PhotoSwipeEventsMap} from "photoswipe/lightbox";
3
+ import "photoswipe/style.css";
4
+ import {
5
+ ImagesGalleryMethodsProvider,
6
+ ImagesGalleryRegistryProvider,
7
+ ImagesGalleryStateProvider,
8
+ } from "../images-gallery/images-gallery";
9
+ import {PropsWithChildren, useCallback, useEffect, useMemo, useReducer, useRef, useState} from "react";
10
+ import {css} from "@linaria/core";
11
+ import {createRoot} from "react-dom/client";
12
+ import {space, themeVars} from "../design-system";
13
+ import {safeAreaInsetLeftVar, safeAreaInsetRightVar, safeAreaInsetTopVar} from "../mobile-styles";
14
+ import {useToast} from "../toast/toast-provider";
15
+ import {ToastQueue} from "../toast/toast-queue";
16
+ import {useThemeMode} from "../theme-provider";
17
+ import {ThemeMode} from "../theme-settings";
18
+ import {SlideButtons} from "./slide-buttons";
19
+ import {useIsPhone} from "../use-is-phone";
20
+
21
+ type Registry = Map<
22
+ string,
23
+ {
24
+ src: string;
25
+ type: "image" | "video" | "iframe";
26
+ contentType?: string;
27
+ actions?: React.ReactNode;
28
+ zoomed: boolean;
29
+ setZoomed: (zoomed: boolean) => void;
30
+ }
31
+ >;
32
+
33
+ type Methods = {
34
+ setVisible: (visible: boolean) => void;
35
+ setActivated: (activated: boolean) => void;
36
+ update: () => void;
37
+ nextImage: () => void;
38
+ prevImage: () => void;
39
+ };
40
+
41
+ const galleryMainClass = css`
42
+ z-index: 1000;
43
+ & .pswp__button--arrow--prev {
44
+ left: calc(${space.s20}px + var(${safeAreaInsetLeftVar}));
45
+ height: ${space.s28}px;
46
+ width: ${space.s28}px;
47
+ margin-top: -${space.s14}px;
48
+ }
49
+ & .pswp__button--arrow--next {
50
+ right: calc(${space.s20}px + var(${safeAreaInsetRightVar}));
51
+ height: ${space.s28}px;
52
+ width: ${space.s28}px;
53
+ margin-top: -${space.s14}px;
54
+ }
55
+
56
+ & .pswp__button--zoom {
57
+ top: ${space.s20}px;
58
+ height: ${space.s28}px;
59
+ width: ${space.s28}px;
60
+ }
61
+
62
+ & .pswp__counter {
63
+ margin-top: ${space.s20}px;
64
+ margin-inline-start: ${space.s24}px;
65
+ }
66
+
67
+ & .pswp__video-container {
68
+ padding: ${space.s60}px;
69
+ }
70
+
71
+ & .pswp__video-container video {
72
+ width: 100%;
73
+ height: 100%;
74
+ object-fit: contain;
75
+ display: block;
76
+ background-color: black;
77
+ }
78
+
79
+ & .pswp__iframe-container {
80
+ padding: ${space.s60}px;
81
+ display: flex;
82
+ justify-content: center;
83
+ align-items: center;
84
+ }
85
+
86
+ & .pswp__iframe-container iframe {
87
+ width: 100%;
88
+ height: 100%;
89
+ object-fit: contain;
90
+ display: block;
91
+ color: ${themeVars.textColor};
92
+ background-color: ${themeVars.colorBgPopup};
93
+ border: none;
94
+ }
95
+
96
+ & .pswp__top-bar {
97
+ top: var(${safeAreaInsetTopVar});
98
+ left: var(${safeAreaInsetLeftVar});
99
+ }
100
+ `;
101
+
102
+ export function ImagesGalleryProvider2({children}: PropsWithChildren) {
103
+ const [imagesRegistry] = useState<Registry>(() => new Map());
104
+ const [galleryState, dispatchState] = useReducer(imagesGalleryReducer, [], initialState);
105
+
106
+ const lightbox = useRef<PhotoSwipeLightbox | null>(null);
107
+ const markAllNotZoomed = useCallback(() => {
108
+ for (const node of imagesRegistry.values()) {
109
+ if (node.zoomed) {
110
+ node.setZoomed(false);
111
+ }
112
+ }
113
+ }, [imagesRegistry]);
114
+
115
+ useEffect(() => {
116
+ return () => {
117
+ lightbox.current?.destroy();
118
+ lightbox.current = null;
119
+ markAllNotZoomed();
120
+ };
121
+ }, [markAllNotZoomed]);
122
+
123
+ const methods: Methods = useMemo(() => {
124
+ return {
125
+ setVisible: () => {},
126
+ setActivated: (activated: boolean) => {
127
+ dispatchState({type: "set-activated", payload: activated});
128
+ },
129
+ update: () => {
130
+ dispatchState({type: "inc"});
131
+ },
132
+ nextImage: () => {
133
+ lightbox.current?.pswp?.next();
134
+ },
135
+ prevImage: () => {
136
+ lightbox.current?.pswp?.prev();
137
+ },
138
+ };
139
+ }, []);
140
+
141
+ const toast = useToast();
142
+ const themeMode = useThemeMode();
143
+ const isPhone = useIsPhone();
144
+
145
+ useEffect(() => {
146
+ if (galleryState.activated) {
147
+ const value = initGallery(imagesRegistry, {toastQueue: toast, isPhone, themeMode});
148
+ value.on("close", () => {
149
+ dispatchState({type: "set-activated", payload: false});
150
+ markAllNotZoomed();
151
+ value.destroy();
152
+ });
153
+
154
+ lightbox.current = value;
155
+ }
156
+
157
+ return () => {
158
+ lightbox.current?.destroy();
159
+ lightbox.current = null;
160
+ };
161
+ }, [galleryState.activated, imagesRegistry, markAllNotZoomed, toast, themeMode, isPhone]);
162
+
163
+ return (
164
+ <ImagesGalleryRegistryProvider value={imagesRegistry}>
165
+ <ImagesGalleryMethodsProvider value={methods}>
166
+ <ImagesGalleryStateProvider value={galleryState}>{children}</ImagesGalleryStateProvider>
167
+ </ImagesGalleryMethodsProvider>
168
+ </ImagesGalleryRegistryProvider>
169
+ );
170
+ }
171
+
172
+ type State = {version: "1" | "2"; visible: boolean; activated: boolean; _inc: number};
173
+ type Actions = {type: "set-visible"; payload: boolean} | {type: "set-activated"; payload: boolean} | {type: "inc"};
174
+
175
+ function initialState(): State {
176
+ return {version: "2", visible: false, activated: false, _inc: 0};
177
+ }
178
+
179
+ function imagesGalleryReducer(state: State, action: Actions) {
180
+ if (action.type === "set-visible") {
181
+ return {...state, visible: action.payload};
182
+ }
183
+ if (action.type === "set-activated") {
184
+ return {...state, activated: action.payload};
185
+ }
186
+ if (action.type === "inc") {
187
+ return {...state, _inc: state._inc + 1};
188
+ }
189
+ return state;
190
+ }
191
+
192
+ type GalleryEntry = {
193
+ type: string;
194
+ src: string;
195
+ contentType: string | null;
196
+ zoomed: boolean;
197
+ setZoomed: (value: boolean) => void;
198
+ state: "none" | "loading" | "error" | "loaded";
199
+ width?: number;
200
+ height?: number;
201
+ };
202
+
203
+ function initGallery(
204
+ imagesRegistry: Registry,
205
+ {toastQueue, themeMode, isPhone}: {toastQueue: ToastQueue; themeMode: ThemeMode; isPhone: boolean}
206
+ ) {
207
+ const items = [...imagesRegistry.values()];
208
+ const dataSource: GalleryEntry[] = items.map((item) => ({
209
+ ...item,
210
+ state: "none",
211
+ contentType: item.contentType ?? null,
212
+ }));
213
+
214
+ const zoomedIndex = dataSource.findIndex((item) => item.zoomed);
215
+
216
+ const lightbox = new PhotoSwipeLightbox({
217
+ dataSource,
218
+ mainClass: galleryMainClass,
219
+ pswpModule: () => import("photoswipe"),
220
+ preloaderDelay: 1,
221
+ arrowPrev: false,
222
+ arrowNext: false,
223
+ close: false,
224
+ zoom: false,
225
+ loop: false,
226
+ });
227
+
228
+ lightbox.addFilter("numItems", (_numItems) => {
229
+ return dataSource.length;
230
+ });
231
+
232
+ lightbox.addFilter("itemData", (_itemData, index) => {
233
+ const item = dataSource[index];
234
+
235
+ if (item.type === "video" || item.type === "iframe") {
236
+ return item;
237
+ }
238
+
239
+ if (item.state === "loaded" || item.state === "error") {
240
+ return item;
241
+ }
242
+
243
+ return {};
244
+ });
245
+
246
+ lightbox.addFilter("isContentLoading", (_isContentLoading, content) => {
247
+ const item = dataSource[content.index];
248
+ if (item.type === "video" || item.type === "iframe") {
249
+ return false;
250
+ }
251
+ const complete = item.state === "loaded" || item.state === "error";
252
+ return !complete;
253
+ });
254
+
255
+ lightbox.addFilter("useContentPlaceholder", () => false);
256
+
257
+ lightbox.init();
258
+
259
+ lightbox.on("contentActivate", (e) => {
260
+ dataSource[e.content.index].setZoomed(true);
261
+ lightbox.pswp?.element?.focus();
262
+ });
263
+
264
+ lightbox.on("contentDeactivate", (e) => {
265
+ dataSource[e.content.index].setZoomed(false);
266
+ e.content.element?.querySelector("video")?.pause();
267
+ });
268
+
269
+ function refreshSlide(index: number) {
270
+ lightbox.pswp?.refreshSlideContent(index);
271
+ if (lightbox.pswp?.currIndex === index) {
272
+ lightbox.pswp?.updateSize(true);
273
+ }
274
+ }
275
+
276
+ const contentAppendTimeouts = [] as ReturnType<typeof setTimeout>[];
277
+ lightbox.on("contentAppend", (e) => {
278
+ // sometimes lightbox's slide is loaded with stale (empty) data
279
+ if (e.content.data !== dataSource[e.content.index]) {
280
+ contentAppendTimeouts.push(
281
+ setTimeout(() => {
282
+ refreshSlide(e.content.index);
283
+ }, 0)
284
+ );
285
+ }
286
+ });
287
+
288
+ lightbox.on("contentRemove", (e) => {
289
+ const item = dataSource[e.content.index];
290
+
291
+ if (item.type === "video" || item.type === "iframe") {
292
+ item.state = "none";
293
+ }
294
+ });
295
+
296
+ lightbox.on("contentLoad", (e) => {
297
+ const item = dataSource[e.content.index];
298
+
299
+ if (item.state === "loading") {
300
+ return;
301
+ }
302
+
303
+ if (item.state === "none") {
304
+ e.preventDefault();
305
+ const eventArgs = {
306
+ e,
307
+ item,
308
+ refreshSlide,
309
+ getPswp: () => lightbox.pswp,
310
+ isPhone,
311
+ };
312
+
313
+ switch (item.type) {
314
+ case "image": {
315
+ onImageContentLoad(eventArgs);
316
+ break;
317
+ }
318
+ case "video": {
319
+ onVideoContentLoad(eventArgs);
320
+ break;
321
+ }
322
+ case "iframe": {
323
+ onIframeContentLoad(eventArgs);
324
+ break;
325
+ }
326
+ default: {
327
+ throw new Error(`unexpected slide type: ${item.type}`);
328
+ }
329
+ }
330
+ } else if (item.state === "error") {
331
+ e.preventDefault();
332
+ e.content.onError();
333
+ }
334
+ });
335
+
336
+ const HIDE_UI_TIMEOUT_MS = 3000;
337
+ let forceShowUI = false;
338
+ let hideTimeout: ReturnType<typeof setTimeout>;
339
+ let isHidden = false;
340
+
341
+ function hideUI() {
342
+ if (forceShowUI) {
343
+ return;
344
+ }
345
+ lightbox.pswp?.element?.classList.remove("pswp--ui-visible");
346
+ lightbox.pswp?.element?.classList.add("pswp--hide-cursor");
347
+ isHidden = true;
348
+ }
349
+
350
+ function showUI() {
351
+ if (isHidden) {
352
+ lightbox.pswp?.element?.classList.add("pswp--ui-visible");
353
+ lightbox.pswp?.element?.classList.remove("pswp--hide-cursor");
354
+ isHidden = false;
355
+ }
356
+ clearTimeout(hideTimeout);
357
+ hideTimeout = setTimeout(hideUI, HIDE_UI_TIMEOUT_MS);
358
+ }
359
+
360
+ lightbox.on("afterInit", () => {
361
+ const pswp = lightbox.pswp;
362
+
363
+ if (!pswp) {
364
+ return;
365
+ }
366
+
367
+ pswp.element?.addEventListener("mousemove", showUI);
368
+ pswp.element?.addEventListener("touchstart", showUI);
369
+
370
+ hideTimeout = setTimeout(hideUI, HIDE_UI_TIMEOUT_MS);
371
+ });
372
+
373
+ const uiHandlers = {
374
+ showUI,
375
+ setForceShowUI: (value: boolean) => {
376
+ forceShowUI = value;
377
+ // resets timer
378
+ if (!forceShowUI) {
379
+ showUI();
380
+ }
381
+ },
382
+ };
383
+
384
+ lightbox.on("uiRegister", () => {
385
+ lightbox.pswp?.ui?.registerElement({
386
+ name: "custom-nav",
387
+ order: 8,
388
+ isButton: false,
389
+ appendTo: "wrapper",
390
+ onInit: (el, pswp) => {
391
+ createRoot(el).render(
392
+ <SlideButtons
393
+ items={items}
394
+ pswp={pswp}
395
+ toastQueue={toastQueue}
396
+ themeMode={themeMode}
397
+ uiHandlers={uiHandlers}
398
+ />
399
+ );
400
+ },
401
+ });
402
+ });
403
+
404
+ lightbox.on("destroy", () => {
405
+ contentAppendTimeouts.forEach((timeoutId) => {
406
+ clearTimeout(timeoutId);
407
+ });
408
+ });
409
+
410
+ lightbox.loadAndOpen(zoomedIndex === -1 ? 0 : zoomedIndex);
411
+
412
+ return lightbox;
413
+ }
414
+
415
+ type ContentLoadArg = {
416
+ e: PhotoSwipeEventsMap["contentLoad"];
417
+ item: GalleryEntry;
418
+ refreshSlide: (index: number) => void;
419
+ getPswp: () => PhotoSwipeLightbox["pswp"];
420
+ isPhone: boolean;
421
+ };
422
+
423
+ function onImageContentLoad({e, item, refreshSlide}: ContentLoadArg) {
424
+ item.state = "loading";
425
+ // we ok if content type request fails
426
+ const contentTypePromise = item.contentType
427
+ ? Promise.resolve(item.contentType)
428
+ : fetch(item.src, {method: "HEAD"})
429
+ .then((response) => response.headers.get("content-type"))
430
+ .catch();
431
+
432
+ const contentPromise = new Promise<{width: number; height: number}>((resolve, reject) => {
433
+ const onLoad = () => {
434
+ resolve({
435
+ width: img.naturalWidth,
436
+ height: img.naturalHeight,
437
+ });
438
+ };
439
+
440
+ const img = new Image();
441
+ img.src = item.src;
442
+ if (img.complete) {
443
+ onLoad();
444
+ }
445
+ img.onload = () => onLoad();
446
+ img.onerror = () => {
447
+ reject("error");
448
+ };
449
+ });
450
+
451
+ Promise.allSettled([contentTypePromise, contentPromise]).then(([contentTypeResult, contentResult]) => {
452
+ if (contentResult.status === "rejected") {
453
+ item.state = "error";
454
+ refreshSlide(e.content.index);
455
+ e.content.onError();
456
+ return;
457
+ }
458
+
459
+ item.state = "loaded";
460
+ item.width = contentResult.value.width;
461
+ item.height = contentResult.value.height;
462
+
463
+ // normalize
464
+ if (contentTypeResult.status === "fulfilled" && contentTypeResult.value?.startsWith("image/svg")) {
465
+ const scale = Math.min(3000 / item.width!, 3000 / item.height!);
466
+ item.width = Math.ceil(scale * item.width!);
467
+ item.height = Math.ceil(scale * item.height!);
468
+ }
469
+
470
+ refreshSlide(e.content.index);
471
+ e.content.onLoaded();
472
+ });
473
+ }
474
+
475
+ function onVideoContentLoad({e, item, refreshSlide, getPswp, isPhone}: ContentLoadArg) {
476
+ item.state = "loaded";
477
+
478
+ e.content.element = document.createElement("div");
479
+ e.content.element.className = "pswp__video-container";
480
+ e.content.element.onclick = () => {
481
+ getPswp()?.close();
482
+ };
483
+
484
+ const video = document.createElement("video");
485
+ video.controls = true;
486
+ video.src = item.src;
487
+ video.onerror = () => {
488
+ item.state = "error";
489
+ refreshSlide(e.content.index);
490
+ e.content.onError();
491
+ };
492
+ video.onclick = (e) => {
493
+ e.preventDefault();
494
+ e.stopPropagation();
495
+ if (isPhone) {
496
+ return;
497
+ }
498
+ if (video.paused) {
499
+ video.play().catch();
500
+ } else {
501
+ video.pause();
502
+ }
503
+ };
504
+
505
+ e.content.element.appendChild(video);
506
+ }
507
+
508
+ function onIframeContentLoad({e, item, getPswp}: ContentLoadArg) {
509
+ item.state = "loaded";
510
+
511
+ e.content.element = document.createElement("div");
512
+ e.content.element.className = "pswp__iframe-container";
513
+
514
+ e.content.element.onclick = () => {
515
+ getPswp()?.close();
516
+ };
517
+
518
+ const iframe = document.createElement("iframe");
519
+ iframe.src = item.src;
520
+ iframe.setAttribute("allowfullscreen", "");
521
+ e.content.element.appendChild(iframe);
522
+ }