@aleph-alpha/ui-library 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/dist/system/index.d.ts +860 -179
- package/dist/system/lib.js +33936 -9729
- package/package.json +1 -2
- package/src/compositions/UiDataTable/UiDataTable.stories.ts +6 -7
- package/src/compositions/UiDataTable/UiDataTableColumnHeader.vue +22 -8
- package/src/compositions/UiDataTable/UiDataTablePagination.vue +5 -5
- package/src/compositions/UiDatePicker/UiDatePicker.vue +2 -2
- package/src/primitives/UiAlert/UiAlert.stories.ts +8 -8
- package/src/primitives/UiBadge/UiBadge.stories.ts +9 -9
- package/src/primitives/UiButton/UiButton.stories.ts +12 -12
- package/src/primitives/UiCalendar/UiCalendar.stories.ts +4 -4
- package/src/primitives/UiDropdownMenu/UiDropdownMenu.stories.ts +2 -2
- package/src/primitives/UiIcon/UiIcon.stories.ts +59 -13
- package/src/primitives/UiIcon/UiIcon.vue +41 -3
- package/src/primitives/UiIcon/__tests__/UiIcon.test.ts +33 -4
- package/src/primitives/UiIcon/index.ts +1 -0
- package/src/primitives/UiIcon/types.ts +24 -5
- package/src/primitives/UiIconButton/UiIconButton.stories.ts +36 -36
- package/src/primitives/UiKbd/UiKbd.stories.ts +551 -0
- package/src/primitives/UiKbd/UiKbd.vue +62 -0
- package/src/primitives/UiKbd/UiKbdGroup.vue +16 -0
- package/src/primitives/UiKbd/__tests__/UiKbd.test.ts +46 -0
- package/src/primitives/UiKbd/index.ts +3 -0
- package/src/primitives/UiKbd/types.ts +32 -0
- package/src/primitives/UiLabel/UiLabel.stories.ts +192 -0
- package/src/primitives/UiLabel/UiLabel.vue +16 -0
- package/src/primitives/UiLabel/__tests__/UiLabel.test.ts +43 -0
- package/src/primitives/UiLabel/index.ts +2 -0
- package/src/primitives/UiLabel/types.ts +16 -0
- package/src/primitives/UiListbox/UiListbox.stories.ts +607 -0
- package/src/primitives/UiListbox/UiListbox.vue +30 -0
- package/src/primitives/UiListbox/UiListboxContent.vue +16 -0
- package/src/primitives/UiListbox/UiListboxFilter.vue +16 -0
- package/src/primitives/UiListbox/UiListboxGroup.vue +16 -0
- package/src/primitives/UiListbox/UiListboxGroupLabel.vue +16 -0
- package/src/primitives/UiListbox/UiListboxItem.vue +20 -0
- package/src/primitives/UiListbox/UiListboxItemIndicator.vue +16 -0
- package/src/primitives/UiListbox/__tests__/UiListbox.test.ts +42 -0
- package/src/primitives/UiListbox/index.ts +8 -0
- package/src/primitives/UiListbox/types.ts +119 -0
- package/src/primitives/UiPopover/index.ts +1 -0
- package/src/primitives/UiSeparator/UiSeparator.stories.ts +177 -0
- package/src/primitives/UiSeparator/UiSeparator.vue +17 -0
- package/src/primitives/UiSeparator/__tests__/UiSeparator.test.ts +34 -0
- package/src/primitives/UiSeparator/index.ts +2 -0
- package/src/primitives/UiSeparator/types.ts +23 -0
- package/src/primitives/UiSkeleton/UiSkeleton.stories.ts +247 -0
- package/src/primitives/UiSkeleton/UiSkeleton.vue +24 -0
- package/src/primitives/UiSkeleton/__tests__/UiSkeleton.test.ts +47 -0
- package/src/primitives/UiSkeleton/index.ts +2 -0
- package/src/primitives/UiSkeleton/types.ts +26 -0
- package/src/primitives/UiTable/UiTable.stories.ts +2 -2
- package/src/primitives/UiTagsInput/UiTagsInput.stories.ts +538 -0
- package/src/primitives/UiTagsInput/UiTagsInput.vue +27 -0
- package/src/primitives/UiTagsInput/UiTagsInputInput.vue +14 -0
- package/src/primitives/UiTagsInput/UiTagsInputItem.vue +16 -0
- package/src/primitives/UiTagsInput/UiTagsInputItemDelete.vue +16 -0
- package/src/primitives/UiTagsInput/UiTagsInputItemText.vue +14 -0
- package/src/primitives/UiTagsInput/__tests__/UiTagsInput.test.ts +44 -0
- package/src/primitives/UiTagsInput/index.ts +6 -0
- package/src/primitives/UiTagsInput/types.ts +60 -0
- package/src/primitives/UiToggle/UiToggle.stories.ts +370 -0
- package/src/primitives/UiToggle/UiToggle.vue +28 -0
- package/src/primitives/UiToggle/__tests__/UiToggle.test.ts +62 -0
- package/src/primitives/UiToggle/index.ts +2 -0
- package/src/primitives/UiToggle/types.ts +35 -0
- package/src/primitives/UiTooltip/UiTooltip.stories.ts +8 -8
- package/src/primitives/index.ts +7 -0
- package/src/primitives/shadcn/accordion/AccordionTrigger.vue +5 -4
- package/src/primitives/shadcn/calendar/CalendarNextButton.vue +2 -2
- package/src/primitives/shadcn/calendar/CalendarPrevButton.vue +2 -2
- package/src/primitives/shadcn/checkbox/Checkbox.vue +2 -2
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuCheckboxItem.vue +2 -2
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuSubTrigger.vue +2 -2
- package/src/primitives/shadcn/kbd/Kbd.vue +20 -0
- package/src/primitives/shadcn/kbd/KbdGroup.vue +12 -0
- package/src/primitives/shadcn/kbd/index.ts +2 -0
- package/src/primitives/shadcn/listbox/Listbox.vue +23 -0
- package/src/primitives/shadcn/listbox/ListboxContent.vue +26 -0
- package/src/primitives/shadcn/listbox/ListboxFilter.vue +30 -0
- package/src/primitives/shadcn/listbox/ListboxGroup.vue +26 -0
- package/src/primitives/shadcn/listbox/ListboxGroupLabel.vue +26 -0
- package/src/primitives/shadcn/listbox/ListboxItem.vue +32 -0
- package/src/primitives/shadcn/listbox/ListboxItemIndicator.vue +40 -0
- package/src/primitives/shadcn/listbox/index.ts +7 -0
- package/src/primitives/shadcn/native-select/NativeSelect.vue +5 -4
- package/src/primitives/shadcn/range-calendar/RangeCalendarNextButton.vue +2 -2
- package/src/primitives/shadcn/range-calendar/RangeCalendarPrevButton.vue +2 -2
- package/src/primitives/shadcn/select/SelectItem.vue +2 -2
- package/src/primitives/shadcn/select/SelectScrollDownButton.vue +2 -2
- package/src/primitives/shadcn/select/SelectScrollUpButton.vue +2 -2
- package/src/primitives/shadcn/select/SelectTrigger.vue +2 -2
- package/src/primitives/shadcn/skeleton/Skeleton.vue +10 -0
- package/src/primitives/shadcn/skeleton/index.ts +1 -0
- package/src/primitives/shadcn/spinner/Spinner.vue +5 -4
- package/src/primitives/shadcn/tags-input/TagsInput.vue +33 -0
- package/src/primitives/shadcn/tags-input/TagsInputInput.vue +24 -0
- package/src/primitives/shadcn/tags-input/TagsInputItem.vue +31 -0
- package/src/primitives/shadcn/tags-input/TagsInputItemDelete.vue +46 -0
- package/src/primitives/shadcn/tags-input/TagsInputItemText.vue +24 -0
- package/src/primitives/shadcn/tags-input/index.ts +5 -0
- package/src/primitives/shadcn/toggle/Toggle.vue +34 -0
- package/src/primitives/shadcn/toggle/index.ts +27 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ListboxItem as ShadcnListboxItem } from '@/primitives/shadcn/listbox';
|
|
3
|
+
import { UiListboxItemProps } from './types';
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'UiListboxItem',
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const props = defineProps<UiListboxItemProps>();
|
|
10
|
+
|
|
11
|
+
const emit = defineEmits<{
|
|
12
|
+
select: [event: Event];
|
|
13
|
+
}>();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ShadcnListboxItem v-bind="props" @select="emit('select', $event)">
|
|
18
|
+
<slot />
|
|
19
|
+
</ShadcnListboxItem>
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ListboxItemIndicator as ShadcnListboxItemIndicator } from '@/primitives/shadcn/listbox';
|
|
3
|
+
import { UiListboxItemIndicatorProps } from './types';
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'UiListboxItemIndicator',
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const props = defineProps<UiListboxItemIndicatorProps>();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<ShadcnListboxItemIndicator v-bind="props">
|
|
14
|
+
<slot />
|
|
15
|
+
</ShadcnListboxItemIndicator>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { render } from '@testing-library/vue';
|
|
2
|
+
import { describe, expect, test } from 'vitest';
|
|
3
|
+
import UiListbox from '../UiListbox.vue';
|
|
4
|
+
import UiListboxContent from '../UiListboxContent.vue';
|
|
5
|
+
import UiListboxItem from '../UiListboxItem.vue';
|
|
6
|
+
import UiListboxItemIndicator from '../UiListboxItemIndicator.vue';
|
|
7
|
+
|
|
8
|
+
describe('UiListbox', () => {
|
|
9
|
+
test('renders listbox with items', () => {
|
|
10
|
+
const { container } = render(UiListbox, {
|
|
11
|
+
props: {
|
|
12
|
+
modelValue: 'apple',
|
|
13
|
+
},
|
|
14
|
+
slots: {
|
|
15
|
+
default: `
|
|
16
|
+
<span>Apple</span>
|
|
17
|
+
<span>Banana</span>
|
|
18
|
+
`,
|
|
19
|
+
},
|
|
20
|
+
global: {
|
|
21
|
+
components: {
|
|
22
|
+
UiListboxContent,
|
|
23
|
+
UiListboxItem,
|
|
24
|
+
UiListboxItemIndicator,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(container.querySelector('[data-slot="listbox"]')).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('renders disabled state', () => {
|
|
33
|
+
const { container } = render(UiListbox, {
|
|
34
|
+
props: {
|
|
35
|
+
modelValue: 'apple',
|
|
36
|
+
disabled: true,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(container.querySelector('[data-slot="listbox"]')).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default as UiListbox } from './UiListbox.vue';
|
|
2
|
+
export { default as UiListboxContent } from './UiListboxContent.vue';
|
|
3
|
+
export { default as UiListboxFilter } from './UiListboxFilter.vue';
|
|
4
|
+
export { default as UiListboxItem } from './UiListboxItem.vue';
|
|
5
|
+
export { default as UiListboxItemIndicator } from './UiListboxItemIndicator.vue';
|
|
6
|
+
export { default as UiListboxGroup } from './UiListboxGroup.vue';
|
|
7
|
+
export { default as UiListboxGroupLabel } from './UiListboxGroupLabel.vue';
|
|
8
|
+
export type * from './types';
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { AcceptableValue } from 'reka-ui';
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A listbox component for displaying a list of selectable options.
|
|
6
|
+
* Use for dropdown menus, selection lists, or any list-based selection UI.
|
|
7
|
+
*
|
|
8
|
+
* @category Form Inputs
|
|
9
|
+
* @useCases option selection, dropdown list, selectable items, multi-select
|
|
10
|
+
* @keywords listbox, select, options, list, dropdown, choices
|
|
11
|
+
* @related UiSelect, UiTagsInput
|
|
12
|
+
*/
|
|
13
|
+
export interface UiListboxProps {
|
|
14
|
+
/**
|
|
15
|
+
* The controlled value of the listbox. Optional; can be bound with v-model.
|
|
16
|
+
* - Omit for uncontrolled mode
|
|
17
|
+
* - Use `v-model` for controlled mode
|
|
18
|
+
*/
|
|
19
|
+
modelValue?: AcceptableValue | AcceptableValue[];
|
|
20
|
+
/**
|
|
21
|
+
* The value of the listbox when initially rendered.
|
|
22
|
+
*/
|
|
23
|
+
defaultValue?: AcceptableValue | AcceptableValue[];
|
|
24
|
+
/**
|
|
25
|
+
* Whether multiple options can be selected.
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
multiple?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The orientation of the listbox.
|
|
31
|
+
*/
|
|
32
|
+
orientation?: 'horizontal' | 'vertical';
|
|
33
|
+
/**
|
|
34
|
+
* The reading direction of the listbox.
|
|
35
|
+
*/
|
|
36
|
+
dir?: 'ltr' | 'rtl';
|
|
37
|
+
/**
|
|
38
|
+
* When true, prevents the user from interacting with listbox.
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* How multiple selection should behave.
|
|
44
|
+
* @default 'toggle'
|
|
45
|
+
*/
|
|
46
|
+
selectionBehavior?: 'toggle' | 'replace';
|
|
47
|
+
/**
|
|
48
|
+
* When true, hover over item will trigger highlight.
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
highlightOnHover?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Use this to compare objects by a particular field.
|
|
54
|
+
*/
|
|
55
|
+
by?: string | ((a: AcceptableValue, b: AcceptableValue) => boolean);
|
|
56
|
+
/**
|
|
57
|
+
* Additional CSS classes to apply to the component.
|
|
58
|
+
*/
|
|
59
|
+
class?: HTMLAttributes['class'];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface UiListboxContentProps {
|
|
63
|
+
/**
|
|
64
|
+
* Additional CSS classes to apply to the content container.
|
|
65
|
+
*/
|
|
66
|
+
class?: HTMLAttributes['class'];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface UiListboxFilterProps {
|
|
70
|
+
/**
|
|
71
|
+
* Placeholder text for the filter input.
|
|
72
|
+
*/
|
|
73
|
+
placeholder?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Whether to render as a child element (for composition with other components).
|
|
76
|
+
*/
|
|
77
|
+
asChild?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Additional CSS classes to apply to the filter input.
|
|
80
|
+
*/
|
|
81
|
+
class?: HTMLAttributes['class'];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface UiListboxItemProps {
|
|
85
|
+
/**
|
|
86
|
+
* The value of the listbox item.
|
|
87
|
+
*/
|
|
88
|
+
value: AcceptableValue;
|
|
89
|
+
/**
|
|
90
|
+
* Whether the item is disabled.
|
|
91
|
+
* @default false
|
|
92
|
+
*/
|
|
93
|
+
disabled?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Additional CSS classes to apply to the item.
|
|
96
|
+
*/
|
|
97
|
+
class?: HTMLAttributes['class'];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface UiListboxItemIndicatorProps {
|
|
101
|
+
/**
|
|
102
|
+
* Additional CSS classes to apply to the indicator.
|
|
103
|
+
*/
|
|
104
|
+
class?: HTMLAttributes['class'];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface UiListboxGroupProps {
|
|
108
|
+
/**
|
|
109
|
+
* Additional CSS classes to apply to the group.
|
|
110
|
+
*/
|
|
111
|
+
class?: HTMLAttributes['class'];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface UiListboxGroupLabelProps {
|
|
115
|
+
/**
|
|
116
|
+
* Additional CSS classes to apply to the group label.
|
|
117
|
+
*/
|
|
118
|
+
class?: HTMLAttributes['class'];
|
|
119
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as UiPopover } from './UiPopover.vue';
|
|
2
2
|
export { default as UiPopoverTrigger } from './UiPopoverTrigger.vue';
|
|
3
3
|
export { default as UiPopoverContent } from './UiPopoverContent.vue';
|
|
4
|
+
export { PopoverAnchor as UiPopoverAnchor } from 'reka-ui';
|
|
4
5
|
|
|
5
6
|
export * from './types';
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import UiSeparator from './UiSeparator.vue';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof UiSeparator> = {
|
|
5
|
+
title: 'Primitives/UiSeparator',
|
|
6
|
+
component: UiSeparator,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
argTypes: {
|
|
9
|
+
orientation: {
|
|
10
|
+
control: 'select',
|
|
11
|
+
options: ['horizontal', 'vertical'],
|
|
12
|
+
description: 'The orientation of the separator.\n\n@default "horizontal"',
|
|
13
|
+
},
|
|
14
|
+
decorative: {
|
|
15
|
+
control: 'boolean',
|
|
16
|
+
description: 'When true, the separator is purely decorative.\n\n@default true',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
orientation: 'horizontal',
|
|
21
|
+
decorative: true,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default meta;
|
|
26
|
+
|
|
27
|
+
type Story = StoryObj<typeof UiSeparator>;
|
|
28
|
+
|
|
29
|
+
const defaultTemplateSource = `<script setup lang="ts">
|
|
30
|
+
import { UiSeparator } from '@aleph-alpha/ui-library'
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<div class="space-y-4">
|
|
35
|
+
<div>
|
|
36
|
+
<h4 class="text-sm font-medium">Section Title</h4>
|
|
37
|
+
<p class="text-sm text-muted-foreground">Description text goes here.</p>
|
|
38
|
+
</div>
|
|
39
|
+
<UiSeparator />
|
|
40
|
+
<div>
|
|
41
|
+
<h4 class="text-sm font-medium">Another Section</h4>
|
|
42
|
+
<p class="text-sm text-muted-foreground">More content below the separator.</p>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</template>`;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Horizontal separator between content sections.
|
|
49
|
+
*/
|
|
50
|
+
export const Default: Story = {
|
|
51
|
+
render: (args) => ({
|
|
52
|
+
components: { UiSeparator },
|
|
53
|
+
setup() {
|
|
54
|
+
return { args };
|
|
55
|
+
},
|
|
56
|
+
template: `<div class="space-y-4">
|
|
57
|
+
<div>
|
|
58
|
+
<h4 class="text-sm font-medium">Section Title</h4>
|
|
59
|
+
<p class="text-sm text-muted-foreground">Description text goes here.</p>
|
|
60
|
+
</div>
|
|
61
|
+
<UiSeparator v-bind="args" />
|
|
62
|
+
<div>
|
|
63
|
+
<h4 class="text-sm font-medium">Another Section</h4>
|
|
64
|
+
<p class="text-sm text-muted-foreground">More content below the separator.</p>
|
|
65
|
+
</div>
|
|
66
|
+
</div>`,
|
|
67
|
+
}),
|
|
68
|
+
parameters: {
|
|
69
|
+
docs: {
|
|
70
|
+
source: {
|
|
71
|
+
code: defaultTemplateSource,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const verticalTemplateSource = `<script setup lang="ts">
|
|
78
|
+
import { UiSeparator } from '@aleph-alpha/ui-library'
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<template>
|
|
82
|
+
<div class="flex h-5 items-center space-x-4 text-sm">
|
|
83
|
+
<span>Home</span>
|
|
84
|
+
<UiSeparator orientation="vertical" />
|
|
85
|
+
<span>Products</span>
|
|
86
|
+
<UiSeparator orientation="vertical" />
|
|
87
|
+
<span>About</span>
|
|
88
|
+
<UiSeparator orientation="vertical" />
|
|
89
|
+
<span>Contact</span>
|
|
90
|
+
</div>
|
|
91
|
+
</template>`;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Vertical separator for inline content.
|
|
95
|
+
*/
|
|
96
|
+
export const Vertical: Story = {
|
|
97
|
+
render: (args) => ({
|
|
98
|
+
components: { UiSeparator },
|
|
99
|
+
setup() {
|
|
100
|
+
return { args };
|
|
101
|
+
},
|
|
102
|
+
template: `<div class="flex h-5 items-center space-x-4 text-sm">
|
|
103
|
+
<span>Home</span>
|
|
104
|
+
<UiSeparator v-bind="args" orientation="vertical" />
|
|
105
|
+
<span>Products</span>
|
|
106
|
+
<UiSeparator v-bind="args" orientation="vertical" />
|
|
107
|
+
<span>About</span>
|
|
108
|
+
<UiSeparator v-bind="args" orientation="vertical" />
|
|
109
|
+
<span>Contact</span>
|
|
110
|
+
</div>`,
|
|
111
|
+
}),
|
|
112
|
+
parameters: {
|
|
113
|
+
docs: {
|
|
114
|
+
source: {
|
|
115
|
+
code: verticalTemplateSource,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const cardTemplateSource = `<script setup lang="ts">
|
|
122
|
+
import { UiSeparator } from '@aleph-alpha/ui-library'
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<template>
|
|
126
|
+
<div class="rounded-lg border p-4">
|
|
127
|
+
<div class="space-y-1">
|
|
128
|
+
<h4 class="text-sm font-medium leading-none">Aleph Alpha UI</h4>
|
|
129
|
+
<p class="text-sm text-muted-foreground">
|
|
130
|
+
An open-source UI component library.
|
|
131
|
+
</p>
|
|
132
|
+
</div>
|
|
133
|
+
<UiSeparator class="my-4" />
|
|
134
|
+
<div class="flex h-5 items-center space-x-4 text-sm">
|
|
135
|
+
<span>Docs</span>
|
|
136
|
+
<UiSeparator orientation="vertical" />
|
|
137
|
+
<span>Source</span>
|
|
138
|
+
<UiSeparator orientation="vertical" />
|
|
139
|
+
<span>Support</span>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</template>`;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Card with both horizontal and vertical separators.
|
|
146
|
+
*/
|
|
147
|
+
export const InCard: Story = {
|
|
148
|
+
render: (args) => ({
|
|
149
|
+
components: { UiSeparator },
|
|
150
|
+
setup() {
|
|
151
|
+
return { args };
|
|
152
|
+
},
|
|
153
|
+
template: `<div class="rounded-lg border p-4">
|
|
154
|
+
<div class="space-y-1">
|
|
155
|
+
<h4 class="text-sm font-medium leading-none">Aleph Alpha UI</h4>
|
|
156
|
+
<p class="text-sm text-muted-foreground">
|
|
157
|
+
An open-source UI component library.
|
|
158
|
+
</p>
|
|
159
|
+
</div>
|
|
160
|
+
<UiSeparator class="my-4" />
|
|
161
|
+
<div class="flex h-5 items-center space-x-4 text-sm">
|
|
162
|
+
<span>Docs</span>
|
|
163
|
+
<UiSeparator orientation="vertical" />
|
|
164
|
+
<span>Source</span>
|
|
165
|
+
<UiSeparator orientation="vertical" />
|
|
166
|
+
<span>Support</span>
|
|
167
|
+
</div>
|
|
168
|
+
</div>`,
|
|
169
|
+
}),
|
|
170
|
+
parameters: {
|
|
171
|
+
docs: {
|
|
172
|
+
source: {
|
|
173
|
+
code: cardTemplateSource,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Separator as ShadcnSeparator } from '@/primitives/shadcn/separator';
|
|
3
|
+
import type { UiSeparatorProps } from './types';
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'UiSeparator',
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const props = withDefaults(defineProps<UiSeparatorProps>(), {
|
|
10
|
+
orientation: 'horizontal',
|
|
11
|
+
decorative: true,
|
|
12
|
+
});
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<ShadcnSeparator :orientation="props.orientation" :decorative="props.decorative" />
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { render } from '@testing-library/vue';
|
|
2
|
+
import { describe, expect, test } from 'vitest';
|
|
3
|
+
import UiSeparator from '../UiSeparator.vue';
|
|
4
|
+
|
|
5
|
+
describe('UiSeparator', () => {
|
|
6
|
+
test('renders with default horizontal orientation', () => {
|
|
7
|
+
const { container } = render(UiSeparator);
|
|
8
|
+
const separator = container.querySelector('[data-slot="separator"]');
|
|
9
|
+
expect(separator).toBeInTheDocument();
|
|
10
|
+
expect(separator).toHaveAttribute('data-orientation', 'horizontal');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('renders with vertical orientation', () => {
|
|
14
|
+
const { container } = render(UiSeparator, {
|
|
15
|
+
props: { orientation: 'vertical' },
|
|
16
|
+
});
|
|
17
|
+
const separator = container.querySelector('[data-slot="separator"]');
|
|
18
|
+
expect(separator).toHaveAttribute('data-orientation', 'vertical');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('is decorative by default (role=none)', () => {
|
|
22
|
+
const { container } = render(UiSeparator);
|
|
23
|
+
const separator = container.querySelector('[data-slot="separator"]');
|
|
24
|
+
expect(separator).toHaveAttribute('role', 'none');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('has separator role when not decorative', () => {
|
|
28
|
+
const { container } = render(UiSeparator, {
|
|
29
|
+
props: { decorative: false },
|
|
30
|
+
});
|
|
31
|
+
const separator = container.querySelector('[data-slot="separator"]');
|
|
32
|
+
expect(separator).toHaveAttribute('role', 'separator');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A visual divider between content sections. Use for grouping
|
|
3
|
+
* related items or creating visual breaks in layouts.
|
|
4
|
+
*
|
|
5
|
+
* @category Layout
|
|
6
|
+
* @useCases divider, section break, content grouping, visual separation
|
|
7
|
+
* @keywords separator, divider, line, hr, break, layout
|
|
8
|
+
* @related UiCard, UiDropdownMenu
|
|
9
|
+
*/
|
|
10
|
+
export interface UiSeparatorProps {
|
|
11
|
+
/**
|
|
12
|
+
* The orientation of the separator.
|
|
13
|
+
* @type {'horizontal' | 'vertical'}
|
|
14
|
+
* @default 'horizontal'
|
|
15
|
+
*/
|
|
16
|
+
orientation?: 'horizontal' | 'vertical';
|
|
17
|
+
/**
|
|
18
|
+
* When true, the separator is purely decorative and not announced by screen readers.
|
|
19
|
+
* @type {boolean}
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
22
|
+
decorative?: boolean;
|
|
23
|
+
}
|