@ulu/frontend 0.1.0-beta.8 → 0.1.0-beta.80
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/CHANGELOG.md +529 -0
- package/README.dev.md +3 -3
- package/README.md +14 -4
- package/dist/ulu-frontend.min.css +1 -1
- package/dist/ulu-frontend.min.js +35 -28
- package/docs-dev/assets/main.js +8290 -635
- package/docs-dev/assets/placeholder/icon-calendar.svg +1 -0
- package/docs-dev/assets/placeholder/icon-check.svg +1 -0
- package/docs-dev/assets/style.css +789 -338
- package/docs-dev/changelog/index.html +6553 -0
- package/docs-dev/demos/accordion/index.html +850 -328
- package/docs-dev/demos/badge/index.html +5265 -0
- package/docs-dev/demos/basic-hero/index.html +111 -0
- package/docs-dev/demos/breakpoints-manager/index.html +5276 -0
- package/docs-dev/demos/button/index.html +892 -328
- package/docs-dev/demos/button-verbose/index.html +5268 -0
- package/docs-dev/demos/callout/index.html +895 -332
- package/docs-dev/demos/captioned-figure/index.html +850 -327
- package/docs-dev/demos/card/index.html +930 -768
- package/docs-dev/demos/card-grid/index.html +5387 -0
- package/docs-dev/demos/counter-list/index.html +5270 -0
- package/docs-dev/demos/css-icons/index.html +850 -327
- package/docs-dev/demos/data-grid/index.html +870 -347
- package/docs-dev/demos/data-table/index.html +1024 -368
- package/docs-dev/demos/details-group/index.html +5297 -0
- package/docs-dev/demos/file-save/index.html +850 -327
- package/docs-dev/demos/flipcard/index.html +850 -327
- package/docs-dev/demos/form-theme/index.html +868 -358
- package/docs-dev/demos/hero/index.html +12 -4
- package/docs-dev/demos/image-grid/index.html +12 -4
- package/docs-dev/demos/index.html +851 -328
- package/docs-dev/demos/list-inline/index.html +850 -327
- package/docs-dev/demos/list-lines/index.html +850 -327
- package/docs-dev/demos/menu-stack/index.html +884 -346
- package/docs-dev/demos/modals/index.html +968 -330
- package/docs-dev/demos/nav-strip/index.html +850 -327
- package/docs-dev/demos/overlay-section/index.html +939 -346
- package/docs-dev/demos/popovers/index.html +1112 -347
- package/docs-dev/demos/print/index.html +850 -327
- package/docs-dev/demos/pull-quote/index.html +850 -327
- package/docs-dev/demos/rule/index.html +863 -328
- package/docs-dev/demos/scroll-slider/index.html +72 -106
- package/docs-dev/demos/scrollpoints/index.html +851 -328
- package/docs-dev/demos/slider/index.html +12 -4
- package/docs-dev/demos/spoke-spinner/index.html +850 -327
- package/docs-dev/demos/{list-inline.1 → sticky-list}/index.html +883 -357
- package/docs-dev/demos/tabs/index.html +886 -327
- package/docs-dev/demos/tag/index.html +850 -327
- package/docs-dev/demos/theme-toggle/index.html +5309 -0
- package/docs-dev/demos/tile-grid-overlay/index.html +12 -4
- package/docs-dev/demos/tiles/index.html +850 -327
- package/docs-dev/demos/tooltip/index.html +850 -327
- package/docs-dev/guide/building-stylesheet/index.html +850 -327
- package/docs-dev/guide/developing-ulu-scss-module/index.html +850 -327
- package/docs-dev/guide/index.html +850 -327
- package/docs-dev/index.html +850 -327
- package/docs-dev/javascript/events/index.html +847 -326
- package/docs-dev/javascript/index.html +850 -327
- package/docs-dev/javascript/settings/index.html +5430 -0
- package/docs-dev/javascript/ui-breakpoints/index.html +862 -341
- package/docs-dev/javascript/ui-collapsible/index.html +847 -326
- package/docs-dev/javascript/ui-details-group/index.html +5352 -0
- package/docs-dev/javascript/ui-dialog/index.html +879 -343
- package/docs-dev/javascript/ui-flipcard/index.html +908 -331
- package/docs-dev/javascript/ui-grid/index.html +857 -362
- package/docs-dev/javascript/ui-modal-builder/index.html +1047 -386
- package/docs-dev/javascript/ui-overflow-scroller/index.html +847 -326
- package/docs-dev/javascript/ui-overflow-scroller-pager/index.html +847 -326
- package/docs-dev/javascript/ui-page/index.html +847 -326
- package/docs-dev/javascript/ui-popover/index.html +855 -338
- package/docs-dev/javascript/ui-print/index.html +847 -334
- package/docs-dev/javascript/ui-print-details/index.html +847 -326
- package/docs-dev/javascript/ui-programmatic-modal/index.html +847 -326
- package/docs-dev/javascript/ui-proxy-click/index.html +934 -328
- package/docs-dev/javascript/ui-resizer/index.html +847 -326
- package/docs-dev/javascript/ui-scroll-slider/index.html +885 -332
- package/docs-dev/javascript/ui-scrollpoint/index.html +853 -339
- package/docs-dev/javascript/ui-slider/index.html +1043 -331
- package/docs-dev/javascript/ui-tabs/index.html +858 -374
- package/docs-dev/javascript/ui-theme-toggle/index.html +5440 -0
- package/docs-dev/javascript/ui-tooltip/index.html +854 -337
- package/docs-dev/javascript/utils-class-logger/index.html +847 -326
- package/docs-dev/javascript/utils-css/index.html +5254 -0
- package/docs-dev/javascript/utils-dom/index.html +887 -446
- package/docs-dev/javascript/utils-file-save/index.html +847 -326
- package/docs-dev/javascript/utils-floating-ui/index.html +847 -326
- package/docs-dev/javascript/utils-id/index.html +847 -326
- package/docs-dev/javascript/utils-pause-youtube-video/index.html +847 -326
- package/docs-dev/javascript/utils-system/index.html +5557 -0
- package/docs-dev/sass/base/color/index.html +847 -326
- package/docs-dev/sass/base/elements/index.html +847 -326
- package/docs-dev/sass/base/index/index.html +847 -326
- package/docs-dev/sass/base/index.html +850 -327
- package/docs-dev/sass/base/keyframes/index.html +847 -326
- package/docs-dev/sass/base/layout/index.html +847 -326
- package/docs-dev/sass/base/normalize/index.html +847 -326
- package/docs-dev/sass/base/print/index.html +847 -326
- package/docs-dev/sass/base/root/index.html +847 -326
- package/docs-dev/sass/base/typography/index.html +847 -326
- package/docs-dev/sass/components/accordion/index.html +866 -338
- package/docs-dev/sass/components/adaptive-spacing/index.html +847 -326
- package/docs-dev/sass/components/badge/index.html +869 -337
- package/docs-dev/sass/components/basic-hero/index.html +5415 -0
- package/docs-dev/sass/components/button/index.html +847 -326
- package/docs-dev/sass/components/button-verbose/index.html +933 -337
- package/docs-dev/sass/components/callout/index.html +958 -418
- package/docs-dev/sass/components/captioned-figure/index.html +970 -334
- package/docs-dev/sass/components/card/index.html +939 -346
- package/docs-dev/sass/components/card-grid/index.html +847 -326
- package/docs-dev/sass/components/counter-list/index.html +5497 -0
- package/docs-dev/sass/components/css-icon/index.html +864 -336
- package/docs-dev/sass/components/data-grid/index.html +868 -340
- package/docs-dev/sass/components/data-table/index.html +1063 -352
- package/docs-dev/sass/components/fill-context/index.html +847 -326
- package/docs-dev/sass/components/flipcard/index.html +888 -336
- package/docs-dev/sass/components/flipcard-grid/index.html +847 -326
- package/docs-dev/sass/components/form-theme/index.html +1063 -446
- package/docs-dev/sass/components/hero/index.html +903 -334
- package/docs-dev/sass/components/horizontal-rule/index.html +847 -326
- package/docs-dev/sass/components/image-grid/index.html +847 -326
- package/docs-dev/sass/components/index/index.html +860 -336
- package/docs-dev/sass/components/index.html +850 -327
- package/docs-dev/sass/components/links/index.html +847 -326
- package/docs-dev/sass/components/list-inline/index.html +847 -326
- package/docs-dev/sass/components/list-lines/index.html +847 -326
- package/docs-dev/sass/components/list-ordered/index.html +847 -326
- package/docs-dev/sass/components/list-unordered/index.html +847 -326
- package/docs-dev/sass/components/menu-stack/index.html +881 -347
- package/docs-dev/sass/components/modal/index.html +891 -342
- package/docs-dev/sass/components/nav-strip/index.html +855 -334
- package/docs-dev/sass/components/overlay-section/index.html +855 -334
- package/docs-dev/sass/components/pager/index.html +847 -326
- package/docs-dev/sass/components/placeholder-block/index.html +847 -326
- package/docs-dev/sass/components/popover/index.html +904 -347
- package/docs-dev/sass/components/pull-quote/index.html +859 -338
- package/docs-dev/sass/components/ratio-box/index.html +855 -334
- package/docs-dev/sass/components/rule/index.html +848 -327
- package/docs-dev/sass/components/scroll-slider/index.html +855 -346
- package/docs-dev/sass/components/skip-link/index.html +847 -326
- package/docs-dev/sass/components/slider/index.html +897 -388
- package/docs-dev/sass/components/spoke-spinner/index.html +849 -328
- package/docs-dev/sass/components/sticky-list/index.html +5633 -0
- package/docs-dev/sass/components/tabs/index.html +872 -336
- package/docs-dev/sass/components/tag/index.html +849 -328
- package/docs-dev/sass/components/tile-button/index.html +847 -326
- package/docs-dev/sass/components/tile-grid/index.html +847 -326
- package/docs-dev/sass/components/tile-grid-overlay/index.html +847 -326
- package/docs-dev/sass/components/vignette/index.html +861 -334
- package/docs-dev/sass/components/wysiwyg/index.html +847 -326
- package/docs-dev/sass/core/breakpoint/index.html +931 -358
- package/docs-dev/sass/core/button/index.html +847 -326
- package/docs-dev/sass/core/color/index.html +1019 -366
- package/docs-dev/sass/core/cssvar/index.html +847 -326
- package/docs-dev/sass/core/element/index.html +1108 -381
- package/docs-dev/sass/core/index.html +847 -326
- package/docs-dev/sass/core/layout/index.html +903 -363
- package/docs-dev/sass/core/path/index.html +847 -326
- package/docs-dev/sass/core/selector/index.html +847 -326
- package/docs-dev/sass/core/typography/index.html +847 -326
- package/docs-dev/sass/core/units/index.html +857 -330
- package/docs-dev/sass/core/utils/index.html +2104 -476
- package/docs-dev/sass/helpers/color/index.html +847 -326
- package/docs-dev/sass/helpers/display/index.html +848 -327
- package/docs-dev/sass/helpers/index/index.html +847 -326
- package/docs-dev/sass/helpers/index.html +850 -327
- package/docs-dev/sass/helpers/print/index.html +759 -298
- package/docs-dev/sass/helpers/typography/index.html +847 -326
- package/docs-dev/sass/helpers/units/index.html +847 -326
- package/docs-dev/sass/helpers/utilities/index.html +849 -328
- package/docs-dev/sass/index.html +850 -327
- package/js/index.js +1 -0
- package/js/settings.js +95 -0
- package/js/ui/breakpoints.js +19 -16
- package/js/ui/collapsible.js +8 -1
- package/js/ui/details-group.js +112 -0
- package/js/ui/dialog.js +85 -42
- package/js/ui/dialog.todo +2 -36
- package/js/ui/flipcard.js +37 -57
- package/js/ui/grid.js +15 -13
- package/js/ui/index.js +1 -0
- package/js/ui/modal-builder.js +105 -59
- package/js/ui/overflow-scroller.js +6 -4
- package/js/ui/page.js +2 -2
- package/js/ui/popover.js +38 -38
- package/js/ui/print.js +16 -25
- package/js/ui/programmatic-modal.js +9 -3
- package/js/ui/proxy-click.js +50 -36
- package/js/ui/scroll-slider.js +24 -30
- package/js/ui/scrollpoint.js +29 -64
- package/js/ui/slider.js +108 -63
- package/js/ui/tabs.js +23 -36
- package/js/ui/theme-toggle.js +332 -94
- package/js/ui/tooltip.js +27 -32
- package/js/utils/css.js +13 -0
- package/js/utils/dom.js +23 -64
- package/js/utils/font-awesome.js +18 -0
- package/js/utils/index.js +2 -1
- package/js/utils/system.js +155 -0
- package/package.json +23 -8
- package/scss/README.md +4 -0
- package/scss/_breakpoint.scss +38 -4
- package/scss/_color.scss +40 -9
- package/scss/_element.scss +108 -2
- package/scss/_layout.scss +7 -8
- package/scss/_units.scss +3 -2
- package/scss/_utils.scss +380 -16
- package/scss/components/README.todos +14 -0
- package/scss/components/_accordion.scss +33 -19
- package/scss/components/_badge.scss +23 -4
- package/scss/components/_basic-hero.scss +112 -0
- package/scss/components/_button-verbose.scss +100 -18
- package/scss/components/_callout.scss +125 -78
- package/scss/components/_captioned-figure.scss +17 -0
- package/scss/components/_card-grid.scss +1 -1
- package/scss/components/_card.scss +246 -74
- package/scss/components/_counter-list.scss +151 -0
- package/scss/components/_css-icon.scss +25 -21
- package/scss/components/_data-grid.scss +55 -9
- package/scss/components/_data-table.scss +39 -3
- package/scss/components/_flipcard.scss +8 -3
- package/scss/components/_form-theme.scss +119 -108
- package/scss/components/_hero.scss +12 -10
- package/scss/components/_index.scss +18 -0
- package/scss/components/_menu-stack.scss +42 -26
- package/scss/components/_modal.scss +42 -26
- package/scss/components/_nav-strip.scss +2 -0
- package/scss/components/_overlay-section.scss +2 -5
- package/scss/components/_popover.scss +165 -64
- package/scss/components/_pull-quote.scss +13 -13
- package/scss/components/_ratio-box.scss +2 -5
- package/scss/components/_rule.scss +1 -0
- package/scss/components/_scroll-slider.scss +1 -5
- package/scss/components/_slider.scss +49 -72
- package/scss/components/_spoke-spinner.scss +2 -2
- package/scss/components/_sticky-list.scss +206 -0
- package/scss/components/_tabs.scss +22 -4
- package/scss/components/_vignette.scss +3 -5
- package/scss/helpers/_display.scss +15 -18
- package/scss/helpers/_print.scss +12 -7
- package/scss/helpers/_utilities.scss +42 -32
- package/types/index.d.ts +1 -0
- package/types/settings.d.ts +66 -0
- package/types/settings.d.ts.map +1 -0
- package/types/ui/breakpoints.d.ts +14 -14
- package/types/ui/breakpoints.d.ts.map +1 -1
- package/types/ui/collapsible.d.ts.map +1 -1
- package/types/ui/details-group.d.ts +38 -0
- package/types/ui/details-group.d.ts.map +1 -0
- package/types/ui/dialog.d.ts +20 -14
- package/types/ui/dialog.d.ts.map +1 -1
- package/types/ui/flipcard.d.ts +16 -10
- package/types/ui/flipcard.d.ts.map +1 -1
- package/types/ui/grid.d.ts +4 -6
- package/types/ui/grid.d.ts.map +1 -1
- package/types/ui/index.d.ts +2 -1
- package/types/ui/modal-builder.d.ts +113 -11
- package/types/ui/modal-builder.d.ts.map +1 -1
- package/types/ui/overflow-scroller.d.ts +2 -2
- package/types/ui/overflow-scroller.d.ts.map +1 -1
- package/types/ui/popover.d.ts +6 -7
- package/types/ui/popover.d.ts.map +1 -1
- package/types/ui/print.d.ts +0 -4
- package/types/ui/print.d.ts.map +1 -1
- package/types/ui/programmatic-modal.d.ts.map +1 -1
- package/types/ui/proxy-click.d.ts +19 -3
- package/types/ui/proxy-click.d.ts.map +1 -1
- package/types/ui/scroll-slider.d.ts +5 -7
- package/types/ui/scroll-slider.d.ts.map +1 -1
- package/types/ui/scrollpoint.d.ts +3 -8
- package/types/ui/scrollpoint.d.ts.map +1 -1
- package/types/ui/slider.d.ts +33 -14
- package/types/ui/slider.d.ts.map +1 -1
- package/types/ui/tabs.d.ts +6 -8
- package/types/ui/tabs.d.ts.map +1 -1
- package/types/ui/theme-toggle.d.ts +51 -7
- package/types/ui/theme-toggle.d.ts.map +1 -1
- package/types/ui/tooltip.d.ts +3 -5
- package/types/ui/tooltip.d.ts.map +1 -1
- package/types/utils/css.d.ts +11 -0
- package/types/utils/css.d.ts.map +1 -0
- package/types/utils/dom.d.ts +12 -32
- package/types/utils/dom.d.ts.map +1 -1
- package/types/utils/font-awesome.d.ts +5 -0
- package/types/utils/font-awesome.d.ts.map +1 -0
- package/types/utils/index.d.ts +2 -1
- package/types/utils/system.d.ts +113 -0
- package/types/utils/system.d.ts.map +1 -0
package/js/ui/theme-toggle.js
CHANGED
|
@@ -1,129 +1,367 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module ui/theme-toggle
|
|
3
|
+
*/
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
import { ComponentInitializer } from "../utils/system.js";
|
|
4
6
|
import { getName } from "../events/index.js";
|
|
7
|
+
import { resolveClasses } from "../utils/dom.js";
|
|
8
|
+
import { hasRequiredProps } from "@ulu/utils/object.js";
|
|
9
|
+
import { getElements } from "@ulu/utils/browser/dom.js";
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Theme Toggle Component Initializer
|
|
13
|
+
*/
|
|
14
|
+
export const initializer = new ComponentInitializer({
|
|
15
|
+
type: "theme-toggle",
|
|
16
|
+
baseAttribute: "data-ulu-theme-toggle"
|
|
17
|
+
});
|
|
11
18
|
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
const attrSelectorLabel = initializer.attributeSelector("label");
|
|
20
|
+
const attrSelectorIcon = initializer.attributeSelector("icon");
|
|
21
|
+
const attrRemote = initializer.getAttribute("remote");
|
|
22
|
+
const attrInit = initializer.getAttribute("init");
|
|
23
|
+
const attrState = initializer.getAttribute("state");
|
|
24
|
+
|
|
25
|
+
// Utils for selecting things based on attributes
|
|
26
|
+
const queryRemotes = group => document.querySelectorAll(
|
|
27
|
+
`[${ attrRemote }="${ group }"]`
|
|
28
|
+
);
|
|
29
|
+
const queryRemotesInitial = group => document.querySelectorAll(
|
|
30
|
+
`[${ attrRemote }="${ group }"]:not([${ attrInit }])`
|
|
31
|
+
);
|
|
32
|
+
const requiredToggleProps = ["target"];
|
|
33
|
+
const checkToggleProps = hasRequiredProps(requiredToggleProps);
|
|
34
|
+
const when = (cond, fn) => cond ? fn() : null; // Consider adding as util
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Default Options
|
|
38
|
+
* - Can be overridden using data-attributes
|
|
39
|
+
*/
|
|
40
|
+
export const defaults = {
|
|
41
|
+
/**
|
|
42
|
+
* Object of each theme that should be toggle/cycled through
|
|
43
|
+
*/
|
|
44
|
+
themes: {
|
|
45
|
+
light: {
|
|
46
|
+
label: "Light",
|
|
47
|
+
value: "light",
|
|
48
|
+
iconClass: "fas fa-moon",
|
|
49
|
+
targetClass: "theme-light",
|
|
50
|
+
mediaQuery: "(prefers-color-scheme: light)"
|
|
51
|
+
},
|
|
52
|
+
dark: {
|
|
53
|
+
label: "Dark",
|
|
54
|
+
iconClass: "fas fa-sun",
|
|
55
|
+
targetClass: "theme-dark",
|
|
56
|
+
mediaQuery: "(prefers-color-scheme: dark)"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
/**
|
|
60
|
+
* Required this is the element(s) that should be changed by a specific toggle
|
|
61
|
+
* - The element should have data-ulu-theme-toggle-target="SOME_IDENTIFIER"
|
|
62
|
+
*/
|
|
63
|
+
target: "body",
|
|
64
|
+
/**
|
|
65
|
+
* Optional group to link remote toggles (toggles that follow the main one and can toggle too)
|
|
66
|
+
*/
|
|
67
|
+
group: null,
|
|
68
|
+
/**
|
|
69
|
+
* Optional callback to do something when the state changes
|
|
70
|
+
*/
|
|
71
|
+
onChange(_ctx) {},
|
|
72
|
+
/**
|
|
73
|
+
* The initial state for this component
|
|
74
|
+
* - May be overridden by saved preference or media query if options are enabled
|
|
75
|
+
*/
|
|
76
|
+
initialState: "light",
|
|
77
|
+
/**
|
|
78
|
+
* Check the OS systems user preference via 'preferenceQuery' option
|
|
79
|
+
*/
|
|
80
|
+
checkMediaQuery: false,
|
|
81
|
+
/**
|
|
82
|
+
* Will store the preference in local storage so it persists between page loads
|
|
83
|
+
*/
|
|
84
|
+
savePreference: false,
|
|
85
|
+
/**
|
|
86
|
+
* The key that will be used to store the preference in local storage
|
|
87
|
+
* - This will be used as prefix in combination with group if defined
|
|
88
|
+
*/
|
|
89
|
+
storagePrefix: "ulu-theme-",
|
|
90
|
+
/**
|
|
91
|
+
* Output information to console for debugging
|
|
92
|
+
*/
|
|
93
|
+
debug: false
|
|
23
94
|
};
|
|
24
95
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
96
|
+
|
|
97
|
+
// Current default objects (user can override these)
|
|
98
|
+
let currentDefaults = { ...defaults };
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {Object} options Change options used as default for dialogs, can then be overridden by data attribute settings on element
|
|
102
|
+
*/
|
|
103
|
+
export function setDefaults(options) {
|
|
104
|
+
currentDefaults = Object.assign({}, currentDefaults, options);
|
|
105
|
+
}
|
|
29
106
|
|
|
30
107
|
/**
|
|
31
108
|
* Initialize everything in document
|
|
32
109
|
* - This will only initialize elements once, it is safe to call on page changes
|
|
33
110
|
*/
|
|
34
111
|
export function init() {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
112
|
+
initializer.init({
|
|
113
|
+
events: ["pageModified"],
|
|
114
|
+
withData: true,
|
|
115
|
+
setup({ element, data, initialize }) {
|
|
116
|
+
setupToggle(element, data);
|
|
117
|
+
initialize();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
41
120
|
}
|
|
42
121
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Sets up a single toggle
|
|
124
|
+
* @param {HTMLElement} toggle A toggle to be setup
|
|
125
|
+
*/
|
|
126
|
+
export function setupToggle(toggle, userOptions) {
|
|
127
|
+
const options = Object.assign({}, defaults, userOptions);
|
|
128
|
+
|
|
129
|
+
if (!checkToggleProps(options)) {
|
|
130
|
+
console.error(`Missing a required option: ${ requiredToggleProps.join(", ") }`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const group = options.group;
|
|
135
|
+
const ctx = { toggle, options };
|
|
136
|
+
const initialKey = resolveInitial(options);
|
|
137
|
+
|
|
138
|
+
if (!initialKey) {
|
|
139
|
+
console.error("Unable to resolve initial key");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
setState(initialKey, ctx);
|
|
144
|
+
|
|
145
|
+
toggle.addEventListener("click", onToggleClick);
|
|
146
|
+
|
|
147
|
+
// Remotes listeners are attached initially and then we also
|
|
148
|
+
// update them vs toggles which would be updated by the main pageModified
|
|
149
|
+
// event in init
|
|
150
|
+
attachRemotes();
|
|
151
|
+
document.addEventListener(getName("pageModified"), attachRemotes);
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Instance function to get the next theme in cycle
|
|
155
|
+
*/
|
|
156
|
+
function toggleState(event) {
|
|
157
|
+
const targets = getElements(options.target);
|
|
158
|
+
const lastKey = targets[0].dataset.uluThemeToggleState;
|
|
159
|
+
const key = getNextThemeKey(lastKey, options);
|
|
160
|
+
if (!key) {
|
|
161
|
+
console.error("Issue getting next theme key");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
setState(key, { ...ctx, event });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Handler for click for both toggle and remote toggles
|
|
169
|
+
*/
|
|
170
|
+
function onToggleClick(event) {
|
|
171
|
+
toggleState(event);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Utility to attach remote handlers
|
|
176
|
+
* - Used initially and when page is modified
|
|
177
|
+
*/
|
|
178
|
+
function attachRemotes() {
|
|
179
|
+
if (!group) return;
|
|
180
|
+
const remotes = queryRemotesInitial(group);
|
|
181
|
+
remotes.forEach(remote => {
|
|
182
|
+
remote.addEventListener("click", onToggleClick);
|
|
183
|
+
initializer.initializeElement(remote);
|
|
54
184
|
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* This only cleans up remotes that are still in DOM
|
|
189
|
+
* - For ones that have been removed we don't store any references to them
|
|
190
|
+
*/
|
|
191
|
+
function cleanupRemotes() {
|
|
192
|
+
if (!group) return;
|
|
193
|
+
const remotes = queryRemotesInitial(group);
|
|
194
|
+
remotes.forEach(remote => {
|
|
195
|
+
remote.removeEventListener("click", onToggleClick);
|
|
196
|
+
remote.removeAttribute(attrInit, "");
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Function to cleanup listeners and remove init attributes
|
|
202
|
+
*/
|
|
203
|
+
function destroy() {
|
|
204
|
+
toggle.removeEventListener("click", onToggleClick);
|
|
205
|
+
toggle.removeAttribute(attrInit, "");
|
|
206
|
+
cleanupRemotes();
|
|
207
|
+
document.removeEventListener(getName("pageModified"), attachRemotes);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
destroy,
|
|
212
|
+
toggle,
|
|
213
|
+
options,
|
|
214
|
+
toggleState,
|
|
215
|
+
setState(themeKey) {
|
|
216
|
+
setState(themeKey, ctx);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
58
219
|
}
|
|
59
220
|
|
|
221
|
+
|
|
222
|
+
|
|
60
223
|
/**
|
|
61
|
-
*
|
|
62
|
-
* @param {Element} body Sets up initial theme on load based on user preference.
|
|
224
|
+
* Change the state of target/toggle
|
|
63
225
|
*/
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
226
|
+
function setState(key, ctx) {
|
|
227
|
+
if (!key) {
|
|
228
|
+
console.error("Missing key");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const { toggle, options } = ctx;
|
|
233
|
+
const { themes, group } = options;
|
|
234
|
+
const elements = {
|
|
235
|
+
targets: getElements(options.target),
|
|
236
|
+
toggles: [toggle, ...(group ? queryRemotes(group) : [])]
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
if (!elements.targets.length || !elements.toggles.length) {
|
|
240
|
+
console.error("Issue setting state, couldn't find needed elements", elements);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const theme = themes[key];
|
|
245
|
+
const otherThemes = getOtherThemes(key, themes);
|
|
246
|
+
const stateCtx = {
|
|
247
|
+
...ctx,
|
|
248
|
+
key,
|
|
249
|
+
elements,
|
|
250
|
+
theme,
|
|
251
|
+
otherThemes
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
if (options.debug) {
|
|
255
|
+
initializer.log("Set state context", stateCtx);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Prepare classes to remove
|
|
259
|
+
const otherTargetClasses = concatThemeClasses(otherThemes, "targetClass");
|
|
260
|
+
const otherIconClasses = concatThemeClasses(otherThemes, "iconClass");
|
|
261
|
+
|
|
262
|
+
// Update all targets
|
|
263
|
+
elements.targets.forEach(element => {
|
|
264
|
+
element.setAttribute(attrState, key);
|
|
265
|
+
element.classList.remove(...otherTargetClasses);
|
|
266
|
+
element.classList.add(...resolveClasses(theme.targetClass));
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Update all toggles and inner children
|
|
270
|
+
elements.toggles.forEach(element => {
|
|
271
|
+
const label = element.querySelector(attrSelectorLabel);
|
|
272
|
+
const icon = element.querySelector(attrSelectorIcon);
|
|
273
|
+
if (label) {
|
|
274
|
+
label.textContent = theme.label;
|
|
275
|
+
}
|
|
276
|
+
if (icon) {
|
|
277
|
+
icon.classList.remove(...otherIconClasses);
|
|
278
|
+
icon.classList.add(...resolveClasses(theme.iconClass));
|
|
279
|
+
}
|
|
280
|
+
element.setAttribute(attrState, key);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Optional callback if user want to set other things (ie. data-theme or something)
|
|
284
|
+
if (options.onChange) {
|
|
285
|
+
options.onChange(stateCtx);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (options.savePreference) {
|
|
289
|
+
localStorage.setItem(getStorageKey(options), key);
|
|
290
|
+
}
|
|
74
291
|
}
|
|
75
292
|
|
|
76
293
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
294
|
+
* Function determines what the initial state is
|
|
295
|
+
* - Check OS preference, saved preference, or initialState depending on options
|
|
296
|
+
* @return {String} The resolved initial theme's key
|
|
79
297
|
*/
|
|
80
|
-
function
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
298
|
+
function resolveInitial(options) {
|
|
299
|
+
const { savePreference, checkMediaQuery, themes, initialState } = options;
|
|
300
|
+
const storageKey = getStorageKey(options);
|
|
301
|
+
const saved = when(savePreference, () => localStorage.getItem(storageKey));
|
|
302
|
+
const mediaQueryPreference = when(checkMediaQuery, () => getMatchingThemeQuery(themes));
|
|
303
|
+
const resolved = saved || mediaQueryPreference || initialState;
|
|
304
|
+
|
|
305
|
+
if (options.debug) {
|
|
306
|
+
initializer.log("Preference Saved", saved);
|
|
307
|
+
initializer.log("Media Query Preference", mediaQueryPreference);
|
|
308
|
+
initializer.log("Initial State:", initialState);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!resolved) {
|
|
312
|
+
initializer.logError("Failed to resolve initial theme (pass 'initialState' to options)");
|
|
89
313
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
localStorage.setItem("data-theme", newTheme);
|
|
93
|
-
currentTheme = newTheme;
|
|
94
|
-
changeIcons();
|
|
314
|
+
|
|
315
|
+
return resolved;
|
|
95
316
|
}
|
|
96
317
|
|
|
97
318
|
/**
|
|
98
|
-
*
|
|
99
|
-
* @
|
|
100
|
-
* @param {Element} context Used to find the icons.
|
|
319
|
+
* Check each theme for a matching media query
|
|
320
|
+
* @return {String} Matching theme key
|
|
101
321
|
*/
|
|
102
|
-
function
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
icon.classList = options.darkIcon;
|
|
107
|
-
} else {
|
|
108
|
-
icon.classList = options.lightIcon;
|
|
322
|
+
function getMatchingThemeQuery(themes) {
|
|
323
|
+
const found = Object.entries(themes).find(([_key, theme]) => {
|
|
324
|
+
if (theme.mediaQuery) {
|
|
325
|
+
return window.matchMedia(theme.mediaQuery).matches;
|
|
109
326
|
}
|
|
110
327
|
});
|
|
328
|
+
// Return just the key
|
|
329
|
+
return found ? found[0] : null;
|
|
111
330
|
}
|
|
112
331
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Get the next key in the themes based on the currentKey
|
|
334
|
+
*/
|
|
335
|
+
function getNextThemeKey(activeKey, options) {
|
|
336
|
+
const { themes } = options;
|
|
337
|
+
const keys = Object.keys(themes);
|
|
338
|
+
const index = keys.findIndex(theme => theme === activeKey);
|
|
339
|
+
// If not found return first, else calculate next index (wrapping)
|
|
340
|
+
const nextIndex = index === -1 ? 0 : (index + 1) % keys.length;
|
|
341
|
+
return keys[nextIndex];
|
|
120
342
|
}
|
|
121
343
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Get all other theme object except the current
|
|
346
|
+
*/
|
|
347
|
+
function getOtherThemes(currentKey, themes) {
|
|
348
|
+
const all = Object.entries(themes);
|
|
349
|
+
return all.filter(([key]) => key !== currentKey).map(([_key, value]) => value);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Concatenates multiple class properties into one array
|
|
354
|
+
*/
|
|
355
|
+
function concatThemeClasses(themes, property) {
|
|
356
|
+
return themes.reduce((acc, theme) => {
|
|
357
|
+
return acc.concat(resolveClasses(theme[property]));
|
|
358
|
+
}, []);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Creates the storage key (either prefix or prefix with group name)
|
|
363
|
+
*/
|
|
364
|
+
function getStorageKey(options) {
|
|
365
|
+
const { storagePrefix, group } = options;
|
|
366
|
+
return group ? `${ storagePrefix }${ group }` : storagePrefix;
|
|
129
367
|
}
|
package/js/ui/tooltip.js
CHANGED
|
@@ -2,46 +2,41 @@
|
|
|
2
2
|
* @module ui/tooltip
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { ComponentInitializer } from "../utils/system.js";
|
|
5
6
|
import { getName as getEventName } from "../events/index.js";
|
|
6
7
|
import { createFloatingUi } from "../utils/floating-ui.js";
|
|
7
8
|
import { createElementFromHtml } from "@ulu/utils/browser/dom.js";
|
|
8
9
|
import { logError } from "../utils/class-logger.js";
|
|
9
|
-
import { getDatasetOptionalJson } from "../utils/dom.js";
|
|
10
10
|
import { newId, ensureId } from "../utils/id.js";
|
|
11
11
|
|
|
12
|
-
const attrs = {
|
|
13
|
-
trigger: "data-ulu-tooltip",
|
|
14
|
-
init: "data-ulu-init",
|
|
15
|
-
body: "data-ulu-tooltip-display-body",
|
|
16
|
-
arrow: "data-ulu-tooltip-arrow"
|
|
17
|
-
};
|
|
18
|
-
const attrSelector = key => `[${ attrs[key] }]`;
|
|
19
|
-
const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
|
|
20
12
|
/**
|
|
21
|
-
*
|
|
13
|
+
* Tooltip Component Initializer
|
|
22
14
|
*/
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
15
|
+
export const initializer = new ComponentInitializer({
|
|
16
|
+
type: "tooltip",
|
|
17
|
+
baseAttribute: "data-ulu-tooltip"
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const attrBody = initializer.getAttribute("body");
|
|
21
|
+
const attrSelectorBody = initializer.attributeSelector("body");
|
|
22
|
+
const attrSelectorArrow = initializer.attributeSelector("arrow");
|
|
27
23
|
|
|
28
24
|
/**
|
|
29
|
-
*
|
|
30
|
-
* - Use this manually if needed
|
|
31
|
-
* - Won't setup a popover more than once
|
|
25
|
+
* Initialize default popover
|
|
32
26
|
*/
|
|
33
|
-
export function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
27
|
+
export function init() {
|
|
28
|
+
initializer.init({
|
|
29
|
+
events: ["pageModified"],
|
|
30
|
+
withData: true,
|
|
31
|
+
setup({ element: trigger, data, initialize }) {
|
|
32
|
+
const options = typeof data === "object" ? data : {};
|
|
33
|
+
if (typeof data === "string") {
|
|
34
|
+
options.content = data;
|
|
35
|
+
}
|
|
36
|
+
initialize();
|
|
37
|
+
(new Tooltip({ trigger }, options));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
/**
|
|
@@ -103,7 +98,7 @@ export class Tooltip {
|
|
|
103
98
|
template(_config) {
|
|
104
99
|
return `
|
|
105
100
|
<div class="popover popover--tooltip">
|
|
106
|
-
<div class="popover__inner" ${
|
|
101
|
+
<div class="popover__inner" ${ attrBody }>
|
|
107
102
|
</div>
|
|
108
103
|
<span class="popover__arrow" data-ulu-tooltip-arrow></span>
|
|
109
104
|
</div>
|
|
@@ -177,7 +172,7 @@ export class Tooltip {
|
|
|
177
172
|
createContentElement() {
|
|
178
173
|
const { options } = this;
|
|
179
174
|
const content = createElementFromHtml(options.template(options));
|
|
180
|
-
const body = content.querySelector(
|
|
175
|
+
const body = content.querySelector(attrSelectorBody);
|
|
181
176
|
const innerContent = this.getInnerContent();
|
|
182
177
|
if (options.isHtml) {
|
|
183
178
|
body.innerHTML = innerContent;
|
|
@@ -190,7 +185,7 @@ export class Tooltip {
|
|
|
190
185
|
}
|
|
191
186
|
|
|
192
187
|
this.elements.content = content;
|
|
193
|
-
this.elements.contentArrow = content.querySelector(
|
|
188
|
+
this.elements.contentArrow = content.querySelector(attrSelectorArrow);
|
|
194
189
|
document.body.appendChild(content);
|
|
195
190
|
}
|
|
196
191
|
attachHandlers() {
|
package/js/utils/css.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module utils/css
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generates a CSS custom property name with a given prefix.
|
|
7
|
+
* @param {string} prefix The prefix to apply to the custom property name.
|
|
8
|
+
* @param {string} propertyName The base name of the custom property.
|
|
9
|
+
* @returns {string} The fully formed CSS custom property name (e.g., "--prefix-propertyName").
|
|
10
|
+
*/
|
|
11
|
+
export function getCustomProperty(prefix, propertyName) {
|
|
12
|
+
return `--${prefix}-${propertyName}`;
|
|
13
|
+
}
|
package/js/utils/dom.js
CHANGED
|
@@ -2,53 +2,17 @@
|
|
|
2
2
|
* @module utils/dom
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
export const regexJsonString = /^[{\[][\s\S]*[}\]]$/;
|
|
5
|
+
import { kebabToCamel } from "@ulu/utils/string.js";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
*
|
|
10
|
-
* @param {
|
|
11
|
-
* @
|
|
12
|
-
* @returns {Object} Empty object or JSON object from dataset
|
|
8
|
+
* Converts a data attribute name to its corresponding dataset property name.
|
|
9
|
+
* @param {string} dataAttribute - The data attribute name (e.g., "data-ulu-dialog").
|
|
10
|
+
* @returns {string} - The dataset property name (e.g., "uluDialog").
|
|
13
11
|
*/
|
|
14
|
-
export function
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
return JSON.parse(passed);
|
|
18
|
-
} catch (error) {
|
|
19
|
-
console.error(`Error getting JSON from dataset (${ key }) -- "${ passed }"\n`, element, error);
|
|
20
|
-
return {};
|
|
21
|
-
}
|
|
12
|
+
export function dataAttributeToDatasetKey(attribute) {
|
|
13
|
+
return kebabToCamel(attribute.replace(/^data-/, ""));
|
|
22
14
|
}
|
|
23
15
|
|
|
24
|
-
/**
|
|
25
|
-
* Get an elements JSON dataset value that could potentially just be a single string
|
|
26
|
-
* - If JSON it will return the object else it will return the value directly
|
|
27
|
-
* @param {Node} element
|
|
28
|
-
* @param {String} key key in dataset object for element
|
|
29
|
-
* @returns {Object|String} JSON object or current dataset value (string or empty string if no value)
|
|
30
|
-
*/
|
|
31
|
-
export function getDatasetOptionalJson(element, key) {
|
|
32
|
-
const passed = element.dataset[key];
|
|
33
|
-
if (passed && regexJsonString.test(passed.trim())) {
|
|
34
|
-
return getDatasetJson(element, key);
|
|
35
|
-
} else {
|
|
36
|
-
return passed;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Check if a pointer event x/y was outside an elements bounding box
|
|
42
|
-
*/
|
|
43
|
-
export function wasClickOutside(element, event) {
|
|
44
|
-
const rect = element.getBoundingClientRect();
|
|
45
|
-
return (event.clientY < rect.top || // above
|
|
46
|
-
event.clientY > rect.top + rect.height || // below
|
|
47
|
-
event.clientX < rect.left || // left side
|
|
48
|
-
event.clientX > rect.left + rect.width); // right side
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
16
|
/**
|
|
53
17
|
* Sets up the positional classes that would come from the equal
|
|
54
18
|
* height module. Needs to be rerun by user when layout changes
|
|
@@ -95,28 +59,23 @@ export function setPositionClasses(parent, classes = {
|
|
|
95
59
|
}
|
|
96
60
|
|
|
97
61
|
/**
|
|
98
|
-
*
|
|
99
|
-
* @param {
|
|
100
|
-
* @
|
|
62
|
+
* Resolves a class input (string or array) into a consistent array of class names.
|
|
63
|
+
* @param {string|string[]} input - The class input, which can be a string, an array of strings, or any other value.
|
|
64
|
+
* @returns {string[]} An array of class names. Returns an empty array for invalid or falsy input.
|
|
65
|
+
* @example
|
|
66
|
+
* resolveClassArray("fas fa-check my-class"); // Returns ["fas", "fa-check", "my-class"]
|
|
67
|
+
* resolveClassArray(["another-class", "yet-another-class"]); // Returns ["another-class", "yet-another-class"]
|
|
68
|
+
* resolveClassArray("single-class"); // Returns ["single-class"]
|
|
101
69
|
*/
|
|
102
|
-
export function
|
|
103
|
-
if (typeof
|
|
104
|
-
return
|
|
105
|
-
} else if (
|
|
106
|
-
return
|
|
70
|
+
export function resolveClasses(classes) {
|
|
71
|
+
if (typeof classes === "string") {
|
|
72
|
+
return classes.split(" ").filter(c => c !== ""); // Split and remove empty strings
|
|
73
|
+
} else if (Array.isArray(classes)) {
|
|
74
|
+
return classes;
|
|
75
|
+
} else if (!classes) {
|
|
76
|
+
return [];
|
|
107
77
|
} else {
|
|
108
|
-
console.warn("
|
|
109
|
-
return
|
|
78
|
+
console.warn("resolveClassArray: Invalid class input type.", classes);
|
|
79
|
+
return [];
|
|
110
80
|
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Sets a CSS custom property equal to the scrollbar width
|
|
115
|
-
* @param {Node} element The element that is the child of a scrollabel container
|
|
116
|
-
* @param {Node} container The container that can be scrolled
|
|
117
|
-
* @param {Stirng} propName Custom property to set
|
|
118
|
-
*/
|
|
119
|
-
export function addScrollbarProperty(element = document.body, container = window, propName = "--ulu-scrollbar-width") {
|
|
120
|
-
const scrollbarWidth = container.innerWidth - element.clientWidth;
|
|
121
|
-
element.style.setProperty(propName, `${ scrollbarWidth }px`);
|
|
122
|
-
}
|
|
81
|
+
}
|