RuntimeErrorFooter.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. const Spacer = require('./Spacer.js');
  2. const theme = require('../theme.js');
  3. /**
  4. * @typedef {Object} RuntimeErrorFooterProps
  5. * @property {string} [initialFocus]
  6. * @property {boolean} multiple
  7. * @property {function(MouseEvent): void} onClickCloseButton
  8. * @property {function(MouseEvent): void} onClickNextButton
  9. * @property {function(MouseEvent): void} onClickPrevButton
  10. */
  11. /**
  12. * A fixed footer that handles pagination of runtime errors.
  13. * @param {Document} document
  14. * @param {HTMLElement} root
  15. * @param {RuntimeErrorFooterProps} props
  16. * @returns {void}
  17. */
  18. function RuntimeErrorFooter(document, root, props) {
  19. const footer = document.createElement('div');
  20. footer.style.backgroundColor = '#' + theme.dimgrey;
  21. footer.style.bottom = '0';
  22. footer.style.boxShadow = '0 -1px 4px rgba(0, 0, 0, 0.3)';
  23. footer.style.height = '2.5rem';
  24. footer.style.left = '0';
  25. footer.style.right = '0';
  26. footer.style.lineHeight = '2.5rem';
  27. footer.style.paddingBottom = '0';
  28. footer.style.paddingBottom = 'env(safe-area-inset-bottom)';
  29. footer.style.position = 'fixed';
  30. footer.style.textAlign = 'center';
  31. footer.style.zIndex = '2';
  32. const BUTTON_CONFIGS = {
  33. prev: {
  34. id: 'prev',
  35. label: '◀ Prev',
  36. onClick: props.onClickPrevButton,
  37. },
  38. close: {
  39. id: 'close',
  40. label: '× Close',
  41. onClick: props.onClickCloseButton,
  42. },
  43. next: {
  44. id: 'next',
  45. label: 'Next ▶',
  46. onClick: props.onClickNextButton,
  47. },
  48. };
  49. let buttons = [BUTTON_CONFIGS.close];
  50. if (props.multiple) {
  51. buttons = [BUTTON_CONFIGS.prev, BUTTON_CONFIGS.close, BUTTON_CONFIGS.next];
  52. }
  53. /** @type {HTMLButtonElement | undefined} */
  54. let initialFocusButton;
  55. for (let i = 0; i < buttons.length; i += 1) {
  56. const buttonConfig = buttons[i];
  57. const button = document.createElement('button');
  58. button.id = buttonConfig.id;
  59. button.innerHTML = buttonConfig.label;
  60. button.tabIndex = 1;
  61. button.style.backgroundColor = '#' + theme.dimgrey;
  62. button.style.border = 'none';
  63. button.style.color = '#' + theme.white;
  64. button.style.cursor = 'pointer';
  65. button.style.fontSize = 'inherit';
  66. button.style.height = '100%';
  67. button.style.padding = '0.5rem 0.75rem';
  68. button.style.width = (100 / buttons.length).toString(10) + '%';
  69. button.addEventListener('click', buttonConfig.onClick);
  70. if (buttonConfig.id === props.initialFocus) {
  71. initialFocusButton = button;
  72. }
  73. footer.appendChild(button);
  74. }
  75. root.appendChild(footer);
  76. Spacer(document, root, { space: '2.5rem' });
  77. if (initialFocusButton) {
  78. initialFocusButton.focus();
  79. }
  80. }
  81. module.exports = RuntimeErrorFooter;