aeico-components 0.1.5 → 0.1.7
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 +26 -32
- package/dist/chunks/alert.cjs.map +1 -1
- package/dist/chunks/alert.js +27 -33
- package/dist/chunks/alert.js.map +1 -1
- package/dist/chunks/badge.cjs +2 -2
- package/dist/chunks/badge.cjs.map +1 -1
- package/dist/chunks/badge.js +3 -3
- package/dist/chunks/badge.js.map +1 -1
- package/dist/chunks/breadcrumb-item.cjs +9 -9
- package/dist/chunks/breadcrumb-item.cjs.map +1 -1
- package/dist/chunks/breadcrumb-item.js +10 -10
- 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 +40 -51
- package/dist/chunks/button.cjs.map +1 -1
- package/dist/chunks/button.js +41 -52
- package/dist/chunks/button.js.map +1 -1
- package/dist/chunks/card.cjs +2 -2
- package/dist/chunks/card.cjs.map +1 -1
- package/dist/chunks/card.js +3 -3
- 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/color.cjs +1 -1
- package/dist/chunks/color.js +1 -1
- package/dist/chunks/copy-button.cjs +171 -0
- package/dist/chunks/copy-button.cjs.map +1 -0
- package/dist/chunks/copy-button.js +172 -0
- package/dist/chunks/copy-button.js.map +1 -0
- package/dist/chunks/detail-group.cjs +65 -0
- package/dist/chunks/detail-group.cjs.map +1 -0
- package/dist/chunks/detail-group.js +66 -0
- package/dist/chunks/detail-group.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 +2 -2
- package/dist/chunks/dialog.cjs.map +1 -1
- package/dist/chunks/dialog.js +3 -3
- package/dist/chunks/dialog.js.map +1 -1
- package/dist/chunks/divider.cjs +2 -2
- package/dist/chunks/divider.cjs.map +1 -1
- package/dist/chunks/divider.js +3 -3
- 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 +10 -11
- package/dist/chunks/dropdown-button.cjs.map +1 -1
- package/dist/chunks/dropdown-button.js +14 -15
- package/dist/chunks/dropdown-button.js.map +1 -1
- package/dist/chunks/icon.cjs +57 -11
- package/dist/chunks/icon.cjs.map +1 -1
- package/dist/chunks/icon.js +58 -12
- 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 +2 -2
- package/dist/chunks/navbar.cjs.map +1 -1
- package/dist/chunks/navbar.js +3 -3
- package/dist/chunks/navbar.js.map +1 -1
- package/dist/chunks/number-input.cjs +110 -0
- package/dist/chunks/number-input.cjs.map +1 -0
- package/dist/chunks/number-input.js +111 -0
- package/dist/chunks/number-input.js.map +1 -0
- 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/size.cjs +1 -1
- package/dist/chunks/size.js +1 -1
- package/dist/chunks/slider.cjs +35 -75
- package/dist/chunks/slider.cjs.map +1 -1
- package/dist/chunks/slider.js +35 -75
- 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 +14 -5
- package/dist/chunks/tab-panel.cjs.map +1 -1
- package/dist/chunks/tab-panel.js +15 -6
- package/dist/chunks/tab-panel.js.map +1 -1
- package/dist/chunks/tag.cjs +2 -2
- package/dist/chunks/tag.cjs.map +1 -1
- package/dist/chunks/tag.js +3 -3
- 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 +292 -0
- package/dist/chunks/tooltip.cjs.map +1 -0
- package/dist/chunks/tooltip.js +293 -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 +273 -249
- package/dist/chunks/variables.cjs.map +1 -1
- package/dist/chunks/variables.js +273 -249
- package/dist/chunks/variables.js.map +1 -1
- 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/detail-group.cjs +6 -0
- package/dist/detail-group.cjs.map +1 -0
- package/dist/detail-group.js +6 -0
- package/dist/detail-group.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/dropdown.js +4 -4
- package/dist/index.cjs +24 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +41 -116
- 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/number-input.cjs +6 -0
- package/dist/number-input.cjs.map +1 -0
- package/dist/number-input.js +6 -0
- package/dist/number-input.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 +2 -2
- package/dist/select.cjs.map +1 -1
- package/dist/select.js +3 -3
- 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/card/defines.d.ts +1 -1
- 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 +2 -1
- 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/defines.d.ts +5 -1
- package/dist/types/icon/icon.d.ts +1 -0
- package/dist/types/icon/index.d.ts +1 -1
- 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/tabs/defines.d.ts +1 -0
- package/dist/types/tabs/tabs.d.ts +3 -0
- 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/card/defines.ts +1 -1
- package/src/checkbox/checkbox.ts +17 -2
- package/src/copy-button/copy-button.ts +150 -0
- package/src/copy-button/defines.ts +5 -0
- package/src/copy-button/index.ts +3 -0
- package/src/detail/defines.ts +2 -1
- 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/defines.ts +6 -1
- package/src/icon/icon.ts +29 -10
- package/src/icon/index.ts +1 -1
- package/src/icon/registry.ts +23 -1
- 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/color.css +91 -91
- package/src/styles/components/action-button.css +37 -0
- package/src/styles/components/alert.css +22 -28
- package/src/styles/components/badge.css +13 -20
- package/src/styles/components/breadcrumb-item.css +7 -7
- package/src/styles/components/button.css +39 -50
- package/src/styles/components/card.css +45 -30
- package/src/styles/components/checkbox.css +9 -36
- package/src/styles/components/copy-button.css +108 -0
- package/src/styles/components/detail-group.css +10 -0
- package/src/styles/components/detail.css +56 -35
- package/src/styles/components/dialog.css +11 -11
- package/src/styles/components/divider.css +3 -3
- package/src/styles/components/drawer.css +152 -0
- package/src/styles/components/dropdown-item.css +7 -8
- package/src/styles/components/dropdown.css +3 -4
- package/src/styles/components/field-label.css +120 -0
- package/src/styles/components/icon-button.css +25 -36
- package/src/styles/components/icon.css +1 -1
- package/src/styles/components/menu-item.css +167 -0
- package/src/styles/components/menu.css +17 -0
- package/src/styles/components/navbar.css +16 -16
- package/src/styles/components/number-input.css +158 -0
- package/src/styles/components/pagination.css +205 -0
- package/src/styles/components/progress-bar.css +2 -3
- package/src/styles/components/radio-group.css +69 -106
- package/src/styles/components/select-option.css +5 -5
- package/src/styles/components/select.css +30 -69
- package/src/styles/components/slider.css +26 -71
- package/src/styles/components/spinner.css +78 -0
- package/src/styles/components/switch.css +64 -27
- package/src/styles/components/tab-panel.css +1 -1
- package/src/styles/components/tab.css +4 -5
- package/src/styles/components/tabs.css +49 -1
- package/src/styles/components/tag.css +14 -21
- package/src/styles/components/text-input.css +17 -64
- package/src/styles/components/textarea.css +66 -0
- package/src/styles/components/tooltip.css +102 -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/styles/radius.css +10 -0
- package/src/styles/size.css +7 -7
- package/src/styles/variables.css +271 -247
- package/src/switch/defines.ts +1 -0
- package/src/switch/switch.ts +61 -12
- package/src/tabs/defines.ts +1 -0
- package/src/tabs/tabs.ts +12 -0
- 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
package/src/aeico-field.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { InferProps, Props, Watchers } from 'aeico';
|
|
2
2
|
import { tags } from 'aeico';
|
|
3
3
|
import AeicoComponent from './aeico-component';
|
|
4
|
-
import { t } from 'aeico-localize';
|
|
5
4
|
|
|
6
5
|
export type FieldAction = 'clear' | 'reset' | 'change';
|
|
7
6
|
export type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
|
7
|
+
export type ActionButtonStyle = 'standalone' | 'integrated';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Base class for form field components
|
|
@@ -25,10 +25,18 @@ class AeicoField<TValue = string> extends AeicoComponent {
|
|
|
25
25
|
defaultValue: { type: String },
|
|
26
26
|
resettable: { type: Boolean },
|
|
27
27
|
resetText: { type: String },
|
|
28
|
+
resetTitle: { type: String },
|
|
28
29
|
clearable: { type: Boolean },
|
|
29
30
|
clearText: { type: String },
|
|
31
|
+
clearTitle: { type: String },
|
|
32
|
+
actionButtonStyle: { type: String },
|
|
30
33
|
size: { type: String },
|
|
31
34
|
disabled: { type: Boolean },
|
|
35
|
+
label: { type: String },
|
|
36
|
+
labelPlacement: { type: String },
|
|
37
|
+
required: { type: Boolean },
|
|
38
|
+
helperText: { type: String },
|
|
39
|
+
error: { type: String },
|
|
32
40
|
};
|
|
33
41
|
|
|
34
42
|
/**
|
|
@@ -36,8 +44,17 @@ class AeicoField<TValue = string> extends AeicoComponent {
|
|
|
36
44
|
*/
|
|
37
45
|
static watchers: Watchers = {
|
|
38
46
|
disabled: 'onDisabledChanged',
|
|
47
|
+
error: 'onErrorChanged',
|
|
39
48
|
};
|
|
40
49
|
|
|
50
|
+
private static _fieldIdCounter = 0;
|
|
51
|
+
private readonly _fieldId: string;
|
|
52
|
+
|
|
53
|
+
constructor() {
|
|
54
|
+
super();
|
|
55
|
+
this._fieldId = `ae-field-${++AeicoField._fieldIdCounter}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
41
58
|
/**
|
|
42
59
|
* The underlying form control element (input, select, etc.)
|
|
43
60
|
* Subclasses should set this to their specific element
|
|
@@ -58,10 +75,18 @@ class AeicoField<TValue = string> extends AeicoComponent {
|
|
|
58
75
|
declare defaultValue?: TValue | string;
|
|
59
76
|
declare resettable?: boolean;
|
|
60
77
|
declare resetText?: string;
|
|
78
|
+
declare resetTitle?: string;
|
|
61
79
|
declare clearable?: boolean;
|
|
62
80
|
declare clearText?: string;
|
|
81
|
+
declare clearTitle?: string;
|
|
82
|
+
declare actionButtonStyle?: ActionButtonStyle;
|
|
63
83
|
declare size?: string;
|
|
64
84
|
declare disabled?: boolean;
|
|
85
|
+
declare label?: string;
|
|
86
|
+
declare labelPlacement?: 'top' | 'left';
|
|
87
|
+
declare required?: boolean;
|
|
88
|
+
declare helperText?: string;
|
|
89
|
+
declare error?: string;
|
|
65
90
|
|
|
66
91
|
/**
|
|
67
92
|
* Lifecycle: Component connected to DOM
|
|
@@ -82,18 +107,30 @@ class AeicoField<TValue = string> extends AeicoComponent {
|
|
|
82
107
|
* Must be called from within a build() callback.
|
|
83
108
|
*/
|
|
84
109
|
protected renderActionButtons(force: boolean = false) {
|
|
85
|
-
this.
|
|
86
|
-
this.
|
|
110
|
+
const style = this.actionButtonStyle || 'integrated';
|
|
111
|
+
const hasActions = force || this.clearable || this.resettable;
|
|
112
|
+
|
|
113
|
+
if (hasActions && style === 'integrated') {
|
|
114
|
+
tags.div({ className: 'action-controls' }, () => {
|
|
115
|
+
this.renderClearButton(force);
|
|
116
|
+
this.renderResetButton(force);
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
this.renderClearButton(force);
|
|
120
|
+
this.renderResetButton(force);
|
|
121
|
+
}
|
|
87
122
|
}
|
|
88
123
|
|
|
89
124
|
protected renderResetButton(force: boolean = false) {
|
|
90
125
|
const { button } = tags;
|
|
126
|
+
const style = this.actionButtonStyle || 'integrated';
|
|
91
127
|
|
|
92
128
|
if (force || this.resettable) {
|
|
129
|
+
const className = style === 'integrated' ? 'reset-btn action-btn' : 'reset-btn';
|
|
93
130
|
this.resetBtn = button({
|
|
94
|
-
className
|
|
131
|
+
className,
|
|
95
132
|
textContent: this.resetText || '↺',
|
|
96
|
-
title:
|
|
133
|
+
title: this.resetTitle || '↺',
|
|
97
134
|
'@click': this.boundOnReset,
|
|
98
135
|
});
|
|
99
136
|
}
|
|
@@ -101,17 +138,63 @@ class AeicoField<TValue = string> extends AeicoComponent {
|
|
|
101
138
|
|
|
102
139
|
protected renderClearButton(force: boolean = false) {
|
|
103
140
|
const { button } = tags;
|
|
141
|
+
const style = this.actionButtonStyle || 'integrated';
|
|
104
142
|
|
|
105
143
|
if (force || this.clearable) {
|
|
144
|
+
const className = style === 'integrated' ? 'clear-btn action-btn' : 'clear-btn';
|
|
106
145
|
this.clearBtn = button({
|
|
107
|
-
className
|
|
146
|
+
className,
|
|
108
147
|
textContent: this.clearText || '✕',
|
|
109
|
-
title:
|
|
148
|
+
title: this.clearTitle || '✕',
|
|
110
149
|
'@click': this.boundOnClear,
|
|
111
150
|
});
|
|
112
151
|
}
|
|
113
152
|
}
|
|
114
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Returns a stable unique ID for this field instance,
|
|
156
|
+
* used to associate <label htmlFor> with the underlying input.
|
|
157
|
+
*/
|
|
158
|
+
protected getFieldId(): string {
|
|
159
|
+
return this._fieldId;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Renders a <label> element when the `label` prop is set.
|
|
164
|
+
* Call this as the first statement inside the render() html() callback.
|
|
165
|
+
* @param fieldId - The id to set on the underlying form control element (pass to input via id prop)
|
|
166
|
+
*/
|
|
167
|
+
protected renderLabel(fieldId: string): void {
|
|
168
|
+
if (!this.label) return;
|
|
169
|
+
const { span } = tags;
|
|
170
|
+
tags.label({ id: `${fieldId}-label`, className: 'field-label', for: fieldId }, () => {
|
|
171
|
+
span({ textContent: this.label! });
|
|
172
|
+
if (this.required) {
|
|
173
|
+
span({ className: 'field-required', 'aria-hidden': 'true', textContent: ' *' });
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Renders helper text below the field. Hidden when `error` is set.
|
|
180
|
+
* Call this after the field-body div in render().
|
|
181
|
+
*/
|
|
182
|
+
protected renderHelperText(): void {
|
|
183
|
+
if (!this.helperText || this.error) return;
|
|
184
|
+
const { span } = tags;
|
|
185
|
+
span({ className: 'field-helper', textContent: this.helperText });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Renders an error message below the field when `error` is set.
|
|
190
|
+
* Call this after renderHelperText() in render().
|
|
191
|
+
*/
|
|
192
|
+
protected renderError(): void {
|
|
193
|
+
if (!this.error) return;
|
|
194
|
+
const { span } = tags;
|
|
195
|
+
span({ className: 'field-error', textContent: this.error });
|
|
196
|
+
}
|
|
197
|
+
|
|
115
198
|
/**
|
|
116
199
|
* Watcher for disabled property
|
|
117
200
|
*/
|
|
@@ -121,6 +204,58 @@ class AeicoField<TValue = string> extends AeicoComponent {
|
|
|
121
204
|
}
|
|
122
205
|
}
|
|
123
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Watcher for error property — syncs aria-invalid on the field element
|
|
209
|
+
*/
|
|
210
|
+
protected onErrorChanged(newValue: string | undefined): void {
|
|
211
|
+
if (this.fieldElement) {
|
|
212
|
+
if (newValue) {
|
|
213
|
+
this.fieldElement.setAttribute('aria-invalid', 'true');
|
|
214
|
+
} else {
|
|
215
|
+
this.fieldElement.removeAttribute('aria-invalid');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Lifecycle: called after every render update.
|
|
222
|
+
* Keeps aria-invalid on fieldElement in sync regardless of watcher timing.
|
|
223
|
+
*/
|
|
224
|
+
protected onUpdated(_changedProps: Map<string, unknown>): void {
|
|
225
|
+
if (!this.fieldElement) return;
|
|
226
|
+
if (this.error) {
|
|
227
|
+
this.fieldElement.setAttribute('aria-invalid', 'true');
|
|
228
|
+
} else {
|
|
229
|
+
this.fieldElement.removeAttribute('aria-invalid');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Returns true if the field passes constraint validation.
|
|
235
|
+
* Delegates to the underlying fieldElement when available;
|
|
236
|
+
* falls back to a manual required-check otherwise.
|
|
237
|
+
*/
|
|
238
|
+
public checkValidity(): boolean {
|
|
239
|
+
if (this.fieldElement) {
|
|
240
|
+
return this.fieldElement.checkValidity();
|
|
241
|
+
}
|
|
242
|
+
if (this.required) {
|
|
243
|
+
const v = this.value;
|
|
244
|
+
return v !== undefined && v !== '' && v !== null;
|
|
245
|
+
}
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Reports validity, showing the browser's built-in validation UI when possible.
|
|
251
|
+
*/
|
|
252
|
+
public reportValidity(): boolean {
|
|
253
|
+
if (this.fieldElement) {
|
|
254
|
+
return this.fieldElement.reportValidity();
|
|
255
|
+
}
|
|
256
|
+
return this.checkValidity();
|
|
257
|
+
}
|
|
258
|
+
|
|
124
259
|
/**
|
|
125
260
|
* Render the field component
|
|
126
261
|
* Override in subclass to provide custom rendering
|
package/src/alert/alert.ts
CHANGED
|
@@ -4,7 +4,6 @@ import colorCSS from '../styles/color.css?inline';
|
|
|
4
4
|
import alertStyle from '../styles/components/alert.css?inline';
|
|
5
5
|
import AeicoComponent from '../aeico-component';
|
|
6
6
|
import { html } from 'aeico';
|
|
7
|
-
import { t } from 'aeico-localize';
|
|
8
7
|
import type { AlertColor, AlertSize, AlertVariant } from './defines';
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -39,6 +38,7 @@ class Alert extends AeicoComponent {
|
|
|
39
38
|
size: { type: String },
|
|
40
39
|
dismissible: { type: Boolean },
|
|
41
40
|
invisible: { type: Boolean },
|
|
41
|
+
closeText: { type: String },
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
protected static useStyles = ['alert'];
|
|
@@ -49,6 +49,7 @@ class Alert extends AeicoComponent {
|
|
|
49
49
|
declare size?: AlertSize;
|
|
50
50
|
declare dismissible?: boolean;
|
|
51
51
|
declare invisible?: boolean;
|
|
52
|
+
declare closeText?: string;
|
|
52
53
|
|
|
53
54
|
protected render() {
|
|
54
55
|
return html(({ div, slot, button, span }) => {
|
|
@@ -67,7 +68,7 @@ class Alert extends AeicoComponent {
|
|
|
67
68
|
{
|
|
68
69
|
className: 'alert-close',
|
|
69
70
|
'@click': () => this._handleClose(),
|
|
70
|
-
title:
|
|
71
|
+
title: this.closeText || 'Close alert',
|
|
71
72
|
},
|
|
72
73
|
() => {
|
|
73
74
|
span({ 'aria-hidden': 'true', textContent: '\u00d7' });
|
package/src/card/defines.ts
CHANGED
package/src/checkbox/checkbox.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { html } from 'aeico';
|
|
|
4
4
|
import styleVariables from '../styles/variables.css?inline';
|
|
5
5
|
import sizeCSS from '../styles/size.css?inline';
|
|
6
6
|
import colorCSS from '../styles/color.css?inline';
|
|
7
|
+
import fieldLabelCSS from '../styles/components/field-label.css?inline';
|
|
8
|
+
import actionButtonCSS from '../styles/components/action-button.css?inline';
|
|
7
9
|
import styles from '../styles/components/checkbox.css?inline';
|
|
8
10
|
import { CheckboxVariant } from './defines';
|
|
9
11
|
|
|
@@ -22,7 +24,14 @@ class Checkbox extends AeicoField<boolean> {
|
|
|
22
24
|
declare defaultChecked?: boolean;
|
|
23
25
|
declare variant?: CheckboxVariant;
|
|
24
26
|
|
|
25
|
-
protected static styles = [
|
|
27
|
+
protected static styles = [
|
|
28
|
+
styleVariables,
|
|
29
|
+
sizeCSS,
|
|
30
|
+
colorCSS,
|
|
31
|
+
fieldLabelCSS,
|
|
32
|
+
actionButtonCSS,
|
|
33
|
+
styles,
|
|
34
|
+
];
|
|
26
35
|
|
|
27
36
|
protected getValue(): boolean {
|
|
28
37
|
return this.fieldElement?.checked ?? false;
|
|
@@ -62,18 +71,24 @@ class Checkbox extends AeicoField<boolean> {
|
|
|
62
71
|
|
|
63
72
|
render() {
|
|
64
73
|
return html(({ div, input }) => {
|
|
65
|
-
|
|
74
|
+
const id = this.getFieldId();
|
|
75
|
+
this.renderLabel(id);
|
|
76
|
+
div({ className: 'checkbox-container field-body', variant: this.variant }, () => {
|
|
66
77
|
div({ className: 'checkbox-wrapper' }, () => {
|
|
67
78
|
this.fieldElement = input({
|
|
79
|
+
id,
|
|
68
80
|
type: 'checkbox',
|
|
69
81
|
className: 'field-input',
|
|
70
82
|
checked: Boolean(this.checked),
|
|
71
83
|
disabled: Boolean(this.disabled),
|
|
84
|
+
required: Boolean(this.required),
|
|
72
85
|
'@change': this.boundOnChange,
|
|
73
86
|
});
|
|
74
87
|
});
|
|
75
88
|
this.renderActionButtons();
|
|
76
89
|
});
|
|
90
|
+
this.renderHelperText();
|
|
91
|
+
this.renderError();
|
|
77
92
|
});
|
|
78
93
|
}
|
|
79
94
|
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { InferProps } from 'aeico';
|
|
2
|
+
import styleVariables from '../styles/variables.css?inline';
|
|
3
|
+
import sizeCSS from '../styles/size.css?inline';
|
|
4
|
+
import colorCSS from '../styles/color.css?inline';
|
|
5
|
+
import copyButtonStyle from '../styles/components/copy-button.css?inline';
|
|
6
|
+
import AeicoComponent from '../aeico-component';
|
|
7
|
+
import { html } from 'aeico';
|
|
8
|
+
import { prop } from 'aeico';
|
|
9
|
+
// Ensure ae-icon and ae-tooltip are registered
|
|
10
|
+
import '../icon/icon';
|
|
11
|
+
import '../tooltip/tooltip';
|
|
12
|
+
import type Tooltip from '../tooltip/tooltip';
|
|
13
|
+
import type { TooltipPlacement } from '../tooltip/defines';
|
|
14
|
+
import type { CopyButtonColor, CopyButtonSize, CopyButtonVariant } from './defines';
|
|
15
|
+
|
|
16
|
+
class CopyButton extends AeicoComponent {
|
|
17
|
+
protected static styles = [styleVariables, sizeCSS, colorCSS, copyButtonStyle];
|
|
18
|
+
|
|
19
|
+
@prop({ type: String })
|
|
20
|
+
accessor text: string | undefined;
|
|
21
|
+
|
|
22
|
+
@prop({ type: String })
|
|
23
|
+
accessor color: CopyButtonColor | undefined;
|
|
24
|
+
|
|
25
|
+
@prop({ type: String })
|
|
26
|
+
accessor variant: CopyButtonVariant | undefined;
|
|
27
|
+
|
|
28
|
+
@prop({ type: String })
|
|
29
|
+
accessor size: CopyButtonSize | undefined;
|
|
30
|
+
|
|
31
|
+
@prop({ type: Boolean })
|
|
32
|
+
accessor disabled: boolean | undefined;
|
|
33
|
+
|
|
34
|
+
@prop({ type: Number })
|
|
35
|
+
accessor duration: number | undefined;
|
|
36
|
+
|
|
37
|
+
@prop({ type: String })
|
|
38
|
+
accessor tooltip: string = 'Copy';
|
|
39
|
+
|
|
40
|
+
@prop({ type: String })
|
|
41
|
+
accessor tooltipCopied: string = 'Copied!';
|
|
42
|
+
|
|
43
|
+
@prop({ type: String })
|
|
44
|
+
accessor tooltipPlacement: TooltipPlacement = 'top';
|
|
45
|
+
|
|
46
|
+
private _slotElement: HTMLSlotElement | null = null;
|
|
47
|
+
private _tooltipEl: Tooltip | null = null;
|
|
48
|
+
private _resetTimer: ReturnType<typeof setTimeout> | null = null;
|
|
49
|
+
|
|
50
|
+
private _getTextToCopy(): string {
|
|
51
|
+
if (this.text != null) return this.text;
|
|
52
|
+
|
|
53
|
+
const nodes = this._slotElement?.assignedNodes({ flatten: true }) ?? [];
|
|
54
|
+
|
|
55
|
+
return nodes
|
|
56
|
+
.reduce<string>((text, n) => {
|
|
57
|
+
if (n.nodeType === Node.TEXT_NODE) return text + (n.textContent ?? '');
|
|
58
|
+
|
|
59
|
+
return text;
|
|
60
|
+
}, '')
|
|
61
|
+
.trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private _handleClick = () => {
|
|
65
|
+
if (this.disabled) return;
|
|
66
|
+
|
|
67
|
+
const textToCopy = this._getTextToCopy();
|
|
68
|
+
|
|
69
|
+
void navigator.clipboard.writeText(textToCopy).then(() => {
|
|
70
|
+
this.setAttribute('copied', '');
|
|
71
|
+
|
|
72
|
+
if (this._tooltipEl) {
|
|
73
|
+
this._tooltipEl.content = this.tooltipCopied;
|
|
74
|
+
this._tooltipEl.open = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (this._resetTimer !== null) {
|
|
78
|
+
clearTimeout(this._resetTimer);
|
|
79
|
+
}
|
|
80
|
+
const duration = this.duration ?? 2000;
|
|
81
|
+
this._resetTimer = setTimeout(() => {
|
|
82
|
+
this.removeAttribute('copied');
|
|
83
|
+
if (this._tooltipEl) {
|
|
84
|
+
this._tooltipEl.content = this.tooltip;
|
|
85
|
+
this._tooltipEl.open = false;
|
|
86
|
+
}
|
|
87
|
+
this._resetTimer = null;
|
|
88
|
+
}, duration);
|
|
89
|
+
|
|
90
|
+
this.dispatchEvent(
|
|
91
|
+
new CustomEvent('copy', {
|
|
92
|
+
bubbles: true,
|
|
93
|
+
composed: true,
|
|
94
|
+
detail: { text: textToCopy },
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
protected onUnmounted() {
|
|
101
|
+
if (this._resetTimer !== null) {
|
|
102
|
+
clearTimeout(this._resetTimer);
|
|
103
|
+
this._resetTimer = null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
protected render() {
|
|
108
|
+
return html(({ aeTooltip, button, span, slot, aeIcon }) => {
|
|
109
|
+
this._tooltipEl = aeTooltip(
|
|
110
|
+
{
|
|
111
|
+
content: this.tooltip,
|
|
112
|
+
placement: this.tooltipPlacement,
|
|
113
|
+
disabled: this.disabled,
|
|
114
|
+
},
|
|
115
|
+
() => {
|
|
116
|
+
button(
|
|
117
|
+
{
|
|
118
|
+
type: 'button',
|
|
119
|
+
disabled: this.disabled,
|
|
120
|
+
part: 'button',
|
|
121
|
+
'aria-label': this.tooltip,
|
|
122
|
+
'aria-disabled': this.disabled,
|
|
123
|
+
'@click': this._handleClick,
|
|
124
|
+
},
|
|
125
|
+
() => {
|
|
126
|
+
span({ className: 'icon-copy' }, () => {
|
|
127
|
+
aeIcon({ name: 'copy', size: this.size });
|
|
128
|
+
});
|
|
129
|
+
span({ className: 'icon-check' }, () => {
|
|
130
|
+
aeIcon({ name: 'check', size: this.size });
|
|
131
|
+
});
|
|
132
|
+
this._slotElement = slot();
|
|
133
|
+
},
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
CopyButton.register();
|
|
142
|
+
|
|
143
|
+
declare global {
|
|
144
|
+
interface HTMLElementTagNameMap {
|
|
145
|
+
'ae-copy-button': CopyButton;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export default CopyButton;
|
|
150
|
+
export type CopyButtonProps = InferProps<typeof CopyButton>;
|
package/src/detail/defines.ts
CHANGED
package/src/detail/detail.ts
CHANGED
|
@@ -5,7 +5,7 @@ import detailStyle from '../styles/components/detail.css?inline';
|
|
|
5
5
|
import AeicoComponent from '../aeico-component';
|
|
6
6
|
import { html } from 'aeico';
|
|
7
7
|
import { prop } from 'aeico';
|
|
8
|
-
import type { DetailColor, DetailVariant } from './defines';
|
|
8
|
+
import type { DetailColor, DetailVariant, DetailIconPlacement } from './defines';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Detail component that can be used to show/hide additional content.
|
|
@@ -35,6 +35,9 @@ class Detail extends AeicoComponent {
|
|
|
35
35
|
@prop({ type: Boolean })
|
|
36
36
|
accessor disabled: boolean = false;
|
|
37
37
|
|
|
38
|
+
@prop({ type: String })
|
|
39
|
+
accessor iconPlacement: DetailIconPlacement = 'end';
|
|
40
|
+
|
|
38
41
|
private _open: boolean = false;
|
|
39
42
|
|
|
40
43
|
/** Opens the detail panel. */
|
|
@@ -120,3 +123,4 @@ declare global {
|
|
|
120
123
|
|
|
121
124
|
export default Detail;
|
|
122
125
|
export type DetailProps = InferProps<typeof Detail>;
|
|
126
|
+
export type { DetailIconPlacement };
|
package/src/detail/index.ts
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { InferProps, Props } from 'aeico';
|
|
2
|
+
import styleVariables from '../styles/variables.css?inline';
|
|
3
|
+
import detailGroupStyle from '../styles/components/detail-group.css?inline';
|
|
4
|
+
import AeicoComponent from '../aeico-component';
|
|
5
|
+
import { html } from 'aeico';
|
|
6
|
+
import type Detail from '../detail/detail';
|
|
7
|
+
import type { DetailColor, DetailVariant } from '../detail/defines';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* DetailGroup component — wraps multiple `ae-detail` elements into an
|
|
11
|
+
* accordion-style group. By default only one item can be open at a time;
|
|
12
|
+
* set `multiple` to allow several items open simultaneously.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```html
|
|
16
|
+
* <ae-detail-group>
|
|
17
|
+
* <ae-detail summary="Section 1">Content 1</ae-detail>
|
|
18
|
+
* <ae-detail summary="Section 2">Content 2</ae-detail>
|
|
19
|
+
* <ae-detail summary="Section 3">Content 3</ae-detail>
|
|
20
|
+
* </ae-detail-group>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
class DetailGroup extends AeicoComponent {
|
|
24
|
+
static tagName = 'detail-group';
|
|
25
|
+
|
|
26
|
+
static props: Props = {
|
|
27
|
+
multiple: { type: Boolean },
|
|
28
|
+
variant: { type: String },
|
|
29
|
+
color: { type: String },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
protected static styles = [styleVariables, detailGroupStyle];
|
|
33
|
+
|
|
34
|
+
declare multiple?: boolean;
|
|
35
|
+
declare variant?: DetailVariant;
|
|
36
|
+
declare color?: DetailColor;
|
|
37
|
+
|
|
38
|
+
private slotEl: HTMLSlotElement | null = null;
|
|
39
|
+
|
|
40
|
+
private readonly DETAIL_RADIUS = 6;
|
|
41
|
+
|
|
42
|
+
connectedCallback() {
|
|
43
|
+
super.connectedCallback();
|
|
44
|
+
this.listen('open', this._handleOpen);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private _getDetails(): Detail[] {
|
|
48
|
+
if (!this.slotEl) return [];
|
|
49
|
+
return (this.slotEl.assignedElements({ flatten: true }) as Detail[]).filter(
|
|
50
|
+
(el) => el.tagName.toLowerCase() === 'ae-detail',
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private _syncChildren(): void {
|
|
55
|
+
const details = this._getDetails();
|
|
56
|
+
const r = this.DETAIL_RADIUS;
|
|
57
|
+
|
|
58
|
+
details.forEach((detail, i) => {
|
|
59
|
+
const isFirst = i === 0;
|
|
60
|
+
const isLast = i === details.length - 1;
|
|
61
|
+
|
|
62
|
+
// Collapse borders between adjacent items
|
|
63
|
+
detail.style.marginTop = isFirst ? '' : '-1px';
|
|
64
|
+
|
|
65
|
+
// Adjust per-corner radius so only the outer edges of the group keep it
|
|
66
|
+
detail.style.setProperty('--detail-r-tl', isFirst ? `${r}px` : '0');
|
|
67
|
+
detail.style.setProperty('--detail-r-tr', isFirst ? `${r}px` : '0');
|
|
68
|
+
detail.style.setProperty('--detail-r-br', isLast ? `${r}px` : '0');
|
|
69
|
+
detail.style.setProperty('--detail-r-bl', isLast ? `${r}px` : '0');
|
|
70
|
+
|
|
71
|
+
// Propagate variant / color only when explicitly set on the group
|
|
72
|
+
if (this.variant !== undefined) detail.variant = this.variant;
|
|
73
|
+
if (this.color !== undefined) detail.color = this.color;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private _handleOpen = (event: Event): void => {
|
|
78
|
+
if (this.multiple) return;
|
|
79
|
+
const opened = event.target as Element;
|
|
80
|
+
this._getDetails().forEach((detail) => {
|
|
81
|
+
if (detail !== opened) detail.close();
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
protected render() {
|
|
86
|
+
return html(({ slot }) => {
|
|
87
|
+
this.slotEl = slot({
|
|
88
|
+
'@slotchange': () => this._syncChildren(),
|
|
89
|
+
});
|
|
90
|
+
this._syncChildren();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
DetailGroup.register();
|
|
96
|
+
|
|
97
|
+
declare global {
|
|
98
|
+
interface HTMLElementTagNameMap {
|
|
99
|
+
'ae-detail-group': DetailGroup;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default DetailGroup;
|
|
104
|
+
export type DetailGroupProps = InferProps<typeof DetailGroup>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type DrawerPlacement = 'left' | 'right' | 'top' | 'bottom';
|