aeico-components 0.1.5 → 0.1.6
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 +0 -0
- package/dist/chunks/action-button.cjs +296 -0
- package/dist/chunks/action-button.cjs.map +1 -0
- package/dist/chunks/action-button.js +297 -0
- package/dist/chunks/action-button.js.map +1 -0
- package/dist/chunks/alert.cjs +4 -4
- package/dist/chunks/alert.cjs.map +1 -1
- package/dist/chunks/alert.js +5 -5
- package/dist/chunks/alert.js.map +1 -1
- package/dist/chunks/badge.cjs +1 -1
- package/dist/chunks/badge.cjs.map +1 -1
- package/dist/chunks/badge.js +2 -2
- package/dist/chunks/badge.js.map +1 -1
- package/dist/chunks/breadcrumb-item.cjs +2 -2
- package/dist/chunks/breadcrumb-item.cjs.map +1 -1
- package/dist/chunks/breadcrumb-item.js +3 -3
- package/dist/chunks/breadcrumb-item.js.map +1 -1
- package/dist/chunks/button-group.cjs +1 -1
- package/dist/chunks/button-group.cjs.map +1 -1
- package/dist/chunks/button-group.js +2 -2
- package/dist/chunks/button-group.js.map +1 -1
- package/dist/chunks/button.cjs +1 -1
- package/dist/chunks/button.cjs.map +1 -1
- package/dist/chunks/button.js +2 -2
- package/dist/chunks/button.js.map +1 -1
- package/dist/chunks/card.cjs +1 -1
- package/dist/chunks/card.cjs.map +1 -1
- package/dist/chunks/card.js +2 -2
- package/dist/chunks/card.js.map +1 -1
- package/dist/chunks/checkbox.cjs +18 -5
- package/dist/chunks/checkbox.cjs.map +1 -1
- package/dist/chunks/checkbox.js +18 -5
- package/dist/chunks/checkbox.js.map +1 -1
- package/dist/chunks/copy-button.cjs +168 -0
- package/dist/chunks/copy-button.cjs.map +1 -0
- package/dist/chunks/copy-button.js +169 -0
- package/dist/chunks/copy-button.js.map +1 -0
- package/dist/chunks/detail.cjs +7 -4
- package/dist/chunks/detail.cjs.map +1 -1
- package/dist/chunks/detail.js +8 -5
- package/dist/chunks/detail.js.map +1 -1
- package/dist/chunks/dialog.cjs +1 -1
- package/dist/chunks/dialog.cjs.map +1 -1
- package/dist/chunks/dialog.js +2 -2
- package/dist/chunks/dialog.js.map +1 -1
- package/dist/chunks/divider.cjs +1 -1
- package/dist/chunks/divider.cjs.map +1 -1
- package/dist/chunks/divider.js +2 -2
- package/dist/chunks/divider.js.map +1 -1
- package/dist/chunks/drawer.cjs +180 -0
- package/dist/chunks/drawer.cjs.map +1 -0
- package/dist/chunks/drawer.js +181 -0
- package/dist/chunks/drawer.js.map +1 -0
- package/dist/chunks/dropdown-button.cjs +2 -2
- package/dist/chunks/dropdown-button.cjs.map +1 -1
- package/dist/chunks/dropdown-button.js +3 -3
- package/dist/chunks/dropdown-button.js.map +1 -1
- package/dist/chunks/icon.cjs +31 -1
- package/dist/chunks/icon.cjs.map +1 -1
- package/dist/chunks/icon.js +32 -2
- package/dist/chunks/icon.js.map +1 -1
- package/dist/chunks/menu.cjs +396 -0
- package/dist/chunks/menu.cjs.map +1 -0
- package/dist/chunks/menu.js +397 -0
- package/dist/chunks/menu.js.map +1 -0
- package/dist/chunks/navbar.cjs +1 -1
- package/dist/chunks/navbar.cjs.map +1 -1
- package/dist/chunks/navbar.js +2 -2
- package/dist/chunks/navbar.js.map +1 -1
- package/dist/chunks/pagination.cjs +475 -0
- package/dist/chunks/pagination.cjs.map +1 -0
- package/dist/chunks/pagination.js +476 -0
- package/dist/chunks/pagination.js.map +1 -0
- package/dist/chunks/progress-bar.cjs +101 -0
- package/dist/chunks/progress-bar.cjs.map +1 -0
- package/dist/chunks/progress-bar.js +102 -0
- package/dist/chunks/progress-bar.js.map +1 -0
- package/dist/chunks/radio.cjs +11 -7
- package/dist/chunks/radio.cjs.map +1 -1
- package/dist/chunks/radio.js +11 -7
- package/dist/chunks/radio.js.map +1 -1
- package/dist/chunks/select.cjs +97 -66
- package/dist/chunks/select.cjs.map +1 -1
- package/dist/chunks/select.js +97 -66
- package/dist/chunks/select.js.map +1 -1
- package/dist/chunks/slider.cjs +9 -46
- package/dist/chunks/slider.cjs.map +1 -1
- package/dist/chunks/slider.js +9 -46
- package/dist/chunks/slider.js.map +1 -1
- package/dist/chunks/spinner.cjs +102 -0
- package/dist/chunks/spinner.cjs.map +1 -0
- package/dist/chunks/spinner.js +103 -0
- package/dist/chunks/spinner.js.map +1 -0
- package/dist/chunks/switch.cjs +110 -16
- package/dist/chunks/switch.cjs.map +1 -1
- package/dist/chunks/switch.js +111 -17
- package/dist/chunks/switch.js.map +1 -1
- package/dist/chunks/tab-panel.cjs +3 -3
- package/dist/chunks/tab-panel.cjs.map +1 -1
- package/dist/chunks/tab-panel.js +4 -4
- package/dist/chunks/tab-panel.js.map +1 -1
- package/dist/chunks/tag.cjs +1 -1
- package/dist/chunks/tag.cjs.map +1 -1
- package/dist/chunks/tag.js +2 -2
- package/dist/chunks/tag.js.map +1 -1
- package/dist/chunks/text-input.cjs +11 -16
- package/dist/chunks/text-input.cjs.map +1 -1
- package/dist/chunks/text-input.js +11 -16
- package/dist/chunks/text-input.js.map +1 -1
- package/dist/chunks/textarea.cjs +137 -0
- package/dist/chunks/textarea.cjs.map +1 -0
- package/dist/chunks/textarea.js +138 -0
- package/dist/chunks/textarea.js.map +1 -0
- package/dist/chunks/tooltip.cjs +293 -0
- package/dist/chunks/tooltip.cjs.map +1 -0
- package/dist/chunks/tooltip.js +294 -0
- package/dist/chunks/tooltip.js.map +1 -0
- package/dist/chunks/tree.cjs +468 -0
- package/dist/chunks/tree.cjs.map +1 -0
- package/dist/chunks/tree.js +469 -0
- package/dist/chunks/tree.js.map +1 -0
- package/dist/chunks/variables.cjs +2 -2
- package/dist/chunks/variables.js +2 -2
- package/dist/copy-button.cjs +6 -0
- package/dist/copy-button.cjs.map +1 -0
- package/dist/copy-button.js +6 -0
- package/dist/copy-button.js.map +1 -0
- package/dist/drawer.cjs +6 -0
- package/dist/drawer.cjs.map +1 -0
- package/dist/drawer.js +6 -0
- package/dist/drawer.js.map +1 -0
- package/dist/index.cjs +175 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +186 -99
- package/dist/index.js.map +1 -1
- package/dist/menu.cjs +6 -0
- package/dist/menu.cjs.map +1 -0
- package/dist/menu.js +6 -0
- package/dist/menu.js.map +1 -0
- package/dist/pagination.cjs +6 -0
- package/dist/pagination.cjs.map +1 -0
- package/dist/pagination.js +6 -0
- package/dist/pagination.js.map +1 -0
- package/dist/progress-bar.cjs +6 -0
- package/dist/progress-bar.cjs.map +1 -0
- package/dist/progress-bar.js +6 -0
- package/dist/progress-bar.js.map +1 -0
- package/dist/select.cjs +1 -1
- package/dist/select.cjs.map +1 -1
- package/dist/select.js +2 -2
- package/dist/select.js.map +1 -1
- package/dist/spinner.cjs +6 -0
- package/dist/spinner.cjs.map +1 -0
- package/dist/spinner.js +6 -0
- package/dist/spinner.js.map +1 -0
- package/dist/textarea.cjs +5 -0
- package/dist/textarea.cjs.map +1 -0
- package/dist/textarea.js +5 -0
- package/dist/textarea.js.map +1 -0
- package/dist/tooltip.cjs +6 -0
- package/dist/tooltip.cjs.map +1 -0
- package/dist/tooltip.js +6 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/tree.cjs +6 -0
- package/dist/tree.cjs.map +1 -0
- package/dist/tree.js +6 -0
- package/dist/tree.js.map +1 -0
- package/dist/types/aeico-field.d.ts +52 -0
- package/dist/types/alert/alert.d.ts +1 -0
- package/dist/types/copy-button/copy-button.d.ts +32 -0
- package/dist/types/copy-button/defines.d.ts +1 -0
- package/dist/types/copy-button/index.d.ts +3 -0
- package/dist/types/detail/defines.d.ts +1 -0
- package/dist/types/detail/detail.d.ts +3 -1
- package/dist/types/detail/index.d.ts +1 -1
- package/dist/types/detail-group/detail-group.d.ts +39 -0
- package/dist/types/detail-group/index.d.ts +2 -0
- package/dist/types/drawer/defines.d.ts +1 -0
- package/dist/types/drawer/drawer.d.ts +31 -0
- package/dist/types/drawer/index.d.ts +3 -0
- package/dist/types/icon/built-in-icons.d.ts +1 -0
- package/dist/types/icon/icon.d.ts +1 -0
- package/dist/types/icon/registry.d.ts +8 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/menu/defines.d.ts +15 -0
- package/dist/types/menu/index.d.ts +5 -0
- package/dist/types/menu/menu-item.d.ts +63 -0
- package/dist/types/menu/menu.d.ts +34 -0
- package/dist/types/number-input/index.d.ts +2 -0
- package/dist/types/number-input/number-input.d.ts +35 -0
- package/dist/types/pagination/defines.d.ts +2 -0
- package/dist/types/pagination/index.d.ts +3 -0
- package/dist/types/pagination/pagination.d.ts +77 -0
- package/dist/types/select/select.d.ts +2 -2
- package/dist/types/spinner/defines.d.ts +3 -0
- package/dist/types/spinner/index.d.ts +3 -0
- package/dist/types/spinner/spinner.d.ts +35 -0
- package/dist/types/switch/defines.d.ts +1 -0
- package/dist/types/switch/switch.d.ts +8 -4
- package/dist/types/text-input/text-input.d.ts +0 -4
- package/dist/types/textarea/index.d.ts +1 -0
- package/dist/types/textarea/textarea.d.ts +26 -0
- package/dist/types/tooltip/defines.d.ts +2 -0
- package/dist/types/tooltip/index.d.ts +4 -0
- package/dist/types/tooltip/tooltip.d.ts +48 -0
- package/dist/types/tree/defines.d.ts +23 -0
- package/dist/types/tree/index.d.ts +5 -0
- package/dist/types/tree/tree-item.d.ts +54 -0
- package/dist/types/tree/tree.d.ts +64 -0
- package/package.json +5 -5
- package/src/aeico-field.ts +142 -7
- package/src/alert/alert.ts +3 -2
- package/src/checkbox/checkbox.ts +17 -2
- package/src/copy-button/copy-button.ts +146 -0
- package/src/copy-button/defines.ts +5 -0
- package/src/copy-button/index.ts +3 -0
- package/src/detail/defines.ts +1 -0
- package/src/detail/detail.ts +5 -1
- package/src/detail/index.ts +1 -1
- package/src/detail-group/detail-group.ts +104 -0
- package/src/detail-group/index.ts +2 -0
- package/src/drawer/defines.ts +1 -0
- package/src/drawer/drawer.ts +157 -0
- package/src/drawer/index.ts +3 -0
- package/src/icon/built-in-icons.ts +21 -0
- package/src/icon/icon.ts +1 -0
- package/src/icon/registry.ts +22 -0
- package/src/index.ts +30 -0
- package/src/menu/defines.ts +17 -0
- package/src/menu/index.ts +5 -0
- package/src/menu/menu-item.ts +315 -0
- package/src/menu/menu.ts +81 -0
- package/src/number-input/index.ts +2 -0
- package/src/number-input/number-input.ts +137 -0
- package/src/pagination/defines.ts +2 -0
- package/src/pagination/index.ts +3 -0
- package/src/pagination/pagination.ts +310 -0
- package/src/radio-group/radio-group.ts +11 -4
- package/src/select/select.ts +111 -70
- package/src/slider/slider.ts +9 -2
- package/src/spinner/defines.ts +12 -0
- package/src/spinner/index.ts +3 -0
- package/src/spinner/spinner.ts +81 -0
- package/src/styles/components/action-button.css +37 -0
- package/src/styles/components/checkbox.css +4 -26
- package/src/styles/components/copy-button.css +119 -0
- package/src/styles/components/detail-group.css +10 -0
- package/src/styles/components/detail.css +10 -1
- package/src/styles/components/drawer.css +161 -0
- package/src/styles/components/field-label.css +120 -0
- package/src/styles/components/menu-item.css +168 -0
- package/src/styles/components/menu.css +17 -0
- package/src/styles/components/number-input.css +167 -0
- package/src/styles/components/pagination.css +205 -0
- package/src/styles/components/radio-group.css +0 -23
- package/src/styles/components/select.css +12 -39
- package/src/styles/components/slider.css +0 -42
- package/src/styles/components/spinner.css +80 -0
- package/src/styles/components/switch.css +68 -19
- package/src/styles/components/tab-panel.css +1 -1
- package/src/styles/components/tabs.css +1 -0
- package/src/styles/components/text-input.css +7 -45
- package/src/styles/components/textarea.css +75 -0
- package/src/styles/components/tooltip.css +103 -0
- package/src/styles/components/tree-item.css +152 -0
- package/src/styles/components/tree.css +10 -0
- package/src/styles/layout.css +457 -25
- package/src/switch/defines.ts +1 -0
- package/src/switch/switch.ts +61 -12
- package/src/text-input/text-input.ts +10 -15
- package/src/textarea/index.ts +1 -0
- package/src/textarea/textarea.ts +107 -0
- package/src/tooltip/defines.ts +11 -0
- package/src/tooltip/index.ts +4 -0
- package/src/tooltip/tooltip.ts +183 -0
- package/src/tree/defines.ts +26 -0
- package/src/tree/index.ts +5 -0
- package/src/tree/tree-item.ts +258 -0
- package/src/tree/tree.ts +237 -0
- package/dist/chunks/aeico-field.cjs +0 -179
- package/dist/chunks/aeico-field.cjs.map +0 -1
- package/dist/chunks/aeico-field.js +0 -180
- package/dist/chunks/aeico-field.js.map +0 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import AeicoField from '../aeico-field';
|
|
2
|
+
import type { InferProps } from 'aeico';
|
|
3
|
+
import { html, prop } from 'aeico';
|
|
4
|
+
import variables from '../styles/variables.css?inline';
|
|
5
|
+
import sizeCSS from '../styles/size.css?inline';
|
|
6
|
+
import fieldLabelCSS from '../styles/components/field-label.css?inline';
|
|
7
|
+
import actionButtonCSS from '../styles/components/action-button.css?inline';
|
|
8
|
+
import style from '../styles/components/textarea.css?inline';
|
|
9
|
+
|
|
10
|
+
export type TextareaResize = 'none' | 'vertical' | 'horizontal' | 'both';
|
|
11
|
+
|
|
12
|
+
class Textarea extends AeicoField {
|
|
13
|
+
protected fieldElement: HTMLTextAreaElement | null = null;
|
|
14
|
+
|
|
15
|
+
static tagName = 'textarea';
|
|
16
|
+
|
|
17
|
+
@prop({ type: String })
|
|
18
|
+
accessor placeholder: string | undefined;
|
|
19
|
+
|
|
20
|
+
@prop({ type: Number })
|
|
21
|
+
accessor rows: number | undefined;
|
|
22
|
+
|
|
23
|
+
@prop({ type: Number })
|
|
24
|
+
accessor maxlength: number | undefined;
|
|
25
|
+
|
|
26
|
+
@prop({ type: Number })
|
|
27
|
+
accessor minlength: number | undefined;
|
|
28
|
+
|
|
29
|
+
@prop({ type: String })
|
|
30
|
+
accessor resize: TextareaResize | undefined;
|
|
31
|
+
|
|
32
|
+
@prop({ type: Boolean })
|
|
33
|
+
accessor autoResize: boolean = false;
|
|
34
|
+
|
|
35
|
+
protected static styles = [variables, sizeCSS, fieldLabelCSS, actionButtonCSS, style];
|
|
36
|
+
|
|
37
|
+
private readonly _boundOnInput = () => {
|
|
38
|
+
if (this.autoResize && this.fieldElement) {
|
|
39
|
+
this._syncAutoResize(this.fieldElement);
|
|
40
|
+
}
|
|
41
|
+
this.setValue(this.getValue(), { silent: false, action: 'change' });
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
render() {
|
|
45
|
+
return html(({ div, textarea }) => {
|
|
46
|
+
const id = this.getFieldId();
|
|
47
|
+
this.renderLabel(id);
|
|
48
|
+
div({ className: 'textarea-container field-body' }, () => {
|
|
49
|
+
this.fieldElement = textarea({
|
|
50
|
+
id,
|
|
51
|
+
placeholder: this.placeholder || '',
|
|
52
|
+
rows: this.rows ?? 3,
|
|
53
|
+
required: Boolean(this.required),
|
|
54
|
+
'@input': this._boundOnInput,
|
|
55
|
+
});
|
|
56
|
+
this.renderActionButtons();
|
|
57
|
+
});
|
|
58
|
+
this.renderHelperText();
|
|
59
|
+
this.renderError();
|
|
60
|
+
|
|
61
|
+
if (this.fieldElement) {
|
|
62
|
+
if (this.value != null) {
|
|
63
|
+
this.fieldElement.value = String(this.value);
|
|
64
|
+
}
|
|
65
|
+
if (this.maxlength != null) this.fieldElement.maxLength = this.maxlength;
|
|
66
|
+
if (this.minlength != null) this.fieldElement.minLength = this.minlength;
|
|
67
|
+
this.fieldElement.style.resize = this.autoResize ? 'none' : (this.resize ?? 'vertical');
|
|
68
|
+
if (this.autoResize) {
|
|
69
|
+
this._syncAutoResize(this.fieldElement);
|
|
70
|
+
}
|
|
71
|
+
this._updateClearButtonVisibility();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private _syncAutoResize(ta: HTMLTextAreaElement): void {
|
|
77
|
+
ta.style.height = 'auto';
|
|
78
|
+
ta.style.height = `${ta.scrollHeight}px`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private _updateClearButtonVisibility(): void {
|
|
82
|
+
if (this.clearBtn && this.fieldElement) {
|
|
83
|
+
this.clearBtn.style.display = this.fieldElement.value.length > 0 ? '' : 'none';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
protected writeValue(value: string): void {
|
|
88
|
+
if (this.fieldElement) {
|
|
89
|
+
this.fieldElement.value = String(value || '');
|
|
90
|
+
if (this.autoResize) {
|
|
91
|
+
this._syncAutoResize(this.fieldElement);
|
|
92
|
+
}
|
|
93
|
+
this._updateClearButtonVisibility();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
Textarea.register();
|
|
99
|
+
|
|
100
|
+
declare global {
|
|
101
|
+
interface HTMLElementTagNameMap {
|
|
102
|
+
'ae-textarea': Textarea;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export default Textarea;
|
|
107
|
+
export type TextareaProps = InferProps<typeof Textarea>;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { InferProps } from 'aeico';
|
|
2
|
+
import styleVariables from '../styles/variables.css?inline';
|
|
3
|
+
import tooltipStyle from '../styles/components/tooltip.css?inline';
|
|
4
|
+
import AeicoComponent from '../aeico-component';
|
|
5
|
+
import { html, prop } from 'aeico';
|
|
6
|
+
import type { TooltipPlacement, TooltipTrigger } from './defines';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Tooltip Component
|
|
10
|
+
*
|
|
11
|
+
* A floating label that appears on hover or focus around its trigger content.
|
|
12
|
+
* Wrap any element in `<ae-tooltip>` and provide content via the `content`
|
|
13
|
+
* attribute (plain text) or the `tooltip` named slot (rich HTML).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```html
|
|
17
|
+
* <ae-tooltip content="Save file">
|
|
18
|
+
* <ae-button>Save</ae-button>
|
|
19
|
+
* </ae-tooltip>
|
|
20
|
+
*
|
|
21
|
+
* <ae-tooltip placement="bottom-start">
|
|
22
|
+
* <span slot="tooltip"><strong>Bold</strong> tip</span>
|
|
23
|
+
* <ae-icon-button name="info"></ae-icon-button>
|
|
24
|
+
* </ae-tooltip>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
class Tooltip extends AeicoComponent {
|
|
28
|
+
protected static styles = [styleVariables, tooltipStyle];
|
|
29
|
+
|
|
30
|
+
@prop({ type: String })
|
|
31
|
+
accessor content: string | undefined;
|
|
32
|
+
|
|
33
|
+
@prop({ type: String })
|
|
34
|
+
accessor placement: TooltipPlacement = 'top';
|
|
35
|
+
|
|
36
|
+
@prop({ type: Boolean })
|
|
37
|
+
accessor disabled: boolean = false;
|
|
38
|
+
|
|
39
|
+
@prop({ type: String })
|
|
40
|
+
accessor trigger: TooltipTrigger = 'hover';
|
|
41
|
+
|
|
42
|
+
@prop({ type: Boolean })
|
|
43
|
+
accessor open: boolean = false;
|
|
44
|
+
|
|
45
|
+
private _outsideClickHandler: ((e: MouseEvent) => void) | null = null;
|
|
46
|
+
|
|
47
|
+
connectedCallback() {
|
|
48
|
+
super.connectedCallback();
|
|
49
|
+
this.listen('mouseenter', this._handleMouseEnter);
|
|
50
|
+
this.listen('mouseleave', this._handleMouseLeave);
|
|
51
|
+
this.listen('focusin', this._handleFocusin);
|
|
52
|
+
this.listen('focusout', this._handleFocusout);
|
|
53
|
+
this.listen('click', this._handleClick);
|
|
54
|
+
|
|
55
|
+
this._outsideClickHandler = (e: MouseEvent) => {
|
|
56
|
+
if (!this.open) return;
|
|
57
|
+
if (!e.composedPath().includes(this)) this.open = false;
|
|
58
|
+
};
|
|
59
|
+
document.addEventListener('click', this._outsideClickHandler);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
disconnectedCallback() {
|
|
63
|
+
super.disconnectedCallback();
|
|
64
|
+
if (this._outsideClickHandler) {
|
|
65
|
+
document.removeEventListener('click', this._outsideClickHandler);
|
|
66
|
+
this._outsideClickHandler = null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private _handleMouseEnter = () => {
|
|
71
|
+
if (this.trigger !== 'hover') return;
|
|
72
|
+
if (this.disabled) return;
|
|
73
|
+
this.open = true;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
private _handleMouseLeave = () => {
|
|
77
|
+
if (this.trigger !== 'hover') return;
|
|
78
|
+
this.open = false;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
private _handleFocusin = () => {
|
|
82
|
+
if (this.trigger !== 'hover') return;
|
|
83
|
+
if (this.disabled) return;
|
|
84
|
+
this.open = true;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
private _handleFocusout = () => {
|
|
88
|
+
if (this.trigger !== 'hover') return;
|
|
89
|
+
this.open = false;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
private _handleClick = () => {
|
|
93
|
+
if (this.trigger !== 'click') return;
|
|
94
|
+
if (this.disabled) return;
|
|
95
|
+
this.open = !this.open;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
private _updatePosition() {
|
|
99
|
+
const panel = this.shadowRoot?.querySelector<HTMLElement>('.tooltip-panel');
|
|
100
|
+
if (!panel) return;
|
|
101
|
+
|
|
102
|
+
const host = this.getBoundingClientRect();
|
|
103
|
+
const panelRect = panel.getBoundingClientRect();
|
|
104
|
+
const gap = 6; // Match --ae-tooltip-gap: 6px
|
|
105
|
+
const pw = panelRect.width;
|
|
106
|
+
const ph = panelRect.height;
|
|
107
|
+
|
|
108
|
+
let top: number;
|
|
109
|
+
let left: number;
|
|
110
|
+
|
|
111
|
+
switch (this.placement) {
|
|
112
|
+
case 'top-start':
|
|
113
|
+
top = host.top - ph - gap;
|
|
114
|
+
left = host.left;
|
|
115
|
+
break;
|
|
116
|
+
case 'top-end':
|
|
117
|
+
top = host.top - ph - gap;
|
|
118
|
+
left = host.right - pw;
|
|
119
|
+
break;
|
|
120
|
+
case 'bottom':
|
|
121
|
+
top = host.bottom + gap;
|
|
122
|
+
left = host.left + host.width / 2 - pw / 2;
|
|
123
|
+
break;
|
|
124
|
+
case 'bottom-start':
|
|
125
|
+
top = host.bottom + gap;
|
|
126
|
+
left = host.left;
|
|
127
|
+
break;
|
|
128
|
+
case 'bottom-end':
|
|
129
|
+
top = host.bottom + gap;
|
|
130
|
+
left = host.right - pw;
|
|
131
|
+
break;
|
|
132
|
+
case 'left':
|
|
133
|
+
top = host.top + host.height / 2 - ph / 2;
|
|
134
|
+
left = host.left - pw - gap;
|
|
135
|
+
break;
|
|
136
|
+
case 'right':
|
|
137
|
+
top = host.top + host.height / 2 - ph / 2;
|
|
138
|
+
left = host.right + gap;
|
|
139
|
+
break;
|
|
140
|
+
default: // 'top'
|
|
141
|
+
top = host.top - ph - gap;
|
|
142
|
+
left = host.left + host.width / 2 - pw / 2;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
panel.style.top = `${top}px`;
|
|
146
|
+
panel.style.left = `${left}px`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
protected onUpdated(changedProps: Map<string, unknown>) {
|
|
150
|
+
if (changedProps.has('open') && this.open) {
|
|
151
|
+
this._updatePosition();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
protected render() {
|
|
156
|
+
return html(({ div, span, slot }) => {
|
|
157
|
+
slot();
|
|
158
|
+
div(
|
|
159
|
+
{
|
|
160
|
+
className: `tooltip-panel placement-${this.placement ?? 'top'}`,
|
|
161
|
+
role: 'tooltip',
|
|
162
|
+
'aria-hidden': String(!this.open),
|
|
163
|
+
},
|
|
164
|
+
() => {
|
|
165
|
+
slot({ name: 'tooltip' }, () => {
|
|
166
|
+
span({ textContent: this.content ?? '' });
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Tooltip.register();
|
|
175
|
+
|
|
176
|
+
declare global {
|
|
177
|
+
interface HTMLElementTagNameMap {
|
|
178
|
+
'ae-tooltip': Tooltip;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export type TooltipProps = InferProps<typeof Tooltip>;
|
|
183
|
+
export default Tooltip;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Minimal interface used by tree-item to read config from its parent ae-tree. */
|
|
2
|
+
export interface ParentTreeLike extends Element {
|
|
3
|
+
checkable?: boolean;
|
|
4
|
+
multiple?: boolean;
|
|
5
|
+
showLine?: boolean;
|
|
6
|
+
defaultExpandAll?: boolean;
|
|
7
|
+
icon?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface TreeSelectDetail {
|
|
11
|
+
key: string;
|
|
12
|
+
selected: boolean;
|
|
13
|
+
selectedKeys: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface TreeExpandDetail {
|
|
17
|
+
key: string;
|
|
18
|
+
expanded: boolean;
|
|
19
|
+
expandedKeys: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TreeCheckDetail {
|
|
23
|
+
key: string;
|
|
24
|
+
checked: boolean;
|
|
25
|
+
checkedKeys: string[];
|
|
26
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Tree } from './tree';
|
|
2
|
+
export { default as TreeItem } from './tree-item';
|
|
3
|
+
export type { TreeProps } from './tree';
|
|
4
|
+
export type { TreeItemProps } from './tree-item';
|
|
5
|
+
export type { TreeSelectDetail, TreeExpandDetail, TreeCheckDetail } from './defines';
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import AeicoComponent from '../aeico-component';
|
|
2
|
+
import type { InferProps } from 'aeico';
|
|
3
|
+
import { html, prop } from 'aeico';
|
|
4
|
+
import style from '../styles/components/tree-item.css?inline';
|
|
5
|
+
import variables from '../styles/variables.css?inline';
|
|
6
|
+
import type { ParentTreeLike } from './defines';
|
|
7
|
+
import { SVG_NS } from '../utils';
|
|
8
|
+
import '../icon';
|
|
9
|
+
|
|
10
|
+
let _autoKeyCounter = 0;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Tree item — used as a direct child of `<ae-tree>` or nested inside another
|
|
14
|
+
* `<ae-tree-item>` to create a multi-level tree.
|
|
15
|
+
*
|
|
16
|
+
* - **Parent item**: nest `<ae-tree-item>` children inside; an expand toggle is shown.
|
|
17
|
+
* - **Leaf item**: no `<ae-tree-item>` children; no expand toggle is shown.
|
|
18
|
+
*
|
|
19
|
+
* @prop {string} key - Unique identifier for this item.
|
|
20
|
+
* @prop {string} icon - Icon name (uses `<ae-icon>`). Optional.
|
|
21
|
+
* @prop {boolean} disabled - Disables interaction.
|
|
22
|
+
* @prop {boolean} expanded - Whether children are visible.
|
|
23
|
+
* @prop {boolean} selected - Whether this item is visually selected.
|
|
24
|
+
* @prop {boolean} checked - Checkbox state (checkable mode).
|
|
25
|
+
* @prop {boolean} indeterminate - Checkbox partial state (checkable mode, JS-only).
|
|
26
|
+
*
|
|
27
|
+
* @slot default - Child `<ae-tree-item>` elements.
|
|
28
|
+
* @slot label - Custom label content (falls back to the `label` attribute text).
|
|
29
|
+
*/
|
|
30
|
+
class TreeItem extends AeicoComponent {
|
|
31
|
+
static tagName = 'tree-item';
|
|
32
|
+
|
|
33
|
+
protected static styles = [variables, style];
|
|
34
|
+
|
|
35
|
+
@prop({ type: String })
|
|
36
|
+
accessor key: string | undefined;
|
|
37
|
+
|
|
38
|
+
@prop({ type: String })
|
|
39
|
+
accessor icon: string | undefined;
|
|
40
|
+
|
|
41
|
+
/** Stable auto-generated key used when `key` prop is not set. */
|
|
42
|
+
private readonly _autoKey = `ae-tree-item-${_autoKeyCounter++}`;
|
|
43
|
+
|
|
44
|
+
private get _effectiveKey(): string {
|
|
45
|
+
return this.key ?? this._autoKey;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@prop({ type: Boolean })
|
|
49
|
+
accessor disabled: boolean = false;
|
|
50
|
+
|
|
51
|
+
@prop({ type: Boolean })
|
|
52
|
+
accessor expanded: boolean = false;
|
|
53
|
+
|
|
54
|
+
@prop({ type: Boolean })
|
|
55
|
+
accessor selected: boolean = false;
|
|
56
|
+
|
|
57
|
+
@prop({ type: Boolean })
|
|
58
|
+
accessor checked: boolean = false;
|
|
59
|
+
|
|
60
|
+
@prop({ type: Boolean })
|
|
61
|
+
accessor indeterminate: boolean = false;
|
|
62
|
+
|
|
63
|
+
private _checkboxEl: HTMLInputElement | null = null;
|
|
64
|
+
|
|
65
|
+
connectedCallback() {
|
|
66
|
+
super.connectedCallback();
|
|
67
|
+
|
|
68
|
+
// Auto-assign slot so users don't need to write slot="sub" manually
|
|
69
|
+
if (
|
|
70
|
+
this.parentElement?.tagName.toLowerCase() === 'ae-tree-item' &&
|
|
71
|
+
!this.hasAttribute('slot')
|
|
72
|
+
) {
|
|
73
|
+
this.setAttribute('slot', 'sub');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let depth = 0;
|
|
77
|
+
let el: Element | null = this.parentElement;
|
|
78
|
+
while (el) {
|
|
79
|
+
const tag = el.tagName.toLowerCase();
|
|
80
|
+
if (tag === 'ae-tree-item') {
|
|
81
|
+
depth++;
|
|
82
|
+
} else if (tag === 'ae-tree') {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
el = el.parentElement;
|
|
86
|
+
}
|
|
87
|
+
this.style.setProperty('--depth', String(depth));
|
|
88
|
+
|
|
89
|
+
if (this._parentTree?.showLine) {
|
|
90
|
+
this.setAttribute('showline', '');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
protected onMounted(): void {
|
|
95
|
+
if (this._parentTree?.defaultExpandAll && this._hasChildren) {
|
|
96
|
+
this.expanded = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private get _parentTree(): ParentTreeLike | null {
|
|
101
|
+
return this.closest<ParentTreeLike>('ae-tree');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private get _isCheckable(): boolean {
|
|
105
|
+
return this._parentTree?.checkable ?? false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private get _hasChildren(): boolean {
|
|
109
|
+
return !!this.querySelector(':scope > ae-tree-item[slot="sub"]');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private _handleExpandClick = (e: Event): void => {
|
|
113
|
+
e.stopPropagation();
|
|
114
|
+
if (this.disabled) return;
|
|
115
|
+
this.dispatchEvent(
|
|
116
|
+
new CustomEvent('_tree-item-toggle-expand', {
|
|
117
|
+
bubbles: true,
|
|
118
|
+
composed: true,
|
|
119
|
+
detail: { key: this._effectiveKey },
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
private _handleLabelClick = (): void => {
|
|
125
|
+
if (this.disabled) return;
|
|
126
|
+
this.dispatchEvent(
|
|
127
|
+
new CustomEvent('_tree-item-select', {
|
|
128
|
+
bubbles: true,
|
|
129
|
+
composed: true,
|
|
130
|
+
detail: { key: this._effectiveKey },
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
private _handleCheckChange = (e: Event): void => {
|
|
136
|
+
if (this.disabled) return;
|
|
137
|
+
const input = e.target as HTMLInputElement;
|
|
138
|
+
this.dispatchEvent(
|
|
139
|
+
new CustomEvent('_tree-item-check', {
|
|
140
|
+
bubbles: true,
|
|
141
|
+
composed: true,
|
|
142
|
+
detail: { key: this._effectiveKey, checked: input.checked },
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
private _handleKeydown = (e: KeyboardEvent): void => {
|
|
148
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
if ((e.target as HTMLElement).classList.contains('tree-item-label')) {
|
|
151
|
+
this._handleLabelClick();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (e.key === 'ArrowRight' && this._hasChildren && !this.expanded) {
|
|
155
|
+
this._handleExpandClick(e);
|
|
156
|
+
}
|
|
157
|
+
if (e.key === 'ArrowLeft' && this.expanded) {
|
|
158
|
+
this._handleExpandClick(e);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
protected onUpdated(): void {
|
|
163
|
+
// indeterminate/checked cannot be set correctly via HTML attribute — must set via JS property
|
|
164
|
+
if (this._checkboxEl) {
|
|
165
|
+
this._checkboxEl.checked = this.checked;
|
|
166
|
+
this._checkboxEl.indeterminate = this.indeterminate;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
protected render() {
|
|
171
|
+
const hasChildren = this._hasChildren;
|
|
172
|
+
const isCheckable = this._isCheckable;
|
|
173
|
+
const expandIcon = this.icon ?? this._parentTree?.icon;
|
|
174
|
+
|
|
175
|
+
return html(({ div, button, span, input, slot, svg, path, aeIcon }) => {
|
|
176
|
+
div(
|
|
177
|
+
{
|
|
178
|
+
className: 'tree-item-content',
|
|
179
|
+
role: 'treeitem',
|
|
180
|
+
'aria-expanded': hasChildren ? String(this.expanded) : undefined,
|
|
181
|
+
'aria-selected': String(this.selected),
|
|
182
|
+
'aria-disabled': this.disabled ? 'true' : undefined,
|
|
183
|
+
},
|
|
184
|
+
() => {
|
|
185
|
+
if (hasChildren) {
|
|
186
|
+
button(
|
|
187
|
+
{
|
|
188
|
+
type: 'button',
|
|
189
|
+
className: 'expand-btn',
|
|
190
|
+
tabIndex: -1,
|
|
191
|
+
'aria-hidden': 'true',
|
|
192
|
+
'@click': this._handleExpandClick,
|
|
193
|
+
},
|
|
194
|
+
() => {
|
|
195
|
+
if (expandIcon) {
|
|
196
|
+
aeIcon({ className: 'expand-icon', name: expandIcon });
|
|
197
|
+
} else {
|
|
198
|
+
svg(
|
|
199
|
+
{
|
|
200
|
+
className: 'expand-icon',
|
|
201
|
+
viewBox: '0 0 10 10',
|
|
202
|
+
'aria-hidden': 'true',
|
|
203
|
+
xmlns: SVG_NS,
|
|
204
|
+
},
|
|
205
|
+
() => {
|
|
206
|
+
path({ d: 'M2 1l6 4-6 4V1z' });
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
} else {
|
|
213
|
+
span({ className: 'expand-placeholder', 'aria-hidden': 'true' });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (isCheckable) {
|
|
217
|
+
this._checkboxEl = input({
|
|
218
|
+
type: 'checkbox',
|
|
219
|
+
className: 'tree-item-checkbox',
|
|
220
|
+
checked: this.checked,
|
|
221
|
+
disabled: this.disabled,
|
|
222
|
+
tabIndex: -1,
|
|
223
|
+
'@change': this._handleCheckChange,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
button(
|
|
228
|
+
{
|
|
229
|
+
type: 'button',
|
|
230
|
+
className: 'tree-item-label',
|
|
231
|
+
disabled: this.disabled,
|
|
232
|
+
'@click': this._handleLabelClick,
|
|
233
|
+
'@keydown': this._handleKeydown,
|
|
234
|
+
},
|
|
235
|
+
() => {
|
|
236
|
+
slot();
|
|
237
|
+
},
|
|
238
|
+
);
|
|
239
|
+
},
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
div({ className: 'tree-item-children', role: 'group' }, () => {
|
|
243
|
+
slot({ name: 'sub' });
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
TreeItem.register();
|
|
250
|
+
|
|
251
|
+
declare global {
|
|
252
|
+
interface HTMLElementTagNameMap {
|
|
253
|
+
'ae-tree-item': TreeItem;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export default TreeItem;
|
|
258
|
+
export type TreeItemProps = InferProps<typeof TreeItem>;
|