Skip to content

useHostStyles internals override each other #551

@Avcharov

Description

@Avcharov

Describe the bug
useHostStyles internally uses useHostStyleVariables() and useHostFonts()

Inside useHostStyleVariables and useHostFonts are assigning different callback to app.onhostcontextchanged which causes overriding while using both of methods together inside useHostStyles:

// useHostFonts
app.onhostcontextchanged = (params) => {
  if (params.styles?.css?.fonts) {
    applyHostFonts(params.styles.css.fonts);
  }
};

// useHostStyleVariables
app.onhostcontextchanged = (params) => {
  if (params.theme) {
    applyDocumentTheme(params.theme);
  }
  if (params.styles?.variables) {
    applyHostStyleVariables(params.styles.variables);
  }
};

// useHostStyles
export function useHostStyles(
  app: App | null,
  initialContext?: McpUiHostContext | null,
): void {
  useHostStyleVariables(app, initialContext);
  useHostFonts(app, initialContext);
}

Overriding happens due to onhostcontextchanged implementation which is based on setNotificationHandler.
typescript-sdk mentions that previous handlers will be overwritten:

  /**
     * Registers a handler to invoke when this protocol object receives a notification with the given method.
     *
     * Note that this will replace any previous notification handler for the same method.
     */
    setNotificationHandler<M extends NotificationMethod>(
        method: M,
        handler: (notification: NotificationTypeMap[M]) => void | Promise<void>
    )

To Reproduce
Steps to reproduce the behavior:
Try to track host style variables changes after using useHostStyles, it wont we tracked

Expected behavior
useHostStyles() works w/o overriding onhostcontextchanged callbacks

Proposal

  1. Instead of reusing useHostStyleVariables and useHostFonts inside useHostStyles just put all needed code into single callback and assign it to onhostcontextchanged.

OR

  1. Draft PR: feat: implement subscribe/unsubscribe methods for multiple event handlers #552
    Implement subscribe(eventName) / unsubscribe(eventName) methods for multiple handlers. Then useHostStyleVariables and useHostFonts would look like:
//useHostFonts
const unsubscribe = app.subscribe("hostcontextchanged", (params) => {
  if (params.styles?.css?.fonts) {
    applyHostFonts(params.styles.css.fonts);
  }
});

return unsubscribe;

//useHostStyleVariables
const unsubscribe = app.subscribe("hostcontextchanged", (params) => {
  if (params.theme) {
    applyDocumentTheme(params.theme);
  }
  if (params.styles?.variables) {
    applyHostStyleVariables(params.styles.variables);
  }
});

return unsubscribe;

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions