srcdev-nuxt-components 1.0.4 → 1.1.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.
@@ -1,12 +1,12 @@
1
1
  <template>
2
- <div class="tabs">
2
+ <div class="tabs-core" :class="`axis-${axis}`">
3
3
  <ul role="tablist" aria-labelledby="channel-name" ref="tabsNavRef" @mouseleave="resetHoverToActivePosition()" class="tabs-list" :class="[elementClasses]">
4
4
  <li v-for="(index, key) in navItems" :key="key">
5
5
  <button
6
6
  @click.prevent="navItemClicked($event)"
7
7
  @mouseover="navItemHovered($event)"
8
8
  :id="`tab-${key}-trigger`"
9
- :data-tab-index="index"
9
+ :data-tab-index="key"
10
10
  data-nav-item
11
11
  role="tab"
12
12
  aria-selected="false"
@@ -32,6 +32,14 @@ const props = defineProps({
32
32
  type: String as PropType<string>,
33
33
  default: 'button',
34
34
  },
35
+ axis: {
36
+ type: String as PropType<'x' | 'y'>,
37
+ default: 'x',
38
+ },
39
+ transitionDuration: {
40
+ type: Number as PropType<number>,
41
+ default: 200,
42
+ },
35
43
  navItems: {
36
44
  type: Array as PropType<ITabNav[]>,
37
45
  required: true,
@@ -59,7 +67,7 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
59
67
  const tabsNavRef = ref<HTMLElement | null>(null);
60
68
  const tabsContentRefs = ref<HTMLElement[] | null>(null);
61
69
 
62
- const { initNavDecorators, navItemClicked, navItemHovered, resetHoverToActivePosition } = useTabs(tabsNavRef, tabsContentRefs);
70
+ const { initNavDecorators, navItemClicked, navItemHovered, resetHoverToActivePosition } = useTabs(props.axis, tabsNavRef, tabsContentRefs, props.transitionDuration);
63
71
 
64
72
  onMounted(() => {
65
73
  initNavDecorators();
@@ -67,7 +75,7 @@ onMounted(() => {
67
75
  </script>
68
76
 
69
77
  <style lang="css">
70
- .tabs {
78
+ .tabs-core {
71
79
  /*
72
80
  * CSS var within /assets/styles/components/tabs.css
73
81
  */
@@ -104,7 +112,7 @@ onMounted(() => {
104
112
  bottom: 0;
105
113
  top: 0;
106
114
  scale: var(--_width-hovered, 0.125) 1;
107
- translate: var(--_left-hovered, 0) 0;
115
+ translate: var(--_x-hovered, 0) 0;
108
116
  transform-origin: left;
109
117
  transition: scale var(--_transition-duration), translate var(--_transition-duration);
110
118
  z-index: 1;
@@ -118,7 +126,7 @@ onMounted(() => {
118
126
  bottom: 0;
119
127
  top: 0;
120
128
  scale: var(--_width-active, 0.125) 1;
121
- translate: var(--_left-active, 0) 0;
129
+ translate: var(--_x-active, 0) 0;
122
130
  transform-origin: left;
123
131
  transition: scale var(--_transition-duration), translate var(--_transition-duration);
124
132
  z-index: 2;
@@ -131,7 +139,7 @@ onMounted(() => {
131
139
  right: 0;
132
140
  bottom: 0;
133
141
  scale: var(--_width-active, 0.125) 1;
134
- translate: var(--_left-active, 0) 0;
142
+ translate: var(--_x-active, 0) 0;
135
143
  transform-origin: left;
136
144
  transition: scale var(--_transition-duration), translate var(--_transition-duration);
137
145
  z-index: 3;
@@ -140,7 +148,7 @@ onMounted(() => {
140
148
  .tabs-list-item {
141
149
  opacity: 0.7;
142
150
  position: relative;
143
- transition: color 0.2s;
151
+ transition: color 100ms;
144
152
  z-index: 4;
145
153
 
146
154
  &:hover {
@@ -181,12 +189,17 @@ onMounted(() => {
181
189
  padding: 1em 2em;
182
190
 
183
191
  &:hover {
192
+ /* background: var(--_tabs-hovered-bg); */
184
193
  color: var(--_tabs-hovered-text);
185
194
  }
186
195
 
187
196
  &[aria-selected='true'] {
188
197
  color: var(--_tabs-active-text);
189
198
  }
199
+
200
+ &.transitioning {
201
+ color: var(--_tabs-hovered-text);
202
+ }
190
203
  }
191
204
  }
192
205
 
@@ -218,4 +231,78 @@ onMounted(() => {
218
231
  } */
219
232
  }
220
233
  }
234
+
235
+ /*
236
+ * Deal with axis-y
237
+ **/
238
+
239
+ .tabs-core {
240
+ &.axis-y {
241
+ display: flex;
242
+ flex-direction: row;
243
+ gap: 2em;
244
+
245
+ .tabs-list {
246
+ flex-direction: column;
247
+
248
+ border-bottom: initial;
249
+ border-left: var(--_tabs-border-bottom);
250
+ position: relative;
251
+
252
+ .tabs-list-item {
253
+ text-align: left;
254
+ width: 100%;
255
+
256
+ /* &:hover {
257
+ color: var(--_tabs-hovered-text);
258
+ }
259
+
260
+ &[aria-selected='true'] {
261
+ color: var(--_tabs-active-text);
262
+ }
263
+
264
+ &.transitioning {
265
+ color: var(--_tabs-hovered-text);
266
+ } */
267
+ }
268
+
269
+ .nav__hovered {
270
+ left: 0;
271
+ right: initial;
272
+ bottom: initial;
273
+ top: 0;
274
+ height: var(--_y-height);
275
+ translate: 0 var(--_y-hovered, 0);
276
+ transform-origin: top;
277
+ width: var(--_y-width);
278
+ }
279
+
280
+ .nav__active {
281
+ left: 0;
282
+ right: initial;
283
+ bottom: initial;
284
+ top: 0;
285
+ height: var(--_y-height);
286
+ translate: 0 var(--_y-active, 0);
287
+ transform-origin: top;
288
+ width: var(--_y-width);
289
+ }
290
+
291
+ .nav__active-indicator {
292
+ left: 0;
293
+ right: initial;
294
+ bottom: initial;
295
+ top: 0;
296
+ height: var(--_y-height);
297
+ scale: var(--_width-active, 0.125) 1;
298
+ translate: 0 var(--_y-active, 0);
299
+ transform-origin: top;
300
+ width: 0.4em;
301
+ }
302
+ }
303
+ .tab-content-wrapper {
304
+ flex-grow: 1;
305
+ }
306
+ }
307
+ }
221
308
  </style>
@@ -1,6 +1,6 @@
1
1
  import { useResizeObserver } from '@vueuse/core';
2
2
 
3
- const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLElement[] | null>, duration: number = 200) => {
3
+ const useTabs = (axis: string, tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLElement[] | null>, duration: number) => {
4
4
  const navItems = ref<HTMLElement[] | null>(null);
5
5
  const previousActiveTab = useState<HTMLElement | null>('previousActiveTab', () => null);
6
6
  const currentActiveTab = ref<HTMLElement>();
@@ -79,20 +79,59 @@ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLE
79
79
  setActiveTabContent();
80
80
  };
81
81
 
82
+ const handleTransitioningClass = (transitionDuration: number = 200) => {
83
+ if (previousHoveredTab.value && currentHoveredTab.value) {
84
+ const newTabPosition = previousHoveredTab.value.compareDocumentPosition(currentHoveredTab.value);
85
+ const navItemsArray = navItems.value || [];
86
+
87
+ const timeout = Math.floor(transitionDuration / Math.abs(navItemsArray.indexOf(currentHoveredTab.value) - navItemsArray.indexOf(previousHoveredTab.value)));
88
+
89
+ if (newTabPosition === 4) {
90
+ for (let i = navItemsArray.indexOf(previousHoveredTab.value); i < navItemsArray.indexOf(currentHoveredTab.value); i++) {
91
+ navItemsArray[i].classList.add('transitioning');
92
+ if (i >= navItemsArray.indexOf(previousHoveredTab.value) && i < navItemsArray.indexOf(currentHoveredTab.value)) {
93
+ setTimeout(() => {
94
+ navItemsArray[i].classList.remove('transitioning');
95
+ // }, timeout * (i - navItemsArray.indexOf(previousHoveredTab.value) - 1));
96
+ }, duration * 1.5);
97
+ }
98
+ }
99
+ } else {
100
+ for (let i = navItemsArray.indexOf(previousHoveredTab.value); i > navItemsArray.indexOf(currentHoveredTab.value); i--) {
101
+ navItemsArray[i].classList.add('transitioning');
102
+ if (i <= navItemsArray.indexOf(previousHoveredTab.value) && i > navItemsArray.indexOf(currentHoveredTab.value)) {
103
+ setTimeout(() => {
104
+ navItemsArray[i].classList.remove('transitioning');
105
+ // }, timeout * (i - navItemsArray.indexOf(previousHoveredTab.value) - 1));
106
+ }, duration * 1.5);
107
+ }
108
+ }
109
+ }
110
+ }
111
+ };
112
+
82
113
  const setFinalHoveredPositions = (resized: boolean = false) => {
83
114
  const setDuration = resized ? 0 : duration;
115
+ // const tabsNavRefYPosition = tabsNavRef.value?.getBoundingClientRect().top || 0;
84
116
  const newTabWidth = currentHoveredTab.value && tabsNavRef.value ? currentHoveredTab.value.offsetWidth / tabsNavRef.value.offsetWidth : 0;
85
117
  tabsNavRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
86
- tabsNavRef.value?.style.setProperty('--_left-hovered', currentHoveredTab.value?.offsetLeft + 'px');
118
+ tabsNavRef.value?.style.setProperty('--_x-hovered', currentHoveredTab.value?.offsetLeft + 'px');
119
+
87
120
  tabsNavRef.value?.style.setProperty('--_width-hovered', newTabWidth?.toString());
121
+ tabsNavRef.value?.style.setProperty('--_y-hovered', currentHoveredTab.value?.offsetTop + 'px');
122
+ tabsNavRef.value?.style.setProperty('--_y-height', currentHoveredTab.value?.offsetHeight + 'px');
123
+ tabsNavRef.value?.style.setProperty('--_y-width', currentHoveredTab.value?.offsetWidth + 'px');
88
124
  };
89
125
 
90
126
  const setFinalActivePositions = (resized: boolean = false) => {
91
127
  const setDuration = resized ? 0 : duration;
92
128
  const newTabWidth = currentActiveTab.value && tabsNavRef.value ? currentActiveTab.value.offsetWidth / tabsNavRef.value.offsetWidth : 0;
93
129
  tabsNavRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
94
- tabsNavRef.value?.style.setProperty('--_left-active', currentActiveTab.value?.offsetLeft + 'px');
130
+ tabsNavRef.value?.style.setProperty('--_x-active', currentActiveTab.value?.offsetLeft + 'px');
95
131
  tabsNavRef.value?.style.setProperty('--_width-active', newTabWidth?.toString());
132
+ tabsNavRef.value?.style.setProperty('--_y-active', currentActiveTab.value?.offsetTop + 'px');
133
+ tabsNavRef.value?.style.setProperty('--_y-height', currentActiveTab.value?.offsetHeight + 'px');
134
+ tabsNavRef.value?.style.setProperty('--_y-width', currentActiveTab.value?.offsetWidth + 'px');
96
135
  };
97
136
 
98
137
  const moveActiveIndicator = () => {
@@ -105,11 +144,13 @@ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLE
105
144
  transitionWidth = currentActiveTab.value && previousActiveTab.value ? currentActiveTab.value.offsetLeft + currentActiveTab.value.offsetWidth - previousActiveTab.value.offsetLeft : 0;
106
145
  } else {
107
146
  transitionWidth = previousActiveTab.value && currentActiveTab.value ? previousActiveTab.value.offsetLeft + previousActiveTab.value.offsetWidth - currentActiveTab.value.offsetLeft : 0;
108
- tabsNavRef.value?.style.setProperty('--_left-active', currentActiveTab.value ? currentActiveTab.value.offsetLeft + 'px' : '0');
147
+ tabsNavRef.value?.style.setProperty('--_x-active', currentActiveTab.value ? currentActiveTab.value.offsetLeft + 'px' : '0');
109
148
  }
110
149
 
111
150
  tabsNavRef.value?.style.setProperty('--_width-active', String(transitionWidth / tabsNavRef.value.offsetWidth));
112
151
 
152
+ handleTransitioningClass(duration);
153
+
113
154
  setTimeout(() => {
114
155
  setFinalActivePositions();
115
156
  }, Math.floor(duration + 20));
@@ -125,11 +166,13 @@ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLE
125
166
  transitionWidth = currentHoveredTab.value && previousHoveredTab.value ? currentHoveredTab.value.offsetLeft + currentHoveredTab.value.offsetWidth - previousHoveredTab.value.offsetLeft : 0;
126
167
  } else {
127
168
  transitionWidth = previousHoveredTab.value && currentHoveredTab.value ? previousHoveredTab.value.offsetLeft + previousHoveredTab.value.offsetWidth - currentHoveredTab.value.offsetLeft : 0;
128
- tabsNavRef.value?.style.setProperty('--_left-hovered', currentHoveredTab.value ? currentHoveredTab.value.offsetLeft + 'px' : '0');
169
+ tabsNavRef.value?.style.setProperty('--_x-hovered', currentHoveredTab.value ? currentHoveredTab.value.offsetLeft + 'px' : '0');
129
170
  }
130
171
 
131
172
  tabsNavRef.value?.style.setProperty('--_width-hovered', String(transitionWidth / tabsNavRef.value.offsetWidth));
132
173
 
174
+ handleTransitioningClass(duration);
175
+
133
176
  setTimeout(() => {
134
177
  setFinalHoveredPositions();
135
178
  }, Math.floor(duration + 20));
@@ -142,10 +185,6 @@ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLE
142
185
  });
143
186
  };
144
187
 
145
- const animationRunning = (running: boolean) => {
146
- console.log('animationRunning', running);
147
- };
148
-
149
188
  useResizeObserver(tabsNavRef, () => {
150
189
  setFinalActivePositions(true);
151
190
  setFinalHoveredPositions(true);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "1.0.4",
4
+ "version": "1.1.1",
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",