@programmerg/bs-elements 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +148 -0
- package/custom-elements.json +7773 -0
- package/dist/bs-elements.bundle.min.js +8 -0
- package/dist/bs-elements.bundle.min.js.map +1 -0
- package/dist/bs-elements.esm.js +1721 -0
- package/dist/bs-elements.esm.js.map +1 -0
- package/dist/bs-elements.min.js +2 -0
- package/dist/bs-elements.min.js.map +1 -0
- package/package.json +50 -0
- package/src/base/BsAccordion.js +116 -0
- package/src/base/BsAlert.js +91 -0
- package/src/base/BsButton.js +129 -0
- package/src/base/BsCarousel.js +216 -0
- package/src/base/BsCollapse.js +84 -0
- package/src/base/BsDropdown.js +98 -0
- package/src/base/BsModal.js +204 -0
- package/src/base/BsOffcanvas.js +157 -0
- package/src/base/BsPopover.js +31 -0
- package/src/base/BsTab.js +69 -0
- package/src/base/BsToast.js +163 -0
- package/src/base/BsTooltip.js +118 -0
- package/src/core/BsElement.js +81 -0
- package/src/core/ReactiveElement.js +183 -0
- package/src/extra/BsCalendar.js +14 -0
- package/src/extra/BsCombobox.js +14 -0
- package/src/extra/BsForm.js +152 -0
- package/src/extra/BsInput.js +209 -0
- package/src/extra/BsTable.js +210 -0
- package/src/extra/BsTabs.js +0 -0
- package/src/extra/BsToastManager.js +0 -0
- package/src/extra/BsTree.js +14 -0
- package/src/extra/BsUploader.js +154 -0
- package/src/index.js +12 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Toast } from "bootstrap";
|
|
2
|
+
import BsElement from "../core/BsElement.js";
|
|
3
|
+
|
|
4
|
+
export default class BsToast extends BsElement {
|
|
5
|
+
|
|
6
|
+
static get properties() {
|
|
7
|
+
return {
|
|
8
|
+
color: {
|
|
9
|
+
description: "Color of the Toast background.",
|
|
10
|
+
type: String,
|
|
11
|
+
default: "",
|
|
12
|
+
values: ["", "primary", "secondary", "success", "danger", "warning", "info", "light", "dark"]
|
|
13
|
+
},
|
|
14
|
+
header: {
|
|
15
|
+
description: "Customize the modal header content.",
|
|
16
|
+
type: String,
|
|
17
|
+
default: undefined
|
|
18
|
+
},
|
|
19
|
+
autohide: {
|
|
20
|
+
description: "Controls whether the Toast component autohides after a certain duration.",
|
|
21
|
+
type: Boolean,
|
|
22
|
+
default: false,
|
|
23
|
+
attribute: "data-bs-autohide"
|
|
24
|
+
},
|
|
25
|
+
delay: {
|
|
26
|
+
description: "The time delay (in milliseconds) before the Toast component autohides.",
|
|
27
|
+
type: Number,
|
|
28
|
+
default: 5000,
|
|
29
|
+
attribute: "data-bs-delay"
|
|
30
|
+
},
|
|
31
|
+
animation: {
|
|
32
|
+
description: "Controls whether the Toast component fades in and out.",
|
|
33
|
+
type: Boolean,
|
|
34
|
+
default: true,
|
|
35
|
+
attribute: "data-bs-animation"
|
|
36
|
+
},
|
|
37
|
+
open: {
|
|
38
|
+
description: "Controls whether the Toast component is initially open.",
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: true
|
|
41
|
+
},
|
|
42
|
+
dismissible: {
|
|
43
|
+
description: "Controls whether the Toast component is dismissible",
|
|
44
|
+
type: Boolean,
|
|
45
|
+
default: true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static get bs() {
|
|
51
|
+
return Toast;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
constructor() {
|
|
55
|
+
super();
|
|
56
|
+
|
|
57
|
+
// this is an external state managed by bootstrap
|
|
58
|
+
Object.defineProperty(this.constructor.prototype, "open", {
|
|
59
|
+
get() {
|
|
60
|
+
return this.classList.contains("show");
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
hide() {
|
|
66
|
+
return this.bs?.hide();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
show() {
|
|
70
|
+
return this.bs?.show();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
isShown() {
|
|
74
|
+
return this.bs?.isShown();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
firstUpdated() {
|
|
78
|
+
this.classList.add("toast");
|
|
79
|
+
if (!this.hasAttribute("role")) this.setAttribute("role", "alert");
|
|
80
|
+
if (!this.hasAttribute("aria-live")) this.setAttribute("aria-live", "assertive");
|
|
81
|
+
if (!this.hasAttribute("aria-atomic")) this.setAttribute("aria-atomic", "true");
|
|
82
|
+
|
|
83
|
+
this._fixMarkup();
|
|
84
|
+
this._updateHeaderState();
|
|
85
|
+
this._updateDismissibleState();
|
|
86
|
+
this._updateColorState();
|
|
87
|
+
this._updateOpenState(true);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_fixMarkup() {
|
|
91
|
+
let header = this.querySelector(":scope > .toast-header");
|
|
92
|
+
if (!header && this.header) {
|
|
93
|
+
header = document.createElement("div");
|
|
94
|
+
header.classList.add("toast-header");
|
|
95
|
+
|
|
96
|
+
header.insertAdjacentHTML("afterbegin", `<strong class="me-auto">${this.header}</strong>`);
|
|
97
|
+
|
|
98
|
+
this.appendChild(header);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let body = this.querySelector(":scope > .toast-body");
|
|
102
|
+
if (!body) {
|
|
103
|
+
body = document.createElement("div");
|
|
104
|
+
body.classList.add("toast-body");
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i < this.childNodes.length; i++) {
|
|
107
|
+
if (this.childNodes[i].classList?.contains("toast-header")) continue;
|
|
108
|
+
body.appendChild(this.childNodes[i]);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.appendChild(body);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_updateHeaderState() {
|
|
116
|
+
let header = this.querySelector(":scope > .toast-header");
|
|
117
|
+
if (!header && this.header) {
|
|
118
|
+
this._fixMarkup();
|
|
119
|
+
header = this.querySelector(":scope > .toast-header");
|
|
120
|
+
header.textContent = this.header || "";
|
|
121
|
+
}
|
|
122
|
+
if (header && !this.header) {
|
|
123
|
+
header.remove();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_updateDismissibleState() {
|
|
128
|
+
const closeBtn = this.querySelector(".btn-close");
|
|
129
|
+
if (this.dismissible) {
|
|
130
|
+
if (!closeBtn) this.firstChild?.insertAdjacentHTML("beforeend",
|
|
131
|
+
`<button type="button" class="btn-close ms-2 mb-1" data-bs-dismiss="toast" aria-label="Close"></button>`
|
|
132
|
+
);
|
|
133
|
+
} else {
|
|
134
|
+
if (closeBtn) closeBtn.remove();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
_updateColorState() {
|
|
139
|
+
this.classList.remove(
|
|
140
|
+
...this.constructor.properties
|
|
141
|
+
.color.values.map(v => "bg-" + v)
|
|
142
|
+
);
|
|
143
|
+
if (this.color) this.classList.add("bg-" + this.color);
|
|
144
|
+
|
|
145
|
+
if (this.color === "" || this.color === "light" || this.color === "warning") {
|
|
146
|
+
this.classList.remove("text-white");
|
|
147
|
+
} else {
|
|
148
|
+
this.classList.add("text-white");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
_updateOpenState(isFirstUpdate = false) {
|
|
153
|
+
const newState = this.__propValues['open'];
|
|
154
|
+
if (isFirstUpdate) this.classList.toggle("show", newState);
|
|
155
|
+
else {
|
|
156
|
+
if (newState) this.show();
|
|
157
|
+
else this.hide();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
customElements.define("bs-toast", BsToast);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Tooltip } from "bootstrap";
|
|
2
|
+
import BsElement from "../core/BsElement.js";
|
|
3
|
+
|
|
4
|
+
export default class BsTooltip extends BsElement {
|
|
5
|
+
|
|
6
|
+
static get properties() {
|
|
7
|
+
return {
|
|
8
|
+
animation: {
|
|
9
|
+
description: "Flag to enable animation for the tooltip.",
|
|
10
|
+
type: Boolean,
|
|
11
|
+
default: true,
|
|
12
|
+
attribute: "data-bs-animation"
|
|
13
|
+
},
|
|
14
|
+
title: {
|
|
15
|
+
description: "The title to be displayed within the tooltip.",
|
|
16
|
+
type: String,
|
|
17
|
+
default: "",
|
|
18
|
+
attribute: "data-bs-title"
|
|
19
|
+
},
|
|
20
|
+
delay: {
|
|
21
|
+
description: "The delay for showing the tooltip (in milliseconds).",
|
|
22
|
+
type: Number,
|
|
23
|
+
default: 0,
|
|
24
|
+
attribute: "data-bs-delay"
|
|
25
|
+
},
|
|
26
|
+
html: {
|
|
27
|
+
description: "",
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: false,
|
|
30
|
+
attribute: "data-bs-html"
|
|
31
|
+
},
|
|
32
|
+
open: {
|
|
33
|
+
description: "Controls the visibility of the tooltip.",
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false
|
|
36
|
+
},
|
|
37
|
+
placement: {
|
|
38
|
+
description: "The preferred placement of the tooltip.",
|
|
39
|
+
type: String,
|
|
40
|
+
default: "top",
|
|
41
|
+
attribute: "data-bs-placement"
|
|
42
|
+
},
|
|
43
|
+
trigger: {
|
|
44
|
+
description: "The trigger action to open/close the popover.",
|
|
45
|
+
type: String,
|
|
46
|
+
default: "click",
|
|
47
|
+
attribute: "data-bs-trigger"
|
|
48
|
+
},
|
|
49
|
+
container: {
|
|
50
|
+
description: "the popover’s HTML appears within that element.",
|
|
51
|
+
type: String,
|
|
52
|
+
default: "body",
|
|
53
|
+
attribute: "data-bs-container"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static get bs() {
|
|
59
|
+
return Tooltip;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
constructor() {
|
|
63
|
+
super();
|
|
64
|
+
|
|
65
|
+
// this is an external state managed by bootstrap
|
|
66
|
+
Object.defineProperty(this.constructor.prototype, "open", {
|
|
67
|
+
get() {
|
|
68
|
+
return this.bs?.tip && this.bs?.tip.classList.contains('show');
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
disable() {
|
|
74
|
+
return this.bs?.disable();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
enable() {
|
|
78
|
+
return this.bs?.enable();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
hide() {
|
|
82
|
+
return this.bs?.hide();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
show() {
|
|
86
|
+
return this.bs?.show();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
toggle() {
|
|
90
|
+
return this.bs?.toggle();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
toggleEnabled() {
|
|
94
|
+
return this.bs?.toggleEnabled();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setContent() {
|
|
98
|
+
return this.bs?.setContent();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
update() {
|
|
102
|
+
return this.bs?.update();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
firstUpdated() {
|
|
106
|
+
if (!this.hasAttribute("data-bs-toggle")) this.setAttribute("data-bs-toggle", "tooltip");
|
|
107
|
+
|
|
108
|
+
this._updateOpenState(true);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_updateOpenState(isFirstUpdate = false) {
|
|
112
|
+
if (isFirstUpdate) this.classList.toggle("show", this.__propValues['open']);
|
|
113
|
+
else this.toggle();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
customElements.define("bs-tooltip", BsTooltip);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import ReactiveElement from "./ReactiveElement.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reactive Element with Bootstrap integration
|
|
5
|
+
*/
|
|
6
|
+
export default class BsElement extends ReactiveElement {
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
|
|
11
|
+
this.bs = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static __bsProps = [];
|
|
15
|
+
|
|
16
|
+
static get bsProps() {
|
|
17
|
+
if (this.__bsProps === undefined) {
|
|
18
|
+
this.__bsProps = [];
|
|
19
|
+
|
|
20
|
+
// memoize related props
|
|
21
|
+
const props = this.properties || this.properties?.() || {};
|
|
22
|
+
for (const [prop, def] of Object.entries(props)) {
|
|
23
|
+
if ((def.attribute ?? '').startsWith('data-bs-')) this.__bsProps.push(prop);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return this.__bsProps;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Must return a Bootstrap JS constructor (e.g. bootstrap.Modal, bootstrap.Collapse)
|
|
31
|
+
*/
|
|
32
|
+
static get bs() {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
createInstance() {
|
|
37
|
+
if (!this.constructor.bs || this.bs) return;
|
|
38
|
+
|
|
39
|
+
const options = this.constructor.bsProps.reduce((acc, key) => {
|
|
40
|
+
if (key in this.__propValues) acc[key] = this.__propValues[key];
|
|
41
|
+
return acc;
|
|
42
|
+
}, {}) || {};
|
|
43
|
+
|
|
44
|
+
this.bs = new this.constructor.bs(this, options);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
dispose() {
|
|
48
|
+
if (!this.bs) return;
|
|
49
|
+
|
|
50
|
+
this.bs?.dispose();
|
|
51
|
+
this.bs = null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
connectedCallback() {
|
|
55
|
+
// try to guess prop initial values from markup when it's not set
|
|
56
|
+
const props = this.properties || this.properties?.() || {};
|
|
57
|
+
for (const [prop, def] of Object.entries(props)) {
|
|
58
|
+
if (this.__propValues[prop] !== undefined) continue;
|
|
59
|
+
this[prop] = def.values?.find(v => this.className.includes(v));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
super.connectedCallback();
|
|
63
|
+
this.createInstance();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
updated(changed) {
|
|
67
|
+
super.updated(changed);
|
|
68
|
+
|
|
69
|
+
const shouldReinit = this.constructor.bsProps.some(p => changed.has(p));
|
|
70
|
+
if (shouldReinit) {
|
|
71
|
+
this.dispose();
|
|
72
|
+
this.createInstance();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
disconnectedCallback() {
|
|
77
|
+
super.disconnectedCallback();
|
|
78
|
+
this.dispose();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
export default class ReactiveElement extends HTMLElement {
|
|
2
|
+
|
|
3
|
+
constructor() {
|
|
4
|
+
super();
|
|
5
|
+
|
|
6
|
+
// reactive internals
|
|
7
|
+
this.__propValues = Object.create(null);
|
|
8
|
+
this.__changed = new Set();
|
|
9
|
+
this.__updateScheduled = false;
|
|
10
|
+
this.__reflecting = false;
|
|
11
|
+
|
|
12
|
+
this.createReactiveProperties();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* ------------------------------------------------------------------
|
|
16
|
+
* Reactive helpers
|
|
17
|
+
* ------------------------------------------------------------------ */
|
|
18
|
+
|
|
19
|
+
static get properties() {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static __propertyToAttributeMap;
|
|
24
|
+
|
|
25
|
+
static __attributeToPropertyMap;
|
|
26
|
+
|
|
27
|
+
static propertyToAttribute(property) {
|
|
28
|
+
if (this.__propertyToAttributeMap.size < 1) this.observedAttributes();
|
|
29
|
+
return this.__propertyToAttributeMap.get(property);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static attributeToProperty(attribute) {
|
|
33
|
+
if (this.__attributeToPropertyMap.size < 1) this.observedAttributes();
|
|
34
|
+
return this.__attributeToPropertyMap.get(attribute);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static get observedAttributes() {
|
|
38
|
+
if (this.__attributeToPropertyMap === undefined) {
|
|
39
|
+
this.__propertyToAttributeMap = new Map();
|
|
40
|
+
this.__attributeToPropertyMap = new Map();
|
|
41
|
+
|
|
42
|
+
// memoize mappings
|
|
43
|
+
const props = this.properties || this.properties?.() || {};
|
|
44
|
+
for (const [prop, def] of Object.entries(props)) {
|
|
45
|
+
const attr = def?.attribute ?? prop.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
46
|
+
this.__propertyToAttributeMap.set(prop, attr);
|
|
47
|
+
this.__attributeToPropertyMap.set(attr, prop);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return [...this.__attributeToPropertyMap.keys()];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getAttrValue(attr, type) {
|
|
54
|
+
const value = this.getAttribute(attr);
|
|
55
|
+
|
|
56
|
+
switch (type) {
|
|
57
|
+
case Boolean:
|
|
58
|
+
return this.hasAttribute(attr) && (value === "" || value === "true");
|
|
59
|
+
case Number:
|
|
60
|
+
const n = Number(value);
|
|
61
|
+
return Number.isNaN(n) ? undefined : n;
|
|
62
|
+
default:
|
|
63
|
+
return value === null ? undefined : value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setAttrValue(attr, value, type) {
|
|
68
|
+
if (value === null || value === undefined || (type === Boolean && !value)) {
|
|
69
|
+
this.removeAttribute(attr);
|
|
70
|
+
} else {
|
|
71
|
+
this.setAttribute(attr, (type === Boolean) ? "" : String(value));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
createReactiveProperties() {
|
|
76
|
+
const props = this.constructor.properties || this.constructor.properties?.() || {};
|
|
77
|
+
for (const [prop, def] of Object.entries(props)) {
|
|
78
|
+
this.createReactiveProperty(prop, def);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
createReactiveProperty(prop, def) {
|
|
83
|
+
const attr = this.constructor.propertyToAttribute(prop);
|
|
84
|
+
|
|
85
|
+
// avoid redefining existing properties
|
|
86
|
+
if (!Object.getOwnPropertyDescriptor(this.constructor.prototype, prop)) {
|
|
87
|
+
Object.defineProperty(this.constructor.prototype, prop, {
|
|
88
|
+
get() {
|
|
89
|
+
return this.__propValues[prop];
|
|
90
|
+
},
|
|
91
|
+
set(value) {
|
|
92
|
+
const old = this.__propValues[prop];
|
|
93
|
+
if (old === value) return;
|
|
94
|
+
|
|
95
|
+
this.__propValues[prop] = value;
|
|
96
|
+
|
|
97
|
+
// reflect props to attributes
|
|
98
|
+
const shouldReflect = def.reflect;
|
|
99
|
+
if (shouldReflect) {
|
|
100
|
+
this.__reflecting = true;
|
|
101
|
+
this.setAttrValue(attr, value, def.type);
|
|
102
|
+
queueMicrotask(() => (this.__reflecting = false));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.__changed.add(prop);
|
|
106
|
+
this.scheduleUpdate();
|
|
107
|
+
},
|
|
108
|
+
configurable: true,
|
|
109
|
+
enumerable: true
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// seed initial values from attributes or defaults
|
|
114
|
+
this.__propValues[prop] = this.getAttrValue(attr, def.type) ?? def.default;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
childrenToSlots(html) {
|
|
118
|
+
var template = document.createElement("template");
|
|
119
|
+
template.innerHTML = html;
|
|
120
|
+
|
|
121
|
+
const slots = template.content.querySelectorAll("slot");
|
|
122
|
+
for (const slot of slots) {
|
|
123
|
+
const slotChildren = this.querySelectorAll(`[slot="${slot.name}"]`);
|
|
124
|
+
slotChildren.forEach(el => el.removeAttribute("slot"));
|
|
125
|
+
slot.replaceWith(...slotChildren);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.replaceChildren(template.content);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* ------------------------------------------------------------------
|
|
132
|
+
* Custom Element Lifecycle
|
|
133
|
+
* ------------------------------------------------------------------ */
|
|
134
|
+
|
|
135
|
+
connectedCallback() {
|
|
136
|
+
this.firstUpdated();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// eslint-disable-next-line class-methods-use-this
|
|
140
|
+
firstUpdated() {}
|
|
141
|
+
|
|
142
|
+
attributeChangedCallback(attrName, oldValue, newValue) {
|
|
143
|
+
if (this.__reflecting) return;
|
|
144
|
+
|
|
145
|
+
const prop = this.constructor.attributeToProperty(attrName);
|
|
146
|
+
|
|
147
|
+
const props = this.constructor.properties || this.constructor.properties?.() || {};
|
|
148
|
+
const def = props[prop] || {};
|
|
149
|
+
|
|
150
|
+
const old = this.__propValues[prop];
|
|
151
|
+
const value = this.getAttrValue(attrName, def.type);
|
|
152
|
+
if (old === value) return;
|
|
153
|
+
this.__propValues[prop] = value;
|
|
154
|
+
this.__changed.add(prop);
|
|
155
|
+
this.scheduleUpdate();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
scheduleUpdate() {
|
|
159
|
+
if (this.__updateScheduled) return;
|
|
160
|
+
this.__updateScheduled = true;
|
|
161
|
+
queueMicrotask(() => {
|
|
162
|
+
this.__updateScheduled = false;
|
|
163
|
+
const changed = new Set(this.__changed);
|
|
164
|
+
this.__changed.clear();
|
|
165
|
+
try {
|
|
166
|
+
this.updated(changed);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.error(e);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
updated(changed) {
|
|
174
|
+
changed.forEach(prop => {
|
|
175
|
+
const fn = `_update${prop.charAt(0).toUpperCase() + prop.slice(1)}State`;
|
|
176
|
+
if (typeof this[fn] === "function") this[fn]();
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// eslint-disable-next-line class-methods-use-this
|
|
181
|
+
disconnectedCallback() {}
|
|
182
|
+
|
|
183
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import BsElement from "../core/BsElement.js";
|
|
2
|
+
|
|
3
|
+
export default class BsCombobox extends BsElement {
|
|
4
|
+
|
|
5
|
+
static get properties() {
|
|
6
|
+
return {}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
firstUpdated() {
|
|
10
|
+
// https://tom-select.js.org/docs/selectize.js
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
customElements.define("bs-combobox", BsCombobox);
|