typescriptbotframeworkweb-chat

BotFramework-Webchat Middleware: set css class names


I'd like to add css class names depending on the card type to the corresponding html element.

I already did this by setting the [AdaptiveCard.customCssSelector] 1 attribute. E.g. you just need to add builder.card.customCssSelector = "ac-thumbnail"; in this line and the resulting html-block will contain class="ac-container ac-thumbnail".

However, I'd like to be independent of Botframework-Webchat updates and put this logic into a middleware. According to the BotFramework-Webchat docs it's possible to add attachmentMiddleware to the renderWebChat function and manipulate the html elements.
In fact I get activities and attachments, but I'm not able to manipulate html-blocks or add a css selector.

Here's my middleware code:

export const cardCssSelector = ({ dispatch }) => next => action => {
    if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
        const { activity } = action.payload;
         for (var index in activity.attachments) {       
            const card  = activity.attachments[index].content;
            if(card.tap && card.tap.value){
                card.customCssSelector = 'tap';
            }
        }
    }
    console.log(action);
    return next(action);
};

Of course this doesn't work, since the attachments don't have the customCssSelector attribute.


Solution

  • To do true custom styling of web chat, then a little hacking is required. Some things to note:

    First, create a store and filter on incoming activities, messages, and then on the ac-adaptiveCard class.

    const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => async action => {
      if(activity.type === 'message') {
        let aCards = document.body.getElementsByClassName('ac-adaptiveCard');
        let bCards = Object.values( aCards);
    
        for(let i = 0; i <= bCards.length - 1; i++) {
          if( cards[i].children[2] && cards[i].children[2].innerText && cards[ i ].children[ 2 ].innerText === 'Request Assistance') {
            cards[i].className += ' card-Adaptive'
          }
    
          if( cards[i].children[2] && cards[i].children[2].innerText && cards[ i ].children[ 2 ].innerText === 'Service details') {
            cards[i].className += ' card-Hero'
          }
        }
      }
    }
    

    I apply styling to the cards by assigned class.

    .card-Adaptive {
      background-color: black;
    }
    
    .card-Adaptive p {
      color: white;
    }
    
    .card-Hero {
      background-color: green;
    }
    

    I pass store as a parameter.

    window.ReactDOM.render(
      <ReactWebChat
        directLine={ directLine }
        store={store}
      />,
      document.getElementById( 'webchat' )
    );
    

    The adaptive card is black and the hero card is green.

    enter image description here