@rocketui/vue 0.0.47 → 0.0.48
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/dist/rocket-ui-vue.d.ts +1812 -0
- package/dist/rocket-ui-vue.js +9270 -0
- package/dist/rocket-ui-vue.umd.cjs +1 -0
- package/dist/style.css +2 -0
- package/package.json +7 -1
- package/.eslintrc.cjs +0 -79
- package/.gitattributes +0 -2
- package/.github/workflows/chromatic.yml +0 -28
- package/.github/workflows/publish-storybook.yml +0 -41
- package/.husky/pre-commit +0 -4
- package/.prettierrc.cjs +0 -10
- package/.storybook/Theme.js +0 -17
- package/.storybook/main.ts +0 -20
- package/.storybook/manager-head.html +0 -3
- package/.storybook/manager.js +0 -8
- package/.storybook/preview-head.html +0 -3
- package/.storybook/preview.ts +0 -36
- package/.storybook/source-panel/manager.js +0 -28
- package/.storybook/withSource.js +0 -91
- package/.vscode/extensions.json +0 -11
- package/.vscode/settings.json +0 -20
- package/index.html +0 -13
- package/lib/main.ts +0 -48
- package/postcss.config.cjs +0 -9
- package/resources/rocket-ui-logo-dark.svg +0 -27
- package/resources/rocket-ui-logo-light.svg +0 -27
- package/shims-rocketui.d.ts +0 -9
- package/src/App.vue +0 -15
- package/src/assets/blank-avatar.svg +0 -3
- package/src/assets/icons/mdi.js +0 -7302
- package/src/assets/logo.svg +0 -1
- package/src/components/Accordion/Accordion.mdx +0 -88
- package/src/components/Accordion/Accordion.stories.ts +0 -257
- package/src/components/Accordion/RAccordion.vue +0 -73
- package/src/components/Accordion/accordion.css +0 -75
- package/src/components/Accordion/accordion.spec.ts +0 -123
- package/src/components/Alert/Alert.mdx +0 -120
- package/src/components/Alert/Alert.stories.ts +0 -118
- package/src/components/Alert/RAlert.vue +0 -119
- package/src/components/Alert/alert.css +0 -136
- package/src/components/Alert/alert.spec.ts +0 -32
- package/src/components/Avatar/Avatar.mdx +0 -96
- package/src/components/Avatar/Avatar.stories.ts +0 -65
- package/src/components/Avatar/RAvatar.vue +0 -115
- package/src/components/Avatar/avatar.css +0 -82
- package/src/components/Avatar/avatar.spec.ts +0 -38
- package/src/components/Badge/Badge.mdx +0 -112
- package/src/components/Badge/Badge.stories.ts +0 -99
- package/src/components/Badge/RBadge.vue +0 -89
- package/src/components/Badge/badge.css +0 -63
- package/src/components/Badge/badge.spec.ts +0 -20
- package/src/components/Box/Box.mdx +0 -20
- package/src/components/Box/Box.stories.ts +0 -56
- package/src/components/Box/RBox.vue +0 -97
- package/src/components/Breadcrumb/Breadcrumb.stories.ts +0 -115
- package/src/components/Breadcrumb/RBreadcrumb.vue +0 -43
- package/src/components/Breadcrumb/breadcrumb.css +0 -29
- package/src/components/Button/Button.mdx +0 -148
- package/src/components/Button/Button.spec.ts +0 -29
- package/src/components/Button/Button.stories.ts +0 -118
- package/src/components/Button/RButton.vue +0 -179
- package/src/components/Button/button.css +0 -146
- package/src/components/Checkbox/Checkbox.mdx +0 -100
- package/src/components/Checkbox/Checkbox.stories.ts +0 -67
- package/src/components/Checkbox/RCheckbox.vue +0 -195
- package/src/components/Checkbox/checkbox.css +0 -67
- package/src/components/Checkbox/checkbox.spec.ts +0 -60
- package/src/components/Chips/Chip.mdx +0 -113
- package/src/components/Chips/Chip.stories.ts +0 -122
- package/src/components/Chips/RChip.vue +0 -125
- package/src/components/Chips/chip.css +0 -62
- package/src/components/Chips/chip.spec.ts +0 -40
- package/src/components/Dropdown/Dropdown.mdx +0 -135
- package/src/components/Dropdown/Dropdown.stories.ts +0 -84
- package/src/components/Dropdown/RDropdown.vue +0 -392
- package/src/components/Dropdown/dropdown.css +0 -113
- package/src/components/Dropdown/dropdown.spec.ts +0 -98
- package/src/components/Flex/Flex.mdx +0 -20
- package/src/components/Flex/Flex.stories.js +0 -127
- package/src/components/Flex/RFlex.vue +0 -91
- package/src/components/Grid/Grid.mdx +0 -20
- package/src/components/Grid/Grid.stories.js +0 -107
- package/src/components/Grid/RGrid.vue +0 -138
- package/src/components/Icon/Icon.mdx +0 -68
- package/src/components/Icon/Icon.stories.ts +0 -33
- package/src/components/Icon/RIcon.vue +0 -56
- package/src/components/Icon/icon.spec.ts +0 -25
- package/src/components/ItemGroup/ItemGroup.stories.ts +0 -91
- package/src/components/ItemGroup/RItem.vue +0 -74
- package/src/components/ItemGroup/RItemGroup.vue +0 -122
- package/src/components/ItemGroup/__snapshots__/itemgroup.spec.ts.snap +0 -13
- package/src/components/ItemGroup/itemgroup.spec.ts +0 -67
- package/src/components/Label/Label.mdx +0 -50
- package/src/components/Label/Label.stories.ts +0 -38
- package/src/components/Label/RLabel.vue +0 -42
- package/src/components/Label/label.css +0 -0
- package/src/components/Modal/Modal.mdx +0 -91
- package/src/components/Modal/Modal.stories.ts +0 -125
- package/src/components/Modal/RModal.vue +0 -130
- package/src/components/Modal/modal.css +0 -41
- package/src/components/Modal/modal.spec.ts +0 -25
- package/src/components/Pagination/Pagination.stories.ts +0 -24
- package/src/components/Pagination/RPagination.vue +0 -103
- package/src/components/Pagination/pagination.css +0 -47
- package/src/components/Pagination/pagination.spec.ts +0 -17
- package/src/components/ProgressBar/ProgressBar.stories.ts +0 -34
- package/src/components/ProgressBar/RProgressBar.vue +0 -21
- package/src/components/ProgressBar/progressbar.css +0 -24
- package/src/components/ProgressBar/progressbar.spec.ts +0 -17
- package/src/components/Shared/Enums.ts +0 -1
- package/src/components/Sidebar/RSidebar.vue +0 -27
- package/src/components/Sidebar/Sidebar.mdx +0 -31
- package/src/components/Sidebar/Sidebar.stories.ts +0 -34
- package/src/components/Sidebar/sidebar.css +0 -18
- package/src/components/Sidebar/sidebar.spec.ts +0 -33
- package/src/components/Snackbar/RSnackbar.vue +0 -136
- package/src/components/Snackbar/Snackbar.mdx +0 -126
- package/src/components/Snackbar/Snackbar.stories.ts +0 -93
- package/src/components/Snackbar/snackbar.css +0 -99
- package/src/components/Snackbar/snackbar.spec.ts +0 -56
- package/src/components/Switch/RSwitch.vue +0 -147
- package/src/components/Switch/Switch.mdx +0 -102
- package/src/components/Switch/Switch.stories.ts +0 -79
- package/src/components/Switch/switch.css +0 -102
- package/src/components/Switch/switch.spec.ts +0 -31
- package/src/components/TabItem/RTabItem.vue +0 -175
- package/src/components/TabItem/TabItem.mdx +0 -95
- package/src/components/TabItem/TabItem.spec.ts +0 -29
- package/src/components/TabItem/TabItem.stories.ts +0 -97
- package/src/components/TabItem/common.ts +0 -6
- package/src/components/TabItem/tab-item.css +0 -29
- package/src/components/Tabs/RTabs.vue +0 -94
- package/src/components/Tabs/Tabs.mdx +0 -78
- package/src/components/Tabs/Tabs.spec.ts +0 -28
- package/src/components/Tabs/Tabs.stories.ts +0 -191
- package/src/components/Tabs/tabs.css +0 -13
- package/src/components/Tabs/types.ts +0 -11
- package/src/components/TextArea/RTextArea.vue +0 -142
- package/src/components/TextArea/TextArea.mdx +0 -108
- package/src/components/TextArea/TextArea.stories.ts +0 -55
- package/src/components/TextArea/textarea.css +0 -51
- package/src/components/TextArea/textarea.spec.ts +0 -36
- package/src/components/Textfield/RTextfield.vue +0 -372
- package/src/components/Textfield/Textfield.mdx +0 -159
- package/src/components/Textfield/Textfield.stories.ts +0 -121
- package/src/components/Textfield/textfield.css +0 -81
- package/src/components/Textfield/textfield.spec.ts +0 -34
- package/src/components/Tooltip/RTooltip.vue +0 -325
- package/src/components/Tooltip/Tooltip.mdx +0 -111
- package/src/components/Tooltip/Tooltip.stories.ts +0 -203
- package/src/components/Tooltip/common.ts +0 -91
- package/src/components/Tooltip/tooltip.css +0 -34
- package/src/components/Tooltip/tooltip.spec.ts +0 -81
- package/src/components/Typography/Typography.mdx +0 -109
- package/src/components/Typography/typography.css +0 -128
- package/src/directives/index.ts +0 -19
- package/src/index.css +0 -241
- package/src/main.ts +0 -5
- package/src/scripts/buildIcons.js +0 -21
- package/src/stories/Colors.mdx +0 -355
- package/src/stories/GettingStarted.mdx +0 -121
- package/src/stories/Layout.mdx +0 -15
- package/tailwind.config.cjs +0 -16
- package/tsconfig.json +0 -24
- package/vite.config.ts +0 -39
- package/vitest.config.ts +0 -12
- /package/{public → dist}/design-tokens.source.json +0 -0
- /package/{public → dist}/favicon.ico +0 -0
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { Canvas, Meta, Story, Controls } from '@storybook/blocks';
|
|
2
|
-
|
|
3
|
-
import * as DropdownStories from './Dropdown.stories';
|
|
4
|
-
|
|
5
|
-
<Meta of={DropdownStories} />
|
|
6
|
-
|
|
7
|
-
# Dropdown
|
|
8
|
-
|
|
9
|
-
A Dropdown component is a UI element that allows users to select from a list of options in a compact, space-efficient manner. It is typically implemented as a button or a toggle that, when clicked, displays a list of options for the user to choose from.
|
|
10
|
-
|
|
11
|
-
- [Overview](#overview)
|
|
12
|
-
|
|
13
|
-
- [Playground](#playground)
|
|
14
|
-
|
|
15
|
-
- [Usage with props](#usage)
|
|
16
|
-
|
|
17
|
-
- [Slots](#slots)
|
|
18
|
-
|
|
19
|
-
- [Stories](#stories)
|
|
20
|
-
|
|
21
|
-
- [Tips](#tips)
|
|
22
|
-
|
|
23
|
-
## Overview <a id="overview" />
|
|
24
|
-
|
|
25
|
-
A Dropdown component is a UI element that allows users to select one or more options from a list in a compact and efficient manner. This particular Dropdown component has several customizable props that can be used to enhance its functionality and user experience.
|
|
26
|
-
It offers a wide range of customization options that allow for greater flexibility and a better user experience. It can be used in a variety of contexts and can be tailored to suit the specific needs of the application.
|
|
27
|
-
|
|
28
|
-
<Canvas>
|
|
29
|
-
<Story of={DropdownStories.Overview} />
|
|
30
|
-
</Canvas>
|
|
31
|
-
|
|
32
|
-
## Playground <a id="playground" />
|
|
33
|
-
|
|
34
|
-
> Changes you make in the controls will be reflected in the example above.
|
|
35
|
-
|
|
36
|
-
<Controls
|
|
37
|
-
of={DropdownStories.Overview}
|
|
38
|
-
exclude={/^(click|prepend-icon|append-icon|option-prepend|update.*|on.*)$/}
|
|
39
|
-
/>
|
|
40
|
-
|
|
41
|
-
## Usage with props <a id="usage" />
|
|
42
|
-
|
|
43
|
-
### appendIcon and prependIcon (optional)
|
|
44
|
-
|
|
45
|
-
The **appendIcon** and "prependIcon" props allow for the inclusion of icons or other visual elements at the end or beginning of the dropdown button, providing a clear indication of its purpose and functionality.
|
|
46
|
-
|
|
47
|
-
### options (required)
|
|
48
|
-
|
|
49
|
-
The **options** prop allows you to define the list of choices that the user can select from, which can be represented as text or other visual elements.
|
|
50
|
-
|
|
51
|
-
#### options: label (required)
|
|
52
|
-
|
|
53
|
-
The **label** prop allows you to define the text that will be displayed in the dropdown button.
|
|
54
|
-
|
|
55
|
-
#### options: value (required)
|
|
56
|
-
|
|
57
|
-
The **value** prop allows you to define the value of the selected option.
|
|
58
|
-
|
|
59
|
-
#### options: prependIcon (optional)
|
|
60
|
-
|
|
61
|
-
The **prependIcon** prop allows for the inclusion of icons or other visual elements at the beginning of the option, providing a clear indication of its purpose and functionality.
|
|
62
|
-
|
|
63
|
-
#### options: disabled (optional)
|
|
64
|
-
|
|
65
|
-
The **disabled** prop disables the option and prevent the user from interacting with it
|
|
66
|
-
|
|
67
|
-
### placeholder (optional)
|
|
68
|
-
|
|
69
|
-
The **placeholder** prop allows you to define the default text displayed in the dropdown button before a user makes a selection.
|
|
70
|
-
|
|
71
|
-
### taggable (optional)
|
|
72
|
-
|
|
73
|
-
The **taggable** prop allows users to create new options on-the-fly, rather than just selecting from pre-defined options.
|
|
74
|
-
|
|
75
|
-
### multiple (optional)
|
|
76
|
-
|
|
77
|
-
The **multiple** prop allows users to select more than one option at a time.
|
|
78
|
-
|
|
79
|
-
### disabled (optional)
|
|
80
|
-
|
|
81
|
-
The **disabled** prop disables the component and prevent the user from interacting with it
|
|
82
|
-
|
|
83
|
-
### loading (optional)
|
|
84
|
-
|
|
85
|
-
The **loading** prop allows you to indicate that the component is in a loading state and the user should wait for the options to appear.
|
|
86
|
-
|
|
87
|
-
### modelValue (optional)
|
|
88
|
-
|
|
89
|
-
The **modelValue** prop allows you to define the value of the selected option.
|
|
90
|
-
|
|
91
|
-
## Slots <a id="slots" />
|
|
92
|
-
|
|
93
|
-
### option-prepend (optional)
|
|
94
|
-
|
|
95
|
-
The **option-prepend** slot allows you to define the content that will be displayed before the option label.
|
|
96
|
-
|
|
97
|
-
### option-append (optional)
|
|
98
|
-
|
|
99
|
-
The **option-append** slot allows you to define the content that will be displayed after the option label.
|
|
100
|
-
|
|
101
|
-
### prependIcon (optional)
|
|
102
|
-
|
|
103
|
-
The **prependIcon** slot allows you to define the content that will be displayed before the dropdown button label.
|
|
104
|
-
|
|
105
|
-
## Stories <a id="stories" />
|
|
106
|
-
|
|
107
|
-
### Multiple
|
|
108
|
-
|
|
109
|
-
<Canvas>
|
|
110
|
-
<Story of={DropdownStories.Multiple} />
|
|
111
|
-
</Canvas>
|
|
112
|
-
|
|
113
|
-
### Taggable
|
|
114
|
-
|
|
115
|
-
<Canvas>
|
|
116
|
-
<Story of={DropdownStories.Taggable} />
|
|
117
|
-
</Canvas>
|
|
118
|
-
|
|
119
|
-
### Tips <a id="tips" />
|
|
120
|
-
|
|
121
|
-
💡 A long list of options can be overwhelming for users and make it difficult for them to find what they're looking for. Consider using a search or filtering feature to help users narrow down the options.
|
|
122
|
-
|
|
123
|
-
💡 The options in the list should have clear, concise labels that are easy for users to understand. Avoid using technical jargon or abbreviations that may be unfamiliar to some users.
|
|
124
|
-
|
|
125
|
-
💡 The Dropdown component should provide clear visual cues to indicate when it has focus, when an option is selected, and when the options list is open. This helps users understand the current state of the component and makes it easier for them to use.
|
|
126
|
-
|
|
127
|
-
💡 The Dropdown component should be operable by keyboard and screen reader users. This means providing clear labels and role attributes, as well as allowing users to navigate through the options using the arrow keys.
|
|
128
|
-
|
|
129
|
-
💡 Think about the specific context in which the Dropdown component will be used, and design it accordingly. For example, if it will be used for selecting a date, it may be helpful to include a calendar view or date picker.
|
|
130
|
-
|
|
131
|
-
💡 When an option is selected, the selected option should be clearly indicated, for example by changing the color of the selected option, and the selected option should be clearly visible.
|
|
132
|
-
|
|
133
|
-
💡 If the options are loaded asynchronously, it's a good practice to provide a clear indication of loading state, for example by showing a spinner, so the user knows that the options are not yet available and they have to wait.
|
|
134
|
-
|
|
135
|
-
💡 Make sure the component is accessible to all users, including those with disabilities. This means providing clear, accessible labels, and ensuring that the component can be easily operated by keyboard and screen reader users.
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
-
import { action } from '@storybook/addon-actions';
|
|
3
|
-
|
|
4
|
-
import Dropdown from './RDropdown.vue';
|
|
5
|
-
|
|
6
|
-
const DefaultArgs = {
|
|
7
|
-
options: [
|
|
8
|
-
{ value: '1', label: 'Option 1' },
|
|
9
|
-
{ value: '2', label: '2' },
|
|
10
|
-
{ value: '3', label: '3' },
|
|
11
|
-
{ value: '4', label: 'Option 4' },
|
|
12
|
-
{ value: '5', label: 'Option 5' },
|
|
13
|
-
{ value: '6', label: 'Option 6' },
|
|
14
|
-
{ value: '7', label: '7' },
|
|
15
|
-
{ value: '8', label: 'Option 8' },
|
|
16
|
-
{ value: '9', label: 'Option 9' },
|
|
17
|
-
{ value: '10', label: 'Option 10' },
|
|
18
|
-
],
|
|
19
|
-
placeholder: 'Select an option',
|
|
20
|
-
taggable: false,
|
|
21
|
-
multiple: false,
|
|
22
|
-
disabled: false,
|
|
23
|
-
loading: false,
|
|
24
|
-
prependIcon: 'mdiFaceMan',
|
|
25
|
-
appendIcon: 'mdiChevronDown',
|
|
26
|
-
modelValue: '',
|
|
27
|
-
searchable: false,
|
|
28
|
-
};
|
|
29
|
-
const DropdownStory = {
|
|
30
|
-
title: 'Components/Dropdown',
|
|
31
|
-
component: Dropdown,
|
|
32
|
-
setup: (args: typeof Dropdown) => ({
|
|
33
|
-
args,
|
|
34
|
-
update: action('update:modelValue'),
|
|
35
|
-
}),
|
|
36
|
-
template: `
|
|
37
|
-
<Dropdown v-bind="args" @update="update" />
|
|
38
|
-
`,
|
|
39
|
-
args: DefaultArgs,
|
|
40
|
-
argTypes: {
|
|
41
|
-
'onUpdate:modelValue': { action: 'update:modelValue' },
|
|
42
|
-
},
|
|
43
|
-
} as Meta<typeof Dropdown>;
|
|
44
|
-
|
|
45
|
-
export default DropdownStory;
|
|
46
|
-
|
|
47
|
-
type Story = StoryObj<typeof DropdownStory>;
|
|
48
|
-
|
|
49
|
-
export const Overview: Story = {
|
|
50
|
-
args: {
|
|
51
|
-
appendIcon: 'mdiChevronDown',
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const Multiple: Story = {
|
|
56
|
-
args: {
|
|
57
|
-
multiple: true,
|
|
58
|
-
placeholder: 'Select multiple options',
|
|
59
|
-
appendIcon: 'mdiChevronDown',
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export const Taggable: Story = {
|
|
64
|
-
args: {
|
|
65
|
-
taggable: true,
|
|
66
|
-
placeholder: 'Search or create a tag',
|
|
67
|
-
appendIcon: 'mdiChevronDown',
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export const Search: Story = {
|
|
72
|
-
args: {
|
|
73
|
-
options: [
|
|
74
|
-
{ value: '1', label: 'Option 1' },
|
|
75
|
-
{ value: '2', label: 'Option 2' },
|
|
76
|
-
{ value: '3', label: 'Option 3' },
|
|
77
|
-
{ value: '4', label: 'Option 4' },
|
|
78
|
-
],
|
|
79
|
-
placeholder: 'Search',
|
|
80
|
-
prependIcon: 'mdiMagnify',
|
|
81
|
-
appendIcon: 'mdiChevronDown',
|
|
82
|
-
searchable: true,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, reactive, ref, defineEmits, watch, onMounted } from 'vue';
|
|
3
|
-
import { onClickOutside } from '@vueuse/core';
|
|
4
|
-
import Chip from '../Chips/RChip.vue';
|
|
5
|
-
import Icon from '../Icon/RIcon.vue';
|
|
6
|
-
import './dropdown.css';
|
|
7
|
-
export interface Option {
|
|
8
|
-
value: string | number;
|
|
9
|
-
label: string;
|
|
10
|
-
prependIcon?: string;
|
|
11
|
-
disabled?: boolean;
|
|
12
|
-
}
|
|
13
|
-
export interface SelectProps {
|
|
14
|
-
/**
|
|
15
|
-
* Options of the Dropdown
|
|
16
|
-
* @type Option[]
|
|
17
|
-
* @default []
|
|
18
|
-
* @example
|
|
19
|
-
* <Dropdown
|
|
20
|
-
* :options="[
|
|
21
|
-
* {
|
|
22
|
-
* value: '1',
|
|
23
|
-
* label: 'Option 1',
|
|
24
|
-
* },
|
|
25
|
-
* {
|
|
26
|
-
* value: '2',
|
|
27
|
-
* label: '2',
|
|
28
|
-
* },
|
|
29
|
-
* ]"
|
|
30
|
-
* />
|
|
31
|
-
*/
|
|
32
|
-
options: Option[];
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Value of the Dropdown
|
|
36
|
-
* @type string | number | Option | Option[]
|
|
37
|
-
* @default ''
|
|
38
|
-
* @example
|
|
39
|
-
* <Dropdown v-model="model" />
|
|
40
|
-
*/
|
|
41
|
-
modelValue: string | number | Option | Option[];
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Placeholder Dropdown
|
|
45
|
-
* @type InputHTMLAttributes['placeholder'];
|
|
46
|
-
* @default ''
|
|
47
|
-
* @example
|
|
48
|
-
* <Dropdown placeholder="Placeholder" />
|
|
49
|
-
* @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#placeholder
|
|
50
|
-
*/
|
|
51
|
-
placeholder?: string;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Allow to create new options
|
|
55
|
-
* @type boolean
|
|
56
|
-
* @default false
|
|
57
|
-
* @example
|
|
58
|
-
* <Dropdown taggable />
|
|
59
|
-
*/
|
|
60
|
-
taggable?: boolean;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Allow to select multiple options
|
|
64
|
-
* @type boolean
|
|
65
|
-
* @default false
|
|
66
|
-
* @example
|
|
67
|
-
* <Dropdown multiple />
|
|
68
|
-
*/
|
|
69
|
-
multiple?: boolean;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Disable the Dropdown
|
|
73
|
-
* @type boolean
|
|
74
|
-
* @default false
|
|
75
|
-
* @example
|
|
76
|
-
* <Dropdown disabled />
|
|
77
|
-
*/
|
|
78
|
-
disabled?: boolean;
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Loading state of the Dropdown
|
|
82
|
-
* @type boolean
|
|
83
|
-
* @default false
|
|
84
|
-
* @example
|
|
85
|
-
* <Dropdown loading />
|
|
86
|
-
*/
|
|
87
|
-
loading?: boolean;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Icon to prepend
|
|
91
|
-
* @type string
|
|
92
|
-
* @default ''
|
|
93
|
-
* @example
|
|
94
|
-
* <Dropdown prependIcon="search" />
|
|
95
|
-
*/
|
|
96
|
-
prependIcon?: string;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Icon to append
|
|
100
|
-
* @type string
|
|
101
|
-
* @default 'expand_less'
|
|
102
|
-
* @example
|
|
103
|
-
* <Dropdown appendIcon="expand_more" />
|
|
104
|
-
*/
|
|
105
|
-
appendIcon?: string;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Allow to search for options
|
|
109
|
-
* @type boolean
|
|
110
|
-
* @default false
|
|
111
|
-
* @example
|
|
112
|
-
* <Dropdown searchable />
|
|
113
|
-
*/
|
|
114
|
-
searchable?: boolean;
|
|
115
|
-
parentElement?: string;
|
|
116
|
-
id?: string;
|
|
117
|
-
}
|
|
118
|
-
const props = withDefaults(defineProps<SelectProps>(), {
|
|
119
|
-
options: () => [],
|
|
120
|
-
modelValue: '',
|
|
121
|
-
placeholder: '',
|
|
122
|
-
taggable: false,
|
|
123
|
-
multiple: false,
|
|
124
|
-
disabled: false,
|
|
125
|
-
loading: false,
|
|
126
|
-
prependIcon: '',
|
|
127
|
-
appendIcon: 'mdiChevronDown',
|
|
128
|
-
searchable: false,
|
|
129
|
-
id: 'test',
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const selected = ref<string | number>('');
|
|
133
|
-
const selectedMultiple = reactive<Option[]>([]);
|
|
134
|
-
const active = ref(false);
|
|
135
|
-
const inputModel = ref('');
|
|
136
|
-
const emit = defineEmits(['update:modelValue']);
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* @description - HTML elements references
|
|
140
|
-
*/
|
|
141
|
-
const dropdown = ref<HTMLElement | null>(null);
|
|
142
|
-
const input = ref<HTMLInputElement | null>(null);
|
|
143
|
-
const wrapper = ref<HTMLElement | null>(null);
|
|
144
|
-
/**
|
|
145
|
-
* @description - Handles the appearance of the select list
|
|
146
|
-
* @param e MouseEvent
|
|
147
|
-
* @returns void
|
|
148
|
-
*/
|
|
149
|
-
const setActive = (e: MouseEvent) => {
|
|
150
|
-
if (props.disabled) return;
|
|
151
|
-
e.stopPropagation();
|
|
152
|
-
active.value = !active.value;
|
|
153
|
-
if (active.value) {
|
|
154
|
-
dropdown.value?.classList.add('dropdown--active');
|
|
155
|
-
dropdown.value?.focus();
|
|
156
|
-
if (props.searchable) input.value?.focus();
|
|
157
|
-
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
removeActive();
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* @description - Removes the active state
|
|
165
|
-
* @returns void
|
|
166
|
-
*/
|
|
167
|
-
const removeActive = () => {
|
|
168
|
-
active.value = false;
|
|
169
|
-
dropdown.value?.classList.remove('dropdown--active');
|
|
170
|
-
dropdown.value?.blur();
|
|
171
|
-
input.value?.blur();
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* @description - Selects an option
|
|
176
|
-
* @param e Click event
|
|
177
|
-
* @param option Selected option
|
|
178
|
-
* @returns void
|
|
179
|
-
*/
|
|
180
|
-
const selectOption = (e: MouseEvent, option: Option) => {
|
|
181
|
-
if (props.multiple || props.taggable) {
|
|
182
|
-
e.stopPropagation();
|
|
183
|
-
if (!selectedMultiple.find((opt) => opt.value === option.value)) {
|
|
184
|
-
selectedMultiple.push(option);
|
|
185
|
-
} else {
|
|
186
|
-
selectedMultiple.splice(selectedMultiple.indexOf(option), 1);
|
|
187
|
-
}
|
|
188
|
-
inputModel.value = '';
|
|
189
|
-
if (props.searchable) input.value?.focus();
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
selectOneOption(e, option);
|
|
194
|
-
};
|
|
195
|
-
/**
|
|
196
|
-
* @description - Selects one option
|
|
197
|
-
* @param option Selected option
|
|
198
|
-
* @returns void
|
|
199
|
-
*/
|
|
200
|
-
const selectOneOption = (e: MouseEvent, option: Option) => {
|
|
201
|
-
if (selected.value === option.value) {
|
|
202
|
-
selected.value = '';
|
|
203
|
-
inputModel.value = '';
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
inputModel.value = option.label;
|
|
207
|
-
selected.value = option.value;
|
|
208
|
-
setActive(e);
|
|
209
|
-
emit('update:modelValue', option);
|
|
210
|
-
};
|
|
211
|
-
/**
|
|
212
|
-
* @description - Removes an option from the selected options
|
|
213
|
-
* @param option Option to remove
|
|
214
|
-
* @returns void
|
|
215
|
-
*/
|
|
216
|
-
const removeOption = (e: MouseEvent | KeyboardEvent, option: Option) => {
|
|
217
|
-
if (e instanceof KeyboardEvent && e.key !== 'Backspace') return;
|
|
218
|
-
if (inputModel.value !== '') return;
|
|
219
|
-
e.stopPropagation();
|
|
220
|
-
const index = selectedMultiple.findIndex((opt) => opt.value === option.value);
|
|
221
|
-
selectedMultiple.splice(index, 1);
|
|
222
|
-
};
|
|
223
|
-
/**
|
|
224
|
-
* @description - Handles the not existing options
|
|
225
|
-
* @returns void
|
|
226
|
-
*/
|
|
227
|
-
const createTag = (e: KeyboardEvent) => {
|
|
228
|
-
if (!props.taggable) return;
|
|
229
|
-
e.stopPropagation();
|
|
230
|
-
const value = inputModel.value;
|
|
231
|
-
if (value === '') return;
|
|
232
|
-
const option = props.options.find((opt) => opt.label === value);
|
|
233
|
-
if (!option) {
|
|
234
|
-
selectedMultiple.push({ value, label: value });
|
|
235
|
-
inputModel.value = '';
|
|
236
|
-
input.value?.focus();
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
const isSelected = (option: Option) => {
|
|
240
|
-
if (props.multiple) {
|
|
241
|
-
return selectedMultiple.find((opt) => opt.value === option.value);
|
|
242
|
-
}
|
|
243
|
-
return selected.value === option.value;
|
|
244
|
-
};
|
|
245
|
-
/**
|
|
246
|
-
* @description - Search for options
|
|
247
|
-
* @returns {Option[]} - Returns an array of options
|
|
248
|
-
*/
|
|
249
|
-
const searchedOptions = computed(() => {
|
|
250
|
-
if (!props.searchable) return props.options;
|
|
251
|
-
const result = props.options.filter((option) => {
|
|
252
|
-
return option.label.toLowerCase().includes(inputModel.value.toLowerCase());
|
|
253
|
-
});
|
|
254
|
-
return result;
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
onMounted(() => {
|
|
258
|
-
if (props.modelValue) {
|
|
259
|
-
if (props.multiple) {
|
|
260
|
-
selectedMultiple.push(props.modelValue as Option);
|
|
261
|
-
} else {
|
|
262
|
-
selected.value = (props.modelValue as Option).value;
|
|
263
|
-
inputModel.value = (props.modelValue as Option).label;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
/**
|
|
268
|
-
* @description - Watch the selected multiple options
|
|
269
|
-
* @returns void
|
|
270
|
-
*/
|
|
271
|
-
watch(selectedMultiple, (value) => {
|
|
272
|
-
emit('update:modelValue', value);
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* @description - Watch the outside click
|
|
277
|
-
* @returns void
|
|
278
|
-
*/
|
|
279
|
-
onClickOutside(wrapper, removeActive);
|
|
280
|
-
</script>
|
|
281
|
-
<template>
|
|
282
|
-
<div class="dropdown-wrapper" ref="wrapper">
|
|
283
|
-
<div
|
|
284
|
-
ref="dropdown"
|
|
285
|
-
:class="{
|
|
286
|
-
dropdown: true,
|
|
287
|
-
'dropdown--disabled': props.disabled,
|
|
288
|
-
'dropdown--loading': props.loading,
|
|
289
|
-
}"
|
|
290
|
-
@click="setActive"
|
|
291
|
-
>
|
|
292
|
-
<div
|
|
293
|
-
v-if="props.prependIcon || $slots['prepend']"
|
|
294
|
-
:class="{
|
|
295
|
-
'dropdown__prepend-icon': true,
|
|
296
|
-
'dropdown__prepend-icon--active': active,
|
|
297
|
-
}"
|
|
298
|
-
>
|
|
299
|
-
<slot name="prepend">
|
|
300
|
-
<Icon v-if="props.prependIcon" :name="props.prependIcon" />
|
|
301
|
-
</slot>
|
|
302
|
-
</div>
|
|
303
|
-
<div v-if="props.taggable" class="dropdown__tags">
|
|
304
|
-
<Chip
|
|
305
|
-
v-for="(option, index) in selectedMultiple"
|
|
306
|
-
:key="index"
|
|
307
|
-
:label="option.label"
|
|
308
|
-
appendIcon="close"
|
|
309
|
-
class="dropdown__tags__chip"
|
|
310
|
-
variant="primary"
|
|
311
|
-
@click:close="removeOption($event, option)"
|
|
312
|
-
/>
|
|
313
|
-
</div>
|
|
314
|
-
<div v-if="props.multiple" class="dropdown__multiple">
|
|
315
|
-
<p v-for="(option, index) in selectedMultiple" :key="index">
|
|
316
|
-
{{ option.label + ',' }}
|
|
317
|
-
</p>
|
|
318
|
-
</div>
|
|
319
|
-
<input
|
|
320
|
-
:id="props.id"
|
|
321
|
-
ref="input"
|
|
322
|
-
type="text"
|
|
323
|
-
v-model="inputModel"
|
|
324
|
-
:class="{
|
|
325
|
-
dropdown__input: true,
|
|
326
|
-
'dropdown__input--loading': props.loading,
|
|
327
|
-
}"
|
|
328
|
-
:disabled="props.disabled"
|
|
329
|
-
:placeholder="props.placeholder"
|
|
330
|
-
:readonly="!props.searchable"
|
|
331
|
-
@keydown.backspace="
|
|
332
|
-
removeOption($event, selectedMultiple[selectedMultiple.length - 1])
|
|
333
|
-
"
|
|
334
|
-
@keydown.enter="createTag($event)"
|
|
335
|
-
/>
|
|
336
|
-
<div
|
|
337
|
-
v-if="props.appendIcon || $slots['append']"
|
|
338
|
-
:class="{
|
|
339
|
-
'dropdown__append-icon': true,
|
|
340
|
-
'dropdown__append-icon--active': active,
|
|
341
|
-
}"
|
|
342
|
-
>
|
|
343
|
-
<slot name="append">
|
|
344
|
-
<Icon v-if="props.appendIcon" :name="props.appendIcon" />
|
|
345
|
-
</slot>
|
|
346
|
-
</div>
|
|
347
|
-
</div>
|
|
348
|
-
<ul
|
|
349
|
-
:class="{ 'dropdown-options': true, 'dropdown-options--active': active }"
|
|
350
|
-
>
|
|
351
|
-
<li
|
|
352
|
-
v-for="option in searchedOptions"
|
|
353
|
-
:key="option.value"
|
|
354
|
-
:class="{
|
|
355
|
-
'dropdown-options__option': true,
|
|
356
|
-
'dropdown-options__option--active': isSelected(option),
|
|
357
|
-
}"
|
|
358
|
-
:aria-disabled="option.disabled"
|
|
359
|
-
@click="selectOption($event, option)"
|
|
360
|
-
>
|
|
361
|
-
<div style="display: flex; align-items: center">
|
|
362
|
-
<slot v-if="!option.prependIcon" name="option-prepend" />
|
|
363
|
-
<Icon
|
|
364
|
-
v-else
|
|
365
|
-
:class="{
|
|
366
|
-
'dropdown-options__option__prepend-icon': true,
|
|
367
|
-
'dropdown-options__option__prepend-icon--active':
|
|
368
|
-
isSelected(option),
|
|
369
|
-
}"
|
|
370
|
-
:name="option.prependIcon"
|
|
371
|
-
/>
|
|
372
|
-
<p
|
|
373
|
-
:class="{
|
|
374
|
-
'dropdown-options__option__label': true,
|
|
375
|
-
'dropdown-options__option__label--active': isSelected(option),
|
|
376
|
-
}"
|
|
377
|
-
>
|
|
378
|
-
{{ option.label }}
|
|
379
|
-
</p>
|
|
380
|
-
</div>
|
|
381
|
-
<Icon
|
|
382
|
-
v-if="isSelected(option)"
|
|
383
|
-
:class="{
|
|
384
|
-
'dropdown-options__option__append-icon': true,
|
|
385
|
-
'dropdown-options__option__append-icon--active': isSelected(option),
|
|
386
|
-
}"
|
|
387
|
-
name="mdiCheck"
|
|
388
|
-
/>
|
|
389
|
-
</li>
|
|
390
|
-
</ul>
|
|
391
|
-
</div>
|
|
392
|
-
</template>
|