/
styling.ts
105 lines (98 loc) · 2.68 KB
/
styling.ts
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
99
100
101
102
103
104
105
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
import { caretDownEmptyIcon } from '@jupyterlab/ui-components';
/**
* A namespace for node styling.
*/
export namespace Styling {
/**
* Style a node and its child elements with the default tag names.
*
* @param node - The base node.
*
* @param className - The optional CSS class to add to styled nodes.
*/
export function styleNode(node: HTMLElement, className = ''): void {
styleNodeByTag(node, 'select', className);
styleNodeByTag(node, 'textarea', className);
styleNodeByTag(node, 'input', className);
styleNodeByTag(node, 'button', className);
}
/**
* Style a node and its elements that have a given tag name.
*
* @param node - The base node.
*
* @param tagName - The html tag name to style.
*
* @param className - The optional CSS class to add to styled nodes.
*/
export function styleNodeByTag(
node: HTMLElement,
tagName: string,
className = ''
): void {
if (node.localName === tagName) {
node.classList.add('jp-mod-styled');
}
if (node.localName === 'select') {
wrapSelect(node as HTMLSelectElement);
}
let nodes = node.getElementsByTagName(tagName);
for (let i = 0; i < nodes.length; i++) {
let child = nodes[i];
child.classList.add('jp-mod-styled');
if (className) {
child.classList.add(className);
}
if (tagName === 'select') {
wrapSelect(child as HTMLSelectElement);
}
}
}
/**
* Wrap a select node.
*/
export function wrapSelect(node: HTMLSelectElement): HTMLElement {
let wrapper = document.createElement('div');
wrapper.classList.add('jp-select-wrapper');
node.addEventListener('focus', Private.onFocus);
node.addEventListener('blur', Private.onFocus);
node.classList.add('jp-mod-styled');
if (node.parentElement) {
node.parentElement.replaceChild(wrapper, node);
}
wrapper.appendChild(node);
// add the icon node
wrapper.appendChild(
caretDownEmptyIcon.element({
tag: 'span',
stylesheet: 'select',
right: '8px',
top: '5px',
width: '18px'
})
);
return wrapper;
}
}
/**
* The namespace for module private data.
*/
namespace Private {
/**
* Handle a focus event on a styled select.
*/
export function onFocus(event: FocusEvent): void {
let target = event.target as Element;
let parent = target.parentElement;
if (!parent) {
return;
}
if (event.type === 'focus') {
parent.classList.add('jp-mod-focused');
} else {
parent.classList.remove('jp-mod-focused');
}
}
}