fix(primitives): eslint/tsconfig migration, asChild refactor, type fixes
- Migrate to eslint flat config + composite tsconfig. - Complete the asChild→as="template" refactor (remove asChild prop + :as-child bindings across components, matching Primitive's slot model). - Fix test type errors and source type-safety (useGraceArea hull/point math, FocusScope/util ref typing). Note: ~53 vue-tsc errors remain (HTML attr/event passthrough typing on transparent wrapper components + a couple of duplicate-export naming collisions) — not gated by CI (build/lint/test green); pending a component-attribute-typing design decision.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
import type { PrimitiveProps } from '../primitive';
|
||||
|
||||
export interface StepperDescriptionProps extends PrimitiveProps {}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Primitive } from '../primitive';
|
||||
import { useForwardExpose } from '@robonen/vue';
|
||||
import { useStepperItemContext } from './context';
|
||||
|
||||
const { as = 'p' } = defineProps<StepperDescriptionProps>();
|
||||
|
||||
const item = useStepperItemContext();
|
||||
const { forwardRef } = useForwardExpose();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive
|
||||
:ref="forwardRef"
|
||||
:as="as"
|
||||
:id="item.descriptionId"
|
||||
>
|
||||
<slot />
|
||||
</Primitive>
|
||||
</template>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script lang="ts">
|
||||
import type { PrimitiveProps } from '../primitive';
|
||||
|
||||
export interface StepperIndicatorProps extends PrimitiveProps {}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Primitive } from '../primitive';
|
||||
import { useForwardExpose } from '@robonen/vue';
|
||||
import { useStepperItemContext } from './context';
|
||||
|
||||
const { as = 'div' } = defineProps<StepperIndicatorProps>();
|
||||
|
||||
const item = useStepperItemContext();
|
||||
const { forwardRef } = useForwardExpose();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive
|
||||
:ref="forwardRef"
|
||||
:as="as"
|
||||
:data-state="item.state.value"
|
||||
>
|
||||
<slot :step="item.step.value" :state="item.state.value">
|
||||
{{ item.step.value }}
|
||||
</slot>
|
||||
</Primitive>
|
||||
</template>
|
||||
@@ -0,0 +1,63 @@
|
||||
<script lang="ts">
|
||||
import type { PrimitiveProps } from '../primitive';
|
||||
|
||||
export interface StepperItemProps extends PrimitiveProps {
|
||||
/** 1-based index associating this item with a step. */
|
||||
step: number;
|
||||
/** Disable this specific step. */
|
||||
disabled?: boolean;
|
||||
/** Mark the step as completed regardless of current `modelValue`. */
|
||||
completed?: boolean;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, toRef } from 'vue';
|
||||
import { provideStepperItemContext, useStepperRootContext } from './context';
|
||||
import { Primitive } from '../primitive';
|
||||
import { useForwardExpose } from '@robonen/vue';
|
||||
import { useId } from '../config-provider';
|
||||
|
||||
const { as = 'div', step, disabled = false, completed = false } = defineProps<StepperItemProps>();
|
||||
|
||||
const root = useStepperRootContext();
|
||||
const { forwardRef } = useForwardExpose();
|
||||
|
||||
const state = computed(() => {
|
||||
if (completed) return 'completed' as const;
|
||||
if (root.value.value === step) return 'active' as const;
|
||||
if (root.value.value > step) return 'completed' as const;
|
||||
return 'inactive' as const;
|
||||
});
|
||||
|
||||
const focusable = computed(() => {
|
||||
if (disabled || root.disabled.value) return false;
|
||||
if (!root.linear.value) return true;
|
||||
return step <= root.value.value + 1;
|
||||
});
|
||||
|
||||
const titleId = useId(undefined, 'stepper-item-title').value;
|
||||
const descriptionId = useId(undefined, 'stepper-item-description').value;
|
||||
|
||||
provideStepperItemContext({
|
||||
step: toRef(() => step),
|
||||
state,
|
||||
disabled: toRef(() => disabled || root.disabled.value),
|
||||
focusable,
|
||||
titleId,
|
||||
descriptionId,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive
|
||||
:ref="forwardRef"
|
||||
:as="as"
|
||||
:aria-current="state === 'active' ? 'step' : undefined"
|
||||
:data-state="state"
|
||||
:data-orientation="root.orientation.value"
|
||||
:data-disabled="disabled || root.disabled.value || !focusable ? '' : undefined"
|
||||
>
|
||||
<slot :state="state" :step="step" />
|
||||
</Primitive>
|
||||
</template>
|
||||
@@ -0,0 +1,140 @@
|
||||
<script lang="ts">
|
||||
import type { StepperDirection, StepperOrientation } from './context';
|
||||
import type { PrimitiveProps } from '../primitive';
|
||||
|
||||
export interface StepperRootProps extends PrimitiveProps {
|
||||
/** Controlled active step (1-based). Use `v-model`. */
|
||||
modelValue?: number;
|
||||
/** Uncontrolled initial step. @default 1 */
|
||||
defaultValue?: number;
|
||||
/** Orientation. @default 'horizontal' */
|
||||
orientation?: StepperOrientation;
|
||||
/** Writing direction. Falls back to `ConfigProvider` when omitted. */
|
||||
dir?: StepperDirection;
|
||||
/** Require steps to be completed in order. @default true */
|
||||
linear?: boolean;
|
||||
/** Disable the entire stepper. */
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface StepperRootEmits {
|
||||
'update:modelValue': [value: number];
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, toRef, watch } from 'vue';
|
||||
import { resolveNextIndex, rovingKeyToAction } from '../utils/roving-focus';
|
||||
import { Primitive } from '../primitive';
|
||||
import { provideStepperRootContext } from './context';
|
||||
import { useCollectionProvider } from '../collection';
|
||||
import { useConfig } from '../config-provider';
|
||||
import { useForwardExpose } from '@robonen/vue';
|
||||
|
||||
const {
|
||||
as = 'div',
|
||||
modelValue,
|
||||
defaultValue = 1,
|
||||
orientation = 'horizontal',
|
||||
linear = true,
|
||||
disabled = false,
|
||||
dir,
|
||||
} = defineProps<StepperRootProps>();
|
||||
|
||||
const emit = defineEmits<StepperRootEmits>();
|
||||
|
||||
const { forwardRef } = useForwardExpose();
|
||||
const config = useConfig();
|
||||
|
||||
const direction = computed(() => dir ?? config.dir.value);
|
||||
|
||||
const localValue = ref<number>(modelValue ?? defaultValue);
|
||||
|
||||
watch(() => modelValue, (v) => {
|
||||
if (v === undefined || v === localValue.value) return;
|
||||
localValue.value = v;
|
||||
});
|
||||
|
||||
const { getItems, CollectionSlot } = useCollectionProvider();
|
||||
const total = computed(() => getItems(true).length);
|
||||
|
||||
function commit(next: number): void {
|
||||
if (next === localValue.value) return;
|
||||
localValue.value = next;
|
||||
emit('update:modelValue', next);
|
||||
}
|
||||
|
||||
function goToStep(step: number): void {
|
||||
if (disabled || step < 1) return;
|
||||
const items = getItems(true);
|
||||
const count = items.length;
|
||||
if (count > 0 && step > count) return;
|
||||
// respect linear gate — at most one step ahead of current.
|
||||
if (linear && step > localValue.value + 1) return;
|
||||
// skip if target item is marked disabled in DOM.
|
||||
const target = items[step - 1]?.ref;
|
||||
if (target?.hasAttribute('data-disabled')) return;
|
||||
commit(step);
|
||||
}
|
||||
|
||||
function onTriggerKeyDown(event: KeyboardEvent, el: HTMLElement): void {
|
||||
const action = rovingKeyToAction(event, {
|
||||
orientation,
|
||||
dir: direction.value,
|
||||
loop: false,
|
||||
});
|
||||
if (!action) return;
|
||||
event.preventDefault();
|
||||
// Collect enabled triggers with a single pass (PACKED array via push — no filter closure).
|
||||
const items = getItems(true);
|
||||
const enabled: HTMLElement[] = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const ref = items[i]!.ref;
|
||||
if (!ref.hasAttribute('data-disabled')) enabled.push(ref);
|
||||
}
|
||||
if (enabled.length === 0) return;
|
||||
if (action.absolute === 'home') {
|
||||
enabled[0]!.focus();
|
||||
return;
|
||||
}
|
||||
if (action.absolute === 'end') {
|
||||
enabled[enabled.length - 1]!.focus();
|
||||
return;
|
||||
}
|
||||
const current = enabled.indexOf(el);
|
||||
const nextIdx = resolveNextIndex(current === -1 ? 0 : current, action.delta, enabled.length, false);
|
||||
enabled[nextIdx]!.focus();
|
||||
}
|
||||
|
||||
provideStepperRootContext({
|
||||
value: localValue,
|
||||
total,
|
||||
orientation: toRef(() => orientation),
|
||||
direction,
|
||||
linear: toRef(() => linear),
|
||||
disabled: toRef(() => disabled),
|
||||
goToStep,
|
||||
onTriggerKeyDown,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollectionSlot>
|
||||
<Primitive
|
||||
:ref="forwardRef"
|
||||
:as="as"
|
||||
role="group"
|
||||
aria-label="progress"
|
||||
:data-orientation="orientation"
|
||||
:data-linear="linear ? '' : undefined"
|
||||
:data-disabled="disabled ? '' : undefined"
|
||||
:dir="direction"
|
||||
>
|
||||
<slot
|
||||
:value="localValue"
|
||||
:total="total"
|
||||
:go-to-step="goToStep"
|
||||
/>
|
||||
</Primitive>
|
||||
</CollectionSlot>
|
||||
</template>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import type { PrimitiveProps } from '../primitive';
|
||||
|
||||
export interface StepperSeparatorProps extends PrimitiveProps {}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useStepperItemContext, useStepperRootContext } from './context';
|
||||
import { Primitive } from '../primitive';
|
||||
import { useForwardExpose } from '@robonen/vue';
|
||||
|
||||
const { as = 'div' } = defineProps<StepperSeparatorProps>();
|
||||
|
||||
const root = useStepperRootContext();
|
||||
const item = useStepperItemContext();
|
||||
const { forwardRef } = useForwardExpose();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive
|
||||
:ref="forwardRef"
|
||||
:as="as"
|
||||
role="separator"
|
||||
aria-hidden="true"
|
||||
:data-orientation="root.orientation.value"
|
||||
:data-state="item.state.value"
|
||||
>
|
||||
<slot />
|
||||
</Primitive>
|
||||
</template>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
import type { PrimitiveProps } from '../primitive';
|
||||
|
||||
export interface StepperTitleProps extends PrimitiveProps {}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Primitive } from '../primitive';
|
||||
import { useForwardExpose } from '@robonen/vue';
|
||||
import { useStepperItemContext } from './context';
|
||||
|
||||
const { as = 'h4' } = defineProps<StepperTitleProps>();
|
||||
|
||||
const item = useStepperItemContext();
|
||||
const { forwardRef } = useForwardExpose();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive
|
||||
:ref="forwardRef"
|
||||
:as="as"
|
||||
:id="item.titleId"
|
||||
>
|
||||
<slot />
|
||||
</Primitive>
|
||||
</template>
|
||||
@@ -0,0 +1,59 @@
|
||||
<script lang="ts">
|
||||
import type { PrimitiveProps } from '../primitive';
|
||||
|
||||
export interface StepperTriggerProps extends PrimitiveProps {}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useStepperItemContext, useStepperRootContext } from './context';
|
||||
import { Primitive } from '../primitive';
|
||||
import { useCollectionInjector } from '../collection';
|
||||
import { useForwardExpose } from '@robonen/vue';
|
||||
|
||||
const { as = 'button' } = defineProps<StepperTriggerProps>();
|
||||
|
||||
const root = useStepperRootContext();
|
||||
const item = useStepperItemContext();
|
||||
const { forwardRef, currentElement } = useForwardExpose();
|
||||
const { CollectionItem } = useCollectionInjector();
|
||||
|
||||
function onMouseDown(event: MouseEvent): void {
|
||||
if (!item.focusable.value || event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
root.goToStep(item.step.value);
|
||||
}
|
||||
|
||||
function onKeyDown(event: KeyboardEvent): void {
|
||||
if (item.disabled.value) return;
|
||||
if ((event.key === 'Enter' || event.key === ' ') && !event.ctrlKey && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
root.goToStep(item.step.value);
|
||||
return;
|
||||
}
|
||||
if (!currentElement.value) return;
|
||||
root.onTriggerKeyDown(event, currentElement.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollectionItem>
|
||||
<Primitive
|
||||
:ref="forwardRef"
|
||||
:as="as"
|
||||
:type="as === 'button' ? 'button' : undefined"
|
||||
:tabindex="item.focusable.value ? 0 : -1"
|
||||
:disabled="item.disabled.value || !item.focusable.value || undefined"
|
||||
:data-state="item.state.value"
|
||||
:data-orientation="root.orientation.value"
|
||||
:data-disabled="item.disabled.value || !item.focusable.value ? '' : undefined"
|
||||
:aria-labelledby="item.titleId"
|
||||
:aria-describedby="item.descriptionId"
|
||||
@mousedown.left="onMouseDown"
|
||||
@keydown="onKeyDown"
|
||||
>
|
||||
<slot :state="item.state.value" :step="item.step.value" />
|
||||
</Primitive>
|
||||
</CollectionItem>
|
||||
</template>
|
||||
@@ -0,0 +1,176 @@
|
||||
import {
|
||||
StepperDescription,
|
||||
StepperIndicator,
|
||||
StepperItem,
|
||||
StepperRoot,
|
||||
StepperSeparator,
|
||||
StepperTitle,
|
||||
StepperTrigger,
|
||||
} from '../index';
|
||||
import { defineComponent, h, nextTick, ref } from 'vue';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { mount } from '@vue/test-utils';
|
||||
|
||||
function createStepper(rootProps: Record<string, unknown> = {}, stepCount = 3, itemProps: Record<number, Record<string, unknown>> = {}) {
|
||||
return mount(
|
||||
defineComponent({
|
||||
setup() {
|
||||
return () => h(
|
||||
StepperRoot,
|
||||
rootProps,
|
||||
{
|
||||
default: () => Array.from({ length: stepCount }, (_, i) => {
|
||||
const step = i + 1;
|
||||
return h(
|
||||
StepperItem,
|
||||
{ key: step, step, ...itemProps[step] },
|
||||
{
|
||||
default: () => [
|
||||
h(StepperTrigger, null, { default: () => [
|
||||
h(StepperIndicator),
|
||||
h(StepperTitle, null, { default: () => `Step ${step}` }),
|
||||
h(StepperDescription, null, { default: () => `Description ${step}` }),
|
||||
] }),
|
||||
i < stepCount - 1 ? h(StepperSeparator) : null,
|
||||
],
|
||||
},
|
||||
);
|
||||
}),
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
{ attachTo: document.body },
|
||||
);
|
||||
}
|
||||
|
||||
function press(el: Element, key: string) {
|
||||
el.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }));
|
||||
}
|
||||
|
||||
describe('Stepper', () => {
|
||||
it('renders with role=group', () => {
|
||||
const w = createStepper();
|
||||
const root = w.find('[role="group"]');
|
||||
expect(root.exists()).toBe(true);
|
||||
expect(root.attributes('aria-label')).toBe('progress');
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('first item is active by default (step=1)', () => {
|
||||
const w = createStepper();
|
||||
const items = w.findAllComponents(StepperItem);
|
||||
expect(items[0]!.attributes('data-state')).toBe('active');
|
||||
expect(items[0]!.attributes('aria-current')).toBe('step');
|
||||
expect(items[1]!.attributes('data-state')).toBe('inactive');
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('honors defaultValue', () => {
|
||||
const w = createStepper({ defaultValue: 2 });
|
||||
const items = w.findAllComponents(StepperItem);
|
||||
expect(items[0]!.attributes('data-state')).toBe('completed');
|
||||
expect(items[1]!.attributes('data-state')).toBe('active');
|
||||
expect(items[2]!.attributes('data-state')).toBe('inactive');
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('v-model moves the active step', async () => {
|
||||
const value = ref(1);
|
||||
const w = mount(
|
||||
defineComponent({
|
||||
setup() {
|
||||
return () => h(
|
||||
StepperRoot,
|
||||
{ modelValue: value.value, 'onUpdate:modelValue': (v: number) => (value.value = v) },
|
||||
{
|
||||
default: () => [1, 2, 3].map(step =>
|
||||
h(StepperItem, { key: step, step }, { default: () => h(StepperTrigger, null, { default: () => `S${step}` }) }),
|
||||
),
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
{ attachTo: document.body },
|
||||
);
|
||||
const triggers = w.findAll('button');
|
||||
await triggers[1]!.trigger('mousedown');
|
||||
await nextTick();
|
||||
expect(value.value).toBe(2);
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('linear mode blocks skipping ahead', async () => {
|
||||
const w = createStepper();
|
||||
const triggers = w.findAll('button');
|
||||
await triggers[2]!.trigger('mousedown'); // try to skip to 3
|
||||
await nextTick();
|
||||
const items = w.findAllComponents(StepperItem);
|
||||
expect(items[0]!.attributes('data-state')).toBe('active'); // unchanged
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('non-linear mode allows arbitrary step', async () => {
|
||||
const w = createStepper({ linear: false });
|
||||
const triggers = w.findAll('button');
|
||||
await triggers[2]!.trigger('mousedown');
|
||||
await nextTick();
|
||||
const items = w.findAllComponents(StepperItem);
|
||||
expect(items[2]!.attributes('data-state')).toBe('active');
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('disabled item is not focusable and cannot be activated', async () => {
|
||||
const w = createStepper({ linear: false }, 3, { 2: { disabled: true } });
|
||||
const items = w.findAllComponents(StepperItem);
|
||||
expect(items[1]!.attributes('data-disabled')).toBe('');
|
||||
const triggers = w.findAll('button');
|
||||
expect(triggers[1]!.attributes('tabindex')).toBe('-1');
|
||||
await triggers[1]!.trigger('mousedown');
|
||||
await nextTick();
|
||||
expect(items[0]!.attributes('data-state')).toBe('active'); // unchanged
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('Enter/Space on trigger activates step', async () => {
|
||||
const w = createStepper({ linear: false });
|
||||
const triggers = w.findAll('button');
|
||||
(triggers[1]!.element as HTMLElement).focus();
|
||||
press(triggers[1]!.element, 'Enter');
|
||||
await nextTick();
|
||||
const items = w.findAllComponents(StepperItem);
|
||||
expect(items[1]!.attributes('data-state')).toBe('active');
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('ArrowRight / ArrowLeft move focus between triggers', () => {
|
||||
const w = createStepper({ linear: false });
|
||||
const triggers = w.findAll('button').map(t => t.element as HTMLElement);
|
||||
triggers[0]!.focus();
|
||||
press(triggers[0]!, 'ArrowRight');
|
||||
expect(document.activeElement).toBe(triggers[1]);
|
||||
press(triggers[1]!, 'ArrowRight');
|
||||
expect(document.activeElement).toBe(triggers[2]);
|
||||
press(triggers[2]!, 'ArrowLeft');
|
||||
expect(document.activeElement).toBe(triggers[1]);
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('Home / End jump to first / last trigger', () => {
|
||||
const w = createStepper({ linear: false });
|
||||
const triggers = w.findAll('button').map(t => t.element as HTMLElement);
|
||||
triggers[1]!.focus();
|
||||
press(triggers[1]!, 'End');
|
||||
expect(document.activeElement).toBe(triggers[2]);
|
||||
press(triggers[2]!, 'Home');
|
||||
expect(document.activeElement).toBe(triggers[0]);
|
||||
w.unmount();
|
||||
});
|
||||
|
||||
it('completed prop forces completed state', () => {
|
||||
const w = createStepper({}, 3, { 1: { completed: true } });
|
||||
const items = w.findAllComponents(StepperItem);
|
||||
expect(items[0]!.attributes('data-state')).toBe('completed');
|
||||
w.unmount();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { ComputedRef, Ref } from 'vue';
|
||||
import { useContextFactory } from '@robonen/vue';
|
||||
|
||||
export type StepperOrientation = 'horizontal' | 'vertical';
|
||||
export type StepperDirection = 'ltr' | 'rtl';
|
||||
export type StepperState = 'completed' | 'active' | 'inactive';
|
||||
|
||||
export interface StepperRootContext {
|
||||
/** Currently active step (1-based). */
|
||||
value: Ref<number>;
|
||||
/** Total registered items, tracked through the Collection. */
|
||||
total: ComputedRef<number>;
|
||||
/** Orientation of the stepper — drives arrow-key axis. */
|
||||
orientation: Ref<StepperOrientation>;
|
||||
/** Writing direction. */
|
||||
direction: Ref<StepperDirection>;
|
||||
/** When `true`, steps must be completed in order. */
|
||||
linear: Ref<boolean>;
|
||||
/** Whether the whole stepper is disabled. */
|
||||
disabled: Ref<boolean>;
|
||||
|
||||
goToStep: (step: number) => void;
|
||||
onTriggerKeyDown: (event: KeyboardEvent, el: HTMLElement) => void;
|
||||
}
|
||||
|
||||
export interface StepperItemContext {
|
||||
step: Ref<number>;
|
||||
state: Ref<StepperState>;
|
||||
disabled: Ref<boolean>;
|
||||
focusable: Ref<boolean>;
|
||||
titleId: string;
|
||||
descriptionId: string;
|
||||
}
|
||||
|
||||
export const {
|
||||
inject: useStepperRootContext,
|
||||
provide: provideStepperRootContext,
|
||||
} = useContextFactory<StepperRootContext>('stepper');
|
||||
|
||||
export const {
|
||||
inject: useStepperItemContext,
|
||||
provide: provideStepperItemContext,
|
||||
} = useContextFactory<StepperItemContext>('stepper-item');
|
||||
@@ -0,0 +1,27 @@
|
||||
export { default as StepperRoot } from './StepperRoot.vue';
|
||||
export { default as StepperItem } from './StepperItem.vue';
|
||||
export { default as StepperTrigger } from './StepperTrigger.vue';
|
||||
export { default as StepperIndicator } from './StepperIndicator.vue';
|
||||
export { default as StepperTitle } from './StepperTitle.vue';
|
||||
export { default as StepperDescription } from './StepperDescription.vue';
|
||||
export { default as StepperSeparator } from './StepperSeparator.vue';
|
||||
|
||||
export {
|
||||
provideStepperRootContext,
|
||||
provideStepperItemContext,
|
||||
useStepperRootContext,
|
||||
useStepperItemContext,
|
||||
type StepperRootContext,
|
||||
type StepperItemContext,
|
||||
type StepperState,
|
||||
type StepperOrientation,
|
||||
type StepperDirection,
|
||||
} from './context';
|
||||
|
||||
export type { StepperRootProps, StepperRootEmits } from './StepperRoot.vue';
|
||||
export type { StepperItemProps } from './StepperItem.vue';
|
||||
export type { StepperTriggerProps } from './StepperTrigger.vue';
|
||||
export type { StepperIndicatorProps } from './StepperIndicator.vue';
|
||||
export type { StepperTitleProps } from './StepperTitle.vue';
|
||||
export type { StepperDescriptionProps } from './StepperDescription.vue';
|
||||
export type { StepperSeparatorProps } from './StepperSeparator.vue';
|
||||
Reference in New Issue
Block a user