@rocketui/vue 0.0.46 → 0.0.47
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/.eslintrc.cjs +79 -0
- package/.gitattributes +2 -0
- package/.github/workflows/chromatic.yml +28 -0
- package/.github/workflows/publish-storybook.yml +41 -0
- package/.husky/pre-commit +4 -0
- package/.prettierrc.cjs +10 -0
- package/.storybook/Theme.js +17 -0
- package/.storybook/main.ts +20 -0
- package/.storybook/manager-head.html +3 -0
- package/.storybook/manager.js +8 -0
- package/.storybook/preview-head.html +3 -0
- package/.storybook/preview.ts +36 -0
- package/.storybook/source-panel/manager.js +28 -0
- package/.storybook/withSource.js +91 -0
- package/.vscode/extensions.json +11 -0
- package/.vscode/settings.json +20 -0
- package/index.html +13 -0
- package/lib/main.ts +48 -0
- package/package.json +2 -8
- package/postcss.config.cjs +9 -0
- package/resources/rocket-ui-logo-dark.svg +27 -0
- package/resources/rocket-ui-logo-light.svg +27 -0
- package/shims-rocketui.d.ts +9 -0
- package/src/App.vue +15 -0
- package/src/assets/blank-avatar.svg +3 -0
- package/src/assets/icons/mdi.js +7302 -0
- package/src/assets/logo.svg +1 -0
- package/src/components/Accordion/Accordion.mdx +88 -0
- package/src/components/Accordion/Accordion.stories.ts +257 -0
- package/src/components/Accordion/RAccordion.vue +73 -0
- package/src/components/Accordion/accordion.css +75 -0
- package/src/components/Accordion/accordion.spec.ts +123 -0
- package/src/components/Alert/Alert.mdx +120 -0
- package/src/components/Alert/Alert.stories.ts +118 -0
- package/src/components/Alert/RAlert.vue +119 -0
- package/src/components/Alert/alert.css +136 -0
- package/src/components/Alert/alert.spec.ts +32 -0
- package/src/components/Avatar/Avatar.mdx +96 -0
- package/src/components/Avatar/Avatar.stories.ts +65 -0
- package/src/components/Avatar/RAvatar.vue +115 -0
- package/src/components/Avatar/avatar.css +82 -0
- package/src/components/Avatar/avatar.spec.ts +38 -0
- package/src/components/Badge/Badge.mdx +112 -0
- package/src/components/Badge/Badge.stories.ts +99 -0
- package/src/components/Badge/RBadge.vue +89 -0
- package/src/components/Badge/badge.css +63 -0
- package/src/components/Badge/badge.spec.ts +20 -0
- package/src/components/Box/Box.mdx +20 -0
- package/src/components/Box/Box.stories.ts +56 -0
- package/src/components/Box/RBox.vue +97 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.ts +115 -0
- package/src/components/Breadcrumb/RBreadcrumb.vue +43 -0
- package/src/components/Breadcrumb/breadcrumb.css +29 -0
- package/src/components/Button/Button.mdx +148 -0
- package/src/components/Button/Button.spec.ts +29 -0
- package/src/components/Button/Button.stories.ts +118 -0
- package/src/components/Button/RButton.vue +179 -0
- package/src/components/Button/button.css +146 -0
- package/src/components/Checkbox/Checkbox.mdx +100 -0
- package/src/components/Checkbox/Checkbox.stories.ts +67 -0
- package/src/components/Checkbox/RCheckbox.vue +195 -0
- package/src/components/Checkbox/checkbox.css +67 -0
- package/src/components/Checkbox/checkbox.spec.ts +60 -0
- package/src/components/Chips/Chip.mdx +113 -0
- package/src/components/Chips/Chip.stories.ts +122 -0
- package/src/components/Chips/RChip.vue +125 -0
- package/src/components/Chips/chip.css +62 -0
- package/src/components/Chips/chip.spec.ts +40 -0
- package/src/components/Dropdown/Dropdown.mdx +135 -0
- package/src/components/Dropdown/Dropdown.stories.ts +84 -0
- package/src/components/Dropdown/RDropdown.vue +392 -0
- package/src/components/Dropdown/dropdown.css +113 -0
- package/src/components/Dropdown/dropdown.spec.ts +98 -0
- package/src/components/Flex/Flex.mdx +20 -0
- package/src/components/Flex/Flex.stories.js +127 -0
- package/src/components/Flex/RFlex.vue +91 -0
- package/src/components/Grid/Grid.mdx +20 -0
- package/src/components/Grid/Grid.stories.js +107 -0
- package/src/components/Grid/RGrid.vue +138 -0
- package/src/components/Icon/Icon.mdx +68 -0
- package/src/components/Icon/Icon.stories.ts +33 -0
- package/src/components/Icon/RIcon.vue +56 -0
- package/src/components/Icon/icon.spec.ts +25 -0
- package/src/components/ItemGroup/ItemGroup.stories.ts +91 -0
- package/src/components/ItemGroup/RItem.vue +74 -0
- package/src/components/ItemGroup/RItemGroup.vue +122 -0
- package/src/components/ItemGroup/__snapshots__/itemgroup.spec.ts.snap +13 -0
- package/src/components/ItemGroup/itemgroup.spec.ts +67 -0
- package/src/components/Label/Label.mdx +50 -0
- package/src/components/Label/Label.stories.ts +38 -0
- package/src/components/Label/RLabel.vue +42 -0
- package/src/components/Label/label.css +0 -0
- package/src/components/Modal/Modal.mdx +91 -0
- package/src/components/Modal/Modal.stories.ts +125 -0
- package/src/components/Modal/RModal.vue +130 -0
- package/src/components/Modal/modal.css +41 -0
- package/src/components/Modal/modal.spec.ts +25 -0
- package/src/components/Pagination/Pagination.stories.ts +24 -0
- package/src/components/Pagination/RPagination.vue +103 -0
- package/src/components/Pagination/pagination.css +47 -0
- package/src/components/Pagination/pagination.spec.ts +17 -0
- package/src/components/ProgressBar/ProgressBar.stories.ts +34 -0
- package/src/components/ProgressBar/RProgressBar.vue +21 -0
- package/src/components/ProgressBar/progressbar.css +24 -0
- package/src/components/ProgressBar/progressbar.spec.ts +17 -0
- package/src/components/Shared/Enums.ts +1 -0
- package/src/components/Sidebar/RSidebar.vue +27 -0
- package/src/components/Sidebar/Sidebar.mdx +31 -0
- package/src/components/Sidebar/Sidebar.stories.ts +34 -0
- package/src/components/Sidebar/sidebar.css +18 -0
- package/src/components/Sidebar/sidebar.spec.ts +33 -0
- package/src/components/Snackbar/RSnackbar.vue +136 -0
- package/src/components/Snackbar/Snackbar.mdx +126 -0
- package/src/components/Snackbar/Snackbar.stories.ts +93 -0
- package/src/components/Snackbar/snackbar.css +99 -0
- package/src/components/Snackbar/snackbar.spec.ts +56 -0
- package/src/components/Switch/RSwitch.vue +147 -0
- package/src/components/Switch/Switch.mdx +102 -0
- package/src/components/Switch/Switch.stories.ts +79 -0
- package/src/components/Switch/switch.css +102 -0
- package/src/components/Switch/switch.spec.ts +31 -0
- package/src/components/TabItem/RTabItem.vue +175 -0
- package/src/components/TabItem/TabItem.mdx +95 -0
- package/src/components/TabItem/TabItem.spec.ts +29 -0
- package/src/components/TabItem/TabItem.stories.ts +97 -0
- package/src/components/TabItem/common.ts +6 -0
- package/src/components/TabItem/tab-item.css +29 -0
- package/src/components/Tabs/RTabs.vue +94 -0
- package/src/components/Tabs/Tabs.mdx +78 -0
- package/src/components/Tabs/Tabs.spec.ts +28 -0
- package/src/components/Tabs/Tabs.stories.ts +191 -0
- package/src/components/Tabs/tabs.css +13 -0
- package/src/components/Tabs/types.ts +11 -0
- package/src/components/TextArea/RTextArea.vue +142 -0
- package/src/components/TextArea/TextArea.mdx +108 -0
- package/src/components/TextArea/TextArea.stories.ts +55 -0
- package/src/components/TextArea/textarea.css +51 -0
- package/src/components/TextArea/textarea.spec.ts +36 -0
- package/src/components/Textfield/RTextfield.vue +372 -0
- package/src/components/Textfield/Textfield.mdx +159 -0
- package/src/components/Textfield/Textfield.stories.ts +121 -0
- package/src/components/Textfield/textfield.css +81 -0
- package/src/components/Textfield/textfield.spec.ts +34 -0
- package/src/components/Tooltip/RTooltip.vue +325 -0
- package/src/components/Tooltip/Tooltip.mdx +111 -0
- package/src/components/Tooltip/Tooltip.stories.ts +203 -0
- package/src/components/Tooltip/common.ts +91 -0
- package/src/components/Tooltip/tooltip.css +34 -0
- package/src/components/Tooltip/tooltip.spec.ts +81 -0
- package/src/components/Typography/Typography.mdx +109 -0
- package/src/components/Typography/typography.css +128 -0
- package/src/directives/index.ts +19 -0
- package/src/index.css +241 -0
- package/src/main.ts +5 -0
- package/src/scripts/buildIcons.js +21 -0
- package/src/stories/Colors.mdx +355 -0
- package/src/stories/GettingStarted.mdx +121 -0
- package/src/stories/Layout.mdx +15 -0
- package/tailwind.config.cjs +16 -0
- package/tsconfig.json +24 -0
- package/vite.config.ts +39 -0
- package/vitest.config.ts +12 -0
- package/dist/rocket-ui-vue.js +0 -9381
- package/dist/rocket-ui-vue.umd.cjs +0 -1
- package/dist/style.css +0 -2
- package/dist/types/main.d.ts +0 -25
- /package/{dist → public}/design-tokens.source.json +0 -0
- /package/{dist → public}/favicon.ico +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, type CSSProperties } from 'vue';
|
|
3
|
+
import '../../index.css';
|
|
4
|
+
export interface IProps extends CSSProperties {
|
|
5
|
+
/**
|
|
6
|
+
* Shorthand prop for `gridTemplateColumns`
|
|
7
|
+
* @type CSSProperties["gridTemplateColumns"]
|
|
8
|
+
* @default 'none'
|
|
9
|
+
* @example
|
|
10
|
+
* <Grid templateColumns="repeat(12, 1fr)" />
|
|
11
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
|
|
12
|
+
*/
|
|
13
|
+
templateColumns?: CSSProperties['gridTemplateColumns'];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Shorthand prop for `gridGap`
|
|
17
|
+
* @type CSSProperties["gridGap"]
|
|
18
|
+
* @default '0'
|
|
19
|
+
* @example
|
|
20
|
+
* <Grid gap="0" />
|
|
21
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/gap
|
|
22
|
+
*/
|
|
23
|
+
gap?: CSSProperties['gap'];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Shorthand prop for `rowGap`
|
|
27
|
+
* @type CSSProperties["rowGap"]
|
|
28
|
+
* @default '1rem'
|
|
29
|
+
* @example
|
|
30
|
+
* <Grid rowGap="1rem" />
|
|
31
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap
|
|
32
|
+
*/
|
|
33
|
+
rowGap?: CSSProperties['rowGap'];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Shorthand prop for `columnGap`
|
|
37
|
+
* @type CSSProperties["columnGap"]
|
|
38
|
+
* @default '1rem'
|
|
39
|
+
* @example
|
|
40
|
+
* <Grid columnGap="1rem" />
|
|
41
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap
|
|
42
|
+
*/
|
|
43
|
+
columnGap?: CSSProperties['columnGap'];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Shorthand prop for `gridAutoFlow`
|
|
47
|
+
* @type CSSProperties["gridAutoFlow"]
|
|
48
|
+
* @default 'row'
|
|
49
|
+
* @example
|
|
50
|
+
* <Grid autoFlow="row" />
|
|
51
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow
|
|
52
|
+
*/
|
|
53
|
+
autoFlow?: CSSProperties['gridAutoFlow'];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Shorthand prop for `gridAutoRows`
|
|
57
|
+
* @type CSSProperties["gridAutoRows"]
|
|
58
|
+
* @default 'auto'
|
|
59
|
+
* @example
|
|
60
|
+
* <Grid autoRows="auto" />
|
|
61
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-rows
|
|
62
|
+
*/
|
|
63
|
+
autoRows?: CSSProperties['gridAutoRows'];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Shorthand prop for `gridAutoColumns`
|
|
67
|
+
* @type CSSProperties["gridAutoColumns"]
|
|
68
|
+
* @default 'auto'
|
|
69
|
+
* @example
|
|
70
|
+
* <Grid autoColumns="auto" />
|
|
71
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-columns
|
|
72
|
+
*/
|
|
73
|
+
autoColumns?: CSSProperties['gridAutoColumns'];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Shorthand prop for `gridTemplateRows`
|
|
77
|
+
* @type CSSProperties["gridTemplateRows"]
|
|
78
|
+
* @default 'repeat(12, 1fr)'
|
|
79
|
+
* @example
|
|
80
|
+
* <Grid templateRows="repeat(12, 1fr)" />
|
|
81
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows
|
|
82
|
+
*/
|
|
83
|
+
templateRows?: CSSProperties['gridTemplateRows'];
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Shorthand prop for `gridTemplateAreas`
|
|
87
|
+
* @type CSSProperties["gridTemplateAreas"]
|
|
88
|
+
* @default 'repeat(12, 1fr)'
|
|
89
|
+
* @example
|
|
90
|
+
* <Grid templateAreas="repeat(12, 1fr)" />
|
|
91
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas
|
|
92
|
+
*/
|
|
93
|
+
templateAreas?: CSSProperties['gridTemplateAreas'];
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Shorthand prop for `gridColumn`
|
|
97
|
+
* @type CSSProperties["gridColumn"]
|
|
98
|
+
* @example
|
|
99
|
+
* <Grid column="1 / 3" />
|
|
100
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column
|
|
101
|
+
*/
|
|
102
|
+
column?: CSSProperties['gridColumn'];
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Shorthand prop for `gridRow`
|
|
106
|
+
* @type CSSProperties["gridRow"]
|
|
107
|
+
* @example
|
|
108
|
+
* <Grid row="1 / 3" />
|
|
109
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row
|
|
110
|
+
*/
|
|
111
|
+
row?: CSSProperties['gridRow'];
|
|
112
|
+
}
|
|
113
|
+
const props = defineProps<IProps>();
|
|
114
|
+
|
|
115
|
+
const gridStyle = computed(() => ({
|
|
116
|
+
gridTemplateColumns: props.templateColumns,
|
|
117
|
+
gridGap: props.gap,
|
|
118
|
+
rowGap: props.rowGap,
|
|
119
|
+
columnGap: props.columnGap,
|
|
120
|
+
gridAutoFlow: props.autoFlow,
|
|
121
|
+
gridAutoRows: props.autoRows,
|
|
122
|
+
gridAutoColumns: props.autoColumns,
|
|
123
|
+
gridTemplateRows: props.templateRows,
|
|
124
|
+
gridTemplateAreas: props.templateAreas,
|
|
125
|
+
gridColumn: props.column,
|
|
126
|
+
gridRow: props.row,
|
|
127
|
+
}));
|
|
128
|
+
</script>
|
|
129
|
+
<template>
|
|
130
|
+
<div class="grid" :style="gridStyle">
|
|
131
|
+
<slot />
|
|
132
|
+
</div>
|
|
133
|
+
</template>
|
|
134
|
+
<style scoped>
|
|
135
|
+
.grid {
|
|
136
|
+
display: grid;
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Canvas, Meta, Story, Controls } from '@storybook/blocks';
|
|
2
|
+
import * as IconStories from './Icon.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={IconStories} />
|
|
5
|
+
|
|
6
|
+
# Icon
|
|
7
|
+
|
|
8
|
+
The Icon component is used to display a graphical icon in your application.
|
|
9
|
+
|
|
10
|
+
- [Overview](#overview)
|
|
11
|
+
|
|
12
|
+
- [Playground](#playground)
|
|
13
|
+
|
|
14
|
+
- [Usage with props](#usage)
|
|
15
|
+
|
|
16
|
+
- [Tips](#tips)
|
|
17
|
+
|
|
18
|
+
## Overview <a id="overview" />
|
|
19
|
+
|
|
20
|
+
The Icon component is a graphical element that is used to visually represent an idea, concept, or action. It is typically used in conjunction with text or other graphical elements to provide a clear and concise way of conveying information to the user. It is highly customizable, allowing the developer to control the size, color, and style of the icon to match the design of the application.
|
|
21
|
+
|
|
22
|
+
The Icon component is a versatile and useful tool for adding visual emphasis and clarity to an application's user interface. It is important to use icons consistently and thoughtfully in order to create a cohesive and intuitive user experience.
|
|
23
|
+
|
|
24
|
+
To access a comprehensive list of icons available in our design system, please refer to the icon list page by clicking [the following link](https://pictogrammers.com/library/mdi/).
|
|
25
|
+
|
|
26
|
+
<Canvas>
|
|
27
|
+
<Story of={IconStories.Overview} />
|
|
28
|
+
</Canvas>
|
|
29
|
+
|
|
30
|
+
### Playground <a id="playground" />
|
|
31
|
+
|
|
32
|
+
> Changes you make in the controls will be reflected in the example above.
|
|
33
|
+
|
|
34
|
+
<Controls of={IconStories.Overview} />
|
|
35
|
+
|
|
36
|
+
## Usage with props <a id="usage" />
|
|
37
|
+
|
|
38
|
+
### name (required)
|
|
39
|
+
|
|
40
|
+
The **name** prop is a string that specifies the name of the icon you want to display. The list of available icons and their names can be found in the design system's icon library.
|
|
41
|
+
|
|
42
|
+
### size (optional)
|
|
43
|
+
|
|
44
|
+
The **size** prop is a number that specifies the size of the icon.
|
|
45
|
+
|
|
46
|
+
### viewBox (optional)
|
|
47
|
+
|
|
48
|
+
The **viewBox** prop is a string that specifies the viewBox of the icon.
|
|
49
|
+
|
|
50
|
+
### flip (optional)
|
|
51
|
+
|
|
52
|
+
The **flip** prop is a string that specifies the flip of the icon.
|
|
53
|
+
|
|
54
|
+
### rotate (optional)
|
|
55
|
+
|
|
56
|
+
The **rotate** prop is a number that specifies the rotation of the icon.
|
|
57
|
+
|
|
58
|
+
### Tips <a id="tips" />
|
|
59
|
+
|
|
60
|
+
💡 Choose a set of icons that are visually consistent and easy to understand. This will help create a cohesive look and feel for your application.
|
|
61
|
+
|
|
62
|
+
💡 Icons should be used to supplement text, not replace it. Text is still the most effective way to convey information, so make sure to use icons in conjunction with clear, concise text labels.
|
|
63
|
+
|
|
64
|
+
💡 Make sure to choose an icon that accurately represents the action or concept it is being used to represent. Using the wrong icon can lead to confusion for the user.
|
|
65
|
+
|
|
66
|
+
💡 Choose colors and sizes for your icons that are consistent with the overall design of your application. Large, bright icons may be attention-grabbing, but they can also be overwhelming if used too frequently.
|
|
67
|
+
|
|
68
|
+
💡 Make sure to consider accessibility when using icons. Use appropriate alt text for your icons, and consider providing additional information for users who may be unable to see the icons.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import { action } from '@storybook/addon-actions';
|
|
3
|
+
|
|
4
|
+
import Icon from './RIcon.vue';
|
|
5
|
+
|
|
6
|
+
const DefaultArgs = {};
|
|
7
|
+
|
|
8
|
+
const DefaultArgTypes = {};
|
|
9
|
+
|
|
10
|
+
// More on how to set up stories at: https://storybook.js.org/docs/vue/writing-stories/introduction
|
|
11
|
+
const IconStory = {
|
|
12
|
+
title: 'Components/Icon',
|
|
13
|
+
component: Icon,
|
|
14
|
+
setup: (args: typeof Icon) => ({
|
|
15
|
+
args,
|
|
16
|
+
onClick: action('click'),
|
|
17
|
+
}),
|
|
18
|
+
template: `<Icon v-bind="args" @click="onClick"/>`,
|
|
19
|
+
// This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/vue/writing-docs/autodocs
|
|
20
|
+
tags: [],
|
|
21
|
+
args: DefaultArgs,
|
|
22
|
+
argTypes: DefaultArgTypes,
|
|
23
|
+
} as Meta<typeof Icon>;
|
|
24
|
+
|
|
25
|
+
export default IconStory;
|
|
26
|
+
|
|
27
|
+
type Story = StoryObj<typeof IconStory>;
|
|
28
|
+
|
|
29
|
+
export const Overview: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
name: 'mdiFaceMan',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SVGAttributes } from 'vue';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import icons from '@/assets/icons/mdi.js';
|
|
5
|
+
|
|
6
|
+
export interface IProps {
|
|
7
|
+
/**
|
|
8
|
+
* Name of the icon
|
|
9
|
+
* @type SVGAttributes['name']
|
|
10
|
+
* @default ''
|
|
11
|
+
* @example
|
|
12
|
+
* <Icon name="icon" />
|
|
13
|
+
*/
|
|
14
|
+
name: SVGAttributes['name'];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Size of the icon
|
|
18
|
+
* @type SVGAttributes['width'] | SVGAttributes['height']
|
|
19
|
+
* @default 24
|
|
20
|
+
* @example
|
|
21
|
+
* <Icon size="24" />
|
|
22
|
+
*/
|
|
23
|
+
size?: SVGAttributes['width'] | SVGAttributes['height'];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Viewbox of the icon
|
|
27
|
+
* @type SVGAttributes['viewBox']
|
|
28
|
+
* @default '0 0 24 24'
|
|
29
|
+
* @example
|
|
30
|
+
* <Icon viewBox="0 0 24 24" />
|
|
31
|
+
*/
|
|
32
|
+
viewBox?: SVGAttributes['viewBox'];
|
|
33
|
+
}
|
|
34
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
35
|
+
name: '',
|
|
36
|
+
size: 24,
|
|
37
|
+
viewBox: '0 0 24 24',
|
|
38
|
+
});
|
|
39
|
+
</script>
|
|
40
|
+
<template>
|
|
41
|
+
<svg
|
|
42
|
+
class="r-icon"
|
|
43
|
+
:width="props.size"
|
|
44
|
+
:height="props.size"
|
|
45
|
+
:viewBox="props.viewBox"
|
|
46
|
+
>
|
|
47
|
+
<path :d="icons[props.name]" />
|
|
48
|
+
</svg>
|
|
49
|
+
</template>
|
|
50
|
+
<style>
|
|
51
|
+
.r-icon {
|
|
52
|
+
path {
|
|
53
|
+
fill: currentColor;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { mount } from '@vue/test-utils';
|
|
4
|
+
import Icon from './RIcon.vue';
|
|
5
|
+
|
|
6
|
+
describe('Icon', () => {
|
|
7
|
+
it('renders properly', () => {
|
|
8
|
+
const wrapper = mount(Icon, {
|
|
9
|
+
props: {
|
|
10
|
+
name: 'face',
|
|
11
|
+
size: '24',
|
|
12
|
+
color: 'rgb(255, 255, 255)',
|
|
13
|
+
kind: 'outlined',
|
|
14
|
+
fontWeight: 'bold',
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
expect(wrapper.exists()).toBe(true);
|
|
18
|
+
expect(wrapper.find('span').exists()).toBe(true);
|
|
19
|
+
expect(wrapper.find('span').classes().includes('material-icons-outlined'));
|
|
20
|
+
expect(wrapper.find('span').text()).toBe('face');
|
|
21
|
+
expect(wrapper.find('span').attributes('style')).toContain(
|
|
22
|
+
'font-size: 24px; font-weight: bold; color: rgb(255, 255, 255);'
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
|
|
3
|
+
import ItemGroup from './RItemGroup.vue';
|
|
4
|
+
import Item from './RItem.vue';
|
|
5
|
+
|
|
6
|
+
const ItemGroupStory = {
|
|
7
|
+
title: 'Selections/ItemGroup',
|
|
8
|
+
component: ItemGroup,
|
|
9
|
+
setup(args: typeof ItemGroup) {
|
|
10
|
+
return { args };
|
|
11
|
+
},
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
argTypes: {
|
|
14
|
+
default: {
|
|
15
|
+
description: 'Slot for the items',
|
|
16
|
+
table: {
|
|
17
|
+
type: {
|
|
18
|
+
summary: JSON.stringify({
|
|
19
|
+
select: '(id: number, value: boolean) => void',
|
|
20
|
+
isSelected: '(id: number) => boolean',
|
|
21
|
+
selected: 'number[]',
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
itemProps: {
|
|
27
|
+
table: {
|
|
28
|
+
category: 'component',
|
|
29
|
+
type: {
|
|
30
|
+
summary: JSON.stringify({
|
|
31
|
+
value: 'number',
|
|
32
|
+
disabled: 'boolean',
|
|
33
|
+
selectedClass: 'string',
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
itemSlot: {
|
|
39
|
+
table: {
|
|
40
|
+
category: 'component',
|
|
41
|
+
type: {
|
|
42
|
+
summary: JSON.stringify({
|
|
43
|
+
isSelected: '(id: number) => boolean',
|
|
44
|
+
value: 'number',
|
|
45
|
+
selectedClass: 'string',
|
|
46
|
+
disabled: 'boolean',
|
|
47
|
+
select: '(id: number, value: boolean) => void',
|
|
48
|
+
toggle: '(id: number) => void',
|
|
49
|
+
}),
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
} as Meta<typeof ItemGroup>;
|
|
55
|
+
|
|
56
|
+
export default ItemGroupStory;
|
|
57
|
+
|
|
58
|
+
type Story = StoryObj<typeof ItemGroupStory>;
|
|
59
|
+
|
|
60
|
+
export const Overview: Story = {
|
|
61
|
+
render: (args: any) => ({
|
|
62
|
+
components: { ItemGroup, Item },
|
|
63
|
+
setup() {
|
|
64
|
+
return { args, selected: [] };
|
|
65
|
+
},
|
|
66
|
+
template: `
|
|
67
|
+
<ItemGroup v-model="selected" selectedClass="bg-blue-500 text-white">
|
|
68
|
+
<div class="flex gap-2">
|
|
69
|
+
<Item
|
|
70
|
+
v-for="i in 5"
|
|
71
|
+
:key="i"
|
|
72
|
+
:value="i"
|
|
73
|
+
:disabled="i === 3"
|
|
74
|
+
v-slot="{ isSelected, toggle, disabled, selectedClass }"
|
|
75
|
+
>
|
|
76
|
+
<div
|
|
77
|
+
:class="[
|
|
78
|
+
'p-2 border border-gray-300 rounded cursor-pointer',
|
|
79
|
+
isSelected ? selectedClass : 'bg-white',
|
|
80
|
+
disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100',
|
|
81
|
+
]"
|
|
82
|
+
@click="toggle"
|
|
83
|
+
>
|
|
84
|
+
<div>{{ isSelected ? 'Selected' : 'Click Me!' }}</div>
|
|
85
|
+
</div>
|
|
86
|
+
</Item>
|
|
87
|
+
</div>
|
|
88
|
+
</ItemGroup>
|
|
89
|
+
`,
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject, withDefaults } from 'vue';
|
|
3
|
+
|
|
4
|
+
export interface ItemProps {
|
|
5
|
+
/**
|
|
6
|
+
* The value of the item
|
|
7
|
+
* @default null
|
|
8
|
+
* @type any
|
|
9
|
+
* @example
|
|
10
|
+
* <RItem :value="1" />
|
|
11
|
+
*/
|
|
12
|
+
value: any;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Whether the item is disabled
|
|
16
|
+
* @default false
|
|
17
|
+
* @type boolean
|
|
18
|
+
* @example
|
|
19
|
+
* <RItem :disabled="true" />
|
|
20
|
+
*/
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The class to apply to the selected item
|
|
25
|
+
* @default ''
|
|
26
|
+
* @type string
|
|
27
|
+
* @example
|
|
28
|
+
* <RItem selectedClass="bg-blue-500 text-white" />
|
|
29
|
+
*/
|
|
30
|
+
selectedClass?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const RItemGroupSymbol = 'rocket-ui:r-item-group';
|
|
34
|
+
|
|
35
|
+
const props = withDefaults(defineProps<ItemProps>(), {
|
|
36
|
+
disabled: false,
|
|
37
|
+
selectedClass: '',
|
|
38
|
+
value: null,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const isSelected = inject(`${RItemGroupSymbol}:isSelected`) as (
|
|
42
|
+
id: number
|
|
43
|
+
) => boolean;
|
|
44
|
+
|
|
45
|
+
const classes = inject(`${RItemGroupSymbol}:selectedClass`, '') as string;
|
|
46
|
+
const selectedClass = computed(() => {
|
|
47
|
+
return isSelected(props.value) && [classes, props.selectedClass];
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const select = inject(`${RItemGroupSymbol}:select`) as (
|
|
51
|
+
id: number,
|
|
52
|
+
value: boolean
|
|
53
|
+
) => void;
|
|
54
|
+
|
|
55
|
+
const handleToggle = () => {
|
|
56
|
+
if (props.disabled) return;
|
|
57
|
+
select(props.value as number, !isSelected(props.value as number));
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const handleSelect = () => {
|
|
61
|
+
if (props.disabled) return;
|
|
62
|
+
select(props.value as number, true);
|
|
63
|
+
};
|
|
64
|
+
</script>
|
|
65
|
+
<template>
|
|
66
|
+
<slot
|
|
67
|
+
:isSelected="isSelected(props.value as number)"
|
|
68
|
+
:value="props.value"
|
|
69
|
+
:selectedClass="selectedClass"
|
|
70
|
+
:disabled="props.disabled"
|
|
71
|
+
:select="handleSelect"
|
|
72
|
+
:toggle="handleToggle"
|
|
73
|
+
/>
|
|
74
|
+
</template>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed, provide, withDefaults } from 'vue';
|
|
3
|
+
|
|
4
|
+
export interface ItemGroupProps {
|
|
5
|
+
/**
|
|
6
|
+
* The value of the selected items
|
|
7
|
+
* @default []
|
|
8
|
+
* @model
|
|
9
|
+
* @type number[]
|
|
10
|
+
* @example
|
|
11
|
+
* <RItemGroup v-model="selectedItems" />
|
|
12
|
+
*/
|
|
13
|
+
modelValue: number[];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The class to apply to the selected items
|
|
17
|
+
* @default ''
|
|
18
|
+
* @type string
|
|
19
|
+
* @example
|
|
20
|
+
* <RItemGroup selectedClass="bg-blue-500 text-white" />
|
|
21
|
+
*/
|
|
22
|
+
selectedClass?: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whether the item group is disabled
|
|
26
|
+
* @default false
|
|
27
|
+
* @type boolean
|
|
28
|
+
* @example
|
|
29
|
+
* <RItemGroup :disabled="true" />
|
|
30
|
+
*/
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether the item group is mandatory
|
|
35
|
+
* @default false
|
|
36
|
+
* @type boolean
|
|
37
|
+
* @example
|
|
38
|
+
* ```js
|
|
39
|
+
* const selected = ref<number[]>([1]);
|
|
40
|
+
* ```
|
|
41
|
+
* ```html
|
|
42
|
+
* <RItemGroup :mandatory="true" v-model="selected" />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
mandatory?: boolean;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The maximum number of items that can be selected
|
|
49
|
+
* @default 0
|
|
50
|
+
* @type number
|
|
51
|
+
* @example
|
|
52
|
+
* <RItemGroup :max="5" />
|
|
53
|
+
*/
|
|
54
|
+
max?: number;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The tag to use for the item group
|
|
58
|
+
* @default div
|
|
59
|
+
* @type string
|
|
60
|
+
* @example
|
|
61
|
+
* <RItemGroup as="ul" />
|
|
62
|
+
*/
|
|
63
|
+
as?: string;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Whether the item group allows multiple selections
|
|
67
|
+
* @default false
|
|
68
|
+
* @type boolean
|
|
69
|
+
* @example
|
|
70
|
+
* <RItemGroup :multiple="true" />
|
|
71
|
+
*/
|
|
72
|
+
multiple?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const RItemGroupSymbol = 'rocket-ui:r-item-group';
|
|
76
|
+
|
|
77
|
+
const props = withDefaults(defineProps<ItemGroupProps>(), {
|
|
78
|
+
disabled: false,
|
|
79
|
+
mandatory: false,
|
|
80
|
+
max: 0,
|
|
81
|
+
as: 'div',
|
|
82
|
+
selectedClass: '',
|
|
83
|
+
modelValue: () => [] as number[],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const emits = defineEmits(['update:modelValue']);
|
|
87
|
+
|
|
88
|
+
const tag = ref<string>(props.as ?? 'div');
|
|
89
|
+
|
|
90
|
+
const selectedItems = ref<number[]>(props.modelValue ?? []);
|
|
91
|
+
|
|
92
|
+
const selectedClass = computed(() => props.selectedClass);
|
|
93
|
+
provide(`${RItemGroupSymbol}:selectedClass`, selectedClass.value);
|
|
94
|
+
|
|
95
|
+
const isSelected = (id: number) => {
|
|
96
|
+
return selectedItems.value.includes(id);
|
|
97
|
+
};
|
|
98
|
+
provide(`${RItemGroupSymbol}:isSelected`, isSelected);
|
|
99
|
+
|
|
100
|
+
const select = (id: number, value: boolean) => {
|
|
101
|
+
if (props.disabled) return;
|
|
102
|
+
if (props.mandatory && selectedItems.value.length === 1 && value) return;
|
|
103
|
+
if (props.max && selectedItems.value.length === props.max && value) return;
|
|
104
|
+
if (props.multiple) {
|
|
105
|
+
if (value) {
|
|
106
|
+
selectedItems.value.push(id);
|
|
107
|
+
} else {
|
|
108
|
+
selectedItems.value = selectedItems.value.filter((item) => item !== id);
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
selectedItems.value = value ? [id] : [];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
emits('update:modelValue', selectedItems.value);
|
|
115
|
+
};
|
|
116
|
+
provide(`${RItemGroupSymbol}:select`, select);
|
|
117
|
+
</script>
|
|
118
|
+
<template>
|
|
119
|
+
<component :is="tag">
|
|
120
|
+
<slot :select="select" :isSelected="isSelected" :selected="selectedItems" />
|
|
121
|
+
</component>
|
|
122
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`ItemGroup > should render correctly 1`] = `
|
|
4
|
+
"<div>
|
|
5
|
+
<div>Item</div>
|
|
6
|
+
</div>"
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
exports[`RItemGroup > should render correctly 1`] = `
|
|
10
|
+
"<div>
|
|
11
|
+
<div>Item</div>
|
|
12
|
+
</div>"
|
|
13
|
+
`;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { mount } from '@vue/test-utils';
|
|
4
|
+
|
|
5
|
+
import { h } from 'vue';
|
|
6
|
+
|
|
7
|
+
import RItemGroup from './RItemGroup.vue';
|
|
8
|
+
import RItem from './RItem.vue';
|
|
9
|
+
|
|
10
|
+
const defaultSlot = () => [
|
|
11
|
+
h(
|
|
12
|
+
RItem,
|
|
13
|
+
{ value: 'foo' },
|
|
14
|
+
{
|
|
15
|
+
default: ({ toggle }: any) =>
|
|
16
|
+
h('div', { id: 'item', onClick: toggle }, ['foo']),
|
|
17
|
+
}
|
|
18
|
+
),
|
|
19
|
+
h(
|
|
20
|
+
RItem,
|
|
21
|
+
{ value: 'bar' },
|
|
22
|
+
{
|
|
23
|
+
default: ({ toggle }: any) =>
|
|
24
|
+
h('div', { id: 'item', onClick: toggle }, ['bar']),
|
|
25
|
+
}
|
|
26
|
+
),
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
describe('RItemGroup', () => {
|
|
30
|
+
it('should render correctly', async () => {
|
|
31
|
+
const wrapper = mount(RItemGroup, {
|
|
32
|
+
slots: {
|
|
33
|
+
default: defaultSlot,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const items = wrapper.findAll('#item');
|
|
38
|
+
|
|
39
|
+
await items[0].trigger('click');
|
|
40
|
+
await items[1].trigger('click');
|
|
41
|
+
|
|
42
|
+
const events = wrapper.emitted('update:modelValue');
|
|
43
|
+
|
|
44
|
+
expect(events).toHaveLength(2);
|
|
45
|
+
expect(events).toEqual([[['foo']], [['bar']]]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should not deselect value when using mandatory prop', async () => {
|
|
49
|
+
const wrapper = mount(RItemGroup, {
|
|
50
|
+
props: {
|
|
51
|
+
mandatory: true,
|
|
52
|
+
modelValue: 'foo',
|
|
53
|
+
},
|
|
54
|
+
slots: {
|
|
55
|
+
default: defaultSlot,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const items = wrapper.findAll('#item');
|
|
60
|
+
|
|
61
|
+
await items[0].trigger('click');
|
|
62
|
+
|
|
63
|
+
const events = wrapper.emitted('update:modelValue');
|
|
64
|
+
|
|
65
|
+
expect(events).toHaveLength(1);
|
|
66
|
+
});
|
|
67
|
+
});
|