Explorar o código

Create new observable component for MUC sidebar occupants

and lazy load the VCard
JC Brand hai 4 meses
pai
achega
48c9c41ba2
Modificáronse 80 ficheiros con 304 adicións e 216 borrados
  1. 2 3
      src/headless/plugins/muc/occupants.js
  2. 1 2
      src/headless/plugins/vcard/utils.js
  3. 4 0
      src/headless/shared/model-with-contact.js
  4. 1 16
      src/plugins/muc-views/occupants.js
  5. 53 0
      src/plugins/muc-views/sidebar-occupant.js
  6. 5 5
      src/plugins/muc-views/templates/muc-occupants.js
  7. 3 3
      src/plugins/muc-views/templates/occupant.js
  8. 5 5
      src/plugins/muc-views/tests/nickname.js
  9. 3 0
      src/plugins/profile/modals/profile.js
  10. 18 10
      src/plugins/profile/templates/profile_modal.js
  11. 1 1
      src/plugins/rosterview/tests/protocol.js
  12. 3 0
      src/plugins/rosterview/tests/roster.js
  13. 3 2
      src/shared/chat/message.js
  14. 1 1
      src/types/plugins/adhoc-views/adhoc-commands.d.ts
  15. 2 2
      src/types/plugins/bookmark-views/components/bookmarks-list.d.ts
  16. 2 2
      src/types/plugins/chatview/message-form.d.ts
  17. 1 1
      src/types/plugins/controlbox/controlbox.d.ts
  18. 2 2
      src/types/plugins/controlbox/loginform.d.ts
  19. 2 2
      src/types/plugins/controlbox/model.d.ts
  20. 1 1
      src/types/plugins/controlbox/utils.d.ts
  21. 4 4
      src/types/plugins/dragresize/utils.d.ts
  22. 1 1
      src/types/plugins/headlines-view/feed-list.d.ts
  23. 1 1
      src/types/plugins/headlines-view/view.d.ts
  24. 1 1
      src/types/plugins/minimize/utils.d.ts
  25. 2 2
      src/types/plugins/minimize/view.d.ts
  26. 1 1
      src/types/plugins/modal/api.d.ts
  27. 3 2
      src/types/plugins/modal/modal.d.ts
  28. 1 0
      src/types/plugins/muc-views/bottom-panel.d.ts
  29. 2 2
      src/types/plugins/muc-views/message-form.d.ts
  30. 1 1
      src/types/plugins/muc-views/modals/muc-list.d.ts
  31. 2 1
      src/types/plugins/muc-views/modtools.d.ts
  32. 1 1
      src/types/plugins/muc-views/occupant-bottom-panel.d.ts
  33. 1 1
      src/types/plugins/muc-views/occupant.d.ts
  34. 1 6
      src/types/plugins/muc-views/occupants.d.ts
  35. 25 0
      src/types/plugins/muc-views/sidebar-occupant.d.ts
  36. 1 1
      src/types/plugins/muc-views/templates/muc-bottom-panel.d.ts
  37. 1 1
      src/types/plugins/muc-views/templates/occupant.d.ts
  38. 1 1
      src/types/plugins/muc-views/utils.d.ts
  39. 1 1
      src/types/plugins/notifications/utils.d.ts
  40. 1 1
      src/types/plugins/omemo/device.d.ts
  41. 1 1
      src/types/plugins/omemo/devicelist.d.ts
  42. 1 1
      src/types/plugins/omemo/store.d.ts
  43. 1 5
      src/types/plugins/profile/modals/profile.d.ts
  44. 1 1
      src/types/plugins/profile/templates/profile_modal.d.ts
  45. 1 1
      src/types/plugins/push/utils.d.ts
  46. 6 6
      src/types/plugins/register/form.d.ts
  47. 1 1
      src/types/plugins/roomslist/model.d.ts
  48. 2 2
      src/types/plugins/roomslist/view.d.ts
  49. 5 5
      src/types/plugins/rosterview/rosterview.d.ts
  50. 2 2
      src/types/plugins/rosterview/utils.d.ts
  51. 7 7
      src/types/shared/autocomplete/autocomplete.d.ts
  52. 2 2
      src/types/shared/autocomplete/component.d.ts
  53. 3 3
      src/types/shared/chat/baseview.d.ts
  54. 2 2
      src/types/shared/chat/emoji-dropdown.d.ts
  55. 1 1
      src/types/shared/chat/emoji-picker-content.d.ts
  56. 5 5
      src/types/shared/chat/emoji-picker.d.ts
  57. 1 1
      src/types/shared/chat/message-body.d.ts
  58. 2 2
      src/types/shared/chat/message.d.ts
  59. 1 1
      src/types/shared/chat/toolbar.d.ts
  60. 2 2
      src/types/shared/chat/utils.d.ts
  61. 1 1
      src/types/shared/components/dropdown.d.ts
  62. 3 3
      src/types/shared/components/dropdownbase.d.ts
  63. 2 2
      src/types/shared/components/element.d.ts
  64. 4 4
      src/types/shared/components/gif.d.ts
  65. 1 1
      src/types/shared/components/image-picker.d.ts
  66. 1 1
      src/types/shared/components/list-filter.d.ts
  67. 1 1
      src/types/shared/components/observable.d.ts
  68. 9 9
      src/types/shared/components/split-resize.d.ts
  69. 4 4
      src/types/shared/directives/image.d.ts
  70. 5 5
      src/types/shared/dom-navigator.d.ts
  71. 8 8
      src/types/shared/gif/index.d.ts
  72. 1 0
      src/types/shared/modals/user-details.d.ts
  73. 1 1
      src/types/shared/texture/component.d.ts
  74. 2 2
      src/types/shared/texture/directive.d.ts
  75. 33 33
      src/types/shared/texture/texture.d.ts
  76. 1 1
      src/types/shared/texture/utils.d.ts
  77. 1 1
      src/types/templates/audio.d.ts
  78. 1 1
      src/types/templates/video.d.ts
  79. 1 0
      src/types/utils/html.d.ts
  80. 12 0
      src/utils/html.js

+ 2 - 3
src/headless/plugins/muc/occupants.js

@@ -162,10 +162,9 @@ class MUCOccupants extends Collection {
      * @returns {MUCOccupant}
      */
     getOwnOccupant () {
-        const bare_jid = _converse.session.get('bare_jid');
         return this.findOccupant({
-            'jid': bare_jid,
-            'occupant_id': this.chatroom.get('occupant_id')
+            jid: _converse.session.get('bare_jid'),
+            occupant_id: this.chatroom.get('occupant_id')
         });
     }
 }

+ 1 - 2
src/headless/plugins/vcard/utils.js

@@ -131,7 +131,7 @@ export async function getVCardForOccupant(occupant, create = true) {
         if (jid) {
             return vcards.get(jid) || (create ? vcards.create({ jid }) : null);
         } else {
-            log.warn(`Could not get VCard for occupant because no JID found!`);
+            log.debug(`Could not get VCard for occupant because no JID found!`);
             return null;
         }
     }
@@ -157,7 +157,6 @@ async function getVCardForMUCMessage(message, create = true) {
         if (jid) {
             return vcards.get(jid) || (create ? vcards.create({ jid }) : null);
         } else {
-            debugger;
             log.warn(`Could not get VCard for message because no JID found! msgid: ${message.get("msgid")}`);
             return null;
         }

+ 4 - 0
src/headless/shared/model-with-contact.js

@@ -50,6 +50,10 @@ export default function ModelWithContact(BaseModel) {
                     this.trigger('contact:change', changed);
                 });
 
