Skip to content

Commit daa99e8

Browse files
Add a lightweight alternative to PersistedElement for stickers
Fix Widget API behavior in sidebar mode.
1 parent 84349f9 commit daa99e8

4 files changed

Lines changed: 211 additions & 92 deletions

File tree

apps/web/res/css/views/rooms/_Stickers.pcss

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,43 @@
88
}
99

1010
#mx_persistedElement_stickerPicker {
11-
.mx_AppTileFullWidth {
11+
.mx_Stickers_hostInner_popover .mx_AppTileFullWidth {
1212
height: unset;
1313
box-sizing: border-box;
1414
border-left: none;
1515
border-right: none;
1616
border-bottom: none;
1717
}
1818

19-
.mx_AppTileMenuBar {
19+
.mx_Stickers_hostInner_popover .mx_AppTileMenuBar {
2020
padding: 0;
2121
}
2222

23-
iframe {
23+
.mx_Stickers_hostInner_popover iframe {
2424
/* Sticker picker depends on a fixed popover height */
2525
height: 433px; /* 450px popover minus the AppTile menu bar */
2626
}
27+
28+
.mx_Stickers_hostInner_sidebar,
29+
.mx_Stickers_hostInner_sidebar .mx_AppTileFullWidth,
30+
.mx_Stickers_hostInner_sidebar .mx_AppTileBody--large,
31+
.mx_Stickers_hostInner_sidebar .mx_AppTile_persistedWrapper {
32+
width: 100%;
33+
height: 100%;
34+
min-height: 0;
35+
}
36+
37+
.mx_Stickers_hostInner_sidebar .mx_AppTileFullWidth,
38+
.mx_Stickers_hostInner_sidebar .mx_AppTileBody--large,
39+
.mx_Stickers_hostInner_sidebar .mx_AppTile_persistedWrapper {
40+
display: flex;
41+
flex: 1 1 0;
42+
flex-direction: column;
43+
}
44+
45+
.mx_Stickers_hostInner_sidebar iframe {
46+
height: 100%;
47+
}
2748
}
2849

2950
.mx_Stickers_contentPlaceholder {
@@ -47,28 +68,65 @@
4768

4869
.mx_Stickers_sidebar {
4970
display: flex;
50-
flex: 1;
71+
flex: 1 1 0;
5172
width: 100%;
5273
min-height: 0;
5374
overflow: hidden;
5475

55-
.mx_AppTileFullWidth {
56-
width: 100% !important;
57-
max-width: unset;
76+
> div {
77+
display: flex;
78+
flex: 1;
79+
width: 100%;
80+
min-height: 0;
5881
}
82+
83+
> div > div {
84+
width: 100%;
85+
height: 100%;
86+
}
87+
}
88+
89+
.mx_Stickers_host {
90+
display: flex;
91+
width: 100%;
92+
min-height: 0;
93+
}
94+
95+
.mx_Stickers_host_popover {
96+
height: 100%;
97+
}
98+
99+
.mx_Stickers_host_sidebar {
100+
flex: 1 1 0;
101+
height: 100%;
102+
}
103+
104+
.mx_Stickers_hostInner {
105+
display: flex;
106+
min-height: 0;
107+
}
108+
109+
.mx_Stickers_hostInner_sidebar {
110+
flex: 1 1 0;
59111
}
60112

61113
.mx_Stickers_sidebarPlaceholder {
62114
display: flex;
63-
flex: 1;
115+
flex: 1 1 0;
64116
width: 100%;
65117
min-height: 0;
66118
}
67119

68120
.mx_Stickers_loading {
69121
display: flex;
70-
flex: 1;
122+
flex: 1 1 0;
71123
min-height: 0;
72124
align-items: center;
73125
justify-content: center;
74126
}
127+
128+
.mx_WidgetCard > .mx_Stickers_sidebar,
129+
.mx_WidgetCard > .mx_Stickers_sidebarPlaceholder {
130+
flex: 1 1 0;
131+
min-height: 0;
132+
}

apps/web/src/components/views/elements/AppTile.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ interface IProps {
108108
handleMinimisePointerEvents?: boolean;
109109
// Optionally hide the popout widget icon
110110
showPopout?: boolean;
111+
// Whether sending a sticker should close the sticker picker widget
112+
closeOnStickerSend?: boolean;
111113
// Is this an instance of a user widget
112114
userWidget: boolean;
113115
// sets the pointer-events property on the iframe
@@ -148,6 +150,7 @@ export default class AppTile extends React.Component<IProps, IState> {
148150
showMenubar: true,
149151
showTitle: true,
150152
showPopout: true,
153+
closeOnStickerSend: true,
151154
handleMinimisePointerEvents: false,
152155
userWidget: false,
153156
miniMode: false,
@@ -586,7 +589,9 @@ export default class AppTile extends React.Component<IProps, IState> {
586589
threadId: this.props.threadId,
587590
},
588591
});
589-
dis.dispatch({ action: "stickerpicker_close" });
592+
if (this.props.closeOnStickerSend) {
593+
dis.dispatch({ action: "stickerpicker_close" });
594+
}
590595
} else {
591596
logger.warn("Ignoring sticker message. Invalid capability");
592597
}

apps/web/src/components/views/rooms/Stickerpicker.tsx

Lines changed: 24 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@ Please see LICENSE files in the repository root for full details.
88
import React, { type JSX } from "react";
99
import { type Room, ClientEvent } from "matrix-js-sdk/src/matrix";
1010
import { logger } from "matrix-js-sdk/src/logger";
11-
import { type IWidget } from "matrix-widget-api";
1211

1312
import { _t, _td } from "../../../languageHandler";
14-
import AppTile from "../elements/AppTile";
13+
import type { TranslationKey } from "../../../languageHandler";
1514
import Spinner from "../elements/Spinner";
16-
import { MatrixClientPeg } from "../../../MatrixClientPeg";
1715
import dis from "../../../dispatcher/dispatcher";
1816
import AccessibleButton from "../elements/AccessibleButton";
1917
import WidgetUtils, { type UserWidget } from "../../../utils/WidgetUtils";
@@ -28,13 +26,7 @@ import GenericElementContextMenu from "../context_menus/GenericElementContextMen
2826
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
2927
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
3028
import { setStickerpickerAttachedToSidebar } from "./StickerpickerSidebarStore";
31-
32-
// This should be below the dialog level (4000), but above the rest of the UI (1000-2000).
33-
// We sit in a context menu, so this should be given to the context menu.
34-
const STICKERPICKER_Z_INDEX = 3500;
35-
36-
// Key to store the widget's AppTile under in PersistedElement
37-
const PERSISTED_ELEMENT_KEY = "stickerPicker";
29+
import StickerpickerHost, { PERSISTED_ELEMENT_KEY, STICKERPICKER_Z_INDEX } from "./StickerpickerHost";
3830

3931
interface IProps {
4032
room: Room;
@@ -61,7 +53,6 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
6153
public static currentWidget?: UserWidget;
6254

6355
private dispatcherRef?: string;
64-
6556
private prevSentVisibility?: boolean;
6657

6758
private popoverWidth = 340;
@@ -135,7 +126,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
135126
this.dispatcherRef = dis.register(this.onAction);
136127

137128
// Track updates to widget state in account data
138-
MatrixClientPeg.safeGet().on(ClientEvent.AccountData, this.updateWidget);
129+
this.props.room.client.on(ClientEvent.AccountData, this.updateWidget);
139130

140131
if (this.props.displayMode === "popover") {
141132
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
@@ -145,8 +136,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
145136
}
146137

147138
public componentWillUnmount(): void {
148-
const client = MatrixClientPeg.get();
149-
if (client) client.removeListener(ClientEvent.AccountData, this.updateWidget);
139+
this.props.room.client.removeListener(ClientEvent.AccountData, this.updateWidget);
150140
if (this.props.displayMode === "popover") {
151141
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
152142
}
@@ -260,92 +250,44 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
260250
}
261251
}
262252

263-
private getStickerpickerApp(): IWidget | null {
264-
const stickerpickerWidget = this.state.stickerpickerWidget;
265-
if (!stickerpickerWidget?.content?.url) return null;
266-
267-
stickerpickerWidget.content.name = stickerpickerWidget.content.name || _t("common|stickerpack");
268-
269-
return {
270-
id: stickerpickerWidget.id,
271-
url: stickerpickerWidget.content.url,
272-
name: stickerpickerWidget.content.name,
273-
type: stickerpickerWidget.content.type,
274-
data: stickerpickerWidget.content.data,
275-
creatorUserId: stickerpickerWidget.content.creatorUserId || stickerpickerWidget.sender,
276-
};
277-
}
278-
279-
private renderStickerpickerApp(stickerApp: IWidget, sidebarMode = false): JSX.Element {
280-
const stickerpickerWidget = this.state.stickerpickerWidget!;
281-
282-
return (
283-
<AppTile
284-
app={stickerApp}
285-
room={this.props.room}
286-
threadId={this.props.threadId}
287-
fullWidth={true}
288-
userId={MatrixClientPeg.safeGet().credentials.userId!}
289-
creatorUserId={stickerpickerWidget.sender || MatrixClientPeg.safeGet().credentials.userId!}
290-
waitForIframeLoad={true}
291-
showMenubar={!sidebarMode}
292-
onEditClick={this.launchManageIntegrations}
293-
onDeleteClick={this.removeStickerpickerWidgets}
294-
onAttachToSidebarClick={this.props.displayMode === "popover" ? this.attachToSidebar : undefined}
295-
showTitle={false}
296-
showPopout={false}
297-
handleMinimisePointerEvents={true}
298-
userWidget={true}
299-
showLayoutButtons={false}
300-
/>
301-
);
302-
}
303-
304-
public getStickerpickerContent(): JSX.Element {
253+
private renderStickerpickerWidget(displayMode: "popover" | "sidebar"): JSX.Element {
305254
if (this.state.imError) {
306255
return this.errorStickerpickerContent();
307256
}
308257

309-
const stickerApp = this.getStickerpickerApp();
310-
311-
if (stickerApp) {
258+
if (this.state.stickerpickerWidget?.content?.url) {
312259
return (
313-
<div className="mx_Stickers_content_container">
314-
<div
315-
id="stickersContent"
316-
className="mx_Stickers_content"
317-
style={{
318-
border: "none",
319-
height: this.popoverHeight,
320-
width: this.popoverWidth,
321-
}}
322-
>
323-
<PersistedElement persistKey={PERSISTED_ELEMENT_KEY} zIndex={STICKERPICKER_Z_INDEX}>
324-
{this.renderStickerpickerApp(stickerApp)}
325-
</PersistedElement>
326-
</div>
327-
</div>
260+
<StickerpickerHost
261+
room={this.props.room}
262+
threadId={this.props.threadId}
263+
stickerpickerWidget={this.state.stickerpickerWidget}
264+
displayMode={displayMode}
265+
popoverWidth={this.popoverWidth}
266+
popoverHeight={this.popoverHeight}
267+
onEditClick={this.launchManageIntegrations}
268+
onDeleteClick={this.removeStickerpickerWidgets}
269+
onAttachToSidebarClick={this.attachToSidebar}
270+
/>
328271
);
329272
}
330273

331274
return this.defaultStickerpickerContent();
332275
}
333276

334-
public getSidebarStickerpickerContent(): JSX.Element {
335-
if (this.state.imError) {
336-
return this.errorStickerpickerContent();
337-
}
277+
public getStickerpickerContent(): JSX.Element {
278+
return this.renderStickerpickerWidget("popover");
279+
}
338280

281+
public getSidebarStickerpickerContent(): JSX.Element {
339282
if (!this.state.widgetStateLoaded) {
340283
return <div className="mx_Stickers_sidebar">{this.loadingStickerpickerContent()}</div>;
341284
}
342285

343-
const stickerApp = this.getStickerpickerApp();
344-
if (stickerApp) {
345-
return <div className="mx_Stickers_sidebar">{this.renderStickerpickerApp(stickerApp, true)}</div>;
286+
if (this.state.imError) {
287+
return this.errorStickerpickerContent();
346288
}
347289

348-
return <div className="mx_Stickers_sidebarPlaceholder">{this.defaultStickerpickerContent()}</div>;
290+
return <div className="mx_Stickers_sidebar">{this.renderStickerpickerWidget("sidebar")}</div>;
349291
}
350292

351293
/**

0 commit comments

Comments
 (0)