@ulu/frontend-vue 0.1.3-beta.2 → 0.1.3-beta.20
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/dist/frontend-vue.css +1 -1
- package/dist/frontend-vue.js +3315 -2668
- package/dist/types/components/collapsible/UluAccordionGroup.vue.d.ts +20 -0
- package/dist/types/components/collapsible/UluAccordionGroup.vue.d.ts.map +1 -1
- package/dist/types/components/elements/UluList.vue.d.ts.map +1 -1
- package/dist/types/components/elements/UluRule.vue.d.ts +19 -0
- package/dist/types/components/elements/UluRule.vue.d.ts.map +1 -0
- package/dist/types/components/forms/UluFormRadio.vue.d.ts +4 -4
- package/dist/types/components/index.d.ts +12 -0
- package/dist/types/components/layout/UluDataGrid.vue.d.ts +16 -1
- package/dist/types/components/layout/UluDataGrid.vue.d.ts.map +1 -1
- package/dist/types/components/layout/UluWhenBreakpoint.vue.d.ts.map +1 -1
- package/dist/types/components/systems/facets/UluFacetsFilterSelects.vue.d.ts +21 -2
- package/dist/types/components/systems/facets/UluFacetsFilterSelects.vue.d.ts.map +1 -1
- package/dist/types/components/systems/facets/UluFacetsSearch.vue.d.ts.map +1 -1
- package/dist/types/components/systems/index.d.ts +4 -0
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchors.vue.d.ts +20 -58
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchors.vue.d.ts.map +1 -1
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsHeadlessSection.vue.d.ts +27 -0
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsHeadlessSection.vue.d.ts.map +1 -0
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNav.vue.d.ts +17 -13
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNav.vue.d.ts.map +1 -1
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue.d.ts +27 -30
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue.d.ts.map +1 -1
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsSection.vue.d.ts +27 -45
- package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsSection.vue.d.ts.map +1 -1
- package/dist/types/components/systems/scroll-anchors/useScrollAnchorSection.d.ts +9 -0
- package/dist/types/components/systems/scroll-anchors/useScrollAnchorSection.d.ts.map +1 -0
- package/dist/types/components/systems/scroll-anchors/useScrollAnchorSections.d.ts +8 -0
- package/dist/types/components/systems/scroll-anchors/useScrollAnchorSections.d.ts.map +1 -0
- package/dist/types/components/systems/scroll-anchors/useScrollAnchors.d.ts +14 -0
- package/dist/types/components/systems/scroll-anchors/useScrollAnchors.d.ts.map +1 -0
- package/dist/types/plugins/popovers/defaults.d.ts.map +1 -1
- package/dist/types/plugins/popovers/index.d.ts.map +1 -1
- package/lib/components/_index.scss +1 -0
- package/lib/components/collapsible/UluAccordionGroup.vue +39 -5
- package/lib/components/collapsible/UluModal.vue +8 -8
- package/lib/components/elements/UluList.vue +3 -4
- package/lib/components/elements/UluRule.vue +49 -0
- package/lib/components/forms/UluFormRadio.vue +2 -2
- package/lib/components/index.js +12 -0
- package/lib/components/layout/UluDataGrid.vue +55 -15
- package/lib/components/layout/UluWhenBreakpoint.vue +14 -4
- package/lib/components/navigation/UluSkipLink.vue +1 -1
- package/lib/components/systems/facets/UluFacetsFilterSelects.vue +34 -7
- package/lib/components/systems/facets/UluFacetsSearch.vue +3 -3
- package/lib/components/systems/facets/UluFacetsSort.vue +3 -3
- package/lib/components/systems/index.js +4 -0
- package/lib/components/systems/scroll-anchors/UluScrollAnchors.vue +46 -145
- package/lib/components/systems/scroll-anchors/UluScrollAnchorsHeadlessSection.vue +50 -0
- package/lib/components/systems/scroll-anchors/UluScrollAnchorsNav.vue +18 -16
- package/lib/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue +100 -89
- package/lib/components/systems/scroll-anchors/UluScrollAnchorsSection.vue +65 -51
- package/lib/components/systems/scroll-anchors/_scroll-anchors-nav-animated.scss +67 -0
- package/lib/components/systems/scroll-anchors/useScrollAnchorSection.js +60 -0
- package/lib/components/systems/scroll-anchors/useScrollAnchorSections.js +15 -0
- package/lib/components/systems/scroll-anchors/useScrollAnchors.js +158 -0
- package/lib/plugins/popovers/defaults.js +10 -10
- package/lib/plugins/popovers/index.js +9 -0
- package/package.json +2 -2
- package/dist/types/components/systems/scroll-anchors/symbols.d.ts +0 -7
- package/dist/types/components/systems/scroll-anchors/symbols.d.ts.map +0 -1
- package/lib/components/systems/scroll-anchors/symbols.js +0 -6
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { onMounted, onUnmounted, nextTick, watch } from "vue";
|
|
2
|
+
import { getScrollParent } from "@ulu/utils/browser/dom.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The main composable that contains the core "engine" for the Scroll Anchors system.
|
|
6
|
+
* It encapsulates the IntersectionObserver logic to track sections and manage their active state.
|
|
7
|
+
* This is intended for advanced use cases where a developer needs to build a custom provider
|
|
8
|
+
* component instead of using the default `UluScrollAnchors`.
|
|
9
|
+
* @param {{sections: object, props: object, emit: Function, componentElRef: object}} options
|
|
10
|
+
*/
|
|
11
|
+
export function useScrollAnchors({ sections, props, emit, componentElRef }) {
|
|
12
|
+
let observer = null;
|
|
13
|
+
|
|
14
|
+
function getSectionIndex(el) {
|
|
15
|
+
return sections.value.findIndex(({ element }) => el === element);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function removeActive(except = null, scrollDirection = 'down') {
|
|
19
|
+
sections.value.forEach(s => {
|
|
20
|
+
if (s !== except) {
|
|
21
|
+
if (s.active) {
|
|
22
|
+
s.inactiveFrom = scrollDirection === 'down' ? 'forward' : 'reverse';
|
|
23
|
+
s.activeFrom = null;
|
|
24
|
+
}
|
|
25
|
+
s.active = false;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createObserver() {
|
|
31
|
+
let lastScrollY = 0;
|
|
32
|
+
let isInitialObservation = true;
|
|
33
|
+
|
|
34
|
+
const onObserve = (entries) => {
|
|
35
|
+
const { root } = observer;
|
|
36
|
+
const currentScrollY = root ? root.scrollTop : document.documentElement.scrollTop || window.scrollY;
|
|
37
|
+
|
|
38
|
+
if (props.debug) {
|
|
39
|
+
console.group("useScrollAnchors: onObserve");
|
|
40
|
+
console.log("Observer:", observer);
|
|
41
|
+
console.log("Last/Current Y:", `${ lastScrollY }/${ currentScrollY }`);
|
|
42
|
+
console.log("Entries:", entries.map(e => ({ el: e.target, is: e.isIntersecting })));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (isInitialObservation && props.firstItemActive) {
|
|
46
|
+
if (props.debug) console.log("Initial observation, respecting `firstItemActive`.");
|
|
47
|
+
isInitialObservation = false;
|
|
48
|
+
lastScrollY = currentScrollY;
|
|
49
|
+
if (props.debug) console.groupEnd();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
isInitialObservation = false;
|
|
53
|
+
|
|
54
|
+
const scrollDirection = currentScrollY > lastScrollY ? 'down' : 'up';
|
|
55
|
+
lastScrollY = currentScrollY;
|
|
56
|
+
if (props.debug) console.log(`Scroll direction: ${scrollDirection}`);
|
|
57
|
+
|
|
58
|
+
const intersectingEntries = entries.filter(entry => entry.isIntersecting);
|
|
59
|
+
if (props.debug) console.log("Intersecting entries:", intersectingEntries.map(e => e.target));
|
|
60
|
+
|
|
61
|
+
if (intersectingEntries.length > 0) {
|
|
62
|
+
intersectingEntries.sort((a, b) => getSectionIndex(a.target) - getSectionIndex(b.target));
|
|
63
|
+
|
|
64
|
+
const targetEntry = scrollDirection === 'down'
|
|
65
|
+
? intersectingEntries[intersectingEntries.length - 1]
|
|
66
|
+
: intersectingEntries[0];
|
|
67
|
+
if (props.debug) console.log("Chosen target entry:", targetEntry.target);
|
|
68
|
+
|
|
69
|
+
const sectionToActivate = sections.value[getSectionIndex(targetEntry.target)];
|
|
70
|
+
|
|
71
|
+
if (sectionToActivate && !sectionToActivate.active) {
|
|
72
|
+
if (props.debug) console.log("Activating section:", sectionToActivate.title);
|
|
73
|
+
nextTick(() => {
|
|
74
|
+
removeActive(sectionToActivate, scrollDirection);
|
|
75
|
+
sectionToActivate.active = true;
|
|
76
|
+
sectionToActivate.inactiveFrom = null;
|
|
77
|
+
sectionToActivate.activeFrom = scrollDirection === 'down' ? 'forward' : 'reverse';
|
|
78
|
+
emit("section-change", { section: sectionToActivate, sections: sections.value, active: true });
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
if (props.debug) console.log("No intersecting entries. Checking edge cases.");
|
|
83
|
+
const activeSection = sections.value.find(s => s.active);
|
|
84
|
+
if (activeSection) {
|
|
85
|
+
const entryForActive = entries.find(e => e.target === activeSection.element);
|
|
86
|
+
if (entryForActive && !entryForActive.isIntersecting) {
|
|
87
|
+
const index = getSectionIndex(entryForActive.target);
|
|
88
|
+
const isFirst = index === 0;
|
|
89
|
+
const isLast = index === sections.value.length - 1;
|
|
90
|
+
if ((isFirst && scrollDirection === 'up' && !props.firstItemActive) || (isLast && scrollDirection === 'down')) {
|
|
91
|
+
if (props.debug) console.log("Deactivating section at edge:", activeSection.title);
|
|
92
|
+
nextTick(() => {
|
|
93
|
+
removeActive(null, scrollDirection);
|
|
94
|
+
emit("section-change", { section: activeSection, sections: sections.value, active: false });
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (props.debug) console.groupEnd();
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
let root = null;
|
|
104
|
+
if (props.observerOptions && props.observerOptions.root) {
|
|
105
|
+
root = props.observerOptions.root;
|
|
106
|
+
} else if (componentElRef.value) {
|
|
107
|
+
root = getScrollParent(componentElRef.value);
|
|
108
|
+
if (root === document.scrollingElement) {
|
|
109
|
+
root = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const finalObserverOptions = {
|
|
114
|
+
...props.observerOptions,
|
|
115
|
+
root
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
observer = new IntersectionObserver(onObserve, finalObserverOptions);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function observeItems() {
|
|
122
|
+
if (!observer) return;
|
|
123
|
+
observer.disconnect();
|
|
124
|
+
sections.value.forEach(({ element }) => {
|
|
125
|
+
if (element) {
|
|
126
|
+
observer.observe(element);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function destroyObserver() {
|
|
132
|
+
if (observer) {
|
|
133
|
+
observer.disconnect();
|
|
134
|
+
observer = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
onMounted(() => {
|
|
139
|
+
if (props.firstItemActive && sections.value.length > 0) {
|
|
140
|
+
const first = sections.value[0];
|
|
141
|
+
if (first) {
|
|
142
|
+
first.active = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
createObserver();
|
|
146
|
+
observeItems();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
onUnmounted(() => {
|
|
150
|
+
destroyObserver();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
watch(() => sections.value.length, () => {
|
|
154
|
+
nextTick(() => {
|
|
155
|
+
observeItems();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
}
|
|
@@ -9,16 +9,7 @@ export default {
|
|
|
9
9
|
* @type {String}
|
|
10
10
|
*/
|
|
11
11
|
directiveName: "ulu-tooltip",
|
|
12
|
-
|
|
13
|
-
* The element that the tooltip should be rendered within
|
|
14
|
-
* - Default bottom of the body (on top of everything)
|
|
15
|
-
* - Doesn't need to be inline for accessibility since tooltips are just an enhancement
|
|
16
|
-
* content displayed within them should be hidden for assistive devices,
|
|
17
|
-
* they are not visible to assistive devices
|
|
18
|
-
* @type {String}
|
|
19
|
-
*/
|
|
20
|
-
tooltipTeleportTo: "body",
|
|
21
|
-
},
|
|
12
|
+
},
|
|
22
13
|
/**
|
|
23
14
|
* Default Popover Options
|
|
24
15
|
*/
|
|
@@ -59,6 +50,15 @@ export default {
|
|
|
59
50
|
* @type {Object}
|
|
60
51
|
*/
|
|
61
52
|
tooltip: {
|
|
53
|
+
/**
|
|
54
|
+
* The element that the tooltip should be rendered within
|
|
55
|
+
* - Default bottom of the body if this is unset
|
|
56
|
+
* - Doesn't need to be inline for accessibility since tooltips are just an enhancement
|
|
57
|
+
* content displayed within them should be hidden for assistive devices,
|
|
58
|
+
* they are not visible to assistive devices
|
|
59
|
+
* @type {String}
|
|
60
|
+
*/
|
|
61
|
+
teleportTo: null,
|
|
62
62
|
/**
|
|
63
63
|
* Optional class binding for tooltip element
|
|
64
64
|
* @type {String|Object|Array}
|
|
@@ -70,6 +70,15 @@ export default function install(app, userOptions = {}) {
|
|
|
70
70
|
config: {},
|
|
71
71
|
});
|
|
72
72
|
const showTooltip = (triggerEl, configObj) => {
|
|
73
|
+
// If a teleport target isn't already specified in the config,
|
|
74
|
+
// try to find a parent dialog to teleport to automatically.
|
|
75
|
+
if (triggerEl && !configObj.teleportTo) {
|
|
76
|
+
const dialog = triggerEl.closest("dialog");
|
|
77
|
+
if (dialog) {
|
|
78
|
+
configObj.teleportTo = dialog;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
// If a tooltip is already active for a different element, remove its attribute.
|
|
74
83
|
if (tooltipState.trigger && tooltipState.trigger !== triggerEl) {
|
|
75
84
|
if (tooltipState.trigger?.removeAttribute) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ulu/frontend-vue",
|
|
3
|
-
"version": "0.1.3-beta.
|
|
3
|
+
"version": "0.1.3-beta.20",
|
|
4
4
|
"description": "A modular and tree-shakeable Vue 3 component library for the Ulu frontend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@floating-ui/vue": "^1.1.8",
|
|
68
|
-
"@ulu/utils": "^0.0.
|
|
68
|
+
"@ulu/utils": "^0.0.33",
|
|
69
69
|
"lodash-es": "^4.17.21"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../../../../../lib/components/systems/scroll-anchors/symbols.js"],"names":[],"mappings":"AAAA;;GAEG;AACH,qCAAiC;AACjC,uCAAmC;AACnC,qCAAiC"}
|