@ulu/frontend-vue 0.1.3-beta.1 → 0.1.3-beta.11

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.
Files changed (58) hide show
  1. package/dist/frontend-vue.css +1 -1
  2. package/dist/frontend-vue.js +3147 -2580
  3. package/dist/types/components/collapsible/UluModal.vue.d.ts.map +1 -1
  4. package/dist/types/components/elements/UluList.vue.d.ts.map +1 -1
  5. package/dist/types/components/elements/UluRule.vue.d.ts +19 -0
  6. package/dist/types/components/elements/UluRule.vue.d.ts.map +1 -0
  7. package/dist/types/components/forms/UluFormRadio.vue.d.ts +4 -4
  8. package/dist/types/components/index.d.ts +12 -0
  9. package/dist/types/components/layout/UluDataGrid.vue.d.ts +16 -1
  10. package/dist/types/components/layout/UluDataGrid.vue.d.ts.map +1 -1
  11. package/dist/types/components/systems/facets/UluFacetsFilterSelects.vue.d.ts +21 -2
  12. package/dist/types/components/systems/facets/UluFacetsFilterSelects.vue.d.ts.map +1 -1
  13. package/dist/types/components/systems/facets/UluFacetsSearch.vue.d.ts.map +1 -1
  14. package/dist/types/components/systems/index.d.ts +4 -0
  15. package/dist/types/components/systems/scroll-anchors/UluScrollAnchors.vue.d.ts +20 -58
  16. package/dist/types/components/systems/scroll-anchors/UluScrollAnchors.vue.d.ts.map +1 -1
  17. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsHeadlessSection.vue.d.ts +24 -0
  18. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsHeadlessSection.vue.d.ts.map +1 -0
  19. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNav.vue.d.ts +17 -13
  20. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNav.vue.d.ts.map +1 -1
  21. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue.d.ts +27 -30
  22. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue.d.ts.map +1 -1
  23. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsSection.vue.d.ts +27 -45
  24. package/dist/types/components/systems/scroll-anchors/UluScrollAnchorsSection.vue.d.ts.map +1 -1
  25. package/dist/types/components/systems/scroll-anchors/useScrollAnchorSection.d.ts +9 -0
  26. package/dist/types/components/systems/scroll-anchors/useScrollAnchorSection.d.ts.map +1 -0
  27. package/dist/types/components/systems/scroll-anchors/useScrollAnchorSections.d.ts +8 -0
  28. package/dist/types/components/systems/scroll-anchors/useScrollAnchorSections.d.ts.map +1 -0
  29. package/dist/types/components/systems/scroll-anchors/useScrollAnchors.d.ts +14 -0
  30. package/dist/types/components/systems/scroll-anchors/useScrollAnchors.d.ts.map +1 -0
  31. package/dist/types/plugins/popovers/defaults.d.ts.map +1 -1
  32. package/dist/types/plugins/popovers/index.d.ts.map +1 -1
  33. package/lib/components/_index.scss +1 -0
  34. package/lib/components/collapsible/UluModal.vue +9 -10
  35. package/lib/components/elements/UluList.vue +3 -4
  36. package/lib/components/elements/UluRule.vue +49 -0
  37. package/lib/components/forms/UluFormRadio.vue +2 -2
  38. package/lib/components/index.js +12 -0
  39. package/lib/components/layout/UluDataGrid.vue +45 -16
  40. package/lib/components/systems/facets/UluFacetsFilterSelects.vue +34 -7
  41. package/lib/components/systems/facets/UluFacetsSearch.vue +3 -3
  42. package/lib/components/systems/facets/UluFacetsSort.vue +3 -3
  43. package/lib/components/systems/index.js +4 -0
  44. package/lib/components/systems/scroll-anchors/UluScrollAnchors.vue +46 -145
  45. package/lib/components/systems/scroll-anchors/UluScrollAnchorsHeadlessSection.vue +36 -0
  46. package/lib/components/systems/scroll-anchors/UluScrollAnchorsNav.vue +18 -16
  47. package/lib/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue +100 -89
  48. package/lib/components/systems/scroll-anchors/UluScrollAnchorsSection.vue +55 -52
  49. package/lib/components/systems/scroll-anchors/_scroll-anchors-nav-animated.scss +66 -0
  50. package/lib/components/systems/scroll-anchors/useScrollAnchorSection.js +56 -0
  51. package/lib/components/systems/scroll-anchors/useScrollAnchorSections.js +15 -0
  52. package/lib/components/systems/scroll-anchors/useScrollAnchors.js +152 -0
  53. package/lib/plugins/popovers/defaults.js +10 -10
  54. package/lib/plugins/popovers/index.js +9 -0
  55. package/package.json +2 -2
  56. package/dist/types/components/systems/scroll-anchors/symbols.d.ts +0 -7
  57. package/dist/types/components/systems/scroll-anchors/symbols.d.ts.map +0 -1
  58. package/lib/components/systems/scroll-anchors/symbols.js +0 -6
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <hr v-if="semantic" class="rule" :class="resolvedModifiers">
3
+ <div v-else class="rule" :class="resolvedModifiers"></div>
4
+ </template>
5
+
6
+ <script setup>
7
+ import { computed } from "vue";
8
+ import { useModifiers } from "../../composables/useModifiers.js";
9
+
10
+ const props = defineProps({
11
+ /**
12
+ * Whether to use the actual <hr> vs superficial <div></div> for rule element
13
+ */
14
+ semantic: Boolean,
15
+ /**
16
+ * Use short modifier
17
+ */
18
+ short: Boolean,
19
+ /**
20
+ * Optional margin (keyword from your rule margins config in frontend)
21
+ */
22
+ margin: String,
23
+ /**
24
+ * Add light modifier (if set, usually exists, this is for convenience, use modifiers prop if you have custom naming)
25
+ */
26
+ light: Boolean,
27
+ /**
28
+ * Add large modifier (if set, usually exists, this is for convenience, use modifiers prop if you have custom naming)
29
+ */
30
+ large: Boolean,
31
+ /**
32
+ * Modifiers (to add any modifier classes based on base class [ie. 'tertiary'])
33
+ */
34
+ modifiers: [String, Array]
35
+ });
36
+
37
+ const internalModifiers = computed(() => ({
38
+ "short" : props.short,
39
+ "light" : props.light,
40
+ "large" : props.large,
41
+ [`margin-${ props.margin }`] : props.margin
42
+ }));
43
+
44
+ const { resolvedModifiers } = useModifiers({
45
+ props,
46
+ baseClass: "rule",
47
+ internal: internalModifiers
48
+ });
49
+ </script>
@@ -27,11 +27,11 @@ defineProps({
27
27
  /**
28
28
  * The value of the selected radio button in the group (for v-model).
29
29
  */
30
- modelValue: String,
30
+ modelValue: [String, Number],
31
31
  /**
32
32
  * The value of this radio button.
33
33
  */
34
- value: String,
34
+ value: [String, Number],
35
35
  /**
36
36
  * The name of the radio button group.
37
37
  */
@@ -4,6 +4,7 @@
4
4
  * - Used in main plugin and bundle exports
5
5
  */
6
6
  export { default as UluAccordion } from './collapsible/UluAccordion.vue';
7
+ export { default as UluAccordionGroup } from './collapsible/UluAccordionGroup.vue';
7
8
  export { default as UluCollapsible } from './collapsible/UluCollapsible.vue';
8
9
  export { default as UluDropdown } from './collapsible/UluDropdown.vue';
9
10
  export { default as UluModal } from './collapsible/UluModal.vue';
@@ -25,6 +26,7 @@ export { default as UluExternalLink } from './elements/UluExternalLink.vue';
25
26
  export { default as UluIcon } from './elements/UluIcon.vue';
26
27
  export { default as UluList } from './elements/UluList.vue';
27
28
  export { default as UluMain } from './elements/UluMain.vue';
29
+ export { default as UluRule } from './elements/UluRule.vue';
28
30
  export { default as UluSpokeSpinner } from './elements/UluSpokeSpinner.vue';
29
31
  export { default as UluTag } from './elements/UluTag.vue';
30
32
  export { default as UluSelectableMenu } from './forms/UluSelectableMenu.vue';
@@ -34,9 +36,19 @@ export { default as UluFormMessage } from './forms/UluFormMessage.vue';
34
36
  export { default as UluFormSelect } from './forms/UluFormSelect.vue';
35
37
  export { default as UluFormText } from './forms/UluFormText.vue';
36
38
  export { default as UluSearchForm } from './forms/UluSearchForm.vue';
39
+ export { default as UluForm } from './forms/UluForm.vue';
40
+ export { default as UluFormActions } from './forms/UluFormActions.vue';
41
+ export { default as UluFormCheckbox } from './forms/UluFormCheckbox.vue';
42
+ export { default as UluFormFieldset } from './forms/UluFormFieldset.vue';
43
+ export { default as UluFormItem } from './forms/UluFormItem.vue';
44
+ export { default as UluFormItemsInline } from './forms/UluFormItemsInline.vue';
45
+ export { default as UluFormRadio } from './forms/UluFormRadio.vue';
46
+ export { default as UluFormRequiredChar } from './forms/UluFormRequiredChar.vue';
47
+ export { default as UluFormTextarea } from './forms/UluFormTextarea.vue';
37
48
  export { default as UluAdaptiveLayout } from './layout/UluAdaptiveLayout.vue';
38
49
  export { default as UluDataGrid } from './layout/UluDataGrid.vue';
39
50
  export { default as UluTitleRail } from './layout/UluTitleRail.vue';
51
+ export { default as UluWhenBreakpoint } from './layout/UluWhenBreakpoint.vue';
40
52
  export { default as UluBreadcrumb } from './navigation/UluBreadcrumb.vue';
41
53
  export { default as UluMenu } from './navigation/UluMenu.vue';
42
54
  export { default as UluMenuStack } from './navigation/UluMenuStack.vue';
@@ -16,26 +16,55 @@
16
16
  -->
17
17
 
18
18
  <template>
19
- <div>
19
+ <component :is="element" ref="rootElement">
20
20
  <slot />
21
- </div>
21
+ </component>
22
22
  </template>
23
23
 
24
- <script>
25
- import { setPositionClasses } from "@ulu/frontend/js/utils/dom.js";
24
+ <script setup>
25
+ import { ref, onMounted, onBeforeUnmount, watch } from "vue";
26
26
  import { debounce } from "@ulu/utils/performance.js";
27
- export default {
28
- name: "UluDataGrid",
29
- async mounted() {
30
- const setClasses = () => setPositionClasses(this.$el);
31
- setClasses();
32
- this.resizeHandler = debounce(setClasses, 200, false, this);
33
- window.addEventListener("resize", this.resizeHandler);
27
+ import { setPositionClasses } from "@ulu/frontend/js/utils/dom.js";
28
+
29
+ const props = defineProps({
30
+ /**
31
+ * The element to use on data-grid container
32
+ */
33
+ element: {
34
+ type: String,
35
+ default: "div"
34
36
  },
35
- beforeUnmount() {
36
- if (this.resizeHandler) {
37
- window.removeEventListener("resize", this.resizeHandler);
38
- }
37
+ /**
38
+ * Tell the component when this grid is actually in a hidden container
39
+ * - When value changes the component will properly update position classes
40
+ */
41
+ hidden: Boolean // New prop from SSR version
42
+ });
43
+
44
+ const rootElement = ref(null); // Ref for the template root element
45
+ let setThisPositionClasses = null; // To store the setPositionClasses function
46
+ let resizeHandler = null; // To store the debounced resize handler
47
+
48
+ onMounted(async () => {
49
+ setThisPositionClasses = () => setPositionClasses(rootElement.value);
50
+ setThisPositionClasses(); // Initial call
51
+ resizeHandler = debounce(setThisPositionClasses, 200, false); // `this` context is not needed in setup
52
+ window.addEventListener("resize", resizeHandler);
53
+ });
54
+
55
+ onBeforeUnmount(() => {
56
+ if (resizeHandler) {
57
+ window.removeEventListener("resize", resizeHandler);
58
+ resizeHandler = null;
59
+ setThisPositionClasses = null; // Clear the function reference
60
+ }
61
+ });
62
+
63
+ // Watcher for the hidden prop
64
+ watch(() => props.hidden, (newVal, oldVal) => {
65
+ // Only run setClasses if it was hidden and now it's not, and the function exists
66
+ if (oldVal && !newVal && setThisPositionClasses) {
67
+ setThisPositionClasses();
39
68
  }
40
- };
69
+ });
41
70
  </script>
@@ -1,26 +1,40 @@
1
1
  <template>
2
- <div class="facets-dropdown-filters">
2
+ <div class="facets-dropdown-filters" :class="classes.container">
3
3
  <div
4
4
  class="facets-dropdown-filters__group"
5
+ :class="classes.group"
5
6
  v-for="group in facets"
6
7
  :key="group.uid"
7
8
  >
8
- <label :for="`facet-dropdown-${group.uid}`" class="facets-dropdown-filters__label">
9
- {{ group.name }}
9
+ <label
10
+ :for="`facet-dropdown-${ group.uid }`"
11
+ class="facets-dropdown-filters__label"
12
+ :class="classes.label"
13
+ >
14
+ <slot name="label">
15
+ {{ group.name }}
16
+ </slot>
10
17
  </label>
11
18
  <select
12
19
  :id="`facet-dropdown-${group.uid}`"
13
20
  class="facets-dropdown-filters__select"
21
+ :class="classes.select"
14
22
  @change="onFilterChange(group, $event)"
15
23
  >
16
- <option value="">All {{ group.name }}s</option>
24
+ <option value="">
25
+ <slot name="optionAll" :group="group">
26
+ All {{ group.name }}s
27
+ </slot>
28
+ </option>
17
29
  <option
18
- v-for="option in group.children"
30
+ v-for="(option, index) in group.children"
19
31
  :key="option.uid"
20
32
  :value="option.uid"
21
33
  :selected="option.selected"
22
34
  >
23
- {{ option.label }}
35
+ <slot name="option" :group="group" :option="option" :index="index">
36
+ {{ option.label }}
37
+ </slot>
24
38
  </option>
25
39
  </select>
26
40
  </div>
@@ -29,12 +43,25 @@
29
43
 
30
44
  <script setup>
31
45
  const props = defineProps({
46
+ /**
47
+ * Facets Array
48
+ */
32
49
  facets: {
33
50
  type: Array,
34
51
  default: () => []
35
- }
52
+ },
53
+ /**
54
+ * Optional classes bindings for all elements { container, group, label, select }
55
+ */
56
+ classes: {
57
+ type: Object,
58
+ default: () => ({})
59
+ },
36
60
  });
37
61
 
62
+ console.log(props);
63
+
64
+
38
65
  const emit = defineEmits(['facet-change']);
39
66
 
40
67
  function onFilterChange(group, event) {
@@ -1,11 +1,11 @@
1
1
  <template>
2
- <div class="facets-search">
3
- <label :class="classes.searchLabel" :for="id">
2
+ <div class="facets-search" :class="classes.container">
3
+ <label :class="classes.label" :for="id">
4
4
  <strong>Search</strong>
5
5
  </label>
6
6
  <input
7
7
  :id="id"
8
- :class="classes.searchInput"
8
+ :class="classes.input"
9
9
  v-model="localValue"
10
10
  type="text"
11
11
  :placeholder="placeholder"
@@ -1,8 +1,8 @@
1
1
  <template>
2
- <div class="facets-sort" :class="classes.sortForm">
2
+ <div class="facets-sort" :class="classes.container">
3
3
  <label
4
4
  :for="sortId"
5
- :class="classes.sortFormLabel"
5
+ :class="classes.label"
6
6
  >
7
7
  <slot>Sort:</slot>
8
8
  </label>
@@ -10,7 +10,7 @@
10
10
  :value="modelValue"
11
11
  @change="emit('update:modelValue', $event.target.value)"
12
12
  :id="sortId"
13
- :class="classes.sortFormSelect"
13
+ :class="classes.select"
14
14
  >
15
15
  <option v-for="(item, key) in sortTypes" :value="key" :key="key">
16
16
  {{ item.text }}
@@ -11,10 +11,14 @@ export { default as UluFacetsSidebarLayout } from './facets/UluFacetsSidebarLayo
11
11
  export { default as UluFacetsSort } from './facets/UluFacetsSort.vue';
12
12
  export { default as UluFacetsList } from './facets/UluFacetsList.vue';
13
13
 
14
+ export { useScrollAnchors } from './scroll-anchors/useScrollAnchors.js';
15
+ export { useScrollAnchorSection } from './scroll-anchors/useScrollAnchorSection.js';
16
+ export { useScrollAnchorSections } from './scroll-anchors/useScrollAnchorSections.js';
14
17
  export { default as UluScrollAnchors } from './scroll-anchors/UluScrollAnchors.vue';
15
18
  export { default as UluScrollAnchorsNav } from './scroll-anchors/UluScrollAnchorsNav.vue';
16
19
  export { default as UluScrollAnchorsNavAnimated } from './scroll-anchors/UluScrollAnchorsNavAnimated.vue';
17
20
  export { default as UluScrollAnchorsSection } from './scroll-anchors/UluScrollAnchorsSection.vue';
21
+ export { default as UluScrollAnchorsHeadlessSection } from './scroll-anchors/UluScrollAnchorsHeadlessSection.vue';
18
22
 
19
23
  export { default as UluShowSkeleton } from './skeleton/UluShowSkeleton.vue';
20
24
  export { default as UluSkeletonContent } from './skeleton/UluSkeletonContent.vue';
@@ -1,153 +1,54 @@
1
- <!-- Version: 0.0.2? (NEED to diff, unsure of changes) -->
2
1
  <template>
3
- <div class="scroll-anchors">
2
+ <div class="scroll-anchors" ref="componentEl">
4
3
  <slot/>
5
4
  </div>
6
5
  </template>
7
6
 
8
- <script>
9
- import { computed } from "vue";
10
- import { SECTIONS, REGISTER, UNREGISTER } from "./symbols.js";
11
- export default {
12
- name: "ScrollAnchors",
13
- emits: ["section-change"],
14
- props: {
15
- firstItemActive: Boolean,
16
- /**
17
- * Observe
18
- */
19
- observerOptions: {
20
- type: Object,
21
- default: () => ({
22
- root: null,
23
- threshhold: [0,1],
24
- rootMargin: "-25% 0px -55% 0px"
25
- // root: null,
26
- // threshhold: [0,1],
27
- // rootMargin: "25% 0px 75% 0px"
28
- })
29
- }
30
- },
31
- data() {
32
- return {
33
- isMounted: false,
34
- sections: [], // Child components will section themselves
35
- };
36
- },
7
+ <script setup>
8
+ import { ref, computed, provide } from "vue";
9
+ import { useScrollAnchors } from "./useScrollAnchors.js";
10
+
11
+ const props = defineProps({
37
12
  /**
38
- * Interface for chil components to register themselves
39
- * - Uses symbols
13
+ * Make the first item active by default on load
40
14
  */
41
- provide() {
42
- return {
43
- [SECTIONS]: computed(() => this.sections),
44
- [REGISTER]: (instance) => {
45
- const { titleId, title } = instance;
46
- const { element } = instance.$refs;
47
- this.sections.push({
48
- instance,
49
- titleId,
50
- title,
51
- element,
52
- active: false
53
- });
54
- this.update();
55
- },
56
- [UNREGISTER]: (instance) => {
57
- const sections = this.sections;
58
- const index = sections.findIndex(r => r.instance === instance);
59
- if (index > -1) {
60
- sections.splice(index, 1);
61
- }
62
- this.update();
63
- },
64
- };
65
- },
66
- methods: {
67
- update() {
68
- if (this.isMounted) {
69
- this.observeItems();
70
- }
71
- },
72
- getSectionIndex(el) {
73
- return this.sections.findIndex(({ element }) => el === element);
74
- },
75
- /**
76
- * Sets up a new observer to watch the section visibility
77
- */
78
- createObserver() {
79
- const { observerOptions, sections, removeActive, firstItemActive } = this;
80
- let lastY = 0;
81
- // Observer callback, basically just sets active state for a given slide
82
- // - isIntersecting will change when the element enters and leaves
83
- const onObserve = (entries) => {
84
- entries.forEach(({ target, isIntersecting }) => {
85
- const index = this.getSectionIndex(target);
86
- const y = target.offsetTop;
87
- const section = sections[index];
88
- const firstExiting = index === 0 && lastY > y;
89
- const lastExiting = index === sections.length - 1 && lastY < y;
90
- if (section) {
91
- this.$nextTick(() => {
92
- if (isIntersecting) {
93
- removeActive(section);
94
- section.active = true;
95
- // Only allow first and last to
96
- } else if (firstExiting && !firstItemActive) {
97
- removeActive();
98
- } else if (lastExiting && section.active) {
99
- removeActive();
100
- }
101
- this.$emit("section-change", {
102
- section,
103
- sections,
104
- active: isIntersecting
105
- });
106
- });
107
- }
108
- });
109
- };
110
- // Add non-reactive prop for removal and changes to targets
111
- this.observer = new IntersectionObserver(onObserve, observerOptions);
112
- },
113
- /**
114
- * Add all slide elements as targets in observer
115
- */
116
- observeItems() {
117
- const { observer, sections } = this;
118
- observer.disconnect();
119
- sections.forEach(({ element }) => {
120
- if (element) {
121
- observer.observe(element);
122
- }
123
- });
124
- },
125
- removeActive(except = null) {
126
- this.sections.forEach(s => {
127
- if (s !== except) {
128
- s.active = false;
129
- }
130
- });
131
- },
132
- /**
133
- * Remove observer and it's internal DOM references (GC)
134
- */
135
- destroyObserver() {
136
- this.observer.disconnect();
137
- this.observer = null;
138
- },
139
- },
140
- mounted() {
141
- const first = this.sections[0];
142
- if (this.firstItemActive && first) {
143
- first.active = true;
144
- }
145
- this.createObserver();
146
- this.observeItems();
147
- this.isMounted = true;
148
- },
149
- unmounted() {
150
- this.destroyObserver();
15
+ firstItemActive: Boolean,
16
+ /**
17
+ * IntersectionObserver options
18
+ * - Defaults: { root: null, threshold: 0, rootMargin: "-25% 0px -55% 0px" }
19
+ * See: https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver
20
+ */
21
+ observerOptions: {
22
+ type: Object,
23
+ default: () => ({
24
+ root: null,
25
+ threshold: 0,
26
+ rootMargin: "-25% 0px -55% 0px"
27
+ })
151
28
  },
152
- };
153
- </script>
29
+ /**
30
+ * Enable debug logging for the IntersectionObserver
31
+ */
32
+ debug: Boolean
33
+ });
34
+
35
+ const emit = defineEmits(["section-change"]);
36
+
37
+ const sections = ref([]);
38
+ const componentEl = ref(null);
39
+
40
+ useScrollAnchors({ sections, props, emit, componentElRef: componentEl });
41
+
42
+ provide('uluScrollAnchorsSections', computed(() => sections.value));
43
+
44
+ provide('uluScrollAnchorsRegister', (section) => {
45
+ sections.value.push(section);
46
+ });
47
+
48
+ provide('uluScrollAnchorsUnregister', (sectionId) => {
49
+ const index = sections.value.findIndex(r => r.id === sectionId);
50
+ if (index > -1) {
51
+ sections.value.splice(index, 1);
52
+ }
53
+ });
54
+ </script>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <component
3
+ :is="element"
4
+ :class="['scroll-anchors__section', { 'is-active': isActive }]"
5
+ ref="sectionRef"
6
+ >
7
+ <slot :isActive="isActive" :titleId="titleId" :section="section" />
8
+ </component>
9
+ </template>
10
+
11
+ <script setup>
12
+ import { useScrollAnchorSection } from "./useScrollAnchorSection";
13
+
14
+ const props = defineProps({
15
+ /**
16
+ * The title of the section, used for navigation and generating a default ID
17
+ */
18
+ title: {
19
+ type: String,
20
+ required: true
21
+ },
22
+ /**
23
+ * A custom ID to use for the section anchor, overriding the auto-generated one
24
+ */
25
+ customTitleId: String,
26
+ /**
27
+ * Element to use
28
+ */
29
+ element: {
30
+ type: String,
31
+ default: "div"
32
+ }
33
+ });
34
+
35
+ const { sectionRef, titleId, isActive, section } = useScrollAnchorSection(props);
36
+ </script>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component
3
- v-if="sections.length"
3
+ v-if="sections && sections.length"
4
4
  :is="element"
5
5
  class="scroll-anchors__nav"
6
6
  >
@@ -13,25 +13,27 @@
13
13
  :class="{ 'is-active' : item.active }"
14
14
  :href="`#${ item.titleId }`"
15
15
  >
16
- {{ item.title }}
16
+ <slot :item="item" :index="index">
17
+ {{ item.title }}
18
+ </slot>
17
19
  </a>
18
20
  </li>
19
21
  </ul>
20
22
  </component>
21
23
  </template>
22
24
 
23
- <script>
24
- import { SECTIONS } from "./symbols.js";
25
- export default {
26
- name: "ScrollAnchorsNav",
27
- inject: {
28
- sections: { from: SECTIONS }
29
- },
30
- props: {
31
- element: {
32
- type: String,
33
- default: "nav"
34
- }
25
+ <script setup>
26
+ import { useScrollAnchorSections } from "./useScrollAnchorSections.js";
27
+
28
+ defineProps({
29
+ /**
30
+ * The HTML element to use for the navigation root
31
+ */
32
+ element: {
33
+ type: String,
34
+ default: "nav"
35
35
  }
36
- };
37
- </script>
36
+ });
37
+
38
+ const sections = useScrollAnchorSections();
39
+ </script>