kmaterialize 2.0.0 → 2.3.3-1.0.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 -21
- package/README.md +55 -91
- package/components/appbar/_navbar.old.scss +223 -0
- package/components/appbar/appbar.css +235 -0
- package/components/appbar/appbar.mjs +54 -0
- package/components/appbar/appbar.test.mjs +9 -0
- package/components/atomic/atomic.mjs +19 -0
- package/components/atomic/component.mjs +67 -0
- package/components/badge/_badges.scss +75 -0
- package/components/badge/badge.mjs +11 -0
- package/components/breadcrumb/_breadcrumb.scss +27 -0
- package/components/button/_buttons.scss +352 -0
- package/components/button/button.mjs +11 -0
- package/components/button/buttons.stories.ts +150 -0
- package/components/button/buttons.ts +282 -0
- package/components/button/examples.iso.js +18 -0
- package/components/button/fabSpec.js +65 -0
- package/components/button/test-button.mjs +16 -0
- package/components/card/_cards.scss +229 -0
- package/components/card/card.mjs +10 -0
- package/components/card/cards.ts +185 -0
- package/components/card/cardsSpec.js +269 -0
- package/components/carousel/_carousel.scss +93 -0
- package/components/carousel/_slider.scss +119 -0
- package/components/carousel/carousel.ts +693 -0
- package/components/carousel/carouselSpec.js +61 -0
- package/components/carousel/slider.ts +431 -0
- package/components/carousel/sliderSpec.js +99 -0
- package/components/checkbox/_checkboxes.scss +281 -0
- package/components/checkbox/checkbox.mdx +24 -0
- package/components/checkbox/checkbox.stories.ts +120 -0
- package/components/chip/chip.mjs +37 -0
- package/components/chip/chip.test.mjs +10 -0
- package/components/chip/chips.css +126 -0
- package/components/chip/chips.mdx +33 -0
- package/components/chip/chips.ts +440 -0
- package/components/chip/chipsSpec.js +165 -0
- package/components/chip/readme.md +323 -0
- package/components/collapsible/_collapsible.scss +82 -0
- package/components/collapsible/collapsible.ts +230 -0
- package/components/collapsible/collapsibleSpec.js +240 -0
- package/components/datepicker/_datepicker.scss +268 -0
- package/components/datepicker/datepicker.ts +1450 -0
- package/components/datepicker/datepickerSpec.js +162 -0
- package/components/dialog/_materialbox.scss +42 -0
- package/components/dialog/_modal.scss +79 -0
- package/components/dialog/materialbox.ts +446 -0
- package/components/dialog/materialboxSpec.js +37 -0
- package/components/dialog/modal.ts +111 -0
- package/components/dialog/modalSpec.js +83 -0
- package/components/dialog/readme.md +5 -0
- package/components/divider/readme.md +15 -0
- package/components/dropdown/_dropdown.scss +83 -0
- package/components/dropdown/dropdown.ts +653 -0
- package/components/dropdown/dropdownSpec.js +108 -0
- package/components/list/_collection.scss +114 -0
- package/components/list/_list.scss +6 -0
- package/components/list/list.mjs +58 -0
- package/components/list/list.test.mjs +16 -0
- package/components/loading/loading.mjs +26 -0
- package/components/loading/loading.test.mjs +10 -0
- package/components/navigation-bar/_old +582 -0
- package/components/navigation-bar/navigation-bar.mdx +20 -0
- package/components/navigation-bar/navigation-bar.stories.ts +39 -0
- package/components/navigation-drawer/_sidenav.scss +247 -0
- package/components/navigation-drawer/sidenav.ts +546 -0
- package/components/navigation-drawer/sidenavSpec.js +124 -0
- package/components/pagination/_pagination.scss +47 -0
- package/components/progress/_preloader.scss +416 -0
- package/components/radio-button/_radio-buttons.scss +112 -0
- package/components/radio-button/radio-buttons.mdx +28 -0
- package/components/radio-button/radio-buttons.stories.ts +51 -0
- package/components/search/autocomplete.ts +620 -0
- package/components/search/autocompleteSpec.js +321 -0
- package/components/slider/_range.scss +157 -0
- package/components/slider/range.ts +216 -0
- package/components/snackbar/_toast.scss +68 -0
- package/components/snackbar/toastSpec.js +132 -0
- package/components/snackbar/toasts.ts +312 -0
- package/components/switch/_switches.scss +121 -0
- package/components/tabs/_tabs.scss +171 -0
- package/components/tabs/tabs.mjs +31 -0
- package/components/tabs/tabs.ts +358 -0
- package/components/tabs/tabsSpec.js +180 -0
- package/components/textfield/_file-input.scss +41 -0
- package/components/textfield/_input-fields.scss +368 -0
- package/components/textfield/_select.scss +104 -0
- package/components/textfield/formfields.css +311 -0
- package/components/textfield/forms.ts +182 -0
- package/components/textfield/formsSpec.js +142 -0
- package/components/textfield/select.ts +472 -0
- package/components/textfield/selectSpec.js +390 -0
- package/components/textfield/textfield.mjs +29 -0
- package/components/textfield/textfield.test.mjs +10 -0
- package/components/timepicker/_timepicker.scss +362 -0
- package/components/timepicker/timepicker.ts +905 -0
- package/components/tooltip/_tooltip.scss +40 -0
- package/components/tooltip/tooltip.ts +380 -0
- package/components/tooltip/tooltipSpec.js +145 -0
- package/dist/css/materialize.colors.min.css +6 -0
- package/dist/css/materialize.css +7578 -6326
- package/dist/css/materialize.min.css +6 -13
- package/dist/css/materialize.min.css.map +1 -0
- package/dist/js/materialize.cjs.js +8410 -0
- package/dist/js/materialize.d.ts +2625 -0
- package/dist/js/materialize.js +8415 -12374
- package/dist/js/materialize.min.js +6 -6
- package/dist/js/materialize.mjs +8382 -0
- package/package.json +82 -47
- package/sass/_colors.scss +417 -0
- package/sass/_global.scss +490 -0
- package/sass/_grid.scss +172 -0
- package/sass/_table_of_contents.scss +28 -0
- package/sass/_tapTarget.scss +102 -0
- package/sass/_typography.scss +58 -0
- package/sass/_variables.scss +56 -0
- package/sass/materialize.scss +51 -0
- package/sass/mixins.module.scss +168 -0
- package/extras/noUiSlider/nouislider.css +0 -406
- package/extras/noUiSlider/nouislider.js +0 -2147
- package/extras/noUiSlider/nouislider.min.js +0 -1
- package/js/anime.min.js +0 -34
- package/js/autocomplete.js +0 -448
- package/js/buttons.js +0 -354
- package/js/cards.js +0 -40
- package/js/carousel.js +0 -717
- package/js/cash.js +0 -960
- package/js/characterCounter.js +0 -136
- package/js/chips.js +0 -481
- package/js/collapsible.js +0 -275
- package/js/component.js +0 -44
- package/js/datepicker.js +0 -975
- package/js/dropdown.js +0 -635
- package/js/forms.js +0 -275
- package/js/global.js +0 -444
- package/js/materialbox.js +0 -453
- package/js/modal.js +0 -382
- package/js/parallax.js +0 -138
- package/js/pushpin.js +0 -148
- package/js/range.js +0 -263
- package/js/scrollspy.js +0 -295
- package/js/select.js +0 -450
- package/js/sidenav.js +0 -580
- package/js/slider.js +0 -359
- package/js/tabs.js +0 -402
- package/js/tapTarget.js +0 -314
- package/js/timepicker.js +0 -647
- package/js/toasts.js +0 -310
- package/js/tooltip.js +0 -303
- package/js/waves.js +0 -335
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { Utils } from '../../src/utils';
|
|
2
|
+
import { BaseOptions, Component, InitElements, MElement } from '../../src/component';
|
|
3
|
+
|
|
4
|
+
export interface MaterialboxOptions extends BaseOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Transition in duration in milliseconds.
|
|
7
|
+
* @default 275
|
|
8
|
+
*/
|
|
9
|
+
inDuration: number;
|
|
10
|
+
/**
|
|
11
|
+
* Transition out duration in milliseconds.
|
|
12
|
+
* @default 200
|
|
13
|
+
*/
|
|
14
|
+
outDuration: number;
|
|
15
|
+
/**
|
|
16
|
+
* Callback function called before materialbox is opened.
|
|
17
|
+
* @default null
|
|
18
|
+
*/
|
|
19
|
+
onOpenStart: (el: Element) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Callback function called after materialbox is opened.
|
|
22
|
+
* @default null
|
|
23
|
+
*/
|
|
24
|
+
onOpenEnd: (el: Element) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Callback function called before materialbox is closed.
|
|
27
|
+
* @default null
|
|
28
|
+
*/
|
|
29
|
+
onCloseStart: (el: Element) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Callback function called after materialbox is closed.
|
|
32
|
+
* @default null
|
|
33
|
+
*/
|
|
34
|
+
onCloseEnd: (el: Element) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const _defaults: MaterialboxOptions = {
|
|
38
|
+
inDuration: 275,
|
|
39
|
+
outDuration: 200,
|
|
40
|
+
onOpenStart: null,
|
|
41
|
+
onOpenEnd: null,
|
|
42
|
+
onCloseStart: null,
|
|
43
|
+
onCloseEnd: null
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export class Materialbox extends Component<MaterialboxOptions> {
|
|
47
|
+
/** If the materialbox overlay is showing. */
|
|
48
|
+
overlayActive: boolean;
|
|
49
|
+
/** If the materialbox is no longer being animated. */
|
|
50
|
+
doneAnimating: boolean;
|
|
51
|
+
/** Caption, if specified. */
|
|
52
|
+
caption: string;
|
|
53
|
+
/** Original width of image. */
|
|
54
|
+
originalWidth: number;
|
|
55
|
+
/** Original height of image. */
|
|
56
|
+
originalHeight: number;
|
|
57
|
+
private originInlineStyles: string;
|
|
58
|
+
private placeholder: HTMLElement;
|
|
59
|
+
private _changedAncestorList: HTMLElement[];
|
|
60
|
+
private newHeight: number;
|
|
61
|
+
private newWidth: number;
|
|
62
|
+
private windowWidth: number;
|
|
63
|
+
private windowHeight: number;
|
|
64
|
+
private attrWidth: string;
|
|
65
|
+
private attrHeight: string;
|
|
66
|
+
private _overlay: HTMLElement;
|
|
67
|
+
private _photoCaption: HTMLElement;
|
|
68
|
+
|
|
69
|
+
constructor(el: HTMLElement, options: Partial<MaterialboxOptions>) {
|
|
70
|
+
super(el, options, Materialbox);
|
|
71
|
+
this.el['M_Materialbox'] = this;
|
|
72
|
+
|
|
73
|
+
this.options = {
|
|
74
|
+
...Materialbox.defaults,
|
|
75
|
+
...options
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
this.overlayActive = false;
|
|
79
|
+
this.doneAnimating = true;
|
|
80
|
+
this.placeholder = document.createElement('div');
|
|
81
|
+
this.placeholder.classList.add('material-placeholder');
|
|
82
|
+
this.originalWidth = 0;
|
|
83
|
+
this.originalHeight = 0;
|
|
84
|
+
this.originInlineStyles = this.el.getAttribute('style');
|
|
85
|
+
this.caption = this.el.getAttribute('data-caption') || '';
|
|
86
|
+
this.el.tabIndex = 0;
|
|
87
|
+
// Wrap
|
|
88
|
+
this.el.before(this.placeholder);
|
|
89
|
+
this.placeholder.append(this.el);
|
|
90
|
+
this._setupEventHandlers();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static get defaults(): MaterialboxOptions {
|
|
94
|
+
return _defaults;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Initializes instance of MaterialBox.
|
|
99
|
+
* @param el HTML element.
|
|
100
|
+
* @param options Component options.
|
|
101
|
+
*/
|
|
102
|
+
static init(el: HTMLElement, options?: Partial<MaterialboxOptions>): Materialbox;
|
|
103
|
+
/**
|
|
104
|
+
* Initializes instances of MaterialBox.
|
|
105
|
+
* @param els HTML elements.
|
|
106
|
+
* @param options Component options.
|
|
107
|
+
*/
|
|
108
|
+
static init(els: InitElements<MElement>, options?: Partial<MaterialboxOptions>): Materialbox[];
|
|
109
|
+
/**
|
|
110
|
+
* Initializes instances of MaterialBox.
|
|
111
|
+
* @param els HTML elements.
|
|
112
|
+
* @param options Component options.
|
|
113
|
+
*/
|
|
114
|
+
static init(
|
|
115
|
+
els: HTMLElement | InitElements<MElement>,
|
|
116
|
+
options: Partial<MaterialboxOptions> = {}
|
|
117
|
+
): Materialbox | Materialbox[] {
|
|
118
|
+
return super.init(els, options, Materialbox);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static getInstance(el: HTMLElement): Materialbox {
|
|
122
|
+
return el['M_Materialbox'];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
destroy() {
|
|
126
|
+
this._removeEventHandlers();
|
|
127
|
+
this.el['M_Materialbox'] = undefined;
|
|
128
|
+
// Unwrap image
|
|
129
|
+
//this.placeholder.after(this.el).remove();
|
|
130
|
+
this.placeholder.remove();
|
|
131
|
+
this.el.removeAttribute('style');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private _setupEventHandlers() {
|
|
135
|
+
this.el.addEventListener('click', this._handleMaterialboxClick);
|
|
136
|
+
this.el.addEventListener('keypress', this._handleMaterialboxKeypress);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private _removeEventHandlers() {
|
|
140
|
+
this.el.removeEventListener('click', this._handleMaterialboxClick);
|
|
141
|
+
this.el.removeEventListener('keypress', this._handleMaterialboxKeypress);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private _handleMaterialboxClick = () => {
|
|
145
|
+
this._handleMaterialboxToggle();
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
private _handleMaterialboxKeypress = (e: KeyboardEvent) => {
|
|
149
|
+
if (Utils.keys.ENTER.includes(e.key)) {
|
|
150
|
+
this._handleMaterialboxToggle();
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
private _handleMaterialboxToggle = () => {
|
|
155
|
+
// If already modal, return to original
|
|
156
|
+
if (this.doneAnimating === false || (this.overlayActive && this.doneAnimating)) this.close();
|
|
157
|
+
else this.open();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
private _handleWindowScroll = () => {
|
|
161
|
+
if (this.overlayActive) this.close();
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
private _handleWindowResize = () => {
|
|
165
|
+
if (this.overlayActive) this.close();
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
private _handleWindowEscape = (e: KeyboardEvent) => {
|
|
169
|
+
if (Utils.keys.ESC.includes(e.key) && this.doneAnimating && this.overlayActive) this.close();
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
private _makeAncestorsOverflowVisible() {
|
|
173
|
+
this._changedAncestorList = [];
|
|
174
|
+
let ancestor = this.placeholder.parentNode;
|
|
175
|
+
while (ancestor !== null && ancestor !== document) {
|
|
176
|
+
const curr = <HTMLElement>ancestor;
|
|
177
|
+
if (curr.style.overflow !== 'visible') {
|
|
178
|
+
curr.style.overflow = 'visible';
|
|
179
|
+
this._changedAncestorList.push(curr);
|
|
180
|
+
}
|
|
181
|
+
ancestor = ancestor.parentNode;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private _offset(el: HTMLElement) {
|
|
186
|
+
const box = el.getBoundingClientRect();
|
|
187
|
+
const docElem = document.documentElement;
|
|
188
|
+
return {
|
|
189
|
+
top: box.top + window.scrollY - docElem.clientTop,
|
|
190
|
+
left: box.left + window.scrollX - docElem.clientLeft
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
private _updateVars(): void {
|
|
194
|
+
this.windowWidth = window.innerWidth;
|
|
195
|
+
this.windowHeight = window.innerHeight;
|
|
196
|
+
this.caption = this.el.getAttribute('data-caption') || '';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Image
|
|
200
|
+
private _animateImageIn(): void {
|
|
201
|
+
this.el.style.maxHeight = this.newHeight.toString() + 'px';
|
|
202
|
+
this.el.style.maxWidth = this.newWidth.toString() + 'px';
|
|
203
|
+
const duration = this.options.inDuration;
|
|
204
|
+
// from
|
|
205
|
+
this.el.style.transition = 'none';
|
|
206
|
+
this.el.style.height = this.originalHeight + 'px';
|
|
207
|
+
this.el.style.width = this.originalWidth + 'px';
|
|
208
|
+
setTimeout(() => {
|
|
209
|
+
// easeOutQuad
|
|
210
|
+
this.el.style.transition = `height ${duration}ms ease,
|
|
211
|
+
width ${duration}ms ease,
|
|
212
|
+
left ${duration}ms ease,
|
|
213
|
+
top ${duration}ms ease
|
|
214
|
+
`;
|
|
215
|
+
// to
|
|
216
|
+
this.el.style.height = this.newHeight + 'px';
|
|
217
|
+
this.el.style.width = this.newWidth + 'px';
|
|
218
|
+
this.el.style.left =
|
|
219
|
+
Utils.getDocumentScrollLeft() +
|
|
220
|
+
this.windowWidth / 2 -
|
|
221
|
+
this._offset(this.placeholder).left -
|
|
222
|
+
this.newWidth / 2 +
|
|
223
|
+
'px';
|
|
224
|
+
|
|
225
|
+
this.el.style.top =
|
|
226
|
+
Utils.getDocumentScrollTop() +
|
|
227
|
+
this.windowHeight / 2 -
|
|
228
|
+
this._offset(this.placeholder).top -
|
|
229
|
+
this.newHeight / 2 +
|
|
230
|
+
'px';
|
|
231
|
+
}, 1);
|
|
232
|
+
|
|
233
|
+
setTimeout(() => {
|
|
234
|
+
this.doneAnimating = true;
|
|
235
|
+
if (typeof this.options.onOpenEnd === 'function') this.options.onOpenEnd.call(this, this.el);
|
|
236
|
+
}, duration);
|
|
237
|
+
|
|
238
|
+
/*
|
|
239
|
+
anim({
|
|
240
|
+
targets: this.el, // image
|
|
241
|
+
height: [this.originalHeight, this.newHeight],
|
|
242
|
+
width: [this.originalWidth, this.newWidth],
|
|
243
|
+
left:
|
|
244
|
+
Utils.getDocumentScrollLeft() +
|
|
245
|
+
this.windowWidth / 2 -
|
|
246
|
+
this._offset(this.placeholder).left -
|
|
247
|
+
this.newWidth / 2,
|
|
248
|
+
top:
|
|
249
|
+
Utils.getDocumentScrollTop() +
|
|
250
|
+
this.windowHeight / 2 -
|
|
251
|
+
this._offset(this.placeholder).top -
|
|
252
|
+
this.newHeight / 2,
|
|
253
|
+
|
|
254
|
+
duration: this.options.inDuration,
|
|
255
|
+
easing: 'easeOutQuad',
|
|
256
|
+
complete: () => {
|
|
257
|
+
this.doneAnimating = true;
|
|
258
|
+
if (typeof this.options.onOpenEnd === 'function') this.options.onOpenEnd.call(this, this.el);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
*/
|
|
262
|
+
}
|
|
263
|
+
private _animateImageOut(): void {
|
|
264
|
+
const duration = this.options.outDuration;
|
|
265
|
+
// easeOutQuad
|
|
266
|
+
this.el.style.transition = `height ${duration}ms ease,
|
|
267
|
+
width ${duration}ms ease,
|
|
268
|
+
left ${duration}ms ease,
|
|
269
|
+
top ${duration}ms ease
|
|
270
|
+
`;
|
|
271
|
+
// to
|
|
272
|
+
this.el.style.height = this.originalWidth + 'px';
|
|
273
|
+
this.el.style.width = this.originalWidth + 'px';
|
|
274
|
+
this.el.style.left = '0';
|
|
275
|
+
this.el.style.top = '0';
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
this.placeholder.style.height = '';
|
|
278
|
+
this.placeholder.style.width = '';
|
|
279
|
+
this.placeholder.style.position = '';
|
|
280
|
+
this.placeholder.style.top = '';
|
|
281
|
+
this.placeholder.style.left = '';
|
|
282
|
+
// Revert to width or height attribute
|
|
283
|
+
if (this.attrWidth) this.el.setAttribute('width', this.attrWidth.toString());
|
|
284
|
+
if (this.attrHeight) this.el.setAttribute('height', this.attrHeight.toString());
|
|
285
|
+
this.el.removeAttribute('style');
|
|
286
|
+
if (this.originInlineStyles) this.el.setAttribute('style', this.originInlineStyles);
|
|
287
|
+
// Remove class
|
|
288
|
+
this.el.classList.remove('active');
|
|
289
|
+
this.doneAnimating = true;
|
|
290
|
+
// Remove overflow overrides on ancestors
|
|
291
|
+
this._changedAncestorList.forEach((anchestor) => (anchestor.style.overflow = ''));
|
|
292
|
+
// onCloseEnd callback
|
|
293
|
+
if (typeof this.options.onCloseEnd === 'function')
|
|
294
|
+
this.options.onCloseEnd.call(this, this.el);
|
|
295
|
+
}, duration);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Caption
|
|
299
|
+
private _addCaption(): void {
|
|
300
|
+
this._photoCaption = document.createElement('div');
|
|
301
|
+
this._photoCaption.classList.add('materialbox-caption');
|
|
302
|
+
this._photoCaption.innerText = this.caption;
|
|
303
|
+
document.body.append(this._photoCaption);
|
|
304
|
+
this._photoCaption.style.display = 'inline';
|
|
305
|
+
// Animate
|
|
306
|
+
this._photoCaption.style.transition = 'none';
|
|
307
|
+
this._photoCaption.style.opacity = '0';
|
|
308
|
+
const duration = this.options.inDuration;
|
|
309
|
+
setTimeout(() => {
|
|
310
|
+
this._photoCaption.style.transition = `opacity ${duration}ms ease`;
|
|
311
|
+
this._photoCaption.style.opacity = '1';
|
|
312
|
+
}, 1);
|
|
313
|
+
}
|
|
314
|
+
private _removeCaption(): void {
|
|
315
|
+
const duration = this.options.outDuration;
|
|
316
|
+
this._photoCaption.style.transition = `opacity ${duration}ms ease`;
|
|
317
|
+
this._photoCaption.style.opacity = '0';
|
|
318
|
+
setTimeout(() => {
|
|
319
|
+
this._photoCaption.remove();
|
|
320
|
+
}, duration);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Overlay
|
|
324
|
+
private _addOverlay(): void {
|
|
325
|
+
this._overlay = document.createElement('div');
|
|
326
|
+
this._overlay.id = 'materialbox-overlay';
|
|
327
|
+
this._overlay.addEventListener(
|
|
328
|
+
'click',
|
|
329
|
+
() => {
|
|
330
|
+
if (this.doneAnimating) this.close();
|
|
331
|
+
},
|
|
332
|
+
{ once: true }
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
// Put before in origin image to preserve z-index layering.
|
|
336
|
+
this.el.before(this._overlay);
|
|
337
|
+
|
|
338
|
+
// Set dimensions if needed
|
|
339
|
+
const overlayOffset = this._overlay.getBoundingClientRect();
|
|
340
|
+
this._overlay.style.width = this.windowWidth + 'px';
|
|
341
|
+
this._overlay.style.height = this.windowHeight + 'px';
|
|
342
|
+
this._overlay.style.left = -1 * overlayOffset.left + 'px';
|
|
343
|
+
this._overlay.style.top = -1 * overlayOffset.top + 'px';
|
|
344
|
+
|
|
345
|
+
// Animate
|
|
346
|
+
this._overlay.style.transition = 'none';
|
|
347
|
+
this._overlay.style.opacity = '0';
|
|
348
|
+
const duration = this.options.inDuration;
|
|
349
|
+
setTimeout(() => {
|
|
350
|
+
this._overlay.style.transition = `opacity ${duration}ms ease`;
|
|
351
|
+
this._overlay.style.opacity = '1';
|
|
352
|
+
}, 1);
|
|
353
|
+
}
|
|
354
|
+
private _removeOverlay(): void {
|
|
355
|
+
const duration = this.options.outDuration;
|
|
356
|
+
this._overlay.style.transition = `opacity ${duration}ms ease`;
|
|
357
|
+
this._overlay.style.opacity = '0';
|
|
358
|
+
setTimeout(() => {
|
|
359
|
+
this.overlayActive = false;
|
|
360
|
+
this._overlay.remove();
|
|
361
|
+
}, duration);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Open materialbox.
|
|
366
|
+
*/
|
|
367
|
+
open = () => {
|
|
368
|
+
this._updateVars();
|
|
369
|
+
this.originalWidth = this.el.getBoundingClientRect().width;
|
|
370
|
+
this.originalHeight = this.el.getBoundingClientRect().height;
|
|
371
|
+
// Set states
|
|
372
|
+
this.doneAnimating = false;
|
|
373
|
+
this.el.classList.add('active');
|
|
374
|
+
this.overlayActive = true;
|
|
375
|
+
// onOpenStart callback
|
|
376
|
+
if (typeof this.options.onOpenStart === 'function')
|
|
377
|
+
this.options.onOpenStart.call(this, this.el);
|
|
378
|
+
// Set positioning for placeholder
|
|
379
|
+
this.placeholder.style.width = this.placeholder.getBoundingClientRect().width + 'px';
|
|
380
|
+
this.placeholder.style.height = this.placeholder.getBoundingClientRect().height + 'px';
|
|
381
|
+
this.placeholder.style.position = 'relative';
|
|
382
|
+
this.placeholder.style.top = '0';
|
|
383
|
+
this.placeholder.style.left = '0';
|
|
384
|
+
this._makeAncestorsOverflowVisible();
|
|
385
|
+
// Set css on origin
|
|
386
|
+
this.el.style.position = 'absolute';
|
|
387
|
+
this.el.style.zIndex = '1000';
|
|
388
|
+
this.el.style.willChange = 'left, top, width, height';
|
|
389
|
+
// Change from width or height attribute to css
|
|
390
|
+
this.attrWidth = this.el.getAttribute('width');
|
|
391
|
+
this.attrHeight = this.el.getAttribute('height');
|
|
392
|
+
if (this.attrWidth) {
|
|
393
|
+
this.el.style.width = this.attrWidth + 'px';
|
|
394
|
+
this.el.removeAttribute('width');
|
|
395
|
+
}
|
|
396
|
+
if (this.attrHeight) {
|
|
397
|
+
this.el.style.width = this.attrHeight + 'px';
|
|
398
|
+
this.el.removeAttribute('height');
|
|
399
|
+
}
|
|
400
|
+
this._addOverlay();
|
|
401
|
+
// Add and animate caption if it exists
|
|
402
|
+
if (this.caption !== '') this._addCaption();
|
|
403
|
+
// Resize Image
|
|
404
|
+
const widthPercent = this.originalWidth / this.windowWidth;
|
|
405
|
+
const heightPercent = this.originalHeight / this.windowHeight;
|
|
406
|
+
this.newWidth = 0;
|
|
407
|
+
this.newHeight = 0;
|
|
408
|
+
if (widthPercent > heightPercent) {
|
|
409
|
+
// Width first
|
|
410
|
+
const ratio = this.originalHeight / this.originalWidth;
|
|
411
|
+
this.newWidth = this.windowWidth * 0.9;
|
|
412
|
+
this.newHeight = this.windowWidth * 0.9 * ratio;
|
|
413
|
+
} else {
|
|
414
|
+
// Height first
|
|
415
|
+
const ratio = this.originalWidth / this.originalHeight;
|
|
416
|
+
this.newWidth = this.windowHeight * 0.9 * ratio;
|
|
417
|
+
this.newHeight = this.windowHeight * 0.9;
|
|
418
|
+
}
|
|
419
|
+
this._animateImageIn();
|
|
420
|
+
// Handle Exit triggers
|
|
421
|
+
window.addEventListener('scroll', this._handleWindowScroll);
|
|
422
|
+
window.addEventListener('resize', this._handleWindowResize);
|
|
423
|
+
window.addEventListener('keyup', this._handleWindowEscape);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Close materialbox.
|
|
428
|
+
*/
|
|
429
|
+
close = () => {
|
|
430
|
+
this._updateVars();
|
|
431
|
+
this.doneAnimating = false;
|
|
432
|
+
// onCloseStart callback
|
|
433
|
+
if (typeof this.options.onCloseStart === 'function')
|
|
434
|
+
this.options.onCloseStart.call(this, this.el);
|
|
435
|
+
//anim.remove(this.el);
|
|
436
|
+
//anim.remove(this._overlay);
|
|
437
|
+
//if (this.caption !== '') anim.remove(this._photoCaption);
|
|
438
|
+
// disable exit handlers
|
|
439
|
+
window.removeEventListener('scroll', this._handleWindowScroll);
|
|
440
|
+
window.removeEventListener('resize', this._handleWindowResize);
|
|
441
|
+
window.removeEventListener('keyup', this._handleWindowEscape);
|
|
442
|
+
this._removeOverlay();
|
|
443
|
+
this._animateImageOut();
|
|
444
|
+
if (this.caption !== '') this._removeCaption();
|
|
445
|
+
};
|
|
446
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
describe('Materialbox:', () => {
|
|
2
|
+
const fixture = `<div id="transformTest" style="transform: translate3d(1px,1px,1px)">
|
|
3
|
+
<img
|
|
4
|
+
class="materialboxed"
|
|
5
|
+
width="650"
|
|
6
|
+
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==">
|
|
7
|
+
</div>`;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => XloadHtml(fixture));
|
|
10
|
+
afterEach(() => XunloadFixtures());
|
|
11
|
+
|
|
12
|
+
describe('Materialbox opens correctly with transformed ancestor', () => {
|
|
13
|
+
it('Opens a correctly placed overlay when clicked', (done) => {
|
|
14
|
+
const transformMaterialbox = document.querySelector('#transformTest');
|
|
15
|
+
M.Materialbox.init(document.querySelector('.materialboxed'), {
|
|
16
|
+
inDuration: 0,
|
|
17
|
+
outDuration: 0
|
|
18
|
+
});
|
|
19
|
+
// Mouse click
|
|
20
|
+
click(transformMaterialbox.querySelector('.materialboxed'));
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
// Check overlay is attached
|
|
23
|
+
const overlay = transformMaterialbox.querySelector('#materialbox-overlay');
|
|
24
|
+
const overlayRect = overlay.getBoundingClientRect();
|
|
25
|
+
const windowWidth = window.innerWidth;
|
|
26
|
+
const windowHeight = window.innerHeight;
|
|
27
|
+
expect(overlay).toExist('because it is generated on init');
|
|
28
|
+
expect(overlay).toBeVisible('because materialbox was clicked');
|
|
29
|
+
expect(overlayRect.top).toEqual(0);
|
|
30
|
+
expect(overlayRect.left).toEqual(0);
|
|
31
|
+
expect(overlayRect.width).toEqual(windowWidth);
|
|
32
|
+
expect(overlayRect.height).toEqual(windowHeight);
|
|
33
|
+
done();
|
|
34
|
+
}, 10);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Component, BaseOptions, InitElements, MElement } from '../../src/component';
|
|
2
|
+
|
|
3
|
+
// Obsolete for versions > 2.1.1
|
|
4
|
+
|
|
5
|
+
interface ModalOptions extends BaseOptions {
|
|
6
|
+
opacity: number;
|
|
7
|
+
inDuration: number;
|
|
8
|
+
outDuration: number;
|
|
9
|
+
preventScrolling: boolean;
|
|
10
|
+
onOpenStart: (this: Modal, el: HTMLElement) => void;
|
|
11
|
+
onOpenEnd: (this: Modal, el: HTMLElement) => void;
|
|
12
|
+
onCloseStart: (el: HTMLElement) => void;
|
|
13
|
+
onCloseEnd: (el: HTMLElement) => void;
|
|
14
|
+
dismissible: boolean;
|
|
15
|
+
startingTop: string;
|
|
16
|
+
endingTop: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const _defaults = {
|
|
20
|
+
opacity: 0.5,
|
|
21
|
+
inDuration: 250,
|
|
22
|
+
outDuration: 250,
|
|
23
|
+
onOpenStart: null,
|
|
24
|
+
onOpenEnd: null,
|
|
25
|
+
onCloseStart: null,
|
|
26
|
+
onCloseEnd: null,
|
|
27
|
+
preventScrolling: true,
|
|
28
|
+
dismissible: true,
|
|
29
|
+
startingTop: '4%',
|
|
30
|
+
endingTop: '10%'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
class Modal extends Component<ModalOptions> {
|
|
34
|
+
constructor(el: HTMLElement, options: Partial<ModalOptions>) {
|
|
35
|
+
super(el, options, Modal);
|
|
36
|
+
this.el['M_Modal'] = this;
|
|
37
|
+
this.options = {
|
|
38
|
+
...Modal.defaults,
|
|
39
|
+
...options
|
|
40
|
+
};
|
|
41
|
+
this.el.tabIndex = 0;
|
|
42
|
+
this._setupEventHandlers();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static get defaults() {
|
|
46
|
+
return _defaults;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static init(el: HTMLElement, options?: Partial<ModalOptions>): Modal;
|
|
50
|
+
static init(els: InitElements<MElement>, options?: Partial<ModalOptions>): Modal[];
|
|
51
|
+
static init(
|
|
52
|
+
els: HTMLElement | InitElements<MElement>,
|
|
53
|
+
options: Partial<ModalOptions> = {}
|
|
54
|
+
): Modal | Modal[] {
|
|
55
|
+
return super.init(els, options, Modal);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static getInstance(el: HTMLElement): Modal {
|
|
59
|
+
return el['M_Modal'];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
destroy() {}
|
|
63
|
+
_setupEventHandlers() {}
|
|
64
|
+
_removeEventHandlers() {}
|
|
65
|
+
_handleTriggerClick() {}
|
|
66
|
+
_handleOverlayClick() {}
|
|
67
|
+
_handleModalCloseClick() {}
|
|
68
|
+
_handleKeydown() {}
|
|
69
|
+
_handleFocus() {}
|
|
70
|
+
open() {
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
close() {
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Experimental!
|
|
78
|
+
|
|
79
|
+
static #createHtml(config: ModalCreateConfig) {
|
|
80
|
+
return `<dialog id="modal1" class="modal">
|
|
81
|
+
${config.header ? '<div class="modal-header">' + config.header + '</div>' : ''}
|
|
82
|
+
<div class="modal-content">
|
|
83
|
+
${config.content}
|
|
84
|
+
</div>
|
|
85
|
+
${config.header ? '<div class="modal-footer">' + config.footer + '</div>' : ''}
|
|
86
|
+
</dialog>`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static #createHtmlElement(config: ModalCreateConfig) {
|
|
90
|
+
const dialog = document.createElement('dialog');
|
|
91
|
+
dialog.id = config.id;
|
|
92
|
+
return dialog;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static create(config) {
|
|
96
|
+
const isServer = false;
|
|
97
|
+
if (isServer) return this.#createHtml(config);
|
|
98
|
+
return this.#createHtmlElement(config);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
static {}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface ModalCreateConfig {
|
|
105
|
+
id: string;
|
|
106
|
+
header: string | HTMLElement;
|
|
107
|
+
content: string | HTMLElement;
|
|
108
|
+
footer: string | HTMLElement;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { Modal, ModalOptions };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
describe('Modal:', () => {
|
|
2
|
+
const fixture = `<a class="btn tonal trigger waves-effect waves-light" href="#" onclick="modal1.showModal(); return false;">Modal</a>
|
|
3
|
+
<button class="btn btn-floating fixed-action-btn" onclick="modal1.showModal()"><i class="material-icons">menu</i></button>
|
|
4
|
+
|
|
5
|
+
<dialog id="modal1" class="modal">
|
|
6
|
+
<div class="modal-header">
|
|
7
|
+
<h4>Modal Header</h4>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="modal-content">
|
|
10
|
+
<p>A bunch of text</p>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="modal-footer">
|
|
13
|
+
<a href="#" onclick="modal1.close(); return false;" class="waves-effect waves-green btn-flat">Agree</a>
|
|
14
|
+
</div>
|
|
15
|
+
</dialog>
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => XloadHtml(fixture));
|
|
19
|
+
afterEach(() => XunloadFixtures());
|
|
20
|
+
|
|
21
|
+
describe('Modals', () => {
|
|
22
|
+
it('Should open and close correctly', (done) => {
|
|
23
|
+
const modal1 = document.querySelector('.modal');
|
|
24
|
+
const trigger = document.querySelector('.trigger');
|
|
25
|
+
expect(modal1).toBeHidden('Modal should be hidden');
|
|
26
|
+
click(trigger);
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
expect(modal1).toBeVisible('Modal should be shown');
|
|
29
|
+
done();
|
|
30
|
+
}, 10);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('Should open and close correctly with children elements in trigger', (done) => {
|
|
34
|
+
const modal1 = document.querySelector('.modal');
|
|
35
|
+
const triggerIcon1 = document.querySelector('button i');
|
|
36
|
+
expect(modal1).toBeHidden('Modal should be hidden');
|
|
37
|
+
click(triggerIcon1);
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
expect(modal1).toBeVisible('Modal should be shown');
|
|
40
|
+
done();
|
|
41
|
+
}, 10);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// it('Should have a dismissible option', (done) => {
|
|
45
|
+
// // M.Modal.init(modal1, {
|
|
46
|
+
// // dismissible: false,
|
|
47
|
+
// // inDuration: 0,
|
|
48
|
+
// // outDuration: 0
|
|
49
|
+
// // });
|
|
50
|
+
// click(trigger1);
|
|
51
|
+
// setTimeout(() => {
|
|
52
|
+
// expect(modal1).toBeVisible('Modal should be shown');
|
|
53
|
+
// let overlay = M.Modal.getInstance(modal1)._overlay;
|
|
54
|
+
// let overlayInDOM = document.contains(overlay);
|
|
55
|
+
// expect(overlayInDOM).toEqual(true, 'Overlay should be attached on open');
|
|
56
|
+
// click(overlay);
|
|
57
|
+
// setTimeout(() => {
|
|
58
|
+
// expect(modal1).toBeVisible('Modal should be shown');
|
|
59
|
+
// let overlayInDOM = document.contains(overlay);
|
|
60
|
+
// expect(overlayInDOM).toEqual(true, 'modal should not be dismissable');
|
|
61
|
+
// done();
|
|
62
|
+
// }, 10);
|
|
63
|
+
// }, 10);
|
|
64
|
+
// });
|
|
65
|
+
|
|
66
|
+
it('Should have callbacks', (done) => {
|
|
67
|
+
let hasBeenClosed = false;
|
|
68
|
+
const modal = document.querySelector('.modal');
|
|
69
|
+
const trigger1 = document.querySelector('.trigger');
|
|
70
|
+
|
|
71
|
+
modal.addEventListener('close', () => {
|
|
72
|
+
hasBeenClosed = true;
|
|
73
|
+
});
|
|
74
|
+
click(trigger1);
|
|
75
|
+
expect(hasBeenClosed).toEqual(false, 'callback not yet fired');
|
|
76
|
+
click(document.querySelector('.modal-footer a'));
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
expect(hasBeenClosed).toEqual(true, 'callback fired');
|
|
79
|
+
done();
|
|
80
|
+
}, 200);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|