@haiyue/ui 0.1.0 → 0.1.2
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/CHANGELOG.md +29 -0
- package/LICENSE +1 -1
- package/README.md +226 -2
- package/dist/border-beam.d.ts +26 -0
- package/dist/border-beam.js +174 -0
- package/dist/button.d.ts +10 -0
- package/dist/button.js +85 -0
- package/dist/checkbox.d.ts +2 -2
- package/dist/checkbox.js +11 -11
- package/dist/context-menu.d.ts +6 -6
- package/dist/context-menu.js +11 -9
- package/dist/dialog.d.ts +5 -5
- package/dist/dialog.js +18 -18
- package/dist/drawer.d.ts +49 -0
- package/dist/drawer.js +377 -0
- package/dist/dropdown.d.ts +9 -9
- package/dist/dropdown.js +9 -9
- package/dist/expandable.d.ts +32 -0
- package/dist/expandable.js +136 -0
- package/dist/history-controls.d.ts +40 -0
- package/dist/history-controls.js +123 -0
- package/dist/index.d.ts +36 -31
- package/dist/index.js +35 -85
- package/dist/input.d.ts +5 -5
- package/dist/input.js +13 -13
- package/dist/menu-shared.d.ts +4 -4
- package/dist/menu-shared.js +4 -4
- package/dist/notification.d.ts +55 -0
- package/dist/notification.js +357 -0
- package/dist/radio.d.ts +2 -2
- package/dist/radio.js +12 -12
- package/dist/range.d.ts +74 -0
- package/dist/range.js +393 -0
- package/dist/select.d.ts +6 -6
- package/dist/select.js +20 -20
- package/dist/split.d.ts +6 -6
- package/dist/split.js +14 -14
- package/dist/tabs.d.ts +10 -6
- package/dist/tabs.js +94 -30
- package/dist/tooltip.d.ts +4 -4
- package/dist/tooltip.js +9 -9
- package/dist/tree-model.d.ts +15 -7
- package/dist/tree-model.js +93 -80
- package/dist/tree-node.d.ts +3 -3
- package/dist/tree-node.js +3 -3
- package/dist/tree-types.d.ts +14 -14
- package/dist/tree.d.ts +9 -7
- package/dist/tree.js +68 -66
- package/dist/virtual-list.d.ts +61 -0
- package/dist/virtual-list.js +324 -0
- package/package.json +100 -7
- package/themes/haiyue-dark.css +46 -0
- package/themes/haiyue-light.css +46 -0
- package/src/checkbox.ts +0 -215
- package/src/context-menu.ts +0 -248
- package/src/dialog.ts +0 -195
- package/src/dropdown.ts +0 -249
- package/src/index.ts +0 -192
- package/src/input.ts +0 -150
- package/src/menu-shared.ts +0 -65
- package/src/radio.ts +0 -216
- package/src/select.ts +0 -271
- package/src/split.ts +0 -306
- package/src/tabs.ts +0 -182
- package/src/tooltip.ts +0 -321
- package/src/tree-model.ts +0 -305
- package/src/tree-node.ts +0 -67
- package/src/tree-types.ts +0 -47
- package/src/tree.ts +0 -1002
package/src/dropdown.ts
DELETED
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
import { GE_MENU_ITEM_STYLES, createMenuItemButton, createMenuSeparator } from './menu-shared.js';
|
|
2
|
-
|
|
3
|
-
export interface GEDropdownItem {
|
|
4
|
-
label?: string;
|
|
5
|
-
value?: string;
|
|
6
|
-
disabled?: boolean;
|
|
7
|
-
separator?: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface GEDropdownSelectDetail {
|
|
11
|
-
value: string;
|
|
12
|
-
item: GEDropdownItem;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type GEDropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
|
|
16
|
-
|
|
17
|
-
export class GEDropdown extends HTMLElement {
|
|
18
|
-
private readonly _root: ShadowRoot;
|
|
19
|
-
private readonly _style = document.createElement('style');
|
|
20
|
-
private readonly _triggerSlot = document.createElement('slot');
|
|
21
|
-
private readonly _menu = document.createElement('div');
|
|
22
|
-
private _items: GEDropdownItem[] = [];
|
|
23
|
-
private _documentListenerAbort: AbortController | null = null;
|
|
24
|
-
|
|
25
|
-
static get observedAttributes(): string[] {
|
|
26
|
-
return ['items', 'open', 'disabled', 'placement'];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
constructor() {
|
|
30
|
-
super();
|
|
31
|
-
this._root = this.attachShadow({ mode: 'open' });
|
|
32
|
-
this._style.textContent = `
|
|
33
|
-
:host {
|
|
34
|
-
display: inline-block;
|
|
35
|
-
width: max-content;
|
|
36
|
-
min-width: 0;
|
|
37
|
-
color: var(--ge-text-color, #d8e2f2);
|
|
38
|
-
font: 12px system-ui, sans-serif;
|
|
39
|
-
}
|
|
40
|
-
:host([disabled]) {
|
|
41
|
-
pointer-events: none;
|
|
42
|
-
opacity: 0.55;
|
|
43
|
-
}
|
|
44
|
-
.menu {
|
|
45
|
-
position: fixed;
|
|
46
|
-
z-index: 10000;
|
|
47
|
-
box-sizing: border-box;
|
|
48
|
-
min-width: 148px;
|
|
49
|
-
max-height: min(320px, calc(100vh - 12px));
|
|
50
|
-
overflow: auto;
|
|
51
|
-
display: none;
|
|
52
|
-
padding: 4px;
|
|
53
|
-
border: 1px solid var(--ge-border-color, #303746);
|
|
54
|
-
border-radius: 4px;
|
|
55
|
-
color: var(--ge-text-color, #d8e2f2);
|
|
56
|
-
background: var(--ge-menu-bg-color, var(--ge-surface-elevated-color, #1b2230));
|
|
57
|
-
box-shadow: 0 10px 26px var(--ge-menu-shadow-color, rgba(0, 0, 0, 0.36));
|
|
58
|
-
}
|
|
59
|
-
:host([open]) .menu {
|
|
60
|
-
display: block;
|
|
61
|
-
}
|
|
62
|
-
${GE_MENU_ITEM_STYLES}
|
|
63
|
-
`;
|
|
64
|
-
this._triggerSlot.name = 'trigger';
|
|
65
|
-
this._menu.className = 'menu';
|
|
66
|
-
this._root.append(this._style, this._triggerSlot, this._menu);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
connectedCallback(): void {
|
|
70
|
-
this._readItemsAttribute();
|
|
71
|
-
this._render();
|
|
72
|
-
this.addEventListener('click', this._onHostClick);
|
|
73
|
-
this._syncDocumentListeners();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
disconnectedCallback(): void {
|
|
77
|
-
this.removeEventListener('click', this._onHostClick);
|
|
78
|
-
this._detachDocumentListeners();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {
|
|
82
|
-
if (name === 'items') {
|
|
83
|
-
this._readItemsAttribute();
|
|
84
|
-
this._render();
|
|
85
|
-
}
|
|
86
|
-
if (name === 'open') {
|
|
87
|
-
this._syncDocumentListeners();
|
|
88
|
-
if (newValue !== null) this._syncPosition();
|
|
89
|
-
}
|
|
90
|
-
if (name === 'placement' && this.open) this._syncPosition();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
get items(): GEDropdownItem[] {
|
|
94
|
-
return this._items;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
set items(value: GEDropdownItem[]) {
|
|
98
|
-
this._items = Array.isArray(value) ? value : [];
|
|
99
|
-
this._render();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
get open(): boolean {
|
|
103
|
-
return this.hasAttribute('open');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
set open(value: boolean) {
|
|
107
|
-
if (value) this.setAttribute('open', '');
|
|
108
|
-
else this.removeAttribute('open');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
get disabled(): boolean {
|
|
112
|
-
return this.hasAttribute('disabled');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
set disabled(value: boolean) {
|
|
116
|
-
if (value) this.setAttribute('disabled', '');
|
|
117
|
-
else this.removeAttribute('disabled');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
get placement(): GEDropdownPlacement {
|
|
121
|
-
return (this.getAttribute('placement') as GEDropdownPlacement | null) ?? 'bottom-start';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
set placement(value: GEDropdownPlacement) {
|
|
125
|
-
this.setAttribute('placement', value);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
show(): void {
|
|
129
|
-
if (this.disabled) return;
|
|
130
|
-
this.open = true;
|
|
131
|
-
this._syncPosition();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
close(): void {
|
|
135
|
-
this.open = false;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
toggle(): void {
|
|
139
|
-
if (this.open) this.close();
|
|
140
|
-
else this.show();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private _readItemsAttribute(): void {
|
|
144
|
-
const raw = this.getAttribute('items');
|
|
145
|
-
if (!raw) {
|
|
146
|
-
this._items = [];
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
try {
|
|
150
|
-
const parsed = JSON.parse(raw);
|
|
151
|
-
this._items = Array.isArray(parsed)
|
|
152
|
-
? parsed.map(item => ({
|
|
153
|
-
...(item.separator ? {} : {
|
|
154
|
-
label: String(item.label ?? item.value ?? ''),
|
|
155
|
-
value: String(item.value ?? item.label ?? ''),
|
|
156
|
-
}),
|
|
157
|
-
disabled: Boolean(item.disabled),
|
|
158
|
-
separator: Boolean(item.separator),
|
|
159
|
-
}))
|
|
160
|
-
: [];
|
|
161
|
-
} catch (error) {
|
|
162
|
-
console.warn('Invalid ge-dropdown items attribute.', error);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private _render(): void {
|
|
167
|
-
this._menu.replaceChildren();
|
|
168
|
-
for (const item of this._items) {
|
|
169
|
-
if (item.separator) {
|
|
170
|
-
this._menu.append(createMenuSeparator());
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
const button = createMenuItemButton(item);
|
|
174
|
-
button.addEventListener('click', (event) => {
|
|
175
|
-
event.stopPropagation();
|
|
176
|
-
if (!item.value || item.disabled) return;
|
|
177
|
-
this.dispatchEvent(new CustomEvent<GEDropdownSelectDetail>('item-select', {
|
|
178
|
-
detail: { value: item.value, item },
|
|
179
|
-
bubbles: true,
|
|
180
|
-
composed: true,
|
|
181
|
-
}));
|
|
182
|
-
this.close();
|
|
183
|
-
});
|
|
184
|
-
this._menu.append(button);
|
|
185
|
-
}
|
|
186
|
-
if (this.open) this._syncPosition();
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
private _syncPosition(): void {
|
|
190
|
-
if (!this.open) return;
|
|
191
|
-
const hostRect = this.getBoundingClientRect();
|
|
192
|
-
this._menu.style.left = '0px';
|
|
193
|
-
this._menu.style.top = '0px';
|
|
194
|
-
this._menu.style.minWidth = `${Math.max(148, hostRect.width)}px`;
|
|
195
|
-
const menuRect = this._menu.getBoundingClientRect();
|
|
196
|
-
const placement = this.placement;
|
|
197
|
-
const left = placement.endsWith('end') ? hostRect.right - menuRect.width : hostRect.left;
|
|
198
|
-
const top = placement.startsWith('top') ? hostRect.top - menuRect.height - 4 : hostRect.bottom + 4;
|
|
199
|
-
const viewport = getVisualViewportRect();
|
|
200
|
-
this._menu.style.left = `${Math.max(viewport.left + 4, Math.min(left, viewport.left + viewport.width - menuRect.width - 4))}px`;
|
|
201
|
-
this._menu.style.top = `${Math.max(viewport.top + 4, Math.min(top, viewport.top + viewport.height - menuRect.height - 4))}px`;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
private _syncDocumentListeners(): void {
|
|
205
|
-
if (this.open && this.isConnected) this._attachDocumentListeners();
|
|
206
|
-
else this._detachDocumentListeners();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
private _attachDocumentListeners(): void {
|
|
210
|
-
if (this._documentListenerAbort) return;
|
|
211
|
-
this._documentListenerAbort = new AbortController();
|
|
212
|
-
const { signal } = this._documentListenerAbort;
|
|
213
|
-
document.addEventListener('pointerdown', this._onDocumentPointerDown, { capture: true, signal });
|
|
214
|
-
document.addEventListener('keydown', this._onDocumentKeyDown, { capture: true, signal });
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
private _detachDocumentListeners(): void {
|
|
218
|
-
this._documentListenerAbort?.abort();
|
|
219
|
-
this._documentListenerAbort = null;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
private _onHostClick = (event: MouseEvent): void => {
|
|
223
|
-
if (event.composedPath().includes(this._menu)) return;
|
|
224
|
-
this.toggle();
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
private _onDocumentPointerDown = (event: PointerEvent): void => {
|
|
228
|
-
if (!this.open) return;
|
|
229
|
-
const path = event.composedPath();
|
|
230
|
-
if (!path.includes(this)) this.close();
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
private _onDocumentKeyDown = (event: KeyboardEvent): void => {
|
|
234
|
-
if (event.key === 'Escape') this.close();
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function getVisualViewportRect(): { left: number; top: number; width: number; height: number } {
|
|
239
|
-
const viewport = window.visualViewport;
|
|
240
|
-
return viewport
|
|
241
|
-
? { left: viewport.offsetLeft, top: viewport.offsetTop, width: viewport.width, height: viewport.height }
|
|
242
|
-
: { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight };
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
export function defineDropdownComponents(): void {
|
|
246
|
-
if (!customElements.get('ge-dropdown')) {
|
|
247
|
-
customElements.define('ge-dropdown', GEDropdown);
|
|
248
|
-
}
|
|
249
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
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
|
-
|
|
13
|
-
export {
|
|
14
|
-
defineTreeComponents,
|
|
15
|
-
GETree,
|
|
16
|
-
GETreeNode,
|
|
17
|
-
} from './tree.js';
|
|
18
|
-
export {
|
|
19
|
-
defineSplitComponents,
|
|
20
|
-
GESplit,
|
|
21
|
-
} from './split.js';
|
|
22
|
-
export {
|
|
23
|
-
defineSelectComponents,
|
|
24
|
-
GESelect,
|
|
25
|
-
} from './select.js';
|
|
26
|
-
export {
|
|
27
|
-
defineTabsComponents,
|
|
28
|
-
GETabs,
|
|
29
|
-
} from './tabs.js';
|
|
30
|
-
export {
|
|
31
|
-
defineContextMenuComponents,
|
|
32
|
-
GEContextMenu,
|
|
33
|
-
} from './context-menu.js';
|
|
34
|
-
export {
|
|
35
|
-
defineDropdownComponents,
|
|
36
|
-
GEDropdown,
|
|
37
|
-
} from './dropdown.js';
|
|
38
|
-
export {
|
|
39
|
-
defineTooltipComponents,
|
|
40
|
-
GETooltip,
|
|
41
|
-
} from './tooltip.js';
|
|
42
|
-
export {
|
|
43
|
-
defineCheckboxComponents,
|
|
44
|
-
GECheckbox,
|
|
45
|
-
} from './checkbox.js';
|
|
46
|
-
export {
|
|
47
|
-
defineRadioComponents,
|
|
48
|
-
GERadio,
|
|
49
|
-
} from './radio.js';
|
|
50
|
-
export {
|
|
51
|
-
defineDialogComponents,
|
|
52
|
-
GEDialog,
|
|
53
|
-
} from './dialog.js';
|
|
54
|
-
export {
|
|
55
|
-
defineInputComponents,
|
|
56
|
-
GEInput,
|
|
57
|
-
} from './input.js';
|
|
58
|
-
export type {
|
|
59
|
-
GESplitDirection,
|
|
60
|
-
GESplitRatioChangeDetail,
|
|
61
|
-
} from './split.js';
|
|
62
|
-
export type {
|
|
63
|
-
GESelectChangeDetail,
|
|
64
|
-
GESelectOption,
|
|
65
|
-
} from './select.js';
|
|
66
|
-
export type {
|
|
67
|
-
GETabChangeDetail,
|
|
68
|
-
GETabOption,
|
|
69
|
-
} from './tabs.js';
|
|
70
|
-
export type {
|
|
71
|
-
GEContextMenuItem,
|
|
72
|
-
GEContextMenuSelectDetail,
|
|
73
|
-
} from './context-menu.js';
|
|
74
|
-
export type {
|
|
75
|
-
GEDropdownItem,
|
|
76
|
-
GEDropdownPlacement,
|
|
77
|
-
GEDropdownSelectDetail,
|
|
78
|
-
} from './dropdown.js';
|
|
79
|
-
export type {
|
|
80
|
-
GETooltipPlacement,
|
|
81
|
-
} from './tooltip.js';
|
|
82
|
-
export type {
|
|
83
|
-
GECheckboxChangeDetail,
|
|
84
|
-
} from './checkbox.js';
|
|
85
|
-
export type {
|
|
86
|
-
GERadioChangeDetail,
|
|
87
|
-
} from './radio.js';
|
|
88
|
-
export type {
|
|
89
|
-
GEDialogCloseDetail,
|
|
90
|
-
GEDialogCloseReason,
|
|
91
|
-
} from './dialog.js';
|
|
92
|
-
export type {
|
|
93
|
-
GEInputChangeDetail,
|
|
94
|
-
GEInputType,
|
|
95
|
-
} from './input.js';
|
|
96
|
-
export type {
|
|
97
|
-
GETreeDataChangeDetail,
|
|
98
|
-
GETreeDropPosition,
|
|
99
|
-
GETreeNodeContextMenuDetail,
|
|
100
|
-
GETreeNodeData,
|
|
101
|
-
GETreeSelectionChangeDetail,
|
|
102
|
-
} from './tree.js';
|
|
103
|
-
|
|
104
|
-
export class GEButton extends HTMLElement {
|
|
105
|
-
private readonly _button = document.createElement('button');
|
|
106
|
-
private readonly _slot = document.createElement('slot');
|
|
107
|
-
|
|
108
|
-
static get observedAttributes(): string[] {
|
|
109
|
-
return ['label', 'disabled', 'aria-label', 'title', 'icon-only'];
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
constructor() {
|
|
113
|
-
super();
|
|
114
|
-
const root = this.attachShadow({ mode: 'open' });
|
|
115
|
-
const style = document.createElement('style');
|
|
116
|
-
style.textContent = `
|
|
117
|
-
:host { display: inline-block; }
|
|
118
|
-
button {
|
|
119
|
-
min-height: 28px;
|
|
120
|
-
padding: 0 10px;
|
|
121
|
-
border: 1px solid #3d4654;
|
|
122
|
-
border-radius: 4px;
|
|
123
|
-
background: #202733;
|
|
124
|
-
color: #eef3ff;
|
|
125
|
-
font: 12px system-ui, sans-serif;
|
|
126
|
-
cursor: pointer;
|
|
127
|
-
}
|
|
128
|
-
button.icon-only {
|
|
129
|
-
width: 28px;
|
|
130
|
-
padding: 0;
|
|
131
|
-
display: inline-grid;
|
|
132
|
-
place-items: center;
|
|
133
|
-
}
|
|
134
|
-
::slotted(svg) {
|
|
135
|
-
width: 16px;
|
|
136
|
-
height: 16px;
|
|
137
|
-
display: block;
|
|
138
|
-
fill: none;
|
|
139
|
-
stroke: currentColor;
|
|
140
|
-
stroke-width: 2;
|
|
141
|
-
stroke-linecap: round;
|
|
142
|
-
stroke-linejoin: round;
|
|
143
|
-
}
|
|
144
|
-
button:disabled {
|
|
145
|
-
opacity: 0.5;
|
|
146
|
-
cursor: default;
|
|
147
|
-
}
|
|
148
|
-
`;
|
|
149
|
-
root.append(style, this._button);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
connectedCallback(): void {
|
|
153
|
-
this._sync();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
attributeChangedCallback(): void {
|
|
157
|
-
this._sync();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private _sync(): void {
|
|
161
|
-
const label = this.getAttribute('label');
|
|
162
|
-
if (label !== null) {
|
|
163
|
-
this._button.textContent = label;
|
|
164
|
-
this._button.classList.remove('icon-only');
|
|
165
|
-
this._button.removeAttribute('aria-label');
|
|
166
|
-
} else {
|
|
167
|
-
if (this._button.firstChild !== this._slot) this._button.replaceChildren(this._slot);
|
|
168
|
-
this._button.classList.toggle('icon-only', this.hasAttribute('icon-only'));
|
|
169
|
-
const accessibleLabel = this.getAttribute('aria-label') ?? this.getAttribute('title') ?? '';
|
|
170
|
-
if (accessibleLabel) this._button.setAttribute('aria-label', accessibleLabel);
|
|
171
|
-
else this._button.removeAttribute('aria-label');
|
|
172
|
-
}
|
|
173
|
-
this._button.disabled = this.hasAttribute('disabled');
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export function defineHaiyueUI(): void {
|
|
178
|
-
if (!customElements.get('ge-button')) {
|
|
179
|
-
customElements.define('ge-button', GEButton);
|
|
180
|
-
}
|
|
181
|
-
defineTreeComponents();
|
|
182
|
-
defineSplitComponents();
|
|
183
|
-
defineSelectComponents();
|
|
184
|
-
defineTabsComponents();
|
|
185
|
-
defineContextMenuComponents();
|
|
186
|
-
defineDropdownComponents();
|
|
187
|
-
defineTooltipComponents();
|
|
188
|
-
defineCheckboxComponents();
|
|
189
|
-
defineRadioComponents();
|
|
190
|
-
defineDialogComponents();
|
|
191
|
-
defineInputComponents();
|
|
192
|
-
}
|
package/src/input.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
export type GEInputType = 'text' | 'number' | 'color';
|
|
2
|
-
|
|
3
|
-
export interface GEInputChangeDetail {
|
|
4
|
-
value: string;
|
|
5
|
-
valueAsNumber: number | null;
|
|
6
|
-
valid: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class GEInput extends HTMLElement {
|
|
10
|
-
private readonly _input = document.createElement('input');
|
|
11
|
-
|
|
12
|
-
static get observedAttributes(): string[] {
|
|
13
|
-
return [
|
|
14
|
-
'type', 'value', 'min', 'max', 'step', 'placeholder', 'disabled', 'readonly',
|
|
15
|
-
'required', 'name', 'autocomplete', 'aria-label', 'title',
|
|
16
|
-
];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
const root = this.attachShadow({ mode: 'open' });
|
|
22
|
-
const style = document.createElement('style');
|
|
23
|
-
style.textContent = `
|
|
24
|
-
:host {
|
|
25
|
-
display: block;
|
|
26
|
-
width: 100%;
|
|
27
|
-
min-width: 0;
|
|
28
|
-
}
|
|
29
|
-
input {
|
|
30
|
-
box-sizing: border-box;
|
|
31
|
-
width: 100%;
|
|
32
|
-
height: var(--ge-input-height, 28px);
|
|
33
|
-
min-width: 0;
|
|
34
|
-
padding: 0 8px;
|
|
35
|
-
border: 1px solid var(--ge-border-color, #303746);
|
|
36
|
-
border-radius: 4px;
|
|
37
|
-
outline: none;
|
|
38
|
-
color: var(--ge-text-color, #d8e2f2);
|
|
39
|
-
background: var(--ge-input-bg-color, var(--ge-surface-color, #121822));
|
|
40
|
-
font: var(--ge-input-font, 12px system-ui, sans-serif);
|
|
41
|
-
color-scheme: dark;
|
|
42
|
-
}
|
|
43
|
-
input:hover:not(:disabled):not(:read-only) {
|
|
44
|
-
border-color: var(--ge-hover-border-color, #435268);
|
|
45
|
-
}
|
|
46
|
-
input:focus {
|
|
47
|
-
border-color: var(--ge-focus-border-color, #3d6fa8);
|
|
48
|
-
box-shadow: 0 0 0 2px var(--ge-focus-ring-color, rgba(61, 111, 168, 0.24));
|
|
49
|
-
}
|
|
50
|
-
input:invalid {
|
|
51
|
-
border-color: var(--ge-invalid-border-color, #b64f62);
|
|
52
|
-
}
|
|
53
|
-
input:disabled,
|
|
54
|
-
input:read-only {
|
|
55
|
-
opacity: 0.55;
|
|
56
|
-
cursor: default;
|
|
57
|
-
}
|
|
58
|
-
input[type="color"] {
|
|
59
|
-
padding: 3px;
|
|
60
|
-
cursor: pointer;
|
|
61
|
-
}
|
|
62
|
-
input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
|
|
63
|
-
input[type="color"]::-webkit-color-swatch {
|
|
64
|
-
border: 0;
|
|
65
|
-
border-radius: 2px;
|
|
66
|
-
}
|
|
67
|
-
`;
|
|
68
|
-
root.append(style, this._input);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
connectedCallback(): void {
|
|
72
|
-
this._input.addEventListener('input', this._onInput);
|
|
73
|
-
this._input.addEventListener('change', this._onChange);
|
|
74
|
-
this._sync();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
disconnectedCallback(): void {
|
|
78
|
-
this._input.removeEventListener('input', this._onInput);
|
|
79
|
-
this._input.removeEventListener('change', this._onChange);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
attributeChangedCallback(): void {
|
|
83
|
-
this._sync();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
get type(): GEInputType { return normalizedType(this.getAttribute('type')); }
|
|
87
|
-
set type(value: GEInputType) { this.setAttribute('type', normalizedType(value)); }
|
|
88
|
-
|
|
89
|
-
get value(): string { return this.getAttribute('value') ?? ''; }
|
|
90
|
-
set value(value: string) {
|
|
91
|
-
this.setAttribute('value', String(value));
|
|
92
|
-
this._input.value = String(value);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
get valueAsNumber(): number {
|
|
96
|
-
return this._input.valueAsNumber;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
get disabled(): boolean { return this.hasAttribute('disabled'); }
|
|
100
|
-
set disabled(value: boolean) { this.toggleAttribute('disabled', value); }
|
|
101
|
-
|
|
102
|
-
get readOnly(): boolean { return this.hasAttribute('readonly'); }
|
|
103
|
-
set readOnly(value: boolean) { this.toggleAttribute('readonly', value); }
|
|
104
|
-
|
|
105
|
-
get valid(): boolean { return this._input.validity.valid; }
|
|
106
|
-
|
|
107
|
-
override focus(options?: FocusOptions): void { this._input.focus(options); }
|
|
108
|
-
select(): void { this._input.select(); }
|
|
109
|
-
|
|
110
|
-
private _sync(): void {
|
|
111
|
-
const type = this.type;
|
|
112
|
-
if (this._input.type !== type) this._input.type = type;
|
|
113
|
-
const value = this.value;
|
|
114
|
-
if (this._input.value !== value) this._input.value = type === 'color' && !/^#[0-9a-f]{6}$/iu.test(value)
|
|
115
|
-
? '#000000'
|
|
116
|
-
: value;
|
|
117
|
-
for (const name of ['min', 'max', 'step', 'placeholder', 'name', 'autocomplete', 'aria-label', 'title']) {
|
|
118
|
-
const attribute = this.getAttribute(name);
|
|
119
|
-
if (attribute === null) this._input.removeAttribute(name);
|
|
120
|
-
else this._input.setAttribute(name, attribute);
|
|
121
|
-
}
|
|
122
|
-
this._input.disabled = this.disabled;
|
|
123
|
-
this._input.readOnly = this.readOnly;
|
|
124
|
-
this._input.required = this.hasAttribute('required');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
private _onInput = (): void => {
|
|
128
|
-
this.setAttribute('value', this._input.value);
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
private _onChange = (): void => {
|
|
132
|
-
this.setAttribute('value', this._input.value);
|
|
133
|
-
const number = this.type === 'number' && Number.isFinite(this._input.valueAsNumber)
|
|
134
|
-
? this._input.valueAsNumber
|
|
135
|
-
: null;
|
|
136
|
-
this.dispatchEvent(new CustomEvent<GEInputChangeDetail>('value-change', {
|
|
137
|
-
detail: { value: this._input.value, valueAsNumber: number, valid: this.valid },
|
|
138
|
-
bubbles: true,
|
|
139
|
-
composed: true,
|
|
140
|
-
}));
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function defineInputComponents(): void {
|
|
145
|
-
if (!customElements.get('ge-input')) customElements.define('ge-input', GEInput);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function normalizedType(value: string | null): GEInputType {
|
|
149
|
-
return value === 'number' || value === 'color' ? value : 'text';
|
|
150
|
-
}
|
package/src/menu-shared.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
export interface GEMenuItemLike {
|
|
2
|
-
label?: string;
|
|
3
|
-
value?: string;
|
|
4
|
-
disabled?: boolean;
|
|
5
|
-
separator?: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface GEMenuButtonOptions {
|
|
9
|
-
index?: number;
|
|
10
|
-
role?: string;
|
|
11
|
-
tabIndex?: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const GE_MENU_ITEM_STYLES = `
|
|
15
|
-
button {
|
|
16
|
-
box-sizing: border-box;
|
|
17
|
-
width: 100%;
|
|
18
|
-
height: 26px;
|
|
19
|
-
display: flex;
|
|
20
|
-
align-items: center;
|
|
21
|
-
padding: 0 8px;
|
|
22
|
-
border: 0;
|
|
23
|
-
border-radius: 3px;
|
|
24
|
-
color: var(--ge-text-color, #d8e2f2);
|
|
25
|
-
background: transparent;
|
|
26
|
-
font: inherit;
|
|
27
|
-
text-align: left;
|
|
28
|
-
cursor: pointer;
|
|
29
|
-
}
|
|
30
|
-
button:hover,
|
|
31
|
-
button:focus,
|
|
32
|
-
button.active {
|
|
33
|
-
background: var(--ge-menu-item-hover-bg-color, var(--ge-accent-strong-color, #255a91));
|
|
34
|
-
outline: none;
|
|
35
|
-
}
|
|
36
|
-
button:disabled {
|
|
37
|
-
color: var(--ge-muted-color, #66758b);
|
|
38
|
-
cursor: default;
|
|
39
|
-
}
|
|
40
|
-
button:disabled:hover {
|
|
41
|
-
background: transparent;
|
|
42
|
-
}
|
|
43
|
-
.separator {
|
|
44
|
-
height: 1px;
|
|
45
|
-
margin: 4px 2px;
|
|
46
|
-
background: var(--ge-border-color, #303746);
|
|
47
|
-
}
|
|
48
|
-
`;
|
|
49
|
-
|
|
50
|
-
export function createMenuSeparator(): HTMLDivElement {
|
|
51
|
-
const separator = document.createElement('div');
|
|
52
|
-
separator.className = 'separator';
|
|
53
|
-
return separator;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function createMenuItemButton(item: GEMenuItemLike, options: GEMenuButtonOptions = {}): HTMLButtonElement {
|
|
57
|
-
const button = document.createElement('button');
|
|
58
|
-
button.type = 'button';
|
|
59
|
-
button.textContent = item.label ?? item.value ?? '';
|
|
60
|
-
button.disabled = Boolean(item.disabled);
|
|
61
|
-
if (options.index !== undefined) button.dataset.index = String(options.index);
|
|
62
|
-
if (options.role) button.setAttribute('role', options.role);
|
|
63
|
-
if (options.tabIndex !== undefined) button.tabIndex = options.tabIndex;
|
|
64
|
-
return button;
|
|
65
|
-
}
|