Skip to content

Commit

Permalink
feat(Tabs): implemented click event and icon slot on pf-tab and all…
Browse files Browse the repository at this point in the history
…owed to set href and target on the tab link
  • Loading branch information
mtorromeo committed Nov 26, 2023
1 parent 3d6d2b5 commit 1cab563
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 25 deletions.
39 changes: 28 additions & 11 deletions packages/core/src/components/Tabs/Tab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,30 @@
:class="[styles.tabsItem, {
[styles.modifiers.current]: key === activeKey,
}]">
<button
:id="`pf-tab-${String(key )}-${String(idSuffix)}`"
type="button"
<pf-tab-button
:id="`pf-tab-${typeof key === 'symbol' ? (key.description ?? '') : key}-${String(idSuffix)}`"
:class="[styles.tabsLink, {
[styles.modifiers.disabled]: disabled && href,
[styles.modifiers.ariaDisabled]: ariaDisabled,
}]"
:href="href"
:target="target"
:disabled="disabled && !href"
:tabindex="disabled || ariaDisabled ? (href ? -1 : undefined) : undefined"
:aria-disabled="disabled || ariaDisabled"
:aria-controls="`pf-tab-section-${String(key)}-${String(idSuffix)}`"
:tabindex="disabled || ariaDisabled ? (href ? -1 : undefined) : undefined"
@click="activeKey = key"
:aria-selected="activeKey === key"
role="tab"
@click="handleClick($event as PointerEvent)"
>
<pf-tab-title-icon v-if="$slots.icon">
<slot name="icon" />
</pf-tab-title-icon>
<pf-tab-title-text v-if="title">
{{ title }}
</pf-tab-title-text>
<slot v-else />
</button>
</pf-tab-button>
</li>
</teleport>

Expand All @@ -40,7 +46,9 @@
import styles from '@patternfly/react-styles/css/components/Tabs/tabs';
import { computed, getCurrentInstance, inject, ref, watch, watchEffect, type HTMLAttributes } from 'vue';
import { TabsKey, TabsProvideKey } from './Tabs.vue';
import PfTabTitleIcon from './TabTitleIcon.vue';
import PfTabTitleText from './TabTitleText.vue';
import PfTabButton from './TabButton.vue';
import PfTabContent from './TabContent.vue';
import { useChildrenTracker } from '../../use';
Expand All @@ -52,28 +60,30 @@ defineOptions({
export interface Props extends /* @vue-ignore */ HTMLAttributes {
/** Content rendered in the tab title. */
title?: string;
/** URL associated with the Tab. A Tab with an href will render as an <a> instead of a <button>. A Tab inside a <Tabs component="nav"> should have an href. */
href?: string;
/** Link target */
target?: string;
/** Adds disabled styling and disables the button using the disabled html attribute */
disabled?: boolean;
/** Adds disabled styling and communicates that the button is disabled using the aria-disabled html attribute */
ariaDisabled?: boolean;
contentRef?: InstanceType<typeof PfTabContent>;
/** Waits until the first "enter" transition to mount tab children (add them to the DOM) */
mountOnEnter?: boolean;
/** Unmounts tab children (removes them from the DOM) when they are no longer visible */
unmountOnExit?: boolean;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(name: 'click', event: PointerEvent): void;
}>();
defineSlots<{
default?: (props?: Record<never, never>) => any;
icon?: (props?: Record<never, never>) => any;
}>();
const instance = getCurrentInstance();
Expand Down Expand Up @@ -102,6 +112,13 @@ watchEffect(() => {
}
});
function handleClick(event: PointerEvent) {
if (activeKey) {
activeKey.value = key.value;
}
emit('click', event);
}
defineExpose({
key,
});
Expand Down
24 changes: 24 additions & 0 deletions packages/core/src/components/Tabs/TabButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<component :is="href ? 'a' : 'button'" :type="href ? undefined : 'button'" :href="href">
<slot />
</component>
</template>

<script lang="ts" setup>
import type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'vue';
defineOptions({
name: 'PfTabButton',
});
export interface Props extends /* @vue-ignore */ Omit<ButtonHTMLAttributes, 'type'>, /* @vue-ignore */ Omit<AnchorHTMLAttributes, 'type'> {
/** URL associated with the Tab. A Tab with an href will render as an <a> instead of a <button>. A Tab inside a <Tabs component="nav"> should have an href. */
href?: string;
}
defineProps<Props>();
defineSlots<{
default?: (props?: Record<never, never>) => any;
}>();
</script>
17 changes: 3 additions & 14 deletions packages/core/src/components/Tabs/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
[styles.modifiers.box]: box,
[styles.modifiers.scrollable]: !vertical && showScrollButtons,
[styles.modifiers.pageInsets]: pageInsets,
[styles.modifiers.noBorderBottom]: noBorderBottom,
[styles.modifiers.colorSchemeLight_300]: variant === 'light300',
}]"
>
Expand Down Expand Up @@ -66,46 +67,34 @@ export type TabKey = number | string | symbol;
export interface Props extends InsetBreakpointProps, /* @vue-ignore */ HTMLAttributes {
id?: string;
/** Tabs background color variant */
variant?: 'default' | 'light300';
/** The index of the active tab */
activeKey?: TabKey;
/** The index of the default active tab. Set this for uncontrolled Tabs */
defaultActiveKey?: TabKey;
/** Enables the filled tab list layout */
filled?: boolean;
/** Enables secondary tab styling */
secondary?: boolean;
/** Enables box styling to the tab component */
box?: boolean;
/** Enables vertical tab styling */
vertical?: boolean;
/** Disables border bottom tab styling on tabs. Defaults to false. To remove the bottom border, set this prop to true. */
noBorderBottom?: boolean;
/** Aria-label for the left scroll button */
leftScrollAriaLabel?: string;
/** Aria-label for the right scroll button */
rightScrollAriaLabel?: string;
/** Determines what tag is used around the tabs. Use "nav" to define the tabs inside a navigation region */
component?: 'div' | 'nav';
/** Provides an accessible label for the tabs. Labels should be unique for each set of tabs that are present on a page. When component is set to nav, this prop should be defined to differentiate the tabs from other navigation regions on the page. */
ariaLabel?: string;
/** Waits until the first "enter" transition to mount tab children (add them to the DOM) */
mountOnEnter?: boolean;
/** Unmounts tab children (removes them from the DOM) when they are no longer visible */
unmountOnExit?: boolean;
/** Flag indicates that the tabs should use page insets. */
pageInsets?: boolean;
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/components/Tabs/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as PfTabs } from './Tabs.vue';
export { default as PfTab } from './Tab.vue';
export { default as PfTabButton } from './TabButton.vue';
export { default as PfTabContent } from './TabContent.vue';
export { default as PfTabTitleText } from './TabTitleText.vue';
export { default as PfTabTitleIcon } from './TabTitleIcon.vue';

0 comments on commit 1cab563

Please sign in to comment.