+                this.listenTo(this.contact, 'vcard:change', (changed) => {
+                    this.trigger('contact:change', changed);
+                });
+
                 this.listenTo(this.contact, 'change', (changed) => {
                     if (changed.nickname) {
                         this.set('nickname', changed.nickname);

+ 1 - 16
src/plugins/muc-views/occupants.js

@@ -42,11 +42,9 @@ export default class MUCOccupants extends CustomElement {
 
         this.listenTo(this.model, 'change', () => this.requestUpdate());
         this.listenTo(this.model.occupants, 'add', debouncedRequestUpdate);
-        this.listenTo(this.model.occupants, 'remove', debouncedRequestUpdate);
         this.listenTo(this.model.occupants, 'change', debouncedRequestUpdate);
+        this.listenTo(this.model.occupants, 'remove', debouncedRequestUpdate);
         this.listenTo(this.model.occupants, 'sort', debouncedRequestUpdate);
-        this.listenTo(this.model.occupants, 'vcard:change', debouncedRequestUpdate);
-        this.listenTo(this.model.occupants, 'vcard:add', debouncedRequestUpdate);
         this.listenTo(this.model.features, 'change:open', () => this.requestUpdate());
 
         this.model.initialized.then(() => this.requestUpdate());
@@ -75,19 +73,6 @@ export default class MUCOccupants extends CustomElement {
         ev?.preventDefault?.();
         u.safeSave(this.model, { 'hidden_occupants': true });
     }
-
-    /**
-     * @param {MouseEvent} ev
-     * @param {import('@converse/headless/types/plugins/muc/occupant.js').default} occupant
-     */
-    onOccupantClicked (ev, occupant) {
-        ev.preventDefault();
-        if (this.model.getOwnOccupant() === occupant) {
-            api.modal.show('converse-profile-modal', {model: _converse.state.xmppstatus}, ev);
-        } else {
-            this.model.save({ 'sidebar_view': `occupant:${occupant.id}` })
-        }
-    }
 }
 
 api.elements.define('converse-muc-occupants', MUCOccupants);

+ 53 - 0
src/plugins/muc-views/sidebar-occupant.js

@@ -0,0 +1,53 @@
+import { Model } from "@converse/skeletor";
+import { MUC, _converse, api } from "@converse/headless";
+import { ObservableElement } from "shared/components/observable.js";
+import tplMUCOccupant from "./templates/occupant.js";
+import "./occupant-bottom-panel.js";
+
+export default class MUCOccupantListItem extends ObservableElement {
+    /**
+     * @typedef {import('shared/components/types').ObservableProperty} ObservableProperty
+     */
+
+    constructor() {
+        super();
+        this.muc = null;
+        this.observable = /** @type {ObservableProperty} */ ("once");
+    }
+
+    static get properties() {
+        return {
+            ...super.properties,
+            model: { type: Model },
+            muc: { type: MUC },
+        };
+    }
+
+    async initialize() {
+        super.initialize();
+        await this.muc.initialized;
+        this.listenTo(this.model, "change", () => this.requestUpdate());
+        this.listenTo(this.model, "vcard:add", () => this.requestUpdate());
+        this.listenTo(this.model, "vcard:change", () => this.requestUpdate());
+        this.requestUpdate();
+    }
+
+    render() {
+        return this.muc ? tplMUCOccupant(this) : "";
+    }
+
+    /**
+     * @param {MouseEvent} ev
+     * @param {import('@converse/headless/types/plugins/muc/occupant.js').default} occupant
+     */
+    onOccupantClicked(ev, occupant) {
+        ev.preventDefault();
+        if (this.muc.getOwnOccupant() === occupant) {
+            api.modal.show("converse-profile-modal", { model: _converse.state.xmppstatus }, ev);
+        } else {
+            this.muc.save({ sidebar_view: `occupant:${occupant.id}` });
+        }
+    }
+}
+
+api.elements.define("converse-muc-occupant-list-item", MUCOccupantListItem);

+ 5 - 5
src/plugins/muc-views/templates/muc-occupants.js

@@ -1,12 +1,12 @@
 /**
  * @typedef {import('@converse/headless').MUCOccupant} MUCOccupant
  */
-import 'shared/components/list-filter.js';
-import tplOccupant from "./occupant.js";
-import tplOccupantsFilter from './occupants-filter.js';
-import { __ } from 'i18n';
 import { html } from "lit";
 import { repeat } from 'lit/directives/repeat.js';
+import { __ } from 'i18n';
+import 'shared/components/list-filter.js';
+import './../sidebar-occupant.js';
+import tplOccupantsFilter from './occupants-filter.js';
 
 /**
  * @param {import('../occupants').default} el
@@ -109,7 +109,7 @@ export default (el) => {
                 ${repeat(
                     el.model.occupants.models,
                     (occ) => occ.get('jid'),
-                    (occ) => isOccupantFiltered(el, occ) ? '' : tplOccupant(el, occ)
+                    (occ) => isOccupantFiltered(el, occ) ? '' : html`<converse-muc-occupant-list-item .muc="${el.model}" .model="${occ}" />`
                 )}
             </ul>
         </div>

+ 3 - 3
src/plugins/muc-views/templates/occupant.js

@@ -146,10 +146,10 @@ async function tplActionButtons(o) {
 }
 
 /**
- * @param {import('../occupants').default} el
- * @param {MUCOccupant} o
+ * @param {import('../sidebar-occupant').default} el
  */
-export default (el, o) => {
+export default (el) => {
+    const o = el.model;
     const affiliation = o.get('affiliation');
     const hint_show = PRETTY_CHAT_STATUS[o.get('show')];
     const role = o.get('role');

+ 5 - 5
src/plugins/muc-views/tests/nickname.js

@@ -305,13 +305,13 @@ describe("A MUC", function () {
         }));
 
         it("will use the nickname set in the global settings if the user doesn't have a VCard nickname",
-                mock.initConverse(['chatBoxesFetched'], { nickname: 'Benedict-Cucumberpatch'},
-                async function (_converse) {
-
+            mock.initConverse(['chatBoxesFetched'], {
+                blacklisted_plugins: ['converse-vcard'],
+                nickname: 'Benedict-Cucumberpatch'
+            },
+        async function (_converse) {
             const { api } = _converse;
             const muc_jid = 'roomy@muc.montague.lit';
-            // Delete the VCard
-            delete _converse.state.xmppstatus.vcard;
             api.rooms.open(muc_jid);
             await mock.waitForMUCDiscoInfo(_converse, muc_jid);
             await mock.waitForReservedNick(_converse, muc_jid, '');

+ 3 - 0
src/plugins/profile/modals/profile.js

@@ -14,6 +14,9 @@ export default class ProfileModal extends BaseModal {
      * @typedef {import("@converse/headless").XMPPStatus} XMPPStatus
      */
 
+    /**
+     * @param {Object} options
+     */
     constructor (options) {
         super(options);
         this.tab = 'profile';

+ 18 - 10
src/plugins/profile/templates/profile_modal.js

@@ -4,14 +4,22 @@ import { _converse } from  "@converse/headless";
 import { html } from "lit";
 
 
-const tplOmemoPage = (el) => html`
-    <div class="tab-pane ${ el.tab === 'omemo' ? 'active' : ''}" id="omemo-tabpanel" role="tabpanel" aria-labelledby="omemo-tab">
-        ${ el.tab === 'omemo' ? html`<converse-omemo-profile></converse-omemo-profile>` : '' }
-    </div>`;
+/**
+ * @param {import('../modals/profile').default} el
+ */
+function tplOmemoPage(el) {
+    return html`
+        <div class="tab-pane ${ el.tab === 'omemo' ? 'active' : ''}" id="omemo-tabpanel" role="tabpanel" aria-labelledby="omemo-tab">
+            ${ el.tab === 'omemo' ? html`<converse-omemo-profile></converse-omemo-profile>` : '' }
+        </div>`;
+}
 
 
+/**
+ * @param {import('../modals/profile').default} el
+ */
 export default (el) => {
-    const o = { ...el.model.toJSON(), ...el.model.vcard.toJSON() };
+    const o = { ...el.model.toJSON(), ...el.model.vcard?.toJSON() };
     const i18n_email = __('Email');
     const i18n_fullname = __('Full Name');
     const i18n_jid = __('XMPP Address');
@@ -32,7 +40,7 @@ export default (el) => {
                href="#profile-tabpanel"
                aria-controls="profile-tabpanel"
                role="tab"
-               @click=${ev => el.switchTab(ev)}
+               @click="${ev => el.switchTab(ev)}"
                data-name="profile"
                data-toggle="tab">${ i18n_profile }</a>
             </li>`
@@ -40,12 +48,12 @@ export default (el) => {
 
     navigation_tabs.push(
         html`<li role="presentation" class="nav-item">
-                <a class="nav-link ${el.tab === "passwordreset" ? "active" : ""}"
+                <a class="nav-link ${el.tab === 'passwordreset' ? 'active' : ''}"
                 id="passwordreset-tab"
                 href="#passwordreset-tabpanel"
                 aria-controls="passwordreset-tabpanel"
                 role="tab"
-                @click=${ev => el.switchTab(ev)}
+                @click="${ev => el.switchTab(ev)}"
                 data-name="passwordreset"
                 data-toggle="tab">${ ii18n_reset_password }</a>
         </li>`
@@ -54,12 +62,12 @@ export default (el) => {
     if (_converse.pluggable.plugins['converse-omemo']?.enabled(_converse)) {
         navigation_tabs.push(
             html`<li role="presentation" class="nav-item">
-                <a class="nav-link ${el.tab === "omemo" ? "active" : ""}"
+                <a class="nav-link ${el.tab === 'omemo' ? 'active' : ''}"
                    id="omemo-tab"
                    href="#omemo-tabpanel"
                    aria-controls="omemo-tabpanel"
                    role="tab"
-                   @click=${ev => el.switchTab(ev)}
+                   @click="${ev => el.switchTab(ev)}"
                    data-name="omemo"
                    data-toggle="tab">${ i18n_omemo }</a>
             </li>`

+ 1 - 1
src/plugins/rosterview/tests/protocol.js

@@ -43,7 +43,7 @@ describe("Presence subscriptions", function () {
             let stanza;
             await mock.waitForRoster(_converse, 'current', 0);
             await mock.waitUntilDiscoConfirmed(_converse, 'montague.lit', [], ['vcard-temp']);
-            await u.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'), 300);
+            await u.waitUntil(() => _converse.xmppstatus.vcard?.get('fullname'), 300);
             /* The process by which a user subscribes to a contact, including
              * the interaction between roster items and subscription states.
              */

+ 3 - 0
src/plugins/rosterview/tests/roster.js

@@ -823,6 +823,7 @@ describe("The Contacts Roster", function () {
                 [], {},
                 async function (_converse) {
 
+            const { api } = _converse;
             await mock.waitForRoster(_converse, 'current', 0);
             await mock.openControlBox(_converse);
             const rosterview = document.querySelector('converse-roster');
@@ -836,6 +837,8 @@ describe("The Contacts Roster", function () {
                 return u.waitUntil(() => contact.initialized);
             }));
             await u.waitUntil(() => sizzle('li', rosterview).length);
+            await api.waitUntil('VCardsInitialized');
+
             // Check that they are sorted alphabetically
             const els = sizzle('.current-xmpp-contact.offline a.open-chat .contact-name', rosterview)
             const t = els.reduce((result, value) => (result + value.textContent.trim()), '');

+ 3 - 2
src/shared/chat/message.js

@@ -50,9 +50,10 @@ export default class Message extends CustomElement {
         this.listenTo(this.model_with_messages, 'change:first_unread_id', () => this.requestUpdate());
         this.listenTo(this.model, 'change', () => this.requestUpdate());
         this.listenTo(this.model, 'contact:change', () => this.requestUpdate());
-        this.listenTo(this.model, 'vcard:change', () => this.requestUpdate());
-        this.listenTo(this.model, 'occupant:change', () => this.requestUpdate());
         this.listenTo(this.model, 'occupant:add', () => this.requestUpdate());
+        this.listenTo(this.model, 'occupant:change', () => this.requestUpdate());
+        this.listenTo(this.model, 'vcard:add',  () => this.requestUpdate());
+        this.listenTo(this.model, 'vcard:change', () => this.requestUpdate());
         this.requestUpdate();
     }
 

+ 1 - 1
src/types/plugins/adhoc-views/adhoc-commands.d.ts

@@ -32,7 +32,7 @@ export default class AdHocCommands extends CustomElement {
      * @param {SubmitEvent} ev
      */
     fetchCommands(ev: SubmitEvent): Promise<void>;
-    alert_type: string;
+    alert_type: string | undefined;
     alert: any;
     /**
      * @param {MouseEvent} ev

+ 2 - 2
src/types/plugins/bookmark-views/components/bookmarks-list.d.ts

@@ -1,7 +1,7 @@
 export default class BookmarksView extends CustomElement {
     initialize(): Promise<void>;
-    liveFilter: import("lodash").DebouncedFunc<(ev: any) => false | Model>;
-    model: Model;
+    liveFilter: import("lodash").DebouncedFunc<(ev: any) => false | Model> | undefined;
+    model: Model | undefined;
     render(): import("lit").TemplateResult<1>;
     /**
      * @param {Event} ev

+ 2 - 2
src/types/plugins/chatview/message-form.d.ts

@@ -6,7 +6,7 @@ export default class MessageForm extends CustomElement {
     };
     model: any;
     initialize(): Promise<void>;
-    handleEmojiSelection: ({ detail }: CustomEvent) => void;
+    handleEmojiSelection: (({ detail }: CustomEvent) => void) | undefined;
     render(): import("lit").TemplateResult<1>;
     /**
      * Insert a particular string value into the textarea of this chat box.
@@ -18,7 +18,7 @@ export default class MessageForm extends CustomElement {
      * @param { number } [position] - The end index of the string to be
      *  replaced with the new value.
      */
-    insertIntoTextArea(value: string, replace?: (boolean | string), correcting?: boolean, position?: number, separator?: string): void;
+    insertIntoTextArea(value: string, replace?: string | boolean | undefined, correcting?: boolean, position?: number | undefined, separator?: string): void;
     onMessageCorrecting(message: any): void;
     onEscapePressed(ev: any): void;
     onPaste(ev: any): void;

+ 1 - 1
src/types/plugins/controlbox/controlbox.d.ts

@@ -11,7 +11,7 @@ declare class ControlBoxView extends CustomElement {
     setModel(): void;
     model: any;
     render(): import("lit").TemplateResult<1> | "";
-    close(ev: any): this;
+    close(ev: any): this | undefined;
     afterShown(): this;
 }
 import { CustomElement } from 'shared/components/element.js';

+ 2 - 2
src/types/plugins/controlbox/loginform.d.ts

@@ -1,7 +1,7 @@
 export default LoginForm;
 declare class LoginForm extends CustomElement {
     initialize(): void;
-    handler: () => void;
+    handler: (() => void) | undefined;
     connectedCallback(): void;
     render(): import("lit").TemplateResult<1>;
     firstUpdated(): void;
@@ -17,7 +17,7 @@ declare class LoginForm extends CustomElement {
     /**
      * @param {string} [jid]
      */
-    connect(jid?: string): void;
+    connect(jid?: string | undefined): void;
 }
 import { CustomElement } from 'shared/components/element.js';
 //# sourceMappingURL=loginform.d.ts.map

+ 2 - 2
src/types/plugins/controlbox/model.d.ts

@@ -10,7 +10,7 @@ declare class ControlBox extends Model {
     defaults(): {
         bookmarked: boolean;
         box_id: string;
-        chat_state: any;
+        chat_state: undefined;
         closed: boolean;
         num_unread: number;
         time_opened: any;
@@ -21,7 +21,7 @@ declare class ControlBox extends Model {
     /**
      * @param {boolean} [force]
      */
-    maybeShow(force?: boolean): any;
+    maybeShow(force?: boolean | undefined): any;
     onReconnection(): void;
 }
 import { Model } from '@converse/skeletor';

+ 1 - 1
src/types/plugins/controlbox/utils.d.ts

@@ -2,7 +2,7 @@ export function addControlBox(): any;
 /**
  * @param {Event} [ev]
  */
-export function showControlBox(ev?: Event): void;
+export function showControlBox(ev?: Event | undefined): void;
 /**
  * @param {string} jid
  */

+ 4 - 4
src/types/plugins/dragresize/utils.d.ts

@@ -15,8 +15,8 @@ export function initializeDragResize(model: import("@converse/headless/types/sha
  * @returns {string}
  */
 export function getResizingDirection(): string;
-export function onStartVerticalResize(ev: any, trigger?: boolean): boolean;
-export function onStartHorizontalResize(ev: any, trigger?: boolean): boolean;
+export function onStartVerticalResize(ev: any, trigger?: boolean): true | undefined;
+export function onStartHorizontalResize(ev: any, trigger?: boolean): true | undefined;
 export function onStartDiagonalResize(ev: any): void;
 /**
  * Applies some resistance to `value` around the `default_value`.
@@ -27,8 +27,8 @@ export function onStartDiagonalResize(ev: any): void;
  * @returns { number }
  */
 export function applyDragResistance(value: number, default_value: number): number;
-export function onMouseMove(ev: any): boolean;
-export function onMouseUp(ev: any): boolean;
+export function onMouseMove(ev: any): true | undefined;
+export function onMouseUp(ev: any): true | undefined;
 export type ResizingData = {
     chatbox: HTMLElement;
     direction: string;

+ 1 - 1
src/types/plugins/headlines-view/feed-list.d.ts

@@ -8,7 +8,7 @@ export class HeadlinesFeedsList extends CustomElement {
     initialize(): void;
     model: any;
     render(): import("lit").TemplateResult<1>;
-    renderIfHeadline(model: any): void;
+    renderIfHeadline(model: any): false | void;
     openHeadline(ev: any): Promise<void>;
 }
 import { CustomElement } from 'shared/components/element.js';

+ 1 - 1
src/types/plugins/headlines-view/view.d.ts

@@ -6,7 +6,7 @@ declare class HeadlinesFeedView extends BaseChatView {
      * @param {Event} ev
      */
     close(ev: Event): Promise<this>;
-    getNotifications(): any[];
+    getNotifications(): never[];
     afterShown(): void;
 }
 import BaseChatView from 'shared/chat/baseview.js';

+ 1 - 1
src/types/plugins/minimize/utils.d.ts

@@ -9,7 +9,7 @@ export function initializeChat(chat: ChatBox | MUC): void;
  * to create space.
  * @param {ChatView|MUCView|ControlBoxView|HeadlinesFeedView} [newchat]
  */
-export function trimChats(newchat?: ChatView | MUCView | ControlBoxView | HeadlinesFeedView): void;
+export function trimChats(newchat?: import("plugins/chatview/chat").default | import("plugins/muc-views/muc").default | import("plugins/controlbox/controlbox").default | import("plugins/headlines-view/view").default | undefined): void;
 export function addMinimizeButtonToChat(view: any, buttons: any): any[];
 export function addMinimizeButtonToMUC(view: any, buttons: any): any[];
 export function maximize(ev: any, chatbox: any): void;

+ 2 - 2
src/types/plugins/minimize/view.d.ts

@@ -3,11 +3,11 @@ export default class MinimizedChats extends CustomElement {
     model: any;
     render(): import("lit").TemplateResult<1>;
     initToggle(): Promise<void>;
-    minchats: MinimizedChatsToggle;
+    minchats: MinimizedChatsToggle | undefined;
     /**
      * @param {Event} [ev]
      */
-    toggle(ev?: Event): void;
+    toggle(ev?: Event | undefined): void;
 }
 import { CustomElement } from 'shared/components/element';
 import MinimizedChatsToggle from './toggle.js';

+ 1 - 1
src/types/plugins/modal/api.d.ts

@@ -9,7 +9,7 @@ declare namespace modal_api {
          * @param {Object} [properties] - Optional properties that will be set on a newly created modal instance.
          * @param {Event} [ev] - The DOM event that causes the modal to be shown.
          */
-        function show(name: string | any, properties?: any, ev?: Event): any;
+        function show(name: string | any, properties?: any, ev?: Event | undefined): any;
         /**
          * Return a modal with the passed-in identifier, if it exists.
          * @param { String } id

+ 3 - 2
src/types/plugins/modal/modal.d.ts

@@ -13,6 +13,7 @@ declare class BaseModal extends CustomElement {
      */
     constructor(options: any);
     model: any;
+    ariaHidden: string;
     initialized: any;
     get modal(): Modal;
     initialize(): void;
@@ -32,8 +33,8 @@ declare class BaseModal extends CustomElement {
     /**
      * @param {Event} [ev]
      */
-    switchTab(ev?: Event): void;
-    tab: string;
+    switchTab(ev?: Event | undefined): void;
+    tab: string | null | undefined;
     close(): void;
     insertIntoDOM(): void;
     /**

+ 1 - 0
src/types/plugins/muc-views/bottom-panel.d.ts

@@ -1,4 +1,5 @@
 export default class MUCBottomPanel extends BottomPanel {
+    render(): import("lit").TemplateResult<1> | "" | undefined;
     renderIfOwnOccupant(o: any): void;
 }
 import BottomPanel from 'plugins/chatview/bottom-panel.js';

+ 2 - 2
src/types/plugins/muc-views/message-form.d.ts

@@ -1,8 +1,8 @@
 export default class MUCMessageForm extends MessageForm {
     shouldAutoComplete(): boolean;
     initMentionAutoComplete(): void;
-    mention_auto_complete: AutoComplete;
-    auto_completing: boolean;
+    mention_auto_complete: AutoComplete | undefined;
+    auto_completing: boolean | undefined;
     getAutoCompleteList(): any;
     /**
      * @param {Event} ev

+ 1 - 1
src/types/plugins/muc-views/modals/muc-list.d.ts

@@ -13,7 +13,7 @@ export default class MUCListModal extends BaseModal {
      * @method _converse.ChatRoomView#onRoomsFound
      * @param {HTMLElement} [iq]
      */
-    onRoomsFound(iq?: HTMLElement): boolean;
+    onRoomsFound(iq?: HTMLElement | undefined): boolean;
     /**
      * Send an IQ stanza to the server asking for all groupchats
      * @private

+ 2 - 1
src/types/plugins/muc-views/modtools.d.ts

@@ -45,6 +45,7 @@ export default class ModeratorTools extends CustomElement {
     tab: string;
     affiliation: any;
     affiliations_filter: string;
+    role: string;
     roles_filter: string;
     updated(changed: any): void;
     initialize(): Promise<void>;
@@ -53,7 +54,7 @@ export default class ModeratorTools extends CustomElement {
     render(): import("lit").TemplateResult<1> | "";
     switchTab(ev: any): void;
     onSearchAffiliationChange(): Promise<void>;
-    loading_users_with_affiliation: boolean;
+    loading_users_with_affiliation: boolean | undefined;
     users_with_affiliation: any;
     onSearchRoleChange(): Promise<void>;
     users_with_role: any;

+ 1 - 1
src/types/plugins/muc-views/occupant-bottom-panel.d.ts

@@ -9,7 +9,7 @@ export default class OccupantBottomPanel extends BottomPanel {
         };
     };
     muc: any;
-    canPostMessages(): boolean;
+    canPostMessages(): any;
     openChat(): any;
     invite(): any;
 }

+ 1 - 1
src/types/plugins/muc-views/occupant.d.ts

@@ -19,7 +19,7 @@ export default class MUCOccupant extends CustomElement {
     openChat(jid: string): void;
     closeSidebar(): void;
     /** @param {MouseEvent} [ev] */
-    showOccupantModal(ev?: MouseEvent): void;
+    showOccupantModal(ev?: MouseEvent | undefined): void;
     getVcard(): any;
     addToContacts(): void;
     /**

+ 1 - 6
src/types/plugins/muc-views/occupants.d.ts

@@ -6,7 +6,7 @@ export default class MUCOccupants extends CustomElement {
     };
     jid: any;
     initialize(): void;
-    filter: RosterFilter;
+    filter: RosterFilter | undefined;
     model: any;
     render(): import("lit").TemplateResult<1>;
     /**
@@ -17,11 +17,6 @@ export default class MUCOccupants extends CustomElement {
     toggleFilter(ev: MouseEvent): void;
     /** @param {MouseEvent} ev */
     closeSidebar(ev: MouseEvent): void;
-    /**
-     * @param {MouseEvent} ev
-     * @param {import('@converse/headless/types/plugins/muc/occupant.js').default} occupant
-     */
-    onOccupantClicked(ev: MouseEvent, occupant: import("@converse/headless/types/plugins/muc/occupant.js").default): void;
 }
 import { CustomElement } from 'shared/components/element.js';
 import { RosterFilter } from "@converse/headless";

+ 25 - 0
src/types/plugins/muc-views/sidebar-occupant.d.ts

@@ -0,0 +1,25 @@
+export default class MUCOccupantListItem extends ObservableElement {
+    static get properties(): {
+        model: {
+            type: typeof Model;
+        };
+        muc: {
+            type: typeof MUC;
+        };
+        observable: {
+            type: StringConstructor;
+        };
+    };
+    muc: any;
+    initialize(): Promise<void>;
+    render(): import("lit").TemplateResult<1> | "";
+    /**
+     * @param {MouseEvent} ev
+     * @param {import('@converse/headless/types/plugins/muc/occupant.js').default} occupant
+     */
+    onOccupantClicked(ev: MouseEvent, occupant: import("@converse/headless/types/plugins/muc/occupant.js").default): void;
+}
+import { ObservableElement } from "shared/components/observable.js";
+import { Model } from "@converse/skeletor";
+import { MUC } from "@converse/headless";
+//# sourceMappingURL=sidebar-occupant.d.ts.map

+ 1 - 1
src/types/plugins/muc-views/templates/muc-bottom-panel.d.ts

@@ -1,3 +1,3 @@
-declare function _default(el: import("../bottom-panel").default): import("lit").TemplateResult<1> | "";
+declare function _default(el: import("../bottom-panel").default): import("lit").TemplateResult<1> | "" | undefined;
 export default _default;
 //# sourceMappingURL=muc-bottom-panel.d.ts.map

+ 1 - 1
src/types/plugins/muc-views/templates/occupant.d.ts

@@ -1,4 +1,4 @@
-declare function _default(el: import("../occupants").default, o: MUCOccupant): import("lit").TemplateResult<1>;
+declare function _default(el: import("../sidebar-occupant").default): import("lit").TemplateResult<1>;
 export default _default;
 export type MUCOccupant = import("@converse/headless").MUCOccupant;
 //# sourceMappingURL=occupant.d.ts.map

+ 1 - 1
src/types/plugins/muc-views/utils.d.ts

@@ -36,7 +36,7 @@ export function getAutoCompleteList(): Promise<any[]>;
  * @param {MUC} muc
  * @param {string} [affiliation]
  */
-export function showModeratorToolsModal(muc: MUC, affiliation?: string): void;
+export function showModeratorToolsModal(muc: MUC, affiliation?: string | undefined): void;
 export function showOccupantModal(ev: any, occupant: any): void;
 export function parseMessageForMUCCommands(data: any, handled: any): any;
 export type MUC = import("@converse/headless/types/plugins/muc/muc.js").default;

+ 1 - 1
src/types/plugins/notifications/utils.d.ts

@@ -15,7 +15,7 @@ export function showFeedbackNotification(data: any): void;
  * Event handler for the on('message') event. Will call methods
  * to play sounds and show HTML5 notifications.
  */
-export function handleMessageNotification(data: any): Promise<boolean>;
+export function handleMessageNotification(data: any): Promise<false | undefined>;
 export function handleFeedback(data: any): void;
 /**
  * Event handler for on('contactPresenceChanged').

+ 1 - 1
src/types/plugins/omemo/device.d.ts

@@ -17,7 +17,7 @@ declare class Device extends Model {
             signature: any;
         };
         prekeys: any;
-    }>;
+    } | null>;
     /**
      * Fetch and save the bundle information associated with
      * this device, if the information is not cached already.

+ 1 - 1
src/types/plugins/omemo/devicelist.d.ts

@@ -10,7 +10,7 @@ declare class DeviceList extends Model {
     devices: any;
     onDevicesFound(collection: any): Promise<void>;
     fetchDevices(): Promise<any>;
-    _devices_promise: Promise<any>;
+    _devices_promise: Promise<any> | undefined;
     getOwnDeviceId(): Promise<any>;
     publishCurrentDevice(device_ids: any): Promise<any>;
     fetchDevicesFromServer(): Promise<any[]>;

+ 1 - 1
src/types/plugins/omemo/store.d.ts

@@ -53,7 +53,7 @@ declare class OMEMOStore extends Model {
      */
     generateBundle(): Promise<void>;
     fetchSession(): Promise<any>;
-    _setup_promise: Promise<any>;
+    _setup_promise: Promise<any> | undefined;
 }
 import { Model } from '@converse/skeletor';
 //# sourceMappingURL=store.d.ts.map

+ 1 - 5
src/types/plugins/profile/modals/profile.d.ts

@@ -1,9 +1,5 @@
 export default class ProfileModal extends BaseModal {
-    /**
-     * @typedef {import('@converse/headless/types/plugins/vcard/api').VCardData} VCardData
-     * @typedef {import("@converse/headless").XMPPStatus} XMPPStatus
-     */
-    constructor(options: any);
+    tab: string;
     renderModal(): import("lit").TemplateResult<1>;
     getModalTitle(): any;
     /**

+ 1 - 1
src/types/plugins/profile/templates/profile_modal.d.ts

@@ -1,3 +1,3 @@
-declare function _default(el: any): import("lit").TemplateResult<1>;
+declare function _default(el: import("../modals/profile").default): import("lit").TemplateResult<1>;
 export default _default;
 //# sourceMappingURL=profile_modal.d.ts.map

+ 1 - 1
src/types/plugins/push/utils.d.ts

@@ -1,6 +1,6 @@
 /**
  * @param {string} [domain]
  */
-export function enablePush(domain?: string): Promise<void>;
+export function enablePush(domain?: string | undefined): Promise<void>;
 export function onChatBoxAdded(model: any): void;
 //# sourceMappingURL=utils.d.ts.map

+ 6 - 6
src/types/plugins/register/form.d.ts

@@ -27,7 +27,7 @@ declare class RegistrationForm extends CustomElement {
     setErrorMessage: (m: string) => void;
     setFeedbackMessage: (m: string) => void;
     initialize(): void;
-    status: number;
+    status: number | undefined;
     render(): import("lit").TemplateResult<1>;
     /**
      * @param {string} message
@@ -40,14 +40,14 @@ declare class RegistrationForm extends CustomElement {
      * requesting the registration fields.
      */
     registerHooks(): void;
-    _registering: boolean;
+    _registering: boolean | undefined;
     /**
      * Send an IQ stanza to the XMPP server asking for the registration fields.
      * @method _converse.RegistrationForm#getRegistrationFields
      * @param {Request} req - The current request
      * @param {Function} callback - The callback function
      */
-    getRegistrationFields(req: import("strophe.js").Request, callback: Function): boolean;
+    getRegistrationFields(req: import("strophe.js").Request, callback: Function): boolean | undefined;
     /**
      * Handler for {@link _converse.RegistrationForm#getRegistrationFields}
      * @method _converse.RegistrationForm#onRegistrationFields
@@ -71,7 +71,7 @@ declare class RegistrationForm extends CustomElement {
      * @param {string} domain_name - XMPP server domain
      * @param {string|null} [service_url]
      */
-    fetchRegistrationForm(domain_name: string, service_url?: string | null): boolean;
+    fetchRegistrationForm(domain_name: string, service_url?: string | null | undefined): boolean;
     /**
      * Callback function called by Strophe whenever the connection status changes.
      * Passed to Strophe specifically during a registration attempt.
@@ -90,7 +90,7 @@ declare class RegistrationForm extends CustomElement {
      * @param {Element} stanza - The IQ stanza received from the XMPP server.
      */
     renderRegistrationForm(stanza: Element): void;
-    form_fields: any[];
+    form_fields: any[] | undefined;
     /**
      * Report back to the user any error messages received from the
      * XMPP server after attempted registration.
@@ -123,7 +123,7 @@ declare class RegistrationForm extends CustomElement {
      */
     setFieldsFromLegacy(query: Element): void;
     instructions: any;
-    form_type: string;
+    form_type: string | undefined;
     /**
      * @param {Element} xform
      */

+ 1 - 1
src/types/plugins/roomslist/model.d.ts

@@ -3,7 +3,7 @@ declare class RoomsListModel extends Model {
     defaults(): {
         muc_domain: any;
         toggle_state: "opened";
-        collapsed_domains: any[];
+        collapsed_domains: never[];
     };
     /**
      * @param {string} jid

+ 2 - 2
src/types/plugins/roomslist/view.d.ts

@@ -1,6 +1,6 @@
 export class RoomsList extends CustomElement {
     initialize(): void;
-    model: RoomsListModel;
+    model: RoomsListModel | undefined;
     render(): import("lit").TemplateResult<1>;
     /** @param {Model} model */
     renderIfChatRoom(model: Model): void;
@@ -11,7 +11,7 @@ export class RoomsList extends CustomElement {
     /** @param {Event} ev */
     closeRoom(ev: Event): Promise<void>;
     /** @param {Event} [ev] */
-    toggleRoomsList(ev?: Event): void;
+    toggleRoomsList(ev?: Event | undefined): void;
     /**
      * @param {Event} ev
      * @param {string} domain

+ 5 - 5
src/types/plugins/rosterview/rosterview.d.ts

@@ -5,19 +5,19 @@
  */
 export default class RosterView extends CustomElement {
     initialize(): Promise<void>;
-    model: Model;
+    model: Model | undefined;
     render(): import("lit").TemplateResult<1>;
     /** @param {MouseEvent} ev */
     showAddContactModal(ev: MouseEvent): void;
     /** @param {MouseEvent} ev */
     showNewChatModal(ev: MouseEvent): void;
     /** @param {MouseEvent} [ev] */
-    syncContacts(ev?: MouseEvent): Promise<void>;
-    syncing_contacts: boolean;
+    syncContacts(ev?: MouseEvent | undefined): Promise<void>;
+    syncing_contacts: boolean | undefined;
     /** @param {MouseEvent} [ev] */
-    toggleRoster(ev?: MouseEvent): void;
+    toggleRoster(ev?: MouseEvent | undefined): void;
     /** @param {MouseEvent} [ev] */
-    toggleFilter(ev?: MouseEvent): void;
+    toggleFilter(ev?: MouseEvent | undefined): void;
 }
 import { CustomElement } from 'shared/components/element.js';
 import { Model } from '@converse/skeletor';

+ 2 - 2
src/types/plugins/rosterview/utils.d.ts

@@ -3,7 +3,7 @@
  * @param {boolean} [unauthorize]
  * @returns {Promise<boolean>}
  */
-export function removeContact(contact: RosterContact, unauthorize?: boolean): Promise<boolean>;
+export function removeContact(contact: RosterContact, unauthorize?: boolean | undefined): Promise<boolean>;
 /**
  * @param {RosterContact} contact
  * @returns {Promise<boolean>}
@@ -58,7 +58,7 @@ export function contactsComparator(contact1: RosterContact | XMPPStatus, contact
  * @param {string} a
  * @param {string} b
  */
-export function groupsComparator(a: string, b: string): 0 | 1 | -1;
+export function groupsComparator(a: string, b: string): 0 | 1 | -1 | undefined;
 export function getGroupsAutoCompleteList(): any[];
 export function getJIDsAutoCompleteList(): any[];
 /**

+ 7 - 7
src/types/shared/autocomplete/autocomplete.d.ts

@@ -21,7 +21,7 @@ export class AutoComplete extends AutoComplete_base {
     is_opened: boolean;
     auto_evaluate: boolean;
     match_current_word: boolean;
-    sort: (a: any, b: any) => number;
+    sort: ((a: any, b: any) => number) | null;
     filter: (text: any, input: any) => boolean;
     ac_triggers: any[];
     include_triggers: any[];
@@ -30,10 +30,10 @@ export class AutoComplete extends AutoComplete_base {
     auto_first: boolean;
     data: (a: any, _v: any) => any;
     item: (text: any, input: any) => HTMLLIElement;
-    container: Element | HTMLElement;
+    container: Element | HTMLElement | null;
     input: HTMLInputElement;
-    ul: Element;
-    status: Element;
+    ul: Element | null;
+    status: Element | null;
     index: number;
     set list(list: any);
     get list(): any;
@@ -53,14 +53,14 @@ export class AutoComplete extends AutoComplete_base {
      */
     goto(i: number, scroll?: boolean): void;
     select(selected: any): void;
-    auto_completing: boolean;
+    auto_completing: boolean | undefined;
     onMouseOver(ev: any): void;
     onMouseDown(ev: any): void;
-    onKeyDown(ev: any): boolean;
+    onKeyDown(ev: any): true | undefined;
     /**
      * @param {KeyboardEvent} [ev]
      */
-    evaluate(ev?: KeyboardEvent): Promise<void>;
+    evaluate(ev?: KeyboardEvent | undefined): Promise<void>;
 }
 export default AutoComplete;
 //# sourceMappingURL=autocomplete.d.ts.map

+ 2 - 2
src/types/shared/autocomplete/component.d.ts

@@ -113,8 +113,8 @@ export default class AutoCompleteComponent extends CustomElement {
     value: string;
     render(): import("lit").TemplateResult<1>;
     firstUpdated(): void;
-    auto_complete: AutoComplete;
-    auto_completing: boolean;
+    auto_complete: AutoComplete | undefined;
+    auto_completing: boolean | undefined;
     /** @param {KeyboardEvent} ev */
     onKeyDown(ev: KeyboardEvent): void;
     /** @param {KeyboardEvent} ev */

+ 3 - 3
src/types/shared/chat/baseview.d.ts

@@ -10,8 +10,8 @@ export default class BaseChatView extends CustomElement {
     close(ev: any): any;
     maybeFocus(): void;
     focus(): this;
-    getBottomPanel(): Element;
-    getMessageForm(): Element;
+    getBottomPanel(): Element | null;
+    getMessageForm(): Element | null;
     /**
      * Scrolls the chat down.
      *
@@ -19,7 +19,7 @@ export default class BaseChatView extends CustomElement {
      * whether the user scrolled up manually or not.
      * @param { Event } [ev] - An optional event that is the cause for needing to scroll down.
      */
-    scrollDown(ev?: Event): void;
+    scrollDown(ev?: Event | undefined): void;
     onWindowStateChanged(): void;
 }
 export type Model = import("@converse/skeletor").Model;

+ 2 - 2
src/types/shared/chat/emoji-dropdown.d.ts

@@ -11,10 +11,10 @@ export default class EmojiDropdown extends DropdownBase {
         };
     };
     render_emojis: boolean;
-    state: EmojiPicker;
+    state: EmojiPicker | null;
     model: any;
     initModel(): Promise<void>;
-    init_promise: Promise<void>;
+    init_promise: Promise<void> | undefined;
     connectedCallback(): void;
     onShown(): Promise<void>;
 }

+ 1 - 1
src/types/shared/chat/emoji-picker-content.d.ts

@@ -20,7 +20,7 @@ export default class EmojiPickerContent extends CustomElement {
     render(): import("lit").TemplateResult<1>;
     firstUpdated(): void;
     initIntersectionObserver(): void;
-    observer: IntersectionObserver;
+    observer: IntersectionObserver | undefined;
     setCategoryOnVisibilityChange(entries: any): void;
     /**
      * @param {MouseEvent} ev

+ 5 - 5
src/types/shared/chat/emoji-picker.d.ts

@@ -29,7 +29,7 @@ export default class EmojiPicker extends CustomElement {
     _search_results: any[];
     debouncedFilter: import("lodash").DebouncedFunc<(input: HTMLInputElement) => any>;
     initialize(): void;
-    dropdown: Element;
+    dropdown: Element | null | undefined;
     firstUpdated(changed: any): void;
     set search_results(value: any[]);
     get search_results(): any[];
@@ -39,10 +39,10 @@ export default class EmojiPicker extends CustomElement {
     current_category: any;
     current_skintone: any;
     setScrollPosition(): void;
-    preserve_scroll: boolean;
-    updateSearchResults(changed: any): any[];
+    preserve_scroll: boolean | undefined;
+    updateSearchResults(changed: any): any[] | undefined;
     registerEvents(): void;
-    onGlobalKeyDown: (ev: any) => void;
+    onGlobalKeyDown: ((ev: any) => void) | undefined;
     connectedCallback(): void;
     onDropdownHide(): void;
     /**
@@ -74,7 +74,7 @@ export default class EmojiPicker extends CustomElement {
      */
     getTonedShortname(shortname: string): string;
     initArrowNavigation(): void;
-    navigator: DOMNavigator;
+    navigator: DOMNavigator | undefined;
     disableArrowNavigation(): void;
     /**
      * @param {KeyboardEvent} ev

+ 1 - 1
src/types/shared/chat/message-body.d.ts

@@ -21,7 +21,7 @@ export default class MessageBody extends CustomElement {
     onImgLoad(): void;
     render(): import("lit/directive").DirectiveResult<{
         new (_partInfo: import("lit/directive").PartInfo): {
-            render(text: string, offset: number, options: object, callback?: Function): import("lit").TemplateResult<1>;
+            render(text: string, offset: number, options: object, callback?: Function | undefined): import("lit").TemplateResult<1>;
             readonly _$isConnected: boolean;
             update(_part: import("lit").Part, props: Array<unknown>): unknown;
         };

+ 2 - 2
src/types/shared/chat/message.d.ts

@@ -17,10 +17,10 @@ export default class Message extends CustomElement {
     renderInfoMessage(): import("lit").TemplateResult<1>;
     renderFileProgress(): import("lit").TemplateResult<1> | "";
     renderChatMessage(): import("lit").TemplateResult<1>;
-    shouldShowAvatar(): boolean;
+    shouldShowAvatar(): any;
     onUnfurlAnimationEnd(): void;
     onRetryClicked(): Promise<void>;
-    show_spinner: boolean;
+    show_spinner: boolean | undefined;
     hasMentions(): any;
     getOccupantAffiliation(): any;
     getOccupantRole(): any;

+ 1 - 1
src/types/shared/chat/toolbar.d.ts

@@ -40,7 +40,7 @@ export class ChatToolbar extends CustomElement {
      * @param {boolean} is_supported
      */
     getHTTPUploadButton(is_supported: boolean): import("lit").TemplateResult<1> | "";
-    getSpoilerButton(): import("lit").TemplateResult<1>;
+    getSpoilerButton(): import("lit").TemplateResult<1> | undefined;
     /** @param {MouseEvent} ev */
     toggleFileUpload(ev: MouseEvent): void;
     /** @param {InputEvent} ev */

+ 2 - 2
src/types/shared/chat/utils.d.ts

@@ -86,8 +86,8 @@ export function shortnamesToEmojis(str: string, options?: {
  */
 export const markScrolled: import("lodash").DebouncedFunc<(ev: Event) => void>;
 export type EmojiMarkupOptions = {
-    unicode_only?: boolean;
-    add_title_wrapper?: boolean;
+    unicode_only?: boolean | undefined;
+    add_title_wrapper?: boolean | undefined;
 };
 export type HeadingButtonAttributes = import("plugins/chatview/types").HeadingButtonAttributes;
 export type ChatView = import("../../plugins/chatview/chat.js").default;

+ 1 - 1
src/types/shared/components/dropdown.d.ts

@@ -13,7 +13,7 @@ export default class Dropdown extends DropdownBase {
     firstUpdated(): void;
     onHidden(): void;
     initArrowNavigation(): void;
-    navigator: DOMNavigator;
+    navigator: DOMNavigator | undefined;
     enableArrowNavigation(ev: any): void;
     handleKeyUp(ev: any): void;
 }

+ 3 - 3
src/types/shared/components/dropdownbase.d.ts

@@ -1,8 +1,8 @@
 export default class DropdownBase extends CustomElement {
     firstUpdated(changed: any): void;
-    menu: Element;
-    button: HTMLButtonElement;
-    dropdown: BootstrapDropdown;
+    menu: Element | null | undefined;
+    button: HTMLButtonElement | null | undefined;
+    dropdown: BootstrapDropdown | undefined;
 }
 import { CustomElement } from './element.js';
 import { Dropdown as BootstrapDropdown } from 'bootstrap';

+ 2 - 2
src/types/shared/components/element.d.ts

@@ -13,8 +13,8 @@ declare const CustomElement_base: (new (...args: any[]) => {
 }) & typeof LitElement;
 export class CustomElement extends CustomElement_base {
     createRenderRoot(): this;
-    initialize(): any;
-    connectedCallback(): any;
+    initialize(): null;
+    connectedCallback(): null;
 }
 import { LitElement } from 'lit';
 export {};

+ 4 - 4
src/types/shared/components/gif.d.ts

@@ -22,12 +22,12 @@ export default class ConverseGIFElement extends CustomElement {
     fallback: string;
     progress_color: any;
     initGIF(): void;
-    supergif: ConverseGif;
+    supergif: ConverseGif | undefined;
     updated(changed: any): void;
-    render(): string | import("utils/html.js").TemplateResult;
-    renderErrorFallback(): string | import("utils/html.js").TemplateResult;
+    render(): string | import("utils/html.js").TemplateResult | undefined;
+    renderErrorFallback(): string | import("utils/html.js").TemplateResult | undefined;
     setHover(): void;
-    hover_timeout: NodeJS.Timeout;
+    hover_timeout: NodeJS.Timeout | undefined;
     unsetHover(): void;
     onControlsClicked(ev: any): void;
 }

+ 1 - 1
src/types/shared/components/image-picker.d.ts

@@ -14,7 +14,7 @@ export default class ImagePicker extends CustomElement {
     width: any;
     height: any;
     data: Model;
-    nonce: string;
+    nonce: string | null | undefined;
     render(): import("lit").TemplateResult<1>;
     /**
      * @param {Event} ev

+ 1 - 1
src/types/shared/components/list-filter.d.ts

@@ -21,7 +21,7 @@ export default class ListFilter extends CustomElement {
     template: any;
     promise: Promise<void>;
     initialize(): void;
-    liveFilter: import("lodash").DebouncedFunc<(ev: any) => any>;
+    liveFilter: import("lodash").DebouncedFunc<(ev: any) => any> | undefined;
     render(): any;
     dispatchUpdateEvent(): void;
     /**

+ 1 - 1
src/types/shared/components/observable.d.ts

@@ -18,7 +18,7 @@ export class ObservableElement extends CustomElement {
     observableRatio: number;
     observableDelay: number;
     initIntersectionObserver(): void;
-    intersectionObserver: IntersectionObserver;
+    intersectionObserver: IntersectionObserver | undefined;
     /**
      * @param {IntersectionObserverEntry[]} entries
      */

+ 9 - 9
src/types/shared/components/split-resize.d.ts

@@ -27,7 +27,7 @@ export default class SplitResize extends CustomElement {
          * 5. Actually size the pair elements, insert gutters and attach event listeners.
          */
         move: (this: Window, ev: Event) => any;
-    };
+    } | null;
     render(): import("lit").TemplateResult<1>;
     /**
      * @param {Map<string, any>} changed
@@ -203,18 +203,18 @@ export default class SplitResize extends CustomElement {
      * @param {HTMLElement[]} els
      */
     setupSplit(els: HTMLElement[], options?: {}): void;
-    parent: HTMLElement;
-    minSizes: any[];
+    parent: HTMLElement | null | undefined;
+    minSizes: any[] | undefined;
     gutterSize: any;
     gutterAlign: any;
     dragInterval: any;
     direction: any;
     cursor: any;
-    dimension: string;
-    clientAxis: string;
-    position: string;
-    positionEnd: string;
-    clientSize: string;
+    dimension: string | undefined;
+    clientAxis: string | undefined;
+    position: string | undefined;
+    positionEnd: string | undefined;
+    clientSize: string | undefined;
     elements: {
         element: HTMLElement;
         size: any;
@@ -222,7 +222,7 @@ export default class SplitResize extends CustomElement {
         maxSize: any;
         snapOffset: any;
         i: number;
-    }[];
+    }[] | undefined;
     /**
      * @param {HTMLElement[]} els
      * @param {HTMLElement} el

+ 4 - 4
src/types/shared/directives/image.d.ts

@@ -7,7 +7,7 @@
  * @param { Function } onLoad - A callback function to be called once the image has loaded.
  * @param { Function } onClick - A callback function to be called once the image has been clicked.
  */
-export const renderImage: (src: string, href?: string, onLoad?: Function, onClick?: Function) => import("lit/async-directive.js").DirectiveResult<typeof ImageDirective>;
+export const renderImage: (src: string, href?: string | undefined, onLoad?: Function | undefined, onClick?: Function | undefined) => import("lit/async-directive.js").DirectiveResult<typeof ImageDirective>;
 declare class ImageDirective extends AsyncDirective {
     /**
      * @param {string} src - The source URL of the image.
@@ -16,7 +16,7 @@ declare class ImageDirective extends AsyncDirective {
      * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
      * @returns {import('lit').TemplateResult}
      */
-    render(src: string, href?: string, onLoad?: Function, onClick?: Function): import("lit").TemplateResult;
+    render(src: string, href?: string | undefined, onLoad?: Function | undefined, onClick?: Function | undefined): import("lit").TemplateResult;
     /**
      * @param {string} src - The source URL of the image.
      * @param {string} [href] - The optional hyperlink for the image.
@@ -24,7 +24,7 @@ declare class ImageDirective extends AsyncDirective {
      * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
      * @returns {import('lit').TemplateResult}
      */
-    renderImage(src: string, href?: string, onLoad?: Function, onClick?: Function): import("lit").TemplateResult;
+    renderImage(src: string, href?: string | undefined, onLoad?: Function | undefined, onClick?: Function | undefined): import("lit").TemplateResult;
     /**
      * Handles errors that occur during image loading.
      * @param {string} src - The source URL of the image that failed to load.
@@ -32,7 +32,7 @@ declare class ImageDirective extends AsyncDirective {
      * @param {Function} [onLoad] - Callback function to be called once the image has loaded.
      * @param {Function} [onClick] - Callback function to be called once the image has been clicked.
      */
-    onError(src: string, href?: string, onLoad?: Function, onClick?: Function): void;
+    onError(src: string, href?: string | undefined, onLoad?: Function | undefined, onClick?: Function | undefined): void;
 }
 import { AsyncDirective } from 'lit/async-directive.js';
 export {};

+ 5 - 5
src/types/shared/dom-navigator.d.ts

@@ -59,14 +59,14 @@ declare class DOMNavigator {
      */
     init(): void;
     selected: any;
-    keydownHandler: (event: any) => void;
-    elements: {};
-    keys: {};
+    keydownHandler: ((event: any) => void) | null | undefined;
+    elements: {} | undefined;
+    keys: {} | undefined;
     /**
      * Enable this navigator.
      */
     enable(): void;
-    enabled: boolean;
+    enabled: boolean | undefined;
     /**
      * Disable this navigator.
      */
@@ -85,7 +85,7 @@ declare class DOMNavigator {
      * @param {HTMLElement} el The DOM element to select.
      * @param {string} [direction] The direction.
      */
-    select(el: HTMLElement, direction?: string): void;
+    select(el: HTMLElement, direction?: string | undefined): void;
     /**
      * Remove the current selection
      */

+ 8 - 8
src/types/shared/gif/index.d.ts

@@ -17,21 +17,21 @@ export default class ConverseGif {
     constructor(el: import("lit").LitElement, opts: any);
     options: any;
     el: import("lit").LitElement;
-    gif_el: HTMLImageElement;
-    canvas: HTMLCanvasElement;
-    ctx: CanvasRenderingContext2D;
+    gif_el: HTMLImageElement | null;
+    canvas: HTMLCanvasElement | null;
+    ctx: CanvasRenderingContext2D | null;
     offscreenCanvas: HTMLCanvasElement;
     patchCanvas: HTMLCanvasElement;
     ctx_scaled: boolean;
     frames: any[];
-    load_error: boolean;
+    load_error: boolean | null;
     playing: any;
     frame_idx: number;
     iteration_count: number;
     start: any;
     hovering: any;
-    frameImageData: ImageData;
-    disposal_restore_from_idx: number;
+    frameImageData: ImageData | null;
+    disposal_restore_from_idx: number | null;
     initialize(): Promise<void>;
     initPlayer(): void;
     /**
@@ -83,7 +83,7 @@ export default class ConverseGif {
     } | {
         width: number;
         height: number;
-    };
+    } | undefined;
     lsd: {
         backgroundColorIndex: number;
         gct: {
@@ -95,7 +95,7 @@ export default class ConverseGif {
         height: number;
         width: number;
         pixelAspectRatio: number;
-    };
+    } | undefined;
     drawError(): void;
     showError(): void;
     manageDisposal(i: any): void;

+ 1 - 0
src/types/shared/modals/user-details.d.ts

@@ -1,5 +1,6 @@
 export default class UserDetailsModal extends BaseModal {
     constructor(options: any);
+    tab: string;
     addListeners(): void;
     /**
      * @param {Map<string, any>} changed

+ 1 - 1
src/types/shared/texture/component.d.ts

@@ -57,7 +57,7 @@ export default class Texture extends LitElement {
     show_me_message: boolean;
     render(): import("lit/directive.js").DirectiveResult<{
         new (_partInfo: import("lit/directive.js").PartInfo): {
-            render(text: string, offset: number, options: object, callback?: Function): import("lit").TemplateResult<1>;
+            render(text: string, offset: number, options: object, callback?: Function | undefined): import("lit").TemplateResult<1>;
             readonly _$isConnected: boolean;
             update(_part: import("lit").Part, props: Array<unknown>): unknown;
         };

+ 2 - 2
src/types/shared/texture/directive.d.ts

@@ -1,5 +1,5 @@
 export default renderTexture;
-declare const renderTexture: (text: string, offset: number, options: any, callback?: Function) => import("lit/directive.js").DirectiveResult<typeof TextureDirective>;
+declare const renderTexture: (text: string, offset: number, options: any, callback?: Function | undefined) => import("lit/directive.js").DirectiveResult<typeof TextureDirective>;
 declare class TextureDirective extends Directive {
     /**
      * @param {string} text
@@ -7,7 +7,7 @@ declare class TextureDirective extends Directive {
      * @param {object} options
      * @param {Function} [callback]
      */
-    render(text: string, offset: number, options: object, callback?: Function): import("lit").TemplateResult<1>;
+    render(text: string, offset: number, options: object, callback?: Function | undefined): import("lit").TemplateResult<1>;
 }
 import { Directive } from 'lit/directive.js';
 //# sourceMappingURL=directive.d.ts.map

+ 33 - 33
src/types/shared/texture/texture.d.ts

@@ -57,44 +57,44 @@ export class Texture extends String {
      * @typedef {module:headless-shared-parsers.MediaURLMetadata} MediaURLMetadata
      */
     constructor(text: string, offset?: number, options?: {
-        nick?: string;
-        render_styling?: boolean;
-        embed_audio?: boolean;
-        embed_videos?: boolean;
-        mentions?: any[];
-        media_urls?: any[];
-        show_images?: boolean;
-        show_me_message?: boolean;
-        onImgClick?: Function;
-        onImgLoad?: Function;
-        hide_media_urls?: boolean;
-    });
-    embed_audio: boolean;
-    embed_videos: boolean;
+        nick?: string | undefined;
+        render_styling?: boolean | undefined;
+        embed_audio?: boolean | undefined;
+        embed_videos?: boolean | undefined;
+        mentions?: any[] | undefined;
+        media_urls?: any[] | undefined;
+        show_images?: boolean | undefined;
+        show_me_message?: boolean | undefined;
+        onImgClick?: Function | undefined;
+        onImgLoad?: Function | undefined;
+        hide_media_urls?: boolean | undefined;
+    } | undefined);
+    embed_audio: boolean | undefined;
+    embed_videos: boolean | undefined;
     mentions: any[];
-    media_urls: any[];
-    nick: string;
+    media_urls: any[] | undefined;
+    nick: string | undefined;
     offset: number;
-    onImgClick: Function;
-    onImgLoad: Function;
+    onImgClick: Function | undefined;
+    onImgLoad: Function | undefined;
     options: {
-        nick?: string;
-        render_styling?: boolean;
-        embed_audio?: boolean;
-        embed_videos?: boolean;
-        mentions?: any[];
-        media_urls?: any[];
-        show_images?: boolean;
-        show_me_message?: boolean;
-        onImgClick?: Function;
-        onImgLoad?: Function;
-        hide_media_urls?: boolean;
+        nick?: string | undefined;
+        render_styling?: boolean | undefined;
+        embed_audio?: boolean | undefined;
+        embed_videos?: boolean | undefined;
+        mentions?: any[] | undefined;
+        media_urls?: any[] | undefined;
+        show_images?: boolean | undefined;
+        show_me_message?: boolean | undefined;
+        onImgClick?: Function | undefined;
+        onImgLoad?: Function | undefined;
+        hide_media_urls?: boolean | undefined;
     };
     payload: any[];
     references: any[];
-    render_styling: boolean;
-    show_images: boolean;
-    hide_media_urls: boolean;
+    render_styling: boolean | undefined;
+    show_images: boolean | undefined;
+    hide_media_urls: boolean | undefined;
     /**
      * @param {string} url - The URL to be checked
      * @param {'audio'|'image'|'video'} type - The type of media
@@ -173,6 +173,6 @@ export class Texture extends String {
      * instances to be rendered to the DOM.
      * @method Texture#marshall
      */
-    marshall(): any[];
+    marshall(): string;
 }
 //# sourceMappingURL=texture.d.ts.map

+ 1 - 1
src/types/shared/texture/utils.d.ts

@@ -28,7 +28,7 @@ export function tplMention(o: any): import("lit").TemplateResult<1>;
  * @param {number} i
  */
 export function getDirectiveAndLength(text: import("./texture").Texture, i: number): {
-    d: string;
+    d: string | null;
     length: number;
 } | {
     d?: undefined;

+ 1 - 1
src/types/templates/audio.d.ts

@@ -1,3 +1,3 @@
-declare function _default(url: string, hide_url?: boolean, title?: string): import("lit").TemplateResult<1>;
+declare function _default(url: string, hide_url?: boolean | undefined, title?: string | undefined): import("lit").TemplateResult<1>;
 export default _default;
 //# sourceMappingURL=audio.d.ts.map

+ 1 - 1
src/types/templates/video.d.ts

@@ -1,3 +1,3 @@
-declare function _default(url: string, hide_url?: boolean): import("lit").TemplateResult<1>;
+declare function _default(url: string, hide_url?: boolean | undefined): import("lit").TemplateResult<1>;
 export default _default;
 //# sourceMappingURL=video.d.ts.map

+ 1 - 0
src/types/utils/html.d.ts

@@ -78,6 +78,7 @@ export function xFormField2TemplateResult(xfield: import("@converse/headless/sha
  * @param {boolean} include_margin
  */
 export function getOuterWidth(el: HTMLElement, include_margin?: boolean): number;
+export function getRootElement(): any;
 export default u;
 export type TemplateResult = import("lit").TemplateResult;
 import { u } from '@converse/headless';

+ 12 - 0
src/utils/html.js

@@ -546,6 +546,16 @@ export function getOuterWidth (el, include_margin=false) {
     return width;
 }
 
+
+let root;
+
+export function getRootElement() {
+    if (!root) {
+        root = document.createElement("converse-root");
+    }
+    return root;
+}
+
 Object.assign(u, {
     addClass,
     ancestor,
@@ -555,6 +565,7 @@ Object.assign(u, {
     getNextElement,
     getOOBURLMarkup,
     getOuterWidth,
+    getRootElement,
     hasClass,
     hideElement,
     isEqualNode,
@@ -571,3 +582,4 @@ Object.assign(u, {
 });
 
 export default u;
+