@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/dist/context-menu.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GE_MENU_ITEM_STYLES, createMenuItemButton, createMenuSeparator } from './menu-shared.js';
|
|
2
|
-
export class
|
|
2
|
+
export class HYContextMenu extends HTMLElement {
|
|
3
3
|
_root;
|
|
4
4
|
_style = document.createElement('style');
|
|
5
5
|
_menu = document.createElement('div');
|
|
@@ -18,7 +18,7 @@ export class GEContextMenu extends HTMLElement {
|
|
|
18
18
|
z-index: 10000;
|
|
19
19
|
display: none;
|
|
20
20
|
min-width: 132px;
|
|
21
|
-
color: var(--
|
|
21
|
+
color: var(--hy-text-color, #d8e2f2);
|
|
22
22
|
font: 12px system-ui, sans-serif;
|
|
23
23
|
}
|
|
24
24
|
:host([open]) {
|
|
@@ -28,10 +28,10 @@ export class GEContextMenu extends HTMLElement {
|
|
|
28
28
|
box-sizing: border-box;
|
|
29
29
|
min-width: 132px;
|
|
30
30
|
padding: 4px;
|
|
31
|
-
border: 1px solid var(--
|
|
31
|
+
border: 1px solid var(--hy-border-color, #303746);
|
|
32
32
|
border-radius: 4px;
|
|
33
|
-
background: var(--
|
|
34
|
-
box-shadow: 0 10px 26px var(--
|
|
33
|
+
background: var(--hy-menu-bg-color, var(--hy-surface-elevated-color, #1b2230));
|
|
34
|
+
box-shadow: 0 10px 26px var(--hy-menu-shadow-color, rgba(0, 0, 0, 0.36));
|
|
35
35
|
}
|
|
36
36
|
${GE_MENU_ITEM_STYLES}
|
|
37
37
|
`;
|
|
@@ -107,7 +107,7 @@ ${GE_MENU_ITEM_STYLES}
|
|
|
107
107
|
this._items = Array.isArray(parsed) ? parsed : [];
|
|
108
108
|
}
|
|
109
109
|
catch (error) {
|
|
110
|
-
console.warn('Invalid
|
|
110
|
+
console.warn('Invalid hy-context-menu items attribute.', error);
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
_render() {
|
|
@@ -188,7 +188,9 @@ ${GE_MENU_ITEM_STYLES}
|
|
|
188
188
|
_nextEnabledIndex(direction) {
|
|
189
189
|
if (!this._items.length)
|
|
190
190
|
return -1;
|
|
191
|
-
|
|
191
|
+
let start = this._activeIndex;
|
|
192
|
+
if (start < 0)
|
|
193
|
+
start = direction > 0 ? -1 : this._items.length;
|
|
192
194
|
for (let step = 1; step <= this._items.length; step++) {
|
|
193
195
|
const index = (start + direction * step + this._items.length) % this._items.length;
|
|
194
196
|
if (this._isEnabledItem(index))
|
|
@@ -218,8 +220,8 @@ function getVisualViewportRect() {
|
|
|
218
220
|
: { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight };
|
|
219
221
|
}
|
|
220
222
|
export function defineContextMenuComponents() {
|
|
221
|
-
if (!customElements.get('
|
|
222
|
-
customElements.define('
|
|
223
|
+
if (!customElements.get('hy-context-menu')) {
|
|
224
|
+
customElements.define('hy-context-menu', HYContextMenu);
|
|
223
225
|
}
|
|
224
226
|
}
|
|
225
227
|
//# sourceMappingURL=context-menu.js.map
|
package/dist/dialog.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export interface
|
|
3
|
-
readonly reason:
|
|
1
|
+
export type HYDialogCloseReason = 'action' | 'backdrop' | 'escape' | 'programmatic';
|
|
2
|
+
export interface HYDialogCloseDetail {
|
|
3
|
+
readonly reason: HYDialogCloseReason | string;
|
|
4
4
|
}
|
|
5
5
|
/** Accessible modal surface with slotted body/footer content and reflected open state. */
|
|
6
|
-
export declare class
|
|
6
|
+
export declare class HYDialog extends HTMLElement {
|
|
7
7
|
private readonly _dialog;
|
|
8
8
|
private readonly _title;
|
|
9
9
|
private readonly _closeButton;
|
|
@@ -20,7 +20,7 @@ export declare class GEDialog extends HTMLElement {
|
|
|
20
20
|
get heading(): string;
|
|
21
21
|
set heading(value: string);
|
|
22
22
|
showModal(): void;
|
|
23
|
-
close(reason?:
|
|
23
|
+
close(reason?: HYDialogCloseDetail['reason']): void;
|
|
24
24
|
private _syncHeading;
|
|
25
25
|
private _syncOpen;
|
|
26
26
|
private _onCancel;
|
package/dist/dialog.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Accessible modal surface with slotted body/footer content and reflected open state. */
|
|
2
|
-
export class
|
|
2
|
+
export class HYDialog extends HTMLElement {
|
|
3
3
|
_dialog = document.createElement('dialog');
|
|
4
4
|
_title = document.createElement('h2');
|
|
5
5
|
_closeButton = document.createElement('button');
|
|
@@ -14,31 +14,31 @@ export class GEDialog extends HTMLElement {
|
|
|
14
14
|
const style = document.createElement('style');
|
|
15
15
|
style.textContent = `
|
|
16
16
|
:host {
|
|
17
|
-
color: var(--
|
|
17
|
+
color: var(--hy-text-color, #e6edf7);
|
|
18
18
|
font: 13px system-ui, sans-serif;
|
|
19
19
|
}
|
|
20
20
|
dialog {
|
|
21
|
-
width: min(var(--
|
|
21
|
+
width: min(var(--hy-dialog-width, 460px), calc(100vw - 32px));
|
|
22
22
|
max-height: calc(100vh - 32px);
|
|
23
23
|
margin: auto;
|
|
24
24
|
padding: 0;
|
|
25
25
|
overflow: hidden;
|
|
26
|
-
border: 1px solid var(--
|
|
27
|
-
border-radius: var(--
|
|
26
|
+
border: 1px solid var(--hy-border-color, #303746);
|
|
27
|
+
border-radius: var(--hy-dialog-radius, 8px);
|
|
28
28
|
color: inherit;
|
|
29
|
-
background: var(--
|
|
30
|
-
box-shadow: 0 22px 70px var(--
|
|
29
|
+
background: var(--hy-dialog-bg-color, var(--hy-surface-elevated-color, #171e2a));
|
|
30
|
+
box-shadow: 0 22px 70px var(--hy-dialog-shadow-color, rgba(0, 0, 0, 0.52));
|
|
31
31
|
}
|
|
32
32
|
dialog::backdrop {
|
|
33
|
-
background: var(--
|
|
34
|
-
backdrop-filter: blur(var(--
|
|
33
|
+
background: var(--hy-dialog-backdrop-color, rgba(3, 7, 12, 0.66));
|
|
34
|
+
backdrop-filter: blur(var(--hy-dialog-backdrop-blur, 2px));
|
|
35
35
|
}
|
|
36
36
|
.header {
|
|
37
37
|
display: flex;
|
|
38
38
|
align-items: center;
|
|
39
39
|
min-height: 49px;
|
|
40
40
|
padding: 0 12px 0 16px;
|
|
41
|
-
border-bottom: 1px solid var(--
|
|
41
|
+
border-bottom: 1px solid var(--hy-border-color, #303746);
|
|
42
42
|
}
|
|
43
43
|
h2 {
|
|
44
44
|
flex: 1;
|
|
@@ -56,18 +56,18 @@ export class GEDialog extends HTMLElement {
|
|
|
56
56
|
height: 28px;
|
|
57
57
|
border: 0;
|
|
58
58
|
border-radius: 5px;
|
|
59
|
-
color: var(--
|
|
59
|
+
color: var(--hy-secondary-text-color, #8b99ad);
|
|
60
60
|
background: transparent;
|
|
61
61
|
cursor: pointer;
|
|
62
62
|
font: 20px/1 system-ui, sans-serif;
|
|
63
63
|
}
|
|
64
64
|
:host([dismissible]) .close { display: grid; place-items: center; }
|
|
65
|
-
.close:hover { color: inherit; background: var(--
|
|
65
|
+
.close:hover { color: inherit; background: var(--hy-hover-bg-color, #242d3b); }
|
|
66
66
|
.body {
|
|
67
67
|
max-height: calc(100vh - 160px);
|
|
68
68
|
overflow: auto;
|
|
69
|
-
padding: var(--
|
|
70
|
-
color: var(--
|
|
69
|
+
padding: var(--hy-dialog-body-padding, 16px);
|
|
70
|
+
color: var(--hy-dialog-body-color, var(--hy-secondary-text-color, #a8b4c5));
|
|
71
71
|
line-height: 1.55;
|
|
72
72
|
}
|
|
73
73
|
.footer {
|
|
@@ -76,8 +76,8 @@ export class GEDialog extends HTMLElement {
|
|
|
76
76
|
gap: 8px;
|
|
77
77
|
min-height: 54px;
|
|
78
78
|
padding: 10px 14px;
|
|
79
|
-
border-top: 1px solid var(--
|
|
80
|
-
background: var(--
|
|
79
|
+
border-top: 1px solid var(--hy-border-color, #303746);
|
|
80
|
+
background: var(--hy-dialog-footer-bg-color, rgba(9, 13, 19, 0.22));
|
|
81
81
|
}
|
|
82
82
|
slot[name="footer"]::slotted(*) { margin: 0; }
|
|
83
83
|
`;
|
|
@@ -177,7 +177,7 @@ export class GEDialog extends HTMLElement {
|
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
export function defineDialogComponents() {
|
|
180
|
-
if (!customElements.get('
|
|
181
|
-
customElements.define('
|
|
180
|
+
if (!customElements.get('hy-dialog'))
|
|
181
|
+
customElements.define('hy-dialog', HYDialog);
|
|
182
182
|
}
|
|
183
183
|
//# sourceMappingURL=dialog.js.map
|
package/dist/drawer.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type HYDrawerPlacement = 'top' | 'right' | 'bottom' | 'left';
|
|
2
|
+
export type HYDrawerCloseReason = 'action' | 'mask' | 'escape' | 'programmatic';
|
|
3
|
+
export interface HYDrawerCloseDetail {
|
|
4
|
+
readonly reason: HYDrawerCloseReason | string;
|
|
5
|
+
}
|
|
6
|
+
/** Sliding dialog surface with optional mask and hidden-content unmounting. */
|
|
7
|
+
export declare class HYDrawer extends HTMLElement {
|
|
8
|
+
private readonly _panel;
|
|
9
|
+
private readonly _title;
|
|
10
|
+
private readonly _closeButton;
|
|
11
|
+
private readonly _footer;
|
|
12
|
+
private readonly _footerSlot;
|
|
13
|
+
private readonly _detachedContent;
|
|
14
|
+
private _documentListenerAbort;
|
|
15
|
+
private _destroyTimer;
|
|
16
|
+
private _returnFocus;
|
|
17
|
+
private _closeReason;
|
|
18
|
+
private _wasOpen;
|
|
19
|
+
static get observedAttributes(): string[];
|
|
20
|
+
constructor();
|
|
21
|
+
connectedCallback(): void;
|
|
22
|
+
disconnectedCallback(): void;
|
|
23
|
+
attributeChangedCallback(name: string): void;
|
|
24
|
+
get open(): boolean;
|
|
25
|
+
set open(value: boolean);
|
|
26
|
+
get heading(): string;
|
|
27
|
+
set heading(value: string);
|
|
28
|
+
get placement(): HYDrawerPlacement;
|
|
29
|
+
set placement(value: HYDrawerPlacement);
|
|
30
|
+
/** The mask defaults to true; use mask="false" or set the property to false to disable it. */
|
|
31
|
+
get mask(): boolean;
|
|
32
|
+
set mask(value: boolean);
|
|
33
|
+
get destroyOnHidden(): boolean;
|
|
34
|
+
set destroyOnHidden(value: boolean);
|
|
35
|
+
show(): void;
|
|
36
|
+
close(reason?: HYDrawerCloseDetail['reason']): void;
|
|
37
|
+
private _syncHeading;
|
|
38
|
+
private _syncPlacement;
|
|
39
|
+
private _syncFooter;
|
|
40
|
+
private _syncPanelSemantics;
|
|
41
|
+
private _syncOpen;
|
|
42
|
+
private _attachDocumentListener;
|
|
43
|
+
private _detachDocumentListener;
|
|
44
|
+
private _onDocumentKeyDown;
|
|
45
|
+
private _scheduleContentDestroy;
|
|
46
|
+
private _cancelContentDestroy;
|
|
47
|
+
private _restoreContent;
|
|
48
|
+
}
|
|
49
|
+
export declare function defineDrawerComponents(): void;
|
package/dist/drawer.js
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
const CONTENT_DESTROY_DELAY = 220;
|
|
2
|
+
const FOCUSABLE_SELECTOR = [
|
|
3
|
+
'a[href]',
|
|
4
|
+
'button:not([disabled])',
|
|
5
|
+
'input:not([disabled])',
|
|
6
|
+
'select:not([disabled])',
|
|
7
|
+
'textarea:not([disabled])',
|
|
8
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
9
|
+
].join(',');
|
|
10
|
+
const DRAWER_STYLES = `
|
|
11
|
+
:host {
|
|
12
|
+
position: fixed;
|
|
13
|
+
z-index: var(--hy-drawer-z-index, 1000);
|
|
14
|
+
inset: 0;
|
|
15
|
+
display: block;
|
|
16
|
+
pointer-events: none;
|
|
17
|
+
color: var(--hy-text-color, #e6edf7);
|
|
18
|
+
font: 13px/1.5 system-ui, sans-serif;
|
|
19
|
+
--_duration: var(--hy-drawer-duration, 200ms);
|
|
20
|
+
}
|
|
21
|
+
.root {
|
|
22
|
+
position: absolute;
|
|
23
|
+
inset: 0;
|
|
24
|
+
visibility: hidden;
|
|
25
|
+
transition: visibility 0s linear var(--_duration);
|
|
26
|
+
}
|
|
27
|
+
:host([open]) .root {
|
|
28
|
+
visibility: visible;
|
|
29
|
+
transition-delay: 0s;
|
|
30
|
+
}
|
|
31
|
+
.mask {
|
|
32
|
+
position: absolute;
|
|
33
|
+
inset: 0;
|
|
34
|
+
opacity: 0;
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
background: var(--hy-drawer-mask-color, rgba(3, 7, 18, 0.58));
|
|
37
|
+
backdrop-filter: blur(var(--hy-drawer-mask-blur, 1px));
|
|
38
|
+
transition: opacity var(--_duration) ease;
|
|
39
|
+
}
|
|
40
|
+
:host([open]) .mask { opacity: 1; pointer-events: auto; }
|
|
41
|
+
:host([mask="false"]) .mask { display: none; }
|
|
42
|
+
.panel {
|
|
43
|
+
position: absolute;
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
width: min(var(--hy-drawer-width, 378px), calc(100vw - 24px));
|
|
47
|
+
height: 100%;
|
|
48
|
+
max-width: 100vw;
|
|
49
|
+
max-height: 100vh;
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
pointer-events: auto;
|
|
52
|
+
outline: none;
|
|
53
|
+
color: inherit;
|
|
54
|
+
background: var(--hy-drawer-bg-color, var(--hy-surface-elevated-color, #171e2a));
|
|
55
|
+
box-shadow: 0 0 54px var(--hy-drawer-shadow-color, rgba(0, 0, 0, 0.42));
|
|
56
|
+
transition: transform var(--_duration) cubic-bezier(0.22, 1, 0.36, 1);
|
|
57
|
+
box-sizing: border-box;
|
|
58
|
+
}
|
|
59
|
+
:host(:not([placement])) .panel, :host([placement="right"]) .panel {
|
|
60
|
+
inset: 0 0 0 auto;
|
|
61
|
+
border-left: 1px solid var(--hy-border-color, #303746);
|
|
62
|
+
transform: translateX(100%);
|
|
63
|
+
}
|
|
64
|
+
:host([placement="left"]) .panel {
|
|
65
|
+
inset: 0 auto 0 0;
|
|
66
|
+
border-right: 1px solid var(--hy-border-color, #303746);
|
|
67
|
+
transform: translateX(-100%);
|
|
68
|
+
}
|
|
69
|
+
:host([placement="top"]) .panel,
|
|
70
|
+
:host([placement="bottom"]) .panel {
|
|
71
|
+
width: 100%;
|
|
72
|
+
height: min(var(--hy-drawer-height, 320px), calc(100vh - 24px));
|
|
73
|
+
}
|
|
74
|
+
:host([placement="top"]) .panel {
|
|
75
|
+
inset: 0 0 auto;
|
|
76
|
+
border-bottom: 1px solid var(--hy-border-color, #303746);
|
|
77
|
+
transform: translateY(-100%);
|
|
78
|
+
}
|
|
79
|
+
:host([placement="bottom"]) .panel {
|
|
80
|
+
inset: auto 0 0;
|
|
81
|
+
border-top: 1px solid var(--hy-border-color, #303746);
|
|
82
|
+
transform: translateY(100%);
|
|
83
|
+
}
|
|
84
|
+
:host([open]) .panel { transform: translate(0); }
|
|
85
|
+
.header {
|
|
86
|
+
display: flex;
|
|
87
|
+
flex: 0 0 auto;
|
|
88
|
+
align-items: center;
|
|
89
|
+
min-height: 52px;
|
|
90
|
+
padding: 0 12px 0 18px;
|
|
91
|
+
border-bottom: 1px solid var(--hy-border-color, #303746);
|
|
92
|
+
}
|
|
93
|
+
h2 {
|
|
94
|
+
flex: 1;
|
|
95
|
+
min-width: 0;
|
|
96
|
+
margin: 0;
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
font-size: 14px;
|
|
99
|
+
font-weight: 650;
|
|
100
|
+
text-overflow: ellipsis;
|
|
101
|
+
white-space: nowrap;
|
|
102
|
+
}
|
|
103
|
+
.close {
|
|
104
|
+
display: grid;
|
|
105
|
+
width: 30px;
|
|
106
|
+
height: 30px;
|
|
107
|
+
padding: 0;
|
|
108
|
+
border: 0;
|
|
109
|
+
border-radius: 5px;
|
|
110
|
+
place-items: center;
|
|
111
|
+
color: var(--hy-secondary-text-color, #8b99ad);
|
|
112
|
+
background: transparent;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
font: 20px/1 system-ui, sans-serif;
|
|
115
|
+
}
|
|
116
|
+
.close:hover { color: inherit; background: var(--hy-hover-bg-color, #242d3b); }
|
|
117
|
+
.close:focus-visible, .panel:focus-visible {
|
|
118
|
+
outline: 2px solid var(--hy-focus-border-color, #79a8ff);
|
|
119
|
+
outline-offset: -2px;
|
|
120
|
+
}
|
|
121
|
+
.body {
|
|
122
|
+
flex: 1 1 auto;
|
|
123
|
+
min-height: 0;
|
|
124
|
+
overflow: auto;
|
|
125
|
+
padding: var(--hy-drawer-body-padding, 18px);
|
|
126
|
+
color: var(--hy-secondary-text-color, #a8b4c5);
|
|
127
|
+
}
|
|
128
|
+
.footer {
|
|
129
|
+
display: flex;
|
|
130
|
+
flex: 0 0 auto;
|
|
131
|
+
justify-content: flex-end;
|
|
132
|
+
gap: 8px;
|
|
133
|
+
min-height: 56px;
|
|
134
|
+
padding: 10px 16px;
|
|
135
|
+
border-top: 1px solid var(--hy-border-color, #303746);
|
|
136
|
+
background: var(--hy-drawer-footer-bg-color, rgba(9, 13, 19, 0.22));
|
|
137
|
+
box-sizing: border-box;
|
|
138
|
+
}
|
|
139
|
+
.footer[hidden] { display: none; }
|
|
140
|
+
slot[name="footer"]::slotted(*) { margin: 0; }
|
|
141
|
+
@media (prefers-reduced-motion: reduce) {
|
|
142
|
+
:host { --_duration: 1ms; }
|
|
143
|
+
}
|
|
144
|
+
`;
|
|
145
|
+
/** Sliding dialog surface with optional mask and hidden-content unmounting. */
|
|
146
|
+
export class HYDrawer extends HTMLElement {
|
|
147
|
+
_panel = document.createElement('section');
|
|
148
|
+
_title = document.createElement('h2');
|
|
149
|
+
_closeButton = document.createElement('button');
|
|
150
|
+
_footer = document.createElement('footer');
|
|
151
|
+
_footerSlot = document.createElement('slot');
|
|
152
|
+
_detachedContent = document.createDocumentFragment();
|
|
153
|
+
_documentListenerAbort = null;
|
|
154
|
+
_destroyTimer = null;
|
|
155
|
+
_returnFocus = null;
|
|
156
|
+
_closeReason = 'programmatic';
|
|
157
|
+
_wasOpen = false;
|
|
158
|
+
static get observedAttributes() {
|
|
159
|
+
return ['open', 'heading', 'placement', 'mask', 'destroy-on-hidden'];
|
|
160
|
+
}
|
|
161
|
+
constructor() {
|
|
162
|
+
super();
|
|
163
|
+
const root = this.attachShadow({ mode: 'open' });
|
|
164
|
+
const style = document.createElement('style');
|
|
165
|
+
style.textContent = DRAWER_STYLES;
|
|
166
|
+
const container = document.createElement('div');
|
|
167
|
+
container.className = 'root';
|
|
168
|
+
const mask = document.createElement('div');
|
|
169
|
+
mask.className = 'mask';
|
|
170
|
+
mask.part.add('mask');
|
|
171
|
+
mask.setAttribute('aria-hidden', 'true');
|
|
172
|
+
this._panel.className = 'panel';
|
|
173
|
+
this._panel.part.add('panel');
|
|
174
|
+
this._panel.setAttribute('role', 'dialog');
|
|
175
|
+
this._panel.setAttribute('aria-labelledby', 'drawer-title');
|
|
176
|
+
this._panel.setAttribute('aria-hidden', 'true');
|
|
177
|
+
this._panel.tabIndex = -1;
|
|
178
|
+
const header = document.createElement('header');
|
|
179
|
+
header.className = 'header';
|
|
180
|
+
header.part.add('header');
|
|
181
|
+
this._title.id = 'drawer-title';
|
|
182
|
+
this._closeButton.className = 'close';
|
|
183
|
+
this._closeButton.part.add('close-button');
|
|
184
|
+
this._closeButton.type = 'button';
|
|
185
|
+
this._closeButton.setAttribute('aria-label', 'Close drawer');
|
|
186
|
+
this._closeButton.textContent = '×';
|
|
187
|
+
header.append(this._title, this._closeButton);
|
|
188
|
+
const body = document.createElement('div');
|
|
189
|
+
body.className = 'body';
|
|
190
|
+
body.part.add('body');
|
|
191
|
+
body.append(document.createElement('slot'));
|
|
192
|
+
this._footer.className = 'footer';
|
|
193
|
+
this._footer.part.add('footer');
|
|
194
|
+
this._footerSlot.name = 'footer';
|
|
195
|
+
this._footer.append(this._footerSlot);
|
|
196
|
+
this._panel.append(header, body, this._footer);
|
|
197
|
+
container.append(mask, this._panel);
|
|
198
|
+
root.append(style, container);
|
|
199
|
+
mask.addEventListener('click', () => this.close('mask'));
|
|
200
|
+
this._closeButton.addEventListener('click', () => this.close('action'));
|
|
201
|
+
this._footerSlot.addEventListener('slotchange', () => this._syncFooter());
|
|
202
|
+
}
|
|
203
|
+
connectedCallback() {
|
|
204
|
+
this._syncPlacement();
|
|
205
|
+
this._syncHeading();
|
|
206
|
+
this._syncFooter();
|
|
207
|
+
this._syncOpen();
|
|
208
|
+
}
|
|
209
|
+
disconnectedCallback() {
|
|
210
|
+
this._detachDocumentListener();
|
|
211
|
+
this._cancelContentDestroy();
|
|
212
|
+
this._returnFocus = null;
|
|
213
|
+
this._wasOpen = false;
|
|
214
|
+
}
|
|
215
|
+
attributeChangedCallback(name) {
|
|
216
|
+
if (name === 'heading')
|
|
217
|
+
this._syncHeading();
|
|
218
|
+
if (name === 'placement')
|
|
219
|
+
this._syncPlacement();
|
|
220
|
+
if (name === 'mask')
|
|
221
|
+
this._syncPanelSemantics();
|
|
222
|
+
if (name === 'open' && this.isConnected)
|
|
223
|
+
this._syncOpen();
|
|
224
|
+
if (name === 'destroy-on-hidden' && this.isConnected && !this.open) {
|
|
225
|
+
if (this.destroyOnHidden)
|
|
226
|
+
this._scheduleContentDestroy(0);
|
|
227
|
+
else
|
|
228
|
+
this._restoreContent();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
get open() { return this.hasAttribute('open'); }
|
|
232
|
+
set open(value) { this.toggleAttribute('open', Boolean(value)); }
|
|
233
|
+
get heading() { return this.getAttribute('heading') ?? ''; }
|
|
234
|
+
set heading(value) { this.setAttribute('heading', String(value)); }
|
|
235
|
+
get placement() {
|
|
236
|
+
const value = this.getAttribute('placement');
|
|
237
|
+
return value === 'top' || value === 'bottom' || value === 'left' ? value : 'right';
|
|
238
|
+
}
|
|
239
|
+
set placement(value) {
|
|
240
|
+
this.setAttribute('placement', value === 'top' || value === 'bottom' || value === 'left' ? value : 'right');
|
|
241
|
+
}
|
|
242
|
+
/** The mask defaults to true; use mask="false" or set the property to false to disable it. */
|
|
243
|
+
get mask() { return this.getAttribute('mask') !== 'false'; }
|
|
244
|
+
set mask(value) { this.setAttribute('mask', String(Boolean(value))); }
|
|
245
|
+
get destroyOnHidden() { return this.hasAttribute('destroy-on-hidden'); }
|
|
246
|
+
set destroyOnHidden(value) { this.toggleAttribute('destroy-on-hidden', Boolean(value)); }
|
|
247
|
+
show() {
|
|
248
|
+
if (this.open)
|
|
249
|
+
return;
|
|
250
|
+
this._closeReason = 'programmatic';
|
|
251
|
+
this.open = true;
|
|
252
|
+
}
|
|
253
|
+
close(reason = 'programmatic') {
|
|
254
|
+
if (!this.open)
|
|
255
|
+
return;
|
|
256
|
+
this._closeReason = reason;
|
|
257
|
+
this.open = false;
|
|
258
|
+
}
|
|
259
|
+
_syncHeading() {
|
|
260
|
+
this._title.textContent = this.heading || 'Drawer';
|
|
261
|
+
}
|
|
262
|
+
_syncPlacement() {
|
|
263
|
+
const value = this.getAttribute('placement');
|
|
264
|
+
if (value !== null && value !== 'top' && value !== 'right' && value !== 'bottom' && value !== 'left') {
|
|
265
|
+
this.setAttribute('placement', 'right');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
_syncFooter() {
|
|
269
|
+
this._footer.hidden = this._footerSlot.assignedElements().length === 0;
|
|
270
|
+
}
|
|
271
|
+
_syncPanelSemantics() {
|
|
272
|
+
if (this.open && this.mask)
|
|
273
|
+
this._panel.setAttribute('aria-modal', 'true');
|
|
274
|
+
else
|
|
275
|
+
this._panel.removeAttribute('aria-modal');
|
|
276
|
+
}
|
|
277
|
+
_syncOpen() {
|
|
278
|
+
if (this.open) {
|
|
279
|
+
this._cancelContentDestroy();
|
|
280
|
+
this._restoreContent();
|
|
281
|
+
this._returnFocus ??= document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
282
|
+
this._panel.setAttribute('aria-hidden', 'false');
|
|
283
|
+
this._syncPanelSemantics();
|
|
284
|
+
this._attachDocumentListener();
|
|
285
|
+
this._wasOpen = true;
|
|
286
|
+
queueMicrotask(() => {
|
|
287
|
+
if (this.open && this.isConnected)
|
|
288
|
+
this._closeButton.focus();
|
|
289
|
+
});
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
this._panel.setAttribute('aria-hidden', 'true');
|
|
293
|
+
this._syncPanelSemantics();
|
|
294
|
+
this._detachDocumentListener();
|
|
295
|
+
this._scheduleContentDestroy(this._wasOpen ? CONTENT_DESTROY_DELAY : 0);
|
|
296
|
+
if (!this._wasOpen)
|
|
297
|
+
return;
|
|
298
|
+
this._wasOpen = false;
|
|
299
|
+
const reason = this._closeReason;
|
|
300
|
+
this._closeReason = 'programmatic';
|
|
301
|
+
this.dispatchEvent(new CustomEvent('drawer-close', {
|
|
302
|
+
detail: { reason },
|
|
303
|
+
bubbles: true,
|
|
304
|
+
composed: true,
|
|
305
|
+
}));
|
|
306
|
+
this._returnFocus?.focus();
|
|
307
|
+
this._returnFocus = null;
|
|
308
|
+
}
|
|
309
|
+
_attachDocumentListener() {
|
|
310
|
+
if (this._documentListenerAbort)
|
|
311
|
+
return;
|
|
312
|
+
this._documentListenerAbort = new AbortController();
|
|
313
|
+
document.addEventListener('keydown', this._onDocumentKeyDown, {
|
|
314
|
+
capture: true,
|
|
315
|
+
signal: this._documentListenerAbort.signal,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
_detachDocumentListener() {
|
|
319
|
+
this._documentListenerAbort?.abort();
|
|
320
|
+
this._documentListenerAbort = null;
|
|
321
|
+
}
|
|
322
|
+
_onDocumentKeyDown = (event) => {
|
|
323
|
+
if (!this.open)
|
|
324
|
+
return;
|
|
325
|
+
if (event.key === 'Escape') {
|
|
326
|
+
event.preventDefault();
|
|
327
|
+
this.close('escape');
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (event.key !== 'Tab' || !this.mask)
|
|
331
|
+
return;
|
|
332
|
+
const focusable = [this._closeButton, ...this.querySelectorAll(FOCUSABLE_SELECTOR)]
|
|
333
|
+
.filter(element => !element.hidden && element.getAttribute('aria-hidden') !== 'true');
|
|
334
|
+
if (focusable.length === 0) {
|
|
335
|
+
event.preventDefault();
|
|
336
|
+
this._panel.focus();
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const active = this.shadowRoot?.activeElement ?? document.activeElement;
|
|
340
|
+
const index = focusable.indexOf(active);
|
|
341
|
+
if (event.shiftKey && index <= 0) {
|
|
342
|
+
event.preventDefault();
|
|
343
|
+
focusable[focusable.length - 1]?.focus();
|
|
344
|
+
}
|
|
345
|
+
else if (!event.shiftKey && (index < 0 || index === focusable.length - 1)) {
|
|
346
|
+
event.preventDefault();
|
|
347
|
+
focusable[0]?.focus();
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
_scheduleContentDestroy(delay) {
|
|
351
|
+
this._cancelContentDestroy();
|
|
352
|
+
if (!this.destroyOnHidden || this.open)
|
|
353
|
+
return;
|
|
354
|
+
this._destroyTimer = window.setTimeout(() => {
|
|
355
|
+
this._destroyTimer = null;
|
|
356
|
+
if (!this.open && this.destroyOnHidden)
|
|
357
|
+
this._detachedContent.append(...Array.from(this.childNodes));
|
|
358
|
+
}, delay);
|
|
359
|
+
}
|
|
360
|
+
_cancelContentDestroy() {
|
|
361
|
+
if (this._destroyTimer === null)
|
|
362
|
+
return;
|
|
363
|
+
window.clearTimeout(this._destroyTimer);
|
|
364
|
+
this._destroyTimer = null;
|
|
365
|
+
}
|
|
366
|
+
_restoreContent() {
|
|
367
|
+
if (!this._detachedContent.hasChildNodes())
|
|
368
|
+
return;
|
|
369
|
+
this.insertBefore(this._detachedContent, this.firstChild);
|
|
370
|
+
this._syncFooter();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
export function defineDrawerComponents() {
|
|
374
|
+
if (!customElements.get('hy-drawer'))
|
|
375
|
+
customElements.define('hy-drawer', HYDrawer);
|
|
376
|
+
}
|
|
377
|
+
//# sourceMappingURL=drawer.js.map
|
package/dist/dropdown.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface HYDropdownItem {
|
|
2
2
|
label?: string;
|
|
3
3
|
value?: string;
|
|
4
4
|
disabled?: boolean;
|
|
5
5
|
separator?: boolean;
|
|
6
6
|
}
|
|
7
|
-
export interface
|
|
7
|
+
export interface HYDropdownSelectDetail {
|
|
8
8
|
value: string;
|
|
9
|
-
item:
|
|
9
|
+
item: HYDropdownItem;
|
|
10
10
|
}
|
|
11
|
-
export type
|
|
12
|
-
export declare class
|
|
11
|
+
export type HYDropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
|
|
12
|
+
export declare class HYDropdown extends HTMLElement {
|
|
13
13
|
private readonly _root;
|
|
14
14
|
private readonly _style;
|
|
15
15
|
private readonly _triggerSlot;
|
|
@@ -21,14 +21,14 @@ export declare class GEDropdown extends HTMLElement {
|
|
|
21
21
|
connectedCallback(): void;
|
|
22
22
|
disconnectedCallback(): void;
|
|
23
23
|
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void;
|
|
24
|
-
get items():
|
|
25
|
-
set items(value:
|
|
24
|
+
get items(): HYDropdownItem[];
|
|
25
|
+
set items(value: HYDropdownItem[]);
|
|
26
26
|
get open(): boolean;
|
|
27
27
|
set open(value: boolean);
|
|
28
28
|
get disabled(): boolean;
|
|
29
29
|
set disabled(value: boolean);
|
|
30
|
-
get placement():
|
|
31
|
-
set placement(value:
|
|
30
|
+
get placement(): HYDropdownPlacement;
|
|
31
|
+
set placement(value: HYDropdownPlacement);
|
|
32
32
|
show(): void;
|
|
33
33
|
close(): void;
|
|
34
34
|
toggle(): void;
|