material 3.4.0 → 3.4.2
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/README.md +2 -2
- package/dist/components/button-group/button-group.js +5 -2
- package/dist/components/dialog/api.js +109 -109
- package/dist/components/dialog/config.js +0 -52
- package/dist/components/dialog/dialog.js +2 -2
- package/dist/components/dialog/features.js +113 -65
- package/dist/components/dialog/types.d.ts +2 -3
- package/dist/components/search/features/states.js +14 -7
- package/dist/core/dom/focus.js +2 -2
- package/dist/elements/css/bottom-sheet.css +1 -1
- package/dist/elements/css/bottom-sheet.js +1 -1
- package/dist/elements/css/checkbox.css +1 -1
- package/dist/elements/css/checkbox.js +1 -1
- package/dist/elements/css/datepicker.css +1 -1
- package/dist/elements/css/datepicker.js +1 -1
- package/dist/elements/css/dialog.css +1 -1
- package/dist/elements/css/dialog.js +1 -1
- package/dist/elements/css/fab.css +1 -1
- package/dist/elements/css/fab.js +1 -1
- package/dist/elements/css/list.css +1 -1
- package/dist/elements/css/list.js +1 -1
- package/dist/elements/css/navigation-rail.css +1 -1
- package/dist/elements/css/navigation-rail.js +1 -1
- package/dist/elements/css/radios.css +1 -1
- package/dist/elements/css/radios.js +1 -1
- package/dist/elements/css/search.css +1 -1
- package/dist/elements/css/search.js +1 -1
- package/dist/elements/css/side-sheet.css +1 -1
- package/dist/elements/css/side-sheet.js +1 -1
- package/dist/elements/css/slider.css +1 -1
- package/dist/elements/css/slider.js +1 -1
- package/dist/elements/css/switch.css +1 -1
- package/dist/elements/css/switch.js +1 -1
- package/dist/elements/css/timepicker.css +1 -1
- package/dist/elements/css/timepicker.js +1 -1
- package/dist/elements/css/tooltip.css +1 -1
- package/dist/elements/css/tooltip.js +1 -1
- package/dist/elements/preupgrade/badge.css +1 -1
- package/dist/elements/preupgrade/bottom-app-bar.css +1 -1
- package/dist/elements/preupgrade/bottom-sheet.css +1 -1
- package/dist/elements/preupgrade/button-group.css +1 -1
- package/dist/elements/preupgrade/button.css +1 -1
- package/dist/elements/preupgrade/card.css +1 -1
- package/dist/elements/preupgrade/carousel.css +1 -1
- package/dist/elements/preupgrade/checkbox.css +1 -1
- package/dist/elements/preupgrade/chips.css +1 -1
- package/dist/elements/preupgrade/datepicker.css +1 -1
- package/dist/elements/preupgrade/dialog.css +1 -1
- package/dist/elements/preupgrade/divider.css +1 -1
- package/dist/elements/preupgrade/drawer.css +1 -1
- package/dist/elements/preupgrade/extended-fab.css +1 -1
- package/dist/elements/preupgrade/fab-menu.css +1 -1
- package/dist/elements/preupgrade/fab.css +1 -1
- package/dist/elements/preupgrade/icon-button.css +1 -1
- package/dist/elements/preupgrade/list.css +1 -1
- package/dist/elements/preupgrade/loading-indicator.css +1 -1
- package/dist/elements/preupgrade/menu.css +1 -1
- package/dist/elements/preupgrade/navigation-bar.css +1 -1
- package/dist/elements/preupgrade/navigation-rail.css +1 -1
- package/dist/elements/preupgrade/progress.css +1 -1
- package/dist/elements/preupgrade/radios.css +1 -1
- package/dist/elements/preupgrade/search.css +1 -1
- package/dist/elements/preupgrade/select.css +1 -1
- package/dist/elements/preupgrade/side-sheet.css +1 -1
- package/dist/elements/preupgrade/slider.css +1 -1
- package/dist/elements/preupgrade/snackbar.css +1 -1
- package/dist/elements/preupgrade/split-button.css +1 -1
- package/dist/elements/preupgrade/switch.css +1 -1
- package/dist/elements/preupgrade/tabs.css +1 -1
- package/dist/elements/preupgrade/text-field.css +2 -2
- package/dist/elements/preupgrade/timepicker.css +1 -1
- package/dist/elements/preupgrade/toolbar.css +1 -1
- package/dist/elements/preupgrade/tooltip.css +1 -1
- package/dist/elements/preupgrade/top-app-bar.css +1 -1
- package/dist/elements/preupgrade.css +2 -2
- package/dist/elements/preupgrade.js +1 -1
- package/dist/package.json +1 -1
- package/dist/styles/badge.css +1 -1
- package/dist/styles/base.css +1 -1
- package/dist/styles/bottom-app-bar.css +1 -1
- package/dist/styles/bottom-sheet.css +2 -2
- package/dist/styles/button-group.css +1 -1
- package/dist/styles/button.css +1 -1
- package/dist/styles/card.css +1 -1
- package/dist/styles/carousel.css +1 -1
- package/dist/styles/checkbox.css +2 -2
- package/dist/styles/chips.css +1 -1
- package/dist/styles/contrast.css +1 -1
- package/dist/styles/datepicker.css +2 -2
- package/dist/styles/dialog.css +2 -2
- package/dist/styles/divider.css +1 -1
- package/dist/styles/drawer.css +1 -1
- package/dist/styles/extended-fab.css +1 -1
- package/dist/styles/fab-menu.css +1 -1
- package/dist/styles/fab.css +2 -2
- package/dist/styles/icon-button.css +1 -1
- package/dist/styles/list.css +2 -2
- package/dist/styles/loading-indicator.css +1 -1
- package/dist/styles/menu.css +1 -1
- package/dist/styles/navigation-bar.css +1 -1
- package/dist/styles/navigation-rail.css +2 -2
- package/dist/styles/progress.css +1 -1
- package/dist/styles/radios.css +2 -2
- package/dist/styles/search.css +2 -2
- package/dist/styles/select.css +1 -1
- package/dist/styles/side-sheet.css +2 -2
- package/dist/styles/slider.css +2 -2
- package/dist/styles/snackbar.css +1 -1
- package/dist/styles/split-button.css +1 -1
- package/dist/styles/switch.css +2 -2
- package/dist/styles/tabs.css +1 -1
- package/dist/styles/text-field.css +1 -1
- package/dist/styles/timepicker.css +2 -2
- package/dist/styles/toolbar.css +1 -1
- package/dist/styles/tooltip.css +2 -2
- package/dist/styles/top-app-bar.css +1 -1
- package/dist/styles/typography.css +1 -1
- package/dist/styles/utilities.css +2 -2
- package/dist/styles.css +2 -2
- package/dist/themes/autumn-contrast.css +1 -1
- package/dist/themes/autumn.css +2 -2
- package/dist/themes/baseline-contrast.css +1 -1
- package/dist/themes/baseline.css +1 -1
- package/dist/themes/brownbeige-contrast.css +1 -1
- package/dist/themes/brownbeige.css +2 -2
- package/dist/themes/content-contrast.css +1 -1
- package/dist/themes/content.css +2 -2
- package/dist/themes/desert-contrast.css +1 -1
- package/dist/themes/desert.css +2 -2
- package/dist/themes/expressive-contrast.css +1 -1
- package/dist/themes/expressive.css +2 -2
- package/dist/themes/fidelity-contrast.css +1 -1
- package/dist/themes/fidelity.css +2 -2
- package/dist/themes/forest-contrast.css +1 -1
- package/dist/themes/forest.css +1 -1
- package/dist/themes/fruit-salad-contrast.css +1 -1
- package/dist/themes/fruit-salad.css +2 -2
- package/dist/themes/highcontrast-contrast.css +1 -1
- package/dist/themes/highcontrast.css +2 -2
- package/dist/themes/monochrome-contrast.css +1 -1
- package/dist/themes/monochrome.css +2 -2
- package/dist/themes/neutral-contrast.css +1 -1
- package/dist/themes/neutral.css +2 -2
- package/dist/themes/ocean-contrast.css +1 -1
- package/dist/themes/ocean.css +1 -1
- package/dist/themes/rainbow-contrast.css +1 -1
- package/dist/themes/rainbow.css +2 -2
- package/dist/themes/sageivory-contrast.css +1 -1
- package/dist/themes/sageivory.css +2 -2
- package/dist/themes/spring-contrast.css +1 -1
- package/dist/themes/spring.css +1 -1
- package/dist/themes/summer-contrast.css +1 -1
- package/dist/themes/summer.css +2 -2
- package/dist/themes/sunset-contrast.css +1 -1
- package/dist/themes/sunset.css +1 -1
- package/dist/themes/tealcaramel-contrast.css +1 -1
- package/dist/themes/tealcaramel.css +2 -2
- package/dist/themes/vibrant-contrast.css +1 -1
- package/dist/themes/vibrant.css +2 -2
- package/package.json +1 -1
- package/src/styles/components/_bottom-sheet.scss +1 -0
- package/src/styles/components/_checkbox.scss +1 -0
- package/src/styles/components/_datepicker.scss +2 -1
- package/src/styles/components/_dialog.scss +9 -0
- package/src/styles/components/_fab.scss +1 -0
- package/src/styles/components/_list.scss +1 -0
- package/src/styles/components/_navigation-rail.scss +2 -0
- package/src/styles/components/_radios.scss +1 -0
- package/src/styles/components/_search.scss +2 -5
- package/src/styles/components/_side-sheet.scss +2 -1
- package/src/styles/components/_slider.scss +1 -7
- package/src/styles/components/_switch.scss +1 -0
- package/src/styles/components/_timepicker.scss +1 -0
- package/src/styles/components/_tooltip.scss +0 -2
- package/src/styles/elements/_text-field.scss +7 -1
- package/src/styles/main.scss +2 -1
- package/src/styles/themes/_autumn.scss +2 -13
- package/src/styles/themes/_base-theme.scss +16 -7
- package/src/styles/themes/_brownbeige.scss +5 -3
- package/src/styles/themes/_content.scss +5 -3
- package/src/styles/themes/_desert.scss +5 -3
- package/src/styles/themes/_expressive.scss +5 -3
- package/src/styles/themes/_fidelity.scss +5 -3
- package/src/styles/themes/_fruit-salad.scss +5 -3
- package/src/styles/themes/_highcontrast.scss +5 -3
- package/src/styles/themes/_monochrome.scss +5 -3
- package/src/styles/themes/_neutral.scss +5 -3
- package/src/styles/themes/_rainbow.scss +5 -3
- package/src/styles/themes/_sageivory.scss +5 -3
- package/src/styles/themes/_summer.scss +5 -3
- package/src/styles/themes/_tealcaramel.scss +5 -3
- package/src/styles/themes/_vibrant.scss +5 -3
- package/src/styles/utilities/_typography.scss +9 -3
- package/src/styles/utilities/_visibility.scss +2 -7
package/README.md
CHANGED
|
@@ -94,10 +94,10 @@ What a bundler keeps, minified and gzipped (kB is 1,000 bytes), measured from th
|
|
|
94
94
|
| `createButton` from `material`, with code splitting: the initial chunks (the progress indicator loads on demand) | 7.6 kB |
|
|
95
95
|
| `createButton`, without code splitting (the progress indicator included) | 13.9 kB |
|
|
96
96
|
| `createButton`, `createTextField` and `createCheckbox`, without code splitting | 20.4 kB |
|
|
97
|
-
| Everything the root exports (`export * from 'material'`), without code splitting | 127.
|
|
97
|
+
| Everything the root exports (`export * from 'material'`), without code splitting | 127.3 kB |
|
|
98
98
|
| `material/styles/base` | 2.9 kB |
|
|
99
99
|
| `material/styles/base` and `material/styles/button` | 5.2 kB |
|
|
100
|
-
| `material/styles`, the full stylesheet | 63.
|
|
100
|
+
| `material/styles`, the full stylesheet | 63.6 kB |
|
|
101
101
|
<!-- /sizes -->
|
|
102
102
|
|
|
103
103
|
`material` publishes ESM only, so bundlers drop what you do not import. Each component's page on [md3.io/components](https://md3.io/components/) gives its size.
|
|
@@ -81,14 +81,17 @@ const createButtonGroup = (config = {}) => {
|
|
|
81
81
|
let growth = 0;
|
|
82
82
|
const apply = [];
|
|
83
83
|
const compress = (i, side) => {
|
|
84
|
-
const
|
|
84
|
+
const facing = padding(i, side);
|
|
85
|
+
const room = facing > 0
|
|
86
|
+
? Math.min(facing, BUTTON_GROUP_COMPRESSION_LIMIT)
|
|
87
|
+
: BUTTON_GROUP_COMPRESSION_LIMIT;
|
|
88
|
+
const limit = Math.min(share, room, widths[i]);
|
|
85
89
|
if (limit <= 0)
|
|
86
90
|
return;
|
|
87
91
|
const el = buttons[i].element;
|
|
88
92
|
const to = widths[i] - limit;
|
|
89
93
|
el.style.minWidth = `${to}px`;
|
|
90
94
|
el.style.width = `${widths[i]}px`;
|
|
91
|
-
const facing = padding(i, side);
|
|
92
95
|
apply.push(() => {
|
|
93
96
|
el.style.width = `${to}px`;
|
|
94
97
|
if (facing > 0)
|
|
@@ -1,113 +1,113 @@
|
|
|
1
1
|
import { removeClass } from "../../core/dom/classes.js";
|
|
2
2
|
import { hideFromTopLayer } from "../../core/dom/layer.js";
|
|
3
|
-
export const withAPI = (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
3
|
+
export const withAPI = (component) => {
|
|
4
|
+
const options = component;
|
|
5
|
+
return {
|
|
6
|
+
...component,
|
|
7
|
+
open() {
|
|
8
|
+
options.visibility.open();
|
|
9
|
+
return this;
|
|
10
|
+
},
|
|
11
|
+
close() {
|
|
12
|
+
options.visibility.close();
|
|
13
|
+
return this;
|
|
14
|
+
},
|
|
15
|
+
toggle(open) {
|
|
16
|
+
options.visibility.toggle(open);
|
|
17
|
+
return this;
|
|
18
|
+
},
|
|
19
|
+
isOpen() {
|
|
20
|
+
return options.visibility.isOpen();
|
|
21
|
+
},
|
|
22
|
+
setTitle(title) {
|
|
23
|
+
options.content.setTitle(title);
|
|
24
|
+
return this;
|
|
25
|
+
},
|
|
26
|
+
getTitle() {
|
|
27
|
+
return options.content.getTitle();
|
|
28
|
+
},
|
|
29
|
+
setSubtitle(subtitle) {
|
|
30
|
+
options.content.setSubtitle(subtitle);
|
|
31
|
+
return this;
|
|
32
|
+
},
|
|
33
|
+
getSubtitle() {
|
|
34
|
+
return options.content.getSubtitle();
|
|
35
|
+
},
|
|
36
|
+
setContent(content) {
|
|
37
|
+
options.content.setContent(content);
|
|
38
|
+
return this;
|
|
39
|
+
},
|
|
40
|
+
getContent() {
|
|
41
|
+
return options.content.getContent();
|
|
42
|
+
},
|
|
43
|
+
addButton(button) {
|
|
44
|
+
options.buttons.addButton(button);
|
|
45
|
+
return this;
|
|
46
|
+
},
|
|
47
|
+
removeButton(indexOrText) {
|
|
48
|
+
options.buttons.removeButton(indexOrText);
|
|
49
|
+
return this;
|
|
50
|
+
},
|
|
51
|
+
getButtons() {
|
|
52
|
+
return options.buttons.getButtons();
|
|
53
|
+
},
|
|
54
|
+
setFooterAlignment(alignment) {
|
|
55
|
+
options.buttons.setFooterAlignment(alignment);
|
|
56
|
+
return this;
|
|
57
|
+
},
|
|
58
|
+
toggleDivider(show) {
|
|
59
|
+
options.divider.toggleDivider(show);
|
|
60
|
+
return this;
|
|
61
|
+
},
|
|
62
|
+
hasDivider() {
|
|
63
|
+
return options.divider.hasDivider();
|
|
64
|
+
},
|
|
65
|
+
setSize(size) {
|
|
66
|
+
options.size.setSize(size);
|
|
67
|
+
return this;
|
|
68
|
+
},
|
|
69
|
+
on(event, handler) {
|
|
70
|
+
options.on(event, handler);
|
|
71
|
+
return this;
|
|
72
|
+
},
|
|
73
|
+
off(event, handler) {
|
|
74
|
+
options.off(event, handler);
|
|
75
|
+
return this;
|
|
76
|
+
},
|
|
77
|
+
getHeaderElement() {
|
|
78
|
+
return options.content.getHeaderElement();
|
|
79
|
+
},
|
|
80
|
+
getContentElement() {
|
|
81
|
+
return options.content.getContentElement();
|
|
82
|
+
},
|
|
83
|
+
getFooterElement() {
|
|
84
|
+
return options.content.getFooterElement();
|
|
85
|
+
},
|
|
86
|
+
confirm(options) {
|
|
86
87
|
return component.confirm(options || { message: "Are you sure?" });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
options.focus.releaseFocus();
|
|
88
|
+
},
|
|
89
|
+
destroy() {
|
|
90
|
+
const wasOpen = this.isOpen();
|
|
91
|
+
options.visibility.cancel();
|
|
92
|
+
if (wasOpen) {
|
|
93
|
+
const dialogVisibleClass = `${component.getClass("dialog")}--visible`;
|
|
94
|
+
const overlayVisibleClass = `${component.getClass("dialog__overlay")}--visible`;
|
|
95
|
+
removeClass(component.element, dialogVisibleClass);
|
|
96
|
+
removeClass(component.overlay, overlayVisibleClass);
|
|
97
|
+
hideFromTopLayer(component.element);
|
|
98
|
+
if (options.focus && options.focus.releaseFocus) {
|
|
99
|
+
options.focus.releaseFocus();
|
|
100
|
+
}
|
|
101
101
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
102
|
+
options.lifecycle.destroy();
|
|
103
|
+
if (component.overlay && component.overlay.parentNode) {
|
|
104
|
+
component.overlay.parentNode.removeChild(component.overlay);
|
|
105
|
+
}
|
|
106
|
+
if (component.element.parentNode !== component.overlay) {
|
|
107
|
+
component.element.remove();
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
element: component.element,
|
|
111
|
+
overlay: component.overlay,
|
|
112
|
+
};
|
|
113
|
+
};
|
|
@@ -35,56 +35,4 @@ export const getElementConfig = (config) => {
|
|
|
35
35
|
className: config.class
|
|
36
36
|
});
|
|
37
37
|
};
|
|
38
|
-
export const getOverlayConfig = () => {
|
|
39
|
-
return {
|
|
40
|
-
tag: 'div',
|
|
41
|
-
attributes: {},
|
|
42
|
-
className: ''
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
export const getApiConfig = (comp) => ({
|
|
46
|
-
visibility: {
|
|
47
|
-
open: () => comp.visibility.open(),
|
|
48
|
-
close: () => comp.visibility.close(),
|
|
49
|
-
toggle: (visible) => comp.visibility.toggle(visible),
|
|
50
|
-
isOpen: () => comp.visibility.isOpen(),
|
|
51
|
-
cancel: () => comp.visibility.cancel()
|
|
52
|
-
},
|
|
53
|
-
content: {
|
|
54
|
-
setTitle: (title) => comp.content.setTitle(title),
|
|
55
|
-
getTitle: () => comp.content.getTitle(),
|
|
56
|
-
setSubtitle: (subtitle) => comp.content.setSubtitle(subtitle),
|
|
57
|
-
getSubtitle: () => comp.content.getSubtitle(),
|
|
58
|
-
setContent: (content) => comp.content.setContent(content),
|
|
59
|
-
getContent: () => comp.content.getContent(),
|
|
60
|
-
getHeaderElement: () => comp.content.getHeaderElement(),
|
|
61
|
-
getContentElement: () => comp.content.getContentElement(),
|
|
62
|
-
getFooterElement: () => comp.content.getFooterElement()
|
|
63
|
-
},
|
|
64
|
-
buttons: {
|
|
65
|
-
addButton: (button) => comp.buttons.addButton(button),
|
|
66
|
-
removeButton: (indexOrText) => comp.buttons.removeButton(indexOrText),
|
|
67
|
-
getButtons: () => comp.buttons.getButtons(),
|
|
68
|
-
setFooterAlignment: (alignment) => comp.buttons.setFooterAlignment(alignment)
|
|
69
|
-
},
|
|
70
|
-
focus: {
|
|
71
|
-
trapFocus: () => comp.focus.trapFocus(),
|
|
72
|
-
releaseFocus: () => comp.focus.releaseFocus()
|
|
73
|
-
},
|
|
74
|
-
size: {
|
|
75
|
-
setSize: (size) => comp.size.setSize(size)
|
|
76
|
-
},
|
|
77
|
-
divider: {
|
|
78
|
-
toggleDivider: (show) => comp.divider.toggleDivider(show),
|
|
79
|
-
hasDivider: () => comp.divider.hasDivider()
|
|
80
|
-
},
|
|
81
|
-
events: {
|
|
82
|
-
on: (event, handler) => comp.on(event, handler),
|
|
83
|
-
off: (event, handler) => comp.off(event, handler),
|
|
84
|
-
trigger: (event, data) => comp.emit(event, data)
|
|
85
|
-
},
|
|
86
|
-
lifecycle: {
|
|
87
|
-
destroy: () => comp.lifecycle.destroy()
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
38
|
export default defaultConfig;
|
|
@@ -3,11 +3,11 @@ import { createBase, withElement } from "../../core/compose/component.js";
|
|
|
3
3
|
import { withEvents, withLifecycle } from "../../core/compose/features/index.js";
|
|
4
4
|
import { withStructure, withVisibility, withContent, withButtons, withSize, withConfirm, withDivider } from "./features.js";
|
|
5
5
|
import { withAPI } from "./api.js";
|
|
6
|
-
import { createBaseConfig, getElementConfig
|
|
6
|
+
import { createBaseConfig, getElementConfig } from "./config.js";
|
|
7
7
|
const createDialog = (config = {}) => {
|
|
8
8
|
const baseConfig = createBaseConfig(config);
|
|
9
9
|
try {
|
|
10
|
-
const dialog = pipe(createBase, withEvents(), withElement(getElementConfig(baseConfig)), withStructure(baseConfig, () => dialog), withVisibility(() => dialog), withContent(), withButtons(() => dialog), withSize(), withDivider(), withConfirm(), withLifecycle(),
|
|
10
|
+
const dialog = pipe(createBase, withEvents(), withElement(getElementConfig(baseConfig)), withStructure(baseConfig, () => dialog), withVisibility(() => dialog), withContent(), withButtons(() => dialog), withSize(), withDivider(), withConfirm(), withLifecycle(), withAPI)(baseConfig);
|
|
11
11
|
if (baseConfig.on) {
|
|
12
12
|
Object.entries(baseConfig.on).forEach(([event, handler]) => {
|
|
13
13
|
if (typeof handler === 'function') {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { getOverlayConfig } from "./config.js";
|
|
2
1
|
import createButton from "../button/index.js";
|
|
3
|
-
import { createDivider } from "../divider/index.js";
|
|
4
2
|
import { addClass, removeClass } from "../../core/dom/classes.js";
|
|
5
3
|
import { setHTML } from "../../core/dom/html.js";
|
|
6
|
-
import {
|
|
4
|
+
import { deepActiveElement, tabStops, wrapTab } from "../../core/dom/focus.js";
|
|
7
5
|
import { hideFromTopLayer, onModalEscape, onTopLayerClose, showInTopLayer } from "../../core/dom/layer.js";
|
|
8
6
|
const DIALOG_EVENTS = {
|
|
9
7
|
OPEN: "open",
|
|
@@ -18,17 +16,8 @@ export const withStructure = (config, getComponent) => (component) => {
|
|
|
18
16
|
const uid = `${component.getClass("dialog")}-${++dialogCount}`;
|
|
19
17
|
const titleId = `${uid}-title`;
|
|
20
18
|
const contentId = `${uid}-content`;
|
|
21
|
-
const
|
|
22
|
-
const overlay = document.createElement(overlayConfig.tag || "div");
|
|
19
|
+
const overlay = document.createElement("div");
|
|
23
20
|
overlay.classList.add(component.getClass("dialog__overlay"));
|
|
24
|
-
if (overlayConfig.attributes &&
|
|
25
|
-
typeof overlayConfig.attributes === "object") {
|
|
26
|
-
Object.entries(overlayConfig.attributes).forEach(([key, value]) => {
|
|
27
|
-
if (key && typeof key === "string" && value !== undefined) {
|
|
28
|
-
overlay.setAttribute(key, String(value));
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
21
|
if (config.zIndex) {
|
|
33
22
|
overlay.style.zIndex = String(config.zIndex);
|
|
34
23
|
}
|
|
@@ -95,10 +84,8 @@ export const withStructure = (config, getComponent) => (component) => {
|
|
|
95
84
|
return footer;
|
|
96
85
|
};
|
|
97
86
|
const createDividerElement = () => {
|
|
98
|
-
const divider =
|
|
99
|
-
|
|
100
|
-
class: component.getClass("dialog__divider"),
|
|
101
|
-
});
|
|
87
|
+
const divider = document.createElement("hr");
|
|
88
|
+
divider.classList.add(component.getClass("dialog__divider"));
|
|
102
89
|
return divider;
|
|
103
90
|
};
|
|
104
91
|
const header = createHeader();
|
|
@@ -129,16 +116,16 @@ export const withStructure = (config, getComponent) => (component) => {
|
|
|
129
116
|
let footerDivider = null;
|
|
130
117
|
if (config.divider) {
|
|
131
118
|
headerDivider = createDividerElement();
|
|
132
|
-
headerDivider.
|
|
133
|
-
component.element.appendChild(headerDivider
|
|
119
|
+
headerDivider.classList.add(component.getClass("dialog__header-divider"));
|
|
120
|
+
component.element.appendChild(headerDivider);
|
|
134
121
|
if (footer) {
|
|
135
122
|
footerDivider = createDividerElement();
|
|
136
|
-
footerDivider.
|
|
123
|
+
footerDivider.classList.add(component.getClass("dialog__footer-divider"));
|
|
137
124
|
}
|
|
138
125
|
}
|
|
139
126
|
component.element.appendChild(content);
|
|
140
127
|
if (footerDivider) {
|
|
141
|
-
component.element.appendChild(footerDivider
|
|
128
|
+
component.element.appendChild(footerDivider);
|
|
142
129
|
}
|
|
143
130
|
if (footer) {
|
|
144
131
|
component.element.appendChild(footer);
|
|
@@ -170,29 +157,25 @@ export const withDivider = () => (component) => {
|
|
|
170
157
|
divider: {
|
|
171
158
|
toggleDivider(show) {
|
|
172
159
|
if (show && !component.structure.headerDivider) {
|
|
173
|
-
const headerDivider =
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
});
|
|
177
|
-
component.element.insertBefore(headerDivider.element, component.structure.content);
|
|
160
|
+
const headerDivider = document.createElement("hr");
|
|
161
|
+
headerDivider.classList.add(component.getClass("dialog__divider"), component.getClass("dialog__header-divider"));
|
|
162
|
+
component.element.insertBefore(headerDivider, component.structure.content);
|
|
178
163
|
component.structure.headerDivider = headerDivider;
|
|
179
164
|
if (component.structure.footer &&
|
|
180
165
|
!component.structure.footerDivider) {
|
|
181
|
-
const footerDivider =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
});
|
|
185
|
-
component.element.insertBefore(footerDivider.element, component.structure.footer);
|
|
166
|
+
const footerDivider = document.createElement("hr");
|
|
167
|
+
footerDivider.classList.add(component.getClass("dialog__divider"), component.getClass("dialog__footer-divider"));
|
|
168
|
+
component.element.insertBefore(footerDivider, component.structure.footer);
|
|
186
169
|
component.structure.footerDivider = footerDivider;
|
|
187
170
|
}
|
|
188
171
|
}
|
|
189
172
|
else if (!show) {
|
|
190
173
|
if (component.structure.headerDivider) {
|
|
191
|
-
component.structure.headerDivider.
|
|
174
|
+
component.structure.headerDivider.remove();
|
|
192
175
|
component.structure.headerDivider = null;
|
|
193
176
|
}
|
|
194
177
|
if (component.structure.footerDivider) {
|
|
195
|
-
component.structure.footerDivider.
|
|
178
|
+
component.structure.footerDivider.remove();
|
|
196
179
|
component.structure.footerDivider = null;
|
|
197
180
|
}
|
|
198
181
|
}
|
|
@@ -251,39 +234,42 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
251
234
|
let showTimer;
|
|
252
235
|
let afterOpenTimer;
|
|
253
236
|
let afterCloseTimer;
|
|
237
|
+
let afterOpenWaiting = false;
|
|
254
238
|
const openDuration = component.config.animationDuration ?? 500;
|
|
255
239
|
const closeDuration = component.config.animationDuration ?? 150;
|
|
256
240
|
const top = component.config.layer === "top";
|
|
257
241
|
const scrim = top ? component.element : component.overlay;
|
|
258
|
-
const focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
259
242
|
let previouslyFocusedElement = null;
|
|
260
243
|
let mouseDownOnOverlay = false;
|
|
261
244
|
const inerted = [];
|
|
262
245
|
let scrollLock = null;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
246
|
+
let focusFrame;
|
|
247
|
+
let focusView;
|
|
248
|
+
let focusRequest = 0;
|
|
249
|
+
let focusPending = false;
|
|
250
|
+
const cancelFocusFrame = () => {
|
|
251
|
+
focusRequest += 1;
|
|
252
|
+
focusPending = false;
|
|
253
|
+
if (focusFrame !== undefined) {
|
|
254
|
+
focusView?.cancelAnimationFrame(focusFrame);
|
|
255
|
+
focusFrame = undefined;
|
|
256
|
+
focusView = undefined;
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const emitAfterOpen = () => {
|
|
260
|
+
afterOpenWaiting = false;
|
|
261
|
+
if (!opened || typeof component.emit !== "function")
|
|
268
262
|
return;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
263
|
+
component.emit(DIALOG_EVENTS.AFTER_OPEN, { dialog: getComponent() });
|
|
264
|
+
};
|
|
265
|
+
const afterOpenDue = () => {
|
|
266
|
+
afterOpenTimer = undefined;
|
|
267
|
+
if (focusPending) {
|
|
268
|
+
afterOpenWaiting = true;
|
|
273
269
|
return;
|
|
274
270
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const active = activeElementOf(component.element);
|
|
278
|
-
if (e.shiftKey && (active === first || !component.element.contains(active))) {
|
|
279
|
-
last.focus();
|
|
280
|
-
e.preventDefault();
|
|
281
|
-
}
|
|
282
|
-
else if (!e.shiftKey && active === last) {
|
|
283
|
-
first.focus();
|
|
284
|
-
e.preventDefault();
|
|
285
|
-
}
|
|
286
|
-
}
|
|
271
|
+
emitAfterOpen();
|
|
272
|
+
};
|
|
287
273
|
const inertBackground = () => {
|
|
288
274
|
if (component.config.modal === false)
|
|
289
275
|
return;
|
|
@@ -313,20 +299,76 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
313
299
|
scrollLock = null;
|
|
314
300
|
}
|
|
315
301
|
};
|
|
302
|
+
let containerPosition = null;
|
|
303
|
+
const unscopeScrim = () => {
|
|
304
|
+
removeClass(component.overlay, `${component.getClass("dialog__overlay")}--contained`);
|
|
305
|
+
if (containerPosition === null)
|
|
306
|
+
return;
|
|
307
|
+
component.structure.container.style.position = containerPosition;
|
|
308
|
+
containerPosition = null;
|
|
309
|
+
};
|
|
310
|
+
const scopeScrim = () => {
|
|
311
|
+
const container = component.structure.container;
|
|
312
|
+
if (top || container === document.body)
|
|
313
|
+
return;
|
|
314
|
+
if (getComputedStyle(container).position === "static") {
|
|
315
|
+
containerPosition ?? (containerPosition = container.style.position);
|
|
316
|
+
container.style.position = "relative";
|
|
317
|
+
}
|
|
318
|
+
addClass(component.overlay, `${component.getClass("dialog__overlay")}--contained`);
|
|
319
|
+
if (!container.clientHeight ||
|
|
320
|
+
container.clientWidth < component.element.offsetWidth ||
|
|
321
|
+
container.clientHeight < component.element.offsetHeight) {
|
|
322
|
+
unscopeScrim();
|
|
323
|
+
}
|
|
324
|
+
};
|
|
316
325
|
const handleWrap = (e) => wrapTab(component.element, e);
|
|
326
|
+
const focusWhenVisible = (target) => {
|
|
327
|
+
const view = target.ownerDocument.defaultView;
|
|
328
|
+
if (!view || typeof view.requestAnimationFrame !== "function") {
|
|
329
|
+
target.focus();
|
|
330
|
+
focusPending = false;
|
|
331
|
+
if (afterOpenWaiting)
|
|
332
|
+
emitAfterOpen();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
cancelFocusFrame();
|
|
336
|
+
const request = focusRequest;
|
|
337
|
+
const settle = () => {
|
|
338
|
+
focusFrame = undefined;
|
|
339
|
+
if (request !== focusRequest)
|
|
340
|
+
return;
|
|
341
|
+
if (!opened || !target.isConnected) {
|
|
342
|
+
focusPending = false;
|
|
343
|
+
if (afterOpenWaiting)
|
|
344
|
+
emitAfterOpen();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (view.getComputedStyle(target).visibility !== "hidden") {
|
|
348
|
+
target.focus();
|
|
349
|
+
focusPending = false;
|
|
350
|
+
if (afterOpenWaiting)
|
|
351
|
+
emitAfterOpen();
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
focusPending = true;
|
|
355
|
+
focusFrame = view.requestAnimationFrame(settle);
|
|
356
|
+
focusView = view;
|
|
357
|
+
};
|
|
358
|
+
settle();
|
|
359
|
+
};
|
|
317
360
|
const trapFocus = () => {
|
|
318
361
|
inertBackground();
|
|
319
362
|
if (component.config.autofocus !== false) {
|
|
320
363
|
const requested = component.element.querySelector("[autofocus]");
|
|
321
|
-
const target = requested ||
|
|
322
|
-
target
|
|
364
|
+
const target = requested || tabStops(component.element)[0] || component.element;
|
|
365
|
+
focusWhenVisible(target);
|
|
323
366
|
}
|
|
324
367
|
if (component.config.trapFocus !== false) {
|
|
325
|
-
component.element.addEventListener("keydown",
|
|
368
|
+
component.element.addEventListener("keydown", handleWrap);
|
|
326
369
|
}
|
|
327
370
|
};
|
|
328
371
|
const releaseFocus = () => {
|
|
329
|
-
component.element.removeEventListener("keydown", handleTabKey);
|
|
330
372
|
component.element.removeEventListener("keydown", handleWrap);
|
|
331
373
|
releaseBackground();
|
|
332
374
|
if (previouslyFocusedElement) {
|
|
@@ -390,6 +432,7 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
390
432
|
component.element.setAttribute("open", "");
|
|
391
433
|
}
|
|
392
434
|
};
|
|
435
|
+
scopeScrim();
|
|
393
436
|
if (isOpen) {
|
|
394
437
|
if (top)
|
|
395
438
|
showModal();
|
|
@@ -417,6 +460,8 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
417
460
|
return;
|
|
418
461
|
opened = true;
|
|
419
462
|
clearTimeout(afterCloseTimer);
|
|
463
|
+
afterOpenWaiting = false;
|
|
464
|
+
focusPending = false;
|
|
420
465
|
if (top) {
|
|
421
466
|
showModal();
|
|
422
467
|
void component.element.offsetWidth;
|
|
@@ -426,9 +471,7 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
426
471
|
component.emit(DIALOG_EVENTS.OPEN, { dialog: getComponent() });
|
|
427
472
|
if (!opened)
|
|
428
473
|
return;
|
|
429
|
-
afterOpenTimer = setTimeout(
|
|
430
|
-
component.emit(DIALOG_EVENTS.AFTER_OPEN, { dialog: getComponent() });
|
|
431
|
-
}, openDuration);
|
|
474
|
+
afterOpenTimer = setTimeout(afterOpenDue, openDuration);
|
|
432
475
|
return;
|
|
433
476
|
}
|
|
434
477
|
if (component.element.parentNode !== component.overlay) {
|
|
@@ -438,6 +481,7 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
438
481
|
const container = component.structure.container || document.body;
|
|
439
482
|
container.appendChild(component.overlay);
|
|
440
483
|
}
|
|
484
|
+
scopeScrim();
|
|
441
485
|
setupEvents();
|
|
442
486
|
if (typeof component.emit === "function") {
|
|
443
487
|
component.emit(DIALOG_EVENTS.OPEN, { dialog: getComponent() });
|
|
@@ -449,9 +493,7 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
449
493
|
addClass(component.element, `${component.getClass("dialog")}--visible`);
|
|
450
494
|
trapFocus();
|
|
451
495
|
if (typeof component.emit === "function") {
|
|
452
|
-
afterOpenTimer = setTimeout(
|
|
453
|
-
component.emit(DIALOG_EVENTS.AFTER_OPEN, { dialog: getComponent() });
|
|
454
|
-
}, openDuration);
|
|
496
|
+
afterOpenTimer = setTimeout(afterOpenDue, openDuration);
|
|
455
497
|
}
|
|
456
498
|
}, 10);
|
|
457
499
|
},
|
|
@@ -474,6 +516,8 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
474
516
|
opened = false;
|
|
475
517
|
clearTimeout(showTimer);
|
|
476
518
|
clearTimeout(afterOpenTimer);
|
|
519
|
+
afterOpenWaiting = false;
|
|
520
|
+
cancelFocusFrame();
|
|
477
521
|
const dialogVisibleClass = `${component.getClass("dialog")}--visible`;
|
|
478
522
|
const overlayVisibleClass = `${component.getClass("dialog__overlay")}--visible`;
|
|
479
523
|
removeClass(component.element, dialogVisibleClass);
|
|
@@ -491,6 +535,7 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
491
535
|
if (!top && component.overlay && component.overlay.parentNode) {
|
|
492
536
|
component.overlay.parentNode.removeChild(component.overlay);
|
|
493
537
|
}
|
|
538
|
+
unscopeScrim();
|
|
494
539
|
if (typeof component.emit === "function") {
|
|
495
540
|
component.emit(DIALOG_EVENTS.AFTER_CLOSE, { dialog: getComponent() });
|
|
496
541
|
}
|
|
@@ -515,7 +560,10 @@ export const withVisibility = (getComponent) => (component) => {
|
|
|
515
560
|
clearTimeout(showTimer);
|
|
516
561
|
clearTimeout(afterOpenTimer);
|
|
517
562
|
clearTimeout(afterCloseTimer);
|
|
563
|
+
afterOpenWaiting = false;
|
|
564
|
+
cancelFocusFrame();
|
|
518
565
|
cleanupEvents();
|
|
566
|
+
unscopeScrim();
|
|
519
567
|
},
|
|
520
568
|
};
|
|
521
569
|
if (component && component.on) {
|