srcdev-nuxt-components 0.0.27 → 0.0.29

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.
@@ -1,19 +1,33 @@
1
1
  <template>
2
- <ul role="tablist" aria-labelledby="channel-name" ref="navContainerRef" @mouseleave="resetHoverToActivePosition()" class="tabs-list" :class="[elementClasses]">
3
- <li v-for="(item, index) in navItems" class="masonry-grid-ordered-item" ref="gridItemsRefs">
4
- <button @click.prevent="navItemClicked($event)" @mouseover="navItemHovered($event)" :data-tab-index="index" data-nav-item role="tab" aria-selected="false" class="tabs-list-item">
5
- {{ item.name }}
6
- </button>
7
- </li>
8
- </ul>
2
+ <div class="tabs">
3
+ <ul role="tablist" aria-labelledby="channel-name" ref="tabsNavRef" @mouseleave="resetHoverToActivePosition()" class="tabs-list" :class="[elementClasses]">
4
+ <li v-for="(index, key) in navItems" :key="key">
5
+ <button
6
+ @click.prevent="navItemClicked($event)"
7
+ @mouseover="navItemHovered($event)"
8
+ :id="`tab-${key}-trigger`"
9
+ :data-tab-index="index"
10
+ data-nav-item
11
+ role="tab"
12
+ aria-selected="false"
13
+ class="tabs-list-item"
14
+ >
15
+ <slot :name="`tab-${key}-trigger`"></slot>
16
+ </button>
17
+ </li>
18
+ </ul>
19
+ <div class="tab-content-wrapper">
20
+ <div v-for="(item, key) in navItems" :key="key" class="tab-content" :aria-labelledby="`tab-${key}-trigger`" :id="`tab-${key}-content`" role="region" aria-hidden="true" ref="tabsContentRefs">
21
+ <div>
22
+ <slot :name="`tab-${key}-content`"></slot>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
9
27
  </template>
10
28
 
11
29
  <script setup lang="ts">
12
- interface INavLink {
13
- action?: string;
14
- name: string;
15
- path?: string;
16
- }
30
+ import type { ITabNav } from '@/types/types.tabs';
17
31
 
