File size: 3,204 Bytes
3f22414
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
 * <view-mode-controls> — segmented icon-button radio for the canvas view mode.
 *
 * Renders one button per mode; the currently-selected mode is marked with
 * `aria-pressed="true"`. Clicking a different button switches and emits
 * `mode-change` { detail: { mode } }.
 *
 * Mode keys: 'fit-width' | 'fit-height' | 'one-to-one'.
 */

const VIEW_MODES = [
  { key: 'fit-width',   label: 'Fit Width',   icon: 'fa-arrows-left-right' },
  { key: 'fit-height',  label: 'Fit Height',  icon: 'fa-arrows-up-down' },
  { key: 'one-to-one',  label: '1:1',         icon: 'fa-vector-square' },
];

class ViewModeControls extends HTMLElement {
  #mode = 'fit-width';

  connectedCallback() {
    this.#render();
    this.addEventListener('click', this.#onClick);
  }

  get mode() { return this.#mode; }
  set mode(value) {
    if (!VIEW_MODES.find(m => m.key === value)) return;
    if (this.#mode === value) return;
    this.#mode = value;
    this.#render();
  }

  #onClick = (e) => {
    const btn = e.target.closest('button[data-mode]');
    if (!btn) return;
    e.stopPropagation();
    if (btn.dataset.mode === this.#mode) return;
    this.#mode = btn.dataset.mode;
    this.#render();
    this.dispatchEvent(new CustomEvent('mode-change', { detail: { mode: this.#mode } }));
  };

  #render() {
    const buttons = VIEW_MODES.map(m => `
      <button type="button" class="secondary outline" data-mode="${m.key}"
              aria-pressed="${m.key === this.#mode}"
              title="${m.label}" aria-label="${m.label}">
        <i class="fas ${m.icon}"></i>
      </button>
    `).join('');
    this.innerHTML = `
      <style>
        view-mode-controls {
          display: inline-flex;
          vertical-align: middle;
        }
        view-mode-controls .vm-row {
          display: inline-flex;
          gap: 0;
        }
        view-mode-controls .vm-row > button {
          border-radius: 0;
        }
        view-mode-controls .vm-row > button:first-child {
          border-top-left-radius: var(--pico-border-radius);
          border-bottom-left-radius: var(--pico-border-radius);
        }
        view-mode-controls .vm-row > button:last-child {
          border-top-right-radius: var(--pico-border-radius);
          border-bottom-right-radius: var(--pico-border-radius);
        }
        view-mode-controls .vm-row > button:not(:first-child) {
          margin-left: -1px;
        }
        view-mode-controls button .fas {
          margin-right: 0 !important;
        }
        /* Pressed state: disable the host toolbar's mix-blend-mode trick and
           paint a solid filled background so the active mode is unambiguous
           against the surrounding outline buttons. */
        view-mode-controls button[aria-pressed="true"] {
          mix-blend-mode: normal !important;
          background: rgba(255, 255, 255, 0.22) !important;
          opacity: 1 !important;
          border-color: #fff !important;
          color: #fff !important;
          z-index: 1;
        }
      </style>
      <div class="vm-row" role="radiogroup" aria-label="View mode">
        ${buttons}
      </div>
    `;
  }
}

customElements.define('view-mode-controls', ViewModeControls);