Skip to content

Commit

Permalink
feat(steps): support w3c WAI-ARIA pattern (#1183)
Browse files Browse the repository at this point in the history
  • Loading branch information
mlmoravek authored Feb 13, 2025
1 parent 21dff42 commit c0f9c9f
Show file tree
Hide file tree
Showing 16 changed files with 608 additions and 552 deletions.
4 changes: 2 additions & 2 deletions packages/docs/components/Steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ Breaking things down into multiple steps can improve the user experience by keep

| Prop name | Description | Type | Values | Default |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| activateOnFocus | Set the step active on navigation focus | boolean | - | <code style='white-space: nowrap; padding: 0;'>false</code> |
| animateInitially | Apply animation on the initial render | boolean | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;animateInitially: false<br>}</code> |
| animated | Step navigation is animated | boolean | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;animated: true<br>}</code> |
| animation | Transition animation name | [string, string, string, string] \| [string, string] | `[next`, `prev]`, `[right`, `left`, `down`, `up]` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;animation: [ "slide-next", "slide-prev", "slide-down", "slide-up",]<br>}</code> |
| ariaLabel | Accessibility aria-label to be passed to the tablist wrapper element | string | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;ariaLabel: undefined<br>}</code> |
| ariaNextLabel | Accessibility next button aria label | string | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;ariaNextLabel: "Next"<br>}</code> |
| ariaPreviousLabel | Accessibility previous button aria label | string | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;ariaPreviousLabel: "Previous"<br>}</code> |
| hasNavigation | Next and previous buttons below the component. You can use this property if you want to use your own custom navigation items. | boolean | - | <code style='white-space: nowrap; padding: 0;'>true</code> |
Expand Down Expand Up @@ -91,7 +93,6 @@ Breaking things down into multiple steps can improve the user experience by keep

| Prop name | Description | Type | Values | Default |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| ariaRole | Role attribute to be passed to the li wrapper for better accessibility | string | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;ariaRole: "tab"<br>}</code> |
| clickable | Item can be used directly to navigate.<br/>If undefined, previous steps are clickable while the others are not | boolean | - | |
| component | Component to be injected. | Component | - | |
| content | Text content, unnecessary when default slot is used | string | - | |
Expand All @@ -103,7 +104,6 @@ Breaking things down into multiple steps can improve the user experience by keep
| override | Override existing theme classes completely | boolean | - | |
| props | Props to be binded to the injected component | any | - | |
| step | Step marker content (when there is no icon) | number \| string | - | |
| tag | Step item tag name | DynamicComponent | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>steps: {<br>&nbsp;&nbsp;itemTag: "button"<br>}</code> |
| value | Item value (it will be used as v-model of wrapper component) - default is an uuid | string\|number\|object | - | |
| variant | Default style for the step.<br/>This will override parent type.<br/>Could be used to set a completed step to "success" for example | string | - | |
| visible | Show/hide item | boolean | - | <code style='white-space: nowrap; padding: 0;'>true</code> |
Expand Down
48 changes: 21 additions & 27 deletions packages/oruga/src/components/steps/StepItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ const props = withDefaults(defineProps<StepItemProps<T, C>>(), {
visible: true,
icon: () => getDefault("steps.icon"),
iconPack: () => getDefault("steps.iconPack"),
tag: () => getDefault("steps.itemTag", "button"),
ariaRole: () => getDefault("steps.ariaRole", "tab"),
content: undefined,
component: undefined,
props: undefined,
Expand All @@ -48,15 +46,14 @@ const itemValue = props.value ?? useId();
const slots = useSlots();
// provided data is a computed ref to enjure reactivity
// provided data is a computed ref to ensure reactivity
const providedData = computed<StepItemComponent<T>>(() => ({
...props,
value: itemValue,
$slots: slots,
navClasses: navItemClasses.value,
stepClasses: stepClasses.value,
labelClasses: stepLabelClasses.value,
iconClasses: stepIconClasses.value,
labelClasses: stepLabelClasses.value,
isTransitioning: isTransitioning.value,
activate,
deactivate,
Expand Down Expand Up @@ -118,45 +115,40 @@ function beforeLeave(): void {
// --- Computed Component Classes ---
const navItemClasses = defineClasses(
["navItemClass", "o-steps__nav-item"],
const stepClasses = defineClasses(
["stepClass", "o-steps__step"],
[
"navItemVariantClass",
"o-steps__nav-item--",
"stepVariantClass",
"o-steps__step--",
computed(() => parent.value?.variant || props.variant),
computed(() => !!parent.value?.variant || !!props.variant),
],
["navItemActiveClass", "o-steps__nav-item--active", null, isActive],
["stepActiveClass", "o-steps__step--active", null, isActive],
["stepClickableClass", "o-steps__step--clickable", null, isClickable],
[
"stepDisabledClass",
"o-steps__step--disabled",
null,
computed(() => props.disabled),
],
[
"navItemPreviousClass",
"o-steps__nav-item--previous",
"stepPreviousClass",
"o-steps__step--previous",
null,
computed(() => item.value.index < parent.value?.activeIndex),
],
[
"navItemNextClass",
"o-steps__nav-item--next",
"stepNextClass",
"o-steps__step--next",
null,
computed(() => item.value.index > parent.value?.activeIndex),
],
);
const stepClasses = defineClasses(
["stepClass", "o-steps__step"],
[
"stepLabelPositionClass",
"o-steps__step-label-",
"o-steps__step--label-",
computed(() => parent.value?.labelPosition),
computed(() => !!parent.value?.labelPosition),
],
["stepActiveClass", "o-steps__step--active", null, isActive],
["stepClickableClass", "o-steps__step--clickable", null, isClickable],
[
"stepDisabledClass",
"o-steps__step--disabled",
null,
computed(() => props.disabled),
],
);
const stepLabelClasses = defineClasses([
Expand Down Expand Up @@ -184,6 +176,8 @@ const panelClasses = defineClasses(["stepPanelClass", "o-steps__panel"]);
data-oruga="steps-item"
:data-id="`steps-${item.identifier}`"
:class="panelClasses"
role="tabpanel"
:hidden="!isActive"
:aria-labelledby="`tab-${item.identifier}`"
aria-roledescription="item">
<!--
Expand Down
Loading

0 comments on commit c0f9c9f

Please sign in to comment.