18
32
  const props = defineProps({
19
33
  tag: {
@@ -21,7 +35,7 @@ const props = defineProps({
21
35
  default: 'button',
22
36
  },
23
37
  navItems: {
24
- type: Array as PropType<INavLink[]>,
38
+ type: Array as PropType<ITabNav[]>,
25
39
  required: true,
26
40
  },
27
41
  trackHover: {
@@ -44,9 +58,10 @@ const props = defineProps({
44
58
 
45
59
  const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
46
60
 
47
- const navContainerRef = ref<HTMLElement | null>(null);
61
+ const tabsNavRef = ref<HTMLElement | null>(null);
62
+ const tabsContentRefs = ref<HTMLElement[] | null>(null);
48
63
 
49
- const { initNavDecorators, navItemClicked, navItemHovered, resetHoverToActivePosition } = useNavDecoration(navContainerRef);
64
+ const { initNavDecorators, navItemClicked, navItemHovered, resetHoverToActivePosition } = useTabs(tabsNavRef, tabsContentRefs);
50
65
 
51
66
  onMounted(() => {
52
67
  initNavDecorators();
@@ -55,13 +70,16 @@ onMounted(() => {
55
70
 
56
71
  <style lang="css">
57
72
  .tabs-list {
58
- --_default-text: light-dark(var(--gray-12), var(--gray-0));
59
- --_active-bg: light-dark(var(--gray-12), var(--gray-0));
60
- --_active-text: light-dark(var(--gray-0), var(--gray-12));
61
- --_active-indicator: light-dark(var(--gray-12), var(--gray-0));
62
- --_hovered-bg: light-dark(var(--gray-7), var(--gray-3));
63
- --_hovered-text: light-dark(var(--gray-0), var(--gray-12));
64
- --_border-bottom: light-dark(var(--gray-12), var(--gray-0));
73
+ /*
74
+ * CSS var within /assets/styles/components/tabs.css
75
+ */
76
+ --_tabs-default-text: var(--tabs-default-text, light-dark(var(--gray-12), var(--gray-0)));
77
+ --_tabs-active-bg: var(--tabs-active-bg, light-dark(var(--gray-12), var(--gray-0)));
78
+ --_tabs-active-text: var(--tabs-active-text, light-dark(var(--gray-0), var(--gray-12)));
79
+ --_tabs-active-indicator: var(--tabs-active-indicator, light-dark(var(--gray-12), var(--gray-0)));
80
+ --_tabs-hovered-bg: var(--tabs-hovered-bg, light-dark(var(--gray-7), var(--gray-3)));
81
+ --_tabs-hovered-text: var(--tabs-hovered-text, light-dark(var(--gray-0), var(--gray-12)));
82
+ --_tabs-border-bottom: var(--tabs-border-bottom, light-dark(var(--gray-12), var(--gray-0)));
65
83
 
66
84
  position: relative;
67
85
  display: flex;
@@ -130,28 +148,28 @@ onMounted(() => {
130
148
  /*
131
149
  * User configurable variables
132
150
  */
133
- border-bottom: 1px solid var(--_border-bottom);
151
+ border-bottom: 1px solid var(--_tabs-border-bottom);
134
152
  margin-block: 3rem;
135
153
 
136
154
  .nav__hovered {
137
- background: var(--_hovered-bg);
138
- color: var(--_hovered-text);
155
+ background: var(--_tabs-hovered-bg);
156
+ color: var(--_tabs-hovered-text);
139
157
  }
140
158
 
141
159
  .nav__active {
142
- background: var(--_active-bg);
143
- color: var(--_active-text);
160
+ background: var(--_tabs-active-bg);
161
+ color: var(--_tabs-active-text);
144
162
  }
145
163
 
146
164
  .nav__active-indicator {
147
- background: var(--_active-indicator);
165
+ background: var(--_tabs-active-indicator);
148
166
  height: 4px;
149
167
  }
150
168
 
151
169
  .tabs-list-item {
152
170
  background: transparent;
153
171
  border: 0;
154
- color: var(--_default-text);
172
+ color: var(--_tabs-default-text);
155
173
  cursor: pointer;
156
174
  font: inherit;
157
175
  text-transform: uppercase;
@@ -160,12 +178,22 @@ onMounted(() => {
160
178
  padding: 1em 2em;
161
179
 
162
180
  &:hover {
163
- color: var(--_hovered-text);
181
+ color: var(--_tabs-hovered-text);
164
182
  }
165
183
 
166
184
  &[aria-selected='true'] {
167
- color: var(--_active-text);
185
+ color: var(--_tabs-active-text);
168
186
  }
169
187
  }
170
188
  }
189
+
190
+ .tab-content-wrapper {
191
+ display: grid;
192
+ grid-template-areas: 'element-stack';
193
+
194
+ .tab-content {
195
+ grid-area: element-stack;
196
+ display: none;
197
+ }
198
+ }
171
199
  </style>
@@ -1,6 +1,6 @@
1
1
  import { useResizeObserver } from '@vueuse/core';
2
2
 
3
- const useNavDecoration = (navContainerRef: Ref<HTMLElement | null>, duration: number = 200) => {
3
+ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLElement[] | null>, duration: number = 200) => {
4
4
  const navItems = ref<HTMLElement[] | null>(null);
5
5
  const previousActiveTab = useState<HTMLElement | null>('previousActiveTab', () => null);
6
6
  const currentActiveTab = ref<HTMLElement>();
@@ -10,7 +10,7 @@ const useNavDecoration = (navContainerRef: Ref<HTMLElement | null>, duration: nu
10
10
  const tagName = ref<string>();
11
11
 
12
12
  const initNavDecorators = () => {
13
- navItems.value = navContainerRef.value ? (Array.from(navContainerRef.value.querySelectorAll('[data-nav-item')) as HTMLElement[]) : [];
13
+ navItems.value = tabsNavRef.value ? (Array.from(tabsNavRef.value.querySelectorAll('[data-nav-item')) as HTMLElement[]) : [];
14
14
  tagName.value = navItems.value[0].tagName.toLowerCase();
15
15
 
16
16
  const activeIndex = ref(0);
@@ -34,15 +34,16 @@ const useNavDecoration = (navContainerRef: Ref<HTMLElement | null>, duration: nu
34
34
  previousHoveredTab.value = navItems.value[activeIndex.value];
35
35
 
36
36
  addNavDecorators();
37
+ setActiveTabContent();
37
38
  };
38
39
 
39
40
  const addNavDecorators = () => {
40
41
  const elementClasses = ['nav__active-indicator', 'nav__active', 'nav__hovered'];
41
- if (navContainerRef.value) {
42
+ if (tabsNavRef.value) {
42
43
  for (let i = 0; i < 3; i++) {
43
44
  const div = document.createElement('div');
44
45
  div.classList.add(elementClasses[i]);
45
- navContainerRef.value.appendChild(div);
46
+ tabsNavRef.value.appendChild(div);
46
47
  }
47
48
  }
48
49
  };
@@ -75,26 +76,27 @@ const useNavDecoration = (navContainerRef: Ref<HTMLElement | null>, duration: nu
75
76
  });
76
77
 
77
78
  moveActiveIndicator();
79
+ setActiveTabContent();
78
80
  };
79
81
 
80
82
  const setFinalHoveredPositions = (resized: boolean = false) => {
81
83
  const setDuration = resized ? 0 : duration;
82
- const newTabWidth = currentHoveredTab.value && navContainerRef.value ? currentHoveredTab.value.offsetWidth / navContainerRef.value.offsetWidth : 0;
83
- navContainerRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
84
- navContainerRef.value?.style.setProperty('--_left-hovered', currentHoveredTab.value?.offsetLeft + 'px');
85
- navContainerRef.value?.style.setProperty('--_width-hovered', newTabWidth?.toString());
84
+ const newTabWidth = currentHoveredTab.value && tabsNavRef.value ? currentHoveredTab.value.offsetWidth / tabsNavRef.value.offsetWidth : 0;
85
+ tabsNavRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
86
+ tabsNavRef.value?.style.setProperty('--_left-hovered', currentHoveredTab.value?.offsetLeft + 'px');
87
+ tabsNavRef.value?.style.setProperty('--_width-hovered', newTabWidth?.toString());
86
88
  };
87
89
 
88
90
  const setFinalActivePositions = (resized: boolean = false) => {
89
91
  const setDuration = resized ? 0 : duration;
90
- const newTabWidth = currentActiveTab.value && navContainerRef.value ? currentActiveTab.value.offsetWidth / navContainerRef.value.offsetWidth : 0;
91
- navContainerRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
92
- navContainerRef.value?.style.setProperty('--_left-active', currentActiveTab.value?.offsetLeft + 'px');
93
- navContainerRef.value?.style.setProperty('--_width-active', newTabWidth?.toString());
92
+ const newTabWidth = currentActiveTab.value && tabsNavRef.value ? currentActiveTab.value.offsetWidth / tabsNavRef.value.offsetWidth : 0;
93
+ tabsNavRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
94
+ tabsNavRef.value?.style.setProperty('--_left-active', currentActiveTab.value?.offsetLeft + 'px');
95
+ tabsNavRef.value?.style.setProperty('--_width-active', newTabWidth?.toString());
94
96
  };
95
97
 
96
98
  const moveActiveIndicator = () => {
97
- navContainerRef.value?.style.setProperty('--_transition-duration', duration + 'ms');
99
+ tabsNavRef.value?.style.setProperty('--_transition-duration', duration + 'ms');
98
100
 
99
101
  const newTabPosition = previousActiveTab.value && currentActiveTab.value ? previousActiveTab.value.compareDocumentPosition(currentActiveTab.value) : 0;
100
102
  let transitionWidth;
@@ -103,10 +105,10 @@ const useNavDecoration = (navContainerRef: Ref<HTMLElement | null>, duration: nu
103
105
  transitionWidth = currentActiveTab.value && previousActiveTab.value ? currentActiveTab.value.offsetLeft + currentActiveTab.value.offsetWidth - previousActiveTab.value.offsetLeft : 0;
104
106
  } else {
105
107
  transitionWidth = previousActiveTab.value && currentActiveTab.value ? previousActiveTab.value.offsetLeft + previousActiveTab.value.offsetWidth - currentActiveTab.value.offsetLeft : 0;
106
- navContainerRef.value?.style.setProperty('--_left-active', currentActiveTab.value ? currentActiveTab.value.offsetLeft + 'px' : '0');
108
+ tabsNavRef.value?.style.setProperty('--_left-active', currentActiveTab.value ? currentActiveTab.value.offsetLeft + 'px' : '0');
107
109
  }
108
110
 
109
- navContainerRef.value?.style.setProperty('--_width-active', String(transitionWidth / navContainerRef.value.offsetWidth));
111
+ tabsNavRef.value?.style.setProperty('--_width-active', String(transitionWidth / tabsNavRef.value.offsetWidth));
110
112
 
111
113
  setTimeout(() => {
112
114
  setFinalActivePositions();
@@ -114,7 +116,7 @@ const useNavDecoration = (navContainerRef: Ref<HTMLElement | null>, duration: nu
114
116
  };
115
117
 
116
118
  const moveHoveredIndicator = () => {
117
- navContainerRef.value?.style.setProperty('--_transition-duration', duration + 'ms');
119
+ tabsNavRef.value?.style.setProperty('--_transition-duration', duration + 'ms');
118
120
 
119
121
  const newTabPosition = previousHoveredTab.value && currentHoveredTab.value ? previousHoveredTab.value.compareDocumentPosition(currentHoveredTab.value) : 0;
120
122
  let transitionWidth;
@@ -123,28 +125,38 @@ const useNavDecoration = (navContainerRef: Ref<HTMLElement | null>, duration: nu
123
125
  transitionWidth = currentHoveredTab.value && previousHoveredTab.value ? currentHoveredTab.value.offsetLeft + currentHoveredTab.value.offsetWidth - previousHoveredTab.value.offsetLeft : 0;
124
126
  } else {
125
127
  transitionWidth = previousHoveredTab.value && currentHoveredTab.value ? previousHoveredTab.value.offsetLeft + previousHoveredTab.value.offsetWidth - currentHoveredTab.value.offsetLeft : 0;
126
- navContainerRef.value?.style.setProperty('--_left-hovered', currentHoveredTab.value ? currentHoveredTab.value.offsetLeft + 'px' : '0');
128
+ tabsNavRef.value?.style.setProperty('--_left-hovered', currentHoveredTab.value ? currentHoveredTab.value.offsetLeft + 'px' : '0');
127
129
  }
128
130
 
129
- navContainerRef.value?.style.setProperty('--_width-hovered', String(transitionWidth / navContainerRef.value.offsetWidth));
131
+ tabsNavRef.value?.style.setProperty('--_width-hovered', String(transitionWidth / tabsNavRef.value.offsetWidth));
130
132
 
131
133
  setTimeout(() => {
132
134
  setFinalHoveredPositions();
133
135
  }, Math.floor(duration + 20));
134
136
  };
135
137
 
136
- useResizeObserver(navContainerRef, () => {
138
+ const setActiveTabContent = () => {
139
+ const activeIndex = navItems.value?.findIndex((el) => el === currentActiveTab.value);
140
+ tabsContentRefs.value?.forEach((tabContent: HTMLElement, index: number) => {
141
+ tabContent.style.display = activeIndex === index ? 'block' : 'none';
142
+ });
143
+ };
144
+
145
+ const animationRunning = (running: boolean) => {
146
+ console.log('animationRunning', running);
147
+ };
148
+
149
+ useResizeObserver(tabsNavRef, () => {
137
150
  setFinalActivePositions(true);
138
151
  setFinalHoveredPositions(true);
139
152
  });
140
153
 
141
154
  return {
142
155
  initNavDecorators,
143
- navContainerRef,
144
156
  navItemClicked,
145
157
  navItemHovered,
146
158
  resetHoverToActivePosition,
147
159
  };
148
160
  };
149
161
 
150
- export default useNavDecoration;
162
+ export default useTabs;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "0.0.27",
4
+ "version": "0.0.29",
5
5
  "main": "nuxt.config.ts",
6
6
  "scripts": {
7
7
  "clean": "rm -rf .nuxt && rm -rf .output && rm -rf .playground/.nuxt && rm -rf .playground/.output",