Skip to content

Commit

Permalink
feat(tabs|steps): add animation and animateInitially prop (#797)
Browse files Browse the repository at this point in the history
* feat(tabs|steps): add animation and animateInitially prop

* fix(step): fix wrong animation 

* fix(tabs): fix wrong animation
  • Loading branch information
mlmoravek authored Feb 23, 2024
1 parent 18a45f2 commit f04362e
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 79 deletions.
38 changes: 20 additions & 18 deletions packages/docs-next/components/Steps.md

Large diffs are not rendered by default.

26 changes: 14 additions & 12 deletions packages/docs-next/components/Tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,20 @@ title: Tabs

### Props

| Prop name | Description | Type | Values | Default |
| --------- | ----------------------------------------------- | -------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| animated | Tab will have an animation | boolean | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;animated: true<br>}</code> |
| expanded | Tabs will be expanded (full-width) | boolean | - | <code style='white-space: nowrap; padding: 0;'>false</code> |
| multiline | Show tab items multiline when there is no space | boolean | - | <code style='white-space: nowrap; padding: 0;'>false</code> |
| override | Override existing theme classes completely | boolean | - | |
| position | Position of the tabs | string | `left`, `centered`, `right` | |
| size | Tab size | string | `small`, `medium`, `large` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;size: undefined<br>}</code> |
| type | Tab type | string | `boxed`, `toggle` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;type: "default"<br>}</code> |
| v-model | | string\|number | - | <code style='white-space: nowrap; padding: 0;'>0</code> |
| variant | Color of the control | string | `primary`, `info`, `success`, `warning`, `danger`, `and any other custom color` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;variant: undefined<br>}</code> |
| vertical | Show tab in vertical layout | boolean | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;vertical: false<br>}</code> |
| Prop name | Description | Type | Values | Default |
| ---------------- | ----------------------------------------------- | ------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| animateInitially | Apply animation on the initial render | boolean | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;animateInitially: false<br>}</code> |
| animated | Tab will have an animation | boolean | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;animated: true<br>}</code> |
| animation | Transition animation name | Array&lt;string&gt; | `[next`, `prev]`, `[right`, `left`, `down`, `up]` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;animation: [ "slide-next", "slide-prev", "slide-down", "slide-up", ]<br>}</code> |
| expanded | Tabs will be expanded (full-width) | boolean | - | <code style='white-space: nowrap; padding: 0;'>false</code> |
| multiline | Show tab items multiline when there is no space | boolean | - | <code style='white-space: nowrap; padding: 0;'>false</code> |
| override | Override existing theme classes completely | boolean | - | |
| position | Position of the tabs | string | `left`, `centered`, `right` | |
| size | Tab size | string | `small`, `medium`, `large` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;size: undefined<br>}</code> |
| type | Tab type | string | `boxed`, `toggle` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;type: "default"<br>}</code> |
| v-model | | string\|number | - | <code style='white-space: nowrap; padding: 0;'>0</code> |
| variant | Color of the control | string | `primary`, `info`, `success`, `warning`, `danger`, `and any other custom color` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;variant: undefined<br>}</code> |
| vertical | Show tab in vertical layout | boolean | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>tabs: {<br>&nbsp;&nbsp;vertical: false<br>}</code> |

### Events

