@ulu/frontend 0.0.23 → 0.1.0-beta.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/deprecated/js/drupal-programmatic-modal.js +91 -0
- package/{js/ui/modals.js → deprecated/js/micromodal-modals.js} +41 -67
- package/dist/ulu-frontend.min.css +1 -1
- package/dist/ulu-frontend.min.js +70 -1
- package/index.js +6 -1
- package/js/events/index.js +58 -7
- package/js/index.js +3 -7
- package/js/{helpers/css-breakpoint.js → ui/breakpoints.js} +9 -11
- package/js/ui/collapsible.js +195 -0
- package/js/ui/dialog.js +157 -0
- package/js/ui/dialog.todo +37 -0
- package/js/ui/flipcard.js +55 -11
- package/js/ui/grid.js +2 -47
- package/js/ui/index.js +21 -0
- package/js/ui/modal-builder.js +197 -0
- package/js/ui/overflow-scroller-pager.js +1 -1
- package/js/ui/overflow-scroller.js +8 -5
- package/js/ui/page.js +14 -0
- package/js/ui/popover.js +135 -0
- package/js/ui/print-details.js +44 -0
- package/js/ui/print.js +67 -0
- package/js/ui/programmatic-modal.js +79 -81
- package/js/ui/proxy-click.js +80 -0
- package/js/ui/resizer.js +3 -3
- package/js/ui/scroll-slider.js +56 -0
- package/js/ui/scrollpoint.js +300 -0
- package/js/ui/slider.js +72 -10
- package/js/ui/tabs.js +85 -58
- package/js/ui/theme-toggle.js +129 -0
- package/js/ui/tooltip.js +268 -67
- package/js/utils/{logger.js → class-logger.js} +6 -5
- package/js/utils/dom.js +122 -0
- package/js/utils/file-save.js +67 -0
- package/js/utils/floating-ui.js +83 -0
- package/js/utils/id.js +22 -0
- package/js/utils/index.js +7 -0
- package/js/{helpers → utils}/pause-youtube-video.js +1 -1
- package/package.json +32 -11
- package/resources/drupal/twig-macros/accordion.twig +99 -0
- package/resources/drupal/twig-macros/dropdown.twig +44 -0
- package/resources/drupal/twig-macros/flipcard.twig +69 -0
- package/resources/drupal/twig-macros/image.twig +30 -0
- package/resources/drupal/twig-macros/layout.twig +338 -0
- package/resources/drupal/twig-macros/slider.twig +214 -0
- package/resources/drupal/twig-macros/tabs.twig +84 -0
- package/scss/README.md +13 -1
- package/scss/_breakpoint.scss +69 -26
- package/scss/_button.scss +148 -57
- package/scss/_color.scss +46 -28
- package/scss/_cssvar.scss +103 -12
- package/scss/_element.scss +84 -67
- package/scss/_index.scss +0 -3
- package/scss/_layout.scss +57 -26
- package/scss/_path.scss +2 -2
- package/scss/_selector.scss +20 -11
- package/scss/_typography.scss +115 -82
- package/scss/_units.scss +14 -13
- package/scss/_utils.scss +280 -18
- package/scss/base/_color.scss +2 -1
- package/scss/base/_elements.scss +61 -35
- package/scss/base/_index.scss +60 -23
- package/scss/base/_keyframes.scss +115 -16
- package/scss/base/_layout.scss +10 -6
- package/scss/base/_normalize.scss +6 -122
- package/scss/base/_print.scss +49 -0
- package/scss/base/_root.scss +28 -0
- package/scss/base/_typography.scss +4 -1
- package/scss/components/_accordion.scss +217 -0
- package/scss/components/_adaptive-spacing.scss +148 -0
- package/scss/components/_badge.scss +17 -14
- package/scss/components/_button-verbose.scss +138 -0
- package/scss/components/_button.scss +9 -4
- package/scss/components/_callout.scss +175 -0
- package/scss/components/_captioned-figure.scss +173 -0
- package/scss/components/_card-grid.scss +75 -0
- package/scss/components/_card.scss +420 -0
- package/scss/components/_css-icon.scss +433 -0
- package/scss/{_grid.scss → components/_data-grid.scss} +100 -68
- package/scss/components/_data-table.scss +180 -0
- package/scss/components/_fill-context.scss +20 -22
- package/scss/components/_flipcard-grid.scss +66 -0
- package/scss/components/_flipcard.scss +304 -0
- package/scss/components/_form-theme.scss +633 -0
- package/scss/components/_hero.scss +183 -0
- package/scss/components/_horizontal-rule.scss +51 -0
- package/scss/components/_image-grid.scss +71 -0
- package/scss/components/_index.scss +276 -38
- package/scss/components/_links.scss +1 -1
- package/scss/components/_list-lines.scss +14 -3
- package/scss/components/_list-ordered.scss +3 -1
- package/scss/components/_list-unordered.scss +3 -1
- package/scss/components/_menu-stack.scss +245 -0
- package/scss/components/_modal.scss +495 -0
- package/scss/components/_nav-strip.scss +148 -0
- package/scss/components/_overlay-section.scss +122 -0
- package/scss/components/_pager.scss +168 -0
- package/scss/components/_placeholder-block.scss +121 -0
- package/scss/components/_popover.scss +263 -0
- package/scss/components/_pull-quote.scss +111 -0
- package/scss/components/_ratio-box.scss +64 -0
- package/scss/components/_rule.scss +12 -9
- package/scss/components/_scroll-slider.scss +204 -0
- package/scss/components/_skip-link.scss +92 -0
- package/scss/components/_slider.scss +241 -0
- package/scss/components/_spoke-spinner.scss +193 -0
- package/scss/components/_tabs.scss +179 -0
- package/scss/components/_tag.scss +142 -0
- package/scss/components/_tile-button.scss +131 -0
- package/scss/components/_tile-grid-overlay.scss +132 -0
- package/scss/components/_tile-grid.scss +172 -0
- package/scss/components/_vignette.scss +65 -0
- package/scss/components/_wysiwyg.scss +94 -0
- package/scss/helpers/_color.scss +1 -0
- package/scss/helpers/_display.scss +2 -1
- package/scss/helpers/_index.scss +45 -22
- package/scss/helpers/_print.scss +20 -43
- package/scss/helpers/_typography.scss +3 -0
- package/scss/helpers/_units.scss +10 -13
- package/scss/helpers/_utilities.scss +5 -1
- package/scss/stylesheets/base-styles.scss +7 -0
- package/scss/stylesheets/component-styles.scss +7 -0
- package/scss/stylesheets/helper-styles.scss +7 -0
- package/types/events/index.d.ts +1 -1
- package/types/events/index.d.ts.map +1 -1
- package/types/index.d.ts +2 -2
- package/types/{helpers/css-breakpoint.d.ts → ui/breakpoints.d.ts} +3 -3
- package/types/ui/breakpoints.d.ts.map +1 -0
- package/types/ui/collapsible.d.ts +67 -0
- package/types/ui/collapsible.d.ts.map +1 -0
- package/types/ui/dialog.d.ts +42 -0
- package/types/ui/dialog.d.ts.map +1 -0
- package/types/ui/flipcard.d.ts +8 -1
- package/types/ui/flipcard.d.ts.map +1 -1
- package/types/ui/grid.d.ts +0 -11
- package/types/ui/grid.d.ts.map +1 -1
- package/types/ui/index.d.ts +23 -0
- package/types/ui/index.d.ts.map +1 -0
- package/types/ui/modal-builder.d.ts +54 -0
- package/types/ui/modal-builder.d.ts.map +1 -0
- package/types/ui/overflow-scroller-pager.d.ts +1 -1
- package/types/ui/overflow-scroller-pager.d.ts.map +1 -1
- package/types/ui/overflow-scroller.d.ts +3 -1
- package/types/ui/overflow-scroller.d.ts.map +1 -1
- package/types/ui/page.d.ts +5 -0
- package/types/ui/page.d.ts.map +1 -0
- package/types/ui/popover.d.ts +40 -0
- package/types/ui/popover.d.ts.map +1 -0
- package/types/ui/print-details.d.ts +10 -0
- package/types/ui/print-details.d.ts.map +1 -0
- package/types/ui/print.d.ts +10 -0
- package/types/ui/print.d.ts.map +1 -0
- package/types/ui/programmatic-modal.d.ts +19 -1
- package/types/ui/programmatic-modal.d.ts.map +1 -1
- package/types/ui/proxy-click.d.ts +18 -0
- package/types/ui/proxy-click.d.ts.map +1 -0
- package/types/ui/resizer.d.ts +1 -1
- package/types/ui/resizer.d.ts.map +1 -1
- package/types/ui/scroll-slider.d.ts +13 -0
- package/types/ui/scroll-slider.d.ts.map +1 -0
- package/types/ui/scrollpoint.d.ts +133 -0
- package/types/ui/scrollpoint.d.ts.map +1 -0
- package/types/ui/slider.d.ts +14 -2
- package/types/ui/slider.d.ts.map +1 -1
- package/types/ui/tabs.d.ts +22 -0
- package/types/ui/tabs.d.ts.map +1 -1
- package/types/ui/theme-toggle.d.ts +14 -0
- package/types/ui/theme-toggle.d.ts.map +1 -0
- package/types/ui/tooltip.d.ts +92 -10
- package/types/ui/tooltip.d.ts.map +1 -1
- package/types/utils/{logger.d.ts → class-logger.d.ts} +1 -1
- package/types/utils/class-logger.d.ts.map +1 -0
- package/types/utils/dom.d.ts +48 -0
- package/types/utils/dom.d.ts.map +1 -0
- package/types/utils/file-save.d.ts +64 -0
- package/types/utils/file-save.d.ts.map +1 -0
- package/types/utils/floating-ui.d.ts +19 -0
- package/types/utils/floating-ui.d.ts.map +1 -0
- package/types/utils/id.d.ts +10 -0
- package/types/utils/id.d.ts.map +1 -0
- package/types/utils/index.d.ts +9 -0
- package/types/utils/index.d.ts.map +1 -0
- package/types/utils/pause-youtube-video.d.ts.map +1 -0
- package/js/helpers/file-save.js +0 -52
- package/js/helpers/scrollbar-width-property.js +0 -14
- package/project.todo +0 -22
- package/scss/_calculate.scss +0 -64
- package/scss/_utility.scss +0 -12
- package/types/helpers/css-breakpoint.d.ts.map +0 -1
- package/types/helpers/file-save.d.ts +0 -17
- package/types/helpers/file-save.d.ts.map +0 -1
- package/types/helpers/node-data-manager.d.ts +0 -45
- package/types/helpers/node-data-manager.d.ts.map +0 -1
- package/types/helpers/pause-youtube-video.d.ts.map +0 -1
- package/types/helpers/scrollbar-width-property.d.ts +0 -11
- package/types/helpers/scrollbar-width-property.d.ts.map +0 -1
- package/types/ui/modals.d.ts +0 -27
- package/types/ui/modals.d.ts.map +0 -1
- package/types/utils/logger.d.ts.map +0 -1
- package/vite.config.js +0 -36
- /package/{js/deprecated → deprecated/js}/doc-ready.js +0 -0
- /package/{js/deprecated → deprecated/js}/jquery-prototypes.js +0 -0
- /package/{js/deprecated → deprecated/js}/mini-collapsible-popper-positioning.js +0 -0
- /package/{js/deprecated → deprecated/js}/mini-collapsible.js +0 -0
- /package/{js/helpers → deprecated/js}/node-data-manager.js +0 -0
- /package/{js/deprecated → deprecated/js}/script-loader.js +0 -0
- /package/{js/deprecated → deprecated/js}/waypoints/README.md +0 -0
- /package/{js/deprecated → deprecated/js}/waypoints/anchor-menu.js +0 -0
- /package/{js/deprecated → deprecated/js}/waypoints/element-waypoint.js +0 -0
- /package/{js/deprecated → deprecated/js}/waypoints/examples/page-link-menu.md +0 -0
- /package/{js/deprecated → deprecated/js}/waypoints/state-in-attribute.js +0 -0
- /package/types/{helpers → utils}/pause-youtube-video.d.ts +0 -0
package/js/ui/grid.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @module ui/grid
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { setPositionClasses } from "../utils/dom.js";
|
|
5
6
|
import { getName } from "../events/index.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -22,50 +23,4 @@ export function init(selector = "[data-grid]", classes) {
|
|
|
22
23
|
*/
|
|
23
24
|
export function setup(selector, classes) {
|
|
24
25
|
document.querySelectorAll(selector).forEach(element => setPositionClasses(element, classes || undefined));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Sets up the positonal classes that would come from the equal
|
|
29
|
-
* height module. Needs to be rerun by user when layout changes
|
|
30
|
-
* or new instances are added to the screen
|
|
31
|
-
* - Used for gutter crops
|
|
32
|
-
* - Used for rule placement
|
|
33
|
-
* - **Devs** Remember that default classes should match sass defaults
|
|
34
|
-
* @param {Node} parent The grid parent <data-grid="">
|
|
35
|
-
* @param {Object} classes Override the default equal heights classes
|
|
36
|
-
*/
|
|
37
|
-
export function setPositionClasses(parent, classes = {
|
|
38
|
-
columnFirst: 'position-column-first',
|
|
39
|
-
columnLast: 'position-column-last',
|
|
40
|
-
rowFirst: 'position-row-first',
|
|
41
|
-
rowLast: 'position-row-last'
|
|
42
|
-
}) {
|
|
43
|
-
const children = [...parent.children];
|
|
44
|
-
const rows = [];
|
|
45
|
-
let lastY;
|
|
46
|
-
// Check element against last
|
|
47
|
-
// If they don't match it's a new row create a new array
|
|
48
|
-
// Then push into the last array in the rows array
|
|
49
|
-
children.forEach((child) => {
|
|
50
|
-
const y = child.getBoundingClientRect().y;
|
|
51
|
-
if (lastY !== y) rows.push([]);
|
|
52
|
-
rows[rows.length - 1].push(child);
|
|
53
|
-
lastY = y;
|
|
54
|
-
child.classList.remove(...Object.values(classes)); // Remove previously set classes
|
|
55
|
-
});
|
|
56
|
-
// Apply Classes
|
|
57
|
-
rows.forEach((row, index) => {
|
|
58
|
-
if (index === 0)
|
|
59
|
-
row.forEach(child => child.classList.add(classes.rowFirst));
|
|
60
|
-
if (index == rows.length - 1)
|
|
61
|
-
row.forEach(child => child.classList.add(classes.rowLast));
|
|
62
|
-
|
|
63
|
-
row.forEach((child, childIndex) => {
|
|
64
|
-
if (childIndex === 0)
|
|
65
|
-
child.classList.add(classes.columnFirst);
|
|
66
|
-
if (childIndex == row.length - 1)
|
|
67
|
-
child.classList.add(classes.columnLast);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
}
|
|
26
|
+
}
|
package/js/ui/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export * as page from "./page.js";
|
|
2
|
+
export * as breakpoints from "./breakpoints.js";
|
|
3
|
+
export * as collapsible from "./collapsible.js";
|
|
4
|
+
export * as modalBuilder from "./modal-builder.js";
|
|
5
|
+
export * as dialog from "./dialog.js";
|
|
6
|
+
export * as flipcard from "./flipcard.js";
|
|
7
|
+
export * as grid from "./grid.js";
|
|
8
|
+
export * as index from "./index.js";
|
|
9
|
+
export * as overflowScrollerPager from "./overflow-scroller-pager.js";
|
|
10
|
+
export * as overflowScroller from "./overflow-scroller.js";
|
|
11
|
+
export * as popover from "./popover.js";
|
|
12
|
+
export * as tooltip from "./tooltip.js";
|
|
13
|
+
export * as resizer from "./resizer.js";
|
|
14
|
+
export * as slider from "./slider.js";
|
|
15
|
+
export * as tabs from "./tabs.js";
|
|
16
|
+
export * as proxyClick from "./proxy-click.js";
|
|
17
|
+
export * as scrollpoint from "./scrollpoint.js";
|
|
18
|
+
export * as print from "./print.js";
|
|
19
|
+
export * as printDetails from "./print-details.js";
|
|
20
|
+
export * as scrollSlider from "./scroll-slider.js";
|
|
21
|
+
export * as themeToggle from "./theme-toggle.js";
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ui/modal-builder
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Note this needs to be run before dialogs are initialized!
|
|
6
|
+
|
|
7
|
+
import { getName } from "../events/index.js";
|
|
8
|
+
import { createElementFromHtml } from "@ulu/utils/browser/dom.js";
|
|
9
|
+
import { Resizer } from "./resizer.js";
|
|
10
|
+
import { getDatasetJson } from "../utils/dom.js";
|
|
11
|
+
import { defaults as dialogDefaults, attrs as dialogAttrs } from "./dialog.js";
|
|
12
|
+
|
|
13
|
+
const attrs = {
|
|
14
|
+
builder: "data-ulu-modal-builder",
|
|
15
|
+
body: "data-ulu-modal-builder-body",
|
|
16
|
+
resizer: "data-ulu-modal-builder-resizer"
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const attrSelector = key => `[${ attrs[key] }]`;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Default builder options (extends dialog defaults, watch name collisions)
|
|
23
|
+
* - Decided to extend defaults so the interface in HTML is singular
|
|
24
|
+
* - This is sometimes easier to template (merging and serializing options
|
|
25
|
+
* in twig for example)
|
|
26
|
+
*/
|
|
27
|
+
export const defaults = {
|
|
28
|
+
title: null,
|
|
29
|
+
titleIcon: null,
|
|
30
|
+
nonModal: false,
|
|
31
|
+
documentEnd: true,
|
|
32
|
+
allowResize: false,
|
|
33
|
+
position: "center",
|
|
34
|
+
bodyFills: false,
|
|
35
|
+
noBackdrop: false,
|
|
36
|
+
size: "default",
|
|
37
|
+
print: false,
|
|
38
|
+
noMinHeight: false,
|
|
39
|
+
class: "",
|
|
40
|
+
classCloseIcon: "css-icon css-icon--close",
|
|
41
|
+
classResizerIcon: "css-icon css-icon--drag",
|
|
42
|
+
debug: false,
|
|
43
|
+
templateCloseIcon(config) {
|
|
44
|
+
return `<span class="modal__close-icon ${ config.classCloseIcon }" aria-hidden="true"></span>`;
|
|
45
|
+
},
|
|
46
|
+
templateResizerIcon(config) {
|
|
47
|
+
return `<span class="modal__resizer-icon ${ config.classResizerIcon }" aria-hidden="true"></span>`;
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* Default modal template
|
|
51
|
+
* @param {String} id ID for new modal
|
|
52
|
+
* @param {Object} config Resolved options
|
|
53
|
+
* @returns {String} Markup for modal
|
|
54
|
+
*/
|
|
55
|
+
template(id, config) {
|
|
56
|
+
const classes = [
|
|
57
|
+
"modal",
|
|
58
|
+
`modal--${ config.position }`,
|
|
59
|
+
`modal--${ config.size }`,
|
|
60
|
+
`modal--${ config.allowResize ? "resize" : "no-resize" }`,
|
|
61
|
+
...(!config.title ? ["modal--no-header"] : []),
|
|
62
|
+
...(config.bodyFills ? ["modal--body-fills"] : []),
|
|
63
|
+
...(config.noBackdrop ? ["modal--no-backdrop"] : []),
|
|
64
|
+
...(config.noMinHeight ? ["modal--no-min-height"] : [] ),
|
|
65
|
+
...(config.class ? [config.class] : []),
|
|
66
|
+
];
|
|
67
|
+
return `
|
|
68
|
+
<dialog id="${ id }" class="${ classes.join(" ") }">
|
|
69
|
+
${ config.title ? `
|
|
70
|
+
<header class="modal__header">
|
|
71
|
+
<h2 class="modal__title">
|
|
72
|
+
${ config.titleIcon ?
|
|
73
|
+
`<span class="modal__title-icon ${ config.titleIcon }" aria-hidden="true"></span>` : ""
|
|
74
|
+
}
|
|
75
|
+
<span class="modal__title-text">${ config.title }</span>
|
|
76
|
+
</h2>
|
|
77
|
+
<button class="modal__close" aria-label="Close modal" ${ dialogAttrs.close } autofocus>
|
|
78
|
+
${ config.templateCloseIcon(config) }
|
|
79
|
+
</button>
|
|
80
|
+
</header>
|
|
81
|
+
` : "" }
|
|
82
|
+
<div class="modal__body" ${ attrs.body }></div>
|
|
83
|
+
${ config.hasResizer ?
|
|
84
|
+
`<div class="modal__resizer" ${ attrs.resizer }>
|
|
85
|
+
${ config.templateResizerIcon(config) }
|
|
86
|
+
</div>` : ""
|
|
87
|
+
}
|
|
88
|
+
</div>
|
|
89
|
+
`;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Current default objects (user can override these)
|
|
94
|
+
let currentDefaults = { ...defaults };
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {Object} options Change options used as default for dialogs, can then be overridden by data attribute settings on element
|
|
98
|
+
*/
|
|
99
|
+
export function setDefaults(options) {
|
|
100
|
+
currentDefaults = Object.assign({}, currentDefaults, options);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Initialize everything in document
|
|
105
|
+
* - This will only initialize elements once, it is safe to call on page changes
|
|
106
|
+
*/
|
|
107
|
+
export function init() {
|
|
108
|
+
document.addEventListener(getName("pageModified"), setup);
|
|
109
|
+
setup();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Query and setup all builder
|
|
114
|
+
*/
|
|
115
|
+
export function setup() {
|
|
116
|
+
const builders = document.querySelectorAll(attrSelector("builder"));
|
|
117
|
+
builders.forEach(setupBuilder);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Build a dialog for the given content
|
|
122
|
+
* @param {Node} element
|
|
123
|
+
*/
|
|
124
|
+
export function setupBuilder(element) {
|
|
125
|
+
const options = getDatasetJson(element, "uluModalBuilder");
|
|
126
|
+
element.removeAttribute(attrs.builder);
|
|
127
|
+
buildModal(element, options);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
*
|
|
132
|
+
* @param {Node} content Content element of the dialog (what is inserted into the body)
|
|
133
|
+
* @param {Object} options Options for built dialog (see defaults)
|
|
134
|
+
*/
|
|
135
|
+
export function buildModal(content, options) {
|
|
136
|
+
|
|
137
|
+
const config = Object.assign({}, currentDefaults, options);
|
|
138
|
+
|
|
139
|
+
if (config.position !== "center" && config.allowResize) {
|
|
140
|
+
config.hasResizer = true;
|
|
141
|
+
}
|
|
142
|
+
if (config.debug) {
|
|
143
|
+
console.log(config, content);
|
|
144
|
+
}
|
|
145
|
+
if (!content.id) {
|
|
146
|
+
throw new Error("Missing ID on modal");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const markup = config.template(content.id, config);
|
|
150
|
+
const modal = createElementFromHtml(markup.trim());
|
|
151
|
+
const selectChild = key => modal.querySelector(attrSelector(key));
|
|
152
|
+
const body = selectChild("body");
|
|
153
|
+
const resizer = selectChild("resizer");
|
|
154
|
+
const dialogOptions = separateDialogOptions(config);
|
|
155
|
+
|
|
156
|
+
// Replace content with new dialog, and then insert the content into the new dialogs body
|
|
157
|
+
content.removeAttribute("id");
|
|
158
|
+
content.removeAttribute("hidden");
|
|
159
|
+
content.removeAttribute(attrs.builder);
|
|
160
|
+
content.parentNode.replaceChild(modal, content);
|
|
161
|
+
body.appendChild(content);
|
|
162
|
+
|
|
163
|
+
// Add dialog options for other scripts
|
|
164
|
+
modal.setAttribute(dialogAttrs.dialog, JSON.stringify(dialogOptions));
|
|
165
|
+
|
|
166
|
+
if (config.hasResizer) {
|
|
167
|
+
new Resizer(modal, resizer, {
|
|
168
|
+
fromLeft: config.position === "right"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (config.print) {
|
|
173
|
+
let printClone;
|
|
174
|
+
document.addEventListener(getName("beforePrint"), () => {
|
|
175
|
+
printClone = content.cloneNode(true);
|
|
176
|
+
modal.after(printClone);
|
|
177
|
+
});
|
|
178
|
+
document.addEventListener(getName("afterPrint"), () => {
|
|
179
|
+
printClone.remove();
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return { modal };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Returns JSON string to embed in data-ulu-dialog for dialog handling
|
|
187
|
+
* @param {Object} config Config object to pull dialog specific settings from
|
|
188
|
+
* @returns {Object}
|
|
189
|
+
*/
|
|
190
|
+
function separateDialogOptions(config) {
|
|
191
|
+
return Object.keys(dialogDefaults).reduce((acc, key) => {
|
|
192
|
+
if (key in config) {
|
|
193
|
+
acc[key] = config[key];
|
|
194
|
+
}
|
|
195
|
+
return acc;
|
|
196
|
+
}, {});
|
|
197
|
+
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* @return {Function} A function to be used in overflow scrollers "amount" configuration property
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
export
|
|
17
|
+
export function createPager() {
|
|
18
18
|
return function pager(instance, dir) {
|
|
19
19
|
const isNext = dir === "next";
|
|
20
20
|
const { track } = instance.elements;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
*/
|
|
13
13
|
import { hasRequiredProps } from '@ulu/utils/object.js';
|
|
14
|
-
import { logError } from "../utils/logger.js";
|
|
14
|
+
import { logError } from "../utils/class-logger.js";
|
|
15
15
|
const requiredElements = [
|
|
16
16
|
"track",
|
|
17
17
|
"controls"
|
|
@@ -25,6 +25,9 @@ export class OverflowScroller {
|
|
|
25
25
|
offsetStart: 100,
|
|
26
26
|
offsetEnd: 100,
|
|
27
27
|
amount: "auto",
|
|
28
|
+
buttonClasses: ["button", "button--icon"],
|
|
29
|
+
iconClassesPrevious: ["css-icon", "css-icon--angle-left"],
|
|
30
|
+
iconClassesNext: ["css-icon", "css-icon--angle-right"]
|
|
28
31
|
}
|
|
29
32
|
constructor(elements, config) {
|
|
30
33
|
this.options = Object.assign({}, OverflowScroller.defaults, config);
|
|
@@ -78,14 +81,16 @@ export class OverflowScroller {
|
|
|
78
81
|
const button = document.createElement("button");
|
|
79
82
|
button.classList.add(this.getClass("control-button"));
|
|
80
83
|
button.classList.add(this.getClass(`control-button--${ action }`));
|
|
84
|
+
button.classList.add(...this.options.buttonClasses);
|
|
81
85
|
button.setAttribute("type", "button");
|
|
82
86
|
button.innerHTML = this.getControlContent(action);
|
|
83
87
|
return button;
|
|
84
88
|
}
|
|
85
89
|
getControlContent(action) {
|
|
90
|
+
const classes = this.options[action === "next" ? "iconClassesNext" : "iconClassesPrevious"];
|
|
86
91
|
return `
|
|
87
92
|
<span class="hidden-visually">${ action }</span>
|
|
88
|
-
<span
|
|
93
|
+
<span class="${ classes.join(' ') }" aria-hidden="true"></span>
|
|
89
94
|
`;
|
|
90
95
|
}
|
|
91
96
|
onScroll(event) {
|
|
@@ -158,6 +163,4 @@ export class OverflowScroller {
|
|
|
158
163
|
const { namespace } = this.options;
|
|
159
164
|
return `${ namespace }__${ child }`;
|
|
160
165
|
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export default OverflowScroller;
|
|
166
|
+
}
|
package/js/ui/page.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General/Document Related
|
|
3
|
+
* - Add custom properties for scrollbar
|
|
4
|
+
* @module ui/page
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { addScrollbarProperty } from "../utils/dom";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initialize page module
|
|
11
|
+
*/
|
|
12
|
+
export function init() {
|
|
13
|
+
addScrollbarProperty();
|
|
14
|
+
}
|
package/js/ui/popover.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ui/popover
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getName } from "../events/index.js";
|
|
6
|
+
import { createFloatingUi } from "../utils/floating-ui.js";
|
|
7
|
+
import { Collapsible } from "./collapsible.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Array of current instances
|
|
11
|
+
*/
|
|
12
|
+
export const instances = new WeakMap;
|
|
13
|
+
|
|
14
|
+
const logError = (...msgs) => console.error("@ulu (popovers):", ...msgs);
|
|
15
|
+
|
|
16
|
+
const attrs = {
|
|
17
|
+
trigger: "data-ulu-popover-trigger",
|
|
18
|
+
content: "data-ulu-popover-content",
|
|
19
|
+
arrow: "data-ulu-popover-arrow",
|
|
20
|
+
anchor: "data-ulu-popover-trigger-anchor",
|
|
21
|
+
};
|
|
22
|
+
const attrSelector = key => `[${ attrs[key] }]`;
|
|
23
|
+
|
|
24
|
+
// This modules collapsible defaults
|
|
25
|
+
const collapsibleDefaults = {
|
|
26
|
+
clickOutsideCloses: true,
|
|
27
|
+
escapeCloses: true
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize default popover
|
|
32
|
+
*/
|
|
33
|
+
export function init() {
|
|
34
|
+
document.addEventListener(getName("pageModified"), setup);
|
|
35
|
+
setup();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Query all popovers on current page and set them up
|
|
40
|
+
* - Use this manually if needed
|
|
41
|
+
* - Won't setup a popover more than once
|
|
42
|
+
*/
|
|
43
|
+
export function setup() {
|
|
44
|
+
const triggers = document.querySelectorAll(attrSelector("trigger"));
|
|
45
|
+
// Only triggers we don't have instances for
|
|
46
|
+
const resolved = Array.from(triggers)
|
|
47
|
+
.filter(trigger => !instances.has(trigger))
|
|
48
|
+
.map(resolve)
|
|
49
|
+
.filter(v => v);
|
|
50
|
+
|
|
51
|
+
resolved.forEach(({ elements, options, floatingOptions }) => {
|
|
52
|
+
instances.set(elements.trigger, new Popover(elements, options, floatingOptions));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Find the popover's elements
|
|
58
|
+
*/
|
|
59
|
+
export function resolve(trigger) {
|
|
60
|
+
const raw = trigger.dataset.uluPopoverTrigger;
|
|
61
|
+
const options = raw?.length ? JSON.parse(raw) : {};
|
|
62
|
+
const content = getContentByTrigger(trigger);
|
|
63
|
+
const elements = {
|
|
64
|
+
trigger,
|
|
65
|
+
content,
|
|
66
|
+
anchor: trigger.querySelector(attrSelector("anchor")) || trigger,
|
|
67
|
+
contentArrow: content.querySelector(attrSelector("arrow"))
|
|
68
|
+
};
|
|
69
|
+
const floatingOptions = options.floating || {};
|
|
70
|
+
delete options.floating;
|
|
71
|
+
if (content) {
|
|
72
|
+
return { elements, options, floatingOptions };
|
|
73
|
+
} else {
|
|
74
|
+
logError("Unable to make popover for", trigger);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// - grab from aria-controls (optional)
|
|
80
|
+
// - or from direct sibling
|
|
81
|
+
// - lastly check the parent container for any children that have the attribute
|
|
82
|
+
export function getContentByTrigger(trigger) {
|
|
83
|
+
let content;
|
|
84
|
+
const ariaControls = trigger.getAttribute("aria-controls");
|
|
85
|
+
|
|
86
|
+
if (ariaControls) {
|
|
87
|
+
content = document.getElementById(ariaControls);
|
|
88
|
+
} else if (trigger?.nextElementSibling?.hasAttribute(attrs.content)) {
|
|
89
|
+
content = trigger.nextElementSibling;
|
|
90
|
+
// @todo - Consider removing this (non standard, users like this should be using aria-controls)
|
|
91
|
+
} else {
|
|
92
|
+
const children = Array.from(trigger.parentNode.children);
|
|
93
|
+
const triggerIndex = children.findIndex(c => c === trigger);
|
|
94
|
+
const childrenAfter = children.slice(triggerIndex);
|
|
95
|
+
content = childrenAfter.find(child => child.matches(attrSelector("content")));
|
|
96
|
+
}
|
|
97
|
+
if (!content) {
|
|
98
|
+
logError("Unable to resolve 'content' element for popover", trigger);
|
|
99
|
+
}
|
|
100
|
+
return content;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Class that extends Collapsible adding floating-ui for popover behavior
|
|
106
|
+
*/
|
|
107
|
+
export class Popover extends Collapsible {
|
|
108
|
+
constructor(elements, config, floatingOptions) {
|
|
109
|
+
const options = Object.assign({}, collapsibleDefaults, config);
|
|
110
|
+
super(elements, options);
|
|
111
|
+
this.floatingOptions = floatingOptions || {};
|
|
112
|
+
}
|
|
113
|
+
setState(isOpen, event) {
|
|
114
|
+
super.setState(isOpen, event);
|
|
115
|
+
this.destroyFloatingInstance();
|
|
116
|
+
if (isOpen) {
|
|
117
|
+
this.createFloatingInstance();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
destroy() {
|
|
121
|
+
super.destroy();
|
|
122
|
+
this.destroyFloatingInstance();
|
|
123
|
+
}
|
|
124
|
+
createFloatingInstance() {
|
|
125
|
+
const { content, anchor, contentArrow } = this.elements;
|
|
126
|
+
const floatingElements = { trigger: anchor, contentArrow, content };
|
|
127
|
+
this.floatingCleanup = createFloatingUi(floatingElements, this.floatingOptions);
|
|
128
|
+
}
|
|
129
|
+
destroyFloatingInstance() {
|
|
130
|
+
if (this.floatingCleanup) {
|
|
131
|
+
this.floatingCleanup();
|
|
132
|
+
this.floatingCleanup = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ui/print-details
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getName } from "../events/index.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Default data attributes
|
|
9
|
+
*/
|
|
10
|
+
export const attrs = {
|
|
11
|
+
opened: "data-ulu-print-details-opened",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const attrSelector = key => `[${ attrs[key] }]`;
|
|
15
|
+
|
|
16
|
+
const defaults = {
|
|
17
|
+
selector: "details:not([open])"
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initialize details print
|
|
22
|
+
* - will open details before print
|
|
23
|
+
* - will return to previous state after
|
|
24
|
+
*/
|
|
25
|
+
export function init(options) {
|
|
26
|
+
const config = Object.assign({}, defaults, options);
|
|
27
|
+
|
|
28
|
+
// Add flag and open each details that's closed
|
|
29
|
+
document.addEventListener(getName("beforePrint"), () => {
|
|
30
|
+
document.querySelectorAll(config.selector).forEach(details => {
|
|
31
|
+
if (!details.open) {
|
|
32
|
+
details.setAttribute(attrs.opened, true);
|
|
33
|
+
details.open = true;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
// When print ends find all flagged and close
|
|
38
|
+
document.addEventListener(getName("afterPrint"), () => {
|
|
39
|
+
document.querySelectorAll(attrSelector("opened")).forEach(details => {
|
|
40
|
+
details.removeAttribute(attrs.opened);
|
|
41
|
+
details.open = false;
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
package/js/ui/print.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ui/print
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getName } from "../events/index.js";
|
|
6
|
+
import { getDatasetOptionalJson, getElement } from "../utils/dom.js";
|
|
7
|
+
import { printElement } from "@ulu/utils/browser/print.js";
|
|
8
|
+
|
|
9
|
+
export const attrs = {
|
|
10
|
+
trigger: "data-ulu-print",
|
|
11
|
+
init: "data-ulu-print-init",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const attrSelector = key => `[${ attrs[key] }]`;
|
|
15
|
+
const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
|
|
16
|
+
const queryAllInitial = key => document.querySelectorAll(attrSelectorInitial(key));
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Default options
|
|
20
|
+
*/
|
|
21
|
+
const defaults = {
|
|
22
|
+
/**
|
|
23
|
+
* Print element/selector
|
|
24
|
+
*/
|
|
25
|
+
element: null,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Initialize everything in document
|
|
30
|
+
* - This will only initialize elements once, it is safe to call on page changes
|
|
31
|
+
*/
|
|
32
|
+
export function init() {
|
|
33
|
+
document.addEventListener(getName("pageModified"), setup);
|
|
34
|
+
setup();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Setup all triggers currently on the page
|
|
39
|
+
*/
|
|
40
|
+
function setup() {
|
|
41
|
+
const triggers = queryAllInitial("trigger");
|
|
42
|
+
triggers.forEach(trigger => {
|
|
43
|
+
const options = getDatasetOptionalJson(trigger, "uluPrint");
|
|
44
|
+
setupTrigger(trigger, options);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Setup a single trigger (can be used manually without attr if needed)
|
|
50
|
+
*/
|
|
51
|
+
function setupTrigger(trigger, options) {
|
|
52
|
+
const config = Object.assign({}, defaults, options);
|
|
53
|
+
trigger.addEventListener("click", (event) => {
|
|
54
|
+
// Option to print a specific element
|
|
55
|
+
if (config.element) {
|
|
56
|
+
const element = getElement(config.element);
|
|
57
|
+
if (element) {
|
|
58
|
+
printElement(element);
|
|
59
|
+
} else {
|
|
60
|
+
console.error("Unable to find element to print", trigger, config);
|
|
61
|
+
}
|
|
62
|
+
// Default behavior print window
|
|
63
|
+
} else {
|
|
64
|
+
window.print();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|