@ulu/frontend-vue 0.1.0-beta.1

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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/dist/breakpoints-ClT9bfZm.js +211 -0
  4. package/dist/frontend-vue.css +1 -0
  5. package/dist/frontend-vue.js +82 -0
  6. package/dist/frontend-vue.umd.cjs +561 -0
  7. package/dist/index-P5Rwl_Dl.js +7263 -0
  8. package/dist/index.es-HlG3u0J5.js +3134 -0
  9. package/lib/_index.scss +14 -0
  10. package/lib/components/_index.scss +6 -0
  11. package/lib/components/collapsible/UluAccordion.vue +82 -0
  12. package/lib/components/collapsible/UluCollapsibleRegion.vue +278 -0
  13. package/lib/components/collapsible/UluDropdown.vue +42 -0
  14. package/lib/components/collapsible/UluModal.vue +384 -0
  15. package/lib/components/collapsible/UluOverflowPopover.vue +52 -0
  16. package/lib/components/collapsible/UluTab.vue +9 -0
  17. package/lib/components/collapsible/UluTabGroup.vue +31 -0
  18. package/lib/components/collapsible/UluTabList.vue +9 -0
  19. package/lib/components/collapsible/UluTabPanel.vue +9 -0
  20. package/lib/components/collapsible/UluTabPanels.vue +9 -0
  21. package/lib/components/elements/UluAlert.vue +81 -0
  22. package/lib/components/elements/UluBadge.vue +58 -0
  23. package/lib/components/elements/UluBadgeStack.vue +27 -0
  24. package/lib/components/elements/UluButton.vue +161 -0
  25. package/lib/components/elements/UluCallout.vue +30 -0
  26. package/lib/components/elements/UluCard.vue +241 -0
  27. package/lib/components/elements/UluDefinitionList.vue +40 -0
  28. package/lib/components/elements/UluExternalLink.vue +47 -0
  29. package/lib/components/elements/UluIcon.vue +108 -0
  30. package/lib/components/elements/UluList.vue +87 -0
  31. package/lib/components/elements/UluMain.vue +5 -0
  32. package/lib/components/elements/UluSpokeSpinner.vue +25 -0
  33. package/lib/components/elements/UluTag.vue +53 -0
  34. package/lib/components/forms/UluCheckboxMenu.vue +36 -0
  35. package/lib/components/forms/UluFileDisplay.vue +39 -0
  36. package/lib/components/forms/UluFormDropzone.vue +62 -0
  37. package/lib/components/forms/UluFormFile.vue +47 -0
  38. package/lib/components/forms/UluFormMessage.vue +20 -0
  39. package/lib/components/forms/UluFormSelect.vue +37 -0
  40. package/lib/components/forms/UluFormText.vue +32 -0
  41. package/lib/components/forms/UluSearchForm.vue +31 -0
  42. package/lib/components/index.js +54 -0
  43. package/lib/components/layout/UluAdaptiveLayout.vue +11 -0
  44. package/lib/components/layout/UluDataGrid.vue +41 -0
  45. package/lib/components/layout/UluTitleRail.vue +56 -0
  46. package/lib/components/layout/UluWhenBreakpoint.vue +86 -0
  47. package/lib/components/navigation/UluBreadcrumb.vue +72 -0
  48. package/lib/components/navigation/UluMenu.vue +105 -0
  49. package/lib/components/navigation/UluMenuStack.vue +49 -0
  50. package/lib/components/navigation/UluNavStrip.vue +48 -0
  51. package/lib/components/navigation/UluSkipLink.vue +5 -0
  52. package/lib/components/systems/facets/UluFacets.vue +380 -0
  53. package/lib/components/systems/facets/UluFacetsList.vue +39 -0
  54. package/lib/components/systems/facets/UluFacetsSearch.vue +67 -0
  55. package/lib/components/systems/facets/_facets.scss +64 -0
  56. package/lib/components/systems/index.js +17 -0
  57. package/lib/components/systems/scroll-anchors/UluScrollAnchors.vue +152 -0
  58. package/lib/components/systems/scroll-anchors/UluScrollAnchorsNav.vue +37 -0
  59. package/lib/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue +124 -0
  60. package/lib/components/systems/scroll-anchors/UluScrollAnchorsSection.vue +63 -0
  61. package/lib/components/systems/scroll-anchors/symbols.js +6 -0
  62. package/lib/components/systems/skeleton/UluShowSkeleton.vue +13 -0
  63. package/lib/components/systems/skeleton/UluSkeletonContent.vue +60 -0
  64. package/lib/components/systems/skeleton/UluSkeletonMedia.vue +11 -0
  65. package/lib/components/systems/skeleton/UluSkeletonTextInline.vue +9 -0
  66. package/lib/components/systems/slider/UluImageSlideShow.vue +75 -0
  67. package/lib/components/systems/slider/UluSlideShow.vue +331 -0
  68. package/lib/components/systems/slider/UluSlideShowSlide.vue +25 -0
  69. package/lib/components/systems/table-sticky/UluTableSticky.vue +793 -0
  70. package/lib/components/systems/table-sticky/UluTableStickyRows.vue +73 -0
  71. package/lib/components/systems/table-sticky/UluTableStickyTable.vue +237 -0
  72. package/lib/components/systems/table-sticky/_table-sticky.scss +185 -0
  73. package/lib/components/utils/UluCondText.vue +28 -0
  74. package/lib/components/utils/UluEmpty.vue +3 -0
  75. package/lib/components/utils/UluEmptyView.vue +3 -0
  76. package/lib/components/utils/UluPlaceholderImage.vue +53 -0
  77. package/lib/components/utils/UluPlaceholderText.vue +25 -0
  78. package/lib/components/utils/UluRouteAnnouncer.vue +83 -0
  79. package/lib/components/visualizations/UluAnimateNumber.vue +32 -0
  80. package/lib/components/visualizations/UluProgressBar.vue +94 -0
  81. package/lib/components/visualizations/UluProgressDonut.vue +97 -0
  82. package/lib/composables/index.js +10 -0
  83. package/lib/composables/useBreakpointManager.js +68 -0
  84. package/lib/composables/useIcon.js +62 -0
  85. package/lib/composables/useModifiers.js +93 -0
  86. package/lib/composables/useWindowResize.js +64 -0
  87. package/lib/index.js +10 -0
  88. package/lib/plugins/_index.scss +7 -0
  89. package/lib/plugins/breakpoints/index.js +47 -0
  90. package/lib/plugins/index.js +11 -0
  91. package/lib/plugins/modals/UluModalsDisplay.vue +59 -0
  92. package/lib/plugins/modals/api.js +76 -0
  93. package/lib/plugins/modals/index.js +60 -0
  94. package/lib/plugins/modals/useModals.js +9 -0
  95. package/lib/plugins/popovers/UluPopover.vue +189 -0
  96. package/lib/plugins/popovers/UluTooltipDisplay.vue +15 -0
  97. package/lib/plugins/popovers/UluTooltipPopover.vue +83 -0
  98. package/lib/plugins/popovers/defaults.js +108 -0
  99. package/lib/plugins/popovers/directive.js +95 -0
  100. package/lib/plugins/popovers/index.js +18 -0
  101. package/lib/plugins/popovers/manager.js +54 -0
  102. package/lib/plugins/popovers/useFollow.js +80 -0
  103. package/lib/plugins/popovers/utils.js +5 -0
  104. package/lib/plugins/toast/UluToast.vue +87 -0
  105. package/lib/plugins/toast/UluToastDisplay.vue +35 -0
  106. package/lib/plugins/toast/_toast.scss +198 -0
  107. package/lib/plugins/toast/defaults.js +30 -0
  108. package/lib/plugins/toast/index.js +17 -0
  109. package/lib/plugins/toast/store.js +71 -0
  110. package/lib/plugins/toast/useToast.js +18 -0
  111. package/lib/settings.js +119 -0
  112. package/lib/utils/dom.js +14 -0
  113. package/lib/utils/placeholder.js +6 -0
  114. package/lib/utils/vue-router.js +219 -0
  115. package/package.json +75 -0
