@haiyue/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/checkbox.d.ts +30 -0
- package/dist/checkbox.js +204 -0
- package/dist/context-menu.d.ts +41 -0
- package/dist/context-menu.js +225 -0
- package/dist/dialog.d.ts +30 -0
- package/dist/dialog.js +183 -0
- package/dist/dropdown.d.ts +45 -0
- package/dist/dropdown.js +228 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +110 -0
- package/dist/input.d.ts +30 -0
- package/dist/input.js +131 -0
- package/dist/menu-shared.d.ts +14 -0
- package/dist/menu-shared.js +54 -0
- package/dist/radio.d.ts +30 -0
- package/dist/radio.js +205 -0
- package/dist/select.d.ts +40 -0
- package/dist/select.js +253 -0
- package/dist/split.d.ts +46 -0
- package/dist/split.js +277 -0
- package/dist/tabs.d.ts +28 -0
- package/dist/tabs.js +161 -0
- package/dist/tooltip.d.ts +37 -0
- package/dist/tooltip.js +286 -0
- package/dist/tree-model.d.ts +35 -0
- package/dist/tree-model.js +281 -0
- package/dist/tree-node.d.ts +11 -0
- package/dist/tree-node.js +63 -0
- package/dist/tree-types.d.ts +41 -0
- package/dist/tree-types.js +2 -0
- package/dist/tree.d.ts +102 -0
- package/dist/tree.js +942 -0
- package/package.json +46 -0
- package/src/checkbox.ts +215 -0
- package/src/context-menu.ts +248 -0
- package/src/dialog.ts +195 -0
- package/src/dropdown.ts +249 -0
- package/src/index.ts +192 -0
- package/src/input.ts +150 -0
- package/src/menu-shared.ts +65 -0
- package/src/radio.ts +216 -0
- package/src/select.ts +271 -0
- package/src/split.ts +306 -0
- package/src/tabs.ts +182 -0
- package/src/tooltip.ts +321 -0
- package/src/tree-model.ts +305 -0
- package/src/tree-node.ts +67 -0
- package/src/tree-types.ts +47 -0
- package/src/tree.ts +1002 -0
package/dist/dialog.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/** Accessible modal surface with slotted body/footer content and reflected open state. */
|
|
2
|
+
export class GEDialog extends HTMLElement {
|
|
3
|
+
_dialog = document.createElement('dialog');
|
|
4
|
+
_title = document.createElement('h2');
|
|
5
|
+
_closeButton = document.createElement('button');
|
|
6
|
+
_returnFocus = null;
|
|
7
|
+
_closeReason = 'programmatic';
|
|
8
|
+
static get observedAttributes() {
|
|
9
|
+
return ['open', 'heading', 'dismissible'];
|
|
10
|
+
}
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
const root = this.attachShadow({ mode: 'open' });
|
|
14
|
+
const style = document.createElement('style');
|
|
15
|
+
style.textContent = `
|
|
16
|
+
:host {
|
|
17
|
+
color: var(--ge-text-color, #e6edf7);
|
|
18
|
+
font: 13px system-ui, sans-serif;
|
|
19
|
+
}
|
|
20
|
+
dialog {
|
|
21
|
+
width: min(var(--ge-dialog-width, 460px), calc(100vw - 32px));
|
|
22
|
+
max-height: calc(100vh - 32px);
|
|
23
|
+
margin: auto;
|
|
24
|
+
padding: 0;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
border: 1px solid var(--ge-border-color, #303746);
|
|
27
|
+
border-radius: var(--ge-dialog-radius, 8px);
|
|
28
|
+
color: inherit;
|
|
29
|
+
background: var(--ge-dialog-bg-color, var(--ge-surface-elevated-color, #171e2a));
|
|
30
|
+
box-shadow: 0 22px 70px var(--ge-dialog-shadow-color, rgba(0, 0, 0, 0.52));
|
|
31
|
+
}
|
|
32
|
+
dialog::backdrop {
|
|
33
|
+
background: var(--ge-dialog-backdrop-color, rgba(3, 7, 12, 0.66));
|
|
34
|
+
backdrop-filter: blur(var(--ge-dialog-backdrop-blur, 2px));
|
|
35
|
+
}
|
|
36
|
+
.header {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
min-height: 49px;
|
|
40
|
+
padding: 0 12px 0 16px;
|
|
41
|
+
border-bottom: 1px solid var(--ge-border-color, #303746);
|
|
42
|
+
}
|
|
43
|
+
h2 {
|
|
44
|
+
flex: 1;
|
|
45
|
+
min-width: 0;
|
|
46
|
+
margin: 0;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
font-size: 14px;
|
|
49
|
+
font-weight: 650;
|
|
50
|
+
text-overflow: ellipsis;
|
|
51
|
+
white-space: nowrap;
|
|
52
|
+
}
|
|
53
|
+
.close {
|
|
54
|
+
display: none;
|
|
55
|
+
width: 28px;
|
|
56
|
+
height: 28px;
|
|
57
|
+
border: 0;
|
|
58
|
+
border-radius: 5px;
|
|
59
|
+
color: var(--ge-secondary-text-color, #8b99ad);
|
|
60
|
+
background: transparent;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
font: 20px/1 system-ui, sans-serif;
|
|
63
|
+
}
|
|
64
|
+
:host([dismissible]) .close { display: grid; place-items: center; }
|
|
65
|
+
.close:hover { color: inherit; background: var(--ge-hover-bg-color, #242d3b); }
|
|
66
|
+
.body {
|
|
67
|
+
max-height: calc(100vh - 160px);
|
|
68
|
+
overflow: auto;
|
|
69
|
+
padding: var(--ge-dialog-body-padding, 16px);
|
|
70
|
+
color: var(--ge-dialog-body-color, var(--ge-secondary-text-color, #a8b4c5));
|
|
71
|
+
line-height: 1.55;
|
|
72
|
+
}
|
|
73
|
+
.footer {
|
|
74
|
+
display: flex;
|
|
75
|
+
justify-content: flex-end;
|
|
76
|
+
gap: 8px;
|
|
77
|
+
min-height: 54px;
|
|
78
|
+
padding: 10px 14px;
|
|
79
|
+
border-top: 1px solid var(--ge-border-color, #303746);
|
|
80
|
+
background: var(--ge-dialog-footer-bg-color, rgba(9, 13, 19, 0.22));
|
|
81
|
+
}
|
|
82
|
+
slot[name="footer"]::slotted(*) { margin: 0; }
|
|
83
|
+
`;
|
|
84
|
+
const header = document.createElement('header');
|
|
85
|
+
header.className = 'header';
|
|
86
|
+
this._title.id = 'title';
|
|
87
|
+
this._closeButton.className = 'close';
|
|
88
|
+
this._closeButton.type = 'button';
|
|
89
|
+
this._closeButton.setAttribute('aria-label', 'Close');
|
|
90
|
+
this._closeButton.textContent = '×';
|
|
91
|
+
header.append(this._title, this._closeButton);
|
|
92
|
+
const body = document.createElement('div');
|
|
93
|
+
body.className = 'body';
|
|
94
|
+
body.append(document.createElement('slot'));
|
|
95
|
+
const footer = document.createElement('footer');
|
|
96
|
+
footer.className = 'footer';
|
|
97
|
+
const footerSlot = document.createElement('slot');
|
|
98
|
+
footerSlot.name = 'footer';
|
|
99
|
+
footer.append(footerSlot);
|
|
100
|
+
this._dialog.setAttribute('aria-labelledby', this._title.id);
|
|
101
|
+
this._dialog.append(header, body, footer);
|
|
102
|
+
root.append(style, this._dialog);
|
|
103
|
+
this._closeButton.addEventListener('click', () => this.close('action'));
|
|
104
|
+
this._dialog.addEventListener('cancel', this._onCancel);
|
|
105
|
+
this._dialog.addEventListener('click', this._onDialogClick);
|
|
106
|
+
this._dialog.addEventListener('close', this._onNativeClose);
|
|
107
|
+
}
|
|
108
|
+
connectedCallback() {
|
|
109
|
+
this._syncHeading();
|
|
110
|
+
this._syncOpen();
|
|
111
|
+
}
|
|
112
|
+
attributeChangedCallback(name) {
|
|
113
|
+
if (name === 'heading')
|
|
114
|
+
this._syncHeading();
|
|
115
|
+
if (name === 'open' && this.isConnected)
|
|
116
|
+
this._syncOpen();
|
|
117
|
+
}
|
|
118
|
+
get open() { return this.hasAttribute('open'); }
|
|
119
|
+
set open(value) { this.toggleAttribute('open', value); }
|
|
120
|
+
get dismissible() { return this.hasAttribute('dismissible'); }
|
|
121
|
+
set dismissible(value) { this.toggleAttribute('dismissible', value); }
|
|
122
|
+
get heading() { return this.getAttribute('heading') ?? ''; }
|
|
123
|
+
set heading(value) { this.setAttribute('heading', value); }
|
|
124
|
+
showModal() {
|
|
125
|
+
if (this.open && this._dialog.open)
|
|
126
|
+
return;
|
|
127
|
+
this._returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
128
|
+
this._closeReason = 'programmatic';
|
|
129
|
+
this.open = true;
|
|
130
|
+
}
|
|
131
|
+
close(reason = 'programmatic') {
|
|
132
|
+
if (!this.open && !this._dialog.open)
|
|
133
|
+
return;
|
|
134
|
+
this._closeReason = reason;
|
|
135
|
+
this.open = false;
|
|
136
|
+
}
|
|
137
|
+
_syncHeading() {
|
|
138
|
+
this._title.textContent = this.heading || 'Dialog';
|
|
139
|
+
}
|
|
140
|
+
_syncOpen() {
|
|
141
|
+
if (this.open && !this._dialog.open) {
|
|
142
|
+
this._returnFocus ??= document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
143
|
+
this._dialog.showModal();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (!this.open && this._dialog.open)
|
|
147
|
+
this._dialog.close();
|
|
148
|
+
}
|
|
149
|
+
_onCancel = (event) => {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
if (!this.dismissible)
|
|
152
|
+
return;
|
|
153
|
+
const forwarded = new CustomEvent('dialog-cancel', { bubbles: true, composed: true, cancelable: true });
|
|
154
|
+
if (this.dispatchEvent(forwarded))
|
|
155
|
+
this.close('escape');
|
|
156
|
+
};
|
|
157
|
+
_onDialogClick = (event) => {
|
|
158
|
+
if (!this.dismissible || event.target !== this._dialog)
|
|
159
|
+
return;
|
|
160
|
+
const rect = this._dialog.getBoundingClientRect();
|
|
161
|
+
const inside = event.clientX >= rect.left && event.clientX <= rect.right
|
|
162
|
+
&& event.clientY >= rect.top && event.clientY <= rect.bottom;
|
|
163
|
+
if (!inside)
|
|
164
|
+
this.close('backdrop');
|
|
165
|
+
};
|
|
166
|
+
_onNativeClose = () => {
|
|
167
|
+
this.removeAttribute('open');
|
|
168
|
+
const reason = this._closeReason;
|
|
169
|
+
this._closeReason = 'programmatic';
|
|
170
|
+
this.dispatchEvent(new CustomEvent('dialog-close', {
|
|
171
|
+
detail: { reason },
|
|
172
|
+
bubbles: true,
|
|
173
|
+
composed: true,
|
|
174
|
+
}));
|
|
175
|
+
this._returnFocus?.focus();
|
|
176
|
+
this._returnFocus = null;
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
export function defineDialogComponents() {
|
|
180
|
+
if (!customElements.get('ge-dialog'))
|
|
181
|
+
customElements.define('ge-dialog', GEDialog);
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=dialog.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface GEDropdownItem {
|
|
2
|
+
label?: string;
|
|
3
|
+
value?: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
separator?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface GEDropdownSelectDetail {
|
|
8
|
+
value: string;
|
|
9
|
+
item: GEDropdownItem;
|
|
10
|
+
}
|
|
11
|
+
export type GEDropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
|
|
12
|
+
export declare class GEDropdown extends HTMLElement {
|
|
13
|
+
private readonly _root;
|
|
14
|
+
private readonly _style;
|
|
15
|
+
private readonly _triggerSlot;
|
|
16
|
+
private readonly _menu;
|
|
17
|
+
private _items;
|
|
18
|
+
private _documentListenerAbort;
|
|
19
|
+
static get observedAttributes(): string[];
|
|
20
|
+
constructor();
|
|
21
|
+
connectedCallback(): void;
|
|
22
|
+
disconnectedCallback(): void;
|
|
23
|
+
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void;
|
|
24
|
+
get items(): GEDropdownItem[];
|
|
25
|
+
set items(value: GEDropdownItem[]);
|
|
26
|
+
get open(): boolean;
|
|
27
|
+
set open(value: boolean);
|
|
28
|
+
get disabled(): boolean;
|
|
29
|
+
set disabled(value: boolean);
|
|
30
|
+
get placement(): GEDropdownPlacement;
|
|
31
|
+
set placement(value: GEDropdownPlacement);
|
|
32
|
+
show(): void;
|
|
33
|
+
close(): void;
|
|
34
|
+
toggle(): void;
|
|
35
|
+
private _readItemsAttribute;
|
|
36
|
+
private _render;
|
|
37
|
+
private _syncPosition;
|
|
38
|
+
private _syncDocumentListeners;
|
|
39
|
+
private _attachDocumentListeners;
|
|
40
|
+
private _detachDocumentListeners;
|
|
41
|
+
private _onHostClick;
|
|
42
|
+
private _onDocumentPointerDown;
|
|
43
|
+
private _onDocumentKeyDown;
|
|
44
|
+
}
|
|
45
|
+
export declare function defineDropdownComponents(): void;
|
package/dist/dropdown.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { GE_MENU_ITEM_STYLES, createMenuItemButton, createMenuSeparator } from './menu-shared.js';
|
|
2
|
+
export class GEDropdown extends HTMLElement {
|
|
3
|
+
_root;
|
|
4
|
+
_style = document.createElement('style');
|
|
5
|
+
_triggerSlot = document.createElement('slot');
|
|
6
|
+
_menu = document.createElement('div');
|
|
7
|
+
_items = [];
|
|
8
|
+
_documentListenerAbort = null;
|
|
9
|
+
static get observedAttributes() {
|
|
10
|
+
return ['items', 'open', 'disabled', 'placement'];
|
|
11
|
+
}
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this._root = this.attachShadow({ mode: 'open' });
|
|
15
|
+
this._style.textContent = `
|
|
16
|
+
:host {
|
|
17
|
+
display: inline-block;
|
|
18
|
+
width: max-content;
|
|
19
|
+
min-width: 0;
|
|
20
|
+
color: var(--ge-text-color, #d8e2f2);
|
|
21
|
+
font: 12px system-ui, sans-serif;
|
|
22
|
+
}
|
|
23
|
+
:host([disabled]) {
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
opacity: 0.55;
|
|
26
|
+
}
|
|
27
|
+
.menu {
|
|
28
|
+
position: fixed;
|
|
29
|
+
z-index: 10000;
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
min-width: 148px;
|
|
32
|
+
max-height: min(320px, calc(100vh - 12px));
|
|
33
|
+
overflow: auto;
|
|
34
|
+
display: none;
|
|
35
|
+
padding: 4px;
|
|
36
|
+
border: 1px solid var(--ge-border-color, #303746);
|
|
37
|
+
border-radius: 4px;
|
|
38
|
+
color: var(--ge-text-color, #d8e2f2);
|
|
39
|
+
background: var(--ge-menu-bg-color, var(--ge-surface-elevated-color, #1b2230));
|
|
40
|
+
box-shadow: 0 10px 26px var(--ge-menu-shadow-color, rgba(0, 0, 0, 0.36));
|
|
41
|
+
}
|
|
42
|
+
:host([open]) .menu {
|
|
43
|
+
display: block;
|
|
44
|
+
}
|
|
45
|
+
${GE_MENU_ITEM_STYLES}
|
|
46
|
+
`;
|
|
47
|
+
this._triggerSlot.name = 'trigger';
|
|
48
|
+
this._menu.className = 'menu';
|
|
49
|
+
this._root.append(this._style, this._triggerSlot, this._menu);
|
|
50
|
+
}
|
|
51
|
+
connectedCallback() {
|
|
52
|
+
this._readItemsAttribute();
|
|
53
|
+
this._render();
|
|
54
|
+
this.addEventListener('click', this._onHostClick);
|
|
55
|
+
this._syncDocumentListeners();
|
|
56
|
+
}
|
|
57
|
+
disconnectedCallback() {
|
|
58
|
+
this.removeEventListener('click', this._onHostClick);
|
|
59
|
+
this._detachDocumentListeners();
|
|
60
|
+
}
|
|
61
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
|
62
|
+
if (name === 'items') {
|
|
63
|
+
this._readItemsAttribute();
|
|
64
|
+
this._render();
|
|
65
|
+
}
|
|
66
|
+
if (name === 'open') {
|
|
67
|
+
this._syncDocumentListeners();
|
|
68
|
+
if (newValue !== null)
|
|
69
|
+
this._syncPosition();
|
|
70
|
+
}
|
|
71
|
+
if (name === 'placement' && this.open)
|
|
72
|
+
this._syncPosition();
|
|
73
|
+
}
|
|
74
|
+
get items() {
|
|
75
|
+
return this._items;
|
|
76
|
+
}
|
|
77
|
+
set items(value) {
|
|
78
|
+
this._items = Array.isArray(value) ? value : [];
|
|
79
|
+
this._render();
|
|
80
|
+
}
|
|
81
|
+
get open() {
|
|
82
|
+
return this.hasAttribute('open');
|
|
83
|
+
}
|
|
84
|
+
set open(value) {
|
|
85
|
+
if (value)
|
|
86
|
+
this.setAttribute('open', '');
|
|
87
|
+
else
|
|
88
|
+
this.removeAttribute('open');
|
|
89
|
+
}
|
|
90
|
+
get disabled() {
|
|
91
|
+
return this.hasAttribute('disabled');
|
|
92
|
+
}
|
|
93
|
+
set disabled(value) {
|
|
94
|
+
if (value)
|
|
95
|
+
this.setAttribute('disabled', '');
|
|
96
|
+
else
|
|
97
|
+
this.removeAttribute('disabled');
|
|
98
|
+
}
|
|
99
|
+
get placement() {
|
|
100
|
+
return this.getAttribute('placement') ?? 'bottom-start';
|
|
101
|
+
}
|
|
102
|
+
set placement(value) {
|
|
103
|
+
this.setAttribute('placement', value);
|
|
104
|
+
}
|
|
105
|
+
show() {
|
|
106
|
+
if (this.disabled)
|
|
107
|
+
return;
|
|
108
|
+
this.open = true;
|
|
109
|
+
this._syncPosition();
|
|
110
|
+
}
|
|
111
|
+
close() {
|
|
112
|
+
this.open = false;
|
|
113
|
+
}
|
|
114
|
+
toggle() {
|
|
115
|
+
if (this.open)
|
|
116
|
+
this.close();
|
|
117
|
+
else
|
|
118
|
+
this.show();
|
|
119
|
+
}
|
|
120
|
+
_readItemsAttribute() {
|
|
121
|
+
const raw = this.getAttribute('items');
|
|
122
|
+
if (!raw) {
|
|
123
|
+
this._items = [];
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const parsed = JSON.parse(raw);
|
|
128
|
+
this._items = Array.isArray(parsed)
|
|
129
|
+
? parsed.map(item => ({
|
|
130
|
+
...(item.separator ? {} : {
|
|
131
|
+
label: String(item.label ?? item.value ?? ''),
|
|
132
|
+
value: String(item.value ?? item.label ?? ''),
|
|
133
|
+
}),
|
|
134
|
+
disabled: Boolean(item.disabled),
|
|
135
|
+
separator: Boolean(item.separator),
|
|
136
|
+
}))
|
|
137
|
+
: [];
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
console.warn('Invalid ge-dropdown items attribute.', error);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
_render() {
|
|
144
|
+
this._menu.replaceChildren();
|
|
145
|
+
for (const item of this._items) {
|
|
146
|
+
if (item.separator) {
|
|
147
|
+
this._menu.append(createMenuSeparator());
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const button = createMenuItemButton(item);
|
|
151
|
+
button.addEventListener('click', (event) => {
|
|
152
|
+
event.stopPropagation();
|
|
153
|
+
if (!item.value || item.disabled)
|
|
154
|
+
return;
|
|
155
|
+
this.dispatchEvent(new CustomEvent('item-select', {
|
|
156
|
+
detail: { value: item.value, item },
|
|
157
|
+
bubbles: true,
|
|
158
|
+
composed: true,
|
|
159
|
+
}));
|
|
160
|
+
this.close();
|
|
161
|
+
});
|
|
162
|
+
this._menu.append(button);
|
|
163
|
+
}
|
|
164
|
+
if (this.open)
|
|
165
|
+
this._syncPosition();
|
|
166
|
+
}
|
|
167
|
+
_syncPosition() {
|
|
168
|
+
if (!this.open)
|
|
169
|
+
return;
|
|
170
|
+
const hostRect = this.getBoundingClientRect();
|
|
171
|
+
this._menu.style.left = '0px';
|
|
172
|
+
this._menu.style.top = '0px';
|
|
173
|
+
this._menu.style.minWidth = `${Math.max(148, hostRect.width)}px`;
|
|
174
|
+
const menuRect = this._menu.getBoundingClientRect();
|
|
175
|
+
const placement = this.placement;
|
|
176
|
+
const left = placement.endsWith('end') ? hostRect.right - menuRect.width : hostRect.left;
|
|
177
|
+
const top = placement.startsWith('top') ? hostRect.top - menuRect.height - 4 : hostRect.bottom + 4;
|
|
178
|
+
const viewport = getVisualViewportRect();
|
|
179
|
+
this._menu.style.left = `${Math.max(viewport.left + 4, Math.min(left, viewport.left + viewport.width - menuRect.width - 4))}px`;
|
|
180
|
+
this._menu.style.top = `${Math.max(viewport.top + 4, Math.min(top, viewport.top + viewport.height - menuRect.height - 4))}px`;
|
|
181
|
+
}
|
|
182
|
+
_syncDocumentListeners() {
|
|
183
|
+
if (this.open && this.isConnected)
|
|
184
|
+
this._attachDocumentListeners();
|
|
185
|
+
else
|
|
186
|
+
this._detachDocumentListeners();
|
|
187
|
+
}
|
|
188
|
+
_attachDocumentListeners() {
|
|
189
|
+
if (this._documentListenerAbort)
|
|
190
|
+
return;
|
|
191
|
+
this._documentListenerAbort = new AbortController();
|
|
192
|
+
const { signal } = this._documentListenerAbort;
|
|
193
|
+
document.addEventListener('pointerdown', this._onDocumentPointerDown, { capture: true, signal });
|
|
194
|
+
document.addEventListener('keydown', this._onDocumentKeyDown, { capture: true, signal });
|
|
195
|
+
}
|
|
196
|
+
_detachDocumentListeners() {
|
|
197
|
+
this._documentListenerAbort?.abort();
|
|
198
|
+
this._documentListenerAbort = null;
|
|
199
|
+
}
|
|
200
|
+
_onHostClick = (event) => {
|
|
201
|
+
if (event.composedPath().includes(this._menu))
|
|
202
|
+
return;
|
|
203
|
+
this.toggle();
|
|
204
|
+
};
|
|
205
|
+
_onDocumentPointerDown = (event) => {
|
|
206
|
+
if (!this.open)
|
|
207
|
+
return;
|
|
208
|
+
const path = event.composedPath();
|
|
209
|
+
if (!path.includes(this))
|
|
210
|
+
this.close();
|
|
211
|
+
};
|
|
212
|
+
_onDocumentKeyDown = (event) => {
|
|
213
|
+
if (event.key === 'Escape')
|
|
214
|
+
this.close();
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function getVisualViewportRect() {
|
|
218
|
+
const viewport = window.visualViewport;
|
|
219
|
+
return viewport
|
|
220
|
+
? { left: viewport.offsetLeft, top: viewport.offsetTop, width: viewport.width, height: viewport.height }
|
|
221
|
+
: { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight };
|
|
222
|
+
}
|
|
223
|
+
export function defineDropdownComponents() {
|
|
224
|
+
if (!customElements.get('ge-dropdown')) {
|
|
225
|
+
customElements.define('ge-dropdown', GEDropdown);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=dropdown.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export { defineTreeComponents, GETree, GETreeNode, } from './tree.js';
|
|
2
|
+
export { defineSplitComponents, GESplit, } from './split.js';
|
|
3
|
+
export { defineSelectComponents, GESelect, } from './select.js';
|
|
4
|
+
export { defineTabsComponents, GETabs, } from './tabs.js';
|
|
5
|
+
export { defineContextMenuComponents, GEContextMenu, } from './context-menu.js';
|
|
6
|
+
export { defineDropdownComponents, GEDropdown, } from './dropdown.js';
|
|
7
|
+
export { defineTooltipComponents, GETooltip, } from './tooltip.js';
|
|
8
|
+
export { defineCheckboxComponents, GECheckbox, } from './checkbox.js';
|
|
9
|
+
export { defineRadioComponents, GERadio, } from './radio.js';
|
|
10
|
+
export { defineDialogComponents, GEDialog, } from './dialog.js';
|
|
11
|
+
export { defineInputComponents, GEInput, } from './input.js';
|
|
12
|
+
export type { GESplitDirection, GESplitRatioChangeDetail, } from './split.js';
|
|
13
|
+
export type { GESelectChangeDetail, GESelectOption, } from './select.js';
|
|
14
|
+
export type { GETabChangeDetail, GETabOption, } from './tabs.js';
|
|
15
|
+
export type { GEContextMenuItem, GEContextMenuSelectDetail, } from './context-menu.js';
|
|
16
|
+
export type { GEDropdownItem, GEDropdownPlacement, GEDropdownSelectDetail, } from './dropdown.js';
|
|
17
|
+
export type { GETooltipPlacement, } from './tooltip.js';
|
|
18
|
+
export type { GECheckboxChangeDetail, } from './checkbox.js';
|
|
19
|
+
export type { GERadioChangeDetail, } from './radio.js';
|
|
20
|
+
export type { GEDialogCloseDetail, GEDialogCloseReason, } from './dialog.js';
|
|
21
|
+
export type { GEInputChangeDetail, GEInputType, } from './input.js';
|
|
22
|
+
export type { GETreeDataChangeDetail, GETreeDropPosition, GETreeNodeContextMenuDetail, GETreeNodeData, GETreeSelectionChangeDetail, } from './tree.js';
|
|
23
|
+
export declare class GEButton extends HTMLElement {
|
|
24
|
+
private readonly _button;
|
|
25
|
+
private readonly _slot;
|
|
26
|
+
static get observedAttributes(): string[];
|
|
27
|
+
constructor();
|
|
28
|
+
connectedCallback(): void;
|
|
29
|
+
attributeChangedCallback(): void;
|
|
30
|
+
private _sync;
|
|
31
|
+
}
|
|
32
|
+
export declare function defineHaiyueUI(): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { defineTreeComponents } from './tree.js';
|
|
2
|
+
import { defineSplitComponents } from './split.js';
|
|
3
|
+
import { defineSelectComponents } from './select.js';
|
|
4
|
+
import { defineTabsComponents } from './tabs.js';
|
|
5
|
+
import { defineContextMenuComponents } from './context-menu.js';
|
|
6
|
+
import { defineDropdownComponents } from './dropdown.js';
|
|
7
|
+
import { defineTooltipComponents } from './tooltip.js';
|
|
8
|
+
import { defineCheckboxComponents } from './checkbox.js';
|
|
9
|
+
import { defineRadioComponents } from './radio.js';
|
|
10
|
+
import { defineDialogComponents } from './dialog.js';
|
|
11
|
+
import { defineInputComponents } from './input.js';
|
|
12
|
+
export { defineTreeComponents, GETree, GETreeNode, } from './tree.js';
|
|
13
|
+
export { defineSplitComponents, GESplit, } from './split.js';
|
|
14
|
+
export { defineSelectComponents, GESelect, } from './select.js';
|
|
15
|
+
export { defineTabsComponents, GETabs, } from './tabs.js';
|
|
16
|
+
export { defineContextMenuComponents, GEContextMenu, } from './context-menu.js';
|
|
17
|
+
export { defineDropdownComponents, GEDropdown, } from './dropdown.js';
|
|
18
|
+
export { defineTooltipComponents, GETooltip, } from './tooltip.js';
|
|
19
|
+
export { defineCheckboxComponents, GECheckbox, } from './checkbox.js';
|
|
20
|
+
export { defineRadioComponents, GERadio, } from './radio.js';
|
|
21
|
+
export { defineDialogComponents, GEDialog, } from './dialog.js';
|
|
22
|
+
export { defineInputComponents, GEInput, } from './input.js';
|
|
23
|
+
export class GEButton extends HTMLElement {
|
|
24
|
+
_button = document.createElement('button');
|
|
25
|
+
_slot = document.createElement('slot');
|
|
26
|
+
static get observedAttributes() {
|
|
27
|
+
return ['label', 'disabled', 'aria-label', 'title', 'icon-only'];
|
|
28
|
+
}
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
const root = this.attachShadow({ mode: 'open' });
|
|
32
|
+
const style = document.createElement('style');
|
|
33
|
+
style.textContent = `
|
|
34
|
+
:host { display: inline-block; }
|
|
35
|
+
button {
|
|
36
|
+
min-height: 28px;
|
|
37
|
+
padding: 0 10px;
|
|
38
|
+
border: 1px solid #3d4654;
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
background: #202733;
|
|
41
|
+
color: #eef3ff;
|
|
42
|
+
font: 12px system-ui, sans-serif;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
}
|
|
45
|
+
button.icon-only {
|
|
46
|
+
width: 28px;
|
|
47
|
+
padding: 0;
|
|
48
|
+
display: inline-grid;
|
|
49
|
+
place-items: center;
|
|
50
|
+
}
|
|
51
|
+
::slotted(svg) {
|
|
52
|
+
width: 16px;
|
|
53
|
+
height: 16px;
|
|
54
|
+
display: block;
|
|
55
|
+
fill: none;
|
|
56
|
+
stroke: currentColor;
|
|
57
|
+
stroke-width: 2;
|
|
58
|
+
stroke-linecap: round;
|
|
59
|
+
stroke-linejoin: round;
|
|
60
|
+
}
|
|
61
|
+
button:disabled {
|
|
62
|
+
opacity: 0.5;
|
|
63
|
+
cursor: default;
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
root.append(style, this._button);
|
|
67
|
+
}
|
|
68
|
+
connectedCallback() {
|
|
69
|
+
this._sync();
|
|
70
|
+
}
|
|
71
|
+
attributeChangedCallback() {
|
|
72
|
+
this._sync();
|
|
73
|
+
}
|
|
74
|
+
_sync() {
|
|
75
|
+
const label = this.getAttribute('label');
|
|
76
|
+
if (label !== null) {
|
|
77
|
+
this._button.textContent = label;
|
|
78
|
+
this._button.classList.remove('icon-only');
|
|
79
|
+
this._button.removeAttribute('aria-label');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
if (this._button.firstChild !== this._slot)
|
|
83
|
+
this._button.replaceChildren(this._slot);
|
|
84
|
+
this._button.classList.toggle('icon-only', this.hasAttribute('icon-only'));
|
|
85
|
+
const accessibleLabel = this.getAttribute('aria-label') ?? this.getAttribute('title') ?? '';
|
|
86
|
+
if (accessibleLabel)
|
|
87
|
+
this._button.setAttribute('aria-label', accessibleLabel);
|
|
88
|
+
else
|
|
89
|
+
this._button.removeAttribute('aria-label');
|
|
90
|
+
}
|
|
91
|
+
this._button.disabled = this.hasAttribute('disabled');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export function defineHaiyueUI() {
|
|
95
|
+
if (!customElements.get('ge-button')) {
|
|
96
|
+
customElements.define('ge-button', GEButton);
|
|
97
|
+
}
|
|
98
|
+
defineTreeComponents();
|
|
99
|
+
defineSplitComponents();
|
|
100
|
+
defineSelectComponents();
|
|
101
|
+
defineTabsComponents();
|
|
102
|
+
defineContextMenuComponents();
|
|
103
|
+
defineDropdownComponents();
|
|
104
|
+
defineTooltipComponents();
|
|
105
|
+
defineCheckboxComponents();
|
|
106
|
+
defineRadioComponents();
|
|
107
|
+
defineDialogComponents();
|
|
108
|
+
defineInputComponents();
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=index.js.map
|
package/dist/input.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type GEInputType = 'text' | 'number' | 'color';
|
|
2
|
+
export interface GEInputChangeDetail {
|
|
3
|
+
value: string;
|
|
4
|
+
valueAsNumber: number | null;
|
|
5
|
+
valid: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class GEInput extends HTMLElement {
|
|
8
|
+
private readonly _input;
|
|
9
|
+
static get observedAttributes(): string[];
|
|
10
|
+
constructor();
|
|
11
|
+
connectedCallback(): void;
|
|
12
|
+
disconnectedCallback(): void;
|
|
13
|
+
attributeChangedCallback(): void;
|
|
14
|
+
get type(): GEInputType;
|
|
15
|
+
set type(value: GEInputType);
|
|
16
|
+
get value(): string;
|
|
17
|
+
set value(value: string);
|
|
18
|
+
get valueAsNumber(): number;
|
|
19
|
+
get disabled(): boolean;
|
|
20
|
+
set disabled(value: boolean);
|
|
21
|
+
get readOnly(): boolean;
|
|
22
|
+
set readOnly(value: boolean);
|
|
23
|
+
get valid(): boolean;
|
|
24
|
+
focus(options?: FocusOptions): void;
|
|
25
|
+
select(): void;
|
|
26
|
+
private _sync;
|
|
27
|
+
private _onInput;
|
|
28
|
+
private _onChange;
|
|
29
|
+
}
|
|
30
|
+
export declare function defineInputComponents(): void;
|