build: convert touch-bar to typescript (#24511)

This commit is contained in:
Samuel Attard 2020-07-16 11:37:38 -07:00 коммит произвёл GitHub
Родитель 3f37ff87d2
Коммит 4c3da359fc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 491 добавлений и 366 удалений

Просмотреть файл

@ -41,6 +41,10 @@ the button in the touch bar.
A `NativeImage` representing the button's current icon. Changing this value immediately updates the button A `NativeImage` representing the button's current icon. Changing this value immediately updates the button
in the touch bar. in the touch bar.
#### `touchBarButton.iconPosition`
A `String` - Can be `left`, `right` or `overlay`. Defaults to `overlay`.
#### `touchBarButton.enabled` #### `touchBarButton.enabled`
A `Boolean` representing whether the button is in an enabled state. A `Boolean` representing whether the button is in an enabled state.

Просмотреть файл

@ -49,3 +49,7 @@ updates the control in the touch bar. Updating deep properties inside this array
An `Integer` representing the currently selected segment. Changing this value immediately updates the control An `Integer` representing the currently selected segment. Changing this value immediately updates the control
in the touch bar. User interaction with the touch bar will update this value automatically. in the touch bar. User interaction with the touch bar will update this value automatically.
#### `touchBarSegmentedControl.mode`
A `String` representing the current selection mode of the control. Can be `single`, `multiple` or `buttons`.

Просмотреть файл

@ -11,3 +11,11 @@ Process: [Main](../tutorial/application-architecture.md#main-and-renderer-proces
* `small` - Small space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceSmall`. This is the default. * `small` - Small space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceSmall`. This is the default.
* `large` - Large space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceLarge`. * `large` - Large space between items. Maps to `NSTouchBarItemIdentifierFixedSpaceLarge`.
* `flexible` - Take up all available space. Maps to `NSTouchBarItemIdentifierFlexibleSpace`. * `flexible` - Take up all available space. Maps to `NSTouchBarItemIdentifierFlexibleSpace`.
### Instance Properties
The following properties are available on instances of `TouchBarSpacer`:
#### `touchBarSpacer.size`
A `String` representing the size of the spacer. Can be `small`, `large` or `flexible`.

Просмотреть файл

@ -217,7 +217,7 @@ auto_filenames = {
"lib/browser/api/screen.ts", "lib/browser/api/screen.ts",
"lib/browser/api/session.ts", "lib/browser/api/session.ts",
"lib/browser/api/system-preferences.ts", "lib/browser/api/system-preferences.ts",
"lib/browser/api/touch-bar.js", "lib/browser/api/touch-bar.ts",
"lib/browser/api/tray.ts", "lib/browser/api/tray.ts",
"lib/browser/api/view.ts", "lib/browser/api/view.ts",
"lib/browser/api/views/image-view.ts", "lib/browser/api/views/image-view.ts",

Просмотреть файл

@ -1,365 +0,0 @@
'use strict';
const { EventEmitter } = require('events');
let nextItemID = 1;
class TouchBar extends EventEmitter {
// Bind a touch bar to a window
static _setOnWindow (touchBar, window) {
if (window._touchBar != null) {
window._touchBar._removeFromWindow(window);
}
if (touchBar == null) {
window._setTouchBarItems([]);
return;
}
if (Array.isArray(touchBar)) {
touchBar = new TouchBar(touchBar);
}
touchBar._addToWindow(window);
}
constructor (options) {
super();
if (options == null) {
throw new Error('Must specify options object as first argument');
}
let { items, escapeItem } = options;
if (!Array.isArray(items)) {
items = [];
}
this.changeListener = (item) => {
this.emit('change', item.id, item.type);
};
this.windowListeners = {};
this.items = {};
this.ordereredItems = [];
this.escapeItem = escapeItem;
const registerItem = (item) => {
this.items[item.id] = item;
item.on('change', this.changeListener);
if (item.child instanceof TouchBar) {
item.child.ordereredItems.forEach(registerItem);
}
};
let hasOtherItemsProxy = false;
const idSet = new Set();
items.forEach((item) => {
if (!(item instanceof TouchBarItem)) {
throw new Error('Each item must be an instance of TouchBarItem');
}
if (item.type === 'other_items_proxy') {
if (!hasOtherItemsProxy) {
hasOtherItemsProxy = true;
} else {
throw new Error('Must only have one OtherItemsProxy per TouchBar');
}
}
if (!idSet.has(item.id)) {
idSet.add(item.id);
} else {
throw new Error('Cannot add a single instance of TouchBarItem multiple times in a TouchBar');
}
});
// register in separate loop after all items are validated
for (const item of items) {
this.ordereredItems.push(item);
registerItem(item);
}
}
set escapeItem (item) {
if (item != null && !(item instanceof TouchBarItem)) {
throw new Error('Escape item must be an instance of TouchBarItem');
}
if (this.escapeItem != null) {
this.escapeItem.removeListener('change', this.changeListener);
}
this._escapeItem = item;
if (this.escapeItem != null) {
this.escapeItem.on('change', this.changeListener);
}
this.emit('escape-item-change', item);
}
get escapeItem () {
return this._escapeItem;
}
_addToWindow (window) {
const { id } = window;
// Already added to window
if (Object.prototype.hasOwnProperty.call(this.windowListeners, id)) return;
window._touchBar = this;
const changeListener = (itemID) => {
window._refreshTouchBarItem(itemID);
};
this.on('change', changeListener);
const escapeItemListener = (item) => {
window._setEscapeTouchBarItem(item != null ? item : {});
};
this.on('escape-item-change', escapeItemListener);
const interactionListener = (event, itemID, details) => {
let item = this.items[itemID];
if (item == null && this.escapeItem != null && this.escapeItem.id === itemID) {
item = this.escapeItem;
}
if (item != null && item.onInteraction != null) {
item.onInteraction(details);
}
};
window.on('-touch-bar-interaction', interactionListener);
const removeListeners = () => {
this.removeListener('change', changeListener);
this.removeListener('escape-item-change', escapeItemListener);
window.removeListener('-touch-bar-interaction', interactionListener);
window.removeListener('closed', removeListeners);
window._touchBar = null;
delete this.windowListeners[id];
const unregisterItems = (items) => {
for (const item of items) {
item.removeListener('change', this.changeListener);
if (item.child instanceof TouchBar) {
unregisterItems(item.child.ordereredItems);
}
}
};
unregisterItems(this.ordereredItems);
if (this.escapeItem) {
this.escapeItem.removeListener('change', this.changeListener);
}
};
window.once('closed', removeListeners);
this.windowListeners[id] = removeListeners;
window._setTouchBarItems(this.ordereredItems);
escapeItemListener(this.escapeItem);
}
_removeFromWindow (window) {
const removeListeners = this.windowListeners[window.id];
if (removeListeners != null) removeListeners();
}
}
class TouchBarItem extends EventEmitter {
constructor () {
super();
this._addImmutableProperty('id', `${nextItemID++}`);
this._parents = [];
}
_addImmutableProperty (name, value) {
Object.defineProperty(this, name, {
get: function () {
return value;
},
set: function () {
throw new Error(`Cannot override property ${name}`);
},
enumerable: true,
configurable: false
});
}
_addLiveProperty (name, initialValue) {
const privateName = `_${name}`;
this[privateName] = initialValue;
Object.defineProperty(this, name, {
get: function () {
return this[privateName];
},
set: function (value) {
this[privateName] = value;
this.emit('change', this);
},
enumerable: true
});
}
_addParent (item) {
const existing = this._parents.some(test => test.id === item.id);
if (!existing) {
this._parents.push({
id: item.id,
type: item.type
});
}
}
}
TouchBar.TouchBarButton = class TouchBarButton extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'button');
this._addLiveProperty('label', config.label);
this._addLiveProperty('accessibilityLabel', config.accessibilityLabel);
this._addLiveProperty('backgroundColor', config.backgroundColor);
this._addLiveProperty('icon', config.icon);
this._addLiveProperty('iconPosition', config.iconPosition);
this._addLiveProperty('enabled', typeof config.enabled !== 'boolean' ? true : config.enabled);
if (typeof config.click === 'function') {
this._addImmutableProperty('onInteraction', () => {
config.click();
});
}
}
};
TouchBar.TouchBarColorPicker = class TouchBarColorPicker extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'colorpicker');
this._addLiveProperty('availableColors', config.availableColors);
this._addLiveProperty('selectedColor', config.selectedColor);
if (typeof config.change === 'function') {
this._addImmutableProperty('onInteraction', (details) => {
this._selectedColor = details.color;
config.change(details.color);
});
}
}
};
TouchBar.TouchBarGroup = class TouchBarGroup extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'group');
const defaultChild = (config.items instanceof TouchBar) ? config.items : new TouchBar(config.items);
this._addLiveProperty('child', defaultChild);
this.child.ordereredItems.forEach((item) => item._addParent(this));
}
};
TouchBar.TouchBarLabel = class TouchBarLabel extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'label');
this._addLiveProperty('label', config.label);
this._addLiveProperty('accessibilityLabel', config.accessibilityLabel);
this._addLiveProperty('textColor', config.textColor);
}
};
TouchBar.TouchBarPopover = class TouchBarPopover extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'popover');
this._addLiveProperty('label', config.label);
this._addLiveProperty('icon', config.icon);
this._addLiveProperty('showCloseButton', config.showCloseButton);
const defaultChild = (config.items instanceof TouchBar) ? config.items : new TouchBar(config.items);
this._addLiveProperty('child', defaultChild);
this.child.ordereredItems.forEach((item) => item._addParent(this));
}
};
TouchBar.TouchBarSlider = class TouchBarSlider extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'slider');
this._addLiveProperty('label', config.label);
this._addLiveProperty('minValue', config.minValue);
this._addLiveProperty('maxValue', config.maxValue);
this._addLiveProperty('value', config.value);
if (typeof config.change === 'function') {
this._addImmutableProperty('onInteraction', (details) => {
this._value = details.value;
config.change(details.value);
});
}
}
};
TouchBar.TouchBarSpacer = class TouchBarSpacer extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'spacer');
this._addImmutableProperty('size', config.size);
}
};
TouchBar.TouchBarSegmentedControl = class TouchBarSegmentedControl extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
this._addImmutableProperty('type', 'segmented_control');
this._addLiveProperty('segmentStyle', config.segmentStyle);
this._addLiveProperty('segments', config.segments || []);
this._addLiveProperty('selectedIndex', config.selectedIndex);
this._addLiveProperty('mode', config.mode);
if (typeof config.change === 'function') {
this._addImmutableProperty('onInteraction', (details) => {
this._selectedIndex = details.selectedIndex;
config.change(details.selectedIndex, details.isSelected);
});
}
}
};
TouchBar.TouchBarScrubber = class TouchBarScrubber extends TouchBarItem {
constructor (config) {
super();
if (config == null) config = {};
let { select, highlight } = config;
this._addImmutableProperty('type', 'scrubber');
this._addLiveProperty('items', config.items);
this._addLiveProperty('selectedStyle', config.selectedStyle || null);
this._addLiveProperty('overlayStyle', config.overlayStyle || null);
this._addLiveProperty('showArrowButtons', config.showArrowButtons || false);
this._addLiveProperty('mode', config.mode || 'free');
const cont = typeof config.continuous === 'undefined' ? true : config.continuous;
this._addLiveProperty('continuous', cont);
if (typeof select === 'function' || typeof highlight === 'function') {
if (select == null) select = () => {};
if (highlight == null) highlight = () => {};
this._addImmutableProperty('onInteraction', (details) => {
if (details.type === 'select' && typeof select === 'function') {
select(details.selectedIndex);
} else if (details.type === 'highlight' && typeof highlight === 'function') {
highlight(details.highlightedIndex);
}
});
}
}
};
TouchBar.TouchBarOtherItemsProxy = class TouchBarOtherItemsProxy extends TouchBarItem {
constructor (config) {
super();
this._addImmutableProperty('type', 'other_items_proxy');
}
};
module.exports = TouchBar;

Просмотреть файл

@ -0,0 +1,459 @@
import { EventEmitter } from 'events';
let nextItemID = 1;
const hiddenProperties = Symbol('hidden touch bar props');
const extendConstructHook = (target: any, hook: Function) => {
const existingHook = target._hook;
target._hook = function () {
hook.call(this);
if (existingHook) existingHook.call(this);
};
};
const ImmutableProperty = <T extends TouchBarItem<any>>(def: (config: T extends TouchBarItem<infer C> ? C : never, setInternalProp: <K extends keyof T>(k: K, v: T[K]) => void) => any) => (target: T, propertyKey: keyof T) => {
extendConstructHook(target as any, function (this: T) {
(this as any)[hiddenProperties][propertyKey] = def((this as any)._config, (k, v) => {
(this as any)[hiddenProperties][k] = v;
});
});
Object.defineProperty(target, propertyKey, {
get: function () {
return (this as any)[hiddenProperties][propertyKey];
},
set: function () {
throw new Error(`Cannot override property ${name}`);
},
enumerable: true,
configurable: false
});
};
const LiveProperty = <T extends TouchBarItem<any>>(def: (config: T extends TouchBarItem<infer C> ? C : never) => any, onMutate?: (self: T, newValue: any) => void) => (target: T, propertyKey: keyof T) => {
extendConstructHook(target as any, function (this: T) {
(this as any)[hiddenProperties][propertyKey] = def((this as any)._config);
if (onMutate) onMutate((this as any), (this as any)[hiddenProperties][propertyKey]);
});
Object.defineProperty(target, propertyKey, {
get: function () {
return this[hiddenProperties][propertyKey];
},
set: function (value) {
if (onMutate) onMutate((this as any), value);
this[hiddenProperties][propertyKey] = value;
this.emit('change', this);
},
enumerable: true
});
};
abstract class TouchBarItem<ConfigType> extends EventEmitter {
@ImmutableProperty(() => `${nextItemID++}`) id!: string;
abstract type: string;
abstract onInteraction: Function | null;
child?: TouchBar;
private _parents: { id: string; type: string }[] = [];
private _config!: ConfigType;
constructor (config: ConfigType) {
super();
this._config = this._config || config || {} as any;
(this as any)[hiddenProperties] = {};
const hook = (this as any)._hook;
if (hook) hook.call(this);
delete (this as any)._hook;
}
public _addParent (item: TouchBarItem<any>) {
const existing = this._parents.some(test => test.id === item.id);
if (!existing) {
this._parents.push({
id: item.id,
type: item.type
});
}
}
public _removeParent (item: TouchBarItem<any>) {
this._parents = this._parents.filter(test => test.id !== item.id);
}
}
class TouchBarButton extends TouchBarItem<Electron.TouchBarButtonConstructorOptions> implements Electron.TouchBarButton {
@ImmutableProperty(() => 'button')
type!: string;
@LiveProperty<TouchBarButton>(config => config.label)
label!: string;
@LiveProperty<TouchBarButton>(config => config.accessibilityLabel)
accessibilityLabel!: string;
@LiveProperty<TouchBarButton>(config => config.backgroundColor)
backgroundColor!: string;
@LiveProperty<TouchBarButton>(config => config.icon)
icon!: Electron.NativeImage;
@LiveProperty<TouchBarButton>(config => config.iconPosition)
iconPosition!: Electron.TouchBarButton['iconPosition'];
@LiveProperty<TouchBarButton>(config => typeof config.enabled !== 'boolean' ? true : config.enabled)
enabled!: boolean;
@ImmutableProperty<TouchBarButton>(({ click: onClick }) => typeof onClick === 'function' ? () => onClick() : null)
onInteraction!: Function | null;
}
class TouchBarColorPicker extends TouchBarItem<Electron.TouchBarColorPickerConstructorOptions> implements Electron.TouchBarColorPicker {
@ImmutableProperty(() => 'colorpicker')
type!: string;
@LiveProperty<TouchBarColorPicker>(config => config.availableColors)
availableColors!: string[];
@LiveProperty<TouchBarColorPicker>(config => config.selectedColor)
selectedColor!: string;
@ImmutableProperty<TouchBarColorPicker>(({ change: onChange }, setInternalProp) => typeof onChange === 'function' ? (details: { color: string }) => {
setInternalProp('selectedColor', details.color);
onChange(details.color);
} : null)
onInteraction!: Function | null;
}
class TouchBarGroup extends TouchBarItem<Electron.TouchBarGroupConstructorOptions> implements Electron.TouchBarGroup {
@ImmutableProperty(() => 'group')
type!: string;
@LiveProperty<TouchBarGroup>(config => config.items instanceof TouchBar ? config.items : new TouchBar(config.items), (self, newChild: TouchBar) => {
if (self.child) {
for (const item of self.child.orderedItems) {
item._removeParent(self);
}
}
for (const item of newChild.orderedItems) {
item._addParent(item);
}
})
child!: TouchBar;
onInteraction = null;
}
class TouchBarLabel extends TouchBarItem<Electron.TouchBarLabelConstructorOptions> implements Electron.TouchBarLabel {
@ImmutableProperty(() => 'label')
type!: string;
@LiveProperty<TouchBarLabel>(config => config.label)
label!: string;
@LiveProperty<TouchBarLabel>(config => config.accessibilityLabel)
accessibilityLabel!: string;
@LiveProperty<TouchBarLabel>(config => config.textColor)
textColor!: string;
onInteraction = null;
}
class TouchBarPopover extends TouchBarItem<Electron.TouchBarPopoverConstructorOptions> implements Electron.TouchBarPopover {
@ImmutableProperty(() => 'popover')
type!: string;
@LiveProperty<TouchBarPopover>(config => config.label)
label!: string;
@LiveProperty<TouchBarPopover>(config => config.icon)
icon!: Electron.NativeImage;
@LiveProperty<TouchBarPopover>(config => config.showCloseButton)
showCloseButton!: boolean;
@LiveProperty<TouchBarPopover>(config => config.items instanceof TouchBar ? config.items : new TouchBar(config.items), (self, newChild: TouchBar) => {
if (self.child) {
for (const item of self.child.orderedItems) {
item._removeParent(self);
}
}
for (const item of newChild.orderedItems) {
item._addParent(item);
}
})
child!: TouchBar;
onInteraction = null;
}
class TouchBarSlider extends TouchBarItem<Electron.TouchBarSliderConstructorOptions> implements Electron.TouchBarSlider {
@ImmutableProperty(() => 'slider')
type!: string;
@LiveProperty<TouchBarSlider>(config => config.label)
label!: string;
@LiveProperty<TouchBarSlider>(config => config.minValue)
minValue!: number;
@LiveProperty<TouchBarSlider>(config => config.maxValue)
maxValue!: number;
@LiveProperty<TouchBarSlider>(config => config.value)
value!: number;
@ImmutableProperty<TouchBarSlider>(({ change: onChange }, setInternalProp) => typeof onChange === 'function' ? (details: { value: number }) => {
setInternalProp('value', details.value);
onChange(details.value);
} : null)
onInteraction!: Function | null;
}
class TouchBarSpacer extends TouchBarItem<Electron.TouchBarSpacerConstructorOptions> implements Electron.TouchBarSpacer {
@ImmutableProperty(() => 'spacer')
type!: string;
@ImmutableProperty<TouchBarSpacer>(config => config.size)
size!: Electron.TouchBarSpacer['size'];
onInteraction = null;
}
class TouchBarSegmentedControl extends TouchBarItem<Electron.TouchBarSegmentedControlConstructorOptions> implements Electron.TouchBarSegmentedControl {
@ImmutableProperty(() => 'segmented_control')
type!: string;
@LiveProperty<TouchBarSegmentedControl>(config => config.segmentStyle)
segmentStyle!: Electron.TouchBarSegmentedControl['segmentStyle'];
@LiveProperty<TouchBarSegmentedControl>(config => config.segments || [])
segments!: Electron.SegmentedControlSegment[];
@LiveProperty<TouchBarSegmentedControl>(config => config.selectedIndex)
selectedIndex!: number;
@LiveProperty<TouchBarSegmentedControl>(config => config.mode)
mode!: Electron.TouchBarSegmentedControl['mode'];
@ImmutableProperty<TouchBarSegmentedControl>(({ change: onChange }, setInternalProp) => typeof onChange === 'function' ? (details: { selectedIndex: number, isSelected: boolean }) => {
setInternalProp('selectedIndex', details.selectedIndex);
onChange(details.selectedIndex, details.isSelected);
} : null)
onInteraction!: Function | null;
}
class TouchBarScrubber extends TouchBarItem<Electron.TouchBarScrubberConstructorOptions> implements Electron.TouchBarScrubber {
@ImmutableProperty(() => 'scrubber')
type!: string;
@LiveProperty<TouchBarScrubber>(config => config.items)
items!: Electron.ScrubberItem[];
@LiveProperty<TouchBarScrubber>(config => config.selectedStyle || null)
selectedStyle!: Electron.TouchBarScrubber['selectedStyle'];
@LiveProperty<TouchBarScrubber>(config => config.overlayStyle || null)
overlayStyle!: Electron.TouchBarScrubber['overlayStyle'];
@LiveProperty<TouchBarScrubber>(config => config.showArrowButtons || false)
showArrowButtons!: boolean;
@LiveProperty<TouchBarScrubber>(config => config.mode || 'free')
mode!: Electron.TouchBarScrubber['mode'];
@LiveProperty<TouchBarScrubber>(config => typeof config.continuous === 'undefined' ? true : config.continuous)
continuous!: boolean;
@ImmutableProperty<TouchBarScrubber>(({ select: onSelect, highlight: onHighlight }) => typeof onSelect === 'function' || typeof onHighlight === 'function' ? (details: { type: 'select'; selectedIndex: number } | { type: 'highlight'; highlightedIndex: number }) => {
if (details.type === 'select') {
if (onSelect) onSelect(details.selectedIndex);
} else {
if (onHighlight) onHighlight(details.highlightedIndex);
}
} : null)
onInteraction!: Function | null;
}
class TouchBarOtherItemsProxy extends TouchBarItem<null> implements Electron.TouchBarOtherItemsProxy {
@ImmutableProperty(() => 'other_items_proxy') type!: string;
onInteraction = null;
}
const escapeItemSymbol = Symbol('escape item');
class TouchBar extends EventEmitter implements Electron.TouchBar {
// Bind a touch bar to a window
static _setOnWindow (touchBar: TouchBar | Electron.TouchBarConstructorOptions['items'], window: Electron.BrowserWindow) {
if (window._touchBar != null) {
window._touchBar._removeFromWindow(window);
}
if (!touchBar) {
window._setTouchBarItems([]);
return;
}
if (Array.isArray(touchBar)) {
touchBar = new TouchBar({ items: touchBar });
}
touchBar._addToWindow(window);
}
private windowListeners: Record<number, Function> = {};
private items: Record<string, TouchBarItem<any>> = {};
orderedItems: TouchBarItem<any>[] = [];
constructor (options: Electron.TouchBarConstructorOptions) {
super();
if (options == null) {
throw new Error('Must specify options object as first argument');
}
let { items, escapeItem } = options;
if (!Array.isArray(items)) {
items = [];
}
this.windowListeners = {};
this.items = {};
this.escapeItem = (escapeItem as any) || null;
const registerItem = (item: TouchBarItem<any>) => {
this.items[item.id] = item;
item.on('change', this.changeListener);
if (item.child instanceof TouchBar) {
item.child.orderedItems.forEach(registerItem);
}
};
let hasOtherItemsProxy = false;
const idSet = new Set();
items.forEach((item) => {
if (!(item instanceof TouchBarItem)) {
throw new Error('Each item must be an instance of TouchBarItem');
}
if (item.type === 'other_items_proxy') {
if (!hasOtherItemsProxy) {
hasOtherItemsProxy = true;
} else {
throw new Error('Must only have one OtherItemsProxy per TouchBar');
}
}
if (!idSet.has(item.id)) {
idSet.add(item.id);
} else {
throw new Error('Cannot add a single instance of TouchBarItem multiple times in a TouchBar');
}
});
// register in separate loop after all items are validated
for (const item of (items as TouchBarItem<any>[])) {
this.orderedItems.push(item);
registerItem(item);
}
}
private changeListener = (item: TouchBarItem<any>) => {
this.emit('change', item.id, item.type);
};
private [escapeItemSymbol]: TouchBarItem<unknown> | null = null;
set escapeItem (item: TouchBarItem<unknown> | null) {
if (item != null && !(item instanceof TouchBarItem)) {
throw new Error('Escape item must be an instance of TouchBarItem');
}
const escapeItem = this.escapeItem;
if (escapeItem) {
escapeItem.removeListener('change', this.changeListener);
}
this[escapeItemSymbol] = item;
if (this.escapeItem != null) {
this.escapeItem.on('change', this.changeListener);
}
this.emit('escape-item-change', item);
}
get escapeItem (): TouchBarItem<unknown> | null {
return this[escapeItemSymbol];
}
_addToWindow (window: Electron.BrowserWindow) {
const { id } = window;
// Already added to window
if (Object.prototype.hasOwnProperty.call(this.windowListeners, id)) return;
window._touchBar = this;
const changeListener = (itemID: string) => {
window._refreshTouchBarItem(itemID);
};
this.on('change', changeListener);
const escapeItemListener = (item: Electron.TouchBarItemType | null) => {
window._setEscapeTouchBarItem(item != null ? item : {});
};
this.on('escape-item-change', escapeItemListener);
const interactionListener = (_: any, itemID: string, details: any) => {
let item = this.items[itemID];
if (item == null && this.escapeItem != null && this.escapeItem.id === itemID) {
item = this.escapeItem;
}
if (item != null && item.onInteraction != null) {
item.onInteraction(details);
}
};
window.on('-touch-bar-interaction', interactionListener);
const removeListeners = () => {
this.removeListener('change', changeListener);
this.removeListener('escape-item-change', escapeItemListener);
window.removeListener('-touch-bar-interaction', interactionListener);
window.removeListener('closed', removeListeners);
window._touchBar = null;
delete this.windowListeners[id];
const unregisterItems = (items: TouchBarItem<any>[]) => {
for (const item of items) {
item.removeListener('change', this.changeListener);
if (item.child instanceof TouchBar) {
unregisterItems(item.child.orderedItems);
}
}
};
unregisterItems(this.orderedItems);
if (this.escapeItem) {
this.escapeItem.removeListener('change', this.changeListener);
}
};
window.once('closed', removeListeners);
this.windowListeners[id] = removeListeners;
window._setTouchBarItems(this.orderedItems);
escapeItemListener(this.escapeItem);
}
_removeFromWindow (window: Electron.BrowserWindow) {
const removeListeners = this.windowListeners[window.id];
if (removeListeners != null) removeListeners();
}
static TouchBarButton = TouchBarButton;
static TouchBarColorPicker = TouchBarColorPicker;
static TouchBarGroup = TouchBarGroup;
static TouchBarLabel = TouchBarLabel;
static TouchBarPopover = TouchBarPopover;
static TouchBarSlider = TouchBarSlider;
static TouchBarSpacer = TouchBarSpacer;
static TouchBarSegmentedControl = TouchBarSegmentedControl;
static TouchBarScrubber = TouchBarScrubber;
static TouchBarOtherItemsProxy = TouchBarOtherItemsProxy;
}
export default TouchBar;

15
typings/internal-electron.d.ts поставляемый
Просмотреть файл

@ -19,6 +19,17 @@ declare namespace Electron {
setAppPath(path: string | null): void; setAppPath(path: string | null): void;
} }
type TouchBarItemType = NonNullable<Electron.TouchBarConstructorOptions['items']>[0];
interface BrowserWindow {
_touchBar: Electron.TouchBar | null;
_setTouchBarItems: (items: TouchBarItemType[]) => void;
_setEscapeTouchBarItem: (item: TouchBarItemType | {}) => void;
_refreshTouchBarItem: (itemID: string) => void;
on(event: '-touch-bar-interaction', listener: (event: Event, itemID: string, details: any) => void): this;
removeListener(event: '-touch-bar-interaction', listener: (event: Event, itemID: string, details: any) => void): this;
}
interface ContextBridge { interface ContextBridge {
internalContextBridge: { internalContextBridge: {
contextIsolationEnabled: boolean; contextIsolationEnabled: boolean;
@ -29,6 +40,10 @@ declare namespace Electron {
} }
} }
interface TouchBar {
_removeFromWindow: (win: BrowserWindow) => void;
}
interface WebContents { interface WebContents {
_getURL(): string; _getURL(): string;
_loadURL(url: string, options: Electron.LoadURLOptions): void; _loadURL(url: string, options: Electron.LoadURLOptions): void;