Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ktabs): add before change prop #2644

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions docs/components/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,80 @@ const tabChange = (hash: string): void => {
</script>
```

### beforeChange

Prop that takes a function return value of which determines whether tab change should be skipped. Useful when some information needs to me brought to user's attention before they leave the content in the currently displayed tab.

The function receives new tab value as an argument and returns a boolean value, `false` will prevent tab change. Defaults to `() => true`.

<KTabs
:before-change="onBeforeTabChange"
:model-value="confirmedTab"
:tabs="tabs"
>
<template #tab1>
Tab 1 content
</template>
<template #tab2>
Tab 2 content
</template>
</KTabs>

<KPrompt
message="Notice that the tab doesn't change until you've confirmed your action."
:visible="confirmPromptVisible"
@cancel="onCancel"
@proceed="onConfirm"
/>

```vue
<template>
<KTabs
:before-change="onBeforeTabChange"
:model-value="activeTab"
:tabs="tabs"
>
<template #tab1>
Tab 1 content
</template>
<template #tab2>
Tab 2 content
</template>
</KTabs>

<KPrompt
message="Notice that the tab doesn't change until you've confirmed your action."
:visible="confirmPromptVisible"
@cancel="onCancel"
@proceed="onConfirm"
/>
</template>

<script setup lang="ts">
const activeTab = ref<string>('#tab1')
const confirmPromptVisible = ref<boolean>(false)
const targetTab = ref<string | null>(null)

const onBeforeTabChange = (tab: string) => {
confirmPromptVisible.value = true
targetTab.value = tab

return false
}

const onConfirm = () => {
confirmPromptVisible.value = false
activeTab.value = targetTab.value!
targetTab.value = null
}

const onCancel = () => {
confirmPromptVisible.value = false
targetTab.value = null
}
</script>
```

## Slots

### anchor & panel
Expand Down Expand Up @@ -351,6 +425,25 @@ const panelsActiveHash = ref('#gateway')
const panelsChange = (hash: string) => {
panelsActiveHash.value = hash;
}

const confirmedTab = ref<string>('#tab1')
const confirmPromptVisible = ref<boolean>(false)
const targetTab = ref<string | null>(null)
const onBeforeTabChange = (tab: string) => {
confirmPromptVisible.value = true
targetTab.value = tab

return false
}
const onConfirm = () => {
confirmPromptVisible.value = false
confirmedTab.value = targetTab.value!
targetTab.value = null
}
const onCancel = () => {
confirmPromptVisible.value = false
targetTab.value = null
}
</script>

<style lang="scss" scoped>
Expand Down
43 changes: 43 additions & 0 deletions sandbox/pages/SandboxTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,30 @@
Tab 3 content
</div>
</SandboxSectionComponent>
<SandboxSectionComponent title="beforeChange">
<KTabs
:before-change="onBeforeTabChange"
:model-value="confirmedTab"
:tabs="items"
>
<template #tab1>
Tab 1 content
</template>
<template #tab2>
Tab 2 content
</template>
<template #tab3>
Tab 3 content
</template>
</KTabs>

<KPrompt
message="Notice that the tab doesn't change until you've confirmed your action."
:visible="confirmPromptVisible"
@cancel="onCancel"
@proceed="onConfirm"
/>
</SandboxSectionComponent>

<!-- Slots -->
<SandboxTitleComponent
Expand Down Expand Up @@ -155,6 +179,7 @@ const items = [

const vModel1 = ref<string>('#tab2')
const vModel2 = ref<string>('#tab2')
const confirmedTab = ref<string>('#tab1')

const dynamicRouterViewItems = [
{
Expand All @@ -168,4 +193,22 @@ const dynamicRouterViewItems = [
to: { hash: '#two' },
},
]

const confirmPromptVisible = ref<boolean>(false)
const targetTab = ref<string | null>(null)
const onBeforeTabChange = (tab: string) => {
confirmPromptVisible.value = true
targetTab.value = tab

return false
}
const onConfirm = () => {
confirmPromptVisible.value = false
confirmedTab.value = targetTab.value!
targetTab.value = null
}
const onCancel = () => {
confirmPromptVisible.value = false
targetTab.value = null
}
</script>
13 changes: 13 additions & 0 deletions src/components/KTabs/KTabs.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,19 @@ describe('KTabs', () => {
cy.get('.tab-item .tab-link').eq(1).should('not.have.attr', 'href')
})

it('does not change the tab when beforeChange returns false', () => {
cy.mount(KTabs, {
props: {
tabs: TABS,
beforeChange: () => false,
},
})

cy.get('.tab-item').eq(1).click().then(() => {
cy.wrap(Cypress.vueWrapper.emitted()).should('not.have.property', 'change')
})
})

describe('slots', () => {
it('provides the #hash slot content', () => {
const picturesSlot = 'I love pictures'
Expand Down
12 changes: 9 additions & 3 deletions src/components/KTabs/KTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ const props = defineProps({
default: 0,
validator: (val: number): boolean => val >= -1 && val <= 32767,
},
beforeChange: {
type: Function as PropType<(tab: string) => boolean>,
default: () => true,
},
})

const emit = defineEmits<{
Expand All @@ -97,9 +101,11 @@ const emit = defineEmits<{
const activeTab = ref<string>(props.modelValue ? props.modelValue : props.tabs[0]?.hash)

const handleTabChange = (tab: string): void => {
activeTab.value = tab
emit('change', tab)
emit('update:modelValue', tab)
if (props.beforeChange(tab)) {
activeTab.value = tab
emit('change', tab)
emit('update:modelValue', tab)
}
}

const getTabSlotName = (tabHash: string): string => tabHash.replace('#', '')
Expand Down