srcdev-nuxt-components 1.1.0 → 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,5 +1,5 @@
|
|
|
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
|
|
@@ -32,6 +32,10 @@ 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
|
+
},
|
|
35
39
|
transitionDuration: {
|
|
36
40
|
type: Number as PropType<number>,
|
|
37
41
|
default: 200,
|
|
@@ -63,7 +67,7 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
|
63
67
|
const tabsNavRef = ref<HTMLElement | null>(null);
|
|
64
68
|
const tabsContentRefs = ref<HTMLElement[] | null>(null);
|
|
65
69
|
|
|
66
|
-
const { initNavDecorators, navItemClicked, navItemHovered, resetHoverToActivePosition } = useTabs(tabsNavRef, tabsContentRefs, props.transitionDuration);
|
|
70
|
+
const { initNavDecorators, navItemClicked, navItemHovered, resetHoverToActivePosition } = useTabs(props.axis, tabsNavRef, tabsContentRefs, props.transitionDuration);
|
|
67
71
|
|
|
68
72
|
onMounted(() => {
|
|
69
73
|
initNavDecorators();
|
|
@@ -71,7 +75,7 @@ onMounted(() => {
|
|
|
71
75
|
</script>
|
|
72
76
|
|
|
73
77
|
<style lang="css">
|
|
74
|
-
.tabs {
|
|
78
|
+
.tabs-core {
|
|
75
79
|
/*
|
|
76
80
|
* CSS var within /assets/styles/components/tabs.css
|
|
77
81
|
*/
|
|
@@ -108,7 +112,7 @@ onMounted(() => {
|
|
|
108
112
|
bottom: 0;
|
|
109
113
|
top: 0;
|
|
110
114
|
scale: var(--_width-hovered, 0.125) 1;
|
|
111
|
-
translate: var(--
|
|
115
|
+
translate: var(--_x-hovered, 0) 0;
|
|
112
116
|
transform-origin: left;
|
|
113
117
|
transition: scale var(--_transition-duration), translate var(--_transition-duration);
|
|
114
118
|
z-index: 1;
|
|
@@ -122,7 +126,7 @@ onMounted(() => {
|
|
|
122
126
|
bottom: 0;
|
|
123
127
|
top: 0;
|
|
124
128
|
scale: var(--_width-active, 0.125) 1;
|
|
125
|
-
translate: var(--
|
|
129
|
+
translate: var(--_x-active, 0) 0;
|
|
126
130
|
transform-origin: left;
|
|
127
131
|
transition: scale var(--_transition-duration), translate var(--_transition-duration);
|
|
128
132
|
z-index: 2;
|
|
@@ -135,7 +139,7 @@ onMounted(() => {
|
|
|
135
139
|
right: 0;
|
|
136
140
|
bottom: 0;
|
|
137
141
|
scale: var(--_width-active, 0.125) 1;
|
|
138
|
-
translate: var(--
|
|
142
|
+
translate: var(--_x-active, 0) 0;
|
|
139
143
|
transform-origin: left;
|
|
140
144
|
transition: scale var(--_transition-duration), translate var(--_transition-duration);
|
|
141
145
|
z-index: 3;
|
|
@@ -185,6 +189,7 @@ onMounted(() => {
|
|
|
185
189
|
padding: 1em 2em;
|
|
186
190
|
|
|
187
191
|
&:hover {
|
|
192
|
+
/* background: var(--_tabs-hovered-bg); */
|
|
188
193
|
color: var(--_tabs-hovered-text);
|
|
189
194
|
}
|
|
190
195
|
|
|
@@ -226,4 +231,78 @@ onMounted(() => {
|
|
|
226
231
|
} */
|
|
227
232
|
}
|
|
228
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
|
+
}
|
|
229
308
|
</style>
|
package/composables/useTabs.ts
CHANGED
|
@@ -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) => {
|
|
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>();
|
|
@@ -112,18 +112,26 @@ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLE
|
|
|
112
112
|
|
|
113
113
|
const setFinalHoveredPositions = (resized: boolean = false) => {
|
|
114
114
|
const setDuration = resized ? 0 : duration;
|
|
115
|
+
// const tabsNavRefYPosition = tabsNavRef.value?.getBoundingClientRect().top || 0;
|
|
115
116
|
const newTabWidth = currentHoveredTab.value && tabsNavRef.value ? currentHoveredTab.value.offsetWidth / tabsNavRef.value.offsetWidth : 0;
|
|
116
117
|
tabsNavRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
|
|
117
|
-
tabsNavRef.value?.style.setProperty('--
|
|
118
|
+
tabsNavRef.value?.style.setProperty('--_x-hovered', currentHoveredTab.value?.offsetLeft + 'px');
|
|
119
|
+
|
|
118
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');
|
|
119
124
|
};
|
|
120
125
|
|
|
121
126
|
const setFinalActivePositions = (resized: boolean = false) => {
|
|
122
127
|
const setDuration = resized ? 0 : duration;
|
|
123
128
|
const newTabWidth = currentActiveTab.value && tabsNavRef.value ? currentActiveTab.value.offsetWidth / tabsNavRef.value.offsetWidth : 0;
|
|
124
129
|
tabsNavRef.value?.style.setProperty('--_transition-duration', setDuration + 'ms');
|
|
125
|
-
tabsNavRef.value?.style.setProperty('--
|
|
130
|
+
tabsNavRef.value?.style.setProperty('--_x-active', currentActiveTab.value?.offsetLeft + 'px');
|
|
126
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');
|
|
127
135
|
};
|
|
128
136
|
|
|
129
137
|
const moveActiveIndicator = () => {
|
|
@@ -136,7 +144,7 @@ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLE
|
|
|
136
144
|
transitionWidth = currentActiveTab.value && previousActiveTab.value ? currentActiveTab.value.offsetLeft + currentActiveTab.value.offsetWidth - previousActiveTab.value.offsetLeft : 0;
|
|
137
145
|
} else {
|
|
138
146
|
transitionWidth = previousActiveTab.value && currentActiveTab.value ? previousActiveTab.value.offsetLeft + previousActiveTab.value.offsetWidth - currentActiveTab.value.offsetLeft : 0;
|
|
139
|
-
tabsNavRef.value?.style.setProperty('--
|
|
147
|
+
tabsNavRef.value?.style.setProperty('--_x-active', currentActiveTab.value ? currentActiveTab.value.offsetLeft + 'px' : '0');
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
tabsNavRef.value?.style.setProperty('--_width-active', String(transitionWidth / tabsNavRef.value.offsetWidth));
|
|
@@ -158,7 +166,7 @@ const useTabs = (tabsNavRef: Ref<HTMLElement | null>, tabsContentRefs: Ref<HTMLE
|
|
|
158
166
|
transitionWidth = currentHoveredTab.value && previousHoveredTab.value ? currentHoveredTab.value.offsetLeft + currentHoveredTab.value.offsetWidth - previousHoveredTab.value.offsetLeft : 0;
|
|
159
167
|
} else {
|
|
160
168
|
transitionWidth = previousHoveredTab.value && currentHoveredTab.value ? previousHoveredTab.value.offsetLeft + previousHoveredTab.value.offsetWidth - currentHoveredTab.value.offsetLeft : 0;
|
|
161
|
-
tabsNavRef.value?.style.setProperty('--
|
|
169
|
+
tabsNavRef.value?.style.setProperty('--_x-hovered', currentHoveredTab.value ? currentHoveredTab.value.offsetLeft + 'px' : '0');
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
tabsNavRef.value?.style.setProperty('--_width-hovered', String(transitionWidth / tabsNavRef.value.offsetWidth));
|
package/package.json
CHANGED