@kupola/kupola 1.2.0 → 1.4.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 +21 -0
- package/README.md +330 -286
- package/adapters/axios.d.ts +34 -0
- package/adapters/axios.js +122 -0
- package/adapters/navios-http.d.ts +110 -0
- package/adapters/navios-http.js +151 -0
- package/css/components-ext.css +157 -0
- package/css/components.css +69 -0
- package/css/theme-dark.css +5 -5
- package/css/utilities.css +119 -1
- package/dist/css/accessibility.css +119 -0
- package/dist/css/animations.css +224 -0
- package/dist/css/brand-themes.css +300 -0
- package/dist/css/colors_and_type.css +441 -0
- package/dist/css/components-ext.css +4165 -0
- package/dist/css/components.css +1483 -0
- package/dist/css/kupola.css +1 -12
- package/dist/css/kupola.min.css +1 -0
- package/dist/css/responsive.css +697 -0
- package/dist/css/scaffold.css +145 -0
- package/dist/css/states.css +316 -0
- package/dist/css/theme-dark.css +296 -0
- package/dist/css/theme-light.css +296 -0
- package/dist/css/utilities.css +171 -0
- package/dist/icons.svg +284 -0
- package/dist/kupola.cjs.js +17409 -257
- package/dist/kupola.cjs.js.map +1 -1
- package/dist/kupola.css +9000 -0
- package/dist/kupola.esm.js +17183 -7597
- package/dist/kupola.esm.js.map +1 -1
- package/dist/kupola.min.css +1 -0
- package/dist/kupola.min.js +2 -0
- package/dist/kupola.min.js.map +1 -0
- package/dist/kupola.umd.js +17415 -257
- package/dist/kupola.umd.js.map +1 -1
- package/dist/plugins/vite-plugin-kupola.js +120 -0
- package/dist/types/kupola.d.ts +421 -323
- package/js/calendar.js +334 -25
- package/js/carousel.js +182 -48
- package/js/collapse.js +148 -34
- package/js/color-picker.js +416 -108
- package/js/component.js +8 -19
- package/js/countdown.js +9 -8
- package/js/data-bind.js +73 -16
- package/js/datepicker.js +488 -110
- package/js/depends.js +710 -0
- package/js/dialog.js +4 -2
- package/js/drawer.js +172 -8
- package/js/dropdown.js +272 -17
- package/js/dynamic-tags.js +156 -40
- package/js/fileupload.js +9 -8
- package/js/form.js +280 -254
- package/js/global-events.js +281 -188
- package/js/heatmap.js +10 -7
- package/js/i18n.js +18 -10
- package/js/icons.js +141 -161
- package/js/image-preview.js +146 -2
- package/js/initializer.js +151 -71
- package/js/kupola-core.js +123 -45
- package/js/kupola-lifecycle.js +13 -11
- package/js/message.js +8 -1
- package/js/modal.js +207 -59
- package/js/notification.js +8 -1
- package/js/numberinput.js +9 -8
- package/js/pagination.js +263 -0
- package/js/registry.js +29 -12
- package/js/select.js +482 -27
- package/js/slide-captcha.js +11 -2
- package/js/slider.js +442 -25
- package/js/statcard.js +9 -7
- package/js/table.js +1210 -0
- package/js/tag.js +268 -14
- package/js/theme-standalone.js +88 -0
- package/js/theme.js +14 -43
- package/js/timepicker.js +335 -66
- package/js/tooltip.js +317 -86
- package/js/utils.js +6 -2
- package/js/validation.js +6 -2
- package/js/virtual-list.js +11 -7
- package/js/web-components.js +288 -0
- package/package.json +81 -67
- package/plugins/vite-plugin-kupola.js +120 -0
- package/scripts/build-css.cjs +113 -0
- package/scripts/build-svg-sprite.cjs +107 -0
- package/types/kupola.d.ts +421 -323
- package/CHANGELOG.md +0 -130
- package/INTEGRATION.md +0 -440
- package/PROJECT_SUMMARY.md +0 -312
- package/SKILL.md +0 -572
- package/dist/utils/utils/Kupola.cs +0 -77
- package/dist/utils/utils/Kupola.java +0 -104
- package/dist/utils/utils/kupola.go +0 -120
- package/dist/utils/utils/kupola.js +0 -63
- package/dist/utils/utils/kupola.py +0 -1392
- package/dist/utils/utils/kupola.rb +0 -69
- package/js/composition-api.js +0 -458
- package/js/error-handler.js +0 -181
- package/js/http.js +0 -419
- package/js/kupola-devtools.js +0 -598
- package/js/performance.js +0 -250
- package/js/router.js +0 -396
- package/js/security.js +0 -189
- package/js/test-utils.js +0 -251
- package/templates/base.html +0 -30
- package/templates/base_dashboard.html +0 -99
- package/utils/Kupola.cs +0 -77
- package/utils/Kupola.java +0 -104
- package/utils/kupola.go +0 -120
- package/utils/kupola.js +0 -63
- package/utils/kupola.py +0 -1392
- package/utils/kupola.rb +0 -69
package/js/kupola-core.js
CHANGED
|
@@ -1,66 +1,144 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
createHttp
|
|
15
|
-
};
|
|
16
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Kupola Core — Component system bootstrap, registry, and lifecycle management.
|
|
3
|
+
* @module kupola-core
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { KupolaComponent, applyMixin } from './component.js';
|
|
7
|
+
import { KupolaComponentRegistry } from './registry.js';
|
|
8
|
+
import { KupolaLifecycle } from './kupola-lifecycle.js';
|
|
9
|
+
import { kupolaInitializer } from './initializer.js';
|
|
10
|
+
import { kupolaData } from './data-bind.js';
|
|
11
|
+
import { initTheme } from './theme.js';
|
|
12
|
+
|
|
13
|
+
let kupolaRegistry = null;
|
|
17
14
|
|
|
18
|
-
if (window
|
|
19
|
-
|
|
15
|
+
if (typeof window !== 'undefined') {
|
|
16
|
+
kupolaRegistry = new KupolaComponentRegistry();
|
|
20
17
|
}
|
|
21
18
|
|
|
19
|
+
/** Bootstrap the Kupola component system (data binding, theme, component discovery). */
|
|
22
20
|
async function kupolaBootstrap() {
|
|
23
|
-
if (window
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
if (typeof window !== 'undefined') {
|
|
22
|
+
// Load persisted data and bind data-bind elements
|
|
23
|
+
kupolaData.loadPersisted();
|
|
24
|
+
kupolaData.bind();
|
|
25
|
+
// Initialize theme
|
|
26
|
+
initTheme();
|
|
27
|
+
// Initialize function-based components first
|
|
28
|
+
await kupolaInitializer.initializeAll();
|
|
29
|
+
// Then bootstrap class-based components
|
|
30
|
+
if (kupolaRegistry) {
|
|
31
|
+
await kupolaRegistry.bootstrap();
|
|
32
|
+
}
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
if (document.readyState === 'loading') {
|
|
36
|
+
if (typeof document !== 'undefined' && document.readyState === 'loading') {
|
|
32
37
|
document.addEventListener('DOMContentLoaded', kupolaBootstrap);
|
|
33
|
-
} else {
|
|
38
|
+
} else if (typeof window !== 'undefined') {
|
|
34
39
|
setTimeout(kupolaBootstrap, 0);
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
/** Register a class-based component. */
|
|
43
|
+
function registerComponent(name, componentClass) {
|
|
44
|
+
if (kupolaRegistry) {
|
|
45
|
+
kupolaRegistry.register(name, componentClass);
|
|
40
46
|
}
|
|
41
|
-
}
|
|
47
|
+
}
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
/** Register a lazy-loaded component (loaded on first use). */
|
|
50
|
+
function registerLazyComponent(name, loader) {
|
|
51
|
+
if (kupolaRegistry) {
|
|
52
|
+
kupolaRegistry.registerLazy(name, loader);
|
|
46
53
|
}
|
|
47
|
-
}
|
|
54
|
+
}
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
/** Manually bootstrap components within a specific root element. */
|
|
57
|
+
function bootstrapComponents(root) {
|
|
58
|
+
if (kupolaRegistry) {
|
|
59
|
+
return kupolaRegistry.bootstrap(root);
|
|
52
60
|
}
|
|
53
61
|
return Promise.resolve();
|
|
54
|
-
}
|
|
62
|
+
}
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
/** Define a reusable mixin for component classes. */
|
|
65
|
+
function defineMixin(name, mixin) {
|
|
66
|
+
if (kupolaRegistry) {
|
|
67
|
+
kupolaRegistry.defineMixin(name, mixin);
|
|
59
68
|
}
|
|
60
|
-
}
|
|
69
|
+
}
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
/** Apply named mixins to a component class. */
|
|
72
|
+
function useMixin(componentClass, ...mixinNames) {
|
|
73
|
+
if (kupolaRegistry) {
|
|
74
|
+
kupolaRegistry.useMixin(componentClass, ...mixinNames);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Unified component registration API.
|
|
80
|
+
* @param {string} name - Component name
|
|
81
|
+
* @param {object} options
|
|
82
|
+
* @param {Function} [options.init] - Init function (for function-based components)
|
|
83
|
+
* @param {Function} [options.cleanup] - Cleanup function
|
|
84
|
+
* @param {Function} [options.componentClass] - Component class (for class-based components)
|
|
85
|
+
* @param {Function} [options.lazy] - Lazy loader function
|
|
86
|
+
* @param {string} [options.dataAttribute] - Custom data attribute (e.g. 'data-my-component')
|
|
87
|
+
* @param {string} [options.cssClass] - CSS class selector (e.g. 'ds-my-component')
|
|
88
|
+
*/
|
|
89
|
+
function defineComponent(name, options) {
|
|
90
|
+
if (!options || typeof options !== 'object') {
|
|
91
|
+
throw new Error(`defineComponent("${name}"): options must be an object`);
|
|
92
|
+
}
|
|
93
|
+
// Register with registry (class or lazy)
|
|
94
|
+
if (options.componentClass) {
|
|
95
|
+
if (kupolaRegistry) {
|
|
96
|
+
kupolaRegistry.register(name, options.componentClass);
|
|
97
|
+
}
|
|
98
|
+
} else if (options.lazy) {
|
|
99
|
+
if (kupolaRegistry) {
|
|
100
|
+
kupolaRegistry.registerLazy(name, options.lazy);
|
|
101
|
+
}
|
|
65
102
|
}
|
|
66
|
-
|
|
103
|
+
// Register with initializer (function-based)
|
|
104
|
+
if (options.init) {
|
|
105
|
+
kupolaInitializer.register(name, options.init, options.cleanup || null, {
|
|
106
|
+
dataAttribute: options.dataAttribute,
|
|
107
|
+
cssClass: options.cssClass
|
|
108
|
+
});
|
|
109
|
+
} else if (options.dataAttribute || options.cssClass) {
|
|
110
|
+
// Even without init, register selectors so MutationObserver can find them
|
|
111
|
+
kupolaInitializer.register(name, () => {}, null, {
|
|
112
|
+
dataAttribute: options.dataAttribute,
|
|
113
|
+
cssClass: options.cssClass
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export {
|
|
119
|
+
KupolaComponent,
|
|
120
|
+
applyMixin,
|
|
121
|
+
KupolaComponentRegistry,
|
|
122
|
+
KupolaLifecycle,
|
|
123
|
+
kupolaRegistry,
|
|
124
|
+
kupolaInitializer,
|
|
125
|
+
kupolaBootstrap,
|
|
126
|
+
registerComponent,
|
|
127
|
+
registerLazyComponent,
|
|
128
|
+
bootstrapComponents,
|
|
129
|
+
defineMixin,
|
|
130
|
+
useMixin,
|
|
131
|
+
defineComponent
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
if (typeof window !== 'undefined') {
|
|
135
|
+
window.kupolaRegistry = kupolaRegistry;
|
|
136
|
+
window.kupolaInitializer = kupolaInitializer;
|
|
137
|
+
window.kupolaBootstrap = kupolaBootstrap;
|
|
138
|
+
window.registerComponent = registerComponent;
|
|
139
|
+
window.registerLazyComponent = registerLazyComponent;
|
|
140
|
+
window.bootstrapComponents = bootstrapComponents;
|
|
141
|
+
window.defineMixin = defineMixin;
|
|
142
|
+
window.useMixin = useMixin;
|
|
143
|
+
window.defineComponent = defineComponent;
|
|
144
|
+
}
|
package/js/kupola-lifecycle.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class KupolaLifecycle {
|
|
1
|
+
export class KupolaLifecycle {
|
|
2
2
|
constructor(scope = 'app') {
|
|
3
3
|
this.scope = scope;
|
|
4
4
|
this.hooks = new Map();
|
|
@@ -345,7 +345,7 @@ class KupolaLifecycle {
|
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
class KupolaPluginManager {
|
|
348
|
+
export class KupolaPluginManager {
|
|
349
349
|
constructor() {
|
|
350
350
|
this.plugins = new Map();
|
|
351
351
|
this.enabledPlugins = new Set();
|
|
@@ -477,7 +477,7 @@ class KupolaPluginManager {
|
|
|
477
477
|
const pluginHooks = this.pluginHooks.get(pluginName);
|
|
478
478
|
|
|
479
479
|
Object.keys(hooks).forEach(phase => {
|
|
480
|
-
const unsubscribe = window.kupolaLifecycle?.on(phase, hooks[phase], { name: `${pluginName}:${phase}` });
|
|
480
|
+
const unsubscribe = typeof window !== 'undefined' && window.kupolaLifecycle?.on(phase, hooks[phase], { name: `${pluginName}:${phase}` });
|
|
481
481
|
if (unsubscribe) {
|
|
482
482
|
pluginHooks.push({ phase, unsubscribe });
|
|
483
483
|
}
|
|
@@ -496,15 +496,17 @@ class KupolaPluginManager {
|
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
-
const kupolaLifecycle = new KupolaLifecycle('app');
|
|
500
|
-
const kupolaPluginManager = new KupolaPluginManager();
|
|
499
|
+
export const kupolaLifecycle = new KupolaLifecycle('app');
|
|
500
|
+
export const kupolaPluginManager = new KupolaPluginManager();
|
|
501
501
|
|
|
502
|
-
function createLifecycle(scope = 'app') {
|
|
502
|
+
export function createLifecycle(scope = 'app') {
|
|
503
503
|
return new KupolaLifecycle(scope);
|
|
504
504
|
}
|
|
505
505
|
|
|
506
|
-
window
|
|
507
|
-
window.
|
|
508
|
-
window.
|
|
509
|
-
window.
|
|
510
|
-
window.
|
|
506
|
+
if (typeof window !== 'undefined') {
|
|
507
|
+
window.KupolaLifecycle = KupolaLifecycle;
|
|
508
|
+
window.KupolaPluginManager = KupolaPluginManager;
|
|
509
|
+
window.kupolaLifecycle = kupolaLifecycle;
|
|
510
|
+
window.kupolaPluginManager = kupolaPluginManager;
|
|
511
|
+
window.createLifecycle = createLifecycle;
|
|
512
|
+
}
|
package/js/message.js
CHANGED
package/js/modal.js
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
class Modal {
|
|
2
|
-
constructor(element) {
|
|
2
|
+
constructor(element, options = {}) {
|
|
3
3
|
this.element = element;
|
|
4
4
|
this.mask = element.querySelector('.ds-modal-mask');
|
|
5
5
|
this.modal = element.querySelector('.ds-modal');
|
|
6
6
|
this.closeBtn = element.querySelector('.ds-modal__close');
|
|
7
7
|
|
|
8
|
+
// Options
|
|
9
|
+
this.fullscreen = options.fullscreen || element.hasAttribute('data-modal-fullscreen');
|
|
10
|
+
this.closableOnMask = options.closableOnMask !== false; // default true
|
|
11
|
+
this.escClose = options.escClose !== false;
|
|
12
|
+
this.width = options.width || element.getAttribute('data-modal-width') || '';
|
|
13
|
+
this.center = options.center !== false;
|
|
14
|
+
this.onBeforeOpen = options.onBeforeOpen || null;
|
|
15
|
+
this.onBeforeClose = options.onBeforeClose || null;
|
|
16
|
+
this.onOpened = options.onOpened || null;
|
|
17
|
+
this.onClosed = options.onClosed || null;
|
|
18
|
+
|
|
8
19
|
this._keydownHandler = (e) => {
|
|
9
|
-
if (e.key === 'Escape' && this.isVisible()) {
|
|
20
|
+
if (this.escClose && e.key === 'Escape' && this.isVisible()) {
|
|
10
21
|
this.close();
|
|
11
22
|
}
|
|
12
23
|
};
|
|
@@ -14,7 +25,7 @@ class Modal {
|
|
|
14
25
|
this._closeBtnClickHandler = () => this.close();
|
|
15
26
|
|
|
16
27
|
this._maskClickHandler = (e) => {
|
|
17
|
-
if (e.target === this.mask) {
|
|
28
|
+
if (this.closableOnMask && e.target === this.mask) {
|
|
18
29
|
this.close();
|
|
19
30
|
}
|
|
20
31
|
};
|
|
@@ -32,24 +43,93 @@ class Modal {
|
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
document.addEventListener('keydown', this._keydownHandler);
|
|
46
|
+
|
|
47
|
+
// Apply fullscreen
|
|
48
|
+
if (this.fullscreen && this.modal) {
|
|
49
|
+
this.modal.classList.add('ds-modal--fullscreen');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Apply custom width
|
|
53
|
+
if (this.width && this.modal) {
|
|
54
|
+
this.modal.style.maxWidth = this.width;
|
|
55
|
+
}
|
|
35
56
|
}
|
|
36
57
|
|
|
37
58
|
open() {
|
|
38
|
-
this.
|
|
59
|
+
if (this.onBeforeOpen) {
|
|
60
|
+
const result = this.onBeforeOpen();
|
|
61
|
+
if (result === false) return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (this.mask) {
|
|
65
|
+
this.mask.classList.add('is-visible');
|
|
66
|
+
this.mask.classList.add('ds-modal-fade-enter');
|
|
67
|
+
requestAnimationFrame(() => {
|
|
68
|
+
this.mask.classList.add('ds-modal-fade-enter-active');
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (this.modal) {
|
|
72
|
+
this.modal.classList.add('ds-modal-zoom-enter');
|
|
73
|
+
requestAnimationFrame(() => {
|
|
74
|
+
this.modal.classList.add('ds-modal-zoom-enter-active');
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
39
78
|
Modal._openCount = (Modal._openCount || 0) + 1;
|
|
40
79
|
document.body.style.overflow = 'hidden';
|
|
80
|
+
|
|
81
|
+
if (this.onOpened) {
|
|
82
|
+
setTimeout(() => this.onOpened(), 300);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.element.dispatchEvent(new CustomEvent('kupola:modal-open', { bubbles: true }));
|
|
41
86
|
}
|
|
42
87
|
|
|
43
88
|
close() {
|
|
44
|
-
this.
|
|
89
|
+
if (this.onBeforeClose) {
|
|
90
|
+
const result = this.onBeforeClose();
|
|
91
|
+
if (result === false) return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (this.mask) {
|
|
95
|
+
this.mask.classList.remove('ds-modal-fade-enter-active');
|
|
96
|
+
this.mask.classList.add('ds-modal-fade-leave-active');
|
|
97
|
+
}
|
|
98
|
+
if (this.modal) {
|
|
99
|
+
this.modal.classList.remove('ds-modal-zoom-enter-active');
|
|
100
|
+
this.modal.classList.add('ds-modal-zoom-leave-active');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
if (this.mask) {
|
|
105
|
+
this.mask.classList.remove('is-visible', 'ds-modal-fade-enter', 'ds-modal-fade-leave-active');
|
|
106
|
+
}
|
|
107
|
+
if (this.modal) {
|
|
108
|
+
this.modal.classList.remove('ds-modal-zoom-enter', 'ds-modal-zoom-leave-active');
|
|
109
|
+
}
|
|
110
|
+
}, 300);
|
|
111
|
+
|
|
45
112
|
Modal._openCount = Math.max(0, (Modal._openCount || 0) - 1);
|
|
46
113
|
if (Modal._openCount === 0) {
|
|
47
114
|
document.body.style.overflow = '';
|
|
48
115
|
}
|
|
116
|
+
|
|
117
|
+
if (this.onClosed) {
|
|
118
|
+
setTimeout(() => this.onClosed(), 300);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.element.dispatchEvent(new CustomEvent('kupola:modal-close', { bubbles: true }));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
toggleFullscreen() {
|
|
125
|
+
this.fullscreen = !this.fullscreen;
|
|
126
|
+
if (this.modal) {
|
|
127
|
+
this.modal.classList.toggle('ds-modal--fullscreen', this.fullscreen);
|
|
128
|
+
}
|
|
49
129
|
}
|
|
50
130
|
|
|
51
131
|
isVisible() {
|
|
52
|
-
return this.mask.classList.contains('is-visible');
|
|
132
|
+
return this.mask && this.mask.classList.contains('is-visible');
|
|
53
133
|
}
|
|
54
134
|
|
|
55
135
|
destroy() {
|
|
@@ -72,89 +152,151 @@ function createModal(options = {}) {
|
|
|
72
152
|
const {
|
|
73
153
|
title = '',
|
|
74
154
|
content = '',
|
|
155
|
+
html = false,
|
|
75
156
|
width = '480px',
|
|
157
|
+
fullscreen = false,
|
|
158
|
+
showCancel = true,
|
|
159
|
+
showConfirm = true,
|
|
160
|
+
confirmText = 'OK',
|
|
161
|
+
cancelText = 'Cancel',
|
|
162
|
+
confirmClass = 'ds-btn--brand',
|
|
163
|
+
cancelClass = 'ds-btn--ghost',
|
|
164
|
+
closable = true,
|
|
165
|
+
maskClosable = true,
|
|
76
166
|
onConfirm,
|
|
77
|
-
onCancel
|
|
167
|
+
onCancel,
|
|
168
|
+
onOpen,
|
|
169
|
+
onClose,
|
|
170
|
+
footer = null
|
|
78
171
|
} = options;
|
|
79
172
|
|
|
80
173
|
const container = document.createElement('div');
|
|
81
174
|
container.className = 'ds-modal-container';
|
|
175
|
+
|
|
176
|
+
let footerHTML = '';
|
|
177
|
+
if (footer !== null) {
|
|
178
|
+
if (typeof footer === 'string') {
|
|
179
|
+
footerHTML = `<div class="ds-modal__footer">${footer}</div>`;
|
|
180
|
+
} else if (showConfirm || showCancel) {
|
|
181
|
+
footerHTML = `<div class="ds-modal__footer">
|
|
182
|
+
${showCancel ? `<button class="ds-btn ${cancelClass}" data-modal-cancel>${cancelText}</button>` : ''}
|
|
183
|
+
${showConfirm ? `<button class="ds-btn ${confirmClass}" data-modal-confirm>${confirmText}</button>` : ''}
|
|
184
|
+
</div>`;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
82
188
|
container.innerHTML = `
|
|
83
189
|
<div class="ds-modal-mask">
|
|
84
|
-
<div class="ds-modal" style="max-width:
|
|
190
|
+
<div class="ds-modal${fullscreen ? ' ds-modal--fullscreen' : ''}" style="${!fullscreen ? 'max-width: ' + width : ''}">
|
|
85
191
|
<div class="ds-modal__header">
|
|
86
192
|
<span class="ds-modal__title"></span>
|
|
87
|
-
|
|
193
|
+
${closable ? `<button class="ds-modal__close" aria-label="Close">
|
|
88
194
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
89
195
|
<path d="M18 6L6 18M6 6l12 12"/>
|
|
90
196
|
</svg>
|
|
91
|
-
</button
|
|
197
|
+
</button>` : ''}
|
|
92
198
|
</div>
|
|
93
199
|
<div class="ds-modal__body"></div>
|
|
94
|
-
${
|
|
95
|
-
<div class="ds-modal__footer">
|
|
96
|
-
${onCancel ? `<button class="ds-btn ds-btn--ghost" data-modal-cancel>Cancel</button>` : ''}
|
|
97
|
-
${onConfirm ? `<button class="ds-btn ds-btn--brand" data-modal-confirm>OK</button>` : ''}
|
|
98
|
-
</div>
|
|
99
|
-
` : ''}
|
|
200
|
+
${footerHTML}
|
|
100
201
|
</div>
|
|
101
202
|
</div>
|
|
102
203
|
`;
|
|
103
204
|
|
|
104
205
|
document.body.appendChild(container);
|
|
105
206
|
|
|
106
|
-
const modal = new Modal(container);
|
|
207
|
+
const modal = new Modal(container, { fullscreen, closableOnMask: maskClosable });
|
|
107
208
|
|
|
108
209
|
const titleEl = container.querySelector('.ds-modal__title');
|
|
109
210
|
if (titleEl) titleEl.textContent = title;
|
|
110
211
|
const bodyEl = container.querySelector('.ds-modal__body');
|
|
111
|
-
if (bodyEl)
|
|
212
|
+
if (bodyEl) {
|
|
213
|
+
if (html) {
|
|
214
|
+
bodyEl.innerHTML = content;
|
|
215
|
+
} else {
|
|
216
|
+
bodyEl.textContent = content;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
112
219
|
|
|
113
220
|
const confirmBtn = container.querySelector('[data-modal-confirm]');
|
|
114
221
|
const cancelBtn = container.querySelector('[data-modal-cancel]');
|
|
115
222
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (cancelBtn) {
|
|
131
|
-
cancelBtn.addEventListener('click', cancelHandler);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const closeAndDestroy = () => {
|
|
135
|
-
setTimeout(() => {
|
|
136
|
-
if (confirmBtn) {
|
|
137
|
-
confirmBtn.removeEventListener('click', confirmHandler);
|
|
138
|
-
}
|
|
139
|
-
if (cancelBtn) {
|
|
140
|
-
cancelBtn.removeEventListener('click', cancelHandler);
|
|
223
|
+
let isConfirming = false;
|
|
224
|
+
|
|
225
|
+
const confirmHandler = async () => {
|
|
226
|
+
if (onConfirm) {
|
|
227
|
+
// Support async onConfirm
|
|
228
|
+
confirmBtn.disabled = true;
|
|
229
|
+
confirmBtn.classList.add('is-loading');
|
|
230
|
+
try {
|
|
231
|
+
const result = await onConfirm();
|
|
232
|
+
if (result === false) {
|
|
233
|
+
confirmBtn.disabled = false;
|
|
234
|
+
confirmBtn.classList.remove('is-loading');
|
|
235
|
+
return;
|
|
141
236
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
237
|
+
} catch(e) {
|
|
238
|
+
confirmBtn.disabled = false;
|
|
239
|
+
confirmBtn.classList.remove('is-loading');
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
isConfirming = true;
|
|
244
|
+
modal.close();
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const cancelHandler = () => {
|
|
248
|
+
if (onCancel) onCancel();
|
|
249
|
+
modal.close();
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
if (confirmBtn) confirmBtn.addEventListener('click', confirmHandler);
|
|
253
|
+
if (cancelBtn) cancelBtn.addEventListener('click', cancelHandler);
|
|
254
|
+
|
|
255
|
+
const closeAndDestroy = () => {
|
|
256
|
+
setTimeout(() => {
|
|
257
|
+
if (confirmBtn) confirmBtn.removeEventListener('click', confirmHandler);
|
|
258
|
+
if (cancelBtn) cancelBtn.removeEventListener('click', cancelHandler);
|
|
259
|
+
modal.destroy();
|
|
260
|
+
container.remove();
|
|
261
|
+
if (onClose) onClose(isConfirming);
|
|
262
|
+
}, 300);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const originalClose = modal.close.bind(modal);
|
|
266
|
+
modal.close = () => {
|
|
267
|
+
originalClose();
|
|
268
|
+
closeAndDestroy();
|
|
269
|
+
};
|
|
152
270
|
|
|
153
271
|
modal.open();
|
|
272
|
+
if (onOpen) setTimeout(() => onOpen(), 50);
|
|
154
273
|
|
|
155
274
|
return modal;
|
|
156
275
|
}
|
|
157
276
|
|
|
277
|
+
// Convenience methods
|
|
278
|
+
function confirmModal(options) {
|
|
279
|
+
if (typeof options === 'string') {
|
|
280
|
+
options = { content: options };
|
|
281
|
+
}
|
|
282
|
+
return createModal({
|
|
283
|
+
...options,
|
|
284
|
+
showCancel: true,
|
|
285
|
+
showConfirm: true
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function alertModal(options) {
|
|
290
|
+
if (typeof options === 'string') {
|
|
291
|
+
options = { content: options };
|
|
292
|
+
}
|
|
293
|
+
return createModal({
|
|
294
|
+
...options,
|
|
295
|
+
showCancel: false,
|
|
296
|
+
showConfirm: true
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
158
300
|
function initModal(element) {
|
|
159
301
|
if (element.__kupolaInitialized) return;
|
|
160
302
|
|
|
@@ -179,13 +321,19 @@ function initModals() {
|
|
|
179
321
|
});
|
|
180
322
|
}
|
|
181
323
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
324
|
+
export { Modal, initModals, initModal, cleanupModal, createModal, confirmModal, alertModal };
|
|
325
|
+
|
|
326
|
+
if (typeof window !== 'undefined') {
|
|
327
|
+
window.Modal = Modal;
|
|
185
328
|
window.initModal = initModal;
|
|
186
329
|
window.cleanupModal = cleanupModal;
|
|
330
|
+
window.initModals = initModals;
|
|
331
|
+
window.createModal = createModal;
|
|
332
|
+
window.confirmModal = confirmModal;
|
|
333
|
+
window.alertModal = alertModal;
|
|
334
|
+
|
|
335
|
+
if (window.kupolaInitializer) {
|
|
336
|
+
window.kupolaInitializer.register('modal', initModal, cleanupModal);
|
|
337
|
+
}
|
|
187
338
|
}
|
|
188
339
|
|
|
189
|
-
if (window.kupolaInitializer) {
|
|
190
|
-
window.kupolaInitializer.register('modal', initModal, cleanupModal);
|
|
191
|
-
}
|
package/js/notification.js
CHANGED
|
@@ -70,4 +70,11 @@ const Notification = {
|
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
function initNotifications() {}
|
|
73
|
+
function initNotifications() {}
|
|
74
|
+
|
|
75
|
+
export { Notification, initNotifications };
|
|
76
|
+
|
|
77
|
+
if (typeof window !== 'undefined') {
|
|
78
|
+
window.Notification = Notification;
|
|
79
|
+
window.initNotifications = initNotifications;
|
|
80
|
+
}
|
package/js/numberinput.js
CHANGED
|
@@ -86,7 +86,7 @@ class NumberInput {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
dispatchChange() {
|
|
89
|
-
this.element.dispatchEvent(new CustomEvent('
|
|
89
|
+
this.element.dispatchEvent(new CustomEvent('kupola:number-input-change', {
|
|
90
90
|
detail: {
|
|
91
91
|
value: this.getValue()
|
|
92
92
|
}
|
|
@@ -133,14 +133,15 @@ function initNumberInputs() {
|
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
export { NumberInput, initNumberInputs, initNumberInput, cleanupNumberInput };
|
|
137
|
+
|
|
138
|
+
if (typeof window !== 'undefined') {
|
|
139
139
|
window.NumberInput = NumberInput;
|
|
140
140
|
window.initNumberInput = initNumberInput;
|
|
141
141
|
window.cleanupNumberInput = cleanupNumberInput;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (window.kupolaInitializer) {
|
|
145
|
-
|
|
142
|
+
window.initNumberInputs = initNumberInputs;
|
|
143
|
+
|
|
144
|
+
if (window.kupolaInitializer) {
|
|
145
|
+
window.kupolaInitializer.register('number-input', initNumberInput, cleanupNumberInput);
|
|
146
|
+
}
|
|
146
147
|
}
|