Expand Down
32 changes: 18 additions & 14 deletions packages/oruga-next/src/components/steps/StepItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -117,30 +117,32 @@ const isActive = computed(() => parent.value.activeId === props.value);
const isTransitioning = ref(false);
const nextAnimation = computed(() => {
const idx =
parent.value.vertical && parent.value.animation.length === 4 ? 2 : 0;
return parent.value.animation[idx];
});
const prevAnimation = computed(() => {
const idx =
parent.value.vertical && parent.value.animation.length === 4 ? 3 : 1;
return parent.value.animation[idx];
});
/** Activate element, alter animation name based on the index. */
function activate(oldIndex: number): void {
transitionName.value =
item.value.index < oldIndex
? parent.value.vertical
? "slide-down"
: "slide-next"
: parent.value.vertical
? "slide-up"
: "slide-prev";
item.value.index < oldIndex ? nextAnimation.value : prevAnimation.value;
// emit event
emits("activate");
}
/** Deactivate element, alter animation name based on the index. */
function deactivate(newIndex: number): void {
transitionName.value =
newIndex < item.value.index
? parent.value.vertical
? "slide-down"
: "slide-next"
: parent.value.vertical
? "slide-up"
: "slide-prev";
newIndex < item.value.index ? nextAnimation.value : prevAnimation.value;
// emit event
emits("deactivate");
}
Expand All @@ -162,7 +164,9 @@ const elementClasses = defineClasses(["itemClass", "o-steps__item"]);

