A Code outputs

A.1 Mastering {htmltools}

A.1.1 Shiny RPG rework

Final code expected in section 2.6.6:

rpgSelect <- function(inputId, label, choices, selected = NULL,
                      multiple = FALSE, size = NULL) {
  selectTag <- shiny::selectInput(
    inputId,
    label,
    choices,
    selected,
    multiple,
    selectize = FALSE,
    width = NULL,
    size
  )
  
  selectClass <- if (is.null(size)) { # add class
    "rpgui-dropdown"
  } else {
    "rpgui-list"
  }
  
  tagQuery(selectTag)$
    removeAttrs("class")$ # remove outer div class
    find(".control-label")$
    removeAttrs("class")$ # remove class from child label
    siblings()$ # go down to the div 
    children()$ # go down to the select tag
    addClass(selectClass)$ # add class to child select
    resetSelected()$# go back to div parent
    each(function(x, i) {
      x$children[[2]] <- x$children[[2]]$children
    })$ # replace div parent 
    allTags()
}

A.2 Case Study 2: Mobile development with Shiny

A.2.1 Reconstruct {shinyMobile}

The init.js code obtained in 23 is shown below.

$( document ).ready(function() {
  // collect all data elements stored in body
  let config = $(document).find('script[data-for="app"]');
  config = JSON.parse(config.html());

  // always erase existing root value just in case 
  // the user changes the root. This may be harmful
  config.root = '#app';
  
  // store app methods
  config.methods =  {
      toggleDarkTheme: function() {
        var self = this;
        var $html = self.$('html');
        $html.toggleClass('theme-dark');
      }
    };

  // create app instance
  app = new Framework7(config);

  // init main view
  let mainView = app.views.create('.view-main');
  
  // tapHold custom css
  if (config.hasOwnProperty('touch')) {
    if (config.touch.tapHold) {
      $('<style>')
        .prop('type', 'text/css')
        .html(
          `-moz-user-select: none;
          -webkit-user-select: none;
          user-select: none;`
        )
        .appendTo('head');
    }
  }

  let notification = app.notification.create({
    text: 'Hello, how are you?',
    on: {
      opened: function () {
        console.log('Notification opened');
      }
    }
  }).open();

  let otherMessage = app.notification.create({
    text: 'You look great!'
  });

  // equivalent to setTimeout ...
  app.utils.nextTick(function() {
    otherMessage.open();
  }, 1000);

  // taphold test
  $('#mybutton').on('taphold', function () {
    app.dialog.alert('Tap hold fired!');
  });

  // Set color theme
  if (config.hasOwnProperty('color')) {
    let color = config.color
    let colorCSS = app.utils.colorThemeCSSProperties(color);
    $('<style>')
      .prop('type', 'text/css')
      .html(`:root {
    --f7-theme-color:${colorCSS['--f7-theme-color']};
    --f7-theme-color-rgb:${colorCSS['--f7-theme-color-rgb']};
    --f7-theme-color-shade:${colorCSS['--f7-theme-color-shade']};
    --f7-theme-color-tint:${colorCSS['--f7-theme-color-tint']};
      }`)
      .appendTo('head');
  }

  // Filled theme
  if (!config.hasOwnProperty('filled')) config.filled = false;
  if (config.filled) {
    let filledCSS = `
      :root,
      :root.theme-dark,
      :root .theme-dark {
        --f7-bars-bg-color: var(--f7-theme-color);
        --f7-bars-bg-color-rgb: var(--f7-theme-color-rgb);
        --f7-bars-translucent-opacity: 0.9;
        --f7-bars-text-color: #fff;
        --f7-bars-link-color: #fff;
        --f7-navbar-subtitle-text-color: rgba(255,255,255,0.85);
        --f7-bars-border-color: transparent;
        --f7-tabbar-link-active-color: #fff;
        --f7-tabbar-link-inactive-color: rgba(255,255,255,0.54);
        --f7-sheet-border-color: transparent;
        --f7-tabbar-link-active-border-color: #fff;
      }
      .appbar,
      .navbar,
      .toolbar,
      .subnavbar,
      .calendar-header,
      .calendar-footer {
      --f7-touch-ripple-color: var(--f7-touch-ripple-white);
      --f7-link-highlight-color: var(--f7-link-highlight-white);
      --f7-button-text-color: #fff;
      --f7-button-pressed-bg-color: rgba(255,255,255,0.1);
      }
      .navbar-large-transparent,
      .navbar-large.navbar-transparent {
        --f7-navbar-large-title-text-color: #000;
      
        --r: 0;
        --g: 122;
        --b: 255;
        --progress: var(--f7-navbar-large-collapse-progress);
        --f7-bars-link-color: rgb(
          calc(var(--r) + (255 - var(--r)) * var(--progress)),
          calc(var(--g) + (255 - var(--g)) * var(--progress)),
          calc(var(--b) + (255 - var(--b)) * var(--progress))
        );
      }
      .theme-dark .navbar-large-transparent,
      .theme-dark .navbar-large.navbar-transparent {
        --f7-navbar-large-title-text-color: #fff;
    }`;
    
    $('<style>')
      .prop('type', 'text/css')
      .html(`${filledCSS}`)
      .appendTo('head');
  }

  // dark mode
  if (!config.hasOwnProperty('dark')) config.dark = false;
  if (config.dark) {
    app.methods.toggleDarkTheme();
  }
});

A.3 R + Shiny + React: welcome {reactR}

A.3.1 Introduction to {reactR}

A.3.1.1 Exercise 2

JSX code from section 27.2.7 may be found below.

import { reactShinyInput } from 'reactR';
// reactstrap components
import { Button } from 'reactstrap';

function ActionButton({configuration, value, setValue}) {
  let iconTag, btnCl, innerTag;
  if (...) {
    btnCl = 'btn-icon';
    innerTag = <>
      <span className="btn-inner--icon">
        <i className=... />
      </span>
      <span className="btn-inner--text">...</span>
    </>;
  } else {
    innerTag = configuration.label;
  }

  let outlined;
  if (...) {
    outlined = true;
  }

  return (
    <Button
      color={configuration.status}
      className=...
      outline=...
      size=...
      onClick={() => setValue(value + 1)}>
      {innerTag}
    </Button>
  );
}

reactShinyInput(
  '.action_button', 
  'reactstrapTest.action_button', 
  ActionButton
);