@@ -0,0 +1,152 @@
1
+ <!-- Version: 0.0.2? (NEED to diff, unsure of changes) -->
2
+ <template>
3
+ <div class="scroll-anchors">
4
+ <slot/>
5
+ </div>
6
+ </template>
7
+
8
+ <script>
9
+ import { computed } from "vue";
10
+ import { SECTIONS, REGISTER, UNREGISTER } from "./symbols.js";
11
+ export default {
12
+ name: "ScrollAnchors",
13
+ props: {
14
+ firstItemActive: Boolean,
15
+ /**
16
+ * Observe
17
+ */
18
+ observerOptions: {
19
+ type: Object,
20
+ default: () => ({
21
+ root: null,
22
+ threshhold: [0,1],
23
+ rootMargin: "-25% 0px -55% 0px"
24
+ // root: null,
25
+ // threshhold: [0,1],
26
+ // rootMargin: "25% 0px 75% 0px"
27
+ })
28
+ }
29
+ },
30
+ data() {
31
+ return {
32
+ isMounted: false,
33
+ sections: [], // Child components will section themselves
34
+ };
35
+ },
36
+ /**
37
+ * Interface for chil components to register themselves
38
+ * - Uses symbols
39
+ */
40
+ provide() {
41
+ return {
42
+ [SECTIONS]: computed(() => this.sections),
43
+ [REGISTER]: (instance) => {
44
+ const { titleId, title } = instance;
45
+ const { element } = instance.$refs;
46
+ this.sections.push({
47
+ instance,
48
+ titleId,
49
+ title,
50
+ element,
51
+ active: false
52
+ });
53
+ this.update();
54
+ },
55
+ [UNREGISTER]: (instance) => {
56
+ const sections = this.sections;
57
+ const index = sections.findIndex(r => r.instance === instance);
58
+ if (index > -1) {
59
+ sections.splice(index, 1);
60
+ }
61
+ this.update();
62
+ },
63
+ };
64
+ },
65
+ methods: {
66
+ update() {
67
+ if (this.isMounted) {
68
+ this.observeItems();
69
+ }
70
+ },
71
+ getSectionIndex(el) {
72
+ return this.sections.findIndex(({ element }) => el === element);
73
+ },
74
+ /**
75
+ * Sets up a new observer to watch the section visibility
76
+ */
77
+ createObserver() {
78
+ const { observerOptions, sections, removeActive, firstItemActive } = this;
79
+ let lastY = 0;
80
+ // Observer callback, basically just sets active state for a given slide
81
+ // - isIntersecting will change when the element enters and leaves
82
+ const onObserve = (entries) => {
83
+ entries.forEach(({ target, isIntersecting }) => {
84
+ const index = this.getSectionIndex(target);
85
+ const y = target.offsetTop;
86
+ const section = sections[index];
87
+ const firstExiting = index === 0 && lastY > y;
88
+ const lastExiting = index === sections.length - 1 && lastY < y;
89
+ if (section) {
90
+ this.$nextTick(() => {
91
+ if (isIntersecting) {
92
+ removeActive(section);
93
+ section.active = true;
94
+ // Only allow first and last to
95
+ } else if (firstExiting && !firstItemActive) {
96
+ removeActive();
97
+ } else if (lastExiting && section.active) {
98
+ removeActive();
99
+ }
100
+ this.$emit("sectionChange", {
101
+ section,
102
+ sections,
103
+ active: isIntersecting
104
+ });
105
+ });
106
+ }
107
+ });
108
+ };
109
+ // Add non-reactive prop for removal and changes to targets
110
+ this.observer = new IntersectionObserver(onObserve, observerOptions);
111
+ },
112
+ /**
113
+ * Add all slide elements as targets in observer
114
+ */
115
+ observeItems() {
116
+ const { observer, sections } = this;
117
+ observer.disconnect();
118
+ sections.forEach(({ element }) => {
119
+ if (element) {
120
+ observer.observe(element);
121
+ }
122
+ });
123
+ },
124
+ removeActive(except = null) {
125
+ this.sections.forEach(s => {
126
+ if (s !== except) {
127
+ s.active = false;
128
+ }
129
+ });
130
+ },
131
+ /**
132
+ * Remove observer and it's internal DOM references (GC)
133
+ */
134
+ destroyObserver() {
135
+ this.observer.disconnect();
136
+ this.observer = null;
137
+ },
138
+ },
139
+ mounted() {
140
+ const first = this.sections[0];
141
+ if (this.firstItemActive && first) {
142
+ first.active = true;
143
+ }
144
+ this.createObserver();
145
+ this.observeItems();
146
+ this.isMounted = true;
147
+ },
148
+ unmounted() {
149
+ this.destroyObserver();
150
+ },
151
+ };
152
+ </script>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <component
3
+ v-if="sections.length"
4
+ :is="element"
5
+ class="scroll-anchors__nav"
6
+ >
7
+ <ul>
8
+ <li
9
+ v-for="(item, index) in sections" :key="index"
10
+ :class="{ 'is-active' : item.active }"
11
+ >
12
+ <a
13
+ :class="{ 'is-active' : item.active }"
14
+ :href="`#${ item.titleId }`"
15
+ >
16
+ {{ item.title }}
17
+ </a>
18
+ </li>
19
+ </ul>
20
+ </component>
21
+ </template>
22
+
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
+ }
35
+ }
36
+ };
37
+ </script>
@@ -0,0 +1,124 @@
1
+ <!--
2
+ Version: 0.0.2
3
+ Changes:
4
+ - 0.0.2 | Added transition initial state/class so the indicator
5
+ doesn't transition at first
6
+ -->
7
+ <template>
8
+ <component
9
+ v-if="sections.length"
10
+ :is="element"
11
+ class="scroll-anchors__nav scroll-anchors__nav--animated"
12
+ >
13
+ <ul class="scroll-anchors__rail">
14
+ <li
15
+ v-for="(item, index) in sections" :key="index"
16
+ :class="{ 'is-active' : item.active }"
17
+ >
18
+ <a
19
+ :class="{ 'is-active' : item.active }"
20
+ :ref="(el) => addLinkRef(index, el)"
21
+ :href="`#${ item.titleId }`"
22
+ >
23
+ {{ item.title }}
24
+ </a>
25
+ </li>
26
+ </ul>
27
+ <div
28
+ class="scroll-anchors__indicator"
29
+ :class="{
30
+ 'scroll-anchors__indicator--can-transition' : indicatorAnimReady
31
+ }"
32
+ ref="indicator"
33
+ :style="{
34
+ opacity: indicatorStyles ? '1' : '0',
35
+ transform: `translateY(${ indicatorStyles.y }px)`,
36
+ height: `${ indicatorStyles.height }px`,
37
+ }"
38
+ ></div>
39
+ </component>
40
+ </template>
41
+
42
+ <script>
43
+ import { runAfterFramePaint } from "@ulu/utils/browser/performance.js";
44
+ import { SECTIONS } from "./symbols.js";
45
+ export default {
46
+ name: "ScrollAnchorsNavAnimated",
47
+ inject: {
48
+ sections: { from: SECTIONS }
49
+ },
50
+ props: {
51
+ /**
52
+ * Element to use for container
53
+ */
54
+ element: {
55
+ type: String,
56
+ default: "nav"
57
+ },
58
+ },
59
+ data() {
60
+ return {
61
+ linkRefs: {},
62
+ indicatorAnimReady: false
63
+ };
64
+ },
65
+ computed: {
66
+ indicatorStyles() {
67
+ const { sections, linkRefs } = this;
68
+ const linkCount = Object.keys(linkRefs).length;
69
+ // Checking for sections and link refs incase
70
+ // we were waiting for the components to mount, etc
71
+ if (!sections || !linkCount) {
72
+ return false;
73
+ }
74
+ const activeIndex = sections.findIndex(s => s.active);
75
+ if (activeIndex === -1) {
76
+ return false;
77
+ }
78
+ const link = this.linkRefs[activeIndex];
79
+ const { offsetTop, offsetHeight } = link;
80
+ return {
81
+ y: offsetTop,
82
+ height: offsetHeight,
83
+ initial: this.inidica
84
+ };
85
+ }
86
+ },
87
+ watch: {
88
+ indicatorStyles(val) {
89
+ if (val && !this.indicatorAnimReady) {
90
+ runAfterFramePaint(() => {
91
+ this.indicatorAnimReady = true;
92
+ });
93
+ }
94
+ }
95
+ },
96
+ methods: {
97
+ addLinkRef(index, el) {
98
+ this.linkRefs[index] = el;
99
+ }
100
+ }
101
+ };
102
+ </script>
103
+
104
+ <style lang="scss">
105
+ // User can override these styles
106
+ // - Think this is better than props/etc
107
+ // - Refactored from props to just plain css to be overridden
108
+ .scroll-anchors__rail {
109
+ border-left: 3px solid rgb(220, 220, 220);
110
+ padding-left: 1rem;
111
+ }
112
+ .scroll-anchors__indicator {
113
+ position: absolute;
114
+ top: 0;
115
+ left: 0;
116
+ width: 3px;
117
+ background-color: black;
118
+ }
119
+ .scroll-anchors__indicator--can-transition {
120
+ transition-property: height, transform;
121
+ transition-timing-function: ease-in-out;
122
+ transition-duration: 250ms;
123
+ }
124
+ </style>
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <div :class="[wrapperClass, { [activeClass] : activeClass && section?.active }]" ref="element">
3
+ <component :is="titleElement" :class="titleClass" :id="titleId">
4
+ {{ title }}
5
+ </component>
6
+ <slot :section="section"></slot>
7
+ </div>
8
+ </template>
9
+
10
+ <script>
11
+ import { computed } from "vue";
12
+ import { urlize } from "@ulu/utils/string.js";
13
+ import { REGISTER, UNREGISTER, SECTIONS } from "./symbols.js";
14
+ export default {
15
+ name: "ScrollAnchorsSection",
16
+ props: {
17
+ title: String,
18
+ titleElement: {
19
+ type: String,
20
+ default: "h2"
21
+ },
22
+ titleClass: {
23
+ type: String,
24
+ default: "h2"
25
+ },
26
+ anchorId: String,
27
+ wrapperClass: {
28
+ type: String,
29
+ default: "scroll-anchors__section"
30
+ },
31
+ activeClass: {
32
+ type: String,
33
+ default: 'is-active'
34
+ }
35
+ },
36
+ inject: {
37
+ register: { from: REGISTER },
38
+ unregister: { from: UNREGISTER },
39
+ sections: { from: SECTIONS, default: () => computed(() => []) }
40
+ },
41
+ data() {
42
+ const { anchorId, title } = this;
43
+ return {
44
+ titleId: anchorId || `sas-title-${ urlize(title) }`
45
+ };
46
+ },
47
+ computed: {
48
+ section() {
49
+ return this.sections.find(s => s.instance === this);
50
+ }
51
+ },
52
+ mounted() {
53
+ if (this.register) {
54
+ this.register(this);
55
+ }
56
+ },
57
+ unmounted() {
58
+ if (this.unregister) {
59
+ this.unregister(this);
60
+ }
61
+ }
62
+ };
63
+ </script>
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Symbol for register provide/inject
3
+ */
4
+ export const REGISTER = Symbol();
5
+ export const UNREGISTER = Symbol();
6
+ export const SECTIONS = Symbol();
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <slot v-if="!when"/>
3
+ <SkeletonTextInline class="skeleton" v-else/>
4
+ </template>
5
+
6
+ <script>
7
+ export default {
8
+ name: "ShowSkeleton",
9
+ props: {
10
+ when: Boolean,
11
+ },
12
+ };
13
+ </script>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div class="skeleton">
3
+ <div v-for="(line, index) in linesWithSegments" :key="index">
4
+ <span
5
+ v-for="segment in line"
6
+ :key="segment"
7
+ class="skeleton__text skeleton__text--inline"
8
+ :class="{ 'skeleton__alt' : segment.alt }"
9
+ :style="{ width: `${ segment.width }%` }"
10
+ >
11
+ </span>
12
+ </div>
13
+ </div>
14
+ </template>
15
+
16
+ <script>
17
+ import { randomInt } from "@ulu/utils/random.js";
18
+ import { arrayCreate } from "@ulu/utils/array.js";
19
+ export default {
20
+ name: "SkeletonContent",
21
+ props: {
22
+ lines: {
23
+ type: Number,
24
+ default: 6
25
+ },
26
+ },
27
+ methods: {
28
+ randomInt
29
+ },
30
+ computed: {
31
+ /**
32
+ * Creates the segments (like words) for the given line count
33
+ * - Uses random number of segments and makes sure to fill the line between 70% - 100%
34
+ */
35
+ linesWithSegments() {
36
+ return arrayCreate(this.lines, () => {
37
+ const minWidth = 15;
38
+ const total = randomInt(70, 100);
39
+ let widthCurrent = 0;
40
+ const newWidth = () => {
41
+ const remaining = total - widthCurrent;
42
+ const width = randomInt(minWidth, remaining);
43
+ widthCurrent += width;
44
+ return width;
45
+ };
46
+ const segments = [];
47
+ while (widthCurrent < total - minWidth) {
48
+ segments.push(newWidth());
49
+ }
50
+ const getActualTotal = () => segments.reduce((acc, a) => acc + a, 0);
51
+ while (getActualTotal() >= total) {
52
+ let removed = segments.pop();
53
+ if (!removed) break;
54
+ }
55
+ return segments.map(width => ({ width, alt: Math.random() < 0.5 }));
56
+ });
57
+ }
58
+ }
59
+ };
60
+ </script>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="skeleton__block skeleton__block--media layout-flex-center-all">
3
+ <FaIcon style="font-size: 2rem" icon="image"/>
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: "SkeletonMedia",
10
+ };
11
+ </script>
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <span class="skeleton__text skeleton__text--inline"></span>
3
+ </template>
4
+
5
+ <script>
6
+ export default {
7
+ name: "SkeletonTextInline",
8
+ };
9
+ </script>
@@ -0,0 +1,75 @@
1
+ <!--
2
+ Note: This is the image implementation of SlideShow
3
+ Notes:
4
+ - Should the images resize to fit the nav?
5
+ - Should the nav slide based on the active index?
6
+
7
+ -->
8
+ <template>
9
+ <UluSlideShow
10
+ class="slideshow--images"
11
+ :items="images"
12
+ @slideChange="slideChange"
13
+ >
14
+ <template #slide="{ item }">
15
+ <img :src="item.src" :alt="item.alt">
16
+ <!-- Adding this in here for now, not generic meant for selection in compare ui -->
17
+ <div class="slideshow__image-actions">
18
+ <AppButton v-if="selectButton" class="type-small" icon="plus" small iconBefore>
19
+ Select
20
+ </AppButton>
21
+ </div>
22
+ </template>
23
+ <template #nav="{ index }">
24
+ <img :src="images[index].src" :alt="`View image ${ index }`">
25
+ </template>
26
+ </UluSlideShow>
27
+ </template>
28
+
29
+ <script>
30
+ import UluSlideShow from "./UluSlideShow.vue";
31
+ export default {
32
+ name: 'ImageSlideShow',
33
+ components: {
34
+ UluSlideShow,
35
+ },
36
+ props: {
37
+ images: Array,
38
+ selectButton: Boolean
39
+ },
40
+ watch: {
41
+ images() {
42
+ console.log('watch image from outer');
43
+ }
44
+ },
45
+ methods: {
46
+ /**
47
+ * Test to see if the active slide's nav button (thumbnail) is in view
48
+ * if not, scroll the nav to ensure it is visible. This function will take
49
+ * into account which side of the overflow nav the item is hidden in and will
50
+ * scroll either to fit it to the flush end (if overflow to the right) or flush start
51
+ */
52
+ slideChange({ slide, nav }) {
53
+ const { active, navElement } = slide;
54
+ if (!navElement) return;
55
+ const { offsetWidth, scrollLeft: left } = nav;
56
+ const { offsetLeft, offsetWidth: navWidth } = navElement;
57
+ const right = left + offsetWidth;
58
+ const navRight = offsetLeft + navWidth;
59
+ let amount = null;
60
+ console.log('left/right', left, right);
61
+ if (active && navElement) {
62
+
63
+ if (navRight > right) {
64
+ amount = left + (navRight - right);
65
+ } else if (offsetLeft < left) {
66
+ amount = offsetLeft;
67
+ }
68
+ if (amount !== null) {
69
+ nav.scrollTo({ left: amount, top: 0, behavior: "smooth" });
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ </script>