<template>
<Transition
:disabled="!parent.animated"
:name="transitionName"
:appear="parent.animateInitially"
@after-enter="afterEnter"
@before-leave="beforeLeave">
<div
Expand Down
42 changes: 35 additions & 7 deletions packages/oruga-next/src/components/steps/Steps.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,27 @@ const props = defineProps({
type: Boolean,
default: () => getOption("steps.animated", true),
},
/**
* Transition animation name
* @values [next, prev], [right, left, down, up]
*/
animation: {
type: Array as PropType<Array<string>>,
default: () =>
getOption("tabs.animation", [
"slide-next",
"slide-prev",
"slide-down",
"slide-up",
]),
validator: (value: Array<string>) =>
value.length === 2 || value.length === 4,
},
/** Apply animation on the initial render */
animateInitially: {
type: Boolean,
default: () => getOption("steps.animateInitially", false),
},
/**
* Position of the marker label
* @values bottom, right, left
Expand Down Expand Up @@ -225,6 +246,9 @@ const rootRef = ref();
const provideData = computed(() => ({
activeId: activeId.value,
vertical: props.vertical,
animated: props.animated,
animation: props.animation,
animateInitially: props.animateInitially,
}));
/** Provide functionalities and data to child item components */
Expand All @@ -242,7 +266,7 @@ const items = computed<StepItem[]>(() =>
const activeId = useVModelBinding(props, emits, { passive: true });
/** When v-model is changed set the new active tab. */
/** When v-model is changed set the new active tab. */
watch(
() => props.modelValue,
(value) => {
Expand Down Expand Up @@ -321,13 +345,17 @@ function itemClick(item: StepItem): void {
/** Activate next child and deactivate prev child */
function performAction(newId: number | string): void {
const oldId = activeItem.value.value;
const oldItem = items.value.find((item) => item.value === oldId);
activeId.value = newId;
const oldItem = activeItem.value;
const newItem =
items.value.find((item) => item.value === newId) || items.value[0];
if (oldItem && newItem) {
oldItem.deactivate(newItem.index);
newItem.activate(oldItem.index);
}
nextTick(() => {
if (oldItem && activeItem.value) {
oldItem.deactivate(activeItem.value.index);
activeItem.value.activate(oldItem.index);
}
activeId.value = newId;
emits("change", newId, oldId);
});
}
Expand Down
3 changes: 3 additions & 0 deletions packages/oruga-next/src/components/steps/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export type StepItemComponent = StepItemProps & {
export type StepsComponent = {
activeId: string | number;
vertical: boolean;
animated: boolean;
animation: string[];
animateInitially: boolean;
};

export type StepItem = Omit<ProviderItem, "data"> & StepItemComponent;
32 changes: 18 additions & 14 deletions packages/oruga-next/src/components/tabs/TabItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,30 +118,32 @@ const isActive = computed(() => parent.value.activeId === props.value);
const isTransitioning = ref(false);
const nextAnimation = computed(() => {
const idx =
parent.value.vertical && parent.value.animation.length === 4 ? 2 : 0;
return parent.value.animation[idx];
});
const prevAnimation = computed(() => {
const idx =
parent.value.vertical && parent.value.animation.length === 4 ? 3 : 1;
return parent.value.animation[idx];
});
/** Activate element, alter animation name based on the index. */
function activate(oldIndex: number): void {
transitionName.value =
item.value.index < oldIndex
? parent.value.vertical
? "slide-down"
: "slide-next"
: parent.value.vertical
? "slide-up"
: "slide-prev";
item.value.index < oldIndex ? nextAnimation.value : prevAnimation.value;
// emit event
emits("activate");
}
/** Deactivate element, alter animation name based on the index. */
function deactivate(newIndex: number): void {
transitionName.value =
newIndex < item.value.index
? parent.value.vertical
? "slide-down"
: "slide-next"
: parent.value.vertical
? "slide-up"
: "slide-prev";
newIndex < item.value.index ? nextAnimation.value : prevAnimation.value;
// emit event
emits("deactivate");
}
Expand Down Expand Up @@ -173,7 +175,9 @@ const headerTextClasses = defineClasses([

<template>
<Transition
:disabled="!parent.animated"
:name="transitionName"
:appear="parent.animateInitially"
@after-enter="afterEnter"
@before-leave="beforeLeave">
<div
Expand Down
47 changes: 37 additions & 10 deletions packages/oruga-next/src/components/tabs/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,27 @@ const props = defineProps({
type: Boolean,
default: () => getOption("tabs.animated", true),
},
/**
* Transition animation name
* @values [next, prev], [right, left, down, up]
*/
animation: {
type: Array as PropType<Array<string>>,
default: () =>
getOption("tabs.animation", [
"slide-next",
"slide-prev",
"slide-down",
"slide-up",
]),
validator: (value: Array<string>) =>
value.length === 2 || value.length === 4,
},
/** Apply animation on the initial render */
animateInitially: {
type: Boolean,
default: () => getOption("tabs.animateInitially", false),
},
/** Show tab items multiline when there is no space */
multiline: { type: Boolean, default: false },
// class props (will not be displayed in the docs)
Expand Down Expand Up @@ -162,6 +183,9 @@ const provideData = computed(() => ({
activeId: activeId.value,
type: props.type,
vertical: props.vertical,
animated: props.animated,
animation: props.animation,
animateInitially: props.animateInitially,
}));
/** Provide functionalities and data to child item components */
Expand Down Expand Up @@ -256,17 +280,19 @@ function clickFirstViableChild(startingIndex: number, forward: boolean): void {
/** Activate next child and deactivate prev child */
function performAction(newId: number | string): void {
const oldValue = activeId.value;
const oldTab = isDefined(oldValue)
? items.value.find((item) => item.value === oldValue) || items.value[0]
: items.value[0];
activeId.value = newId;
const oldId = activeId.value;
const oldItem = activeItem.value;
const newItem =
items.value.find((item) => item.value === newId) || items.value[0];
if (oldItem && newItem) {
oldItem.deactivate(newItem.index);
newItem.activate(oldItem.index);
}
nextTick(() => {
if (oldTab && activeItem.value) {
oldTab.deactivate(activeItem.value.index);
activeItem.value.activate(oldTab.index);
}
emits("change", newId, oldValue);
activeId.value = newId;
emits("change", newId, oldId);
});
}
Expand Down Expand Up @@ -389,6 +415,7 @@ function itemHeaderClasses(
@keydown.down.prevent="next"
@keydown.home.prevent="homePressed"
@keydown.end.prevent="endPressed" />

<component
:is="childItem.tag"
v-else
Expand Down
3 changes: 3 additions & 0 deletions packages/oruga-next/src/components/tabs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export type TabsComponent = {
activeId: number;
type: string;
vertical: boolean;
animated: boolean;
animation: string[];
animateInitially: boolean;
};

export type TabItem = Omit<ProviderItem, "data"> & TabItemComponent;
Loading

0 comments on commit f04362e

Please sign in to comment.